@capxul/sdk 0.2.0-alpha.3 → 0.2.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +4 -266
  2. package/dist/InMemoryAuthCacheAdapter-BK-B_ERB.mjs +113 -0
  3. package/dist/InMemoryAuthCacheAdapter-BK-B_ERB.mjs.map +1 -0
  4. package/dist/index.d.mts +1263 -0
  5. package/dist/index.d.mts.map +1 -0
  6. package/dist/index.mjs +4740 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/dist/node/index.d.mts +55 -0
  9. package/dist/node/index.d.mts.map +1 -0
  10. package/dist/node/index.mjs +159 -0
  11. package/dist/node/index.mjs.map +1 -0
  12. package/dist/ports/safe-deployment.d.mts +2 -0
  13. package/dist/ports/safe-deployment.mjs +38 -0
  14. package/dist/ports/safe-deployment.mjs.map +1 -0
  15. package/dist/safe-deployment-Vni46k3t.d.mts +137 -0
  16. package/dist/safe-deployment-Vni46k3t.d.mts.map +1 -0
  17. package/dist/signer-oaYGfjDe.d.mts +142 -0
  18. package/dist/signer-oaYGfjDe.d.mts.map +1 -0
  19. package/package.json +37 -71
  20. package/CHANGELOG.md +0 -256
  21. package/LICENSE +0 -44
  22. package/dist/client-B_Z3ThFO.d.cts +0 -1484
  23. package/dist/client-pMBRFcsz.d.ts +0 -1484
  24. package/dist/client.cjs +0 -4324
  25. package/dist/client.d.cts +0 -6
  26. package/dist/client.d.ts +0 -6
  27. package/dist/client.js +0 -4322
  28. package/dist/errors-CwhCWGxm.d.ts +0 -70
  29. package/dist/errors-rqxuUhQP.d.cts +0 -70
  30. package/dist/errors.cjs +0 -35
  31. package/dist/errors.d.cts +0 -2
  32. package/dist/errors.d.ts +0 -2
  33. package/dist/errors.js +0 -31
  34. package/dist/index.cjs +0 -4626
  35. package/dist/index.d.cts +0 -571
  36. package/dist/index.d.ts +0 -571
  37. package/dist/index.js +0 -4585
  38. package/dist/next-action-CTGl8wpy.d.cts +0 -177
  39. package/dist/next-action-CTGl8wpy.d.ts +0 -177
  40. package/dist/types-Brucpq0Z.d.cts +0 -1191
  41. package/dist/types-V_D7qjxY.d.ts +0 -1191
  42. package/dist/webhooks.cjs +0 -118
  43. package/dist/webhooks.d.cts +0 -33
  44. package/dist/webhooks.d.ts +0 -33
  45. package/dist/webhooks.js +0 -116
package/README.md CHANGED
@@ -1,270 +1,8 @@
1
1
  # @capxul/sdk
2
2
 
3
- Headless TypeScript client for Capxul issue and accept stablecoin
4
- payments, manage organization treasuries, and orchestrate on-chain
5
- flows backed by audited custody contracts.
3
+ Layer 0 SDK package. Stage 1 currently ships the `@capxul/sdk/env` subpath.
6
4
 
7
- > **Alpha — `0.x` is pre-release.** APIs can change between alpha
8
- > versions. Pin to an exact version (`@capxul/sdk@0.1.0-alpha.0`) and
9
- > read the changelog before upgrading.
5
+ See `docs/env.md` for the env Module contract.
10
6
 
11
- ## Install
12
-
13
- ```bash
14
- pnpm add @capxul/sdk @capxul/sdk-react
15
- # or: npm install @capxul/sdk @capxul/sdk-react
16
- ```
17
-
18
- `@capxul/sdk` is the headless contract — flows, types, errors. The
19
- React-flavored entry point lives in `@capxul/sdk-react`. Pick:
20
-
21
- - **Browser apps (recommended).** Install both. Use
22
- `<CapxulProvider config={{ mode: "publishable-key", publishableKey }}>`
23
- from `@capxul/sdk-react` and the `useMe` / `useCapxulStatus` hooks.
24
- See that package's README for the lazy-DX example.
25
- - **Server / CLI / scripts.** Install only `@capxul/sdk`. Build a
26
- `CapxulClient` directly with your own auth and Convex adapters
27
- (see "Server-side construction" below).
28
-
29
- ## Two-layer trust
30
-
31
- Capxul splits the platform into two layers with different licenses:
32
-
33
- | Layer | What it does | License |
34
- |---|---|---|
35
- | Custody (on-chain) | Safe v1.4.1 + ERC-4337 modules — every contract that holds, transfers, or signs over user funds | Open source, audited, in the [Capxul GitHub repo](https://github.com/Xelmar-tech/Capxul/tree/main/packages/contracts) |
36
- | Orchestration (this package) | Workflow logic, business rules, integration glue, the `/v1/*` HTTP client | Proprietary — see `LICENSE` |
37
-
38
- You don't have to take our word for the parts that hold money — those
39
- contracts are open and auditable. The parts that orchestrate workflows
40
- on top are our product.
41
-
42
- ## Quickstart (server / CLI)
43
-
44
- ```ts
45
- import { createCapxulClient, createLocalSigner, tryCatch } from "@capxul/sdk";
46
-
47
- const signer = createLocalSigner(process.env.CAPXUL_PRIVATE_KEY!);
48
- const capxul = createCapxulClient({
49
- apiKey: process.env.CAPXUL_API_KEY!, // server-to-server partner key
50
- signer,
51
- });
52
-
53
- const [err, payment] = await tryCatch(
54
- capxul.payments.create({
55
- to: { email: "vendor@example.com" },
56
- amount: { value: "100", currency: "USD" },
57
- }),
58
- );
59
-
60
- if (err) {
61
- if (err.code === "INSUFFICIENT_BALANCE") {
62
- // narrow `err.code` to route the UI / reply
63
- }
64
- throw err;
65
- }
66
-
67
- console.log(payment.id);
68
- ```
69
-
70
- ## Quickstart (browser via React)
71
-
72
- See [`@capxul/sdk-react`](https://www.npmjs.com/package/@capxul/sdk-react).
73
- The browser path uses a publishable key (`cap_pk_…`) and bootstraps
74
- runtime URLs lazily — no need to ship secrets to the client:
75
-
76
- ```tsx
77
- import { CapxulProvider, useMe, useCapxulStatus } from "@capxul/sdk-react";
78
-
79
- <CapxulProvider
80
- config={{
81
- mode: "publishable-key",
82
- publishableKey: process.env.NEXT_PUBLIC_CAPXUL_PUBLISHABLE_KEY!,
83
- }}
84
- >
85
- <App />
86
- </CapxulProvider>;
87
- ```
88
-
89
- ## Publishable-key transport
90
-
91
- The browser transport accepts a publishable key, then lazily resolves
92
- runtime URLs by POSTing to `/v1/client/bootstrap` on the first auth or
93
- `ensureRuntime()` call. The successful backend response is intentionally
94
- small:
95
-
96
- ```json
97
- { "authBaseUrl": "https://<deployment>.convex.site/api/auth", "convexUrl": "https://<deployment>.convex.cloud" }
98
- ```
99
-
100
- The resolved runtime is cached for the lifetime of the transport. Concurrent
101
- callers share one bootstrap request, successful resolutions are reused, and
102
- failed bootstrap attempts reset so the next call can retry. Tests and
103
- non-default deployments can inject both `fetchImpl` and an absolute
104
- `bootstrapUrl`:
105
-
106
- ```ts
107
- import { makeHttpTransport, CapxulError } from "@capxul/sdk";
108
-
109
- const transport = makeHttpTransport({
110
- mode: "publishable-key",
111
- publishableKey: process.env.NEXT_PUBLIC_CAPXUL_PUBLISHABLE_KEY!,
112
- bootstrapUrl: "https://api.capxul.com/v1/client/bootstrap",
113
- fetchImpl: fetch,
114
- });
115
-
116
- await transport.ensureRuntime();
117
- ```
118
-
119
- Local setup errors and backend bootstrap errors both use `CapxulError`, but
120
- carry different `details.source` values:
121
-
122
- ```ts
123
- try {
124
- await transport.ensureRuntime();
125
- } catch (error) {
126
- if (error instanceof CapxulError) {
127
- if (error.details?.source === "sdk-config") {
128
- // Missing or malformed local config, such as publishableKey or bootstrapUrl.
129
- }
130
- if (error.details?.source === "backend-bootstrap") {
131
- // Sanitized backend refusal, such as NOT_AUTHENTICATED or PERMISSION_DENIED.
132
- }
133
- }
134
- }
135
- ```
136
-
137
- Runtime proof status:
138
-
139
- | Surface | Source support | Runtime proof | Status |
140
- |---|---|---|---|
141
- | SDK transport | `makeHttpTransport({ mode: "publishable-key", publishableKey })` | `packages/sdk/tests/unit/transport.test.ts` proves config validation, singleflight bootstrap, retry after failure, lifecycle transitions, and sanitized backend errors. | Proven with mocked fetch |
142
- | React provider | `CapxulProvider config={{ mode: "publishable-key", ... }}` | `packages/sdk-react/ops/proof/react-headless.test.tsx` proves bootstrap before a real `useMe()` read through the provider and lazy Convex data client. | Proven with mocked fetch + headless React |
143
- | Reference CLI | `bootstrap probe --mock --json` | `apps/reference-cli/scripts/agent-driver.ts` phase 0 and the direct CLI command prove provider/bootstrap/auth ordering and sanitized output. | Proven locally; live endpoint remains manual-key gated |
144
-
145
- Copy-paste local replication:
146
-
147
- ```bash
148
- corepack pnpm --filter @capxul/sdk check-types
149
- corepack pnpm --filter @capxul/sdk build
150
- corepack pnpm --filter @capxul/sdk-react check-types
151
- corepack pnpm --filter @capxul/sdk-react build
152
- corepack pnpm --filter @capxul/reference-cli check-types
153
- corepack pnpm --filter @capxul/reference-cli build
154
- node apps/reference-cli/dist/cli.js bootstrap probe --mock --json
155
- ```
156
-
157
- Run the SDK and React SDK builds before the reference CLI typecheck in a
158
- fresh checkout; the CLI depends on their generated declaration outputs.
159
-
160
- Expected sanitized pass signal:
161
-
162
- ```json
163
- {"command":"bootstrap.probe","ok":true,"mode":"publishable-key","status":"ready","bootstrapRequests":1,"authRequests":1,"keyLengthClass":"provided","mocked":true}
164
- ```
165
-
166
- ## Public surface (alpha)
167
-
168
- ```ts
169
- capxul.auth // sendOtp, verifyOtp, signOut, serviceTokenMint
170
- capxul.me // get, update — first-party caller identity
171
- capxul.accounts // create, retrieve, list
172
- capxul.organizations // CRUD + members + payments + treasury
173
- capxul.payments // create, retrieve, list
174
- capxul.invoices // create, retrieve, list
175
- capxul.withdrawals // create, retrieve, list
176
- capxul.documents // KYC uploads, invoices, receipts, tax forms
177
- capxul.flows.{auth, onboarding, provisioning} // XState v5 flows
178
- ```
179
-
180
- Helpers:
181
-
182
- - `tryCatch(promise)` — error tuple `[error, data]`; routes on
183
- `error.code` (typed `CapxulErrorCode` union)
184
- - `matchError`, `matchStatus`, `matchAction` — exhaustive pattern
185
- matchers per CANON.md §4.44
186
- - Branded type constructors — `toEmail`, `toAccountId`,
187
- `toOrganizationId`, … — never cast raw strings
188
-
189
- ## Organizations
190
-
191
- Create an organization, manage its treasury, and invite members with
192
- role-based access:
193
-
194
- ```ts
195
- // Create
196
- const [err, org] = await capxul.organizations.create({ name: "Acme" });
197
-
198
- // Invite a member — returns the raw token once
199
- const [err, { member, inviteToken }] = await capxul.organizations.members.invite({
200
- organizationId: org.id,
201
- email: "alice@example.com",
202
- role: "finance_manager",
203
- });
204
-
205
- // List members — defaults to active; pass status to filter
206
- const [err, list] = await capxul.organizations.members.list({
207
- organizationId: org.id,
208
- status: "pending", // "pending" | "active" | "revoked" | "expired" | "all"
209
- });
210
-
211
- // Accept an invitation (called by the invitee)
212
- const [err, member] = await capxul.organizations.members.accept({ token: inviteToken });
213
-
214
- // Revoke a pending invitation
215
- const [err] = await capxul.organizations.members.revoke({
216
- organizationId: org.id,
217
- memberId: member.id,
218
- });
219
-
220
- // Remove an active member
221
- const [err] = await capxul.organizations.members.remove({
222
- organizationId: org.id,
223
- memberId: member.id,
224
- });
225
- ```
226
-
227
- Member roles: `owner`, `finance_manager`, `payments_operator`,
228
- `org_admin`, `viewer`, `accountant`. Only `owner` and `org_admin` can
229
- invite, revoke, remove, or change roles.
230
-
231
- Pending invitations auto-accept on first sign-in when the user's email
232
- matches. Overdue pending invitations expire via a nightly cron.
233
-
234
- ## Error model
235
-
236
- Every method returns a `CapxulResult<T, Codes>` tuple. Errors are
237
- instances of `CapxulError` with a typed `code` (narrowed per method).
238
-
239
- ```ts
240
- const [err, account] = await tryCatch(capxul.me.get());
241
-
242
- if (err) {
243
- switch (err.code) {
244
- case "PROFILE_NOT_FOUND": return router.push("/onboarding");
245
- case "NOT_AUTHENTICATED": return router.push("/login");
246
- default: throw err; // unhandled — bubble to the error boundary
247
- }
248
- }
249
- ```
250
-
251
- There is no second error type. Backend `CapxulError` → Convex
252
- serialization → SDK deserialization → frontend `CapxulError` — one
253
- class, 34 codes, end-to-end.
254
-
255
- ## Telemetry (opt-out)
256
-
257
- The SDK reports operational telemetry (operation IDs, latencies,
258
- correlation IDs, error codes) to Capxul. **PII is never sent** — events
259
- are scrubbed at the source. Disable by passing
260
- `{ telemetry: { enabled: false } }` (coming in `0.2.0`); current alpha
261
- sends only operational signals which Capxul Terms disclose explicitly.
262
-
263
- ## License
264
-
265
- Proprietary — see [`LICENSE`](./LICENSE). The orchestration code in
266
- this package is governed by the Capxul Terms of Service. The
267
- value-bearing custody contracts are open source — see "Two-layer trust"
268
- above.
269
-
270
- Contact: [legal@capxul.com](mailto:legal@capxul.com)
7
+ See `docs/identity-adapters.md` for the Effect-native identity port and adapter
8
+ Layer exports.
@@ -0,0 +1,113 @@
1
+ import { Context, Data, Effect, Layer } from "effect";
2
+ import { toAuthUserId, toEmail, toEpochMs, toEpochSeconds, toJwtToken, toSessionToken } from "@capxul/types";
3
+ //#region src/ports/auth-cache.ts
4
+ var AuthCacheError = class extends Data.TaggedError("AuthCacheError") {};
5
+ var AuthCachePortTag = class extends Context.Tag("@capxul/sdk/ports/AuthCachePort")() {};
6
+ //#endregion
7
+ //#region src/adapters/auth-cache/serialization.ts
8
+ function parseAuthSession(raw) {
9
+ if (typeof raw !== "object" || raw === null) return null;
10
+ const candidate = raw;
11
+ try {
12
+ return {
13
+ authUserId: toAuthUserId(candidate.authUserId),
14
+ email: toEmail(candidate.email),
15
+ token: toSessionToken(candidate.token),
16
+ expiresAt: toEpochMs(candidate.expiresAt)
17
+ };
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+ function parseCachedJwt(raw) {
23
+ if (typeof raw !== "object" || raw === null) return null;
24
+ const candidate = raw;
25
+ try {
26
+ return {
27
+ token: toJwtToken(candidate.token),
28
+ expEpochSeconds: toEpochSeconds(candidate.expEpochSeconds)
29
+ };
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ //#endregion
35
+ //#region src/adapters/auth-cache/BrowserAuthCacheAdapter.ts
36
+ const SESSION_KEY = "capxul.session";
37
+ const JWT_KEY = "capxul.jwt";
38
+ var BrowserAuthCacheAdapter = class {
39
+ storage;
40
+ constructor(storage) {
41
+ this.storage = storage;
42
+ }
43
+ getSession = authCacheTry("getSession", () => {
44
+ const raw = this.storage.getItem(SESSION_KEY);
45
+ if (raw === null) return null;
46
+ try {
47
+ return parseAuthSession(JSON.parse(raw));
48
+ } catch {
49
+ return null;
50
+ }
51
+ });
52
+ setSession = (session) => authCacheTry("setSession", () => {
53
+ this.storage.setItem(SESSION_KEY, JSON.stringify(session));
54
+ });
55
+ clearSession = authCacheTry("clearSession", () => {
56
+ this.storage.removeItem(SESSION_KEY);
57
+ });
58
+ getJwt = authCacheTry("getJwt", () => {
59
+ const raw = this.storage.getItem(JWT_KEY);
60
+ if (raw === null) return null;
61
+ try {
62
+ return parseCachedJwt(JSON.parse(raw));
63
+ } catch {
64
+ return null;
65
+ }
66
+ });
67
+ setJwt = (jwt) => authCacheTry("setJwt", () => {
68
+ this.storage.setItem(JWT_KEY, JSON.stringify(jwt));
69
+ });
70
+ clearJwt = authCacheTry("clearJwt", () => {
71
+ this.storage.removeItem(JWT_KEY);
72
+ });
73
+ };
74
+ function toAuthCacheError(operation, cause) {
75
+ return new AuthCacheError({
76
+ operation,
77
+ cause
78
+ });
79
+ }
80
+ function authCacheTry(operation, run) {
81
+ return Effect.try({
82
+ try: run,
83
+ catch: (cause) => toAuthCacheError(operation, cause)
84
+ });
85
+ }
86
+ //#endregion
87
+ //#region src/adapters/auth-cache/InMemoryAuthCacheAdapter.ts
88
+ var InMemoryAuthCacheAdapter = class {
89
+ session = null;
90
+ jwt = null;
91
+ getSession = Effect.sync(() => this.session);
92
+ setSession = (session) => Effect.sync(() => {
93
+ this.session = session;
94
+ });
95
+ clearSession = Effect.sync(() => {
96
+ this.session = null;
97
+ });
98
+ getJwt = Effect.sync(() => this.jwt);
99
+ setJwt = (jwt) => Effect.sync(() => {
100
+ this.jwt = jwt;
101
+ });
102
+ clearJwt = Effect.sync(() => {
103
+ this.jwt = null;
104
+ });
105
+ };
106
+ Layer.effect(AuthCachePortTag, Effect.sync(() => new InMemoryAuthCacheAdapter()).pipe(Effect.mapError((cause) => new AuthCacheError({
107
+ operation: "initialize",
108
+ cause
109
+ }))));
110
+ //#endregion
111
+ export { AuthCacheError as a, parseCachedJwt as i, BrowserAuthCacheAdapter as n, AuthCachePortTag as o, parseAuthSession as r, InMemoryAuthCacheAdapter as t };
112
+
113
+ //# sourceMappingURL=InMemoryAuthCacheAdapter-BK-B_ERB.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryAuthCacheAdapter-BK-B_ERB.mjs","names":[],"sources":["../src/ports/auth-cache.ts","../src/adapters/auth-cache/serialization.ts","../src/adapters/auth-cache/BrowserAuthCacheAdapter.ts","../src/adapters/auth-cache/InMemoryAuthCacheAdapter.ts"],"sourcesContent":["import { Context, Data, Effect } from \"effect\";\nimport type { AuthSession, EpochSeconds, JwtToken } from \"@capxul/types\";\n\n/**\n * AuthCachePort (TA4) — replaces `SessionStoragePort` in the rebuild slice's\n * consumer-facing wiring. Stores the user-snapshot Session AND the cached\n * Convex JWT (W7 bridge endpoint). The two slots are independent so a session\n * refresh doesn't invalidate the JWT and vice versa.\n *\n * Three adapters (TA7):\n * - `BrowserAuthCacheAdapter` — backed by `localStorage`\n * - `FileSystemAuthCacheAdapter` — mode-0600 JSON file in `~/.config/capxul/`\n * - `InMemoryAuthCacheAdapter` — for tests\n *\n * `SessionStoragePort` was retired by the Stage 4 rebuild; session and JWT\n * persistence now share this cache boundary.\n */\nexport interface AuthCachePort {\n readonly getSession: Effect.Effect<AuthSession | null, AuthCacheError>;\n readonly setSession: (session: AuthSession) => Effect.Effect<void, AuthCacheError>;\n readonly clearSession: Effect.Effect<void, AuthCacheError>;\n\n /**\n * JWT cache for the `/api/auth/convex/token` bridge endpoint (W7).\n * Stored separately from the session so a session refresh doesn't\n * invalidate cached JWT.\n */\n readonly getJwt: Effect.Effect<CachedJwt | null, AuthCacheError>;\n readonly setJwt: (jwt: CachedJwt) => Effect.Effect<void, AuthCacheError>;\n readonly clearJwt: Effect.Effect<void, AuthCacheError>;\n}\n\n/**\n * Cached Convex JWT shape (TA4). `expEpochSeconds` is decoded from the JWT's\n * `exp` claim at fetch time so the `tokenProvider` cache eviction logic can\n * proactively refresh at `exp - 30s` per TA3.\n */\nexport interface CachedJwt {\n readonly token: JwtToken;\n readonly expEpochSeconds: EpochSeconds;\n}\n\nexport class AuthCacheError extends Data.TaggedError(\"AuthCacheError\")<{\n readonly operation: string;\n readonly cause: unknown;\n}> {}\n\nexport class AuthCachePortTag extends Context.Tag(\"@capxul/sdk/ports/AuthCachePort\")<\n AuthCachePortTag,\n AuthCachePort\n>() {}\n","import {\n toAuthUserId,\n toEmail,\n toEpochMs,\n toEpochSeconds,\n toJwtToken,\n toSessionToken,\n type AuthSession,\n} from \"@capxul/types\";\n\nimport type { CachedJwt } from \"../../ports/auth-cache\";\n\nexport function parseAuthSession(raw: unknown): AuthSession | null {\n if (typeof raw !== \"object\" || raw === null) return null;\n const candidate = raw as {\n readonly authUserId?: unknown;\n readonly email?: unknown;\n readonly token?: unknown;\n readonly expiresAt?: unknown;\n };\n\n try {\n return {\n authUserId: toAuthUserId(candidate.authUserId),\n email: toEmail(candidate.email),\n token: toSessionToken(candidate.token),\n expiresAt: toEpochMs(candidate.expiresAt),\n };\n } catch {\n return null;\n }\n}\n\nexport function parseCachedJwt(raw: unknown): CachedJwt | null {\n if (typeof raw !== \"object\" || raw === null) return null;\n const candidate = raw as {\n readonly token?: unknown;\n readonly expEpochSeconds?: unknown;\n };\n\n try {\n return {\n token: toJwtToken(candidate.token),\n expEpochSeconds: toEpochSeconds(candidate.expEpochSeconds),\n };\n } catch {\n return null;\n }\n}\n","import { Effect, Layer } from \"effect\";\nimport type { AuthSession } from \"@capxul/types\";\n\nimport {\n AuthCacheError,\n AuthCachePortTag,\n type AuthCachePort,\n type CachedJwt,\n} from \"../../ports/auth-cache\";\nimport { parseAuthSession, parseCachedJwt } from \"./serialization\";\n\nexport interface BrowserStorageShape {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\nconst SESSION_KEY = \"capxul.session\";\nconst JWT_KEY = \"capxul.jwt\";\n\nexport class BrowserAuthCacheAdapter implements AuthCachePort {\n private readonly storage: BrowserStorageShape;\n\n constructor(storage: BrowserStorageShape) {\n this.storage = storage;\n }\n\n readonly getSession = authCacheTry(\"getSession\", () => {\n const raw = this.storage.getItem(SESSION_KEY);\n if (raw === null) return null;\n try {\n return parseAuthSession(JSON.parse(raw));\n } catch {\n return null;\n }\n });\n\n readonly setSession = (session: AuthSession) =>\n authCacheTry(\"setSession\", () => {\n this.storage.setItem(SESSION_KEY, JSON.stringify(session));\n });\n\n readonly clearSession = authCacheTry(\"clearSession\", () => {\n this.storage.removeItem(SESSION_KEY);\n });\n\n readonly getJwt = authCacheTry(\"getJwt\", () => {\n const raw = this.storage.getItem(JWT_KEY);\n if (raw === null) return null;\n try {\n return parseCachedJwt(JSON.parse(raw));\n } catch {\n return null;\n }\n });\n\n readonly setJwt = (jwt: CachedJwt) =>\n authCacheTry(\"setJwt\", () => {\n this.storage.setItem(JWT_KEY, JSON.stringify(jwt));\n });\n\n readonly clearJwt = authCacheTry(\"clearJwt\", () => {\n this.storage.removeItem(JWT_KEY);\n });\n}\n\nexport function BrowserAuthCacheLayer(input: {\n readonly storage: BrowserStorageShape;\n}): Layer.Layer<AuthCachePortTag, AuthCacheError> {\n return Layer.effect(\n AuthCachePortTag,\n Effect.sync(() => new BrowserAuthCacheAdapter(input.storage)).pipe(\n Effect.mapError((cause) => toAuthCacheError(\"initialize\", cause)),\n ),\n );\n}\n\nfunction toAuthCacheError(operation: string, cause: unknown): AuthCacheError {\n return new AuthCacheError({ operation, cause });\n}\n\nfunction authCacheTry<T>(operation: string, run: () => T): Effect.Effect<T, AuthCacheError> {\n return Effect.try({\n try: run,\n catch: (cause) => toAuthCacheError(operation, cause),\n });\n}\n","import { Effect, Layer } from \"effect\";\nimport type { AuthSession } from \"@capxul/types\";\n\nimport {\n AuthCacheError,\n AuthCachePortTag,\n type AuthCachePort,\n type CachedJwt,\n} from \"../../ports/auth-cache\";\n\nexport class InMemoryAuthCacheAdapter implements AuthCachePort {\n private session: AuthSession | null = null;\n private jwt: CachedJwt | null = null;\n\n readonly getSession = Effect.sync(() => this.session);\n\n readonly setSession = (session: AuthSession) =>\n Effect.sync(() => {\n this.session = session;\n });\n\n readonly clearSession = Effect.sync(() => {\n this.session = null;\n });\n\n readonly getJwt = Effect.sync(() => this.jwt);\n\n readonly setJwt = (jwt: CachedJwt) =>\n Effect.sync(() => {\n this.jwt = jwt;\n });\n\n readonly clearJwt = Effect.sync(() => {\n this.jwt = null;\n });\n}\n\nexport const InMemoryAuthCacheLayer = Layer.effect(\n AuthCachePortTag,\n Effect.sync(() => new InMemoryAuthCacheAdapter()).pipe(\n Effect.mapError((cause) => new AuthCacheError({ operation: \"initialize\", cause })),\n ),\n);\n"],"mappings":";;;AA0CA,IAAa,iBAAb,cAAoC,KAAK,YAAY,gBAAgB,EAGlE,CAAC;AAEJ,IAAa,mBAAb,cAAsC,QAAQ,IAAI,iCAAiC,EAGjF,EAAE,CAAC;;;ACtCL,SAAgB,iBAAiB,KAAkC;CACjE,IAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM,OAAO;CACpD,MAAM,YAAY;CAOlB,IAAI;EACF,OAAO;GACL,YAAY,aAAa,UAAU,UAAU;GAC7C,OAAO,QAAQ,UAAU,KAAK;GAC9B,OAAO,eAAe,UAAU,KAAK;GACrC,WAAW,UAAU,UAAU,SAAS;EAC1C;CACF,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,eAAe,KAAgC;CAC7D,IAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM,OAAO;CACpD,MAAM,YAAY;CAKlB,IAAI;EACF,OAAO;GACL,OAAO,WAAW,UAAU,KAAK;GACjC,iBAAiB,eAAe,UAAU,eAAe;EAC3D;CACF,QAAQ;EACN,OAAO;CACT;AACF;;;AC/BA,MAAM,cAAc;AACpB,MAAM,UAAU;AAEhB,IAAa,0BAAb,MAA8D;CAC5D;CAEA,YAAY,SAA8B;EACxC,KAAK,UAAU;CACjB;CAEA,aAAsB,aAAa,oBAAoB;EACrD,MAAM,MAAM,KAAK,QAAQ,QAAQ,WAAW;EAC5C,IAAI,QAAQ,MAAM,OAAO;EACzB,IAAI;GACF,OAAO,iBAAiB,KAAK,MAAM,GAAG,CAAC;EACzC,QAAQ;GACN,OAAO;EACT;CACF,CAAC;CAED,cAAuB,YACrB,aAAa,oBAAoB;EAC/B,KAAK,QAAQ,QAAQ,aAAa,KAAK,UAAU,OAAO,CAAC;CAC3D,CAAC;CAEH,eAAwB,aAAa,sBAAsB;EACzD,KAAK,QAAQ,WAAW,WAAW;CACrC,CAAC;CAED,SAAkB,aAAa,gBAAgB;EAC7C,MAAM,MAAM,KAAK,QAAQ,QAAQ,OAAO;EACxC,IAAI,QAAQ,MAAM,OAAO;EACzB,IAAI;GACF,OAAO,eAAe,KAAK,MAAM,GAAG,CAAC;EACvC,QAAQ;GACN,OAAO;EACT;CACF,CAAC;CAED,UAAmB,QACjB,aAAa,gBAAgB;EAC3B,KAAK,QAAQ,QAAQ,SAAS,KAAK,UAAU,GAAG,CAAC;CACnD,CAAC;CAEH,WAAoB,aAAa,kBAAkB;EACjD,KAAK,QAAQ,WAAW,OAAO;CACjC,CAAC;AACH;AAaA,SAAS,iBAAiB,WAAmB,OAAgC;CAC3E,OAAO,IAAI,eAAe;EAAE;EAAW;CAAM,CAAC;AAChD;AAEA,SAAS,aAAgB,WAAmB,KAAgD;CAC1F,OAAO,OAAO,IAAI;EAChB,KAAK;EACL,QAAQ,UAAU,iBAAiB,WAAW,KAAK;CACrD,CAAC;AACH;;;AC5EA,IAAa,2BAAb,MAA+D;CAC7D,UAAsC;CACtC,MAAgC;CAEhC,aAAsB,OAAO,WAAW,KAAK,OAAO;CAEpD,cAAuB,YACrB,OAAO,WAAW;EAChB,KAAK,UAAU;CACjB,CAAC;CAEH,eAAwB,OAAO,WAAW;EACxC,KAAK,UAAU;CACjB,CAAC;CAED,SAAkB,OAAO,WAAW,KAAK,GAAG;CAE5C,UAAmB,QACjB,OAAO,WAAW;EAChB,KAAK,MAAM;CACb,CAAC;CAEH,WAAoB,OAAO,WAAW;EACpC,KAAK,MAAM;CACb,CAAC;AACH;AAEsC,MAAM,OAC1C,kBACA,OAAO,WAAW,IAAI,yBAAyB,CAAC,EAAE,KAChD,OAAO,UAAU,UAAU,IAAI,eAAe;CAAE,WAAW;CAAc;AAAM,CAAC,CAAC,CACnF,CACF"}