@capxul/sdk 4.2.0-rc.7 → 4.2.0-rc.9
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.
- package/dist/{OAuthBearerAuthClient-hPwtSpEf.mjs → OAuthBearerAuthClient-IB2W1Fzj.mjs} +104 -5
- package/dist/capxul-source.json +3 -3
- package/dist/index.d.mts +13 -1
- package/dist/index.mjs +2 -2
- package/dist/node/index.mjs +1 -1
- package/dist/{production-D-wB2nFa.mjs → production-216hsAKc.mjs} +510 -13
- package/dist/{production-B8BQj9l0.d.mts → production-Du4Vc7YD.d.mts} +130 -2
- package/dist/testing/index.d.mts +77 -2
- package/dist/testing/index.mjs +94 -3
- package/package.json +5 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as toRoleKey, B as toCurrencyCode, C as ASSET_ID_RE, Ct as redactSecrets, D as WEI_RE, E as SUPPORTED_CURRENCY_CODES, F as toAssetId, G as toHandle, H as toEmail, I as toAuthUserId, J as toOrgId, K as toJwtToken, L as toBudgetId, M as toAddress, N as toAllowedOrigin, O as ZERO_BYTES32, Q as toPublishableKey, R as toChainId, S as APP_ID_RE, St as isCredentialField, T as EVM_ADDRESS_RE$1, U as toEpochMs, V as toDurationMs, W as toEpochSeconds, X as toPayrollGroupId, Y as toPartyId, Z as toPayrollRunId, _ as normalizeBindingEmail, _t as failureFingerprint, at as decodeConvexError, bt as revertSummaryText, c as AuthCachePortTag, ct as EXPECTED_OPERATION_OUTCOMES, d as authClientPortFromPromiseAdapter, dt as CHAIN_UPSTREAMS, et as toSessionToken, f as AuthClientError, ft as FAILURE_MODES$1, gt as decodeChainCause, h as orgRoleKeyForLabel, ht as chainEvidenceLabel, i as BrowserAuthCacheAdapter, j as toAccountId, l as SystemClockLayer, lt as Errors, m as ADMIN_ROLE_LABEL, mt as chainCauseProperties, nt as toTxHash, ot as CAPXUL_ERROR_CODES, p as AuthClientPortTag, pt as boundedResponseHeaders, q as toKycTier, r as InMemoryAuthCacheAdapter, rt as validateHandle, st as CapxulError, tt as toTesterKind, u as ClockPortTag, ut as isCapxulError, v as BASE_SEPOLIA_CHAIN_ID, vt as isChainUpstream, w as BYTES32_RE, wt as redactUrlSecrets, x as ACCOUNT_ID_RE, xt as containsSensitiveMaterial, y as deriveCapxulSafeAddress, yt as isFailureMode, z as toCountryCode } from "./OAuthBearerAuthClient-IB2W1Fzj.mjs";
|
|
2
2
|
import { formatUnits, keccak256, parseUnits, recoverAddress, stringToHex, toBytes } from "viem";
|
|
3
3
|
import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, Layer, Option, Queue, Ref, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stream, Tracer } from "effect";
|
|
4
4
|
import { getFunctionName, makeFunctionReference } from "convex/server";
|
|
@@ -448,6 +448,8 @@ const CAPXUL_OPERATIONS = {
|
|
|
448
448
|
emitAnnotationSaved: "activity.emitAnnotationSaved",
|
|
449
449
|
get: "activity.get",
|
|
450
450
|
list: "activity.list",
|
|
451
|
+
/** The SDK's live Activity read over the indexer's SSE stream. */
|
|
452
|
+
subscribe: "activity.subscribe",
|
|
451
453
|
summary: "activity.summary"
|
|
452
454
|
},
|
|
453
455
|
addressBook: {
|
|
@@ -946,6 +948,17 @@ const AuthFailedProps = Schema.Struct({
|
|
|
946
948
|
auth_type: OptionalString,
|
|
947
949
|
reason: OptionalString
|
|
948
950
|
});
|
|
951
|
+
const IdentityRefusedProps = Schema.Struct({
|
|
952
|
+
...TelemetryEnvelopeProps,
|
|
953
|
+
/** The refused identity event tag, for example CreateOrganization. */
|
|
954
|
+
event: OptionalString,
|
|
955
|
+
/** The machine's refusal code: WRONG_STATE, SUPERSEDED or STALE_EPOCH. */
|
|
956
|
+
refusal_code: OptionalString,
|
|
957
|
+
/** The machine slot the request targeted, for example identity:org. */
|
|
958
|
+
slot: OptionalString,
|
|
959
|
+
/** The machine state at refusal, for example authenticated:claiming. */
|
|
960
|
+
state: OptionalString
|
|
961
|
+
});
|
|
949
962
|
const AuthSignedOutProps = Schema.Struct(TelemetryEnvelopeProps);
|
|
950
963
|
const ProvisioningSafeCreatedProps = Schema.Struct({
|
|
951
964
|
...TelemetryEnvelopeProps,
|
|
@@ -1396,6 +1409,10 @@ Schema.Struct({
|
|
|
1396
1409
|
name: Schema.Literal("auth_failed"),
|
|
1397
1410
|
props: AuthFailedProps
|
|
1398
1411
|
});
|
|
1412
|
+
Schema.Struct({
|
|
1413
|
+
name: Schema.Literal("identity_refused"),
|
|
1414
|
+
props: IdentityRefusedProps
|
|
1415
|
+
});
|
|
1399
1416
|
Schema.Struct({
|
|
1400
1417
|
name: Schema.Literal("auth_signed_out"),
|
|
1401
1418
|
props: AuthSignedOutProps
|
|
@@ -2212,6 +2229,10 @@ const BootstrapEnvelope = Schema.Struct({
|
|
|
2212
2229
|
siteBaseUrl: Schema.String,
|
|
2213
2230
|
openfortPublishableKey: Schema.String,
|
|
2214
2231
|
shieldPublishableKey: Schema.String,
|
|
2232
|
+
/** Which Openfort third-party auth provider the signer presents; absent means better-auth. */
|
|
2233
|
+
openfortAuthProvider: Schema.optional(Schema.Literals(["better-auth", "oidc"])),
|
|
2234
|
+
/** Origin of the Ponder indexer the SDK reads directly; absent means no indexer reads. */
|
|
2235
|
+
indexerUrl: Schema.optional(Schema.String),
|
|
2215
2236
|
engineeringTelemetry: Schema.optional(EngineeringTelemetryBootstrapPolicy)
|
|
2216
2237
|
})
|
|
2217
2238
|
});
|
|
@@ -2286,6 +2307,7 @@ const CAPXUL_FUNCTIONS = {
|
|
|
2286
2307
|
prepareOrganizationPaymentExecution: "moneyExecution/paymentCommandActions:prepareOrganizationPaymentExecution",
|
|
2287
2308
|
submitPaymentCommandExecution: "moneyExecution/paymentCommandActions:submitPaymentCommandExecution"
|
|
2288
2309
|
},
|
|
2310
|
+
"moneyExecution/providerSendWitness": { read: "moneyExecution/providerSendWitness:read" },
|
|
2289
2311
|
media: {
|
|
2290
2312
|
generateUploadUrl: "media:generateUploadUrl",
|
|
2291
2313
|
setOrgLogo: "media:setOrgLogo",
|
|
@@ -2334,8 +2356,7 @@ const CAPXUL_FUNCTIONS = {
|
|
|
2334
2356
|
listMine: "org/queries:listMine",
|
|
2335
2357
|
listRolesByOrgId: "org/queries:listRolesByOrgId",
|
|
2336
2358
|
loadByOrgId: "org/queries:loadByOrgId",
|
|
2337
|
-
me: "org/queries:me"
|
|
2338
|
-
pendingSetup: "org/queries:pendingSetup"
|
|
2359
|
+
me: "org/queries:me"
|
|
2339
2360
|
},
|
|
2340
2361
|
"smartAccount/actions": {
|
|
2341
2362
|
claim: "smartAccount/actions:claim",
|
|
@@ -2346,6 +2367,11 @@ const CAPXUL_FUNCTIONS = {
|
|
|
2346
2367
|
loadByAuthUserId: "smartAccount/queries:loadByAuthUserId",
|
|
2347
2368
|
loadBySmartAccountAddress: "smartAccount/queries:loadBySmartAccountAddress"
|
|
2348
2369
|
},
|
|
2370
|
+
e2eControls: {
|
|
2371
|
+
holdUserOperationReceipt: "e2eControls:holdUserOperationReceipt",
|
|
2372
|
+
isUserOperationReceiptHeld: "e2eControls:isUserOperationReceiptHeld",
|
|
2373
|
+
releaseUserOperationReceipt: "e2eControls:releaseUserOperationReceipt"
|
|
2374
|
+
},
|
|
2349
2375
|
system: { health: "system:health" }
|
|
2350
2376
|
};
|
|
2351
2377
|
//#endregion
|
|
@@ -5657,7 +5683,7 @@ const moneyExecutionContract = {
|
|
|
5657
5683
|
};
|
|
5658
5684
|
//#endregion
|
|
5659
5685
|
//#region package.json
|
|
5660
|
-
var version = "4.2.0-rc.
|
|
5686
|
+
var version = "4.2.0-rc.9";
|
|
5661
5687
|
//#endregion
|
|
5662
5688
|
//#region src/telemetry/exception-projection.ts
|
|
5663
5689
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -5850,6 +5876,17 @@ function observeFailedResult(result, adapter, operation, origin) {
|
|
|
5850
5876
|
return result;
|
|
5851
5877
|
}
|
|
5852
5878
|
/**
|
|
5879
|
+
* @internal Reports a failure that can never become a method result.
|
|
5880
|
+
*
|
|
5881
|
+
* A reactive stream is torn down after its call already returned, so nothing
|
|
5882
|
+
* downstream observes it. `captureException` is the right kind: the caller did
|
|
5883
|
+
* not ask for the end, so it is not an expected product outcome.
|
|
5884
|
+
*/
|
|
5885
|
+
function observeStreamFailure(adapter, operation, cause) {
|
|
5886
|
+
if (adapter === void 0) return;
|
|
5887
|
+
report(adapter, "exception", operation, cause, resolveAdapterSnapshot(adapter));
|
|
5888
|
+
}
|
|
5889
|
+
/**
|
|
5853
5890
|
* One failure, one event. The identity machine reports a failed transition
|
|
5854
5891
|
* first; when the same `CapxulError` then surfaces as a public method result
|
|
5855
5892
|
* (directly or down its `cause` chain), the boundary drops that second report.
|
|
@@ -8673,7 +8710,7 @@ function isTransientBootstrapFailure(error) {
|
|
|
8673
8710
|
const status = error.details?.httpStatus;
|
|
8674
8711
|
return typeof status === "number" && isTransientHttpStatus(status);
|
|
8675
8712
|
}
|
|
8676
|
-
async function safeText(res) {
|
|
8713
|
+
async function safeText$1(res) {
|
|
8677
8714
|
try {
|
|
8678
8715
|
return await res.text();
|
|
8679
8716
|
} catch {
|
|
@@ -8746,6 +8783,8 @@ var HttpBootstrapAdapter = class {
|
|
|
8746
8783
|
siteBaseUrl: normalizeRuntimeUrl("siteBaseUrl", decodedState.siteBaseUrl),
|
|
8747
8784
|
openfortPublishableKey: decodedState.openfortPublishableKey,
|
|
8748
8785
|
shieldPublishableKey: decodedState.shieldPublishableKey,
|
|
8786
|
+
...decodedState.openfortAuthProvider === void 0 ? {} : { openfortAuthProvider: decodedState.openfortAuthProvider },
|
|
8787
|
+
...decodedState.indexerUrl === void 0 ? {} : { indexerUrl: decodedState.indexerUrl },
|
|
8749
8788
|
...decodedEngineeringTelemetry !== void 0 && Result.isSuccess(decodedEngineeringTelemetry) ? { engineeringTelemetry: decodedEngineeringTelemetry.success } : {}
|
|
8750
8789
|
};
|
|
8751
8790
|
},
|
|
@@ -8754,7 +8793,7 @@ var HttpBootstrapAdapter = class {
|
|
|
8754
8793
|
return bootstrapErrorFromCapxul("malformedBody", Errors.providerError("convex", "bootstrap", cause instanceof Error ? cause : new Error(String(cause))));
|
|
8755
8794
|
}
|
|
8756
8795
|
});
|
|
8757
|
-
return Effect.promise(() => safeText(res)).pipe(Effect.flatMap((body) => {
|
|
8796
|
+
return Effect.promise(() => safeText$1(res)).pipe(Effect.flatMap((body) => {
|
|
8758
8797
|
if (res.status === 401 || body.startsWith("NOT_AUTHENTICATED")) return Effect.fail(bootstrapErrorFromCapxul("notAuthenticated", Errors.notAuthenticated()));
|
|
8759
8798
|
if (res.status === 400 || body.startsWith("INVALID_INPUT")) return Effect.fail(bootstrapErrorFromCapxul("invalidInput", Errors.invalidInput("publishableKey", "rejected by bootstrap")));
|
|
8760
8799
|
const responseBody = body.slice(0, 300);
|
|
@@ -8984,6 +9023,12 @@ function makeConnectionId() {
|
|
|
8984
9023
|
}
|
|
8985
9024
|
//#endregion
|
|
8986
9025
|
//#region src/adapters/convex-call/ConvexCallAdapter.ts
|
|
9026
|
+
/**
|
|
9027
|
+
* A socket that has not emitted `close` within this window is not going to.
|
|
9028
|
+
* ponytail: one fixed bound; `closeTimeoutMs` is the knob if a slow runtime
|
|
9029
|
+
* ever needs a different one.
|
|
9030
|
+
*/
|
|
9031
|
+
const DEFAULT_CLOSE_TIMEOUT_MS = 5e3;
|
|
8987
9032
|
/** Exact floor-first allowlist; every additional handler must migrate its validator first. */
|
|
8988
9033
|
const OBSERVED_CONVEX_ACTIONS = /* @__PURE__ */ new Set([
|
|
8989
9034
|
"payroll/actions:authorizeRun",
|
|
@@ -9052,7 +9097,9 @@ var ConvexCallAdapter = class {
|
|
|
9052
9097
|
#applicationId;
|
|
9053
9098
|
#observation;
|
|
9054
9099
|
#connectionMonitor;
|
|
9100
|
+
#closeTimeoutMs;
|
|
9055
9101
|
constructor(deps) {
|
|
9102
|
+
this.#closeTimeoutMs = deps.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
|
|
9056
9103
|
this.#connectionMonitor = new ConvexConnectionMonitor();
|
|
9057
9104
|
const webSocketConstructor = this.#connectionMonitor.observedWebSocketConstructor();
|
|
9058
9105
|
this.#client = deps.client ?? new ConvexClient(deps.convexUrl, webSocketConstructor === void 0 ? {} : { webSocketConstructor });
|
|
@@ -9151,11 +9198,33 @@ var ConvexCallAdapter = class {
|
|
|
9151
9198
|
callback({ status: "loading" });
|
|
9152
9199
|
})));
|
|
9153
9200
|
}
|
|
9201
|
+
/**
|
|
9202
|
+
* Teardown always completes. `ConvexClient.close()` resolves only when the
|
|
9203
|
+
* socket emits `close`, and `WebSocketManager.close()` in the `connecting`
|
|
9204
|
+
* state arms `ws.onopen = () => ws.close()` without ever closing the socket
|
|
9205
|
+
* itself — so a handshake that stalls right after a server-initiated close
|
|
9206
|
+
* (code 1012, which is what a Convex deploy sends) leaves that promise
|
|
9207
|
+
* pending for as long as the page lives. Convex marks the client closed and
|
|
9208
|
+
* terminates the socket manager synchronously before returning it, so
|
|
9209
|
+
* abandoning it drops nothing. A rejection is dropped for the same reason —
|
|
9210
|
+
* the layer release turns it into a defect that fails the whole scope close,
|
|
9211
|
+
* and teardown has no caller who can act on it.
|
|
9212
|
+
*/
|
|
9154
9213
|
async close() {
|
|
9155
9214
|
this.#connectionMonitor.close();
|
|
9156
|
-
await this.#client.close();
|
|
9215
|
+
await settledWithin(this.#client.close(), this.#closeTimeoutMs);
|
|
9157
9216
|
}
|
|
9158
9217
|
};
|
|
9218
|
+
function settledWithin(promise, timeoutMs) {
|
|
9219
|
+
return new Promise((resolve) => {
|
|
9220
|
+
const timer = setTimeout(resolve, timeoutMs);
|
|
9221
|
+
const finish = () => {
|
|
9222
|
+
clearTimeout(timer);
|
|
9223
|
+
resolve();
|
|
9224
|
+
};
|
|
9225
|
+
promise.then(finish, finish);
|
|
9226
|
+
});
|
|
9227
|
+
}
|
|
9159
9228
|
function ConvexCallLayer(deps) {
|
|
9160
9229
|
return Layer.effect(ConvexCallPortTag, Effect.acquireRelease(Effect.sync(() => new ConvexCallAdapter(deps)), (adapter) => Effect.promise(() => adapter.close()).pipe(Effect.orDie)));
|
|
9161
9230
|
}
|
|
@@ -10265,8 +10334,9 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
|
|
|
10265
10334
|
});
|
|
10266
10335
|
throw failOpenfort("configure", "no-secure-context", /* @__PURE__ */ new Error("Web Crypto unavailable: browser is not a secure context"));
|
|
10267
10336
|
}
|
|
10268
|
-
|
|
10269
|
-
|
|
10337
|
+
const authProvider = bootstrap.openfortAuthProvider ?? "better-auth";
|
|
10338
|
+
function accessTokenUrl() {
|
|
10339
|
+
return authProvider === "oidc" ? `${authBaseUrl}/convex/token` : `${authBaseUrl}/get-session`;
|
|
10270
10340
|
}
|
|
10271
10341
|
function encryptionSessionUrl() {
|
|
10272
10342
|
return `${authBaseUrl}/encryption-session`;
|
|
@@ -10289,7 +10359,7 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
|
|
|
10289
10359
|
tokenCalls += 1;
|
|
10290
10360
|
const tokenStartedAt = Date.now();
|
|
10291
10361
|
try {
|
|
10292
|
-
const response = await fetch(
|
|
10362
|
+
const response = await fetch(accessTokenUrl(), {
|
|
10293
10363
|
credentials: "include",
|
|
10294
10364
|
cache: "no-store"
|
|
10295
10365
|
});
|
|
@@ -10302,7 +10372,8 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
|
|
|
10302
10372
|
});
|
|
10303
10373
|
return null;
|
|
10304
10374
|
}
|
|
10305
|
-
const
|
|
10375
|
+
const body = await response.json();
|
|
10376
|
+
const token = (authProvider === "oidc" ? body.token : body.session?.token)?.trim();
|
|
10306
10377
|
if (token === void 0 || token.length === 0) {
|
|
10307
10378
|
diagnostic?.trace("openfort.token", {
|
|
10308
10379
|
ok: false,
|
|
@@ -10314,6 +10385,7 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
|
|
|
10314
10385
|
diagnostic?.trace("openfort.token", {
|
|
10315
10386
|
ok: true,
|
|
10316
10387
|
tokenPresent: true,
|
|
10388
|
+
provider: authProvider,
|
|
10317
10389
|
call: tokenCalls,
|
|
10318
10390
|
duration_ms: Date.now() - tokenStartedAt,
|
|
10319
10391
|
elapsed_ms: sinceCycleStart()
|
|
@@ -10332,7 +10404,7 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
|
|
|
10332
10404
|
baseConfiguration: { publishableKey: bootstrap.openfortPublishableKey },
|
|
10333
10405
|
shieldConfiguration: { shieldPublishableKey: bootstrap.shieldPublishableKey },
|
|
10334
10406
|
thirdPartyAuth: {
|
|
10335
|
-
provider: ThirdPartyOAuthProvider.BETTER_AUTH,
|
|
10407
|
+
provider: authProvider === "oidc" ? ThirdPartyOAuthProvider.OIDC : ThirdPartyOAuthProvider.BETTER_AUTH,
|
|
10336
10408
|
getAccessToken: fetchBetterAuthAccessToken
|
|
10337
10409
|
}
|
|
10338
10410
|
});
|
|
@@ -13333,11 +13405,28 @@ const authFailure = (record, reason, mode) => ({
|
|
|
13333
13405
|
...linkage(record)
|
|
13334
13406
|
}
|
|
13335
13407
|
});
|
|
13408
|
+
const REFUSAL_EVENTS = /* @__PURE__ */ new Set([
|
|
13409
|
+
"ClaimAccount",
|
|
13410
|
+
"RetryAccount",
|
|
13411
|
+
"CreateOrganization",
|
|
13412
|
+
"AttachOrganization",
|
|
13413
|
+
"RetryOrganization"
|
|
13414
|
+
]);
|
|
13336
13415
|
function mapIdentityProductObservation(record, state) {
|
|
13337
13416
|
if (record.machine !== "identity" || !IDENTITY_EVENT_TAG_SET.has(record.event)) return NONE;
|
|
13338
13417
|
if (record.outcome === "cancelled") return NONE;
|
|
13339
13418
|
if (record.slot === "identity:auth" && record.outcome === "refused") return authFailure(record, record.refusal_code, void 0);
|
|
13340
13419
|
if (record.slot === "identity:auth" && record.outcome === "failed") return authFailure(record, record.error_code, record.failure?.mode);
|
|
13420
|
+
if (record.outcome === "refused" && REFUSAL_EVENTS.has(record.event)) return {
|
|
13421
|
+
name: "identity_refused",
|
|
13422
|
+
props: {
|
|
13423
|
+
event: record.event,
|
|
13424
|
+
refusal_code: record.refusal_code,
|
|
13425
|
+
slot: record.slot,
|
|
13426
|
+
state: record.state,
|
|
13427
|
+
...linkage(record)
|
|
13428
|
+
}
|
|
13429
|
+
};
|
|
13341
13430
|
if (record.outcome !== "applied") return NONE;
|
|
13342
13431
|
switch (APPLIED_ACTION_BY_EVENT[record.event]) {
|
|
13343
13432
|
case "none": return NONE;
|
|
@@ -13663,6 +13752,7 @@ function assembleCapxulClient(input) {
|
|
|
13663
13752
|
identity: identityRuntime,
|
|
13664
13753
|
bootstrap: input.bootstrap,
|
|
13665
13754
|
accounts: { fund: accounts.fund },
|
|
13755
|
+
...input.ports.indexerRead === void 0 ? {} : { indexer: input.ports.indexerRead },
|
|
13666
13756
|
organizationSetup: { getProofReceipt: (orgId) => runPortEffect(input.ports.convexCall.query(organizationSetupProofReceiptQuery, { orgId })) },
|
|
13667
13757
|
telemetry: input.ports.telemetry,
|
|
13668
13758
|
captureExternalAddressAcknowledged: (address, organizationId) => {
|
|
@@ -13864,6 +13954,382 @@ function snapshotHostObservability(observability) {
|
|
|
13864
13954
|
function isPromiseLike(value) {
|
|
13865
13955
|
return (typeof value === "object" && value !== null || typeof value === "function") && "then" in value;
|
|
13866
13956
|
}
|
|
13957
|
+
//#endregion
|
|
13958
|
+
//#region src/ports/indexer-read.ts
|
|
13959
|
+
/** The indexer's own page bound. Exceeding it is a caller defect, not a refusal. */
|
|
13960
|
+
const INDEXER_MAX_LIMIT = 1e3;
|
|
13961
|
+
const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
|
|
13962
|
+
/**
|
|
13963
|
+
* Refuse a page the indexer would refuse, before any implementation spends a
|
|
13964
|
+
* round trip on it. Every implementation calls this, so a consumer test written
|
|
13965
|
+
* against the hermetic adapter cannot pass on input production rejects. Throws
|
|
13966
|
+
* a `CapxulError`; callers convert it to an `IndexerReadError`.
|
|
13967
|
+
*/
|
|
13968
|
+
function assertIndexerPage(input) {
|
|
13969
|
+
const safe = String(input.safe).toLowerCase();
|
|
13970
|
+
if (!LOWER_CASE_ADDRESS.test(safe)) throw Errors.invalidInput("safe", "must be a lower-case EVM address");
|
|
13971
|
+
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1e3) throw Errors.invalidInput("limit", `must be an integer from 1 to ${INDEXER_MAX_LIMIT}`);
|
|
13972
|
+
const offset = input.offset ?? 0;
|
|
13973
|
+
if (!Number.isSafeInteger(offset) || offset < 0) throw Errors.invalidInput("offset", "must be a non-negative integer");
|
|
13974
|
+
return safe;
|
|
13975
|
+
}
|
|
13976
|
+
var IndexerReadError = class extends Data.TaggedError("IndexerReadError") {};
|
|
13977
|
+
function indexerReadErrorFromCapxul(operation, error, cause = error) {
|
|
13978
|
+
return new IndexerReadError({
|
|
13979
|
+
operation,
|
|
13980
|
+
publicCode: error.code,
|
|
13981
|
+
publicError: error,
|
|
13982
|
+
cause,
|
|
13983
|
+
...error.details === void 0 ? {} : { details: error.details }
|
|
13984
|
+
});
|
|
13985
|
+
}
|
|
13986
|
+
Context.Service()("@capxul/sdk/ports/IndexerReadPort");
|
|
13987
|
+
//#endregion
|
|
13988
|
+
//#region src/adapters/ponder/decode.ts
|
|
13989
|
+
/**
|
|
13990
|
+
* Decode the indexer's rows at the trust boundary.
|
|
13991
|
+
*
|
|
13992
|
+
* Ponder returns the raw PostgreSQL result: `integer` arrives as a number,
|
|
13993
|
+
* `numeric(78)` and `text` arrive as strings. Amounts, block numbers and
|
|
13994
|
+
* timestamps are `numeric(78)`, so they become `bigint` here and never pass
|
|
13995
|
+
* through `Number`. Every decoder throws a `CapxulError`; the adapter turns
|
|
13996
|
+
* that into a typed `IndexerReadError`.
|
|
13997
|
+
*/
|
|
13998
|
+
const HEX = /^0x[0-9a-fA-F]+$/;
|
|
13999
|
+
function field(row, key) {
|
|
14000
|
+
if (!(key in row)) throw Errors.invalidInput(key, "missing from the indexer row");
|
|
14001
|
+
return row[key];
|
|
14002
|
+
}
|
|
14003
|
+
function text(row, key) {
|
|
14004
|
+
const value = field(row, key);
|
|
14005
|
+
if (typeof value !== "string") throw Errors.invalidInput(key, "must be a string");
|
|
14006
|
+
return value;
|
|
14007
|
+
}
|
|
14008
|
+
function hex(row, key) {
|
|
14009
|
+
const value = text(row, key);
|
|
14010
|
+
if (!HEX.test(value)) throw Errors.invalidInput(key, "must be a hex string");
|
|
14011
|
+
return value.toLowerCase();
|
|
14012
|
+
}
|
|
14013
|
+
function integer(row, key) {
|
|
14014
|
+
const value = field(row, key);
|
|
14015
|
+
const parsed = typeof value === "string" ? Number(value) : value;
|
|
14016
|
+
if (typeof parsed !== "number" || !Number.isSafeInteger(parsed)) throw Errors.invalidInput(key, "must be an integer");
|
|
14017
|
+
return parsed;
|
|
14018
|
+
}
|
|
14019
|
+
/** `numeric(78)` crosses the wire as a decimal string; keep every digit. */
|
|
14020
|
+
function big(row, key) {
|
|
14021
|
+
const value = field(row, key);
|
|
14022
|
+
if (typeof value === "bigint") return value;
|
|
14023
|
+
const raw = typeof value === "number" ? String(value) : value;
|
|
14024
|
+
if (typeof raw !== "string" || !/^-?[0-9]+$/.test(raw)) throw Errors.invalidInput(key, "must be an exact integer amount");
|
|
14025
|
+
return BigInt(raw);
|
|
14026
|
+
}
|
|
14027
|
+
function asRow(value) {
|
|
14028
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw Errors.invalidInput("row", "must be an object");
|
|
14029
|
+
return value;
|
|
14030
|
+
}
|
|
14031
|
+
function identity(row) {
|
|
14032
|
+
return {
|
|
14033
|
+
id: text(row, "id"),
|
|
14034
|
+
chainId: toChainId(integer(row, "chain_id")),
|
|
14035
|
+
txHash: toTxHash(hex(row, "tx_hash")),
|
|
14036
|
+
transactionLogOrdinal: integer(row, "transaction_log_ordinal"),
|
|
14037
|
+
blockNumber: big(row, "block_number"),
|
|
14038
|
+
blockHash: hex(row, "block_hash"),
|
|
14039
|
+
timestamp: big(row, "timestamp")
|
|
14040
|
+
};
|
|
14041
|
+
}
|
|
14042
|
+
function decodeTransfer(value) {
|
|
14043
|
+
const row = asRow(value);
|
|
14044
|
+
return {
|
|
14045
|
+
...identity(row),
|
|
14046
|
+
assetId: toAssetId(text(row, "asset_id")),
|
|
14047
|
+
token: toAddress(hex(row, "token")),
|
|
14048
|
+
from: toAddress(hex(row, "from")),
|
|
14049
|
+
to: toAddress(hex(row, "to")),
|
|
14050
|
+
amount: big(row, "amount")
|
|
14051
|
+
};
|
|
14052
|
+
}
|
|
14053
|
+
function decodePayment(value) {
|
|
14054
|
+
const row = asRow(value);
|
|
14055
|
+
return {
|
|
14056
|
+
...identity(row),
|
|
14057
|
+
contract: toAddress(hex(row, "contract")),
|
|
14058
|
+
settlementId: hex(row, "settlement_id"),
|
|
14059
|
+
sender: toAddress(hex(row, "sender")),
|
|
14060
|
+
recipient: toAddress(hex(row, "recipient")),
|
|
14061
|
+
assetId: toAssetId(text(row, "asset_id")),
|
|
14062
|
+
token: toAddress(hex(row, "token")),
|
|
14063
|
+
amount: big(row, "amount"),
|
|
14064
|
+
kind: integer(row, "kind"),
|
|
14065
|
+
documentHash: hex(row, "document_hash")
|
|
14066
|
+
};
|
|
14067
|
+
}
|
|
14068
|
+
/** The `balance` view exposes the signed sum under the underlying column name `to`. */
|
|
14069
|
+
function decodeBalance(value) {
|
|
14070
|
+
const row = asRow(value);
|
|
14071
|
+
return {
|
|
14072
|
+
chainId: toChainId(integer(row, "chain_id")),
|
|
14073
|
+
assetId: toAssetId(text(row, "asset_id")),
|
|
14074
|
+
address: toAddress(hex(row, "to")),
|
|
14075
|
+
amount: big(row, "amount")
|
|
14076
|
+
};
|
|
14077
|
+
}
|
|
14078
|
+
const DECODERS = {
|
|
14079
|
+
transfer: decodeTransfer,
|
|
14080
|
+
payment: decodePayment,
|
|
14081
|
+
balance: decodeBalance
|
|
14082
|
+
};
|
|
14083
|
+
/** Decode one `/sql/db` or `/sql/live` payload. Ponder returns `{ rows: [...] }`. */
|
|
14084
|
+
function decodeRows(table, body) {
|
|
14085
|
+
const rows = asRow(body).rows;
|
|
14086
|
+
if (!Array.isArray(rows)) throw Errors.invalidInput("rows", "must be an array");
|
|
14087
|
+
const decode = DECODERS[table];
|
|
14088
|
+
return rows.map(decode);
|
|
14089
|
+
}
|
|
14090
|
+
/** Decode Ponder's native `/status`: `{ [chainName]: { id, block: { number, timestamp } } }`. */
|
|
14091
|
+
function decodeStatus(body) {
|
|
14092
|
+
const chains = asRow(body);
|
|
14093
|
+
return Object.entries(chains).map(([chain, value]) => {
|
|
14094
|
+
const entry = asRow(value);
|
|
14095
|
+
const block = asRow(field(entry, "block"));
|
|
14096
|
+
return {
|
|
14097
|
+
chain,
|
|
14098
|
+
chainId: toChainId(integer(entry, "id")),
|
|
14099
|
+
blockNumber: big(block, "number"),
|
|
14100
|
+
blockTimestamp: big(block, "timestamp")
|
|
14101
|
+
};
|
|
14102
|
+
});
|
|
14103
|
+
}
|
|
14104
|
+
//#endregion
|
|
14105
|
+
//#region src/adapters/ponder/statements.ts
|
|
14106
|
+
/**
|
|
14107
|
+
* The exact statements the indexer accepts.
|
|
14108
|
+
*
|
|
14109
|
+
* `apps/indexer/src/queries.ts` compiles its allowlist with `@ponder/client`
|
|
14110
|
+
* and compares `sql`, `params` and `typings` byte for byte against the caller's
|
|
14111
|
+
* statement. Anything else gets 403. The SDK therefore reproduces the compiled
|
|
14112
|
+
* text here rather than pulling Ponder and Drizzle into a published browser
|
|
14113
|
+
* bundle to regenerate three fixed statements.
|
|
14114
|
+
*
|
|
14115
|
+
* `statements.test.ts` pins the text. When the indexer schema or a query in
|
|
14116
|
+
* that allowlist changes, this file changes with it or every read fails 403.
|
|
14117
|
+
*/
|
|
14118
|
+
const HEADS = {
|
|
14119
|
+
transfer: "select \"id\", \"chain_id\", \"tx_hash\", \"transaction_log_ordinal\", \"block_number\", \"block_hash\", \"timestamp\", \"asset_id\", \"token\", \"from\", \"to\", \"amount\" from \"transfer\" where (\"transfer\".\"from\" = $1 or \"transfer\".\"to\" = $2) order by \"transfer\".\"block_number\" desc, \"transfer\".\"id\" desc",
|
|
14120
|
+
payment: "select \"id\", \"chain_id\", \"tx_hash\", \"transaction_log_ordinal\", \"block_number\", \"block_hash\", \"timestamp\", \"contract\", \"settlement_id\", \"sender\", \"recipient\", \"asset_id\", \"token\", \"amount\", \"kind\", \"document_hash\" from \"payment\" where (\"payment\".\"sender\" = $1 or \"payment\".\"recipient\" = $2) order by \"payment\".\"block_number\" desc, \"payment\".\"id\" desc",
|
|
14121
|
+
balance: "select \"chain_id\", \"asset_id\", \"to\", \"amount\" from \"balance\" where \"balance\".\"to\" = $1"
|
|
14122
|
+
};
|
|
14123
|
+
/** How many times the statement binds the Safe address. */
|
|
14124
|
+
const ACTOR_PARAMS = {
|
|
14125
|
+
transfer: 2,
|
|
14126
|
+
payment: 2,
|
|
14127
|
+
balance: 1
|
|
14128
|
+
};
|
|
14129
|
+
/**
|
|
14130
|
+
* Build the compiled query for one table and page. Throws a `CapxulError` for
|
|
14131
|
+
* a page or address the indexer would refuse, so the caller never spends a
|
|
14132
|
+
* round trip to learn it built the request wrong.
|
|
14133
|
+
*/
|
|
14134
|
+
function ponderQuery(table, input) {
|
|
14135
|
+
const safe = assertIndexerPage(input);
|
|
14136
|
+
const offset = input.offset ?? 0;
|
|
14137
|
+
const actors = ACTOR_PARAMS[table];
|
|
14138
|
+
const params = [];
|
|
14139
|
+
for (let i = 0; i < actors; i++) params.push(safe);
|
|
14140
|
+
params.push(input.limit);
|
|
14141
|
+
let sql = `${HEADS[table]} limit $${actors + 1}`;
|
|
14142
|
+
if (offset > 0) {
|
|
14143
|
+
params.push(offset);
|
|
14144
|
+
sql = `${sql} offset $${actors + 2}`;
|
|
14145
|
+
}
|
|
14146
|
+
return {
|
|
14147
|
+
sql,
|
|
14148
|
+
params,
|
|
14149
|
+
typings: params.map(() => "none")
|
|
14150
|
+
};
|
|
14151
|
+
}
|
|
14152
|
+
/**
|
|
14153
|
+
* The `?sql=` value. `@ponder/client` sends `superjson.stringify(query)`; for a
|
|
14154
|
+
* payload of strings and numbers superjson emits no `meta`, so the wire form is
|
|
14155
|
+
* exactly this envelope.
|
|
14156
|
+
*/
|
|
14157
|
+
function ponderQueryParam(query) {
|
|
14158
|
+
return JSON.stringify({ json: query });
|
|
14159
|
+
}
|
|
14160
|
+
//#endregion
|
|
14161
|
+
//#region src/adapters/ponder/sse.ts
|
|
14162
|
+
/**
|
|
14163
|
+
* The smallest SSE reader that can carry an `Authorization` header.
|
|
14164
|
+
*
|
|
14165
|
+
* `@ponder/client` opens its live query with `EventSource`, which accepts no
|
|
14166
|
+
* headers, so it cannot reach the guarded indexer at all. The indexer's CORS
|
|
14167
|
+
* policy allows exactly one request header (`Authorization`), so this reader
|
|
14168
|
+
* sends nothing else. Ponder writes one `data:` line per frame.
|
|
14169
|
+
*/
|
|
14170
|
+
async function readEventStream(body, onData, stopped) {
|
|
14171
|
+
const reader = body.getReader();
|
|
14172
|
+
const decoder = new TextDecoder();
|
|
14173
|
+
let buffer = "";
|
|
14174
|
+
try {
|
|
14175
|
+
for (;;) {
|
|
14176
|
+
const { done, value } = await reader.read();
|
|
14177
|
+
if (done || stopped()) return;
|
|
14178
|
+
buffer += decoder.decode(value, { stream: true });
|
|
14179
|
+
let split = buffer.indexOf("\n\n");
|
|
14180
|
+
while (split !== -1) {
|
|
14181
|
+
const frame = buffer.slice(0, split);
|
|
14182
|
+
buffer = buffer.slice(split + 2);
|
|
14183
|
+
const data = frameData(frame);
|
|
14184
|
+
if (data !== void 0) onData(data);
|
|
14185
|
+
if (stopped()) return;
|
|
14186
|
+
split = buffer.indexOf("\n\n");
|
|
14187
|
+
}
|
|
14188
|
+
}
|
|
14189
|
+
} finally {
|
|
14190
|
+
await reader.cancel().catch(() => void 0);
|
|
14191
|
+
}
|
|
14192
|
+
}
|
|
14193
|
+
function frameData(frame) {
|
|
14194
|
+
const lines = [];
|
|
14195
|
+
for (const line of frame.split("\n")) {
|
|
14196
|
+
if (!line.startsWith("data:")) continue;
|
|
14197
|
+
lines.push(line.slice(line.startsWith("data: ") ? 6 : 5));
|
|
14198
|
+
}
|
|
14199
|
+
return lines.length === 0 ? void 0 : lines.join("\n");
|
|
14200
|
+
}
|
|
14201
|
+
//#endregion
|
|
14202
|
+
//#region src/adapters/ponder/PonderIndexerAdapter.ts
|
|
14203
|
+
var PonderIndexerAdapter = class {
|
|
14204
|
+
#baseUrl;
|
|
14205
|
+
#token;
|
|
14206
|
+
#fetch;
|
|
14207
|
+
#observation;
|
|
14208
|
+
constructor(deps) {
|
|
14209
|
+
this.#baseUrl = deps.baseUrl.replace(/\/$/, "");
|
|
14210
|
+
this.#token = deps.token;
|
|
14211
|
+
this.#observation = deps.observation;
|
|
14212
|
+
this.#fetch = deps.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
14213
|
+
}
|
|
14214
|
+
read(table, input) {
|
|
14215
|
+
const operation = `indexer.read.${table}`;
|
|
14216
|
+
return Effect.tryPromise({
|
|
14217
|
+
try: async () => {
|
|
14218
|
+
return decodeRows(table, await (await this.#request("db", table, input, operation)).json());
|
|
14219
|
+
},
|
|
14220
|
+
catch: (cause) => toIndexerReadError(operation, cause)
|
|
14221
|
+
});
|
|
14222
|
+
}
|
|
14223
|
+
subscribe(table, input, callback) {
|
|
14224
|
+
const operation = CAPXUL_OPERATIONS.activity.subscribe;
|
|
14225
|
+
return Effect.sync(() => {
|
|
14226
|
+
let stopped = false;
|
|
14227
|
+
const unsubscribe = () => {
|
|
14228
|
+
stopped = true;
|
|
14229
|
+
};
|
|
14230
|
+
callback({ status: "loading" });
|
|
14231
|
+
this.#stream(table, input, operation, callback, () => stopped).catch(() => void 0);
|
|
14232
|
+
return unsubscribe;
|
|
14233
|
+
});
|
|
14234
|
+
}
|
|
14235
|
+
status = Effect.tryPromise({
|
|
14236
|
+
try: async () => {
|
|
14237
|
+
const response = await this.#fetch(`${this.#baseUrl}/status`, { method: "GET" });
|
|
14238
|
+
if (!response.ok) throw httpError("indexer.status", response.status, await safeText(response));
|
|
14239
|
+
return decodeStatus(await response.json());
|
|
14240
|
+
},
|
|
14241
|
+
catch: (cause) => toIndexerReadError("indexer.status", cause)
|
|
14242
|
+
});
|
|
14243
|
+
/** One authenticated `/sql/:method` call. Throws a `CapxulError` on refusal. */
|
|
14244
|
+
async #request(method, table, input, operation) {
|
|
14245
|
+
const query = ponderQuery(table, input);
|
|
14246
|
+
const token = await this.#token({ forceRefreshToken: false });
|
|
14247
|
+
if (token === null || token === "") throw Errors.notAuthenticated();
|
|
14248
|
+
const url = `${this.#baseUrl}/sql/${method}?sql=${encodeURIComponent(ponderQueryParam(query))}`;
|
|
14249
|
+
const headers = { authorization: `Bearer ${token}` };
|
|
14250
|
+
if (method === "live") headers.accept = "text/event-stream";
|
|
14251
|
+
let response;
|
|
14252
|
+
try {
|
|
14253
|
+
response = await this.#fetch(url, {
|
|
14254
|
+
method: "GET",
|
|
14255
|
+
headers
|
|
14256
|
+
});
|
|
14257
|
+
} catch (cause) {
|
|
14258
|
+
throw Errors.networkError(operation, cause, {
|
|
14259
|
+
provider: "indexer",
|
|
14260
|
+
failure_mode: "upstream-down"
|
|
14261
|
+
});
|
|
14262
|
+
}
|
|
14263
|
+
if (!response.ok) throw httpError(operation, response.status, await safeText(response));
|
|
14264
|
+
return response;
|
|
14265
|
+
}
|
|
14266
|
+
/**
|
|
14267
|
+
* Follow the live stream until the caller unsubscribes or the indexer closes
|
|
14268
|
+
* it. The indexer closes the stream on token expiry or revoked authority
|
|
14269
|
+
* with no frame, so any end the caller did not ask for is a teardown: it
|
|
14270
|
+
* reaches `captureException` under `activity.subscribe` and the caller sees
|
|
14271
|
+
* one `error` snapshot.
|
|
14272
|
+
*/
|
|
14273
|
+
async #stream(table, input, operation, callback, stopped) {
|
|
14274
|
+
let failure;
|
|
14275
|
+
try {
|
|
14276
|
+
const response = await this.#request("live", table, input, operation);
|
|
14277
|
+
if (response.body === null) throw Errors.providerError("indexer", operation, "empty stream");
|
|
14278
|
+
await readEventStream(response.body, (data) => {
|
|
14279
|
+
try {
|
|
14280
|
+
callback({
|
|
14281
|
+
status: "ok",
|
|
14282
|
+
value: decodeRows(table, JSON.parse(data))
|
|
14283
|
+
});
|
|
14284
|
+
} catch (cause) {
|
|
14285
|
+
failure = toPublicError$1(operation, cause);
|
|
14286
|
+
}
|
|
14287
|
+
}, () => stopped() || failure !== void 0);
|
|
14288
|
+
} catch (cause) {
|
|
14289
|
+
failure = toPublicError$1(operation, cause);
|
|
14290
|
+
}
|
|
14291
|
+
if (stopped()) return;
|
|
14292
|
+
const error = failure ?? Errors.capabilityUnavailable("indexer", operation);
|
|
14293
|
+
observeStreamFailure(this.#observation, CAPXUL_OPERATIONS.activity.subscribe, error);
|
|
14294
|
+
callback({
|
|
14295
|
+
status: "error",
|
|
14296
|
+
error
|
|
14297
|
+
});
|
|
14298
|
+
}
|
|
14299
|
+
};
|
|
14300
|
+
/**
|
|
14301
|
+
* Map an indexer refusal into the shared error vocabulary.
|
|
14302
|
+
*
|
|
14303
|
+
* 401 is the expected outcome of an expired or revoked session. 403 is not:
|
|
14304
|
+
* the indexer accepts only its own compiled statements for a Safe in the
|
|
14305
|
+
* claim, so a refusal means this SDK and that deployment disagree, or the
|
|
14306
|
+
* session gained a Safe and still holds the older token. Both must be loud.
|
|
14307
|
+
*/
|
|
14308
|
+
function httpError(operation, status, body) {
|
|
14309
|
+
if (status === 401) return Errors.notAuthenticated();
|
|
14310
|
+
if (status === 429) return Errors.rateLimited({ resource: "indexer" });
|
|
14311
|
+
if (status === 503) return Errors.capabilityUnavailable("indexer", operation);
|
|
14312
|
+
return Errors.providerError("indexer", operation, body, {
|
|
14313
|
+
httpStatus: status,
|
|
14314
|
+
...status >= 500 ? { failure_mode: "upstream-down" } : {},
|
|
14315
|
+
details: { reason: status === 403 ? "scope-refused" : "http-status" }
|
|
14316
|
+
});
|
|
14317
|
+
}
|
|
14318
|
+
function toPublicError$1(operation, cause) {
|
|
14319
|
+
if (cause instanceof CapxulError) return cause;
|
|
14320
|
+
return Errors.providerError("indexer", operation, cause);
|
|
14321
|
+
}
|
|
14322
|
+
function toIndexerReadError(operation, cause) {
|
|
14323
|
+
if (cause instanceof IndexerReadError) return cause;
|
|
14324
|
+
return indexerReadErrorFromCapxul(operation, toPublicError$1(operation, cause), cause);
|
|
14325
|
+
}
|
|
14326
|
+
async function safeText(response) {
|
|
14327
|
+
try {
|
|
14328
|
+
return await response.text();
|
|
14329
|
+
} catch {
|
|
14330
|
+
return "";
|
|
14331
|
+
}
|
|
14332
|
+
}
|
|
13867
14333
|
const SDK_VERSION = version;
|
|
13868
14334
|
/**
|
|
13869
14335
|
* Project the built graph into the flat `FlowPorts` record the method bundles
|
|
@@ -14113,7 +14579,16 @@ async function createProductionAdapters(input) {
|
|
|
14113
14579
|
}));
|
|
14114
14580
|
const applicationLayer = Layer.merge(portsLayer, optionalEngineeringTelemetryLayer(bootstrapResult.value.engineeringTelemetry, resolvedInput.value.runtime));
|
|
14115
14581
|
const context = await Effect.runPromise(Layer.buildWithScope(applicationLayer, scope));
|
|
14116
|
-
const
|
|
14582
|
+
const collected = await Effect.runPromise(collectProductionFlowPorts.pipe(Effect.provide(context)));
|
|
14583
|
+
const indexerUrl = input.indexerUrl ?? bootstrapResult.value.indexerUrl;
|
|
14584
|
+
const indexerRead = productionIndexerReadPort(indexerUrl === void 0 ? input : {
|
|
14585
|
+
...input,
|
|
14586
|
+
indexerUrl
|
|
14587
|
+
}, collected, observation);
|
|
14588
|
+
const ports = indexerRead === void 0 ? collected : {
|
|
14589
|
+
...collected,
|
|
14590
|
+
indexerRead
|
|
14591
|
+
};
|
|
14117
14592
|
const stopConnectionObservation = observeProductionConvexConnection(ports.convexCall, context);
|
|
14118
14593
|
const close = idempotentClose(async () => {
|
|
14119
14594
|
try {
|
|
@@ -14445,5 +14920,27 @@ function idempotentClose(close) {
|
|
|
14445
14920
|
await close();
|
|
14446
14921
|
};
|
|
14447
14922
|
}
|
|
14923
|
+
/**
|
|
14924
|
+
* Build the Ponder read port for this client, or `undefined` when no indexer
|
|
14925
|
+
* origin was supplied. The token provider is the same
|
|
14926
|
+
* `AuthClientPort.getConvexJwt` closure `ConvexCallPort` uses, so the indexer
|
|
14927
|
+
* and Convex see one session with one scope.
|
|
14928
|
+
*/
|
|
14929
|
+
function productionIndexerReadPort(input, ports, observation) {
|
|
14930
|
+
if (input.indexerUrl === void 0 || input.indexerUrl === "") return void 0;
|
|
14931
|
+
return new PonderIndexerAdapter({
|
|
14932
|
+
baseUrl: normalizeHttpUrl("indexerUrl", input.indexerUrl),
|
|
14933
|
+
token: async ({ forceRefreshToken }) => {
|
|
14934
|
+
const token = await Effect.runPromise(Effect.result(ports.authClient.getConvexJwt({
|
|
14935
|
+
forceRefresh: forceRefreshToken,
|
|
14936
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
14937
|
+
})));
|
|
14938
|
+
if (Result.isFailure(token)) return null;
|
|
14939
|
+
return String(token.success.token);
|
|
14940
|
+
},
|
|
14941
|
+
...input.fetch === void 0 ? {} : { fetch: input.fetch },
|
|
14942
|
+
...observation === void 0 ? {} : { observation }
|
|
14943
|
+
});
|
|
14944
|
+
}
|
|
14448
14945
|
//#endregion
|
|
14449
14946
|
export { signerFailure as A, isRestoring as B, normalizeExceptionErrorKind as C, fromWei as D, safeExceptionLabel as E, CAPXUL_OPERATIONS as F, isCapxulOperation as I, normalizeCapxulOperation as L, PAYMENT_DIRECTIONS as M, PAYMENT_STATUSES as N, isSettingUpLifecycle as O, redactTelemetryEvent as P, destination as R, SDK_VERSION$1 as S, projectSdkException as T, fingerprintPaymentIntent as _, smartAccountErrorFromCapxul as a, failureDetail as b, identityErrorFromCapxul as c, embeddedSigner as d, openfortEmbeddedSigner as f, devPrivateKeySigner as g, deriveDevPrivateKey as h, assembleCapxulClient as i, resolveFailureMode as j, injectedWalletSigner as k, convexCallErrorFromCapxul as l, openfortEmbeddedWalletPort as m, createCapxulClientWithSignerControls as n, accountReadErrorFromCapxul as o, openfortEmbeddedSignerFromWallet as p, postHogObservability as r, wireChainId as s, createCapxulClient as t, bootstrapErrorFromCapxul as u, toWei as v, normalizeExceptionOperation as w, EXCEPTION_MESSAGE as x, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as y, isClaimed as z };
|