@capxul/mcp 4.2.0-rc.8 → 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/capxul-source.json +3 -3
- package/dist/main.mjs +597 -11
- package/package.json +3 -3
package/dist/capxul-source.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": {
|
|
3
|
-
"commit": "
|
|
4
|
-
"tree": "
|
|
3
|
+
"commit": "1c96a26356e8f36402e47eb4ac60bb89d6aeed7f",
|
|
4
|
+
"tree": "375f49f76377eeec331fd44ce17238d4a6f02ad4",
|
|
5
5
|
"branch": "codex/programme-rc",
|
|
6
6
|
"repository": "https://github.com/Xelmar-tech/infrastructure",
|
|
7
7
|
"lockfileSha256": "5870f53b72706d103220c1bcf733cb4fb71196aea32a9cfbdc277d73cc959264"
|
|
8
8
|
},
|
|
9
9
|
"name": "@capxul/mcp",
|
|
10
|
-
"version": "4.2.0-rc.
|
|
10
|
+
"version": "4.2.0-rc.9"
|
|
11
11
|
}
|
package/dist/main.mjs
CHANGED
|
@@ -852,6 +852,7 @@ const COUNTRY_CODE_RE = /^[A-Z]{2}$/;
|
|
|
852
852
|
const ACCOUNT_ID_RE = /^account_[0-9A-Za-z]+$/;
|
|
853
853
|
const PARTY_ID_RE$1 = /^party_[0-9A-Za-z]+$/;
|
|
854
854
|
const APP_ID_RE = /^app_[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
855
|
+
const TX_HASH_RE = /^0x[0-9a-f]{64}$/i;
|
|
855
856
|
const WEI_RE = /^[0-9]+$/;
|
|
856
857
|
Math.floor(Number.MAX_SAFE_INTEGER / 1e3);
|
|
857
858
|
function toAddress(raw) {
|
|
@@ -903,6 +904,10 @@ function toPublishableKey(raw) {
|
|
|
903
904
|
if (typeof raw !== "string" || !PUBLISHABLE_KEY_PATTERN.test(raw)) throw Errors.invalidInput("publishableKey", invalidValueReason("must match cap_pk_(test|live) plus 32 Crockford base32 chars", raw));
|
|
904
905
|
return raw;
|
|
905
906
|
}
|
|
907
|
+
function toTxHash(raw) {
|
|
908
|
+
if (typeof raw !== "string" || !TX_HASH_RE.test(raw)) throw Errors.invalidInput("txHash", invalidValueReason("must be 0x + 64 hex chars", raw));
|
|
909
|
+
return raw.toLowerCase();
|
|
910
|
+
}
|
|
906
911
|
function toEpochMs(raw) {
|
|
907
912
|
assertSafeNonNegativeInteger(raw, "epochMs");
|
|
908
913
|
return raw;
|
|
@@ -982,19 +987,108 @@ function invalidValueReason(prefix, raw) {
|
|
|
982
987
|
//#region ../../packages/config/src/tokens.ts
|
|
983
988
|
/** `TestUSDC` ("USDX") — Base Sepolia, 6 decimals, open `mint`. (Canon §1.) */
|
|
984
989
|
const USDX_ADDRESS_BASE_SEPOLIA = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
|
|
990
|
+
const USDX_DEPLOYMENT_START_BLOCK = 39860173;
|
|
991
|
+
/**
|
|
992
|
+
* The ERC-20 `symbol()` the deployed `TestUSDC` contract returns
|
|
993
|
+
* (`packages/contracts/src/TestUSDC.sol:10`). It travels with the address and
|
|
994
|
+
* the decimals so a holdings row can never carry one token's address with
|
|
995
|
+
* another token's display symbol. This is the display symbol, not the
|
|
996
|
+
* currency: see `USDX_CURRENCY` below.
|
|
997
|
+
*/
|
|
998
|
+
const USDX_SYMBOL = "USDX";
|
|
999
|
+
const SYNTHETIC_TEST_ASSET_SOURCE = "synthetic-test-liquidity";
|
|
985
1000
|
const USDX_ASSET = {
|
|
986
1001
|
assetId: assetIdFor(84532, USDX_ADDRESS_BASE_SEPOLIA),
|
|
987
1002
|
chainId: toChainId(84532),
|
|
988
|
-
symbol:
|
|
1003
|
+
symbol: USDX_SYMBOL,
|
|
989
1004
|
peg: toCurrencyCode("USD"),
|
|
990
1005
|
tokenAddress: USDX_ADDRESS_BASE_SEPOLIA,
|
|
991
|
-
deploymentStartBlock:
|
|
992
|
-
decimals: 6
|
|
1006
|
+
deploymentStartBlock: USDX_DEPLOYMENT_START_BLOCK,
|
|
1007
|
+
decimals: 6,
|
|
1008
|
+
source: "settlement"
|
|
993
1009
|
};
|
|
994
|
-
|
|
1010
|
+
/**
|
|
1011
|
+
* The settlement tier: rows the exact-transfer path and the Movement scanner
|
|
1012
|
+
* admit, each carrying the legacy `currency` projection those readers expect.
|
|
1013
|
+
* Adding an owned test asset here would put candidate liquidity on the
|
|
1014
|
+
* money-write path, so M03's rows go to the candidate tier below instead.
|
|
1015
|
+
*/
|
|
1016
|
+
const CONFIGURED_MONEY_ASSETS = [{
|
|
995
1017
|
...USDX_ASSET,
|
|
996
1018
|
currency: USDX_ASSET.peg
|
|
997
|
-
}]
|
|
1019
|
+
}];
|
|
1020
|
+
/**
|
|
1021
|
+
* The candidate tier: five owned test assets, every field read back from Base
|
|
1022
|
+
* Sepolia after the deployment that created it (chain 84532, blocks
|
|
1023
|
+
* 46,465,978–46,465,982). Real contracts, authored liquidity, no settlement
|
|
1024
|
+
* admission — so rollback is removing consumers, never relabelling a
|
|
1025
|
+
* deployed address or deleting its history.
|
|
1026
|
+
*
|
|
1027
|
+
* `symbol` is the display string the owned contract returns. A
|
|
1028
|
+
* provider-supported USDC would be a different contract at a different
|
|
1029
|
+
* address returning the same symbol, which is why the resolvers below key on
|
|
1030
|
+
* `assetId`, or on chain plus address, and never on a symbol.
|
|
1031
|
+
*/
|
|
1032
|
+
const SYNTHETIC_TEST_ASSETS = [
|
|
1033
|
+
{
|
|
1034
|
+
assetId: assetIdFor(84532, "0xb3d8566fb90f7df939f4bc08a09b19047117f549"),
|
|
1035
|
+
chainId: toChainId(84532),
|
|
1036
|
+
tokenAddress: "0xb3d8566fb90f7df939f4bc08a09b19047117f549",
|
|
1037
|
+
symbol: "USDC",
|
|
1038
|
+
decimals: 6,
|
|
1039
|
+
peg: toCurrencyCode("USD"),
|
|
1040
|
+
deploymentStartBlock: 46465978,
|
|
1041
|
+
deploymentTransaction: "0xa7fb8bb9d1fd1cc5fe2fc42fa4cdccace7742efae8ea99f091a283e5709343de",
|
|
1042
|
+
source: SYNTHETIC_TEST_ASSET_SOURCE
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
assetId: assetIdFor(84532, "0x7ddcfb6aaffb9908c4c2db308b784c269eec8a01"),
|
|
1046
|
+
chainId: toChainId(84532),
|
|
1047
|
+
tokenAddress: "0x7ddcfb6aaffb9908c4c2db308b784c269eec8a01",
|
|
1048
|
+
symbol: "USDT",
|
|
1049
|
+
decimals: 6,
|
|
1050
|
+
peg: toCurrencyCode("USD"),
|
|
1051
|
+
deploymentStartBlock: 46465979,
|
|
1052
|
+
deploymentTransaction: "0xa17ad76fe8b24cdf1fbcff245c3eb022444710cf9fa7b5ee59818be654f4ae10",
|
|
1053
|
+
source: SYNTHETIC_TEST_ASSET_SOURCE
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
assetId: assetIdFor(84532, "0x1d93d525f73453fe18eebf044e8a3954bfe3721e"),
|
|
1057
|
+
chainId: toChainId(84532),
|
|
1058
|
+
tokenAddress: "0x1d93d525f73453fe18eebf044e8a3954bfe3721e",
|
|
1059
|
+
symbol: "WETH",
|
|
1060
|
+
decimals: 18,
|
|
1061
|
+
peg: null,
|
|
1062
|
+
deploymentStartBlock: 46465980,
|
|
1063
|
+
deploymentTransaction: "0xcb9b2d024686fac93ec1243ccf02d3567fd531da46176115660cba2ba644b09d",
|
|
1064
|
+
source: SYNTHETIC_TEST_ASSET_SOURCE
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
assetId: assetIdFor(84532, "0x8fe52c70aa9f7b6d74d8bb26eca33d87413cb624"),
|
|
1068
|
+
chainId: toChainId(84532),
|
|
1069
|
+
tokenAddress: "0x8fe52c70aa9f7b6d74d8bb26eca33d87413cb624",
|
|
1070
|
+
symbol: "WBTC",
|
|
1071
|
+
decimals: 8,
|
|
1072
|
+
peg: null,
|
|
1073
|
+
deploymentStartBlock: 46465981,
|
|
1074
|
+
deploymentTransaction: "0x728ba7b430ffd141f83d0ed5ce429d050049d7b097c936fd11e9c572d1243854",
|
|
1075
|
+
source: SYNTHETIC_TEST_ASSET_SOURCE
|
|
1076
|
+
},
|
|
1077
|
+
{
|
|
1078
|
+
assetId: assetIdFor(84532, "0x5865fe9787ac214feb5facaebaec06969ac0a9a3"),
|
|
1079
|
+
chainId: toChainId(84532),
|
|
1080
|
+
tokenAddress: "0x5865fe9787ac214feb5facaebaec06969ac0a9a3",
|
|
1081
|
+
symbol: "cNGN",
|
|
1082
|
+
decimals: 6,
|
|
1083
|
+
peg: toCurrencyCode("NGN"),
|
|
1084
|
+
deploymentStartBlock: 46465982,
|
|
1085
|
+
deploymentTransaction: "0xcedf254bcef57fc64189261a5ab1161bc4fde370e470933f627c4d8ddb5a2e26",
|
|
1086
|
+
source: SYNTHETIC_TEST_ASSET_SOURCE
|
|
1087
|
+
}
|
|
1088
|
+
];
|
|
1089
|
+
toChainId(84532);
|
|
1090
|
+
[...CONFIGURED_MONEY_ASSETS, ...SYNTHETIC_TEST_ASSETS];
|
|
1091
|
+
CONFIGURED_MONEY_ASSETS.map((asset) => asset.tokenAddress.toLowerCase());
|
|
998
1092
|
//#endregion
|
|
999
1093
|
//#region ../../node_modules/.pnpm/abitype@1.2.3_typescript@7.0.2_zod@4.4.3/node_modules/abitype/dist/esm/regex.js
|
|
1000
1094
|
function execTyped(regex, string) {
|
|
@@ -6794,6 +6888,8 @@ const CAPXUL_OPERATIONS = {
|
|
|
6794
6888
|
emitAnnotationSaved: "activity.emitAnnotationSaved",
|
|
6795
6889
|
get: "activity.get",
|
|
6796
6890
|
list: "activity.list",
|
|
6891
|
+
/** The SDK's live Activity read over the indexer's SSE stream. */
|
|
6892
|
+
subscribe: "activity.subscribe",
|
|
6797
6893
|
summary: "activity.summary"
|
|
6798
6894
|
},
|
|
6799
6895
|
addressBook: {
|
|
@@ -7277,6 +7373,17 @@ const AuthFailedProps = Schema.Struct({
|
|
|
7277
7373
|
auth_type: OptionalString,
|
|
7278
7374
|
reason: OptionalString
|
|
7279
7375
|
});
|
|
7376
|
+
const IdentityRefusedProps = Schema.Struct({
|
|
7377
|
+
...TelemetryEnvelopeProps,
|
|
7378
|
+
/** The refused identity event tag, for example CreateOrganization. */
|
|
7379
|
+
event: OptionalString,
|
|
7380
|
+
/** The machine's refusal code: WRONG_STATE, SUPERSEDED or STALE_EPOCH. */
|
|
7381
|
+
refusal_code: OptionalString,
|
|
7382
|
+
/** The machine slot the request targeted, for example identity:org. */
|
|
7383
|
+
slot: OptionalString,
|
|
7384
|
+
/** The machine state at refusal, for example authenticated:claiming. */
|
|
7385
|
+
state: OptionalString
|
|
7386
|
+
});
|
|
7280
7387
|
const AuthSignedOutProps = Schema.Struct(TelemetryEnvelopeProps);
|
|
7281
7388
|
const ProvisioningSafeCreatedProps = Schema.Struct({
|
|
7282
7389
|
...TelemetryEnvelopeProps,
|
|
@@ -7727,6 +7834,10 @@ Schema.Struct({
|
|
|
7727
7834
|
name: Schema.Literal("auth_failed"),
|
|
7728
7835
|
props: AuthFailedProps
|
|
7729
7836
|
});
|
|
7837
|
+
Schema.Struct({
|
|
7838
|
+
name: Schema.Literal("identity_refused"),
|
|
7839
|
+
props: IdentityRefusedProps
|
|
7840
|
+
});
|
|
7730
7841
|
Schema.Struct({
|
|
7731
7842
|
name: Schema.Literal("auth_signed_out"),
|
|
7732
7843
|
props: AuthSignedOutProps
|
|
@@ -8538,6 +8649,8 @@ const BootstrapEnvelope = Schema.Struct({
|
|
|
8538
8649
|
shieldPublishableKey: Schema.String,
|
|
8539
8650
|
/** Which Openfort third-party auth provider the signer presents; absent means better-auth. */
|
|
8540
8651
|
openfortAuthProvider: Schema.optional(Schema.Literals(["better-auth", "oidc"])),
|
|
8652
|
+
/** Origin of the Ponder indexer the SDK reads directly; absent means no indexer reads. */
|
|
8653
|
+
indexerUrl: Schema.optional(Schema.String),
|
|
8541
8654
|
engineeringTelemetry: Schema.optional(EngineeringTelemetryBootstrapPolicy)
|
|
8542
8655
|
})
|
|
8543
8656
|
});
|
|
@@ -8612,6 +8725,7 @@ const CAPXUL_FUNCTIONS = {
|
|
|
8612
8725
|
prepareOrganizationPaymentExecution: "moneyExecution/paymentCommandActions:prepareOrganizationPaymentExecution",
|
|
8613
8726
|
submitPaymentCommandExecution: "moneyExecution/paymentCommandActions:submitPaymentCommandExecution"
|
|
8614
8727
|
},
|
|
8728
|
+
"moneyExecution/providerSendWitness": { read: "moneyExecution/providerSendWitness:read" },
|
|
8615
8729
|
media: {
|
|
8616
8730
|
generateUploadUrl: "media:generateUploadUrl",
|
|
8617
8731
|
setOrgLogo: "media:setOrgLogo",
|
|
@@ -8671,6 +8785,11 @@ const CAPXUL_FUNCTIONS = {
|
|
|
8671
8785
|
loadByAuthUserId: "smartAccount/queries:loadByAuthUserId",
|
|
8672
8786
|
loadBySmartAccountAddress: "smartAccount/queries:loadBySmartAccountAddress"
|
|
8673
8787
|
},
|
|
8788
|
+
e2eControls: {
|
|
8789
|
+
holdUserOperationReceipt: "e2eControls:holdUserOperationReceipt",
|
|
8790
|
+
isUserOperationReceiptHeld: "e2eControls:isUserOperationReceiptHeld",
|
|
8791
|
+
releaseUserOperationReceipt: "e2eControls:releaseUserOperationReceipt"
|
|
8792
|
+
},
|
|
8674
8793
|
system: { health: "system:health" }
|
|
8675
8794
|
};
|
|
8676
8795
|
//#endregion
|
|
@@ -12259,7 +12378,7 @@ const moneyExecutionContract = {
|
|
|
12259
12378
|
};
|
|
12260
12379
|
//#endregion
|
|
12261
12380
|
//#region ../../packages/sdk/package.json
|
|
12262
|
-
var version$1 = "4.2.0-rc.
|
|
12381
|
+
var version$1 = "4.2.0-rc.9";
|
|
12263
12382
|
//#endregion
|
|
12264
12383
|
//#region ../../packages/sdk/src/telemetry/exception-projection.ts
|
|
12265
12384
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -12356,6 +12475,17 @@ function observeFailedResult(result, adapter, operation, origin) {
|
|
|
12356
12475
|
return result;
|
|
12357
12476
|
}
|
|
12358
12477
|
/**
|
|
12478
|
+
* @internal Reports a failure that can never become a method result.
|
|
12479
|
+
*
|
|
12480
|
+
* A reactive stream is torn down after its call already returned, so nothing
|
|
12481
|
+
* downstream observes it. `captureException` is the right kind: the caller did
|
|
12482
|
+
* not ask for the end, so it is not an expected product outcome.
|
|
12483
|
+
*/
|
|
12484
|
+
function observeStreamFailure(adapter, operation, cause) {
|
|
12485
|
+
if (adapter === void 0) return;
|
|
12486
|
+
report(adapter, "exception", operation, cause, resolveAdapterSnapshot(adapter));
|
|
12487
|
+
}
|
|
12488
|
+
/**
|
|
12359
12489
|
* One failure, one event. The identity machine reports a failed transition
|
|
12360
12490
|
* first; when the same `CapxulError` then surfaces as a public method result
|
|
12361
12491
|
* (directly or down its `cause` chain), the boundary drops that second report.
|
|
@@ -15273,7 +15403,7 @@ function isTransientBootstrapFailure(error) {
|
|
|
15273
15403
|
const status = error.details?.httpStatus;
|
|
15274
15404
|
return typeof status === "number" && isTransientHttpStatus(status);
|
|
15275
15405
|
}
|
|
15276
|
-
async function safeText(res) {
|
|
15406
|
+
async function safeText$1(res) {
|
|
15277
15407
|
try {
|
|
15278
15408
|
return await res.text();
|
|
15279
15409
|
} catch {
|
|
@@ -15347,6 +15477,7 @@ var HttpBootstrapAdapter = class {
|
|
|
15347
15477
|
openfortPublishableKey: decodedState.openfortPublishableKey,
|
|
15348
15478
|
shieldPublishableKey: decodedState.shieldPublishableKey,
|
|
15349
15479
|
...decodedState.openfortAuthProvider === void 0 ? {} : { openfortAuthProvider: decodedState.openfortAuthProvider },
|
|
15480
|
+
...decodedState.indexerUrl === void 0 ? {} : { indexerUrl: decodedState.indexerUrl },
|
|
15350
15481
|
...decodedEngineeringTelemetry !== void 0 && Result.isSuccess(decodedEngineeringTelemetry) ? { engineeringTelemetry: decodedEngineeringTelemetry.success } : {}
|
|
15351
15482
|
};
|
|
15352
15483
|
},
|
|
@@ -15355,7 +15486,7 @@ var HttpBootstrapAdapter = class {
|
|
|
15355
15486
|
return bootstrapErrorFromCapxul("malformedBody", Errors.providerError("convex", "bootstrap", cause instanceof Error ? cause : new Error(String(cause))));
|
|
15356
15487
|
}
|
|
15357
15488
|
});
|
|
15358
|
-
return Effect.promise(() => safeText(res)).pipe(Effect.flatMap((body) => {
|
|
15489
|
+
return Effect.promise(() => safeText$1(res)).pipe(Effect.flatMap((body) => {
|
|
15359
15490
|
if (res.status === 401 || body.startsWith("NOT_AUTHENTICATED")) return Effect.fail(bootstrapErrorFromCapxul("notAuthenticated", Errors.notAuthenticated()));
|
|
15360
15491
|
if (res.status === 400 || body.startsWith("INVALID_INPUT")) return Effect.fail(bootstrapErrorFromCapxul("invalidInput", Errors.invalidInput("publishableKey", "rejected by bootstrap")));
|
|
15361
15492
|
const responseBody = body.slice(0, 300);
|
|
@@ -18538,6 +18669,12 @@ function makeConnectionId() {
|
|
|
18538
18669
|
}
|
|
18539
18670
|
//#endregion
|
|
18540
18671
|
//#region ../../packages/sdk/src/adapters/convex-call/ConvexCallAdapter.ts
|
|
18672
|
+
/**
|
|
18673
|
+
* A socket that has not emitted `close` within this window is not going to.
|
|
18674
|
+
* ponytail: one fixed bound; `closeTimeoutMs` is the knob if a slow runtime
|
|
18675
|
+
* ever needs a different one.
|
|
18676
|
+
*/
|
|
18677
|
+
const DEFAULT_CLOSE_TIMEOUT_MS = 5e3;
|
|
18541
18678
|
/** Exact floor-first allowlist; every additional handler must migrate its validator first. */
|
|
18542
18679
|
const OBSERVED_CONVEX_ACTIONS = /* @__PURE__ */ new Set([
|
|
18543
18680
|
"payroll/actions:authorizeRun",
|
|
@@ -18606,7 +18743,9 @@ var ConvexCallAdapter = class {
|
|
|
18606
18743
|
#applicationId;
|
|
18607
18744
|
#observation;
|
|
18608
18745
|
#connectionMonitor;
|
|
18746
|
+
#closeTimeoutMs;
|
|
18609
18747
|
constructor(deps) {
|
|
18748
|
+
this.#closeTimeoutMs = deps.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
|
|
18610
18749
|
this.#connectionMonitor = new ConvexConnectionMonitor();
|
|
18611
18750
|
const webSocketConstructor = this.#connectionMonitor.observedWebSocketConstructor();
|
|
18612
18751
|
this.#client = deps.client ?? new ConvexClient(deps.convexUrl, webSocketConstructor === void 0 ? {} : { webSocketConstructor });
|
|
@@ -18705,11 +18844,33 @@ var ConvexCallAdapter = class {
|
|
|
18705
18844
|
callback({ status: "loading" });
|
|
18706
18845
|
})));
|
|
18707
18846
|
}
|
|
18847
|
+
/**
|
|
18848
|
+
* Teardown always completes. `ConvexClient.close()` resolves only when the
|
|
18849
|
+
* socket emits `close`, and `WebSocketManager.close()` in the `connecting`
|
|
18850
|
+
* state arms `ws.onopen = () => ws.close()` without ever closing the socket
|
|
18851
|
+
* itself — so a handshake that stalls right after a server-initiated close
|
|
18852
|
+
* (code 1012, which is what a Convex deploy sends) leaves that promise
|
|
18853
|
+
* pending for as long as the page lives. Convex marks the client closed and
|
|
18854
|
+
* terminates the socket manager synchronously before returning it, so
|
|
18855
|
+
* abandoning it drops nothing. A rejection is dropped for the same reason —
|
|
18856
|
+
* the layer release turns it into a defect that fails the whole scope close,
|
|
18857
|
+
* and teardown has no caller who can act on it.
|
|
18858
|
+
*/
|
|
18708
18859
|
async close() {
|
|
18709
18860
|
this.#connectionMonitor.close();
|
|
18710
|
-
await this.#client.close();
|
|
18861
|
+
await settledWithin(this.#client.close(), this.#closeTimeoutMs);
|
|
18711
18862
|
}
|
|
18712
18863
|
};
|
|
18864
|
+
function settledWithin(promise, timeoutMs) {
|
|
18865
|
+
return new Promise((resolve) => {
|
|
18866
|
+
const timer = setTimeout(resolve, timeoutMs);
|
|
18867
|
+
const finish = () => {
|
|
18868
|
+
clearTimeout(timer);
|
|
18869
|
+
resolve();
|
|
18870
|
+
};
|
|
18871
|
+
promise.then(finish, finish);
|
|
18872
|
+
});
|
|
18873
|
+
}
|
|
18713
18874
|
function ConvexCallLayer(deps) {
|
|
18714
18875
|
return Layer.effect(ConvexCallPortTag, Effect.acquireRelease(Effect.sync(() => new ConvexCallAdapter(deps)), (adapter) => Effect.promise(() => adapter.close()).pipe(Effect.orDie)));
|
|
18715
18876
|
}
|
|
@@ -45945,11 +46106,28 @@ const authFailure = (record, reason, mode) => ({
|
|
|
45945
46106
|
...linkage(record)
|
|
45946
46107
|
}
|
|
45947
46108
|
});
|
|
46109
|
+
const REFUSAL_EVENTS = /* @__PURE__ */ new Set([
|
|
46110
|
+
"ClaimAccount",
|
|
46111
|
+
"RetryAccount",
|
|
46112
|
+
"CreateOrganization",
|
|
46113
|
+
"AttachOrganization",
|
|
46114
|
+
"RetryOrganization"
|
|
46115
|
+
]);
|
|
45948
46116
|
function mapIdentityProductObservation(record, state) {
|
|
45949
46117
|
if (record.machine !== "identity" || !IDENTITY_EVENT_TAG_SET.has(record.event)) return NONE;
|
|
45950
46118
|
if (record.outcome === "cancelled") return NONE;
|
|
45951
46119
|
if (record.slot === "identity:auth" && record.outcome === "refused") return authFailure(record, record.refusal_code, void 0);
|
|
45952
46120
|
if (record.slot === "identity:auth" && record.outcome === "failed") return authFailure(record, record.error_code, record.failure?.mode);
|
|
46121
|
+
if (record.outcome === "refused" && REFUSAL_EVENTS.has(record.event)) return {
|
|
46122
|
+
name: "identity_refused",
|
|
46123
|
+
props: {
|
|
46124
|
+
event: record.event,
|
|
46125
|
+
refusal_code: record.refusal_code,
|
|
46126
|
+
slot: record.slot,
|
|
46127
|
+
state: record.state,
|
|
46128
|
+
...linkage(record)
|
|
46129
|
+
}
|
|
46130
|
+
};
|
|
45953
46131
|
if (record.outcome !== "applied") return NONE;
|
|
45954
46132
|
switch (APPLIED_ACTION_BY_EVENT[record.event]) {
|
|
45955
46133
|
case "none": return NONE;
|
|
@@ -46275,6 +46453,7 @@ function assembleCapxulClient(input) {
|
|
|
46275
46453
|
identity: identityRuntime,
|
|
46276
46454
|
bootstrap: input.bootstrap,
|
|
46277
46455
|
accounts: { fund: accounts.fund },
|
|
46456
|
+
...input.ports.indexerRead === void 0 ? {} : { indexer: input.ports.indexerRead },
|
|
46278
46457
|
organizationSetup: { getProofReceipt: (orgId) => runPortEffect(input.ports.convexCall.query(organizationSetupProofReceiptQuery, { orgId })) },
|
|
46279
46458
|
telemetry: input.ports.telemetry,
|
|
46280
46459
|
captureExternalAddressAcknowledged: (address, organizationId) => {
|
|
@@ -46356,6 +46535,382 @@ function snapshotHostObservability(observability) {
|
|
|
46356
46535
|
};
|
|
46357
46536
|
}
|
|
46358
46537
|
//#endregion
|
|
46538
|
+
//#region ../../packages/sdk/src/ports/indexer-read.ts
|
|
46539
|
+
/** The indexer's own page bound. Exceeding it is a caller defect, not a refusal. */
|
|
46540
|
+
const INDEXER_MAX_LIMIT = 1e3;
|
|
46541
|
+
const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
|
|
46542
|
+
/**
|
|
46543
|
+
* Refuse a page the indexer would refuse, before any implementation spends a
|
|
46544
|
+
* round trip on it. Every implementation calls this, so a consumer test written
|
|
46545
|
+
* against the hermetic adapter cannot pass on input production rejects. Throws
|
|
46546
|
+
* a `CapxulError`; callers convert it to an `IndexerReadError`.
|
|
46547
|
+
*/
|
|
46548
|
+
function assertIndexerPage(input) {
|
|
46549
|
+
const safe = String(input.safe).toLowerCase();
|
|
46550
|
+
if (!LOWER_CASE_ADDRESS.test(safe)) throw Errors.invalidInput("safe", "must be a lower-case EVM address");
|
|
46551
|
+
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}`);
|
|
46552
|
+
const offset = input.offset ?? 0;
|
|
46553
|
+
if (!Number.isSafeInteger(offset) || offset < 0) throw Errors.invalidInput("offset", "must be a non-negative integer");
|
|
46554
|
+
return safe;
|
|
46555
|
+
}
|
|
46556
|
+
var IndexerReadError = class extends Data.TaggedError("IndexerReadError") {};
|
|
46557
|
+
function indexerReadErrorFromCapxul(operation, error, cause = error) {
|
|
46558
|
+
return new IndexerReadError({
|
|
46559
|
+
operation,
|
|
46560
|
+
publicCode: error.code,
|
|
46561
|
+
publicError: error,
|
|
46562
|
+
cause,
|
|
46563
|
+
...error.details === void 0 ? {} : { details: error.details }
|
|
46564
|
+
});
|
|
46565
|
+
}
|
|
46566
|
+
Context.Service()("@capxul/sdk/ports/IndexerReadPort");
|
|
46567
|
+
//#endregion
|
|
46568
|
+
//#region ../../packages/sdk/src/adapters/ponder/decode.ts
|
|
46569
|
+
/**
|
|
46570
|
+
* Decode the indexer's rows at the trust boundary.
|
|
46571
|
+
*
|
|
46572
|
+
* Ponder returns the raw PostgreSQL result: `integer` arrives as a number,
|
|
46573
|
+
* `numeric(78)` and `text` arrive as strings. Amounts, block numbers and
|
|
46574
|
+
* timestamps are `numeric(78)`, so they become `bigint` here and never pass
|
|
46575
|
+
* through `Number`. Every decoder throws a `CapxulError`; the adapter turns
|
|
46576
|
+
* that into a typed `IndexerReadError`.
|
|
46577
|
+
*/
|
|
46578
|
+
const HEX = /^0x[0-9a-fA-F]+$/;
|
|
46579
|
+
function field(row, key) {
|
|
46580
|
+
if (!(key in row)) throw Errors.invalidInput(key, "missing from the indexer row");
|
|
46581
|
+
return row[key];
|
|
46582
|
+
}
|
|
46583
|
+
function text(row, key) {
|
|
46584
|
+
const value = field(row, key);
|
|
46585
|
+
if (typeof value !== "string") throw Errors.invalidInput(key, "must be a string");
|
|
46586
|
+
return value;
|
|
46587
|
+
}
|
|
46588
|
+
function hex(row, key) {
|
|
46589
|
+
const value = text(row, key);
|
|
46590
|
+
if (!HEX.test(value)) throw Errors.invalidInput(key, "must be a hex string");
|
|
46591
|
+
return value.toLowerCase();
|
|
46592
|
+
}
|
|
46593
|
+
function integer(row, key) {
|
|
46594
|
+
const value = field(row, key);
|
|
46595
|
+
const parsed = typeof value === "string" ? Number(value) : value;
|
|
46596
|
+
if (typeof parsed !== "number" || !Number.isSafeInteger(parsed)) throw Errors.invalidInput(key, "must be an integer");
|
|
46597
|
+
return parsed;
|
|
46598
|
+
}
|
|
46599
|
+
/** `numeric(78)` crosses the wire as a decimal string; keep every digit. */
|
|
46600
|
+
function big(row, key) {
|
|
46601
|
+
const value = field(row, key);
|
|
46602
|
+
if (typeof value === "bigint") return value;
|
|
46603
|
+
const raw = typeof value === "number" ? String(value) : value;
|
|
46604
|
+
if (typeof raw !== "string" || !/^-?[0-9]+$/.test(raw)) throw Errors.invalidInput(key, "must be an exact integer amount");
|
|
46605
|
+
return BigInt(raw);
|
|
46606
|
+
}
|
|
46607
|
+
function asRow(value) {
|
|
46608
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw Errors.invalidInput("row", "must be an object");
|
|
46609
|
+
return value;
|
|
46610
|
+
}
|
|
46611
|
+
function identity(row) {
|
|
46612
|
+
return {
|
|
46613
|
+
id: text(row, "id"),
|
|
46614
|
+
chainId: toChainId(integer(row, "chain_id")),
|
|
46615
|
+
txHash: toTxHash(hex(row, "tx_hash")),
|
|
46616
|
+
transactionLogOrdinal: integer(row, "transaction_log_ordinal"),
|
|
46617
|
+
blockNumber: big(row, "block_number"),
|
|
46618
|
+
blockHash: hex(row, "block_hash"),
|
|
46619
|
+
timestamp: big(row, "timestamp")
|
|
46620
|
+
};
|
|
46621
|
+
}
|
|
46622
|
+
function decodeTransfer(value) {
|
|
46623
|
+
const row = asRow(value);
|
|
46624
|
+
return {
|
|
46625
|
+
...identity(row),
|
|
46626
|
+
assetId: toAssetId(text(row, "asset_id")),
|
|
46627
|
+
token: toAddress(hex(row, "token")),
|
|
46628
|
+
from: toAddress(hex(row, "from")),
|
|
46629
|
+
to: toAddress(hex(row, "to")),
|
|
46630
|
+
amount: big(row, "amount")
|
|
46631
|
+
};
|
|
46632
|
+
}
|
|
46633
|
+
function decodePayment(value) {
|
|
46634
|
+
const row = asRow(value);
|
|
46635
|
+
return {
|
|
46636
|
+
...identity(row),
|
|
46637
|
+
contract: toAddress(hex(row, "contract")),
|
|
46638
|
+
settlementId: hex(row, "settlement_id"),
|
|
46639
|
+
sender: toAddress(hex(row, "sender")),
|
|
46640
|
+
recipient: toAddress(hex(row, "recipient")),
|
|
46641
|
+
assetId: toAssetId(text(row, "asset_id")),
|
|
46642
|
+
token: toAddress(hex(row, "token")),
|
|
46643
|
+
amount: big(row, "amount"),
|
|
46644
|
+
kind: integer(row, "kind"),
|
|
46645
|
+
documentHash: hex(row, "document_hash")
|
|
46646
|
+
};
|
|
46647
|
+
}
|
|
46648
|
+
/** The `balance` view exposes the signed sum under the underlying column name `to`. */
|
|
46649
|
+
function decodeBalance(value) {
|
|
46650
|
+
const row = asRow(value);
|
|
46651
|
+
return {
|
|
46652
|
+
chainId: toChainId(integer(row, "chain_id")),
|
|
46653
|
+
assetId: toAssetId(text(row, "asset_id")),
|
|
46654
|
+
address: toAddress(hex(row, "to")),
|
|
46655
|
+
amount: big(row, "amount")
|
|
46656
|
+
};
|
|
46657
|
+
}
|
|
46658
|
+
const DECODERS = {
|
|
46659
|
+
transfer: decodeTransfer,
|
|
46660
|
+
payment: decodePayment,
|
|
46661
|
+
balance: decodeBalance
|
|
46662
|
+
};
|
|
46663
|
+
/** Decode one `/sql/db` or `/sql/live` payload. Ponder returns `{ rows: [...] }`. */
|
|
46664
|
+
function decodeRows(table, body) {
|
|
46665
|
+
const rows = asRow(body).rows;
|
|
46666
|
+
if (!Array.isArray(rows)) throw Errors.invalidInput("rows", "must be an array");
|
|
46667
|
+
const decode = DECODERS[table];
|
|
46668
|
+
return rows.map(decode);
|
|
46669
|
+
}
|
|
46670
|
+
/** Decode Ponder's native `/status`: `{ [chainName]: { id, block: { number, timestamp } } }`. */
|
|
46671
|
+
function decodeStatus(body) {
|
|
46672
|
+
const chains = asRow(body);
|
|
46673
|
+
return Object.entries(chains).map(([chain, value]) => {
|
|
46674
|
+
const entry = asRow(value);
|
|
46675
|
+
const block = asRow(field(entry, "block"));
|
|
46676
|
+
return {
|
|
46677
|
+
chain,
|
|
46678
|
+
chainId: toChainId(integer(entry, "id")),
|
|
46679
|
+
blockNumber: big(block, "number"),
|
|
46680
|
+
blockTimestamp: big(block, "timestamp")
|
|
46681
|
+
};
|
|
46682
|
+
});
|
|
46683
|
+
}
|
|
46684
|
+
//#endregion
|
|
46685
|
+
//#region ../../packages/sdk/src/adapters/ponder/statements.ts
|
|
46686
|
+
/**
|
|
46687
|
+
* The exact statements the indexer accepts.
|
|
46688
|
+
*
|
|
46689
|
+
* `apps/indexer/src/queries.ts` compiles its allowlist with `@ponder/client`
|
|
46690
|
+
* and compares `sql`, `params` and `typings` byte for byte against the caller's
|
|
46691
|
+
* statement. Anything else gets 403. The SDK therefore reproduces the compiled
|
|
46692
|
+
* text here rather than pulling Ponder and Drizzle into a published browser
|
|
46693
|
+
* bundle to regenerate three fixed statements.
|
|
46694
|
+
*
|
|
46695
|
+
* `statements.test.ts` pins the text. When the indexer schema or a query in
|
|
46696
|
+
* that allowlist changes, this file changes with it or every read fails 403.
|
|
46697
|
+
*/
|
|
46698
|
+
const HEADS = {
|
|
46699
|
+
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",
|
|
46700
|
+
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",
|
|
46701
|
+
balance: "select \"chain_id\", \"asset_id\", \"to\", \"amount\" from \"balance\" where \"balance\".\"to\" = $1"
|
|
46702
|
+
};
|
|
46703
|
+
/** How many times the statement binds the Safe address. */
|
|
46704
|
+
const ACTOR_PARAMS = {
|
|
46705
|
+
transfer: 2,
|
|
46706
|
+
payment: 2,
|
|
46707
|
+
balance: 1
|
|
46708
|
+
};
|
|
46709
|
+
/**
|
|
46710
|
+
* Build the compiled query for one table and page. Throws a `CapxulError` for
|
|
46711
|
+
* a page or address the indexer would refuse, so the caller never spends a
|
|
46712
|
+
* round trip to learn it built the request wrong.
|
|
46713
|
+
*/
|
|
46714
|
+
function ponderQuery(table, input) {
|
|
46715
|
+
const safe = assertIndexerPage(input);
|
|
46716
|
+
const offset = input.offset ?? 0;
|
|
46717
|
+
const actors = ACTOR_PARAMS[table];
|
|
46718
|
+
const params = [];
|
|
46719
|
+
for (let i = 0; i < actors; i++) params.push(safe);
|
|
46720
|
+
params.push(input.limit);
|
|
46721
|
+
let sql = `${HEADS[table]} limit $${actors + 1}`;
|
|
46722
|
+
if (offset > 0) {
|
|
46723
|
+
params.push(offset);
|
|
46724
|
+
sql = `${sql} offset $${actors + 2}`;
|
|
46725
|
+
}
|
|
46726
|
+
return {
|
|
46727
|
+
sql,
|
|
46728
|
+
params,
|
|
46729
|
+
typings: params.map(() => "none")
|
|
46730
|
+
};
|
|
46731
|
+
}
|
|
46732
|
+
/**
|
|
46733
|
+
* The `?sql=` value. `@ponder/client` sends `superjson.stringify(query)`; for a
|
|
46734
|
+
* payload of strings and numbers superjson emits no `meta`, so the wire form is
|
|
46735
|
+
* exactly this envelope.
|
|
46736
|
+
*/
|
|
46737
|
+
function ponderQueryParam(query) {
|
|
46738
|
+
return JSON.stringify({ json: query });
|
|
46739
|
+
}
|
|
46740
|
+
//#endregion
|
|
46741
|
+
//#region ../../packages/sdk/src/adapters/ponder/sse.ts
|
|
46742
|
+
/**
|
|
46743
|
+
* The smallest SSE reader that can carry an `Authorization` header.
|
|
46744
|
+
*
|
|
46745
|
+
* `@ponder/client` opens its live query with `EventSource`, which accepts no
|
|
46746
|
+
* headers, so it cannot reach the guarded indexer at all. The indexer's CORS
|
|
46747
|
+
* policy allows exactly one request header (`Authorization`), so this reader
|
|
46748
|
+
* sends nothing else. Ponder writes one `data:` line per frame.
|
|
46749
|
+
*/
|
|
46750
|
+
async function readEventStream(body, onData, stopped) {
|
|
46751
|
+
const reader = body.getReader();
|
|
46752
|
+
const decoder = new TextDecoder();
|
|
46753
|
+
let buffer = "";
|
|
46754
|
+
try {
|
|
46755
|
+
for (;;) {
|
|
46756
|
+
const { done, value } = await reader.read();
|
|
46757
|
+
if (done || stopped()) return;
|
|
46758
|
+
buffer += decoder.decode(value, { stream: true });
|
|
46759
|
+
let split = buffer.indexOf("\n\n");
|
|
46760
|
+
while (split !== -1) {
|
|
46761
|
+
const frame = buffer.slice(0, split);
|
|
46762
|
+
buffer = buffer.slice(split + 2);
|
|
46763
|
+
const data = frameData(frame);
|
|
46764
|
+
if (data !== void 0) onData(data);
|
|
46765
|
+
if (stopped()) return;
|
|
46766
|
+
split = buffer.indexOf("\n\n");
|
|
46767
|
+
}
|
|
46768
|
+
}
|
|
46769
|
+
} finally {
|
|
46770
|
+
await reader.cancel().catch(() => void 0);
|
|
46771
|
+
}
|
|
46772
|
+
}
|
|
46773
|
+
function frameData(frame) {
|
|
46774
|
+
const lines = [];
|
|
46775
|
+
for (const line of frame.split("\n")) {
|
|
46776
|
+
if (!line.startsWith("data:")) continue;
|
|
46777
|
+
lines.push(line.slice(line.startsWith("data: ") ? 6 : 5));
|
|
46778
|
+
}
|
|
46779
|
+
return lines.length === 0 ? void 0 : lines.join("\n");
|
|
46780
|
+
}
|
|
46781
|
+
//#endregion
|
|
46782
|
+
//#region ../../packages/sdk/src/adapters/ponder/PonderIndexerAdapter.ts
|
|
46783
|
+
var PonderIndexerAdapter = class {
|
|
46784
|
+
#baseUrl;
|
|
46785
|
+
#token;
|
|
46786
|
+
#fetch;
|
|
46787
|
+
#observation;
|
|
46788
|
+
constructor(deps) {
|
|
46789
|
+
this.#baseUrl = deps.baseUrl.replace(/\/$/, "");
|
|
46790
|
+
this.#token = deps.token;
|
|
46791
|
+
this.#observation = deps.observation;
|
|
46792
|
+
this.#fetch = deps.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
46793
|
+
}
|
|
46794
|
+
read(table, input) {
|
|
46795
|
+
const operation = `indexer.read.${table}`;
|
|
46796
|
+
return Effect.tryPromise({
|
|
46797
|
+
try: async () => {
|
|
46798
|
+
return decodeRows(table, await (await this.#request("db", table, input, operation)).json());
|
|
46799
|
+
},
|
|
46800
|
+
catch: (cause) => toIndexerReadError(operation, cause)
|
|
46801
|
+
});
|
|
46802
|
+
}
|
|
46803
|
+
subscribe(table, input, callback) {
|
|
46804
|
+
const operation = CAPXUL_OPERATIONS.activity.subscribe;
|
|
46805
|
+
return Effect.sync(() => {
|
|
46806
|
+
let stopped = false;
|
|
46807
|
+
const unsubscribe = () => {
|
|
46808
|
+
stopped = true;
|
|
46809
|
+
};
|
|
46810
|
+
callback({ status: "loading" });
|
|
46811
|
+
this.#stream(table, input, operation, callback, () => stopped).catch(() => void 0);
|
|
46812
|
+
return unsubscribe;
|
|
46813
|
+
});
|
|
46814
|
+
}
|
|
46815
|
+
status = Effect.tryPromise({
|
|
46816
|
+
try: async () => {
|
|
46817
|
+
const response = await this.#fetch(`${this.#baseUrl}/status`, { method: "GET" });
|
|
46818
|
+
if (!response.ok) throw httpError("indexer.status", response.status, await safeText(response));
|
|
46819
|
+
return decodeStatus(await response.json());
|
|
46820
|
+
},
|
|
46821
|
+
catch: (cause) => toIndexerReadError("indexer.status", cause)
|
|
46822
|
+
});
|
|
46823
|
+
/** One authenticated `/sql/:method` call. Throws a `CapxulError` on refusal. */
|
|
46824
|
+
async #request(method, table, input, operation) {
|
|
46825
|
+
const query = ponderQuery(table, input);
|
|
46826
|
+
const token = await this.#token({ forceRefreshToken: false });
|
|
46827
|
+
if (token === null || token === "") throw Errors.notAuthenticated();
|
|
46828
|
+
const url = `${this.#baseUrl}/sql/${method}?sql=${encodeURIComponent(ponderQueryParam(query))}`;
|
|
46829
|
+
const headers = { authorization: `Bearer ${token}` };
|
|
46830
|
+
if (method === "live") headers.accept = "text/event-stream";
|
|
46831
|
+
let response;
|
|
46832
|
+
try {
|
|
46833
|
+
response = await this.#fetch(url, {
|
|
46834
|
+
method: "GET",
|
|
46835
|
+
headers
|
|
46836
|
+
});
|
|
46837
|
+
} catch (cause) {
|
|
46838
|
+
throw Errors.networkError(operation, cause, {
|
|
46839
|
+
provider: "indexer",
|
|
46840
|
+
failure_mode: "upstream-down"
|
|
46841
|
+
});
|
|
46842
|
+
}
|
|
46843
|
+
if (!response.ok) throw httpError(operation, response.status, await safeText(response));
|
|
46844
|
+
return response;
|
|
46845
|
+
}
|
|
46846
|
+
/**
|
|
46847
|
+
* Follow the live stream until the caller unsubscribes or the indexer closes
|
|
46848
|
+
* it. The indexer closes the stream on token expiry or revoked authority
|
|
46849
|
+
* with no frame, so any end the caller did not ask for is a teardown: it
|
|
46850
|
+
* reaches `captureException` under `activity.subscribe` and the caller sees
|
|
46851
|
+
* one `error` snapshot.
|
|
46852
|
+
*/
|
|
46853
|
+
async #stream(table, input, operation, callback, stopped) {
|
|
46854
|
+
let failure;
|
|
46855
|
+
try {
|
|
46856
|
+
const response = await this.#request("live", table, input, operation);
|
|
46857
|
+
if (response.body === null) throw Errors.providerError("indexer", operation, "empty stream");
|
|
46858
|
+
await readEventStream(response.body, (data) => {
|
|
46859
|
+
try {
|
|
46860
|
+
callback({
|
|
46861
|
+
status: "ok",
|
|
46862
|
+
value: decodeRows(table, JSON.parse(data))
|
|
46863
|
+
});
|
|
46864
|
+
} catch (cause) {
|
|
46865
|
+
failure = toPublicError$1(operation, cause);
|
|
46866
|
+
}
|
|
46867
|
+
}, () => stopped() || failure !== void 0);
|
|
46868
|
+
} catch (cause) {
|
|
46869
|
+
failure = toPublicError$1(operation, cause);
|
|
46870
|
+
}
|
|
46871
|
+
if (stopped()) return;
|
|
46872
|
+
const error = failure ?? Errors.capabilityUnavailable("indexer", operation);
|
|
46873
|
+
observeStreamFailure(this.#observation, CAPXUL_OPERATIONS.activity.subscribe, error);
|
|
46874
|
+
callback({
|
|
46875
|
+
status: "error",
|
|
46876
|
+
error
|
|
46877
|
+
});
|
|
46878
|
+
}
|
|
46879
|
+
};
|
|
46880
|
+
/**
|
|
46881
|
+
* Map an indexer refusal into the shared error vocabulary.
|
|
46882
|
+
*
|
|
46883
|
+
* 401 is the expected outcome of an expired or revoked session. 403 is not:
|
|
46884
|
+
* the indexer accepts only its own compiled statements for a Safe in the
|
|
46885
|
+
* claim, so a refusal means this SDK and that deployment disagree, or the
|
|
46886
|
+
* session gained a Safe and still holds the older token. Both must be loud.
|
|
46887
|
+
*/
|
|
46888
|
+
function httpError(operation, status, body) {
|
|
46889
|
+
if (status === 401) return Errors.notAuthenticated();
|
|
46890
|
+
if (status === 429) return Errors.rateLimited({ resource: "indexer" });
|
|
46891
|
+
if (status === 503) return Errors.capabilityUnavailable("indexer", operation);
|
|
46892
|
+
return Errors.providerError("indexer", operation, body, {
|
|
46893
|
+
httpStatus: status,
|
|
46894
|
+
...status >= 500 ? { failure_mode: "upstream-down" } : {},
|
|
46895
|
+
details: { reason: status === 403 ? "scope-refused" : "http-status" }
|
|
46896
|
+
});
|
|
46897
|
+
}
|
|
46898
|
+
function toPublicError$1(operation, cause) {
|
|
46899
|
+
if (cause instanceof CapxulError) return cause;
|
|
46900
|
+
return Errors.providerError("indexer", operation, cause);
|
|
46901
|
+
}
|
|
46902
|
+
function toIndexerReadError(operation, cause) {
|
|
46903
|
+
if (cause instanceof IndexerReadError) return cause;
|
|
46904
|
+
return indexerReadErrorFromCapxul(operation, toPublicError$1(operation, cause), cause);
|
|
46905
|
+
}
|
|
46906
|
+
async function safeText(response) {
|
|
46907
|
+
try {
|
|
46908
|
+
return await response.text();
|
|
46909
|
+
} catch {
|
|
46910
|
+
return "";
|
|
46911
|
+
}
|
|
46912
|
+
}
|
|
46913
|
+
//#endregion
|
|
46359
46914
|
//#region ../../packages/sdk/src/adapters/_shared/clock.ts
|
|
46360
46915
|
async function readClockNow(clock) {
|
|
46361
46916
|
try {
|
|
@@ -46812,7 +47367,16 @@ async function createProductionAdapters(input) {
|
|
|
46812
47367
|
}));
|
|
46813
47368
|
const applicationLayer = Layer.merge(portsLayer, optionalEngineeringTelemetryLayer(bootstrapResult.value.engineeringTelemetry, resolvedInput.value.runtime));
|
|
46814
47369
|
const context = await Effect.runPromise(Layer.buildWithScope(applicationLayer, scope));
|
|
46815
|
-
const
|
|
47370
|
+
const collected = await Effect.runPromise(collectProductionFlowPorts.pipe(Effect.provide(context)));
|
|
47371
|
+
const indexerUrl = input.indexerUrl ?? bootstrapResult.value.indexerUrl;
|
|
47372
|
+
const indexerRead = productionIndexerReadPort(indexerUrl === void 0 ? input : {
|
|
47373
|
+
...input,
|
|
47374
|
+
indexerUrl
|
|
47375
|
+
}, collected, observation);
|
|
47376
|
+
const ports = indexerRead === void 0 ? collected : {
|
|
47377
|
+
...collected,
|
|
47378
|
+
indexerRead
|
|
47379
|
+
};
|
|
46816
47380
|
const stopConnectionObservation = observeProductionConvexConnection(ports.convexCall, context);
|
|
46817
47381
|
const close = idempotentClose(async () => {
|
|
46818
47382
|
try {
|
|
@@ -47144,6 +47708,28 @@ function idempotentClose(close) {
|
|
|
47144
47708
|
await close();
|
|
47145
47709
|
};
|
|
47146
47710
|
}
|
|
47711
|
+
/**
|
|
47712
|
+
* Build the Ponder read port for this client, or `undefined` when no indexer
|
|
47713
|
+
* origin was supplied. The token provider is the same
|
|
47714
|
+
* `AuthClientPort.getConvexJwt` closure `ConvexCallPort` uses, so the indexer
|
|
47715
|
+
* and Convex see one session with one scope.
|
|
47716
|
+
*/
|
|
47717
|
+
function productionIndexerReadPort(input, ports, observation) {
|
|
47718
|
+
if (input.indexerUrl === void 0 || input.indexerUrl === "") return void 0;
|
|
47719
|
+
return new PonderIndexerAdapter({
|
|
47720
|
+
baseUrl: normalizeHttpUrl("indexerUrl", input.indexerUrl),
|
|
47721
|
+
token: async ({ forceRefreshToken }) => {
|
|
47722
|
+
const token = await Effect.runPromise(Effect.result(ports.authClient.getConvexJwt({
|
|
47723
|
+
forceRefresh: forceRefreshToken,
|
|
47724
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
47725
|
+
})));
|
|
47726
|
+
if (Result.isFailure(token)) return null;
|
|
47727
|
+
return String(token.success.token);
|
|
47728
|
+
},
|
|
47729
|
+
...input.fetch === void 0 ? {} : { fetch: input.fetch },
|
|
47730
|
+
...observation === void 0 ? {} : { observation }
|
|
47731
|
+
});
|
|
47732
|
+
}
|
|
47147
47733
|
//#endregion
|
|
47148
47734
|
//#region src/tools/account.ts
|
|
47149
47735
|
const READ = "account:read";
|
|
@@ -47755,7 +48341,7 @@ function stdioIdentity(env = process.env, options = {}) {
|
|
|
47755
48341
|
}
|
|
47756
48342
|
//#endregion
|
|
47757
48343
|
//#region package.json
|
|
47758
|
-
var version = "4.2.0-rc.
|
|
48344
|
+
var version = "4.2.0-rc.9";
|
|
47759
48345
|
//#endregion
|
|
47760
48346
|
//#region src/deps.ts
|
|
47761
48347
|
const NO_IDENTITY = async () => void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capxul/mcp",
|
|
3
|
-
"version": "4.2.0-rc.
|
|
3
|
+
"version": "4.2.0-rc.9",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Capxul MCP server for auth, Account readiness, identity, Organizations, relationships, requests, destinations, and testnet funding over Streamable HTTP.",
|
|
6
6
|
"keywords": [
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.0",
|
|
52
52
|
"vite-plus": "0.3.0",
|
|
53
53
|
"@capxul/config": "0.3.0",
|
|
54
|
-
"@capxul/
|
|
55
|
-
"@capxul/
|
|
54
|
+
"@capxul/sdk": "4.2.0-rc.9",
|
|
55
|
+
"@capxul/typescript-config": "0.0.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"dev": "vp exec tsx src/main.ts serve",
|