@capxul/mcp 4.2.0-rc.9 → 4.20.0-beta.1
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/main.mjs +1527 -252
- package/package.json +3 -3
- package/dist/capxul-source.json +0 -11
package/dist/main.mjs
CHANGED
|
@@ -8,9 +8,9 @@ import { createHash } from "node:crypto";
|
|
|
8
8
|
import { createServer } from "node:http";
|
|
9
9
|
import { localhostHostValidation, localhostOriginValidation, toNodeHandler } from "@modelcontextprotocol/node";
|
|
10
10
|
import { z } from "zod";
|
|
11
|
-
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";
|
|
12
|
-
import { FetchHttpClient, Headers, HttpClient } from "effect/unstable/http";
|
|
13
|
-
import { OtlpExporter, OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
|
|
11
|
+
import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, Layer, Logger, Option, Queue, Ref, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stream, Tracer } from "effect";
|
|
12
|
+
import { FetchHttpClient, Headers, HttpBody, HttpClient, HttpClientResponse, HttpTraceContext } from "effect/unstable/http";
|
|
13
|
+
import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
|
|
14
14
|
import { resolve } from "path";
|
|
15
15
|
import util from "util";
|
|
16
16
|
import stream, { Readable } from "stream";
|
|
@@ -127,14 +127,19 @@ function redactUrlSecrets(value, source) {
|
|
|
127
127
|
changed ||= safeName !== name || safeEntry !== entry;
|
|
128
128
|
return [safeName, safeEntry];
|
|
129
129
|
})).toString();
|
|
130
|
-
const provider = source
|
|
131
|
-
const
|
|
132
|
-
const
|
|
130
|
+
const provider = source === "alchemy" || source === "infura" || /(?:^|\.)(?:alchemy\.com|alchemyapi\.io|infura\.io)$/iu.test(url.hostname);
|
|
131
|
+
const rawPath = absolute || protocolRelative ? url.pathname : value.split(/[?#]/u)[0] ?? "";
|
|
132
|
+
const segments = rawPath.split("/");
|
|
133
|
+
let path = segments.map((segment, index) => {
|
|
133
134
|
const decoded = decodeUrlComponent(segment);
|
|
134
135
|
const masked = provider && /^v[23]$/u.test(decodeUrlComponent(segments[index - 1] ?? "")) && decoded.length > 0 ? "[REDACTED]" : maskText(decoded);
|
|
135
136
|
changed ||= masked !== decoded;
|
|
136
137
|
return masked === decoded ? segment : encodeURIComponent(masked);
|
|
137
138
|
}).join("/");
|
|
139
|
+
if (source === "gateway" && rawPath.length > 0) {
|
|
140
|
+
path = `${rawPath.startsWith("/") ? "/" : ""}${encodeURIComponent("[REDACTED]")}`;
|
|
141
|
+
changed = true;
|
|
142
|
+
}
|
|
138
143
|
const query = maskParams(url.searchParams);
|
|
139
144
|
const fragment = url.hash.slice(1);
|
|
140
145
|
const decodedFragment = decodeUrlComponent(fragment);
|
|
@@ -149,6 +154,7 @@ function redactUrlSecrets(value, source) {
|
|
|
149
154
|
if (!changed) return value;
|
|
150
155
|
return `${origin}${path}${query ? `?${query}` : ""}${hash ? `#${hash}` : ""}`;
|
|
151
156
|
} catch {
|
|
157
|
+
if (source === "gateway") return "[REDACTED]";
|
|
152
158
|
return maskText(value.replace(/(https?:\/\/)[^/\s@]+@/giu, "$1[REDACTED]@").replace(/([?&#])([^=&#]+)=([^&#]*)/gu, (whole, separator, name) => isCredentialField(decodeUrlComponent(name)) || /^(?:code|draft|__posthog)$/iu.test(decodeUrlComponent(name)) ? `${separator}${name}=[REDACTED]` : whole));
|
|
153
159
|
}
|
|
154
160
|
}
|
|
@@ -931,6 +937,10 @@ function toChainId(raw) {
|
|
|
931
937
|
if (typeof raw !== "number" || !Number.isSafeInteger(raw) || raw <= 0) throw Errors.invalidInput("chainId", invalidValueReason("must be a positive safe integer", raw));
|
|
932
938
|
return raw;
|
|
933
939
|
}
|
|
940
|
+
function toWeiAmount(raw) {
|
|
941
|
+
if (typeof raw !== "string" || !WEI_RE.test(raw)) throw Errors.invalidInput("weiAmount", invalidValueReason("must be a non-negative integer string", raw));
|
|
942
|
+
return raw;
|
|
943
|
+
}
|
|
934
944
|
function toCountryCode(raw) {
|
|
935
945
|
if (typeof raw !== "string") throw Errors.invalidInput("countryCode", "must be a string");
|
|
936
946
|
const upper = raw.toUpperCase();
|
|
@@ -1087,8 +1097,18 @@ const SYNTHETIC_TEST_ASSETS = [
|
|
|
1087
1097
|
}
|
|
1088
1098
|
];
|
|
1089
1099
|
toChainId(84532);
|
|
1090
|
-
|
|
1100
|
+
/**
|
|
1101
|
+
* Every known asset in ONE identity space. The tiers above declare admission;
|
|
1102
|
+
* this is the only list an identity resolves against, so an asset is never
|
|
1103
|
+
* two different things depending on which list a caller happened to read.
|
|
1104
|
+
*/
|
|
1105
|
+
const MONEY_ASSET_REGISTRY = [...CONFIGURED_MONEY_ASSETS, ...SYNTHETIC_TEST_ASSETS];
|
|
1091
1106
|
CONFIGURED_MONEY_ASSETS.map((asset) => asset.tokenAddress.toLowerCase());
|
|
1107
|
+
/** The registry row for `assetId` across every tier, or `null`. */
|
|
1108
|
+
function configuredMoneyAssetById(assetId) {
|
|
1109
|
+
const canonical = toAssetId(assetId);
|
|
1110
|
+
return MONEY_ASSET_REGISTRY.find((asset) => asset.assetId === canonical) ?? null;
|
|
1111
|
+
}
|
|
1092
1112
|
//#endregion
|
|
1093
1113
|
//#region ../../node_modules/.pnpm/abitype@1.2.3_typescript@7.0.2_zod@4.4.3/node_modules/abitype/dist/esm/regex.js
|
|
1094
1114
|
function execTyped(regex, string) {
|
|
@@ -6933,8 +6953,12 @@ const CAPXUL_OPERATIONS = {
|
|
|
6933
6953
|
cancelRequest: "financialOps.cancelRequest",
|
|
6934
6954
|
createPayee: "financialOps.createPayee",
|
|
6935
6955
|
declineRequest: "financialOps.declineRequest",
|
|
6956
|
+
emitInvoiceIssued: "financialOps.emitInvoiceIssued",
|
|
6957
|
+
emitInvoiceRequestTransitioned: "financialOps.emitInvoiceRequestTransitioned",
|
|
6936
6958
|
emitPaymentWriterTelemetry: "financialOps.emitPaymentWriterTelemetry",
|
|
6937
6959
|
issueRequest: "financialOps.issueRequest",
|
|
6960
|
+
migrateEvidenceIdentity: "financialOps.migrateEvidenceIdentity",
|
|
6961
|
+
planEvidenceIdentity: "financialOps.planEvidenceIdentity",
|
|
6938
6962
|
recoverSettlementVerification: "financialOps.recoverSettlementVerification",
|
|
6939
6963
|
removeDestination: "financialOps.removeDestination",
|
|
6940
6964
|
verifySettlement: "financialOps.verifySettlement"
|
|
@@ -6943,6 +6967,7 @@ const CAPXUL_OPERATIONS = {
|
|
|
6943
6967
|
current: "holdings.current",
|
|
6944
6968
|
primary: "holdings.primary"
|
|
6945
6969
|
},
|
|
6970
|
+
indexer: { reconcile: "indexer.reconcile" },
|
|
6946
6971
|
identity: {
|
|
6947
6972
|
accountAt: "identity.AccountAt",
|
|
6948
6973
|
accountClaimed: "identity.AccountClaimed",
|
|
@@ -7032,6 +7057,7 @@ const CAPXUL_OPERATIONS = {
|
|
|
7032
7057
|
createOrg: "org.createOrg",
|
|
7033
7058
|
create: "org.create",
|
|
7034
7059
|
detectAndAcceptPendingInvitations: "org.detectAndAcceptPendingInvitations",
|
|
7060
|
+
emitInviteProgressed: "org.emitInviteProgressed",
|
|
7035
7061
|
expireInvitations: "org.expireInvitations",
|
|
7036
7062
|
getLifecycle: "org.getLifecycle",
|
|
7037
7063
|
getProofReceipt: "org.getProofReceipt",
|
|
@@ -7135,6 +7161,8 @@ const CAPXUL_OPERATIONS = {
|
|
|
7135
7161
|
recipient: { resolve: "recipient.resolve" },
|
|
7136
7162
|
payroll: {
|
|
7137
7163
|
authorizeRun: "payroll.authorizeRun",
|
|
7164
|
+
emitGroupChanged: "payroll.emitGroupChanged",
|
|
7165
|
+
emitRunTransitioned: "payroll.emitRunTransitioned",
|
|
7138
7166
|
groups: {
|
|
7139
7167
|
access: "payroll.groups",
|
|
7140
7168
|
list: "payroll.groups.list",
|
|
@@ -7266,6 +7294,10 @@ const OptionalAccountId = Schema.optional(AccountIdSchema$1);
|
|
|
7266
7294
|
const OptionalWeiAmount = Schema.optional(WeiAmountSchema$1);
|
|
7267
7295
|
const OptionalCurrencyCode = Schema.optional(CurrencyCodeSchema$1);
|
|
7268
7296
|
const OptionalBalanceBucket = Schema.optional(BalanceBucketSchema);
|
|
7297
|
+
/** Which Safe a money record is about. Declared here so the money-domain
|
|
7298
|
+
* props below can name it as well as the UI-step props further down. */
|
|
7299
|
+
const AccountKindSchema = Schema.Literals(["personalSafe", "orgTreasury"]);
|
|
7300
|
+
const OptionalAccountKind = Schema.optional(AccountKindSchema);
|
|
7269
7301
|
const OptionalAddress = Schema.optional(AddressSchema$1);
|
|
7270
7302
|
const OptionalAppId = Schema.optional(AppIdSchema$1);
|
|
7271
7303
|
const OptionalBlockNumber = Schema.optional(BlockNumberSchema$1);
|
|
@@ -7418,9 +7450,22 @@ const BootstrapFailedProps = Schema.Struct({
|
|
|
7418
7450
|
reason: OptionalString,
|
|
7419
7451
|
target_host: OptionalString
|
|
7420
7452
|
});
|
|
7453
|
+
/**
|
|
7454
|
+
* R08 (#1966): which Safe was read, on which chain, of which token. `currency`
|
|
7455
|
+
* is the DISPLAY code the surface shows ("USD"); it never says which ERC-20 the
|
|
7456
|
+
* `balanceOf` actually hit, so a reader could not tell a treasury read from a
|
|
7457
|
+
* personal one, nor USDX from any other dollar-labelled token. The producer
|
|
7458
|
+
* takes each of these from the authority that already decided it — the verified
|
|
7459
|
+
* Organization row's chain, the configured token address — never from a label.
|
|
7460
|
+
* The verified `organization_id` and its group arrive from the backend
|
|
7461
|
+
* attribution, so they are not repeated here.
|
|
7462
|
+
*/
|
|
7421
7463
|
const AccountBalanceReadProps = Schema.Struct({
|
|
7422
7464
|
...TelemetryEnvelopeProps,
|
|
7423
7465
|
account_id: OptionalAccountId,
|
|
7466
|
+
account_kind: OptionalAccountKind,
|
|
7467
|
+
chain_id: OptionalChainId,
|
|
7468
|
+
token_address: OptionalAddress,
|
|
7424
7469
|
currency: OptionalCurrencyCode,
|
|
7425
7470
|
balance_bucket: OptionalBalanceBucket,
|
|
7426
7471
|
durationMs: OptionalDurationMs
|
|
@@ -7788,7 +7833,27 @@ const PermissionMirrorVerificationProps = Schema.Struct({
|
|
|
7788
7833
|
"conflicting_replay",
|
|
7789
7834
|
"revision_mismatch"
|
|
7790
7835
|
])),
|
|
7791
|
-
command_id: OptionalString
|
|
7836
|
+
command_id: OptionalString,
|
|
7837
|
+
/**
|
|
7838
|
+
* #1961 R03. The authorized stored row names the Permission it changed; the
|
|
7839
|
+
* verified receipt names the chain facts that prove it. Every field is
|
|
7840
|
+
* optional because a pending or provider-failed verification has neither an
|
|
7841
|
+
* application result nor a receipt to report.
|
|
7842
|
+
*/
|
|
7843
|
+
permission_id: OptionalString,
|
|
7844
|
+
permission_assignment_id: OptionalString,
|
|
7845
|
+
permission_operation: Schema.optional(Schema.Literals([
|
|
7846
|
+
"create",
|
|
7847
|
+
"change",
|
|
7848
|
+
"assign",
|
|
7849
|
+
"revoke",
|
|
7850
|
+
"replace"
|
|
7851
|
+
])),
|
|
7852
|
+
revision: Schema.optional(Schema.Number),
|
|
7853
|
+
user_op_hash: OptionalString,
|
|
7854
|
+
transaction_hash: OptionalString,
|
|
7855
|
+
block_number: Schema.optional(Schema.Number),
|
|
7856
|
+
log_index: Schema.optional(Schema.Number)
|
|
7792
7857
|
});
|
|
7793
7858
|
const MovementScanWindowProps = Schema.Struct({
|
|
7794
7859
|
...TelemetryEnvelopeProps,
|
|
@@ -7814,6 +7879,33 @@ const MovementScanIncidentProps = Schema.Struct({
|
|
|
7814
7879
|
incident_kind: Schema.String,
|
|
7815
7880
|
anchor_block_number: Schema.Number
|
|
7816
7881
|
});
|
|
7882
|
+
/**
|
|
7883
|
+
* One durable row the reconciliation job corrected against Ponder (SPEC D9).
|
|
7884
|
+
*
|
|
7885
|
+
* Both block fields are optional and for the same reason: a correction INTO
|
|
7886
|
+
* drift (a Payment settled in Convex whose Ponder fact a reorg removed) has no
|
|
7887
|
+
* current block, and a correction that confirms a later fact has one.
|
|
7888
|
+
*
|
|
7889
|
+
* `projection_kind` is closed. A later ticket that reconciles a deploy, a
|
|
7890
|
+
* bootstrap or a grant outcome adds its kind here in the same change; an
|
|
7891
|
+
* unknown kind must not decode.
|
|
7892
|
+
*/
|
|
7893
|
+
const IndexerDriftCorrectedProps = Schema.Struct({
|
|
7894
|
+
...TelemetryEnvelopeProps,
|
|
7895
|
+
projection_kind: Schema.Literals([
|
|
7896
|
+
"member_authority",
|
|
7897
|
+
"payment_settlement",
|
|
7898
|
+
"permission_assignment"
|
|
7899
|
+
]),
|
|
7900
|
+
previous_state: Schema.String,
|
|
7901
|
+
current_state: Schema.String,
|
|
7902
|
+
previous_block: Schema.optional(Schema.Number),
|
|
7903
|
+
current_block: Schema.optional(Schema.Number),
|
|
7904
|
+
logical_event_id: Schema.optional(Schema.String),
|
|
7905
|
+
scope_kind: Schema.optional(Schema.Literals(["account", "organization"])),
|
|
7906
|
+
account_id: OptionalAccountId,
|
|
7907
|
+
reference_id: OptionalString
|
|
7908
|
+
});
|
|
7817
7909
|
Schema.Struct({
|
|
7818
7910
|
name: Schema.Literal("auth_otp_requested"),
|
|
7819
7911
|
props: AuthOtpRequestedProps
|
|
@@ -8018,9 +8110,12 @@ Schema.Struct({
|
|
|
8018
8110
|
name: Schema.Literal("movement_scan_incident"),
|
|
8019
8111
|
props: MovementScanIncidentProps
|
|
8020
8112
|
});
|
|
8113
|
+
Schema.Struct({
|
|
8114
|
+
name: Schema.Literal("indexer_drift_corrected"),
|
|
8115
|
+
props: IndexerDriftCorrectedProps
|
|
8116
|
+
});
|
|
8021
8117
|
/** The one spelling of "whose scope did this happen in" across every surface. */
|
|
8022
8118
|
const ScopeKindSchema = Schema.Literals(["account", "organization"]);
|
|
8023
|
-
const AccountKindSchema = Schema.Literals(["personalSafe", "orgTreasury"]);
|
|
8024
8119
|
const OptionalReasonCode = Schema.optional(Schema.Literals(CAPXUL_ERROR_CODES));
|
|
8025
8120
|
const ActivityReferenceProps = {
|
|
8026
8121
|
reference_kind: Schema.Literals(["payment", "movement"]),
|
|
@@ -8085,6 +8180,20 @@ const ContactActionProps = {
|
|
|
8085
8180
|
party_id: OptionalString,
|
|
8086
8181
|
reason_code: OptionalReasonCode
|
|
8087
8182
|
};
|
|
8183
|
+
Schema.Struct({
|
|
8184
|
+
name: Schema.Literal("cli_diagnostic_completed"),
|
|
8185
|
+
props: Schema.Struct({
|
|
8186
|
+
...TelemetryEnvelopeProps,
|
|
8187
|
+
outcome: Schema.Literals([
|
|
8188
|
+
"succeeded",
|
|
8189
|
+
"refused",
|
|
8190
|
+
"failed",
|
|
8191
|
+
"cancelled"
|
|
8192
|
+
]),
|
|
8193
|
+
invocation_id: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u)),
|
|
8194
|
+
cli_version: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/u))
|
|
8195
|
+
})
|
|
8196
|
+
});
|
|
8088
8197
|
Schema.Struct({
|
|
8089
8198
|
name: Schema.Literal("ui_contact_action_completed"),
|
|
8090
8199
|
props: Schema.Union([
|
|
@@ -8118,6 +8227,16 @@ Schema.Struct({
|
|
|
8118
8227
|
Schema.Struct({
|
|
8119
8228
|
name: Schema.Literal("ui_activity_action_completed"),
|
|
8120
8229
|
props: Schema.Union([
|
|
8230
|
+
Schema.Struct({
|
|
8231
|
+
...ActivityActionProps,
|
|
8232
|
+
action: Schema.Literal("read"),
|
|
8233
|
+
outcome: Schema.Literals(["partial_displayed", "recovered"]),
|
|
8234
|
+
surface: Schema.Literals([
|
|
8235
|
+
"transactions",
|
|
8236
|
+
"recent",
|
|
8237
|
+
"summary"
|
|
8238
|
+
])
|
|
8239
|
+
}),
|
|
8121
8240
|
Schema.Struct({
|
|
8122
8241
|
...ActivityActionProps,
|
|
8123
8242
|
...ActivityFilterProps,
|
|
@@ -8334,6 +8453,12 @@ Schema.Struct({
|
|
|
8334
8453
|
"settled"
|
|
8335
8454
|
]),
|
|
8336
8455
|
run_id: Schema.String,
|
|
8456
|
+
/**
|
|
8457
|
+
* The `paymentCommands` row at `payrollRuns.batchRef` — the durable owner of
|
|
8458
|
+
* this run's Payment membership. `payment_count` counts THAT command's
|
|
8459
|
+
* `paymentIds`, so an unrelated Payment quoting the run id changes neither.
|
|
8460
|
+
*/
|
|
8461
|
+
command_id: OptionalString,
|
|
8337
8462
|
payment_count: Schema.optional(Schema.Number),
|
|
8338
8463
|
occurred_at: Schema.Number
|
|
8339
8464
|
})
|
|
@@ -8359,6 +8484,71 @@ function redactTelemetryProps(name, props, options = {}) {
|
|
|
8359
8484
|
for (const key of PII_PROP_KEYS_BY_EVENT[name] ?? []) redactProperty(clone, key);
|
|
8360
8485
|
return clone;
|
|
8361
8486
|
}
|
|
8487
|
+
/** In unstructured bodies, preserve text around explicitly named credentials. */
|
|
8488
|
+
const NETWORK_FIELD = /((?:"?)([A-Za-z_][A-Za-z0-9_.-]*)(?:"?)\s*[:=]\s*)("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[^\s,;&}]+)/gu;
|
|
8489
|
+
function maskNetworkText(text, context) {
|
|
8490
|
+
return redactSecrets(text).replace(NETWORK_FIELD, (whole, prefix, name, value) => {
|
|
8491
|
+
if (!isCredentialField(name, context)) return whole;
|
|
8492
|
+
const quote = value.startsWith("\"") ? "\"" : value.startsWith("'") ? "'" : "";
|
|
8493
|
+
return `${prefix}${quote}[REDACTED]${quote}`;
|
|
8494
|
+
});
|
|
8495
|
+
}
|
|
8496
|
+
function maskNetworkHeaders(headers) {
|
|
8497
|
+
if (headers === void 0) return void 0;
|
|
8498
|
+
const masked = {};
|
|
8499
|
+
for (const [name, value] of Object.entries(headers)) masked[name] = isCredentialField(name, "header") ? "[REDACTED]" : /^(?:location|content-location|referer)$/iu.test(name) ? redactUrlSecrets(value) : maskNetworkText(value);
|
|
8500
|
+
return masked;
|
|
8501
|
+
}
|
|
8502
|
+
function maskJsonValue(value, depth = 0, context) {
|
|
8503
|
+
if (typeof value === "function" || typeof value === "symbol") return "[UNREADABLE]";
|
|
8504
|
+
if (typeof value === "string") return maskNetworkText(value, context);
|
|
8505
|
+
if (typeof value !== "object" || value === null) return value;
|
|
8506
|
+
if (depth >= 16) return "[REDACTED]";
|
|
8507
|
+
if (Array.isArray(value)) return value.map((item) => maskJsonValue(item, depth + 1, context));
|
|
8508
|
+
const masked = Object.create(null);
|
|
8509
|
+
for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
|
|
8510
|
+
if (!descriptor.enumerable) continue;
|
|
8511
|
+
masked[key] = isCredentialField(key, context) ? "[REDACTED]" : !("value" in descriptor) ? "[UNREADABLE]" : typeof descriptor.value === "string" && isPostHogUrlProperty(key) ? redactUrlSecrets(descriptor.value) : maskJsonValue(descriptor.value, depth + 1, context);
|
|
8512
|
+
}
|
|
8513
|
+
return masked;
|
|
8514
|
+
}
|
|
8515
|
+
function maskNetworkBody(body, context) {
|
|
8516
|
+
try {
|
|
8517
|
+
if (typeof body !== "string") return maskJsonValue(body, 0, context);
|
|
8518
|
+
let parsed;
|
|
8519
|
+
try {
|
|
8520
|
+
parsed = JSON.parse(body);
|
|
8521
|
+
} catch {
|
|
8522
|
+
if (/^[^=&\s]+=[\s\S]*$/u.test(body)) return new URLSearchParams(Array.from(new URLSearchParams(body), ([name, value]) => [name, isCredentialField(name, context) ? "[REDACTED]" : maskNetworkText(value)])).toString();
|
|
8523
|
+
return maskNetworkText(body, context);
|
|
8524
|
+
}
|
|
8525
|
+
return JSON.stringify(maskJsonValue(parsed, 0, context));
|
|
8526
|
+
} catch {
|
|
8527
|
+
return "[UNREADABLE]";
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8530
|
+
/** Keep request evidence while masking credential values at the browser boundary. */
|
|
8531
|
+
function maskCapturedNetworkRequest(request) {
|
|
8532
|
+
const requestUrl = request.name ?? request.url ?? "";
|
|
8533
|
+
let context;
|
|
8534
|
+
try {
|
|
8535
|
+
const path = new URL(requestUrl, "https://capxul.invalid").pathname;
|
|
8536
|
+
if (/\/(?:auth|oauth|sign-in|signin|login|verify-otp|verify-email)(?:\/|$)/iu.test(path)) context = "authentication";
|
|
8537
|
+
} catch {}
|
|
8538
|
+
return {
|
|
8539
|
+
...request,
|
|
8540
|
+
...request.name === void 0 ? {} : { name: redactUrlSecrets(request.name) },
|
|
8541
|
+
...request.url === void 0 ? {} : { url: redactUrlSecrets(request.url) },
|
|
8542
|
+
requestHeaders: maskNetworkHeaders(request.requestHeaders),
|
|
8543
|
+
responseHeaders: maskNetworkHeaders(request.responseHeaders),
|
|
8544
|
+
requestBody: maskNetworkBody(request.requestBody, context),
|
|
8545
|
+
responseBody: maskNetworkBody(request.responseBody)
|
|
8546
|
+
};
|
|
8547
|
+
}
|
|
8548
|
+
function isPostHogUrlProperty(key) {
|
|
8549
|
+
const normalized = key.toLowerCase();
|
|
8550
|
+
return normalized.includes("url") || normalized.includes("referrer") || normalized.includes("path") || normalized.includes("filename");
|
|
8551
|
+
}
|
|
8362
8552
|
const PII_PROP_KEYS_BY_EVENT = {
|
|
8363
8553
|
auth_otp_requested: ["email"],
|
|
8364
8554
|
auth_otp_delivered: ["email"],
|
|
@@ -8713,6 +8903,7 @@ const CAPXUL_FUNCTIONS = {
|
|
|
8713
8903
|
list: "movement/activity:list",
|
|
8714
8904
|
summary: "movement/activity:summary"
|
|
8715
8905
|
},
|
|
8906
|
+
"movement/annotations": { overlay: "movement/annotations:overlay" },
|
|
8716
8907
|
"moneyExecution/actions": {
|
|
8717
8908
|
abandonPaymentExecution: "moneyExecution/actions:abandonPaymentExecution",
|
|
8718
8909
|
preparePermissionExecution: "moneyExecution/actions:preparePermissionExecution",
|
|
@@ -8790,7 +8981,10 @@ const CAPXUL_FUNCTIONS = {
|
|
|
8790
8981
|
isUserOperationReceiptHeld: "e2eControls:isUserOperationReceiptHeld",
|
|
8791
8982
|
releaseUserOperationReceipt: "e2eControls:releaseUserOperationReceipt"
|
|
8792
8983
|
},
|
|
8793
|
-
system: {
|
|
8984
|
+
system: {
|
|
8985
|
+
health: "system:health",
|
|
8986
|
+
healthObserved: "system:healthObserved"
|
|
8987
|
+
}
|
|
8794
8988
|
};
|
|
8795
8989
|
//#endregion
|
|
8796
8990
|
//#region ../../packages/wire/src/status.ts
|
|
@@ -9311,7 +9505,19 @@ const StoredPermissionCommandSchema = Schema.Struct({
|
|
|
9311
9505
|
roleKey: RoleKeySchema,
|
|
9312
9506
|
allowanceKey: Schema.NullOr(AllowanceKeySchema),
|
|
9313
9507
|
memberSafe: Schema.NullOr(SafeAddressSchema),
|
|
9314
|
-
expectedAuthorityEvents: Schema.Array(Bytes32Schema)
|
|
9508
|
+
expectedAuthorityEvents: Schema.Array(Bytes32Schema),
|
|
9509
|
+
/**
|
|
9510
|
+
* #1961 R03. The authenticated user who created the command, and the browser
|
|
9511
|
+
* linkage captured with it. Delayed verification and bounded retries read
|
|
9512
|
+
* this snapshot instead of the current viewer, so one command keeps one
|
|
9513
|
+
* origin. Both are absent on commands created before this contract.
|
|
9514
|
+
*
|
|
9515
|
+
* The context stays `unknown` on purpose: `sanitizeObservationContext` owns
|
|
9516
|
+
* the field allowlist, and every reader passes the stored value through it
|
|
9517
|
+
* rather than repeating those rules here.
|
|
9518
|
+
*/
|
|
9519
|
+
originatingAuthUserId: Schema.optional(Schema.String),
|
|
9520
|
+
originatingObservationContext: Schema.optional(Schema.Unknown)
|
|
9315
9521
|
});
|
|
9316
9522
|
Schema.Struct({
|
|
9317
9523
|
command: StoredPermissionCommandSchema,
|
|
@@ -9471,7 +9677,9 @@ const ExpectedPaymentCommonSchema = Schema.Struct({
|
|
|
9471
9677
|
chainId: BaseSepoliaChainIdSchema,
|
|
9472
9678
|
contractAddress: AddressSchema,
|
|
9473
9679
|
userOpHash: Bytes32Schema,
|
|
9474
|
-
userOpSenderSafe: SafeAddressSchema
|
|
9680
|
+
userOpSenderSafe: SafeAddressSchema,
|
|
9681
|
+
/** Retained receipt location only; it cannot replace UserOperation or financial proof. */
|
|
9682
|
+
recordedTransactionHash: Schema.optional(Bytes32Schema)
|
|
9475
9683
|
});
|
|
9476
9684
|
Schema.Union([
|
|
9477
9685
|
Schema.Struct({
|
|
@@ -9589,6 +9797,13 @@ Schema.Struct({
|
|
|
9589
9797
|
transfers: Schema.Array(TransferEvidenceSchema),
|
|
9590
9798
|
requestCount: nonNegativeInteger("requestCount")
|
|
9591
9799
|
});
|
|
9800
|
+
/**
|
|
9801
|
+
* `chainId:txHash:transactionLogOrdinal` — the indexer's own row id. The
|
|
9802
|
+
* ordinal is the position in the transaction's receipt logs, never the
|
|
9803
|
+
* block-global index that `eventLogIndex` carries.
|
|
9804
|
+
*/
|
|
9805
|
+
const LOGICAL_EVENT_ID_RE = /^[1-9][0-9]{0,9}:0x[0-9a-f]{64}:(0|[1-9][0-9]{0,5})$/u;
|
|
9806
|
+
const LogicalEventIdSchema = Schema.String.pipe(Schema.refine((value) => LOGICAL_EVENT_ID_RE.test(value), { message: "must be chainId:txHash:transactionLogOrdinal" }));
|
|
9592
9807
|
const VerifiedMoneyEvidenceCommonSchema = Schema.Struct({
|
|
9593
9808
|
chainId: BaseSepoliaChainIdSchema,
|
|
9594
9809
|
contractAddress: AddressSchema,
|
|
@@ -9597,7 +9812,18 @@ const VerifiedMoneyEvidenceCommonSchema = Schema.Struct({
|
|
|
9597
9812
|
blockNumber: BlockNumberSchema,
|
|
9598
9813
|
blockHash: Bytes32Schema,
|
|
9599
9814
|
blockTimestamp: Uint48Schema,
|
|
9600
|
-
|
|
9815
|
+
/**
|
|
9816
|
+
* The block-global log index of the settled event, as
|
|
9817
|
+
* `eth_getTransactionReceipt` reports it. Both readers key on this value, and
|
|
9818
|
+
* the ledger de-duplicates a settlement on `(txHash, eventLogIndex)`.
|
|
9819
|
+
*/
|
|
9820
|
+
eventLogIndex: LogIndexSchema,
|
|
9821
|
+
/**
|
|
9822
|
+
* Stable chain event identity. Ponder supplies its row id; the receipt-backed
|
|
9823
|
+
* direct-send reader derives the same ordinal from the complete transaction
|
|
9824
|
+
* receipt. Legacy and remaining Commitment readers can omit this field.
|
|
9825
|
+
*/
|
|
9826
|
+
logicalEventId: Schema.optional(LogicalEventIdSchema)
|
|
9601
9827
|
});
|
|
9602
9828
|
const VerifiedPaymentEvidenceSchema = Schema.Struct({
|
|
9603
9829
|
...VerifiedMoneyEvidenceCommonSchema.fields,
|
|
@@ -11145,7 +11371,9 @@ function verifiedOperationFields(attributes) {
|
|
|
11145
11371
|
for (const [key, allowed] of [
|
|
11146
11372
|
["scope_kind", ["account", "organization"]],
|
|
11147
11373
|
["account_kind", ["personalSafe", "orgTreasury"]],
|
|
11148
|
-
["network", ["base-sepolia"]]
|
|
11374
|
+
["network", ["base-sepolia"]],
|
|
11375
|
+
["read_source", ["indexer", "convex"]],
|
|
11376
|
+
["read_warning", ["indexer-unavailable"]]
|
|
11149
11377
|
]) {
|
|
11150
11378
|
const value = attributes.get(key);
|
|
11151
11379
|
if (typeof value === "string" && allowed.some((candidate) => candidate === value)) domain[key] = value;
|
|
@@ -11829,31 +12057,31 @@ function makeActorRelationshipMethods(deps) {
|
|
|
11829
12057
|
reference: input.reference,
|
|
11830
12058
|
...input.memo === void 0 ? {} : { memo: input.memo },
|
|
11831
12059
|
...input.expiresAt === void 0 ? {} : { expiresAt: input.expiresAt }
|
|
11832
|
-
}))), (request) => mapActorRequest(request, input.payer)), controls, CAPXUL_OPERATIONS.requests.issue, deps.runPromise);
|
|
12060
|
+
}))), (request) => mapActorRequest(request, input.payer)).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.requests.issue, deps.runPromise);
|
|
11833
12061
|
},
|
|
11834
12062
|
list: (options) => {
|
|
11835
12063
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
11836
|
-
return runPortEffect(mapReply(CAPXUL_OPERATIONS.requests.list, Effect.suspend(() => convexCall.query(fns.requestsList, copyInvocationObservation(controls, { actor }))), (requests) => requests.map((request) => mapActorRequest(request))), controls, CAPXUL_OPERATIONS.requests.list, deps.runPromise);
|
|
12064
|
+
return runPortEffect(mapReply(CAPXUL_OPERATIONS.requests.list, Effect.suspend(() => convexCall.query(fns.requestsList, copyInvocationObservation(controls, { actor }))), (requests) => requests.map((request) => mapActorRequest(request))).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.requests.list, deps.runPromise);
|
|
11837
12065
|
},
|
|
11838
12066
|
get: (requestId, options) => {
|
|
11839
12067
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
11840
12068
|
return runPortEffect(mapReply(CAPXUL_OPERATIONS.requests.get, Effect.suspend(() => convexCall.query(fns.requestsGet, copyInvocationObservation(controls, {
|
|
11841
12069
|
actor,
|
|
11842
12070
|
paymentRequestId: requestId
|
|
11843
|
-
}))), (request) => request === null ? null : mapActorRequest(request)), controls, CAPXUL_OPERATIONS.requests.get, deps.runPromise);
|
|
12071
|
+
}))), (request) => request === null ? null : mapActorRequest(request)).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.requests.get, deps.runPromise);
|
|
11844
12072
|
},
|
|
11845
12073
|
cancel: (requestId, options) => {
|
|
11846
12074
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
11847
12075
|
return runPortEffect(mapReply(CAPXUL_OPERATIONS.requests.cancel, Effect.suspend(() => convexCall.mutation(fns.requestsCancel, copyInvocationObservation(controls, {
|
|
11848
12076
|
actor,
|
|
11849
12077
|
paymentRequestId: requestId
|
|
11850
|
-
}))), (request) => mapActorRequest(request)), controls, CAPXUL_OPERATIONS.requests.cancel, deps.runPromise);
|
|
12078
|
+
}))), (request) => mapActorRequest(request)).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.requests.cancel, deps.runPromise);
|
|
11851
12079
|
}
|
|
11852
12080
|
},
|
|
11853
12081
|
inbox: {
|
|
11854
12082
|
list: (options) => {
|
|
11855
12083
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
11856
|
-
return runPortEffect(mapReply(CAPXUL_OPERATIONS.inbox.list, Effect.suspend(() => convexCall.query(fns.inboxList, copyInvocationObservation(controls, { actor }))), (items) => items.map(mapInboxItem)), controls, CAPXUL_OPERATIONS.inbox.list, deps.runPromise);
|
|
12084
|
+
return runPortEffect(mapReply(CAPXUL_OPERATIONS.inbox.list, Effect.suspend(() => convexCall.query(fns.inboxList, copyInvocationObservation(controls, { actor }))), (items) => items.map(mapInboxItem)).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.inbox.list, deps.runPromise);
|
|
11857
12085
|
},
|
|
11858
12086
|
approve: (input, options) => {
|
|
11859
12087
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
@@ -11865,14 +12093,14 @@ function makeActorRelationshipMethods(deps) {
|
|
|
11865
12093
|
}))).pipe(Effect.flatMap((prepared) => {
|
|
11866
12094
|
const result = mapApprovedInboxPayment(prepared, input);
|
|
11867
12095
|
return result.ok ? Effect.succeed(result.value) : Effect.fail({ publicError: result.error });
|
|
11868
|
-
})), controls, CAPXUL_OPERATIONS.inbox.approve, deps.runPromise);
|
|
12096
|
+
}), Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.inbox.approve, deps.runPromise);
|
|
11869
12097
|
},
|
|
11870
12098
|
decline: (requestId, options) => {
|
|
11871
12099
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
11872
12100
|
return runPortEffect(mapReply(CAPXUL_OPERATIONS.inbox.decline, Effect.suspend(() => convexCall.mutation(fns.inboxDecline, copyInvocationObservation(controls, {
|
|
11873
12101
|
actor,
|
|
11874
12102
|
paymentRequestId: requestId
|
|
11875
|
-
}))), mapInboxItem), controls, CAPXUL_OPERATIONS.inbox.decline, deps.runPromise);
|
|
12103
|
+
}))), mapInboxItem).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.inbox.decline, deps.runPromise);
|
|
11876
12104
|
}
|
|
11877
12105
|
},
|
|
11878
12106
|
profile: {
|
|
@@ -12361,6 +12589,7 @@ const financialOpsContract = {
|
|
|
12361
12589
|
activitySummary: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].summary),
|
|
12362
12590
|
activityGet: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].get),
|
|
12363
12591
|
activityAnnotate: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].annotate),
|
|
12592
|
+
activityOverlay: makeFunctionReference(CAPXUL_FUNCTIONS["movement/annotations"].overlay),
|
|
12364
12593
|
verifyPaymentDocument: makeFunctionReference(CAPXUL_FUNCTIONS["financialOps/queries"].verifyPaymentDocument),
|
|
12365
12594
|
renderStoredDocument: makeFunctionReference(CAPXUL_FUNCTIONS["financialOps/queries"].renderStoredDocument)
|
|
12366
12595
|
};
|
|
@@ -12377,8 +12606,383 @@ const moneyExecutionContract = {
|
|
|
12377
12606
|
submitPaymentCommandExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/paymentCommandActions"].submitPaymentCommandExecution)
|
|
12378
12607
|
};
|
|
12379
12608
|
//#endregion
|
|
12609
|
+
//#region ../../packages/sdk/src/ports/indexer-read.ts
|
|
12610
|
+
/** The indexer's own page bound. Exceeding it is a caller defect, not a refusal. */
|
|
12611
|
+
const INDEXER_MAX_LIMIT = 1e3;
|
|
12612
|
+
const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
|
|
12613
|
+
/**
|
|
12614
|
+
* Refuse a page the indexer would refuse, before any implementation spends a
|
|
12615
|
+
* round trip on it. Every implementation calls this, so a consumer test written
|
|
12616
|
+
* against the hermetic adapter cannot pass on input production rejects. Throws
|
|
12617
|
+
* a `CapxulError`; callers convert it to an `IndexerReadError`.
|
|
12618
|
+
*/
|
|
12619
|
+
function assertIndexerPage(input) {
|
|
12620
|
+
const safe = String(input.safe).toLowerCase();
|
|
12621
|
+
if (!LOWER_CASE_ADDRESS.test(safe)) throw Errors.invalidInput("safe", "must be a lower-case EVM address");
|
|
12622
|
+
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}`);
|
|
12623
|
+
const offset = input.offset ?? 0;
|
|
12624
|
+
if (!Number.isSafeInteger(offset) || offset < 0) throw Errors.invalidInput("offset", "must be a non-negative integer");
|
|
12625
|
+
return safe;
|
|
12626
|
+
}
|
|
12627
|
+
var IndexerReadError = class extends Data.TaggedError("IndexerReadError") {};
|
|
12628
|
+
function indexerReadErrorFromCapxul(operation, error, cause = error) {
|
|
12629
|
+
return new IndexerReadError({
|
|
12630
|
+
operation,
|
|
12631
|
+
publicCode: error.code,
|
|
12632
|
+
publicError: error,
|
|
12633
|
+
cause,
|
|
12634
|
+
...error.details === void 0 ? {} : { details: error.details }
|
|
12635
|
+
});
|
|
12636
|
+
}
|
|
12637
|
+
Context.Service()("@capxul/sdk/ports/IndexerReadPort");
|
|
12638
|
+
//#endregion
|
|
12639
|
+
//#region ../../packages/sdk/src/surface/activity-stitch.ts
|
|
12640
|
+
/** Epoch milliseconds of the block that carried the row. */
|
|
12641
|
+
function blockMillis(row) {
|
|
12642
|
+
return Number(row.timestamp) * 1e3;
|
|
12643
|
+
}
|
|
12644
|
+
/** `0x1234…abcd` — the counterparty of an unclaimed transfer is an address. */
|
|
12645
|
+
function shortAddressLabel(address) {
|
|
12646
|
+
return address.length <= 12 ? address : `${address.slice(0, 6)}…${address.slice(-4)}`;
|
|
12647
|
+
}
|
|
12648
|
+
function directionFor(safe, transfer) {
|
|
12649
|
+
const from = transfer.from.toLowerCase();
|
|
12650
|
+
const to = transfer.to.toLowerCase();
|
|
12651
|
+
if (from === safe && to === safe) return "self";
|
|
12652
|
+
return to === safe ? "in" : "out";
|
|
12653
|
+
}
|
|
12654
|
+
/**
|
|
12655
|
+
* The Transfer a protocol Payment moved is the same money as its `payment`
|
|
12656
|
+
* row. One actor sees one item for it, so the Transfer is claimed and does not
|
|
12657
|
+
* become a second row. Another transfer in the same transaction that this
|
|
12658
|
+
* payment did not move stays unclaimed and keeps its own row.
|
|
12659
|
+
*/
|
|
12660
|
+
function claimedTransferIds(transfers, payments) {
|
|
12661
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
12662
|
+
for (const payment of payments) {
|
|
12663
|
+
const match = transfers.find((transfer) => !claimed.has(transfer.id) && transfer.txHash === payment.txHash && transfer.token.toLowerCase() === payment.token.toLowerCase() && transfer.amount === payment.amount && transfer.to.toLowerCase() === payment.recipient.toLowerCase());
|
|
12664
|
+
if (match !== void 0) claimed.add(match.id);
|
|
12665
|
+
}
|
|
12666
|
+
return claimed;
|
|
12667
|
+
}
|
|
12668
|
+
function withAnnotation(item, annotation) {
|
|
12669
|
+
return annotation?.counterpartyLabel === void 0 ? item : {
|
|
12670
|
+
...item,
|
|
12671
|
+
counterpartyLabel: annotation.counterpartyLabel
|
|
12672
|
+
};
|
|
12673
|
+
}
|
|
12674
|
+
/**
|
|
12675
|
+
* An indexed settlement confirms the intent. A missing row can be outside
|
|
12676
|
+
* this page or still backfilling; only the correction owner can prove rollback.
|
|
12677
|
+
*/
|
|
12678
|
+
function confirmPayment(intent, chain) {
|
|
12679
|
+
if (chain !== void 0) return {
|
|
12680
|
+
...intent,
|
|
12681
|
+
status: "settled",
|
|
12682
|
+
receipt: {
|
|
12683
|
+
chainId: chain.chainId,
|
|
12684
|
+
transactionHash: chain.txHash
|
|
12685
|
+
},
|
|
12686
|
+
updatedAt: blockMillis(chain)
|
|
12687
|
+
};
|
|
12688
|
+
return intent;
|
|
12689
|
+
}
|
|
12690
|
+
/**
|
|
12691
|
+
* One unclaimed Transfer as an Activity row, or `null` when this SDK cannot
|
|
12692
|
+
* denominate its asset. The indexer serves only configured assets, so a row
|
|
12693
|
+
* the registry does not know means the SDK and that deployment disagree; it is
|
|
12694
|
+
* dropped rather than shown with a guessed currency.
|
|
12695
|
+
*/
|
|
12696
|
+
function transferItem(safe, transfer, annotation) {
|
|
12697
|
+
const asset = configuredMoneyAssetById(transfer.assetId);
|
|
12698
|
+
if (asset === null) return null;
|
|
12699
|
+
const direction = directionFor(safe, transfer);
|
|
12700
|
+
const counterparty = direction === "in" ? transfer.from : transfer.to;
|
|
12701
|
+
const at = blockMillis(transfer);
|
|
12702
|
+
return withAnnotation({
|
|
12703
|
+
kind: "movement",
|
|
12704
|
+
id: transfer.id,
|
|
12705
|
+
classification: "movement_only_outflow",
|
|
12706
|
+
amount: {
|
|
12707
|
+
currency: asset.peg ?? asset.symbol,
|
|
12708
|
+
value: formatUnits(transfer.amount, asset.decimals),
|
|
12709
|
+
decimals: asset.decimals
|
|
12710
|
+
},
|
|
12711
|
+
direction,
|
|
12712
|
+
counterpartyLabel: shortAddressLabel(counterparty),
|
|
12713
|
+
receipt: {
|
|
12714
|
+
chainId: transfer.chainId,
|
|
12715
|
+
transactionHash: transfer.txHash
|
|
12716
|
+
},
|
|
12717
|
+
createdAt: at,
|
|
12718
|
+
updatedAt: at
|
|
12719
|
+
}, annotation);
|
|
12720
|
+
}
|
|
12721
|
+
/** Newest first. A Payment precedes a Movement at one instant, as the ledger reader orders them. */
|
|
12722
|
+
function compareItems(left, right) {
|
|
12723
|
+
if (right.createdAt !== left.createdAt) return right.createdAt - left.createdAt;
|
|
12724
|
+
if (left.kind !== right.kind) return left.kind === "payment" ? -1 : 1;
|
|
12725
|
+
if (left.id === right.id) return 0;
|
|
12726
|
+
return left.id < right.id ? 1 : -1;
|
|
12727
|
+
}
|
|
12728
|
+
function stitchActivity(input) {
|
|
12729
|
+
const safe = input.safe.toLowerCase();
|
|
12730
|
+
const chainBySettlement = /* @__PURE__ */ new Map();
|
|
12731
|
+
for (const row of input.payments) chainBySettlement.set(row.settlementId.toLowerCase(), row);
|
|
12732
|
+
const chainByPaymentId = /* @__PURE__ */ new Map();
|
|
12733
|
+
for (const link of input.links) {
|
|
12734
|
+
const row = chainBySettlement.get(link.settlementId.toLowerCase());
|
|
12735
|
+
if (row !== void 0) chainByPaymentId.set(link.paymentId, row);
|
|
12736
|
+
}
|
|
12737
|
+
const annotations = /* @__PURE__ */ new Map();
|
|
12738
|
+
for (const annotation of input.annotations) annotations.set(`${annotation.reference.kind}:${annotation.reference.id}`, annotation);
|
|
12739
|
+
const items = [];
|
|
12740
|
+
const claiming = [];
|
|
12741
|
+
for (const intent of input.intents) {
|
|
12742
|
+
if (intent.kind !== "payment") continue;
|
|
12743
|
+
const chain = chainByPaymentId.get(intent.id);
|
|
12744
|
+
if (chain !== void 0) claiming.push(chain);
|
|
12745
|
+
items.push(withAnnotation(confirmPayment(intent, chain), annotations.get(`payment:${intent.id}`)));
|
|
12746
|
+
}
|
|
12747
|
+
const claimed = claimedTransferIds(input.transfers, claiming);
|
|
12748
|
+
for (const transfer of input.transfers) {
|
|
12749
|
+
if (claimed.has(transfer.id)) continue;
|
|
12750
|
+
const item = transferItem(safe, transfer, annotations.get(`movement:${transfer.id}`));
|
|
12751
|
+
if (item !== null) items.push(item);
|
|
12752
|
+
}
|
|
12753
|
+
return items.sort(compareItems);
|
|
12754
|
+
}
|
|
12755
|
+
/** The reference ids one stitched page needs its Convex overlay for. */
|
|
12756
|
+
function overlayReferences(items) {
|
|
12757
|
+
return items.map((item) => ({
|
|
12758
|
+
kind: item.kind,
|
|
12759
|
+
id: item.id
|
|
12760
|
+
}));
|
|
12761
|
+
}
|
|
12762
|
+
/**
|
|
12763
|
+
* Money in, money out and the pending share, one bucket per currency and
|
|
12764
|
+
* precision. Two assets that peg to the same currency at different precision
|
|
12765
|
+
* stay distinct buckets: their raw units are not interchangeable.
|
|
12766
|
+
*/
|
|
12767
|
+
function summarizeItems(items) {
|
|
12768
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
12769
|
+
for (const item of items) {
|
|
12770
|
+
const key = `${item.amount.currency}:${String(item.amount.decimals)}`;
|
|
12771
|
+
const bucket = buckets.get(key) ?? {
|
|
12772
|
+
currency: item.amount.currency,
|
|
12773
|
+
decimals: item.amount.decimals,
|
|
12774
|
+
in: 0n,
|
|
12775
|
+
out: 0n,
|
|
12776
|
+
pendingIn: 0n
|
|
12777
|
+
};
|
|
12778
|
+
const raw = rawUnits(item.amount.value, item.amount.decimals);
|
|
12779
|
+
if (item.kind === "payment" && item.status !== "settled") {
|
|
12780
|
+
if (item.direction === "in" && item.status !== "cancelled" && item.status !== "failed") bucket.pendingIn += raw;
|
|
12781
|
+
} else if (item.direction === "in") bucket.in += raw;
|
|
12782
|
+
else if (item.direction === "out") bucket.out += raw;
|
|
12783
|
+
buckets.set(key, bucket);
|
|
12784
|
+
}
|
|
12785
|
+
return [...buckets.values()].map((bucket) => ({
|
|
12786
|
+
currency: bucket.currency,
|
|
12787
|
+
decimals: bucket.decimals,
|
|
12788
|
+
in: bucket.in.toString(),
|
|
12789
|
+
out: bucket.out.toString(),
|
|
12790
|
+
net: (bucket.in - bucket.out).toString(),
|
|
12791
|
+
pendingIn: bucket.pendingIn.toString()
|
|
12792
|
+
}));
|
|
12793
|
+
}
|
|
12794
|
+
/** The inverse of `formatUnits`, kept exact: `"1.25"` at 6 decimals is `1250000n`. */
|
|
12795
|
+
function rawUnits(value, decimals) {
|
|
12796
|
+
const negative = value.startsWith("-");
|
|
12797
|
+
const [whole = "0", fraction = ""] = (negative ? value.slice(1) : value).split(".");
|
|
12798
|
+
const raw = BigInt(`${whole}${fraction.padEnd(decimals, "0").slice(0, decimals)}`);
|
|
12799
|
+
return negative ? -raw : raw;
|
|
12800
|
+
}
|
|
12801
|
+
//#endregion
|
|
12802
|
+
//#region ../../packages/sdk/src/surface/activity-read.ts
|
|
12803
|
+
/** How many Convex intent rows one page reads for its labels and pending rows. */
|
|
12804
|
+
const INTENT_WINDOW = 100;
|
|
12805
|
+
/** movement/annotations:overlay bounds each identifier array to 200. */
|
|
12806
|
+
const MAX_OVERLAY_IDS = 200;
|
|
12807
|
+
/** The window a summary aggregates over. The indexer's own page bound. */
|
|
12808
|
+
const SUMMARY_WINDOW = INDEXER_MAX_LIMIT;
|
|
12809
|
+
function parseCursor(value) {
|
|
12810
|
+
if (value === void 0) return 0;
|
|
12811
|
+
try {
|
|
12812
|
+
const parsed = JSON.parse(value);
|
|
12813
|
+
return Number.isSafeInteger(parsed.offset) && parsed.offset >= 0 ? parsed.offset : 0;
|
|
12814
|
+
} catch {
|
|
12815
|
+
return 0;
|
|
12816
|
+
}
|
|
12817
|
+
}
|
|
12818
|
+
function inRange(item, range) {
|
|
12819
|
+
if (range?.from !== void 0 && item.createdAt < range.from) return false;
|
|
12820
|
+
return range?.to === void 0 || item.createdAt <= range.to;
|
|
12821
|
+
}
|
|
12822
|
+
/** The caller's filter applied to the merged page. The join owns the order. */
|
|
12823
|
+
function matchesFilter(item, filter) {
|
|
12824
|
+
if (filter === void 0) return true;
|
|
12825
|
+
if (filter.kind !== void 0 && item.kind !== filter.kind) return false;
|
|
12826
|
+
if (filter.direction !== void 0 && item.direction !== filter.direction) return false;
|
|
12827
|
+
if (filter.status === void 0) return true;
|
|
12828
|
+
return item.kind === "payment" && filter.status.includes(item.status);
|
|
12829
|
+
}
|
|
12830
|
+
function overlay(deps, actor, controls, input) {
|
|
12831
|
+
const count = Math.max(input.references?.length ?? 0, input.settlementIds?.length ?? 0);
|
|
12832
|
+
const offsets = Array.from({ length: Math.max(1, Math.ceil(count / MAX_OVERLAY_IDS)) }, (_, index) => index * MAX_OVERLAY_IDS);
|
|
12833
|
+
return Effect.forEach(offsets, (offset) => deps.convexCall.query(deps.functions.activityOverlay, copyInvocationObservation(controls, { input: {
|
|
12834
|
+
...actor === void 0 ? {} : { actor },
|
|
12835
|
+
...input.references === void 0 ? {} : { references: input.references.slice(offset, offset + MAX_OVERLAY_IDS) },
|
|
12836
|
+
...input.settlementIds === void 0 ? {} : { settlementIds: input.settlementIds.slice(offset, offset + MAX_OVERLAY_IDS) }
|
|
12837
|
+
} })), { concurrency: 2 }).pipe(Effect.map((pages) => ({
|
|
12838
|
+
...pages[0],
|
|
12839
|
+
links: pages.flatMap((page) => page.links),
|
|
12840
|
+
annotations: pages.flatMap((page) => page.annotations)
|
|
12841
|
+
})));
|
|
12842
|
+
}
|
|
12843
|
+
function convexPage(deps, actor, controls, input) {
|
|
12844
|
+
return deps.convexCall.query(deps.functions.activityList, copyInvocationObservation(controls, { input: {
|
|
12845
|
+
...actor === void 0 ? {} : { actor },
|
|
12846
|
+
...input.cursor === void 0 ? {} : { cursor: input.cursor },
|
|
12847
|
+
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
12848
|
+
...input.range === void 0 ? {} : { range: input.range }
|
|
12849
|
+
} }));
|
|
12850
|
+
}
|
|
12851
|
+
/** Both indexed tables for one Safe, or `null` when the indexer cannot answer. */
|
|
12852
|
+
function chainRows(deps, safe, limit) {
|
|
12853
|
+
const page = {
|
|
12854
|
+
safe,
|
|
12855
|
+
limit: Math.min(limit, INDEXER_MAX_LIMIT)
|
|
12856
|
+
};
|
|
12857
|
+
return Effect.all([deps.indexer.read("transfer", page), deps.indexer.read("payment", page)], { concurrency: 2 }).pipe(Effect.map(([transfers, payments]) => ({
|
|
12858
|
+
transfers,
|
|
12859
|
+
payments
|
|
12860
|
+
})), Effect.catch(() => Effect.succeed(null)));
|
|
12861
|
+
}
|
|
12862
|
+
/** The stitched, filtered rows of one window, newest first. */
|
|
12863
|
+
function stitchedWindow(deps, actor, controls, window, params) {
|
|
12864
|
+
return Effect.gen(function* () {
|
|
12865
|
+
const scope = yield* overlay(deps, actor, controls, {});
|
|
12866
|
+
const convex = yield* convexPage(deps, actor, controls, {
|
|
12867
|
+
limit: INTENT_WINDOW,
|
|
12868
|
+
...params.range === void 0 ? {} : { range: params.range }
|
|
12869
|
+
});
|
|
12870
|
+
const rows = scope.safe === null ? null : yield* chainRows(deps, scope.safe, window);
|
|
12871
|
+
if (rows === null || scope.safe === null) {
|
|
12872
|
+
if (scope.safe !== null) yield* Effect.annotateCurrentSpan({
|
|
12873
|
+
read_source: "convex",
|
|
12874
|
+
read_warning: "indexer-unavailable"
|
|
12875
|
+
});
|
|
12876
|
+
return {
|
|
12877
|
+
items: convex.items.filter((item) => matchesFilter(item, params.filter)),
|
|
12878
|
+
stitched: false,
|
|
12879
|
+
...scope.safe === null ? {} : { readWarning: "indexer-unavailable" }
|
|
12880
|
+
};
|
|
12881
|
+
}
|
|
12882
|
+
yield* Effect.annotateCurrentSpan({ read_source: "indexer" });
|
|
12883
|
+
const decoration = yield* overlay(deps, actor, controls, {
|
|
12884
|
+
references: [...overlayReferences(convex.items), ...rows.transfers.map((row) => ({
|
|
12885
|
+
kind: "movement",
|
|
12886
|
+
id: row.id
|
|
12887
|
+
}))],
|
|
12888
|
+
settlementIds: rows.payments.map((row) => row.settlementId)
|
|
12889
|
+
});
|
|
12890
|
+
const intents = [...convex.items];
|
|
12891
|
+
const missing = new Set(decoration.links.map((link) => link.paymentId));
|
|
12892
|
+
for (const item of intents) if (item.kind === "payment") missing.delete(item.id);
|
|
12893
|
+
let cursor = convex.cursor;
|
|
12894
|
+
while (missing.size > 0 && cursor !== null) {
|
|
12895
|
+
const page = yield* convexPage(deps, actor, controls, {
|
|
12896
|
+
limit: INTENT_WINDOW,
|
|
12897
|
+
cursor,
|
|
12898
|
+
...params.range === void 0 ? {} : { range: params.range }
|
|
12899
|
+
});
|
|
12900
|
+
for (const item of page.items) if (item.kind === "payment" && missing.delete(item.id)) intents.push(item);
|
|
12901
|
+
cursor = page.cursor;
|
|
12902
|
+
}
|
|
12903
|
+
const older = intents.slice(convex.items.length);
|
|
12904
|
+
const olderDecoration = older.length === 0 ? [] : (yield* overlay(deps, actor, controls, { references: overlayReferences(older) })).annotations;
|
|
12905
|
+
return {
|
|
12906
|
+
items: stitchActivity({
|
|
12907
|
+
safe: scope.safe,
|
|
12908
|
+
transfers: rows.transfers,
|
|
12909
|
+
payments: rows.payments,
|
|
12910
|
+
intents,
|
|
12911
|
+
links: decoration.links,
|
|
12912
|
+
annotations: [...decoration.annotations, ...olderDecoration]
|
|
12913
|
+
}).filter((item) => inRange(item, params.range) && matchesFilter(item, params.filter)),
|
|
12914
|
+
stitched: true
|
|
12915
|
+
};
|
|
12916
|
+
});
|
|
12917
|
+
}
|
|
12918
|
+
function readActivityPage(deps, actor, controls, params) {
|
|
12919
|
+
const limit = params?.limit ?? 25;
|
|
12920
|
+
const offset = parseCursor(params?.cursor);
|
|
12921
|
+
return stitchedWindow(deps, actor, controls, offset + limit + 1, {
|
|
12922
|
+
...params?.range === void 0 ? {} : { range: params.range },
|
|
12923
|
+
...params?.filter === void 0 ? {} : { filter: params.filter }
|
|
12924
|
+
}).pipe(Effect.map(({ items, stitched, readWarning }) => {
|
|
12925
|
+
const observedAt = Date.now();
|
|
12926
|
+
if (!stitched) return {
|
|
12927
|
+
items: items.slice(0, limit),
|
|
12928
|
+
cursor: null,
|
|
12929
|
+
checkpoint: observedAt,
|
|
12930
|
+
observedAt,
|
|
12931
|
+
...readWarning === void 0 ? {} : { readWarning }
|
|
12932
|
+
};
|
|
12933
|
+
return {
|
|
12934
|
+
items: items.slice(offset, offset + limit),
|
|
12935
|
+
cursor: items.length > offset + limit ? JSON.stringify({ offset: offset + limit }) : null,
|
|
12936
|
+
checkpoint: observedAt,
|
|
12937
|
+
observedAt
|
|
12938
|
+
};
|
|
12939
|
+
}));
|
|
12940
|
+
}
|
|
12941
|
+
function readActivitySummary(deps, actor, controls, params) {
|
|
12942
|
+
return stitchedWindow(deps, actor, controls, SUMMARY_WINDOW, params?.window === void 0 ? {} : { range: params.window }).pipe(Effect.map(({ items, readWarning }) => ({
|
|
12943
|
+
window: {
|
|
12944
|
+
from: params?.window?.from ?? null,
|
|
12945
|
+
to: params?.window?.to ?? null
|
|
12946
|
+
},
|
|
12947
|
+
totals: summarizeItems(items),
|
|
12948
|
+
count: items.length,
|
|
12949
|
+
observedAt: Date.now(),
|
|
12950
|
+
...readWarning === void 0 ? {} : { readWarning }
|
|
12951
|
+
})));
|
|
12952
|
+
}
|
|
12953
|
+
/**
|
|
12954
|
+
* Tell the caller when the indexed page for this Safe changed.
|
|
12955
|
+
*
|
|
12956
|
+
* The transport is the indexer's one SSE connection, wired in the Ponder
|
|
12957
|
+
* adapter under `activity.subscribe`. A reactive snapshot is not a product
|
|
12958
|
+
* event, so nothing here emits telemetry: the adapter reports a teardown, and
|
|
12959
|
+
* the caller re-reads.
|
|
12960
|
+
*/
|
|
12961
|
+
function subscribeActivity(deps, actor, controls, onChange) {
|
|
12962
|
+
return Effect.gen(function* () {
|
|
12963
|
+
const scope = yield* overlay(deps, actor, controls, {});
|
|
12964
|
+
if (scope.safe === null) return () => {};
|
|
12965
|
+
const page = {
|
|
12966
|
+
safe: scope.safe,
|
|
12967
|
+
limit: INTENT_WINDOW
|
|
12968
|
+
};
|
|
12969
|
+
let delivered = false;
|
|
12970
|
+
const notify = () => {
|
|
12971
|
+
if (delivered) onChange();
|
|
12972
|
+
delivered = true;
|
|
12973
|
+
};
|
|
12974
|
+
return yield* deps.indexer.subscribe("transfer", page, (snapshot) => {
|
|
12975
|
+
if (snapshot.status === "ok") notify();
|
|
12976
|
+
if (snapshot.status === "error") {
|
|
12977
|
+
delivered = true;
|
|
12978
|
+
onChange();
|
|
12979
|
+
}
|
|
12980
|
+
});
|
|
12981
|
+
});
|
|
12982
|
+
}
|
|
12983
|
+
//#endregion
|
|
12380
12984
|
//#region ../../packages/sdk/package.json
|
|
12381
|
-
var version$1 = "4.
|
|
12985
|
+
var version$1 = "4.20.0-beta.1";
|
|
12382
12986
|
//#endregion
|
|
12383
12987
|
//#region ../../packages/sdk/src/telemetry/exception-projection.ts
|
|
12384
12988
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -12480,10 +13084,15 @@ function observeFailedResult(result, adapter, operation, origin) {
|
|
|
12480
13084
|
* A reactive stream is torn down after its call already returned, so nothing
|
|
12481
13085
|
* downstream observes it. `captureException` is the right kind: the caller did
|
|
12482
13086
|
* not ask for the end, so it is not an expected product outcome.
|
|
13087
|
+
*
|
|
13088
|
+
* A caller that DID ask for the end — the session it authenticated with
|
|
13089
|
+
* expired, and the service closed the stream on purpose — passes
|
|
13090
|
+
* `kind: "operation"` instead, so the refusal lands in the expected-outcome
|
|
13091
|
+
* stream its code already declares.
|
|
12483
13092
|
*/
|
|
12484
|
-
function observeStreamFailure(adapter, operation, cause) {
|
|
13093
|
+
function observeStreamFailure(adapter, operation, cause, kind = "exception") {
|
|
12485
13094
|
if (adapter === void 0) return;
|
|
12486
|
-
report(adapter,
|
|
13095
|
+
report(adapter, kind, operation, cause, resolveAdapterSnapshot(adapter));
|
|
12487
13096
|
}
|
|
12488
13097
|
/**
|
|
12489
13098
|
* One failure, one event. The identity machine reports a failed transition
|
|
@@ -13475,6 +14084,11 @@ function paymentExecutionIntent(input) {
|
|
|
13475
14084
|
}
|
|
13476
14085
|
function makeFinancialOpsMethods(deps) {
|
|
13477
14086
|
const fns = deps.functions ?? financialOpsContract;
|
|
14087
|
+
const indexerDeps = deps.indexerRead === void 0 ? void 0 : {
|
|
14088
|
+
indexer: deps.indexerRead,
|
|
14089
|
+
convexCall: deps.convexCall,
|
|
14090
|
+
functions: fns
|
|
14091
|
+
};
|
|
13478
14092
|
const executionFns = deps.moneyExecutionFunctions ?? moneyExecutionContract;
|
|
13479
14093
|
const requestKeyScope = deps.requestKeyScope ?? randomPaymentRequestKey();
|
|
13480
14094
|
const inFlightPersonalPayments = /* @__PURE__ */ new Map();
|
|
@@ -13621,10 +14235,12 @@ function makeFinancialOpsMethods(deps) {
|
|
|
13621
14235
|
return runPortEffect(Effect.suspend(() => deps.convexCall.query(fns.depositInstructions, copyInvocationObservation(controls, {}))).pipe(Effect.tap((instructions) => emitDepositInitiated(deps.telemetry, instructions, controls))), controls, CAPXUL_OPERATIONS.me.depositInstructions, deps.runPromise);
|
|
13622
14236
|
}
|
|
13623
14237
|
},
|
|
13624
|
-
targets: { resolve:
|
|
13625
|
-
const
|
|
13626
|
-
|
|
13627
|
-
|
|
14238
|
+
targets: { resolve: (reference, options) => {
|
|
14239
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
14240
|
+
return runPortEffect(projectReply(Effect.suspend(() => {
|
|
14241
|
+
const recipient = normalizeTargetForBackend(reference, "reference");
|
|
14242
|
+
return recipient.ok ? deps.convexCall.query(fns.resolveRecipient, copyInvocationObservation(controls, { recipient: recipient.value })) : Effect.fail({ publicError: recipient.error });
|
|
14243
|
+
}), resolvedTargetFromResolution), controls, CAPXUL_OPERATIONS.recipient.resolve, deps.runPromise);
|
|
13628
14244
|
} },
|
|
13629
14245
|
destinations: {
|
|
13630
14246
|
add: (input, options) => {
|
|
@@ -13687,8 +14303,14 @@ function makeFinancialOpsMethods(deps) {
|
|
|
13687
14303
|
kind: "claim",
|
|
13688
14304
|
paymentId
|
|
13689
14305
|
}, deps.invocationControls?.(options) ?? options, CAPXUL_OPERATIONS.payments.claim),
|
|
13690
|
-
list:
|
|
13691
|
-
|
|
14306
|
+
list: (options) => {
|
|
14307
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
14308
|
+
return runPortEffect(projectReply(Effect.suspend(() => deps.convexCall.query(fns.listPayments, copyInvocationObservation(controls, {}))), (payments) => payments.map(normalizePaymentTiming)), controls, CAPXUL_OPERATIONS.payments.list, deps.runPromise);
|
|
14309
|
+
},
|
|
14310
|
+
get: (paymentId, options) => {
|
|
14311
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
14312
|
+
return runPortEffect(projectReply(Effect.suspend(() => deps.convexCall.query(fns.getPayment, copyInvocationObservation(controls, { paymentId }))), (payment) => payment === null ? null : normalizePaymentTiming(payment)), controls, CAPXUL_OPERATIONS.payments.get, deps.runPromise);
|
|
14313
|
+
},
|
|
13692
14314
|
cancel: (paymentId, options) => runLifecycle({
|
|
13693
14315
|
kind: "cancel",
|
|
13694
14316
|
paymentId
|
|
@@ -13705,22 +14327,26 @@ function makeFinancialOpsMethods(deps) {
|
|
|
13705
14327
|
}
|
|
13706
14328
|
},
|
|
13707
14329
|
activity: {
|
|
14330
|
+
subscribe: (onChange, params, options) => {
|
|
14331
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
14332
|
+
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => indexerDeps === void 0 ? Effect.succeed(() => {}) : Effect.suspend(() => subscribeActivity(indexerDeps, actor, controls, onChange)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.subscribe, deps.runPromise);
|
|
14333
|
+
},
|
|
13708
14334
|
list: (params, options) => {
|
|
13709
14335
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
13710
|
-
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => deps.convexCall.query(fns.activityList, copyInvocationObservation(controls, { input: {
|
|
14336
|
+
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => indexerDeps === void 0 ? deps.convexCall.query(fns.activityList, copyInvocationObservation(controls, { input: {
|
|
13711
14337
|
...actor === void 0 ? {} : { actor },
|
|
13712
14338
|
...params?.cursor === void 0 ? {} : { cursor: params.cursor },
|
|
13713
14339
|
...params?.limit === void 0 ? {} : { limit: params.limit },
|
|
13714
14340
|
...params?.range === void 0 ? {} : { range: params.range },
|
|
13715
14341
|
...params?.filter === void 0 ? {} : { filter: params.filter }
|
|
13716
|
-
} }))).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
|
|
14342
|
+
} })) : readActivityPage(indexerDeps, actor, controls, params)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
|
|
13717
14343
|
},
|
|
13718
14344
|
summary: (params, options) => {
|
|
13719
14345
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
13720
|
-
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => deps.convexCall.query(fns.activitySummary, copyInvocationObservation(controls, { input: {
|
|
14346
|
+
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => indexerDeps === void 0 ? deps.convexCall.query(fns.activitySummary, copyInvocationObservation(controls, { input: {
|
|
13721
14347
|
...actor === void 0 ? {} : { actor },
|
|
13722
14348
|
...params?.window === void 0 ? {} : { window: params.window }
|
|
13723
|
-
} }))).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.summary, deps.runPromise);
|
|
14349
|
+
} })) : readActivitySummary(indexerDeps, actor, controls, params)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.summary, deps.runPromise);
|
|
13724
14350
|
},
|
|
13725
14351
|
get: (reference, options) => {
|
|
13726
14352
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
@@ -14052,6 +14678,22 @@ function normalizePaymentTiming(payment) {
|
|
|
14052
14678
|
timing: payment.timing ?? payment.release ?? { kind: "instant" }
|
|
14053
14679
|
};
|
|
14054
14680
|
}
|
|
14681
|
+
/**
|
|
14682
|
+
* `mapOk`, moved inside the observed Effect (R09 #1967).
|
|
14683
|
+
*
|
|
14684
|
+
* The projection can refuse — `toAddress` and `toPartyId` throw on a malformed
|
|
14685
|
+
* reply — and every verb on this surface returns a `CapxulResult`, so that
|
|
14686
|
+
* throw stays a value here (ADR-0023). The error identity is `mapOk`'s: a
|
|
14687
|
+
* `CapxulError` passes through, anything else becomes `Errors.unknown(cause)`.
|
|
14688
|
+
* Running it inside the runner is what puts the decode failure on the same
|
|
14689
|
+
* operation record as the read that produced the reply.
|
|
14690
|
+
*/
|
|
14691
|
+
function projectReply(program, project) {
|
|
14692
|
+
return program.pipe(Effect.flatMap((value) => Effect.try({
|
|
14693
|
+
try: () => project(value),
|
|
14694
|
+
catch: (cause) => ({ publicError: cause instanceof CapxulError ? cause : Errors.unknown(cause) })
|
|
14695
|
+
})));
|
|
14696
|
+
}
|
|
14055
14697
|
function mapOk(result, f) {
|
|
14056
14698
|
if (!result.ok) return result;
|
|
14057
14699
|
try {
|
|
@@ -14423,13 +15065,18 @@ const postHogOtlpEndpoints = (host) => {
|
|
|
14423
15065
|
const base = host.replace(/\/+$/, "");
|
|
14424
15066
|
return {
|
|
14425
15067
|
logs: `${base}/i/v1/logs`,
|
|
14426
|
-
traces: `${base}/i/v1/traces
|
|
15068
|
+
traces: `${base}/i/v1/traces`,
|
|
15069
|
+
metrics: `${base}/i/v1/metrics`
|
|
14427
15070
|
};
|
|
14428
15071
|
};
|
|
14429
15072
|
const ENGINEERING_CAPXUL_ENV_SET = new Set(ENGINEERING_CAPXUL_ENVS);
|
|
14430
15073
|
const ENGINEERING_PRODUCERS = /* @__PURE__ */ new Set(["browser", "server"]);
|
|
14431
15074
|
const PUBLIC_POSTHOG_AUTHORIZATION = /^Bearer phc_[A-Za-z0-9_-]{1,191}$/u;
|
|
14432
15075
|
const SAFE_RESOURCE_VALUE = /^[A-Za-z0-9][A-Za-z0-9._+@/-]{0,127}$/u;
|
|
15076
|
+
function validateEngineeringPrivacy(config) {
|
|
15077
|
+
if (config.privacy !== void 0 && config.privacy !== "minimal") throw new TypeError("engineering telemetry privacy must be minimal when specified");
|
|
15078
|
+
if (config.privacy === "minimal" && (!/^[A-Za-z0-9][A-Za-z0-9._+@-]{0,127}$/u.test(config.sdkVersion) || config.serviceName !== void 0 && !/^[A-Za-z0-9][A-Za-z0-9._+@-]{0,127}$/u.test(config.serviceName))) throw new TypeError("minimal engineering resource values must not contain paths");
|
|
15079
|
+
}
|
|
14433
15080
|
const validateEngineeringTelemetryConfig = (config) => {
|
|
14434
15081
|
let url;
|
|
14435
15082
|
try {
|
|
@@ -14440,6 +15087,8 @@ const validateEngineeringTelemetryConfig = (config) => {
|
|
|
14440
15087
|
if (url.protocol !== "https:" || url.username.length > 0 || url.password.length > 0 || url.pathname !== "/" || url.search.length > 0 || url.hash.length > 0 || !(url.hostname === "posthog.com" || url.hostname.endsWith(".posthog.com"))) throw new TypeError("engineering telemetry host must be a credential-free HTTPS origin");
|
|
14441
15088
|
if (!ENGINEERING_CAPXUL_ENV_SET.has(config.capxulEnv)) throw new TypeError("engineering telemetry capxulEnv is not canonical");
|
|
14442
15089
|
if (!ENGINEERING_PRODUCERS.has(config.producer)) throw new TypeError("engineering telemetry producer is not canonical");
|
|
15090
|
+
if (config.enabled !== void 0 && typeof config.enabled !== "boolean" && typeof config.enabled !== "function") throw new TypeError("engineering telemetry enabled must be a boolean or callback");
|
|
15091
|
+
validateEngineeringPrivacy(config);
|
|
14443
15092
|
if (!SAFE_RESOURCE_VALUE.test(config.sdkVersion)) throw new TypeError("engineering telemetry sdkVersion must be a bounded safe value");
|
|
14444
15093
|
if (config.serviceName !== void 0 && !SAFE_RESOURCE_VALUE.test(config.serviceName)) throw new TypeError("engineering telemetry serviceName must be a bounded safe value");
|
|
14445
15094
|
const headerEntries = Object.entries(config.headers);
|
|
@@ -14490,25 +15139,34 @@ const spanUpstream = (span) => {
|
|
|
14490
15139
|
let current = span;
|
|
14491
15140
|
while (current?._tag === "Span") {
|
|
14492
15141
|
const upstream = current.attributes.get("chain.upstream");
|
|
14493
|
-
if (upstream === "alchemy" || upstream === "infura") return upstream;
|
|
15142
|
+
if (upstream === "alchemy" || upstream === "infura" || upstream === "gateway") return upstream;
|
|
14494
15143
|
current = current.parent._tag === "Some" ? current.parent.value : void 0;
|
|
14495
15144
|
}
|
|
14496
15145
|
};
|
|
15146
|
+
function redactHttpPath(path, fullUrl, source) {
|
|
15147
|
+
let origin = "https://redaction.invalid";
|
|
15148
|
+
try {
|
|
15149
|
+
const url = new URL(String(fullUrl));
|
|
15150
|
+
if (url.protocol === "https:" || url.protocol === "http:") origin = url.origin;
|
|
15151
|
+
} catch {}
|
|
15152
|
+
const prefix = path.startsWith("/") ? origin : "";
|
|
15153
|
+
return redactUrlSecrets(`${prefix}${path}`, source).slice(prefix.length, prefix.length + 2048);
|
|
15154
|
+
}
|
|
14497
15155
|
/** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
|
|
14498
|
-
const makeLeakSafeEngineeringTracer = (delegate) => Tracer.make({
|
|
15156
|
+
const makeLeakSafeEngineeringTracer = (delegate, enabled = () => true) => Tracer.make({
|
|
14499
15157
|
span(options) {
|
|
14500
|
-
const span = delegate.span(options);
|
|
15158
|
+
const span = enabled() ? delegate.span(options) : new Tracer.NativeSpan(options);
|
|
14501
15159
|
const wrapped = Object.create(span);
|
|
14502
15160
|
Object.defineProperty(wrapped, "attribute", { value: (name, value) => {
|
|
14503
15161
|
const source = spanUpstream(span);
|
|
14504
15162
|
const header = /^http\.(?:request|response)\.header\.(.+)$/u.exec(name)?.[1];
|
|
14505
15163
|
if (header !== void 0 && isCredentialField(header, "header")) span.attribute(name, "[REDACTED]");
|
|
14506
15164
|
else if (typeof value === "string" && name === "url.query") span.attribute(name, redactUrlSecrets(`?${value}`).slice(1, 2049));
|
|
14507
|
-
else if (typeof value === "string" && name === "url.path") {
|
|
14508
|
-
const fullUrl = span.attributes.get("url.full");
|
|
14509
|
-
const path = typeof fullUrl === "string" ? /^https?:\/\/[^/]+([^?#]*)/u.exec(fullUrl)?.[1] ?? value : value;
|
|
14510
|
-
span.attribute(name,
|
|
14511
|
-
} else if (typeof value === "string" && (name === "url.full" || header === "location" || header === "referer" || header === "referrer")) span.attribute(name, redactUrlSecrets(value, source).slice(0, 2048));
|
|
15165
|
+
else if (typeof value === "string" && (name === "url.path" || name === "http.target")) {
|
|
15166
|
+
const fullUrl = span.attributes.get("url.full") ?? span.attributes.get("http.url");
|
|
15167
|
+
const path = name === "url.path" && typeof fullUrl === "string" ? /^https?:\/\/[^/]+([^?#]*)/u.exec(fullUrl)?.[1] ?? value : value;
|
|
15168
|
+
span.attribute(name, redactHttpPath(path, fullUrl, source));
|
|
15169
|
+
} else if (typeof value === "string" && (name === "url.full" || name === "http.url" || header === "location" || header === "referer" || header === "referrer")) span.attribute(name, redactUrlSecrets(value, source).slice(0, 2048));
|
|
14512
15170
|
else if (header !== void 0 && typeof value === "string") span.attribute(name, redactSecrets(value, source).slice(0, 2048));
|
|
14513
15171
|
else span.attribute(name, value);
|
|
14514
15172
|
} });
|
|
@@ -14516,6 +15174,15 @@ const makeLeakSafeEngineeringTracer = (delegate) => Tracer.make({
|
|
|
14516
15174
|
configurable: false,
|
|
14517
15175
|
enumerable: false,
|
|
14518
15176
|
value: (endTime, exit) => {
|
|
15177
|
+
if (!enabled()) {
|
|
15178
|
+
Object.defineProperty(wrapped, "status", { value: {
|
|
15179
|
+
_tag: "Ended",
|
|
15180
|
+
startTime: span.status.startTime,
|
|
15181
|
+
endTime,
|
|
15182
|
+
exit
|
|
15183
|
+
} });
|
|
15184
|
+
return;
|
|
15185
|
+
}
|
|
14519
15186
|
if (Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause)) {
|
|
14520
15187
|
const first = exit.cause.reasons.find((reason) => !Cause.isInterruptReason(reason));
|
|
14521
15188
|
const code = failureText(first === void 0 ? void 0 : Cause.isFailReason(first) ? first.error : first.defect, "code", 128);
|
|
@@ -14529,53 +15196,360 @@ const makeLeakSafeEngineeringTracer = (delegate) => Tracer.make({
|
|
|
14529
15196
|
},
|
|
14530
15197
|
...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
|
|
14531
15198
|
});
|
|
15199
|
+
const MINIMAL_LOG_NAMES = /* @__PURE__ */ new Set([
|
|
15200
|
+
"capxul_sdk_operation",
|
|
15201
|
+
"identity.transition",
|
|
15202
|
+
"convex.connection.changed",
|
|
15203
|
+
"convex.action.connection_lost",
|
|
15204
|
+
"cli.command.completed",
|
|
15205
|
+
"cli.sdk.operation.failed"
|
|
15206
|
+
]);
|
|
15207
|
+
const MINIMAL_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
15208
|
+
...CAPXUL_ERROR_CODES,
|
|
15209
|
+
"CLI_USAGE",
|
|
15210
|
+
"CLI_CONFIG",
|
|
15211
|
+
"CLI_STORAGE",
|
|
15212
|
+
"CLI_DEFECT"
|
|
15213
|
+
]);
|
|
15214
|
+
const MINIMAL_NUMBERS = /* @__PURE__ */ new Set([
|
|
15215
|
+
"schema_version",
|
|
15216
|
+
"duration_ms",
|
|
15217
|
+
"wait_duration_ms",
|
|
15218
|
+
"retry_count",
|
|
15219
|
+
"http.status_code",
|
|
15220
|
+
"http.response.status_code",
|
|
15221
|
+
"http_status",
|
|
15222
|
+
"rpc.code",
|
|
15223
|
+
"connection_count",
|
|
15224
|
+
"connection_retries"
|
|
15225
|
+
]);
|
|
15226
|
+
const MINIMAL_CORRELATIONS = /* @__PURE__ */ new Set([
|
|
15227
|
+
"correlation_id",
|
|
15228
|
+
"journey_id",
|
|
15229
|
+
"invocation_id"
|
|
15230
|
+
]);
|
|
15231
|
+
const MINIMAL_METRIC_LABELS = /* @__PURE__ */ new Set([
|
|
15232
|
+
"command",
|
|
15233
|
+
"outcome",
|
|
15234
|
+
"capxul_env",
|
|
15235
|
+
"unit"
|
|
15236
|
+
]);
|
|
15237
|
+
const MINIMAL_METRIC_NAMES = /* @__PURE__ */ new Set(["capxul.cli.command.count", "capxul.cli.command.duration"]);
|
|
15238
|
+
const traceId = (value) => typeof value === "string" && /^(?!0+$)[0-9a-f]{32}$/u.test(value);
|
|
15239
|
+
const spanId = (value) => typeof value === "string" && /^(?!0+$)[0-9a-f]{16}$/u.test(value);
|
|
15240
|
+
const minimalName = (value) => typeof value === "string" && (MINIMAL_LOG_NAMES.has(value) || isCapxulOperation(value)) ? value : "capxul.engineering";
|
|
15241
|
+
const MINIMAL_ENUM_VALUES = /* @__PURE__ */ new Map([
|
|
15242
|
+
["outcome", [
|
|
15243
|
+
"succeeded",
|
|
15244
|
+
"refused",
|
|
15245
|
+
"failed",
|
|
15246
|
+
"cancelled",
|
|
15247
|
+
"applied"
|
|
15248
|
+
]],
|
|
15249
|
+
["mode", FAILURE_MODES$1],
|
|
15250
|
+
["failure_mode", FAILURE_MODES$1],
|
|
15251
|
+
["capxul_env", ENGINEERING_CAPXUL_ENVS],
|
|
15252
|
+
["producer", ["browser", "server"]],
|
|
15253
|
+
["command", ["doctor"]],
|
|
15254
|
+
["output_mode", ["human", "json"]],
|
|
15255
|
+
["unit", [
|
|
15256
|
+
"1",
|
|
15257
|
+
"s",
|
|
15258
|
+
"ms"
|
|
15259
|
+
]]
|
|
15260
|
+
]);
|
|
15261
|
+
const MINIMAL_CODE_KEYS = /* @__PURE__ */ new Set([
|
|
15262
|
+
"error.code",
|
|
15263
|
+
"error_code",
|
|
15264
|
+
"failure_code",
|
|
15265
|
+
"refusal_code",
|
|
15266
|
+
"capxul_error_code"
|
|
15267
|
+
]);
|
|
15268
|
+
const MINIMAL_VERSION_KEYS = /* @__PURE__ */ new Set([
|
|
15269
|
+
"sdk_version",
|
|
15270
|
+
"cli_version",
|
|
15271
|
+
"release"
|
|
15272
|
+
]);
|
|
15273
|
+
function minimalStringValue(key, text) {
|
|
15274
|
+
if (key === "operation") return isCapxulOperation(text);
|
|
15275
|
+
if (MINIMAL_CODE_KEYS.has(key)) return MINIMAL_ERROR_CODES.has(text);
|
|
15276
|
+
if (MINIMAL_VERSION_KEYS.has(key)) return /^[A-Za-z0-9][A-Za-z0-9._+@-]{0,127}$/u.test(text);
|
|
15277
|
+
if (key === "trace_id") return traceId(text);
|
|
15278
|
+
if (key === "span_id" || key === "parent_span_id") return spanId(text);
|
|
15279
|
+
const values = MINIMAL_ENUM_VALUES.get(key);
|
|
15280
|
+
if (values !== void 0) return values.includes(text);
|
|
15281
|
+
return MINIMAL_CORRELATIONS.has(key) && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(text) && !/^0x[0-9a-f]+$/iu.test(text) && redactSecrets(text) === text;
|
|
15282
|
+
}
|
|
15283
|
+
/** A named privacy projection, separate from the default credential-only redaction policy. */
|
|
15284
|
+
function minimalAttributes(attributes, metric = false) {
|
|
15285
|
+
return attributes.flatMap(({ key, value }) => {
|
|
15286
|
+
if (metric && !MINIMAL_METRIC_LABELS.has(key)) return [];
|
|
15287
|
+
const text = value.stringValue;
|
|
15288
|
+
const number = value.doubleValue ?? value.intValue;
|
|
15289
|
+
if (MINIMAL_NUMBERS.has(key) && typeof number === "number" && Number.isFinite(number)) return [{
|
|
15290
|
+
key,
|
|
15291
|
+
value: { doubleValue: number }
|
|
15292
|
+
}];
|
|
15293
|
+
if (typeof text !== "string") return [];
|
|
15294
|
+
return minimalStringValue(key, text) ? [{
|
|
15295
|
+
key,
|
|
15296
|
+
value: { stringValue: text }
|
|
15297
|
+
}] : [];
|
|
15298
|
+
});
|
|
15299
|
+
}
|
|
15300
|
+
const finiteProtocolNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
15301
|
+
const protocolCount = (value, maximum = Number.MAX_SAFE_INTEGER) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= maximum ? value : void 0;
|
|
15302
|
+
const protocolFlags = (value) => protocolCount(Object.getOwnPropertyDescriptor(value, "flags")?.value, 4294967295);
|
|
15303
|
+
function protocolTime(value) {
|
|
15304
|
+
if (typeof value === "string" && /^\d{1,20}$/u.test(value) && BigInt(value) <= 18446744073709551615n) return value;
|
|
15305
|
+
const number = protocolCount(value);
|
|
15306
|
+
if (number !== void 0) return String(number);
|
|
15307
|
+
if (value === null || typeof value !== "object") return void 0;
|
|
15308
|
+
const low = protocolCount(Object.getOwnPropertyDescriptor(value, "low")?.value, 4294967295);
|
|
15309
|
+
const high = protocolCount(Object.getOwnPropertyDescriptor(value, "high")?.value, 4294967295);
|
|
15310
|
+
return low === void 0 || high === void 0 ? void 0 : (BigInt(high) << 32n | BigInt(low)).toString();
|
|
15311
|
+
}
|
|
15312
|
+
function minimalNumberPoints(points) {
|
|
15313
|
+
return points.flatMap((point) => {
|
|
15314
|
+
const attributes = minimalAttributes(point.attributes, true);
|
|
15315
|
+
const asDouble = finiteProtocolNumber(point.asDouble);
|
|
15316
|
+
const asInt = typeof point.asInt === "number" && Number.isSafeInteger(point.asInt) ? point.asInt : void 0;
|
|
15317
|
+
if (attributes.length !== point.attributes.length || asDouble === void 0 && asInt === void 0) return [];
|
|
15318
|
+
return [{
|
|
15319
|
+
attributes,
|
|
15320
|
+
timeUnixNano: protocolTime(point.timeUnixNano),
|
|
15321
|
+
startTimeUnixNano: protocolTime(point.startTimeUnixNano),
|
|
15322
|
+
asDouble,
|
|
15323
|
+
asInt: asDouble === void 0 ? asInt : void 0,
|
|
15324
|
+
flags: protocolFlags(point)
|
|
15325
|
+
}];
|
|
15326
|
+
});
|
|
15327
|
+
}
|
|
15328
|
+
function minimalHistogramPoints(points) {
|
|
15329
|
+
return points.flatMap((point) => {
|
|
15330
|
+
const attributes = minimalAttributes(point.attributes ?? [], true);
|
|
15331
|
+
const count = protocolCount(point.count);
|
|
15332
|
+
const bucketCounts = point.bucketCounts;
|
|
15333
|
+
const explicitBounds = point.explicitBounds;
|
|
15334
|
+
if (attributes.length !== (point.attributes?.length ?? 0) || count === void 0 || !Array.isArray(bucketCounts) || !bucketCounts.every((value) => protocolCount(value) !== void 0) || !Array.isArray(explicitBounds) || !explicitBounds.every((value) => finiteProtocolNumber(value) !== void 0) || bucketCounts.length !== explicitBounds.length + 1) return [];
|
|
15335
|
+
return [{
|
|
15336
|
+
attributes,
|
|
15337
|
+
timeUnixNano: protocolTime(point.timeUnixNano),
|
|
15338
|
+
startTimeUnixNano: protocolTime(point.startTimeUnixNano),
|
|
15339
|
+
count,
|
|
15340
|
+
sum: finiteProtocolNumber(point.sum),
|
|
15341
|
+
min: finiteProtocolNumber(point.min),
|
|
15342
|
+
max: finiteProtocolNumber(point.max),
|
|
15343
|
+
bucketCounts: bucketCounts.map((value) => value),
|
|
15344
|
+
explicitBounds: explicitBounds.map((value) => value),
|
|
15345
|
+
flags: protocolFlags(point)
|
|
15346
|
+
}];
|
|
15347
|
+
});
|
|
15348
|
+
}
|
|
15349
|
+
function minimalSerialization(config) {
|
|
15350
|
+
const service = config.serviceName ?? "capxul-sdk";
|
|
15351
|
+
const resource = { attributes: Object.entries({
|
|
15352
|
+
"service.name": service,
|
|
15353
|
+
"service.version": config.sdkVersion,
|
|
15354
|
+
sdk_version: config.sdkVersion,
|
|
15355
|
+
capxul_env: config.capxulEnv,
|
|
15356
|
+
producer: config.producer
|
|
15357
|
+
}).map(([key, value]) => ({
|
|
15358
|
+
key,
|
|
15359
|
+
value: { stringValue: value }
|
|
15360
|
+
})) };
|
|
15361
|
+
return {
|
|
15362
|
+
logs: (data) => HttpBody.jsonUnsafe({ resourceLogs: data.resourceLogs.map((entry) => ({
|
|
15363
|
+
resource,
|
|
15364
|
+
scopeLogs: entry.scopeLogs.map((scope) => ({
|
|
15365
|
+
scope: { name: service },
|
|
15366
|
+
logRecords: (scope.logRecords ?? []).map((record) => ({
|
|
15367
|
+
timeUnixNano: protocolTime(record.timeUnixNano),
|
|
15368
|
+
observedTimeUnixNano: protocolTime(record.observedTimeUnixNano),
|
|
15369
|
+
severityNumber: protocolCount(record.severityNumber, 24),
|
|
15370
|
+
severityText: [
|
|
15371
|
+
"All",
|
|
15372
|
+
"Trace",
|
|
15373
|
+
"Debug",
|
|
15374
|
+
"Info",
|
|
15375
|
+
"Warn",
|
|
15376
|
+
"Error",
|
|
15377
|
+
"Fatal",
|
|
15378
|
+
"None"
|
|
15379
|
+
].includes(record.severityText ?? "") ? record.severityText : void 0,
|
|
15380
|
+
body: { stringValue: minimalName(record.body?.stringValue) },
|
|
15381
|
+
attributes: minimalAttributes(record.attributes),
|
|
15382
|
+
droppedAttributesCount: protocolCount(record.droppedAttributesCount) ?? 0,
|
|
15383
|
+
traceId: traceId(record.traceId) ? record.traceId : void 0,
|
|
15384
|
+
spanId: spanId(record.spanId) ? record.spanId : void 0,
|
|
15385
|
+
flags: protocolFlags(record)
|
|
15386
|
+
}))
|
|
15387
|
+
}))
|
|
15388
|
+
})) }),
|
|
15389
|
+
traces: (data) => HttpBody.jsonUnsafe({ resourceSpans: data.resourceSpans.map((entry) => ({
|
|
15390
|
+
resource,
|
|
15391
|
+
scopeSpans: entry.scopeSpans.map((scope) => ({
|
|
15392
|
+
scope: { name: service },
|
|
15393
|
+
spans: scope.spans.filter((span) => traceId(span.traceId) && spanId(span.spanId)).map((span) => {
|
|
15394
|
+
const attributes = minimalAttributes(span.attributes);
|
|
15395
|
+
const code = attributes.find((attribute) => attribute.key === "error.code");
|
|
15396
|
+
return {
|
|
15397
|
+
traceId: span.traceId,
|
|
15398
|
+
spanId: span.spanId,
|
|
15399
|
+
name: minimalName(span.name),
|
|
15400
|
+
kind: protocolCount(span.kind, 5) ?? 0,
|
|
15401
|
+
startTimeUnixNano: protocolTime(span.startTimeUnixNano),
|
|
15402
|
+
endTimeUnixNano: protocolTime(span.endTimeUnixNano),
|
|
15403
|
+
attributes,
|
|
15404
|
+
droppedAttributesCount: protocolCount(span.droppedAttributesCount) ?? 0,
|
|
15405
|
+
parentSpanId: spanId(span.parentSpanId) ? span.parentSpanId : void 0,
|
|
15406
|
+
flags: protocolFlags(span),
|
|
15407
|
+
status: { code: protocolCount(span.status.code, 2) ?? 0 },
|
|
15408
|
+
events: span.events.slice(0, 8).map((event) => ({
|
|
15409
|
+
timeUnixNano: protocolTime(event.timeUnixNano),
|
|
15410
|
+
droppedAttributesCount: protocolCount(event.droppedAttributesCount) ?? 0,
|
|
15411
|
+
name: event.name === "exception" ? "exception" : minimalName(event.name),
|
|
15412
|
+
attributes: event.name === "exception" ? [{
|
|
15413
|
+
key: "exception.type",
|
|
15414
|
+
value: code?.value ?? { stringValue: "Error" }
|
|
15415
|
+
}] : minimalAttributes(event.attributes)
|
|
15416
|
+
})),
|
|
15417
|
+
droppedEventsCount: protocolCount(span.droppedEventsCount) ?? 0,
|
|
15418
|
+
links: span.links.filter((link) => traceId(link.traceId) && spanId(link.spanId)).slice(0, 8).map((link) => ({
|
|
15419
|
+
traceId: link.traceId,
|
|
15420
|
+
spanId: link.spanId,
|
|
15421
|
+
flags: protocolFlags(link),
|
|
15422
|
+
attributes: minimalAttributes(link.attributes),
|
|
15423
|
+
droppedAttributesCount: protocolCount(link.droppedAttributesCount) ?? 0
|
|
15424
|
+
})),
|
|
15425
|
+
droppedLinksCount: protocolCount(span.droppedLinksCount) ?? 0
|
|
15426
|
+
};
|
|
15427
|
+
})
|
|
15428
|
+
}))
|
|
15429
|
+
})) }),
|
|
15430
|
+
metrics: (data) => {
|
|
15431
|
+
const resourceMetrics = data.resourceMetrics.map((entry) => ({
|
|
15432
|
+
resource,
|
|
15433
|
+
scopeMetrics: entry.scopeMetrics.map((scope) => ({
|
|
15434
|
+
scope: { name: service },
|
|
15435
|
+
metrics: scope.metrics.filter((metric) => MINIMAL_METRIC_NAMES.has(metric.name)).flatMap((metric) => {
|
|
15436
|
+
const gauge = metric.gauge === void 0 ? void 0 : { dataPoints: minimalNumberPoints(metric.gauge.dataPoints) };
|
|
15437
|
+
const sum = metric.sum === void 0 ? void 0 : {
|
|
15438
|
+
aggregationTemporality: protocolCount(metric.sum.aggregationTemporality, 2) ?? 0,
|
|
15439
|
+
isMonotonic: metric.sum.isMonotonic === true,
|
|
15440
|
+
dataPoints: minimalNumberPoints(metric.sum.dataPoints)
|
|
15441
|
+
};
|
|
15442
|
+
const histogram = metric.histogram === void 0 ? void 0 : {
|
|
15443
|
+
aggregationTemporality: protocolCount(metric.histogram.aggregationTemporality, 2) ?? 0,
|
|
15444
|
+
dataPoints: minimalHistogramPoints(metric.histogram.dataPoints)
|
|
15445
|
+
};
|
|
15446
|
+
if (![
|
|
15447
|
+
gauge,
|
|
15448
|
+
sum,
|
|
15449
|
+
histogram
|
|
15450
|
+
].some((series) => (series?.dataPoints.length ?? 0) > 0)) return [];
|
|
15451
|
+
return [{
|
|
15452
|
+
name: metric.name,
|
|
15453
|
+
unit: [
|
|
15454
|
+
"1",
|
|
15455
|
+
"s",
|
|
15456
|
+
"ms"
|
|
15457
|
+
].includes(metric.unit ?? "") ? metric.unit : "1",
|
|
15458
|
+
...gauge === void 0 ? {} : { gauge },
|
|
15459
|
+
...sum === void 0 ? {} : { sum },
|
|
15460
|
+
...histogram === void 0 ? {} : { histogram }
|
|
15461
|
+
}];
|
|
15462
|
+
})
|
|
15463
|
+
}))
|
|
15464
|
+
}));
|
|
15465
|
+
return resourceMetrics.some((entry) => entry.scopeMetrics.some((scope) => scope.metrics.length > 0)) ? HttpBody.jsonUnsafe({ resourceMetrics }) : HttpBody.empty;
|
|
15466
|
+
}
|
|
15467
|
+
};
|
|
15468
|
+
}
|
|
15469
|
+
Effect.flatMap(OtlpExporter.Flusher, (flusher) => flusher.flush);
|
|
14532
15470
|
/** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */
|
|
14533
15471
|
const makeEngineeringTelemetryLayer = (config) => {
|
|
14534
15472
|
const validated = validateEngineeringTelemetryConfig(config);
|
|
14535
|
-
|
|
14536
|
-
|
|
14537
|
-
|
|
14538
|
-
|
|
14539
|
-
|
|
14540
|
-
|
|
14541
|
-
|
|
14542
|
-
|
|
14543
|
-
|
|
14544
|
-
|
|
14545
|
-
|
|
14546
|
-
|
|
14547
|
-
|
|
14548
|
-
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
|
|
14552
|
-
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
const
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
};
|
|
14566
|
-
const
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
14573
|
-
|
|
14574
|
-
|
|
15473
|
+
return Layer.suspend(() => {
|
|
15474
|
+
const endpoints = postHogOtlpEndpoints(validated.host);
|
|
15475
|
+
let disabled = false;
|
|
15476
|
+
const enabled = () => {
|
|
15477
|
+
if (disabled) return false;
|
|
15478
|
+
try {
|
|
15479
|
+
disabled = (typeof validated.enabled === "function" ? validated.enabled() : validated.enabled ?? true) !== true;
|
|
15480
|
+
} catch {
|
|
15481
|
+
disabled = true;
|
|
15482
|
+
}
|
|
15483
|
+
return !disabled;
|
|
15484
|
+
};
|
|
15485
|
+
const delivery = {
|
|
15486
|
+
...validated.shutdownTimeout === void 0 ? {} : { shutdownTimeout: validated.shutdownTimeout },
|
|
15487
|
+
...validated.exportInterval === void 0 ? {} : { exportInterval: validated.exportInterval }
|
|
15488
|
+
};
|
|
15489
|
+
const resource = {
|
|
15490
|
+
serviceName: validated.serviceName ?? "capxul-sdk",
|
|
15491
|
+
serviceVersion: validated.sdkVersion,
|
|
15492
|
+
attributes: {
|
|
15493
|
+
capxul_env: validated.capxulEnv,
|
|
15494
|
+
producer: validated.producer,
|
|
15495
|
+
sdk_version: validated.sdkVersion
|
|
15496
|
+
}
|
|
15497
|
+
};
|
|
15498
|
+
const tracing = Layer.effect(Tracer.Tracer, OtlpTracer.make({
|
|
15499
|
+
url: endpoints.traces,
|
|
15500
|
+
headers: validated.headers,
|
|
15501
|
+
resource,
|
|
15502
|
+
...delivery
|
|
15503
|
+
}).pipe(Effect.map((tracer) => makeLeakSafeEngineeringTracer(tracer, enabled)))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
15504
|
+
const logging = Logger.layer([OtlpLogger.make({
|
|
15505
|
+
url: endpoints.logs,
|
|
15506
|
+
headers: validated.headers,
|
|
15507
|
+
resource,
|
|
15508
|
+
...delivery
|
|
15509
|
+
}).pipe(Effect.map((logger) => Logger.make((options) => {
|
|
15510
|
+
if (enabled()) logger.log(options);
|
|
15511
|
+
})))], { mergeWithExisting: true }).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
15512
|
+
const metrics = OtlpMetrics.layer({
|
|
15513
|
+
url: endpoints.metrics,
|
|
15514
|
+
headers: validated.headers,
|
|
15515
|
+
resource,
|
|
15516
|
+
temporality: "delta",
|
|
15517
|
+
...delivery
|
|
15518
|
+
});
|
|
15519
|
+
const headerPolicy = Layer.merge(Layer.succeed(HttpClient.TracerHeaderFilter, traceHeaderFilter), Layer.succeed(Headers.CurrentRedactedNames, [credentialHeaderPattern]));
|
|
15520
|
+
const browserLifecycle = Layer.effectDiscard(Effect.gen(function* () {
|
|
15521
|
+
if (validated.producer !== "browser" || !hasBrowserDocument()) return;
|
|
15522
|
+
const browserWindow = window;
|
|
15523
|
+
const browserDocument = document;
|
|
15524
|
+
const flusher = yield* OtlpExporter.Flusher;
|
|
15525
|
+
const run = yield* FiberSet.makeRuntime();
|
|
15526
|
+
const flush = () => {
|
|
15527
|
+
run(flusher.flush);
|
|
15528
|
+
};
|
|
15529
|
+
const visibilityChanged = () => {
|
|
15530
|
+
if (browserDocument.visibilityState === "hidden") flush();
|
|
15531
|
+
};
|
|
15532
|
+
yield* Effect.acquireRelease(Effect.sync(() => {
|
|
15533
|
+
browserDocument.addEventListener("visibilitychange", visibilityChanged);
|
|
15534
|
+
browserWindow.addEventListener("pagehide", flush);
|
|
15535
|
+
}), () => Effect.sync(() => {
|
|
15536
|
+
browserDocument.removeEventListener("visibilitychange", visibilityChanged);
|
|
15537
|
+
browserWindow.removeEventListener("pagehide", flush);
|
|
15538
|
+
}));
|
|
14575
15539
|
}));
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
15540
|
+
const transport = Layer.effect(HttpClient.HttpClient, Effect.map(HttpClient.HttpClient, (client) => {
|
|
15541
|
+
const selectedTransport = validated.producer === "browser" && hasBrowserDocument() ? browserExportClient(client) : client;
|
|
15542
|
+
return HttpClient.transform(selectedTransport, (response, request) => Effect.suspend(() => enabled() && request.body._tag !== "Empty" ? response : Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null, { status: 200 })))));
|
|
15543
|
+
})).pipe(Layer.provide(FetchHttpClient.layer));
|
|
15544
|
+
const serialization = Layer.effect(OtlpSerialization.OtlpSerialization, Effect.map(OtlpSerialization.OtlpSerialization, (json) => {
|
|
15545
|
+
const projected = minimalSerialization(validated);
|
|
15546
|
+
return validated.privacy === "minimal" ? projected : {
|
|
15547
|
+
...json,
|
|
15548
|
+
metrics: projected.metrics
|
|
15549
|
+
};
|
|
15550
|
+
})).pipe(Layer.provide(OtlpSerialization.layerJson));
|
|
15551
|
+
return browserLifecycle.pipe(Layer.provideMerge(Layer.mergeAll(tracing, logging, metrics, headerPolicy)), Layer.provide(serialization), Layer.provide(transport));
|
|
15552
|
+
});
|
|
14579
15553
|
};
|
|
14580
15554
|
//#endregion
|
|
14581
15555
|
//#region ../../packages/sdk/src/ports/auth-client.ts
|
|
@@ -14900,9 +15874,16 @@ var BetterAuthBrowserAdapter = class {
|
|
|
14900
15874
|
ok: false,
|
|
14901
15875
|
error: Errors.notAuthenticated()
|
|
14902
15876
|
};
|
|
15877
|
+
if (res.status === 429) return {
|
|
15878
|
+
ok: false,
|
|
15879
|
+
error: Errors.rateLimited({ resource: "auth.token" })
|
|
15880
|
+
};
|
|
14903
15881
|
if (!res.ok) return {
|
|
14904
15882
|
ok: false,
|
|
14905
|
-
error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error(`HTTP ${res.status}`)
|
|
15883
|
+
error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error(`HTTP ${res.status}`), {
|
|
15884
|
+
httpStatus: res.status,
|
|
15885
|
+
...res.status >= 500 ? { failure_mode: "upstream-down" } : {}
|
|
15886
|
+
})
|
|
14906
15887
|
};
|
|
14907
15888
|
const body = await safeJson$1(res);
|
|
14908
15889
|
if (typeof body === "object" && body !== null) {
|
|
@@ -15331,9 +16312,16 @@ var BetterAuthNodeAdapter = class {
|
|
|
15331
16312
|
ok: false,
|
|
15332
16313
|
error: Errors.notAuthenticated()
|
|
15333
16314
|
};
|
|
16315
|
+
if (res.status === 429) return {
|
|
16316
|
+
ok: false,
|
|
16317
|
+
error: Errors.rateLimited({ resource: "auth.token" })
|
|
16318
|
+
};
|
|
15334
16319
|
if (!res.ok) return {
|
|
15335
16320
|
ok: false,
|
|
15336
|
-
error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error(`HTTP ${res.status}`)
|
|
16321
|
+
error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error(`HTTP ${res.status}`), {
|
|
16322
|
+
httpStatus: res.status,
|
|
16323
|
+
...res.status >= 500 ? { failure_mode: "upstream-down" } : {}
|
|
16324
|
+
})
|
|
15337
16325
|
};
|
|
15338
16326
|
const body = await safeJson(res);
|
|
15339
16327
|
if (typeof body === "object" && body !== null) {
|
|
@@ -18675,8 +19663,20 @@ function makeConnectionId() {
|
|
|
18675
19663
|
* ever needs a different one.
|
|
18676
19664
|
*/
|
|
18677
19665
|
const DEFAULT_CLOSE_TIMEOUT_MS = 5e3;
|
|
19666
|
+
const writeConvexDiagnostic = (...args) => {
|
|
19667
|
+
try {
|
|
19668
|
+
console.error(...maskCapturedNetworkRequest({ requestBody: args }).requestBody);
|
|
19669
|
+
} catch {}
|
|
19670
|
+
};
|
|
19671
|
+
const stderrConvexLogger = {
|
|
19672
|
+
log: writeConvexDiagnostic,
|
|
19673
|
+
warn: writeConvexDiagnostic,
|
|
19674
|
+
error: writeConvexDiagnostic,
|
|
19675
|
+
logVerbose: () => void 0
|
|
19676
|
+
};
|
|
18678
19677
|
/** Exact floor-first allowlist; every additional handler must migrate its validator first. */
|
|
18679
19678
|
const OBSERVED_CONVEX_ACTIONS = /* @__PURE__ */ new Set([
|
|
19679
|
+
"system:healthObserved",
|
|
18680
19680
|
"payroll/actions:authorizeRun",
|
|
18681
19681
|
"account/actions:readBalance",
|
|
18682
19682
|
"holdings/actions:current",
|
|
@@ -18687,6 +19687,9 @@ const OBSERVED_CONVEX_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
18687
19687
|
"org/actions:resumeBootstrapSubmission",
|
|
18688
19688
|
"org/actions:confirmBootstrap",
|
|
18689
19689
|
"org/actions:readTreasury",
|
|
19690
|
+
"moneyExecution/actions:preparePermissionExecution",
|
|
19691
|
+
"moneyExecution/actions:submitPermissionExecution",
|
|
19692
|
+
"permission/actions:verify",
|
|
18690
19693
|
"moneyExecution/actions:preparePaymentExecution",
|
|
18691
19694
|
"moneyExecution/actions:abandonPaymentExecution",
|
|
18692
19695
|
"moneyExecution/actions:submitPaymentExecution",
|
|
@@ -18699,6 +19702,8 @@ const OBSERVED_CONVEX_QUERIES = /* @__PURE__ */ new Set([
|
|
|
18699
19702
|
"movement/activity:summary",
|
|
18700
19703
|
"movement/activity:get",
|
|
18701
19704
|
"financialOps/queries:depositInstructions",
|
|
19705
|
+
"financialOps/queries:listPayments",
|
|
19706
|
+
"financialOps/queries:getPayment",
|
|
18702
19707
|
"financialOps/destinations:list",
|
|
18703
19708
|
"financialOps/queries:verifyPaymentDocument",
|
|
18704
19709
|
"financialOps/queries:renderStoredDocument",
|
|
@@ -18711,6 +19716,9 @@ const OBSERVED_CONVEX_QUERIES = /* @__PURE__ */ new Set([
|
|
|
18711
19716
|
"payroll/queries:groups",
|
|
18712
19717
|
"payroll/queries:terms",
|
|
18713
19718
|
"financialOps/queries:resolveRecipient",
|
|
19719
|
+
"org/queries:me",
|
|
19720
|
+
"permission/queries:read",
|
|
19721
|
+
"permission/queries:authorize",
|
|
18714
19722
|
"identity/queries:loadByAuthUserId",
|
|
18715
19723
|
"smartAccount/queries:loadByAuthUserId",
|
|
18716
19724
|
"org/lifecycle:load"
|
|
@@ -18729,6 +19737,7 @@ const OBSERVED_CONVEX_MUTATIONS = /* @__PURE__ */ new Set([
|
|
|
18729
19737
|
"financialOps/requestsInbox:decline",
|
|
18730
19738
|
"payroll/mutations:saveGroup",
|
|
18731
19739
|
"payroll/mutations:removeGroup",
|
|
19740
|
+
"permission/mutations:command",
|
|
18732
19741
|
"identity/mutations:create",
|
|
18733
19742
|
"identity/mutations:update",
|
|
18734
19743
|
"identity/mutations:completeOnboarding",
|
|
@@ -18748,7 +19757,10 @@ var ConvexCallAdapter = class {
|
|
|
18748
19757
|
this.#closeTimeoutMs = deps.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
|
|
18749
19758
|
this.#connectionMonitor = new ConvexConnectionMonitor();
|
|
18750
19759
|
const webSocketConstructor = this.#connectionMonitor.observedWebSocketConstructor();
|
|
18751
|
-
this.#client = deps.client ?? new ConvexClient(deps.convexUrl,
|
|
19760
|
+
this.#client = deps.client ?? new ConvexClient(deps.convexUrl, {
|
|
19761
|
+
...webSocketConstructor === void 0 ? {} : { webSocketConstructor },
|
|
19762
|
+
...deps.logToStderr === true ? { logger: stderrConvexLogger } : {}
|
|
19763
|
+
});
|
|
18752
19764
|
this.#tokenProvider = deps.tokenProvider;
|
|
18753
19765
|
this.#applicationId = deps.applicationId;
|
|
18754
19766
|
this.#observation = deps.observation;
|
|
@@ -18796,9 +19808,13 @@ var ConvexCallAdapter = class {
|
|
|
18796
19808
|
}
|
|
18797
19809
|
#observedArgs(allowlist, path, args, traceparent) {
|
|
18798
19810
|
if (!allowlist.has(path)) return args;
|
|
19811
|
+
const invocationSnapshot = readInvocationObservation(args);
|
|
19812
|
+
if (path === "system:healthObserved" && invocationSnapshot?.active === false) {
|
|
19813
|
+
const { observationContext: _context, ...unobservedArgs } = args;
|
|
19814
|
+
return unobservedArgs;
|
|
19815
|
+
}
|
|
18799
19816
|
const carriedContext = sanitizeObservationContext(args.observationContext);
|
|
18800
19817
|
let hostContext;
|
|
18801
|
-
const invocationSnapshot = readInvocationObservation(args);
|
|
18802
19818
|
if (invocationSnapshot !== void 0) hostContext = invocationSnapshot.active ? invocationSnapshot.context : void 0;
|
|
18803
19819
|
else {
|
|
18804
19820
|
const resolveContext = this.#observation?.resolveContext;
|
|
@@ -19419,11 +20435,11 @@ var ConvexOrganizationAdapter = class {
|
|
|
19419
20435
|
return this.listMembers(input).pipe(Effect.map((members) => members.filter((member) => member.status === "pending" || member.status === "pending_safe" || member.status === "pending_grant")));
|
|
19420
20436
|
}
|
|
19421
20437
|
inviteMember(input) {
|
|
19422
|
-
return this.#convex.action(this.#fns.inviteMember, {
|
|
20438
|
+
return this.#convex.action(this.#fns.inviteMember, copyInvocationObservation(input, {
|
|
19423
20439
|
orgId: input.orgId,
|
|
19424
20440
|
email: input.input.email,
|
|
19425
20441
|
role: input.input.role
|
|
19426
|
-
}).pipe(Effect.mapError((error) => orgErrorFromCapxul("inviteMember", error.publicError, error)), Effect.map(brandOrgMember), Effect.catchDefect((cause) => Effect.fail(toOrgError("inviteMember", cause))));
|
|
20442
|
+
})).pipe(Effect.mapError((error) => orgErrorFromCapxul("inviteMember", error.publicError, error)), Effect.map(brandOrgMember), Effect.catchDefect((cause) => Effect.fail(toOrgError("inviteMember", cause))));
|
|
19427
20443
|
}
|
|
19428
20444
|
resendInviteToken(input) {
|
|
19429
20445
|
return this.#convex.mutation(this.#fns.resendInvite, {
|
|
@@ -44703,11 +45719,18 @@ function makeMediaMethods(deps) {
|
|
|
44703
45719
|
}
|
|
44704
45720
|
//#endregion
|
|
44705
45721
|
//#region ../../packages/sdk/src/contract/system.ts
|
|
44706
|
-
const
|
|
45722
|
+
const healthAction = makeFunctionReference(CAPXUL_FUNCTIONS.system.healthObserved);
|
|
44707
45723
|
//#endregion
|
|
44708
45724
|
//#region ../../packages/sdk/src/surface/system.ts
|
|
44709
45725
|
function makeSystemMethods(deps) {
|
|
44710
|
-
return { health: (nonce, options) =>
|
|
45726
|
+
return { health: (nonce, options) => {
|
|
45727
|
+
let controls = deps.invocationControls?.(options) ?? options;
|
|
45728
|
+
const invocation = readInvocationObservation(controls);
|
|
45729
|
+
const traceparent = invocation?.active === false ? void 0 : sanitizeObservationContext(invocation?.context)?.traceparent;
|
|
45730
|
+
const parent = traceparent === void 0 ? void 0 : Option.getOrUndefined(HttpTraceContext.fromHeaders(Headers.fromRecordUnsafe({ traceparent })));
|
|
45731
|
+
if (parent !== void 0) controls = carryInvocationParentSpan(controls, parent);
|
|
45732
|
+
return runCapxulEffect(Effect.suspend(() => deps.convexCall.action(healthAction, copyInvocationObservation(controls, { nonce }))).pipe(Effect.mapError((error) => error.publicError)), controls, CAPXUL_OPERATIONS.system.health, deps.runPromise);
|
|
45733
|
+
} };
|
|
44711
45734
|
}
|
|
44712
45735
|
//#endregion
|
|
44713
45736
|
//#region ../../packages/sdk/src/contract/org.ts
|
|
@@ -44732,8 +45755,33 @@ function toOrgMe(wire) {
|
|
|
44732
45755
|
observedAt: wire.observedAt
|
|
44733
45756
|
};
|
|
44734
45757
|
}
|
|
45758
|
+
/**
|
|
45759
|
+
* The read runs through the canonical observed runner, so `org.me` owns one
|
|
45760
|
+
* `capxul_sdk_operation` record and one span like every other public method.
|
|
45761
|
+
*
|
|
45762
|
+
* The call-start invocation snapshot travels on the query arguments: the
|
|
45763
|
+
* Convex adapter reads it there and sends the browser linkage with the call,
|
|
45764
|
+
* so an account switch mid-flight cannot re-resolve the actor. A successful
|
|
45765
|
+
* read proves participation in this Organization, so the owning span carries
|
|
45766
|
+
* the verified Organization and the two authority booleans the backend
|
|
45767
|
+
* actually enforces. Labels and Budget caps stay off the record.
|
|
45768
|
+
*/
|
|
44735
45769
|
function makeOrgMeMethod(deps, orgId) {
|
|
44736
|
-
return (options) =>
|
|
45770
|
+
return (options) => {
|
|
45771
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
45772
|
+
return runCapxulEffect(Effect.gen(function* () {
|
|
45773
|
+
const wire = yield* deps.convexCall.query(orgReadContract.me, copyInvocationObservation(controls, { orgId })).pipe(Effect.mapError((failure) => failure.publicError));
|
|
45774
|
+
yield* Effect.annotateCurrentSpan({
|
|
45775
|
+
verified_organization_id: orgId,
|
|
45776
|
+
scope_kind: "organization",
|
|
45777
|
+
can_manage_people: wire.capabilities.canManagePeople,
|
|
45778
|
+
can_spend: wire.capabilities.canSpend,
|
|
45779
|
+
budget_count: wire.budgets.length,
|
|
45780
|
+
observed_at: wire.observedAt
|
|
45781
|
+
}).pipe(Effect.catchCause(() => Effect.void));
|
|
45782
|
+
return toOrgMe(wire);
|
|
45783
|
+
}), controls, CAPXUL_OPERATIONS.org.me, deps.runPromise);
|
|
45784
|
+
};
|
|
44737
45785
|
}
|
|
44738
45786
|
//#endregion
|
|
44739
45787
|
//#region ../../packages/sdk/src/contract/permission.ts
|
|
@@ -44743,7 +45791,34 @@ const permissionContract = { read: makeFunctionReference(CAPXUL_FUNCTIONS["permi
|
|
|
44743
45791
|
function isAborted(signal) {
|
|
44744
45792
|
return signal?.aborted === true;
|
|
44745
45793
|
}
|
|
44746
|
-
|
|
45794
|
+
/**
|
|
45795
|
+
* One owning operation per public Permission method. The compound command
|
|
45796
|
+
* (prepare, equality checks, sign, submit) keeps owning its own cancellation;
|
|
45797
|
+
* the observed runner around it is what gives the attempt its
|
|
45798
|
+
* `capxul_sdk_operation` record, its span and its failure capture, so a signer
|
|
45799
|
+
* refusal or an unexpected provider error joins to the operation like every
|
|
45800
|
+
* other public surface.
|
|
45801
|
+
*/
|
|
45802
|
+
function observed(deps, operation, options, run) {
|
|
45803
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
45804
|
+
let verifiedOrganizationId;
|
|
45805
|
+
return runCapxulEffect(Effect.gen(function* () {
|
|
45806
|
+
if (controls?.signal?.aborted === true) return yield* Effect.fail(Errors.cancelled({ operation }));
|
|
45807
|
+
const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
|
|
45808
|
+
const captured = carryInvocationParentSpan(controls, parent);
|
|
45809
|
+
const result = yield* Effect.tryPromise({
|
|
45810
|
+
try: () => run(controls?.signal, captured, (orgId) => {
|
|
45811
|
+
verifiedOrganizationId = orgId;
|
|
45812
|
+
}),
|
|
45813
|
+
catch: (cause) => cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
45814
|
+
});
|
|
45815
|
+
return yield* result.ok ? Effect.succeed(result.value) : Effect.fail(result.error);
|
|
45816
|
+
}).pipe(Effect.ensuring(Effect.suspend(() => verifiedOrganizationId === void 0 ? Effect.void : Effect.annotateCurrentSpan({
|
|
45817
|
+
verified_organization_id: verifiedOrganizationId,
|
|
45818
|
+
scope_kind: "organization"
|
|
45819
|
+
})).pipe(Effect.catchCause(() => Effect.void)))), observationOnlyControls(controls), operation, deps.runPromise);
|
|
45820
|
+
}
|
|
45821
|
+
async function execute(deps, orgId, command, signal, controls, verifiedOrganization) {
|
|
44747
45822
|
if (isAborted(signal)) return {
|
|
44748
45823
|
ok: false,
|
|
44749
45824
|
error: Errors.cancelled({ operation: "permissions" })
|
|
@@ -44767,17 +45842,18 @@ async function execute(deps, orgId, command, signal) {
|
|
|
44767
45842
|
};
|
|
44768
45843
|
}
|
|
44769
45844
|
const executionFns = deps.executionFunctions ?? moneyExecutionContract;
|
|
44770
|
-
const prepared = await runIfActive(signal, CAPXUL_OPERATIONS.permissions.prepareExecution, () => deps.convexCall.action(executionFns.preparePermissionExecution, { input: {
|
|
45845
|
+
const prepared = await runIfActive(signal, CAPXUL_OPERATIONS.permissions.prepareExecution, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.action(executionFns.preparePermissionExecution, copyInvocationObservation(controls, { input: {
|
|
44771
45846
|
orgId,
|
|
44772
45847
|
signerAddress,
|
|
44773
45848
|
command
|
|
44774
|
-
} }));
|
|
45849
|
+
} }))), controls), deps.runPromise);
|
|
44775
45850
|
if (!prepared.ok) return prepared;
|
|
44776
45851
|
const expectedSafe = deriveCapxulSafeAddress({ email: session.email });
|
|
44777
45852
|
if (prepared.value.chainId !== deps.chainId || prepared.value.signerAddress.toLowerCase() !== signerAddress.toLowerCase() || prepared.value.userOpSenderSafe.toLowerCase() !== expectedSafe.toLowerCase() || prepared.value.operation !== command.operation || prepared.value.orgId !== orgId || canonicalJson(prepared.value.command) !== canonicalJson(command)) return {
|
|
44778
45853
|
ok: false,
|
|
44779
45854
|
error: Errors.invalidInput("permission", "prepared authority mismatch")
|
|
44780
45855
|
};
|
|
45856
|
+
verifiedOrganization(prepared.value.orgId);
|
|
44781
45857
|
if (isAborted(signal)) return {
|
|
44782
45858
|
ok: false,
|
|
44783
45859
|
error: Errors.cancelled({ operation: "permissions" })
|
|
@@ -44795,43 +45871,46 @@ async function execute(deps, orgId, command, signal) {
|
|
|
44795
45871
|
ok: false,
|
|
44796
45872
|
error: Errors.cancelled({ operation: "permissions" })
|
|
44797
45873
|
};
|
|
44798
|
-
return runIfActive(void 0, CAPXUL_OPERATIONS.permissions.submitExecution, () => deps.convexCall.action(executionFns.submitPermissionExecution, { input: {
|
|
45874
|
+
return runIfActive(void 0, CAPXUL_OPERATIONS.permissions.submitExecution, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.action(executionFns.submitPermissionExecution, copyInvocationObservation(controls, { input: {
|
|
44799
45875
|
executionId: prepared.value.executionId,
|
|
44800
45876
|
signature
|
|
44801
|
-
} }));
|
|
45877
|
+
} }))), controls), deps.runPromise);
|
|
44802
45878
|
}
|
|
44803
45879
|
function makePermissionMethods(deps, orgId) {
|
|
44804
45880
|
const reads = deps.permissionFunctions ?? permissionContract;
|
|
45881
|
+
const ops = CAPXUL_OPERATIONS.org.permissions;
|
|
45882
|
+
const read = (signal, operation, controls) => runIfActive(signal, operation, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.query(reads.read, copyInvocationObservation(controls, { orgId }))), controls), deps.runPromise);
|
|
45883
|
+
const command = (operation, build, options) => observed(deps, operation, options, (signal, captured, verifiedOrganization) => execute(deps, orgId, build(), signal, captured, verifiedOrganization));
|
|
44805
45884
|
return {
|
|
44806
|
-
create: (input, options) =>
|
|
45885
|
+
create: (input, options) => command(ops.create, () => ({
|
|
44807
45886
|
operation: "create",
|
|
44808
45887
|
...input
|
|
44809
|
-
}, options
|
|
44810
|
-
change: (input, options) =>
|
|
45888
|
+
}), options),
|
|
45889
|
+
change: (input, options) => command(ops.change, () => ({
|
|
44811
45890
|
operation: "change",
|
|
44812
45891
|
...input
|
|
44813
|
-
}, options
|
|
44814
|
-
assign: (input, options) =>
|
|
45892
|
+
}), options),
|
|
45893
|
+
assign: (input, options) => command(ops.assign, () => ({
|
|
44815
45894
|
operation: "assign",
|
|
44816
45895
|
...input
|
|
44817
|
-
}, options
|
|
44818
|
-
revoke: (input, options) =>
|
|
45896
|
+
}), options),
|
|
45897
|
+
revoke: (input, options) => command(ops.revoke, () => ({
|
|
44819
45898
|
operation: "revoke",
|
|
44820
45899
|
...input
|
|
44821
|
-
}, options
|
|
44822
|
-
replace: (input, options) =>
|
|
45900
|
+
}), options),
|
|
45901
|
+
replace: (input, options) => command(ops.replace, () => ({
|
|
44823
45902
|
operation: "replace",
|
|
44824
45903
|
...input
|
|
44825
|
-
}, options
|
|
44826
|
-
list: (options) =>
|
|
44827
|
-
get:
|
|
44828
|
-
const listed = await
|
|
45904
|
+
}), options),
|
|
45905
|
+
list: (options) => observed(deps, ops.list, options, (signal, captured) => read(signal, CAPXUL_OPERATIONS.permissions.list, captured)),
|
|
45906
|
+
get: (permissionId, options) => observed(deps, ops.get, options, async (signal, captured) => {
|
|
45907
|
+
const listed = await read(signal, CAPXUL_OPERATIONS.permissions.get, captured);
|
|
44829
45908
|
if (!listed.ok) return listed;
|
|
44830
45909
|
return {
|
|
44831
45910
|
ok: true,
|
|
44832
45911
|
value: listed.value.permissions.find((row) => row.permissionId === permissionId) ?? null
|
|
44833
45912
|
};
|
|
44834
|
-
}
|
|
45913
|
+
})
|
|
44835
45914
|
};
|
|
44836
45915
|
}
|
|
44837
45916
|
//#endregion
|
|
@@ -45326,18 +46405,6 @@ function emitOrgCreateFailed(telemetry, error) {
|
|
|
45326
46405
|
}
|
|
45327
46406
|
});
|
|
45328
46407
|
}
|
|
45329
|
-
function emitOrgInviteSent(telemetry, input) {
|
|
45330
|
-
const domain = emailDomain$1(input.email);
|
|
45331
|
-
return emitOrgTelemetry(telemetry, {
|
|
45332
|
-
name: "org_invite_sent",
|
|
45333
|
-
props: {
|
|
45334
|
-
org_id: input.orgId,
|
|
45335
|
-
...domain === void 0 ? {} : { email_domain: domain },
|
|
45336
|
-
role: input.role,
|
|
45337
|
-
status: input.status
|
|
45338
|
-
}
|
|
45339
|
-
});
|
|
45340
|
-
}
|
|
45341
46408
|
function reportOrgTelemetryFailure(kind, name, cause) {
|
|
45342
46409
|
if (!isOrgTelemetryDebugEnabled()) return;
|
|
45343
46410
|
globalThis.console?.warn?.("[capxul] org telemetry dropped", {
|
|
@@ -45513,25 +46580,26 @@ function listMembersProgram(orgId) {
|
|
|
45513
46580
|
return [];
|
|
45514
46581
|
});
|
|
45515
46582
|
}
|
|
46583
|
+
/**
|
|
46584
|
+
* R06 (#1964): the SDK no longer emits `org_invite_sent`. The backend action
|
|
46585
|
+
* that writes the invitation is its ONE producer, so a hermetic call — which
|
|
46586
|
+
* writes nothing — can no longer report an invitation that never happened, and
|
|
46587
|
+
* a live call is counted once instead of twice. The captured attempt rides the
|
|
46588
|
+
* port input, so the durable event carries the correlation this call ran under.
|
|
46589
|
+
*/
|
|
45516
46590
|
function inviteMemberProgram(orgId, input) {
|
|
45517
46591
|
return Effect.gen(function* () {
|
|
45518
46592
|
const deps = yield* OrgDepsTag;
|
|
45519
|
-
|
|
45520
|
-
orgId,
|
|
45521
|
-
input
|
|
45522
|
-
}).pipe(Effect.mapError((error) => error.publicError)) : hermeticMember({
|
|
46593
|
+
if (deps.orgPort === void 0) return hermeticMember({
|
|
45523
46594
|
orgId,
|
|
45524
46595
|
email: input.email,
|
|
45525
46596
|
role: input.role,
|
|
45526
46597
|
status: "pending"
|
|
45527
46598
|
});
|
|
45528
|
-
yield*
|
|
46599
|
+
return yield* deps.orgPort.inviteMember(copyInvocationObservation(deps.invocationSource, {
|
|
45529
46600
|
orgId,
|
|
45530
|
-
|
|
45531
|
-
|
|
45532
|
-
status: member.status
|
|
45533
|
-
}));
|
|
45534
|
-
return member;
|
|
46601
|
+
input
|
|
46602
|
+
})).pipe(Effect.mapError((error) => error.publicError));
|
|
45535
46603
|
});
|
|
45536
46604
|
}
|
|
45537
46605
|
function detectAndAcceptPendingInvitationsProgram() {
|
|
@@ -45639,6 +46707,13 @@ function isRetryableOrganizationSetupFailure(error) {
|
|
|
45639
46707
|
* constructed for each `org(orgId)` call. It has no shared mutable active-Org
|
|
45640
46708
|
* state. The closed-over `orgId` is its only entity reference.
|
|
45641
46709
|
*/
|
|
46710
|
+
/** The observed-runner pair a method bundle needs to own its operation records. */
|
|
46711
|
+
function observedRunnerDeps(deps) {
|
|
46712
|
+
return {
|
|
46713
|
+
...deps.runPromise === void 0 ? {} : { runPromise: deps.runPromise },
|
|
46714
|
+
...deps.invocationControls === void 0 ? {} : { invocationControls: deps.invocationControls }
|
|
46715
|
+
};
|
|
46716
|
+
}
|
|
45642
46717
|
function makeOrgMethods(deps) {
|
|
45643
46718
|
const orgDeps = {
|
|
45644
46719
|
...deps.orgPort === void 0 ? {} : { orgPort: deps.orgPort },
|
|
@@ -45689,7 +46764,10 @@ function makeOrgMethods(deps) {
|
|
|
45689
46764
|
},
|
|
45690
46765
|
...convexCall === void 0 ? {} : { convexCall }
|
|
45691
46766
|
}),
|
|
45692
|
-
me: convexCall === void 0 ? orgMeUnavailable : makeOrgMeMethod({
|
|
46767
|
+
me: convexCall === void 0 ? orgMeUnavailable : makeOrgMeMethod({
|
|
46768
|
+
convexCall,
|
|
46769
|
+
...observedRunnerDeps(deps)
|
|
46770
|
+
}, String(orgId)),
|
|
45693
46771
|
async getLifecycle(options) {
|
|
45694
46772
|
if (options?.signal?.aborted) return {
|
|
45695
46773
|
ok: false,
|
|
@@ -45746,32 +46824,27 @@ function makeOrgMethods(deps) {
|
|
|
45746
46824
|
});
|
|
45747
46825
|
return treasury(orgId, deps.invocationControls?.(options) ?? options);
|
|
45748
46826
|
},
|
|
45749
|
-
account: {
|
|
45750
|
-
if (options?.signal?.aborted) return {
|
|
45751
|
-
ok: false,
|
|
45752
|
-
error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.org.account.get })
|
|
45753
|
-
};
|
|
46827
|
+
account: { get(options) {
|
|
45754
46828
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
45755
|
-
|
|
45756
|
-
if (!treasuryResult.ok) return {
|
|
45757
|
-
ok: false,
|
|
45758
|
-
error: treasuryResult.error
|
|
45759
|
-
};
|
|
45760
|
-
const orgList = await listOrganizations(controls);
|
|
45761
|
-
if (!orgList.ok) return {
|
|
46829
|
+
if (controls?.signal?.aborted) return Promise.resolve({
|
|
45762
46830
|
ok: false,
|
|
45763
|
-
error:
|
|
45764
|
-
};
|
|
45765
|
-
|
|
45766
|
-
|
|
45767
|
-
|
|
45768
|
-
|
|
46831
|
+
error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.org.account.get })
|
|
46832
|
+
});
|
|
46833
|
+
return runCapxulEffect(Effect.gen(function* () {
|
|
46834
|
+
const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
|
|
46835
|
+
const captured = carryInvocationParentSpan(controls, parent);
|
|
46836
|
+
const treasuryResult = yield* Effect.promise(() => treasury(orgId, captured));
|
|
46837
|
+
if (!treasuryResult.ok) return yield* Effect.fail(treasuryResult.error);
|
|
46838
|
+
const orgList = yield* Effect.promise(() => listOrganizations(captured));
|
|
46839
|
+
if (!orgList.ok) return yield* Effect.fail(orgList.error);
|
|
46840
|
+
const org = orgList.value.find((candidate) => candidate.id === orgId);
|
|
46841
|
+
return {
|
|
45769
46842
|
id: treasuryResult.value.id,
|
|
45770
46843
|
address: org?.safeAddress ?? null,
|
|
45771
46844
|
balance: treasuryResult.value.balance,
|
|
45772
46845
|
available: treasuryResult.value.available
|
|
45773
|
-
}
|
|
45774
|
-
};
|
|
46846
|
+
};
|
|
46847
|
+
}), observationOnlyControls(controls), CAPXUL_OPERATIONS.org.account.get, deps.runPromise);
|
|
45775
46848
|
} },
|
|
45776
46849
|
members(_options) {
|
|
45777
46850
|
if (_options?.signal?.aborted) return Promise.resolve({
|
|
@@ -45788,11 +46861,15 @@ function makeOrgMethods(deps) {
|
|
|
45788
46861
|
return toCapxulResult(listRolesProgram(orgId), layer);
|
|
45789
46862
|
},
|
|
45790
46863
|
invite(_input, _options) {
|
|
45791
|
-
|
|
46864
|
+
const controls = deps.invocationControls?.(_options) ?? _options;
|
|
46865
|
+
if (controls?.signal?.aborted) return Promise.resolve({
|
|
45792
46866
|
ok: false,
|
|
45793
46867
|
error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.org.invite })
|
|
45794
46868
|
});
|
|
45795
|
-
return
|
|
46869
|
+
return runCapxulEffect(inviteMemberProgram(orgId, _input).pipe(Effect.provide(orgDepsLayer({
|
|
46870
|
+
...orgDeps,
|
|
46871
|
+
...controls === void 0 ? {} : { invocationSource: controls }
|
|
46872
|
+
}))), controls, CAPXUL_OPERATIONS.org.invite, deps.runPromise);
|
|
45796
46873
|
},
|
|
45797
46874
|
auditLog(_options) {
|
|
45798
46875
|
if (_options?.signal?.aborted) return Promise.resolve({
|
|
@@ -45806,6 +46883,7 @@ function makeOrgMethods(deps) {
|
|
|
45806
46883
|
},
|
|
45807
46884
|
permissions: convexCall === void 0 ? makeNotImplementedPermissionMethods() : makePermissionMethods({
|
|
45808
46885
|
convexCall,
|
|
46886
|
+
...observedRunnerDeps(deps),
|
|
45809
46887
|
...deps.actor === void 0 ? {} : { actor: deps.actor },
|
|
45810
46888
|
...deps.chainId === void 0 ? {} : { chainId: Number(deps.chainId) },
|
|
45811
46889
|
...deps.signer === void 0 ? {} : { signer: deps.signer }
|
|
@@ -45925,14 +47003,65 @@ function compareDecimal(first, second) {
|
|
|
45925
47003
|
}
|
|
45926
47004
|
//#endregion
|
|
45927
47005
|
//#region ../../packages/sdk/src/surface/holdings.ts
|
|
47006
|
+
/** SPEC Freshness: past this block age the read is labelled stale. Nothing refuses. */
|
|
47007
|
+
const FRESHNESS_LIMIT_SECONDS = 60;
|
|
47008
|
+
/**
|
|
47009
|
+
* The Ponder balance view for one Safe as `CurrentHoldings`.
|
|
47010
|
+
*
|
|
47011
|
+
* The view is the signed sum of every indexed transfer, so the balance IS what
|
|
47012
|
+
* the chain said — there is no snapshot to go stale behind it. `observedAt` is
|
|
47013
|
+
* the indexed block's own timestamp, which is what the last-good label reads,
|
|
47014
|
+
* and `stale` is that block's age. A stopped indexer therefore shows an old
|
|
47015
|
+
* "as of" and the stale flag; it never turns the read into a refusal.
|
|
47016
|
+
*/
|
|
47017
|
+
function indexerHoldings(indexer, convexCall, overlay, actor, controls) {
|
|
47018
|
+
return Effect.gen(function* () {
|
|
47019
|
+
const scope = yield* convexCall.query(overlay, copyInvocationObservation(controls, actor?.kind === "organization" ? { input: { actor: {
|
|
47020
|
+
kind: "organization",
|
|
47021
|
+
orgId: actor.organizationId
|
|
47022
|
+
} } } : { input: {} }));
|
|
47023
|
+
if (scope.safe === null) return null;
|
|
47024
|
+
const balances = yield* indexer.read("balance", {
|
|
47025
|
+
safe: toAddress(scope.safe),
|
|
47026
|
+
limit: INDEXER_MAX_LIMIT
|
|
47027
|
+
});
|
|
47028
|
+
const status = yield* indexer.status.pipe(Effect.catch(() => Effect.succeed([])));
|
|
47029
|
+
const rows = [];
|
|
47030
|
+
for (const balance of balances) {
|
|
47031
|
+
const asset = configuredMoneyAssetById(balance.assetId);
|
|
47032
|
+
if (asset === null || balance.amount < 0n) continue;
|
|
47033
|
+
rows.push({
|
|
47034
|
+
assetKind: "erc20",
|
|
47035
|
+
tokenAddress: toAddress(asset.tokenAddress),
|
|
47036
|
+
symbol: asset.symbol,
|
|
47037
|
+
decimals: asset.decimals,
|
|
47038
|
+
rawBalance: toWeiAmount(balance.amount.toString())
|
|
47039
|
+
});
|
|
47040
|
+
}
|
|
47041
|
+
const chainId = balances[0]?.chainId ?? status[0]?.chainId;
|
|
47042
|
+
if (chainId === void 0) return null;
|
|
47043
|
+
const head = status.find((entry) => entry.chainId === chainId);
|
|
47044
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
47045
|
+
const headSeconds = head === void 0 ? void 0 : Number(head.blockTimestamp);
|
|
47046
|
+
return {
|
|
47047
|
+
actor: scope.actor,
|
|
47048
|
+
chainId: toChainId(chainId),
|
|
47049
|
+
observedAt: headSeconds === void 0 ? Date.now() : headSeconds * 1e3,
|
|
47050
|
+
stale: headSeconds === void 0 || nowSeconds - headSeconds > FRESHNESS_LIMIT_SECONDS,
|
|
47051
|
+
rows
|
|
47052
|
+
};
|
|
47053
|
+
}).pipe(Effect.catch(() => Effect.succeed(null)));
|
|
47054
|
+
}
|
|
45928
47055
|
function makeHoldingsMethods(deps) {
|
|
45929
47056
|
const functions = deps.functions ?? holdingsContract;
|
|
47057
|
+
const overlay = (deps.financialOpsFunctions ?? financialOpsContract).activityOverlay;
|
|
45930
47058
|
const read = (operation, actor, options, pick) => {
|
|
45931
47059
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
45932
|
-
|
|
47060
|
+
const convexSnapshot = retryIdempotentRead(deps.convexCall.action(functions.current, copyInvocationObservation(controls, actor?.kind === "organization" ? { actor: {
|
|
45933
47061
|
kind: "organization",
|
|
45934
47062
|
orgId: actor.organizationId
|
|
45935
|
-
} } : {})), operation, deps.telemetry, controls).pipe(Effect.
|
|
47063
|
+
} } : {})), operation, deps.telemetry, controls).pipe(Effect.mapError((error) => error.publicError));
|
|
47064
|
+
return runCapxulEffect((deps.indexerRead === void 0 ? convexSnapshot : indexerHoldings(deps.indexerRead, deps.convexCall, overlay, actor, controls).pipe(Effect.flatMap((current) => current === null ? convexSnapshot : Effect.succeed(current)))).pipe(Effect.map(pick)), controls, operation, deps.runPromise);
|
|
45936
47065
|
};
|
|
45937
47066
|
return {
|
|
45938
47067
|
current: (input, options) => read(CAPXUL_OPERATIONS.holdings.current, input?.actor, options, (snapshot) => snapshot),
|
|
@@ -46066,8 +47195,8 @@ const APPLIED_ACTION_BY_EVENT = {
|
|
|
46066
47195
|
RestoreSession: "none",
|
|
46067
47196
|
ResumeOtpEntry: "none",
|
|
46068
47197
|
Reset: "none",
|
|
46069
|
-
SessionRestored: "
|
|
46070
|
-
SessionAbsent: "
|
|
47198
|
+
SessionRestored: "restoration",
|
|
47199
|
+
SessionAbsent: "restoration",
|
|
46071
47200
|
EnsureAccount: "none",
|
|
46072
47201
|
ClaimAccount: "none",
|
|
46073
47202
|
RetryAccount: "none",
|
|
@@ -46079,8 +47208,8 @@ const APPLIED_ACTION_BY_EVENT = {
|
|
|
46079
47208
|
OtpFailed: "failed",
|
|
46080
47209
|
Verified: "verified",
|
|
46081
47210
|
VerifyFailed: "failed",
|
|
46082
|
-
SessionRead: "
|
|
46083
|
-
SessionReadFailed: "
|
|
47211
|
+
SessionRead: "restoration",
|
|
47212
|
+
SessionReadFailed: "restoration",
|
|
46084
47213
|
SignedOut: "signed-out",
|
|
46085
47214
|
SignOutFailed: "failed",
|
|
46086
47215
|
AccountAt: "none",
|
|
@@ -46106,6 +47235,49 @@ const authFailure = (record, reason, mode) => ({
|
|
|
46106
47235
|
...linkage(record)
|
|
46107
47236
|
}
|
|
46108
47237
|
});
|
|
47238
|
+
/**
|
|
47239
|
+
* The label of the restore window every client boots into. A settled session
|
|
47240
|
+
* fact that left this label is the restoration result (#1962 R04); the same
|
|
47241
|
+
* facts from a signed-out or authenticated state are the routine session probe
|
|
47242
|
+
* that `getSession()` runs, and a probe is not a restoration attempt.
|
|
47243
|
+
*/
|
|
47244
|
+
const RESTORE_WINDOW = "restoring";
|
|
47245
|
+
/**
|
|
47246
|
+
* Which result the window settled on. `SessionRestored` and `SessionAbsent` are
|
|
47247
|
+
* the cache door and say it themselves. `ReadSession` is also valid inside the
|
|
47248
|
+
* window — `getSession()` drives it on a cache miss and its `SessionRead`
|
|
47249
|
+
* completion settles the window — so that one event reports both halves and the
|
|
47250
|
+
* state it produced is what separates them.
|
|
47251
|
+
*/
|
|
47252
|
+
const restorationOutcome = (event, state) => {
|
|
47253
|
+
switch (event) {
|
|
47254
|
+
case "SessionRestored": return "restored";
|
|
47255
|
+
case "SessionAbsent": return "absent";
|
|
47256
|
+
case "SessionReadFailed": return "failed";
|
|
47257
|
+
case "SessionRead":
|
|
47258
|
+
if (state.phase === "authenticated") return "restored";
|
|
47259
|
+
return state.phase === "signed_out" ? "absent" : void 0;
|
|
47260
|
+
default: return;
|
|
47261
|
+
}
|
|
47262
|
+
};
|
|
47263
|
+
/**
|
|
47264
|
+
* The restore window's one result, or nothing when this settled session fact
|
|
47265
|
+
* belongs to a probe rather than to the window.
|
|
47266
|
+
*/
|
|
47267
|
+
const restorationObservation = (record, state) => {
|
|
47268
|
+
if (record.slot !== "identity:session" || record.from !== RESTORE_WINDOW) return NONE;
|
|
47269
|
+
const outcome = restorationOutcome(record.event, state);
|
|
47270
|
+
if (outcome === void 0) return NONE;
|
|
47271
|
+
return {
|
|
47272
|
+
name: "access_recovery_completed",
|
|
47273
|
+
props: {
|
|
47274
|
+
recovery: "session_restoration",
|
|
47275
|
+
outcome,
|
|
47276
|
+
...outcome === "failed" && state.phase === "faulted" ? { reason_code: state.failure.code } : {},
|
|
47277
|
+
...linkage(record)
|
|
47278
|
+
}
|
|
47279
|
+
};
|
|
47280
|
+
};
|
|
46109
47281
|
const REFUSAL_EVENTS = /* @__PURE__ */ new Set([
|
|
46110
47282
|
"ClaimAccount",
|
|
46111
47283
|
"RetryAccount",
|
|
@@ -46150,6 +47322,7 @@ function mapIdentityProductObservation(record, state) {
|
|
|
46150
47322
|
name: "auth_signed_out",
|
|
46151
47323
|
props: linkage(record)
|
|
46152
47324
|
};
|
|
47325
|
+
case "restoration": return restorationObservation(record, state);
|
|
46153
47326
|
}
|
|
46154
47327
|
}
|
|
46155
47328
|
const ignoreTransportFailure = (operation, operationName, eventName) => Effect.suspend(operation).pipe(Effect.catchCause(() => Effect.logWarning("identity.product.telemetry.dropped").pipe(Effect.annotateLogs({
|
|
@@ -46161,7 +47334,7 @@ function executeIdentityProductObservation(telemetry, record, state) {
|
|
|
46161
47334
|
if (mapped === null) return Effect.void;
|
|
46162
47335
|
copyInvocationObservation(record, mapped);
|
|
46163
47336
|
const invocationTelemetry = bindProductTelemetryInvocation(telemetry, mapped);
|
|
46164
|
-
const after = () => mapped.name === "auth_verified"
|
|
47337
|
+
const after = () => state.phase === "authenticated" && (mapped.name === "auth_verified" || mapped.name === "access_recovery_completed") ? invocationTelemetry.identify({
|
|
46165
47338
|
distinctId: state.session.authUserId,
|
|
46166
47339
|
traits: { email_domain: emailDomain(state.session.email) }
|
|
46167
47340
|
}) : mapped.name === "auth_signed_out" ? invocationTelemetry.reset() : Effect.void;
|
|
@@ -46206,6 +47379,73 @@ function startSignerReadinessOnClaim(actor, signer) {
|
|
|
46206
47379
|
browserSigner.ensureWalletReady?.().catch(() => {});
|
|
46207
47380
|
});
|
|
46208
47381
|
}
|
|
47382
|
+
/**
|
|
47383
|
+
* Report the result of each signer readiness cycle (#1962 R04).
|
|
47384
|
+
*
|
|
47385
|
+
* The readiness store already carries the cycle boundary this needs, so no
|
|
47386
|
+
* public signer hook, second identity subscriber, or render counter is added.
|
|
47387
|
+
* `ensureOpenfortWalletReady` writes `recovering` synchronously when it starts
|
|
47388
|
+
* a cycle, and only the cycle that is still the current one writes `ready` or
|
|
47389
|
+
* `unavailable` (`create-openfort-browser-signer.ts:501-521`). Callers that
|
|
47390
|
+
* join a live cycle share that single write, and a `resetSession` writes
|
|
47391
|
+
* `unknown` first, so a cycle that a reset or an account replacement outran
|
|
47392
|
+
* reports nothing.
|
|
47393
|
+
*
|
|
47394
|
+
* The host context is bound when the cycle starts, so a person who signs out
|
|
47395
|
+
* and back in while a cycle runs cannot relabel the result that began under
|
|
47396
|
+
* the previous person. A signer with no readiness cycle — a node or dev key,
|
|
47397
|
+
* and a headless client whose requirement never opens the account lane —
|
|
47398
|
+
* writes no status and reports nothing.
|
|
47399
|
+
*/
|
|
47400
|
+
function observeSignerReadinessCycles(signer, telemetry, hostObservationSnapshot, runPromise) {
|
|
47401
|
+
const statusStore = signer?.statusStore;
|
|
47402
|
+
if (statusStore === void 0 || telemetry === void 0) return () => {};
|
|
47403
|
+
let running = false;
|
|
47404
|
+
let startContext;
|
|
47405
|
+
return statusStore.subscribe((status) => {
|
|
47406
|
+
if (status === "recovering") {
|
|
47407
|
+
running = true;
|
|
47408
|
+
startContext = hostObservationSnapshot?.();
|
|
47409
|
+
return;
|
|
47410
|
+
}
|
|
47411
|
+
const cycleContext = startContext;
|
|
47412
|
+
const completesCycle = running;
|
|
47413
|
+
running = false;
|
|
47414
|
+
startContext = void 0;
|
|
47415
|
+
if (!completesCycle || status !== "ready" && status !== "unavailable") return;
|
|
47416
|
+
const event = {
|
|
47417
|
+
name: "access_recovery_completed",
|
|
47418
|
+
props: {
|
|
47419
|
+
recovery: "signer_readiness",
|
|
47420
|
+
outcome: status
|
|
47421
|
+
}
|
|
47422
|
+
};
|
|
47423
|
+
if (cycleContext !== void 0) attachInvocationObservation(event, cycleContext);
|
|
47424
|
+
runPromise(Effect.suspend(() => bindProductTelemetryInvocation(telemetry, event).emit(event)).pipe(Effect.catchCause(() => Effect.void))).catch(() => {});
|
|
47425
|
+
});
|
|
47426
|
+
}
|
|
47427
|
+
/** Join the assembled actor lifetime to the adapter lifetime for internal client factories. */
|
|
47428
|
+
function withAdapterClose(client, closeAdapter) {
|
|
47429
|
+
const closeActor = client._internal.close;
|
|
47430
|
+
let closePromise;
|
|
47431
|
+
const close = () => {
|
|
47432
|
+
closePromise ??= Promise.allSettled([Promise.resolve().then(() => closeActor?.()), Promise.resolve().then(closeAdapter)]).then((results) => {
|
|
47433
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
47434
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
47435
|
+
});
|
|
47436
|
+
return closePromise;
|
|
47437
|
+
};
|
|
47438
|
+
return {
|
|
47439
|
+
...client,
|
|
47440
|
+
close: () => closeClientResources(close),
|
|
47441
|
+
_internal: {
|
|
47442
|
+
...client._internal,
|
|
47443
|
+
close
|
|
47444
|
+
}
|
|
47445
|
+
};
|
|
47446
|
+
}
|
|
47447
|
+
/** Keep lifecycle failures on the same public result boundary as domain work. */
|
|
47448
|
+
const closeClientResources = (close) => toCapxulResult(Effect.promise(close), Layer.empty);
|
|
46209
47449
|
function assembleCapxulClient(input) {
|
|
46210
47450
|
const observation = input;
|
|
46211
47451
|
const authCache = input.authCache ?? detectAuthCacheAdapter();
|
|
@@ -46235,12 +47475,14 @@ function assembleCapxulClient(input) {
|
|
|
46235
47475
|
}, failureObservation, normalizeCapxulOperation(`identity.${record.event}`), "machine");
|
|
46236
47476
|
});
|
|
46237
47477
|
const unsubscribeSignerReadiness = startSignerReadinessOnClaim(actor, input.signer);
|
|
47478
|
+
const unsubscribeReadinessObservation = observeSignerReadinessCycles(input.signer, input.ports.telemetry, observation.hostObservationSnapshot, effectRunner.runPromise);
|
|
46238
47479
|
let stopPromise = null;
|
|
46239
47480
|
const stopActor = () => {
|
|
46240
47481
|
if (stopPromise === null) {
|
|
46241
47482
|
unsubscribeProductTelemetry();
|
|
46242
47483
|
unsubscribeFailureObservation();
|
|
46243
47484
|
unsubscribeSignerReadiness();
|
|
47485
|
+
unsubscribeReadinessObservation();
|
|
46244
47486
|
stopPromise = effectRunner.runPromise(Scope.close(scope, Exit.void));
|
|
46245
47487
|
}
|
|
46246
47488
|
return stopPromise;
|
|
@@ -46257,7 +47499,8 @@ function assembleCapxulClient(input) {
|
|
|
46257
47499
|
convexCall: input.ports.convexCall,
|
|
46258
47500
|
...input.signer === void 0 ? {} : { signer: input.signer },
|
|
46259
47501
|
telemetry: input.ports.telemetry,
|
|
46260
|
-
requestKeyScope: `${input.bootstrap.convexUrl}:${String(input.bootstrap.chainId)}
|
|
47502
|
+
requestKeyScope: `${input.bootstrap.convexUrl}:${String(input.bootstrap.chainId)}`,
|
|
47503
|
+
...input.ports.indexerRead === void 0 ? {} : { indexerRead: input.ports.indexerRead }
|
|
46261
47504
|
});
|
|
46262
47505
|
const accountBundle = makeAccountMethods({
|
|
46263
47506
|
actor,
|
|
@@ -46322,13 +47565,18 @@ function assembleCapxulClient(input) {
|
|
|
46322
47565
|
subscribeIdentity: actor.subscribe,
|
|
46323
47566
|
sendIdentity: (event, options) => runCapxulEffect(askIdentity(actor, event, options), options, CAPXUL_OPERATIONS._internal.identity.send, effectRunner.runPromise)
|
|
46324
47567
|
});
|
|
46325
|
-
const system = makeSystemMethods({
|
|
47568
|
+
const system = makeSystemMethods({
|
|
47569
|
+
convexCall: input.ports.convexCall,
|
|
47570
|
+
runPromise: effectRunner.runPromise,
|
|
47571
|
+
invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls)
|
|
47572
|
+
});
|
|
46326
47573
|
const media = makeMediaMethods({ convexCall: input.ports.convexCall });
|
|
46327
47574
|
const holdings = makeHoldingsMethods({
|
|
46328
47575
|
convexCall: input.ports.convexCall,
|
|
46329
47576
|
telemetry: input.ports.telemetry,
|
|
46330
47577
|
runPromise: effectRunner.runPromise,
|
|
46331
|
-
invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls, actor.authSession()?.authUserId)
|
|
47578
|
+
invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls, actor.authSession()?.authUserId),
|
|
47579
|
+
...input.ports.indexerRead === void 0 ? {} : { indexerRead: input.ports.indexerRead }
|
|
46332
47580
|
});
|
|
46333
47581
|
const accounts = makeAccountsMethods({
|
|
46334
47582
|
accountReadPort: input.ports.accountRead,
|
|
@@ -46471,7 +47719,8 @@ function assembleCapxulClient(input) {
|
|
|
46471
47719
|
})).pipe(Effect.catchCause(() => Effect.void)));
|
|
46472
47720
|
},
|
|
46473
47721
|
close: stopActor
|
|
46474
|
-
}
|
|
47722
|
+
},
|
|
47723
|
+
close: () => closeClientResources(stopActor)
|
|
46475
47724
|
}, observation.failureObservation, observation.hostObservationSnapshot);
|
|
46476
47725
|
}
|
|
46477
47726
|
function transitionError(record) {
|
|
@@ -46521,6 +47770,7 @@ function withHostObservationControls(snapshot, input, actorId) {
|
|
|
46521
47770
|
}
|
|
46522
47771
|
//#endregion
|
|
46523
47772
|
//#region ../../packages/sdk/src/host-observability.ts
|
|
47773
|
+
const HOST_ENGINEERING_POLICY = Symbol("capxul.host-engineering-policy");
|
|
46524
47774
|
const HOST_INVOCATION = Symbol("capxul.host-observability-invocation");
|
|
46525
47775
|
/** @internal Bind both projections to one call-start decision/context snapshot. */
|
|
46526
47776
|
function bindHostObservabilityInvocation(observability) {
|
|
@@ -46534,36 +47784,14 @@ function snapshotHostObservability(observability) {
|
|
|
46534
47784
|
...snapshot.context === void 0 ? {} : { context: snapshot.context }
|
|
46535
47785
|
};
|
|
46536
47786
|
}
|
|
46537
|
-
|
|
46538
|
-
|
|
46539
|
-
|
|
46540
|
-
|
|
46541
|
-
|
|
46542
|
-
|
|
46543
|
-
|
|
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
|
-
});
|
|
47787
|
+
/** @internal Carry the explicit host engineering policy into production composition. */
|
|
47788
|
+
function hostEngineeringPolicy(observability) {
|
|
47789
|
+
const policy = observability?.[HOST_ENGINEERING_POLICY];
|
|
47790
|
+
return {
|
|
47791
|
+
...policy?.engineeringEnabled === void 0 ? {} : { enabled: policy.engineeringEnabled },
|
|
47792
|
+
...policy?.engineeringPrivacy === void 0 ? {} : { privacy: policy.engineeringPrivacy }
|
|
47793
|
+
};
|
|
46565
47794
|
}
|
|
46566
|
-
Context.Service()("@capxul/sdk/ports/IndexerReadPort");
|
|
46567
47795
|
//#endregion
|
|
46568
47796
|
//#region ../../packages/sdk/src/adapters/ponder/decode.ts
|
|
46569
47797
|
/**
|
|
@@ -46614,6 +47842,7 @@ function identity(row) {
|
|
|
46614
47842
|
chainId: toChainId(integer(row, "chain_id")),
|
|
46615
47843
|
txHash: toTxHash(hex(row, "tx_hash")),
|
|
46616
47844
|
transactionLogOrdinal: integer(row, "transaction_log_ordinal"),
|
|
47845
|
+
logIndex: integer(row, "log_index"),
|
|
46617
47846
|
blockNumber: big(row, "block_number"),
|
|
46618
47847
|
blockHash: hex(row, "block_hash"),
|
|
46619
47848
|
timestamp: big(row, "timestamp")
|
|
@@ -46696,8 +47925,8 @@ function decodeStatus(body) {
|
|
|
46696
47925
|
* that allowlist changes, this file changes with it or every read fails 403.
|
|
46697
47926
|
*/
|
|
46698
47927
|
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",
|
|
47928
|
+
transfer: "select \"id\", \"chain_id\", \"tx_hash\", \"transaction_log_ordinal\", \"log_index\", \"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",
|
|
47929
|
+
payment: "select \"id\", \"chain_id\", \"tx_hash\", \"transaction_log_ordinal\", \"log_index\", \"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
47930
|
balance: "select \"chain_id\", \"asset_id\", \"to\", \"amount\" from \"balance\" where \"balance\".\"to\" = $1"
|
|
46702
47931
|
};
|
|
46703
47932
|
/** How many times the statement binds the Safe address. */
|
|
@@ -46747,11 +47976,16 @@ function ponderQueryParam(query) {
|
|
|
46747
47976
|
* policy allows exactly one request header (`Authorization`), so this reader
|
|
46748
47977
|
* sends nothing else. Ponder writes one `data:` line per frame.
|
|
46749
47978
|
*/
|
|
46750
|
-
async function readEventStream(body, onData, stopped) {
|
|
47979
|
+
async function readEventStream(body, onData, stopped, signal) {
|
|
46751
47980
|
const reader = body.getReader();
|
|
46752
47981
|
const decoder = new TextDecoder();
|
|
46753
47982
|
let buffer = "";
|
|
47983
|
+
const cancel = () => {
|
|
47984
|
+
reader.cancel().catch(() => void 0);
|
|
47985
|
+
};
|
|
47986
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
46754
47987
|
try {
|
|
47988
|
+
if (signal?.aborted) return;
|
|
46755
47989
|
for (;;) {
|
|
46756
47990
|
const { done, value } = await reader.read();
|
|
46757
47991
|
if (done || stopped()) return;
|
|
@@ -46767,6 +48001,7 @@ async function readEventStream(body, onData, stopped) {
|
|
|
46767
48001
|
}
|
|
46768
48002
|
}
|
|
46769
48003
|
} finally {
|
|
48004
|
+
signal?.removeEventListener("abort", cancel);
|
|
46770
48005
|
await reader.cancel().catch(() => void 0);
|
|
46771
48006
|
}
|
|
46772
48007
|
}
|
|
@@ -46803,12 +48038,10 @@ var PonderIndexerAdapter = class {
|
|
|
46803
48038
|
subscribe(table, input, callback) {
|
|
46804
48039
|
const operation = CAPXUL_OPERATIONS.activity.subscribe;
|
|
46805
48040
|
return Effect.sync(() => {
|
|
46806
|
-
|
|
46807
|
-
const unsubscribe = () =>
|
|
46808
|
-
stopped = true;
|
|
46809
|
-
};
|
|
48041
|
+
const controller = new AbortController();
|
|
48042
|
+
const unsubscribe = () => controller.abort();
|
|
46810
48043
|
callback({ status: "loading" });
|
|
46811
|
-
this.#stream(table, input, operation, callback,
|
|
48044
|
+
this.#stream(table, input, operation, callback, controller.signal).catch(() => void 0);
|
|
46812
48045
|
return unsubscribe;
|
|
46813
48046
|
});
|
|
46814
48047
|
}
|
|
@@ -46821,9 +48054,13 @@ var PonderIndexerAdapter = class {
|
|
|
46821
48054
|
catch: (cause) => toIndexerReadError("indexer.status", cause)
|
|
46822
48055
|
});
|
|
46823
48056
|
/** One authenticated `/sql/:method` call. Throws a `CapxulError` on refusal. */
|
|
46824
|
-
async #request(method, table, input, operation) {
|
|
48057
|
+
async #request(method, table, input, operation, signal, forceRefreshToken = false) {
|
|
46825
48058
|
const query = ponderQuery(table, input);
|
|
46826
|
-
const token = await this.#token({
|
|
48059
|
+
const token = await this.#token({
|
|
48060
|
+
forceRefreshToken,
|
|
48061
|
+
...signal === void 0 ? {} : { signal }
|
|
48062
|
+
});
|
|
48063
|
+
if (signal?.aborted) throw Errors.cancelled({ operation });
|
|
46827
48064
|
if (token === null || token === "") throw Errors.notAuthenticated();
|
|
46828
48065
|
const url = `${this.#baseUrl}/sql/${method}?sql=${encodeURIComponent(ponderQueryParam(query))}`;
|
|
46829
48066
|
const headers = { authorization: `Bearer ${token}` };
|
|
@@ -46832,7 +48069,8 @@ var PonderIndexerAdapter = class {
|
|
|
46832
48069
|
try {
|
|
46833
48070
|
response = await this.#fetch(url, {
|
|
46834
48071
|
method: "GET",
|
|
46835
|
-
headers
|
|
48072
|
+
headers,
|
|
48073
|
+
...signal === void 0 ? {} : { signal }
|
|
46836
48074
|
});
|
|
46837
48075
|
} catch (cause) {
|
|
46838
48076
|
throw Errors.networkError(operation, cause, {
|
|
@@ -46844,39 +48082,72 @@ var PonderIndexerAdapter = class {
|
|
|
46844
48082
|
return response;
|
|
46845
48083
|
}
|
|
46846
48084
|
/**
|
|
46847
|
-
*
|
|
46848
|
-
*
|
|
46849
|
-
*
|
|
46850
|
-
* reaches `captureException` under `activity.subscribe` and the caller sees
|
|
46851
|
-
* one `error` snapshot.
|
|
48085
|
+
* Keep the subscription alive across transport loss. Every new connection
|
|
48086
|
+
* rechecks authority. A refusal or invalid payload is terminal. Unsubscribe
|
|
48087
|
+
* aborts both the current request and any reconnect delay.
|
|
46852
48088
|
*/
|
|
46853
|
-
async #stream(table, input, operation, callback,
|
|
46854
|
-
let
|
|
46855
|
-
|
|
46856
|
-
|
|
46857
|
-
|
|
46858
|
-
|
|
46859
|
-
|
|
46860
|
-
|
|
46861
|
-
|
|
46862
|
-
|
|
46863
|
-
|
|
46864
|
-
|
|
46865
|
-
|
|
46866
|
-
|
|
46867
|
-
|
|
46868
|
-
|
|
46869
|
-
|
|
48089
|
+
async #stream(table, input, operation, callback, signal) {
|
|
48090
|
+
let refreshToken = false;
|
|
48091
|
+
let delay = 1e3;
|
|
48092
|
+
let reported = false;
|
|
48093
|
+
while (!signal.aborted) {
|
|
48094
|
+
let failure;
|
|
48095
|
+
let invalidFrame = false;
|
|
48096
|
+
let reading = false;
|
|
48097
|
+
const startedAt = Date.now();
|
|
48098
|
+
try {
|
|
48099
|
+
const response = await this.#request("live", table, input, operation, signal, refreshToken);
|
|
48100
|
+
if (response.body === null) throw Errors.providerError("indexer", operation, "empty stream");
|
|
48101
|
+
reading = true;
|
|
48102
|
+
await readEventStream(response.body, (data) => {
|
|
48103
|
+
try {
|
|
48104
|
+
callback({
|
|
48105
|
+
status: "ok",
|
|
48106
|
+
value: decodeRows(table, JSON.parse(data))
|
|
48107
|
+
});
|
|
48108
|
+
reported = false;
|
|
48109
|
+
} catch (cause) {
|
|
48110
|
+
invalidFrame = true;
|
|
48111
|
+
failure = toPublicError$1(operation, cause);
|
|
48112
|
+
}
|
|
48113
|
+
}, () => signal.aborted || failure !== void 0, signal);
|
|
48114
|
+
} catch (cause) {
|
|
48115
|
+
failure = reading && !(cause instanceof CapxulError) ? Errors.networkError(operation, cause, {
|
|
48116
|
+
provider: "indexer",
|
|
48117
|
+
failure_mode: "upstream-down"
|
|
48118
|
+
}) : toPublicError$1(operation, cause);
|
|
48119
|
+
}
|
|
48120
|
+
if (signal.aborted || failure?.code === "CANCELLED") return;
|
|
48121
|
+
const error = failure ?? Errors.capabilityUnavailable("indexer", operation);
|
|
48122
|
+
const retryable = !invalidFrame && (error.code === "NETWORK_ERROR" || error.code === "CAPABILITY_UNAVAILABLE" || error.code === "RATE_LIMITED" || error.mode === "upstream-down");
|
|
48123
|
+
if (!reported || !retryable) {
|
|
48124
|
+
observeStreamFailure(this.#observation, operation, error, error.code === "NOT_AUTHENTICATED" ? "operation" : "exception");
|
|
48125
|
+
callback({
|
|
48126
|
+
status: "error",
|
|
48127
|
+
error
|
|
48128
|
+
});
|
|
48129
|
+
reported = true;
|
|
48130
|
+
}
|
|
48131
|
+
if (!retryable) return;
|
|
48132
|
+
if (Date.now() - startedAt >= 3e4) delay = 1e3;
|
|
48133
|
+
await reconnectDelay(delay, signal);
|
|
48134
|
+
delay = Math.min(delay * 2, 3e4);
|
|
48135
|
+
refreshToken = true;
|
|
46870
48136
|
}
|
|
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
48137
|
}
|
|
46879
48138
|
};
|
|
48139
|
+
function reconnectDelay(milliseconds, signal) {
|
|
48140
|
+
return new Promise((resolve) => {
|
|
48141
|
+
const finish = () => {
|
|
48142
|
+
clearTimeout(timer);
|
|
48143
|
+
signal.removeEventListener("abort", finish);
|
|
48144
|
+
resolve();
|
|
48145
|
+
};
|
|
48146
|
+
const timer = setTimeout(finish, milliseconds);
|
|
48147
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
48148
|
+
if (signal.aborted) finish();
|
|
48149
|
+
});
|
|
48150
|
+
}
|
|
46880
48151
|
/**
|
|
46881
48152
|
* Map an indexer refusal into the shared error vocabulary.
|
|
46882
48153
|
*
|
|
@@ -47244,6 +48515,7 @@ function productionAuthCacheLayer(input) {
|
|
|
47244
48515
|
function productionConvexCallLayer(input, refreshConvexAuthRef) {
|
|
47245
48516
|
return Layer.unwrap(Effect.map(AuthClientPortTag, (authClient) => ConvexCallLayer({
|
|
47246
48517
|
convexUrl: input.runtimeUrls.convexUrl,
|
|
48518
|
+
logToStderr: input.runtime === "node",
|
|
47247
48519
|
...input.applicationId === void 0 ? {} : { applicationId: input.applicationId },
|
|
47248
48520
|
...input.observation === void 0 ? {} : { observation: input.observation },
|
|
47249
48521
|
...input.convexClient === void 0 ? {} : { client: input.convexClient },
|
|
@@ -47365,7 +48637,7 @@ async function createProductionAdapters(input) {
|
|
|
47365
48637
|
...input.signal === void 0 ? {} : { signal: input.signal },
|
|
47366
48638
|
...input.resetSignerSession === void 0 ? {} : { resetSignerSession: input.resetSignerSession }
|
|
47367
48639
|
}));
|
|
47368
|
-
const applicationLayer = Layer.merge(portsLayer, optionalEngineeringTelemetryLayer(bootstrapResult.value.engineeringTelemetry, resolvedInput.value.runtime));
|
|
48640
|
+
const applicationLayer = Layer.merge(portsLayer, optionalEngineeringTelemetryLayer(bootstrapResult.value.engineeringTelemetry, resolvedInput.value.runtime, hostEngineeringPolicy(input.observability))).pipe(Layer.provideMerge(resolvedInput.value.runtime === "node" ? Layer.succeed(Logger.LogToStderr, true) : Layer.empty));
|
|
47369
48641
|
const context = await Effect.runPromise(Layer.buildWithScope(applicationLayer, scope));
|
|
47370
48642
|
const collected = await Effect.runPromise(collectProductionFlowPorts.pipe(Effect.provide(context)));
|
|
47371
48643
|
const indexerUrl = input.indexerUrl ?? bootstrapResult.value.indexerUrl;
|
|
@@ -47414,7 +48686,7 @@ function observeProductionConvexConnection(convexCall, context) {
|
|
|
47414
48686
|
return () => {};
|
|
47415
48687
|
}
|
|
47416
48688
|
}
|
|
47417
|
-
function optionalEngineeringTelemetryLayer(policy, runtime) {
|
|
48689
|
+
function optionalEngineeringTelemetryLayer(policy, runtime, hostPolicy) {
|
|
47418
48690
|
if (policy === void 0) return Layer.empty;
|
|
47419
48691
|
try {
|
|
47420
48692
|
return makeEngineeringTelemetryLayer({
|
|
@@ -47422,7 +48694,8 @@ function optionalEngineeringTelemetryLayer(policy, runtime) {
|
|
|
47422
48694
|
headers: { authorization: `Bearer ${policy.projectToken}` },
|
|
47423
48695
|
capxulEnv: policy.capxulEnv,
|
|
47424
48696
|
producer: runtime === "browser" ? "browser" : "server",
|
|
47425
|
-
sdkVersion: SDK_VERSION
|
|
48697
|
+
sdkVersion: SDK_VERSION,
|
|
48698
|
+
...hostPolicy
|
|
47426
48699
|
});
|
|
47427
48700
|
} catch {
|
|
47428
48701
|
return Layer.empty;
|
|
@@ -47517,7 +48790,7 @@ async function createCapxulClientWithSignerControls(input, controls) {
|
|
|
47517
48790
|
}
|
|
47518
48791
|
};
|
|
47519
48792
|
}
|
|
47520
|
-
const
|
|
48793
|
+
const ownedClient = withAdapterClose(assembleCapxulClient({
|
|
47521
48794
|
ports: adapters.value.ports,
|
|
47522
48795
|
bootstrap: adapters.value.bootstrap,
|
|
47523
48796
|
authCache: adapters.value.ports.authCache,
|
|
@@ -47538,8 +48811,7 @@ async function createCapxulClientWithSignerControls(input, controls) {
|
|
|
47538
48811
|
runSync: Effect.runSyncWith(adapters.value.context),
|
|
47539
48812
|
runPromise: Effect.runPromiseWith(adapters.value.context)
|
|
47540
48813
|
}
|
|
47541
|
-
});
|
|
47542
|
-
const upstreamClose = adapters.value.close;
|
|
48814
|
+
}), adapters.value.close);
|
|
47543
48815
|
const close = idempotentClose(async () => {
|
|
47544
48816
|
try {
|
|
47545
48817
|
if (signer !== void 0 && "resetSession" in signer) try {
|
|
@@ -47548,15 +48820,16 @@ async function createCapxulClientWithSignerControls(input, controls) {
|
|
|
47548
48820
|
throw signerFailure(signer.source, "resetSession", cause);
|
|
47549
48821
|
}
|
|
47550
48822
|
} finally {
|
|
47551
|
-
await
|
|
48823
|
+
await ownedClient._internal.close?.();
|
|
47552
48824
|
}
|
|
47553
48825
|
});
|
|
47554
48826
|
return {
|
|
47555
48827
|
ok: true,
|
|
47556
48828
|
value: {
|
|
47557
|
-
...
|
|
48829
|
+
...ownedClient,
|
|
48830
|
+
close: () => closeClientResources(close),
|
|
47558
48831
|
_internal: {
|
|
47559
|
-
...
|
|
48832
|
+
...ownedClient._internal,
|
|
47560
48833
|
close
|
|
47561
48834
|
}
|
|
47562
48835
|
}
|
|
@@ -47715,15 +48988,17 @@ function idempotentClose(close) {
|
|
|
47715
48988
|
* and Convex see one session with one scope.
|
|
47716
48989
|
*/
|
|
47717
48990
|
function productionIndexerReadPort(input, ports, observation) {
|
|
48991
|
+
if (input.activityReadSource === "convex") return void 0;
|
|
47718
48992
|
if (input.indexerUrl === void 0 || input.indexerUrl === "") return void 0;
|
|
47719
48993
|
return new PonderIndexerAdapter({
|
|
47720
48994
|
baseUrl: normalizeHttpUrl("indexerUrl", input.indexerUrl),
|
|
47721
|
-
token: async ({ forceRefreshToken }) => {
|
|
48995
|
+
token: async ({ forceRefreshToken, signal }) => {
|
|
48996
|
+
const tokenSignal = input.signal === void 0 ? signal : signal === void 0 ? input.signal : AbortSignal.any([input.signal, signal]);
|
|
47722
48997
|
const token = await Effect.runPromise(Effect.result(ports.authClient.getConvexJwt({
|
|
47723
48998
|
forceRefresh: forceRefreshToken,
|
|
47724
|
-
...
|
|
48999
|
+
...tokenSignal === void 0 ? {} : { signal: tokenSignal }
|
|
47725
49000
|
})));
|
|
47726
|
-
if (Result.isFailure(token))
|
|
49001
|
+
if (Result.isFailure(token)) throw toPublicError(token.failure, "getConvexJwt");
|
|
47727
49002
|
return String(token.success.token);
|
|
47728
49003
|
},
|
|
47729
49004
|
...input.fetch === void 0 ? {} : { fetch: input.fetch },
|
|
@@ -48341,7 +49616,7 @@ function stdioIdentity(env = process.env, options = {}) {
|
|
|
48341
49616
|
}
|
|
48342
49617
|
//#endregion
|
|
48343
49618
|
//#region package.json
|
|
48344
|
-
var version = "4.
|
|
49619
|
+
var version = "4.20.0-beta.1";
|
|
48345
49620
|
//#endregion
|
|
48346
49621
|
//#region src/deps.ts
|
|
48347
49622
|
const NO_IDENTITY = async () => void 0;
|