@capxul/cli 4.20.0-beta.6 → 4.20.0-beta.7
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/README.md +111 -5
- package/dist/browser/signer.js +446 -26
- package/dist/browser/signer.js.map +1 -1
- package/dist/main.mjs +1818 -180
- package/dist/main.mjs.map +1 -1
- package/package.json +3 -3
package/dist/main.mjs
CHANGED
|
@@ -307,7 +307,7 @@ const privateTransition = (state, event) => {
|
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
};
|
|
310
|
-
const transition = (state, event, config = DEFAULT_CONFIG) => {
|
|
310
|
+
const transition$1 = (state, event, config = DEFAULT_CONFIG) => {
|
|
311
311
|
if (isPrivate(event)) return privateTransition(state, event);
|
|
312
312
|
if (event._tag === "VerifyOtp" && !/^\d{6}$/.test(event.otp)) return { refused: "INVALID_INPUT" };
|
|
313
313
|
if (event._tag === "CreateOrganization" && event.draft.handle.trim() === "") return { refused: "INVALID_INPUT" };
|
|
@@ -2609,7 +2609,8 @@ const SETTLEMENT_ASSETS_BASE_SEPOLIA = Object.freeze({
|
|
|
2609
2609
|
CAPXUL_TEST_WETH: SYNTHETIC_TEST_ASSET_FIXTURES.weth
|
|
2610
2610
|
});
|
|
2611
2611
|
const CONFIGURED_MONEY_ASSETS = Object.freeze(Object.values(SETTLEMENT_ASSETS_BASE_SEPOLIA));
|
|
2612
|
-
|
|
2612
|
+
/** Public AssetIds for the admitted Base Sepolia test assets. */
|
|
2613
|
+
const TOKENS = Object.freeze({ BASE_SEPOLIA: Object.freeze({
|
|
2613
2614
|
CAPXUL_TEST_USDC: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_USDC.assetId,
|
|
2614
2615
|
CAPXUL_TEST_USDT: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_USDT.assetId,
|
|
2615
2616
|
CAPXUL_TEST_WETH: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_WETH.assetId
|
|
@@ -4258,6 +4259,28 @@ function getCreate2Address(opts) {
|
|
|
4258
4259
|
//#region ../../packages/config/src/org-payments.ts
|
|
4259
4260
|
/** Zodiac MultiSendCallOnly module on Base Sepolia. */
|
|
4260
4261
|
const MULTI_SEND_CALL_ONLY = "0x9641d764fc13c8b624c04430c7356c1c7c8102e2";
|
|
4262
|
+
/** Supported Organization permission identities, newest first. */
|
|
4263
|
+
const ORG_PERMISSION_IDENTITY_PROFILES = [{
|
|
4264
|
+
id: "zodiac-roles-2.1.1",
|
|
4265
|
+
moduleFactoryRuntimeKeccak256: "0x01623cbcf010a1c326230f1b2d5f48a66b440232ee49096102bc84967dc5f21e",
|
|
4266
|
+
mastercopy: "0xf2964ce6161ce0e75964fe7927ce114cb0b283d5",
|
|
4267
|
+
mastercopyRuntimeKeccak256: "0x471d8b3b419f1eb955230c0326c8812176df49bf3c7b414a563fda5a3c6c10b6",
|
|
4268
|
+
proxyRuntimeKeccak256: "0x248f9591f94c24c199ade3e73feb477cf02d387b2bea91f2f931a0deb094f163",
|
|
4269
|
+
multiSendUnwrapper: "0xb4cd4bb764c089f20da18700ce8bc5e49f369efd",
|
|
4270
|
+
multiSendUnwrapperRuntimeKeccak256: "0x1f6e088be5e6ef9d0fbe0547d3fa9a9e40d823433fd8a4449215b5663209a1eb"
|
|
4271
|
+
}, {
|
|
4272
|
+
id: "zodiac-roles-2.1.0",
|
|
4273
|
+
moduleFactoryRuntimeKeccak256: "0x01623cbcf010a1c326230f1b2d5f48a66b440232ee49096102bc84967dc5f21e",
|
|
4274
|
+
mastercopy: "0x9646fdad06d3e24444381f44362a3b0eb343d337",
|
|
4275
|
+
mastercopyRuntimeKeccak256: "0x87911cbc6aa0496e6bcb07dab2462b9c76daea130dede6dcc57d0adf307fa7ec",
|
|
4276
|
+
proxyRuntimeKeccak256: "0x9d4059abf46db50e4b48d9b6404b1f200cb5a1efeb3725be2de630a2a9001944",
|
|
4277
|
+
multiSendUnwrapper: "0x93b7fcbc63ed8a3a24b59e1c3e6649d50b7427c0",
|
|
4278
|
+
multiSendUnwrapperRuntimeKeccak256: "0x4d8d8608b70a6e2f40726b9dd74406bbf73e90cac58e23ee953e2b45ad7dc3df"
|
|
4279
|
+
}];
|
|
4280
|
+
const CURRENT_ORG_PERMISSION_IDENTITY = ORG_PERMISSION_IDENTITY_PROFILES[0];
|
|
4281
|
+
ORG_PERMISSION_IDENTITY_PROFILES[1];
|
|
4282
|
+
CURRENT_ORG_PERMISSION_IDENTITY.mastercopy;
|
|
4283
|
+
CURRENT_ORG_PERMISSION_IDENTITY.multiSendUnwrapper;
|
|
4261
4284
|
//#endregion
|
|
4262
4285
|
//#region ../../packages/config/src/safe.ts
|
|
4263
4286
|
const BASE_SEPOLIA_CHAIN_ID = 84532;
|
|
@@ -4480,14 +4503,6 @@ function deriveCapxulSafeAddressForOwner(input) {
|
|
|
4480
4503
|
//#endregion
|
|
4481
4504
|
//#region ../../packages/config/src/role-dsl.ts
|
|
4482
4505
|
const ADMIN_ROLE_LABEL = "Admin";
|
|
4483
|
-
function normalizeOrgRoleLabel(label) {
|
|
4484
|
-
const normalized = label.trim().replace(/\s+/g, " ");
|
|
4485
|
-
if (normalized.length === 0) throw Errors.invalidInput("role.label", "must be a non-empty role label");
|
|
4486
|
-
return normalized;
|
|
4487
|
-
}
|
|
4488
|
-
function orgRoleKeyForLabel(label) {
|
|
4489
|
-
return keccak256(toBytes(normalizeOrgRoleLabel(label).toLowerCase()));
|
|
4490
|
-
}
|
|
4491
4506
|
//#endregion
|
|
4492
4507
|
//#region ../../packages/config/src/capxul-payments-v2.ts
|
|
4493
4508
|
/** The exact compiled CapxulPaymentsV2 ABI. */
|
|
@@ -5159,6 +5174,44 @@ const ROLE_AUTHORITY_EVENT_BY_FUNCTION_SELECTOR = new Map([
|
|
|
5159
5174
|
toEventSelector("AssignRoles(address,bytes32[],bool[])");
|
|
5160
5175
|
new Set([...ROLE_AUTHORITY_EVENT_BY_FUNCTION_SELECTOR.values()].map((topic) => topic.toLowerCase()));
|
|
5161
5176
|
//#endregion
|
|
5177
|
+
//#region ../../packages/sdk/src/domain/money/parse-money.ts
|
|
5178
|
+
const AMOUNT_PATTERN = /^(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?$/;
|
|
5179
|
+
const ZERO_PATTERN = /^0+(?:\.0+)?$/;
|
|
5180
|
+
/** Shared input grammar. Callers retain their own amount size limits. */
|
|
5181
|
+
function parseDecimalInput(input, decimals, maximumLength) {
|
|
5182
|
+
if (!Number.isInteger(decimals) || decimals < 0) throw Errors.invalidInput("asset.decimals", "must be a non-negative integer");
|
|
5183
|
+
const value = input.trim();
|
|
5184
|
+
if (value.length === 0) return {
|
|
5185
|
+
kind: "error",
|
|
5186
|
+
reason: "required"
|
|
5187
|
+
};
|
|
5188
|
+
if (value.length > maximumLength) return {
|
|
5189
|
+
kind: "error",
|
|
5190
|
+
reason: "too-long"
|
|
5191
|
+
};
|
|
5192
|
+
const negative = value.startsWith("-");
|
|
5193
|
+
const unsigned = negative ? value.slice(1) : value;
|
|
5194
|
+
if (!AMOUNT_PATTERN.test(unsigned)) return {
|
|
5195
|
+
kind: "error",
|
|
5196
|
+
reason: "invalid-format"
|
|
5197
|
+
};
|
|
5198
|
+
if (negative) return {
|
|
5199
|
+
kind: "error",
|
|
5200
|
+
reason: "non-positive"
|
|
5201
|
+
};
|
|
5202
|
+
const normalized = unsigned.replaceAll(",", "");
|
|
5203
|
+
const fraction = normalized.split(".")[1];
|
|
5204
|
+
if (fraction !== void 0 && fraction.length > decimals) return {
|
|
5205
|
+
kind: "error",
|
|
5206
|
+
reason: "too-many-decimals"
|
|
5207
|
+
};
|
|
5208
|
+
if (ZERO_PATTERN.test(normalized)) return {
|
|
5209
|
+
kind: "error",
|
|
5210
|
+
reason: "non-positive"
|
|
5211
|
+
};
|
|
5212
|
+
return { value: normalized };
|
|
5213
|
+
}
|
|
5214
|
+
//#endregion
|
|
5162
5215
|
//#region ../../packages/sdk/src/domain/money/asset-amount.ts
|
|
5163
5216
|
/** Convert raw units without rounding or changing asset identity. */
|
|
5164
5217
|
function assetAmountFromRaw(raw, asset) {
|
|
@@ -5174,6 +5227,14 @@ function toRaw(amount, asset) {
|
|
|
5174
5227
|
if (amount.asset !== asset.assetId) throw Errors.invalidInput("amount.asset", "must match the selected asset on its chain");
|
|
5175
5228
|
return decimalToRaw(amount.value, asset.decimals);
|
|
5176
5229
|
}
|
|
5230
|
+
function parseAssetAmount(input, asset) {
|
|
5231
|
+
validateMetadata(asset);
|
|
5232
|
+
const parsed = parseDecimalInput(input, asset.decimals, 100);
|
|
5233
|
+
return "kind" in parsed ? parsed : {
|
|
5234
|
+
asset: asset.assetId,
|
|
5235
|
+
value: parsed.value.replace(/^0+(?=\d)/, "")
|
|
5236
|
+
};
|
|
5237
|
+
}
|
|
5177
5238
|
function requireAsset(id) {
|
|
5178
5239
|
const asset = configuredMoneyAssetById(id);
|
|
5179
5240
|
if (asset === null) throw Errors.invalidInput("amount.asset", "is not a registered asset");
|
|
@@ -5564,10 +5625,12 @@ const CAPXUL_OPERATIONS = {
|
|
|
5564
5625
|
prepareOrganizationPaymentExecution: "moneyExecution.prepareOrganizationPaymentExecution",
|
|
5565
5626
|
preparePaymentExecution: "moneyExecution.preparePaymentExecution",
|
|
5566
5627
|
preparePaymentLifecycleExecution: "moneyExecution.preparePaymentLifecycleExecution",
|
|
5628
|
+
prepareInvitationConfiguration: "moneyExecution.prepareInvitationConfiguration",
|
|
5567
5629
|
preparePermissionExecution: "moneyExecution.preparePermissionExecution",
|
|
5568
5630
|
recoverSubmissionClaims: "moneyExecution.recoverSubmissionClaims",
|
|
5569
5631
|
submit: "moneyExecution.submit",
|
|
5570
5632
|
submitPaymentCommandExecution: "moneyExecution.submitPaymentCommandExecution",
|
|
5633
|
+
submitInvitationConfigurationExecution: "moneyExecution.submitInvitationConfigurationExecution",
|
|
5571
5634
|
submitPaymentExecution: "moneyExecution.submitPaymentExecution",
|
|
5572
5635
|
submitPermissionExecution: "moneyExecution.submitPermissionExecution"
|
|
5573
5636
|
},
|
|
@@ -5589,20 +5652,52 @@ const CAPXUL_OPERATIONS = {
|
|
|
5589
5652
|
completePerson: "onboarding.completePerson"
|
|
5590
5653
|
},
|
|
5591
5654
|
org: {
|
|
5592
|
-
acceptInvitations: "org.acceptInvitations",
|
|
5593
5655
|
account: { get: "org.account.get" },
|
|
5594
|
-
activateMember: "org.activateMember",
|
|
5595
5656
|
auditLog: "org.auditLog",
|
|
5596
5657
|
confirmBootstrap: "org.confirmBootstrap",
|
|
5597
5658
|
createOrg: "org.createOrg",
|
|
5598
5659
|
create: "org.create",
|
|
5599
|
-
|
|
5660
|
+
/**
|
|
5661
|
+
* §11: the consent mutation reports `org_invite_accepted` through its own
|
|
5662
|
+
* scheduled emitter. It is named for the emit, not the acceptance, because
|
|
5663
|
+
* the interactive acceptance itself owns `org.invitations.accept`.
|
|
5664
|
+
*/
|
|
5665
|
+
emitInviteAccepted: "org.emitInviteAccepted",
|
|
5600
5666
|
emitInviteProgressed: "org.emitInviteProgressed",
|
|
5601
5667
|
expireInvitations: "org.expireInvitations",
|
|
5602
5668
|
getLifecycle: "org.getLifecycle",
|
|
5603
5669
|
getProofReceipt: "org.getProofReceipt",
|
|
5604
5670
|
invite: "org.invite",
|
|
5605
|
-
|
|
5671
|
+
/** D8 invitation lifecycle: preview, own list, read, and the four transitions. */
|
|
5672
|
+
invitations: {
|
|
5673
|
+
/** The exact grantee's consent commit (§8): one accepted digest, once. */
|
|
5674
|
+
accept: "org.invitations.accept",
|
|
5675
|
+
/**
|
|
5676
|
+
* The authoring write. It is named `authorize`, not `invite`, because the
|
|
5677
|
+
* backend already uses `org.invitations.invite` as a refusal label and
|
|
5678
|
+
* `lint:telemetry-spine` refuses a label that collides with an operation.
|
|
5679
|
+
*/
|
|
5680
|
+
authorize: "org.invitations.authorize",
|
|
5681
|
+
cancel: "org.invitations.cancel",
|
|
5682
|
+
decline: "org.invitations.decline",
|
|
5683
|
+
get: "org.invitations.get",
|
|
5684
|
+
list: "org.invitations.list",
|
|
5685
|
+
/**
|
|
5686
|
+
* The Admin-scoped Organization list. It is named `listScoped`, not
|
|
5687
|
+
* `list`, because the own-offer list already owns `org.invitations.list`.
|
|
5688
|
+
*/
|
|
5689
|
+
listScoped: "org.invitations.listScoped",
|
|
5690
|
+
/**
|
|
5691
|
+
* The authoring write's inner hops: the SDK drives the backend's existing
|
|
5692
|
+
* prepare/submit pair, and these names label the two Convex calls. The
|
|
5693
|
+
* owning `capxul_sdk_operation` record stays `org.invitations.authorize`.
|
|
5694
|
+
*/
|
|
5695
|
+
prepareConfiguration: "org.invitations.prepareConfiguration",
|
|
5696
|
+
preview: "org.invitations.preview",
|
|
5697
|
+
resend: "org.invitations.resend",
|
|
5698
|
+
retry: "org.invitations.retry",
|
|
5699
|
+
submitConfiguration: "org.invitations.submitConfiguration"
|
|
5700
|
+
},
|
|
5606
5701
|
list: "org.list",
|
|
5607
5702
|
load: "org.load",
|
|
5608
5703
|
me: "org.me",
|
|
@@ -5661,7 +5756,6 @@ const CAPXUL_OPERATIONS = {
|
|
|
5661
5756
|
},
|
|
5662
5757
|
recordFailure: "org.recordFailure",
|
|
5663
5758
|
recordProgress: "org.recordProgress",
|
|
5664
|
-
resendInviteToken: "org.resendInviteToken",
|
|
5665
5759
|
resumeBootstrapSubmission: "org.resumeBootstrapSubmission",
|
|
5666
5760
|
retry: "org.retry",
|
|
5667
5761
|
retrySetup: "org.retrySetup",
|
|
@@ -5678,7 +5772,6 @@ const CAPXUL_OPERATIONS = {
|
|
|
5678
5772
|
retry: "organizationPayments.retry"
|
|
5679
5773
|
},
|
|
5680
5774
|
organizationSetup: { getProofReceipt: "organizationSetup.getProofReceipt" },
|
|
5681
|
-
organizations: { detectAndAcceptPendingInvitations: "orgs.detectAndAcceptPendingInvitations" },
|
|
5682
5775
|
payments: {
|
|
5683
5776
|
cancel: "payments.cancel",
|
|
5684
5777
|
claim: "payments.claim",
|
|
@@ -5716,6 +5809,7 @@ const CAPXUL_OPERATIONS = {
|
|
|
5716
5809
|
terms: "payroll.terms"
|
|
5717
5810
|
},
|
|
5718
5811
|
permission: {
|
|
5812
|
+
verifyInvitationConfiguration: "permission.verifyInvitationConfiguration",
|
|
5719
5813
|
command: "permission.command",
|
|
5720
5814
|
retryVerification: "permission.retryVerification",
|
|
5721
5815
|
verify: "permission.verify",
|
|
@@ -6273,6 +6367,11 @@ const OrgCreateFailedProps = Schema.Struct({
|
|
|
6273
6367
|
const OrgInviteSentProps = Schema.Struct({
|
|
6274
6368
|
...TelemetryEnvelopeProps,
|
|
6275
6369
|
org_id: OptionalOrgId,
|
|
6370
|
+
invitation_id: OptionalString,
|
|
6371
|
+
generation: OptionalString,
|
|
6372
|
+
command_id: OptionalString,
|
|
6373
|
+
subject_party_id: OptionalString,
|
|
6374
|
+
persisted_at: OptionalEpochMs,
|
|
6276
6375
|
email_domain: OptionalString,
|
|
6277
6376
|
role: OptionalString,
|
|
6278
6377
|
status: OptionalString
|
|
@@ -6280,6 +6379,11 @@ const OrgInviteSentProps = Schema.Struct({
|
|
|
6280
6379
|
const OrgInviteAcceptedProps = Schema.Struct({
|
|
6281
6380
|
...TelemetryEnvelopeProps,
|
|
6282
6381
|
org_id: OptionalOrgId,
|
|
6382
|
+
invitation_id: OptionalString,
|
|
6383
|
+
accepted_at: OptionalEpochMs,
|
|
6384
|
+
generation: OptionalString,
|
|
6385
|
+
command_id: OptionalString,
|
|
6386
|
+
subject_party_id: OptionalString,
|
|
6283
6387
|
role: OptionalString,
|
|
6284
6388
|
status: OptionalString
|
|
6285
6389
|
});
|
|
@@ -6287,6 +6391,7 @@ const OrgInviteExpiredProps = Schema.Struct({
|
|
|
6287
6391
|
...TelemetryEnvelopeProps,
|
|
6288
6392
|
org_id: OptionalOrgId,
|
|
6289
6393
|
email_domain: OptionalString,
|
|
6394
|
+
invitation_id: OptionalString,
|
|
6290
6395
|
reason: OptionalString,
|
|
6291
6396
|
role: OptionalString,
|
|
6292
6397
|
status: OptionalString
|
|
@@ -6439,9 +6544,24 @@ const PermissionMirrorVerificationProps = Schema.Struct({
|
|
|
6439
6544
|
"applied",
|
|
6440
6545
|
"replayed",
|
|
6441
6546
|
"conflicting_replay",
|
|
6442
|
-
"revision_mismatch"
|
|
6547
|
+
"revision_mismatch",
|
|
6548
|
+
"cleanup_required",
|
|
6549
|
+
"not_applied",
|
|
6550
|
+
"application_failure",
|
|
6551
|
+
"mismatch",
|
|
6552
|
+
"refused"
|
|
6443
6553
|
])),
|
|
6554
|
+
command_kind: Schema.optional(Schema.Literals(["invitation_configuration", "invitation_eoa"])),
|
|
6444
6555
|
command_id: OptionalString,
|
|
6556
|
+
invitation_id: OptionalString,
|
|
6557
|
+
generation: OptionalString,
|
|
6558
|
+
purpose: Schema.optional(Schema.Literals([
|
|
6559
|
+
"configure",
|
|
6560
|
+
"grant",
|
|
6561
|
+
"disable",
|
|
6562
|
+
"compensate"
|
|
6563
|
+
])),
|
|
6564
|
+
$insert_id: OptionalString,
|
|
6445
6565
|
/**
|
|
6446
6566
|
* #1961 R03. The authorized stored row names the Permission it changed; the
|
|
6447
6567
|
* verified receipt names the chain facts that prove it. Every field is
|
|
@@ -6828,6 +6948,13 @@ const CLI_COMMAND_NAMES = [
|
|
|
6828
6948
|
"auth.profile",
|
|
6829
6949
|
"auth.status",
|
|
6830
6950
|
"auth.logout",
|
|
6951
|
+
"contact",
|
|
6952
|
+
"contact.list",
|
|
6953
|
+
"contact.get",
|
|
6954
|
+
"contact.add",
|
|
6955
|
+
"contact.label",
|
|
6956
|
+
"contact.hide",
|
|
6957
|
+
"contact.unhide",
|
|
6831
6958
|
"org",
|
|
6832
6959
|
CAPXUL_OPERATIONS.org.list,
|
|
6833
6960
|
"org.use",
|
|
@@ -6836,6 +6963,24 @@ const CLI_COMMAND_NAMES = [
|
|
|
6836
6963
|
CAPXUL_OPERATIONS.org.members,
|
|
6837
6964
|
"org.member",
|
|
6838
6965
|
"org.member.get",
|
|
6966
|
+
"org.member.invite",
|
|
6967
|
+
"org.contact",
|
|
6968
|
+
"org.contact.list",
|
|
6969
|
+
"org.contact.get",
|
|
6970
|
+
"org.contact.add",
|
|
6971
|
+
"org.contact.label",
|
|
6972
|
+
"org.contact.hide",
|
|
6973
|
+
"org.contact.unhide",
|
|
6974
|
+
CAPXUL_OPERATIONS.org.invite,
|
|
6975
|
+
"org.invite.list",
|
|
6976
|
+
"org.invite.get",
|
|
6977
|
+
"org.invite.wait",
|
|
6978
|
+
"org.invite.review",
|
|
6979
|
+
"org.invite.accept",
|
|
6980
|
+
"org.invite.decline",
|
|
6981
|
+
"org.invite.cancel",
|
|
6982
|
+
"org.invite.resend",
|
|
6983
|
+
"org.invite.retry",
|
|
6839
6984
|
"org.wait",
|
|
6840
6985
|
CAPXUL_OPERATIONS.org.create,
|
|
6841
6986
|
CAPXUL_OPERATIONS.org.retry,
|
|
@@ -6846,7 +6991,8 @@ const CLI_CAPABILITIES = [
|
|
|
6846
6991
|
"diagnostics",
|
|
6847
6992
|
"collection",
|
|
6848
6993
|
"authentication",
|
|
6849
|
-
"organization"
|
|
6994
|
+
"organization",
|
|
6995
|
+
"contacts"
|
|
6850
6996
|
];
|
|
6851
6997
|
const CLI_INVOCATION_KINDS = [
|
|
6852
6998
|
"command",
|
|
@@ -7090,6 +7236,7 @@ const TELEMETRY_EVENT_SCHEMAS = {
|
|
|
7090
7236
|
...TelemetryEnvelopeProps,
|
|
7091
7237
|
organization_id: OrgIdTelemetrySchema,
|
|
7092
7238
|
progress: Schema.Literals([
|
|
7239
|
+
"configuration_authorized",
|
|
7093
7240
|
"account_ready",
|
|
7094
7241
|
"permission_applied",
|
|
7095
7242
|
"membership_activated",
|
|
@@ -7097,6 +7244,9 @@ const TELEMETRY_EVENT_SCHEMAS = {
|
|
|
7097
7244
|
]),
|
|
7098
7245
|
/** The invited Party. The initiating actor stays on the envelope's identity. */
|
|
7099
7246
|
member_party_id: Schema.String,
|
|
7247
|
+
invitation_id: Schema.optional(Schema.String),
|
|
7248
|
+
generation: Schema.optional(Schema.String),
|
|
7249
|
+
command_id: Schema.optional(Schema.String),
|
|
7100
7250
|
occurred_at: Schema.Number
|
|
7101
7251
|
})
|
|
7102
7252
|
}),
|
|
@@ -7800,8 +7950,10 @@ const CAPXUL_FUNCTIONS = {
|
|
|
7800
7950
|
"movement/annotations": { overlay: "movement/annotations:overlay" },
|
|
7801
7951
|
"moneyExecution/actions": {
|
|
7802
7952
|
abandonPaymentExecution: "moneyExecution/actions:abandonPaymentExecution",
|
|
7953
|
+
prepareInvitationConfiguration: "moneyExecution/actions:prepareInvitationConfiguration",
|
|
7803
7954
|
preparePermissionExecution: "moneyExecution/actions:preparePermissionExecution",
|
|
7804
7955
|
preparePaymentExecution: "moneyExecution/actions:preparePaymentExecution",
|
|
7956
|
+
submitInvitationConfigurationExecution: "moneyExecution/actions:submitInvitationConfigurationExecution",
|
|
7805
7957
|
submitPermissionExecution: "moneyExecution/actions:submitPermissionExecution",
|
|
7806
7958
|
submitPaymentExecution: "moneyExecution/actions:submitPaymentExecution"
|
|
7807
7959
|
},
|
|
@@ -7818,8 +7970,6 @@ const CAPXUL_FUNCTIONS = {
|
|
|
7818
7970
|
},
|
|
7819
7971
|
"org/actions": {
|
|
7820
7972
|
confirmBootstrap: "org/actions:confirmBootstrap",
|
|
7821
|
-
detectAndAcceptPendingInvitations: "org/actions:detectAndAcceptPendingInvitations",
|
|
7822
|
-
inviteMember: "org/actions:inviteMember",
|
|
7823
7973
|
prepareBootstrap: "org/actions:prepareBootstrap",
|
|
7824
7974
|
prepareFounderAccount: "org/actions:prepareFounderAccount",
|
|
7825
7975
|
readTreasury: "org/actions:readTreasury",
|
|
@@ -7850,16 +8000,25 @@ const CAPXUL_FUNCTIONS = {
|
|
|
7850
8000
|
startOrResume: "org/lifecycle:startOrResume"
|
|
7851
8001
|
},
|
|
7852
8002
|
"org/mutations": {
|
|
8003
|
+
accept: "org/mutations:accept",
|
|
8004
|
+
cancel: "org/mutations:cancel",
|
|
7853
8005
|
createOrg: "org/mutations:createOrg",
|
|
7854
|
-
|
|
8006
|
+
decline: "org/mutations:decline",
|
|
8007
|
+
invite: "org/mutations:invite",
|
|
8008
|
+
resend: "org/mutations:resend",
|
|
8009
|
+
retry: "org/mutations:retry"
|
|
7855
8010
|
},
|
|
7856
8011
|
"org/queries": {
|
|
8012
|
+
getInvitation: "org/queries:getInvitation",
|
|
7857
8013
|
listAll: "org/queries:listAll",
|
|
8014
|
+
listInvitations: "org/queries:listInvitations",
|
|
7858
8015
|
listMembersByOrgId: "org/queries:listMembersByOrgId",
|
|
7859
8016
|
listMine: "org/queries:listMine",
|
|
8017
|
+
listMyInvitations: "org/queries:listMyInvitations",
|
|
7860
8018
|
listRolesByOrgId: "org/queries:listRolesByOrgId",
|
|
7861
8019
|
loadByOrgId: "org/queries:loadByOrgId",
|
|
7862
|
-
me: "org/queries:me"
|
|
8020
|
+
me: "org/queries:me",
|
|
8021
|
+
previewInvite: "org/queries:previewInvite"
|
|
7863
8022
|
},
|
|
7864
8023
|
"smartAccount/actions": {
|
|
7865
8024
|
claim: "smartAccount/actions:claim",
|
|
@@ -8819,6 +8978,94 @@ const EventRefSchema = Schema.Struct({
|
|
|
8819
8978
|
topic0: Bytes32Schema,
|
|
8820
8979
|
dataHash: Bytes32Schema
|
|
8821
8980
|
});
|
|
8981
|
+
const InvitationEoaReceiptSchema = Schema.Struct({
|
|
8982
|
+
kind: Schema.Literal("invitation_eoa"),
|
|
8983
|
+
chainId: BaseSepoliaChainIdSchema,
|
|
8984
|
+
transactionHash: TxHashSchema,
|
|
8985
|
+
blockNumber: BlockNumberSchema,
|
|
8986
|
+
blockHash: Bytes32Schema,
|
|
8987
|
+
sender: AddressSchema,
|
|
8988
|
+
nonce: Schema.String.pipe(Schema.refine((value) => /^(0|[1-9][0-9]*)$/.test(value)))
|
|
8989
|
+
});
|
|
8990
|
+
const PermissionReceiptRefSchema = Schema.Union([Schema.Struct({
|
|
8991
|
+
kind: Schema.Literal("user_operation"),
|
|
8992
|
+
...ReceiptRefSchema.fields
|
|
8993
|
+
}), InvitationEoaReceiptSchema]);
|
|
8994
|
+
const PermissionEventRefSchema = Schema.Struct({
|
|
8995
|
+
receipt: PermissionReceiptRefSchema,
|
|
8996
|
+
emitter: AddressSchema,
|
|
8997
|
+
transactionIndex: LogIndexSchema,
|
|
8998
|
+
logIndex: LogIndexSchema,
|
|
8999
|
+
topic0: Bytes32Schema,
|
|
9000
|
+
dataHash: Bytes32Schema
|
|
9001
|
+
});
|
|
9002
|
+
Schema.Union([
|
|
9003
|
+
Schema.Struct({
|
|
9004
|
+
status: Schema.Literal("pending"),
|
|
9005
|
+
reason: Schema.Literal("receipt_missing")
|
|
9006
|
+
}),
|
|
9007
|
+
Schema.Struct({
|
|
9008
|
+
status: Schema.Literal("provider_failure"),
|
|
9009
|
+
retryable: Schema.Literal(true)
|
|
9010
|
+
}),
|
|
9011
|
+
Schema.Struct({
|
|
9012
|
+
status: Schema.Literal("mismatch"),
|
|
9013
|
+
code: Schema.Literals([
|
|
9014
|
+
"wrong_chain",
|
|
9015
|
+
"wrong_sender",
|
|
9016
|
+
"wrong_transaction",
|
|
9017
|
+
"failed_transaction",
|
|
9018
|
+
"non_canonical_block",
|
|
9019
|
+
"wrong_contract_identity",
|
|
9020
|
+
"missing_event",
|
|
9021
|
+
"extra_authority_event",
|
|
9022
|
+
"wrong_fact_tuple",
|
|
9023
|
+
"wrong_state",
|
|
9024
|
+
"conflicting_replay"
|
|
9025
|
+
]),
|
|
9026
|
+
attemptTransactionHash: Schema.optional(TxHashSchema),
|
|
9027
|
+
receipt: Schema.optional(InvitationEoaReceiptSchema)
|
|
9028
|
+
}),
|
|
9029
|
+
Schema.Struct({
|
|
9030
|
+
status: Schema.Literal("verified"),
|
|
9031
|
+
commandId: PaymentCommandIdSchema,
|
|
9032
|
+
receipt: InvitationEoaReceiptSchema,
|
|
9033
|
+
events: Schema.Array(PermissionEventRefSchema),
|
|
9034
|
+
factsHash: Bytes32Schema
|
|
9035
|
+
})
|
|
9036
|
+
]);
|
|
9037
|
+
/**
|
|
9038
|
+
* One stored `setAllowance` call inside a command's expected authority set.
|
|
9039
|
+
*
|
|
9040
|
+
* The pinned Roles module emits `SetAllowance` as *post-state*, not as the call
|
|
9041
|
+
* arguments: `maxRefill = 0` becomes `type(uint128).max`, and `timestamp = 0`
|
|
9042
|
+
* becomes the receipt block's timestamp. A hash over the call arguments can
|
|
9043
|
+
* therefore never match that receipt. `index` names the entry in
|
|
9044
|
+
* `expectedAuthorityEvents` the call produced, and `data` is the call's own
|
|
9045
|
+
* calldata, so the verifier can rebuild the one hash the module actually emits.
|
|
9046
|
+
* The rule is pinned by `test:invitation-conformance`.
|
|
9047
|
+
*/
|
|
9048
|
+
const AllowanceExpectationSchema = Schema.Struct({
|
|
9049
|
+
index: nonNegativeInteger("index"),
|
|
9050
|
+
data: Schema.String.pipe(Schema.refine((value) => /^0x[0-9a-fA-F]+$/u.test(value), { message: "data must be 0x-prefixed hex" }))
|
|
9051
|
+
});
|
|
9052
|
+
Schema.Struct({
|
|
9053
|
+
commandId: PaymentCommandIdSchema,
|
|
9054
|
+
userOpHash: Bytes32Schema,
|
|
9055
|
+
generationHash: Bytes32Schema,
|
|
9056
|
+
chainId: BaseSepoliaChainIdSchema,
|
|
9057
|
+
organizationSafe: SafeAddressSchema,
|
|
9058
|
+
rolesModule: ModuleAddressSchema,
|
|
9059
|
+
userOpSenderSafe: SafeAddressSchema,
|
|
9060
|
+
expectedAuthorityEvents: Schema.Array(Bytes32Schema),
|
|
9061
|
+
/**
|
|
9062
|
+
* Absent means "no normalization": every expected hash is compared as stored.
|
|
9063
|
+
* A command whose set contains `setAllowance` then refuses (`wrong_fact_tuple`)
|
|
9064
|
+
* rather than passing on a weakened proof, so an incomplete caller fails
|
|
9065
|
+
* closed.
|
|
9066
|
+
*/
|
|
9067
|
+
allowanceExpectations: Schema.optional(Schema.Array(AllowanceExpectationSchema))
|
|
9068
|
+
});
|
|
8822
9069
|
const PermissionOperationSchema = Schema.Literals([
|
|
8823
9070
|
"create",
|
|
8824
9071
|
"change",
|
|
@@ -8862,7 +9109,9 @@ const StoredPermissionCommandSchema = Schema.Struct({
|
|
|
8862
9109
|
});
|
|
8863
9110
|
Schema.Struct({
|
|
8864
9111
|
command: StoredPermissionCommandSchema,
|
|
8865
|
-
userOpHash: Bytes32Schema
|
|
9112
|
+
userOpHash: Bytes32Schema,
|
|
9113
|
+
/** The stored `setAllowance` calls of this command's own expectation. */
|
|
9114
|
+
allowanceExpectations: Schema.optional(Schema.Array(AllowanceExpectationSchema))
|
|
8866
9115
|
});
|
|
8867
9116
|
Schema.Union([
|
|
8868
9117
|
Schema.Struct({
|
|
@@ -9706,6 +9955,27 @@ Schema.Struct({
|
|
|
9706
9955
|
digest: Bytes32Schema,
|
|
9707
9956
|
value: PermissionResourceSchema
|
|
9708
9957
|
});
|
|
9958
|
+
Schema.Struct({
|
|
9959
|
+
commandId: PaymentCommandIdSchema,
|
|
9960
|
+
signerAddress: AddressSchema
|
|
9961
|
+
});
|
|
9962
|
+
Schema.Struct({
|
|
9963
|
+
executionId: MoneyExecutionIdSchema,
|
|
9964
|
+
commandId: PaymentCommandIdSchema,
|
|
9965
|
+
orgId: nonEmpty("orgId"),
|
|
9966
|
+
invitationId: nonEmpty("invitationId"),
|
|
9967
|
+
generationHash: Bytes32Schema,
|
|
9968
|
+
chainId: BaseSepoliaChainIdSchema,
|
|
9969
|
+
signerAddress: AddressSchema,
|
|
9970
|
+
userOpSenderSafe: SafeAddressSchema,
|
|
9971
|
+
digest: Bytes32Schema
|
|
9972
|
+
});
|
|
9973
|
+
Schema.Struct({
|
|
9974
|
+
status: Schema.Literal("submitted"),
|
|
9975
|
+
executionId: MoneyExecutionIdSchema,
|
|
9976
|
+
commandId: PaymentCommandIdSchema,
|
|
9977
|
+
userOpHash: Bytes32Schema
|
|
9978
|
+
});
|
|
9709
9979
|
Schema.Struct({
|
|
9710
9980
|
status: Schema.Literal("submitted"),
|
|
9711
9981
|
executionId: MoneyExecutionIdSchema,
|
|
@@ -10279,6 +10549,160 @@ const CurrentPolicySchema = Schema.Union([Schema.Struct({
|
|
|
10279
10549
|
actions: Schema.NonEmptyArray(Schema.Literals(["pay", "commitments"]))
|
|
10280
10550
|
})
|
|
10281
10551
|
}), Schema.Struct({ type: Schema.Literal("managePeople") })]);
|
|
10552
|
+
const BudgetIntentSchema = CurrentPolicySchema.pipe(Schema.refine((value) => {
|
|
10553
|
+
if (value.type !== "budget") return false;
|
|
10554
|
+
const { actions, recipients } = value.scope;
|
|
10555
|
+
if (new Set(actions).size !== actions.length) return false;
|
|
10556
|
+
return recipients.type === "anyone" || recipients.accounts.length >= 1 && recipients.accounts.length <= 32 && new Set(recipients.accounts).size === recipients.accounts.length;
|
|
10557
|
+
}));
|
|
10558
|
+
const InvitationIdSchema = Schema.NonEmptyString;
|
|
10559
|
+
const InvitationTargetSchema = Schema.Struct({ invitationId: InvitationIdSchema });
|
|
10560
|
+
Schema.Struct({
|
|
10561
|
+
...InvitationTargetSchema.fields,
|
|
10562
|
+
expectedOfferDigest: Bytes32Schema
|
|
10563
|
+
});
|
|
10564
|
+
/** The requested grantee of one invitation. */
|
|
10565
|
+
const GranteeRefSchema = Schema.Union([Schema.Struct({
|
|
10566
|
+
type: Schema.Literal("email"),
|
|
10567
|
+
email: Schema.NonEmptyString
|
|
10568
|
+
}), Schema.Struct({
|
|
10569
|
+
type: Schema.Literal("account"),
|
|
10570
|
+
accountId: AccountIdSchema
|
|
10571
|
+
})]);
|
|
10572
|
+
Schema.Struct({
|
|
10573
|
+
requestKey: Schema.String.pipe(Schema.refine((value) => /^[\x20-\x7e]{1,128}$/.test(value))),
|
|
10574
|
+
to: GranteeRefSchema,
|
|
10575
|
+
grants: Schema.Array(Schema.Union([
|
|
10576
|
+
Schema.Struct({
|
|
10577
|
+
type: Schema.Literal("budget"),
|
|
10578
|
+
budgetId: PermissionIdSchema
|
|
10579
|
+
}),
|
|
10580
|
+
Schema.Struct({
|
|
10581
|
+
type: Schema.Literal("managePeople"),
|
|
10582
|
+
permissionId: PermissionIdSchema
|
|
10583
|
+
}),
|
|
10584
|
+
Schema.Struct({
|
|
10585
|
+
type: Schema.Literal("new_budget"),
|
|
10586
|
+
label: Schema.String.pipe(Schema.refine((value) => value.trim().length >= 1 && value.trim().length <= 128)),
|
|
10587
|
+
intent: BudgetIntentSchema
|
|
10588
|
+
})
|
|
10589
|
+
]))
|
|
10590
|
+
}).pipe(Schema.refine((value) => {
|
|
10591
|
+
if (value.grants.length < 1 || value.grants.length > 16) return false;
|
|
10592
|
+
const existing = value.grants.flatMap((grant) => grant.type === "new_budget" ? [] : [grant.type === "budget" ? grant.budgetId : grant.permissionId]);
|
|
10593
|
+
return new Set(existing).size === existing.length && value.grants.filter((grant) => grant.type === "new_budget").length <= 4;
|
|
10594
|
+
}));
|
|
10595
|
+
const InvitationPhaseSchema = Schema.Literals([
|
|
10596
|
+
"authorizing",
|
|
10597
|
+
"pending",
|
|
10598
|
+
"pending_grant",
|
|
10599
|
+
"active",
|
|
10600
|
+
"revoking",
|
|
10601
|
+
"declined",
|
|
10602
|
+
"cancelled",
|
|
10603
|
+
"expired",
|
|
10604
|
+
"revoked"
|
|
10605
|
+
]);
|
|
10606
|
+
const EndingReasonSchema = Schema.Literals([
|
|
10607
|
+
"declined",
|
|
10608
|
+
"cancelled",
|
|
10609
|
+
"expired",
|
|
10610
|
+
"revoked"
|
|
10611
|
+
]);
|
|
10612
|
+
const OfferedAuthoritySchema = Schema.Union([Schema.Struct({
|
|
10613
|
+
type: Schema.Literal("budget"),
|
|
10614
|
+
budgetId: Schema.NonEmptyString.pipe(Schema.refine((value) => value.length > 0)),
|
|
10615
|
+
label: Schema.String,
|
|
10616
|
+
policy: BudgetIntentSchema,
|
|
10617
|
+
policyDigest: Bytes32Schema
|
|
10618
|
+
}), Schema.Struct({
|
|
10619
|
+
type: Schema.Literal("managePeople"),
|
|
10620
|
+
permissionId: PermissionIdSchema,
|
|
10621
|
+
label: Schema.String
|
|
10622
|
+
})]);
|
|
10623
|
+
const NewBudgetOfferSchema = Schema.Struct({
|
|
10624
|
+
type: Schema.Literal("new_budget"),
|
|
10625
|
+
label: Schema.String,
|
|
10626
|
+
policy: BudgetIntentSchema,
|
|
10627
|
+
policyDigest: Bytes32Schema
|
|
10628
|
+
});
|
|
10629
|
+
const PreviewGranteeSchema = Schema.Struct({
|
|
10630
|
+
partyId: Schema.NullOr(PartyIdSchema),
|
|
10631
|
+
accountId: Schema.NullOr(AccountIdSchema),
|
|
10632
|
+
safeAddress: AddressSchema,
|
|
10633
|
+
accountReady: Schema.NullOr(Schema.Boolean)
|
|
10634
|
+
});
|
|
10635
|
+
Schema.Struct({
|
|
10636
|
+
orgId: Schema.NonEmptyString.pipe(Schema.refine((value) => value.length > 0)),
|
|
10637
|
+
grantee: PreviewGranteeSchema,
|
|
10638
|
+
grants: Schema.Array(Schema.Union([OfferedAuthoritySchema, NewBudgetOfferSchema])),
|
|
10639
|
+
existingAssignments: Schema.Array(PermissionAssignmentIdSchema),
|
|
10640
|
+
includesManagement: Schema.Boolean,
|
|
10641
|
+
observedAt: EpochMsSchema
|
|
10642
|
+
});
|
|
10643
|
+
Schema.Struct({
|
|
10644
|
+
cursor: Schema.optional(Schema.NonEmptyString),
|
|
10645
|
+
limit: Schema.optional(Schema.Number.pipe(Schema.refine((value) => Number.isSafeInteger(value) && value >= 1 && value <= 100))),
|
|
10646
|
+
phases: Schema.optional(Schema.Array(InvitationPhaseSchema).pipe(Schema.refine((value) => new Set(value).size === value.length)))
|
|
10647
|
+
});
|
|
10648
|
+
const InvitationRecoverySchema = Schema.Struct({
|
|
10649
|
+
actor: Schema.Literals([
|
|
10650
|
+
"system",
|
|
10651
|
+
"invitee",
|
|
10652
|
+
"admin"
|
|
10653
|
+
]),
|
|
10654
|
+
action: Schema.Literals([
|
|
10655
|
+
"wait",
|
|
10656
|
+
"retry",
|
|
10657
|
+
"review_offer",
|
|
10658
|
+
"reauthorize"
|
|
10659
|
+
]),
|
|
10660
|
+
reason: Schema.Literals([
|
|
10661
|
+
"configuration_pending",
|
|
10662
|
+
"grant_pending",
|
|
10663
|
+
"provider_unavailable",
|
|
10664
|
+
"policy_changed",
|
|
10665
|
+
"cleanup_pending",
|
|
10666
|
+
"signer_unavailable"
|
|
10667
|
+
])
|
|
10668
|
+
});
|
|
10669
|
+
const InvitationViewSchema = Schema.Struct({
|
|
10670
|
+
id: InvitationIdSchema,
|
|
10671
|
+
orgId: Schema.NonEmptyString.pipe(Schema.refine((value) => value.length > 0)),
|
|
10672
|
+
organizationName: Schema.String,
|
|
10673
|
+
grantee: Schema.Struct({
|
|
10674
|
+
partyId: PartyIdSchema,
|
|
10675
|
+
accountId: Schema.NullOr(AccountIdSchema),
|
|
10676
|
+
safeAddress: AddressSchema,
|
|
10677
|
+
accountReady: Schema.NullOr(Schema.Boolean)
|
|
10678
|
+
}),
|
|
10679
|
+
phase: InvitationPhaseSchema,
|
|
10680
|
+
grants: Schema.Array(Schema.Union([Schema.Struct({
|
|
10681
|
+
type: Schema.Literal("budget"),
|
|
10682
|
+
budgetId: Schema.NonEmptyString.pipe(Schema.refine((value) => value.length > 0))
|
|
10683
|
+
}), Schema.Struct({
|
|
10684
|
+
type: Schema.Literal("managePeople"),
|
|
10685
|
+
permissionId: PermissionIdSchema
|
|
10686
|
+
})])),
|
|
10687
|
+
offers: Schema.Array(OfferedAuthoritySchema),
|
|
10688
|
+
recovery: Schema.NullOr(InvitationRecoverySchema),
|
|
10689
|
+
offerDigest: Bytes32Schema,
|
|
10690
|
+
authorizedAt: Schema.NullOr(EpochMsSchema),
|
|
10691
|
+
acceptedAt: Schema.NullOr(EpochMsSchema),
|
|
10692
|
+
expiresAt: Schema.NullOr(EpochMsSchema),
|
|
10693
|
+
commandId: Schema.NullOr(PaymentCommandIdSchema),
|
|
10694
|
+
endingReason: Schema.NullOr(EndingReasonSchema),
|
|
10695
|
+
delivery: Schema.Literals([
|
|
10696
|
+
"not_confirmed",
|
|
10697
|
+
"sent",
|
|
10698
|
+
"failed"
|
|
10699
|
+
])
|
|
10700
|
+
});
|
|
10701
|
+
Schema.Struct({
|
|
10702
|
+
items: Schema.Array(InvitationViewSchema),
|
|
10703
|
+
nextCursor: Schema.NullOr(Schema.NonEmptyString),
|
|
10704
|
+
observedAt: EpochMsSchema
|
|
10705
|
+
});
|
|
10282
10706
|
const ActiveBudgetSchema = Schema.Struct({
|
|
10283
10707
|
id: PermissionIdSchema,
|
|
10284
10708
|
label: Schema.String,
|
|
@@ -12214,11 +12638,13 @@ const financialOpsContract = {
|
|
|
12214
12638
|
//#region ../../packages/sdk/src/contract/money-execution.ts
|
|
12215
12639
|
const moneyExecutionContract = {
|
|
12216
12640
|
abandonPaymentExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/actions"].abandonPaymentExecution),
|
|
12641
|
+
prepareInvitationConfiguration: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/actions"].prepareInvitationConfiguration),
|
|
12217
12642
|
preparePermissionExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/actions"].preparePermissionExecution),
|
|
12218
12643
|
preparePaymentExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/actions"].preparePaymentExecution),
|
|
12219
12644
|
prepareOrganizationPaymentExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/paymentCommandActions"].prepareOrganizationPaymentExecution),
|
|
12220
12645
|
preparePaymentLifecycleExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/paymentCommandActions"].preparePaymentLifecycleExecution),
|
|
12221
12646
|
submitPaymentExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/actions"].submitPaymentExecution),
|
|
12647
|
+
submitInvitationConfigurationExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/actions"].submitInvitationConfigurationExecution),
|
|
12222
12648
|
submitPermissionExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/actions"].submitPermissionExecution),
|
|
12223
12649
|
submitPaymentCommandExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/paymentCommandActions"].submitPaymentCommandExecution)
|
|
12224
12650
|
};
|
|
@@ -12799,7 +13225,7 @@ function subscribeActivity(deps, actor, controls, onChange) {
|
|
|
12799
13225
|
}
|
|
12800
13226
|
//#endregion
|
|
12801
13227
|
//#region ../../packages/sdk/package.json
|
|
12802
|
-
var version$1 = "4.20.0-beta.
|
|
13228
|
+
var version$1 = "4.20.0-beta.7";
|
|
12803
13229
|
//#endregion
|
|
12804
13230
|
//#region ../../packages/sdk/src/telemetry/exception-projection.ts
|
|
12805
13231
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -13635,7 +14061,7 @@ function isMoneyTelemetryDebugEnabled() {
|
|
|
13635
14061
|
}
|
|
13636
14062
|
//#endregion
|
|
13637
14063
|
//#region ../../packages/sdk/src/surface/payment-command-execution.ts
|
|
13638
|
-
function isAborted$
|
|
14064
|
+
function isAborted$3(signal) {
|
|
13639
14065
|
return signal?.aborted === true;
|
|
13640
14066
|
}
|
|
13641
14067
|
function canonicalJson(value) {
|
|
@@ -13661,7 +14087,7 @@ async function abandonPrepared$1(deps, executionId, closePayment, reason, result
|
|
|
13661
14087
|
return result;
|
|
13662
14088
|
}
|
|
13663
14089
|
async function executePrepared(deps, prepare, isExpectedRequest, closePaymentOnExit, onPreparedClosed, signal, controls) {
|
|
13664
|
-
if (isAborted$
|
|
14090
|
+
if (isAborted$3(signal)) return {
|
|
13665
14091
|
ok: false,
|
|
13666
14092
|
error: Errors.cancelled({ operation: "payments" })
|
|
13667
14093
|
};
|
|
@@ -13690,7 +14116,7 @@ async function executePrepared(deps, prepare, isExpectedRequest, closePaymentOnE
|
|
|
13690
14116
|
ok: false,
|
|
13691
14117
|
error: Errors.invalidInput("payment", "prepared authority mismatch")
|
|
13692
14118
|
}, onPreparedClosed, controls);
|
|
13693
|
-
if (isAborted$
|
|
14119
|
+
if (isAborted$3(signal)) return abandonPrepared$1(deps, prepared.value.executionId, closePaymentOnExit, "cancelled", {
|
|
13694
14120
|
ok: false,
|
|
13695
14121
|
error: Errors.cancelled({ operation: "payments" })
|
|
13696
14122
|
}, onPreparedClosed, controls);
|
|
@@ -13716,7 +14142,7 @@ async function executePrepared(deps, prepare, isExpectedRequest, closePaymentOnE
|
|
|
13716
14142
|
error: signerFailure(deps.signer.source, "signUserOpHash", cause)
|
|
13717
14143
|
}, onPreparedClosed, controls);
|
|
13718
14144
|
}
|
|
13719
|
-
if (isAborted$
|
|
14145
|
+
if (isAborted$3(signal)) return abandonPrepared$1(deps, prepared.value.executionId, closePaymentOnExit, "cancelled", {
|
|
13720
14146
|
ok: false,
|
|
13721
14147
|
error: Errors.cancelled({ operation: "payments" })
|
|
13722
14148
|
}, onPreparedClosed, controls);
|
|
@@ -13751,7 +14177,7 @@ function cancelled(operation) {
|
|
|
13751
14177
|
error: Errors.cancelled({ operation })
|
|
13752
14178
|
};
|
|
13753
14179
|
}
|
|
13754
|
-
function isAborted$
|
|
14180
|
+
function isAborted$2(signal) {
|
|
13755
14181
|
return signal?.aborted === true;
|
|
13756
14182
|
}
|
|
13757
14183
|
async function signerCall(source, operation, run) {
|
|
@@ -13777,7 +14203,7 @@ async function abandonPrepared(deps, executionId, reason, result, onPreparedClos
|
|
|
13777
14203
|
return result;
|
|
13778
14204
|
}
|
|
13779
14205
|
async function executePersonalPayment(deps, payment, signal, requestKey, onPreparedClosed) {
|
|
13780
|
-
if (isAborted$
|
|
14206
|
+
if (isAborted$2(signal)) return cancelled(CAPXUL_OPERATIONS.payments.pay);
|
|
13781
14207
|
if (deps.signer === void 0) return mismatch("signer", "payments.pay requires a configured CapxulSigner");
|
|
13782
14208
|
const session = deps.actor.authSession();
|
|
13783
14209
|
if (session === null) return {
|
|
@@ -13805,10 +14231,10 @@ async function executePersonalPayment(deps, payment, signal, requestKey, onPrepa
|
|
|
13805
14231
|
executionId: prepared.value.executionId,
|
|
13806
14232
|
recipient: prepared.value.recipientObservation
|
|
13807
14233
|
});
|
|
13808
|
-
if (isAborted$
|
|
14234
|
+
if (isAborted$2(signal)) return abandonPrepared(deps, prepared.value.executionId, "cancelled", cancelled(CAPXUL_OPERATIONS.payments.pay), onPreparedClosed);
|
|
13809
14235
|
const signature = await signerCall(deps.signer.source, "signUserOpHash", () => deps.signer.signUserOpHash(prepared.value.digest));
|
|
13810
14236
|
if (!signature.ok) return abandonPrepared(deps, prepared.value.executionId, "signer_rejected", signature, onPreparedClosed);
|
|
13811
|
-
if (isAborted$
|
|
14237
|
+
if (isAborted$2(signal)) return abandonPrepared(deps, prepared.value.executionId, "cancelled", cancelled(CAPXUL_OPERATIONS.payments.pay), onPreparedClosed);
|
|
13812
14238
|
return runIfActive(void 0, CAPXUL_OPERATIONS.payments.submitExecution, () => deps.convexCall.action(deps.functions.submitPaymentExecution, { input: {
|
|
13813
14239
|
executionId: prepared.value.executionId,
|
|
13814
14240
|
signature: signature.value
|
|
@@ -44803,7 +45229,9 @@ const OBSERVED_CONVEX_MUTATIONS = /* @__PURE__ */ new Set([
|
|
|
44803
45229
|
"smartAccount/mutations:provision",
|
|
44804
45230
|
"org/lifecycle:startOrResume",
|
|
44805
45231
|
"org/lifecycle:recordFailure",
|
|
44806
|
-
"org/lifecycle:retry"
|
|
45232
|
+
"org/lifecycle:retry",
|
|
45233
|
+
"org/mutations:invite",
|
|
45234
|
+
"org/mutations:accept"
|
|
44807
45235
|
]);
|
|
44808
45236
|
var ConvexCallAdapter = class {
|
|
44809
45237
|
#client;
|
|
@@ -45476,10 +45904,7 @@ const DEFAULT_FUNCTIONS$1 = {
|
|
|
45476
45904
|
listAll: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].listAll),
|
|
45477
45905
|
listRoles: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].listRolesByOrgId),
|
|
45478
45906
|
listMembers: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].listMembersByOrgId),
|
|
45479
|
-
readTreasury: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].readTreasury)
|
|
45480
|
-
inviteMember: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].inviteMember),
|
|
45481
|
-
resendInvite: makeFunctionReference(CAPXUL_FUNCTIONS["org/mutations"].resendInviteToken),
|
|
45482
|
-
detectInvitations: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].detectAndAcceptPendingInvitations)
|
|
45907
|
+
readTreasury: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].readTreasury)
|
|
45483
45908
|
};
|
|
45484
45909
|
/**
|
|
45485
45910
|
* Standard production Organization read adapter. It intentionally has no
|
|
@@ -45515,22 +45940,6 @@ var ConvexOrganizationAdapter = class {
|
|
|
45515
45940
|
pendingMembers(input) {
|
|
45516
45941
|
return this.listMembers(input).pipe(Effect.map((members) => members.filter((member) => member.status === "pending" || member.status === "pending_safe" || member.status === "pending_grant")));
|
|
45517
45942
|
}
|
|
45518
|
-
inviteMember(input) {
|
|
45519
|
-
return this.#convex.action(this.#fns.inviteMember, copyInvocationObservation(input, {
|
|
45520
|
-
orgId: input.orgId,
|
|
45521
|
-
email: input.input.email,
|
|
45522
|
-
role: input.input.role
|
|
45523
|
-
})).pipe(Effect.mapError((error) => orgErrorFromCapxul("inviteMember", error.publicError, error)), Effect.map(brandOrgMember), Effect.catchDefect((cause) => Effect.fail(toOrgError("inviteMember", cause))));
|
|
45524
|
-
}
|
|
45525
|
-
resendInviteToken(input) {
|
|
45526
|
-
return this.#convex.mutation(this.#fns.resendInvite, {
|
|
45527
|
-
orgId: input.orgId,
|
|
45528
|
-
email: input.email
|
|
45529
|
-
}).pipe(Effect.mapError((error) => orgErrorFromCapxul("resendInviteToken", error.publicError, error)), Effect.map(brandOrgMember), Effect.catchDefect((cause) => Effect.fail(toOrgError("resendInviteToken", cause))));
|
|
45530
|
-
}
|
|
45531
|
-
detectAndAcceptPendingInvitations(_input) {
|
|
45532
|
-
return this.#convex.action(this.#fns.detectInvitations, {}).pipe(Effect.mapError((error) => orgErrorFromCapxul("detectAndAcceptPendingInvitations", error.publicError, error)), Effect.map((result) => ({ matched: result.matched.map(toOrgId) })), Effect.catchDefect((cause) => Effect.fail(toOrgError("detectAndAcceptPendingInvitations", cause))));
|
|
45533
|
-
}
|
|
45534
45943
|
#readTreasuryWire(input) {
|
|
45535
45944
|
const orgId = String(input.orgId);
|
|
45536
45945
|
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) => {
|
|
@@ -45575,11 +45984,12 @@ var ConvexOrganizationSetupAdapter = class {
|
|
|
45575
45984
|
#fns;
|
|
45576
45985
|
constructor(input) {
|
|
45577
45986
|
this.#convex = input.convex;
|
|
45578
|
-
this.#signer = input.signer;
|
|
45987
|
+
this.#signer = input.signer ?? null;
|
|
45579
45988
|
this.#chainId = input.chainId;
|
|
45580
45989
|
this.#fns = input.functions ?? DEFAULT_FUNCTIONS;
|
|
45581
45990
|
}
|
|
45582
45991
|
async startOrResume(input) {
|
|
45992
|
+
if (this.#signer === null) return fail$2(Errors.capabilityUnavailable("signer", "startOrResume"));
|
|
45583
45993
|
const result = await runCall("startOrResume", this.#convex.mutation(this.#fns.startOrResume, copyInvocationObservation(input, {
|
|
45584
45994
|
...input,
|
|
45585
45995
|
chainId: this.#chainId
|
|
@@ -45607,7 +46017,9 @@ var ConvexOrganizationSetupAdapter = class {
|
|
|
45607
46017
|
async authorizeAndSubmitBootstrap(input) {
|
|
45608
46018
|
const cancelled = cancellation(input.signal);
|
|
45609
46019
|
if (cancelled !== void 0) return cancelled;
|
|
45610
|
-
const
|
|
46020
|
+
const signer = this.#signer;
|
|
46021
|
+
if (signer === null) return fail$2(Errors.capabilityUnavailable("signer", "authorizeAndSubmitBootstrap"));
|
|
46022
|
+
const signerAddress = await signerResult(signer.source, "getAddress", () => signer.getAddress());
|
|
45611
46023
|
if (!signerAddress.ok) return signerAddress;
|
|
45612
46024
|
const prepared = await runCall("prepareBootstrap", this.#convex.action(this.#fns.prepareBootstrap, copyInvocationObservation(input, {
|
|
45613
46025
|
orgId: input.orgId,
|
|
@@ -45619,7 +46031,7 @@ var ConvexOrganizationSetupAdapter = class {
|
|
|
45619
46031
|
if (!authority.ok) return authority;
|
|
45620
46032
|
const cancelledAfterPrepare = cancellation(input.signal);
|
|
45621
46033
|
if (cancelledAfterPrepare !== void 0) return cancelledAfterPrepare;
|
|
45622
|
-
const signature = await signerResult(
|
|
46034
|
+
const signature = await signerResult(signer.source, "signUserOpHash", () => signer.signUserOpHash(prepared.value.digest));
|
|
45623
46035
|
if (!signature.ok) return signature;
|
|
45624
46036
|
const cancelledAfterSign = cancellation(input.signal);
|
|
45625
46037
|
if (cancelledAfterSign !== void 0) return cancelledAfterSign;
|
|
@@ -45675,7 +46087,8 @@ var ConvexOrganizationSetupAdapter = class {
|
|
|
45675
46087
|
...input.observationContext === void 0 ? {} : { observationContext: input.observationContext }
|
|
45676
46088
|
});
|
|
45677
46089
|
if (!current.ok) return current;
|
|
45678
|
-
if (current.value.status === "failed" && current.value.retryable &&
|
|
46090
|
+
if (current.value.status === "failed" && current.value.retryable && current.value.at === "awaitingFounderAuthorization") {
|
|
46091
|
+
if (this.#signer === null) return fail$2(Errors.capabilityUnavailable("signer", "retry"));
|
|
45679
46092
|
const reset = resetSignerSession(this.#signer);
|
|
45680
46093
|
if (!reset.ok) return reset;
|
|
45681
46094
|
}
|
|
@@ -46338,7 +46751,7 @@ const identitySpec = (input, sessionStore = { current: null }) => {
|
|
|
46338
46751
|
initial: RESTORING,
|
|
46339
46752
|
label,
|
|
46340
46753
|
slot: identitySlot,
|
|
46341
|
-
transition: (state, event) => transition(state, event, config),
|
|
46754
|
+
transition: (state, event) => transition$1(state, event, config),
|
|
46342
46755
|
recoverFailure: recoverIdentityFailure,
|
|
46343
46756
|
invalidates: (event) => event._tag === "Reset" ? [
|
|
46344
46757
|
IDENTITY_SLOT.auth,
|
|
@@ -47723,6 +48136,271 @@ function makeOrgMeMethod(deps, orgId) {
|
|
|
47723
48136
|
};
|
|
47724
48137
|
}
|
|
47725
48138
|
//#endregion
|
|
48139
|
+
//#region ../../packages/sdk/src/contract/invitations.ts
|
|
48140
|
+
const invitationContract = {
|
|
48141
|
+
preview: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].previewInvite),
|
|
48142
|
+
listMine: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].listMyInvitations),
|
|
48143
|
+
listScoped: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].listInvitations),
|
|
48144
|
+
get: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].getInvitation),
|
|
48145
|
+
invite: makeFunctionReference(CAPXUL_FUNCTIONS["org/mutations"].invite),
|
|
48146
|
+
accept: makeFunctionReference(CAPXUL_FUNCTIONS["org/mutations"].accept),
|
|
48147
|
+
decline: makeFunctionReference(CAPXUL_FUNCTIONS["org/mutations"].decline),
|
|
48148
|
+
cancel: makeFunctionReference(CAPXUL_FUNCTIONS["org/mutations"].cancel),
|
|
48149
|
+
resend: makeFunctionReference(CAPXUL_FUNCTIONS["org/mutations"].resend),
|
|
48150
|
+
retry: makeFunctionReference(CAPXUL_FUNCTIONS["org/mutations"].retry)
|
|
48151
|
+
};
|
|
48152
|
+
//#endregion
|
|
48153
|
+
//#region ../../packages/sdk/src/surface/invitations.ts
|
|
48154
|
+
/**
|
|
48155
|
+
* The one refusal a scoped invitation result that names another Organization
|
|
48156
|
+
* receives, whether it was read or returned by the authoring write.
|
|
48157
|
+
*/
|
|
48158
|
+
function scopeRefusal(orgId) {
|
|
48159
|
+
return Errors.invalidInput("orgId", `The invitation result does not belong to Organization ${JSON.stringify(orgId)}.`);
|
|
48160
|
+
}
|
|
48161
|
+
/**
|
|
48162
|
+
* A scoped invitation result belongs to the Organization it was read under.
|
|
48163
|
+
*
|
|
48164
|
+
* One owner holds the refusal copy and the verified-scope span: a single view
|
|
48165
|
+
* reports whether it names the scope, and a page — which names no Organization
|
|
48166
|
+
* of its own — reports whether every row does. A result that does not belong is
|
|
48167
|
+
* refused here rather than handed to a consumer, so a future route change
|
|
48168
|
+
* cannot turn into a silent cross-Organization read on a caller that trusted
|
|
48169
|
+
* the scope it passed. A successful scoped read also marks the verifying
|
|
48170
|
+
* Organization on the owning span, exactly as `org.me` does — the caller's
|
|
48171
|
+
* scope hint is not authority, the completed scoped read is.
|
|
48172
|
+
*/
|
|
48173
|
+
function verifyScope(orgId, value, belongsToScope) {
|
|
48174
|
+
if (!belongsToScope(value)) return Effect.fail(scopeRefusal(orgId));
|
|
48175
|
+
return Effect.annotateCurrentSpan({
|
|
48176
|
+
verified_organization_id: orgId,
|
|
48177
|
+
scope_kind: "organization"
|
|
48178
|
+
}).pipe(Effect.as(value));
|
|
48179
|
+
}
|
|
48180
|
+
/** One view names its own Organization. */
|
|
48181
|
+
const namesScope = (orgId) => (value) => String(value.orgId) === orgId;
|
|
48182
|
+
/** A page names no Organization of its own, so every row must name the scope. */
|
|
48183
|
+
const rowsNameScope = (orgId) => (page) => page.items.every((item) => String(item.orgId) === orgId);
|
|
48184
|
+
const ops = CAPXUL_OPERATIONS.org.invitations;
|
|
48185
|
+
/** Truth for a caller-owned signal, without narrowing its type. */
|
|
48186
|
+
function isAborted$1(signal) {
|
|
48187
|
+
return signal?.aborted === true;
|
|
48188
|
+
}
|
|
48189
|
+
/**
|
|
48190
|
+
* One observed operation around one Convex hop, exactly like `org.me`. The
|
|
48191
|
+
* call-start invocation snapshot rides the arguments, so the backend continues
|
|
48192
|
+
* the attempt this call started rather than resolving a new one.
|
|
48193
|
+
*/
|
|
48194
|
+
function observed$1(deps, operation, options, args, call, check) {
|
|
48195
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
48196
|
+
return runCapxulEffect(call(copyInvocationObservation(controls, args)).pipe(Effect.mapError((failure) => failure.publicError), Effect.flatMap((value) => check === void 0 ? Effect.succeed(value) : check(value))), controls, operation, deps.runPromise);
|
|
48197
|
+
}
|
|
48198
|
+
/**
|
|
48199
|
+
* The Admin's preview stays a read: it reaches the preview query and nothing
|
|
48200
|
+
* else. It reads current policies and live assignments, so the operator sees
|
|
48201
|
+
* what the offered authority is now, not a frozen copy.
|
|
48202
|
+
*/
|
|
48203
|
+
function makeOrgInvitationMethods(deps, orgId) {
|
|
48204
|
+
const scopeCheck = (value) => verifyScope(orgId, value, namesScope(orgId));
|
|
48205
|
+
return {
|
|
48206
|
+
preview: (input, options) => observed$1(deps, ops.preview, options, {
|
|
48207
|
+
orgId,
|
|
48208
|
+
request: input
|
|
48209
|
+
}, (args) => deps.convexCall.query(invitationContract.preview, args), scopeCheck),
|
|
48210
|
+
invite: makeInviteMethod(deps, orgId),
|
|
48211
|
+
accept: (input, options) => observed$1(deps, ops.accept, options, {
|
|
48212
|
+
orgId,
|
|
48213
|
+
invitationId: input.invitationId,
|
|
48214
|
+
expectedOfferDigest: input.expectedOfferDigest
|
|
48215
|
+
}, (args) => deps.convexCall.mutation(invitationContract.accept, args), scopeCheck),
|
|
48216
|
+
list: (input, options) => observed$1(deps, ops.listScoped, options, {
|
|
48217
|
+
orgId,
|
|
48218
|
+
...pageArgs(input)
|
|
48219
|
+
}, (args) => deps.convexCall.query(invitationContract.listScoped, args), (page) => verifyScope(orgId, page, rowsNameScope(orgId))),
|
|
48220
|
+
get: (input, options) => observed$1(deps, ops.get, options, {
|
|
48221
|
+
orgId,
|
|
48222
|
+
invitationId: input.invitationId
|
|
48223
|
+
}, (args) => deps.convexCall.query(invitationContract.get, args), scopeCheck),
|
|
48224
|
+
decline: (input, options) => observed$1(deps, ops.decline, options, {
|
|
48225
|
+
orgId,
|
|
48226
|
+
invitationId: input.invitationId
|
|
48227
|
+
}, (args) => deps.convexCall.mutation(invitationContract.decline, args), scopeCheck),
|
|
48228
|
+
cancel: (input, options) => observed$1(deps, ops.cancel, options, {
|
|
48229
|
+
orgId,
|
|
48230
|
+
invitationId: input.invitationId
|
|
48231
|
+
}, (args) => deps.convexCall.mutation(invitationContract.cancel, args), scopeCheck),
|
|
48232
|
+
resend: (input, options) => observed$1(deps, ops.resend, options, {
|
|
48233
|
+
orgId,
|
|
48234
|
+
invitationId: input.invitationId
|
|
48235
|
+
}, (args) => deps.convexCall.mutation(invitationContract.resend, args), scopeCheck),
|
|
48236
|
+
retry: (input, options) => observed$1(deps, ops.retry, options, {
|
|
48237
|
+
orgId,
|
|
48238
|
+
invitationId: input.invitationId
|
|
48239
|
+
}, (args) => deps.convexCall.mutation(invitationContract.retry, args), scopeCheck)
|
|
48240
|
+
};
|
|
48241
|
+
}
|
|
48242
|
+
/**
|
|
48243
|
+
* The authoring write, including its configuration hop.
|
|
48244
|
+
*
|
|
48245
|
+
* The mutation persists the invitation and its configure command before any
|
|
48246
|
+
* signature exists. The write then drives the existing human configuration
|
|
48247
|
+
* owner exactly as the Permission and payment surfaces drive theirs: prepare
|
|
48248
|
+
* the stored command for this Account's Safe, check the prepared authority
|
|
48249
|
+
* against the request, deliver the durable identity to the caller, sign the
|
|
48250
|
+
* returned digest, and submit it. The backend keeps the only authorization
|
|
48251
|
+
* rule (`prepareInvitationConfigurationIntentInTx` /
|
|
48252
|
+
* `submitInvitationConfigurationExecution`); this edge adds no second one.
|
|
48253
|
+
*
|
|
48254
|
+
* Cancellation owns the whole compound: an abort before the digest is signed
|
|
48255
|
+
* stops the write and forwards no signature, and an already-signed submission
|
|
48256
|
+
* completes.
|
|
48257
|
+
*/
|
|
48258
|
+
async function executeInvite(deps, orgId, input, signal, controls, verifiedOrganization, onPrepared) {
|
|
48259
|
+
if (isAborted$1(signal)) return {
|
|
48260
|
+
ok: false,
|
|
48261
|
+
error: Errors.cancelled({ operation: ops.authorize })
|
|
48262
|
+
};
|
|
48263
|
+
if (deps.actor === void 0 || deps.chainId === void 0 || deps.signer === void 0) return {
|
|
48264
|
+
ok: false,
|
|
48265
|
+
error: Errors.notImplemented("invitations", "executionComposition")
|
|
48266
|
+
};
|
|
48267
|
+
const session = deps.actor.authSession();
|
|
48268
|
+
if (session === null) return {
|
|
48269
|
+
ok: false,
|
|
48270
|
+
error: Errors.notAuthenticated()
|
|
48271
|
+
};
|
|
48272
|
+
const authored = await runIfActive(signal, ops.authorize, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.mutation(invitationContract.invite, copyInvocationObservation(controls, {
|
|
48273
|
+
orgId,
|
|
48274
|
+
request: input
|
|
48275
|
+
}))), controls), deps.runPromise);
|
|
48276
|
+
if (!authored.ok) return authored;
|
|
48277
|
+
const view = authored.value;
|
|
48278
|
+
if (String(view.orgId) !== orgId) return {
|
|
48279
|
+
ok: false,
|
|
48280
|
+
error: scopeRefusal(orgId)
|
|
48281
|
+
};
|
|
48282
|
+
if (view.phase !== "authorizing") return {
|
|
48283
|
+
ok: true,
|
|
48284
|
+
value: view
|
|
48285
|
+
};
|
|
48286
|
+
if (view.commandId === null) return {
|
|
48287
|
+
ok: false,
|
|
48288
|
+
error: Errors.invalidInput("invitationId", "The invitation does not name its configuration command.")
|
|
48289
|
+
};
|
|
48290
|
+
const commandId = view.commandId;
|
|
48291
|
+
let signerAddress;
|
|
48292
|
+
try {
|
|
48293
|
+
signerAddress = await deps.signer.getAddress();
|
|
48294
|
+
} catch (cause) {
|
|
48295
|
+
return {
|
|
48296
|
+
ok: false,
|
|
48297
|
+
error: signerFailure(deps.signer.source, "getAddress", cause)
|
|
48298
|
+
};
|
|
48299
|
+
}
|
|
48300
|
+
const prepared = await runIfActive(signal, ops.prepareConfiguration, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.action(moneyExecutionContract.prepareInvitationConfiguration, copyInvocationObservation(controls, { input: {
|
|
48301
|
+
commandId,
|
|
48302
|
+
signerAddress
|
|
48303
|
+
} }))), controls), deps.runPromise);
|
|
48304
|
+
if (!prepared.ok) return prepared;
|
|
48305
|
+
const expectedSafe = deriveCapxulSafeAddress({ email: session.email });
|
|
48306
|
+
if (!preparedAuthorityMatches({
|
|
48307
|
+
prepared: prepared.value,
|
|
48308
|
+
chainId: deps.chainId,
|
|
48309
|
+
signerAddress,
|
|
48310
|
+
expectedSafe,
|
|
48311
|
+
commandId,
|
|
48312
|
+
invitationId: view.id,
|
|
48313
|
+
orgId
|
|
48314
|
+
})) return {
|
|
48315
|
+
ok: false,
|
|
48316
|
+
error: Errors.invalidInput("invitation", "prepared authority mismatch")
|
|
48317
|
+
};
|
|
48318
|
+
verifiedOrganization(prepared.value.orgId);
|
|
48319
|
+
if (isAborted$1(signal)) return {
|
|
48320
|
+
ok: false,
|
|
48321
|
+
error: Errors.cancelled({ operation: ops.authorize })
|
|
48322
|
+
};
|
|
48323
|
+
if (onPrepared !== void 0) try {
|
|
48324
|
+
await onPrepared({
|
|
48325
|
+
invitationId: prepared.value.invitationId,
|
|
48326
|
+
commandId: prepared.value.commandId
|
|
48327
|
+
});
|
|
48328
|
+
} catch (cause) {
|
|
48329
|
+
return {
|
|
48330
|
+
ok: false,
|
|
48331
|
+
error: cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
48332
|
+
};
|
|
48333
|
+
}
|
|
48334
|
+
if (isAborted$1(signal)) return {
|
|
48335
|
+
ok: false,
|
|
48336
|
+
error: Errors.cancelled({ operation: ops.authorize })
|
|
48337
|
+
};
|
|
48338
|
+
let signature;
|
|
48339
|
+
try {
|
|
48340
|
+
signature = await deps.signer.signUserOpHash(prepared.value.digest);
|
|
48341
|
+
} catch (cause) {
|
|
48342
|
+
return {
|
|
48343
|
+
ok: false,
|
|
48344
|
+
error: signerFailure(deps.signer.source, "signUserOpHash", cause)
|
|
48345
|
+
};
|
|
48346
|
+
}
|
|
48347
|
+
if (isAborted$1(signal)) return {
|
|
48348
|
+
ok: false,
|
|
48349
|
+
error: Errors.cancelled({ operation: ops.authorize })
|
|
48350
|
+
};
|
|
48351
|
+
const submitted = await runIfActive(void 0, ops.submitConfiguration, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.action(moneyExecutionContract.submitInvitationConfigurationExecution, copyInvocationObservation(controls, { input: {
|
|
48352
|
+
executionId: prepared.value.executionId,
|
|
48353
|
+
signature
|
|
48354
|
+
} }))), controls), deps.runPromise);
|
|
48355
|
+
if (!submitted.ok) return submitted;
|
|
48356
|
+
return {
|
|
48357
|
+
ok: true,
|
|
48358
|
+
value: view
|
|
48359
|
+
};
|
|
48360
|
+
}
|
|
48361
|
+
/**
|
|
48362
|
+
* The prepared authority must be exactly the one this write asked for: the same
|
|
48363
|
+
* chain, the caller's signer, this Account's Safe, and the exact command and
|
|
48364
|
+
* invitation the authoring view named.
|
|
48365
|
+
*/
|
|
48366
|
+
function preparedAuthorityMatches(input) {
|
|
48367
|
+
return input.prepared.chainId === input.chainId && input.prepared.signerAddress.toLowerCase() === input.signerAddress.toLowerCase() && input.prepared.userOpSenderSafe.toLowerCase() === input.expectedSafe.toLowerCase() && input.prepared.commandId === input.commandId && input.prepared.invitationId === input.invitationId && input.prepared.orgId === input.orgId;
|
|
48368
|
+
}
|
|
48369
|
+
function makeInviteMethod(deps, orgId) {
|
|
48370
|
+
return (input, options) => {
|
|
48371
|
+
const { onPrepared, ...supplied } = options ?? {};
|
|
48372
|
+
const controls = deps.invocationControls?.(supplied) ?? supplied;
|
|
48373
|
+
let verifiedOrganizationId;
|
|
48374
|
+
return runCapxulEffect(Effect.gen(function* () {
|
|
48375
|
+
if (controls?.signal?.aborted === true) return yield* Effect.fail(Errors.cancelled({ operation: ops.authorize }));
|
|
48376
|
+
const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
|
|
48377
|
+
const captured = carryInvocationParentSpan(controls, parent);
|
|
48378
|
+
const result = yield* Effect.tryPromise({
|
|
48379
|
+
try: () => executeInvite(deps, orgId, input, controls?.signal, captured, (id) => {
|
|
48380
|
+
verifiedOrganizationId = id;
|
|
48381
|
+
}, onPrepared),
|
|
48382
|
+
catch: (cause) => cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
48383
|
+
});
|
|
48384
|
+
return yield* result.ok ? Effect.succeed(result.value) : Effect.fail(result.error);
|
|
48385
|
+
}).pipe(Effect.ensuring(Effect.suspend(() => verifiedOrganizationId === void 0 ? Effect.void : Effect.annotateCurrentSpan({
|
|
48386
|
+
verified_organization_id: verifiedOrganizationId,
|
|
48387
|
+
scope_kind: "organization"
|
|
48388
|
+
})).pipe(Effect.catchCause(() => Effect.void)))), observationOnlyControls(controls), ops.authorize, deps.runPromise);
|
|
48389
|
+
};
|
|
48390
|
+
}
|
|
48391
|
+
/** Drop the page fields the caller did not supply; a bounded page sends only its bounds. */
|
|
48392
|
+
function pageArgs(input) {
|
|
48393
|
+
if (input === void 0) return {};
|
|
48394
|
+
return {
|
|
48395
|
+
...input.cursor === void 0 ? {} : { cursor: input.cursor },
|
|
48396
|
+
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
48397
|
+
...input.phases === void 0 ? {} : { phases: input.phases }
|
|
48398
|
+
};
|
|
48399
|
+
}
|
|
48400
|
+
function makeOwnInvitationsMethod(deps) {
|
|
48401
|
+
return (input, options) => observed$1(deps, ops.list, options, pageArgs(input), (args) => deps.convexCall.query(invitationContract.listMine, args));
|
|
48402
|
+
}
|
|
48403
|
+
//#endregion
|
|
47726
48404
|
//#region ../../packages/sdk/src/contract/permission.ts
|
|
47727
48405
|
const permissionContract = { read: makeFunctionReference(CAPXUL_FUNCTIONS["permission/queries"].read) };
|
|
47728
48406
|
//#endregion
|
|
@@ -48410,20 +49088,6 @@ function hermeticOrgView(input) {
|
|
|
48410
49088
|
observedAt: 0
|
|
48411
49089
|
};
|
|
48412
49090
|
}
|
|
48413
|
-
function hermeticMember(input) {
|
|
48414
|
-
return {
|
|
48415
|
-
orgId: input.orgId,
|
|
48416
|
-
accountId: null,
|
|
48417
|
-
email: toEmail(input.email),
|
|
48418
|
-
name: null,
|
|
48419
|
-
personalSafeAddress: input.personalSafeAddress ?? null,
|
|
48420
|
-
role: input.role,
|
|
48421
|
-
roleKey: toRoleKey(orgRoleKeyForLabel(input.role)),
|
|
48422
|
-
status: input.status,
|
|
48423
|
-
grantTxHash: input.grantTxHash ?? null,
|
|
48424
|
-
revokeTxHash: input.revokeTxHash ?? null
|
|
48425
|
-
};
|
|
48426
|
-
}
|
|
48427
49091
|
function createOrgProgram(input) {
|
|
48428
49092
|
return Effect.gen(function* () {
|
|
48429
49093
|
const deps = yield* OrgDepsTag;
|
|
@@ -48524,35 +49188,6 @@ function listMembersProgram(orgId) {
|
|
|
48524
49188
|
return [];
|
|
48525
49189
|
});
|
|
48526
49190
|
}
|
|
48527
|
-
/**
|
|
48528
|
-
* R06 (#1964): the SDK no longer emits `org_invite_sent`. The backend action
|
|
48529
|
-
* that writes the invitation is its ONE producer, so a hermetic call — which
|
|
48530
|
-
* writes nothing — can no longer report an invitation that never happened, and
|
|
48531
|
-
* a live call is counted once instead of twice. The captured attempt rides the
|
|
48532
|
-
* port input, so the durable event carries the correlation this call ran under.
|
|
48533
|
-
*/
|
|
48534
|
-
function inviteMemberProgram(orgId, input) {
|
|
48535
|
-
return Effect.gen(function* () {
|
|
48536
|
-
const deps = yield* OrgDepsTag;
|
|
48537
|
-
if (deps.orgPort === void 0) return hermeticMember({
|
|
48538
|
-
orgId,
|
|
48539
|
-
email: input.email,
|
|
48540
|
-
role: input.role,
|
|
48541
|
-
status: "pending"
|
|
48542
|
-
});
|
|
48543
|
-
return yield* deps.orgPort.inviteMember(copyInvocationObservation(deps.invocationSource, {
|
|
48544
|
-
orgId,
|
|
48545
|
-
input
|
|
48546
|
-
})).pipe(Effect.mapError((error) => error.publicError));
|
|
48547
|
-
});
|
|
48548
|
-
}
|
|
48549
|
-
function detectAndAcceptPendingInvitationsProgram() {
|
|
48550
|
-
return Effect.gen(function* () {
|
|
48551
|
-
const deps = yield* OrgDepsTag;
|
|
48552
|
-
if (deps.orgPort !== void 0) return yield* deps.orgPort.detectAndAcceptPendingInvitations({}).pipe(Effect.mapError((error) => error.publicError));
|
|
48553
|
-
return { matched: [] };
|
|
48554
|
-
});
|
|
48555
|
-
}
|
|
48556
49191
|
function listOrgsProgram() {
|
|
48557
49192
|
return Effect.gen(function* () {
|
|
48558
49193
|
const deps = yield* OrgDepsTag;
|
|
@@ -48658,6 +49293,20 @@ function observedRunnerDeps(deps) {
|
|
|
48658
49293
|
...deps.invocationControls === void 0 ? {} : { invocationControls: deps.invocationControls }
|
|
48659
49294
|
};
|
|
48660
49295
|
}
|
|
49296
|
+
/**
|
|
49297
|
+
* The invitation edge needs the call seam, the observed-runner pair, and — for
|
|
49298
|
+
* the authoring write's configuration hop — the same execution composition the
|
|
49299
|
+
* Permission, payment, and payroll bundles receive.
|
|
49300
|
+
*/
|
|
49301
|
+
function invitationMethodsDeps(deps, convexCall) {
|
|
49302
|
+
return {
|
|
49303
|
+
convexCall,
|
|
49304
|
+
...observedRunnerDeps(deps),
|
|
49305
|
+
...deps.actor === void 0 ? {} : { actor: deps.actor },
|
|
49306
|
+
...deps.chainId === void 0 ? {} : { chainId: Number(deps.chainId) },
|
|
49307
|
+
...deps.signer === void 0 ? {} : { signer: deps.signer }
|
|
49308
|
+
};
|
|
49309
|
+
}
|
|
48661
49310
|
function makeOrgMethods(deps) {
|
|
48662
49311
|
const orgDeps = {
|
|
48663
49312
|
...deps.orgPort === void 0 ? {} : { orgPort: deps.orgPort },
|
|
@@ -48689,13 +49338,10 @@ function makeOrgMethods(deps) {
|
|
|
48689
49338
|
});
|
|
48690
49339
|
return toCapxulResult(createOrgProgram(input), layer);
|
|
48691
49340
|
},
|
|
48692
|
-
orgs: Object.assign((options) => listOrganizations(deps.invocationControls?.(options) ?? options), {
|
|
48693
|
-
|
|
48694
|
-
|
|
48695
|
-
|
|
48696
|
-
});
|
|
48697
|
-
return toCapxulResult(detectAndAcceptPendingInvitationsProgram(), layer);
|
|
48698
|
-
} }),
|
|
49341
|
+
orgs: Object.assign((options) => listOrganizations(deps.invocationControls?.(options) ?? options), { invitations: deps.convexCall === void 0 ? () => Promise.resolve({
|
|
49342
|
+
ok: false,
|
|
49343
|
+
error: Errors.notImplemented("invitations", "listOwn")
|
|
49344
|
+
}) : makeOwnInvitationsMethod(invitationMethodsDeps(deps, deps.convexCall)) }),
|
|
48699
49345
|
org(orgId) {
|
|
48700
49346
|
const convexCall = deps.convexCall;
|
|
48701
49347
|
return {
|
|
@@ -48803,17 +49449,7 @@ function makeOrgMethods(deps) {
|
|
|
48803
49449
|
});
|
|
48804
49450
|
return toCapxulResult(listRolesProgram(orgId), layer);
|
|
48805
49451
|
},
|
|
48806
|
-
|
|
48807
|
-
const controls = deps.invocationControls?.(_options) ?? _options;
|
|
48808
|
-
if (controls?.signal?.aborted) return Promise.resolve({
|
|
48809
|
-
ok: false,
|
|
48810
|
-
error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.org.invite })
|
|
48811
|
-
});
|
|
48812
|
-
return runCapxulEffect(inviteMemberProgram(orgId, _input).pipe(Effect.provide(orgDepsLayer({
|
|
48813
|
-
...orgDeps,
|
|
48814
|
-
...controls === void 0 ? {} : { invocationSource: controls }
|
|
48815
|
-
}))), controls, CAPXUL_OPERATIONS.org.invite, deps.runPromise);
|
|
48816
|
-
},
|
|
49452
|
+
invitations: convexCall === void 0 ? makeNotImplementedInvitationMethods() : makeOrgInvitationMethods(invitationMethodsDeps(deps, convexCall), String(orgId)),
|
|
48817
49453
|
auditLog(_options) {
|
|
48818
49454
|
if (_options?.signal?.aborted) return Promise.resolve({
|
|
48819
49455
|
ok: false,
|
|
@@ -48876,6 +49512,28 @@ const orgMeUnavailable = () => Promise.resolve({
|
|
|
48876
49512
|
ok: false,
|
|
48877
49513
|
error: Errors.notImplemented("org", "me")
|
|
48878
49514
|
});
|
|
49515
|
+
/**
|
|
49516
|
+
* The closed invitation surface for a client with no backend seam. It reports
|
|
49517
|
+
* `NOT_IMPLEMENTED` for every method rather than an empty list or a fabricated
|
|
49518
|
+
* view: an absent composition root is not an absent invitation.
|
|
49519
|
+
*/
|
|
49520
|
+
function makeNotImplementedInvitationMethods() {
|
|
49521
|
+
return {
|
|
49522
|
+
preview: invitationExecutionUnavailable,
|
|
49523
|
+
invite: invitationExecutionUnavailable,
|
|
49524
|
+
accept: invitationExecutionUnavailable,
|
|
49525
|
+
list: invitationExecutionUnavailable,
|
|
49526
|
+
get: invitationExecutionUnavailable,
|
|
49527
|
+
decline: invitationExecutionUnavailable,
|
|
49528
|
+
cancel: invitationExecutionUnavailable,
|
|
49529
|
+
resend: invitationExecutionUnavailable,
|
|
49530
|
+
retry: invitationExecutionUnavailable
|
|
49531
|
+
};
|
|
49532
|
+
}
|
|
49533
|
+
const invitationExecutionUnavailable = () => Promise.resolve({
|
|
49534
|
+
ok: false,
|
|
49535
|
+
error: Errors.notImplemented("invitations", "executionComposition")
|
|
49536
|
+
});
|
|
48879
49537
|
const permissionExecutionUnavailable = () => Promise.resolve({
|
|
48880
49538
|
ok: false,
|
|
48881
49539
|
error: Errors.notImplemented("permissions", "executionComposition")
|
|
@@ -49375,7 +50033,6 @@ function assembleCapxulClient(input) {
|
|
|
49375
50033
|
};
|
|
49376
50034
|
if (input.signal !== void 0) input.signal.addEventListener("abort", () => void stopActor(), { once: true });
|
|
49377
50035
|
const selectedOrgPort = input.orgPort ?? input.orgDeploymentPort;
|
|
49378
|
-
let detectPendingOrgInvitations;
|
|
49379
50036
|
let kickProvisioning;
|
|
49380
50037
|
const financialOps = makeFinancialOpsMethods({
|
|
49381
50038
|
runPromise: effectRunner.runPromise,
|
|
@@ -49424,7 +50081,6 @@ function assembleCapxulClient(input) {
|
|
|
49424
50081
|
if (browserSigner.statusStore?.status() === "unknown" && typeof browserSigner.ensureWalletReady === "function") browserSigner.ensureWalletReady().catch(() => {});
|
|
49425
50082
|
}
|
|
49426
50083
|
if (accountSetup === "explicit") return;
|
|
49427
|
-
await detectPendingOrgInvitations?.();
|
|
49428
50084
|
kickProvisioning?.();
|
|
49429
50085
|
}
|
|
49430
50086
|
});
|
|
@@ -49492,9 +50148,6 @@ function assembleCapxulClient(input) {
|
|
|
49492
50148
|
...input.signer === void 0 ? {} : { signer: input.signer },
|
|
49493
50149
|
...input.organizationSetup === void 0 ? {} : { organizationSetup: input.organizationSetup }
|
|
49494
50150
|
});
|
|
49495
|
-
if (selectedOrgPort !== void 0) detectPendingOrgInvitations = async () => {
|
|
49496
|
-
await orgMethods.orgs.detectAndAcceptPendingInvitations();
|
|
49497
|
-
};
|
|
49498
50151
|
const currentUser = makeCurrentUserMethods({
|
|
49499
50152
|
me: financialOps.me,
|
|
49500
50153
|
accounts,
|
|
@@ -50667,11 +51320,11 @@ async function createCapxulClientWithSignerControls(input, controls) {
|
|
|
50667
51320
|
accountSetup: input.accountSetup,
|
|
50668
51321
|
...signer === void 0 ? {} : { signer },
|
|
50669
51322
|
orgPort: Context.get(adapters.value.context, OrgPortTag),
|
|
50670
|
-
|
|
51323
|
+
organizationSetup: new ConvexOrganizationSetupAdapter({
|
|
50671
51324
|
convex: adapters.value.ports.convexCall,
|
|
50672
|
-
signer,
|
|
51325
|
+
...signer === void 0 ? {} : { signer },
|
|
50673
51326
|
chainId: adapters.value.bootstrap.chainId
|
|
50674
|
-
})
|
|
51327
|
+
}),
|
|
50675
51328
|
...input.signal === void 0 ? {} : { signal: input.signal },
|
|
50676
51329
|
...input.otpTtlMs === void 0 ? {} : { otpTtlMs: input.otpTtlMs },
|
|
50677
51330
|
invokeTimeoutMs: input.invokeTimeoutMs ?? 3e4,
|
|
@@ -51010,8 +51663,8 @@ function captureException(telemetry, error, context) {
|
|
|
51010
51663
|
}
|
|
51011
51664
|
//#endregion
|
|
51012
51665
|
//#region src/version.ts
|
|
51013
|
-
const cliVersion = "4.20.0-beta.
|
|
51014
|
-
const sdkVersion = "4.20.0-beta.
|
|
51666
|
+
const cliVersion = "4.20.0-beta.7";
|
|
51667
|
+
const sdkVersion = "4.20.0-beta.7";
|
|
51015
51668
|
const ReleaseVersion = Schema.String.check(Schema.isMaxLength(256), Schema.isPattern(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?$/u)).pipe(Schema.brand("CliReleaseVersion"));
|
|
51016
51669
|
const parts = (version) => {
|
|
51017
51670
|
const [core = "", ...prerelease] = version.split("+")[0].split("-");
|
|
@@ -51677,7 +52330,7 @@ function parsedCommand(cause) {
|
|
|
51677
52330
|
//#endregion
|
|
51678
52331
|
//#region src/runtime/config.ts
|
|
51679
52332
|
const bundledKey = Redacted.make("cap_pk_test_DXF9C0HPKB9GPQX5C6RDP6NXKZG1B0D7");
|
|
51680
|
-
const bundledOrigin = "https://
|
|
52333
|
+
const bundledOrigin = "https://site.preview.abuusama.dev";
|
|
51681
52334
|
const defaultHost = "https://us.i.posthog.com";
|
|
51682
52335
|
const defaultProjectToken = Redacted.make("phc_BZuAVofrkNXzwpJkuDG7Rdfurir45fj2dudQvJZk847e");
|
|
51683
52336
|
const optionalText$1 = (name) => Config.option(Config.string(name));
|
|
@@ -52238,9 +52891,17 @@ const boundedLine = (value) => typeof value === "number" && Number.isSafeInteger
|
|
|
52238
52891
|
const writeStdout = (text) => Effect.flatMap(Stdio.Stdio, (stdio) => Stream.run(Stream.make(text), stdio.stdout()));
|
|
52239
52892
|
const writeStderr = (text) => Effect.flatMap(Stdio.Stdio, (stdio) => Stream.run(Stream.make(text), stdio.stderr()));
|
|
52240
52893
|
function renderResult(mode, envelope, lines = []) {
|
|
52241
|
-
|
|
52242
|
-
|
|
52894
|
+
const pretty = process.stdout.isTTY === true;
|
|
52895
|
+
if (mode === "json") return writeStdout(`${JSON.stringify(envelope, null, pretty ? 2 : void 0)}\n`);
|
|
52896
|
+
return envelope.outcome === "succeeded" ? writeStdout(`${(pretty ? lines.map(readableLine) : lines).join("\n")}\n`) : writeStderr(`${envelope.error.code}: ${envelope.error.message}\n`);
|
|
52243
52897
|
}
|
|
52898
|
+
const readableLine = (line) => {
|
|
52899
|
+
try {
|
|
52900
|
+
return JSON.stringify(JSON.parse(line), null, 2);
|
|
52901
|
+
} catch {
|
|
52902
|
+
return line;
|
|
52903
|
+
}
|
|
52904
|
+
};
|
|
52244
52905
|
//#endregion
|
|
52245
52906
|
//#region src/runtime/command-metadata.ts
|
|
52246
52907
|
var CliCommandMetadata = class extends Context.Service()("capxul-cli/CommandMetadata") {};
|
|
@@ -52380,7 +53041,7 @@ const checkDoctor = (config, options) => Effect.gen(function* () {
|
|
|
52380
53041
|
};
|
|
52381
53042
|
if (!options.online) return report;
|
|
52382
53043
|
const key = config.publishableKey;
|
|
52383
|
-
if (key === void 0 || Redacted.value(key).length === 0) return yield* Effect.fail(configurationFailure("Set CAPXUL_PUBLISHABLE_KEY for the
|
|
53044
|
+
if (key === void 0 || Redacted.value(key).length === 0) return yield* Effect.fail(configurationFailure("Set CAPXUL_PUBLISHABLE_KEY for the staging application before an online check."));
|
|
52384
53045
|
const result = yield* Effect.gen(function* () {
|
|
52385
53046
|
const started = yield* Clock.currentTimeMillis;
|
|
52386
53047
|
const client = yield* acquireClient({
|
|
@@ -52767,13 +53428,19 @@ main{display:flex;min-height:100dvh;flex-direction:column;align-items:center;jus
|
|
|
52767
53428
|
.logo{width:48px;height:48px;flex:none;animation:capxul-pulse 2s ease-in-out infinite}
|
|
52768
53429
|
[data-state=ready] .logo,[data-state=failed] .logo{animation:none}
|
|
52769
53430
|
h1{max-width:448px;margin:0;font-size:18px;font-weight:500;line-height:28px;text-wrap:balance}
|
|
53431
|
+
[data-state=working] h1{animation:capxul-breathe 2.4s ease-in-out infinite}
|
|
53432
|
+
@keyframes capxul-breathe{50%{opacity:.5}}
|
|
52770
53433
|
.message{max-width:448px;margin:0;color:#525252;font-size:14px;line-height:20px;text-wrap:pretty}
|
|
53434
|
+
.action{margin:0;padding:10px 18px;border:1px solid currentColor;border-radius:9999px;background:transparent;color:inherit;font:inherit;cursor:pointer}
|
|
53435
|
+
.action:hover{opacity:.75}
|
|
53436
|
+
.action:focus-visible{outline:2px solid #F97316;outline-offset:2px}
|
|
53437
|
+
[hidden]{display:none!important}
|
|
52771
53438
|
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
|
|
52772
53439
|
@media(prefers-color-scheme:dark){.message{color:#D4D4D4}}
|
|
52773
|
-
@media(prefers-reduced-motion:reduce){.logo{animation:none}}
|
|
53440
|
+
@media(prefers-reduced-motion:reduce){.logo,h1{animation:none}}
|
|
52774
53441
|
@keyframes capxul-pulse{50%{opacity:.45}}
|
|
52775
53442
|
</style>
|
|
52776
|
-
</head><body><main data-state="working" aria-busy="true"><svg class="logo" role="img" aria-label="Capxul" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 10C0 4.47715 4.47715 0 10 0H26C31.5228 0 36 4.47715 36 10V26C36 31.5228 31.5228 36 26 36H10C4.47715 36 0 31.5228 0 26V10Z" fill="#F97316"/><path d="M26.642 12.0117H25.2845C24.9618 12.012 24.6495 11.8993 24.4036 11.6936C24.1576 11.4879 23.994 11.2028 23.9421 10.8892C23.9303 10.8185 23.9244 10.747 23.9245 10.6754V9.3377C23.9245 8.98325 23.7816 8.6433 23.5273 8.39248C23.2729 8.14167 22.9279 8.00051 22.5679 8H14.5592C14.1991 8.00088 13.854 8.14175 13.5988 8.39197L8.39806 13.5136C8.27192 13.6376 8.17184 13.785 8.10354 13.9472C8.03524 14.1094 8.00006 14.2832 8 14.4588V22.6511C8.00065 23.0055 8.14405 23.3452 8.39873 23.5956C8.65341 23.8461 8.99858 23.9868 9.3585 23.9869H10.716C11.0762 23.987 11.4217 24.128 11.6763 24.3789C11.931 24.6297 12.074 24.9699 12.074 25.3246V26.6613C12.0742 27.016 12.2174 27.3562 12.4721 27.6069C12.7269 27.8577 13.0723 27.9986 13.4325 27.9986H21.4408C21.6192 27.9989 21.7959 27.9644 21.9608 27.8971C22.1256 27.8298 22.2753 27.7311 22.4012 27.6066L24.324 25.7142L27.6005 22.4879C27.7273 22.3639 27.8279 22.2164 27.8967 22.0539C27.9654 21.8914 28.0008 21.7172 28.001 21.5412V13.3494C28.001 13.1736 27.9658 12.9997 27.8975 12.8373C27.8292 12.675 27.7291 12.5275 27.6029 12.4033C27.4767 12.2791 27.3269 12.1805 27.162 12.1133C26.9971 12.0461 26.8204 12.0116 26.642 12.0117Z" fill="white"/><path d="M25.2012 18.4218V20.3672L22.2138 23.3089H15.9015V20.3672H22.2138V18.4218H25.2012ZM15.9015 11.0154L12.9141 13.9571V20.3672H15.9015V13.9571H22.2138V11.0154H15.9015ZM22.2138 13.9571V15.8707H25.2012V13.9571H22.2138Z" fill="#F97316"/></svg><h1 id="title">Connecting to Capxul CLI</h1><p class="message" id="status"
|
|
53443
|
+
</head><body><main data-state="working" aria-busy="true"><svg class="logo" role="img" aria-label="Capxul" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 10C0 4.47715 4.47715 0 10 0H26C31.5228 0 36 4.47715 36 10V26C36 31.5228 31.5228 36 26 36H10C4.47715 36 0 31.5228 0 26V10Z" fill="#F97316"/><path d="M26.642 12.0117H25.2845C24.9618 12.012 24.6495 11.8993 24.4036 11.6936C24.1576 11.4879 23.994 11.2028 23.9421 10.8892C23.9303 10.8185 23.9244 10.747 23.9245 10.6754V9.3377C23.9245 8.98325 23.7816 8.6433 23.5273 8.39248C23.2729 8.14167 22.9279 8.00051 22.5679 8H14.5592C14.1991 8.00088 13.854 8.14175 13.5988 8.39197L8.39806 13.5136C8.27192 13.6376 8.17184 13.785 8.10354 13.9472C8.03524 14.1094 8.00006 14.2832 8 14.4588V22.6511C8.00065 23.0055 8.14405 23.3452 8.39873 23.5956C8.65341 23.8461 8.99858 23.9868 9.3585 23.9869H10.716C11.0762 23.987 11.4217 24.128 11.6763 24.3789C11.931 24.6297 12.074 24.9699 12.074 25.3246V26.6613C12.0742 27.016 12.2174 27.3562 12.4721 27.6069C12.7269 27.8577 13.0723 27.9986 13.4325 27.9986H21.4408C21.6192 27.9989 21.7959 27.9644 21.9608 27.8971C22.1256 27.8298 22.2753 27.7311 22.4012 27.6066L24.324 25.7142L27.6005 22.4879C27.7273 22.3639 27.8279 22.2164 27.8967 22.0539C27.9654 21.8914 28.0008 21.7172 28.001 21.5412V13.3494C28.001 13.1736 27.9658 12.9997 27.8975 12.8373C27.8292 12.675 27.7291 12.5275 27.6029 12.4033C27.4767 12.2791 27.3269 12.1805 27.162 12.1133C26.9971 12.0461 26.8204 12.0116 26.642 12.0117Z" fill="white"/><path d="M25.2012 18.4218V20.3672L22.2138 23.3089H15.9015V20.3672H22.2138V18.4218H25.2012ZM15.9015 11.0154L12.9141 13.9571V20.3672H15.9015V13.9571H22.2138V11.0154H15.9015ZM22.2138 13.9571V15.8707H25.2012V13.9571H22.2138Z" fill="#F97316"/></svg><h1 id="title" role="status" aria-live="polite">Connecting to Capxul CLI</h1><p class="message" id="status"></p><button class="action" id="dismiss" type="button" hidden>Close this page</button><p class="sr-only">Account <span id="account">Personal account</span>. Environment <span id="environment">Loading</span>.</p></main><script src="/signer.js" defer><\/script></body></html>`;
|
|
52777
53444
|
const json = (response, status, body) => {
|
|
52778
53445
|
response.writeHead(status, {
|
|
52779
53446
|
"cache-control": "no-store",
|
|
@@ -53540,61 +54207,61 @@ const logout = (config, suppliedEmail) => Effect.gen(function* () {
|
|
|
53540
54207
|
});
|
|
53541
54208
|
//#endregion
|
|
53542
54209
|
//#region src/commands/auth.ts
|
|
53543
|
-
const emailFlag$
|
|
54210
|
+
const emailFlag$3 = Flag.string("email").pipe(Flag.withDescription("Account email"), Flag.optional);
|
|
53544
54211
|
const otpStdinFlag = Flag.boolean("otp-stdin").pipe(Flag.withDefault(false), Flag.withDescription("Read the six-digit OTP from stdin; never pass it as an argument"));
|
|
53545
54212
|
const displayNameFlag = Flag.string("display-name").pipe(Flag.withDescription("Profile display name"), Flag.optional);
|
|
53546
54213
|
const countryFlag = Flag.string("country").pipe(Flag.withDescription("Two-letter ISO country code"), Flag.optional);
|
|
53547
54214
|
const handleFlag = Flag.string("handle").pipe(Flag.withDescription("Globally unique Capxul handle"), Flag.optional);
|
|
53548
|
-
const metadata$
|
|
54215
|
+
const metadata$4 = (name) => ({
|
|
53549
54216
|
name,
|
|
53550
54217
|
capability: "authentication",
|
|
53551
54218
|
observation: "command"
|
|
53552
54219
|
});
|
|
53553
54220
|
const loginCommand = Command.make("login", {
|
|
53554
|
-
email: emailFlag$
|
|
54221
|
+
email: emailFlag$3,
|
|
53555
54222
|
otpStdin: otpStdinFlag
|
|
53556
54223
|
}, ({ email, otpStdin }) => runCommand({
|
|
53557
|
-
...metadata$
|
|
54224
|
+
...metadata$4("auth.login"),
|
|
53558
54225
|
network: true
|
|
53559
|
-
}, (config) => login(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
54226
|
+
}, (config) => login(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.login")), Command.withDescription("Establish a first-party session with terminal-owned email OTP"));
|
|
53560
54227
|
const signupCommand = Command.make("signup", {
|
|
53561
|
-
email: emailFlag$
|
|
54228
|
+
email: emailFlag$3,
|
|
53562
54229
|
otpStdin: otpStdinFlag,
|
|
53563
54230
|
displayName: displayNameFlag,
|
|
53564
54231
|
country: countryFlag,
|
|
53565
54232
|
handle: handleFlag
|
|
53566
54233
|
}, ({ email, otpStdin, displayName, country, handle }) => runCommand({
|
|
53567
|
-
...metadata$
|
|
54234
|
+
...metadata$4("auth.signup"),
|
|
53568
54235
|
network: true
|
|
53569
54236
|
}, (config) => signup(config, Option.getOrUndefined(email), otpStdin, {
|
|
53570
54237
|
displayName: Option.getOrUndefined(displayName),
|
|
53571
54238
|
country: Option.getOrUndefined(country),
|
|
53572
54239
|
handle: Option.getOrUndefined(handle)
|
|
53573
|
-
}))).pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
53574
|
-
const sendCommand = Command.make("send", { email: emailFlag$
|
|
53575
|
-
...metadata$
|
|
54240
|
+
}))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.signup")), Command.withDescription("Verify email and complete Profile, Openfort wallet, and Account setup"));
|
|
54241
|
+
const sendCommand = Command.make("send", { email: emailFlag$3 }, ({ email }) => runCommand({
|
|
54242
|
+
...metadata$4("auth.send"),
|
|
53576
54243
|
network: true
|
|
53577
|
-
}, (config) => sendOtp(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
54244
|
+
}, (config) => sendOtp(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.send")), Command.withDescription("Send an OTP and save non-secret continuation context"));
|
|
53578
54245
|
const verifyCommand = Command.make("verify", {
|
|
53579
|
-
email: emailFlag$
|
|
54246
|
+
email: emailFlag$3,
|
|
53580
54247
|
otpStdin: otpStdinFlag
|
|
53581
54248
|
}, ({ email, otpStdin }) => runCommand({
|
|
53582
|
-
...metadata$
|
|
54249
|
+
...metadata$4("auth.verify"),
|
|
53583
54250
|
network: true
|
|
53584
|
-
}, (config) => verifyOtp(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
53585
|
-
const profileCommand = Command.make("profile", { email: emailFlag$
|
|
53586
|
-
...metadata$
|
|
54251
|
+
}, (config) => verifyOtp(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.verify")), Command.withDescription("Verify a delivered OTP and persist the first-party session"));
|
|
54252
|
+
const profileCommand = Command.make("profile", { email: emailFlag$3 }, ({ email }) => runCommand({
|
|
54253
|
+
...metadata$4("auth.profile"),
|
|
53587
54254
|
network: true
|
|
53588
|
-
}, (config) => readProfile(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
53589
|
-
const statusCommand = Command.make("status", { email: emailFlag$
|
|
53590
|
-
...metadata$
|
|
54255
|
+
}, (config) => readProfile(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.profile")), Command.withDescription("Restore the session and read the backend profile and account lifecycle"));
|
|
54256
|
+
const statusCommand = Command.make("status", { email: emailFlag$3 }, ({ email }) => runCommand({
|
|
54257
|
+
...metadata$4("auth.status"),
|
|
53591
54258
|
network: true
|
|
53592
|
-
}, (config) => status$2(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
53593
|
-
const logoutCommand = Command.make("logout", { email: emailFlag$
|
|
53594
|
-
...metadata$
|
|
54259
|
+
}, (config) => status$2(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.status")), Command.withDescription("Validate a first-party session or show a tagged legacy grant"));
|
|
54260
|
+
const logoutCommand = Command.make("logout", { email: emailFlag$3 }, ({ email }) => runCommand({
|
|
54261
|
+
...metadata$4("auth.logout"),
|
|
53595
54262
|
network: true
|
|
53596
|
-
}, (config) => logout(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
53597
|
-
const auth = Command.make("auth").pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
54263
|
+
}, (config) => logout(config, Option.getOrUndefined(email)))).pipe(Command.annotate(CliCommandMetadata, metadata$4("auth.logout")), Command.withDescription("Forget local credentials and revoke their remote session or grant"));
|
|
54264
|
+
const auth = Command.make("auth").pipe(Command.annotate(CliCommandMetadata, metadata$4("auth")), Command.withDescription("First-party email sessions (broader authority than legacy account:read grants)"), Command.withSubcommands([
|
|
53598
54265
|
loginCommand,
|
|
53599
54266
|
signupCommand,
|
|
53600
54267
|
sendCommand,
|
|
@@ -53605,7 +54272,7 @@ const auth = Command.make("auth").pipe(Command.annotate(CliCommandMetadata, meta
|
|
|
53605
54272
|
]));
|
|
53606
54273
|
//#endregion
|
|
53607
54274
|
//#region src/commands/doctor.ts
|
|
53608
|
-
const metadata$
|
|
54275
|
+
const metadata$3 = {
|
|
53609
54276
|
name: "doctor",
|
|
53610
54277
|
capability: "diagnostics",
|
|
53611
54278
|
observation: "command"
|
|
@@ -53614,14 +54281,14 @@ const doctor = Command.make("doctor", {
|
|
|
53614
54281
|
online: Flag.boolean("online").pipe(Flag.withDefault(false), Flag.withDescription("Also check the backend through the public SDK")),
|
|
53615
54282
|
timeoutMs: Flag.integer("timeout-ms").pipe(Flag.filter((value) => value >= 1 && value <= 3e5, () => "Use --timeout-ms between 1 and 300000."), Flag.withDefault(3e4), Flag.withDescription("Online check deadline in milliseconds (1 to 300000)"))
|
|
53616
54283
|
}, ({ online, timeoutMs }) => runCommand({
|
|
53617
|
-
...metadata$
|
|
54284
|
+
...metadata$3,
|
|
53618
54285
|
network: online
|
|
53619
54286
|
}, (config, observation, onFinalize) => checkDoctor(config, {
|
|
53620
54287
|
online,
|
|
53621
54288
|
timeoutMs,
|
|
53622
54289
|
...observation === void 0 ? {} : { observation },
|
|
53623
54290
|
...onFinalize === void 0 ? {} : { onFinalize }
|
|
53624
|
-
}))).pipe(Command.annotate(CliCommandMetadata, metadata$
|
|
54291
|
+
}))).pipe(Command.annotate(CliCommandMetadata, metadata$3), Command.withDescription("Check local configuration; --online also checks the backend"));
|
|
53625
54292
|
//#endregion
|
|
53626
54293
|
//#region src/commands/telemetry.ts
|
|
53627
54294
|
const statusMetadata = {
|
|
@@ -53932,7 +54599,7 @@ const makeOrganizationProgress = (mode, run) => {
|
|
|
53932
54599
|
* resolved, and it always asks, even when `--confirm` was supplied. A prompt that
|
|
53933
54600
|
* cannot be answered is a refusal.
|
|
53934
54601
|
*/
|
|
53935
|
-
const
|
|
54602
|
+
const confirmWrite = (preview) => Effect.gen(function* () {
|
|
53936
54603
|
yield* writeStderr(`${preview.lines.join("\n")}\n`);
|
|
53937
54604
|
if (!(yield* Prompt.confirm({ message: preview.question }).pipe(Effect.catch(() => Effect.succeed(false))))) return yield* Effect.fail(inputRequired("The write was not confirmed."));
|
|
53938
54605
|
});
|
|
@@ -53980,10 +54647,11 @@ const organizationWaitTimeout = () => new CliFailure({
|
|
|
53980
54647
|
* the label keeps the existing fallback.
|
|
53981
54648
|
*
|
|
53982
54649
|
* `resetSession` is part of the contract the SDK's Organization setup owner
|
|
53983
|
-
* calls before it resumes a lane that failed at founder authorization
|
|
53984
|
-
*
|
|
53985
|
-
* reset
|
|
53986
|
-
*
|
|
54650
|
+
* calls before it resumes a lane that failed at founder authorization; a lane
|
|
54651
|
+
* that resumes a recorded bootstrap submission does not touch the signer. The
|
|
54652
|
+
* bridge's own reset stops its loopback server, so a reset here clears the
|
|
54653
|
+
* stale readiness, closes that bridge, and lets the next address or digest
|
|
54654
|
+
* request open one for the same command.
|
|
53987
54655
|
*/
|
|
53988
54656
|
const organizationWriteSigner = (config, opened, run, beforeSignature) => Effect.gen(function* () {
|
|
53989
54657
|
const runtime = yield* CliRuntime;
|
|
@@ -54080,7 +54748,7 @@ const createOrganization = (config, input) => Effect.gen(function* () {
|
|
|
54080
54748
|
if (interactivelyConfirm) {
|
|
54081
54749
|
const preview = yield* restoreVerifiedClient(config, opened, { requirement: "none" });
|
|
54082
54750
|
const resolved = yield* organizationPreviewLines(preview.client, null);
|
|
54083
|
-
yield*
|
|
54751
|
+
yield* confirmWrite({
|
|
54084
54752
|
lines: [
|
|
54085
54753
|
`Create Organization ${JSON.stringify(draft.name)} (@${draft.handle}, ${draft.country})`,
|
|
54086
54754
|
...draft.bio === void 0 ? [] : [`Bio: ${JSON.stringify(draft.bio)}`],
|
|
@@ -54168,7 +54836,7 @@ const retryOrganization = (config, input) => Effect.gen(function* () {
|
|
|
54168
54836
|
if (interactivelyConfirm) {
|
|
54169
54837
|
const preview = yield* restoreVerifiedClient(config, opened, { requirement: "none" });
|
|
54170
54838
|
const resolved = yield* organizationPreviewLines(preview.client, organizationId);
|
|
54171
|
-
yield*
|
|
54839
|
+
yield* confirmWrite({
|
|
54172
54840
|
lines: [`Resume setup for Organization ${JSON.stringify(String(organizationId))}`, ...resolved],
|
|
54173
54841
|
question: "Resume this Organization's setup?"
|
|
54174
54842
|
});
|
|
@@ -54204,6 +54872,979 @@ const retryOrganization = (config, input) => Effect.gen(function* () {
|
|
|
54204
54872
|
};
|
|
54205
54873
|
});
|
|
54206
54874
|
//#endregion
|
|
54875
|
+
//#region src/invitation.ts
|
|
54876
|
+
const INVITATION_PHASES = [
|
|
54877
|
+
"authorizing",
|
|
54878
|
+
"pending",
|
|
54879
|
+
"pending_grant",
|
|
54880
|
+
"active",
|
|
54881
|
+
"revoking",
|
|
54882
|
+
"declined",
|
|
54883
|
+
"cancelled",
|
|
54884
|
+
"expired",
|
|
54885
|
+
"revoked"
|
|
54886
|
+
];
|
|
54887
|
+
/** Phases at which a wait has nothing left to watch. */
|
|
54888
|
+
const SETTLED_PHASES = /* @__PURE__ */ new Set([
|
|
54889
|
+
"pending",
|
|
54890
|
+
"active",
|
|
54891
|
+
"declined",
|
|
54892
|
+
"cancelled",
|
|
54893
|
+
"expired",
|
|
54894
|
+
"revoked"
|
|
54895
|
+
]);
|
|
54896
|
+
/** The own-offer projection the CLI reads to resolve one invitation's scope. */
|
|
54897
|
+
const OWN_OFFER_PAGE_LIMIT = 100;
|
|
54898
|
+
/** The Base Sepolia assets this CLI accepts, by exact key or exact AssetId. */
|
|
54899
|
+
const ACCEPTED_ASSETS = TOKENS.BASE_SEPOLIA;
|
|
54900
|
+
/** The timeout a read command may omit; the write grammar always carries one. */
|
|
54901
|
+
const readOptionalTimeout = (value) => readWriteTimeout(value ?? 120);
|
|
54902
|
+
/** One exact Organization scope. Reads may omit it; writes may not. */
|
|
54903
|
+
const readExactOrg = (orgs, requirement) => Effect.gen(function* () {
|
|
54904
|
+
const ids = [...new Set(orgs)];
|
|
54905
|
+
if (ids.length > 1) return yield* Effect.fail(inputRequired("Provide one exact Organization ID."));
|
|
54906
|
+
const raw = ids[0];
|
|
54907
|
+
if (raw === void 0) {
|
|
54908
|
+
if (requirement === "required") return yield* Effect.fail(inputRequired("Provide --org."));
|
|
54909
|
+
return null;
|
|
54910
|
+
}
|
|
54911
|
+
return yield* Effect.try({
|
|
54912
|
+
try: () => toOrgId(raw),
|
|
54913
|
+
catch: () => inputRequired("Provide a valid Organization ID.")
|
|
54914
|
+
});
|
|
54915
|
+
});
|
|
54916
|
+
const readInvitationId = (value) => Effect.gen(function* () {
|
|
54917
|
+
if (value === void 0) return yield* Effect.fail(inputRequired("Provide --invitation-id."));
|
|
54918
|
+
const trimmed = value.trim();
|
|
54919
|
+
if (trimmed.length === 0 || trimmed.length > 256 || /[^\x21-\x7e]/.test(trimmed)) return yield* Effect.fail(inputRequired("Provide a valid --invitation-id."));
|
|
54920
|
+
return trimmed;
|
|
54921
|
+
});
|
|
54922
|
+
/** One bounded page request. Unknown or duplicate phases refuse before any read. */
|
|
54923
|
+
const readPageBounds = (input) => Effect.gen(function* () {
|
|
54924
|
+
const limit = input.limit;
|
|
54925
|
+
if (limit !== void 0 && (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)) return yield* Effect.fail(inputRequired("Provide --limit as an integer from 1 to 100."));
|
|
54926
|
+
const cursor = input.cursor?.trim();
|
|
54927
|
+
if (input.cursor !== void 0 && (cursor === void 0 || cursor.length === 0)) return yield* Effect.fail(inputRequired("Provide a nonempty --cursor."));
|
|
54928
|
+
const requested = input.phases ?? [];
|
|
54929
|
+
if (requested.find((phase) => !INVITATION_PHASES.some((known) => known === phase)) !== void 0) return yield* Effect.fail(inputRequired("Provide --phase from the invitation phases."));
|
|
54930
|
+
if (new Set(requested).size !== requested.length) return yield* Effect.fail(inputRequired("Provide each --phase at most once."));
|
|
54931
|
+
return {
|
|
54932
|
+
...cursor === void 0 ? {} : { cursor },
|
|
54933
|
+
...limit === void 0 ? {} : { limit },
|
|
54934
|
+
...requested.length === 0 ? {} : { phases: requested }
|
|
54935
|
+
};
|
|
54936
|
+
});
|
|
54937
|
+
/**
|
|
54938
|
+
* The Organization of one invitation the caller can already see.
|
|
54939
|
+
*
|
|
54940
|
+
* The grantee's bounded own-offer projection is what resolves an absent
|
|
54941
|
+
* `--org`, for `get` and `wait` alike: a caller who holds no Admin authority
|
|
54942
|
+
* still reads their own offer, and a saved read default is never consulted. The
|
|
54943
|
+
* row carries its own OrgId, and a row the caller cannot see is refused rather
|
|
54944
|
+
* than probed in another scope.
|
|
54945
|
+
*
|
|
54946
|
+
* The walk follows the versioned cursor until the row is found or the pages
|
|
54947
|
+
* end. One 100-row page is not the projection: an invitation the caller can see
|
|
54948
|
+
* would otherwise refuse only because it is not the newest.
|
|
54949
|
+
*/
|
|
54950
|
+
const resolveOwningOrganization = (client, invitationId) => Effect.gen(function* () {
|
|
54951
|
+
let cursor;
|
|
54952
|
+
for (;;) {
|
|
54953
|
+
const page = yield* Effect.promise((signal) => client.orgs.invitations(cursor === void 0 ? { limit: OWN_OFFER_PAGE_LIMIT } : {
|
|
54954
|
+
limit: OWN_OFFER_PAGE_LIMIT,
|
|
54955
|
+
cursor
|
|
54956
|
+
}, { signal })).pipe(Effect.flatMap(resultValue));
|
|
54957
|
+
const match = page.items.find((invitation) => invitation.id === invitationId);
|
|
54958
|
+
if (match !== void 0) return match.orgId;
|
|
54959
|
+
if (page.nextCursor === null) return yield* Effect.fail(Errors.invalidInput("invitationId", "The invitation is not in your available offers. Provide --org to read it directly."));
|
|
54960
|
+
cursor = page.nextCursor;
|
|
54961
|
+
}
|
|
54962
|
+
});
|
|
54963
|
+
/** The exact scoped bundle a read, transition, or write is about to use. */
|
|
54964
|
+
const scopedInvitations = (client, organizationId) => client.org(organizationId).invitations;
|
|
54965
|
+
const scopedRead = (client, organizationId, invitationId) => Effect.promise((signal) => scopedInvitations(client, organizationId).get({ invitationId }, { signal })).pipe(Effect.flatMap(resultValue));
|
|
54966
|
+
const settled = (invitation) => SETTLED_PHASES.has(invitation.phase) || invitation.recovery !== null && invitation.recovery.action !== "wait";
|
|
54967
|
+
const invitationLines = (invitation) => [JSON.stringify({ invitation })];
|
|
54968
|
+
const waitTimeout = () => new CliFailure({
|
|
54969
|
+
code: "NETWORK_ERROR",
|
|
54970
|
+
message: "The invitation did not settle within the command deadline.",
|
|
54971
|
+
exitCode: 5,
|
|
54972
|
+
outcome: "failed"
|
|
54973
|
+
});
|
|
54974
|
+
/** The same dependency failure, named for the phase it happened in. */
|
|
54975
|
+
const resolutionTimeout = () => new CliFailure({
|
|
54976
|
+
code: "NETWORK_ERROR",
|
|
54977
|
+
message: "The invitation's Organization could not be resolved within the command deadline.",
|
|
54978
|
+
exitCode: 5,
|
|
54979
|
+
outcome: "failed"
|
|
54980
|
+
});
|
|
54981
|
+
const deadlineFailure = (message) => new CliFailure({
|
|
54982
|
+
code: "NETWORK_ERROR",
|
|
54983
|
+
message,
|
|
54984
|
+
exitCode: 5,
|
|
54985
|
+
outcome: "failed"
|
|
54986
|
+
});
|
|
54987
|
+
/** Bound one scoped operation by the command's own deadline; the backend keeps its state. */
|
|
54988
|
+
const withinDeadline = (effect, timeoutSeconds, message) => Effect.gen(function* () {
|
|
54989
|
+
const settledResult = yield* effect.pipe(Effect.timeoutOption(timeoutSeconds * 1e3));
|
|
54990
|
+
if (Option.isNone(settledResult)) return yield* Effect.fail(deadlineFailure(message));
|
|
54991
|
+
return settledResult.value;
|
|
54992
|
+
});
|
|
54993
|
+
/**
|
|
54994
|
+
* `capxul org invite list|get|wait|review`.
|
|
54995
|
+
*
|
|
54996
|
+
* `list` is the authenticated grantee's own offers. With `--org` it is the
|
|
54997
|
+
* Admin's view of that Organization's invitations instead: one explicit scope,
|
|
54998
|
+
* never a saved read default, and never a silent change of what plain `list`
|
|
54999
|
+
* returns. `--mine` stays the own-offer projection's declared no-op; combined
|
|
55000
|
+
* with `--org` it refuses, because the scoped route has no invitee filter and
|
|
55001
|
+
* ignoring the flag would return a wider view than the operator asked for.
|
|
55002
|
+
*
|
|
55003
|
+
* `get` and `wait` read one invitation in the Organization named by `--org`,
|
|
55004
|
+
* or resolved from the offer's own row when `--org` is absent. A wait only
|
|
55005
|
+
* reads: it never retries, resends, or accepts.
|
|
55006
|
+
*/
|
|
55007
|
+
const readInvitation = (config, action, input) => {
|
|
55008
|
+
const timeout = readOptionalTimeout(input.timeoutSeconds);
|
|
55009
|
+
return Effect.gen(function* () {
|
|
55010
|
+
const bounds = yield* readPageBounds(input);
|
|
55011
|
+
const invitationId = action === "list" ? null : yield* readInvitationId(input.invitationId);
|
|
55012
|
+
const explicitOrg = yield* readExactOrg(input.orgs ?? [], "optional");
|
|
55013
|
+
if (action === "review" && explicitOrg === null) return yield* Effect.fail(inputRequired("Provide --org to review this invitation."));
|
|
55014
|
+
if (action === "list" && input.mine === true && explicitOrg !== null) return yield* Effect.fail(inputRequired("Provide either --mine or --org; the Organization list is not filtered to you."));
|
|
55015
|
+
const timeoutSeconds = yield* timeout;
|
|
55016
|
+
const { client } = yield* restoreAuthenticatedClient(config, input.email);
|
|
55017
|
+
if (action === "list") return listResult(yield* Effect.promise((signal) => explicitOrg === null ? client.orgs.invitations(bounds, { signal }) : client.org(explicitOrg).invitations.list(bounds, { signal })).pipe(Effect.flatMap(resultValue)));
|
|
55018
|
+
if (invitationId === null) return yield* Effect.fail(inputRequired("Provide --invitation-id."));
|
|
55019
|
+
const resolveOrganizationId = () => explicitOrg === null ? resolveOwningOrganization(client, invitationId) : Effect.succeed(explicitOrg);
|
|
55020
|
+
if (action === "get" || action === "review") {
|
|
55021
|
+
const invitation = yield* withinDeadline(Effect.gen(function* () {
|
|
55022
|
+
const resolved = action === "review" ? explicitOrg : yield* resolveOrganizationId();
|
|
55023
|
+
if (resolved === null) return yield* Effect.fail(inputRequired("Provide --org."));
|
|
55024
|
+
return yield* scopedRead(client, resolved, invitationId);
|
|
55025
|
+
}), timeoutSeconds, "The invitation read did not settle within the command deadline.");
|
|
55026
|
+
return {
|
|
55027
|
+
data: action === "review" ? invitation : { invitation },
|
|
55028
|
+
lines: invitationLines(invitation)
|
|
55029
|
+
};
|
|
55030
|
+
}
|
|
55031
|
+
let resolving = true;
|
|
55032
|
+
const observed = yield* Effect.gen(function* () {
|
|
55033
|
+
const resolved = yield* resolveOrganizationId();
|
|
55034
|
+
resolving = false;
|
|
55035
|
+
let invitation = yield* scopedRead(client, resolved, invitationId);
|
|
55036
|
+
while (!settled(invitation)) {
|
|
55037
|
+
yield* Effect.sleep(1e3);
|
|
55038
|
+
invitation = yield* scopedRead(client, resolved, invitationId);
|
|
55039
|
+
}
|
|
55040
|
+
return invitation;
|
|
55041
|
+
}).pipe(Effect.timeoutOption(timeoutSeconds * 1e3));
|
|
55042
|
+
if (Option.isNone(observed)) return yield* Effect.fail(resolving ? resolutionTimeout() : waitTimeout());
|
|
55043
|
+
return {
|
|
55044
|
+
data: { invitation: observed.value },
|
|
55045
|
+
lines: invitationLines(observed.value)
|
|
55046
|
+
};
|
|
55047
|
+
});
|
|
55048
|
+
};
|
|
55049
|
+
function listResult(page) {
|
|
55050
|
+
return {
|
|
55051
|
+
data: {
|
|
55052
|
+
invitations: page.items,
|
|
55053
|
+
nextCursor: page.nextCursor,
|
|
55054
|
+
observedAt: page.observedAt
|
|
55055
|
+
},
|
|
55056
|
+
lines: [...page.items.map((invitation) => JSON.stringify(invitation)), ...page.nextCursor === null ? [] : [`Next cursor: ${JSON.stringify(page.nextCursor)}`]]
|
|
55057
|
+
};
|
|
55058
|
+
}
|
|
55059
|
+
/**
|
|
55060
|
+
* `capxul org invite decline|cancel|resend|retry`.
|
|
55061
|
+
*
|
|
55062
|
+
* Every transition needs the exact Organization in both modes: an invitation
|
|
55063
|
+
* write never consults the read default. A terminal writes `--confirm`; a
|
|
55064
|
+
* terminal run always sees the resolved current offer and answers a default-no
|
|
55065
|
+
* prompt. The command forwards no acceptance consent: these four transitions
|
|
55066
|
+
* end or retry work that already exists.
|
|
55067
|
+
*/
|
|
55068
|
+
const transitionInvitation = (config, action, input) => Effect.gen(function* () {
|
|
55069
|
+
const invitationId = yield* readInvitationId(input.invitationId);
|
|
55070
|
+
const organizationId = yield* readExactOrg(input.orgs, "required");
|
|
55071
|
+
if (organizationId === null) return yield* Effect.fail(inputRequired("Provide --org."));
|
|
55072
|
+
const timeoutSeconds = yield* readWriteTimeout(input.timeoutSeconds);
|
|
55073
|
+
const interactivelyConfirm = yield* requireWriteConfirmation(input.confirm);
|
|
55074
|
+
const { client } = yield* restoreAuthenticatedClient(config, input.email);
|
|
55075
|
+
if (interactivelyConfirm) {
|
|
55076
|
+
const current = yield* scopedRead(client, organizationId, invitationId);
|
|
55077
|
+
yield* confirmWrite({
|
|
55078
|
+
lines: [`${action} invitation ${JSON.stringify(invitationId)} in Organization ${JSON.stringify(String(organizationId))}`, `Current phase: ${current.phase}; delivery: ${current.delivery}`],
|
|
55079
|
+
question: `${action === "resend" ? "Resend" : action.charAt(0).toUpperCase() + action.slice(1)} this invitation?`
|
|
55080
|
+
});
|
|
55081
|
+
}
|
|
55082
|
+
const invitation = yield* withinDeadline(Effect.promise((signal) => scopedInvitations(client, organizationId)[action]({ invitationId }, { signal })).pipe(Effect.flatMap(resultValue)), timeoutSeconds, "The invitation transition did not settle within the command deadline.");
|
|
55083
|
+
return {
|
|
55084
|
+
data: { invitation },
|
|
55085
|
+
lines: invitationLines(invitation)
|
|
55086
|
+
};
|
|
55087
|
+
});
|
|
55088
|
+
/** The wire's bytes32 form, lowercased: the digest an acceptance states. */
|
|
55089
|
+
const readOfferDigest = (value, flag) => Effect.gen(function* () {
|
|
55090
|
+
const trimmed = value?.trim() ?? "";
|
|
55091
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return yield* Effect.fail(inputRequired(`Provide ${flag} as a 0x-prefixed 32-byte digest.`));
|
|
55092
|
+
return trimmed.toLowerCase();
|
|
55093
|
+
});
|
|
55094
|
+
/**
|
|
55095
|
+
* `capxul org invite accept --invitation-id I --offer-digest D`.
|
|
55096
|
+
*
|
|
55097
|
+
* Acceptance is the grantee's explicit consent, so the digest is the whole
|
|
55098
|
+
* write: the command forwards the digest the operator states and never invents
|
|
55099
|
+
* one. A noninteractive run must state it (`--offer-digest`, with `--confirm`);
|
|
55100
|
+
* an interactive run may leave it out, and then the command reads the offer and
|
|
55101
|
+
* fills D from the exact digest it displayed, behind the same preview/confirm
|
|
55102
|
+
* prompt the other writes use. A stated digest is never replaced by the
|
|
55103
|
+
* displayed one — a mismatch is the backend's typed refusal, not a silent
|
|
55104
|
+
* rewrite of what the operator consented to.
|
|
55105
|
+
*
|
|
55106
|
+
* The command signs nothing: the grant is executed by the deployment's
|
|
55107
|
+
* technical granter after the consent commits. Only the exact grantee can
|
|
55108
|
+
* accept; Admin access to the offer does not grant consent authority.
|
|
55109
|
+
*/
|
|
55110
|
+
const acceptInvitation = (config, input) => Effect.gen(function* () {
|
|
55111
|
+
const invitationId = yield* readInvitationId(input.invitationId);
|
|
55112
|
+
const organizationId = yield* readExactOrg(input.orgs, "required");
|
|
55113
|
+
if (organizationId === null) return yield* Effect.fail(inputRequired("Provide --org."));
|
|
55114
|
+
const timeoutSeconds = yield* readWriteTimeout(input.timeoutSeconds);
|
|
55115
|
+
const runtime = yield* CliRuntime;
|
|
55116
|
+
const interactive = runtime.tty && !runtime.ci && runtime.mode !== "json";
|
|
55117
|
+
const canonical = input.offerDigest === void 0 ? null : yield* readOfferDigest(input.offerDigest, "--offer-digest");
|
|
55118
|
+
const compatibility = input.expectedOfferDigest === void 0 ? null : yield* readOfferDigest(input.expectedOfferDigest, "--expected-offer");
|
|
55119
|
+
if (canonical !== null && compatibility !== null && canonical !== compatibility) return yield* Effect.fail(inputRequired("Provide matching --offer-digest and --expected-offer values."));
|
|
55120
|
+
const stated = canonical ?? compatibility;
|
|
55121
|
+
if (stated === null && !interactive) return yield* Effect.fail(inputRequired("Provide --offer-digest to accept this invitation."));
|
|
55122
|
+
const interactivelyConfirm = yield* requireWriteConfirmation(input.confirm);
|
|
55123
|
+
const { client } = yield* restoreAuthenticatedClient(config, input.email);
|
|
55124
|
+
let expectedOfferDigest = stated;
|
|
55125
|
+
if (interactivelyConfirm) {
|
|
55126
|
+
const current = yield* scopedRead(client, organizationId, invitationId);
|
|
55127
|
+
yield* confirmWrite({
|
|
55128
|
+
lines: [
|
|
55129
|
+
`Accept invitation ${JSON.stringify(invitationId)} in Organization ${JSON.stringify(String(organizationId))}`,
|
|
55130
|
+
`Current offer digest: ${current.offerDigest}`,
|
|
55131
|
+
`Current phase: ${current.phase}; expires at: ${String(current.expiresAt)}`
|
|
55132
|
+
],
|
|
55133
|
+
question: "Accept this offer?"
|
|
55134
|
+
});
|
|
55135
|
+
expectedOfferDigest ??= current.offerDigest;
|
|
55136
|
+
}
|
|
55137
|
+
if (expectedOfferDigest === null) return yield* Effect.fail(inputRequired("Provide --offer-digest to accept."));
|
|
55138
|
+
const invitation = yield* withinDeadline(Effect.promise((signal) => scopedInvitations(client, organizationId).accept({
|
|
55139
|
+
invitationId,
|
|
55140
|
+
expectedOfferDigest
|
|
55141
|
+
}, { signal })).pipe(Effect.flatMap(resultValue)), timeoutSeconds, "The invitation acceptance did not settle within the command deadline.");
|
|
55142
|
+
return {
|
|
55143
|
+
data: invitation,
|
|
55144
|
+
lines: invitationLines(invitation)
|
|
55145
|
+
};
|
|
55146
|
+
});
|
|
55147
|
+
/**
|
|
55148
|
+
* An exact zero, in the helper's own zero form (`parse-money.ts` tests the same
|
|
55149
|
+
* shape, with commas already stripped). It discriminates a zero from a negative
|
|
55150
|
+
* value, which the helper reports under the same `non-positive` reason.
|
|
55151
|
+
*/
|
|
55152
|
+
const ZERO_CAP = /^0+(?:\.0+)?$/;
|
|
55153
|
+
/**
|
|
55154
|
+
* One finite Budget cap.
|
|
55155
|
+
*
|
|
55156
|
+
* The value goes through the shared amount helper first, so the owner keeps its
|
|
55157
|
+
* grammar, its 100-character guard, its precision, and its sign rule. Exactly
|
|
55158
|
+
* one of the helper's verdicts does not apply to a Budget cap: `non-positive`
|
|
55159
|
+
* for an exact zero, which `d9.md` §3 set B permits. That verdict, and only
|
|
55160
|
+
* that one, becomes the legal zero cap.
|
|
55161
|
+
*/
|
|
55162
|
+
const readFiniteLimit = (raw, metadata) => Effect.gen(function* () {
|
|
55163
|
+
const parsed = yield* Effect.try({
|
|
55164
|
+
try: () => parseAssetAmount(raw, metadata),
|
|
55165
|
+
catch: () => inputRequired("Provide --limit as an exact decimal quantity.")
|
|
55166
|
+
});
|
|
55167
|
+
if (!("kind" in parsed)) return parsed.value;
|
|
55168
|
+
if (parsed.reason === "non-positive" && ZERO_CAP.test(raw.trim().replaceAll(",", ""))) return "0";
|
|
55169
|
+
return yield* Effect.fail(inputRequired("Provide --limit as an exact decimal quantity."));
|
|
55170
|
+
});
|
|
55171
|
+
/** One exact asset: a catalog key or the exact AssetId those keys name. */
|
|
55172
|
+
function resolveAssetId(raw) {
|
|
55173
|
+
const candidate = raw.trim();
|
|
55174
|
+
const named = Object.entries(ACCEPTED_ASSETS).find(([key]) => key === candidate);
|
|
55175
|
+
if (named !== void 0) return named[1];
|
|
55176
|
+
return Object.values(ACCEPTED_ASSETS).find((assetId) => assetId === candidate) ?? null;
|
|
55177
|
+
}
|
|
55178
|
+
/** The complete `B` policy flag set for exactly one new Budget. */
|
|
55179
|
+
const readNewBudgetGrant = (flags) => Effect.gen(function* () {
|
|
55180
|
+
const label = flags.label.trim();
|
|
55181
|
+
if (label.length === 0 || label.length > 128) return yield* Effect.fail(inputRequired("Provide --new-budget-name with 1 to 128 characters."));
|
|
55182
|
+
const rawAsset = flags.asset?.trim() ?? "";
|
|
55183
|
+
if (rawAsset.length === 0) return yield* Effect.fail(inputRequired("Provide --asset for --new-budget-name."));
|
|
55184
|
+
const assetId = resolveAssetId(rawAsset);
|
|
55185
|
+
if (assetId === null) return yield* Effect.fail(inputRequired("Provide --asset as CAPXUL_TEST_USDC, CAPXUL_TEST_USDT, CAPXUL_TEST_WETH, or one exact AssetId."));
|
|
55186
|
+
const metadata = yield* Effect.try({
|
|
55187
|
+
try: () => requireAsset(assetId),
|
|
55188
|
+
catch: () => inputRequired("Provide an admitted --asset.")
|
|
55189
|
+
});
|
|
55190
|
+
if (flags.unlimited === (flags.limit !== void 0)) return yield* Effect.fail(inputRequired("Provide exactly one of --limit or --unlimited."));
|
|
55191
|
+
let limit = null;
|
|
55192
|
+
if (!flags.unlimited) limit = yield* readFiniteLimit(String(flags.limit), metadata);
|
|
55193
|
+
const recipients = yield* readRecipients(flags);
|
|
55194
|
+
const actions = yield* readActions(flags.actions);
|
|
55195
|
+
return {
|
|
55196
|
+
type: "new_budget",
|
|
55197
|
+
label,
|
|
55198
|
+
intent: {
|
|
55199
|
+
type: "budget",
|
|
55200
|
+
asset: assetId,
|
|
55201
|
+
limit,
|
|
55202
|
+
scope: {
|
|
55203
|
+
recipients,
|
|
55204
|
+
actions
|
|
55205
|
+
}
|
|
55206
|
+
}
|
|
55207
|
+
};
|
|
55208
|
+
});
|
|
55209
|
+
/** 1–32 distinct recipient Accounts, or the explicit anyone scope. */
|
|
55210
|
+
function readRecipients(flags) {
|
|
55211
|
+
return Effect.gen(function* () {
|
|
55212
|
+
if (flags.anyRecipient === flags.recipientAccounts.length > 0) return yield* Effect.fail(inputRequired("Provide exactly one of --any-recipient or --recipient-account."));
|
|
55213
|
+
if (flags.anyRecipient) return { type: "anyone" };
|
|
55214
|
+
const accounts = [...new Set(flags.recipientAccounts)];
|
|
55215
|
+
if (accounts.length > 32) return yield* Effect.fail(inputRequired("Provide at most 32 --recipient-account values."));
|
|
55216
|
+
return {
|
|
55217
|
+
type: "allowlist",
|
|
55218
|
+
accounts: yield* Effect.forEach(accounts, (accountId) => Effect.try({
|
|
55219
|
+
try: () => toAccountId(accountId),
|
|
55220
|
+
catch: () => inputRequired("Provide each --recipient-account as an Account ID.")
|
|
55221
|
+
}))
|
|
55222
|
+
};
|
|
55223
|
+
});
|
|
55224
|
+
}
|
|
55225
|
+
/** One or both distinct action codes, in the canonical pay-then-commitments order. */
|
|
55226
|
+
function readActions(raw) {
|
|
55227
|
+
return Effect.gen(function* () {
|
|
55228
|
+
const requested = raw.flatMap((value) => value.split(",")).map((value) => value.trim());
|
|
55229
|
+
if (requested.find((value) => value !== "pay" && value !== "commitments") !== void 0 || requested.some((value) => value.length === 0)) return yield* Effect.fail(inputRequired("Provide --actions as pay, commitments, or both."));
|
|
55230
|
+
const [first, ...rest] = ["pay", "commitments"].filter((action) => requested.some((value) => value === action));
|
|
55231
|
+
if (first === void 0) return yield* Effect.fail(inputRequired("Provide --actions as pay, commitments, or both."));
|
|
55232
|
+
return [first, ...rest];
|
|
55233
|
+
});
|
|
55234
|
+
}
|
|
55235
|
+
/**
|
|
55236
|
+
* The new-Budget policy flags that were supplied. None of them means anything
|
|
55237
|
+
* without `--new-budget-name`: a request that silently ignored them would
|
|
55238
|
+
* authorize an offer the operator never stated.
|
|
55239
|
+
*/
|
|
55240
|
+
function orphanedNewBudgetFlags(input) {
|
|
55241
|
+
if (input.newBudgetName !== void 0) return [];
|
|
55242
|
+
return [
|
|
55243
|
+
...input.asset === void 0 ? [] : ["--asset"],
|
|
55244
|
+
...input.limit === void 0 ? [] : ["--limit"],
|
|
55245
|
+
...input.unlimited ? ["--unlimited"] : [],
|
|
55246
|
+
...input.recipientAccounts.length === 0 ? [] : ["--recipient-account"],
|
|
55247
|
+
...input.anyRecipient ? ["--any-recipient"] : [],
|
|
55248
|
+
...input.actions.length === 0 ? [] : ["--actions"]
|
|
55249
|
+
];
|
|
55250
|
+
}
|
|
55251
|
+
/** The bounded request one invite submits, with every grant in canonical order. */
|
|
55252
|
+
const buildInviteRequest = (input) => Effect.gen(function* () {
|
|
55253
|
+
const orphaned = orphanedNewBudgetFlags(input);
|
|
55254
|
+
if (orphaned.length > 0) return yield* Effect.fail(inputRequired(`Provide --new-budget-name with ${orphaned.join(", ")}.`));
|
|
55255
|
+
const toEmail = input.toEmail?.trim() ?? "";
|
|
55256
|
+
const accountId = input.accountId?.trim() ?? "";
|
|
55257
|
+
if (toEmail.length === 0 === (accountId.length === 0)) return yield* Effect.fail(inputRequired("Provide exactly one of --to-email or --account-id."));
|
|
55258
|
+
const grants = [];
|
|
55259
|
+
for (const budgetId of new Set(input.budgetIds)) {
|
|
55260
|
+
if (budgetId.trim().length === 0) return yield* Effect.fail(inputRequired("Provide each --budget-id as a nonempty ID."));
|
|
55261
|
+
grants.push({
|
|
55262
|
+
type: "budget",
|
|
55263
|
+
budgetId: toPermissionId(budgetId.trim())
|
|
55264
|
+
});
|
|
55265
|
+
}
|
|
55266
|
+
for (const permissionId of new Set(input.permissionIds)) {
|
|
55267
|
+
if (permissionId.trim().length === 0) return yield* Effect.fail(inputRequired("Provide each --permission-id as a nonempty ID."));
|
|
55268
|
+
grants.push({
|
|
55269
|
+
type: "managePeople",
|
|
55270
|
+
permissionId: toPermissionId(permissionId.trim())
|
|
55271
|
+
});
|
|
55272
|
+
}
|
|
55273
|
+
if (input.newBudgetName !== void 0) grants.push(yield* readNewBudgetGrant({
|
|
55274
|
+
label: input.newBudgetName,
|
|
55275
|
+
asset: input.asset,
|
|
55276
|
+
limit: input.limit,
|
|
55277
|
+
unlimited: input.unlimited,
|
|
55278
|
+
recipientAccounts: input.recipientAccounts,
|
|
55279
|
+
anyRecipient: input.anyRecipient,
|
|
55280
|
+
actions: input.actions
|
|
55281
|
+
}));
|
|
55282
|
+
if (grants.length === 0) return yield* Effect.fail(inputRequired("Provide at least one of --budget-id, --permission-id, or --new-budget-name."));
|
|
55283
|
+
if (grants.length > 16) return yield* Effect.fail(inputRequired("Provide at most 16 grants."));
|
|
55284
|
+
return {
|
|
55285
|
+
to: toEmail.length > 0 ? {
|
|
55286
|
+
type: "email",
|
|
55287
|
+
email: toEmail
|
|
55288
|
+
} : {
|
|
55289
|
+
type: "account",
|
|
55290
|
+
accountId: yield* Effect.try({
|
|
55291
|
+
try: () => toAccountId(accountId),
|
|
55292
|
+
catch: () => inputRequired("Provide a valid --account-id.")
|
|
55293
|
+
})
|
|
55294
|
+
},
|
|
55295
|
+
grants
|
|
55296
|
+
};
|
|
55297
|
+
});
|
|
55298
|
+
const readRequestKey = (value) => Effect.gen(function* () {
|
|
55299
|
+
const trimmed = value?.trim() ?? "";
|
|
55300
|
+
if (trimmed.length === 0 || trimmed.length > 128 || !/^[A-Za-z0-9_.-]+$/.test(trimmed)) return yield* Effect.fail(inputRequired("Provide --request-key as 1 to 128 letters, digits, underscore, hyphen, or dot."));
|
|
55301
|
+
return trimmed;
|
|
55302
|
+
});
|
|
55303
|
+
/**
|
|
55304
|
+
* The D9 §6 authoring progress line: the durable `{invitationId, commandId}`
|
|
55305
|
+
* pair, written before the configuration digest exists so a lost response is
|
|
55306
|
+
* recoverable by the same identity.
|
|
55307
|
+
*/
|
|
55308
|
+
const preparedLine = (mode, prepared) => mode === "json" ? `${JSON.stringify({
|
|
55309
|
+
type: "invitation.prepared",
|
|
55310
|
+
...prepared
|
|
55311
|
+
})}\n` : `Invitation prepared: invitationId=${prepared.invitationId} commandId=${prepared.commandId}\n`;
|
|
55312
|
+
/**
|
|
55313
|
+
* `capxul org member invite`.
|
|
55314
|
+
*
|
|
55315
|
+
* `--preview` is a read: it shows the exact resolved offer, creates nothing, and
|
|
55316
|
+
* opens no browser. The write needs `--org` in both modes, `--confirm` and
|
|
55317
|
+
* `--request-key` non-interactively, and it prints the key it used before it
|
|
55318
|
+
* submits, so a lost response is replayed with the same identity instead of
|
|
55319
|
+
* authoring a second offer.
|
|
55320
|
+
*
|
|
55321
|
+
* The write also executes the offer's configuration hop: the Admin's personal
|
|
55322
|
+
* embedded wallet signs the stored configure UserOperation through the same
|
|
55323
|
+
* command-scoped browser bridge the other Organization writes use. The bridge
|
|
55324
|
+
* is composed only after confirmation, and the durable identity reaches stderr
|
|
55325
|
+
* before any digest is forwarded.
|
|
55326
|
+
*/
|
|
55327
|
+
const inviteInvitationMember = (config, input) => Effect.gen(function* () {
|
|
55328
|
+
const request = yield* buildInviteRequest(input);
|
|
55329
|
+
const organizationId = yield* readExactOrg(input.orgs, "required");
|
|
55330
|
+
if (organizationId === null) return yield* Effect.fail(inputRequired("Provide --org."));
|
|
55331
|
+
const timeoutSeconds = yield* readWriteTimeout(input.timeoutSeconds);
|
|
55332
|
+
const runtime = yield* CliRuntime;
|
|
55333
|
+
const interactive = runtime.tty && !runtime.ci && runtime.mode !== "json";
|
|
55334
|
+
if (!input.preview && !interactive) {
|
|
55335
|
+
yield* readRequestKey(input.requestKey);
|
|
55336
|
+
yield* requireWriteConfirmation(input.confirm);
|
|
55337
|
+
}
|
|
55338
|
+
const opened = yield* openAuthenticatedSession(config, input.email);
|
|
55339
|
+
if (input.preview) {
|
|
55340
|
+
const { client } = yield* restoreVerifiedClient(config, opened);
|
|
55341
|
+
const preview = yield* withinDeadline(Effect.promise((signal) => scopedInvitations(client, organizationId).preview(request, { signal })).pipe(Effect.flatMap(resultValue)), timeoutSeconds, "The invitation preview did not settle within the command deadline.");
|
|
55342
|
+
return previewResult(preview);
|
|
55343
|
+
}
|
|
55344
|
+
const requestKey = input.requestKey === void 0 ? (yield* generateRequestKey()).trim() : yield* readRequestKey(input.requestKey);
|
|
55345
|
+
if (interactive) {
|
|
55346
|
+
yield* writeStderr(`${JSON.stringify({
|
|
55347
|
+
type: "invitation.requestKey",
|
|
55348
|
+
requestKey
|
|
55349
|
+
})}\n`);
|
|
55350
|
+
const { client } = yield* restoreVerifiedClient(config, opened);
|
|
55351
|
+
const preview = yield* withinDeadline(Effect.promise((signal) => scopedInvitations(client, organizationId).preview(request, { signal })).pipe(Effect.flatMap(resultValue)), timeoutSeconds, "The invitation preview did not settle within the command deadline.");
|
|
55352
|
+
yield* confirmWrite({
|
|
55353
|
+
lines: [`Invite ${JSON.stringify(request.to)} to Organization ${JSON.stringify(String(organizationId))}`, ...previewLines(preview)],
|
|
55354
|
+
question: "Authorize this invitation?"
|
|
55355
|
+
});
|
|
55356
|
+
}
|
|
55357
|
+
const context = yield* Effect.context();
|
|
55358
|
+
const run = Effect.runPromiseWith(context);
|
|
55359
|
+
const deadline = new AbortController();
|
|
55360
|
+
const openfortSignerFactory = yield* organizationWriteSigner(config, opened, run, async () => {
|
|
55361
|
+
const cancelled = cancelledWrite(CAPXUL_OPERATIONS.org.invitations.authorize, deadline.signal);
|
|
55362
|
+
if (cancelled !== null) throw cancelled;
|
|
55363
|
+
});
|
|
55364
|
+
const { client } = yield* restoreVerifiedClient(config, opened, {
|
|
55365
|
+
requirement: "deployed",
|
|
55366
|
+
openfortSignerFactory
|
|
55367
|
+
});
|
|
55368
|
+
const invitations = scopedInvitations(client, organizationId);
|
|
55369
|
+
const invitation = yield* withinDeadline(Effect.promise((signal) => {
|
|
55370
|
+
const forwardAbort = () => deadline.abort();
|
|
55371
|
+
if (signal.aborted) forwardAbort();
|
|
55372
|
+
else signal.addEventListener("abort", forwardAbort, { once: true });
|
|
55373
|
+
return invitations.invite({
|
|
55374
|
+
requestKey,
|
|
55375
|
+
...request
|
|
55376
|
+
}, {
|
|
55377
|
+
signal,
|
|
55378
|
+
onPrepared: async (prepared) => {
|
|
55379
|
+
await run(writeStderr(preparedLine(runtime.mode, prepared)));
|
|
55380
|
+
}
|
|
55381
|
+
}).finally(() => signal.removeEventListener("abort", forwardAbort));
|
|
55382
|
+
}).pipe(Effect.flatMap(resultValue)), timeoutSeconds, "The invitation did not settle within the command deadline.");
|
|
55383
|
+
return {
|
|
55384
|
+
data: { invitation },
|
|
55385
|
+
lines: invitationLines(invitation)
|
|
55386
|
+
};
|
|
55387
|
+
});
|
|
55388
|
+
const generateRequestKey = () => Effect.gen(function* () {
|
|
55389
|
+
return yield* (yield* Crypto.Crypto).randomUUIDv4;
|
|
55390
|
+
});
|
|
55391
|
+
const previewResult = (preview) => ({
|
|
55392
|
+
data: { preview },
|
|
55393
|
+
lines: previewLines(preview)
|
|
55394
|
+
});
|
|
55395
|
+
const previewLines = (preview) => [
|
|
55396
|
+
`Grantee: ${JSON.stringify({
|
|
55397
|
+
safeAddress: preview.grantee.safeAddress,
|
|
55398
|
+
partyId: preview.grantee.partyId,
|
|
55399
|
+
accountReady: preview.grantee.accountReady
|
|
55400
|
+
})}`,
|
|
55401
|
+
...preview.grants.map((grant) => `Offer: ${JSON.stringify(grant)}`),
|
|
55402
|
+
`Existing assignments: ${String(preview.existingAssignments.length)}`,
|
|
55403
|
+
`Includes management: ${String(preview.includesManagement)}`
|
|
55404
|
+
];
|
|
55405
|
+
//#endregion
|
|
55406
|
+
//#region src/commands/org-invite.ts
|
|
55407
|
+
const emailFlag$2 = Flag.string("email").pipe(Flag.optional);
|
|
55408
|
+
const orgFlag$2 = Flag.string("org").pipe(Flag.withAlias("org-id"), Flag.atLeast(0));
|
|
55409
|
+
const invitationIdFlag = Flag.string("invitation-id").pipe(Flag.optional);
|
|
55410
|
+
const timeoutFlag$1 = Flag.integer("timeout-seconds").pipe(Flag.withDefault(120));
|
|
55411
|
+
const confirmFlag$2 = Flag.boolean("confirm").pipe(Flag.withDefault(false));
|
|
55412
|
+
const metadata$2 = (name) => ({
|
|
55413
|
+
name,
|
|
55414
|
+
capability: "organization",
|
|
55415
|
+
observation: "command"
|
|
55416
|
+
});
|
|
55417
|
+
/** Reads and transitions carry the exact invitation ID; only list does not. */
|
|
55418
|
+
const target = {
|
|
55419
|
+
email: emailFlag$2,
|
|
55420
|
+
orgs: orgFlag$2,
|
|
55421
|
+
invitationId: invitationIdFlag
|
|
55422
|
+
};
|
|
55423
|
+
const executeRead = (action, input) => runCommand({
|
|
55424
|
+
...metadata$2(`org.invite.${action}`),
|
|
55425
|
+
network: true
|
|
55426
|
+
}, (config) => readInvitation(config, action, input));
|
|
55427
|
+
const executeTransition = (action, input) => runCommand({
|
|
55428
|
+
...metadata$2(`org.invite.${action}`),
|
|
55429
|
+
network: true
|
|
55430
|
+
}, (config) => transitionInvitation(config, action, input));
|
|
55431
|
+
const list$1 = Command.make("list", {
|
|
55432
|
+
email: emailFlag$2,
|
|
55433
|
+
orgs: orgFlag$2,
|
|
55434
|
+
limit: Flag.integer("limit").pipe(Flag.optional),
|
|
55435
|
+
cursor: Flag.string("cursor").pipe(Flag.optional),
|
|
55436
|
+
phases: Flag.string("phase").pipe(Flag.atLeast(0)),
|
|
55437
|
+
mine: Flag.boolean("mine").pipe(Flag.withDescription("Your own offers; accepted as a no-op on the plain list"), Flag.withDefault(false))
|
|
55438
|
+
}, ({ email, orgs, limit, cursor, phases, mine }) => executeRead("list", {
|
|
55439
|
+
email: Option.getOrUndefined(email),
|
|
55440
|
+
orgs,
|
|
55441
|
+
limit: Option.getOrUndefined(limit),
|
|
55442
|
+
cursor: Option.getOrUndefined(cursor),
|
|
55443
|
+
phases: phases.length === 0 ? void 0 : phases,
|
|
55444
|
+
mine
|
|
55445
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$2("org.invite.list")), Command.withDescription("List your own invitation offers, or an Organization's with --org; the result carries invitations, nextCursor, and observedAt"));
|
|
55446
|
+
const get = Command.make("get", {
|
|
55447
|
+
...target,
|
|
55448
|
+
timeoutSeconds: timeoutFlag$1
|
|
55449
|
+
}, ({ email, orgs, invitationId, timeoutSeconds }) => executeRead("get", {
|
|
55450
|
+
email: Option.getOrUndefined(email),
|
|
55451
|
+
orgs,
|
|
55452
|
+
invitationId: Option.getOrUndefined(invitationId),
|
|
55453
|
+
timeoutSeconds
|
|
55454
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$2("org.invite.get")), Command.withDescription("Read one invitation, in --org or its own resolved Organization"));
|
|
55455
|
+
const wait$1 = Command.make("wait", {
|
|
55456
|
+
...target,
|
|
55457
|
+
timeoutSeconds: timeoutFlag$1
|
|
55458
|
+
}, ({ email, orgs, invitationId, timeoutSeconds }) => executeRead("wait", {
|
|
55459
|
+
email: Option.getOrUndefined(email),
|
|
55460
|
+
orgs,
|
|
55461
|
+
invitationId: Option.getOrUndefined(invitationId),
|
|
55462
|
+
timeoutSeconds
|
|
55463
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$2("org.invite.wait")), Command.withDescription("Poll one invitation read until it settles; never writes"));
|
|
55464
|
+
const review = Command.make("review", {
|
|
55465
|
+
...target,
|
|
55466
|
+
timeoutSeconds: timeoutFlag$1
|
|
55467
|
+
}, ({ email, orgs, invitationId, timeoutSeconds }) => executeRead("review", {
|
|
55468
|
+
email: Option.getOrUndefined(email),
|
|
55469
|
+
orgs,
|
|
55470
|
+
invitationId: Option.getOrUndefined(invitationId),
|
|
55471
|
+
timeoutSeconds
|
|
55472
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$2("org.invite.review")), Command.withDescription("Review one exact current offer without writing or signing"));
|
|
55473
|
+
const transition = (name) => Command.make(name, {
|
|
55474
|
+
...target,
|
|
55475
|
+
confirm: confirmFlag$2,
|
|
55476
|
+
timeoutSeconds: timeoutFlag$1
|
|
55477
|
+
}, ({ email, orgs, invitationId, confirm, timeoutSeconds }) => executeTransition(name, {
|
|
55478
|
+
email: Option.getOrUndefined(email),
|
|
55479
|
+
orgs,
|
|
55480
|
+
invitationId: Option.getOrUndefined(invitationId),
|
|
55481
|
+
confirm,
|
|
55482
|
+
timeoutSeconds
|
|
55483
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$2(`org.invite.${name}`)), Command.withDescription(name === "decline" ? "Decline your own pending offer; starts its cleanup" : name === "cancel" ? "Cancel a pending offer you administer; starts its cleanup" : name === "resend" ? "Retry delivery of a verified pending offer; never extends expiry" : "Resume the current offer state; creates no new consent or grant"));
|
|
55484
|
+
/**
|
|
55485
|
+
* The one consent command. `--offer-digest` is canonical; `--expected-offer`
|
|
55486
|
+
* remains a compatibility spelling and conflicting values refuse.
|
|
55487
|
+
*/
|
|
55488
|
+
const accept = Command.make("accept", {
|
|
55489
|
+
...target,
|
|
55490
|
+
offerDigest: Flag.string("offer-digest").pipe(Flag.optional),
|
|
55491
|
+
expectedOffer: Flag.string("expected-offer").pipe(Flag.optional),
|
|
55492
|
+
confirm: confirmFlag$2,
|
|
55493
|
+
timeoutSeconds: timeoutFlag$1
|
|
55494
|
+
}, ({ email, orgs, invitationId, offerDigest, expectedOffer, confirm, timeoutSeconds }) => runCommand({
|
|
55495
|
+
...metadata$2("org.invite.accept"),
|
|
55496
|
+
network: true
|
|
55497
|
+
}, (config) => acceptInvitation(config, {
|
|
55498
|
+
email: Option.getOrUndefined(email),
|
|
55499
|
+
orgs,
|
|
55500
|
+
invitationId: Option.getOrUndefined(invitationId),
|
|
55501
|
+
offerDigest: Option.getOrUndefined(offerDigest),
|
|
55502
|
+
expectedOfferDigest: Option.getOrUndefined(expectedOffer),
|
|
55503
|
+
confirm,
|
|
55504
|
+
timeoutSeconds
|
|
55505
|
+
}))).pipe(Command.annotate(CliCommandMetadata, metadata$2("org.invite.accept")), Command.withDescription("Accept one exact offer by its current digest and start its grant; noninteractive runs must supply --offer-digest"));
|
|
55506
|
+
const invite = Command.make("invite").pipe(Command.annotate(CliCommandMetadata, metadata$2(CAPXUL_OPERATIONS.org.invite)), Command.withDescription("Invitation reads, the consent commit, and the transitions"), Command.withSubcommands([
|
|
55507
|
+
list$1,
|
|
55508
|
+
get,
|
|
55509
|
+
wait$1,
|
|
55510
|
+
review,
|
|
55511
|
+
accept,
|
|
55512
|
+
transition("decline"),
|
|
55513
|
+
transition("cancel"),
|
|
55514
|
+
transition("resend"),
|
|
55515
|
+
transition("retry")
|
|
55516
|
+
]));
|
|
55517
|
+
const newBudgetFlags = {
|
|
55518
|
+
newBudgetName: Flag.string("new-budget-name").pipe(Flag.optional),
|
|
55519
|
+
asset: Flag.string("asset").pipe(Flag.optional),
|
|
55520
|
+
limit: Flag.string("limit").pipe(Flag.optional),
|
|
55521
|
+
unlimited: Flag.boolean("unlimited").pipe(Flag.withDefault(false)),
|
|
55522
|
+
recipientAccounts: Flag.string("recipient-account").pipe(Flag.atLeast(0)),
|
|
55523
|
+
anyRecipient: Flag.boolean("any-recipient").pipe(Flag.withDefault(false)),
|
|
55524
|
+
actions: Flag.string("actions").pipe(Flag.atLeast(0))
|
|
55525
|
+
};
|
|
55526
|
+
const memberInvite = Command.make("invite", {
|
|
55527
|
+
email: emailFlag$2,
|
|
55528
|
+
orgs: orgFlag$2,
|
|
55529
|
+
toEmail: Flag.string("to-email").pipe(Flag.optional),
|
|
55530
|
+
accountId: Flag.string("account-id").pipe(Flag.optional),
|
|
55531
|
+
budgetIds: Flag.string("budget-id").pipe(Flag.atLeast(0)),
|
|
55532
|
+
permissionIds: Flag.string("permission-id").pipe(Flag.atLeast(0)),
|
|
55533
|
+
...newBudgetFlags,
|
|
55534
|
+
requestKey: Flag.string("request-key").pipe(Flag.optional),
|
|
55535
|
+
preview: Flag.boolean("preview").pipe(Flag.withDefault(false)),
|
|
55536
|
+
confirm: confirmFlag$2,
|
|
55537
|
+
timeoutSeconds: timeoutFlag$1
|
|
55538
|
+
}, ({ email, orgs, toEmail, accountId, budgetIds, permissionIds, newBudgetName, asset, limit, unlimited, recipientAccounts, anyRecipient, actions, requestKey, preview, confirm, timeoutSeconds }) => {
|
|
55539
|
+
return runCommand({
|
|
55540
|
+
...metadata$2("org.member.invite"),
|
|
55541
|
+
network: true
|
|
55542
|
+
}, (config) => inviteInvitationMember(config, {
|
|
55543
|
+
email: Option.getOrUndefined(email),
|
|
55544
|
+
orgs,
|
|
55545
|
+
toEmail: Option.getOrUndefined(toEmail),
|
|
55546
|
+
accountId: Option.getOrUndefined(accountId),
|
|
55547
|
+
budgetIds,
|
|
55548
|
+
permissionIds,
|
|
55549
|
+
newBudgetName: Option.getOrUndefined(newBudgetName),
|
|
55550
|
+
asset: Option.getOrUndefined(asset),
|
|
55551
|
+
limit: Option.getOrUndefined(limit),
|
|
55552
|
+
unlimited,
|
|
55553
|
+
recipientAccounts,
|
|
55554
|
+
anyRecipient,
|
|
55555
|
+
actions,
|
|
55556
|
+
requestKey: Option.getOrUndefined(requestKey),
|
|
55557
|
+
preview,
|
|
55558
|
+
confirm,
|
|
55559
|
+
timeoutSeconds
|
|
55560
|
+
}));
|
|
55561
|
+
}).pipe(Command.annotate(CliCommandMetadata, metadata$2("org.member.invite")), Command.withDescription("Authorize one exact invitation offer; --preview writes nothing"));
|
|
55562
|
+
//#endregion
|
|
55563
|
+
//#region src/platform/bounded-text.ts
|
|
55564
|
+
var UpdateUnavailable = class extends Data.TaggedError("UpdateUnavailable") {};
|
|
55565
|
+
const boundedText = (stream, limit) => Effect.suspend(() => {
|
|
55566
|
+
let size = 0;
|
|
55567
|
+
return stream.pipe(Stream.mapEffect((chunk) => {
|
|
55568
|
+
size += chunk.byteLength;
|
|
55569
|
+
return size > limit ? Effect.fail(new UpdateUnavailable()) : Effect.succeed(chunk);
|
|
55570
|
+
}), Stream.decodeText(), Stream.runFold(() => "", (text, chunk) => text + chunk));
|
|
55571
|
+
});
|
|
55572
|
+
//#endregion
|
|
55573
|
+
//#region src/contact.ts
|
|
55574
|
+
const AddInputJson = Schema.Struct({
|
|
55575
|
+
ref: Schema.Union([
|
|
55576
|
+
Schema.Struct({
|
|
55577
|
+
kind: Schema.Literal("handle"),
|
|
55578
|
+
handle: Schema.NonEmptyString
|
|
55579
|
+
}),
|
|
55580
|
+
Schema.Struct({
|
|
55581
|
+
kind: Schema.Literal("email"),
|
|
55582
|
+
email: Schema.NonEmptyString
|
|
55583
|
+
}),
|
|
55584
|
+
Schema.Struct({
|
|
55585
|
+
kind: Schema.Literal("address"),
|
|
55586
|
+
address: Schema.NonEmptyString
|
|
55587
|
+
}),
|
|
55588
|
+
Schema.Struct({
|
|
55589
|
+
kind: Schema.Literal("party"),
|
|
55590
|
+
partyId: Schema.NonEmptyString
|
|
55591
|
+
})
|
|
55592
|
+
]),
|
|
55593
|
+
label: Schema.optional(Schema.String)
|
|
55594
|
+
});
|
|
55595
|
+
const parseAddInput = (text) => Schema.decodeUnknownEffect(Schema.fromJsonString(AddInputJson), { onExcessProperty: "error" })(text).pipe(Effect.flatMap((value) => {
|
|
55596
|
+
try {
|
|
55597
|
+
const ref = value.ref.kind === "address" ? {
|
|
55598
|
+
kind: "address",
|
|
55599
|
+
address: toAddress(value.ref.address)
|
|
55600
|
+
} : value.ref.kind === "party" ? {
|
|
55601
|
+
kind: "party",
|
|
55602
|
+
partyId: toPartyId(value.ref.partyId)
|
|
55603
|
+
} : value.ref;
|
|
55604
|
+
return Effect.succeed({
|
|
55605
|
+
ref,
|
|
55606
|
+
...value.label === void 0 ? {} : { label: value.label }
|
|
55607
|
+
});
|
|
55608
|
+
} catch (cause) {
|
|
55609
|
+
return Effect.fail(cause);
|
|
55610
|
+
}
|
|
55611
|
+
}), Effect.mapError(() => inputRequired("Provide --input with one valid AddressBookAddInput JSON object.")));
|
|
55612
|
+
const readAddInput = (source) => Effect.gen(function* () {
|
|
55613
|
+
if (source === void 0) {
|
|
55614
|
+
const runtime = yield* CliRuntime;
|
|
55615
|
+
if (!runtime.tty || runtime.ci || runtime.mode === "json") return yield* Effect.fail(inputRequired("Provide --input FILE|- with one AddressBookAddInput JSON object."));
|
|
55616
|
+
const kind = yield* Prompt.select({
|
|
55617
|
+
message: "Reference kind",
|
|
55618
|
+
choices: [
|
|
55619
|
+
"handle",
|
|
55620
|
+
"email",
|
|
55621
|
+
"address",
|
|
55622
|
+
"party"
|
|
55623
|
+
].map((value) => ({
|
|
55624
|
+
title: value,
|
|
55625
|
+
value
|
|
55626
|
+
}))
|
|
55627
|
+
});
|
|
55628
|
+
const value = (yield* Prompt.text({ message: "Reference value" })).trim();
|
|
55629
|
+
const label = (yield* Prompt.text({ message: "Label (optional)" })).trim();
|
|
55630
|
+
return yield* parseAddInput(JSON.stringify({
|
|
55631
|
+
ref: kind === "handle" ? {
|
|
55632
|
+
kind,
|
|
55633
|
+
handle: value
|
|
55634
|
+
} : kind === "email" ? {
|
|
55635
|
+
kind,
|
|
55636
|
+
email: value
|
|
55637
|
+
} : kind === "address" ? {
|
|
55638
|
+
kind,
|
|
55639
|
+
address: value
|
|
55640
|
+
} : {
|
|
55641
|
+
kind,
|
|
55642
|
+
partyId: value
|
|
55643
|
+
},
|
|
55644
|
+
...label === "" ? {} : { label }
|
|
55645
|
+
}));
|
|
55646
|
+
}
|
|
55647
|
+
const text = source === "-" ? yield* boundedText((yield* Stdio.Stdio).stdin, 65536) : yield* Effect.gen(function* () {
|
|
55648
|
+
const fs = yield* FileSystem.FileSystem;
|
|
55649
|
+
return yield* boundedText(fs.stream(source, { bytesToRead: 65537 }), 65536);
|
|
55650
|
+
});
|
|
55651
|
+
return yield* parseAddInput(text);
|
|
55652
|
+
}).pipe(Effect.mapError((error) => error instanceof CliFailure ? error : inputRequired("The contact input file could not be read or was too large.")));
|
|
55653
|
+
const partyId = (value) => Effect.try({
|
|
55654
|
+
try: () => toPartyId(value),
|
|
55655
|
+
catch: () => inputRequired("Provide a valid --entry-id.")
|
|
55656
|
+
});
|
|
55657
|
+
const selectedBook = (client, actor, orgs) => Effect.gen(function* () {
|
|
55658
|
+
const ids = [...new Set(orgs)];
|
|
55659
|
+
if (ids.length > 1) return yield* Effect.fail(inputRequired("Provide one exact Organization ID."));
|
|
55660
|
+
if (actor === "personal") {
|
|
55661
|
+
if (ids.length > 0) return yield* Effect.fail(inputRequired("Personal contacts do not accept --org."));
|
|
55662
|
+
return client.account.addressBook;
|
|
55663
|
+
}
|
|
55664
|
+
if (ids.length === 0) return yield* Effect.fail(inputRequired("Provide --org."));
|
|
55665
|
+
const organizationId = yield* Effect.try({
|
|
55666
|
+
try: () => toOrgId(ids[0]),
|
|
55667
|
+
catch: () => inputRequired("Provide a valid --org.")
|
|
55668
|
+
});
|
|
55669
|
+
return client.org(organizationId).addressBook;
|
|
55670
|
+
});
|
|
55671
|
+
const result = (value, lines) => ({
|
|
55672
|
+
data: value,
|
|
55673
|
+
lines
|
|
55674
|
+
});
|
|
55675
|
+
const requiredLabel = (value) => {
|
|
55676
|
+
const label = value?.trim() ?? "";
|
|
55677
|
+
return label.length === 0 ? Effect.fail(inputRequired("Provide --label.")) : Effect.succeed(label);
|
|
55678
|
+
};
|
|
55679
|
+
const actorLine = (orgs) => orgs[0] === void 0 ? "Actor: personal" : `Actor: Organization ${JSON.stringify(orgs[0])}`;
|
|
55680
|
+
const runContact = (config, action, input) => Effect.gen(function* () {
|
|
55681
|
+
const addInput = action === "add" ? yield* readAddInput(input.input) : void 0;
|
|
55682
|
+
const entryId = action === "get" || action === "label" || action === "hide" || action === "unhide" ? yield* partyId(input.entryId) : void 0;
|
|
55683
|
+
const label = action === "label" ? yield* requiredLabel(input.label) : void 0;
|
|
55684
|
+
const interactiveWrite = action === "add" || action === "label" || action === "hide" || action === "unhide" ? yield* requireWriteConfirmation(input.confirm) : false;
|
|
55685
|
+
const { client } = yield* restoreAuthenticatedClient(config, input.email);
|
|
55686
|
+
const book = yield* selectedBook(client, input.actor, input.orgs);
|
|
55687
|
+
if (action === "add") {
|
|
55688
|
+
if (interactiveWrite) yield* confirmWrite({
|
|
55689
|
+
lines: [actorLine(input.orgs), `Reference: ${JSON.stringify(addInput.ref)}`],
|
|
55690
|
+
question: "Add this contact?"
|
|
55691
|
+
});
|
|
55692
|
+
const entry = yield* Effect.promise((signal) => book.add(addInput, { signal })).pipe(Effect.flatMap(resultValue));
|
|
55693
|
+
return result(entry, [JSON.stringify(entry)]);
|
|
55694
|
+
}
|
|
55695
|
+
if (action === "get") {
|
|
55696
|
+
const entry = yield* Effect.promise((signal) => book.get(entryId, { signal })).pipe(Effect.flatMap(resultValue));
|
|
55697
|
+
return result(entry, [entry === null ? "No contact found" : JSON.stringify(entry)]);
|
|
55698
|
+
}
|
|
55699
|
+
if (action === "list") {
|
|
55700
|
+
const entries = yield* Effect.promise((signal) => book.list(input.includeHidden === true ? { includeHidden: true } : void 0, { signal })).pipe(Effect.flatMap(resultValue));
|
|
55701
|
+
return result(entries, entries.map((entry) => JSON.stringify(entry)));
|
|
55702
|
+
}
|
|
55703
|
+
if (interactiveWrite) {
|
|
55704
|
+
const current = yield* Effect.promise((signal) => book.get(entryId, { signal })).pipe(Effect.flatMap(resultValue));
|
|
55705
|
+
if (current === null) return yield* Effect.fail(inputRequired("No contact has that --entry-id."));
|
|
55706
|
+
yield* confirmWrite({
|
|
55707
|
+
lines: [
|
|
55708
|
+
actorLine(input.orgs),
|
|
55709
|
+
`PartyId: ${current.id}`,
|
|
55710
|
+
`Current: ${JSON.stringify({
|
|
55711
|
+
label: current.label,
|
|
55712
|
+
hidden: current.hidden
|
|
55713
|
+
})}`,
|
|
55714
|
+
`Result: ${JSON.stringify(action === "label" ? {
|
|
55715
|
+
label,
|
|
55716
|
+
hidden: current.hidden
|
|
55717
|
+
} : {
|
|
55718
|
+
label: current.label,
|
|
55719
|
+
hidden: action === "hide"
|
|
55720
|
+
})}`
|
|
55721
|
+
],
|
|
55722
|
+
question: `${action === "label" ? "Label" : action === "hide" ? "Hide" : "Unhide"} this contact?`
|
|
55723
|
+
});
|
|
55724
|
+
}
|
|
55725
|
+
const entry = yield* Effect.promise((signal) => action === "label" ? book.label({
|
|
55726
|
+
entryId,
|
|
55727
|
+
label
|
|
55728
|
+
}, { signal }) : action === "hide" ? book.hide(entryId, { signal }) : book.unhide(entryId, { signal })).pipe(Effect.flatMap(resultValue));
|
|
55729
|
+
return result(entry, [JSON.stringify(entry)]);
|
|
55730
|
+
});
|
|
55731
|
+
//#endregion
|
|
55732
|
+
//#region src/commands/contact.ts
|
|
55733
|
+
const emailFlag$1 = Flag.string("email").pipe(Flag.optional);
|
|
55734
|
+
const orgFlag$1 = Flag.string("org").pipe(Flag.withAlias("org-id"), Flag.atLeast(1));
|
|
55735
|
+
const includeHiddenFlag = Flag.boolean("include-hidden").pipe(Flag.withDefault(false));
|
|
55736
|
+
const entryIdFlag = Flag.string("entry-id");
|
|
55737
|
+
const labelFlag = Flag.string("label");
|
|
55738
|
+
const inputFlag = Flag.string("input").pipe(Flag.optional);
|
|
55739
|
+
const confirmFlag$1 = Flag.boolean("confirm").pipe(Flag.withDefault(false));
|
|
55740
|
+
const names = {
|
|
55741
|
+
personal: {
|
|
55742
|
+
root: "contact",
|
|
55743
|
+
list: "contact.list",
|
|
55744
|
+
get: "contact.get",
|
|
55745
|
+
add: "contact.add",
|
|
55746
|
+
label: "contact.label",
|
|
55747
|
+
hide: "contact.hide",
|
|
55748
|
+
unhide: "contact.unhide"
|
|
55749
|
+
},
|
|
55750
|
+
organization: {
|
|
55751
|
+
root: "org.contact",
|
|
55752
|
+
list: "org.contact.list",
|
|
55753
|
+
get: "org.contact.get",
|
|
55754
|
+
add: "org.contact.add",
|
|
55755
|
+
label: "org.contact.label",
|
|
55756
|
+
hide: "org.contact.hide",
|
|
55757
|
+
unhide: "org.contact.unhide"
|
|
55758
|
+
}
|
|
55759
|
+
};
|
|
55760
|
+
const metadata$1 = (name) => ({
|
|
55761
|
+
name,
|
|
55762
|
+
capability: "contacts",
|
|
55763
|
+
observation: "command"
|
|
55764
|
+
});
|
|
55765
|
+
const makeContactCommand = (actor) => {
|
|
55766
|
+
const selectedNames = names[actor];
|
|
55767
|
+
const scope = actor === "organization" ? { orgs: orgFlag$1 } : {};
|
|
55768
|
+
const execute = (action, input) => runCommand({
|
|
55769
|
+
...metadata$1(selectedNames[action]),
|
|
55770
|
+
network: true
|
|
55771
|
+
}, (config) => runContact(config, action, {
|
|
55772
|
+
actor,
|
|
55773
|
+
orgs: input.orgs ?? [],
|
|
55774
|
+
email: input.email,
|
|
55775
|
+
includeHidden: input.includeHidden,
|
|
55776
|
+
entryId: input.entryId,
|
|
55777
|
+
label: input.label,
|
|
55778
|
+
input: input.input,
|
|
55779
|
+
confirm: input.confirm
|
|
55780
|
+
}));
|
|
55781
|
+
const list = Command.make("list", {
|
|
55782
|
+
email: emailFlag$1,
|
|
55783
|
+
...scope,
|
|
55784
|
+
includeHidden: includeHiddenFlag
|
|
55785
|
+
}, ({ email, includeHidden, ...scoped }) => execute("list", {
|
|
55786
|
+
email: Option.getOrUndefined(email),
|
|
55787
|
+
orgs: "orgs" in scoped ? scoped.orgs : [],
|
|
55788
|
+
includeHidden,
|
|
55789
|
+
confirm: false
|
|
55790
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$1(selectedNames.list)), Command.withDescription("List contacts in the selected actor's address book"));
|
|
55791
|
+
const get = Command.make("get", {
|
|
55792
|
+
email: emailFlag$1,
|
|
55793
|
+
...scope,
|
|
55794
|
+
entryId: entryIdFlag
|
|
55795
|
+
}, ({ email, entryId, ...scoped }) => execute("get", {
|
|
55796
|
+
email: Option.getOrUndefined(email),
|
|
55797
|
+
orgs: "orgs" in scoped ? scoped.orgs : [],
|
|
55798
|
+
entryId,
|
|
55799
|
+
confirm: false
|
|
55800
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$1(selectedNames.get)), Command.withDescription("Read one contact by stable PartyId"));
|
|
55801
|
+
const add = Command.make("add", {
|
|
55802
|
+
email: emailFlag$1,
|
|
55803
|
+
...scope,
|
|
55804
|
+
input: inputFlag,
|
|
55805
|
+
confirm: confirmFlag$1
|
|
55806
|
+
}, ({ email, input, confirm, ...scoped }) => execute("add", {
|
|
55807
|
+
email: Option.getOrUndefined(email),
|
|
55808
|
+
orgs: "orgs" in scoped ? scoped.orgs : [],
|
|
55809
|
+
input: Option.getOrUndefined(input),
|
|
55810
|
+
confirm
|
|
55811
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$1(selectedNames.add)), Command.withDescription("Add one contact from AddressBookAddInput JSON"));
|
|
55812
|
+
const labelContact = Command.make("label", {
|
|
55813
|
+
email: emailFlag$1,
|
|
55814
|
+
...scope,
|
|
55815
|
+
entryId: entryIdFlag,
|
|
55816
|
+
label: labelFlag,
|
|
55817
|
+
confirm: confirmFlag$1
|
|
55818
|
+
}, ({ email, entryId, label, confirm, ...scoped }) => execute("label", {
|
|
55819
|
+
email: Option.getOrUndefined(email),
|
|
55820
|
+
orgs: "orgs" in scoped ? scoped.orgs : [],
|
|
55821
|
+
entryId,
|
|
55822
|
+
label,
|
|
55823
|
+
confirm
|
|
55824
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$1(selectedNames.label)), Command.withDescription("Change one contact label by stable PartyId"));
|
|
55825
|
+
const visibility = (action) => Command.make(action, {
|
|
55826
|
+
email: emailFlag$1,
|
|
55827
|
+
...scope,
|
|
55828
|
+
entryId: entryIdFlag,
|
|
55829
|
+
confirm: confirmFlag$1
|
|
55830
|
+
}, ({ email, entryId, confirm, ...scoped }) => execute(action, {
|
|
55831
|
+
email: Option.getOrUndefined(email),
|
|
55832
|
+
orgs: "orgs" in scoped ? scoped.orgs : [],
|
|
55833
|
+
entryId,
|
|
55834
|
+
confirm
|
|
55835
|
+
})).pipe(Command.annotate(CliCommandMetadata, metadata$1(selectedNames[action])), Command.withDescription(`${action === "hide" ? "Hide" : "Restore"} one contact`));
|
|
55836
|
+
return Command.make("contact").pipe(Command.annotate(CliCommandMetadata, metadata$1(selectedNames.root)), Command.withDescription("Manage the selected actor's contacts"), Command.withSubcommands([
|
|
55837
|
+
list,
|
|
55838
|
+
get,
|
|
55839
|
+
add,
|
|
55840
|
+
labelContact,
|
|
55841
|
+
visibility("hide"),
|
|
55842
|
+
visibility("unhide")
|
|
55843
|
+
]));
|
|
55844
|
+
};
|
|
55845
|
+
const contact = makeContactCommand("personal");
|
|
55846
|
+
const organizationContact = makeContactCommand("organization");
|
|
55847
|
+
//#endregion
|
|
54207
55848
|
//#region src/commands/org.ts
|
|
54208
55849
|
const emailFlag = Flag.string("email").pipe(Flag.optional);
|
|
54209
55850
|
const orgFlag = Flag.string("org").pipe(Flag.withAlias("org-id"), Flag.atLeast(0));
|
|
@@ -54251,7 +55892,11 @@ const memberGet = Command.make("get", {
|
|
|
54251
55892
|
orgs,
|
|
54252
55893
|
accountId
|
|
54253
55894
|
})).pipe(Command.annotate(CliCommandMetadata, metadata("org.member.get")), Command.withDescription("Read one member by exact Account ID"));
|
|
54254
|
-
const member = Command.make("member").pipe(Command.annotate(CliCommandMetadata, metadata("org.member")), Command.withSubcommands([
|
|
55895
|
+
const member = Command.make("member").pipe(Command.annotate(CliCommandMetadata, metadata("org.member")), Command.withSubcommands([
|
|
55896
|
+
members("list"),
|
|
55897
|
+
memberGet,
|
|
55898
|
+
memberInvite
|
|
55899
|
+
]));
|
|
54255
55900
|
const wait = Command.make("wait", {
|
|
54256
55901
|
...scoped,
|
|
54257
55902
|
timeoutSeconds: Flag.integer("timeout-seconds").pipe(Flag.withDefault(120))
|
|
@@ -54303,6 +55948,8 @@ const org = Command.make("org").pipe(Command.annotate(CliCommandMetadata, metada
|
|
|
54303
55948
|
me,
|
|
54304
55949
|
members("members"),
|
|
54305
55950
|
member,
|
|
55951
|
+
organizationContact,
|
|
55952
|
+
invite,
|
|
54306
55953
|
wait,
|
|
54307
55954
|
create,
|
|
54308
55955
|
retry
|
|
@@ -54340,19 +55987,10 @@ const command = Command.make("capxul").pipe(Command.annotate(CliCommandMetadata,
|
|
|
54340
55987
|
auth,
|
|
54341
55988
|
doctor,
|
|
54342
55989
|
telemetry,
|
|
55990
|
+
contact,
|
|
54343
55991
|
org
|
|
54344
55992
|
]), Command.withGlobalFlags([JsonOutput]));
|
|
54345
55993
|
//#endregion
|
|
54346
|
-
//#region src/platform/bounded-text.ts
|
|
54347
|
-
var UpdateUnavailable = class extends Data.TaggedError("UpdateUnavailable") {};
|
|
54348
|
-
const boundedText = (stream, limit) => Effect.suspend(() => {
|
|
54349
|
-
let size = 0;
|
|
54350
|
-
return stream.pipe(Stream.mapEffect((chunk) => {
|
|
54351
|
-
size += chunk.byteLength;
|
|
54352
|
-
return size > limit ? Effect.fail(new UpdateUnavailable()) : Effect.succeed(chunk);
|
|
54353
|
-
}), Stream.decodeText(), Stream.runFold(() => "", (text, chunk) => text + chunk));
|
|
54354
|
-
});
|
|
54355
|
-
//#endregion
|
|
54356
55994
|
//#region src/platform/install-provenance.ts
|
|
54357
55995
|
const Manifest = Schema.Struct({
|
|
54358
55996
|
name: Schema.Literal("@capxul/cli"),
|