@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/dist/index.mjs ADDED
@@ -0,0 +1,4740 @@
1
+ import { n as BrowserAuthCacheAdapter, o as AuthCachePortTag, t as InMemoryAuthCacheAdapter } from "./InMemoryAuthCacheAdapter-BK-B_ERB.mjs";
2
+ import { Context, Data, Deferred, Duration, Effect, Either, Exit, Layer, Ref, Request, Scope } from "effect";
3
+ import { Machine } from "@effect/experimental";
4
+ import { CapxulError, Errors, USDX_CURRENCY, USDX_DECIMALS, compileOrgRoleDefinitions, decodeConvexError, isCapxulError, orgRoleKeyForLabel, orgRoleTemplateDefinitions } from "@capxul/config";
5
+ import { toAccountId, toAddress, toAllowedOrigin, toAnonymousDistinctId, toAppId, toAuthUserId, toChainId, toCountryCode, toCurrencyCode, toDurationMs, toEmail, toEpochMs, toEpochSeconds, toJwtToken, toKycTier, toOrgId, toPublishableKey, toPublishableKeyId, toRoleKey, toSessionToken, toSubAccountId } from "@capxul/types";
6
+ import { redactTelemetryProps } from "@capxul/observability";
7
+ import { formatUnits, isHex, keccak256, parseUnits } from "viem";
8
+ import { privateKeyToAccount } from "viem/accounts";
9
+ import { Schema, TreeFormatter } from "@effect/schema";
10
+ import { BootstrapEnvelope } from "@capxul/wire";
11
+ import { ConvexClient } from "convex/browser";
12
+ import { getFunctionName, makeFunctionReference } from "convex/server";
13
+ //#region src/ports/auth-client.ts
14
+ var AuthClientError = class extends Data.TaggedError("AuthClientError") {};
15
+ var AuthClientPortTag = class extends Context.Tag("@capxul/sdk/ports/AuthClientPort")() {};
16
+ //#endregion
17
+ //#region src/ports/clock.ts
18
+ var ClockError = class extends Data.TaggedError("ClockError") {};
19
+ var ClockPortTag = class extends Context.Tag("@capxul/sdk/ports/ClockPort")() {};
20
+ //#endregion
21
+ //#region src/ports/telemetry.ts
22
+ var TelemetryPortTag = class extends Context.Tag("@capxul/sdk/ports/TelemetryPort")() {};
23
+ //#endregion
24
+ //#region src/flows/auth.ts
25
+ var AuthFlowError = class extends Data.TaggedError("AuthFlowError") {};
26
+ var RequestOtpRequest = class extends Request.TaggedClass("RequestOtp") {};
27
+ var VerifyOtpRequest = class extends Request.TaggedClass("VerifyOtp") {};
28
+ var GetSessionRequest = class extends Request.TaggedClass("GetSession") {};
29
+ var SignOutRequest = class extends Request.TaggedClass("SignOut") {};
30
+ var ResumeOtpEntryRequest = class extends Request.TaggedClass("ResumeOtpEntry") {};
31
+ var ResetAuthFlowRequest = class extends Request.TaggedClass("ResetAuthFlow") {};
32
+ var CommitAuthFlowRequest = class extends Request.TaggedClass("CommitAuthFlow") {};
33
+ const DEFAULT_OTP_TTL_MS = 3e5;
34
+ const ACTOR_MACHINE = /* @__PURE__ */ new WeakMap();
35
+ const RUNTIME_CONTROLS = /* @__PURE__ */ new WeakMap();
36
+ const AUTH_FLOW_TRANSITION_TABLE = {
37
+ idle: {
38
+ valid: [
39
+ "RequestOtp",
40
+ "GetSession",
41
+ "ResetAuthFlow"
42
+ ],
43
+ invalid: ["VerifyOtp WRONG_STATE", "SignOut WRONG_STATE"]
44
+ },
45
+ sending_otp: {
46
+ valid: ["ResetAuthFlow", "SignOut"],
47
+ invalid: [
48
+ "RequestOtp WRONG_STATE",
49
+ "VerifyOtp WRONG_STATE",
50
+ "GetSession WRONG_STATE"
51
+ ]
52
+ },
53
+ otp_requested: {
54
+ valid: [
55
+ "RequestOtp",
56
+ "VerifyOtp",
57
+ "GetSession",
58
+ "SignOut",
59
+ "ResetAuthFlow"
60
+ ],
61
+ invalid: []
62
+ },
63
+ verifying: {
64
+ valid: ["ResetAuthFlow", "SignOut"],
65
+ invalid: [
66
+ "RequestOtp WRONG_STATE",
67
+ "VerifyOtp WRONG_STATE",
68
+ "GetSession WRONG_STATE"
69
+ ]
70
+ },
71
+ authenticated: {
72
+ valid: [
73
+ "GetSession",
74
+ "SignOut",
75
+ "ResetAuthFlow"
76
+ ],
77
+ invalid: ["RequestOtp WRONG_STATE", "VerifyOtp WRONG_STATE"]
78
+ },
79
+ signing_out: {
80
+ valid: ["ResetAuthFlow"],
81
+ invalid: [
82
+ "RequestOtp WRONG_STATE",
83
+ "VerifyOtp WRONG_STATE",
84
+ "GetSession WRONG_STATE",
85
+ "SignOut WRONG_STATE"
86
+ ]
87
+ },
88
+ error: {
89
+ valid: [
90
+ "ResetAuthFlow",
91
+ "RequestOtp",
92
+ "GetSession",
93
+ "ResumeOtpEntry"
94
+ ],
95
+ invalid: ["VerifyOtp WRONG_STATE", "SignOut WRONG_STATE"]
96
+ }
97
+ };
98
+ function tuple(first, second) {
99
+ return [first, second];
100
+ }
101
+ function normalizeInput(input) {
102
+ return { otpTtlMs: input.otpTtlMs ?? DEFAULT_OTP_TTL_MS };
103
+ }
104
+ function publicInput(input) {
105
+ return { otpTtlMs: input.otpTtlMs };
106
+ }
107
+ function initialContext() {
108
+ return {
109
+ state: "idle",
110
+ email: null,
111
+ session: null,
112
+ otpRequestedAt: null,
113
+ error: null
114
+ };
115
+ }
116
+ function createAuthFlowMachine() {
117
+ return Machine.makeWith()((input) => {
118
+ const normalized = normalizeInput(input);
119
+ const bootInput = publicInput(normalized);
120
+ const control = runtimeControl(input);
121
+ return Machine.procedures.make(initialContext(), { identifier: `AuthFlow:${normalized.otpTtlMs}` }).pipe(Machine.procedures.addPrivate()("CommitAuthFlow", ({ request }) => Effect.succeed(tuple(tuple(request.input, request.context), request.context))), Machine.procedures.add()("RequestOtp", (context) => Effect.gen(function* () {
122
+ const email = assertEmailWellFormed(context.request.email);
123
+ if (!canTransition(context.state.state, "RequestOtp")) return yield* Effect.fail(wrongState("RequestOtp", context.state.state));
124
+ const anonDistinctId = context.state.anonDistinctId ?? makeAnonymousDistinctId();
125
+ const transient = {
126
+ state: "sending_otp",
127
+ email,
128
+ session: null,
129
+ otpRequestedAt: null,
130
+ anonDistinctId,
131
+ error: null
132
+ };
133
+ return yield* completeRequest(context.unsafeSendAwait, context.deferred, bootInput, control, requestOtpCompletion(email, anonDistinctId, context.request.options), (failure) => failureContext(failure, {
134
+ email: null,
135
+ session: null,
136
+ otpRequestedAt: null,
137
+ anonDistinctId
138
+ })).pipe(context.forkReplaceWith("auth-flow:request", transient), Effect.as(tuple(Machine.NoReply, transient)));
139
+ })), Machine.procedures.add()("VerifyOtp", (context) => Effect.gen(function* () {
140
+ const email = assertEmailWellFormed(context.request.email);
141
+ if (!/^\d{6}$/.test(context.request.otp)) return yield* Effect.fail(new AuthFlowError({
142
+ operation: "verifyOtp",
143
+ state: context.state.state,
144
+ publicError: Errors.invalidInput("otp", "must be a six digit code"),
145
+ publicCode: "INVALID_INPUT"
146
+ }));
147
+ if (!canTransition(context.state.state, "VerifyOtp")) return yield* Effect.fail(wrongState("VerifyOtp", context.state.state));
148
+ const current = context.state;
149
+ const anonDistinctId = current.anonDistinctId ?? makeAnonymousDistinctId();
150
+ const now = yield* (yield* ClockPortTag).now.pipe(Effect.mapError((cause) => new AuthFlowError({
151
+ operation: "verifyOtp",
152
+ state: current.state,
153
+ publicError: Errors.providerError("clock", "now", cause),
154
+ publicCode: "PROVIDER_ERROR",
155
+ cause
156
+ })));
157
+ if (Number(now) - Number(current.otpRequestedAt) > normalized.otpTtlMs) {
158
+ const failure = new AuthFlowError({
159
+ operation: "verifyOtp",
160
+ state: "otp_requested",
161
+ publicError: Errors.otpExpired({ expiredAt: Number(current.otpRequestedAt) + normalized.otpTtlMs }),
162
+ publicCode: "OTP_EXPIRED"
163
+ });
164
+ yield* emitTelemetry({
165
+ name: "auth_otp_expired",
166
+ props: { email_domain: emailDomain$1(current.email ?? email) }
167
+ });
168
+ return yield* Effect.fail(failure);
169
+ }
170
+ const transient = {
171
+ state: "verifying",
172
+ email,
173
+ session: null,
174
+ otpRequestedAt: current.otpRequestedAt,
175
+ anonDistinctId,
176
+ error: null
177
+ };
178
+ return yield* completeRequest(context.unsafeSendAwait, context.deferred, bootInput, control, verifyOtpCompletion(email, context.request.otp, anonDistinctId, context.request.options), (failure) => failureContext(failure, {
179
+ email,
180
+ session: null,
181
+ otpRequestedAt: current.otpRequestedAt,
182
+ anonDistinctId
183
+ })).pipe(context.forkReplaceWith("auth-flow:request", transient), Effect.as(tuple(Machine.NoReply, transient)));
184
+ })), Machine.procedures.add()("GetSession", (context) => Effect.gen(function* () {
185
+ if (!canTransition(context.state.state, "GetSession")) return yield* Effect.fail(wrongState("GetSession", context.state.state));
186
+ return yield* completeRequest(context.unsafeSendAwait, context.deferred, bootInput, control, getSessionCompletion(context.request.options), (failure) => failureContext(failure, {
187
+ email: context.state.email,
188
+ session: context.state.session,
189
+ otpRequestedAt: context.state.otpRequestedAt,
190
+ ...context.state.anonDistinctId === void 0 ? {} : { anonDistinctId: context.state.anonDistinctId }
191
+ })).pipe(context.forkReplaceWith("auth-flow:request", context.state), Effect.as(tuple(Machine.NoReply, context.state)));
192
+ })), Machine.procedures.add()("SignOut", (context) => Effect.gen(function* () {
193
+ if (!canTransition(context.state.state, "SignOut")) return yield* Effect.fail(wrongState("SignOut", context.state.state));
194
+ const transient = {
195
+ state: "signing_out",
196
+ email: context.state.email,
197
+ session: context.state.session,
198
+ otpRequestedAt: null,
199
+ error: null
200
+ };
201
+ return yield* completeRequest(context.unsafeSendAwait, context.deferred, bootInput, control, signOutCompletion(context.request.options), () => initialContext()).pipe(context.forkReplaceWith("auth-flow:request", transient), Effect.as(tuple(Machine.NoReply, transient)));
202
+ })), Machine.procedures.add()("ResumeOtpEntry", (context) => Effect.gen(function* () {
203
+ if (!canTransition(context.state.state, "ResumeOtpEntry")) return yield* Effect.fail(wrongState("ResumeOtpEntry", context.state.state));
204
+ const current = context.state;
205
+ if (current.email === null || current.otpRequestedAt === null) return yield* Effect.fail(wrongState("ResumeOtpEntry", context.state.state));
206
+ const now = yield* (yield* ClockPortTag).now.pipe(Effect.mapError((cause) => new AuthFlowError({
207
+ operation: "verifyOtp",
208
+ state: current.state,
209
+ publicError: Errors.providerError("clock", "now", cause),
210
+ publicCode: "PROVIDER_ERROR",
211
+ cause
212
+ })));
213
+ if (Number(now) - Number(current.otpRequestedAt) > normalized.otpTtlMs) {
214
+ const failure = new AuthFlowError({
215
+ operation: "verifyOtp",
216
+ state: "error",
217
+ publicError: Errors.otpExpired({ expiredAt: Number(current.otpRequestedAt) + normalized.otpTtlMs }),
218
+ publicCode: "OTP_EXPIRED"
219
+ });
220
+ yield* emitTelemetry({
221
+ name: "auth_otp_expired",
222
+ props: { email_domain: emailDomain$1(current.email) }
223
+ });
224
+ return yield* Effect.fail(failure);
225
+ }
226
+ const restored = {
227
+ state: "otp_requested",
228
+ email: current.email,
229
+ session: null,
230
+ otpRequestedAt: current.otpRequestedAt,
231
+ ...current.anonDistinctId === void 0 ? {} : { anonDistinctId: current.anonDistinctId },
232
+ error: null
233
+ };
234
+ return tuple(tuple(bootInput, restored), restored);
235
+ })), Machine.procedures.add()("ResetAuthFlow", () => {
236
+ const reset = initialContext();
237
+ return Effect.succeed(tuple(tuple(bootInput, reset), reset));
238
+ }));
239
+ });
240
+ }
241
+ function bootAuthFlow(machine, input) {
242
+ return Effect.gen(function* () {
243
+ const bootInput = publicInput(normalizeInput(input));
244
+ const scope = yield* Scope.make();
245
+ const control = { stopped: false };
246
+ const actor = yield* Machine.boot(machine, withRuntimeControl(bootInput, control)).pipe(Scope.extend(scope));
247
+ const statusRef = yield* Ref.make("active");
248
+ const stopDeferred = yield* Deferred.make();
249
+ const flowActor = {
250
+ input: bootInput,
251
+ getSnapshot() {
252
+ const context = Effect.runSync(actor.get);
253
+ const status = Effect.runSync(Ref.get(statusRef));
254
+ return {
255
+ value: context.state,
256
+ context,
257
+ status
258
+ };
259
+ },
260
+ stop() {
261
+ control.stopped = true;
262
+ Effect.runSync(Ref.set(statusRef, "stopped"));
263
+ Effect.runSync(Deferred.succeed(stopDeferred, void 0));
264
+ Effect.runFork(Scope.close(scope, Exit.void));
265
+ },
266
+ send(request) {
267
+ return Ref.get(statusRef).pipe(Effect.flatMap((status) => status === "active" ? actor.send(toMachineRequest(request)).pipe(Effect.raceFirst(Deferred.await(stopDeferred).pipe(Effect.flatMap(() => Effect.fail(new AuthFlowError({
268
+ operation: "transition",
269
+ state: Effect.runSync(actor.get).state,
270
+ publicError: Errors.cancelled({ operation: "authFlow.send" }),
271
+ publicCode: "CANCELLED"
272
+ })))))) : Effect.fail(new AuthFlowError({
273
+ operation: "transition",
274
+ state: Effect.runSync(actor.get).state,
275
+ publicError: Errors.cancelled({ operation: "authFlow.send" }),
276
+ publicCode: "CANCELLED"
277
+ }))), Effect.tapError((failure) => failure.publicCode === "OTP_EXPIRED" ? Effect.void : emitTelemetry({
278
+ name: "auth_failed",
279
+ props: {
280
+ auth_type: "otp",
281
+ reason: failure.publicCode
282
+ }
283
+ })));
284
+ }
285
+ };
286
+ ACTOR_MACHINE.set(flowActor, actor);
287
+ return flowActor;
288
+ });
289
+ }
290
+ function sendAuthFlowRequest(actor, request) {
291
+ return actor.send(request);
292
+ }
293
+ function assertEmailWellFormed(email) {
294
+ return toEmail(email);
295
+ }
296
+ function toMachineRequest(request) {
297
+ switch (request._tag) {
298
+ case "RequestOtp": return new RequestOtpRequest(optionalOptions({ email: request.email }, request.options));
299
+ case "VerifyOtp": return new VerifyOtpRequest(optionalOptions({
300
+ email: request.email,
301
+ otp: request.otp
302
+ }, request.options));
303
+ case "GetSession": return new GetSessionRequest(optionalOptions({}, request.options));
304
+ case "SignOut": return new SignOutRequest(optionalOptions({}, request.options));
305
+ case "ResumeOtpEntry": return new ResumeOtpEntryRequest();
306
+ case "ResetAuthFlow": return new ResetAuthFlowRequest();
307
+ }
308
+ }
309
+ function optionalOptions(base, options) {
310
+ return options === void 0 ? base : {
311
+ ...base,
312
+ options
313
+ };
314
+ }
315
+ function requestOtpCompletion(email, anonDistinctId, options) {
316
+ return Effect.gen(function* () {
317
+ yield* withAuthFlowTimeout((yield* AuthClientPortTag).sendOtp({ email }, authClientOptions(options)), "requestOtp", "sending_otp", options).pipe(Effect.mapError((error) => authClientFailure("requestOtp", "sending_otp", error)));
318
+ const now = yield* (yield* ClockPortTag).now.pipe(Effect.mapError((cause) => new AuthFlowError({
319
+ operation: "requestOtp",
320
+ state: "sending_otp",
321
+ publicError: Errors.providerError("clock", "now", cause),
322
+ publicCode: "PROVIDER_ERROR",
323
+ cause
324
+ })));
325
+ yield* emitTelemetry({
326
+ name: "auth_otp_requested",
327
+ props: { email_domain: emailDomain$1(email) }
328
+ });
329
+ return {
330
+ state: "otp_requested",
331
+ email,
332
+ session: null,
333
+ otpRequestedAt: now,
334
+ anonDistinctId,
335
+ error: null
336
+ };
337
+ });
338
+ }
339
+ function verifyOtpCompletion(email, otp, anonDistinctId, options) {
340
+ return Effect.gen(function* () {
341
+ const session = yield* withAuthFlowTimeout((yield* AuthClientPortTag).verifyOtp({
342
+ email,
343
+ otp
344
+ }, authClientOptions(options)), "verifyOtp", "verifying", options).pipe(Effect.mapError((error) => authClientFailure("verifyOtp", "verifying", error)));
345
+ yield* emitTelemetry({
346
+ name: "auth_verified",
347
+ props: { auth_type: "otp" }
348
+ });
349
+ yield* identifyTelemetry({
350
+ distinctId: session.authUserId,
351
+ anonDistinctId,
352
+ traits: { email_domain: emailDomain$1(session.email) }
353
+ });
354
+ return {
355
+ state: "authenticated",
356
+ email: session.email,
357
+ session,
358
+ otpRequestedAt: null,
359
+ error: null
360
+ };
361
+ });
362
+ }
363
+ function getSessionCompletion(options) {
364
+ return Effect.gen(function* () {
365
+ const session = yield* withAuthFlowTimeout((yield* AuthClientPortTag).getSession(authClientOptions(options)), "getSession", "idle", options).pipe(Effect.mapError((error) => authClientFailure("getSession", "idle", error)));
366
+ if (session === null) return initialContext();
367
+ return {
368
+ state: "authenticated",
369
+ email: session.email,
370
+ session,
371
+ otpRequestedAt: null,
372
+ error: null
373
+ };
374
+ });
375
+ }
376
+ function signOutCompletion(options) {
377
+ return Effect.gen(function* () {
378
+ yield* withAuthFlowTimeout((yield* AuthClientPortTag).signOut(authClientOptions(options)), "signOut", "signing_out", options).pipe(Effect.mapError((error) => authClientFailure("signOut", "signing_out", error)));
379
+ yield* emitTelemetry({ name: "auth_signed_out" });
380
+ yield* resetTelemetry();
381
+ return initialContext();
382
+ });
383
+ }
384
+ function withAuthFlowTimeout(effect, operation, state, options) {
385
+ const timeoutMs = options?.timeoutMs;
386
+ if (timeoutMs === void 0) return effect;
387
+ return effect.pipe(Effect.timeoutFail({
388
+ duration: Duration.millis(timeoutMs),
389
+ onTimeout: () => new AuthFlowError({
390
+ operation,
391
+ state,
392
+ publicError: Errors.providerTimeout("auth-flow", operation, timeoutMs),
393
+ publicCode: "PROVIDER_ERROR"
394
+ })
395
+ }));
396
+ }
397
+ function authClientOptions(options) {
398
+ if (options?.signal === void 0) return void 0;
399
+ return { signal: options.signal };
400
+ }
401
+ function authClientFailure(operation, state, error) {
402
+ if (error instanceof AuthFlowError) return error;
403
+ return toAuthFlowError(operation, state, error);
404
+ }
405
+ function completeRequest(commit, deferred, input, control, effect, toFailureContext) {
406
+ return effect.pipe(Effect.either, Effect.flatMap((result) => {
407
+ const stopped = stoppedFailure();
408
+ if (control.stopped) return commit(new CommitAuthFlowRequest({
409
+ input,
410
+ context: toFailureContext(stopped)
411
+ })).pipe(Effect.zipRight(Deferred.fail(deferred, stopped)));
412
+ if (result._tag === "Right") return commit(new CommitAuthFlowRequest({
413
+ input,
414
+ context: result.right
415
+ })).pipe(Effect.flatMap((snapshot) => Deferred.succeed(deferred, snapshot)));
416
+ return commit(new CommitAuthFlowRequest({
417
+ input,
418
+ context: toFailureContext(result.left)
419
+ })).pipe(Effect.zipRight(Deferred.fail(deferred, result.left)));
420
+ }), Effect.catchAllDefect((cause) => {
421
+ const failure = new AuthFlowError({
422
+ operation: "transition",
423
+ state: "error",
424
+ publicError: Errors.unknown(cause),
425
+ publicCode: "UNKNOWN",
426
+ cause
427
+ });
428
+ return commit(new CommitAuthFlowRequest({
429
+ input,
430
+ context: toFailureContext(failure)
431
+ })).pipe(Effect.zipRight(Deferred.fail(deferred, failure)));
432
+ }), Effect.onInterrupt(() => commit(new CommitAuthFlowRequest({
433
+ input,
434
+ context: toFailureContext(stoppedFailure())
435
+ })).pipe(Effect.zipRight(Deferred.fail(deferred, stoppedFailure())))));
436
+ }
437
+ function stoppedFailure() {
438
+ return new AuthFlowError({
439
+ operation: "transition",
440
+ state: "error",
441
+ publicError: Errors.cancelled({ operation: "authFlow.request" }),
442
+ publicCode: "CANCELLED"
443
+ });
444
+ }
445
+ function withRuntimeControl(input, control) {
446
+ const runtimeInput = { ...input };
447
+ RUNTIME_CONTROLS.set(runtimeInput, control);
448
+ return runtimeInput;
449
+ }
450
+ function runtimeControl(input) {
451
+ return RUNTIME_CONTROLS.get(input) ?? { stopped: false };
452
+ }
453
+ function failureContext(failure, preserved) {
454
+ return {
455
+ state: "error",
456
+ email: preserved.email,
457
+ session: preserved.session,
458
+ otpRequestedAt: preserved.otpRequestedAt,
459
+ ...preserved.anonDistinctId === void 0 ? {} : { anonDistinctId: preserved.anonDistinctId },
460
+ error: failure.publicError
461
+ };
462
+ }
463
+ function canTransition(state, request) {
464
+ return AUTH_FLOW_TRANSITION_TABLE[state].valid.includes(request);
465
+ }
466
+ function wrongState(request, state) {
467
+ return new AuthFlowError({
468
+ operation: "transition",
469
+ state,
470
+ publicError: Errors.wrongState({
471
+ method: request,
472
+ currentState: state,
473
+ validStates: AUTH_FLOW_TRANSITION_TABLE[state].valid
474
+ }),
475
+ publicCode: "WRONG_STATE"
476
+ });
477
+ }
478
+ function toAuthFlowError(operation, state, error) {
479
+ const publicError = toCapxulError(operation, error);
480
+ return new AuthFlowError({
481
+ operation,
482
+ state,
483
+ publicError,
484
+ publicCode: publicError.code,
485
+ cause: error
486
+ });
487
+ }
488
+ function toCapxulError(operation, error) {
489
+ if (error.cause instanceof CapxulError) return error.cause;
490
+ if (operation === "requestOtp" && error.kind === "provider") return Errors.emailDeliveryFailed("provider rejected OTP request");
491
+ return Errors.providerError("auth-client", operation, /* @__PURE__ */ new Error("auth-client provider failure"));
492
+ }
493
+ function emitTelemetry(event) {
494
+ return Effect.gen(function* () {
495
+ yield* (yield* TelemetryPortTag).emit(event).pipe(Effect.catchAllDefect(() => Effect.void), Effect.catchAll(() => Effect.void));
496
+ });
497
+ }
498
+ function identifyTelemetry(input) {
499
+ return Effect.gen(function* () {
500
+ yield* (yield* TelemetryPortTag).identify(input).pipe(Effect.catchAllDefect(() => Effect.void), Effect.catchAll(() => Effect.void));
501
+ });
502
+ }
503
+ function resetTelemetry() {
504
+ return Effect.gen(function* () {
505
+ yield* (yield* TelemetryPortTag).reset().pipe(Effect.catchAllDefect(() => Effect.void), Effect.catchAll(() => Effect.void));
506
+ });
507
+ }
508
+ function makeAnonymousDistinctId() {
509
+ return toAnonymousDistinctId(`anon_${globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}`);
510
+ }
511
+ function emailDomain$1(email) {
512
+ const [, domain = "unknown"] = email.split("@");
513
+ return domain;
514
+ }
515
+ //#endregion
516
+ //#region src/client/capxul-deps.ts
517
+ /** The single Context tag the atoms + public methods both resolve. */
518
+ var CapxulDepsTag = class extends Context.Tag("@capxul/sdk/CapxulDeps")() {};
519
+ /** Wrap a bundle as the `Layer<CapxulDepsTag>` the React provider consumes. */
520
+ function capxulDepsLayer(deps) {
521
+ return Layer.succeed(CapxulDepsTag, deps);
522
+ }
523
+ /**
524
+ * Build the 3-port AuthFlow layer FROM the bundle. The single home for this
525
+ * construction — `auth.ts` imports it for its per-method Effect runners, and
526
+ * each program (`getSessionProgram`, …) provides it internally so the actor
527
+ * send's `AuthClientPortTag | ClockPortTag | TelemetryPortTag` requirement is
528
+ * discharged and the program's external requirement stays `CapxulDepsTag`.
529
+ */
530
+ function authFlowLayer(deps) {
531
+ return Layer.mergeAll(Layer.succeed(AuthClientPortTag, deps.authClient), Layer.succeed(ClockPortTag, deps.clock), Layer.succeed(TelemetryPortTag, deps.telemetry ?? noopTelemetryPort()));
532
+ }
533
+ function noopTelemetryPort() {
534
+ return {
535
+ emit: () => Effect.void,
536
+ identify: () => Effect.void,
537
+ group: () => Effect.void,
538
+ reset: () => Effect.void
539
+ };
540
+ }
541
+ function hasMachineActor(actor) {
542
+ return typeof actor.send === "function";
543
+ }
544
+ /**
545
+ * getSession as a single Effect requiring ONLY `CapxulDepsTag`. Faithful
546
+ * transcription of the current public method body (auth.ts:250-281): the
547
+ * leading `signal.aborted` pre-check stays in the thin method wrapper, while a
548
+ * non-aborted signal is forwarded through the actor request options. The
549
+ * `Effect.provide(authFlowLayer(deps))` on the inner actor send
550
+ * is what narrows R from
551
+ * `CapxulDepsTag | AuthClientPortTag | ClockPortTag | TelemetryPortTag` down to
552
+ * `CapxulDepsTag` — the load-bearing structural property the explicit
553
+ * annotation asserts.
554
+ */
555
+ const getSessionProgramWithOptions = (options) => Effect.gen(function* () {
556
+ const deps = yield* CapxulDepsTag;
557
+ const cached = yield* deps.authCache.getSession.pipe(Effect.mapError((e) => Errors.providerError("auth-cache", "getSession", e)));
558
+ if (cached !== null) return cached;
559
+ if (!hasMachineActor(deps.actor)) {
560
+ const existingError = deps.actor.getSnapshot().context.error;
561
+ if (existingError !== null) return yield* Effect.fail(existingError);
562
+ }
563
+ const refreshed = yield* sendAuthFlowRequest(deps.actor, {
564
+ _tag: "GetSession",
565
+ ...depsRequestOptions(deps, options?.signal)
566
+ }).pipe(Effect.provide(authFlowLayer(deps)), Effect.mapError((failure) => failure.publicError));
567
+ if (refreshed[1].session !== null) return refreshed[1].session;
568
+ const session = deps.actor.getSnapshot().context.session;
569
+ if (session !== null) return session;
570
+ return null;
571
+ });
572
+ getSessionProgramWithOptions();
573
+ /**
574
+ * verifyOtp as a single Effect requiring ONLY `CapxulDepsTag` (PRD #209, slice
575
+ * 3 — parallels {@link getSessionProgram}). Faithful transcription of the
576
+ * current public method body (auth.ts:145-201): the leading `signal.aborted`
577
+ * pre-check stays in the thin method wrapper, while non-aborted per-request
578
+ * signals and the dep-level `invokeTimeoutMs` knob are forwarded. The
579
+ * `Effect.provide(authFlowLayer(
580
+ * deps))` on the inner actor send narrows R from
581
+ * `CapxulDepsTag | AuthClientPortTag | ClockPortTag | TelemetryPortTag` down to
582
+ * `CapxulDepsTag`.
583
+ */
584
+ function verifyOtpProgram(input, options) {
585
+ return Effect.gen(function* () {
586
+ const deps = yield* CapxulDepsTag;
587
+ if (!/^\d{6}$/.test(input.code)) return yield* Effect.fail(Errors.invalidInput("otp", "must be 6 digits"));
588
+ let email;
589
+ try {
590
+ email = toEmail(input.email);
591
+ } catch (err) {
592
+ return yield* Effect.fail(err instanceof CapxulError ? err : Errors.invalidInput("email", "invalid email"));
593
+ }
594
+ let value = String(deps.actor.getSnapshot().value);
595
+ if (value === "error") {
596
+ yield* sendAuthFlowRequest(deps.actor, { _tag: "ResumeOtpEntry" }).pipe(Effect.provide(authFlowLayer(deps)), Effect.mapError((failure) => failure.publicError));
597
+ value = "otp_requested";
598
+ } else if (value !== "otp_requested") return yield* Effect.fail(Errors.wrongState({
599
+ method: "verifyOtp",
600
+ currentState: value,
601
+ validStates: ["otp_requested"]
602
+ }));
603
+ if (!hasMachineActor(deps.actor)) {
604
+ const next = deps.actor.getSnapshot();
605
+ if (String(next.value) === "error") return yield* Effect.fail(next.context.error ?? Errors.unknown({ method: "verifyOtp" }));
606
+ }
607
+ const session = yield* sendAuthFlowRequest(deps.actor, {
608
+ _tag: "VerifyOtp",
609
+ email,
610
+ otp: input.code,
611
+ ...depsRequestOptions(deps, options?.signal)
612
+ }).pipe(Effect.provide(authFlowLayer(deps)), Effect.map((snapshot) => snapshot[1].session), Effect.mapError((failure) => failure.publicError));
613
+ if (session === null) return yield* Effect.fail(Errors.notAuthenticated());
614
+ yield* deps.authCache.setSession(session).pipe(Effect.mapError((e) => Errors.providerError("auth-cache", "setSession", e)));
615
+ return session;
616
+ });
617
+ }
618
+ /**
619
+ * Deps-only request-option builder. The verbatim deps half of `auth.ts`'s
620
+ * former `authRequestOptions(deps, signal)` — the bundle-level
621
+ * `invokeTimeoutMs` and per-request `signal` are forwarded into the actor
622
+ * request options when present.
623
+ */
624
+ function depsRequestOptions(deps, signal) {
625
+ if (deps.invokeTimeoutMs === void 0 && signal === void 0) return {};
626
+ return { options: {
627
+ ...deps.invokeTimeoutMs === void 0 ? {} : { timeoutMs: deps.invokeTimeoutMs },
628
+ ...signal === void 0 ? {} : { signal }
629
+ } };
630
+ }
631
+ /**
632
+ * Clear the local auth cache (session then JWT), mapping each failure into a
633
+ * typed `CapxulError`. Effect transcription of `auth.ts`'s former
634
+ * `clearAuthCache` helper: `clearSession` runs first and short-circuits the
635
+ * JWT clear on failure, matching the original's sequential `if (!ok) return`.
636
+ */
637
+ function clearAuthCacheEffect(authCache) {
638
+ return authCache.clearSession.pipe(Effect.mapError((cause) => Errors.providerError("auth-cache", "clearSession", cause)), Effect.zipRight(authCache.clearJwt.pipe(Effect.mapError((cause) => Errors.providerError("auth-cache", "clearJwt", cause)))));
639
+ }
640
+ function cryptoRandomId() {
641
+ const bytes = new Uint8Array(8);
642
+ if (typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.getRandomValues === "function") globalThis.crypto.getRandomValues(bytes);
643
+ else for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);
644
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
645
+ }
646
+ const canSendOtpProgram = (input, options) => Effect.gen(function* () {
647
+ const deps = yield* CapxulDepsTag;
648
+ const email = yield* Effect.try({
649
+ try: () => toEmail(input.email),
650
+ catch: (err) => err instanceof CapxulError ? err : Errors.invalidInput("email", "invalid email")
651
+ });
652
+ return yield* deps.authClient.canSendOtp({ email }, options?.signal === void 0 ? void 0 : { signal: options.signal }).pipe(Effect.mapError((failure) => failure.cause instanceof CapxulError ? failure.cause : Errors.providerError("auth-client", "canSendOtp", failure.cause)));
653
+ });
654
+ /**
655
+ * `signIn` as a single Effect requiring ONLY `CapxulDepsTag`. Faithful
656
+ * transcription of the former public method body: brand the email, enforce the
657
+ * idle/otp_requested/error precondition, auto-RESET out of error, drive
658
+ * `RequestOtp`, then mint the tracking Result from the clock. Each actor send
659
+ * provides `authFlowLayer(deps)` INTERNALLY so external R stays `CapxulDepsTag`.
660
+ */
661
+ const signInProgram = (input, options) => Effect.gen(function* () {
662
+ const deps = yield* CapxulDepsTag;
663
+ const email = yield* Effect.try({
664
+ try: () => toEmail(input.email),
665
+ catch: (err) => err instanceof CapxulError ? err : Errors.invalidInput("email", "invalid email")
666
+ });
667
+ const value = String(deps.actor.getSnapshot().value);
668
+ if (value !== "idle" && value !== "otp_requested" && value !== "error") return yield* Effect.fail(Errors.wrongState({
669
+ method: "signIn",
670
+ currentState: value,
671
+ validStates: [
672
+ "idle",
673
+ "otp_requested",
674
+ "error"
675
+ ]
676
+ }));
677
+ if (value === "error") yield* sendAuthFlowRequest(deps.actor, {
678
+ _tag: "ResetAuthFlow",
679
+ ...depsRequestOptions(deps, options?.signal)
680
+ }).pipe(Effect.provide(authFlowLayer(deps)), Effect.mapError((failure) => failure.publicError));
681
+ yield* sendAuthFlowRequest(deps.actor, {
682
+ _tag: "RequestOtp",
683
+ email,
684
+ ...depsRequestOptions(deps, options?.signal)
685
+ }).pipe(Effect.provide(authFlowLayer(deps)), Effect.mapError((failure) => failure.publicError));
686
+ const now = yield* deps.clock.now.pipe(Effect.mapError((cause) => Errors.providerError("clock", "now", cause)));
687
+ return {
688
+ sessionId: cryptoRandomId(),
689
+ expiresAt: now + (deps.otpTtlMs ?? 3e5)
690
+ };
691
+ });
692
+ /**
693
+ * `signOut` as a single Effect requiring ONLY `CapxulDepsTag`. Faithful
694
+ * transcription of the former public method body: WRONG_STATE from idle,
695
+ * reset-and-clear from error, otherwise drive `SignOut` and clear the local
696
+ * cache REGARDLESS of the wire outcome. `Effect.either` captures the `SignOut`
697
+ * result without short-circuiting so the cache clear always runs — a cache
698
+ * clear failure then takes precedence over the wire error, matching the former
699
+ * `if (!cacheClear.ok) return cacheClear; return result`.
700
+ */
701
+ const signOutProgramWithOptions = (options) => Effect.gen(function* () {
702
+ const deps = yield* CapxulDepsTag;
703
+ const value = String(deps.actor.getSnapshot().value);
704
+ if (value === "idle") return yield* Effect.fail(Errors.wrongState({
705
+ method: "signOut",
706
+ currentState: value,
707
+ validStates: [
708
+ "authenticated",
709
+ "otp_requested",
710
+ "verifying",
711
+ "sending_otp",
712
+ "error"
713
+ ]
714
+ }));
715
+ if (value === "error") {
716
+ yield* sendAuthFlowRequest(deps.actor, {
717
+ _tag: "ResetAuthFlow",
718
+ ...depsRequestOptions(deps, options?.signal)
719
+ }).pipe(Effect.provide(authFlowLayer(deps)), Effect.mapError((failure) => failure.publicError));
720
+ yield* clearAuthCacheEffect(deps.authCache);
721
+ return;
722
+ }
723
+ const signOutResult = yield* sendAuthFlowRequest(deps.actor, {
724
+ _tag: "SignOut",
725
+ ...depsRequestOptions(deps, options?.signal)
726
+ }).pipe(Effect.provide(authFlowLayer(deps)), Effect.mapError((failure) => failure.publicError), Effect.either);
727
+ yield* clearAuthCacheEffect(deps.authCache);
728
+ if (Either.isLeft(signOutResult)) return yield* Effect.fail(signOutResult.left);
729
+ });
730
+ signOutProgramWithOptions();
731
+ //#endregion
732
+ //#region src/client/to-capxul-result.ts
733
+ async function toCapxulResult(program, layer) {
734
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer), Effect.catchAllDefect((defect) => Effect.fail(Errors.unknown(defect))), Effect.either));
735
+ if (Either.isLeft(result)) return {
736
+ ok: false,
737
+ error: result.left
738
+ };
739
+ return {
740
+ ok: true,
741
+ value: result.right
742
+ };
743
+ }
744
+ //#endregion
745
+ //#region src/client/auth.ts
746
+ function makeAuthMethods(deps) {
747
+ return {
748
+ async canSendOtp(input, options) {
749
+ if (options?.signal?.aborted) return {
750
+ ok: false,
751
+ error: Errors.cancelled({ operation: "canSendOtp" })
752
+ };
753
+ return toCapxulResult(canSendOtpProgram(input, options), capxulDepsLayer(deps));
754
+ },
755
+ async signIn(input, options) {
756
+ if (options?.signal?.aborted) return {
757
+ ok: false,
758
+ error: Errors.cancelled({ operation: "signIn" })
759
+ };
760
+ return toCapxulResult(signInProgram(input, options), capxulDepsLayer(deps));
761
+ },
762
+ async verifyOtp(input, options) {
763
+ if (options?.signal?.aborted) return {
764
+ ok: false,
765
+ error: Errors.cancelled({ operation: "verifyOtp" })
766
+ };
767
+ const result = await toCapxulResult(verifyOtpProgram(input, options), capxulDepsLayer(deps));
768
+ if (result.ok) {
769
+ const afterVerifyOtp = deps.afterVerifyOtp;
770
+ if (afterVerifyOtp !== void 0) Promise.resolve().then(() => afterVerifyOtp()).catch(() => void 0);
771
+ }
772
+ return result;
773
+ },
774
+ async signOut(options) {
775
+ if (options?.signal?.aborted) return {
776
+ ok: false,
777
+ error: Errors.cancelled({ operation: "signOut" })
778
+ };
779
+ return toCapxulResult(signOutProgramWithOptions(options), capxulDepsLayer(deps));
780
+ },
781
+ async getSession(options) {
782
+ if (options?.signal?.aborted) return {
783
+ ok: false,
784
+ error: Errors.cancelled({ operation: "getSession" })
785
+ };
786
+ return toCapxulResult(getSessionProgramWithOptions(options), capxulDepsLayer(deps));
787
+ }
788
+ };
789
+ }
790
+ //#endregion
791
+ //#region src/client/_shared/provisioning-telemetry.ts
792
+ async function emitProvisioningTelemetry(telemetry, smartAccount) {
793
+ if (telemetry === void 0) return;
794
+ await Effect.runPromise(telemetry.emit({
795
+ name: "provisioning_safe_created",
796
+ props: { safe_address: smartAccount.smartAccountAddress }
797
+ }).pipe(Effect.catchAll((cause) => Effect.sync(() => reportProvisioningTelemetryFailure("error", smartAccount, cause))), Effect.catchAllDefect((cause) => Effect.sync(() => reportProvisioningTelemetryFailure("defect", smartAccount, cause)))));
798
+ }
799
+ function reportProvisioningTelemetryFailure(kind, smartAccount, cause) {
800
+ if (!isProvisioningTelemetryDebugEnabled()) return;
801
+ globalThis.console?.warn?.("[capxul] provisioning telemetry dropped", {
802
+ kind,
803
+ safeAddress: smartAccount.smartAccountAddress,
804
+ cause
805
+ });
806
+ }
807
+ function isProvisioningTelemetryDebugEnabled() {
808
+ return globalThis.process?.env?.CAPXUL_DEBUG_TELEMETRY === "1";
809
+ }
810
+ //#endregion
811
+ //#region src/client/smart-account-deps.ts
812
+ /** The single Context tag the `smartAccount.*` methods resolve. */
813
+ var SmartAccountDepsTag = class extends Context.Tag("@capxul/sdk/SmartAccountDeps")() {};
814
+ /** Wrap a bundle as the `Layer<SmartAccountDepsTag>` the React provider consumes. */
815
+ function smartAccountDepsLayer(deps) {
816
+ return Layer.succeed(SmartAccountDepsTag, deps);
817
+ }
818
+ /**
819
+ * `smartAccount.loadCurrent` as a single Effect requiring ONLY
820
+ * `SmartAccountDepsTag`. Faithful transcription of the current public method
821
+ * body (`smart-account.ts`): snapshot the actor for the session authUserId,
822
+ * append the optional sentinel fallback, and return the first non-null
823
+ * `SmartAccountPort` row. The leading `signal.aborted` pre-check stays in the
824
+ * thin method wrapper. Port failures narrow to their `publicError`.
825
+ */
826
+ const loadSmartAccountProgram = Effect.gen(function* () {
827
+ const deps = yield* SmartAccountDepsTag;
828
+ const snap = deps.actor.getSnapshot();
829
+ const fallback = deps.sessionAuthUserIdFallback ?? null;
830
+ const candidates = [];
831
+ if (snap.context.session?.authUserId !== void 0) candidates.push(snap.context.session.authUserId);
832
+ if (fallback !== null) candidates.push(fallback);
833
+ for (const candidate of candidates) {
834
+ const row = yield* deps.smartAccountPort.loadByAuthUserId(candidate).pipe(Effect.mapError((failure) => failure.publicError));
835
+ if (row !== null) return row;
836
+ }
837
+ return null;
838
+ });
839
+ /**
840
+ * `smartAccount.provision` as an input-parameterised program requiring ONLY
841
+ * `SmartAccountDepsTag`. Faithful transcription of the current public method
842
+ * body (`smart-account.ts`): precondition the actor on `authenticated`, brand
843
+ * the external signer at entry, then drive the `SmartAccountPort.provision`
844
+ * port. The leading `signal.aborted` pre-check stays in the thin method
845
+ * wrapper (provision currently takes no signal, so there is none).
846
+ */
847
+ function provisionSmartAccountProgram(input) {
848
+ return Effect.gen(function* () {
849
+ const deps = yield* SmartAccountDepsTag;
850
+ const snap = deps.actor.getSnapshot();
851
+ const value = snap.value;
852
+ if (value !== "authenticated") return yield* Effect.fail(Errors.wrongState({
853
+ method: "smartAccount.provision",
854
+ currentState: value,
855
+ validStates: ["authenticated"]
856
+ }));
857
+ const signer = input?.externalSigner;
858
+ if (signer === void 0) return yield* Effect.fail(Errors.invalidInput("externalSigner", "required for provisioning"));
859
+ let signerAddress;
860
+ try {
861
+ signerAddress = toAddress(signer.address);
862
+ } catch (err) {
863
+ return yield* Effect.fail(err instanceof CapxulError ? err : Errors.invalidInput("externalSigner.address", "invalid EVM address"));
864
+ }
865
+ const session = snap.context.session;
866
+ if (session === null) return yield* Effect.fail(Errors.notAuthenticated());
867
+ const provisioned = yield* deps.smartAccountPort.provision({
868
+ authUserId: session.authUserId,
869
+ signerAddress,
870
+ chainId: deps.chainId
871
+ }).pipe(Effect.mapError((failure) => failure.publicError));
872
+ yield* Effect.promise(() => emitProvisioningTelemetry(deps.telemetry, provisioned));
873
+ return provisioned;
874
+ });
875
+ }
876
+ //#endregion
877
+ //#region src/client/smart-account.ts
878
+ function makeSmartAccountMethods(deps) {
879
+ return {
880
+ async loadCurrent(options) {
881
+ if (options?.signal?.aborted) return {
882
+ ok: false,
883
+ error: Errors.cancelled({ operation: "smartAccount.loadCurrent" })
884
+ };
885
+ return toCapxulResult(loadSmartAccountProgram, smartAccountDepsLayer(deps));
886
+ },
887
+ async provision(input) {
888
+ return toCapxulResult(provisionSmartAccountProgram(input), smartAccountDepsLayer(deps));
889
+ }
890
+ };
891
+ }
892
+ //#endregion
893
+ //#region src/ports/identity.ts
894
+ var IdentityError = class extends Data.TaggedError("IdentityError") {};
895
+ function identityErrorFromCapxul(operation, error, cause = error) {
896
+ return new IdentityError({
897
+ operation,
898
+ publicCode: error.code,
899
+ publicError: error,
900
+ cause,
901
+ ...error.details === void 0 ? {} : { details: error.details }
902
+ });
903
+ }
904
+ var IdentityPortTag = class extends Context.Tag("@capxul/sdk/ports/IdentityPort")() {};
905
+ //#endregion
906
+ //#region src/client/identity-deps.ts
907
+ /** The single Context tag the profile atom + `identity.loadCurrent` resolve. */
908
+ var IdentityDepsTag = class extends Context.Tag("@capxul/sdk/IdentityDeps")() {};
909
+ /** Wrap a bundle as the `Layer<IdentityDepsTag>` the React provider consumes. */
910
+ function identityDepsLayer(deps) {
911
+ return Layer.succeed(IdentityDepsTag, deps);
912
+ }
913
+ /**
914
+ * `identity.loadCurrent` as a single Effect requiring ONLY `IdentityDepsTag`.
915
+ * Faithful transcription of the current public method body (`identity.ts`):
916
+ * the leading `signal.aborted` pre-check stays in the thin method wrapper;
917
+ * the program snapshots the actor session, then narrows the `IdentityPort`
918
+ * failure to its `publicError`. Defects/sync-throws surface as `UNKNOWN`
919
+ * through `toCapxulResult`'s `catchAllDefect` (and the atom's runtime), which
920
+ * replaces the old outer `try/catch`.
921
+ */
922
+ const loadIdentityProgram = Effect.gen(function* () {
923
+ const deps = yield* IdentityDepsTag;
924
+ if (deps.actor === void 0) return yield* Effect.fail(Errors.notAuthenticated());
925
+ const snapshot = deps.actor.getSnapshot();
926
+ const existingError = snapshot.context.error;
927
+ if (existingError instanceof CapxulError) return yield* Effect.fail(existingError);
928
+ const authUserId = snapshot.context.session?.authUserId;
929
+ if (authUserId === void 0) return null;
930
+ return yield* deps.identityPort.loadByAuthUserId(authUserId).pipe(Effect.catchAllDefect((cause) => Effect.fail(identityErrorFromCapxul("loadByAuthUserId", cause instanceof CapxulError ? cause : Errors.unknown(cause), cause))), Effect.mapError((failure) => failure.publicError));
931
+ });
932
+ //#endregion
933
+ //#region src/client/identity.ts
934
+ function makeIdentityMethods(deps) {
935
+ return { async loadCurrent(options) {
936
+ if (options?.signal?.aborted) return {
937
+ ok: false,
938
+ error: Errors.cancelled({ operation: "identity.loadCurrent" })
939
+ };
940
+ return toCapxulResult(loadIdentityProgram, identityDepsLayer(deps));
941
+ } };
942
+ }
943
+ //#endregion
944
+ //#region src/client/_shared/effect-actor-bridge.ts
945
+ /**
946
+ * Bridge an Effect whose typed failure carries `{ publicError: CapxulError }`
947
+ * into the `Promise<CapxulResult<T>>` shape the consumer-facing method
948
+ * bundles return. Applies to every port that surfaces a `publicError`
949
+ * (smart-account, identity, auth-cache, and — post-#161 — account
950
+ * provision/deploy).
951
+ */
952
+ async function runPortEffect(effect) {
953
+ const result = await Effect.runPromise(Effect.either(effect));
954
+ if (Either.isRight(result)) return {
955
+ ok: true,
956
+ value: result.right
957
+ };
958
+ return {
959
+ ok: false,
960
+ error: result.left.publicError
961
+ };
962
+ }
963
+ /** The session carried by the actor's current snapshot, or `null`. */
964
+ function sessionFromActor(actor) {
965
+ return actor.getSnapshot().context.session;
966
+ }
967
+ //#endregion
968
+ //#region src/client/account-deps.ts
969
+ /** The single Context tag the account atom + `account.getStatus` resolve. */
970
+ var AccountDepsTag = class extends Context.Tag("@capxul/sdk/AccountDeps")() {};
971
+ /** Wrap a bundle as the `Layer<AccountDepsTag>` the React provider consumes. */
972
+ function accountDepsLayer(deps) {
973
+ return Layer.succeed(AccountDepsTag, deps);
974
+ }
975
+ /**
976
+ * `account.getStatus` as a single Effect requiring ONLY `AccountDepsTag`.
977
+ * Faithful transcription of the current public method body (`account.ts`):
978
+ * resolve the session (actor first, then the resume-path `authCache`), then
979
+ * walk the readiness ladder. The `SmartAccountPort` failure narrows to its
980
+ * `publicError`; a consumer `AccountProvider.getAddress` rejection becomes a
981
+ * `providerError` (defending the public `CapxulResult` contract).
982
+ */
983
+ const accountStatusProgram = Effect.gen(function* () {
984
+ const deps = yield* AccountDepsTag;
985
+ const session = yield* Effect.promise(() => currentSession(deps.actor, deps.authCache));
986
+ if (session === null) return { status: "notAuthenticated" };
987
+ const current = yield* deps.smartAccountPort.loadByAuthUserId(session.authUserId).pipe(Effect.mapError((failure) => failure.publicError));
988
+ if (current !== null) return statusFromAccount(current, deps.requirement);
989
+ if (deps.requirement === "none") return {
990
+ status: "accountReady",
991
+ requirement: deps.requirement,
992
+ account: null,
993
+ deployment: { status: "counterfactual" }
994
+ };
995
+ const signer = deps.signer;
996
+ if (signer === void 0) return {
997
+ status: "accountRequired",
998
+ requirement: deps.requirement,
999
+ chainId: deps.chainId
1000
+ };
1001
+ const signerAddress = yield* Effect.tryPromise({
1002
+ try: () => signer.getAddress(),
1003
+ catch: (cause) => Errors.providerError("signer", "getAddress", cause)
1004
+ });
1005
+ return {
1006
+ status: "accountProviderReady",
1007
+ requirement: deps.requirement,
1008
+ chainId: deps.chainId,
1009
+ source: signer.source,
1010
+ signerAddress
1011
+ };
1012
+ });
1013
+ /**
1014
+ * Resume-path session resolution. Consults the actor first; if the actor has
1015
+ * no session (e.g. page refresh before any sign-in event), reads
1016
+ * `authCache.getSession`. `AuthCacheError` is non-fatal at this read point —
1017
+ * treat as "no session" and let the consumer's `auth.signIn` path resolve.
1018
+ */
1019
+ async function currentSession(actor, authCache) {
1020
+ const fromActor = sessionFromActor(actor);
1021
+ if (fromActor !== null) return fromActor;
1022
+ if (authCache === void 0) return null;
1023
+ const cached = await Effect.runPromise(Effect.either(authCache.getSession));
1024
+ if (Either.isRight(cached)) return cached.right;
1025
+ return null;
1026
+ }
1027
+ /** Map a backend `SmartAccount` row onto the readiness `AccountStatus`. */
1028
+ function statusFromAccount(account, requirement) {
1029
+ if (requirement === "deployed") {
1030
+ if (account.deployedAt === null) return {
1031
+ status: "accountPrepared",
1032
+ requirement,
1033
+ account,
1034
+ deployment: { status: "counterfactual" }
1035
+ };
1036
+ return {
1037
+ status: "accountReady",
1038
+ requirement,
1039
+ account,
1040
+ deployment: {
1041
+ status: "deployed",
1042
+ deployedAt: account.deployedAt
1043
+ }
1044
+ };
1045
+ }
1046
+ return {
1047
+ status: "accountReady",
1048
+ requirement,
1049
+ account,
1050
+ deployment: account.deployedAt === null ? { status: "counterfactual" } : {
1051
+ status: "deployed",
1052
+ deployedAt: account.deployedAt
1053
+ }
1054
+ };
1055
+ }
1056
+ //#endregion
1057
+ //#region src/client/account.ts
1058
+ function makeAccountMethods(deps) {
1059
+ toChainId(deps.chainId);
1060
+ const requirement = deps.requirement;
1061
+ const getStatus = () => toCapxulResult(accountStatusProgram, accountDepsLayer(deps));
1062
+ const ensureIdentityProfile = async (session) => {
1063
+ const existing = await runPortEffect(deps.identityPort.loadByAuthUserId(session.authUserId));
1064
+ if (!existing.ok) return {
1065
+ ok: false,
1066
+ error: existing.error
1067
+ };
1068
+ if (existing.value !== null) return {
1069
+ ok: true,
1070
+ value: void 0
1071
+ };
1072
+ const created = await runPortEffect(deps.identityPort.create({
1073
+ authUserId: session.authUserId,
1074
+ email: session.email
1075
+ }));
1076
+ if (!created.ok) return {
1077
+ ok: false,
1078
+ error: created.error
1079
+ };
1080
+ return {
1081
+ ok: true,
1082
+ value: void 0
1083
+ };
1084
+ };
1085
+ const provisionImpl = async () => {
1086
+ const session = await currentSession(deps.actor, deps.authCache);
1087
+ if (session === null) return {
1088
+ ok: false,
1089
+ error: Errors.notAuthenticated()
1090
+ };
1091
+ const profileReady = await ensureIdentityProfile(session);
1092
+ if (!profileReady.ok) return {
1093
+ ok: false,
1094
+ error: profileReady.error
1095
+ };
1096
+ const signer = deps.signer;
1097
+ if (signer === void 0) return {
1098
+ ok: false,
1099
+ error: Errors.smartAccountMissing("provision")
1100
+ };
1101
+ const signerAddressResult = await getSignerAddress(signer);
1102
+ if (!signerAddressResult.ok) return {
1103
+ ok: false,
1104
+ error: signerAddressResult.error
1105
+ };
1106
+ const signerAddress = signerAddressResult.value;
1107
+ const provisioned = await runPortEffect(deps.smartAccountPort.provision({
1108
+ authUserId: session.authUserId,
1109
+ signerAddress,
1110
+ chainId: toChainId(deps.chainId)
1111
+ }));
1112
+ if (!provisioned.ok) return provisioned;
1113
+ await emitProvisioningTelemetry(deps.telemetry, provisioned.value);
1114
+ return {
1115
+ ok: true,
1116
+ value: provisioned.value
1117
+ };
1118
+ };
1119
+ const deployMutex = /* @__PURE__ */ new Map();
1120
+ const deploySafeImpl = async () => {
1121
+ const session = await currentSession(deps.actor, deps.authCache);
1122
+ if (session === null) return {
1123
+ ok: false,
1124
+ error: Errors.notAuthenticated()
1125
+ };
1126
+ const signer = deps.signer;
1127
+ if (signer === void 0) return {
1128
+ ok: false,
1129
+ error: Errors.smartAccountMissing("deploySafe")
1130
+ };
1131
+ const existing = await runPortEffect(deps.smartAccountPort.loadByAuthUserId(session.authUserId));
1132
+ if (!existing.ok) return existing;
1133
+ if (existing.value !== null && existing.value.deployedAt !== null) return {
1134
+ ok: true,
1135
+ value: existing.value
1136
+ };
1137
+ if (existing.value === null) {
1138
+ const provisioned = await provisionImpl();
1139
+ if (!provisioned.ok) return provisioned;
1140
+ }
1141
+ const mutexKey = `${String(session.authUserId)}:${deps.chainId}`;
1142
+ const inFlight = deployMutex.get(mutexKey);
1143
+ if (inFlight !== void 0) return inFlight;
1144
+ const work = runBackendDeploy({
1145
+ authUserId: session.authUserId,
1146
+ chainId: deps.chainId,
1147
+ signer,
1148
+ smartAccountPort: deps.smartAccountPort
1149
+ }).finally(() => {
1150
+ deployMutex.delete(mutexKey);
1151
+ });
1152
+ deployMutex.set(mutexKey, work);
1153
+ return work;
1154
+ };
1155
+ const ensureReady = async () => {
1156
+ const status = await getStatus();
1157
+ if (!status.ok) return status;
1158
+ if (status.value.status === "accountProviderReady" && requirement !== "deployed") {
1159
+ const provisioned = await provisionImpl();
1160
+ if (!provisioned.ok) return {
1161
+ ok: false,
1162
+ error: provisioned.error
1163
+ };
1164
+ return getStatus();
1165
+ }
1166
+ if (status.value.status === "accountProviderReady" && requirement === "deployed") {
1167
+ const provisioned = await provisionImpl();
1168
+ if (!provisioned.ok) return {
1169
+ ok: false,
1170
+ error: provisioned.error
1171
+ };
1172
+ const deployed = await deploySafeImpl();
1173
+ if (!deployed.ok) return {
1174
+ ok: false,
1175
+ error: deployed.error
1176
+ };
1177
+ return getStatus();
1178
+ }
1179
+ if (status.value.status === "accountPrepared" && requirement === "deployed") {
1180
+ const deployed = await deploySafeImpl();
1181
+ if (!deployed.ok) return {
1182
+ ok: false,
1183
+ error: deployed.error
1184
+ };
1185
+ return getStatus();
1186
+ }
1187
+ return status;
1188
+ };
1189
+ return {
1190
+ getStatus,
1191
+ ensureReady,
1192
+ _internal: {
1193
+ provision: provisionImpl,
1194
+ deploySafe: deploySafeImpl
1195
+ }
1196
+ };
1197
+ }
1198
+ async function getSignerAddress(signer) {
1199
+ try {
1200
+ return {
1201
+ ok: true,
1202
+ value: await signer.getAddress()
1203
+ };
1204
+ } catch (cause) {
1205
+ return {
1206
+ ok: false,
1207
+ error: Errors.providerError("signer", "getAddress", cause)
1208
+ };
1209
+ }
1210
+ }
1211
+ /**
1212
+ * Backend-orchestrated deploy (backend-orchestrated-deploy.md):
1213
+ * 1. `deployPrepare` — backend builds + gas-fills + paymaster-sponsors the
1214
+ * deployment UserOp and returns the EIP-712 SafeOp digest.
1215
+ * 2. `signer.signUserOpHash(digest)` — the only step needing the user's key.
1216
+ * 3. `deploySubmit` — backend submits via the bundler + confirms deployedAt.
1217
+ */
1218
+ async function runBackendDeploy(input) {
1219
+ const chainId = toChainId(input.chainId);
1220
+ const prepared = await runPortEffect(input.smartAccountPort.deployPrepare({
1221
+ authUserId: input.authUserId,
1222
+ chainId
1223
+ }));
1224
+ if (!prepared.ok) return prepared;
1225
+ let signature;
1226
+ try {
1227
+ signature = await input.signer.signUserOpHash(prepared.value.digest);
1228
+ } catch (cause) {
1229
+ return {
1230
+ ok: false,
1231
+ error: Errors.providerError("signer", "signUserOpHash", cause)
1232
+ };
1233
+ }
1234
+ const confirmed = await runPortEffect(input.smartAccountPort.deploySubmit({
1235
+ authUserId: input.authUserId,
1236
+ chainId,
1237
+ userOp: prepared.value.userOp,
1238
+ signature
1239
+ }));
1240
+ if (!confirmed.ok) return confirmed;
1241
+ if (confirmed.value.deployedAt === null) return {
1242
+ ok: false,
1243
+ error: Errors.providerError("smart-account", "deploySubmit", "missing deployedAt")
1244
+ };
1245
+ return {
1246
+ ok: true,
1247
+ value: confirmed.value
1248
+ };
1249
+ }
1250
+ //#endregion
1251
+ //#region src/money/to-wei.ts
1252
+ /**
1253
+ * Lower consumer `Money` into an on-chain integer string for guarded writes.
1254
+ * Canon `account-balance-model.md` §10 — internal at the SDK boundary only.
1255
+ */
1256
+ function toWei(money) {
1257
+ return parseUnits(money.value, money.decimals).toString();
1258
+ }
1259
+ //#endregion
1260
+ //#region src/client/_shared/money-telemetry.ts
1261
+ /**
1262
+ * Lower a consumer `Money` into a non-negative integer WeiAmount string for
1263
+ * telemetry props. Reuses the SDK boundary `toWei` (viem `parseUnits`, string
1264
+ * math only — never a float multiply per `.claude/rules/numeric-parsing.md`).
1265
+ */
1266
+ function moneyToWeiAmount(money) {
1267
+ return toWei(money);
1268
+ }
1269
+ function transferDirection(from, to) {
1270
+ if (from === "main") return "add";
1271
+ if (to === "main") return "out";
1272
+ return "between";
1273
+ }
1274
+ /** Fire-and-forget emit through an optional port; never throws. */
1275
+ async function emitMoneyTelemetry(telemetry, event) {
1276
+ if (telemetry === void 0) return;
1277
+ await Effect.runPromise(telemetry.emit(event).pipe(Effect.catchAll((cause) => Effect.sync(() => reportMoneyTelemetryFailure("error", event.name, cause))), Effect.catchAllDefect((cause) => Effect.sync(() => reportMoneyTelemetryFailure("defect", event.name, cause)))));
1278
+ }
1279
+ function emitFaucetRequested(telemetry, input) {
1280
+ let amount;
1281
+ try {
1282
+ amount = moneyToWeiAmount(input.amount);
1283
+ } catch (cause) {
1284
+ reportMoneyTelemetryFailure("defect", "faucet_requested", cause);
1285
+ return Promise.resolve();
1286
+ }
1287
+ return emitMoneyTelemetry(telemetry, {
1288
+ name: "faucet_requested",
1289
+ props: {
1290
+ amount,
1291
+ chainId: input.chainId
1292
+ }
1293
+ });
1294
+ }
1295
+ function emitFaucetFailed(telemetry, reason) {
1296
+ return emitMoneyTelemetry(telemetry, {
1297
+ name: "faucet_failed",
1298
+ props: { reason }
1299
+ });
1300
+ }
1301
+ function emitAccountBalanceFailed(telemetry, reason) {
1302
+ return emitMoneyTelemetry(telemetry, {
1303
+ name: "account_balance_failed",
1304
+ props: { reason }
1305
+ });
1306
+ }
1307
+ function emitTransferRequested(telemetry, input) {
1308
+ let amount;
1309
+ try {
1310
+ amount = moneyToWeiAmount(input.amount);
1311
+ } catch (cause) {
1312
+ reportMoneyTelemetryFailure("defect", "transfer_requested", cause);
1313
+ return Promise.resolve();
1314
+ }
1315
+ return emitMoneyTelemetry(telemetry, {
1316
+ name: "transfer_requested",
1317
+ props: {
1318
+ amount,
1319
+ direction: transferDirection(input.from, input.to)
1320
+ }
1321
+ });
1322
+ }
1323
+ function emitTransferFailed(telemetry, reason) {
1324
+ return emitMoneyTelemetry(telemetry, {
1325
+ name: "transfer_failed",
1326
+ props: { reason }
1327
+ });
1328
+ }
1329
+ function emitSubAccountCreated(telemetry, subAccountId) {
1330
+ return emitMoneyTelemetry(telemetry, {
1331
+ name: "subaccount_created",
1332
+ props: { sub_account_id: subAccountId }
1333
+ });
1334
+ }
1335
+ function emitSubAccountRenamed(telemetry, subAccountId) {
1336
+ return emitMoneyTelemetry(telemetry, {
1337
+ name: "subaccount_renamed",
1338
+ props: { sub_account_id: subAccountId }
1339
+ });
1340
+ }
1341
+ function emitSubAccountDeleted(telemetry, subAccountId) {
1342
+ return emitMoneyTelemetry(telemetry, {
1343
+ name: "subaccount_deleted",
1344
+ props: { sub_account_id: subAccountId }
1345
+ });
1346
+ }
1347
+ function emitSubAccountOpFailed(telemetry, op, reason) {
1348
+ return emitMoneyTelemetry(telemetry, {
1349
+ name: "subaccount_op_failed",
1350
+ props: {
1351
+ op,
1352
+ reason
1353
+ }
1354
+ });
1355
+ }
1356
+ function reportMoneyTelemetryFailure(kind, name, cause) {
1357
+ if (!isMoneyTelemetryDebugEnabled()) return;
1358
+ globalThis.console?.warn?.("[capxul] money telemetry dropped", {
1359
+ kind,
1360
+ name,
1361
+ cause
1362
+ });
1363
+ }
1364
+ function isMoneyTelemetryDebugEnabled() {
1365
+ return globalThis.process?.env?.CAPXUL_DEBUG_TELEMETRY === "1";
1366
+ }
1367
+ //#endregion
1368
+ //#region src/client/accounts-deps.ts
1369
+ var AccountsDepsTag = class extends Context.Tag("@capxul/sdk/AccountsDeps")() {};
1370
+ function accountsDepsLayer(deps) {
1371
+ return Layer.succeed(AccountsDepsTag, deps);
1372
+ }
1373
+ const readAccountProgram = Effect.gen(function* () {
1374
+ const deps = yield* AccountsDepsTag;
1375
+ return yield* deps.accountReadPort.readBalance({ chainId: deps.chainId }).pipe(Effect.tapError((error) => Effect.promise(() => emitAccountBalanceFailed(deps.telemetry, error.publicCode))), Effect.mapError((error) => error.publicError));
1376
+ });
1377
+ function fundFromFaucetProgram(amount) {
1378
+ return Effect.gen(function* () {
1379
+ const deps = yield* AccountsDepsTag;
1380
+ yield* Effect.promise(() => emitFaucetRequested(deps.telemetry, {
1381
+ amount,
1382
+ chainId: deps.chainId
1383
+ }));
1384
+ return yield* deps.accountReadPort.fundFromFaucet({
1385
+ chainId: deps.chainId,
1386
+ amount
1387
+ }).pipe(Effect.tapError((error) => Effect.promise(() => emitFaucetFailed(deps.telemetry, error.publicCode))), Effect.mapError((error) => error.publicError));
1388
+ });
1389
+ }
1390
+ //#endregion
1391
+ //#region src/client/accounts.ts
1392
+ /**
1393
+ * Build the accounts bundle. `assembleCapxulClient` exposes the public `read`
1394
+ * half at `client.accounts` (typed `AccountsMethods`) and the dev-only `fund`
1395
+ * half at `client._internal.accounts` (typed `AccountsFaucetMethods`), so the
1396
+ * faucet never appears on the public client surface.
1397
+ */
1398
+ function makeAccountsMethods(deps) {
1399
+ return {
1400
+ async read(options) {
1401
+ if (options?.signal?.aborted) return {
1402
+ ok: false,
1403
+ error: Errors.cancelled({ operation: "accounts.read" })
1404
+ };
1405
+ return toCapxulResult(readAccountProgram, accountsDepsLayer(deps));
1406
+ },
1407
+ async fund(amount, options) {
1408
+ if (options?.signal?.aborted) return {
1409
+ ok: false,
1410
+ error: Errors.cancelled({ operation: "accounts.fund" })
1411
+ };
1412
+ return toCapxulResult(fundFromFaucetProgram(amount), accountsDepsLayer(deps));
1413
+ }
1414
+ };
1415
+ }
1416
+ //#endregion
1417
+ //#region src/client/sub-accounts-deps.ts
1418
+ var SubAccountsDepsTag = class extends Context.Tag("@capxul/sdk/SubAccountsDeps")() {};
1419
+ function subAccountsDepsLayer(deps) {
1420
+ return Layer.succeed(SubAccountsDepsTag, deps);
1421
+ }
1422
+ function createSubAccountProgram(accountId, name) {
1423
+ return Effect.gen(function* () {
1424
+ const deps = yield* SubAccountsDepsTag;
1425
+ const created = yield* deps.subAccountPort.create({
1426
+ accountId,
1427
+ name
1428
+ }).pipe(Effect.tapError((error) => Effect.promise(() => emitSubAccountOpFailed(deps.telemetry, "create", error.publicCode))), Effect.mapError((error) => error.publicError));
1429
+ yield* Effect.promise(() => emitSubAccountCreated(deps.telemetry, created.id));
1430
+ return created;
1431
+ });
1432
+ }
1433
+ function getSubAccountProgram(subAccountId) {
1434
+ return Effect.gen(function* () {
1435
+ return yield* (yield* SubAccountsDepsTag).subAccountPort.get({ subAccountId }).pipe(Effect.mapError((error) => error.publicError));
1436
+ });
1437
+ }
1438
+ function listSubAccountsProgram(accountId) {
1439
+ return Effect.gen(function* () {
1440
+ return yield* (yield* SubAccountsDepsTag).subAccountPort.list({ accountId }).pipe(Effect.mapError((error) => error.publicError));
1441
+ });
1442
+ }
1443
+ function renameSubAccountProgram(subAccountId, name) {
1444
+ return Effect.gen(function* () {
1445
+ const deps = yield* SubAccountsDepsTag;
1446
+ const renamed = yield* deps.subAccountPort.rename({
1447
+ subAccountId,
1448
+ name
1449
+ }).pipe(Effect.tapError((error) => Effect.promise(() => emitSubAccountOpFailed(deps.telemetry, "rename", error.publicCode))), Effect.mapError((error) => error.publicError));
1450
+ yield* Effect.promise(() => emitSubAccountRenamed(deps.telemetry, renamed.id));
1451
+ return renamed;
1452
+ });
1453
+ }
1454
+ function deleteSubAccountProgram(subAccountId) {
1455
+ return Effect.gen(function* () {
1456
+ const deps = yield* SubAccountsDepsTag;
1457
+ yield* deps.subAccountPort.delete({ subAccountId }).pipe(Effect.tapError((error) => Effect.promise(() => emitSubAccountOpFailed(deps.telemetry, "delete", error.publicCode))), Effect.mapError((error) => error.publicError));
1458
+ yield* Effect.promise(() => emitSubAccountDeleted(deps.telemetry, subAccountId));
1459
+ });
1460
+ }
1461
+ function transferSubAccountProgram(input) {
1462
+ return Effect.gen(function* () {
1463
+ const deps = yield* SubAccountsDepsTag;
1464
+ yield* Effect.promise(() => emitTransferRequested(deps.telemetry, {
1465
+ amount: input.amount,
1466
+ from: input.from,
1467
+ to: input.to
1468
+ }));
1469
+ return yield* deps.subAccountPort.transfer(input).pipe(Effect.tapError((error) => Effect.promise(() => emitTransferFailed(deps.telemetry, error.publicCode))), Effect.mapError((error) => error.publicError));
1470
+ });
1471
+ }
1472
+ //#endregion
1473
+ //#region src/client/sub-accounts.ts
1474
+ function makeSubAccountsMethods(deps) {
1475
+ const layer = subAccountsDepsLayer(deps);
1476
+ return {
1477
+ async create(accountId, input, options) {
1478
+ if (options?.signal?.aborted) return {
1479
+ ok: false,
1480
+ error: Errors.cancelled({ operation: "subAccounts.create" })
1481
+ };
1482
+ return toCapxulResult(createSubAccountProgram(accountId, input.name), layer);
1483
+ },
1484
+ async get(subAccountId, options) {
1485
+ if (options?.signal?.aborted) return {
1486
+ ok: false,
1487
+ error: Errors.cancelled({ operation: "subAccounts.get" })
1488
+ };
1489
+ return toCapxulResult(getSubAccountProgram(subAccountId), layer);
1490
+ },
1491
+ async list(accountId, options) {
1492
+ if (options?.signal?.aborted) return {
1493
+ ok: false,
1494
+ error: Errors.cancelled({ operation: "subAccounts.list" })
1495
+ };
1496
+ return toCapxulResult(listSubAccountsProgram(accountId), layer);
1497
+ },
1498
+ async rename(subAccountId, name, options) {
1499
+ if (options?.signal?.aborted) return {
1500
+ ok: false,
1501
+ error: Errors.cancelled({ operation: "subAccounts.rename" })
1502
+ };
1503
+ return toCapxulResult(renameSubAccountProgram(subAccountId, name), layer);
1504
+ },
1505
+ async delete(subAccountId, options) {
1506
+ if (options?.signal?.aborted) return {
1507
+ ok: false,
1508
+ error: Errors.cancelled({ operation: "subAccounts.delete" })
1509
+ };
1510
+ return toCapxulResult(deleteSubAccountProgram(subAccountId), layer);
1511
+ },
1512
+ async transfer(input, options) {
1513
+ if (options?.signal?.aborted) return {
1514
+ ok: false,
1515
+ error: Errors.cancelled({ operation: "subAccounts.transfer" })
1516
+ };
1517
+ return toCapxulResult(transferSubAccountProgram(input), layer);
1518
+ }
1519
+ };
1520
+ }
1521
+ //#endregion
1522
+ //#region src/money/from-wei.ts
1523
+ /**
1524
+ * Lift an on-chain integer (e.g. USDX 6-decimal) into consumer `Money`.
1525
+ * Canon `account-balance-model.md` §10 — internal at the SDK boundary only.
1526
+ */
1527
+ function fromWei(rawBalance, decimals, currency) {
1528
+ if (!Number.isInteger(decimals) || decimals < 0) throw new Error(`fromWei: decimals must be a non-negative integer, got ${String(decimals)}`);
1529
+ const normalized = rawBalance.trim();
1530
+ if (!/^\d+$/.test(normalized)) {
1531
+ const truncated = normalized.length > 80 ? `${normalized.slice(0, 80)}…` : normalized;
1532
+ throw new Error(`fromWei: rawBalance must be a base-10 integer string, got ${truncated}`);
1533
+ }
1534
+ return {
1535
+ currency: toCurrencyCode(currency),
1536
+ value: formatUnits(BigInt(normalized), decimals),
1537
+ decimals
1538
+ };
1539
+ }
1540
+ //#endregion
1541
+ //#region src/client/_shared/org-telemetry.ts
1542
+ /** Extract the domain from an email for telemetry (never the local part / PII). */
1543
+ function emailDomain(email) {
1544
+ const at = email.lastIndexOf("@");
1545
+ if (at < 0 || at === email.length - 1) return void 0;
1546
+ return email.slice(at + 1).toLowerCase();
1547
+ }
1548
+ /** Fire-and-forget emit through an optional port; never throws. */
1549
+ async function emitOrgTelemetry(telemetry, event) {
1550
+ if (telemetry === void 0) return;
1551
+ await Effect.runPromise(telemetry.emit(event).pipe(Effect.catchAll((cause) => Effect.sync(() => reportOrgTelemetryFailure("error", event.name, cause))), Effect.catchAllDefect((cause) => Effect.sync(() => reportOrgTelemetryFailure("defect", event.name, cause)))));
1552
+ }
1553
+ function emitOrgCreateStarted(telemetry, input) {
1554
+ const domain = input.email === void 0 ? void 0 : emailDomain(input.email);
1555
+ return emitOrgTelemetry(telemetry, {
1556
+ name: "org_create_started",
1557
+ props: {
1558
+ template: input.template,
1559
+ ...domain === void 0 ? {} : { email_domain: domain }
1560
+ }
1561
+ });
1562
+ }
1563
+ /** Spread the `chainId` prop only when known — never emit a misleading `0`. */
1564
+ function chainIdProp(chainId) {
1565
+ return chainId === void 0 ? {} : { chainId };
1566
+ }
1567
+ function emitOrgSafeCreated(telemetry, input) {
1568
+ return emitOrgTelemetry(telemetry, {
1569
+ name: "org_safe_created",
1570
+ props: {
1571
+ org_id: input.orgId,
1572
+ safe_address: input.safeAddress,
1573
+ ...chainIdProp(input.chainId)
1574
+ }
1575
+ });
1576
+ }
1577
+ function emitOrgSafeConfirmed(telemetry, input) {
1578
+ return emitOrgTelemetry(telemetry, {
1579
+ name: "org_safe_confirmed",
1580
+ props: {
1581
+ org_id: input.orgId,
1582
+ safe_address: input.safeAddress,
1583
+ ...chainIdProp(input.chainId)
1584
+ }
1585
+ });
1586
+ }
1587
+ function emitOrgRolesSeeded(telemetry, input) {
1588
+ return emitOrgTelemetry(telemetry, {
1589
+ name: "org_roles_seeded",
1590
+ props: {
1591
+ org_id: input.orgId,
1592
+ role: input.role
1593
+ }
1594
+ });
1595
+ }
1596
+ function emitOrgCreated(telemetry, input) {
1597
+ return emitOrgTelemetry(telemetry, {
1598
+ name: "org_created",
1599
+ props: {
1600
+ org_id: input.orgId,
1601
+ safe_address: input.safeAddress,
1602
+ ...chainIdProp(input.chainId)
1603
+ }
1604
+ });
1605
+ }
1606
+ function emitOrgCreateFailed(telemetry, reason) {
1607
+ return emitOrgTelemetry(telemetry, {
1608
+ name: "org_create_failed",
1609
+ props: { reason }
1610
+ });
1611
+ }
1612
+ function emitOrgInviteSent(telemetry, input) {
1613
+ const domain = emailDomain(input.email);
1614
+ return emitOrgTelemetry(telemetry, {
1615
+ name: "org_invite_sent",
1616
+ props: {
1617
+ org_id: input.orgId,
1618
+ ...domain === void 0 ? {} : { email_domain: domain },
1619
+ role: input.role,
1620
+ status: input.status
1621
+ }
1622
+ });
1623
+ }
1624
+ function orgSpendProps(input) {
1625
+ return {
1626
+ org_id: input.orgId,
1627
+ amount: input.amountRaw,
1628
+ currency: input.currency,
1629
+ sub_account_id: input.subAccountId,
1630
+ recipient: input.recipient,
1631
+ ...input.role === void 0 ? {} : { role: input.role },
1632
+ ...input.reason === void 0 ? {} : { reason: input.reason },
1633
+ ...input.txHash === void 0 ? {} : { txHash: input.txHash }
1634
+ };
1635
+ }
1636
+ function emitOrgSpendStarted(telemetry, input) {
1637
+ return emitOrgTelemetry(telemetry, {
1638
+ name: "org_spend_started",
1639
+ props: orgSpendProps(input)
1640
+ });
1641
+ }
1642
+ function emitOrgSpendAuthorized(telemetry, input) {
1643
+ return emitOrgTelemetry(telemetry, {
1644
+ name: "org_spend_authorized",
1645
+ props: orgSpendProps(input)
1646
+ });
1647
+ }
1648
+ function emitOrgSpendSubmitted(telemetry, input) {
1649
+ return emitOrgTelemetry(telemetry, {
1650
+ name: "org_spend_submitted",
1651
+ props: orgSpendProps(input)
1652
+ });
1653
+ }
1654
+ function emitOrgSpendConfirmed(telemetry, input) {
1655
+ return emitOrgTelemetry(telemetry, {
1656
+ name: "org_spend_confirmed",
1657
+ props: orgSpendProps(input)
1658
+ });
1659
+ }
1660
+ function emitOrgSpendRejected(telemetry, input) {
1661
+ return emitOrgTelemetry(telemetry, {
1662
+ name: "org_spend_rejected",
1663
+ props: orgSpendProps(input)
1664
+ });
1665
+ }
1666
+ function reportOrgTelemetryFailure(kind, name, cause) {
1667
+ if (!isOrgTelemetryDebugEnabled()) return;
1668
+ globalThis.console?.warn?.("[capxul] org telemetry dropped", {
1669
+ kind,
1670
+ name,
1671
+ cause
1672
+ });
1673
+ }
1674
+ function isOrgTelemetryDebugEnabled() {
1675
+ return globalThis.process?.env?.CAPXUL_DEBUG_TELEMETRY === "1";
1676
+ }
1677
+ //#endregion
1678
+ //#region src/client/org-spend-gate.ts
1679
+ function evaluateSpendGate(input) {
1680
+ if (!input.activeMember) return reject("not_member", Errors.invalidInput("member", "you are not an active member"));
1681
+ if (!recipientAllowed(input.recipients, input.recipient)) return reject("invalid_recipient", Errors.invalidRecipient("recipient is not allowed by this role"));
1682
+ if (!subAccountAllowed(input.subAccounts, input.subAccountId)) return reject("wrong_envelope", Errors.invalidInput("subAccountId", "sub-account not in scope for this role"));
1683
+ const amount = parseRaw(input.amountRaw, "amountRaw");
1684
+ const balance = parseRaw(input.subAccountBalanceRaw, "subAccountBalanceRaw");
1685
+ if (amount > balance) return reject("insufficient_subaccount_balance", Errors.insufficientBalance(input.currency, balance.toString(10), amount.toString(10)));
1686
+ const perTxCap = parseOptionalRaw(input.perTxCapRaw, "perTxCapRaw");
1687
+ if (perTxCap !== null && amount > perTxCap) return reject("over_cap", Errors.insufficientBalance("role per-transaction cap", perTxCap.toString(10), amount.toString(10)));
1688
+ const perDayCap = parseOptionalRaw(input.perDayCapRaw, "perDayCapRaw");
1689
+ if (perDayCap !== null) {
1690
+ const remaining = perDayCap - (parseOptionalRaw(input.spentTodayRaw, "spentTodayRaw") ?? 0n);
1691
+ if (remaining < amount) return reject("daily_cap_exhausted", Errors.insufficientBalance("role daily cap", remaining.toString(10), amount.toString(10)));
1692
+ }
1693
+ return { ok: true };
1694
+ }
1695
+ function reject(reason, error) {
1696
+ return {
1697
+ ok: false,
1698
+ reason,
1699
+ error
1700
+ };
1701
+ }
1702
+ function recipientAllowed(recipients, recipient) {
1703
+ if (recipients === "anyone") return true;
1704
+ const normalized = recipient.toLowerCase();
1705
+ return recipients.some((allowed) => allowed.toLowerCase() === normalized);
1706
+ }
1707
+ function subAccountAllowed(scope, subAccountId) {
1708
+ if (scope.scope === "all") return true;
1709
+ return scope.subAccountIds.includes(subAccountId);
1710
+ }
1711
+ function parseOptionalRaw(value, field) {
1712
+ if (value === null || value === void 0) return null;
1713
+ return parseRaw(value, field);
1714
+ }
1715
+ function parseRaw(value, field) {
1716
+ if (!/^[0-9]+$/.test(value)) throw Errors.invalidInput(field, "must be a non-negative integer string");
1717
+ return BigInt(value);
1718
+ }
1719
+ //#endregion
1720
+ //#region src/client/org-deps.ts
1721
+ var OrgDepsTag = class extends Context.Tag("@capxul/sdk/OrgDeps")() {};
1722
+ function orgDepsLayer(deps) {
1723
+ return Layer.succeed(OrgDepsTag, deps);
1724
+ }
1725
+ function isHermeticOrgDeps(deps) {
1726
+ return deps.orgPort === void 0 && deps.orgRolesDeploymentPort === void 0 && deps.orgSpendPort === void 0;
1727
+ }
1728
+ function missingLiveOrgDep(portName) {
1729
+ return Errors.invalidInput("orgDeps", `${portName} is required in live org mode`);
1730
+ }
1731
+ /** Zero `Money` in the USDX-backed display currency (a fresh Org's treasury). */
1732
+ function zeroMoney() {
1733
+ return fromWei("0", USDX_DECIMALS, USDX_CURRENCY);
1734
+ }
1735
+ /** A fresh Org's treasury Account: `$0` balance, `available === balance`. */
1736
+ function zeroTreasury(orgId) {
1737
+ const balance = zeroMoney();
1738
+ return {
1739
+ id: toAccountId(`account_${stripPrefix(orgId)}`),
1740
+ balance,
1741
+ available: balance
1742
+ };
1743
+ }
1744
+ /** Drop a known `<prefix>_` so the remainder is reusable as another brand seed. */
1745
+ function stripPrefix(value) {
1746
+ const underscore = value.indexOf("_");
1747
+ const cleaned = (underscore < 0 ? value : value.slice(underscore + 1)).replace(/[^0-9A-Za-z]/g, "");
1748
+ return cleaned.length > 0 ? cleaned : "0";
1749
+ }
1750
+ /** Map an arbitrary string deterministically into lowercase hex chars. */
1751
+ function toHexSeed(value) {
1752
+ let out = "";
1753
+ for (const ch of value) out += (ch.codePointAt(0) ?? 0).toString(16).padStart(2, "0");
1754
+ return out.length > 0 ? out : "0";
1755
+ }
1756
+ /**
1757
+ * Build the hermetic `OrgView` for the no-port L1 path: a deterministic
1758
+ * counterfactual-shaped placeholder Org Safe + a `$0` treasury (D3). The live
1759
+ * path replaces this with the real deployed address + RPC balance.
1760
+ */
1761
+ function hermeticOrgView(input) {
1762
+ const orgId = toOrgId(`org_${stripPrefix(`x_${input.handle}`)}`);
1763
+ const placeholder = `0x${toHexSeed(input.handle).padEnd(40, "0").slice(0, 40)}`;
1764
+ return {
1765
+ id: orgId,
1766
+ name: input.name,
1767
+ handle: input.handle,
1768
+ safeAddress: toAddress(placeholder),
1769
+ role: "Owner",
1770
+ treasury: zeroTreasury(orgId)
1771
+ };
1772
+ }
1773
+ function moneyFromConfig(input) {
1774
+ return {
1775
+ currency: toCurrencyCode(input.currency),
1776
+ value: input.value,
1777
+ decimals: input.decimals
1778
+ };
1779
+ }
1780
+ function recipientsFromConfig(toRecipients) {
1781
+ if (toRecipients === void 0 || toRecipients === "anyone") return toRecipients;
1782
+ return toRecipients.map((recipient) => toAddress(recipient));
1783
+ }
1784
+ function subAccountsFromConfig(subAccounts) {
1785
+ if (subAccounts === void 0) return void 0;
1786
+ if (subAccounts.scope === "all") return { scope: "all" };
1787
+ return { scope: subAccounts.scope.map((subAccountId) => toSubAccountId(subAccountId)) };
1788
+ }
1789
+ function roleDefinitionFromConfig(definition) {
1790
+ const toRecipients = recipientsFromConfig(definition.spend?.toRecipients);
1791
+ const subAccounts = subAccountsFromConfig(definition.subAccounts);
1792
+ return {
1793
+ label: definition.label,
1794
+ ...definition.spend === void 0 ? {} : { spend: {
1795
+ ...definition.spend.perTx === void 0 ? {} : { perTx: moneyFromConfig(definition.spend.perTx) },
1796
+ ...definition.spend.perDay === void 0 ? {} : { perDay: moneyFromConfig(definition.spend.perDay) },
1797
+ ...toRecipients === void 0 ? {} : { toRecipients }
1798
+ } },
1799
+ ...subAccounts === void 0 ? {} : { subAccounts },
1800
+ ...definition.canManageMembers === void 0 ? {} : { canManageMembers: definition.canManageMembers },
1801
+ ...definition.canManageRoles === void 0 ? {} : { canManageRoles: definition.canManageRoles }
1802
+ };
1803
+ }
1804
+ function startupRoleViews(orgId) {
1805
+ return compileOrgRoleDefinitions(orgRoleTemplateDefinitions("Startup")).roles.map((role) => ({
1806
+ orgId,
1807
+ label: role.label,
1808
+ roleKey: toRoleKey(role.roleKey),
1809
+ definition: roleDefinitionFromConfig(role.definition)
1810
+ }));
1811
+ }
1812
+ function hermeticMember(input) {
1813
+ return {
1814
+ orgId: input.orgId,
1815
+ email: toEmail(input.email),
1816
+ name: null,
1817
+ personalSafeAddress: input.personalSafeAddress ?? null,
1818
+ role: input.role,
1819
+ roleKey: toRoleKey(orgRoleKeyForLabel(input.role)),
1820
+ status: input.status,
1821
+ grantTxHash: input.grantTxHash ?? null,
1822
+ revokeTxHash: input.revokeTxHash ?? null
1823
+ };
1824
+ }
1825
+ function hermeticSpendAuthority(input) {
1826
+ return {
1827
+ activeMember: true,
1828
+ subAccountBalanceRaw: "100000000000",
1829
+ recipients: "anyone",
1830
+ subAccounts: {
1831
+ scope: "only",
1832
+ subAccountIds: [input.from]
1833
+ },
1834
+ perTxCapRaw: "25000000000",
1835
+ perDayCapRaw: "100000000000",
1836
+ spentTodayRaw: "0",
1837
+ role: "Finance Manager"
1838
+ };
1839
+ }
1840
+ function hermeticSpendResult(orgId, input) {
1841
+ return { txHash: `0x${toHexSeed(`${orgId}:${input.from}:${input.to}:${input.amount.value}`).padEnd(64, "0").slice(0, 64)}` };
1842
+ }
1843
+ function spendTelemetryInput(input) {
1844
+ return {
1845
+ orgId: input.orgId,
1846
+ amountRaw: input.amountRaw,
1847
+ currency: input.currency,
1848
+ subAccountId: input.spend.from,
1849
+ recipient: input.spend.to,
1850
+ ...input.authority?.role === void 0 ? {} : { role: input.authority.role },
1851
+ ...input.reason === void 0 ? {} : { reason: input.reason },
1852
+ ...input.txHash === void 0 ? {} : { txHash: input.txHash }
1853
+ };
1854
+ }
1855
+ function spendGateInput(input) {
1856
+ return {
1857
+ activeMember: input.authority.activeMember,
1858
+ subAccountId: input.spend.from,
1859
+ subAccountBalanceRaw: input.authority.subAccountBalanceRaw,
1860
+ amountRaw: input.amountRaw,
1861
+ currency: input.currency,
1862
+ recipient: input.spend.to,
1863
+ recipients: input.authority.recipients,
1864
+ subAccounts: input.authority.subAccounts,
1865
+ ...input.authority.perTxCapRaw === void 0 ? {} : { perTxCapRaw: input.authority.perTxCapRaw },
1866
+ ...input.authority.perDayCapRaw === void 0 ? {} : { perDayCapRaw: input.authority.perDayCapRaw },
1867
+ ...input.authority.spentTodayRaw === void 0 ? {} : { spentTodayRaw: input.authority.spentTodayRaw }
1868
+ };
1869
+ }
1870
+ function createOrgProgram(input) {
1871
+ return Effect.gen(function* () {
1872
+ const deps = yield* OrgDepsTag;
1873
+ const chainId = deps.chainId;
1874
+ yield* Effect.promise(() => emitOrgCreateStarted(deps.telemetry, { template: input.template }));
1875
+ return yield* Effect.gen(function* () {
1876
+ if (deps.orgPort !== void 0) {
1877
+ const org = yield* deps.orgPort.createOrg({ input }).pipe(Effect.mapError((error) => error.publicError));
1878
+ yield* emitCreationFunnelTail(deps.telemetry, org, chainId);
1879
+ return org;
1880
+ }
1881
+ const org = hermeticOrgView(input);
1882
+ yield* emitCreationFunnelTail(deps.telemetry, org, chainId);
1883
+ return org;
1884
+ }).pipe(Effect.tapError((error) => Effect.promise(() => emitOrgCreateFailed(deps.telemetry, error.code))));
1885
+ });
1886
+ }
1887
+ /** Emit the remaining `org_creation` funnel steps once the org is built. */
1888
+ function emitCreationFunnelTail(telemetry, org, chainId) {
1889
+ return Effect.promise(async () => {
1890
+ const chain = chainId === void 0 ? {} : { chainId };
1891
+ await emitOrgSafeCreated(telemetry, {
1892
+ orgId: org.id,
1893
+ safeAddress: org.safeAddress,
1894
+ ...chain
1895
+ });
1896
+ await emitOrgSafeConfirmed(telemetry, {
1897
+ orgId: org.id,
1898
+ safeAddress: org.safeAddress,
1899
+ ...chain
1900
+ });
1901
+ await emitOrgRolesSeeded(telemetry, {
1902
+ orgId: org.id,
1903
+ role: org.role
1904
+ });
1905
+ await emitOrgCreated(telemetry, {
1906
+ orgId: org.id,
1907
+ safeAddress: org.safeAddress,
1908
+ ...chain
1909
+ });
1910
+ });
1911
+ }
1912
+ function readTreasuryProgram(orgId) {
1913
+ return Effect.gen(function* () {
1914
+ const deps = yield* OrgDepsTag;
1915
+ if (deps.orgPort !== void 0) return yield* deps.orgPort.readTreasury({ orgId }).pipe(Effect.mapError((error) => error.publicError));
1916
+ return zeroTreasury(orgId);
1917
+ });
1918
+ }
1919
+ function listRolesProgram(orgId) {
1920
+ return Effect.gen(function* () {
1921
+ const deps = yield* OrgDepsTag;
1922
+ if (deps.orgPort !== void 0) return yield* deps.orgPort.listRoles({ orgId }).pipe(Effect.mapError((error) => error.publicError));
1923
+ return startupRoleViews(orgId);
1924
+ });
1925
+ }
1926
+ function deployRolesProgram(orgId) {
1927
+ return Effect.gen(function* () {
1928
+ const deps = yield* OrgDepsTag;
1929
+ if (deps.orgRolesDeploymentPort !== void 0) return (yield* deps.orgRolesDeploymentPort.deployRoles({ orgId }).pipe(Effect.mapError((error) => error.publicError))).roles;
1930
+ if (!isHermeticOrgDeps(deps)) return yield* Effect.fail(missingLiveOrgDep("orgRolesDeploymentPort"));
1931
+ return startupRoleViews(orgId);
1932
+ });
1933
+ }
1934
+ function listMembersProgram(orgId) {
1935
+ return Effect.gen(function* () {
1936
+ const deps = yield* OrgDepsTag;
1937
+ if (deps.orgPort !== void 0) return yield* deps.orgPort.listMembers({ orgId }).pipe(Effect.mapError((error) => error.publicError));
1938
+ return [];
1939
+ });
1940
+ }
1941
+ function inviteMemberProgram(orgId, input) {
1942
+ return Effect.gen(function* () {
1943
+ const deps = yield* OrgDepsTag;
1944
+ const member = deps.orgPort !== void 0 ? yield* deps.orgPort.inviteMember({
1945
+ orgId,
1946
+ input
1947
+ }).pipe(Effect.mapError((error) => error.publicError)) : hermeticMember({
1948
+ orgId,
1949
+ email: input.email,
1950
+ role: input.role,
1951
+ status: "pending"
1952
+ });
1953
+ yield* Effect.promise(() => emitOrgInviteSent(deps.telemetry, {
1954
+ orgId,
1955
+ email: input.email,
1956
+ role: member.role,
1957
+ status: member.status
1958
+ }));
1959
+ return member;
1960
+ });
1961
+ }
1962
+ function detectAndAcceptPendingInvitationsProgram() {
1963
+ return Effect.gen(function* () {
1964
+ const deps = yield* OrgDepsTag;
1965
+ if (deps.orgPort !== void 0) return yield* deps.orgPort.detectAndAcceptPendingInvitations({}).pipe(Effect.mapError((error) => error.publicError));
1966
+ return { matched: [] };
1967
+ });
1968
+ }
1969
+ function assignRoleProgram(orgId, input) {
1970
+ return Effect.gen(function* () {
1971
+ const deps = yield* OrgDepsTag;
1972
+ if (deps.orgRolesDeploymentPort !== void 0) return yield* deps.orgRolesDeploymentPort.grantRole({
1973
+ orgId,
1974
+ input
1975
+ }).pipe(Effect.mapError((error) => error.publicError));
1976
+ if (!isHermeticOrgDeps(deps)) return yield* Effect.fail(missingLiveOrgDep("orgRolesDeploymentPort"));
1977
+ return hermeticMember({
1978
+ orgId,
1979
+ email: "member@example.com",
1980
+ role: input.role,
1981
+ status: "active",
1982
+ personalSafeAddress: input.memberSafeAddress,
1983
+ grantTxHash: `0x${"0".repeat(64)}`
1984
+ });
1985
+ });
1986
+ }
1987
+ function removeMemberProgram(orgId, input) {
1988
+ return Effect.gen(function* () {
1989
+ const deps = yield* OrgDepsTag;
1990
+ if (deps.orgRolesDeploymentPort !== void 0) return yield* deps.orgRolesDeploymentPort.revokeRole({
1991
+ orgId,
1992
+ input
1993
+ }).pipe(Effect.mapError((error) => error.publicError));
1994
+ if (!isHermeticOrgDeps(deps)) return yield* Effect.fail(missingLiveOrgDep("orgRolesDeploymentPort"));
1995
+ });
1996
+ }
1997
+ function spendProgram(orgId, input) {
1998
+ return Effect.gen(function* () {
1999
+ const deps = yield* OrgDepsTag;
2000
+ const amountRaw = yield* Effect.try({
2001
+ try: () => toWei(input.amount),
2002
+ catch: (cause) => Errors.invalidInput("amount", cause instanceof Error ? cause.message : "invalid money")
2003
+ });
2004
+ const currency = String(input.amount.currency);
2005
+ yield* Effect.promise(() => emitOrgSpendStarted(deps.telemetry, {
2006
+ orgId,
2007
+ amountRaw,
2008
+ currency,
2009
+ subAccountId: input.from,
2010
+ recipient: input.to
2011
+ }));
2012
+ if (deps.orgSpendPort === void 0 && !isHermeticOrgDeps(deps)) return yield* Effect.fail(missingLiveOrgDep("orgSpendPort"));
2013
+ const authority = deps.orgSpendPort === void 0 ? hermeticSpendAuthority(input) : yield* deps.orgSpendPort.readSpendAuthority({
2014
+ orgId,
2015
+ input,
2016
+ amountRaw
2017
+ }).pipe(Effect.mapError((error) => error.publicError));
2018
+ const decision = yield* Effect.try({
2019
+ try: () => evaluateSpendGate(spendGateInput({
2020
+ authority,
2021
+ spend: input,
2022
+ amountRaw,
2023
+ currency
2024
+ })),
2025
+ catch: (cause) => isCapxulError(cause) ? cause : Errors.unknown(cause)
2026
+ });
2027
+ if (!decision.ok) {
2028
+ yield* Effect.promise(() => emitOrgSpendRejected(deps.telemetry, spendTelemetryInput({
2029
+ orgId,
2030
+ amountRaw,
2031
+ currency,
2032
+ spend: input,
2033
+ authority,
2034
+ reason: decision.reason
2035
+ })));
2036
+ return yield* Effect.fail(decision.error);
2037
+ }
2038
+ yield* Effect.promise(() => emitOrgSpendAuthorized(deps.telemetry, spendTelemetryInput({
2039
+ orgId,
2040
+ amountRaw,
2041
+ currency,
2042
+ spend: input,
2043
+ authority
2044
+ })));
2045
+ const result = deps.orgSpendPort === void 0 ? hermeticSpendResult(orgId, input) : yield* deps.orgSpendPort.submitSpend({
2046
+ orgId,
2047
+ input,
2048
+ amountRaw,
2049
+ authority
2050
+ }).pipe(Effect.mapError((error) => error.publicError), Effect.tapError((error) => Effect.promise(() => emitOrgSpendRejected(deps.telemetry, spendTelemetryInput({
2051
+ orgId,
2052
+ amountRaw,
2053
+ currency,
2054
+ spend: input,
2055
+ authority,
2056
+ reason: error.code
2057
+ })))));
2058
+ yield* Effect.promise(() => emitOrgSpendSubmitted(deps.telemetry, spendTelemetryInput({
2059
+ orgId,
2060
+ amountRaw,
2061
+ currency,
2062
+ spend: input,
2063
+ authority,
2064
+ txHash: result.txHash
2065
+ })));
2066
+ yield* Effect.promise(() => emitOrgSpendConfirmed(deps.telemetry, spendTelemetryInput({
2067
+ orgId,
2068
+ amountRaw,
2069
+ currency,
2070
+ spend: input,
2071
+ authority,
2072
+ txHash: result.txHash
2073
+ })));
2074
+ return result;
2075
+ });
2076
+ }
2077
+ function listOrgsProgram() {
2078
+ return Effect.gen(function* () {
2079
+ const deps = yield* OrgDepsTag;
2080
+ if (deps.orgPort !== void 0) return yield* deps.orgPort.listOrgs({}).pipe(Effect.mapError((error) => error.publicError));
2081
+ return [];
2082
+ });
2083
+ }
2084
+ //#endregion
2085
+ //#region src/client/org.ts
2086
+ /**
2087
+ * Org method surface (canon §C2/§C3, D13). S1 (#274) wires `createOrg` /
2088
+ * `orgs` / `treasury` to their Effect programs (`org-deps.ts`); the S2→S4
2089
+ * member/role/spend verbs stay `Errors.notImplemented("org", "<verb>")` until
2090
+ * their slices land. The entity-scoped bundle is constructed per `org(orgId)`
2091
+ * call (D13 — explicit scoping, no shared mutable "active org" state); the
2092
+ * closed-over `orgId` is the only entity reference.
2093
+ */
2094
+ function makeOrgMethods(deps) {
2095
+ const layer = orgDepsLayer({
2096
+ ...deps.orgPort === void 0 ? {} : { orgPort: deps.orgPort },
2097
+ ...deps.orgRolesDeploymentPort === void 0 ? {} : { orgRolesDeploymentPort: deps.orgRolesDeploymentPort },
2098
+ ...deps.orgSpendPort === void 0 ? {} : { orgSpendPort: deps.orgSpendPort },
2099
+ ...deps.chainId === void 0 ? {} : { chainId: deps.chainId },
2100
+ ...deps.telemetry === void 0 ? {} : { telemetry: deps.telemetry }
2101
+ });
2102
+ return {
2103
+ createOrg(input, options) {
2104
+ if (options?.signal?.aborted) return Promise.resolve({
2105
+ ok: false,
2106
+ error: Errors.cancelled({ operation: "org.createOrg" })
2107
+ });
2108
+ return toCapxulResult(createOrgProgram(input), layer);
2109
+ },
2110
+ orgs: Object.assign((options) => {
2111
+ if (options?.signal?.aborted) return Promise.resolve({
2112
+ ok: false,
2113
+ error: Errors.cancelled({ operation: "org.orgs" })
2114
+ });
2115
+ return toCapxulResult(listOrgsProgram(), layer);
2116
+ }, { detectAndAcceptPendingInvitations(options) {
2117
+ if (options?.signal?.aborted) return Promise.resolve({
2118
+ ok: false,
2119
+ error: Errors.cancelled({ operation: "orgs.detectAndAcceptPendingInvitations" })
2120
+ });
2121
+ return toCapxulResult(detectAndAcceptPendingInvitationsProgram(), layer);
2122
+ } }),
2123
+ org(orgId) {
2124
+ return {
2125
+ treasury(options) {
2126
+ if (options?.signal?.aborted) return Promise.resolve({
2127
+ ok: false,
2128
+ error: Errors.cancelled({ operation: "org.treasury" })
2129
+ });
2130
+ return toCapxulResult(readTreasuryProgram(orgId), layer);
2131
+ },
2132
+ members(_options) {
2133
+ if (_options?.signal?.aborted) return Promise.resolve({
2134
+ ok: false,
2135
+ error: Errors.cancelled({ operation: "org.members" })
2136
+ });
2137
+ return toCapxulResult(listMembersProgram(orgId), layer);
2138
+ },
2139
+ roles(_options) {
2140
+ if (_options?.signal?.aborted) return Promise.resolve({
2141
+ ok: false,
2142
+ error: Errors.cancelled({ operation: "org.roles" })
2143
+ });
2144
+ return toCapxulResult(listRolesProgram(orgId), layer);
2145
+ },
2146
+ deployRoles(_options) {
2147
+ if (_options?.signal?.aborted) return Promise.resolve({
2148
+ ok: false,
2149
+ error: Errors.cancelled({ operation: "org.deployRoles" })
2150
+ });
2151
+ return toCapxulResult(deployRolesProgram(orgId), layer);
2152
+ },
2153
+ invite(_input, _options) {
2154
+ if (_options?.signal?.aborted) return Promise.resolve({
2155
+ ok: false,
2156
+ error: Errors.cancelled({ operation: "org.invite" })
2157
+ });
2158
+ return toCapxulResult(inviteMemberProgram(orgId, _input), layer);
2159
+ },
2160
+ removeMember(_input, _options) {
2161
+ if (_options?.signal?.aborted) return Promise.resolve({
2162
+ ok: false,
2163
+ error: Errors.cancelled({ operation: "org.removeMember" })
2164
+ });
2165
+ return toCapxulResult(removeMemberProgram(orgId, _input), layer);
2166
+ },
2167
+ assignRole(_input, _options) {
2168
+ if (_options?.signal?.aborted) return Promise.resolve({
2169
+ ok: false,
2170
+ error: Errors.cancelled({ operation: "org.assignRole" })
2171
+ });
2172
+ return toCapxulResult(assignRoleProgram(orgId, _input), layer);
2173
+ },
2174
+ spend(_input, _options) {
2175
+ if (_options?.signal?.aborted) return Promise.resolve({
2176
+ ok: false,
2177
+ error: Errors.cancelled({ operation: "org.spend" })
2178
+ });
2179
+ return toCapxulResult(spendProgram(orgId, _input), layer);
2180
+ }
2181
+ };
2182
+ }
2183
+ };
2184
+ }
2185
+ //#endregion
2186
+ //#region src/client/factory.ts
2187
+ function detectAuthCacheAdapter() {
2188
+ const globalAny = globalThis;
2189
+ if (globalAny.window?.localStorage !== void 0) return new BrowserAuthCacheAdapter(globalAny.window.localStorage);
2190
+ return new InMemoryAuthCacheAdapter();
2191
+ }
2192
+ //#endregion
2193
+ //#region src/client/create-capxul-client.ts
2194
+ function assembleCapxulClient(input) {
2195
+ const authCache = input.authCache ?? detectAuthCacheAdapter();
2196
+ const layer = Layer.mergeAll(Layer.succeed(AuthClientPortTag, input.ports.authClient), Layer.succeed(ClockPortTag, input.ports.clock), Layer.succeed(TelemetryPortTag, input.ports.telemetry));
2197
+ const authFlowInput = input.otpTtlMs === void 0 ? {} : { otpTtlMs: input.otpTtlMs };
2198
+ const actor = Effect.runSync(bootAuthFlow(createAuthFlowMachine(), authFlowInput).pipe(Effect.provide(layer)));
2199
+ if (input.signal !== void 0) input.signal.addEventListener("abort", () => actor.stop(), { once: true });
2200
+ const selectedOrgPort = input.orgPort ?? input.orgDeploymentPort;
2201
+ let detectPendingOrgInvitations;
2202
+ const auth = makeAuthMethods({
2203
+ actor,
2204
+ authClient: input.ports.authClient,
2205
+ authCache,
2206
+ clock: input.ports.clock,
2207
+ telemetry: input.ports.telemetry,
2208
+ ...input.otpTtlMs === void 0 ? {} : { otpTtlMs: input.otpTtlMs },
2209
+ ...input.invokeTimeoutMs === void 0 ? {} : { invokeTimeoutMs: input.invokeTimeoutMs },
2210
+ ...selectedOrgPort === void 0 ? {} : { afterVerifyOtp: async () => {
2211
+ await detectPendingOrgInvitations?.();
2212
+ } }
2213
+ });
2214
+ const smartAccount = makeSmartAccountMethods({
2215
+ actor,
2216
+ smartAccountPort: input.ports.smartAccount,
2217
+ chainId: input.bootstrap.chainId,
2218
+ sessionAuthUserIdFallback: null,
2219
+ telemetry: input.ports.telemetry
2220
+ });
2221
+ const identity = makeIdentityMethods({
2222
+ identityPort: input.ports.identity,
2223
+ actor
2224
+ });
2225
+ const account = makeAccountMethods({
2226
+ actor,
2227
+ authCache,
2228
+ identityPort: input.ports.identity,
2229
+ smartAccountPort: input.ports.smartAccount,
2230
+ telemetry: input.ports.telemetry,
2231
+ chainId: input.bootstrap.chainId,
2232
+ requirement: input.requirement,
2233
+ ...input.signer === void 0 ? {} : { signer: input.signer }
2234
+ });
2235
+ const accounts = makeAccountsMethods({
2236
+ accountReadPort: input.ports.accountRead,
2237
+ chainId: input.bootstrap.chainId,
2238
+ telemetry: input.ports.telemetry
2239
+ });
2240
+ const subAccounts = makeSubAccountsMethods({
2241
+ subAccountPort: input.ports.subAccount,
2242
+ telemetry: input.ports.telemetry
2243
+ });
2244
+ const orgMethods = makeOrgMethods({
2245
+ chainId: input.bootstrap.chainId,
2246
+ telemetry: input.ports.telemetry,
2247
+ ...selectedOrgPort === void 0 ? {} : { orgPort: selectedOrgPort },
2248
+ ...input.orgRolesDeploymentPort === void 0 ? {} : { orgRolesDeploymentPort: input.orgRolesDeploymentPort },
2249
+ ...input.orgSpendPort === void 0 ? {} : { orgSpendPort: input.orgSpendPort }
2250
+ });
2251
+ if (selectedOrgPort !== void 0) detectPendingOrgInvitations = async () => {
2252
+ await orgMethods.orgs.detectAndAcceptPendingInvitations();
2253
+ };
2254
+ return {
2255
+ auth,
2256
+ smartAccount,
2257
+ identity,
2258
+ account,
2259
+ accounts,
2260
+ subAccounts,
2261
+ createOrg: orgMethods.createOrg,
2262
+ orgs: orgMethods.orgs,
2263
+ org: orgMethods.org,
2264
+ bootstrap: input.bootstrap,
2265
+ _internal: {
2266
+ authActor: {
2267
+ input: actor.input,
2268
+ getSnapshot: actor.getSnapshot,
2269
+ stop: actor.stop
2270
+ },
2271
+ accounts: { fund: accounts.fund }
2272
+ }
2273
+ };
2274
+ }
2275
+ //#endregion
2276
+ //#region src/client/account-providers.ts
2277
+ function localPrivateKeyAccountProvider(input) {
2278
+ const account = privateKeyToAccount(input.privateKey);
2279
+ const address = toAddress(account.address);
2280
+ return {
2281
+ source: "local-private-key",
2282
+ async getAddress() {
2283
+ return {
2284
+ ok: true,
2285
+ value: address
2286
+ };
2287
+ },
2288
+ async getDeployAccount() {
2289
+ return {
2290
+ ok: true,
2291
+ value: account
2292
+ };
2293
+ }
2294
+ };
2295
+ }
2296
+ function eip1193AccountProvider(input) {
2297
+ let cachedAddress = null;
2298
+ let inFlight = null;
2299
+ const getAddress = async () => {
2300
+ if (cachedAddress !== null) return {
2301
+ ok: true,
2302
+ value: cachedAddress
2303
+ };
2304
+ if (inFlight !== null) return inFlight;
2305
+ inFlight = (async () => {
2306
+ try {
2307
+ const first = firstAccount(await input.provider.request({ method: "eth_accounts" }));
2308
+ if (first === null) return {
2309
+ ok: false,
2310
+ error: Errors.smartAccountMissing("eip1193-account")
2311
+ };
2312
+ const address = toAddress(first);
2313
+ cachedAddress = address;
2314
+ return {
2315
+ ok: true,
2316
+ value: address
2317
+ };
2318
+ } catch (err) {
2319
+ return {
2320
+ ok: false,
2321
+ error: Errors.providerError("eip1193", "eth_accounts", err)
2322
+ };
2323
+ } finally {
2324
+ inFlight = null;
2325
+ }
2326
+ })();
2327
+ return inFlight;
2328
+ };
2329
+ return {
2330
+ source: "injected-eip1193",
2331
+ getAddress,
2332
+ async getDeployAccount() {
2333
+ return {
2334
+ ok: false,
2335
+ error: Errors.notImplemented("Eip1193AccountProvider", "getDeployAccount")
2336
+ };
2337
+ }
2338
+ };
2339
+ }
2340
+ function openfortEmbeddedAccountProvider() {
2341
+ return {
2342
+ source: "openfort-embedded",
2343
+ async getAddress() {
2344
+ return {
2345
+ ok: false,
2346
+ error: Errors.notImplemented("OpenfortAccountProvider", "getAddress")
2347
+ };
2348
+ },
2349
+ async getDeployAccount() {
2350
+ return {
2351
+ ok: false,
2352
+ error: Errors.notImplemented("OpenfortAccountProvider", "getDeployAccount")
2353
+ };
2354
+ }
2355
+ };
2356
+ }
2357
+ function firstAccount(value) {
2358
+ if (!Array.isArray(value)) return null;
2359
+ const first = value[0];
2360
+ return typeof first === "string" ? first : null;
2361
+ }
2362
+ //#endregion
2363
+ //#region src/signer.ts
2364
+ const EVM_ADDRESS_HEX = /^0x[0-9a-fA-F]{40}$/;
2365
+ const ECDSA_SIGNATURE_HEX = /^0x[0-9a-fA-F]{130}$/;
2366
+ /**
2367
+ * Browser `CapxulSigner` backed by an injected EIP-1193 wallet (MetaMask, etc.).
2368
+ * Signs the SafeOp digest via `eth_sign` (raw-hash signing). The node key signer
2369
+ * lives in `@capxul/sdk/node` (`localPrivateKeySigner`). Wallets that disable
2370
+ * `eth_sign` must enable raw-hash signing before deployed-account flows run.
2371
+ */
2372
+ function injectedWalletSigner(provider) {
2373
+ const resolveAddress = async () => {
2374
+ const accounts = await provider.request({ method: "eth_requestAccounts" });
2375
+ const first = Array.isArray(accounts) ? accounts[0] : void 0;
2376
+ if (typeof first !== "string") throw new Error("injectedWalletSigner: wallet returned no accounts");
2377
+ if (!EVM_ADDRESS_HEX.test(first)) throw new Error("injectedWalletSigner: wallet returned invalid address format");
2378
+ return toAddress(first);
2379
+ };
2380
+ return {
2381
+ source: "injected-eip1193",
2382
+ getAddress: resolveAddress,
2383
+ async signUserOpHash(hash) {
2384
+ const address = await resolveAddress();
2385
+ let signature;
2386
+ try {
2387
+ signature = await provider.request({
2388
+ method: "eth_sign",
2389
+ params: [address, hash]
2390
+ });
2391
+ } catch (cause) {
2392
+ const detail = cause instanceof Error ? cause.message : String(cause);
2393
+ throw new Error(`injectedWalletSigner: eth_sign failed; enable raw-hash signing for deployment (${detail})`);
2394
+ }
2395
+ if (typeof signature !== "string") throw new Error("injectedWalletSigner: wallet returned a non-string signature");
2396
+ if (!ECDSA_SIGNATURE_HEX.test(signature)) throw new Error("injectedWalletSigner: wallet returned invalid signature format");
2397
+ return signature;
2398
+ }
2399
+ };
2400
+ }
2401
+ //#endregion
2402
+ //#region package.json
2403
+ var version = "0.2.0-alpha.5";
2404
+ //#endregion
2405
+ //#region src/adapters/auth-client/effect-port.ts
2406
+ function authClientPortFromPromiseAdapter(adapter) {
2407
+ return {
2408
+ canSendOtp: (input, options) => fromResult("canSendOtp", () => adapter.canSendOtp(input, options)),
2409
+ sendOtp: (input, options) => fromResult("sendOtp", () => adapter.sendOtp(input, options)),
2410
+ verifyOtp: (input, options) => fromResult("verifyOtp", () => adapter.verifyOtp(input, options)),
2411
+ getSession: (options) => fromResult("getSession", () => adapter.getSession(options)),
2412
+ signOut: (options) => fromResult("signOut", () => adapter.signOut(options)),
2413
+ getConvexJwt: (options) => fromResult("getConvexJwt", () => adapter.getConvexJwt(options))
2414
+ };
2415
+ }
2416
+ function fromResult(operation, run) {
2417
+ return Effect.tryPromise({
2418
+ try: run,
2419
+ catch: (cause) => new AuthClientError({
2420
+ operation,
2421
+ kind: "thrown",
2422
+ cause
2423
+ })
2424
+ }).pipe(Effect.flatMap((result) => result.ok ? Effect.succeed(result.value) : Effect.fail(new AuthClientError({
2425
+ operation,
2426
+ kind: errorKind(result.error),
2427
+ cause: result.error
2428
+ }))));
2429
+ }
2430
+ function errorKind(error) {
2431
+ if (error.code === "CANCELLED") return "cancelled";
2432
+ if (error.code === "NETWORK_ERROR") return "network";
2433
+ if (error.code === "INVALID_INPUT" || error.code === "OTP_EXPIRED") return "validation";
2434
+ return "provider";
2435
+ }
2436
+ //#endregion
2437
+ //#region src/adapters/auth-client/resolve-auth-url.ts
2438
+ /** Join bootstrap `authBaseUrl` with a BetterAuth route without duplicating `/api/auth`. */
2439
+ function resolveAuthClientUrl(authBaseUrl, path) {
2440
+ const base = authBaseUrl.replace(/\/$/, "");
2441
+ if (base.endsWith("/api/auth") && path.startsWith("/api/auth")) return `${base}${path.slice(9)}`;
2442
+ return `${base}${path}`;
2443
+ }
2444
+ //#endregion
2445
+ //#region src/adapters/auth-client/BetterAuthBrowserAdapter.ts
2446
+ function withSignal$1(init, signal) {
2447
+ return signal === void 0 ? init : {
2448
+ ...init,
2449
+ signal
2450
+ };
2451
+ }
2452
+ const DEFAULT_JWT_LIFETIME_S$1 = 900;
2453
+ function decodeJwtExp$1(jwt) {
2454
+ const parts = jwt.split(".");
2455
+ if (parts.length < 2 || parts[1] === void 0) return Math.floor(Date.now() / 1e3) + DEFAULT_JWT_LIFETIME_S$1;
2456
+ try {
2457
+ const raw = parts[1].replace(/\s+/g, "");
2458
+ const pad = "=".repeat((4 - raw.length % 4) % 4);
2459
+ const decoded = atob(raw.replace(/-/g, "+").replace(/_/g, "/") + pad);
2460
+ const payload = JSON.parse(decoded);
2461
+ if (typeof payload.exp === "number" && Number.isFinite(payload.exp) && payload.exp > 0) return payload.exp;
2462
+ } catch {}
2463
+ return Math.floor(Date.now() / 1e3) + DEFAULT_JWT_LIFETIME_S$1;
2464
+ }
2465
+ function authSessionFromBetterAuth$1(token, user) {
2466
+ return {
2467
+ authUserId: toAuthUserId(user.id),
2468
+ email: toEmail(user.email),
2469
+ token: toSessionToken(token),
2470
+ expiresAt: toEpochMs(Date.now() + 10080 * 60 * 1e3)
2471
+ };
2472
+ }
2473
+ async function safeJson$1(res) {
2474
+ const raw = await res.text();
2475
+ if (raw.length === 0 || raw === "null") return null;
2476
+ try {
2477
+ return JSON.parse(raw);
2478
+ } catch {
2479
+ return null;
2480
+ }
2481
+ }
2482
+ function mapBetterAuthError(operation, body) {
2483
+ if (typeof body === "object" && body !== null) {
2484
+ const errBody = body;
2485
+ const code = typeof errBody.code === "string" ? errBody.code : "";
2486
+ if (code === "OTP_EXPIRED") return Errors.otpExpired();
2487
+ if (code === "INVALID_OTP") return Errors.invalidInput("otp", errBody.message ?? "invalid OTP");
2488
+ if (code === "VALIDATION_ERROR" || code === "INVALID_EMAIL") return Errors.invalidInput("email", errBody.message ?? "invalid email");
2489
+ }
2490
+ return Errors.providerError("better-auth", operation, new Error(String(body)));
2491
+ }
2492
+ function isAbortError$1(err, signal) {
2493
+ return signal?.aborted === true || err instanceof Error && err.name === "AbortError" || typeof DOMException !== "undefined" && err instanceof DOMException && err.name === "AbortError";
2494
+ }
2495
+ function mapFetchError$1(operation, err, signal) {
2496
+ if (isAbortError$1(err, signal)) return Errors.cancelled({ operation });
2497
+ return Errors.networkError(operation, err instanceof Error ? err : new Error(String(err)));
2498
+ }
2499
+ var BetterAuthBrowserAdapter = class {
2500
+ authBaseUrl;
2501
+ fetchImpl;
2502
+ constructor(deps) {
2503
+ this.authBaseUrl = deps.authBaseUrl.replace(/\/$/, "");
2504
+ this.fetchImpl = deps.fetch ?? fetch;
2505
+ }
2506
+ url(path) {
2507
+ return resolveAuthClientUrl(this.authBaseUrl, path);
2508
+ }
2509
+ async canSendOtp(_input, options) {
2510
+ if (options?.signal?.aborted) return {
2511
+ ok: false,
2512
+ error: Errors.cancelled({ operation: "canSendOtp" })
2513
+ };
2514
+ return {
2515
+ ok: true,
2516
+ value: {
2517
+ allowed: true,
2518
+ cooldownMs: toDurationMs(0)
2519
+ }
2520
+ };
2521
+ }
2522
+ async sendOtp(input, options) {
2523
+ if (options?.signal?.aborted) return {
2524
+ ok: false,
2525
+ error: Errors.cancelled({ operation: "sendOtp" })
2526
+ };
2527
+ try {
2528
+ const res = await this.fetchImpl(this.url("/api/auth/email-otp/send-verification-otp"), withSignal$1({
2529
+ method: "POST",
2530
+ headers: { "Content-Type": "application/json" },
2531
+ body: JSON.stringify({
2532
+ email: input.email,
2533
+ type: "sign-in"
2534
+ }),
2535
+ credentials: "include"
2536
+ }, options?.signal));
2537
+ if (options?.signal?.aborted) return {
2538
+ ok: false,
2539
+ error: Errors.cancelled({ operation: "sendOtp" })
2540
+ };
2541
+ if (res.ok) return {
2542
+ ok: true,
2543
+ value: void 0
2544
+ };
2545
+ if (res.status === 429) return {
2546
+ ok: false,
2547
+ error: Errors.rateLimited({ resource: "better-auth/sendOtp" })
2548
+ };
2549
+ const body = await safeJson$1(res);
2550
+ if (typeof body === "object" && body !== null) {
2551
+ const errBody = body;
2552
+ if (errBody.code === "INVALID_EMAIL" || errBody.code === "VALIDATION_ERROR") return {
2553
+ ok: false,
2554
+ error: Errors.invalidInput("email", errBody.message ?? "invalid email")
2555
+ };
2556
+ }
2557
+ return {
2558
+ ok: false,
2559
+ error: Errors.providerError("better-auth", "sendOtp", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
2560
+ };
2561
+ } catch (err) {
2562
+ return {
2563
+ ok: false,
2564
+ error: mapFetchError$1("sendOtp", err, options?.signal)
2565
+ };
2566
+ }
2567
+ }
2568
+ async verifyOtp(input, options) {
2569
+ if (options?.signal?.aborted) return {
2570
+ ok: false,
2571
+ error: Errors.cancelled({ operation: "verifyOtp" })
2572
+ };
2573
+ try {
2574
+ const res = await this.fetchImpl(this.url("/api/auth/sign-in/email-otp"), withSignal$1({
2575
+ method: "POST",
2576
+ headers: { "Content-Type": "application/json" },
2577
+ body: JSON.stringify({
2578
+ email: input.email,
2579
+ otp: input.otp
2580
+ }),
2581
+ credentials: "include"
2582
+ }, options?.signal));
2583
+ if (options?.signal?.aborted) return {
2584
+ ok: false,
2585
+ error: Errors.cancelled({ operation: "verifyOtp" })
2586
+ };
2587
+ const body = await safeJson$1(res);
2588
+ if (res.ok) {
2589
+ if (typeof body === "object" && body !== null) {
2590
+ const okBody = body;
2591
+ if (typeof okBody.token === "string" && typeof okBody.user === "object" && okBody.user !== null) return {
2592
+ ok: true,
2593
+ value: authSessionFromBetterAuth$1(okBody.token, okBody.user)
2594
+ };
2595
+ }
2596
+ return {
2597
+ ok: false,
2598
+ error: Errors.providerError("better-auth", "verifyOtp", /* @__PURE__ */ new Error("unexpected 200 body"))
2599
+ };
2600
+ }
2601
+ return {
2602
+ ok: false,
2603
+ error: mapBetterAuthError("verifyOtp", body)
2604
+ };
2605
+ } catch (err) {
2606
+ return {
2607
+ ok: false,
2608
+ error: mapFetchError$1("verifyOtp", err, options?.signal)
2609
+ };
2610
+ }
2611
+ }
2612
+ async getSession(options) {
2613
+ if (options?.signal?.aborted) return {
2614
+ ok: false,
2615
+ error: Errors.cancelled({ operation: "getSession" })
2616
+ };
2617
+ try {
2618
+ const res = await this.fetchImpl(this.url("/api/auth/get-session"), withSignal$1({
2619
+ method: "GET",
2620
+ credentials: "include"
2621
+ }, options?.signal));
2622
+ if (options?.signal?.aborted) return {
2623
+ ok: false,
2624
+ error: Errors.cancelled({ operation: "getSession" })
2625
+ };
2626
+ if (!res.ok) return {
2627
+ ok: false,
2628
+ error: Errors.providerError("better-auth", "getSession", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
2629
+ };
2630
+ const body = await safeJson$1(res);
2631
+ if (body === null) return {
2632
+ ok: true,
2633
+ value: null
2634
+ };
2635
+ if (typeof body === "object" && body !== null) {
2636
+ const okBody = body;
2637
+ if (typeof okBody.user === "object" && okBody.user !== null) return {
2638
+ ok: true,
2639
+ value: authSessionFromBetterAuth$1(okBody.session?.token ?? okBody.session?.id ?? "session", okBody.user)
2640
+ };
2641
+ }
2642
+ return {
2643
+ ok: true,
2644
+ value: null
2645
+ };
2646
+ } catch (err) {
2647
+ return {
2648
+ ok: false,
2649
+ error: mapFetchError$1("getSession", err, options?.signal)
2650
+ };
2651
+ }
2652
+ }
2653
+ async signOut(options) {
2654
+ if (options?.signal?.aborted) return {
2655
+ ok: false,
2656
+ error: Errors.cancelled({ operation: "signOut" })
2657
+ };
2658
+ try {
2659
+ const res = await this.fetchImpl(this.url("/api/auth/sign-out"), withSignal$1({
2660
+ method: "POST",
2661
+ headers: { "Content-Type": "application/json" },
2662
+ body: "{}",
2663
+ credentials: "include"
2664
+ }, options?.signal));
2665
+ if (options?.signal?.aborted) return {
2666
+ ok: false,
2667
+ error: Errors.cancelled({ operation: "signOut" })
2668
+ };
2669
+ if (res.ok) return {
2670
+ ok: true,
2671
+ value: void 0
2672
+ };
2673
+ return {
2674
+ ok: false,
2675
+ error: Errors.providerError("better-auth", "signOut", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
2676
+ };
2677
+ } catch (err) {
2678
+ return {
2679
+ ok: false,
2680
+ error: mapFetchError$1("signOut", err, options?.signal)
2681
+ };
2682
+ }
2683
+ }
2684
+ async getConvexJwt(options) {
2685
+ if (options?.signal?.aborted) return {
2686
+ ok: false,
2687
+ error: Errors.cancelled({ operation: "getConvexJwt" })
2688
+ };
2689
+ try {
2690
+ const res = await this.fetchImpl(this.url("/api/auth/convex/token"), withSignal$1({
2691
+ method: "GET",
2692
+ credentials: "include"
2693
+ }, options?.signal));
2694
+ if (options?.signal?.aborted) return {
2695
+ ok: false,
2696
+ error: Errors.cancelled({ operation: "getConvexJwt" })
2697
+ };
2698
+ if (res.status === 401) return {
2699
+ ok: false,
2700
+ error: Errors.notAuthenticated()
2701
+ };
2702
+ if (!res.ok) return {
2703
+ ok: false,
2704
+ error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
2705
+ };
2706
+ const body = await safeJson$1(res);
2707
+ if (typeof body === "object" && body !== null) {
2708
+ const okBody = body;
2709
+ if (typeof okBody.token === "string" && okBody.token.length > 0) return {
2710
+ ok: true,
2711
+ value: {
2712
+ token: toJwtToken(okBody.token),
2713
+ expEpochSeconds: toEpochSeconds(decodeJwtExp$1(okBody.token))
2714
+ }
2715
+ };
2716
+ }
2717
+ return {
2718
+ ok: false,
2719
+ error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error("unexpected body"))
2720
+ };
2721
+ } catch (err) {
2722
+ return {
2723
+ ok: false,
2724
+ error: mapFetchError$1("getConvexJwt", err, options?.signal)
2725
+ };
2726
+ }
2727
+ }
2728
+ };
2729
+ function BetterAuthBrowserLayer(deps) {
2730
+ return Layer.succeed(AuthClientPortTag, authClientPortFromPromiseAdapter(new BetterAuthBrowserAdapter(deps)));
2731
+ }
2732
+ //#endregion
2733
+ //#region src/adapters/auth-client/cookie-jar.ts
2734
+ function parseSetCookie(raw) {
2735
+ const parts = raw.split(";").map((p) => p.trim());
2736
+ if (parts.length === 0 || parts[0] === void 0) return null;
2737
+ const nameValue = parts[0];
2738
+ const eq = nameValue.indexOf("=");
2739
+ if (eq < 0) return null;
2740
+ const name = nameValue.slice(0, eq).trim();
2741
+ const value = nameValue.slice(eq + 1).trim();
2742
+ if (name.length === 0) return null;
2743
+ let maxAgeSeconds = null;
2744
+ let expiresEpochMs = null;
2745
+ let path = null;
2746
+ let httpOnly = false;
2747
+ let secure = false;
2748
+ let sameSite = null;
2749
+ for (let i = 1; i < parts.length; i++) {
2750
+ const part = parts[i];
2751
+ if (part === void 0) continue;
2752
+ const partEq = part.indexOf("=");
2753
+ const key = (partEq < 0 ? part : part.slice(0, partEq)).trim().toLowerCase();
2754
+ const val = partEq < 0 ? "" : part.slice(partEq + 1).trim();
2755
+ if (key === "max-age") {
2756
+ const n = Number(val);
2757
+ if (Number.isFinite(n)) maxAgeSeconds = n;
2758
+ } else if (key === "expires") {
2759
+ const t = Date.parse(val);
2760
+ if (Number.isFinite(t)) expiresEpochMs = t;
2761
+ } else if (key === "path") path = val;
2762
+ else if (key === "httponly") httpOnly = true;
2763
+ else if (key === "secure") secure = true;
2764
+ else if (key === "samesite") {
2765
+ const lc = val.toLowerCase();
2766
+ if (lc === "strict" || lc === "lax" || lc === "none") sameSite = lc;
2767
+ }
2768
+ }
2769
+ return {
2770
+ name,
2771
+ value,
2772
+ maxAgeSeconds,
2773
+ expiresEpochMs,
2774
+ path,
2775
+ httpOnly,
2776
+ secure,
2777
+ sameSite
2778
+ };
2779
+ }
2780
+ function isExpired(cookie, nowEpochMs) {
2781
+ if (cookie.maxAgeSeconds !== null) {
2782
+ if (cookie.maxAgeSeconds <= 0) return true;
2783
+ return nowEpochMs >= cookie.storedAtEpochMs + cookie.maxAgeSeconds * 1e3;
2784
+ }
2785
+ if (cookie.expiresEpochMs !== null) return nowEpochMs >= cookie.expiresEpochMs;
2786
+ return false;
2787
+ }
2788
+ var CookieJar = class {
2789
+ store = /* @__PURE__ */ new Map();
2790
+ set(host, setCookieHeaders) {
2791
+ let perHost = this.store.get(host);
2792
+ const now = Date.now();
2793
+ for (const raw of setCookieHeaders) {
2794
+ const parsed = parseSetCookie(raw);
2795
+ if (parsed === null) continue;
2796
+ if (perHost === void 0) {
2797
+ perHost = /* @__PURE__ */ new Map();
2798
+ this.store.set(host, perHost);
2799
+ }
2800
+ if (parsed.maxAgeSeconds !== null && parsed.maxAgeSeconds <= 0) {
2801
+ perHost.delete(parsed.name);
2802
+ continue;
2803
+ }
2804
+ perHost.set(parsed.name, {
2805
+ ...parsed,
2806
+ storedAtEpochMs: now
2807
+ });
2808
+ }
2809
+ if (perHost !== void 0 && perHost.size === 0) this.store.delete(host);
2810
+ }
2811
+ getCookieHeader(host) {
2812
+ const perHost = this.store.get(host);
2813
+ if (perHost === void 0 || perHost.size === 0) return null;
2814
+ const now = Date.now();
2815
+ const live = [];
2816
+ for (const [name, cookie] of perHost.entries()) {
2817
+ if (isExpired(cookie, now)) {
2818
+ perHost.delete(name);
2819
+ continue;
2820
+ }
2821
+ live.push(`${name}=${cookie.value}`);
2822
+ }
2823
+ if (live.length === 0) {
2824
+ this.store.delete(host);
2825
+ return null;
2826
+ }
2827
+ return live.join("; ");
2828
+ }
2829
+ };
2830
+ //#endregion
2831
+ //#region src/adapters/auth-client/BetterAuthNodeAdapter.ts
2832
+ function withSignal(init, signal) {
2833
+ return signal === void 0 ? init : {
2834
+ ...init,
2835
+ signal
2836
+ };
2837
+ }
2838
+ const DEFAULT_JWT_LIFETIME_S = 900;
2839
+ function decodeJwtExp(jwt) {
2840
+ const parts = jwt.split(".");
2841
+ if (parts.length < 2 || parts[1] === void 0) return Math.floor(Date.now() / 1e3) + DEFAULT_JWT_LIFETIME_S;
2842
+ try {
2843
+ const raw = parts[1].replace(/\s+/g, "");
2844
+ const pad = "=".repeat((4 - raw.length % 4) % 4);
2845
+ const decoded = Buffer.from(raw.replace(/-/g, "+").replace(/_/g, "/") + pad, "base64").toString("utf-8");
2846
+ const payload = JSON.parse(decoded);
2847
+ if (typeof payload.exp === "number" && Number.isFinite(payload.exp) && payload.exp > 0) return payload.exp;
2848
+ } catch {}
2849
+ return Math.floor(Date.now() / 1e3) + DEFAULT_JWT_LIFETIME_S;
2850
+ }
2851
+ function authSessionFromBetterAuth(token, user) {
2852
+ return {
2853
+ authUserId: toAuthUserId(user.id),
2854
+ email: toEmail(user.email),
2855
+ token: toSessionToken(token),
2856
+ expiresAt: toEpochMs(Date.now() + 10080 * 60 * 1e3)
2857
+ };
2858
+ }
2859
+ async function safeJson(res) {
2860
+ const raw = await res.text();
2861
+ if (raw.length === 0 || raw === "null") return null;
2862
+ try {
2863
+ return JSON.parse(raw);
2864
+ } catch {
2865
+ return null;
2866
+ }
2867
+ }
2868
+ function hostFromBaseUrl(baseUrl) {
2869
+ try {
2870
+ return new URL(baseUrl).host;
2871
+ } catch {
2872
+ return baseUrl;
2873
+ }
2874
+ }
2875
+ function originFromBaseUrl(baseUrl) {
2876
+ try {
2877
+ return new URL(baseUrl).origin;
2878
+ } catch {
2879
+ return;
2880
+ }
2881
+ }
2882
+ function setCookiesFromResponse(jar, host, res) {
2883
+ const ext = res.headers;
2884
+ let setCookies = [];
2885
+ if (typeof ext.getSetCookie === "function") setCookies = ext.getSetCookie();
2886
+ else res.headers.forEach((value, key) => {
2887
+ if (key.toLowerCase() === "set-cookie") setCookies.push(value);
2888
+ });
2889
+ if (setCookies.length > 0) jar.set(host, setCookies);
2890
+ }
2891
+ function isAbortError(err, signal) {
2892
+ return signal?.aborted === true || err instanceof Error && err.name === "AbortError" || typeof DOMException !== "undefined" && err instanceof DOMException && err.name === "AbortError";
2893
+ }
2894
+ function mapFetchError(operation, err, signal) {
2895
+ if (isAbortError(err, signal)) return Errors.cancelled({ operation });
2896
+ return Errors.networkError(operation, err instanceof Error ? err : new Error(String(err)));
2897
+ }
2898
+ var BetterAuthNodeAdapter = class {
2899
+ authBaseUrl;
2900
+ host;
2901
+ origin;
2902
+ cookieJar;
2903
+ fetchImpl;
2904
+ constructor(deps) {
2905
+ this.authBaseUrl = deps.authBaseUrl.replace(/\/$/, "");
2906
+ this.host = hostFromBaseUrl(this.authBaseUrl);
2907
+ this.origin = deps.origin?.replace(/\/$/, "");
2908
+ this.cookieJar = deps.cookieJar ?? new CookieJar();
2909
+ this.fetchImpl = deps.fetch ?? fetch;
2910
+ }
2911
+ url(path) {
2912
+ return resolveAuthClientUrl(this.authBaseUrl, path);
2913
+ }
2914
+ headersWithCookie(extra = {}) {
2915
+ const cookie = this.cookieJar.getCookieHeader(this.host);
2916
+ return cookie !== null ? {
2917
+ ...extra,
2918
+ cookie
2919
+ } : { ...extra };
2920
+ }
2921
+ async canSendOtp(_input, options) {
2922
+ if (options?.signal?.aborted) return {
2923
+ ok: false,
2924
+ error: Errors.cancelled({ operation: "canSendOtp" })
2925
+ };
2926
+ return {
2927
+ ok: true,
2928
+ value: {
2929
+ allowed: true,
2930
+ cooldownMs: toDurationMs(0)
2931
+ }
2932
+ };
2933
+ }
2934
+ async sendOtp(input, options) {
2935
+ if (options?.signal?.aborted) return {
2936
+ ok: false,
2937
+ error: Errors.cancelled({ operation: "sendOtp" })
2938
+ };
2939
+ try {
2940
+ const res = await this.fetchImpl(this.url("/api/auth/email-otp/send-verification-otp"), withSignal({
2941
+ method: "POST",
2942
+ headers: {
2943
+ "content-type": "application/json",
2944
+ ...this.origin ? { origin: this.origin } : {}
2945
+ },
2946
+ body: JSON.stringify({
2947
+ email: input.email,
2948
+ type: "sign-in"
2949
+ })
2950
+ }, options?.signal));
2951
+ if (options?.signal?.aborted) return {
2952
+ ok: false,
2953
+ error: Errors.cancelled({ operation: "sendOtp" })
2954
+ };
2955
+ if (res.ok) return {
2956
+ ok: true,
2957
+ value: void 0
2958
+ };
2959
+ if (res.status === 429) return {
2960
+ ok: false,
2961
+ error: Errors.rateLimited({ resource: "better-auth/sendOtp" })
2962
+ };
2963
+ const body = await safeJson(res);
2964
+ if (typeof body === "object" && body !== null) {
2965
+ const errBody = body;
2966
+ if (errBody.code === "INVALID_EMAIL" || errBody.code === "VALIDATION_ERROR") return {
2967
+ ok: false,
2968
+ error: Errors.invalidInput("email", errBody.message ?? "invalid email")
2969
+ };
2970
+ }
2971
+ return {
2972
+ ok: false,
2973
+ error: Errors.providerError("better-auth", "sendOtp", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
2974
+ };
2975
+ } catch (err) {
2976
+ return {
2977
+ ok: false,
2978
+ error: mapFetchError("sendOtp", err, options?.signal)
2979
+ };
2980
+ }
2981
+ }
2982
+ async verifyOtp(input, options) {
2983
+ if (options?.signal?.aborted) return {
2984
+ ok: false,
2985
+ error: Errors.cancelled({ operation: "verifyOtp" })
2986
+ };
2987
+ try {
2988
+ const res = await this.fetchImpl(this.url("/api/auth/sign-in/email-otp"), withSignal({
2989
+ method: "POST",
2990
+ headers: {
2991
+ "content-type": "application/json",
2992
+ ...this.origin ? { origin: this.origin } : {}
2993
+ },
2994
+ body: JSON.stringify({
2995
+ email: input.email,
2996
+ otp: input.otp
2997
+ })
2998
+ }, options?.signal));
2999
+ if (options?.signal?.aborted) return {
3000
+ ok: false,
3001
+ error: Errors.cancelled({ operation: "verifyOtp" })
3002
+ };
3003
+ setCookiesFromResponse(this.cookieJar, this.host, res);
3004
+ const body = await safeJson(res);
3005
+ if (res.ok && typeof body === "object" && body !== null) {
3006
+ const okBody = body;
3007
+ if (typeof okBody.token === "string" && typeof okBody.user === "object" && okBody.user !== null) return {
3008
+ ok: true,
3009
+ value: authSessionFromBetterAuth(okBody.token, okBody.user)
3010
+ };
3011
+ }
3012
+ if (!res.ok) {
3013
+ if (typeof body === "object" && body !== null) {
3014
+ const errBody = body;
3015
+ if (errBody.code === "OTP_EXPIRED") return {
3016
+ ok: false,
3017
+ error: Errors.otpExpired()
3018
+ };
3019
+ if (errBody.code === "INVALID_OTP") return {
3020
+ ok: false,
3021
+ error: Errors.invalidInput("otp", errBody.message ?? "invalid OTP")
3022
+ };
3023
+ }
3024
+ }
3025
+ return {
3026
+ ok: false,
3027
+ error: Errors.providerError("better-auth", "verifyOtp", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
3028
+ };
3029
+ } catch (err) {
3030
+ return {
3031
+ ok: false,
3032
+ error: mapFetchError("verifyOtp", err, options?.signal)
3033
+ };
3034
+ }
3035
+ }
3036
+ async getSession(options) {
3037
+ if (options?.signal?.aborted) return {
3038
+ ok: false,
3039
+ error: Errors.cancelled({ operation: "getSession" })
3040
+ };
3041
+ try {
3042
+ const res = await this.fetchImpl(this.url("/api/auth/get-session"), withSignal({
3043
+ method: "GET",
3044
+ headers: this.headersWithCookie()
3045
+ }, options?.signal));
3046
+ if (options?.signal?.aborted) return {
3047
+ ok: false,
3048
+ error: Errors.cancelled({ operation: "getSession" })
3049
+ };
3050
+ if (!res.ok) return {
3051
+ ok: false,
3052
+ error: Errors.providerError("better-auth", "getSession", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
3053
+ };
3054
+ const body = await safeJson(res);
3055
+ if (body === null) return {
3056
+ ok: true,
3057
+ value: null
3058
+ };
3059
+ if (typeof body === "object" && body !== null) {
3060
+ const okBody = body;
3061
+ if (typeof okBody.user === "object" && okBody.user !== null) return {
3062
+ ok: true,
3063
+ value: authSessionFromBetterAuth(okBody.session?.token ?? okBody.session?.id ?? "session", okBody.user)
3064
+ };
3065
+ }
3066
+ return {
3067
+ ok: true,
3068
+ value: null
3069
+ };
3070
+ } catch (err) {
3071
+ return {
3072
+ ok: false,
3073
+ error: mapFetchError("getSession", err, options?.signal)
3074
+ };
3075
+ }
3076
+ }
3077
+ async signOut(options) {
3078
+ if (options?.signal?.aborted) return {
3079
+ ok: false,
3080
+ error: Errors.cancelled({ operation: "signOut" })
3081
+ };
3082
+ try {
3083
+ const signOutOrigin = originFromBaseUrl(this.authBaseUrl) ?? this.origin;
3084
+ const res = await this.fetchImpl(this.url("/api/auth/sign-out"), withSignal({
3085
+ method: "POST",
3086
+ headers: this.headersWithCookie({
3087
+ "content-type": "application/json",
3088
+ ...signOutOrigin ? { origin: signOutOrigin } : {}
3089
+ }),
3090
+ body: "{}"
3091
+ }, options?.signal));
3092
+ if (options?.signal?.aborted) return {
3093
+ ok: false,
3094
+ error: Errors.cancelled({ operation: "signOut" })
3095
+ };
3096
+ setCookiesFromResponse(this.cookieJar, this.host, res);
3097
+ if (res.ok) return {
3098
+ ok: true,
3099
+ value: void 0
3100
+ };
3101
+ return {
3102
+ ok: false,
3103
+ error: Errors.providerError("better-auth", "signOut", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
3104
+ };
3105
+ } catch (err) {
3106
+ return {
3107
+ ok: false,
3108
+ error: mapFetchError("signOut", err, options?.signal)
3109
+ };
3110
+ }
3111
+ }
3112
+ async getConvexJwt(options) {
3113
+ if (options?.signal?.aborted) return {
3114
+ ok: false,
3115
+ error: Errors.cancelled({ operation: "getConvexJwt" })
3116
+ };
3117
+ try {
3118
+ const res = await this.fetchImpl(this.url("/api/auth/convex/token"), withSignal({
3119
+ method: "GET",
3120
+ headers: this.headersWithCookie()
3121
+ }, options?.signal));
3122
+ if (options?.signal?.aborted) return {
3123
+ ok: false,
3124
+ error: Errors.cancelled({ operation: "getConvexJwt" })
3125
+ };
3126
+ if (res.status === 401) return {
3127
+ ok: false,
3128
+ error: Errors.notAuthenticated()
3129
+ };
3130
+ if (!res.ok) return {
3131
+ ok: false,
3132
+ error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
3133
+ };
3134
+ const body = await safeJson(res);
3135
+ if (typeof body === "object" && body !== null) {
3136
+ const okBody = body;
3137
+ if (typeof okBody.token === "string" && okBody.token.length > 0) return {
3138
+ ok: true,
3139
+ value: {
3140
+ token: toJwtToken(okBody.token),
3141
+ expEpochSeconds: toEpochSeconds(decodeJwtExp(okBody.token))
3142
+ }
3143
+ };
3144
+ }
3145
+ return {
3146
+ ok: false,
3147
+ error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error("unexpected body"))
3148
+ };
3149
+ } catch (err) {
3150
+ return {
3151
+ ok: false,
3152
+ error: mapFetchError("getConvexJwt", err, options?.signal)
3153
+ };
3154
+ }
3155
+ }
3156
+ };
3157
+ function BetterAuthNodeLayer(deps) {
3158
+ return Layer.succeed(AuthClientPortTag, authClientPortFromPromiseAdapter(new BetterAuthNodeAdapter(deps)));
3159
+ }
3160
+ //#endregion
3161
+ //#region src/ports/bootstrap.ts
3162
+ var BootstrapError = class extends Data.TaggedError("BootstrapError") {};
3163
+ function bootstrapErrorFromCapxul(kind, error) {
3164
+ return new BootstrapError({
3165
+ operation: "resolve",
3166
+ kind,
3167
+ publicCode: error.code,
3168
+ cause: error,
3169
+ ...kind === "notAuthenticated" || error.details === void 0 ? {} : { details: error.details }
3170
+ });
3171
+ }
3172
+ var BootstrapPortTag = class extends Context.Tag("@capxul/sdk/ports/BootstrapPort")() {};
3173
+ //#endregion
3174
+ //#region src/adapters/bootstrap/HttpBootstrapAdapter.ts
3175
+ async function safeText(res) {
3176
+ try {
3177
+ return await res.text();
3178
+ } catch {
3179
+ return "";
3180
+ }
3181
+ }
3182
+ var HttpBootstrapAdapter = class {
3183
+ bootstrapBaseUrl;
3184
+ fetchImpl;
3185
+ constructor(deps) {
3186
+ this.bootstrapBaseUrl = deps.bootstrapBaseUrl.replace(/\/$/, "");
3187
+ this.fetchImpl = deps.fetch ?? fetch;
3188
+ }
3189
+ resolve(input) {
3190
+ return Effect.tryPromise({
3191
+ try: () => {
3192
+ const headers = {
3193
+ "content-type": "application/json",
3194
+ ...input.origin === void 0 ? {} : { origin: input.origin }
3195
+ };
3196
+ return this.fetchImpl(`${this.bootstrapBaseUrl}/v1/client/bootstrap`, {
3197
+ method: "POST",
3198
+ headers,
3199
+ body: JSON.stringify({ publishableKey: input.publishableKey })
3200
+ });
3201
+ },
3202
+ catch: (cause) => bootstrapErrorFromCapxul("network", Errors.networkError("bootstrap", cause))
3203
+ }).pipe(Effect.flatMap((res) => this.mapResponse(res)));
3204
+ }
3205
+ mapResponse(res) {
3206
+ if (res.ok) return Effect.tryPromise({
3207
+ try: async () => {
3208
+ const body = await res.json();
3209
+ const decoded = Schema.decodeUnknownEither(BootstrapEnvelope)(body);
3210
+ if (Either.isLeft(decoded)) throw Errors.invalidInput("bootstrapEnvelope", decoded.left.message);
3211
+ const { state } = decoded.right;
3212
+ return {
3213
+ applicationId: state.applicationId,
3214
+ chainId: state.chainId,
3215
+ sessionToken: state.sessionToken,
3216
+ issuedAt: state.issuedAt,
3217
+ expiresIn: state.expiresIn,
3218
+ authBaseUrl: normalizeRuntimeUrl("authBaseUrl", state.authBaseUrl),
3219
+ convexUrl: normalizeRuntimeUrl("convexUrl", state.convexUrl)
3220
+ };
3221
+ },
3222
+ catch: (cause) => {
3223
+ if (cause instanceof CapxulError && cause.code === "INVALID_INPUT") return bootstrapErrorFromCapxul("invalidInput", cause);
3224
+ return bootstrapErrorFromCapxul("malformedBody", Errors.providerError("convex", "bootstrap", cause instanceof Error ? cause : new Error(String(cause))));
3225
+ }
3226
+ });
3227
+ return Effect.promise(() => safeText(res)).pipe(Effect.flatMap((body) => {
3228
+ if (res.status === 401 || body.startsWith("NOT_AUTHENTICATED")) return Effect.fail(bootstrapErrorFromCapxul("notAuthenticated", Errors.notAuthenticated()));
3229
+ if (res.status === 400 || body.startsWith("INVALID_INPUT")) return Effect.fail(bootstrapErrorFromCapxul("invalidInput", Errors.invalidInput("publishableKey", "rejected by bootstrap")));
3230
+ return Effect.fail(bootstrapErrorFromCapxul("provider", Errors.providerError("convex", "bootstrap", /* @__PURE__ */ new Error(`HTTP ${res.status}`))));
3231
+ }));
3232
+ }
3233
+ };
3234
+ function HttpBootstrapLayer(deps) {
3235
+ return Layer.succeed(BootstrapPortTag, new HttpBootstrapAdapter(deps));
3236
+ }
3237
+ function normalizeRuntimeUrl(field, raw) {
3238
+ let parsed;
3239
+ try {
3240
+ parsed = new URL(raw);
3241
+ } catch {
3242
+ throw Errors.invalidInput(field, "must be an http or https URL");
3243
+ }
3244
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw Errors.invalidInput(field, "must be an http or https URL");
3245
+ return parsed.toString().replace(/\/$/, "");
3246
+ }
3247
+ //#endregion
3248
+ //#region src/adapters/clock/SystemClockAdapter.ts
3249
+ var SystemClockAdapter = class {
3250
+ now = Effect.try({
3251
+ try: () => toEpochMs(Date.now()),
3252
+ catch: (cause) => new ClockError({
3253
+ operation: "now",
3254
+ cause
3255
+ })
3256
+ });
3257
+ sleep(duration) {
3258
+ return Effect.async((resume) => {
3259
+ const timeout = setTimeout(() => resume(Effect.void), duration);
3260
+ return Effect.sync(() => clearTimeout(timeout));
3261
+ });
3262
+ }
3263
+ };
3264
+ function SystemClockLayer() {
3265
+ return Layer.succeed(ClockPortTag, new SystemClockAdapter());
3266
+ }
3267
+ //#endregion
3268
+ //#region src/ports/convex-call.ts
3269
+ var ConvexCallError = class extends Data.TaggedError("ConvexCallError") {};
3270
+ function convexCallErrorFromCapxul(operation, error) {
3271
+ return new ConvexCallError({
3272
+ operation,
3273
+ publicCode: error.code,
3274
+ publicError: error,
3275
+ cause: error,
3276
+ ...error.details === void 0 ? {} : { details: error.details }
3277
+ });
3278
+ }
3279
+ var ConvexCallPortTag = class extends Context.Tag("@capxul/sdk/ports/ConvexCallPort")() {};
3280
+ //#endregion
3281
+ //#region src/adapters/convex-call/ConvexCallAdapter.ts
3282
+ var ConvexCallAdapter = class {
3283
+ #client;
3284
+ #tokenProvider;
3285
+ constructor(deps) {
3286
+ this.#client = deps.client ?? new ConvexClient(deps.convexUrl);
3287
+ this.#tokenProvider = deps.tokenProvider;
3288
+ if (this.#tokenProvider) this.#client.setAuth(this.#tokenProvider);
3289
+ }
3290
+ refreshAuth() {
3291
+ if (this.#tokenProvider) this.#client.setAuth(this.#tokenProvider);
3292
+ }
3293
+ query(fn, args) {
3294
+ return Effect.tryPromise({
3295
+ try: () => this.#client.query(fn, args),
3296
+ catch: (cause) => mapToConvexCallError(getFunctionName(fn), cause)
3297
+ });
3298
+ }
3299
+ mutation(fn, args) {
3300
+ return Effect.tryPromise({
3301
+ try: () => this.#client.mutation(fn, args),
3302
+ catch: (cause) => mapToConvexCallError(getFunctionName(fn), cause)
3303
+ });
3304
+ }
3305
+ action(fn, args) {
3306
+ return Effect.tryPromise({
3307
+ try: () => this.#client.action(fn, args),
3308
+ catch: (cause) => mapToConvexCallError(getFunctionName(fn), cause)
3309
+ });
3310
+ }
3311
+ subscribe(fn, args, callback) {
3312
+ return Effect.try({
3313
+ try: () => {
3314
+ const path = getFunctionName(fn);
3315
+ const unsubscribe = this.#client.onUpdate(fn, args, (value) => callback({
3316
+ status: "ok",
3317
+ value
3318
+ }), (err) => callback({
3319
+ status: "error",
3320
+ error: mapToCapxulError(path, err)
3321
+ }));
3322
+ let active = true;
3323
+ return () => {
3324
+ if (!active) return;
3325
+ active = false;
3326
+ unsubscribe();
3327
+ };
3328
+ },
3329
+ catch: (cause) => mapToConvexCallError(getFunctionName(fn), cause)
3330
+ }).pipe(Effect.tap(() => Effect.sync(() => {
3331
+ callback({ status: "loading" });
3332
+ })));
3333
+ }
3334
+ async close() {
3335
+ await this.#client.close();
3336
+ }
3337
+ };
3338
+ function ConvexCallLayer(deps) {
3339
+ return Layer.scoped(ConvexCallPortTag, Effect.acquireRelease(Effect.sync(() => new ConvexCallAdapter(deps)), (adapter) => Effect.promise(() => adapter.close()).pipe(Effect.orDie)));
3340
+ }
3341
+ function mapToCapxulError(operation, err) {
3342
+ const decoded = decodeConvexError(err);
3343
+ if (decoded !== null) return decoded;
3344
+ if (err instanceof CapxulError) return err;
3345
+ if (err instanceof Error) {
3346
+ if (isTransportError(err)) return Errors.networkError(operation, err);
3347
+ return Errors.providerError("convex", operation, err);
3348
+ }
3349
+ return Errors.providerError("convex", operation, new Error(String(err)));
3350
+ }
3351
+ function mapToConvexCallError(operation, err) {
3352
+ return convexCallErrorFromCapxul(operation, mapToCapxulError(operation, err));
3353
+ }
3354
+ function isTransportError(err) {
3355
+ const message = err.message.toLowerCase();
3356
+ return message.includes("failed to fetch") || message.includes("network") || message.includes("econnrefused") || message.includes("econnreset") || message.includes("enotfound") || message.includes("etimedout") || message.includes("socket");
3357
+ }
3358
+ //#endregion
3359
+ //#region src/adapters/_shared/wire.ts
3360
+ /**
3361
+ * Documented brand-erasure helpers for the wire boundary.
3362
+ *
3363
+ * Branded primitives (`Address`, `ChainId`) carry compile-time tags that
3364
+ * vanish at runtime. When sending values across a wire — Convex function
3365
+ * args, viem's template-literal-typed parameters, raw JSON — we have to
3366
+ * remove the brand at the type level so the wire-side type system accepts
3367
+ * the value.
3368
+ *
3369
+ * Using these helpers (rather than ad-hoc `as number` / `as \`0x${string}\``
3370
+ * casts) localizes every de-branding site. If we ever need to centralize
3371
+ * validation (e.g. "must not de-brand a placeholder address"), the change
3372
+ * lands here once instead of grep-and-replace across every adapter.
3373
+ */
3374
+ /**
3375
+ * De-brand a `ChainId` for the wire. The runtime representation is already
3376
+ * `number` — the cast removes the compile-time brand only.
3377
+ */
3378
+ function wireChainId(chainId) {
3379
+ return chainId;
3380
+ }
3381
+ /**
3382
+ * De-brand a `DurationMs` for the wire. The runtime representation is
3383
+ * already `number` — the cast removes the compile-time brand only.
3384
+ *
3385
+ * Used at Convex mutation call sites where the backend's schema expects
3386
+ * a plain `number` for `graceMs` (and similar duration fields). The
3387
+ * branded `DurationMs` type is the SDK's discipline; the wire format is
3388
+ * agnostic.
3389
+ */
3390
+ function wireDurationMs(duration) {
3391
+ return duration;
3392
+ }
3393
+ //#endregion
3394
+ //#region src/ports/credentials.ts
3395
+ var CredentialsError = class extends Data.TaggedError("CredentialsError") {};
3396
+ function credentialsErrorFromCapxul(operation, error, cause = error) {
3397
+ return new CredentialsError({
3398
+ operation,
3399
+ publicCode: error.code,
3400
+ publicError: error,
3401
+ cause,
3402
+ ...error.details === void 0 ? {} : { details: error.details }
3403
+ });
3404
+ }
3405
+ var CredentialsPortTag = class extends Context.Tag("@capxul/sdk/ports/CredentialsPort")() {};
3406
+ //#endregion
3407
+ //#region src/adapters/credentials/ConvexCredentialsAdapter.ts
3408
+ var ConvexCredentialsAdapter = class {
3409
+ #convex;
3410
+ constructor(deps) {
3411
+ this.#convex = deps.convex;
3412
+ }
3413
+ listApplications(authUserId) {
3414
+ return this.#convex.query(applicationsListFn, { authUserId: String(authUserId) }).pipe(Effect.mapError((error) => credentialsErrorFromCapxul("listApplications", error.publicError, error)), Effect.flatMap((rows) => Effect.try({
3415
+ try: () => rows.map(brandDeveloperApplication),
3416
+ catch: (cause) => credentialsErrorFromUnknown("listApplications", cause)
3417
+ })));
3418
+ }
3419
+ createApplication(input) {
3420
+ return this.#convex.mutation(applicationsCreateFn, {
3421
+ authUserId: String(input.authUserId),
3422
+ name: input.name,
3423
+ allowedOrigins: input.allowedOrigins.map(String)
3424
+ }).pipe(Effect.mapError((error) => credentialsErrorFromCapxul("createApplication", error.publicError, error)), Effect.flatMap((row) => Effect.try({
3425
+ try: () => brandDeveloperApplication(row),
3426
+ catch: (cause) => credentialsErrorFromUnknown("createApplication", cause)
3427
+ })));
3428
+ }
3429
+ mintPublishableKey(input) {
3430
+ return this.#convex.mutation(publishableKeysMintFn, {
3431
+ applicationId: String(input.applicationId),
3432
+ authUserId: String(input.authUserId)
3433
+ }).pipe(Effect.mapError((error) => credentialsErrorFromCapxul("mintPublishableKey", error.publicError, error)), Effect.flatMap((row) => Effect.try({
3434
+ try: () => brandPublishableKeyRecord(row),
3435
+ catch: (cause) => credentialsErrorFromUnknown("mintPublishableKey", cause)
3436
+ })));
3437
+ }
3438
+ rotatePublishableKey(input) {
3439
+ return this.#convex.mutation(publishableKeysRotateFn, {
3440
+ keyId: String(input.keyId),
3441
+ authUserId: String(input.authUserId),
3442
+ graceMs: wireDurationMs(input.graceMs)
3443
+ }).pipe(Effect.mapError((error) => credentialsErrorFromCapxul("rotatePublishableKey", error.publicError, error)), Effect.flatMap((row) => Effect.try({
3444
+ try: () => ({
3445
+ active: brandPublishableKeyRecord(row.active),
3446
+ retired: brandPublishableKeyRecord(row.retired)
3447
+ }),
3448
+ catch: (cause) => credentialsErrorFromUnknown("rotatePublishableKey", cause)
3449
+ })));
3450
+ }
3451
+ revokePublishableKey(input) {
3452
+ return this.#convex.mutation(publishableKeysRevokeFn, {
3453
+ keyId: String(input.keyId),
3454
+ authUserId: String(input.authUserId)
3455
+ }).pipe(Effect.mapError((error) => credentialsErrorFromCapxul("revokePublishableKey", error.publicError, error)), Effect.asVoid);
3456
+ }
3457
+ };
3458
+ function ConvexCredentialsLayer() {
3459
+ return Layer.effect(CredentialsPortTag, Effect.map(ConvexCallPortTag, (convex) => new ConvexCredentialsAdapter({ convex })));
3460
+ }
3461
+ const applicationsListFn = makeFunctionReference("credentials/applications:list");
3462
+ const applicationsCreateFn = makeFunctionReference("credentials/applications:create");
3463
+ const publishableKeysMintFn = makeFunctionReference("credentials/publishableKeys:mint");
3464
+ const publishableKeysRotateFn = makeFunctionReference("credentials/publishableKeys:rotate");
3465
+ const publishableKeysRevokeFn = makeFunctionReference("credentials/publishableKeys:revoke");
3466
+ function brandDeveloperApplication(row) {
3467
+ return {
3468
+ id: toAppId(row.id),
3469
+ authUserId: toAuthUserId(row.authUserId),
3470
+ name: row.name,
3471
+ allowedOrigins: row.allowedOrigins.map((o) => toAllowedOrigin(o)),
3472
+ createdAt: toEpochMs(row.createdAt),
3473
+ archivedAt: row.archivedAt === null ? null : toEpochMs(row.archivedAt)
3474
+ };
3475
+ }
3476
+ function brandPublishableKeyRecord(row) {
3477
+ return {
3478
+ id: toPublishableKeyId(row.id),
3479
+ applicationId: toAppId(row.applicationId),
3480
+ activeFromMs: toEpochMs(row.activeFromMs),
3481
+ gracePeriodEndsMs: row.gracePeriodEndsMs === null ? null : toEpochMs(row.gracePeriodEndsMs),
3482
+ revokedAt: row.revokedAt === null ? null : toEpochMs(row.revokedAt)
3483
+ };
3484
+ }
3485
+ function credentialsErrorFromUnknown(operation, cause) {
3486
+ if (cause instanceof CapxulError) return credentialsErrorFromCapxul(operation, cause);
3487
+ return credentialsErrorFromCapxul(operation, Errors.providerError("credentials", operation, cause instanceof Error ? cause : new Error(String(cause))), cause);
3488
+ }
3489
+ //#endregion
3490
+ //#region src/ports/env.ts
3491
+ var EnvError = class extends Data.TaggedError("EnvError") {};
3492
+ function envErrorFromCapxul(key, error, cause = error) {
3493
+ return new EnvError({
3494
+ publicError: error,
3495
+ publicCode: error.code,
3496
+ key,
3497
+ ...error.details === void 0 ? {} : { details: error.details },
3498
+ cause
3499
+ });
3500
+ }
3501
+ var EnvPortTag = class extends Context.Tag("@capxul/sdk/ports/EnvPort")() {};
3502
+ //#endregion
3503
+ //#region src/env/_internal.ts
3504
+ const envFields = {
3505
+ NEXT_PUBLIC_CONVEX_URL: {
3506
+ "runtime": "client",
3507
+ "kind": "url",
3508
+ "required": true,
3509
+ "example": "https://example.convex.cloud"
3510
+ },
3511
+ NEXT_PUBLIC_CONVEX_SITE_URL: {
3512
+ "runtime": "client",
3513
+ "kind": "url",
3514
+ "required": true,
3515
+ "example": "https://example.convex.site"
3516
+ },
3517
+ NEXT_PUBLIC_OPENFORT_PUBLISHABLE_KEY: {
3518
+ "runtime": "client",
3519
+ "kind": "nonempty",
3520
+ "required": true,
3521
+ "example": "pk_test_openfort"
3522
+ },
3523
+ NEXT_PUBLIC_SHIELD_PUBLISHABLE_KEY: {
3524
+ "runtime": "client",
3525
+ "kind": "nonempty",
3526
+ "required": true,
3527
+ "example": "shield_pk_test"
3528
+ },
3529
+ NEXT_PUBLIC_FEE_SPONSORSHIP_ID: {
3530
+ "runtime": "client",
3531
+ "kind": "nonempty",
3532
+ "required": false,
3533
+ "example": "fee_sponsor"
3534
+ },
3535
+ NEXT_PUBLIC_POSTHOG_KEY: {
3536
+ "runtime": "client",
3537
+ "kind": "nonempty",
3538
+ "required": false,
3539
+ "example": "phc_test"
3540
+ },
3541
+ NEXT_PUBLIC_POSTHOG_HOST: {
3542
+ "runtime": "client",
3543
+ "kind": "url",
3544
+ "required": false,
3545
+ "example": "https://us.i.posthog.com"
3546
+ },
3547
+ NEXT_PUBLIC_SENTRY_DSN: {
3548
+ "runtime": "client",
3549
+ "kind": "url",
3550
+ "required": false,
3551
+ "example": "https://public@example.ingest.sentry.io/1"
3552
+ },
3553
+ SITE_URL: {
3554
+ "runtime": "server",
3555
+ "kind": "url",
3556
+ "required": true,
3557
+ "example": "https://app.capxul.test"
3558
+ },
3559
+ OPENFORT_SECRET_KEY: {
3560
+ "runtime": "server",
3561
+ "kind": "nonempty",
3562
+ "required": true,
3563
+ "example": "sk_test_openfort"
3564
+ },
3565
+ OPENFORT_PUBLISHABLE_KEY: {
3566
+ "runtime": "server",
3567
+ "kind": "nonempty",
3568
+ "required": true,
3569
+ "example": "pk_server_openfort"
3570
+ },
3571
+ OPENFORT_WALLET_SECRET: {
3572
+ "runtime": "server",
3573
+ "kind": "nonempty",
3574
+ "required": true,
3575
+ "example": "wallet_secret"
3576
+ },
3577
+ SHIELD_PUBLISHABLE_KEY: {
3578
+ "runtime": "server",
3579
+ "kind": "nonempty",
3580
+ "required": true,
3581
+ "example": "shield_pk_server"
3582
+ },
3583
+ SHIELD_SECRET_KEY: {
3584
+ "runtime": "server",
3585
+ "kind": "nonempty",
3586
+ "required": true,
3587
+ "example": "shield_secret"
3588
+ },
3589
+ SHIELD_ENCRYPTION_SHARE: {
3590
+ "runtime": "server",
3591
+ "kind": "nonempty",
3592
+ "required": true,
3593
+ "example": "shield_share"
3594
+ },
3595
+ FEE_SPONSORSHIP_ID: {
3596
+ "runtime": "server",
3597
+ "kind": "nonempty",
3598
+ "required": true,
3599
+ "example": "fee_sponsor"
3600
+ },
3601
+ RESEND_API_KEY: {
3602
+ "runtime": "server",
3603
+ "kind": "nonempty",
3604
+ "required": false,
3605
+ "example": "re_test"
3606
+ },
3607
+ BREVO_API_KEY: {
3608
+ "runtime": "server",
3609
+ "kind": "nonempty",
3610
+ "required": false,
3611
+ "example": "brevo_test"
3612
+ },
3613
+ AUTH_MODE: {
3614
+ "runtime": "server",
3615
+ "kind": "authMode",
3616
+ "required": false,
3617
+ "example": "development"
3618
+ },
3619
+ AUTH_DEV_OTP: {
3620
+ "runtime": "server",
3621
+ "kind": "nonempty",
3622
+ "required": false,
3623
+ "example": "000000"
3624
+ },
3625
+ SENTRY_DSN: {
3626
+ "runtime": "server",
3627
+ "kind": "url",
3628
+ "required": false,
3629
+ "example": "https://public@example.ingest.sentry.io/1"
3630
+ },
3631
+ POSTHOG_API_KEY: {
3632
+ "runtime": "server",
3633
+ "kind": "nonempty",
3634
+ "required": false,
3635
+ "example": "phx_test"
3636
+ },
3637
+ POSTHOG_PROJECT_TOKEN: {
3638
+ "runtime": "server",
3639
+ "kind": "nonempty",
3640
+ "required": false,
3641
+ "example": "phc_test"
3642
+ },
3643
+ POSTHOG_INGEST_KEY: {
3644
+ "runtime": "server",
3645
+ "kind": "nonempty",
3646
+ "required": false,
3647
+ "example": "phc_test"
3648
+ },
3649
+ POSTHOG_HOST: {
3650
+ "runtime": "server",
3651
+ "kind": "url",
3652
+ "required": false,
3653
+ "example": "https://us.i.posthog.com"
3654
+ },
3655
+ POSTHOG_PERSONAL_API_KEY: {
3656
+ "runtime": "server",
3657
+ "kind": "nonempty",
3658
+ "required": false,
3659
+ "example": "phx_personal"
3660
+ },
3661
+ POSTHOG_PROJECT_ID: {
3662
+ "runtime": "server",
3663
+ "kind": "nonempty",
3664
+ "required": false,
3665
+ "example": "12345"
3666
+ },
3667
+ POSTHOG_ENV_ID: {
3668
+ "runtime": "server",
3669
+ "kind": "nonempty",
3670
+ "required": false,
3671
+ "example": "12345"
3672
+ },
3673
+ SENDER_EMAIL: {
3674
+ "runtime": "server",
3675
+ "kind": "email",
3676
+ "required": false,
3677
+ "example": "noreply@capxul.test"
3678
+ },
3679
+ SHIELD_API_URL: {
3680
+ "runtime": "server",
3681
+ "kind": "url",
3682
+ "required": false,
3683
+ "example": "https://api.shield.test"
3684
+ },
3685
+ ALCHEMY_API_KEY: {
3686
+ "runtime": "server",
3687
+ "kind": "nonempty",
3688
+ "required": false,
3689
+ "example": "alchemy_test"
3690
+ },
3691
+ ALCHEMY_GAS_POLICY_ID: {
3692
+ "runtime": "server",
3693
+ "kind": "nonempty",
3694
+ "required": false,
3695
+ "example": "policy_test"
3696
+ },
3697
+ ALCHEMY_WEBHOOK_SIGNING_KEY: {
3698
+ "runtime": "server",
3699
+ "kind": "nonempty",
3700
+ "required": true,
3701
+ "example": "alchemy_hmac"
3702
+ },
3703
+ ALCHEMY_AUTH_TOKEN: {
3704
+ "runtime": "server",
3705
+ "kind": "nonempty",
3706
+ "required": false,
3707
+ "example": "alchemy_auth"
3708
+ },
3709
+ ALCHEMY_WEBHOOK_ID: {
3710
+ "runtime": "server",
3711
+ "kind": "nonempty",
3712
+ "required": false,
3713
+ "example": "wh_123"
3714
+ },
3715
+ GOLDSKY_WEBHOOK_SECRET: {
3716
+ "runtime": "server",
3717
+ "kind": "nonempty",
3718
+ "required": false,
3719
+ "example": "goldsky_secret"
3720
+ },
3721
+ DEPLOYER_PRIVATE_KEY: {
3722
+ "runtime": "server",
3723
+ "kind": "privateKey",
3724
+ "required": true,
3725
+ "example": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
3726
+ },
3727
+ BASE_SEPOLIA_RPC_URL: {
3728
+ "runtime": "server",
3729
+ "kind": "url",
3730
+ "required": true,
3731
+ "example": "https://sepolia.base.org"
3732
+ },
3733
+ CONVEX_SITE_URL: {
3734
+ "runtime": "server",
3735
+ "kind": "url",
3736
+ "required": false,
3737
+ "example": "https://example.convex.site"
3738
+ },
3739
+ AGENTMAIL_API_KEY: {
3740
+ "runtime": "server",
3741
+ "kind": "nonempty",
3742
+ "required": false,
3743
+ "example": "agentmail_test"
3744
+ },
3745
+ CAPXUL_E2E_PUBLISHABLE_KEY: {
3746
+ "runtime": "server",
3747
+ "kind": "nonempty",
3748
+ "required": false,
3749
+ "example": "cap_pk_test_00000000000000000000000000000000"
3750
+ },
3751
+ CAPXUL_E2E_ORIGIN: {
3752
+ "runtime": "server",
3753
+ "kind": "url",
3754
+ "required": false,
3755
+ "example": "https://e2e.test.capxul.local"
3756
+ },
3757
+ CAPXUL_E2E_REQUIRED: {
3758
+ "runtime": "server",
3759
+ "kind": "nonempty",
3760
+ "required": false,
3761
+ "example": "1"
3762
+ },
3763
+ CAPXUL_FAUCET_ENABLED: {
3764
+ "runtime": "server",
3765
+ "kind": "nonempty",
3766
+ "required": false,
3767
+ "example": "1"
3768
+ }
3769
+ };
3770
+ function schemaFor(kind) {
3771
+ switch (kind) {
3772
+ case "authMode": return Schema.String.pipe(Schema.filter((value) => value === "development" || value === "production" || value === "test", { message: () => "Invalid enum value" }));
3773
+ case "email": return Schema.String.pipe(Schema.filter((value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value), { message: () => "Invalid email" }));
3774
+ case "nonempty": return Schema.String.pipe(Schema.minLength(1));
3775
+ case "privateKey": return Schema.String.pipe(Schema.filter((value) => /^0x[0-9a-fA-F]{64}$/.test(value), { message: () => "Must be a 0x-prefixed 32-byte hex private key" }));
3776
+ case "url": return Schema.String.pipe(Schema.filter((value) => {
3777
+ try {
3778
+ return new URL(value).href.length > 0;
3779
+ } catch {
3780
+ return false;
3781
+ }
3782
+ }, { message: () => "Invalid url" }));
3783
+ default: {
3784
+ const unsupported = kind;
3785
+ throw Errors.invalidInput(String(unsupported), "unsupported environment field kind");
3786
+ }
3787
+ }
3788
+ }
3789
+ const envShapeFields = Object.fromEntries(Object.entries(envFields).map(([key, field]) => [key, field.required ? schemaFor(field.kind) : Schema.optional(schemaFor(field.kind))]));
3790
+ const envShapeSchema = Schema.Struct(envShapeFields);
3791
+ Schema.partial(envShapeSchema);
3792
+ function parseEnvValue$1(key, raw, required) {
3793
+ const field = envFields[key];
3794
+ if (field === void 0) throw Errors.invalidInput(key, "unknown environment key");
3795
+ const normalized = normalizeEnvRaw(raw);
3796
+ if (normalized === void 0) {
3797
+ if (required) throw Errors.envMissing(key);
3798
+ return;
3799
+ }
3800
+ const result = Schema.decodeUnknownEither(schemaFor(field.kind))(normalized);
3801
+ if (Either.isLeft(result)) throw Errors.invalidInput(key, TreeFormatter.formatErrorSync(result.left));
3802
+ return result.right;
3803
+ }
3804
+ function normalizeEnvRaw(raw) {
3805
+ if (raw === void 0 || raw.trim() === "") return;
3806
+ return raw;
3807
+ }
3808
+ function runtimeEnv() {
3809
+ return globalThis.process?.env ?? {};
3810
+ }
3811
+ //#endregion
3812
+ //#region src/adapters/env/_shared.ts
3813
+ function parseEnvValue(key, raw, required) {
3814
+ return parseEnvValue$1(key, raw, required);
3815
+ }
3816
+ function hasEnvValue(key, raw) {
3817
+ if (envFields[key] === void 0) throw envErrorFromCapxul(key, Errors.invalidInput(key, "unknown environment key"));
3818
+ return normalizeEnvRaw(raw) !== void 0;
3819
+ }
3820
+ function catchEnvError(key, cause) {
3821
+ if (cause instanceof EnvError) return cause;
3822
+ if (isCapxulError(cause)) return envErrorFromCapxul(key, cause, cause);
3823
+ const redactedCause = /* @__PURE__ */ new Error(`env ${key} read failed`);
3824
+ return envErrorFromCapxul(key, Errors.providerError("env", key, redactedCause), redactedCause);
3825
+ }
3826
+ //#endregion
3827
+ //#region src/adapters/env/SystemEnvAdapter.ts
3828
+ var SystemEnvAdapter = class {
3829
+ #source;
3830
+ constructor(deps = {}) {
3831
+ this.#source = deps.source ?? runtimeEnv();
3832
+ }
3833
+ require = (key) => Effect.try({
3834
+ try: () => parseEnvValue(key, this.#source[key], true),
3835
+ catch: (cause) => catchEnvError(key, cause)
3836
+ });
3837
+ optional = (key) => Effect.try({
3838
+ try: () => parseEnvValue(key, this.#source[key], false),
3839
+ catch: (cause) => catchEnvError(key, cause)
3840
+ });
3841
+ has = (key) => Effect.try({
3842
+ try: () => hasEnvValue(key, this.#source[key]),
3843
+ catch: (cause) => catchEnvError(key, cause)
3844
+ });
3845
+ };
3846
+ function SystemEnvLayer(deps = {}) {
3847
+ return Layer.succeed(EnvPortTag, new SystemEnvAdapter(deps));
3848
+ }
3849
+ //#endregion
3850
+ //#region src/ports/evm-signer.ts
3851
+ var EvmSignerError = class extends Data.TaggedError("EvmSignerError") {};
3852
+ function evmSignerErrorFromCapxul(operation, error, cause = error) {
3853
+ return new EvmSignerError({
3854
+ publicError: error,
3855
+ publicCode: error.code,
3856
+ operation,
3857
+ ...error.details === void 0 ? {} : { details: error.details },
3858
+ cause
3859
+ });
3860
+ }
3861
+ var EvmSignerPortTag = class extends Context.Tag("@capxul/sdk/ports/EvmSignerPort")() {};
3862
+ //#endregion
3863
+ //#region src/adapters/evm-signer/UnavailableEvmSignerAdapter.ts
3864
+ var UnavailableEvmSignerAdapter = class {
3865
+ getAddress = Effect.fail(evmSignerErrorFromCapxul("getAddress", Errors.notImplemented("evmSigner", "getAddress")));
3866
+ signMessage(_message) {
3867
+ return Effect.fail(evmSignerErrorFromCapxul("signMessage", Errors.notImplemented("evmSigner", "signMessage")));
3868
+ }
3869
+ signUserOp(_userOperation) {
3870
+ return Effect.fail(evmSignerErrorFromCapxul("signUserOp", Errors.notImplemented("evmSigner", "signUserOp")));
3871
+ }
3872
+ };
3873
+ function UnavailableEvmSignerLayer() {
3874
+ return Layer.effect(EvmSignerPortTag, Effect.succeed(new UnavailableEvmSignerAdapter()));
3875
+ }
3876
+ //#endregion
3877
+ //#region src/adapters/convex-identity.ts
3878
+ const identityLoadByAuthUserIdQuery = makeFunctionReference("identity/queries:loadByAuthUserId");
3879
+ const identityCreateMutation = makeFunctionReference("identity/mutations:create");
3880
+ const identityUpdateMutation = makeFunctionReference("identity/mutations:update");
3881
+ var ConvexIdentityAdapter = class {
3882
+ #convex;
3883
+ constructor(deps) {
3884
+ this.#convex = deps.convex;
3885
+ }
3886
+ loadByAuthUserId(authUserId) {
3887
+ return this.#convex.query(identityLoadByAuthUserIdQuery, { authUserId }).pipe(Effect.mapError((error) => identityErrorFromCapxul("loadByAuthUserId", error.publicError, error)), Effect.flatMap((row) => Effect.try({
3888
+ try: () => row === null ? null : brandProfile(row),
3889
+ catch: (cause) => identityErrorFromUnknown("loadByAuthUserId", cause)
3890
+ })), Effect.catchAllDefect((cause) => Effect.fail(identityErrorFromUnknown("loadByAuthUserId", cause))));
3891
+ }
3892
+ create(input) {
3893
+ return this.#convex.mutation(identityCreateMutation, input).pipe(Effect.mapError((error) => identityErrorFromCapxul("create", error.publicError, error)), Effect.flatMap((row) => Effect.try({
3894
+ try: () => brandProfile(row),
3895
+ catch: (cause) => identityErrorFromUnknown("create", cause)
3896
+ })), Effect.catchAllDefect((cause) => Effect.fail(identityErrorFromUnknown("create", cause))));
3897
+ }
3898
+ update(input) {
3899
+ return this.#convex.mutation(identityUpdateMutation, input).pipe(Effect.mapError((error) => identityErrorFromCapxul("update", error.publicError, error)), Effect.flatMap((row) => Effect.try({
3900
+ try: () => brandProfile(row),
3901
+ catch: (cause) => identityErrorFromUnknown("update", cause)
3902
+ })), Effect.catchAllDefect((cause) => Effect.fail(identityErrorFromUnknown("update", cause))));
3903
+ }
3904
+ };
3905
+ function ConvexIdentityLayer() {
3906
+ return Layer.effect(IdentityPortTag, Effect.map(ConvexCallPortTag, (convex) => new ConvexIdentityAdapter({ convex })));
3907
+ }
3908
+ function brandProfile(raw) {
3909
+ return {
3910
+ authUserId: toAuthUserId(raw.authUserId),
3911
+ email: toEmail(raw.email),
3912
+ displayName: raw.displayName,
3913
+ country: raw.country === null ? null : toCountryCode(raw.country),
3914
+ kycTier: toKycTier(raw.kycTier),
3915
+ createdAt: toEpochMs(raw.createdAt),
3916
+ updatedAt: toEpochMs(raw.updatedAt)
3917
+ };
3918
+ }
3919
+ function identityErrorFromUnknown(operation, cause) {
3920
+ if (cause instanceof CapxulError) return identityErrorFromCapxul(operation, cause);
3921
+ return identityErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
3922
+ }
3923
+ //#endregion
3924
+ //#region src/ports/account-read.ts
3925
+ var AccountReadError = class extends Data.TaggedError("AccountReadError") {};
3926
+ function accountReadErrorFromCapxul(operation, error, cause = error) {
3927
+ return new AccountReadError({
3928
+ operation,
3929
+ publicCode: error.code,
3930
+ publicError: error,
3931
+ cause,
3932
+ ...error.details === void 0 ? {} : { details: error.details }
3933
+ });
3934
+ }
3935
+ var AccountReadPortTag = class extends Context.Tag("@capxul/sdk/ports/AccountReadPort")() {};
3936
+ //#endregion
3937
+ //#region src/adapters/account-read/ConvexAccountAdapter.ts
3938
+ const DEFAULT_FUNCTIONS$2 = {
3939
+ readBalance: makeFunctionReference("account/actions:readBalance"),
3940
+ faucetMint: makeFunctionReference("account/actions:faucetMint")
3941
+ };
3942
+ var ConvexAccountAdapter = class {
3943
+ #convex;
3944
+ #fns;
3945
+ constructor(deps) {
3946
+ this.#convex = deps.convex;
3947
+ this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$2;
3948
+ }
3949
+ readBalance(input) {
3950
+ return this.#convex.action(this.#fns.readBalance, { chainId: wireChainId(input.chainId) }).pipe(Effect.mapError((error) => accountReadErrorFromCapxul("readBalance", error.publicError, error)), Effect.flatMap((wire) => brandAccountEffect("readBalance", wire)), Effect.catchAllDefect((cause) => Effect.fail(accountReadErrorFromUnknown("readBalance", cause))));
3951
+ }
3952
+ fundFromFaucet(input) {
3953
+ const operation = "fundFromFaucet";
3954
+ return Effect.suspend(() => {
3955
+ const rawAmount = toWei(input.amount);
3956
+ return this.#convex.action(this.#fns.faucetMint, {
3957
+ chainId: wireChainId(input.chainId),
3958
+ rawAmount
3959
+ });
3960
+ }).pipe(Effect.mapError((error) => accountReadErrorFromCapxul(operation, error.publicError, error)), Effect.map((wire) => ({ txHash: wire.txHash })), Effect.catchAllDefect((cause) => Effect.fail(accountReadErrorFromUnknown(operation, cause))));
3961
+ }
3962
+ };
3963
+ function ConvexAccountLayer() {
3964
+ return Layer.effect(AccountReadPortTag, Effect.map(ConvexCallPortTag, (convex) => new ConvexAccountAdapter({ convex })));
3965
+ }
3966
+ function brandAccountEffect(operation, wire) {
3967
+ return Effect.try({
3968
+ try: () => brandAccount(wire),
3969
+ catch: (cause) => accountReadErrorFromUnknown(operation, cause)
3970
+ });
3971
+ }
3972
+ function brandAccount(wire) {
3973
+ const balance = fromWei(wire.rawBalance, wire.decimals, wire.currency);
3974
+ const available = fromWei(wire.rawAvailableBalance ?? wire.rawBalance, wire.decimals, wire.currency);
3975
+ return {
3976
+ id: toAccountId(wire.accountId),
3977
+ balance,
3978
+ available
3979
+ };
3980
+ }
3981
+ function accountReadErrorFromUnknown(operation, cause) {
3982
+ if (cause instanceof CapxulError) return accountReadErrorFromCapxul(operation, cause);
3983
+ return accountReadErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
3984
+ }
3985
+ //#endregion
3986
+ //#region src/ports/sub-account.ts
3987
+ var SubAccountError = class extends Data.TaggedError("SubAccountError") {};
3988
+ function subAccountErrorFromCapxul(operation, error, cause = error) {
3989
+ return new SubAccountError({
3990
+ operation,
3991
+ publicCode: error.code,
3992
+ publicError: error,
3993
+ cause,
3994
+ ...error.details === void 0 ? {} : { details: error.details }
3995
+ });
3996
+ }
3997
+ var SubAccountPortTag = class extends Context.Tag("@capxul/sdk/ports/SubAccountPort")() {};
3998
+ //#endregion
3999
+ //#region src/adapters/sub-account/ConvexSubAccountAdapter.ts
4000
+ const DEFAULT_FUNCTIONS$1 = {
4001
+ create: makeFunctionReference("subAccount/mutations:create"),
4002
+ get: makeFunctionReference("subAccount/queries:get"),
4003
+ list: makeFunctionReference("subAccount/queries:list"),
4004
+ rename: makeFunctionReference("subAccount/mutations:rename"),
4005
+ remove: makeFunctionReference("subAccount/mutations:remove"),
4006
+ transfer: makeFunctionReference("subAccount/actions:transfer")
4007
+ };
4008
+ var ConvexSubAccountAdapter = class {
4009
+ #convex;
4010
+ #fns;
4011
+ #chainId;
4012
+ constructor(deps) {
4013
+ this.#convex = deps.convex;
4014
+ this.#chainId = deps.chainId;
4015
+ this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$1;
4016
+ }
4017
+ create(input) {
4018
+ return this.#runMutation("create", this.#fns.create, {
4019
+ accountId: input.accountId,
4020
+ name: input.name
4021
+ });
4022
+ }
4023
+ get(input) {
4024
+ return this.#runQuery("get", this.#fns.get, { subAccountId: input.subAccountId }, (wire) => wire === null ? null : brandSubAccount(wire));
4025
+ }
4026
+ list(input) {
4027
+ return this.#runQuery("list", this.#fns.list, { accountId: input.accountId }, (wires) => wires.map((wire) => brandSubAccount(wire)));
4028
+ }
4029
+ rename(input) {
4030
+ return this.#runMutation("rename", this.#fns.rename, {
4031
+ subAccountId: input.subAccountId,
4032
+ name: input.name
4033
+ });
4034
+ }
4035
+ delete(input) {
4036
+ const operation = "delete";
4037
+ return this.#convex.mutation(this.#fns.remove, { subAccountId: input.subAccountId }).pipe(Effect.mapError((error) => subAccountErrorFromCapxul(operation, error.publicError, error)), Effect.asVoid, Effect.catchAllDefect((cause) => Effect.fail(subAccountErrorFromUnknown(operation, cause))));
4038
+ }
4039
+ transfer(input) {
4040
+ const operation = "transfer";
4041
+ return Effect.suspend(() => {
4042
+ const rawAmount = toWei(input.amount);
4043
+ return this.#convex.action(this.#fns.transfer, {
4044
+ chainId: this.#chainId,
4045
+ from: input.from,
4046
+ to: input.to,
4047
+ rawAmount
4048
+ });
4049
+ }).pipe(Effect.mapError((error) => subAccountErrorFromCapxul(operation, error.publicError, error)), Effect.map((wire) => brandTransferResult(wire)), Effect.catchAllDefect((cause) => Effect.fail(subAccountErrorFromUnknown(operation, cause))));
4050
+ }
4051
+ #runMutation(operation, ref, args) {
4052
+ return this.#convex.mutation(ref, args).pipe(Effect.mapError((error) => subAccountErrorFromCapxul(operation, error.publicError, error)), Effect.map((wire) => brandSubAccount(wire)), Effect.catchAllDefect((cause) => Effect.fail(subAccountErrorFromUnknown(operation, cause))));
4053
+ }
4054
+ #runQuery(operation, ref, args, map) {
4055
+ return this.#convex.query(ref, args).pipe(Effect.mapError((error) => subAccountErrorFromCapxul(operation, error.publicError, error)), Effect.map(map), Effect.catchAllDefect((cause) => Effect.fail(subAccountErrorFromUnknown(operation, cause))));
4056
+ }
4057
+ };
4058
+ function ConvexSubAccountLayer(chainId) {
4059
+ return Layer.effect(SubAccountPortTag, Effect.map(ConvexCallPortTag, (convex) => new ConvexSubAccountAdapter({
4060
+ convex,
4061
+ chainId
4062
+ })));
4063
+ }
4064
+ function brandTransferResult(wire) {
4065
+ return {
4066
+ available: fromWei(wire.availableRaw, wire.decimals, wire.currency),
4067
+ from: wire.from === null ? null : brandSubAccount(wire.from),
4068
+ to: wire.to === null ? null : brandSubAccount(wire.to)
4069
+ };
4070
+ }
4071
+ function brandSubAccount(wire) {
4072
+ return {
4073
+ id: toSubAccountId(wire.subAccountId),
4074
+ accountId: toAccountId(wire.accountId),
4075
+ name: wire.name,
4076
+ balance: fromWei(wire.rawBalance, wire.decimals, wire.currency),
4077
+ createdAt: toEpochMs(wire.createdAt)
4078
+ };
4079
+ }
4080
+ function subAccountErrorFromUnknown(operation, cause) {
4081
+ if (cause instanceof CapxulError) return subAccountErrorFromCapxul(operation, cause);
4082
+ return subAccountErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
4083
+ }
4084
+ //#endregion
4085
+ //#region src/ports/smart-account.ts
4086
+ var SmartAccountError = class extends Data.TaggedError("SmartAccountError") {};
4087
+ function smartAccountErrorFromCapxul(operation, error, cause = error) {
4088
+ return new SmartAccountError({
4089
+ operation,
4090
+ publicCode: error.code,
4091
+ publicError: error,
4092
+ cause,
4093
+ ...error.details === void 0 ? {} : { details: error.details }
4094
+ });
4095
+ }
4096
+ var SmartAccountPortTag = class extends Context.Tag("@capxul/sdk/ports/SmartAccountPort")() {};
4097
+ //#endregion
4098
+ //#region src/adapters/smart-account/ConvexSmartAccountAdapter.ts
4099
+ const DEFAULT_FUNCTIONS = {
4100
+ loadByAuthUserId: makeFunctionReference("smartAccount/queries:loadByAuthUserId"),
4101
+ loadBySmartAccountAddress: makeFunctionReference("smartAccount/queries:loadBySmartAccountAddress"),
4102
+ provision: makeFunctionReference("smartAccount/mutations:provision"),
4103
+ confirmDeployment: makeFunctionReference("smartAccount/actions:confirmDeployment"),
4104
+ deployPrepare: makeFunctionReference("smartAccount/actions:deployPrepare"),
4105
+ deploySubmit: makeFunctionReference("smartAccount/actions:deploySubmit")
4106
+ };
4107
+ var ConvexSmartAccountAdapter = class {
4108
+ #convex;
4109
+ #fns;
4110
+ constructor(deps) {
4111
+ this.#convex = deps.convex;
4112
+ this.#fns = deps.functions ?? DEFAULT_FUNCTIONS;
4113
+ }
4114
+ loadByAuthUserId(authUserId) {
4115
+ return this.#convex.query(this.#fns.loadByAuthUserId, { authUserId }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("loadByAuthUserId", error.publicError, error)), Effect.flatMap((row) => brandSmartAccountEffect("loadByAuthUserId", row)), Effect.catchAllDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("loadByAuthUserId", cause))));
4116
+ }
4117
+ loadBySmartAccountAddress(address) {
4118
+ return this.#convex.query(this.#fns.loadBySmartAccountAddress, { address }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("loadBySmartAccountAddress", error.publicError, error)), Effect.flatMap((row) => brandSmartAccountEffect("loadBySmartAccountAddress", row)), Effect.catchAllDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("loadBySmartAccountAddress", cause))));
4119
+ }
4120
+ provision(input) {
4121
+ return this.#convex.mutation(this.#fns.provision, {
4122
+ signerAddress: input.signerAddress,
4123
+ chainId: wireChainId(input.chainId)
4124
+ }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("provision", error.publicError, error)), Effect.flatMap((row) => Effect.try({
4125
+ try: () => brandProvisionedSmartAccount(input.authUserId, row),
4126
+ catch: (cause) => smartAccountErrorFromUnknown("provision", cause)
4127
+ })), Effect.catchAllDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("provision", cause))));
4128
+ }
4129
+ confirmDeployment(input) {
4130
+ const evidence = {
4131
+ chainId: wireChainId(input.evidence.chainId),
4132
+ signerAddress: input.evidence.signerAddress,
4133
+ safeAddress: input.evidence.safeAddress,
4134
+ ...input.evidence.userOpHash === void 0 ? {} : { userOpHash: input.evidence.userOpHash },
4135
+ ...input.evidence.txHash === void 0 ? {} : { txHash: input.evidence.txHash },
4136
+ ...input.evidence.blockNumber === void 0 ? {} : { blockNumber: input.evidence.blockNumber }
4137
+ };
4138
+ return this.#convex.action(this.#fns.confirmDeployment, {
4139
+ chainId: wireChainId(input.chainId),
4140
+ safeAddress: input.safeAddress,
4141
+ ...input.telemetryRunId === void 0 ? {} : { telemetryRunId: input.telemetryRunId },
4142
+ evidence
4143
+ }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("confirmDeployment", error.publicError, error)), Effect.flatMap((row) => Effect.try({
4144
+ try: () => brandProvisionedSmartAccount(input.authUserId, row),
4145
+ catch: (cause) => smartAccountErrorFromUnknown("confirmDeployment", cause)
4146
+ })), Effect.catchAllDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("confirmDeployment", cause))));
4147
+ }
4148
+ deployPrepare(input) {
4149
+ return this.#convex.action(this.#fns.deployPrepare, {
4150
+ chainId: wireChainId(input.chainId),
4151
+ ...input.telemetryRunId === void 0 ? {} : { telemetryRunId: input.telemetryRunId }
4152
+ }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("deployPrepare", error.publicError, error)), Effect.flatMap((result) => Effect.try({
4153
+ try: () => {
4154
+ if (typeof result.digest !== "string" || !isHex(result.digest) || result.digest.length !== 66) throw Errors.invalidInput("digest", "must be 0x-prefixed 32-byte hex");
4155
+ return {
4156
+ digest: result.digest,
4157
+ safeAddress: toAddress(result.safeAddress),
4158
+ userOp: result.userOp
4159
+ };
4160
+ },
4161
+ catch: (cause) => smartAccountErrorFromUnknown("deployPrepare", cause)
4162
+ })), Effect.catchAllDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("deployPrepare", cause))));
4163
+ }
4164
+ deploySubmit(input) {
4165
+ return this.#convex.action(this.#fns.deploySubmit, {
4166
+ chainId: wireChainId(input.chainId),
4167
+ signature: input.signature,
4168
+ userOp: input.userOp,
4169
+ ...input.telemetryRunId === void 0 ? {} : { telemetryRunId: input.telemetryRunId }
4170
+ }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("deploySubmit", error.publicError, error)), Effect.flatMap((row) => Effect.try({
4171
+ try: () => brandProvisionedSmartAccount(input.authUserId, row),
4172
+ catch: (cause) => smartAccountErrorFromUnknown("deploySubmit", cause)
4173
+ })), Effect.catchAllDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("deploySubmit", cause))));
4174
+ }
4175
+ };
4176
+ function ConvexSmartAccountLayer() {
4177
+ return Layer.effect(SmartAccountPortTag, Effect.map(ConvexCallPortTag, (convex) => new ConvexSmartAccountAdapter({ convex })));
4178
+ }
4179
+ function brandSmartAccountEffect(operation, wire) {
4180
+ return Effect.try({
4181
+ try: () => wire === null ? null : brandNonNullSmartAccount(wire),
4182
+ catch: (cause) => smartAccountErrorFromUnknown(operation, cause)
4183
+ });
4184
+ }
4185
+ function brandNonNullSmartAccount(wire) {
4186
+ return {
4187
+ authUserId: toAuthUserId(wire.authUserId),
4188
+ signerAddress: toAddress(wire.signerAddress),
4189
+ smartAccountAddress: toAddress(wire.smartAccountAddress),
4190
+ chainId: toChainId(wire.chainId),
4191
+ deployedAt: wire.deployedAt === null ? null : toEpochMs(wire.deployedAt),
4192
+ createdAt: toEpochMs(wire.createdAt)
4193
+ };
4194
+ }
4195
+ function brandProvisionedSmartAccount(requestedAuthUserId, wire) {
4196
+ if (wire.authUserId !== String(requestedAuthUserId)) throw Errors.notAuthenticated();
4197
+ return brandNonNullSmartAccount(wire);
4198
+ }
4199
+ function smartAccountErrorFromUnknown(operation, cause) {
4200
+ if (cause instanceof CapxulError) return smartAccountErrorFromCapxul(operation, cause);
4201
+ return smartAccountErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
4202
+ }
4203
+ toAddress("0xa6b71e26c5e0845f74c812102ca7114b6a896ab2");
4204
+ keccak256("0x");
4205
+ `${"ab".repeat(32)}`;
4206
+ //#endregion
4207
+ //#region src/adapters/telemetry/PostHogTelemetryAdapter.ts
4208
+ var PostHogTelemetryAdapter = class {
4209
+ #capture;
4210
+ #identify;
4211
+ #group;
4212
+ #reset;
4213
+ constructor(deps) {
4214
+ this.#capture = deps.capture;
4215
+ this.#identify = deps.identify ?? (() => void 0);
4216
+ this.#group = deps.group ?? (() => void 0);
4217
+ this.#reset = deps.reset ?? (() => void 0);
4218
+ }
4219
+ emit(event) {
4220
+ return Effect.sync(() => {
4221
+ this.#runFireAndForget(() => this.#capture(event.name, redactTelemetryProps(event.name, cloneProps(event.props))));
4222
+ });
4223
+ }
4224
+ identify(input) {
4225
+ return Effect.sync(() => {
4226
+ this.#runFireAndForget(() => this.#identify(cloneIdentifyInput(input)));
4227
+ });
4228
+ }
4229
+ group(input) {
4230
+ return Effect.sync(() => {
4231
+ this.#runFireAndForget(() => this.#group(cloneGroupInput(input)));
4232
+ });
4233
+ }
4234
+ reset() {
4235
+ return Effect.sync(() => {
4236
+ this.#runFireAndForget(() => this.#reset());
4237
+ });
4238
+ }
4239
+ #runFireAndForget(operation) {
4240
+ try {
4241
+ Promise.resolve(operation()).catch(() => {});
4242
+ } catch {}
4243
+ }
4244
+ };
4245
+ function PostHogTelemetryLayer(deps) {
4246
+ return Layer.succeed(TelemetryPortTag, new PostHogTelemetryAdapter(deps));
4247
+ }
4248
+ function cloneIdentifyInput(input) {
4249
+ const traits = input.traits === void 0 ? void 0 : cloneProps(input.traits);
4250
+ const properties = input.properties === void 0 ? void 0 : cloneProps(input.properties);
4251
+ return {
4252
+ distinctId: input.distinctId,
4253
+ ...input.anonDistinctId === void 0 ? {} : { anonDistinctId: input.anonDistinctId },
4254
+ ...traits === void 0 ? {} : { traits },
4255
+ ...properties === void 0 ? {} : { properties }
4256
+ };
4257
+ }
4258
+ function cloneGroupInput(input) {
4259
+ const properties = input.properties === void 0 ? void 0 : cloneProps(input.properties);
4260
+ return properties === void 0 ? {
4261
+ groupType: input.groupType,
4262
+ groupKey: input.groupKey
4263
+ } : {
4264
+ groupType: input.groupType,
4265
+ groupKey: input.groupKey,
4266
+ properties
4267
+ };
4268
+ }
4269
+ function cloneProps(props) {
4270
+ if (props === void 0) return void 0;
4271
+ const cloned = {};
4272
+ for (const [key, value] of Object.entries(props)) cloned[key] = cloneTelemetryValue(value);
4273
+ return cloned;
4274
+ }
4275
+ function cloneTelemetryValue(value) {
4276
+ if (Array.isArray(value)) return value.map(cloneTelemetryValue);
4277
+ if (value === null || typeof value !== "object") return value;
4278
+ if (Object.getPrototypeOf(value) !== Object.prototype) return value;
4279
+ const cloned = {};
4280
+ for (const [key, nested] of Object.entries(value)) cloned[key] = cloneTelemetryValue(nested);
4281
+ return cloned;
4282
+ }
4283
+ //#endregion
4284
+ //#region src/ports/transport.ts
4285
+ var TransportError = class extends Data.TaggedError("TransportError") {};
4286
+ function transportErrorFromCapxul(operation, request, error, cause = error) {
4287
+ return new TransportError({
4288
+ operation,
4289
+ name: request.name,
4290
+ publicCode: error.code,
4291
+ publicError: error,
4292
+ cause,
4293
+ ...request.correlationId === void 0 ? {} : { correlationId: request.correlationId },
4294
+ ...error.details === void 0 ? {} : { details: error.details }
4295
+ });
4296
+ }
4297
+ var TransportPortTag = class extends Context.Tag("@capxul/sdk/ports/TransportPort")() {};
4298
+ //#endregion
4299
+ //#region src/adapters/transport/ConvexTransportAdapter.ts
4300
+ var ConvexTransportAdapter = class {
4301
+ #convex;
4302
+ constructor(convex) {
4303
+ this.#convex = convex;
4304
+ }
4305
+ runQuery(request) {
4306
+ return this.#call("query", request, () => {
4307
+ const fn = makeFunctionReference(request.name);
4308
+ return this.#convex.query(fn, asRecordArgs(request.args));
4309
+ });
4310
+ }
4311
+ runMutation(request) {
4312
+ return this.#call("mutation", request, () => {
4313
+ const fn = makeFunctionReference(request.name);
4314
+ return this.#convex.mutation(fn, asRecordArgs(request.args));
4315
+ });
4316
+ }
4317
+ runAction(request) {
4318
+ return this.#call("action", request, () => {
4319
+ const fn = makeFunctionReference(request.name);
4320
+ return this.#convex.action(fn, asRecordArgs(request.args));
4321
+ });
4322
+ }
4323
+ #call(operation, request, run) {
4324
+ return Effect.try({
4325
+ try: run,
4326
+ catch: (cause) => transportErrorFromThrown(operation, request, cause)
4327
+ }).pipe(Effect.flatMap((effect) => effect.pipe(Effect.mapError((error) => transportErrorFromConvex(operation, request, error)), Effect.catchAllDefect((cause) => Effect.fail(transportErrorFromThrown(operation, request, cause))))));
4328
+ }
4329
+ };
4330
+ function ConvexTransportLayer(_deps = {}) {
4331
+ return Layer.effect(TransportPortTag, Effect.gen(function* () {
4332
+ return new ConvexTransportAdapter(yield* ConvexCallPortTag);
4333
+ }));
4334
+ }
4335
+ function transportErrorFromConvex(operation, request, error) {
4336
+ return transportErrorFromCapxul(operation, request, error.publicError, error.cause);
4337
+ }
4338
+ function asRecordArgs(args) {
4339
+ if (args !== null && typeof args === "object" && !Array.isArray(args)) return args;
4340
+ return { value: args };
4341
+ }
4342
+ function transportErrorFromThrown(operation, request, cause) {
4343
+ return transportErrorFromCapxul(operation, request, cause instanceof Error ? Errors.providerError("transport", request.name, cause) : Errors.providerError("transport", request.name, new Error(String(cause))), cause);
4344
+ }
4345
+ const SDK_VERSION = version;
4346
+ const collectProductionFlowPorts = Effect.gen(function* () {
4347
+ const authClient = yield* AuthClientPortTag;
4348
+ const authCache = yield* AuthCachePortTag;
4349
+ const bootstrap = yield* BootstrapPortTag;
4350
+ const clock = yield* ClockPortTag;
4351
+ const convexCall = yield* ConvexCallPortTag;
4352
+ const credentials = yield* CredentialsPortTag;
4353
+ const env = yield* EnvPortTag;
4354
+ const evmSigner = yield* EvmSignerPortTag;
4355
+ return {
4356
+ authClient,
4357
+ authCache,
4358
+ identity: yield* IdentityPortTag,
4359
+ smartAccount: yield* SmartAccountPortTag,
4360
+ accountRead: yield* AccountReadPortTag,
4361
+ subAccount: yield* SubAccountPortTag,
4362
+ credentials,
4363
+ bootstrap,
4364
+ evmSigner,
4365
+ clock,
4366
+ env,
4367
+ telemetry: yield* TelemetryPortTag,
4368
+ transport: yield* TransportPortTag,
4369
+ convexCall
4370
+ };
4371
+ });
4372
+ function makeProductionAdapterLayerEntries(input) {
4373
+ const refreshConvexAuthRef = {
4374
+ current: null,
4375
+ pending: false
4376
+ };
4377
+ return [
4378
+ {
4379
+ name: "bootstrap",
4380
+ layer: productionBootstrapPortLayer(input.bootstrap)
4381
+ },
4382
+ {
4383
+ name: "authClient",
4384
+ layer: productionAuthClientLayer(input, refreshConvexAuthRef)
4385
+ },
4386
+ {
4387
+ name: "authCache",
4388
+ layer: productionAuthCacheLayer(input)
4389
+ },
4390
+ {
4391
+ name: "identity",
4392
+ layer: ConvexIdentityLayer()
4393
+ },
4394
+ {
4395
+ name: "smartAccount",
4396
+ layer: ConvexSmartAccountLayer()
4397
+ },
4398
+ {
4399
+ name: "accountRead",
4400
+ layer: ConvexAccountLayer()
4401
+ },
4402
+ {
4403
+ name: "subAccount",
4404
+ layer: ConvexSubAccountLayer(input.chainId)
4405
+ },
4406
+ {
4407
+ name: "credentials",
4408
+ layer: ConvexCredentialsLayer()
4409
+ },
4410
+ {
4411
+ name: "evmSigner",
4412
+ layer: input.evmSigner === void 0 ? UnavailableEvmSignerLayer() : Layer.succeed(EvmSignerPortTag, input.evmSigner)
4413
+ },
4414
+ {
4415
+ name: "clock",
4416
+ layer: SystemClockLayer()
4417
+ },
4418
+ {
4419
+ name: "env",
4420
+ layer: SystemEnvLayer()
4421
+ },
4422
+ {
4423
+ name: "telemetry",
4424
+ layer: input.telemetry === void 0 ? PostHogTelemetryLayer({ capture: () => void 0 }) : Layer.succeed(TelemetryPortTag, input.telemetry)
4425
+ },
4426
+ {
4427
+ name: "transport",
4428
+ layer: ConvexTransportLayer()
4429
+ },
4430
+ {
4431
+ name: "convexCall",
4432
+ layer: productionConvexCallLayer(input, refreshConvexAuthRef)
4433
+ }
4434
+ ];
4435
+ }
4436
+ function mergeProductionAdapterLayers(entries) {
4437
+ const byName = /* @__PURE__ */ new Map();
4438
+ for (const entry of entries) byName.set(entry.name, entry.layer);
4439
+ const authClientLayer = byName.get("authClient");
4440
+ const convexCallLayer = byName.get("convexCall");
4441
+ const convexCallReadyLayer = convexCallLayer === void 0 || authClientLayer === void 0 ? convexCallLayer : convexCallLayer.pipe(Layer.provide(authClientLayer));
4442
+ return entries.map((entry) => {
4443
+ const layer = byName.get(entry.name) ?? entry.layer;
4444
+ if (entry.name === "convexCall") return convexCallReadyLayer ?? layer;
4445
+ if (isConvexDependentLayer(entry.name)) return convexCallReadyLayer === void 0 ? layer : layer.pipe(Layer.provide(convexCallReadyLayer));
4446
+ return layer;
4447
+ }).reduce((current, layer) => Layer.merge(current, layer), Layer.empty);
4448
+ }
4449
+ function isConvexDependentLayer(name) {
4450
+ return name === "identity" || name === "smartAccount" || name === "accountRead" || name === "subAccount" || name === "credentials" || name === "transport";
4451
+ }
4452
+ function productionBootstrapPortLayer(bootstrap) {
4453
+ return Layer.succeed(BootstrapPortTag, bootstrap);
4454
+ }
4455
+ function productionAuthClientLayer(input, refreshConvexAuthRef) {
4456
+ return (input.runtime === "browser" ? BetterAuthBrowserLayer({
4457
+ authBaseUrl: input.runtimeUrls.authBaseUrl,
4458
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch }
4459
+ }) : BetterAuthNodeLayer({
4460
+ authBaseUrl: input.runtimeUrls.authBaseUrl,
4461
+ ...input.origin === void 0 ? {} : { origin: input.origin },
4462
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch }
4463
+ })).pipe(Layer.map((context) => {
4464
+ const authClient = Context.get(context, AuthClientPortTag);
4465
+ return Context.make(AuthClientPortTag, refreshConvexAuthOnSession(authClient, () => {
4466
+ const refresh = refreshConvexAuthRef.current;
4467
+ if (refresh === null) {
4468
+ refreshConvexAuthRef.pending = true;
4469
+ return;
4470
+ }
4471
+ refresh();
4472
+ }));
4473
+ }));
4474
+ }
4475
+ function productionAuthCacheLayer(input) {
4476
+ return Layer.succeed(AuthCachePortTag, input.authCache ?? detectAuthCacheAdapter());
4477
+ }
4478
+ function productionConvexCallLayer(input, refreshConvexAuthRef) {
4479
+ return Layer.unwrapEffect(Effect.map(AuthClientPortTag, (authClient) => ConvexCallLayer({
4480
+ convexUrl: input.runtimeUrls.convexUrl,
4481
+ ...input.convexClient === void 0 ? {} : { client: input.convexClient },
4482
+ tokenProvider: async ({ forceRefreshToken }) => {
4483
+ const tokenResult = await Effect.runPromise(Effect.either(authClient.getConvexJwt({
4484
+ forceRefresh: forceRefreshToken,
4485
+ ...input.signal === void 0 ? {} : { signal: input.signal }
4486
+ })));
4487
+ if (Either.isLeft(tokenResult)) return null;
4488
+ return String(tokenResult.right.token);
4489
+ }
4490
+ }).pipe(Layer.map((context) => {
4491
+ const convexCall = Context.get(context, ConvexCallPortTag);
4492
+ if (isRefreshableConvexCallPort(convexCall)) {
4493
+ refreshConvexAuthRef.current = () => convexCall.refreshAuth();
4494
+ if (refreshConvexAuthRef.pending) {
4495
+ refreshConvexAuthRef.pending = false;
4496
+ refreshConvexAuthRef.current();
4497
+ }
4498
+ }
4499
+ return context;
4500
+ }))));
4501
+ }
4502
+ function isRefreshableConvexCallPort(convexCall) {
4503
+ return "refreshAuth" in convexCall && typeof convexCall.refreshAuth === "function";
4504
+ }
4505
+ async function createProductionAdapters(input) {
4506
+ const resolvedInput = resolveInput(input);
4507
+ if (!resolvedInput.ok) return resolvedInput;
4508
+ const scope = await Effect.runPromise(Scope.make());
4509
+ const closeScope = idempotentClose(() => Effect.runPromise(Scope.close(scope, Exit.void)));
4510
+ const bootstrapLayer = HttpBootstrapLayer({
4511
+ bootstrapBaseUrl: resolvedInput.value.bootstrapBaseUrl,
4512
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch }
4513
+ });
4514
+ try {
4515
+ const bootstrapContext = await Effect.runPromise(Layer.buildWithScope(bootstrapLayer, scope));
4516
+ const bootstrap = Context.get(bootstrapContext, BootstrapPortTag);
4517
+ const bootstrapResult = await runBootstrap(bootstrap.resolve({
4518
+ publishableKey: resolvedInput.value.publishableKey,
4519
+ ...resolvedInput.value.origin === void 0 ? {} : { origin: resolvedInput.value.origin }
4520
+ }));
4521
+ if (!bootstrapResult.ok) {
4522
+ await emitBootstrapTelemetry(input.telemetry, {
4523
+ name: "bootstrap_failed",
4524
+ props: {
4525
+ ...bootstrapTelemetryEnvelope(input, resolvedInput.value),
4526
+ reason: bootstrapResult.error.code
4527
+ }
4528
+ });
4529
+ await closeScope().catch(() => void 0);
4530
+ return bootstrapResult;
4531
+ }
4532
+ const runtimeUrls = resolveRuntimeUrls(bootstrapResult.value);
4533
+ if (!runtimeUrls.ok) {
4534
+ await emitBootstrapTelemetry(input.telemetry, {
4535
+ name: "bootstrap_failed",
4536
+ props: {
4537
+ ...bootstrapTelemetryEnvelope(input, resolvedInput.value),
4538
+ applicationId: bootstrapResult.value.applicationId,
4539
+ reason: runtimeUrls.error.code
4540
+ }
4541
+ });
4542
+ await closeScope().catch(() => void 0);
4543
+ return runtimeUrls;
4544
+ }
4545
+ await emitBootstrapTelemetry(input.telemetry, {
4546
+ name: "bootstrap_resolved",
4547
+ props: {
4548
+ ...bootstrapTelemetryEnvelope(input, resolvedInput.value),
4549
+ applicationId: bootstrapResult.value.applicationId
4550
+ }
4551
+ });
4552
+ let injectedClient;
4553
+ const convexClientFactory = input.convexClientFactory;
4554
+ if (convexClientFactory !== void 0) try {
4555
+ injectedClient = convexClientFactory(runtimeUrls.value.convexUrl);
4556
+ } catch (cause) {
4557
+ await closeScope().catch(() => void 0);
4558
+ return {
4559
+ ok: false,
4560
+ error: toPublicError(cause, "createProductionAdapters")
4561
+ };
4562
+ }
4563
+ const portsLayer = mergeProductionAdapterLayers(makeProductionAdapterLayerEntries({
4564
+ bootstrap,
4565
+ runtime: resolvedInput.value.runtime,
4566
+ ...resolvedInput.value.origin === void 0 ? {} : { origin: resolvedInput.value.origin },
4567
+ runtimeUrls: runtimeUrls.value,
4568
+ chainId: bootstrapResult.value.chainId,
4569
+ ...input.authCache === void 0 ? {} : { authCache: input.authCache },
4570
+ ...input.telemetry === void 0 ? {} : { telemetry: input.telemetry },
4571
+ ...input.evmSigner === void 0 ? {} : { evmSigner: input.evmSigner },
4572
+ ...injectedClient === void 0 ? {} : { convexClient: injectedClient },
4573
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch },
4574
+ ...input.signal === void 0 ? {} : { signal: input.signal }
4575
+ }));
4576
+ const portsContext = await Effect.runPromise(Layer.buildWithScope(portsLayer, scope));
4577
+ return {
4578
+ ok: true,
4579
+ value: {
4580
+ ports: await Effect.runPromise(collectProductionFlowPorts.pipe(Effect.provide(portsContext))),
4581
+ bootstrap: bootstrapResult.value,
4582
+ close: closeScope
4583
+ }
4584
+ };
4585
+ } catch (cause) {
4586
+ await closeScope().catch(() => void 0);
4587
+ return {
4588
+ ok: false,
4589
+ error: toPublicError(cause, "createProductionAdapters")
4590
+ };
4591
+ }
4592
+ }
4593
+ function refreshConvexAuthOnSession(authClient, refresh) {
4594
+ return {
4595
+ ...authClient,
4596
+ verifyOtp: (input, options) => authClient.verifyOtp(input, options).pipe(Effect.tap(() => Effect.sync(refresh))),
4597
+ signOut: (options) => authClient.signOut(options).pipe(Effect.tap(() => Effect.sync(refresh)))
4598
+ };
4599
+ }
4600
+ async function createCapxulClient(input) {
4601
+ const adapters = await createProductionAdapters(input);
4602
+ if (!adapters.ok) return adapters;
4603
+ try {
4604
+ const orgDeploymentPort = input.orgDeploymentPortFactory === void 0 ? void 0 : input.orgDeploymentPortFactory(adapters.value.ports.convexCall);
4605
+ const client = assembleCapxulClient({
4606
+ ports: adapters.value.ports,
4607
+ bootstrap: adapters.value.bootstrap,
4608
+ authCache: adapters.value.ports.authCache,
4609
+ requirement: input.requirement ?? "none",
4610
+ ...input.signer === void 0 ? {} : { signer: input.signer },
4611
+ ...orgDeploymentPort === void 0 ? {} : {
4612
+ orgDeploymentPort,
4613
+ orgRolesDeploymentPort: orgDeploymentPort,
4614
+ orgSpendPort: orgDeploymentPort
4615
+ },
4616
+ ...input.orgDeploymentConfig === void 0 ? {} : { orgDeploymentConfig: input.orgDeploymentConfig },
4617
+ ...input.signal === void 0 ? {} : { signal: input.signal },
4618
+ ...input.otpTtlMs === void 0 ? {} : { otpTtlMs: input.otpTtlMs },
4619
+ invokeTimeoutMs: input.invokeTimeoutMs ?? 3e4
4620
+ });
4621
+ return {
4622
+ ok: true,
4623
+ value: {
4624
+ ...client,
4625
+ _internal: {
4626
+ ...client._internal,
4627
+ close: adapters.value.close
4628
+ }
4629
+ }
4630
+ };
4631
+ } catch (cause) {
4632
+ await adapters.value.close().catch(() => void 0);
4633
+ return {
4634
+ ok: false,
4635
+ error: toPublicError(cause, "createCapxulClient")
4636
+ };
4637
+ }
4638
+ }
4639
+ function resolveInput(input) {
4640
+ try {
4641
+ const runtime = input.runtime ?? detectRuntime();
4642
+ const publishableKey = toPublishableKey(input.publishableKey);
4643
+ const origin = input.origin === void 0 ? runtime === "browser" ? toAllowedOrigin(derivedBrowserOrigin(runtime)) : void 0 : toAllowedOrigin(input.origin);
4644
+ return {
4645
+ ok: true,
4646
+ value: {
4647
+ publishableKey,
4648
+ ...origin === void 0 ? {} : { origin },
4649
+ bootstrapBaseUrl: normalizeHttpUrl("bootstrapBaseUrl", input.bootstrapBaseUrl ?? "https://api.capxul.com"),
4650
+ runtime
4651
+ }
4652
+ };
4653
+ } catch (cause) {
4654
+ return {
4655
+ ok: false,
4656
+ error: toPublicError(cause, "createProductionAdapters")
4657
+ };
4658
+ }
4659
+ }
4660
+ function detectRuntime() {
4661
+ const globalAny = globalThis;
4662
+ return globalAny.window !== void 0 || globalAny.document !== void 0 ? "browser" : "node";
4663
+ }
4664
+ function derivedBrowserOrigin(runtime) {
4665
+ if (runtime !== "browser") throw Errors.invalidInput("origin", "required outside browser runtime");
4666
+ const globalAny = globalThis;
4667
+ if (typeof globalAny.location?.origin === "string" && globalAny.location.origin.length > 0) return globalAny.location.origin;
4668
+ throw Errors.invalidInput("origin", "required when browser location is unavailable");
4669
+ }
4670
+ function resolveRuntimeUrls(bootstrap) {
4671
+ try {
4672
+ return {
4673
+ ok: true,
4674
+ value: {
4675
+ authBaseUrl: normalizeHttpUrl("authBaseUrl", bootstrap.authBaseUrl),
4676
+ convexUrl: normalizeHttpUrl("convexUrl", bootstrap.convexUrl)
4677
+ }
4678
+ };
4679
+ } catch (cause) {
4680
+ return {
4681
+ ok: false,
4682
+ error: toPublicError(cause, "createProductionAdapters")
4683
+ };
4684
+ }
4685
+ }
4686
+ async function runBootstrap(effect) {
4687
+ const result = await Effect.runPromise(Effect.either(effect));
4688
+ if (Either.isRight(result)) return {
4689
+ ok: true,
4690
+ value: result.right
4691
+ };
4692
+ return {
4693
+ ok: false,
4694
+ error: toPublicError(result.left, "bootstrap.resolve")
4695
+ };
4696
+ }
4697
+ function bootstrapTelemetryEnvelope(input, resolvedInput) {
4698
+ return {
4699
+ capxulEnv: resolvedInput.runtime,
4700
+ env: input.requirement ?? "none",
4701
+ ...resolvedInput.origin === void 0 ? {} : { origin: resolvedInput.origin },
4702
+ sdkVersion: SDK_VERSION
4703
+ };
4704
+ }
4705
+ async function emitBootstrapTelemetry(telemetry, event) {
4706
+ if (telemetry === void 0) return;
4707
+ await Effect.runPromise(telemetry.emit(event).pipe(Effect.catchAllDefect(() => Effect.void)));
4708
+ }
4709
+ function normalizeHttpUrl(field, raw) {
4710
+ let parsed;
4711
+ try {
4712
+ parsed = new URL(raw);
4713
+ } catch {
4714
+ throw Errors.invalidInput(field, "must be an http or https URL");
4715
+ }
4716
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw Errors.invalidInput(field, "must be an http or https URL");
4717
+ return parsed.toString().replace(/\/$/, "");
4718
+ }
4719
+ function toPublicError(cause, operation) {
4720
+ if (cause instanceof CapxulError) return cause;
4721
+ if (typeof cause === "object" && cause !== null) {
4722
+ const publicError = cause.publicError;
4723
+ if (publicError instanceof CapxulError) return publicError;
4724
+ const nestedCause = cause.cause;
4725
+ if (nestedCause instanceof CapxulError) return nestedCause;
4726
+ }
4727
+ return Errors.providerError("sdk-production-adapters", operation, cause);
4728
+ }
4729
+ function idempotentClose(close) {
4730
+ let closed = false;
4731
+ return async () => {
4732
+ if (closed) return;
4733
+ closed = true;
4734
+ await close();
4735
+ };
4736
+ }
4737
+ //#endregion
4738
+ export { assembleCapxulClient, createCapxulClient, eip1193AccountProvider, injectedWalletSigner, localPrivateKeyAccountProvider, openfortEmbeddedAccountProvider };
4739
+
4740
+ //# sourceMappingURL=index.mjs.map