@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/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
- Object.freeze({ BASE_SEPOLIA: Object.freeze({
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
- detectAndAcceptPendingInvitations: "org.detectAndAcceptPendingInvitations",
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
- inviteMember: "org.inviteMember",
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
- resendInviteToken: "org/mutations:resendInviteToken"
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.6";
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$2(signal) {
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$2(signal)) return {
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$2(signal)) return abandonPrepared$1(deps, prepared.value.executionId, closePaymentOnExit, "cancelled", {
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$2(signal)) return abandonPrepared$1(deps, prepared.value.executionId, closePaymentOnExit, "cancelled", {
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$1(signal) {
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$1(signal)) return cancelled(CAPXUL_OPERATIONS.payments.pay);
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$1(signal)) return abandonPrepared(deps, prepared.value.executionId, "cancelled", cancelled(CAPXUL_OPERATIONS.payments.pay), onPreparedClosed);
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$1(signal)) return abandonPrepared(deps, prepared.value.executionId, "cancelled", cancelled(CAPXUL_OPERATIONS.payments.pay), onPreparedClosed);
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 signerAddress = await signerResult(this.#signer.source, "getAddress", () => this.#signer.getAddress());
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(this.#signer.source, "signUserOpHash", () => this.#signer.signUserOpHash(prepared.value.digest));
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 && (current.value.at === "awaitingFounderAuthorization" || current.value.at === "submittingBootstrap")) {
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), { detectAndAcceptPendingInvitations(options) {
48693
- if (options?.signal?.aborted) return Promise.resolve({
48694
- ok: false,
48695
- error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.organizations.detectAndAcceptPendingInvitations })
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
- invite(_input, _options) {
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
- ...signer === void 0 ? {} : { organizationSetup: new ConvexOrganizationSetupAdapter({
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.6";
51014
- const sdkVersion = "4.20.0-beta.6";
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://api.staging.capxul.com";
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
- if (mode === "json") return writeStdout(`${JSON.stringify(envelope)}\n`);
52242
- return envelope.outcome === "succeeded" ? writeStdout(`${lines.join("\n")}\n`) : writeStderr(`${envelope.error.code}: ${envelope.error.message}\n`);
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 Railway application before an online check."));
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" role="status" aria-live="polite">Keep this tab open. Continue in your terminal when the wallet is ready.</p><p class="sr-only" id="lead">Keep this tab open. Continue in your terminal when the wallet is ready.</p><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>`;
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$1 = Flag.string("email").pipe(Flag.withDescription("Account email"), Flag.optional);
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$2 = (name) => ({
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$1,
54221
+ email: emailFlag$3,
53555
54222
  otpStdin: otpStdinFlag
53556
54223
  }, ({ email, otpStdin }) => runCommand({
53557
- ...metadata$2("auth.login"),
54224
+ ...metadata$4("auth.login"),
53558
54225
  network: true
53559
- }, (config) => login(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$2("auth.login")), Command.withDescription("Establish a first-party session with terminal-owned email OTP"));
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$1,
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$2("auth.signup"),
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$2("auth.signup")), Command.withDescription("Verify email and complete Profile, Openfort wallet, and Account setup"));
53574
- const sendCommand = Command.make("send", { email: emailFlag$1 }, ({ email }) => runCommand({
53575
- ...metadata$2("auth.send"),
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$2("auth.send")), Command.withDescription("Send an OTP and save non-secret continuation context"));
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$1,
54246
+ email: emailFlag$3,
53580
54247
  otpStdin: otpStdinFlag
53581
54248
  }, ({ email, otpStdin }) => runCommand({
53582
- ...metadata$2("auth.verify"),
54249
+ ...metadata$4("auth.verify"),
53583
54250
  network: true
53584
- }, (config) => verifyOtp(config, Option.getOrUndefined(email), otpStdin))).pipe(Command.annotate(CliCommandMetadata, metadata$2("auth.verify")), Command.withDescription("Verify a delivered OTP and persist the first-party session"));
53585
- const profileCommand = Command.make("profile", { email: emailFlag$1 }, ({ email }) => runCommand({
53586
- ...metadata$2("auth.profile"),
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$2("auth.profile")), Command.withDescription("Restore the session and read the backend profile and account lifecycle"));
53589
- const statusCommand = Command.make("status", { email: emailFlag$1 }, ({ email }) => runCommand({
53590
- ...metadata$2("auth.status"),
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$2("auth.status")), Command.withDescription("Validate a first-party session or show a tagged legacy grant"));
53593
- const logoutCommand = Command.make("logout", { email: emailFlag$1 }, ({ email }) => runCommand({
53594
- ...metadata$2("auth.logout"),
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$2("auth.logout")), Command.withDescription("Forget local credentials and revoke their remote session or grant"));
53597
- const auth = Command.make("auth").pipe(Command.annotate(CliCommandMetadata, metadata$2("auth")), Command.withDescription("First-party email sessions (broader authority than legacy account:read grants)"), Command.withSubcommands([
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$1 = {
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$1,
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$1), Command.withDescription("Check local configuration; --online also checks the backend"));
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 confirmOrganizationWrite = (preview) => Effect.gen(function* () {
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 or
53984
- * bootstrap submission. The bridge's own reset stops its loopback server, so a
53985
- * reset here clears the stale readiness, closes that bridge, and lets the next
53986
- * address or digest request open one for the same command.
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* confirmOrganizationWrite({
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* confirmOrganizationWrite({
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([members("list"), memberGet]));
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"),