@capxul/mcp 4.20.0-beta.1 → 4.20.0-beta.3
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 +1147 -215
- package/package.json +3 -3
package/dist/main.mjs
CHANGED
|
@@ -8,8 +8,8 @@ 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, 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";
|
|
11
|
+
import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, Layer, Logger, Metric, Option, Queue, Ref, References, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stream, Tracer } from "effect";
|
|
12
|
+
import { FetchHttpClient, Headers, HttpBody, HttpClient, HttpClientError, HttpClientResponse, HttpTraceContext } from "effect/unstable/http";
|
|
13
13
|
import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
|
|
14
14
|
import { resolve } from "path";
|
|
15
15
|
import util from "util";
|
|
@@ -99,7 +99,12 @@ const CREDENTIAL_FIELDS = /* @__PURE__ */ new Set([
|
|
|
99
99
|
"authcode",
|
|
100
100
|
"authorizationcode",
|
|
101
101
|
"oauthcode",
|
|
102
|
-
"codeverifier"
|
|
102
|
+
"codeverifier",
|
|
103
|
+
"devicecode",
|
|
104
|
+
"usercode",
|
|
105
|
+
"continuitytoken",
|
|
106
|
+
"refreshattemptid",
|
|
107
|
+
"revocationtoken"
|
|
103
108
|
]);
|
|
104
109
|
/** Match credential fields by meaning, without hiding token addresses or replay IDs. */
|
|
105
110
|
function isCredentialField(name, context) {
|
|
@@ -858,6 +863,8 @@ const COUNTRY_CODE_RE = /^[A-Z]{2}$/;
|
|
|
858
863
|
const ACCOUNT_ID_RE = /^account_[0-9A-Za-z]+$/;
|
|
859
864
|
const PARTY_ID_RE$1 = /^party_[0-9A-Za-z]+$/;
|
|
860
865
|
const APP_ID_RE = /^app_[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
866
|
+
const CLIENT_REQUEST_ID_RE = /^creq_[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
867
|
+
const CLIENT_GRANT_ID_RE = /^cgrant_[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
861
868
|
const TX_HASH_RE = /^0x[0-9a-f]{64}$/i;
|
|
862
869
|
const WEI_RE = /^[0-9]+$/;
|
|
863
870
|
Math.floor(Number.MAX_SAFE_INTEGER / 1e3);
|
|
@@ -8180,6 +8187,92 @@ const ContactActionProps = {
|
|
|
8180
8187
|
party_id: OptionalString,
|
|
8181
8188
|
reason_code: OptionalReasonCode
|
|
8182
8189
|
};
|
|
8190
|
+
/** One completed online CLI diagnostic. No command input or provider text. */
|
|
8191
|
+
const CLI_COMMAND_NAMES = [
|
|
8192
|
+
"capxul",
|
|
8193
|
+
"doctor",
|
|
8194
|
+
"telemetry",
|
|
8195
|
+
"telemetry.status",
|
|
8196
|
+
"telemetry.enable",
|
|
8197
|
+
"telemetry.disable",
|
|
8198
|
+
"unknown"
|
|
8199
|
+
];
|
|
8200
|
+
const CLI_CAPABILITIES = [
|
|
8201
|
+
"cli",
|
|
8202
|
+
"diagnostics",
|
|
8203
|
+
"collection"
|
|
8204
|
+
];
|
|
8205
|
+
const CLI_INVOCATION_KINDS = [
|
|
8206
|
+
"command",
|
|
8207
|
+
"help",
|
|
8208
|
+
"version",
|
|
8209
|
+
"completion",
|
|
8210
|
+
"parse_refusal",
|
|
8211
|
+
"collection_control"
|
|
8212
|
+
];
|
|
8213
|
+
const CliRelease = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/u));
|
|
8214
|
+
const CliInvocationProps = {
|
|
8215
|
+
...TelemetryEnvelopeProps,
|
|
8216
|
+
schema_version: Schema.Literal(1),
|
|
8217
|
+
command: Schema.Literals(CLI_COMMAND_NAMES),
|
|
8218
|
+
capability: Schema.Literals(CLI_CAPABILITIES),
|
|
8219
|
+
invocation_kind: Schema.Literals(CLI_INVOCATION_KINDS),
|
|
8220
|
+
invocation_id: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u)),
|
|
8221
|
+
cli_identity_kind: Schema.optional(Schema.Literal("anonymous")),
|
|
8222
|
+
anonymous_id: Schema.optional(Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u))),
|
|
8223
|
+
occurred_at: Schema.Number,
|
|
8224
|
+
cli_version: CliRelease,
|
|
8225
|
+
sdk_version: CliRelease,
|
|
8226
|
+
release: CliRelease,
|
|
8227
|
+
platform: Schema.Literals([
|
|
8228
|
+
"darwin",
|
|
8229
|
+
"linux",
|
|
8230
|
+
"unknown"
|
|
8231
|
+
]),
|
|
8232
|
+
architecture: Schema.Literals([
|
|
8233
|
+
"arm64",
|
|
8234
|
+
"x64",
|
|
8235
|
+
"unknown"
|
|
8236
|
+
]),
|
|
8237
|
+
ci: Schema.Boolean,
|
|
8238
|
+
tty: Schema.Boolean,
|
|
8239
|
+
output_mode: Schema.Literals(["human", "json"])
|
|
8240
|
+
};
|
|
8241
|
+
Schema.Struct({
|
|
8242
|
+
name: Schema.Literal("cli_first_used"),
|
|
8243
|
+
props: Schema.Struct(CliInvocationProps)
|
|
8244
|
+
});
|
|
8245
|
+
Schema.Struct({
|
|
8246
|
+
name: Schema.Literal("cli_command_started"),
|
|
8247
|
+
props: Schema.Struct({
|
|
8248
|
+
...CliInvocationProps,
|
|
8249
|
+
invocation_kind: Schema.Literals([
|
|
8250
|
+
"command",
|
|
8251
|
+
"help",
|
|
8252
|
+
"version"
|
|
8253
|
+
])
|
|
8254
|
+
})
|
|
8255
|
+
});
|
|
8256
|
+
Schema.Struct({
|
|
8257
|
+
name: Schema.Literal("cli_command_completed"),
|
|
8258
|
+
props: Schema.Struct({
|
|
8259
|
+
...CliInvocationProps,
|
|
8260
|
+
outcome: Schema.Literals([
|
|
8261
|
+
"succeeded",
|
|
8262
|
+
"refused",
|
|
8263
|
+
"failed",
|
|
8264
|
+
"cancelled"
|
|
8265
|
+
]),
|
|
8266
|
+
duration_ms: Schema.Number,
|
|
8267
|
+
error_code: Schema.optional(Schema.Literals([
|
|
8268
|
+
...CAPXUL_ERROR_CODES,
|
|
8269
|
+
"CLI_USAGE",
|
|
8270
|
+
"CLI_CONFIG",
|
|
8271
|
+
"CLI_STORAGE",
|
|
8272
|
+
"CLI_DEFECT"
|
|
8273
|
+
]))
|
|
8274
|
+
})
|
|
8275
|
+
});
|
|
8183
8276
|
Schema.Struct({
|
|
8184
8277
|
name: Schema.Literal("cli_diagnostic_completed"),
|
|
8185
8278
|
props: Schema.Struct({
|
|
@@ -9045,6 +9138,30 @@ const PAYMENT_DOCUMENT_KINDS = [
|
|
|
9045
9138
|
"receipt",
|
|
9046
9139
|
"withdrawal"
|
|
9047
9140
|
];
|
|
9141
|
+
/** Native browser projection, distinct from the issuer's persisted request state. */
|
|
9142
|
+
const CLIENT_AUTHORIZATION_PHASE = {
|
|
9143
|
+
OTP_REQUIRED: "otp_required",
|
|
9144
|
+
REVIEW: "review",
|
|
9145
|
+
PROCESSING: "processing",
|
|
9146
|
+
CONNECTED: "connected",
|
|
9147
|
+
REFUSED: "refused"
|
|
9148
|
+
};
|
|
9149
|
+
CLIENT_AUTHORIZATION_PHASE.OTP_REQUIRED, CLIENT_AUTHORIZATION_PHASE.REVIEW, CLIENT_AUTHORIZATION_PHASE.PROCESSING, CLIENT_AUTHORIZATION_PHASE.CONNECTED, CLIENT_AUTHORIZATION_PHASE.REFUSED;
|
|
9150
|
+
/** Closed native refusals; existing Capxul error codes retain their own meaning. */
|
|
9151
|
+
const CLIENT_AUTHORIZATION_REFUSALS = [
|
|
9152
|
+
"signup_required",
|
|
9153
|
+
"setup_required",
|
|
9154
|
+
"already_signed_up",
|
|
9155
|
+
"identity_mismatch",
|
|
9156
|
+
"invalid_request",
|
|
9157
|
+
"request_expired",
|
|
9158
|
+
"request_denied",
|
|
9159
|
+
"cancelled",
|
|
9160
|
+
"grant_revoked",
|
|
9161
|
+
"grant_expired",
|
|
9162
|
+
"refresh_reused",
|
|
9163
|
+
"revoke_unconfirmed"
|
|
9164
|
+
];
|
|
9048
9165
|
//#endregion
|
|
9049
9166
|
//#region ../../packages/wire/src/financial-ops.ts
|
|
9050
9167
|
const MINOR_UNIT_STRING_RE = /^[0-9]+$/;
|
|
@@ -10746,6 +10863,251 @@ function isSafeField(field, value) {
|
|
|
10746
10863
|
return value.length > 0 && value.length <= rule.maxLength && value === value.trim() && !value.includes("://") && !containsSensitiveMaterial(value) && rule.pattern.test(value);
|
|
10747
10864
|
}
|
|
10748
10865
|
//#endregion
|
|
10866
|
+
//#region ../../packages/wire/src/client-authorization.ts
|
|
10867
|
+
const NATIVE_CLIENT_ID = "capxul-cli";
|
|
10868
|
+
const NATIVE_CLIENT_SCOPE = "account:read";
|
|
10869
|
+
const NATIVE_CLIENT_LIMITS = {
|
|
10870
|
+
accessMs: 36e5,
|
|
10871
|
+
renewalMs: 2592e6,
|
|
10872
|
+
absoluteMs: 7776e6,
|
|
10873
|
+
requestMs: 6e5,
|
|
10874
|
+
pollSeconds: 5,
|
|
10875
|
+
imageBytes: 5242880
|
|
10876
|
+
};
|
|
10877
|
+
const strict = { parseOptions: { onExcessProperty: "error" } };
|
|
10878
|
+
const text$2 = (max) => Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(max));
|
|
10879
|
+
const nonNegativeInt = Schema.Number.check(Schema.makeFilter((n) => Number.isSafeInteger(n) && n >= 0));
|
|
10880
|
+
const normalize = (f) => Schema.String.pipe(Schema.decodeTo(Schema.String, {
|
|
10881
|
+
decode: SchemaGetter.transform(f),
|
|
10882
|
+
encode: SchemaGetter.transform((s) => s)
|
|
10883
|
+
}));
|
|
10884
|
+
const ClientRequestIdSchema = Schema.String.pipe(Schema.refine((s) => CLIENT_REQUEST_ID_RE.test(s)));
|
|
10885
|
+
const ClientGrantIdSchema = Schema.String.pipe(Schema.refine((s) => CLIENT_GRANT_ID_RE.test(s)));
|
|
10886
|
+
const authUserId = Schema.String.pipe(Schema.refine((s) => s.length > 0));
|
|
10887
|
+
const keyId = Schema.String.pipe(Schema.refine((s) => s.length > 0));
|
|
10888
|
+
const email$1 = normalize((s) => s.toLowerCase()).pipe(Schema.refine((s) => EMAIL_RE$1.test(s))).check(Schema.isMaxLength(254));
|
|
10889
|
+
const handle$1 = Schema.String.pipe(Schema.refine((s) => HANDLE_RE$1.test(s)));
|
|
10890
|
+
const country = normalize((s) => s.toUpperCase()).pipe(Schema.refine((s) => COUNTRY_CODE_RE.test(s)));
|
|
10891
|
+
const credential = Schema.RedactedFromValue(Schema.String.check(Schema.isMinLength(32), Schema.isMaxLength(8192), Schema.isPattern(/^[A-Za-z0-9._~-]+$/u)), { label: "native authorization credential" });
|
|
10892
|
+
const otp = Schema.RedactedFromValue(Schema.String.check(Schema.isPattern(/^[0-9]{6}$/u)), { label: "OTP" });
|
|
10893
|
+
const scopes = Schema.Tuple([Schema.Literal(NATIVE_CLIENT_SCOPE)]);
|
|
10894
|
+
/** Exact HTTPS origin, no credentials/path/query and no retired cloud deployment. */
|
|
10895
|
+
const NativeHttpsOriginSchema = Schema.String.check(Schema.makeFilter((value) => {
|
|
10896
|
+
try {
|
|
10897
|
+
const url = new URL(value);
|
|
10898
|
+
const host = url.hostname.toLowerCase().replace(/\.$/u, "");
|
|
10899
|
+
return url.protocol === "https:" && value === url.origin && !url.username && !url.password && !url.search && !url.hash && host !== "convex.cloud" && !host.endsWith(".convex.cloud") && host !== "convex.site" && !host.endsWith(".convex.site");
|
|
10900
|
+
} catch {
|
|
10901
|
+
return false;
|
|
10902
|
+
}
|
|
10903
|
+
}, { message: "must be a canonical credential-free HTTPS origin outside retired Convex cloud hosts" }));
|
|
10904
|
+
const NativeClientConfigurationSchema = Schema.Struct({
|
|
10905
|
+
clientId: Schema.Literal(NATIVE_CLIENT_ID),
|
|
10906
|
+
applicationId: AppIdSchema,
|
|
10907
|
+
keyId,
|
|
10908
|
+
environment: Schema.Literals([
|
|
10909
|
+
"development",
|
|
10910
|
+
"staging",
|
|
10911
|
+
"production"
|
|
10912
|
+
]),
|
|
10913
|
+
keyEnvironment: Schema.Literals(["test", "live"]),
|
|
10914
|
+
issuer: NativeHttpsOriginSchema,
|
|
10915
|
+
verificationOrigin: NativeHttpsOriginSchema
|
|
10916
|
+
}).annotate(strict).check(Schema.makeFilter((c) => c.keyEnvironment === (c.environment === "production" ? "live" : "test"), { message: "key environment must match the configured deployment" })).annotate(strict);
|
|
10917
|
+
const NativeSignupProfileSchema = Schema.Struct({
|
|
10918
|
+
displayName: normalize((s) => s.trim()).check(Schema.isMinLength(1), Schema.isMaxLength(200)),
|
|
10919
|
+
country,
|
|
10920
|
+
handle: handle$1,
|
|
10921
|
+
payoutAddresses: Schema.optional(Schema.Array(Schema.Struct({
|
|
10922
|
+
chain: Schema.Literals([
|
|
10923
|
+
"evm",
|
|
10924
|
+
"solana",
|
|
10925
|
+
"starknet"
|
|
10926
|
+
]),
|
|
10927
|
+
address: text$2(256)
|
|
10928
|
+
}).annotate(strict)).check(Schema.isMaxLength(10))),
|
|
10929
|
+
image: Schema.optional(Schema.Struct({
|
|
10930
|
+
mediaType: Schema.Literals([
|
|
10931
|
+
"image/jpeg",
|
|
10932
|
+
"image/png",
|
|
10933
|
+
"image/webp"
|
|
10934
|
+
]),
|
|
10935
|
+
byteLength: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
10936
|
+
minimum: 1,
|
|
10937
|
+
maximum: NATIVE_CLIENT_LIMITS.imageBytes
|
|
10938
|
+
})),
|
|
10939
|
+
sha256: Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/u))
|
|
10940
|
+
}).annotate(strict))
|
|
10941
|
+
}).annotate(strict);
|
|
10942
|
+
const ClientAuthorizationIntentSchema = Schema.Union([Schema.Struct({ mode: Schema.Literal("login") }).annotate(strict), Schema.Struct({
|
|
10943
|
+
mode: Schema.Literal("signup"),
|
|
10944
|
+
profile: NativeSignupProfileSchema
|
|
10945
|
+
}).annotate(strict)]).annotate(strict);
|
|
10946
|
+
Schema.Struct({
|
|
10947
|
+
clientId: Schema.Literal(NATIVE_CLIENT_ID),
|
|
10948
|
+
email: email$1,
|
|
10949
|
+
intent: ClientAuthorizationIntentSchema,
|
|
10950
|
+
waitMs: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
10951
|
+
minimum: 1,
|
|
10952
|
+
maximum: NATIVE_CLIENT_LIMITS.requestMs
|
|
10953
|
+
})),
|
|
10954
|
+
continuityToken: Schema.optional(credential)
|
|
10955
|
+
}).annotate(strict);
|
|
10956
|
+
const request = {
|
|
10957
|
+
requestId: ClientRequestIdSchema,
|
|
10958
|
+
revision: nonNegativeInt,
|
|
10959
|
+
expiresAt: EpochMsSchema
|
|
10960
|
+
};
|
|
10961
|
+
const principal = {
|
|
10962
|
+
authUserId,
|
|
10963
|
+
email: email$1
|
|
10964
|
+
};
|
|
10965
|
+
const profileSummary = {
|
|
10966
|
+
displayName: text$2(200),
|
|
10967
|
+
handle: handle$1,
|
|
10968
|
+
country
|
|
10969
|
+
};
|
|
10970
|
+
Schema.Union([
|
|
10971
|
+
Schema.Struct({
|
|
10972
|
+
...request,
|
|
10973
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.OTP_REQUIRED),
|
|
10974
|
+
email: email$1,
|
|
10975
|
+
resendAt: EpochMsSchema
|
|
10976
|
+
}).annotate(strict),
|
|
10977
|
+
Schema.Struct({
|
|
10978
|
+
...request,
|
|
10979
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.REVIEW),
|
|
10980
|
+
...principal,
|
|
10981
|
+
clientLabel: Schema.Literal("Capxul CLI"),
|
|
10982
|
+
scopes,
|
|
10983
|
+
intent: ClientAuthorizationIntentSchema,
|
|
10984
|
+
setupState: Schema.Literals([
|
|
10985
|
+
"not_required",
|
|
10986
|
+
"new",
|
|
10987
|
+
"resumable"
|
|
10988
|
+
])
|
|
10989
|
+
}).annotate(strict).check(Schema.makeFilter((v) => v.intent.mode === "login" === (v.setupState === "not_required"), { message: "login review cannot permit account setup" })),
|
|
10990
|
+
Schema.Struct({
|
|
10991
|
+
...request,
|
|
10992
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.PROCESSING),
|
|
10993
|
+
...principal,
|
|
10994
|
+
purpose: Schema.Literals(["login", "signup"]),
|
|
10995
|
+
step: Schema.Literals([
|
|
10996
|
+
"profile",
|
|
10997
|
+
"wallet",
|
|
10998
|
+
"account",
|
|
10999
|
+
"delivery"
|
|
11000
|
+
])
|
|
11001
|
+
}).annotate(strict).check(Schema.makeFilter((v) => v.purpose === "signup" || v.step === "delivery", { message: "login may wait for delivery but cannot enter signup processing" })),
|
|
11002
|
+
Schema.Struct({
|
|
11003
|
+
...request,
|
|
11004
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.CONNECTED),
|
|
11005
|
+
...principal,
|
|
11006
|
+
...profileSummary,
|
|
11007
|
+
accountId: AccountIdSchema,
|
|
11008
|
+
grantId: ClientGrantIdSchema
|
|
11009
|
+
}).annotate(strict),
|
|
11010
|
+
Schema.Struct({
|
|
11011
|
+
...request,
|
|
11012
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.REFUSED),
|
|
11013
|
+
reason: Schema.Literals(CLIENT_AUTHORIZATION_REFUSALS),
|
|
11014
|
+
code: Schema.Literals(CAPXUL_ERROR_CODES),
|
|
11015
|
+
field: Schema.optional(Schema.Literals([
|
|
11016
|
+
"email",
|
|
11017
|
+
"displayName",
|
|
11018
|
+
"country",
|
|
11019
|
+
"handle",
|
|
11020
|
+
"image",
|
|
11021
|
+
"payoutAddresses"
|
|
11022
|
+
])),
|
|
11023
|
+
retryable: Schema.Boolean
|
|
11024
|
+
}).annotate(strict)
|
|
11025
|
+
]).annotate(strict);
|
|
11026
|
+
Schema.Struct({
|
|
11027
|
+
requestId: ClientRequestIdSchema,
|
|
11028
|
+
revision: nonNegativeInt
|
|
11029
|
+
}).annotate(strict);
|
|
11030
|
+
Schema.Struct({
|
|
11031
|
+
requestId: ClientRequestIdSchema,
|
|
11032
|
+
code: otp
|
|
11033
|
+
}).annotate(strict);
|
|
11034
|
+
Schema.Struct({
|
|
11035
|
+
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
11036
|
+
grant_type: Schema.Literal("refresh_token"),
|
|
11037
|
+
refresh_token: credential,
|
|
11038
|
+
refreshAttemptId: Schema.RedactedFromValue(Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{32,128}$/u)), { label: "refresh attempt" })
|
|
11039
|
+
}).annotate(strict);
|
|
11040
|
+
Schema.Struct({
|
|
11041
|
+
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
11042
|
+
applicationId: AppIdSchema,
|
|
11043
|
+
resource: text$2(2048),
|
|
11044
|
+
token_type: Schema.Literal("Bearer"),
|
|
11045
|
+
access_token: credential,
|
|
11046
|
+
refresh_token: credential,
|
|
11047
|
+
scope: Schema.Literal(NATIVE_CLIENT_SCOPE),
|
|
11048
|
+
expires_in: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
11049
|
+
minimum: 1,
|
|
11050
|
+
maximum: NATIVE_CLIENT_LIMITS.accessMs / 1e3
|
|
11051
|
+
})),
|
|
11052
|
+
grantId: ClientGrantIdSchema,
|
|
11053
|
+
...principal,
|
|
11054
|
+
accountId: AccountIdSchema,
|
|
11055
|
+
issuedAt: EpochMsSchema,
|
|
11056
|
+
grantCreatedAt: EpochMsSchema,
|
|
11057
|
+
accessExpiresAt: EpochMsSchema,
|
|
11058
|
+
renewalExpiresAt: EpochMsSchema,
|
|
11059
|
+
absoluteExpiresAt: EpochMsSchema,
|
|
11060
|
+
revision: nonNegativeInt
|
|
11061
|
+
}).annotate(strict).check(Schema.makeFilter((t) => t.grantCreatedAt <= t.issuedAt && t.absoluteExpiresAt - t.grantCreatedAt === NATIVE_CLIENT_LIMITS.absoluteMs && t.renewalExpiresAt <= Math.min(t.issuedAt + NATIVE_CLIENT_LIMITS.renewalMs, t.absoluteExpiresAt) && t.accessExpiresAt <= Math.min(t.issuedAt + NATIVE_CLIENT_LIMITS.accessMs, t.renewalExpiresAt) && t.expires_in === Math.floor((t.accessExpiresAt - t.issuedAt) / 1e3), { message: "native credentials must obey the approved access, renewal and absolute deadlines" })).annotate(strict);
|
|
11062
|
+
/** One endpoint mapping; consumers cannot substitute callback or resource URLs. */
|
|
11063
|
+
function nativeClientEndpoints(config) {
|
|
11064
|
+
const resource = `${config.issuer}/api/auth/native`;
|
|
11065
|
+
return {
|
|
11066
|
+
resource,
|
|
11067
|
+
device_authorization_endpoint: `${resource}/device/code`,
|
|
11068
|
+
token_endpoint: `${resource}/token`,
|
|
11069
|
+
revocation_endpoint: `${resource}/revoke`,
|
|
11070
|
+
session_endpoint: `${resource}/session`,
|
|
11071
|
+
verification_uri: `${config.verificationOrigin}/connect`
|
|
11072
|
+
};
|
|
11073
|
+
}
|
|
11074
|
+
Schema.Struct({
|
|
11075
|
+
protocol: Schema.Literal("capxul.client-authorization"),
|
|
11076
|
+
version: Schema.Literal(1),
|
|
11077
|
+
configuration: NativeClientConfigurationSchema,
|
|
11078
|
+
scopes_supported: scopes,
|
|
11079
|
+
grant_types_supported: Schema.Tuple([Schema.Literal("urn:ietf:params:oauth:grant-type:device_code"), Schema.Literal("refresh_token")]),
|
|
11080
|
+
resource: text$2(2048),
|
|
11081
|
+
device_authorization_endpoint: text$2(2048),
|
|
11082
|
+
token_endpoint: text$2(2048),
|
|
11083
|
+
revocation_endpoint: text$2(2048),
|
|
11084
|
+
session_endpoint: text$2(2048),
|
|
11085
|
+
verification_uri: text$2(2048)
|
|
11086
|
+
}).annotate(strict).check(Schema.makeFilter((m) => {
|
|
11087
|
+
const expected = nativeClientEndpoints(m.configuration);
|
|
11088
|
+
return m.resource === expected.resource && m.device_authorization_endpoint === expected.device_authorization_endpoint && m.token_endpoint === expected.token_endpoint && m.revocation_endpoint === expected.revocation_endpoint && m.session_endpoint === expected.session_endpoint && m.verification_uri === expected.verification_uri;
|
|
11089
|
+
}, { message: "native endpoints must match their configured issuer and verification origin" })).annotate(strict);
|
|
11090
|
+
Schema.Struct({
|
|
11091
|
+
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
11092
|
+
grant_type: Schema.Literal("urn:ietf:params:oauth:grant-type:device_code"),
|
|
11093
|
+
device_code: credential
|
|
11094
|
+
}).annotate(strict);
|
|
11095
|
+
Schema.Struct({
|
|
11096
|
+
requestId: ClientRequestIdSchema,
|
|
11097
|
+
device_code: credential,
|
|
11098
|
+
user_code: Schema.RedactedFromValue(Schema.String.check(Schema.isPattern(/^[A-Z0-9]{4}-[A-Z0-9]{4}$/u)), { label: "device user code" }),
|
|
11099
|
+
continuityToken: credential,
|
|
11100
|
+
verification_uri: text$2(2048),
|
|
11101
|
+
expires_in: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
11102
|
+
minimum: 1,
|
|
11103
|
+
maximum: NATIVE_CLIENT_LIMITS.requestMs / 1e3
|
|
11104
|
+
})),
|
|
11105
|
+
interval: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
11106
|
+
minimum: NATIVE_CLIENT_LIMITS.pollSeconds,
|
|
11107
|
+
maximum: NATIVE_CLIENT_LIMITS.requestMs / 1e3
|
|
11108
|
+
}))
|
|
11109
|
+
}).annotate(strict);
|
|
11110
|
+
//#endregion
|
|
10749
11111
|
//#region ../../packages/sdk/src/internal/invocation-observation.ts
|
|
10750
11112
|
const INVOCATION_OBSERVATION = Symbol("capxul.invocation-observation");
|
|
10751
11113
|
const FAILURE_INVOCATION_SNAPSHOT = Symbol("capxul.failure-invocation-snapshot");
|
|
@@ -12609,6 +12971,9 @@ const moneyExecutionContract = {
|
|
|
12609
12971
|
//#region ../../packages/sdk/src/ports/indexer-read.ts
|
|
12610
12972
|
/** The indexer's own page bound. Exceeding it is a caller defect, not a refusal. */
|
|
12611
12973
|
const INDEXER_MAX_LIMIT = 1e3;
|
|
12974
|
+
function validTime(value) {
|
|
12975
|
+
return Number.isSafeInteger(value) && value >= 0 && value <= Math.floor(Number.MAX_SAFE_INTEGER / 1e3);
|
|
12976
|
+
}
|
|
12612
12977
|
const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
|
|
12613
12978
|
/**
|
|
12614
12979
|
* Refuse a page the indexer would refuse, before any implementation spends a
|
|
@@ -12616,12 +12981,21 @@ const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
|
|
|
12616
12981
|
* against the hermetic adapter cannot pass on input production rejects. Throws
|
|
12617
12982
|
* a `CapxulError`; callers convert it to an `IndexerReadError`.
|
|
12618
12983
|
*/
|
|
12984
|
+
function assertEventLookup(input, id) {
|
|
12985
|
+
if (input.limit !== 1 || (input.offset ?? 0) !== 0 || input.timeline !== void 0 || input.settlements !== void 0 || !/^[1-9][0-9]{0,9}:0x[0-9a-f]{64}:[0-9]{1,10}$/.test(id)) throw Errors.invalidInput("eventId", "must identify one logical event without another cursor");
|
|
12986
|
+
}
|
|
12619
12987
|
function assertIndexerPage(input) {
|
|
12620
12988
|
const safe = String(input.safe).toLowerCase();
|
|
12621
12989
|
if (!LOWER_CASE_ADDRESS.test(safe)) throw Errors.invalidInput("safe", "must be a lower-case EVM address");
|
|
12622
12990
|
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
12991
|
const offset = input.offset ?? 0;
|
|
12624
12992
|
if (!Number.isSafeInteger(offset) || offset < 0) throw Errors.invalidInput("offset", "must be a non-negative integer");
|
|
12993
|
+
const timeline = input.timeline;
|
|
12994
|
+
if (input.eventId !== void 0) assertEventLookup(input, input.eventId);
|
|
12995
|
+
if (input.settlements !== void 0 && (offset !== 0 || timeline !== void 0 || input.settlements.length < 1 || input.settlements.length > 50 || !input.settlements.every((id) => /^0x[0-9a-f]{64}$/.test(id)))) throw Errors.invalidInput("settlements", "must hold 1 to 50 settlement IDs without another cursor");
|
|
12996
|
+
if (timeline !== void 0) {
|
|
12997
|
+
if (offset !== 0 || !validTime(timeline.from) || !validTime(timeline.to) || timeline.from > timeline.to || timeline.before !== void 0 && (!validTime(timeline.before.timestamp) || !/^[1-9][0-9]{0,9}:0x[0-9a-f]{64}:[0-9]{1,10}$/.test(timeline.before.id))) throw Errors.invalidInput("timeline", "must be a bounded time window with a logical event cursor and no offset");
|
|
12998
|
+
}
|
|
12625
12999
|
return safe;
|
|
12626
13000
|
}
|
|
12627
13001
|
var IndexerReadError = class extends Data.TaggedError("IndexerReadError") {};
|
|
@@ -12651,20 +13025,6 @@ function directionFor(safe, transfer) {
|
|
|
12651
13025
|
if (from === safe && to === safe) return "self";
|
|
12652
13026
|
return to === safe ? "in" : "out";
|
|
12653
13027
|
}
|
|
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
13028
|
function withAnnotation(item, annotation) {
|
|
12669
13029
|
return annotation?.counterpartyLabel === void 0 ? item : {
|
|
12670
13030
|
...item,
|
|
@@ -12675,10 +13035,14 @@ function withAnnotation(item, annotation) {
|
|
|
12675
13035
|
* An indexed settlement confirms the intent. A missing row can be outside
|
|
12676
13036
|
* this page or still backfilling; only the correction owner can prove rollback.
|
|
12677
13037
|
*/
|
|
12678
|
-
function confirmPayment(intent, chain) {
|
|
12679
|
-
if (chain !== void 0) return {
|
|
13038
|
+
function confirmPayment(intent, chain, expected) {
|
|
13039
|
+
if (chain !== void 0 && matchesPaymentFact(chain, expected)) return {
|
|
12680
13040
|
...intent,
|
|
12681
13041
|
status: "settled",
|
|
13042
|
+
...intent.execution === void 0 ? {} : { execution: {
|
|
13043
|
+
status: "settled",
|
|
13044
|
+
retryRequired: false
|
|
13045
|
+
} },
|
|
12682
13046
|
receipt: {
|
|
12683
13047
|
chainId: chain.chainId,
|
|
12684
13048
|
transactionHash: chain.txHash
|
|
@@ -12687,16 +13051,22 @@ function confirmPayment(intent, chain) {
|
|
|
12687
13051
|
};
|
|
12688
13052
|
return intent;
|
|
12689
13053
|
}
|
|
13054
|
+
function matchesPaymentFact(chain, expected) {
|
|
13055
|
+
return chain !== void 0 && expected !== void 0 && chain.chainId === expected.chainId && chain.contract.toLowerCase() === expected.contract.toLowerCase() && chain.sender.toLowerCase() === expected.sender.toLowerCase() && chain.recipient.toLowerCase() === expected.recipient.toLowerCase() && chain.token.toLowerCase() === expected.token.toLowerCase() && chain.amount.toString() === expected.rawAmount && chain.documentHash.toLowerCase() === expected.documentHash.toLowerCase() && chain.kind === expected.kind;
|
|
13056
|
+
}
|
|
12690
13057
|
/**
|
|
12691
13058
|
* One unclaimed Transfer as an Activity row, or `null` when this SDK cannot
|
|
12692
13059
|
* denominate its asset. The indexer serves only configured assets, so a row
|
|
12693
13060
|
* the registry does not know means the SDK and that deployment disagree; it is
|
|
12694
13061
|
* dropped rather than shown with a guessed currency.
|
|
12695
13062
|
*/
|
|
13063
|
+
function isActivityVisible(item) {
|
|
13064
|
+
return !(item.kind === "payment" && item.direction === "in" && item.execution?.notSent);
|
|
13065
|
+
}
|
|
12696
13066
|
function transferItem(safe, transfer, annotation) {
|
|
12697
13067
|
const asset = configuredMoneyAssetById(transfer.assetId);
|
|
12698
13068
|
if (asset === null) return null;
|
|
12699
|
-
const direction = directionFor(safe, transfer);
|
|
13069
|
+
const direction = directionFor(safe.toLowerCase(), transfer);
|
|
12700
13070
|
const counterparty = direction === "in" ? transfer.from : transfer.to;
|
|
12701
13071
|
const at = blockMillis(transfer);
|
|
12702
13072
|
return withAnnotation({
|
|
@@ -12718,47 +13088,6 @@ function transferItem(safe, transfer, annotation) {
|
|
|
12718
13088
|
updatedAt: at
|
|
12719
13089
|
}, annotation);
|
|
12720
13090
|
}
|
|
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
13091
|
/**
|
|
12763
13092
|
* Money in, money out and the pending share, one bucket per currency and
|
|
12764
13093
|
* precision. Two assets that peg to the same currency at different precision
|
|
@@ -12777,7 +13106,7 @@ function summarizeItems(items) {
|
|
|
12777
13106
|
};
|
|
12778
13107
|
const raw = rawUnits(item.amount.value, item.amount.decimals);
|
|
12779
13108
|
if (item.kind === "payment" && item.status !== "settled") {
|
|
12780
|
-
if (item.direction === "in" && item.status !== "cancelled" && item.status !== "failed") bucket.pendingIn += raw;
|
|
13109
|
+
if (item.direction === "in" && item.status !== "cancelled" && item.status !== "failed" && !item.execution?.notSent) bucket.pendingIn += raw;
|
|
12781
13110
|
} else if (item.direction === "in") bucket.in += raw;
|
|
12782
13111
|
else if (item.direction === "out") bucket.out += raw;
|
|
12783
13112
|
buckets.set(key, bucket);
|
|
@@ -12800,179 +13129,412 @@ function rawUnits(value, decimals) {
|
|
|
12800
13129
|
}
|
|
12801
13130
|
//#endregion
|
|
12802
13131
|
//#region ../../packages/sdk/src/surface/activity-read.ts
|
|
12803
|
-
|
|
12804
|
-
const INTENT_WINDOW = 100;
|
|
12805
|
-
/** movement/annotations:overlay bounds each identifier array to 200. */
|
|
13132
|
+
const BATCH = 100;
|
|
12806
13133
|
const MAX_OVERLAY_IDS = 200;
|
|
12807
|
-
|
|
12808
|
-
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
|
|
12812
|
-
|
|
12813
|
-
|
|
12814
|
-
|
|
12815
|
-
|
|
12816
|
-
|
|
13134
|
+
function actorKey(actor) {
|
|
13135
|
+
return actor.kind === "account" ? `account:${actor.accountId}` : `organization:${actor.orgId}`;
|
|
13136
|
+
}
|
|
13137
|
+
function scopeKey(scope) {
|
|
13138
|
+
return `${scope.principalAccountId ?? "legacy"}|${actorKey(scope.actor)}|${scope.safe?.toLowerCase() ?? "none"}`;
|
|
13139
|
+
}
|
|
13140
|
+
function selectionKey(params) {
|
|
13141
|
+
const filter = params?.filter;
|
|
13142
|
+
return JSON.stringify([
|
|
13143
|
+
params?.range?.from ?? null,
|
|
13144
|
+
params?.range?.to ?? null,
|
|
13145
|
+
filter?.kind ?? null,
|
|
13146
|
+
filter?.direction ?? null,
|
|
13147
|
+
filter?.status === void 0 ? null : [...new Set(filter.status)].sort()
|
|
13148
|
+
]);
|
|
12817
13149
|
}
|
|
12818
|
-
function
|
|
12819
|
-
|
|
12820
|
-
|
|
13150
|
+
function validString(value, max) {
|
|
13151
|
+
return typeof value === "string" && value.length <= max;
|
|
13152
|
+
}
|
|
13153
|
+
function validPosition(position) {
|
|
13154
|
+
return position === null || position !== void 0 && typeof position === "object" && Number.isSafeInteger(position.timestamp) && position.timestamp >= 0 && /^[1-9][0-9]{0,9}:0x[0-9a-f]{64}:[0-9]{1,10}$/.test(position.id);
|
|
13155
|
+
}
|
|
13156
|
+
function parseCursor(value, scope, selection) {
|
|
13157
|
+
if (value === void 0) return null;
|
|
13158
|
+
if (value.length > 4e4) throw Errors.invalidInput("cursor", "invalid Activity cursor");
|
|
13159
|
+
const cursor = JSON.parse(value);
|
|
13160
|
+
if (cursor === null || typeof cursor !== "object" || cursor.version !== 1 || cursor.scope !== scope || cursor.selection !== selection || !Number.isSafeInteger(cursor.checkpoint) || cursor.checkpoint < 0 || cursor.source !== "indexed" && cursor.source !== "fallback" || cursor.paymentCursor !== null && !validString(cursor.paymentCursor, 2048) || typeof cursor.paymentDone !== "boolean" || typeof cursor.transferDone !== "boolean" || typeof cursor.degraded !== "boolean" || !Array.isArray(cursor.paymentPending) || cursor.paymentPending.length > BATCH || new Set(cursor.paymentPending).size !== cursor.paymentPending.length || !cursor.paymentPending.every((id) => validString(id, 256)) || !validPosition(cursor.transferBefore)) throw Errors.invalidInput("cursor", "Activity scope or filters changed; restart from the first page");
|
|
13161
|
+
return cursor;
|
|
13162
|
+
}
|
|
13163
|
+
function requireParams(params) {
|
|
13164
|
+
const limit = params?.limit ?? 25;
|
|
13165
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > BATCH) throw Errors.invalidInput("limit", "must be an integer from 1 to 100");
|
|
13166
|
+
for (const value of [params?.range?.from, params?.range?.to]) if (value !== void 0 && !Number.isSafeInteger(value)) throw Errors.invalidInput("range", "must contain integer epoch milliseconds");
|
|
13167
|
+
const f = params?.filter;
|
|
13168
|
+
if (f?.kind !== void 0 && f.kind !== "payment" && f.kind !== "movement" || f?.direction !== void 0 && ![
|
|
13169
|
+
"in",
|
|
13170
|
+
"out",
|
|
13171
|
+
"self"
|
|
13172
|
+
].includes(f.direction) || f?.status !== void 0 && (!Array.isArray(f.status) || !f.status.every((status) => PAYMENT_STATUSES.includes(status)))) throw Errors.invalidInput("filter", "invalid Activity filter");
|
|
12821
13173
|
}
|
|
12822
|
-
/** The caller's filter applied to the merged page. The join owns the order. */
|
|
12823
13174
|
function matchesFilter(item, filter) {
|
|
12824
|
-
|
|
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);
|
|
13175
|
+
return (filter?.kind === void 0 || item.kind === filter.kind) && (filter?.direction === void 0 || item.direction === filter.direction) && (filter?.status === void 0 || item.kind === "payment" && filter.status.includes(item.status));
|
|
12829
13176
|
}
|
|
12830
13177
|
function overlay(deps, actor, controls, input) {
|
|
12831
13178
|
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)) }, (_,
|
|
13179
|
+
const offsets = Array.from({ length: Math.max(1, Math.ceil(count / MAX_OVERLAY_IDS)) }, (_, i) => i * MAX_OVERLAY_IDS);
|
|
12833
13180
|
return Effect.forEach(offsets, (offset) => deps.convexCall.query(deps.functions.activityOverlay, copyInvocationObservation(controls, { input: {
|
|
12834
13181
|
...actor === void 0 ? {} : { actor },
|
|
12835
13182
|
...input.references === void 0 ? {} : { references: input.references.slice(offset, offset + MAX_OVERLAY_IDS) },
|
|
12836
13183
|
...input.settlementIds === void 0 ? {} : { settlementIds: input.settlementIds.slice(offset, offset + MAX_OVERLAY_IDS) }
|
|
12837
|
-
} })), { concurrency: 2 }).pipe(Effect.
|
|
12838
|
-
|
|
12839
|
-
|
|
12840
|
-
|
|
12841
|
-
|
|
13184
|
+
} })), { concurrency: 2 }).pipe(Effect.flatMap((pages) => {
|
|
13185
|
+
const first = pages[0];
|
|
13186
|
+
if (pages.some((page) => scopeKey(page) !== scopeKey(first))) return Effect.fail({ publicError: Errors.invalidInput("actor", "Activity scope changed during the read") });
|
|
13187
|
+
return Effect.succeed({
|
|
13188
|
+
...first,
|
|
13189
|
+
links: pages.flatMap((page) => page.links),
|
|
13190
|
+
annotations: pages.flatMap((page) => page.annotations),
|
|
13191
|
+
...pages.every((page) => page.payments !== void 0) ? { payments: pages.flatMap((page) => page.payments ?? []) } : {}
|
|
13192
|
+
});
|
|
13193
|
+
}));
|
|
12842
13194
|
}
|
|
12843
13195
|
function convexPage(deps, actor, controls, input) {
|
|
12844
13196
|
return deps.convexCall.query(deps.functions.activityList, copyInvocationObservation(controls, { input: {
|
|
12845
|
-
...
|
|
12846
|
-
|
|
12847
|
-
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
12848
|
-
...input.range === void 0 ? {} : { range: input.range }
|
|
13197
|
+
...input,
|
|
13198
|
+
actor
|
|
12849
13199
|
} }));
|
|
12850
13200
|
}
|
|
12851
|
-
|
|
12852
|
-
|
|
12853
|
-
|
|
12854
|
-
|
|
12855
|
-
|
|
12856
|
-
|
|
12857
|
-
|
|
12858
|
-
|
|
12859
|
-
|
|
12860
|
-
|
|
13201
|
+
function chainRead(deps, table, input) {
|
|
13202
|
+
return deps.indexer.read(table, input).pipe(Effect.catch((error) => {
|
|
13203
|
+
if (error.publicError.details?.reason === "scope-refused" || ![
|
|
13204
|
+
"NETWORK_ERROR",
|
|
13205
|
+
"RATE_LIMITED",
|
|
13206
|
+
"PROVIDER_ERROR",
|
|
13207
|
+
"CAPABILITY_UNAVAILABLE",
|
|
13208
|
+
"TIMEOUT"
|
|
13209
|
+
].includes(error.publicCode)) return Effect.fail({ publicError: error.publicError });
|
|
13210
|
+
return Effect.succeed(null);
|
|
13211
|
+
}));
|
|
12861
13212
|
}
|
|
12862
|
-
|
|
12863
|
-
function stitchedWindow(deps, actor, controls, window, params) {
|
|
13213
|
+
function fallbackPage(deps, scope, controls, params, state, degraded) {
|
|
12864
13214
|
return Effect.gen(function* () {
|
|
12865
|
-
const
|
|
12866
|
-
|
|
12867
|
-
|
|
12868
|
-
|
|
13215
|
+
const page = yield* convexPage(deps, scope.actor, controls, {
|
|
13216
|
+
limit: params?.limit ?? 25,
|
|
13217
|
+
...state.paymentCursor === null ? {} : { cursor: state.paymentCursor },
|
|
13218
|
+
range: {
|
|
13219
|
+
...params?.range?.from === void 0 ? {} : { from: params.range.from },
|
|
13220
|
+
to: Math.min(state.checkpoint, params?.range?.to ?? state.checkpoint)
|
|
13221
|
+
},
|
|
13222
|
+
...params?.filter === void 0 ? {} : { filter: params.filter }
|
|
12869
13223
|
});
|
|
12870
|
-
const
|
|
12871
|
-
|
|
12872
|
-
|
|
12873
|
-
|
|
12874
|
-
|
|
12875
|
-
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
13224
|
+
const decoration = yield* overlay(deps, scope.actor, controls, { references: page.items.map((item) => ({
|
|
13225
|
+
kind: item.kind,
|
|
13226
|
+
id: item.id
|
|
13227
|
+
})) });
|
|
13228
|
+
if (scopeKey(decoration) !== scopeKey(scope)) return yield* Effect.fail({ publicError: Errors.invalidInput("actor", "Activity scope changed during fallback") });
|
|
13229
|
+
const annotations = new Map(decoration.annotations.map((annotation) => [`${annotation.reference.kind}:${annotation.reference.id}`, annotation]));
|
|
13230
|
+
yield* Effect.annotateCurrentSpan({
|
|
13231
|
+
read_source: "convex",
|
|
13232
|
+
...degraded ? { read_warning: "indexer-unavailable" } : {}
|
|
13233
|
+
});
|
|
13234
|
+
return {
|
|
13235
|
+
...page,
|
|
13236
|
+
items: page.items.filter(isActivityVisible).map((item) => withAnnotation(item, annotations.get(`${item.kind}:${item.id}`))),
|
|
13237
|
+
checkpoint: state.checkpoint,
|
|
13238
|
+
cursor: page.cursor === null ? null : JSON.stringify({
|
|
13239
|
+
...state,
|
|
13240
|
+
source: "fallback",
|
|
13241
|
+
paymentCursor: page.cursor,
|
|
13242
|
+
degraded
|
|
13243
|
+
}),
|
|
13244
|
+
...degraded ? { readWarning: "indexer-unavailable" } : {}
|
|
13245
|
+
};
|
|
13246
|
+
});
|
|
13247
|
+
}
|
|
13248
|
+
function boundedRange(range, checkpoint) {
|
|
13249
|
+
return {
|
|
13250
|
+
...range?.from === void 0 ? {} : { from: range.from },
|
|
13251
|
+
to: Math.min(checkpoint, range?.to ?? checkpoint)
|
|
13252
|
+
};
|
|
13253
|
+
}
|
|
13254
|
+
function unavailablePage(deps, scope, controls, params, state, first) {
|
|
13255
|
+
if (first) return fallbackPage(deps, scope, controls, params, state, true);
|
|
13256
|
+
return Effect.annotateCurrentSpan({
|
|
13257
|
+
read_source: "indexer",
|
|
13258
|
+
read_warning: "indexer-unavailable"
|
|
13259
|
+
}).pipe(Effect.as({
|
|
13260
|
+
items: [],
|
|
13261
|
+
cursor: null,
|
|
13262
|
+
checkpoint: state.checkpoint,
|
|
13263
|
+
observedAt: Date.now(),
|
|
13264
|
+
readWarning: "indexer-unavailable"
|
|
13265
|
+
}));
|
|
13266
|
+
}
|
|
13267
|
+
function readTransfers(deps, safe, range, state, wanted, first) {
|
|
13268
|
+
const from = Math.max(0, Math.ceil((range.from ?? 0) / 1e3));
|
|
13269
|
+
const to = Math.floor(range.to / 1e3);
|
|
13270
|
+
if (state.transferDone || from > to || !wanted && !first) return Effect.succeed([]);
|
|
13271
|
+
return chainRead(deps, "transfer", {
|
|
13272
|
+
safe: toAddress(safe),
|
|
13273
|
+
limit: wanted ? BATCH : 1,
|
|
13274
|
+
timeline: {
|
|
13275
|
+
from,
|
|
13276
|
+
to,
|
|
13277
|
+
...state.transferBefore === null ? {} : { before: state.transferBefore }
|
|
12881
13278
|
}
|
|
12882
|
-
|
|
12883
|
-
|
|
12884
|
-
|
|
13279
|
+
});
|
|
13280
|
+
}
|
|
13281
|
+
function readPayments(deps, scope, controls, range, state, wanted) {
|
|
13282
|
+
const done = state.paymentDone || !wanted;
|
|
13283
|
+
if (state.paymentPending.length > 0 || done) return Effect.succeed({
|
|
13284
|
+
items: [],
|
|
13285
|
+
pending: state.paymentPending,
|
|
13286
|
+
cursor: state.paymentCursor,
|
|
13287
|
+
done
|
|
13288
|
+
});
|
|
13289
|
+
return convexPage(deps, scope.actor, controls, {
|
|
13290
|
+
limit: BATCH,
|
|
13291
|
+
range,
|
|
13292
|
+
filter: { kind: "payment" },
|
|
13293
|
+
...state.paymentCursor === null ? {} : { cursor: state.paymentCursor }
|
|
13294
|
+
}).pipe(Effect.map((page) => ({
|
|
13295
|
+
items: page.items,
|
|
13296
|
+
pending: page.items.map((item) => item.id),
|
|
13297
|
+
cursor: page.cursor,
|
|
13298
|
+
done: page.cursor === null
|
|
13299
|
+
})));
|
|
13300
|
+
}
|
|
13301
|
+
function readPaymentFacts(deps, safe, settlements) {
|
|
13302
|
+
const offsets = Array.from({ length: Math.ceil(settlements.length / 50) }, (_, i) => i * 50);
|
|
13303
|
+
return Effect.forEach(offsets, (offset) => chainRead(deps, "payment", {
|
|
13304
|
+
safe: toAddress(safe),
|
|
13305
|
+
limit: 50,
|
|
13306
|
+
settlements: settlements.slice(offset, offset + 50)
|
|
13307
|
+
}), { concurrency: 2 }).pipe(Effect.map((pages) => pages.some((page) => page === null) ? null : pages.flatMap((page) => page ?? [])));
|
|
13308
|
+
}
|
|
13309
|
+
function decoratePage(deps, scope, controls, transfers, page, range) {
|
|
13310
|
+
return Effect.gen(function* () {
|
|
13311
|
+
const decoration = yield* overlay(deps, scope.actor, controls, {
|
|
13312
|
+
references: [...page.pending.map((id) => ({
|
|
13313
|
+
kind: "payment",
|
|
13314
|
+
id
|
|
13315
|
+
})), ...transfers.map((row) => ({
|
|
12885
13316
|
kind: "movement",
|
|
12886
13317
|
id: row.id
|
|
12887
13318
|
}))],
|
|
12888
|
-
settlementIds:
|
|
13319
|
+
settlementIds: [...new Set(transfers.flatMap((row) => row.paymentSettlementId ? [row.paymentSettlementId] : []))]
|
|
12889
13320
|
});
|
|
12890
|
-
|
|
12891
|
-
const
|
|
12892
|
-
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
12896
|
-
|
|
12897
|
-
|
|
12898
|
-
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
|
|
13321
|
+
if (scopeKey(decoration) !== scopeKey(scope)) return yield* Effect.fail({ publicError: Errors.invalidInput("actor", "Activity scope changed during the read") });
|
|
13322
|
+
const byId = new Map([...page.items, ...decoration.payments ?? []].map((item) => [item.id, item]));
|
|
13323
|
+
const settlements = [...new Set(decoration.links.map((link) => link.settlementId))];
|
|
13324
|
+
const facts = yield* readPaymentFacts(deps, scope.safe, settlements);
|
|
13325
|
+
if (facts === null) return null;
|
|
13326
|
+
const bySettlement = new Map(facts.map((row) => [row.settlementId, row]));
|
|
13327
|
+
const byPayment = new Map(decoration.links.map((link) => [link.paymentId, {
|
|
13328
|
+
fact: bySettlement.get(link.settlementId),
|
|
13329
|
+
expected: link.expected
|
|
13330
|
+
}]));
|
|
13331
|
+
const annotations = new Map(decoration.annotations.map((annotation) => [`${annotation.reference.kind}:${annotation.reference.id}`, annotation]));
|
|
13332
|
+
return {
|
|
13333
|
+
payments: page.pending.flatMap((id) => {
|
|
13334
|
+
const item = byId.get(id);
|
|
13335
|
+
if (item === void 0 || item.kind !== "payment" || item.createdAt > range.to || range.from !== void 0 && item.createdAt < range.from) return [];
|
|
13336
|
+
const confirmed = withAnnotation(confirmPayment(item, byPayment.get(id)?.fact, byPayment.get(id)?.expected), annotations.get(`payment:${id}`));
|
|
13337
|
+
return isActivityVisible(confirmed) ? [confirmed] : [];
|
|
13338
|
+
}),
|
|
13339
|
+
annotations,
|
|
13340
|
+
linked: new Set(decoration.links.filter((link) => matchesPaymentFact(bySettlement.get(link.settlementId), link.expected)).map((link) => link.settlementId))
|
|
13341
|
+
};
|
|
13342
|
+
});
|
|
13343
|
+
}
|
|
13344
|
+
function mergePage(safe, filter, limit, state, page, decoration, transfers, wantsTransfers) {
|
|
13345
|
+
const { payments, annotations, linked } = decoration;
|
|
13346
|
+
let pi = 0;
|
|
13347
|
+
let ti = 0;
|
|
13348
|
+
const items = [];
|
|
13349
|
+
const transferEnd = !wantsTransfers || transfers.length < BATCH;
|
|
13350
|
+
let transferBefore = state.transferBefore;
|
|
13351
|
+
while (items.length < limit) {
|
|
13352
|
+
if (pi === payments.length && !page.done || ti === transfers.length && !transferEnd) break;
|
|
13353
|
+
const payment = payments[pi];
|
|
13354
|
+
const row = transfers[ti];
|
|
13355
|
+
if (payment === void 0 && row === void 0) break;
|
|
13356
|
+
if (payment !== void 0 && (row === void 0 || payment.createdAt >= Number(row.timestamp) * 1e3)) {
|
|
13357
|
+
pi += 1;
|
|
13358
|
+
if (matchesFilter(payment, filter)) items.push(payment);
|
|
13359
|
+
} else if (row !== void 0) {
|
|
13360
|
+
ti += 1;
|
|
13361
|
+
transferBefore = {
|
|
13362
|
+
timestamp: Number(row.timestamp),
|
|
13363
|
+
id: row.id
|
|
13364
|
+
};
|
|
13365
|
+
if (row.paymentSettlementId && linked.has(row.paymentSettlementId)) continue;
|
|
13366
|
+
const item = transferItem(safe, row, annotations.get(`movement:${row.id}`));
|
|
13367
|
+
if (item !== null && matchesFilter(item, filter)) items.push(item);
|
|
12902
13368
|
}
|
|
12903
|
-
|
|
12904
|
-
|
|
13369
|
+
}
|
|
13370
|
+
return {
|
|
13371
|
+
items,
|
|
13372
|
+
next: {
|
|
13373
|
+
...state,
|
|
13374
|
+
paymentCursor: page.cursor,
|
|
13375
|
+
paymentDone: page.done,
|
|
13376
|
+
paymentPending: payments.slice(pi).map((item) => item.id),
|
|
13377
|
+
transferBefore,
|
|
13378
|
+
transferDone: ti === transfers.length && transferEnd
|
|
13379
|
+
}
|
|
13380
|
+
};
|
|
13381
|
+
}
|
|
13382
|
+
function indexedPage(deps, scope, controls, params, state, first) {
|
|
13383
|
+
return Effect.gen(function* () {
|
|
13384
|
+
const range = boundedRange(params?.range, state.checkpoint);
|
|
13385
|
+
const wantsTransfers = params?.filter?.kind !== "payment" && params?.filter?.status === void 0;
|
|
13386
|
+
const found = yield* readTransfers(deps, scope.safe, range, state, wantsTransfers, first);
|
|
13387
|
+
if (found === null) return yield* unavailablePage(deps, scope, controls, params, state, first);
|
|
13388
|
+
const transfers = wantsTransfers ? found : [];
|
|
13389
|
+
const page = yield* readPayments(deps, scope, controls, range, state, params?.filter?.kind !== "movement");
|
|
13390
|
+
const decoration = yield* decoratePage(deps, scope, controls, transfers, page, range);
|
|
13391
|
+
if (decoration === null) return yield* unavailablePage(deps, scope, controls, params, state, first);
|
|
13392
|
+
const { items, next } = mergePage(scope.safe, params?.filter, params?.limit ?? 25, state, page, decoration, transfers, wantsTransfers);
|
|
13393
|
+
const cursor = next.paymentDone && next.paymentPending.length === 0 && next.transferDone ? null : JSON.stringify(next);
|
|
13394
|
+
if (cursor !== null && cursor === params?.cursor) return yield* Effect.fail({ publicError: Errors.invalidInput("cursor", "Activity source did not advance") });
|
|
13395
|
+
yield* Effect.annotateCurrentSpan({ read_source: "indexer" });
|
|
12905
13396
|
return {
|
|
12906
|
-
items
|
|
12907
|
-
|
|
12908
|
-
|
|
12909
|
-
|
|
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
|
|
13397
|
+
items,
|
|
13398
|
+
cursor,
|
|
13399
|
+
checkpoint: state.checkpoint,
|
|
13400
|
+
observedAt: Date.now()
|
|
12915
13401
|
};
|
|
12916
13402
|
});
|
|
12917
13403
|
}
|
|
12918
13404
|
function readActivityPage(deps, actor, controls, params) {
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
const
|
|
12926
|
-
|
|
12927
|
-
|
|
13405
|
+
return Effect.gen(function* () {
|
|
13406
|
+
yield* Effect.try({
|
|
13407
|
+
try: () => requireParams(params),
|
|
13408
|
+
catch: (cause) => ({ publicError: cause })
|
|
13409
|
+
});
|
|
13410
|
+
const scope = yield* overlay(deps, actor, controls, {});
|
|
13411
|
+
const selection = selectionKey(params);
|
|
13412
|
+
const cursor = yield* Effect.try({
|
|
13413
|
+
try: () => parseCursor(params?.cursor, scopeKey(scope), selection),
|
|
13414
|
+
catch: () => ({ publicError: Errors.invalidInput("cursor", "invalid or obsolete Activity cursor; restart the read") })
|
|
13415
|
+
});
|
|
13416
|
+
const state = cursor ?? {
|
|
13417
|
+
version: 1,
|
|
13418
|
+
scope: scopeKey(scope),
|
|
13419
|
+
selection,
|
|
13420
|
+
checkpoint: Date.now(),
|
|
13421
|
+
source: "indexed",
|
|
13422
|
+
paymentCursor: null,
|
|
13423
|
+
paymentDone: false,
|
|
13424
|
+
paymentPending: [],
|
|
13425
|
+
transferBefore: null,
|
|
13426
|
+
transferDone: false,
|
|
13427
|
+
degraded: false
|
|
13428
|
+
};
|
|
13429
|
+
const range = boundedRange(params?.range, state.checkpoint);
|
|
13430
|
+
if (range.from !== void 0 && range.from > range.to) return {
|
|
13431
|
+
items: [],
|
|
12928
13432
|
cursor: null,
|
|
12929
|
-
checkpoint:
|
|
12930
|
-
observedAt
|
|
12931
|
-
...readWarning === void 0 ? {} : { readWarning }
|
|
13433
|
+
checkpoint: state.checkpoint,
|
|
13434
|
+
observedAt: Date.now()
|
|
12932
13435
|
};
|
|
13436
|
+
if (state.source === "fallback" || scope.safe === null) return yield* fallbackPage(deps, scope, controls, params, state, state.degraded);
|
|
13437
|
+
if (scope.payments === void 0) return yield* unavailablePage(deps, scope, controls, params, state, cursor === null);
|
|
13438
|
+
return yield* indexedPage(deps, scope, controls, params, state, cursor === null);
|
|
13439
|
+
});
|
|
13440
|
+
}
|
|
13441
|
+
function readActivitySummary(deps, actor, controls, params) {
|
|
13442
|
+
return Effect.gen(function* () {
|
|
13443
|
+
const totals = /* @__PURE__ */ new Map();
|
|
13444
|
+
let cursor;
|
|
13445
|
+
let count = 0;
|
|
13446
|
+
let readWarning;
|
|
13447
|
+
do {
|
|
13448
|
+
const page = yield* readActivityPage(deps, actor, controls, {
|
|
13449
|
+
limit: BATCH,
|
|
13450
|
+
...cursor === void 0 ? {} : { cursor },
|
|
13451
|
+
...params?.window === void 0 ? {} : { range: params.window }
|
|
13452
|
+
});
|
|
13453
|
+
count += page.items.length;
|
|
13454
|
+
readWarning ??= page.readWarning;
|
|
13455
|
+
for (const total of summarizeItems(page.items)) {
|
|
13456
|
+
const key = `${total.currency}:${total.decimals}`;
|
|
13457
|
+
const old = totals.get(key);
|
|
13458
|
+
totals.set(key, old === void 0 ? total : {
|
|
13459
|
+
...total,
|
|
13460
|
+
in: String(BigInt(old.in) + BigInt(total.in)),
|
|
13461
|
+
out: String(BigInt(old.out) + BigInt(total.out)),
|
|
13462
|
+
net: String(BigInt(old.net) + BigInt(total.net)),
|
|
13463
|
+
pendingIn: String(BigInt(old.pendingIn) + BigInt(total.pendingIn))
|
|
13464
|
+
});
|
|
13465
|
+
}
|
|
13466
|
+
cursor = page.cursor ?? void 0;
|
|
13467
|
+
} while (cursor !== void 0);
|
|
12933
13468
|
return {
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
13469
|
+
window: {
|
|
13470
|
+
from: params?.window?.from ?? null,
|
|
13471
|
+
to: params?.window?.to ?? null
|
|
13472
|
+
},
|
|
13473
|
+
totals: [...totals.values()],
|
|
13474
|
+
count,
|
|
13475
|
+
observedAt: Date.now(),
|
|
13476
|
+
...readWarning === void 0 ? {} : { readWarning }
|
|
12938
13477
|
};
|
|
12939
|
-
})
|
|
13478
|
+
});
|
|
12940
13479
|
}
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
|
|
12949
|
-
|
|
12950
|
-
|
|
12951
|
-
|
|
13480
|
+
/** An indexed Movement has no Convex materialization. Read its exact native row. */
|
|
13481
|
+
function readIndexedMovement(deps, actor, controls, eventId) {
|
|
13482
|
+
return Effect.gen(function* () {
|
|
13483
|
+
const scope = yield* overlay(deps, actor, controls, { references: [{
|
|
13484
|
+
kind: "movement",
|
|
13485
|
+
id: eventId
|
|
13486
|
+
}] });
|
|
13487
|
+
if (scope.safe === null) return null;
|
|
13488
|
+
const safe = scope.safe.toLowerCase();
|
|
13489
|
+
const row = (yield* deps.indexer.read("transfer", {
|
|
13490
|
+
safe: toAddress(safe),
|
|
13491
|
+
limit: 1,
|
|
13492
|
+
eventId
|
|
13493
|
+
}).pipe(Effect.catch((error) => Effect.fail({ publicError: error.publicError }))))[0];
|
|
13494
|
+
if (row === void 0) return null;
|
|
13495
|
+
const blockNumber = Number(row.blockNumber);
|
|
13496
|
+
if (row.id !== eventId || row.from.toLowerCase() !== safe && row.to.toLowerCase() !== safe || !Number.isSafeInteger(blockNumber) || blockNumber < 0 || !Number.isSafeInteger(row.logIndex) || row.logIndex < 0) return yield* Effect.fail({ publicError: Errors.invalidInput("activity", "indexed Movement does not match the requested scope or evidence") });
|
|
13497
|
+
yield* Effect.annotateCurrentSpan({ read_source: "indexer" });
|
|
13498
|
+
return {
|
|
13499
|
+
kind: "movement",
|
|
13500
|
+
movementId: row.id,
|
|
13501
|
+
viewer: scope.actor,
|
|
13502
|
+
annotation: scope.annotations.find((annotation) => annotation.reference.kind === "movement" && annotation.reference.id === row.id) ?? null,
|
|
13503
|
+
evidence: {
|
|
13504
|
+
chainId: row.chainId,
|
|
13505
|
+
contractAddress: row.token,
|
|
13506
|
+
tokenAddress: row.token,
|
|
13507
|
+
transactionHash: row.txHash,
|
|
13508
|
+
blockNumber,
|
|
13509
|
+
blockHash: row.blockHash,
|
|
13510
|
+
inclusion: "included",
|
|
13511
|
+
verification: "verified",
|
|
13512
|
+
canonicalState: "finalized",
|
|
13513
|
+
transferLogIndex: row.logIndex,
|
|
13514
|
+
source: row.from,
|
|
13515
|
+
destination: row.to,
|
|
13516
|
+
rawAmount: row.amount.toString(),
|
|
13517
|
+
link: {
|
|
13518
|
+
movementId: row.id,
|
|
13519
|
+
depositPaymentId: null
|
|
13520
|
+
}
|
|
13521
|
+
}
|
|
13522
|
+
};
|
|
13523
|
+
});
|
|
12952
13524
|
}
|
|
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
13525
|
function subscribeActivity(deps, actor, controls, onChange) {
|
|
12962
13526
|
return Effect.gen(function* () {
|
|
12963
13527
|
const scope = yield* overlay(deps, actor, controls, {});
|
|
12964
13528
|
if (scope.safe === null) return () => {};
|
|
12965
|
-
const page = {
|
|
12966
|
-
safe: scope.safe,
|
|
12967
|
-
limit: INTENT_WINDOW
|
|
12968
|
-
};
|
|
12969
13529
|
let delivered = false;
|
|
12970
|
-
|
|
12971
|
-
|
|
12972
|
-
|
|
12973
|
-
}
|
|
12974
|
-
|
|
12975
|
-
|
|
13530
|
+
return yield* deps.indexer.subscribe("transfer", {
|
|
13531
|
+
safe: toAddress(scope.safe),
|
|
13532
|
+
limit: BATCH
|
|
13533
|
+
}, (snapshot) => {
|
|
13534
|
+
if (snapshot.status === "ok") {
|
|
13535
|
+
if (delivered) onChange();
|
|
13536
|
+
delivered = true;
|
|
13537
|
+
}
|
|
12976
13538
|
if (snapshot.status === "error") {
|
|
12977
13539
|
delivered = true;
|
|
12978
13540
|
onChange();
|
|
@@ -12982,7 +13544,7 @@ function subscribeActivity(deps, actor, controls, onChange) {
|
|
|
12982
13544
|
}
|
|
12983
13545
|
//#endregion
|
|
12984
13546
|
//#region ../../packages/sdk/package.json
|
|
12985
|
-
var version$1 = "4.20.0-beta.
|
|
13547
|
+
var version$1 = "4.20.0-beta.3";
|
|
12986
13548
|
//#endregion
|
|
12987
13549
|
//#region ../../packages/sdk/src/telemetry/exception-projection.ts
|
|
12988
13550
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -14339,7 +14901,10 @@ function makeFinancialOpsMethods(deps) {
|
|
|
14339
14901
|
...params?.limit === void 0 ? {} : { limit: params.limit },
|
|
14340
14902
|
...params?.range === void 0 ? {} : { range: params.range },
|
|
14341
14903
|
...params?.filter === void 0 ? {} : { filter: params.filter }
|
|
14342
|
-
} })) : readActivityPage(indexerDeps, actor, controls, params)).pipe(Effect.
|
|
14904
|
+
} })) : readActivityPage(indexerDeps, actor, controls, params)).pipe(Effect.map((page) => ({
|
|
14905
|
+
...page,
|
|
14906
|
+
items: page.items.filter(isActivityVisible)
|
|
14907
|
+
})), Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
|
|
14343
14908
|
},
|
|
14344
14909
|
summary: (params, options) => {
|
|
14345
14910
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
@@ -14360,7 +14925,10 @@ function makeFinancialOpsMethods(deps) {
|
|
|
14360
14925
|
actor: scope,
|
|
14361
14926
|
referenceActor: reference.kind === "payment" ? activityActorField(reference.actor).actor : void 0
|
|
14362
14927
|
});
|
|
14363
|
-
}).pipe(Effect.flatMap(({ actor, referenceActor }) => Effect.suspend(() =>
|
|
14928
|
+
}).pipe(Effect.flatMap(({ actor, referenceActor }) => Effect.suspend(() => indexerDeps !== void 0 && reference.kind === "movement" && /^[1-9][0-9]{0,9}:0x[0-9a-f]{64}:[0-9]{1,10}$/.test(reference.id) ? readIndexedMovement(indexerDeps, actor?.kind === "org" ? {
|
|
14929
|
+
kind: "organization",
|
|
14930
|
+
orgId: actor.orgId
|
|
14931
|
+
} : void 0, controls, reference.id) : deps.convexCall.query(fns.activityGet, copyInvocationObservation(controls, {
|
|
14364
14932
|
input: {
|
|
14365
14933
|
kind: reference.kind,
|
|
14366
14934
|
id: reference.id,
|
|
@@ -15052,6 +15620,277 @@ async function recoverRawDigestSigner(input) {
|
|
|
15052
15620
|
}
|
|
15053
15621
|
}
|
|
15054
15622
|
//#endregion
|
|
15623
|
+
//#region ../../packages/observability/src/engineering-delivery.ts
|
|
15624
|
+
/** Fixed admission limits for one CLI invocation and its SDK client. */
|
|
15625
|
+
const CLI_ENGINEERING_LIMITS = Object.freeze({
|
|
15626
|
+
records: 80,
|
|
15627
|
+
ordinaryRecords: 64,
|
|
15628
|
+
recordBytes: 16384,
|
|
15629
|
+
requests: 5,
|
|
15630
|
+
ordinaryRequests: 2,
|
|
15631
|
+
requestBytes: 1572864,
|
|
15632
|
+
metricSeries: 16,
|
|
15633
|
+
requestTimeoutMs: 1e3
|
|
15634
|
+
});
|
|
15635
|
+
const text$1 = (value) => typeof value === "string" ? value.slice(0, 128) : "capxul.engineering";
|
|
15636
|
+
const attributes = (input, limit = 32) => {
|
|
15637
|
+
const out = {};
|
|
15638
|
+
let count = 0;
|
|
15639
|
+
let bytes = 0;
|
|
15640
|
+
try {
|
|
15641
|
+
for (const key in input) {
|
|
15642
|
+
if (count++ >= limit) break;
|
|
15643
|
+
if (key.length > 64) continue;
|
|
15644
|
+
const value = Object.getOwnPropertyDescriptor(input, key)?.value;
|
|
15645
|
+
const scalar = typeof value === "string" ? value.slice(0, 128) : typeof value === "boolean" || typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
15646
|
+
if (scalar === void 0) continue;
|
|
15647
|
+
bytes += new TextEncoder().encode(JSON.stringify([key, scalar])).length;
|
|
15648
|
+
if (bytes > (limit >= 24 ? 2e3 : 300)) break;
|
|
15649
|
+
out[key] = scalar;
|
|
15650
|
+
}
|
|
15651
|
+
} catch {}
|
|
15652
|
+
return out;
|
|
15653
|
+
};
|
|
15654
|
+
const terminalName = (name) => name === "cli.command.completed" || CLI_COMMAND_NAMES.some((command) => name === `cli.command.${command}`);
|
|
15655
|
+
/** Native exporters retain their serialization and scheduling; this owns admission only. */
|
|
15656
|
+
function cliEngineeringDelivery(budget, ownsMetrics) {
|
|
15657
|
+
const closed = Deferred.makeUnsafe();
|
|
15658
|
+
let isClosed = false;
|
|
15659
|
+
let metricsRunning = false;
|
|
15660
|
+
const logs = [];
|
|
15661
|
+
const spans = /* @__PURE__ */ new Map();
|
|
15662
|
+
const terminalBodies = /* @__PURE__ */ new WeakSet();
|
|
15663
|
+
const bodyLeases = /* @__PURE__ */ new WeakMap();
|
|
15664
|
+
const pendingBodies = /* @__PURE__ */ new Set();
|
|
15665
|
+
const holdBody = (body, releases) => {
|
|
15666
|
+
if (releases.length === 0) return;
|
|
15667
|
+
const lease = {
|
|
15668
|
+
started: false,
|
|
15669
|
+
release: () => {
|
|
15670
|
+
if (!pendingBodies.delete(lease)) return;
|
|
15671
|
+
bodyLeases.delete(body);
|
|
15672
|
+
for (const release of releases) release();
|
|
15673
|
+
}
|
|
15674
|
+
};
|
|
15675
|
+
bodyLeases.set(body, lease);
|
|
15676
|
+
pendingBodies.add(lease);
|
|
15677
|
+
};
|
|
15678
|
+
const discardBody = (body) => bodyLeases.get(body)?.release();
|
|
15679
|
+
const drainLogs = () => {
|
|
15680
|
+
for (const release of logs.splice(0)) release();
|
|
15681
|
+
};
|
|
15682
|
+
const close = () => {
|
|
15683
|
+
isClosed = true;
|
|
15684
|
+
Deferred.doneUnsafe(closed, Effect.void);
|
|
15685
|
+
for (const lease of pendingBodies) if (!lease.started) lease.release();
|
|
15686
|
+
drainLogs();
|
|
15687
|
+
for (const release of spans.values()) release();
|
|
15688
|
+
spans.clear();
|
|
15689
|
+
if (ownsMetrics) budget.metricRegistry.clear();
|
|
15690
|
+
};
|
|
15691
|
+
return {
|
|
15692
|
+
close,
|
|
15693
|
+
discardBody,
|
|
15694
|
+
metrics(run) {
|
|
15695
|
+
return Effect.suspend(() => {
|
|
15696
|
+
if (isClosed || metricsRunning) return Effect.void;
|
|
15697
|
+
metricsRunning = true;
|
|
15698
|
+
return run.pipe(Effect.ensuring(Effect.sync(() => {
|
|
15699
|
+
metricsRunning = false;
|
|
15700
|
+
})));
|
|
15701
|
+
});
|
|
15702
|
+
},
|
|
15703
|
+
logger(delegate) {
|
|
15704
|
+
return Logger.make((options) => {
|
|
15705
|
+
if (isClosed) return;
|
|
15706
|
+
let release;
|
|
15707
|
+
try {
|
|
15708
|
+
const message = text$1(Array.isArray(options.message) ? Object.getOwnPropertyDescriptor(options.message, "0")?.value : options.message);
|
|
15709
|
+
release = budget.admitRecord(terminalName(message));
|
|
15710
|
+
if (release === void 0) return;
|
|
15711
|
+
const context = Context.add(options.fiber.context, References.CurrentLogAnnotations, attributes(options.fiber.getRef(References.CurrentLogAnnotations)));
|
|
15712
|
+
const fiber = Object.create(options.fiber);
|
|
15713
|
+
Object.defineProperty(fiber, "getRef", { value: (ref) => Context.get(context, ref) });
|
|
15714
|
+
logs.push(release);
|
|
15715
|
+
delegate.log({
|
|
15716
|
+
...options,
|
|
15717
|
+
message,
|
|
15718
|
+
cause: Cause.empty,
|
|
15719
|
+
fiber
|
|
15720
|
+
});
|
|
15721
|
+
} catch {
|
|
15722
|
+
if (release !== void 0) {
|
|
15723
|
+
const index = logs.indexOf(release);
|
|
15724
|
+
if (index !== -1) logs.splice(index, 1);
|
|
15725
|
+
release();
|
|
15726
|
+
}
|
|
15727
|
+
budget.drop();
|
|
15728
|
+
}
|
|
15729
|
+
});
|
|
15730
|
+
},
|
|
15731
|
+
tracer(delegate) {
|
|
15732
|
+
return Tracer.make({
|
|
15733
|
+
span(options) {
|
|
15734
|
+
const name = text$1(options.name);
|
|
15735
|
+
const release = isClosed ? void 0 : budget.admitRecord(terminalName(name));
|
|
15736
|
+
const spanOptions = {
|
|
15737
|
+
...options,
|
|
15738
|
+
name,
|
|
15739
|
+
annotations: Context.empty(),
|
|
15740
|
+
links: []
|
|
15741
|
+
};
|
|
15742
|
+
const span = release === void 0 ? new Tracer.NativeSpan({
|
|
15743
|
+
...spanOptions,
|
|
15744
|
+
sampled: false
|
|
15745
|
+
}) : delegate.span(spanOptions);
|
|
15746
|
+
if (release !== void 0) spans.set(span.spanId, release);
|
|
15747
|
+
const wrapped = Object.create(span);
|
|
15748
|
+
let fields = 0, events = 0, links = 0, attributeBytes = 0;
|
|
15749
|
+
let ended = false;
|
|
15750
|
+
Object.defineProperties(wrapped, {
|
|
15751
|
+
attribute: { value: (key, value) => {
|
|
15752
|
+
if (fields >= 32 && !span.attributes.has(key)) {
|
|
15753
|
+
budget.drop();
|
|
15754
|
+
return;
|
|
15755
|
+
}
|
|
15756
|
+
const safe = attributes({ [key]: value }, 1);
|
|
15757
|
+
if (!Object.hasOwn(safe, key)) return;
|
|
15758
|
+
const previous = span.attributes.has(key) ? new TextEncoder().encode(JSON.stringify([key, span.attributes.get(key)])).length : 0;
|
|
15759
|
+
const next = new TextEncoder().encode(JSON.stringify([key, safe[key]])).length;
|
|
15760
|
+
if (attributeBytes - previous + next > 2e3) {
|
|
15761
|
+
budget.drop();
|
|
15762
|
+
return;
|
|
15763
|
+
}
|
|
15764
|
+
attributeBytes += next - previous;
|
|
15765
|
+
if (!span.attributes.has(key)) fields += 1;
|
|
15766
|
+
span.attribute(key, safe[key]);
|
|
15767
|
+
} },
|
|
15768
|
+
event: { value: (eventName, time, attrs) => {
|
|
15769
|
+
if (events++ >= 2) {
|
|
15770
|
+
budget.drop();
|
|
15771
|
+
return;
|
|
15772
|
+
}
|
|
15773
|
+
span.event(text$1(eventName), time, attributes(attrs ?? {}, 4));
|
|
15774
|
+
} },
|
|
15775
|
+
addLinks: { value: (items) => {
|
|
15776
|
+
for (const item of items.slice(0, Math.max(0, 2 - links))) {
|
|
15777
|
+
if (!/^[a-f0-9]{32}$/u.test(item.span.traceId) || !/^[a-f0-9]{16}$/u.test(item.span.spanId)) {
|
|
15778
|
+
budget.drop();
|
|
15779
|
+
continue;
|
|
15780
|
+
}
|
|
15781
|
+
span.addLinks([{
|
|
15782
|
+
span: Tracer.externalSpan({
|
|
15783
|
+
traceId: item.span.traceId,
|
|
15784
|
+
spanId: item.span.spanId,
|
|
15785
|
+
sampled: item.span.sampled
|
|
15786
|
+
}),
|
|
15787
|
+
attributes: attributes(item.attributes, 4)
|
|
15788
|
+
}]);
|
|
15789
|
+
links += 1;
|
|
15790
|
+
}
|
|
15791
|
+
} },
|
|
15792
|
+
end: { value: (time, exit) => {
|
|
15793
|
+
if (ended) return;
|
|
15794
|
+
ended = true;
|
|
15795
|
+
span.end(time, Exit.isFailure(exit) ? Exit.fail("CLI operation failed") : Exit.void);
|
|
15796
|
+
} }
|
|
15797
|
+
});
|
|
15798
|
+
wrapped.addLinks(options.links ?? []);
|
|
15799
|
+
return wrapped;
|
|
15800
|
+
},
|
|
15801
|
+
...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
|
|
15802
|
+
});
|
|
15803
|
+
},
|
|
15804
|
+
serialization(delegate) {
|
|
15805
|
+
return {
|
|
15806
|
+
logs(data) {
|
|
15807
|
+
const releases = logs.splice(0);
|
|
15808
|
+
try {
|
|
15809
|
+
const body = delegate.logs(data);
|
|
15810
|
+
if (data.resourceLogs.some((r) => r.scopeLogs.some((s) => s.logRecords?.some((l) => l.body?.stringValue === "cli.command.completed")))) terminalBodies.add(body);
|
|
15811
|
+
holdBody(body, releases);
|
|
15812
|
+
return body;
|
|
15813
|
+
} catch (error) {
|
|
15814
|
+
for (const release of releases) release();
|
|
15815
|
+
throw error;
|
|
15816
|
+
}
|
|
15817
|
+
},
|
|
15818
|
+
traces(data) {
|
|
15819
|
+
const releases = [];
|
|
15820
|
+
for (const resource of data.resourceSpans) for (const scope of resource.scopeSpans) for (const span of scope.spans) {
|
|
15821
|
+
const release = spans.get(span.spanId);
|
|
15822
|
+
if (release !== void 0) releases.push(release);
|
|
15823
|
+
spans.delete(span.spanId);
|
|
15824
|
+
}
|
|
15825
|
+
try {
|
|
15826
|
+
const body = delegate.traces(data);
|
|
15827
|
+
if (data.resourceSpans.some((r) => r.scopeSpans.some((s) => s.spans.some((span) => terminalName(span.name))))) terminalBodies.add(body);
|
|
15828
|
+
holdBody(body, releases);
|
|
15829
|
+
return body;
|
|
15830
|
+
} catch (error) {
|
|
15831
|
+
for (const release of releases) release();
|
|
15832
|
+
throw error;
|
|
15833
|
+
}
|
|
15834
|
+
},
|
|
15835
|
+
metrics(data) {
|
|
15836
|
+
const body = delegate.metrics(data);
|
|
15837
|
+
terminalBodies.add(body);
|
|
15838
|
+
return body;
|
|
15839
|
+
}
|
|
15840
|
+
};
|
|
15841
|
+
},
|
|
15842
|
+
transport(client, enabled = () => true) {
|
|
15843
|
+
const retrying = HttpClient.transform(client, (response, request) => Effect.suspend(() => {
|
|
15844
|
+
if (enabled()) return response;
|
|
15845
|
+
budget.drop();
|
|
15846
|
+
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null)));
|
|
15847
|
+
})).pipe(HttpClient.transformResponse((response) => Effect.tap(response, (result) => {
|
|
15848
|
+
let received = 0;
|
|
15849
|
+
return Stream.runForEach(result.stream, (chunk) => Effect.sync(() => {
|
|
15850
|
+
received += chunk.byteLength;
|
|
15851
|
+
if (received > 65536) throw new Error("Engineering response limit exceeded");
|
|
15852
|
+
})).pipe(Effect.catchTag("HttpClientError", (error) => error.reason._tag === "EmptyBodyError" ? Effect.void : Effect.fail(error)));
|
|
15853
|
+
}))).pipe(HttpClient.filterStatusOk, HttpClient.retryTransient({
|
|
15854
|
+
times: 1,
|
|
15855
|
+
schedule: Schedule.spaced("100 millis").pipe(Schedule.addDelay(({ input }) => Effect.map(Clock.currentTimeMillis, (now) => {
|
|
15856
|
+
if (!HttpClientError.isHttpClientError(input) || input.reason._tag !== "StatusCodeError" || input.reason.response.status !== 429) return Duration.zero;
|
|
15857
|
+
const header = input.reason.response.headers["retry-after"];
|
|
15858
|
+
const numeric = Number(header);
|
|
15859
|
+
const delay = header === void 0 ? 2e3 : Number.isFinite(numeric) ? numeric * 1e3 : Date.parse(header) - now;
|
|
15860
|
+
return Duration.millis(Number.isFinite(delay) ? Math.min(2e3, Math.max(0, delay)) : 2e3);
|
|
15861
|
+
})))
|
|
15862
|
+
}));
|
|
15863
|
+
return HttpClient.transform(retrying, (response, request) => Effect.suspend(() => {
|
|
15864
|
+
if (isClosed) {
|
|
15865
|
+
discardBody(request.body);
|
|
15866
|
+
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null)));
|
|
15867
|
+
}
|
|
15868
|
+
const droppedResponse = () => HttpClientResponse.fromWeb(request, new Response(null, { status: 200 }));
|
|
15869
|
+
if (request.body._tag === "Empty") {
|
|
15870
|
+
discardBody(request.body);
|
|
15871
|
+
return Effect.succeed(droppedResponse());
|
|
15872
|
+
}
|
|
15873
|
+
const bytes = request.body.contentLength;
|
|
15874
|
+
const release = budget.admitRequest(bytes ?? Number.POSITIVE_INFINITY, terminalBodies.has(request.body));
|
|
15875
|
+
if (release === void 0) {
|
|
15876
|
+
discardBody(request.body);
|
|
15877
|
+
return Effect.succeed(droppedResponse());
|
|
15878
|
+
}
|
|
15879
|
+
const lease = bodyLeases.get(request.body);
|
|
15880
|
+
if (lease !== void 0) lease.started = true;
|
|
15881
|
+
return response.pipe(Effect.asVoid, Effect.timeoutOption(CLI_ENGINEERING_LIMITS.requestTimeoutMs), Effect.raceFirst(Deferred.await(closed).pipe(Effect.andThen(Effect.interrupt))), Effect.tap((result) => Effect.sync(() => {
|
|
15882
|
+
if (Option.isNone(result)) budget.drop();
|
|
15883
|
+
})), Effect.catchCause(() => Effect.sync(() => {
|
|
15884
|
+
budget.drop();
|
|
15885
|
+
})), Effect.as(droppedResponse()), Effect.ensuring(Effect.sync(() => {
|
|
15886
|
+
release();
|
|
15887
|
+
discardBody(request.body);
|
|
15888
|
+
})));
|
|
15889
|
+
}));
|
|
15890
|
+
}
|
|
15891
|
+
};
|
|
15892
|
+
}
|
|
15893
|
+
//#endregion
|
|
15055
15894
|
//#region ../../packages/observability/src/engineering.ts
|
|
15056
15895
|
const ENGINEERING_CAPXUL_ENVS = [
|
|
15057
15896
|
"development",
|
|
@@ -15226,10 +16065,13 @@ const MINIMAL_NUMBERS = /* @__PURE__ */ new Set([
|
|
|
15226
16065
|
const MINIMAL_CORRELATIONS = /* @__PURE__ */ new Set([
|
|
15227
16066
|
"correlation_id",
|
|
15228
16067
|
"journey_id",
|
|
15229
|
-
"invocation_id"
|
|
16068
|
+
"invocation_id",
|
|
16069
|
+
"posthogDistinctId"
|
|
15230
16070
|
]);
|
|
15231
16071
|
const MINIMAL_METRIC_LABELS = /* @__PURE__ */ new Set([
|
|
15232
16072
|
"command",
|
|
16073
|
+
"capability",
|
|
16074
|
+
"invocation_kind",
|
|
15233
16075
|
"outcome",
|
|
15234
16076
|
"capxul_env",
|
|
15235
16077
|
"unit"
|
|
@@ -15237,7 +16079,7 @@ const MINIMAL_METRIC_LABELS = /* @__PURE__ */ new Set([
|
|
|
15237
16079
|
const MINIMAL_METRIC_NAMES = /* @__PURE__ */ new Set(["capxul.cli.command.count", "capxul.cli.command.duration"]);
|
|
15238
16080
|
const traceId = (value) => typeof value === "string" && /^(?!0+$)[0-9a-f]{32}$/u.test(value);
|
|
15239
16081
|
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";
|
|
16082
|
+
const minimalName = (value) => typeof value === "string" && (MINIMAL_LOG_NAMES.has(value) || isCapxulOperation(value) || CLI_COMMAND_NAMES.some((command) => value === `cli.command.${command}`)) ? value : "capxul.engineering";
|
|
15241
16083
|
const MINIMAL_ENUM_VALUES = /* @__PURE__ */ new Map([
|
|
15242
16084
|
["outcome", [
|
|
15243
16085
|
"succeeded",
|
|
@@ -15250,7 +16092,10 @@ const MINIMAL_ENUM_VALUES = /* @__PURE__ */ new Map([
|
|
|
15250
16092
|
["failure_mode", FAILURE_MODES$1],
|
|
15251
16093
|
["capxul_env", ENGINEERING_CAPXUL_ENVS],
|
|
15252
16094
|
["producer", ["browser", "server"]],
|
|
15253
|
-
["command",
|
|
16095
|
+
["command", CLI_COMMAND_NAMES],
|
|
16096
|
+
["capability", CLI_CAPABILITIES],
|
|
16097
|
+
["invocation_kind", CLI_INVOCATION_KINDS],
|
|
16098
|
+
["cli_identity_kind", ["anonymous"]],
|
|
15254
16099
|
["output_mode", ["human", "json"]],
|
|
15255
16100
|
["unit", [
|
|
15256
16101
|
"1",
|
|
@@ -15467,10 +16312,12 @@ function minimalSerialization(config) {
|
|
|
15467
16312
|
};
|
|
15468
16313
|
}
|
|
15469
16314
|
Effect.flatMap(OtlpExporter.Flusher, (flusher) => flusher.flush);
|
|
16315
|
+
var EngineeringLog = class extends Context.Service()("capxul/EngineeringLog") {};
|
|
15470
16316
|
/** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */
|
|
15471
16317
|
const makeEngineeringTelemetryLayer = (config) => {
|
|
15472
16318
|
const validated = validateEngineeringTelemetryConfig(config);
|
|
15473
16319
|
return Layer.suspend(() => {
|
|
16320
|
+
const bounded = validated.deliveryBudget === void 0 ? void 0 : cliEngineeringDelivery(validated.deliveryBudget, validated.serviceName === "capxul-cli");
|
|
15474
16321
|
const endpoints = postHogOtlpEndpoints(validated.host);
|
|
15475
16322
|
let disabled = false;
|
|
15476
16323
|
const enabled = () => {
|
|
@@ -15484,7 +16331,12 @@ const makeEngineeringTelemetryLayer = (config) => {
|
|
|
15484
16331
|
};
|
|
15485
16332
|
const delivery = {
|
|
15486
16333
|
...validated.shutdownTimeout === void 0 ? {} : { shutdownTimeout: validated.shutdownTimeout },
|
|
15487
|
-
...validated.exportInterval === void 0 ? {} : { exportInterval: validated.exportInterval }
|
|
16334
|
+
...validated.exportInterval === void 0 ? {} : { exportInterval: validated.exportInterval },
|
|
16335
|
+
...bounded === void 0 ? {} : {
|
|
16336
|
+
maxBatchSize: Number.MAX_SAFE_INTEGER,
|
|
16337
|
+
exportInterval: 1e3,
|
|
16338
|
+
shutdownTimeout: validated.serviceName === "capxul-cli" ? 0 : 500
|
|
16339
|
+
}
|
|
15488
16340
|
};
|
|
15489
16341
|
const resource = {
|
|
15490
16342
|
serviceName: validated.serviceName ?? "capxul-sdk",
|
|
@@ -15500,22 +16352,38 @@ const makeEngineeringTelemetryLayer = (config) => {
|
|
|
15500
16352
|
headers: validated.headers,
|
|
15501
16353
|
resource,
|
|
15502
16354
|
...delivery
|
|
15503
|
-
}).pipe(Effect.map((tracer) => makeLeakSafeEngineeringTracer(tracer, enabled)))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
15504
|
-
const
|
|
16355
|
+
}).pipe(Effect.map((tracer) => makeLeakSafeEngineeringTracer(bounded?.tracer(tracer) ?? tracer, enabled)))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
16356
|
+
const ownedLogging = Layer.effect(EngineeringLog, OtlpLogger.make({
|
|
15505
16357
|
url: endpoints.logs,
|
|
15506
16358
|
headers: validated.headers,
|
|
15507
16359
|
resource,
|
|
15508
|
-
...delivery
|
|
15509
|
-
|
|
15510
|
-
|
|
15511
|
-
|
|
15512
|
-
|
|
16360
|
+
...delivery,
|
|
16361
|
+
...bounded === void 0 ? {} : { excludeLogSpans: true }
|
|
16362
|
+
}).pipe(Effect.map((nativeLogger) => {
|
|
16363
|
+
const logger = bounded?.logger(nativeLogger) ?? nativeLogger;
|
|
16364
|
+
return Logger.make((options) => {
|
|
16365
|
+
if (enabled()) logger.log(options);
|
|
16366
|
+
});
|
|
16367
|
+
}))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
16368
|
+
const logging = Logger.layer([EngineeringLog], { mergeWithExisting: true }).pipe(Layer.provideMerge(ownedLogging));
|
|
16369
|
+
const metricConfig = {
|
|
15513
16370
|
url: endpoints.metrics,
|
|
15514
16371
|
headers: validated.headers,
|
|
15515
16372
|
resource,
|
|
15516
16373
|
temporality: "delta",
|
|
15517
16374
|
...delivery
|
|
15518
|
-
}
|
|
16375
|
+
};
|
|
16376
|
+
const metrics = bounded === void 0 ? OtlpMetrics.layer(metricConfig) : validated.serviceName !== "capxul-cli" ? Layer.empty : Layer.effectDiscard(Effect.gen(function* () {
|
|
16377
|
+
const flusher = yield* OtlpExporter.Flusher;
|
|
16378
|
+
yield* OtlpMetrics.make({
|
|
16379
|
+
...metricConfig,
|
|
16380
|
+
exportInterval: Number.POSITIVE_INFINITY,
|
|
16381
|
+
shutdownTimeout: 0
|
|
16382
|
+
}).pipe(Effect.provideService(OtlpExporter.Flusher, {
|
|
16383
|
+
...flusher,
|
|
16384
|
+
register: (run) => flusher.register(bounded.metrics(run))
|
|
16385
|
+
}));
|
|
16386
|
+
})).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
15519
16387
|
const headerPolicy = Layer.merge(Layer.succeed(HttpClient.TracerHeaderFilter, traceHeaderFilter), Layer.succeed(Headers.CurrentRedactedNames, [credentialHeaderPattern]));
|
|
15520
16388
|
const browserLifecycle = Layer.effectDiscard(Effect.gen(function* () {
|
|
15521
16389
|
if (validated.producer !== "browser" || !hasBrowserDocument()) return;
|
|
@@ -15538,17 +16406,25 @@ const makeEngineeringTelemetryLayer = (config) => {
|
|
|
15538
16406
|
}));
|
|
15539
16407
|
}));
|
|
15540
16408
|
const transport = Layer.effect(HttpClient.HttpClient, Effect.map(HttpClient.HttpClient, (client) => {
|
|
15541
|
-
const
|
|
15542
|
-
|
|
16409
|
+
const originalTransport = validated.producer === "browser" && hasBrowserDocument() ? browserExportClient(client) : client;
|
|
16410
|
+
const selectedTransport = bounded?.transport(originalTransport, enabled) ?? originalTransport;
|
|
16411
|
+
return HttpClient.transform(selectedTransport, (response, request) => Effect.suspend(() => {
|
|
16412
|
+
if (enabled() && request.body._tag !== "Empty") return response;
|
|
16413
|
+
bounded?.discardBody(request.body);
|
|
16414
|
+
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null, { status: 200 })));
|
|
16415
|
+
}));
|
|
15543
16416
|
})).pipe(Layer.provide(FetchHttpClient.layer));
|
|
15544
16417
|
const serialization = Layer.effect(OtlpSerialization.OtlpSerialization, Effect.map(OtlpSerialization.OtlpSerialization, (json) => {
|
|
15545
16418
|
const projected = minimalSerialization(validated);
|
|
15546
|
-
|
|
16419
|
+
const selected = validated.privacy === "minimal" ? projected : {
|
|
15547
16420
|
...json,
|
|
15548
16421
|
metrics: projected.metrics
|
|
15549
16422
|
};
|
|
16423
|
+
return bounded?.serialization(selected) ?? selected;
|
|
15550
16424
|
})).pipe(Layer.provide(OtlpSerialization.layerJson));
|
|
15551
|
-
|
|
16425
|
+
const combined = browserLifecycle.pipe(Layer.provideMerge(Layer.mergeAll(tracing, logging, metrics, headerPolicy)), Layer.provide(serialization), Layer.provide(transport));
|
|
16426
|
+
const scoped = bounded === void 0 ? combined : combined.pipe(Layer.provideMerge(Layer.effectDiscard(Effect.addFinalizer(() => Effect.sync(bounded.close)))));
|
|
16427
|
+
return validated.deliveryBudget === void 0 ? scoped : scoped.pipe(Layer.provideMerge(Layer.succeed(Metric.MetricRegistry, validated.serviceName === "capxul-cli" ? validated.deliveryBudget.metricRegistry : validated.deliveryBudget.emptyMetricRegistry())));
|
|
15552
16428
|
});
|
|
15553
16429
|
};
|
|
15554
16430
|
//#endregion
|
|
@@ -47788,6 +48664,7 @@ function snapshotHostObservability(observability) {
|
|
|
47788
48664
|
function hostEngineeringPolicy(observability) {
|
|
47789
48665
|
const policy = observability?.[HOST_ENGINEERING_POLICY];
|
|
47790
48666
|
return {
|
|
48667
|
+
...policy?.engineeringDeliveryBudget === void 0 ? {} : { deliveryBudget: policy.engineeringDeliveryBudget },
|
|
47791
48668
|
...policy?.engineeringEnabled === void 0 ? {} : { enabled: policy.engineeringEnabled },
|
|
47792
48669
|
...policy?.engineeringPrivacy === void 0 ? {} : { privacy: policy.engineeringPrivacy }
|
|
47793
48670
|
};
|
|
@@ -47856,7 +48733,8 @@ function decodeTransfer(value) {
|
|
|
47856
48733
|
token: toAddress(hex(row, "token")),
|
|
47857
48734
|
from: toAddress(hex(row, "from")),
|
|
47858
48735
|
to: toAddress(hex(row, "to")),
|
|
47859
|
-
amount: big(row, "amount")
|
|
48736
|
+
amount: big(row, "amount"),
|
|
48737
|
+
..."payment_settlement_id" in row ? { paymentSettlementId: row.payment_settlement_id === null ? null : hex(row, "payment_settlement_id") } : {}
|
|
47860
48738
|
};
|
|
47861
48739
|
}
|
|
47862
48740
|
function decodePayment(value) {
|
|
@@ -47942,6 +48820,60 @@ const ACTOR_PARAMS = {
|
|
|
47942
48820
|
*/
|
|
47943
48821
|
function ponderQuery(table, input) {
|
|
47944
48822
|
const safe = assertIndexerPage(input);
|
|
48823
|
+
if (input.eventId !== void 0) {
|
|
48824
|
+
if (table !== "transfer") throw Errors.invalidInput("eventId", "only transfer reads accept a logical event ID");
|
|
48825
|
+
return {
|
|
48826
|
+
sql: `${HEADS.transfer.slice(0, HEADS.transfer.indexOf(" from \"transfer\""))} from "transfer" where (("transfer"."from" = $1 or "transfer"."to" = $2) and "transfer"."id" = $3) limit $4`,
|
|
48827
|
+
params: [
|
|
48828
|
+
safe,
|
|
48829
|
+
safe,
|
|
48830
|
+
input.eventId,
|
|
48831
|
+
1
|
|
48832
|
+
],
|
|
48833
|
+
typings: [
|
|
48834
|
+
"none",
|
|
48835
|
+
"none",
|
|
48836
|
+
"none",
|
|
48837
|
+
"none"
|
|
48838
|
+
]
|
|
48839
|
+
};
|
|
48840
|
+
}
|
|
48841
|
+
if (input.settlements !== void 0) {
|
|
48842
|
+
if (table !== "payment") throw Errors.invalidInput("settlements", "only Payment reads accept settlement IDs");
|
|
48843
|
+
const params = [
|
|
48844
|
+
safe,
|
|
48845
|
+
safe,
|
|
48846
|
+
...input.settlements,
|
|
48847
|
+
input.limit
|
|
48848
|
+
];
|
|
48849
|
+
return {
|
|
48850
|
+
sql: `${HEADS.payment.slice(0, HEADS.payment.indexOf("where "))}where (("payment"."sender" = $1 or "payment"."recipient" = $2) and "payment"."settlement_id" in (${input.settlements.map((_, i) => `$${i + 3}`).join(", ")})) limit $${params.length}`,
|
|
48851
|
+
params,
|
|
48852
|
+
typings: params.map(() => "none")
|
|
48853
|
+
};
|
|
48854
|
+
}
|
|
48855
|
+
if (input.timeline !== void 0) {
|
|
48856
|
+
if (table !== "transfer") throw Errors.invalidInput("timeline", "only transfer reads have a timeline");
|
|
48857
|
+
const { from, to, before } = input.timeline;
|
|
48858
|
+
const params = [
|
|
48859
|
+
safe,
|
|
48860
|
+
safe,
|
|
48861
|
+
from,
|
|
48862
|
+
to
|
|
48863
|
+
];
|
|
48864
|
+
const select = HEADS.transfer.slice(0, HEADS.transfer.indexOf(" from \"transfer\"")) + ", \"payment_settlement_id\" from \"activity_transfer\" ";
|
|
48865
|
+
let where = "(\"activity_transfer\".\"from\" = $1 or \"activity_transfer\".\"to\" = $2) and \"activity_transfer\".\"timestamp\" >= $3 and \"activity_transfer\".\"timestamp\" <= $4";
|
|
48866
|
+
if (before !== void 0) {
|
|
48867
|
+
params.push(before.timestamp, before.timestamp, before.id);
|
|
48868
|
+
where += " and (\"activity_transfer\".\"timestamp\" < $5 or (\"activity_transfer\".\"timestamp\" = $6 and \"activity_transfer\".\"id\" < $7))";
|
|
48869
|
+
}
|
|
48870
|
+
params.push(input.limit);
|
|
48871
|
+
return {
|
|
48872
|
+
sql: `${select}where (${where}) order by "activity_transfer"."timestamp" desc, "activity_transfer"."id" desc limit $${params.length}`,
|
|
48873
|
+
params,
|
|
48874
|
+
typings: params.map(() => "none")
|
|
48875
|
+
};
|
|
48876
|
+
}
|
|
47945
48877
|
const offset = input.offset ?? 0;
|
|
47946
48878
|
const actors = ACTOR_PARAMS[table];
|
|
47947
48879
|
const params = [];
|
|
@@ -49616,7 +50548,7 @@ function stdioIdentity(env = process.env, options = {}) {
|
|
|
49616
50548
|
}
|
|
49617
50549
|
//#endregion
|
|
49618
50550
|
//#region package.json
|
|
49619
|
-
var version = "4.20.0-beta.
|
|
50551
|
+
var version = "4.20.0-beta.3";
|
|
49620
50552
|
//#endregion
|
|
49621
50553
|
//#region src/deps.ts
|
|
49622
50554
|
const NO_IDENTITY = async () => void 0;
|