@capxul/sdk 4.20.0-beta.4 → 4.20.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{OAuthBearerAuthClient-C-ip-z8M.d.mts → OAuthBearerAuthClient-BAxoi3SD.d.mts} +18 -1
- package/dist/{OAuthBearerAuthClient-DWkofxdZ.mjs → OAuthBearerAuthClient-BqQz-bnO.mjs} +17 -13
- package/dist/index.d.mts +43 -10
- package/dist/index.mjs +3 -151
- package/dist/node/index.d.mts +1 -1
- package/dist/node/index.mjs +1 -1
- package/dist/{production-CJwxgI8u.d.mts → production-DAhaxUik.d.mts} +125 -12
- package/dist/{production-BMfmzwHq.mjs → production-q0kwUWcj.mjs} +631 -92
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +22 -13
- package/package.json +6 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as toOrgId, A as EVM_ADDRESS_RE$1, At as redactUrlSecrets, B as toAssetId, C as APP_ID_RE, Ct as failureFingerprint, D as CLIENT_REQUEST_ID_RE, Dt as containsSensitiveMaterial, E as CLIENT_GRANT_ID_RE, Et as revertSummaryText, G as toCurrencyCode, H as toBudgetId, I as toAccountId, J as toEpochMs, K as toDurationMs, L as toAddress, M as WEI_RE, N as ZERO_BYTES32, O as COUNTRY_CODE_RE, Ot as isCredentialField, P as assetIdFor, Q as toKycTier, R as toAllowedOrigin, S as ACCOUNT_ID_RE, St as decodeChainCause, T as BYTES32_RE, Tt as isFailureMode, U as toChainId, V as toAuthUserId, W as toCountryCode, X as toHandle, Y as toEpochSeconds, Z as toJwtToken, _ as normalizeBindingEmail, _t as CHAIN_UPSTREAMS, at as toSessionToken, b as CONFIGURED_MONEY_ASSETS, bt as chainCauseProperties, c as AuthCachePortTag, ct as toWeiAmount, d as authClientPortFromPromiseAdapter, dt as decodeConvexError, et as toPartyId, f as AuthClientError, ft as CAPXUL_ERROR_CODES, gt as isCapxulError, h as orgRoleKeyForLabel, ht as Errors, i as BrowserAuthCacheAdapter, it as toRoleKey, j as SUPPORTED_CURRENCY_CODES, k as EMAIL_RE$1, kt as redactSecrets, l as SystemClockLayer, lt as validateHandle, m as ADMIN_ROLE_LABEL, mt as EXPECTED_OPERATION_OUTCOMES, nt as toPayrollRunId, ot as toTesterKind, p as AuthClientPortTag, pt as CapxulError, q as toEmail, r as InMemoryAuthCacheAdapter, rt as toPublishableKey, st as toTxHash, tt as toPayrollGroupId, u as ClockPortTag, ut as HANDLE_RE$1, v as BASE_SEPOLIA_CHAIN_ID, vt as FAILURE_MODES$1, w as ASSET_ID_RE, wt as isChainUpstream, x as configuredMoneyAssetById, xt as chainEvidenceLabel, y as deriveCapxulSafeAddress, yt as boundedResponseHeaders } from "./OAuthBearerAuthClient-BqQz-bnO.mjs";
|
|
2
2
|
import { formatUnits, keccak256, parseUnits, recoverAddress, stringToHex, toBytes } from "viem";
|
|
3
3
|
import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, Layer, Logger, Metric, Option, Queue, Ref, References, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stream, Tracer } from "effect";
|
|
4
4
|
import { getFunctionName, makeFunctionReference } from "convex/server";
|
|
@@ -406,6 +406,259 @@ const isRestoring = (state) => {
|
|
|
406
406
|
* it in #1521; this ticket ships the selector they move onto. */
|
|
407
407
|
const isClaimed = (state) => state.phase === "authenticated" && state.account.at === "claimed";
|
|
408
408
|
//#endregion
|
|
409
|
+
//#region src/domain/money/parse-money.ts
|
|
410
|
+
/**
|
|
411
|
+
* ADR-0023 R1: the reason is a closed code and the ONLY failure vocabulary —
|
|
412
|
+
* the consuming app maps each code to its own sentence. The SDK ships no
|
|
413
|
+
* English for user-text failure.
|
|
414
|
+
*/
|
|
415
|
+
function isMoneyParseError(value) {
|
|
416
|
+
return "kind" in value;
|
|
417
|
+
}
|
|
418
|
+
const AMOUNT_PATTERN = /^(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?$/;
|
|
419
|
+
const ZERO_PATTERN = /^0+(?:\.0+)?$/;
|
|
420
|
+
function parseMoney(input, asset) {
|
|
421
|
+
const parsed = parseDecimalInput(input, asset.decimals, 24);
|
|
422
|
+
return "kind" in parsed ? parsed : {
|
|
423
|
+
currency: asset.currency,
|
|
424
|
+
value: parsed.value,
|
|
425
|
+
decimals: asset.decimals
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
/** Shared input grammar. Callers retain their own amount size limits. */
|
|
429
|
+
function parseDecimalInput(input, decimals, maximumLength) {
|
|
430
|
+
if (!Number.isInteger(decimals) || decimals < 0) throw Errors.invalidInput("asset.decimals", "must be a non-negative integer");
|
|
431
|
+
const value = input.trim();
|
|
432
|
+
if (value.length === 0) return {
|
|
433
|
+
kind: "error",
|
|
434
|
+
reason: "required"
|
|
435
|
+
};
|
|
436
|
+
if (value.length > maximumLength) return {
|
|
437
|
+
kind: "error",
|
|
438
|
+
reason: "too-long"
|
|
439
|
+
};
|
|
440
|
+
const negative = value.startsWith("-");
|
|
441
|
+
const unsigned = negative ? value.slice(1) : value;
|
|
442
|
+
if (!AMOUNT_PATTERN.test(unsigned)) return {
|
|
443
|
+
kind: "error",
|
|
444
|
+
reason: "invalid-format"
|
|
445
|
+
};
|
|
446
|
+
if (negative) return {
|
|
447
|
+
kind: "error",
|
|
448
|
+
reason: "non-positive"
|
|
449
|
+
};
|
|
450
|
+
const normalized = unsigned.replaceAll(",", "");
|
|
451
|
+
const fraction = normalized.split(".")[1];
|
|
452
|
+
if (fraction !== void 0 && fraction.length > decimals) return {
|
|
453
|
+
kind: "error",
|
|
454
|
+
reason: "too-many-decimals"
|
|
455
|
+
};
|
|
456
|
+
if (ZERO_PATTERN.test(normalized)) return {
|
|
457
|
+
kind: "error",
|
|
458
|
+
reason: "non-positive"
|
|
459
|
+
};
|
|
460
|
+
return { value: normalized };
|
|
461
|
+
}
|
|
462
|
+
//#endregion
|
|
463
|
+
//#region src/domain/money/asset-amount.ts
|
|
464
|
+
/** Convert raw units without rounding or changing asset identity. */
|
|
465
|
+
function assetAmountFromRaw(raw, asset) {
|
|
466
|
+
validateMetadata(asset);
|
|
467
|
+
return {
|
|
468
|
+
asset: asset.assetId,
|
|
469
|
+
value: formatUnits(decimalToRaw(toWeiAmount(raw), 0), asset.decimals)
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
/** Exact scaling. This rejects excess precision instead of rounding it. */
|
|
473
|
+
function toRaw(amount, asset) {
|
|
474
|
+
validateMetadata(asset);
|
|
475
|
+
if (amount.asset !== asset.assetId) throw Errors.invalidInput("amount.asset", "must match the selected asset on its chain");
|
|
476
|
+
return decimalToRaw(amount.value, asset.decimals);
|
|
477
|
+
}
|
|
478
|
+
function parseAssetAmount(input, asset) {
|
|
479
|
+
validateMetadata(asset);
|
|
480
|
+
const parsed = parseDecimalInput(input, asset.decimals, 100);
|
|
481
|
+
return "kind" in parsed ? parsed : {
|
|
482
|
+
asset: asset.assetId,
|
|
483
|
+
value: parsed.value.replace(/^0+(?=\d)/, "")
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
/** Display the full quantity. Only fiat formatting rounds for display. */
|
|
487
|
+
function formatAssetAmount(amount) {
|
|
488
|
+
const asset = requireAsset(amount.asset);
|
|
489
|
+
const [integer = "0", fraction] = formatUnits(toRaw(amount, asset), asset.decimals).split(".");
|
|
490
|
+
return `${integer.replace(/\B(?=(\d{3})+(?!\d))/g, ",")}${fraction === void 0 ? "" : `.${fraction}`} ${asset.symbol}`;
|
|
491
|
+
}
|
|
492
|
+
function assetSymbolFor(asset) {
|
|
493
|
+
return requireAsset(asset).symbol;
|
|
494
|
+
}
|
|
495
|
+
function requireAsset(id) {
|
|
496
|
+
const asset = configuredMoneyAssetById(id);
|
|
497
|
+
if (asset === null) throw Errors.invalidInput("amount.asset", "is not a registered asset");
|
|
498
|
+
return asset;
|
|
499
|
+
}
|
|
500
|
+
function decimalToRaw(value, decimals) {
|
|
501
|
+
validatePrecision(decimals);
|
|
502
|
+
if (!/^\d+(?:\.\d+)?$/.test(value) || value.trim() !== value || value.length > 512) throw Errors.invalidInput("amount.value", "must be a non-negative decimal string of at most 512 characters");
|
|
503
|
+
const [integer = "0", fraction = ""] = value.split(".");
|
|
504
|
+
if (fraction.length > decimals) throw Errors.invalidInput("amount.value", "fraction exceeds asset precision");
|
|
505
|
+
return BigInt(integer) * 10n ** BigInt(decimals) + BigInt(fraction.padEnd(decimals, "0") || "0");
|
|
506
|
+
}
|
|
507
|
+
function validatePrecision(decimals) {
|
|
508
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 255) throw Errors.invalidInput("decimals", "must be an integer from 0 to 255");
|
|
509
|
+
}
|
|
510
|
+
function validateMetadata(asset) {
|
|
511
|
+
validatePrecision(asset.decimals);
|
|
512
|
+
if (asset.assetId !== assetIdFor(asset.chainId, asset.tokenAddress)) throw Errors.invalidInput("amount.asset", "metadata must match its chain and token");
|
|
513
|
+
}
|
|
514
|
+
//#endregion
|
|
515
|
+
//#region src/domain/money/valuation.ts
|
|
516
|
+
const PEG_RATES = (source, into) => (typeof source === "string" ? source : source.peg) === into ? {
|
|
517
|
+
value: "1",
|
|
518
|
+
decimals: 0
|
|
519
|
+
} : null;
|
|
520
|
+
/**
|
|
521
|
+
* The oracle the money READS price with: the account headline, the org
|
|
522
|
+
* treasury headline, and every later total over the same seam (D6).
|
|
523
|
+
*
|
|
524
|
+
* It is `PEG_RATES` today because no price feed exists yet, and a peg is a
|
|
525
|
+
* relationship, not a market price — so an unpegged asset such as WETH reads
|
|
526
|
+
* as unrated rather than as a fabricated number. This binding is the ONE place
|
|
527
|
+
* a real feed arrives; no call site changes when it does.
|
|
528
|
+
*/
|
|
529
|
+
const MONEY_READ_RATES = PEG_RATES;
|
|
530
|
+
/** Sum exact fixed-point values. Missing rates never contribute zero. */
|
|
531
|
+
function valueIn(amounts, displayCurrency, rates = PEG_RATES) {
|
|
532
|
+
const currency = toCurrencyCode(displayCurrency);
|
|
533
|
+
const counted = [];
|
|
534
|
+
const unrated = [];
|
|
535
|
+
let sum = 0n;
|
|
536
|
+
let scale = 0;
|
|
537
|
+
for (const amount of amounts) {
|
|
538
|
+
let source;
|
|
539
|
+
let raw;
|
|
540
|
+
let decimals;
|
|
541
|
+
if ("asset" in amount) {
|
|
542
|
+
source = requireAsset(amount.asset);
|
|
543
|
+
raw = toRaw(amount, source);
|
|
544
|
+
decimals = source.decimals;
|
|
545
|
+
} else {
|
|
546
|
+
source = toCurrencyCode(amount.currency);
|
|
547
|
+
raw = decimalToRaw(amount.value, amount.decimals);
|
|
548
|
+
decimals = amount.decimals;
|
|
549
|
+
}
|
|
550
|
+
const rate = rates(source, currency);
|
|
551
|
+
if (rate === null) {
|
|
552
|
+
unrated.push(amount);
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
validatePrecision(rate.decimals);
|
|
556
|
+
if (!/^\d+$/.test(rate.value) || rate.value.trim() !== rate.value || rate.value.length > 256 || BigInt(rate.value) <= 0n) throw Errors.invalidInput("rate.value", "must be a positive fixed-point integer");
|
|
557
|
+
const termScale = decimals + rate.decimals;
|
|
558
|
+
const nextScale = Math.max(scale, termScale);
|
|
559
|
+
sum = sum * 10n ** BigInt(nextScale - scale) + raw * BigInt(rate.value) * 10n ** BigInt(nextScale - termScale);
|
|
560
|
+
scale = nextScale;
|
|
561
|
+
counted.push(amount);
|
|
562
|
+
}
|
|
563
|
+
return {
|
|
564
|
+
total: counted.length === 0 ? null : {
|
|
565
|
+
currency,
|
|
566
|
+
value: formatUnits(sum, scale),
|
|
567
|
+
decimals: scale
|
|
568
|
+
},
|
|
569
|
+
counted,
|
|
570
|
+
unrated
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
//#endregion
|
|
574
|
+
//#region src/domain/money/account-positions.ts
|
|
575
|
+
/**
|
|
576
|
+
* Lift an Account's raw per-asset positions to the SDK's `AccountPosition`.
|
|
577
|
+
*
|
|
578
|
+
* A position whose `assetId` is not a registered asset refuses. An unregistered
|
|
579
|
+
* token has no identity this SDK can state, so it must never be relabelled as
|
|
580
|
+
* one — the failure is the point, not a row to skip.
|
|
581
|
+
*/
|
|
582
|
+
function accountPositionsFromWire(positions) {
|
|
583
|
+
return positions.map((position) => {
|
|
584
|
+
const asset = configuredMoneyAssetById(toAssetId(position.assetId));
|
|
585
|
+
if (asset === null) throw Errors.invalidInput("assetId", "is not a registered asset");
|
|
586
|
+
const raw = toWeiAmount(position.rawBalance);
|
|
587
|
+
const rawAvailable = toWeiAmount(position.rawAvailableBalance ?? position.rawBalance);
|
|
588
|
+
return {
|
|
589
|
+
asset: asset.assetId,
|
|
590
|
+
symbol: asset.symbol,
|
|
591
|
+
decimals: asset.decimals,
|
|
592
|
+
balance: assetAmountFromRaw(raw, asset).value,
|
|
593
|
+
available: assetAmountFromRaw(rawAvailable, asset).value
|
|
594
|
+
};
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* The fiat currency a position is denominated in: the registry peg of its
|
|
599
|
+
* asset, or `null` when that asset carries no peg (ADR-0028 R3/R4).
|
|
600
|
+
*
|
|
601
|
+
* A consumer must denominate a token amount in the position's OWN peg. The
|
|
602
|
+
* Account's `available.currency` is the display currency of a multi-asset
|
|
603
|
+
* VALUATION (ADR-0028 R6). It is `"USD"` for every Account regardless of what
|
|
604
|
+
* is held, so reading it as a position's denomination labels a token with the
|
|
605
|
+
* headline's fiat — the false identity this cut removes.
|
|
606
|
+
*/
|
|
607
|
+
function positionPeg(asset) {
|
|
608
|
+
return configuredMoneyAssetById(asset)?.peg ?? null;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* The fiat headline of a set of positions: the sum of the positions the given
|
|
612
|
+
* oracle can rate into the display currency (ADR-0028 R6, D6). It never picks
|
|
613
|
+
* a token and never labels one as fiat.
|
|
614
|
+
*
|
|
615
|
+
* The oracle is a PARAMETER (D6 obligation 4). It defaults to `PEG_RATES`, which
|
|
616
|
+
* only rates an asset whose peg equals the display currency, so an unpegged
|
|
617
|
+
* asset such as WETH stays out of the total and out of `counted`:
|
|
618
|
+
* a WETH-only Account reads a `$0.00` headline under that default. Hand it a
|
|
619
|
+
* real oracle and the same Account prices (WETH at `$2000` under
|
|
620
|
+
* `createMockRates`, a live feed later).
|
|
621
|
+
*
|
|
622
|
+
* Either way the unrated position is never zeroed and never dropped: it stays
|
|
623
|
+
* in `Account.balances`, and `valueIn` reports it in its own `unrated` list so
|
|
624
|
+
* a caller can say how complete the total is.
|
|
625
|
+
*/
|
|
626
|
+
function headlineValuation(balances, displayCurrency, rates = PEG_RATES) {
|
|
627
|
+
const total = (pick) => valueIn(balances.map((position) => ({
|
|
628
|
+
asset: position.asset,
|
|
629
|
+
value: pick(position)
|
|
630
|
+
})), displayCurrency, rates).total ?? {
|
|
631
|
+
currency: displayCurrency,
|
|
632
|
+
value: "0",
|
|
633
|
+
decimals: 0
|
|
634
|
+
};
|
|
635
|
+
return {
|
|
636
|
+
balance: total((position) => position.balance),
|
|
637
|
+
available: total((p) => p.available)
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* The Account: its per-asset truth plus the fiat headline valuation. The oracle
|
|
642
|
+
* is threaded from the read that built it, never defaulted past this point
|
|
643
|
+
* (D6): the account read passes the configured one.
|
|
644
|
+
*/
|
|
645
|
+
function accountFromPositions(id, positions, displayCurrency = toCurrencyCode("USD"), rates = PEG_RATES) {
|
|
646
|
+
const balances = accountPositionsFromWire(positions);
|
|
647
|
+
return {
|
|
648
|
+
id,
|
|
649
|
+
balances,
|
|
650
|
+
...headlineValuation(balances, displayCurrency, rates)
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
/** The same lift for positions a caller already holds as `AccountPosition`. */
|
|
654
|
+
function accountFromAccountPositions(id, balances, displayCurrency = toCurrencyCode("USD"), rates = PEG_RATES) {
|
|
655
|
+
return {
|
|
656
|
+
id,
|
|
657
|
+
balances,
|
|
658
|
+
...headlineValuation(balances, displayCurrency, rates)
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
//#endregion
|
|
409
662
|
//#region ../observability/src/operations.ts
|
|
410
663
|
const CAPXUL_OPERATIONS = {
|
|
411
664
|
account: {
|
|
@@ -474,6 +727,26 @@ const CAPXUL_OPERATIONS = {
|
|
|
474
727
|
createOrg: "createOrg",
|
|
475
728
|
orgs: "orgs"
|
|
476
729
|
},
|
|
730
|
+
/** AUTH A3 (#2073): the SDK facade over the native continuation endpoints. */
|
|
731
|
+
clientRequests: {
|
|
732
|
+
decide: "clientRequests.decide",
|
|
733
|
+
read: "clientRequests.read"
|
|
734
|
+
},
|
|
735
|
+
/** AUTH A2 (#2072): the native client authorization issuer and its browser
|
|
736
|
+
* continuation. One name per durable transition the endpoints can fail on. */
|
|
737
|
+
clientAuthorization: {
|
|
738
|
+
acceptRequest: "clientAuthorization.acceptRequest",
|
|
739
|
+
cancelRequest: "clientAuthorization.cancelRequest",
|
|
740
|
+
consumeRequest: "clientAuthorization.consumeRequest",
|
|
741
|
+
denyRequest: "clientAuthorization.denyRequest",
|
|
742
|
+
invalidateContext: "clientAuthorization.invalidateContext",
|
|
743
|
+
markConsented: "clientAuthorization.markConsented",
|
|
744
|
+
readMetadata: "clientAuthorization.readMetadata",
|
|
745
|
+
revokeGrant: "clientAuthorization.revokeGrant",
|
|
746
|
+
rotateGrant: "clientAuthorization.rotateGrant",
|
|
747
|
+
startRequest: "clientAuthorization.startRequest",
|
|
748
|
+
sweepExpired: "clientAuthorization.sweepExpired"
|
|
749
|
+
},
|
|
477
750
|
credentials: {
|
|
478
751
|
bootstrapClient: "credentials.bootstrapClient",
|
|
479
752
|
mintQuickstartKey: "credentials.mintQuickstartKey"
|
|
@@ -972,6 +1245,44 @@ const IdentityRefusedProps = Schema.Struct({
|
|
|
972
1245
|
state: OptionalString
|
|
973
1246
|
});
|
|
974
1247
|
const AuthSignedOutProps = Schema.Struct(TelemetryEnvelopeProps);
|
|
1248
|
+
const NativeAuthorizationMode = Schema.Literals(["login", "signup"]);
|
|
1249
|
+
const NativeAuthorizationStartedProps = Schema.Struct({
|
|
1250
|
+
...TelemetryEnvelopeProps,
|
|
1251
|
+
mode: NativeAuthorizationMode
|
|
1252
|
+
});
|
|
1253
|
+
const NativeAuthorizationReviewedProps = Schema.Struct({
|
|
1254
|
+
...TelemetryEnvelopeProps,
|
|
1255
|
+
mode: NativeAuthorizationMode
|
|
1256
|
+
});
|
|
1257
|
+
const NativeAuthorizationAcceptedProps = Schema.Struct({
|
|
1258
|
+
...TelemetryEnvelopeProps,
|
|
1259
|
+
mode: NativeAuthorizationMode,
|
|
1260
|
+
/** Whether consent also had to finish account setup first. */
|
|
1261
|
+
setup_state: Schema.optional(Schema.Literals([
|
|
1262
|
+
"not_required",
|
|
1263
|
+
"new",
|
|
1264
|
+
"resumable"
|
|
1265
|
+
]))
|
|
1266
|
+
});
|
|
1267
|
+
const NativeAuthorizationDeniedProps = Schema.Struct({
|
|
1268
|
+
...TelemetryEnvelopeProps,
|
|
1269
|
+
mode: NativeAuthorizationMode
|
|
1270
|
+
});
|
|
1271
|
+
const NativeAuthorizationConnectedProps = Schema.Struct({
|
|
1272
|
+
...TelemetryEnvelopeProps,
|
|
1273
|
+
mode: NativeAuthorizationMode
|
|
1274
|
+
});
|
|
1275
|
+
const NativeAuthorizationFailedProps = Schema.Struct({
|
|
1276
|
+
...TelemetryEnvelopeProps,
|
|
1277
|
+
mode: Schema.optional(NativeAuthorizationMode),
|
|
1278
|
+
/** The refusal word the store returned, for example `identity_mismatch` or
|
|
1279
|
+
* `request_expired`. These are the closed `CLIENT_AUTHORIZATION_REFUSALS` from
|
|
1280
|
+
* `@capxul/wire` plus the store-internal `fresh_session_required` (ruling R3),
|
|
1281
|
+
* which the continuation maps to `identity_mismatch` on the wire but reports
|
|
1282
|
+
* truthfully here. Kept as `OptionalString` rather than an imported literal
|
|
1283
|
+
* set: this package must not depend on the transport contract. */
|
|
1284
|
+
reason: OptionalString
|
|
1285
|
+
});
|
|
975
1286
|
const ProvisioningSafeCreatedProps = Schema.Struct({
|
|
976
1287
|
...TelemetryEnvelopeProps,
|
|
977
1288
|
safe_address: OptionalAddress
|
|
@@ -1014,6 +1325,12 @@ const BootstrapFailedProps = Schema.Struct({
|
|
|
1014
1325
|
* Organization row's chain, the configured token address — never from a label.
|
|
1015
1326
|
* The verified `organization_id` and its group arrive from the backend
|
|
1016
1327
|
* attribution, so they are not repeated here.
|
|
1328
|
+
*
|
|
1329
|
+
* D1 (2026-09-10): `asset_id` carries the canonical branded identity the read
|
|
1330
|
+
* resolved, `eip155:<chainId>/erc20:<lowercase-address>`, from the registry
|
|
1331
|
+
* row. `token_address`/`chain_id` are its parts; `currency` is the peg and a
|
|
1332
|
+
* display code. The producer emits the branded id so the live read can be
|
|
1333
|
+
* grouped by ASSET, never by symbol or peg.
|
|
1017
1334
|
*/
|
|
1018
1335
|
const AccountBalanceReadProps = Schema.Struct({
|
|
1019
1336
|
...TelemetryEnvelopeProps,
|
|
@@ -1021,6 +1338,7 @@ const AccountBalanceReadProps = Schema.Struct({
|
|
|
1021
1338
|
account_kind: OptionalAccountKind,
|
|
1022
1339
|
chain_id: OptionalChainId,
|
|
1023
1340
|
token_address: OptionalAddress,
|
|
1341
|
+
asset_id: OptionalString,
|
|
1024
1342
|
currency: OptionalCurrencyCode,
|
|
1025
1343
|
balance_bucket: OptionalBalanceBucket,
|
|
1026
1344
|
durationMs: OptionalDurationMs
|
|
@@ -1489,6 +1807,30 @@ Schema.Struct({
|
|
|
1489
1807
|
name: Schema.Literal("auth_signed_out"),
|
|
1490
1808
|
props: AuthSignedOutProps
|
|
1491
1809
|
});
|
|
1810
|
+
Schema.Struct({
|
|
1811
|
+
name: Schema.Literal("native_authorization_started"),
|
|
1812
|
+
props: NativeAuthorizationStartedProps
|
|
1813
|
+
});
|
|
1814
|
+
Schema.Struct({
|
|
1815
|
+
name: Schema.Literal("native_authorization_reviewed"),
|
|
1816
|
+
props: NativeAuthorizationReviewedProps
|
|
1817
|
+
});
|
|
1818
|
+
Schema.Struct({
|
|
1819
|
+
name: Schema.Literal("native_authorization_accepted"),
|
|
1820
|
+
props: NativeAuthorizationAcceptedProps
|
|
1821
|
+
});
|
|
1822
|
+
Schema.Struct({
|
|
1823
|
+
name: Schema.Literal("native_authorization_denied"),
|
|
1824
|
+
props: NativeAuthorizationDeniedProps
|
|
1825
|
+
});
|
|
1826
|
+
Schema.Struct({
|
|
1827
|
+
name: Schema.Literal("native_authorization_connected"),
|
|
1828
|
+
props: NativeAuthorizationConnectedProps
|
|
1829
|
+
});
|
|
1830
|
+
Schema.Struct({
|
|
1831
|
+
name: Schema.Literal("native_authorization_failed"),
|
|
1832
|
+
props: NativeAuthorizationFailedProps
|
|
1833
|
+
});
|
|
1492
1834
|
Schema.Struct({
|
|
1493
1835
|
name: Schema.Literal("onboarding_intent_selected"),
|
|
1494
1836
|
props: OnboardingIntentSelectedProps
|
|
@@ -1743,12 +2085,18 @@ const CLI_COMMAND_NAMES = [
|
|
|
1743
2085
|
"telemetry.status",
|
|
1744
2086
|
"telemetry.enable",
|
|
1745
2087
|
"telemetry.disable",
|
|
2088
|
+
"auth",
|
|
2089
|
+
"auth.login",
|
|
2090
|
+
"auth.signup",
|
|
2091
|
+
"auth.status",
|
|
2092
|
+
"auth.logout",
|
|
1746
2093
|
"unknown"
|
|
1747
2094
|
];
|
|
1748
2095
|
const CLI_CAPABILITIES = [
|
|
1749
2096
|
"cli",
|
|
1750
2097
|
"diagnostics",
|
|
1751
|
-
"collection"
|
|
2098
|
+
"collection",
|
|
2099
|
+
"authentication"
|
|
1752
2100
|
];
|
|
1753
2101
|
const CLI_INVOCATION_KINDS = [
|
|
1754
2102
|
"command",
|
|
@@ -1766,8 +2114,9 @@ const CliInvocationProps = {
|
|
|
1766
2114
|
capability: Schema.Literals(CLI_CAPABILITIES),
|
|
1767
2115
|
invocation_kind: Schema.Literals(CLI_INVOCATION_KINDS),
|
|
1768
2116
|
invocation_id: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u)),
|
|
1769
|
-
cli_identity_kind: Schema.optional(Schema.
|
|
2117
|
+
cli_identity_kind: Schema.optional(Schema.Literals(["anonymous", "identified"])),
|
|
1770
2118
|
anonymous_id: Schema.optional(Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u))),
|
|
2119
|
+
auth_user_id: Schema.optional(Schema.String.check(Schema.isPattern(/^[^\s]{1,256}$/u))),
|
|
1771
2120
|
occurred_at: Schema.Number,
|
|
1772
2121
|
cli_version: CliRelease,
|
|
1773
2122
|
sdk_version: CliRelease,
|
|
@@ -4446,8 +4795,7 @@ const country = normalize((s) => s.toUpperCase()).pipe(Schema.refine((s) => COUN
|
|
|
4446
4795
|
const credential = Schema.RedactedFromValue(Schema.String.check(Schema.isMinLength(32), Schema.isMaxLength(8192), Schema.isPattern(/^[A-Za-z0-9._~-]+$/u)), { label: "native authorization credential" });
|
|
4447
4796
|
const otp = Schema.RedactedFromValue(Schema.String.check(Schema.isPattern(/^[0-9]{6}$/u)), { label: "OTP" });
|
|
4448
4797
|
const scopes = Schema.Tuple([Schema.Literal(NATIVE_CLIENT_SCOPE)]);
|
|
4449
|
-
|
|
4450
|
-
const NativeHttpsOriginSchema = Schema.String.check(Schema.makeFilter((value) => {
|
|
4798
|
+
const isNativeHttpsOriginValue = (value) => {
|
|
4451
4799
|
try {
|
|
4452
4800
|
const url = new URL(value);
|
|
4453
4801
|
const host = url.hostname.toLowerCase().replace(/\.$/u, "");
|
|
@@ -4455,20 +4803,43 @@ const NativeHttpsOriginSchema = Schema.String.check(Schema.makeFilter((value) =>
|
|
|
4455
4803
|
} catch {
|
|
4456
4804
|
return false;
|
|
4457
4805
|
}
|
|
4458
|
-
}
|
|
4806
|
+
};
|
|
4807
|
+
Schema.String.check(Schema.makeFilter(isNativeHttpsOriginValue, { message: "must be a canonical credential-free HTTPS origin outside retired Convex cloud hosts" }));
|
|
4808
|
+
const isLoopbackOriginValue = (value) => {
|
|
4809
|
+
try {
|
|
4810
|
+
const url = new URL(value);
|
|
4811
|
+
const host = url.hostname.toLowerCase().replace(/\.$/u, "");
|
|
4812
|
+
return url.protocol === "http:" && value === url.origin && !url.username && !url.password && !url.search && !url.hash && (host === "127.0.0.1" || host === "[::1]" || host === "localhost");
|
|
4813
|
+
} catch {
|
|
4814
|
+
return false;
|
|
4815
|
+
}
|
|
4816
|
+
};
|
|
4817
|
+
Schema.String.check(Schema.makeFilter(isLoopbackOriginValue, { message: "must be a canonical credential-free loopback HTTP origin" }));
|
|
4818
|
+
/**
|
|
4819
|
+
* Either a standing-tier HTTPS origin or a devnet loopback origin. A `Union` of
|
|
4820
|
+
* the two refined string schemas does not type-check in this Effect version —
|
|
4821
|
+
* it widens both fields to `unknown` — so the disjunction lives in one filter
|
|
4822
|
+
* and the struct check below is what binds a loopback origin to
|
|
4823
|
+
* `environment: "local"`. Loopback is never admissible on a standing tier.
|
|
4824
|
+
*/
|
|
4825
|
+
const NativeOriginSchema = Schema.String.check(Schema.makeFilter((value) => isNativeHttpsOriginValue(value) || isLoopbackOriginValue(value), { message: "must be a canonical credential-free HTTPS origin outside retired Convex cloud hosts, or a loopback HTTP origin for the local devnet" }));
|
|
4459
4826
|
const NativeClientConfigurationSchema = Schema.Struct({
|
|
4460
4827
|
clientId: Schema.Literal(NATIVE_CLIENT_ID),
|
|
4461
4828
|
applicationId: AppIdSchema,
|
|
4462
4829
|
keyId,
|
|
4463
4830
|
environment: Schema.Literals([
|
|
4831
|
+
"local",
|
|
4464
4832
|
"development",
|
|
4465
4833
|
"staging",
|
|
4466
4834
|
"production"
|
|
4467
4835
|
]),
|
|
4468
4836
|
keyEnvironment: Schema.Literals(["test", "live"]),
|
|
4469
|
-
issuer:
|
|
4470
|
-
verificationOrigin:
|
|
4471
|
-
}).annotate(strict).check(Schema.makeFilter((c) => c.keyEnvironment === (c.environment === "production" ? "live" : "test"), { message: "key environment must match the configured deployment" })).
|
|
4837
|
+
issuer: NativeOriginSchema,
|
|
4838
|
+
verificationOrigin: NativeOriginSchema
|
|
4839
|
+
}).annotate(strict).check(Schema.makeFilter((c) => c.keyEnvironment === (c.environment === "production" ? "live" : "test"), { message: "key environment must match the configured deployment" })).check(Schema.makeFilter((c) => {
|
|
4840
|
+
const loopback = isLoopbackOriginValue(c.issuer) || isLoopbackOriginValue(c.verificationOrigin);
|
|
4841
|
+
return c.environment === "local" ? isLoopbackOriginValue(c.issuer) && isLoopbackOriginValue(c.verificationOrigin) : !loopback;
|
|
4842
|
+
}, { message: "loopback origins belong to the local devnet environment alone" })).annotate(strict);
|
|
4472
4843
|
const NativeSignupProfileSchema = Schema.Struct({
|
|
4473
4844
|
displayName: normalize((s) => s.trim()).check(Schema.isMinLength(1), Schema.isMaxLength(200)),
|
|
4474
4845
|
country,
|
|
@@ -4522,7 +4893,7 @@ const profileSummary = {
|
|
|
4522
4893
|
handle,
|
|
4523
4894
|
country
|
|
4524
4895
|
};
|
|
4525
|
-
Schema.Union([
|
|
4896
|
+
const ClientRequestViewSchema = Schema.Union([
|
|
4526
4897
|
Schema.Struct({
|
|
4527
4898
|
...request,
|
|
4528
4899
|
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.OTP_REQUIRED),
|
|
@@ -4589,8 +4960,7 @@ Schema.Struct({
|
|
|
4589
4960
|
Schema.Struct({
|
|
4590
4961
|
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
4591
4962
|
grant_type: Schema.Literal("refresh_token"),
|
|
4592
|
-
refresh_token: credential
|
|
4593
|
-
refreshAttemptId: Schema.RedactedFromValue(Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{32,128}$/u)), { label: "refresh attempt" })
|
|
4963
|
+
refresh_token: credential
|
|
4594
4964
|
}).annotate(strict);
|
|
4595
4965
|
Schema.Struct({
|
|
4596
4966
|
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
@@ -4662,6 +5032,33 @@ Schema.Struct({
|
|
|
4662
5032
|
maximum: NATIVE_CLIENT_LIMITS.requestMs / 1e3
|
|
4663
5033
|
}))
|
|
4664
5034
|
}).annotate(strict);
|
|
5035
|
+
Schema.Struct({
|
|
5036
|
+
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
5037
|
+
token: credential,
|
|
5038
|
+
token_type_hint: Schema.optional(Schema.Literals([
|
|
5039
|
+
"access_token",
|
|
5040
|
+
"refresh_token",
|
|
5041
|
+
"device_code"
|
|
5042
|
+
]))
|
|
5043
|
+
}).annotate(strict);
|
|
5044
|
+
Schema.Struct({
|
|
5045
|
+
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
5046
|
+
token: credential
|
|
5047
|
+
}).annotate(strict);
|
|
5048
|
+
Schema.Struct({
|
|
5049
|
+
error: Schema.Literals([
|
|
5050
|
+
"authorization_pending",
|
|
5051
|
+
"slow_down",
|
|
5052
|
+
"access_denied",
|
|
5053
|
+
"invalid_grant",
|
|
5054
|
+
"invalid_request",
|
|
5055
|
+
"expired_token",
|
|
5056
|
+
"server_error"
|
|
5057
|
+
]),
|
|
5058
|
+
refusal: Schema.optional(Schema.Literals(CLIENT_AUTHORIZATION_REFUSALS)),
|
|
5059
|
+
retryable: Schema.Boolean,
|
|
5060
|
+
retry_after: Schema.optional(nonNegativeInt)
|
|
5061
|
+
}).annotate(strict);
|
|
4665
5062
|
//#endregion
|
|
4666
5063
|
//#region src/internal/invocation-observation.ts
|
|
4667
5064
|
const INVOCATION_OBSERVATION = Symbol("capxul.invocation-observation");
|
|
@@ -6822,7 +7219,7 @@ function subscribeActivity(deps, actor, controls, onChange) {
|
|
|
6822
7219
|
}
|
|
6823
7220
|
//#endregion
|
|
6824
7221
|
//#region package.json
|
|
6825
|
-
var version = "4.20.0-beta.
|
|
7222
|
+
var version = "4.20.0-beta.5";
|
|
6826
7223
|
//#endregion
|
|
6827
7224
|
//#region src/telemetry/exception-projection.ts
|
|
6828
7225
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -9411,7 +9808,7 @@ const MINIMAL_ENUM_VALUES = /* @__PURE__ */ new Map([
|
|
|
9411
9808
|
["command", CLI_COMMAND_NAMES],
|
|
9412
9809
|
["capability", CLI_CAPABILITIES],
|
|
9413
9810
|
["invocation_kind", CLI_INVOCATION_KINDS],
|
|
9414
|
-
["cli_identity_kind", ["anonymous"]],
|
|
9811
|
+
["cli_identity_kind", ["anonymous", "identified"]],
|
|
9415
9812
|
["output_mode", ["human", "json"]],
|
|
9416
9813
|
["unit", [
|
|
9417
9814
|
"1",
|
|
@@ -11333,13 +11730,15 @@ var ConvexAccountAdapter = class {
|
|
|
11333
11730
|
#convex;
|
|
11334
11731
|
#fns;
|
|
11335
11732
|
#telemetry;
|
|
11733
|
+
#rates;
|
|
11336
11734
|
constructor(deps) {
|
|
11337
11735
|
this.#convex = deps.convex;
|
|
11338
11736
|
this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$3;
|
|
11339
11737
|
this.#telemetry = deps.telemetry;
|
|
11738
|
+
this.#rates = deps.rates ?? MONEY_READ_RATES;
|
|
11340
11739
|
}
|
|
11341
11740
|
readBalance(input) {
|
|
11342
|
-
return retryIdempotentRead(this.#convex.action(this.#fns.readBalance, copyInvocationObservation(input, { chainId: wireChainId(input.chainId) })), CAPXUL_OPERATIONS.accounts.read, this.#telemetry, input).pipe(Effect.mapError((error) => accountReadErrorFromCapxul("readBalance", error.publicError, error)), Effect.flatMap((wire) => brandAccountEffect("readBalance", wire)), Effect.catchDefect((cause) => Effect.fail(accountReadErrorFromUnknown("readBalance", cause))));
|
|
11741
|
+
return retryIdempotentRead(this.#convex.action(this.#fns.readBalance, copyInvocationObservation(input, { chainId: wireChainId(input.chainId) })), CAPXUL_OPERATIONS.accounts.read, this.#telemetry, input).pipe(Effect.mapError((error) => accountReadErrorFromCapxul("readBalance", error.publicError, error)), Effect.flatMap((wire) => brandAccountEffect("readBalance", wire, this.#rates)), Effect.catchDefect((cause) => Effect.fail(accountReadErrorFromUnknown("readBalance", cause))));
|
|
11343
11742
|
}
|
|
11344
11743
|
fundFromFaucet(input) {
|
|
11345
11744
|
const operation = "fundFromFaucet";
|
|
@@ -11352,26 +11751,21 @@ var ConvexAccountAdapter = class {
|
|
|
11352
11751
|
}).pipe(Effect.mapError((error) => accountReadErrorFromCapxul(operation, error.publicError, error)), Effect.map((wire) => ({ txHash: wire.txHash })), Effect.catchDefect((cause) => Effect.fail(accountReadErrorFromUnknown(operation, cause))));
|
|
11353
11752
|
}
|
|
11354
11753
|
};
|
|
11355
|
-
function ConvexAccountLayer() {
|
|
11754
|
+
function ConvexAccountLayer(input = {}) {
|
|
11356
11755
|
return Layer.effect(AccountReadPortTag, Effect.all([ConvexCallPortTag, TelemetryPortTag]).pipe(Effect.map(([convex, telemetry]) => new ConvexAccountAdapter({
|
|
11357
11756
|
convex,
|
|
11358
|
-
telemetry
|
|
11757
|
+
telemetry,
|
|
11758
|
+
...input
|
|
11359
11759
|
}))));
|
|
11360
11760
|
}
|
|
11361
|
-
function brandAccountEffect(operation, wire) {
|
|
11761
|
+
function brandAccountEffect(operation, wire, rates) {
|
|
11362
11762
|
return Effect.try({
|
|
11363
|
-
try: () => brandAccount(wire),
|
|
11763
|
+
try: () => brandAccount(wire, rates),
|
|
11364
11764
|
catch: (cause) => accountReadErrorFromUnknown(operation, cause)
|
|
11365
11765
|
});
|
|
11366
11766
|
}
|
|
11367
|
-
function brandAccount(wire) {
|
|
11368
|
-
|
|
11369
|
-
const available = fromWei(wire.rawAvailableBalance ?? wire.rawBalance, wire.decimals, wire.currency);
|
|
11370
|
-
return {
|
|
11371
|
-
id: toAccountId(wire.accountId),
|
|
11372
|
-
balance,
|
|
11373
|
-
available
|
|
11374
|
-
};
|
|
11767
|
+
function brandAccount(wire, rates) {
|
|
11768
|
+
return accountFromPositions(toAccountId(wire.accountId), wire.positions, void 0, rates);
|
|
11375
11769
|
}
|
|
11376
11770
|
function accountReadErrorFromUnknown(operation, cause) {
|
|
11377
11771
|
if (cause instanceof CapxulError) return accountReadErrorFromCapxul(operation, cause);
|
|
@@ -11510,16 +11904,16 @@ function brandOrgView(wire, treasury, viewerRole) {
|
|
|
11510
11904
|
};
|
|
11511
11905
|
}
|
|
11512
11906
|
/**
|
|
11513
|
-
* Build the Org treasury `Account` from the raw
|
|
11514
|
-
* (the D3 RPC
|
|
11515
|
-
* partition yet (a fresh Org reads back
|
|
11907
|
+
* Build the Org treasury `Account` from the raw per-asset `balanceOf` reads
|
|
11908
|
+
* (the D3 RPC pull). `available === balance` for a treasury with no envelope
|
|
11909
|
+
* partition yet (a fresh Org reads back a zero position per asset).
|
|
11910
|
+
*
|
|
11911
|
+
* `rates` is the oracle the headline prices with (D6). The live read passes the
|
|
11912
|
+
* configured one; it defaults to `PEG_RATES` so an unpegged holding reads as
|
|
11913
|
+
* unrated rather than as a number nobody priced.
|
|
11516
11914
|
*/
|
|
11517
11915
|
function brandOrgTreasury(input) {
|
|
11518
|
-
return {
|
|
11519
|
-
id: toAccountId(`account_${orgIdBody(input.orgId)}`),
|
|
11520
|
-
balance: input.money,
|
|
11521
|
-
available: input.money
|
|
11522
|
-
};
|
|
11916
|
+
return accountFromAccountPositions(toAccountId(`account_${orgIdBody(input.orgId)}`), input.balances, void 0, input.rates);
|
|
11523
11917
|
}
|
|
11524
11918
|
function brandOrgRole(wire) {
|
|
11525
11919
|
return {
|
|
@@ -11606,10 +12000,12 @@ var ConvexOrganizationAdapter = class {
|
|
|
11606
12000
|
#convex;
|
|
11607
12001
|
#fns;
|
|
11608
12002
|
#telemetry;
|
|
12003
|
+
#rates;
|
|
11609
12004
|
constructor(input) {
|
|
11610
12005
|
this.#convex = input.convex;
|
|
11611
12006
|
this.#fns = input.functions ?? DEFAULT_FUNCTIONS$1;
|
|
11612
12007
|
this.#telemetry = input.telemetry;
|
|
12008
|
+
this.#rates = input.rates ?? MONEY_READ_RATES;
|
|
11613
12009
|
}
|
|
11614
12010
|
createOrg(_input) {
|
|
11615
12011
|
return Effect.fail(orgErrorFromCapxul("createOrg", Errors.notImplemented("organizationSetup", "use onboarding.completeOrganization")));
|
|
@@ -11657,15 +12053,11 @@ var ConvexOrganizationAdapter = class {
|
|
|
11657
12053
|
const orgId = String(input.orgId);
|
|
11658
12054
|
return retryIdempotentRead(this.#convex.action(this.#fns.readTreasury, copyInvocationObservation(input, { orgId })), CAPXUL_OPERATIONS.org.treasury, this.#telemetry, input).pipe(Effect.mapError((error) => orgErrorFromCapxul("readTreasury", error.publicError, error)), Effect.map((wire) => {
|
|
11659
12055
|
if (wire.orgId !== orgId) throw Errors.invalidInput("orgId", "Organization treasury scope does not match");
|
|
11660
|
-
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11665
|
-
money: balance
|
|
11666
|
-
}),
|
|
11667
|
-
available
|
|
11668
|
-
};
|
|
12056
|
+
return brandOrgTreasury({
|
|
12057
|
+
orgId: wire.orgId,
|
|
12058
|
+
balances: accountPositionsFromWire(wire.positions),
|
|
12059
|
+
rates: this.#rates
|
|
12060
|
+
});
|
|
11669
12061
|
}));
|
|
11670
12062
|
}
|
|
11671
12063
|
};
|
|
@@ -13306,6 +13698,157 @@ function makeAuthMethods(deps) {
|
|
|
13306
13698
|
};
|
|
13307
13699
|
}
|
|
13308
13700
|
//#endregion
|
|
13701
|
+
//#region src/surface/client-requests.ts
|
|
13702
|
+
function decodeView(body) {
|
|
13703
|
+
try {
|
|
13704
|
+
return {
|
|
13705
|
+
ok: true,
|
|
13706
|
+
value: Schema.decodeUnknownSync(ClientRequestViewSchema)(body)
|
|
13707
|
+
};
|
|
13708
|
+
} catch {
|
|
13709
|
+
return {
|
|
13710
|
+
ok: false,
|
|
13711
|
+
error: Errors.invalidInput("clientRequest", "view is not a closed phase")
|
|
13712
|
+
};
|
|
13713
|
+
}
|
|
13714
|
+
}
|
|
13715
|
+
function httpError$1(status) {
|
|
13716
|
+
if (status === 401) return {
|
|
13717
|
+
ok: false,
|
|
13718
|
+
error: Errors.notAuthenticated()
|
|
13719
|
+
};
|
|
13720
|
+
if (status === 404) return {
|
|
13721
|
+
ok: false,
|
|
13722
|
+
error: Errors.invalidInput("requestId", "is not a live request")
|
|
13723
|
+
};
|
|
13724
|
+
if (status === 429) return {
|
|
13725
|
+
ok: false,
|
|
13726
|
+
error: Errors.rateLimited({ resource: "clientRequest" })
|
|
13727
|
+
};
|
|
13728
|
+
return {
|
|
13729
|
+
ok: false,
|
|
13730
|
+
error: Errors.networkError("clientRequests")
|
|
13731
|
+
};
|
|
13732
|
+
}
|
|
13733
|
+
function makeClientRequestMethods(deps) {
|
|
13734
|
+
const fetchImpl = deps.fetch ?? fetch;
|
|
13735
|
+
const urlFor = (path, query) => {
|
|
13736
|
+
const resolved = resolveAuthClientUrl(deps.authBaseUrl, path);
|
|
13737
|
+
return query === void 0 ? resolved : `${resolved}?${query}`;
|
|
13738
|
+
};
|
|
13739
|
+
async function readView(requestId, options) {
|
|
13740
|
+
if (options?.signal?.aborted) return {
|
|
13741
|
+
ok: false,
|
|
13742
|
+
error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.clientRequests.read })
|
|
13743
|
+
};
|
|
13744
|
+
try {
|
|
13745
|
+
const response = await fetchImpl(urlFor("/api/auth/native/request", `requestId=${encodeURIComponent(requestId)}`), {
|
|
13746
|
+
method: "GET",
|
|
13747
|
+
credentials: "include",
|
|
13748
|
+
...options?.signal === void 0 ? {} : { signal: options.signal }
|
|
13749
|
+
});
|
|
13750
|
+
const body = await response.json().catch(() => null);
|
|
13751
|
+
if (!response.ok) {
|
|
13752
|
+
const viewed = decodeView(body);
|
|
13753
|
+
return viewed.ok ? viewed : httpError$1(response.status);
|
|
13754
|
+
}
|
|
13755
|
+
return decodeView(body);
|
|
13756
|
+
} catch (cause) {
|
|
13757
|
+
if (options?.signal?.aborted) return {
|
|
13758
|
+
ok: false,
|
|
13759
|
+
error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.clientRequests.read })
|
|
13760
|
+
};
|
|
13761
|
+
if (isCapxulError(cause)) return {
|
|
13762
|
+
ok: false,
|
|
13763
|
+
error: cause
|
|
13764
|
+
};
|
|
13765
|
+
return {
|
|
13766
|
+
ok: false,
|
|
13767
|
+
error: Errors.networkError("native request read failed")
|
|
13768
|
+
};
|
|
13769
|
+
}
|
|
13770
|
+
}
|
|
13771
|
+
async function postDecision(path, input, options) {
|
|
13772
|
+
if (options?.signal?.aborted) return {
|
|
13773
|
+
ok: false,
|
|
13774
|
+
error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.clientRequests.decide })
|
|
13775
|
+
};
|
|
13776
|
+
try {
|
|
13777
|
+
const response = await fetchImpl(urlFor(path), {
|
|
13778
|
+
method: "POST",
|
|
13779
|
+
credentials: "include",
|
|
13780
|
+
headers: { "content-type": "application/json" },
|
|
13781
|
+
body: JSON.stringify({
|
|
13782
|
+
requestId: input.requestId,
|
|
13783
|
+
revision: input.revision
|
|
13784
|
+
}),
|
|
13785
|
+
...options?.signal === void 0 ? {} : { signal: options.signal }
|
|
13786
|
+
});
|
|
13787
|
+
const viewed = decodeView(await response.json().catch(() => null));
|
|
13788
|
+
if (viewed.ok) return viewed;
|
|
13789
|
+
if (!response.ok) return httpError$1(response.status);
|
|
13790
|
+
return viewed;
|
|
13791
|
+
} catch (cause) {
|
|
13792
|
+
if (options?.signal?.aborted) return {
|
|
13793
|
+
ok: false,
|
|
13794
|
+
error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.clientRequests.decide })
|
|
13795
|
+
};
|
|
13796
|
+
if (isCapxulError(cause)) return {
|
|
13797
|
+
ok: false,
|
|
13798
|
+
error: cause
|
|
13799
|
+
};
|
|
13800
|
+
return {
|
|
13801
|
+
ok: false,
|
|
13802
|
+
error: Errors.networkError("native request decision failed")
|
|
13803
|
+
};
|
|
13804
|
+
}
|
|
13805
|
+
}
|
|
13806
|
+
return {
|
|
13807
|
+
read: (input, options) => readView(input.requestId, options),
|
|
13808
|
+
async sendOtp(input, options) {
|
|
13809
|
+
const view = await readView(input.requestId, options);
|
|
13810
|
+
if (!view.ok) return view;
|
|
13811
|
+
if (view.value.phase !== "otp_required" && view.value.phase !== "review") return {
|
|
13812
|
+
ok: false,
|
|
13813
|
+
error: Errors.wrongState({
|
|
13814
|
+
method: "clientRequests.sendOtp",
|
|
13815
|
+
currentState: view.value.phase,
|
|
13816
|
+
validStates: ["otp_required", "review"]
|
|
13817
|
+
})
|
|
13818
|
+
};
|
|
13819
|
+
const sent = await deps.signIn({ email: view.value.email }, options);
|
|
13820
|
+
if (!sent.ok) return sent;
|
|
13821
|
+
return {
|
|
13822
|
+
ok: true,
|
|
13823
|
+
value: void 0
|
|
13824
|
+
};
|
|
13825
|
+
},
|
|
13826
|
+
async verifyOtp(input, options) {
|
|
13827
|
+
const view = await readView(input.requestId, options);
|
|
13828
|
+
if (!view.ok) return view;
|
|
13829
|
+
if (view.value.phase !== "otp_required" && view.value.phase !== "review") return {
|
|
13830
|
+
ok: false,
|
|
13831
|
+
error: Errors.wrongState({
|
|
13832
|
+
method: "clientRequests.verifyOtp",
|
|
13833
|
+
currentState: view.value.phase,
|
|
13834
|
+
validStates: ["otp_required", "review"]
|
|
13835
|
+
})
|
|
13836
|
+
};
|
|
13837
|
+
const verified = await deps.verifyOtp({
|
|
13838
|
+
email: view.value.email,
|
|
13839
|
+
code: input.code
|
|
13840
|
+
}, options);
|
|
13841
|
+
if (!verified.ok) return verified;
|
|
13842
|
+
return {
|
|
13843
|
+
ok: true,
|
|
13844
|
+
value: void 0
|
|
13845
|
+
};
|
|
13846
|
+
},
|
|
13847
|
+
accept: (input, options) => postDecision("/api/auth/native/request/accept", input, options),
|
|
13848
|
+
cancel: (input, options) => postDecision("/api/auth/native/request/deny", input, options)
|
|
13849
|
+
};
|
|
13850
|
+
}
|
|
13851
|
+
//#endregion
|
|
13309
13852
|
//#region src/surface/smart-account-deps.ts
|
|
13310
13853
|
/** The single Context tag the `smartAccount.*` methods resolve. */
|
|
13311
13854
|
var SmartAccountDepsTag = class extends Context.Service()("@capxul/sdk/SmartAccountDeps") {};
|
|
@@ -14678,18 +15221,15 @@ var OrgDepsTag = class extends Context.Service()("@capxul/sdk/OrgDeps") {};
|
|
|
14678
15221
|
function orgDepsLayer(deps) {
|
|
14679
15222
|
return Layer.succeed(OrgDepsTag, deps);
|
|
14680
15223
|
}
|
|
14681
|
-
/**
|
|
14682
|
-
function zeroMoney() {
|
|
14683
|
-
return fromWei("0", 6, "USD");
|
|
14684
|
-
}
|
|
14685
|
-
/** A fresh Org's treasury Account: `$0` balance, `available === balance`. */
|
|
15224
|
+
/** A fresh Org's treasury Account: a zero position per settlement asset. */
|
|
14686
15225
|
function zeroTreasury(orgId) {
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
15226
|
+
return accountFromAccountPositions(toAccountId(`account_${stripPrefix(orgId)}`), CONFIGURED_MONEY_ASSETS.map((asset) => ({
|
|
15227
|
+
asset: asset.assetId,
|
|
15228
|
+
symbol: asset.symbol,
|
|
15229
|
+
decimals: asset.decimals,
|
|
15230
|
+
balance: "0",
|
|
15231
|
+
available: "0"
|
|
15232
|
+
})), void 0, MONEY_READ_RATES);
|
|
14693
15233
|
}
|
|
14694
15234
|
/** Drop a known `<prefix>_` so the remainder is reusable as another brand seed. */
|
|
14695
15235
|
function stripPrefix(value) {
|
|
@@ -15097,8 +15637,7 @@ function makeOrgMethods(deps) {
|
|
|
15097
15637
|
return {
|
|
15098
15638
|
id: treasuryResult.value.id,
|
|
15099
15639
|
address: org?.safeAddress ?? null,
|
|
15100
|
-
|
|
15101
|
-
available: treasuryResult.value.available
|
|
15640
|
+
balances: treasuryResult.value.balances
|
|
15102
15641
|
};
|
|
15103
15642
|
}), observationOnlyControls(controls), CAPXUL_OPERATIONS.org.account.get, deps.runPromise);
|
|
15104
15643
|
} },
|
|
@@ -15202,23 +15741,27 @@ const organizationPaymentExecutionUnavailable = () => Promise.resolve({
|
|
|
15202
15741
|
const holdingsContract = { current: makeFunctionReference(CAPXUL_FUNCTIONS["holdings/actions"].current) };
|
|
15203
15742
|
//#endregion
|
|
15204
15743
|
//#region src/domain/money/primary-holding.ts
|
|
15205
|
-
const CURRENCY_BY_TOKEN_SYMBOL = /* @__PURE__ */ new Map([["USDX", toCurrencyCode("USD")]]);
|
|
15206
15744
|
/**
|
|
15207
|
-
* The designated display asset: the
|
|
15208
|
-
* `null` when no row is
|
|
15745
|
+
* The designated display asset: the LOWEST `id` among the renderable rows, or
|
|
15746
|
+
* `null` when no row is renderable.
|
|
15209
15747
|
*
|
|
15210
|
-
* A `HoldingRow` (`packages/wire/src/money.ts`) is a RAW CHAIN ROW
|
|
15211
|
-
*
|
|
15212
|
-
*
|
|
15748
|
+
* A `HoldingRow` (`packages/wire/src/money.ts`) is a RAW CHAIN ROW. A native
|
|
15749
|
+
* row has no ERC-20 identity; a row with no `decimals` cannot be lifted into
|
|
15750
|
+
* major units; a row with no `symbol` cannot be named. Each is SKIPPED rather
|
|
15751
|
+
* than reported — a row nobody can render is not a failure of the read.
|
|
15213
15752
|
*
|
|
15214
|
-
*
|
|
15215
|
-
*
|
|
15216
|
-
*
|
|
15217
|
-
*
|
|
15753
|
+
* WHICH row is named is decided by ASSET IDENTITY — ascending `id` — never by
|
|
15754
|
+
* quantity. Two rows with different assets are not comparable money, so no
|
|
15755
|
+
* quantity can order them: 100 USDC is not "more" than 1 WETH without a rate,
|
|
15756
|
+
* and ranking major units would show whatever asset happens to have the most
|
|
15757
|
+
* decimal places as "primary". An identity order is arbitrary as well, but it
|
|
15758
|
+
* is stable and claims nothing about value. ADR-0028 R6 retires
|
|
15759
|
+
* `holdings.primary` outright; this export stays only until that retirement
|
|
15760
|
+
* lands with its remaining consumers, so no new policy is invented here.
|
|
15218
15761
|
*
|
|
15219
15762
|
* This replaces the app's hand pick in `formatCurrentHoldingsBalance`
|
|
15220
15763
|
* (`dashboard-formatters.ts`): a `.find()` over a hardcoded `["USDX","USDC"]`
|
|
15221
|
-
* list falling back to `rows[0]`.
|
|
15764
|
+
* list falling back to `rows[0]`. Duplicate ids keep the first row, so the same
|
|
15222
15765
|
* snapshot always yields the same answer.
|
|
15223
15766
|
*/
|
|
15224
15767
|
function primaryHolding(rows) {
|
|
@@ -15226,37 +15769,21 @@ function primaryHolding(rows) {
|
|
|
15226
15769
|
for (const row of rows) {
|
|
15227
15770
|
const holding = toHolding(row);
|
|
15228
15771
|
if (holding === null) continue;
|
|
15229
|
-
if (primary === null ||
|
|
15772
|
+
if (primary === null || holding.id < primary.id) primary = holding;
|
|
15230
15773
|
}
|
|
15231
15774
|
return primary;
|
|
15232
15775
|
}
|
|
15233
15776
|
function toHolding(row) {
|
|
15777
|
+
if (row.assetKind !== "erc20") return null;
|
|
15234
15778
|
if (row.symbol === void 0 || row.decimals === void 0) return null;
|
|
15235
|
-
const currency = currencyForTokenSymbol(row.symbol);
|
|
15236
|
-
if (currency === null) return null;
|
|
15237
15779
|
return {
|
|
15238
|
-
id: row.
|
|
15780
|
+
id: row.tokenAddress.toLowerCase(),
|
|
15781
|
+
assetKind: row.assetKind,
|
|
15239
15782
|
symbol: row.symbol,
|
|
15240
|
-
|
|
15783
|
+
decimals: row.decimals,
|
|
15784
|
+
value: formatUnits(BigInt(row.rawBalance), row.decimals)
|
|
15241
15785
|
};
|
|
15242
15786
|
}
|
|
15243
|
-
function currencyForTokenSymbol(symbol) {
|
|
15244
|
-
return CURRENCY_BY_TOKEN_SYMBOL.get(symbol.toUpperCase()) ?? null;
|
|
15245
|
-
}
|
|
15246
|
-
/**
|
|
15247
|
-
* Order two non-negative major-unit decimal strings without converting either
|
|
15248
|
-
* to a JavaScript number. Rows carry different `decimals`, so the raw integers
|
|
15249
|
-
* are not comparable: 1999999999 at 9 decimals is LESS than 2000000 at 6.
|
|
15250
|
-
*/
|
|
15251
|
-
function compareDecimal(first, second) {
|
|
15252
|
-
const [firstWhole = "0", firstFraction = ""] = first.split(".");
|
|
15253
|
-
const [secondWhole = "0", secondFraction = ""] = second.split(".");
|
|
15254
|
-
const width = Math.max(firstFraction.length, secondFraction.length);
|
|
15255
|
-
const firstScaled = BigInt(firstWhole + firstFraction.padEnd(width, "0"));
|
|
15256
|
-
const secondScaled = BigInt(secondWhole + secondFraction.padEnd(width, "0"));
|
|
15257
|
-
if (firstScaled === secondScaled) return 0;
|
|
15258
|
-
return firstScaled < secondScaled ? -1 : 1;
|
|
15259
|
-
}
|
|
15260
15787
|
//#endregion
|
|
15261
15788
|
//#region src/surface/holdings.ts
|
|
15262
15789
|
/** SPEC Freshness: past this block age the read is labelled stale. Nothing refuses. */
|
|
@@ -15597,6 +16124,7 @@ const closeClientResources = (close) => toCapxulResult(Effect.promise(close), La
|
|
|
15597
16124
|
function assembleCapxulClient(input) {
|
|
15598
16125
|
const observation = input;
|
|
15599
16126
|
const authCache = input.authCache ?? detectAuthCacheAdapter();
|
|
16127
|
+
const accountSetup = input.accountSetup ?? "automatic";
|
|
15600
16128
|
const effectRunner = input.effectRunner ?? {
|
|
15601
16129
|
runSync: Effect.runSync,
|
|
15602
16130
|
runPromise: Effect.runPromise
|
|
@@ -15667,7 +16195,7 @@ function assembleCapxulClient(input) {
|
|
|
15667
16195
|
});
|
|
15668
16196
|
kickProvisioning = accountBundle.kickProvisioning;
|
|
15669
16197
|
const account = accountBundle.methods;
|
|
15670
|
-
const
|
|
16198
|
+
const authCore = makeAuthMethods({
|
|
15671
16199
|
actor,
|
|
15672
16200
|
authClient: input.ports.authClient,
|
|
15673
16201
|
authCache,
|
|
@@ -15685,10 +16213,19 @@ function assembleCapxulClient(input) {
|
|
|
15685
16213
|
}
|
|
15686
16214
|
if (browserSigner.statusStore?.status() === "unknown" && typeof browserSigner.ensureWalletReady === "function") browserSigner.ensureWalletReady().catch(() => {});
|
|
15687
16215
|
}
|
|
16216
|
+
if (accountSetup === "explicit") return;
|
|
15688
16217
|
await detectPendingOrgInvitations?.();
|
|
15689
16218
|
kickProvisioning?.();
|
|
15690
16219
|
}
|
|
15691
16220
|
});
|
|
16221
|
+
const auth = {
|
|
16222
|
+
...authCore,
|
|
16223
|
+
clientRequests: makeClientRequestMethods({
|
|
16224
|
+
authBaseUrl: input.bootstrap.authBaseUrl,
|
|
16225
|
+
signIn: authCore.signIn,
|
|
16226
|
+
verifyOtp: authCore.verifyOtp
|
|
16227
|
+
})
|
|
16228
|
+
};
|
|
15692
16229
|
const smartAccount = makeSmartAccountMethods({
|
|
15693
16230
|
actor,
|
|
15694
16231
|
smartAccountPort: input.ports.smartAccount,
|
|
@@ -15852,6 +16389,7 @@ function assembleCapxulClient(input) {
|
|
|
15852
16389
|
...input.ports.indexerRead === void 0 ? {} : { indexer: input.ports.indexerRead },
|
|
15853
16390
|
organizationSetup: { getProofReceipt: (orgId) => runPortEffect(input.ports.convexCall.query(organizationSetupProofReceiptQuery, { orgId })) },
|
|
15854
16391
|
telemetry: input.ports.telemetry,
|
|
16392
|
+
accountSetup,
|
|
15855
16393
|
captureExternalAddressAcknowledged: (address, organizationId) => {
|
|
15856
16394
|
const telemetry = input.ports.telemetry;
|
|
15857
16395
|
if (telemetry === void 0) return;
|
|
@@ -16917,6 +17455,7 @@ async function createCapxulClientWithSignerControls(input, controls) {
|
|
|
16917
17455
|
bootstrap: adapters.value.bootstrap,
|
|
16918
17456
|
authCache: adapters.value.ports.authCache,
|
|
16919
17457
|
requirement: input.requirement ?? "none",
|
|
17458
|
+
accountSetup: input.accountSetup,
|
|
16920
17459
|
...signer === void 0 ? {} : { signer },
|
|
16921
17460
|
orgPort: Context.get(adapters.value.context, OrgPortTag),
|
|
16922
17461
|
...signer === void 0 ? {} : { organizationSetup: new ConvexOrganizationSetupAdapter({
|
|
@@ -17128,4 +17667,4 @@ function productionIndexerReadPort(input, ports, observation) {
|
|
|
17128
17667
|
});
|
|
17129
17668
|
}
|
|
17130
17669
|
//#endregion
|
|
17131
|
-
export {
|
|
17670
|
+
export { resolveFailureMode as A, valueIn as B, normalizeExceptionErrorKind as C, isSettingUpLifecycle as D, safeExceptionLabel as E, isCapxulOperation as F, isMoneyParseError as G, assetSymbolFor as H, normalizeCapxulOperation as I, isClaimed as J, parseMoney as K, accountFromAccountPositions as L, PAYMENT_STATUSES as M, redactTelemetryEvent as N, injectedWalletSigner as O, CAPXUL_OPERATIONS as P, positionPeg as R, SDK_VERSION$1 as S, projectSdkException as T, formatAssetAmount as U, assetAmountFromRaw as V, parseAssetAmount as W, isRestoring as Y, fingerprintPaymentIntent as _, smartAccountErrorFromCapxul as a, failureDetail as b, identityErrorFromCapxul as c, embeddedSigner as d, openfortEmbeddedSigner as f, devPrivateKeySigner as g, deriveDevPrivateKey as h, assembleCapxulClient as i, PAYMENT_DIRECTIONS as j, signerFailure as k, convexCallErrorFromCapxul as l, openfortEmbeddedWalletPort as m, createCapxulClientWithSignerControls as n, accountReadErrorFromCapxul as o, openfortEmbeddedSignerFromWallet as p, destination as q, postHogObservability as r, wireChainId as s, createCapxulClient as t, bootstrapErrorFromCapxul as u, toWei as v, normalizeExceptionOperation as w, EXCEPTION_MESSAGE as x, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as y, PEG_RATES as z };
|