diff --git a/.changeset/stack-auth-0-41-result-api.md b/.changeset/stack-auth-0-41-result-api.md new file mode 100644 index 00000000..0ab8677d --- /dev/null +++ b/.changeset/stack-auth-0-41-result-api.md @@ -0,0 +1,17 @@ +--- +"@cipherstash/stack": minor +"@cipherstash/wizard": patch +"stash": patch +--- + +Bump `@cipherstash/auth` (and its per-platform native bindings) from `0.40.0` to `0.41.0`, and migrate to its new `Result`-returning API. + +**What changed in `@cipherstash/auth` `0.41`.** Every fallible auth operation now returns a `@byteslice/result` `Result` (`{ data }` on success, `{ failure }` on error) instead of throwing. This covers strategy construction (`AccessKeyStrategy.create`, `OidcFederationStrategy.create`, `AutoStrategy.detect`, `DeviceSessionStrategy.fromProfile`), `getToken()`, and the device-code flow (`beginDeviceCodeFlow`, `pollForToken`, `openInBrowser`, `bindClientDevice`). Consumers now write `if (result.failure) …` and read `result.data` rather than `try/catch`. The `AuthError` type was renamed to **`AuthFailure`** — a discriminated union keyed by `type` (`"NOT_AUTHENTICATED"`, `"WORKSPACE_MISMATCH"`, …), replacing the old `error.code` string. + +**`@cipherstash/stack` (breaking type surface).** + +- **`AuthError` is renamed to `AuthFailure`** in the public re-exports from `@cipherstash/stack`. `AuthErrorCode` and `TokenResult` are unchanged. Anyone importing `AuthError` from `@cipherstash/stack` must switch to `AuthFailure`. +- The WASM-inline access-key path (`resolveStrategy`, used by `@cipherstash/stack/wasm-inline`'s `Encryption()`) now unwraps the `Result` from `AccessKeyStrategy.create`. A construction failure (e.g. an invalid CRN or access key) throws a descriptive `[encryption]` error naming the `AuthFailure.type` instead of surfacing the raw auth error. +- Bump `@cipherstash/protect-ffi` from `0.27.0` to `0.28.0`. auth `0.41`'s `getToken()` returns the token inside a `Result` envelope; protect-ffi `0.28` unwraps it (`.data.token`) inside its WASM `newClient`, whereas `0.27` read `.token` off the envelope and got `undefined` — which failed the WASM encrypt/decrypt round-trip with `token field is not a string`. `0.28` is the floor for the WASM path under auth `0.41`. + +**`stash` (CLI) and `@cipherstash/wizard`.** Internal auth call sites (`stash auth login`, device binding, `init` auth check, and the wizard's token acquisition / prerequisite check) were updated to unwrap `Result` and branch on `failure.type`. Behaviour is preserved — auth failures still surface the same way to end users; no CLI/wizard API changed. diff --git a/e2e/wasm/deno.json b/e2e/wasm/deno.json index 47901fe8..5b0e3bc3 100644 --- a/e2e/wasm/deno.json +++ b/e2e/wasm/deno.json @@ -1,6 +1,6 @@ { "//1": "Deno smoke test for @cipherstash/stack/wasm-inline. Run `pnpm exec turbo run build --filter @cipherstash/stack` first so dist/ is fresh.", - "//2": "stack is imported via a file URL because the wasm-inline subpath isn't on a published version yet — once stack ships with /wasm-inline this can switch to a plain npm: specifier. protect-ffi and auth resolve via npm: against the workspace's installed versions (Deno's nodeModulesDir: auto lets it use what pnpm fetched).", + "//2": "Everything resolves to files pnpm already installed in the workspace — no `npm:` specifiers, so Deno never re-resolves against the registry. stack is its locally-built dist; auth and protect-ffi are the WASM-inline entries of the exact versions the catalog pinned, reached via stack's own node_modules symlink (`packages/stack/node_modules/@cipherstash/*`). Both entries import only their own relative wasm bindings, so there are no transitive npm deps to resolve. This keeps the versions in lockstep with the catalog automatically (a bump to pnpm-workspace.yaml needs no edit here) and sidesteps Deno 2.9's default 24h npm freshness cooldown, which would otherwise reject a just-published first-party version and block lockstep bumps for a day. The real supply-chain gate is pnpm's `minimumReleaseAge` (see skills/stash-supply-chain-security/), which already exempts first-party @cipherstash packages.", "//3": "No --allow-ffi grant. If protect-ffi ever silently fell back to a native binding under Deno, the test would fail on missing FFI permission — this is the WASM guarantee.", "nodeModulesDir": "auto", "tasks": { @@ -9,7 +9,7 @@ }, "imports": { "@cipherstash/stack/wasm-inline": "../../packages/stack/dist/wasm-inline.js", - "@cipherstash/protect-ffi/wasm-inline": "npm:@cipherstash/protect-ffi@0.26.0/wasm-inline", - "@cipherstash/auth/wasm-inline": "npm:@cipherstash/auth@0.40.0/wasm-inline" + "@cipherstash/protect-ffi/wasm-inline": "../../packages/stack/node_modules/@cipherstash/protect-ffi/dist/wasm/protect_ffi_inline.js", + "@cipherstash/auth/wasm-inline": "../../packages/stack/node_modules/@cipherstash/auth/wasm-inline.mjs" } } diff --git a/packages/cli/src/commands/auth/login.ts b/packages/cli/src/commands/auth/login.ts index 3ce02232..1a7e375c 100644 --- a/packages/cli/src/commands/auth/login.ts +++ b/packages/cli/src/commands/auth/login.ts @@ -34,23 +34,35 @@ export async function login(region: string, _referrer: string | undefined) { // Must be 'cli' — it's the only OAuth client_id registered with CTS. // Passing anything else (e.g. `cli-supabase`) causes INVALID_CLIENT. + // As of `@cipherstash/auth` `0.41`, the device-code flow returns + // `Result` instead of throwing — unwrap each step. const pending = await beginDeviceCodeFlow(region, 'cli') + if (pending.failure) { + p.log.error(pending.failure.error.message) + process.exit(1) + } + const flow = pending.data - p.log.info(`Your code is: ${pending.userCode}`) - p.log.info(`Visit: ${pending.verificationUriComplete}`) - p.log.info(`Code expires in: ${pending.expiresIn}s`) + p.log.info(`Your code is: ${flow.userCode}`) + p.log.info(`Visit: ${flow.verificationUriComplete}`) + p.log.info(`Code expires in: ${flow.expiresIn}s`) - const opened = pending.openInBrowser() - if (!opened) { + const opened = flow.openInBrowser() + if (opened.failure || !opened.data) { p.log.warn('Could not open browser — please visit the URL above manually.') } s.start('Waiting for authorization...') - const auth = await pending.pollForToken() + const auth = await flow.pollForToken() + if (auth.failure) { + s.stop('Authentication failed!') + p.log.error(auth.failure.error.message) + process.exit(1) + } s.stop('Authenticated!') p.log.info( - `Token expires at: ${new Date(auth.expiresAt * 1000).toISOString()}`, + `Token expires at: ${new Date(auth.data.expiresAt * 1000).toISOString()}`, ) } @@ -58,12 +70,13 @@ export async function bindDevice() { const s = p.spinner() s.start('Binding device to the default Keyset...') - try { - await bindClientDevice() - s.stop('Your device has been bound to the default Keyset!') - } catch (error) { + // `bindClientDevice()` returns `Result` as of + // `@cipherstash/auth` `0.41` — a failure no longer throws. + const result = await bindClientDevice() + if (result.failure) { s.stop('Failed to bind your device to the default Keyset!') - p.log.error(error instanceof Error ? error.message : 'Unknown error') + p.log.error(result.failure.error.message) process.exit(1) } + s.stop('Your device has been bound to the default Keyset!') } diff --git a/packages/cli/src/commands/init/steps/authenticate.ts b/packages/cli/src/commands/init/steps/authenticate.ts index 163581f6..9e2a1004 100644 --- a/packages/cli/src/commands/init/steps/authenticate.ts +++ b/packages/cli/src/commands/init/steps/authenticate.ts @@ -16,13 +16,20 @@ interface ExistingAuth { */ async function checkExistingAuth(): Promise { try { - const strategy = AutoStrategy.detect() - const result = await strategy.getToken() + // As of `@cipherstash/auth` `0.41`, `detect()` and `getToken()` return a + // `Result` instead of throwing — a failure at either step + // just means "not authenticated yet", so fall through to `undefined`. + const detected = AutoStrategy.detect() + if (detected.failure) return undefined - const regionEntry = regions.find((r) => result.issuer.includes(r.value)) + const result = await detected.data.getToken() + if (result.failure) return undefined + + const { issuer, workspaceId } = result.data + const regionEntry = regions.find((r) => issuer.includes(r.value)) const regionLabel = regionEntry?.label ?? 'unknown' - return { workspace: result.workspaceId, regionLabel } + return { workspace: workspaceId, regionLabel } } catch { return undefined } diff --git a/packages/stack/__tests__/helpers/stub-auth-wasm-inline.ts b/packages/stack/__tests__/helpers/stub-auth-wasm-inline.ts index 23711105..386a7eb4 100644 --- a/packages/stack/__tests__/helpers/stub-auth-wasm-inline.ts +++ b/packages/stack/__tests__/helpers/stub-auth-wasm-inline.ts @@ -6,6 +6,10 @@ * lets Vitest load `src/wasm-inline` for pure-helper unit tests. Aliased in via * `vitest.config.ts`. */ +// `@cipherstash/auth` `0.41` `create` returns a `Result` +// rather than throwing. These stubs are only reached by tests that don't +// override the module with `vi.mock`; they still throw loudly so an +// unexpectedly-exercised path fails visibly rather than silently. export const AccessKeyStrategy = { create: (): never => { throw new Error( diff --git a/packages/stack/__tests__/init-strategy.test.ts b/packages/stack/__tests__/init-strategy.test.ts index 65766d4b..85788557 100644 --- a/packages/stack/__tests__/init-strategy.test.ts +++ b/packages/stack/__tests__/init-strategy.test.ts @@ -165,6 +165,20 @@ describe('Encryption config.strategy (deprecated alias)', () => { expect(warnSpy).not.toHaveBeenCalled() }) + + it('warns at most once per process across repeated Encryption calls', async () => { + // No reset between the two calls (the latch is only reset in beforeEach), + // so they share one process-level latch — a regression that dropped the + // `if (warnedStrategyDeprecated) return` guard would warn twice here. + const strategy: AuthStrategy = { + getToken: vi.fn(async () => ({ token: 'service-token' })), + } + + await Encryption({ schemas: [users], config: { strategy } }) + await Encryption({ schemas: [users], config: { strategy } }) + + expect(warnSpy).toHaveBeenCalledTimes(1) + }) }) // A minimal structural EQL v3 table: what marks a table as v3 for wire-format diff --git a/packages/stack/__tests__/wasm-inline-new-client.test.ts b/packages/stack/__tests__/wasm-inline-new-client.test.ts index 2fcd2b57..c7a1e556 100644 --- a/packages/stack/__tests__/wasm-inline-new-client.test.ts +++ b/packages/stack/__tests__/wasm-inline-new-client.test.ts @@ -18,7 +18,9 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' vi.mock('@cipherstash/auth/wasm-inline', () => ({ AccessKeyStrategy: { - create: vi.fn(() => ({ __mock: 'access-key-strategy' })), + // `@cipherstash/auth` `0.41` `create` returns a `Result` + // (`{ data }` on success) — `resolveStrategy` unwraps `.data`. + create: vi.fn(() => ({ data: { __mock: 'access-key-strategy' } })), }, OidcFederationStrategy: class {}, })) diff --git a/packages/stack/__tests__/wasm-inline-strategy.test.ts b/packages/stack/__tests__/wasm-inline-strategy.test.ts index 281fedf2..9c393129 100644 --- a/packages/stack/__tests__/wasm-inline-strategy.test.ts +++ b/packages/stack/__tests__/wasm-inline-strategy.test.ts @@ -17,7 +17,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' vi.mock('@cipherstash/auth/wasm-inline', () => ({ AccessKeyStrategy: { - create: vi.fn(() => ({ __mock: 'access-key-strategy' })), + // `@cipherstash/auth` `0.41` `create` returns a `Result` + // (`{ data }` on success) — `resolveStrategy` unwraps `.data`. + create: vi.fn(() => ({ data: { __mock: 'access-key-strategy' } })), }, OidcFederationStrategy: class {}, })) @@ -65,6 +67,35 @@ describe('wasm-inline resolveStrategy', () => { expect(warnSpy).not.toHaveBeenCalled() }) + it('throws when AccessKeyStrategy.create returns a failure Result', () => { + // `@cipherstash/auth` `0.41` `create` returns `{ failure }` instead of + // throwing — `resolveStrategy` must surface that as a loud construction + // error naming the failure type and the underlying message, not forward + // an unusable strategy. + vi.mocked(AccessKeyStrategy.create).mockReturnValueOnce( + // biome-ignore lint/suspicious/noExplicitAny: mock the 0.41 Result failure arm + { + failure: { + type: 'InvalidWorkspaceCrn', + error: new Error('unparseable CRN'), + }, + } as any, + ) + + expect(() => + // biome-ignore lint/suspicious/noExplicitAny: exercise the access-key arm directly + resolveStrategy({ workspaceCrn: CRN, accessKey: 'CSAK.test' } as any), + ).toThrowError( + /failed to construct.*\(InvalidWorkspaceCrn\): unparseable CRN/, + ) + // The guards passed and it reached the builder before failing. + expect(vi.mocked(AccessKeyStrategy.create)).toHaveBeenCalledWith( + CRN, + 'CSAK.test', + ) + expect(warnSpy).not.toHaveBeenCalled() + }) + it('uses an explicit config.authStrategy verbatim and never builds an access key', () => { const explicit = { getToken: vi.fn() } // biome-ignore lint/suspicious/noExplicitAny: exercise the authStrategy arm of the discriminated union directly @@ -87,6 +118,19 @@ describe('wasm-inline resolveStrategy', () => { ) }) + it('warns at most once per process across repeated resolveStrategy calls', () => { + // No reset between the two calls (the latch is only reset in beforeEach), + // so they share one process-level latch — a regression that dropped the + // `if (warnedStrategyDeprecated) return` guard would warn twice here. + const explicit = { getToken: vi.fn() } + // biome-ignore lint/suspicious/noExplicitAny: exercise the deprecated strategy arm directly + resolveStrategy({ strategy: explicit } as any) + // biome-ignore lint/suspicious/noExplicitAny: exercise the deprecated strategy arm directly + resolveStrategy({ strategy: explicit } as any) + + expect(warnSpy).toHaveBeenCalledTimes(1) + }) + it('prefers authStrategy over the deprecated strategy when both are set, and still warns', () => { const authStrategy = { getToken: vi.fn() } const strategy = { getToken: vi.fn() } diff --git a/packages/stack/package.json b/packages/stack/package.json index c4bcacc6..5efb71b2 100644 --- a/packages/stack/package.json +++ b/packages/stack/package.json @@ -244,7 +244,7 @@ "dependencies": { "@byteslice/result": "0.2.0", "@cipherstash/auth": "catalog:repo", - "@cipherstash/protect-ffi": "0.27.0", + "@cipherstash/protect-ffi": "0.28.0", "evlog": "1.11.0", "uuid": "14.0.0", "zod": "3.25.76" diff --git a/packages/stack/src/index.ts b/packages/stack/src/index.ts index 32d4f48e..2274c86e 100644 --- a/packages/stack/src/index.ts +++ b/packages/stack/src/index.ts @@ -36,6 +36,10 @@ export type OidcFederationStrategy = InstanceType< typeof auth.OidcFederationStrategy > -export type { AuthError, AuthErrorCode, TokenResult } from '@cipherstash/auth' +export type { + AuthErrorCode, + AuthFailure, + TokenResult, +} from '@cipherstash/auth' // Re-export types for convenience export type { Encrypted } from '@/types' diff --git a/packages/stack/src/wasm-inline.ts b/packages/stack/src/wasm-inline.ts index 378a7eaf..54ff117b 100644 --- a/packages/stack/src/wasm-inline.ts +++ b/packages/stack/src/wasm-inline.ts @@ -210,8 +210,11 @@ export type WasmClientConfig = { /** * Any auth strategy accepted on the WASM path. Both expose - * `getToken(): Promise<{ token }>`, which is all protect-ffi's WASM - * `newClient` requires: + * `getToken(): Promise>` — as of + * `@cipherstash/auth` 0.41 the token is wrapped in a `@byteslice/result` + * envelope. `@cipherstash/protect-ffi` 0.28+ unwraps that envelope (reading + * `.data.token`, surfacing `.failure`) inside its WASM `newClient`; 0.27 read + * `.token` off the envelope and saw `undefined`, so keep the ffi floor at 0.28. * * - {@link AccessKeyStrategy} — static M2M / CI access key. * - {@link OidcFederationStrategy} — federates an end-user OIDC JWT into a @@ -465,6 +468,14 @@ export function resolveStrategy(cfg: WasmClientConfig): WasmAuthStrategy { } // `AccessKeyStrategy.create` takes the full workspace CRN — the region is // derived from it inside `@cipherstash/auth`, so the CRN stays the single - // source of truth with no manual region split. - return AccessKeyStrategy.create(cfg.workspaceCrn, cfg.accessKey) + // source of truth with no manual region split. As of `@cipherstash/auth` + // `0.41` `create` returns a `Result` rather + // than throwing — unwrap it and surface a construction failure loudly. + const result = AccessKeyStrategy.create(cfg.workspaceCrn, cfg.accessKey) + if (result.failure) { + throw new Error( + `[encryption]: failed to construct \`AccessKeyStrategy\` from \`config.workspaceCrn\` / \`config.accessKey\` (${result.failure.type}): ${result.failure.error.message}`, + ) + } + return result.data } diff --git a/packages/wizard/src/__tests__/prerequisites.test.ts b/packages/wizard/src/__tests__/prerequisites.test.ts index f57fddb3..3436ae24 100644 --- a/packages/wizard/src/__tests__/prerequisites.test.ts +++ b/packages/wizard/src/__tests__/prerequisites.test.ts @@ -5,14 +5,20 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { checkPrerequisites } from '../lib/prerequisites.js' // Force the auth check to fail so we exercise the missing-list copy. +// `@cipherstash/auth` `0.41`: `detect()` returns `Result` +// and `getToken()` returns `Result` (no throwing). +// A `NOT_AUTHENTICATED` failure is what `hasCredentials` reads as "missing". vi.mock('@cipherstash/auth', () => ({ default: { AutoStrategy: { detect: () => ({ - getToken: async () => { - const err = new Error('not authed') as Error & { code: string } - err.code = 'NOT_AUTHENTICATED' - throw err + data: { + getToken: async () => ({ + failure: { + type: 'NOT_AUTHENTICATED', + error: new Error('not authed'), + }, + }), }, }), }, diff --git a/packages/wizard/src/agent/fetch-prompt.ts b/packages/wizard/src/agent/fetch-prompt.ts index 4d38ee56..ae9b0989 100644 --- a/packages/wizard/src/agent/fetch-prompt.ts +++ b/packages/wizard/src/agent/fetch-prompt.ts @@ -29,8 +29,28 @@ export async function fetchIntegrationPrompt( const { ctx, cliVersion, runner } = options const mode: WizardMode = options.mode ?? 'implement' - const strategy = AutoStrategy.detect() - const { token } = await strategy.getToken() + // As of `@cipherstash/auth` `0.41`, `detect()` and `getToken()` return a + // `Result` instead of throwing — unwrap both, surfacing an + // auth failure as a formatted wizard error. + const detected = AutoStrategy.detect() + if (detected.failure) { + throw new Error( + formatWizardError( + 'Could not authenticate with CipherStash.', + detected.failure.error.message, + ), + ) + } + const tokenResult = await detected.data.getToken() + if (tokenResult.failure) { + throw new Error( + formatWizardError( + 'Could not authenticate with CipherStash.', + tokenResult.failure.error.message, + ), + ) + } + const { token } = tokenResult.data let res: Response try { diff --git a/packages/wizard/src/agent/interface.ts b/packages/wizard/src/agent/interface.ts index 2c1eceac..b4d7b2ab 100644 --- a/packages/wizard/src/agent/interface.ts +++ b/packages/wizard/src/agent/interface.ts @@ -204,9 +204,14 @@ export function wizardCanUseTool( */ async function getAccessToken(): Promise { try { - const strategy = AutoStrategy.detect() - const result = await strategy.getToken() - return result.token + // As of `@cipherstash/auth` `0.41`, `detect()` and `getToken()` return a + // `Result` instead of throwing — a failure at either step + // means no usable token, so fall through to `undefined`. + const detected = AutoStrategy.detect() + if (detected.failure) return undefined + const result = await detected.data.getToken() + if (result.failure) return undefined + return result.data.token } catch { return undefined } diff --git a/packages/wizard/src/lib/prerequisites.ts b/packages/wizard/src/lib/prerequisites.ts index fcf234ac..faa909e8 100644 --- a/packages/wizard/src/lib/prerequisites.ts +++ b/packages/wizard/src/lib/prerequisites.ts @@ -37,16 +37,28 @@ export async function checkPrerequisites( // between auth versions and duplicating it in the CLI is what caused // CIP-2996 in the first place. async function hasCredentials(): Promise { - try { - await auth.AutoStrategy.detect().getToken() - return true - } catch (error) { - const code = (error as { code?: string } | null)?.code - if (code === 'NOT_AUTHENTICATED' || code === 'MISSING_WORKSPACE_CRN') { - return false - } - throw error + // As of `@cipherstash/auth` `0.41`, `detect()` and `getToken()` return a + // `Result` instead of throwing. The `failure.type` + // discriminant carries what used to be `error.code`: a "not authenticated" + // failure means no credentials (return false); any other failure is + // unexpected and rethrown. + const notAuthenticated = (failure: { type: string }): boolean => + failure.type === 'NOT_AUTHENTICATED' || + failure.type === 'MISSING_WORKSPACE_CRN' + + const detected = auth.AutoStrategy.detect() + if (detected.failure) { + if (notAuthenticated(detected.failure)) return false + throw detected.failure.error + } + + const result = await detected.data.getToken() + if (result.failure) { + if (notAuthenticated(result.failure)) return false + throw result.failure.error } + + return true } /** Walk up from cwd to find stash.config.ts. */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7b2f1070..3023ed14 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,26 +7,26 @@ settings: catalogs: repo: '@cipherstash/auth': - specifier: 0.40.0 - version: 0.40.0 + specifier: 0.41.0 + version: 0.41.0 '@cipherstash/auth-darwin-arm64': - specifier: 0.40.0 - version: 0.40.0 + specifier: 0.41.0 + version: 0.41.0 '@cipherstash/auth-darwin-x64': - specifier: 0.40.0 - version: 0.40.0 + specifier: 0.41.0 + version: 0.41.0 '@cipherstash/auth-linux-arm64-gnu': - specifier: 0.40.0 - version: 0.40.0 + specifier: 0.41.0 + version: 0.41.0 '@cipherstash/auth-linux-x64-gnu': - specifier: 0.40.0 - version: 0.40.0 + specifier: 0.41.0 + version: 0.41.0 '@cipherstash/auth-linux-x64-musl': - specifier: 0.40.0 - version: 0.40.0 + specifier: 0.41.0 + version: 0.41.0 '@cipherstash/auth-win32-x64-msvc': - specifier: 0.40.0 - version: 0.40.0 + specifier: 0.41.0 + version: 0.41.0 tsup: specifier: 8.5.1 version: 8.5.1 @@ -235,7 +235,7 @@ importers: dependencies: '@cipherstash/auth': specifier: catalog:repo - version: 0.40.0(@cipherstash/auth-darwin-arm64@0.40.0)(@cipherstash/auth-darwin-x64@0.40.0)(@cipherstash/auth-linux-arm64-gnu@0.40.0)(@cipherstash/auth-linux-x64-gnu@0.40.0)(@cipherstash/auth-linux-x64-musl@0.40.0)(@cipherstash/auth-win32-x64-msvc@0.40.0) + version: 0.41.0(@cipherstash/auth-darwin-arm64@0.41.0)(@cipherstash/auth-darwin-x64@0.41.0)(@cipherstash/auth-linux-arm64-gnu@0.41.0)(@cipherstash/auth-linux-x64-gnu@0.41.0)(@cipherstash/auth-linux-x64-musl@0.41.0)(@cipherstash/auth-win32-x64-msvc@0.41.0) '@cipherstash/migrate': specifier: workspace:* version: link:../migrate @@ -288,22 +288,22 @@ importers: optionalDependencies: '@cipherstash/auth-darwin-arm64': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-darwin-x64': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-arm64-gnu': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-x64-gnu': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-x64-musl': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-win32-x64-msvc': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 packages/drizzle: dependencies: @@ -576,10 +576,10 @@ importers: version: 0.2.0 '@cipherstash/auth': specifier: catalog:repo - version: 0.40.0(@cipherstash/auth-darwin-arm64@0.40.0)(@cipherstash/auth-darwin-x64@0.40.0)(@cipherstash/auth-linux-arm64-gnu@0.40.0)(@cipherstash/auth-linux-x64-gnu@0.40.0)(@cipherstash/auth-linux-x64-musl@0.40.0)(@cipherstash/auth-win32-x64-msvc@0.40.0) + version: 0.41.0(@cipherstash/auth-darwin-arm64@0.41.0)(@cipherstash/auth-darwin-x64@0.41.0)(@cipherstash/auth-linux-arm64-gnu@0.41.0)(@cipherstash/auth-linux-x64-gnu@0.41.0)(@cipherstash/auth-linux-x64-musl@0.41.0)(@cipherstash/auth-win32-x64-msvc@0.41.0) '@cipherstash/protect-ffi': - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.28.0 + version: 0.28.0 evlog: specifier: 1.11.0 version: 1.11.0(next@15.5.18(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) @@ -632,22 +632,22 @@ importers: optionalDependencies: '@cipherstash/auth-darwin-arm64': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-darwin-x64': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-arm64-gnu': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-x64-gnu': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-x64-musl': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-win32-x64-msvc': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 packages/wizard: dependencies: @@ -659,7 +659,7 @@ importers: version: 0.106.0(zod@3.25.76) '@cipherstash/auth': specifier: catalog:repo - version: 0.40.0(@cipherstash/auth-darwin-arm64@0.40.0)(@cipherstash/auth-darwin-x64@0.40.0)(@cipherstash/auth-linux-arm64-gnu@0.40.0)(@cipherstash/auth-linux-x64-gnu@0.40.0)(@cipherstash/auth-linux-x64-musl@0.40.0)(@cipherstash/auth-win32-x64-msvc@0.40.0) + version: 0.41.0(@cipherstash/auth-darwin-arm64@0.41.0)(@cipherstash/auth-darwin-x64@0.41.0)(@cipherstash/auth-linux-arm64-gnu@0.41.0)(@cipherstash/auth-linux-x64-gnu@0.41.0)(@cipherstash/auth-linux-x64-musl@0.41.0)(@cipherstash/auth-win32-x64-msvc@0.41.0) '@clack/prompts': specifier: 1.4.0 version: 1.4.0 @@ -697,22 +697,22 @@ importers: optionalDependencies: '@cipherstash/auth-darwin-arm64': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-darwin-x64': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-arm64-gnu': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-x64-gnu': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-linux-x64-musl': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 '@cipherstash/auth-win32-x64-msvc': specifier: catalog:repo - version: 0.40.0 + version: 0.41.0 packages: @@ -855,6 +855,9 @@ packages: '@byteslice/result@0.2.0': resolution: {integrity: sha512-4zENy+fMQuZ5vvoK+W685qdkPu7FBJ8lo5t5XSUAbqvixsiTzvAGDkxsrAR9WwqlvY3OgitWo8ciCXLSURcNLw==} + '@byteslice/result@0.3.0': + resolution: {integrity: sha512-nIVjzVJ5LEUsj5jZ196OQ+XFYDPw74JVmHrsKs0g/iX1c8llydLWKbseMKmAtcEnpRj8hdsEue5H/naz7wdC4A==} + '@changesets/apply-release-plan@7.1.1': resolution: {integrity: sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA==} @@ -910,48 +913,48 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@cipherstash/auth-darwin-arm64@0.40.0': - resolution: {integrity: sha512-TMVgX+dTiP4zvDEgKDDe92SQSeTZarRMq4+StUFRCJrefRVfjtnNT0zqhWmpZelCxOtnL7Ch+mq+TKRmYCY1cQ==} + '@cipherstash/auth-darwin-arm64@0.41.0': + resolution: {integrity: sha512-2B+J/bPblfiWQcxm3Z9voLhV66TZcmDpzVz5aBNS4y/B7Ke55jGH6m3H9g+c1xHZbe62q7zwDUEatveOy69f2A==} cpu: [arm64] os: [darwin] - '@cipherstash/auth-darwin-x64@0.40.0': - resolution: {integrity: sha512-G8fmOqWrOTE5cO3CwVSSUAqlJXKvvQjHlKzT1aKR8KC9GDExSAmaQMiV7wNDI1NonHq9ERRi2MQ2mYNmfRTqxA==} + '@cipherstash/auth-darwin-x64@0.41.0': + resolution: {integrity: sha512-XrmFRSdQaoed7tqJ+RJLiBvuQr/v7qiSu7LDA3PCVbegHVcsjYQ9D0sd49zDZEEFN4zZlcwmeh80eGAEJiyhKg==} cpu: [x64] os: [darwin] - '@cipherstash/auth-linux-arm64-gnu@0.40.0': - resolution: {integrity: sha512-3c4blsy35OUGK+SaOI9SIQCZW7zByuBYK6NR+HNde6RTXtxPOY2h9bpg72MMKOAvU/5KWkCvDR+jrMammAWRIg==} + '@cipherstash/auth-linux-arm64-gnu@0.41.0': + resolution: {integrity: sha512-NQJK++HzV7XCQPuNbVmIJcC5T4QuflOySYmQtP2PoTg0p+V7WK/3yruZZKgjbbCU6v8tek/D3T8hk02snq/8sQ==} cpu: [arm64] os: [linux] libc: [glibc] - '@cipherstash/auth-linux-x64-gnu@0.40.0': - resolution: {integrity: sha512-Tul+CoQGvhdZCMrPGjKa7/YiHtpr/h4vzLRxX9C8vUHfM0r26d3JvHLJsJPz4wsiBTXfcbfQ9gcV/UEkPhn4vg==} + '@cipherstash/auth-linux-x64-gnu@0.41.0': + resolution: {integrity: sha512-9NMiMs2p8p5NBcir8Cx90zBzOlkM0EWbIZOeCIjokT9X4d6UJy3+JhXi5VRn0gWpqAA7i7+BZD+puZ+fmBzJLQ==} cpu: [x64] os: [linux] libc: [glibc] - '@cipherstash/auth-linux-x64-musl@0.40.0': - resolution: {integrity: sha512-qW5IhDWgIEVZ94oWrI/P0LUqMYd6BdLMRDirevWiTqc0Bfw8PaYe7bfds1MOfzx59kWJqedugVbpf/VApO448A==} + '@cipherstash/auth-linux-x64-musl@0.41.0': + resolution: {integrity: sha512-V8QwrxXLoqO0ED02hnvQJNBid/iDZUawt3zobUL+DqieN3QZxDxI5/viFIkA4bTg7CV6oSmy2b0rINGqiHvkig==} cpu: [x64] os: [linux] libc: [musl] - '@cipherstash/auth-win32-x64-msvc@0.40.0': - resolution: {integrity: sha512-V66Y6p3RPFb4o1M6jB4LRLGBciISqxVOkDYU000ehkk12Ztu2hd1IHihHtq9zxQtlXFbMVJUeWNtxbL4Etmifw==} + '@cipherstash/auth-win32-x64-msvc@0.41.0': + resolution: {integrity: sha512-MkC04kTuyUd7J2/dRWIzdER1if6V+g6tVDRoZI/dql/Uq/+FXtV9lBXDcS1iATDyE/1APLvMMvuAqJeELGrGag==} cpu: [x64] os: [win32] - '@cipherstash/auth@0.40.0': - resolution: {integrity: sha512-UARvsiy29HhxsBZM7cqntIqwqNOVEbuHz1JAkZO5gfFaB927BnDfC5lP5dgU7xjm5NN1MoGfBVSVK9jVMhquog==} + '@cipherstash/auth@0.41.0': + resolution: {integrity: sha512-jhhCthk+vilCQAvOfKYPSnIOZR2J3/+0JEYLNY3+M19rEzZ2ZmTLZDqzu4c+y1P73LgzTX+oWL6ESUoKsMd0TQ==} peerDependencies: - '@cipherstash/auth-darwin-arm64': 0.40.0 - '@cipherstash/auth-darwin-x64': 0.40.0 - '@cipherstash/auth-linux-arm64-gnu': 0.40.0 - '@cipherstash/auth-linux-x64-gnu': 0.40.0 - '@cipherstash/auth-linux-x64-musl': 0.40.0 - '@cipherstash/auth-win32-x64-msvc': 0.40.0 + '@cipherstash/auth-darwin-arm64': 0.41.0 + '@cipherstash/auth-darwin-x64': 0.41.0 + '@cipherstash/auth-linux-arm64-gnu': 0.41.0 + '@cipherstash/auth-linux-x64-gnu': 0.41.0 + '@cipherstash/auth-linux-x64-musl': 0.41.0 + '@cipherstash/auth-win32-x64-msvc': 0.41.0 peerDependenciesMeta: '@cipherstash/auth-darwin-arm64': optional: true @@ -971,8 +974,8 @@ packages: cpu: [arm64] os: [darwin] - '@cipherstash/protect-ffi-darwin-arm64@0.27.0': - resolution: {integrity: sha512-Ikh0DaqbRSsviwFAJZXHOClBMXWneCCqEbUR4YtzzGedCBnGeB3QRxoYBra/uKAkkbdgSKVncaXRJOze33bvag==} + '@cipherstash/protect-ffi-darwin-arm64@0.28.0': + resolution: {integrity: sha512-QRwiovEdgjstbaCONZGYXA82NG4Gwz9mJOZeAzthUmNIQfnVErO9UQAfJ+I1T/YG1Ww2FCWcHltXMl/qjyeK4A==} cpu: [arm64] os: [darwin] @@ -981,8 +984,8 @@ packages: cpu: [x64] os: [darwin] - '@cipherstash/protect-ffi-darwin-x64@0.27.0': - resolution: {integrity: sha512-c9DOzv5h58csIJ12wh1DXuN0RNc4PCfep0BY/9GrlJ8+ZyCmtiHXJmputX7nxIGLLlZ8aIfZFRIKjD4dJU3FoA==} + '@cipherstash/protect-ffi-darwin-x64@0.28.0': + resolution: {integrity: sha512-H8qB2z3drJSc2bR5ITsJSFrOoNKvORbauTdHmaS1e5OleXsLl/F+56Zvghz8NWs+bXs/2aVzHxpYte8FgV8AAQ==} cpu: [x64] os: [darwin] @@ -991,8 +994,8 @@ packages: cpu: [arm64] os: [linux] - '@cipherstash/protect-ffi-linux-arm64-gnu@0.27.0': - resolution: {integrity: sha512-exZw40bjYVjv9gm2dye/agd2hVcneyOVAsNdOYDnLiw6iLiWpAWKi0ndIvOKskLLlzOFfcmGqZxGEY3rWpnnKw==} + '@cipherstash/protect-ffi-linux-arm64-gnu@0.28.0': + resolution: {integrity: sha512-h7vZxB/wako6j1jspkGl41gptTN1dBTWYqAR6jhVnvKJK0TBlyUKuSJwO1NeqyNfFQ/b1KmqJ11JGvY95uRZOA==} cpu: [arm64] os: [linux] @@ -1001,8 +1004,8 @@ packages: cpu: [x64] os: [linux] - '@cipherstash/protect-ffi-linux-x64-gnu@0.27.0': - resolution: {integrity: sha512-xA8V+2VHoK0tqsQcV5KCupEQw2E5jVazsBu56dfTBUypu6y6H7gF5/zyhxFIfQNDMErpFZgfcMDuQGZ7w8B7tQ==} + '@cipherstash/protect-ffi-linux-x64-gnu@0.28.0': + resolution: {integrity: sha512-PgHn0Og0PiCwFdV4yKhipGKfqkCXP6Xchyy6ykTaISabmSlkkbRNkyNF1/tZEQYF65sm5gmqSpwSYzKODaAsbg==} cpu: [x64] os: [linux] @@ -1011,8 +1014,8 @@ packages: cpu: [x64] os: [linux] - '@cipherstash/protect-ffi-linux-x64-musl@0.27.0': - resolution: {integrity: sha512-EcoEXvCq4CcVMKoRIeMxEFgB8UvGfjHHl7Mohy9vkrfazOKgXcmLIuy0oKP3IhNSJuyQU1iP26KEH7XDYbn/Sg==} + '@cipherstash/protect-ffi-linux-x64-musl@0.28.0': + resolution: {integrity: sha512-fMu3k1Y3wYMcGbGpVtrlCMNRLd1//5c9ZHcyWFjKFqimOCbBO5akgCQij4zcvj4kYDHtveu9dOdOKVhaG8k6hQ==} cpu: [x64] os: [linux] @@ -1021,16 +1024,16 @@ packages: cpu: [x64] os: [win32] - '@cipherstash/protect-ffi-win32-x64-msvc@0.27.0': - resolution: {integrity: sha512-G50vcDCp9c/b8WrP0Y6zw+Q3vb4sWlCFww2SDp3KY01loyLQGDadSn8Rbf24W7u/VOef1b2KqZlaCc0qeHJbGQ==} + '@cipherstash/protect-ffi-win32-x64-msvc@0.28.0': + resolution: {integrity: sha512-tF0y7TcyBtgN/jHodYMnrJ4etLkEI/klzDivW8Q8eIuIdoJ3q5muZKFIhNX0MbDDdh2O4GsRdNhXRubs7BiFpA==} cpu: [x64] os: [win32] '@cipherstash/protect-ffi@0.23.0': resolution: {integrity: sha512-Ca8MKLrrumC561VoPDOhuUZcF8C8YenqO1Ig9hSJSRUB+jFeIJXeyn7glExsvKYWtxOx/pRub9FV8A0RyuPHMg==} - '@cipherstash/protect-ffi@0.27.0': - resolution: {integrity: sha512-uGUb5DychOUZqe1OFI1H0zYiQkPbWAnbwW65YV6PgfJUu/Pu//EDMRJmty4SWzeNq8E6BA4t+YUPP2DEXKDnkw==} + '@cipherstash/protect-ffi@0.28.0': + resolution: {integrity: sha512-R2L/8HwMREkVKlR5KCcuELIWz4QNButSBQzY+nRDHl1PUXjRqWG1h265FkKVtTXKNKUup7rB4mswu+M+t9KF3A==} '@clack/core@1.3.0': resolution: {integrity: sha512-xJPHpAmEQUBrXSLx0gF+q5K/IyihXpsHZcha+jB+tyahsKRK3Dxo4D0coZDewHo12NhiuzC3dTtMPbm53GEAAA==} @@ -4137,6 +4140,8 @@ snapshots: '@byteslice/result@0.2.0': {} + '@byteslice/result@0.3.0': {} + '@changesets/apply-release-plan@7.1.1': dependencies: '@changesets/config': 3.1.4 @@ -4280,67 +4285,69 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 - '@cipherstash/auth-darwin-arm64@0.40.0': + '@cipherstash/auth-darwin-arm64@0.41.0': optional: true - '@cipherstash/auth-darwin-x64@0.40.0': + '@cipherstash/auth-darwin-x64@0.41.0': optional: true - '@cipherstash/auth-linux-arm64-gnu@0.40.0': + '@cipherstash/auth-linux-arm64-gnu@0.41.0': optional: true - '@cipherstash/auth-linux-x64-gnu@0.40.0': + '@cipherstash/auth-linux-x64-gnu@0.41.0': optional: true - '@cipherstash/auth-linux-x64-musl@0.40.0': + '@cipherstash/auth-linux-x64-musl@0.41.0': optional: true - '@cipherstash/auth-win32-x64-msvc@0.40.0': + '@cipherstash/auth-win32-x64-msvc@0.41.0': optional: true - '@cipherstash/auth@0.40.0(@cipherstash/auth-darwin-arm64@0.40.0)(@cipherstash/auth-darwin-x64@0.40.0)(@cipherstash/auth-linux-arm64-gnu@0.40.0)(@cipherstash/auth-linux-x64-gnu@0.40.0)(@cipherstash/auth-linux-x64-musl@0.40.0)(@cipherstash/auth-win32-x64-msvc@0.40.0)': + '@cipherstash/auth@0.41.0(@cipherstash/auth-darwin-arm64@0.41.0)(@cipherstash/auth-darwin-x64@0.41.0)(@cipherstash/auth-linux-arm64-gnu@0.41.0)(@cipherstash/auth-linux-x64-gnu@0.41.0)(@cipherstash/auth-linux-x64-musl@0.41.0)(@cipherstash/auth-win32-x64-msvc@0.41.0)': + dependencies: + '@byteslice/result': 0.3.0 optionalDependencies: - '@cipherstash/auth-darwin-arm64': 0.40.0 - '@cipherstash/auth-darwin-x64': 0.40.0 - '@cipherstash/auth-linux-arm64-gnu': 0.40.0 - '@cipherstash/auth-linux-x64-gnu': 0.40.0 - '@cipherstash/auth-linux-x64-musl': 0.40.0 - '@cipherstash/auth-win32-x64-msvc': 0.40.0 + '@cipherstash/auth-darwin-arm64': 0.41.0 + '@cipherstash/auth-darwin-x64': 0.41.0 + '@cipherstash/auth-linux-arm64-gnu': 0.41.0 + '@cipherstash/auth-linux-x64-gnu': 0.41.0 + '@cipherstash/auth-linux-x64-musl': 0.41.0 + '@cipherstash/auth-win32-x64-msvc': 0.41.0 '@cipherstash/protect-ffi-darwin-arm64@0.23.0': optional: true - '@cipherstash/protect-ffi-darwin-arm64@0.27.0': + '@cipherstash/protect-ffi-darwin-arm64@0.28.0': optional: true '@cipherstash/protect-ffi-darwin-x64@0.23.0': optional: true - '@cipherstash/protect-ffi-darwin-x64@0.27.0': + '@cipherstash/protect-ffi-darwin-x64@0.28.0': optional: true '@cipherstash/protect-ffi-linux-arm64-gnu@0.23.0': optional: true - '@cipherstash/protect-ffi-linux-arm64-gnu@0.27.0': + '@cipherstash/protect-ffi-linux-arm64-gnu@0.28.0': optional: true '@cipherstash/protect-ffi-linux-x64-gnu@0.23.0': optional: true - '@cipherstash/protect-ffi-linux-x64-gnu@0.27.0': + '@cipherstash/protect-ffi-linux-x64-gnu@0.28.0': optional: true '@cipherstash/protect-ffi-linux-x64-musl@0.23.0': optional: true - '@cipherstash/protect-ffi-linux-x64-musl@0.27.0': + '@cipherstash/protect-ffi-linux-x64-musl@0.28.0': optional: true '@cipherstash/protect-ffi-win32-x64-msvc@0.23.0': optional: true - '@cipherstash/protect-ffi-win32-x64-msvc@0.27.0': + '@cipherstash/protect-ffi-win32-x64-msvc@0.28.0': optional: true '@cipherstash/protect-ffi@0.23.0': @@ -4354,16 +4361,16 @@ snapshots: '@cipherstash/protect-ffi-linux-x64-musl': 0.23.0 '@cipherstash/protect-ffi-win32-x64-msvc': 0.23.0 - '@cipherstash/protect-ffi@0.27.0': + '@cipherstash/protect-ffi@0.28.0': dependencies: '@neon-rs/load': 0.1.82 optionalDependencies: - '@cipherstash/protect-ffi-darwin-arm64': 0.27.0 - '@cipherstash/protect-ffi-darwin-x64': 0.27.0 - '@cipherstash/protect-ffi-linux-arm64-gnu': 0.27.0 - '@cipherstash/protect-ffi-linux-x64-gnu': 0.27.0 - '@cipherstash/protect-ffi-linux-x64-musl': 0.27.0 - '@cipherstash/protect-ffi-win32-x64-msvc': 0.27.0 + '@cipherstash/protect-ffi-darwin-arm64': 0.28.0 + '@cipherstash/protect-ffi-darwin-x64': 0.28.0 + '@cipherstash/protect-ffi-linux-arm64-gnu': 0.28.0 + '@cipherstash/protect-ffi-linux-x64-gnu': 0.28.0 + '@cipherstash/protect-ffi-linux-x64-musl': 0.28.0 + '@cipherstash/protect-ffi-win32-x64-msvc': 0.28.0 '@clack/core@1.3.0': dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f4ab662c..b52bf674 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,13 +11,13 @@ catalogs: # declare them as `optionalDependencies` via `catalog:repo`. Keep # all seven entries on the same version so a single bump here moves # everything in lockstep. - '@cipherstash/auth': 0.40.0 - '@cipherstash/auth-darwin-arm64': 0.40.0 - '@cipherstash/auth-darwin-x64': 0.40.0 - '@cipherstash/auth-linux-arm64-gnu': 0.40.0 - '@cipherstash/auth-linux-x64-gnu': 0.40.0 - '@cipherstash/auth-linux-x64-musl': 0.40.0 - '@cipherstash/auth-win32-x64-msvc': 0.40.0 + '@cipherstash/auth': 0.41.0 + '@cipherstash/auth-darwin-arm64': 0.41.0 + '@cipherstash/auth-darwin-x64': 0.41.0 + '@cipherstash/auth-linux-arm64-gnu': 0.41.0 + '@cipherstash/auth-linux-x64-gnu': 0.41.0 + '@cipherstash/auth-linux-x64-musl': 0.41.0 + '@cipherstash/auth-win32-x64-msvc': 0.41.0 tsup: 8.5.1 tsx: 4.22.1 typescript: 5.9.3