@capxul/mcp 4.20.0-beta.26 → 4.20.0-beta.27

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.
Files changed (2) hide show
  1. package/dist/main.mjs +551 -420
  2. package/package.json +3 -3
package/dist/main.mjs CHANGED
@@ -9610,10 +9610,19 @@ const ApprovalNetworkSchema = Schema.Struct({
9610
9610
  name: Schema.String,
9611
9611
  explorerUrl: Schema.String
9612
9612
  });
9613
+ /**
9614
+ * Whose money the operation moves: the person's own, or an Organization's,
9615
+ * which a reader follows through that Organization's scope.
9616
+ */
9617
+ const ApprovalActorSchema = Schema.Union([Schema.Struct({ kind: Schema.Literal("personal") }), Schema.Struct({
9618
+ kind: Schema.Literal("organization"),
9619
+ orgId: Schema.NonEmptyString
9620
+ })]);
9613
9621
  /** What the person reads before they sign. */
9614
9622
  const ApprovalSummarySchema = Schema.Struct({
9615
9623
  title: Schema.String,
9616
9624
  from: Schema.Struct({
9625
+ kind: Schema.Literals(["personal", "organization"]),
9617
9626
  label: Schema.String,
9618
9627
  address: AddressSchema$1
9619
9628
  }),
@@ -9635,6 +9644,7 @@ const ApprovalSchema = Schema.Struct({
9635
9644
  url: Schema.String,
9636
9645
  kind: Schema.Literals(APPROVAL_KINDS),
9637
9646
  state: Schema.Literals(APPROVAL_STATES),
9647
+ actor: ApprovalActorSchema,
9638
9648
  summary: ApprovalSummarySchema,
9639
9649
  operation: ApprovalOperationSchema,
9640
9650
  /** Who must sign: the owner key of the paying Safe. */
@@ -13705,7 +13715,11 @@ const ORGANIZATION_OPERATIONS = {
13705
13715
  seedNativeReadiness: "operator.fixtures.seedNativeReadiness",
13706
13716
  seedPrerequisites: "operator.fixtures.seedPrerequisites"
13707
13717
  },
13708
- identities: { purgeByEmail: "operator.identities.purgeByEmail" }
13718
+ identities: {
13719
+ purgeByEmail: "operator.identities.purgeByEmail",
13720
+ /** One Account and every row that refers to it, unless it has Payments or an Organization tie. */
13721
+ purgeAccount: "operator.identities.purgeAccount"
13722
+ }
13709
13723
  },
13710
13724
  /** Organizations' internal functions; its public rows join from `OPERATIONS`. */
13711
13725
  organizations: {
@@ -13955,7 +13969,11 @@ const PLATFORM_OPERATIONS = {
13955
13969
  recordUse: "applications.bootstraps.recordUse",
13956
13970
  resolve: "applications.bootstraps.resolve"
13957
13971
  },
13958
- keys: { issue: "applications.keys.issue" },
13972
+ keys: {
13973
+ issue: "applications.keys.issue",
13974
+ /** Operator-only: revoke one key by its id, whoever owns it. */
13975
+ revokeById: "applications.keys.revokeById"
13976
+ },
13959
13977
  quickstarts: {
13960
13978
  claim: "applications.quickstarts.claim",
13961
13979
  mint: "applications.quickstarts.mint"
@@ -17098,7 +17116,7 @@ function mapAccountLifecycle(input) {
17098
17116
  }
17099
17117
  //#endregion
17100
17118
  //#region ../../packages/sdk/package.json
17101
- var version$2 = "4.20.0-beta.26";
17119
+ var version$2 = "4.20.0-beta.27";
17102
17120
  //#endregion
17103
17121
  //#region ../../packages/sdk/src/observability/telemetry/exception-projection.ts
17104
17122
  /** Fixed fallback for failures that have no safe message. */
@@ -21365,6 +21383,13 @@ function subscribeFreshQuery(deps, args, listener, operation, projection, option
21365
21383
  }
21366
21384
  //#endregion
21367
21385
  //#region ../../packages/sdk/src/payments/lifecycle-execution.ts
21386
+ /**
21387
+ * The prepared command is this lifecycle intent; a retry also names the
21388
+ * original birth command of the scope it was asked for.
21389
+ */
21390
+ const lifecycleCommandCheck = (intent, expectedOrganizationId) => async (request, evidence) => await matchesIntent(intent)(request, evidence) && (intent.kind !== "retry" || (expectedOrganizationId === void 0 ? evidence.sourceCommand?.kind === "birth" && evidence.sourceCommand.actor.kind === "account" : evidence.sourceCommand?.kind === "birth" && evidence.sourceCommand.actor.kind === "organization" && evidence.sourceCommand.actor.orgId === expectedOrganizationId));
21391
+ /** The prepared command pays exactly the request the payer confirmed. */
21392
+ const requestPaymentCheck = (confirmation) => async (request) => "kind" in request && request.kind === "payment_request" && canonicalJson(request.confirmation) === canonicalJson(confirmation);
21368
21393
  function executePaymentLifecycle(deps, intent, signal, controls, expectedOrganizationId, onPrepared) {
21369
21394
  return executePrepared(deps, (signerAddress) => runIfActive(signal, CAPXUL_OPERATIONS.payments.prepareLifecycleExecution, () => withInvocationParentSpan(Effect.suspend(() => callOperation(deps.convexCall, lifecycles.prepareScoped, copyInvocationObservation(controls, {
21370
21395
  signerAddress,
@@ -21373,13 +21398,13 @@ function executePaymentLifecycle(deps, intent, signal, controls, expectedOrganiz
21373
21398
  kind: "organization",
21374
21399
  orgId: expectedOrganizationId
21375
21400
  }
21376
- })).pipe(Effect.mapError((publicError) => ({ publicError })))), controls), deps.runPromise), async (request, evidence) => await matchesIntent(intent)(request, evidence) && (intent.kind !== "retry" || (expectedOrganizationId === void 0 ? evidence.sourceCommand?.kind === "birth" && evidence.sourceCommand.actor.kind === "account" : evidence.sourceCommand?.kind === "birth" && evidence.sourceCommand.actor.kind === "organization" && evidence.sourceCommand.actor.orgId === expectedOrganizationId)), false, void 0, signal, controls, onPrepared);
21401
+ })).pipe(Effect.mapError((publicError) => ({ publicError })))), controls), deps.runPromise), lifecycleCommandCheck(intent, expectedOrganizationId), false, void 0, signal, controls, onPrepared);
21377
21402
  }
21378
21403
  function executeRequestPayment(deps, confirmation, controls, onPrepared) {
21379
21404
  return executePrepared(deps, (signerAddress) => runIfActive(controls?.signal, commands$1.prepareRequest.name, () => withInvocationParentSpan(Effect.suspend(() => callOperation(deps.convexCall, commands$1.prepareRequest, copyInvocationObservation(controls, {
21380
21405
  confirmation,
21381
21406
  signerAddress
21382
- })).pipe(Effect.mapError((publicError) => ({ publicError })))), controls), deps.runPromise), async (request) => "kind" in request && request.kind === "payment_request" && canonicalJson(request.confirmation) === canonicalJson(confirmation), false, void 0, controls?.signal, controls, onPrepared);
21407
+ })).pipe(Effect.mapError((publicError) => ({ publicError })))), controls), deps.runPromise), requestPaymentCheck(confirmation), false, void 0, controls?.signal, controls, onPrepared);
21383
21408
  }
21384
21409
  function executeOrganizationPayment(deps, input, signal, onPreparedClosed, controls, onPrepared) {
21385
21410
  return executePrepared(deps, (signerAddress) => runIfActive(signal, CAPXUL_OPERATIONS.organizationPayments.prepareExecution, () => withInvocationParentSpan(Effect.suspend(() => callOperation(deps.convexCall, commands$1.prepareOrganization, copyInvocationObservation(controls, {
@@ -23859,6 +23884,524 @@ function sleep(ms, signal) {
23859
23884
  });
23860
23885
  }
23861
23886
  //#endregion
23887
+ //#region ../../packages/protocol/src/payroll/model.ts
23888
+ function toPayrollRunId(raw) {
23889
+ return toNonEmptyStringBrand(raw, "payrollRunId", (value) => isNonEmptyString(value));
23890
+ }
23891
+ function toPayrollGroupId(raw) {
23892
+ return toNonEmptyStringBrand(raw, "payrollGroupId", (value) => isNonEmptyString(value));
23893
+ }
23894
+ //#endregion
23895
+ //#region ../../packages/sdk/src/payroll/run-checks.ts
23896
+ /** Match the caller's compensation to the committed V3 Payslip. */
23897
+ function payslipIdentityMatches(message, item, index, runId, period) {
23898
+ return message.runId === runId && message.itemIndex === index && message.employeeRef === item.partyId && message.periodStart === period.start && message.periodEnd === period.end && message.adjustmentsHash === hashAdjustmentsV3(item.adjustments);
23899
+ }
23900
+ function payslipAmountMatches(message, item) {
23901
+ const exact = toExactAssetAmount(item.amount, CONFIGURED_MONEY_ASSETS);
23902
+ return message.gross.asset === exact.asset && message.gross.minorUnits === item.gross && message.gross.decimals === exact.decimals && message.net.asset === exact.asset && message.net.minorUnits === item.net && message.net.decimals === exact.decimals;
23903
+ }
23904
+ function isRunItem(prepared, item, evidence, index, runId, period) {
23905
+ if (prepared === void 0) return false;
23906
+ const bundle = evidence.preparedCommand?.documentBundles?.[index];
23907
+ const preparedItem = evidence.preparedCommand?.items[index];
23908
+ const payslip = bundle?.envelope;
23909
+ if (bundle === void 0 || payslip?.primaryType !== "Payslip") return false;
23910
+ return canonicalJson(prepared.to) === canonicalJson(item.to) && prepared.paymentType === "payroll" && canonicalJson(prepared.amount) === canonicalJson(item.amount) && bundle.adjustments !== void 0 && canonicalJson(bundle.adjustments) === canonicalJson(item.adjustments) && payslipIdentityMatches(payslip.message, item, index, runId, period) && payslipAmountMatches(payslip.message, item) && (preparedItem?.operation === "send" || preparedItem?.operation === "create_commitment") && preparedItem.documentHash === evidence.preparedCommand?.instructionDocuments?.[index]?.documentHash;
23911
+ }
23912
+ /**
23913
+ * The batch the backend derived from a payroll intent must be the batch this
23914
+ * caller asked for, checked before the digest is signed.
23915
+ *
23916
+ * The payslip envelope on each item is server-built and carries the run row's
23917
+ * own `issuedAt`, so the batch cannot be fingerprinted against a local copy
23918
+ * (`matchesIntent` is unavailable here). What CAN be verified is every field
23919
+ * the caller supplied — the org, the Budget, the request key, and per item the
23920
+ * recipient, the amount and the payslip figures — plus the lineage binding the
23921
+ * batch to the run just written. A prepared command that pays a different
23922
+ * person, a different amount, from a different Budget, or under a different
23923
+ * run never reaches the signer.
23924
+ */
23925
+ function isRunBatch(input) {
23926
+ return (batch, evidence) => Promise.resolve(!("kind" in batch) && batch.orgId === input.orgId && batch.permissionId === input.permissionId && batch.requestKey === input.requestKey && batch.lineage?.kind === "payroll" && batch.lineage.runId === input.runId && batch.items.length === input.items.length && batch.items.every((item) => item.amount.asset === input.asset) && input.items.every((item, index) => isRunItem(batch.items[index], item, evidence, index, input.runId, input.period)));
23927
+ }
23928
+ /**
23929
+ * The batch is `isRunBatch` for the run the backend just wrote, and that run
23930
+ * is the period the caller asked for: the payslip's `period` is a
23931
+ * server-formatted label, so the stored run is where the caller's own two
23932
+ * numbers are checkable.
23933
+ */
23934
+ function isAuthorizedRunBatch(input, run) {
23935
+ return (request, evidence) => run === void 0 || run.periodStart !== input.period.start || run.periodEnd !== input.period.end ? Promise.resolve(false) : isRunBatch({
23936
+ ...input,
23937
+ runId: run.id
23938
+ })(request, evidence);
23939
+ }
23940
+ /** A decoded detail is the run asked for, whole: its scope, membership and quantities agree. */
23941
+ function checkPayrollRunDetail(value, orgId, runId) {
23942
+ if (value === null) return {
23943
+ ok: true,
23944
+ value: null
23945
+ };
23946
+ if (value.orgId !== orgId || value.run.id !== runId || value.items.length === 0 || value.items.length !== value.run.recipientCount || new Set(value.items.map((item) => item.payment.id)).size !== value.items.length || value.items.some((item, index) => item.itemIndex !== index || item.amount.asset !== value.run.total.asset || item.payment.amount.asset !== item.amount.asset || item.payment.paymentType !== "payroll")) return {
23947
+ ok: false,
23948
+ error: Errors.invalidInput("run", "Payroll run scope or membership does not match")
23949
+ };
23950
+ try {
23951
+ const total = toExactAssetAmount(value.run.total, CONFIGURED_MONEY_ASSETS);
23952
+ let rawTotal = 0n;
23953
+ for (const item of value.items) {
23954
+ const amount = toExactAssetAmount(item.amount, CONFIGURED_MONEY_ASSETS);
23955
+ const payment = toExactAssetAmount(item.payment.amount, CONFIGURED_MONEY_ASSETS);
23956
+ if (amount.minorUnits !== payment.minorUnits) return {
23957
+ ok: false,
23958
+ error: Errors.invalidInput("run", "Payroll item quantity does not match its Payment")
23959
+ };
23960
+ rawTotal += BigInt(amount.minorUnits);
23961
+ }
23962
+ if (rawTotal !== BigInt(total.minorUnits)) return {
23963
+ ok: false,
23964
+ error: Errors.invalidInput("run", "Payroll run total does not match its items")
23965
+ };
23966
+ } catch {
23967
+ return {
23968
+ ok: false,
23969
+ error: Errors.invalidInput("run", "Payroll run quantities are invalid")
23970
+ };
23971
+ }
23972
+ return {
23973
+ ok: true,
23974
+ value
23975
+ };
23976
+ }
23977
+ //#endregion
23978
+ //#region ../../packages/sdk/src/payroll/run-decoding.ts
23979
+ function toPayrollRun(wire) {
23980
+ return {
23981
+ id: toPayrollRunId(wire.id),
23982
+ status: wire.status,
23983
+ periodStart: wire.periodStart,
23984
+ periodEnd: wire.periodEnd,
23985
+ total: wire.total,
23986
+ recipientCount: wire.recipientCount
23987
+ };
23988
+ }
23989
+ function toPayrollRuns(wire) {
23990
+ return {
23991
+ ...mapPage(wire, toPayrollRun),
23992
+ settledThisMonth: wire.settledThisMonth
23993
+ };
23994
+ }
23995
+ function toPayrollGroup(wire) {
23996
+ return {
23997
+ id: toPayrollGroupId(wire.id),
23998
+ name: wire.name,
23999
+ tone: wire.tone,
24000
+ members: wire.members.map((member) => ({
24001
+ partyId: member.partyId,
24002
+ amount: member.amount,
24003
+ currency: member.currency
24004
+ }))
24005
+ };
24006
+ }
24007
+ function validateRunItems(input) {
24008
+ for (const [index, item] of input.items.entries()) {
24009
+ if (Schema.decodeResult(PayrollRunItemInputSchema, { onExcessProperty: "error" })(item)._tag === "Failure") return Errors.invalidInput(`items.${index}`, "invalid Payroll item");
24010
+ try {
24011
+ const exact = toExactAssetAmount(item.amount, CONFIGURED_MONEY_ASSETS);
24012
+ const net = BigInt(item.net);
24013
+ const gross = BigInt(item.gross);
24014
+ const adjustments = item.adjustments.reduce((sum, row) => sum + BigInt(row.amount), 0n);
24015
+ if (item.amount.asset !== input.asset || item.net !== exact.minorUnits || gross + adjustments !== net) return Errors.invalidInput(`items.${index}`, "invalid Payroll units");
24016
+ } catch {
24017
+ return Errors.invalidInput(`items.${index}`, "invalid Payroll units");
24018
+ }
24019
+ }
24020
+ return null;
24021
+ }
24022
+ const RunInputSchema = Schema.Struct({
24023
+ permissionId: AuthorizePayrollRunExecutionInputSchema.fields.permissionId,
24024
+ asset: AuthorizePayrollRunExecutionInputSchema.fields.asset,
24025
+ period: AuthorizePayrollRunExecutionInputSchema.fields.period,
24026
+ items: AuthorizePayrollRunExecutionInputSchema.fields.items,
24027
+ requestKey: Schema.optional(AuthorizePayrollRunExecutionInputSchema.fields.requestKey)
24028
+ });
24029
+ /** Decode caller input before session or signer work. Keep routing outside the input. */
24030
+ function decodePayrollRunInput(value) {
24031
+ try {
24032
+ const decoded = Schema.decodeUnknownSync(RunInputSchema, { onExcessProperty: "error" })(value);
24033
+ const input = {
24034
+ permissionId: decoded.permissionId,
24035
+ asset: decoded.asset,
24036
+ period: decoded.period,
24037
+ ...decoded.requestKey === void 0 ? {} : { requestKey: decoded.requestKey },
24038
+ items: decoded.items.map((item) => ({
24039
+ amount: item.amount,
24040
+ gross: item.gross,
24041
+ net: item.net,
24042
+ adjustments: item.adjustments,
24043
+ partyId: toPartyId(item.partyId),
24044
+ to: item.to.kind === "party" ? {
24045
+ kind: "party",
24046
+ partyId: toPartyId(item.to.partyId)
24047
+ } : item.to.kind === "address" ? {
24048
+ kind: "address",
24049
+ address: toAddress(item.to.address)
24050
+ } : item.to
24051
+ }))
24052
+ };
24053
+ if (input.items.length === 0 || input.period.start > input.period.end) throw Errors.invalidInput("input", "Payroll requires items and an ordered period");
24054
+ const error = validateRunItems(input);
24055
+ if (error !== null) throw error;
24056
+ return input;
24057
+ } catch (cause) {
24058
+ throw cause instanceof CapxulError ? cause : Errors.invalidInput("input", "Invalid Payroll input");
24059
+ }
24060
+ }
24061
+ /** Read only the exact backend prepare receipt, never an arbitrary signer failure. */
24062
+ function payrollResolution(error, requestKey) {
24063
+ const details = error.details;
24064
+ if (error.code !== "WRONG_STATE" || details?.method !== runs.authorize.name || details.requestKey !== requestKey || typeof details.commandId !== "string" || typeof details.runId !== "string") return void 0;
24065
+ return details.payrollResolution === "failed" || details.payrollResolution === "settled" ? details.payrollResolution : void 0;
24066
+ }
24067
+ function validatePayrollRunLookup(orgId, runId) {
24068
+ return !Schema.is(PayrollRunIdSchema)(runId) || orgId.length === 0 ? {
24069
+ ok: false,
24070
+ error: Errors.invalidInput("runId", "Organization and run ID must be valid")
24071
+ } : {
24072
+ ok: true,
24073
+ value: void 0
24074
+ };
24075
+ }
24076
+ /** Strict saved detail decoder shared by the read and fresh stream. */
24077
+ function decodePayrollRunDetail(raw, orgId, runId) {
24078
+ const decoded = Schema.decodeUnknownResult(Schema.NullOr(PayrollRunDetailSchema), { onExcessProperty: "error" })(raw);
24079
+ if (decoded._tag === "Failure") return {
24080
+ ok: false,
24081
+ error: Errors.invalidInput("run", "Invalid Payroll run detail")
24082
+ };
24083
+ return checkPayrollRunDetail(decoded.success, orgId, runId);
24084
+ }
24085
+ //#endregion
24086
+ //#region ../../packages/sdk/src/payroll/run-subscription.ts
24087
+ function detailValue(result) {
24088
+ if (!result.ok) throw result.error;
24089
+ return result.value;
24090
+ }
24091
+ function subscribePayrollRun(deps, orgId, runId, listener, options) {
24092
+ const operation = CAPXUL_OPERATIONS.org.payroll.subscribeRun;
24093
+ const valid = deps.validate(orgId, runId);
24094
+ if (!valid.ok) return runCapxulEffect(Effect.fail(valid.error), observationOnlyControls(deps.invocationControls?.(options) ?? options), operation, deps.runPromise);
24095
+ const decode = (raw) => detailValue(deps.decode(raw, orgId, runId));
24096
+ return subscribeFreshQuery(deps, {
24097
+ orgId,
24098
+ runId
24099
+ }, listener, operation, {
24100
+ decode,
24101
+ validateCached: (raw) => {
24102
+ decode(raw);
24103
+ },
24104
+ invalidValue: (cause) => isCapxulError(cause) ? cause : Errors.invalidInput("run", "Invalid Payroll run detail"),
24105
+ invalidScope: () => Errors.invalidInput("run", "Payroll run subscription scope does not match"),
24106
+ lostValue: () => Errors.invalidInput("run", "Payroll run is no longer readable"),
24107
+ unavailable: () => Errors.notImplemented("payroll", "subscribeRun")
24108
+ }, options);
24109
+ }
24110
+ //#endregion
24111
+ //#region ../../packages/sdk/src/payroll/run-authorization.ts
24112
+ /**
24113
+ * Authorize one payroll run: a stable request key, the prepared batch checked
24114
+ * against the run the caller asked for, the signature, and the submission.
24115
+ */
24116
+ async function authorizePayrollRun(scope, input, controls, onRequestKey, onResolved) {
24117
+ const { deps, orgId, requestKeyScope } = scope;
24118
+ const signal = controls?.signal;
24119
+ const execution = executionDependencies(deps);
24120
+ if (execution === null) return {
24121
+ ok: false,
24122
+ error: Errors.notImplemented("payroll", "executionComposition")
24123
+ };
24124
+ try {
24125
+ input = decodePayrollRunInput(input);
24126
+ } catch (cause) {
24127
+ return {
24128
+ ok: false,
24129
+ error: asCapxulError(cause)
24130
+ };
24131
+ }
24132
+ const { requestKey: provided, ...canonicalInput } = input;
24133
+ const actorId = onRequestKey === void 0 ? void 0 : execution.actor.authSession()?.authUserId;
24134
+ if (onRequestKey !== void 0 && actorId === void 0) return {
24135
+ ok: false,
24136
+ error: Errors.notAuthenticated()
24137
+ };
24138
+ const requestKey = await paymentRequestKeyLifecycle(`${requestKeyScope}:${AUTHORIZE_RUN}`, onRequestKey === void 0 ? {
24139
+ orgId,
24140
+ input
24141
+ } : {
24142
+ actorId,
24143
+ orgId,
24144
+ input: canonicalInput
24145
+ }, provided, onRequestKey === void 0 ? void 0 : { manageProvidedKey: true });
24146
+ try {
24147
+ await onRequestKey?.(requestKey.key);
24148
+ if (onRequestKey !== void 0 && execution.actor.authSession()?.authUserId !== actorId) {
24149
+ await requestKey.finish(false).catch(() => void 0);
24150
+ return {
24151
+ ok: false,
24152
+ error: Errors.notAuthenticated()
24153
+ };
24154
+ }
24155
+ } catch (cause) {
24156
+ await requestKey.finish(false).catch(() => void 0);
24157
+ return {
24158
+ ok: false,
24159
+ error: asCapxulError(cause)
24160
+ };
24161
+ }
24162
+ let authorized;
24163
+ let acceptedReplay;
24164
+ let preparedClosed = false;
24165
+ let terminalReplay;
24166
+ const submitted = await executePrepared(execution, async (signerAddress) => {
24167
+ const prepared = await runIfActive(signal, AUTHORIZE_RUN, () => withInvocationParentSpan(Effect.suspend(() => callOperation(deps.convexCall, runs.authorize, copyInvocationObservation(controls, {
24168
+ orgId,
24169
+ permissionId: input.permissionId,
24170
+ asset: input.asset,
24171
+ requestKey: requestKey.key,
24172
+ signerAddress,
24173
+ period: input.period,
24174
+ items: input.items
24175
+ }))).pipe(Effect.mapError((publicError) => ({ publicError }))), controls), deps.runPromise);
24176
+ if (!prepared.ok) {
24177
+ terminalReplay = payrollResolution(prepared.error, requestKey.key);
24178
+ return prepared;
24179
+ }
24180
+ authorized = prepared.value.run;
24181
+ acceptedReplay = prepared.value.replay.kind === "accepted" ? prepared.value.replay.submission : void 0;
24182
+ return {
24183
+ ok: true,
24184
+ value: prepared.value.execution
24185
+ };
24186
+ }, (request, evidence) => isAuthorizedRunBatch({
24187
+ orgId,
24188
+ permissionId: input.permissionId,
24189
+ requestKey: requestKey.key,
24190
+ asset: input.asset,
24191
+ period: input.period,
24192
+ items: input.items
24193
+ }, authorized)(request, evidence), true, () => preparedClosed = true, signal, controls, void 0, () => acceptedReplay);
24194
+ const resolution = preparedClosed ? "failed" : terminalReplay;
24195
+ if (resolution !== void 0) try {
24196
+ await onResolved?.(resolution);
24197
+ } catch {}
24198
+ try {
24199
+ await requestKey.finish(submitted.ok || resolution !== void 0);
24200
+ } catch {}
24201
+ if (!submitted.ok) return submitted;
24202
+ return authorized === void 0 ? {
24203
+ ok: false,
24204
+ error: Errors.unknown()
24205
+ } : {
24206
+ ok: true,
24207
+ value: toPayrollRun(authorized)
24208
+ };
24209
+ }
24210
+ const AUTHORIZE_RUN = runs.authorize.name;
24211
+ function executionDependencies(deps) {
24212
+ return deps.actor === void 0 || deps.chainId === void 0 || deps.signer === void 0 ? null : {
24213
+ actor: deps.actor,
24214
+ chainId: deps.chainId,
24215
+ convexCall: deps.convexCall,
24216
+ runPromise: deps.runPromise,
24217
+ signer: deps.signer,
24218
+ ...deps.telemetry === void 0 ? {} : { telemetry: deps.telemetry }
24219
+ };
24220
+ }
24221
+ //#endregion
24222
+ //#region ../../packages/sdk/src/payroll/runs.ts
24223
+ function makePayrollMethods(deps, orgId) {
24224
+ const requestKeyScope = deps.requestKeyScope ?? `client-${crypto.randomUUID()}`;
24225
+ /** One observed call of one payroll row, its reply projected inside the call, under the row's name. */
24226
+ const call = (row, args, options, project) => {
24227
+ const controls = deps.invocationControls?.(options) ?? options;
24228
+ return runPortEffect(callOperation(deps.convexCall, row, copyInvocationObservation(controls, args)).pipe(Effect.map(project), Effect.mapError((publicError) => ({ publicError }))), controls, row.name, deps.runPromise);
24229
+ };
24230
+ return {
24231
+ subscribeRun: (runId, listener, options) => subscribePayrollRun({
24232
+ actor: deps.actor,
24233
+ convexCall: deps.convexCall,
24234
+ query: reference(runs.get),
24235
+ runPromise: deps.runPromise,
24236
+ invocationControls: deps.invocationControls,
24237
+ decode: decodePayrollRunDetail,
24238
+ validate: validatePayrollRunLookup
24239
+ }, orgId, runId, listener, options),
24240
+ getRun: (runId, options) => {
24241
+ const controls = deps.invocationControls?.(options) ?? options;
24242
+ const lifetime = deps.actor?.authLifetime();
24243
+ const operation = runs.get.name;
24244
+ return runCapxulEffect(Effect.gen(function* () {
24245
+ const lookup = validatePayrollRunLookup(orgId, runId);
24246
+ if (!lookup.ok) return yield* Effect.fail(lookup.error);
24247
+ if (lifetime === void 0 || lifetime.authUserId === null || deps.actor === void 0) return yield* Effect.fail(Errors.notAuthenticated());
24248
+ const current = () => deps.actor?.matchesAuthLifetime(lifetime, lifetime.authUserId) === true;
24249
+ if (!current()) return yield* Effect.fail(Errors.notAuthenticated());
24250
+ const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
24251
+ const captured = carryInvocationParentSpan(controls, parent);
24252
+ const run = yield* awaitCapxulResult(() => runIfActive(controls?.signal, operation, () => withInvocationParentSpan(Effect.suspend(() => callOperation(deps.convexCall, runs.get, copyInvocationObservation(captured, {
24253
+ orgId,
24254
+ runId
24255
+ }))).pipe(Effect.mapError((publicError) => ({ publicError }))), captured), deps.runPromise));
24256
+ if (!current()) return yield* Effect.fail(Errors.cancelled({ operation }));
24257
+ const checked = checkPayrollRunDetail(run, orgId, runId);
24258
+ return yield* checked.ok ? Effect.succeed(checked.value) : Effect.fail(checked.error);
24259
+ }), observationOnlyControls(controls), operation, deps.runPromise);
24260
+ },
24261
+ runs: (options) => call(runs.list, { orgId }, options, toPayrollRuns),
24262
+ authorizeRun: (input, options) => {
24263
+ const controls = deps.invocationControls?.(options) ?? options;
24264
+ return runCapxulEffect(Effect.gen(function* () {
24265
+ if (controls?.signal?.aborted === true) return yield* Effect.fail(Errors.cancelled({ operation: AUTHORIZE_RUN }));
24266
+ const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
24267
+ return yield* awaitCapxulResult(() => authorizePayrollRun({
24268
+ deps,
24269
+ orgId,
24270
+ requestKeyScope
24271
+ }, input, carryInvocationParentSpan(controls, parent), options?.onRequestKey, options?.onResolved));
24272
+ }), observationOnlyControls(controls), AUTHORIZE_RUN, deps.runPromise);
24273
+ },
24274
+ terms: (options) => call(terms.list, { orgId }, options, (rates) => rates),
24275
+ groups: {
24276
+ list: (options) => call(groups.list, { orgId }, options, (saved) => mapPage(saved, toPayrollGroup)),
24277
+ save: (input, options) => call(groups.save, {
24278
+ orgId,
24279
+ ...input.id === void 0 ? {} : { id: String(input.id) },
24280
+ name: input.name,
24281
+ tone: input.tone,
24282
+ members: input.members
24283
+ }, options, toPayrollGroup),
24284
+ remove: (id, options) => call(groups.remove, {
24285
+ orgId,
24286
+ id
24287
+ }, options, () => void 0)
24288
+ }
24289
+ };
24290
+ }
24291
+ const payrollUnavailable = () => Promise.resolve({
24292
+ ok: false,
24293
+ error: Errors.notImplemented("payroll", "executionComposition")
24294
+ });
24295
+ /** The bundle an unconfigured client exposes — every verb refuses, none throws. */
24296
+ function makeUnavailablePayrollMethods() {
24297
+ return {
24298
+ getRun: payrollUnavailable,
24299
+ subscribeRun: payrollUnavailable,
24300
+ runs: payrollUnavailable,
24301
+ authorizeRun: payrollUnavailable,
24302
+ terms: payrollUnavailable,
24303
+ groups: {
24304
+ list: payrollUnavailable,
24305
+ save: payrollUnavailable,
24306
+ remove: payrollUnavailable
24307
+ }
24308
+ };
24309
+ }
24310
+ //#endregion
24311
+ //#region ../../packages/sdk/src/accounts/command-approvals.ts
24312
+ /**
24313
+ * Keep a prepared command only when it is the one asked for and its operation
24314
+ * is the person's own. A mismatch is closed unsent when `close`, as the signed
24315
+ * path closes a new Payment; a retry or a request keeps its Payment open.
24316
+ */
24317
+ async function checked(deps, signerAddress, prepared, expected, close) {
24318
+ if (!prepared.ok) return prepared;
24319
+ const session = deps.actor?.authSession() ?? null;
24320
+ if (session === null || deps.chainId === void 0) return {
24321
+ ok: false,
24322
+ error: Errors.notAuthenticated()
24323
+ };
24324
+ const evidence = prepared.value;
24325
+ if (await expected(evidence.request, evidence) && await verifiedPreparedCommand(evidence, session.email, signerAddress, deps.chainId)) return prepared;
24326
+ const refused = {
24327
+ ok: false,
24328
+ error: Errors.invalidInput("execution", "prepared command mismatch")
24329
+ };
24330
+ return close ? abandonPrepared(deps, evidence.executionId, "prepared_mismatch", refused) : refused;
24331
+ }
24332
+ /** A retry, a request payment or a payroll run, rather than a new Payment. */
24333
+ const isCommandApproval = (input) => "retry" in input || "request" in input || "payrollRun" in input;
24334
+ /** Prepare a retry, a request payment or a payroll run for `signerAddress`, checked. */
24335
+ function prepareVerifiedCommand(deps, input, signerAddress, signal) {
24336
+ if ("retry" in input) return prepareVerifiedRetry(deps, input, signerAddress, signal);
24337
+ if ("request" in input) return prepareVerifiedRequestPayment(deps, input, signerAddress, signal);
24338
+ return prepareVerifiedPayrollRun(deps, input, signerAddress, signal);
24339
+ }
24340
+ /** The retry of one Payment, prepared in the scope that paid it. */
24341
+ async function prepareVerifiedRetry(deps, input, signerAddress, signal) {
24342
+ const intent = {
24343
+ kind: "retry",
24344
+ paymentId: input.retry
24345
+ };
24346
+ return checked(deps, signerAddress, await runIfActive(signal, CAPXUL_OPERATIONS.payments.prepareLifecycleExecution, () => callOperation(deps.convexCall, lifecycles.prepareScoped, {
24347
+ signerAddress,
24348
+ intent,
24349
+ expectedScope: input.organizationId === void 0 ? { kind: "account" } : {
24350
+ kind: "organization",
24351
+ orgId: input.organizationId
24352
+ }
24353
+ }).pipe(Effect.mapError((publicError) => ({ publicError }))), deps.runPromise), lifecycleCommandCheck(intent, input.organizationId), false);
24354
+ }
24355
+ /** The Payment of one request, exactly as the request froze it. */
24356
+ async function prepareVerifiedRequestPayment(deps, input, signerAddress, signal) {
24357
+ const decoded = Schema.decodeResult(RequestPaymentConfirmationSchema, { onExcessProperty: "error" })(input.request);
24358
+ if (decoded._tag === "Failure") return {
24359
+ ok: false,
24360
+ error: Errors.invalidInput("confirmation", "invalid request confirmation")
24361
+ };
24362
+ const confirmation = decoded.success;
24363
+ return checked(deps, signerAddress, await runIfActive(signal, commands$1.prepareRequest.name, () => callOperation(deps.convexCall, commands$1.prepareRequest, {
24364
+ confirmation,
24365
+ signerAddress
24366
+ }).pipe(Effect.mapError((publicError) => ({ publicError }))), deps.runPromise), requestPaymentCheck(confirmation), false);
24367
+ }
24368
+ /** One payroll run: the run the backend writes and the batch that pays it, checked together. */
24369
+ async function prepareVerifiedPayrollRun(deps, input, signerAddress, signal) {
24370
+ let run;
24371
+ try {
24372
+ run = decodePayrollRunInput(input.payrollRun);
24373
+ } catch (cause) {
24374
+ return {
24375
+ ok: false,
24376
+ error: asCapxulError(cause)
24377
+ };
24378
+ }
24379
+ const orgId = input.organizationId;
24380
+ const requestKey = run.requestKey ?? `payroll_${crypto.randomUUID()}`;
24381
+ const { permissionId, asset, period, items } = run;
24382
+ const authorized = await runIfActive(signal, runs.authorize.name, () => callOperation(deps.convexCall, runs.authorize, {
24383
+ orgId,
24384
+ permissionId,
24385
+ asset,
24386
+ requestKey,
24387
+ signerAddress,
24388
+ period,
24389
+ items
24390
+ }).pipe(Effect.mapError((publicError) => ({ publicError }))), deps.runPromise);
24391
+ if (!authorized.ok) return authorized;
24392
+ return checked(deps, signerAddress, {
24393
+ ok: true,
24394
+ value: authorized.value.execution
24395
+ }, isAuthorizedRunBatch({
24396
+ orgId,
24397
+ permissionId,
24398
+ requestKey,
24399
+ asset,
24400
+ period,
24401
+ items
24402
+ }, authorized.value.run), authorized.value.replay.kind !== "accepted");
24403
+ }
24404
+ //#endregion
23862
24405
  //#region ../../packages/sdk/src/accounts/organization-approvals.ts
23863
24406
  /** The Organization Payment prepared for `signerAddress` and checked, before any approval. */
23864
24407
  async function prepareVerifiedOrganizationPayment(deps, input, signerAddress, signal) {
@@ -23965,6 +24508,7 @@ function makeApprovalsMethods(deps) {
23965
24508
  };
23966
24509
  const prepare = async (input, options) => {
23967
24510
  const signal = options?.signal;
24511
+ if (isCommandApproval(input)) return openApproval(signal, (signerAddress) => prepareVerifiedCommand(deps, input, signerAddress, signal));
23968
24512
  if ("organizationId" in input) return openApproval(signal, (signerAddress) => prepareVerifiedOrganizationPayment(deps, input, signerAddress, signal));
23969
24513
  const intent = paymentExecutionIntent(input);
23970
24514
  if (!intent.ok) return intent;
@@ -24057,7 +24601,7 @@ function makeApprovalsMethods(deps) {
24057
24601
  ok: true,
24058
24602
  value: null
24059
24603
  };
24060
- const payments = await readApprovalPayments(deps, approval.operation.paymentIds, organizationId, signal);
24604
+ const payments = await readApprovalPayments(deps, approval.operation.paymentIds, organizationId ?? (approval.actor.kind === "organization" ? approval.actor.orgId : void 0), signal);
24061
24605
  if (!payments.ok) return payments;
24062
24606
  if (unsent(approval, payments.value)) {
24063
24607
  const sent = await submit(approvalId);
@@ -26894,14 +27438,6 @@ function executeIdentityProductObservation(telemetry, record, state) {
26894
27438
  return ignoreTransportFailure(() => invocationTelemetry.emit(mapped), "emit", mapped.name).pipe(Effect.andThen(ignoreTransportFailure(after, mapped.name === "auth_signed_out" ? "reset" : "identify", mapped.name)));
26895
27439
  }
26896
27440
  //#endregion
26897
- //#region ../../packages/protocol/src/payroll/model.ts
26898
- function toPayrollRunId(raw) {
26899
- return toNonEmptyStringBrand(raw, "payrollRunId", (value) => isNonEmptyString(value));
26900
- }
26901
- function toPayrollGroupId(raw) {
26902
- return toNonEmptyStringBrand(raw, "payrollGroupId", (value) => isNonEmptyString(value));
26903
- }
26904
- //#endregion
26905
27441
  //#region ../../packages/sdk/src/permissions/command-decoding.ts
26906
27442
  /** The caller's input as a command: ids branded and the intent decoded, or invalid input thrown. */
26907
27443
  const buildCommand = {
@@ -38042,411 +38578,6 @@ function makePermissionMethods(deps, orgId) {
38042
38578
  };
38043
38579
  }
38044
38580
  //#endregion
38045
- //#region ../../packages/sdk/src/payroll/run-checks.ts
38046
- /** Match the caller's compensation to the committed V3 Payslip. */
38047
- function payslipIdentityMatches(message, item, index, runId, period) {
38048
- return message.runId === runId && message.itemIndex === index && message.employeeRef === item.partyId && message.periodStart === period.start && message.periodEnd === period.end && message.adjustmentsHash === hashAdjustmentsV3(item.adjustments);
38049
- }
38050
- function payslipAmountMatches(message, item) {
38051
- const exact = toExactAssetAmount(item.amount, CONFIGURED_MONEY_ASSETS);
38052
- return message.gross.asset === exact.asset && message.gross.minorUnits === item.gross && message.gross.decimals === exact.decimals && message.net.asset === exact.asset && message.net.minorUnits === item.net && message.net.decimals === exact.decimals;
38053
- }
38054
- function isRunItem(prepared, item, evidence, index, runId, period) {
38055
- if (prepared === void 0) return false;
38056
- const bundle = evidence.preparedCommand?.documentBundles?.[index];
38057
- const preparedItem = evidence.preparedCommand?.items[index];
38058
- const payslip = bundle?.envelope;
38059
- if (bundle === void 0 || payslip?.primaryType !== "Payslip") return false;
38060
- return canonicalJson(prepared.to) === canonicalJson(item.to) && prepared.paymentType === "payroll" && canonicalJson(prepared.amount) === canonicalJson(item.amount) && bundle.adjustments !== void 0 && canonicalJson(bundle.adjustments) === canonicalJson(item.adjustments) && payslipIdentityMatches(payslip.message, item, index, runId, period) && payslipAmountMatches(payslip.message, item) && (preparedItem?.operation === "send" || preparedItem?.operation === "create_commitment") && preparedItem.documentHash === evidence.preparedCommand?.instructionDocuments?.[index]?.documentHash;
38061
- }
38062
- /**
38063
- * The batch the backend derived from a payroll intent must be the batch this
38064
- * caller asked for, checked before the digest is signed.
38065
- *
38066
- * The payslip envelope on each item is server-built and carries the run row's
38067
- * own `issuedAt`, so the batch cannot be fingerprinted against a local copy
38068
- * (`matchesIntent` is unavailable here). What CAN be verified is every field
38069
- * the caller supplied — the org, the Budget, the request key, and per item the
38070
- * recipient, the amount and the payslip figures — plus the lineage binding the
38071
- * batch to the run just written. A prepared command that pays a different
38072
- * person, a different amount, from a different Budget, or under a different
38073
- * run never reaches the signer.
38074
- */
38075
- function isRunBatch(input) {
38076
- return (batch, evidence) => Promise.resolve(!("kind" in batch) && batch.orgId === input.orgId && batch.permissionId === input.permissionId && batch.requestKey === input.requestKey && batch.lineage?.kind === "payroll" && batch.lineage.runId === input.runId && batch.items.length === input.items.length && batch.items.every((item) => item.amount.asset === input.asset) && input.items.every((item, index) => isRunItem(batch.items[index], item, evidence, index, input.runId, input.period)));
38077
- }
38078
- /** A decoded detail is the run asked for, whole: its scope, membership and quantities agree. */
38079
- function checkPayrollRunDetail(value, orgId, runId) {
38080
- if (value === null) return {
38081
- ok: true,
38082
- value: null
38083
- };
38084
- if (value.orgId !== orgId || value.run.id !== runId || value.items.length === 0 || value.items.length !== value.run.recipientCount || new Set(value.items.map((item) => item.payment.id)).size !== value.items.length || value.items.some((item, index) => item.itemIndex !== index || item.amount.asset !== value.run.total.asset || item.payment.amount.asset !== item.amount.asset || item.payment.paymentType !== "payroll")) return {
38085
- ok: false,
38086
- error: Errors.invalidInput("run", "Payroll run scope or membership does not match")
38087
- };
38088
- try {
38089
- const total = toExactAssetAmount(value.run.total, CONFIGURED_MONEY_ASSETS);
38090
- let rawTotal = 0n;
38091
- for (const item of value.items) {
38092
- const amount = toExactAssetAmount(item.amount, CONFIGURED_MONEY_ASSETS);
38093
- const payment = toExactAssetAmount(item.payment.amount, CONFIGURED_MONEY_ASSETS);
38094
- if (amount.minorUnits !== payment.minorUnits) return {
38095
- ok: false,
38096
- error: Errors.invalidInput("run", "Payroll item quantity does not match its Payment")
38097
- };
38098
- rawTotal += BigInt(amount.minorUnits);
38099
- }
38100
- if (rawTotal !== BigInt(total.minorUnits)) return {
38101
- ok: false,
38102
- error: Errors.invalidInput("run", "Payroll run total does not match its items")
38103
- };
38104
- } catch {
38105
- return {
38106
- ok: false,
38107
- error: Errors.invalidInput("run", "Payroll run quantities are invalid")
38108
- };
38109
- }
38110
- return {
38111
- ok: true,
38112
- value
38113
- };
38114
- }
38115
- //#endregion
38116
- //#region ../../packages/sdk/src/payroll/run-decoding.ts
38117
- function toPayrollRun(wire) {
38118
- return {
38119
- id: toPayrollRunId(wire.id),
38120
- status: wire.status,
38121
- periodStart: wire.periodStart,
38122
- periodEnd: wire.periodEnd,
38123
- total: wire.total,
38124
- recipientCount: wire.recipientCount
38125
- };
38126
- }
38127
- function toPayrollRuns(wire) {
38128
- return {
38129
- ...mapPage(wire, toPayrollRun),
38130
- settledThisMonth: wire.settledThisMonth
38131
- };
38132
- }
38133
- function toPayrollGroup(wire) {
38134
- return {
38135
- id: toPayrollGroupId(wire.id),
38136
- name: wire.name,
38137
- tone: wire.tone,
38138
- members: wire.members.map((member) => ({
38139
- partyId: member.partyId,
38140
- amount: member.amount,
38141
- currency: member.currency
38142
- }))
38143
- };
38144
- }
38145
- function validateRunItems(input) {
38146
- for (const [index, item] of input.items.entries()) {
38147
- if (Schema.decodeResult(PayrollRunItemInputSchema, { onExcessProperty: "error" })(item)._tag === "Failure") return Errors.invalidInput(`items.${index}`, "invalid Payroll item");
38148
- try {
38149
- const exact = toExactAssetAmount(item.amount, CONFIGURED_MONEY_ASSETS);
38150
- const net = BigInt(item.net);
38151
- const gross = BigInt(item.gross);
38152
- const adjustments = item.adjustments.reduce((sum, row) => sum + BigInt(row.amount), 0n);
38153
- if (item.amount.asset !== input.asset || item.net !== exact.minorUnits || gross + adjustments !== net) return Errors.invalidInput(`items.${index}`, "invalid Payroll units");
38154
- } catch {
38155
- return Errors.invalidInput(`items.${index}`, "invalid Payroll units");
38156
- }
38157
- }
38158
- return null;
38159
- }
38160
- const RunInputSchema = Schema.Struct({
38161
- permissionId: AuthorizePayrollRunExecutionInputSchema.fields.permissionId,
38162
- asset: AuthorizePayrollRunExecutionInputSchema.fields.asset,
38163
- period: AuthorizePayrollRunExecutionInputSchema.fields.period,
38164
- items: AuthorizePayrollRunExecutionInputSchema.fields.items,
38165
- requestKey: Schema.optional(AuthorizePayrollRunExecutionInputSchema.fields.requestKey)
38166
- });
38167
- /** Decode caller input before session or signer work. Keep routing outside the input. */
38168
- function decodePayrollRunInput(value) {
38169
- try {
38170
- const decoded = Schema.decodeUnknownSync(RunInputSchema, { onExcessProperty: "error" })(value);
38171
- const input = {
38172
- permissionId: decoded.permissionId,
38173
- asset: decoded.asset,
38174
- period: decoded.period,
38175
- ...decoded.requestKey === void 0 ? {} : { requestKey: decoded.requestKey },
38176
- items: decoded.items.map((item) => ({
38177
- amount: item.amount,
38178
- gross: item.gross,
38179
- net: item.net,
38180
- adjustments: item.adjustments,
38181
- partyId: toPartyId(item.partyId),
38182
- to: item.to.kind === "party" ? {
38183
- kind: "party",
38184
- partyId: toPartyId(item.to.partyId)
38185
- } : item.to.kind === "address" ? {
38186
- kind: "address",
38187
- address: toAddress(item.to.address)
38188
- } : item.to
38189
- }))
38190
- };
38191
- if (input.items.length === 0 || input.period.start > input.period.end) throw Errors.invalidInput("input", "Payroll requires items and an ordered period");
38192
- const error = validateRunItems(input);
38193
- if (error !== null) throw error;
38194
- return input;
38195
- } catch (cause) {
38196
- throw cause instanceof CapxulError ? cause : Errors.invalidInput("input", "Invalid Payroll input");
38197
- }
38198
- }
38199
- /** Read only the exact backend prepare receipt, never an arbitrary signer failure. */
38200
- function payrollResolution(error, requestKey) {
38201
- const details = error.details;
38202
- if (error.code !== "WRONG_STATE" || details?.method !== runs.authorize.name || details.requestKey !== requestKey || typeof details.commandId !== "string" || typeof details.runId !== "string") return void 0;
38203
- return details.payrollResolution === "failed" || details.payrollResolution === "settled" ? details.payrollResolution : void 0;
38204
- }
38205
- function validatePayrollRunLookup(orgId, runId) {
38206
- return !Schema.is(PayrollRunIdSchema)(runId) || orgId.length === 0 ? {
38207
- ok: false,
38208
- error: Errors.invalidInput("runId", "Organization and run ID must be valid")
38209
- } : {
38210
- ok: true,
38211
- value: void 0
38212
- };
38213
- }
38214
- /** Strict saved detail decoder shared by the read and fresh stream. */
38215
- function decodePayrollRunDetail(raw, orgId, runId) {
38216
- const decoded = Schema.decodeUnknownResult(Schema.NullOr(PayrollRunDetailSchema), { onExcessProperty: "error" })(raw);
38217
- if (decoded._tag === "Failure") return {
38218
- ok: false,
38219
- error: Errors.invalidInput("run", "Invalid Payroll run detail")
38220
- };
38221
- return checkPayrollRunDetail(decoded.success, orgId, runId);
38222
- }
38223
- //#endregion
38224
- //#region ../../packages/sdk/src/payroll/run-subscription.ts
38225
- function detailValue(result) {
38226
- if (!result.ok) throw result.error;
38227
- return result.value;
38228
- }
38229
- function subscribePayrollRun(deps, orgId, runId, listener, options) {
38230
- const operation = CAPXUL_OPERATIONS.org.payroll.subscribeRun;
38231
- const valid = deps.validate(orgId, runId);
38232
- if (!valid.ok) return runCapxulEffect(Effect.fail(valid.error), observationOnlyControls(deps.invocationControls?.(options) ?? options), operation, deps.runPromise);
38233
- const decode = (raw) => detailValue(deps.decode(raw, orgId, runId));
38234
- return subscribeFreshQuery(deps, {
38235
- orgId,
38236
- runId
38237
- }, listener, operation, {
38238
- decode,
38239
- validateCached: (raw) => {
38240
- decode(raw);
38241
- },
38242
- invalidValue: (cause) => isCapxulError(cause) ? cause : Errors.invalidInput("run", "Invalid Payroll run detail"),
38243
- invalidScope: () => Errors.invalidInput("run", "Payroll run subscription scope does not match"),
38244
- lostValue: () => Errors.invalidInput("run", "Payroll run is no longer readable"),
38245
- unavailable: () => Errors.notImplemented("payroll", "subscribeRun")
38246
- }, options);
38247
- }
38248
- //#endregion
38249
- //#region ../../packages/sdk/src/payroll/run-authorization.ts
38250
- /**
38251
- * Authorize one payroll run: a stable request key, the prepared batch checked
38252
- * against the run the caller asked for, the signature, and the submission.
38253
- */
38254
- async function authorizePayrollRun(scope, input, controls, onRequestKey, onResolved) {
38255
- const { deps, orgId, requestKeyScope } = scope;
38256
- const signal = controls?.signal;
38257
- const execution = executionDependencies(deps);
38258
- if (execution === null) return {
38259
- ok: false,
38260
- error: Errors.notImplemented("payroll", "executionComposition")
38261
- };
38262
- try {
38263
- input = decodePayrollRunInput(input);
38264
- } catch (cause) {
38265
- return {
38266
- ok: false,
38267
- error: asCapxulError(cause)
38268
- };
38269
- }
38270
- const { requestKey: provided, ...canonicalInput } = input;
38271
- const actorId = onRequestKey === void 0 ? void 0 : execution.actor.authSession()?.authUserId;
38272
- if (onRequestKey !== void 0 && actorId === void 0) return {
38273
- ok: false,
38274
- error: Errors.notAuthenticated()
38275
- };
38276
- const requestKey = await paymentRequestKeyLifecycle(`${requestKeyScope}:${AUTHORIZE_RUN}`, onRequestKey === void 0 ? {
38277
- orgId,
38278
- input
38279
- } : {
38280
- actorId,
38281
- orgId,
38282
- input: canonicalInput
38283
- }, provided, onRequestKey === void 0 ? void 0 : { manageProvidedKey: true });
38284
- try {
38285
- await onRequestKey?.(requestKey.key);
38286
- if (onRequestKey !== void 0 && execution.actor.authSession()?.authUserId !== actorId) {
38287
- await requestKey.finish(false).catch(() => void 0);
38288
- return {
38289
- ok: false,
38290
- error: Errors.notAuthenticated()
38291
- };
38292
- }
38293
- } catch (cause) {
38294
- await requestKey.finish(false).catch(() => void 0);
38295
- return {
38296
- ok: false,
38297
- error: asCapxulError(cause)
38298
- };
38299
- }
38300
- let authorized;
38301
- let acceptedReplay;
38302
- let preparedClosed = false;
38303
- let terminalReplay;
38304
- const submitted = await executePrepared(execution, async (signerAddress) => {
38305
- const prepared = await runIfActive(signal, AUTHORIZE_RUN, () => withInvocationParentSpan(Effect.suspend(() => callOperation(deps.convexCall, runs.authorize, copyInvocationObservation(controls, {
38306
- orgId,
38307
- permissionId: input.permissionId,
38308
- asset: input.asset,
38309
- requestKey: requestKey.key,
38310
- signerAddress,
38311
- period: input.period,
38312
- items: input.items
38313
- }))).pipe(Effect.mapError((publicError) => ({ publicError }))), controls), deps.runPromise);
38314
- if (!prepared.ok) {
38315
- terminalReplay = payrollResolution(prepared.error, requestKey.key);
38316
- return prepared;
38317
- }
38318
- authorized = prepared.value.run;
38319
- acceptedReplay = prepared.value.replay.kind === "accepted" ? prepared.value.replay.submission : void 0;
38320
- return {
38321
- ok: true,
38322
- value: prepared.value.execution
38323
- };
38324
- }, (request, evidence) => authorized === void 0 || authorized.periodStart !== input.period.start || authorized.periodEnd !== input.period.end ? Promise.resolve(false) : isRunBatch({
38325
- orgId,
38326
- permissionId: input.permissionId,
38327
- requestKey: requestKey.key,
38328
- runId: authorized.id,
38329
- asset: input.asset,
38330
- period: input.period,
38331
- items: input.items
38332
- })(request, evidence), true, () => preparedClosed = true, signal, controls, void 0, () => acceptedReplay);
38333
- const resolution = preparedClosed ? "failed" : terminalReplay;
38334
- if (resolution !== void 0) try {
38335
- await onResolved?.(resolution);
38336
- } catch {}
38337
- try {
38338
- await requestKey.finish(submitted.ok || resolution !== void 0);
38339
- } catch {}
38340
- if (!submitted.ok) return submitted;
38341
- return authorized === void 0 ? {
38342
- ok: false,
38343
- error: Errors.unknown()
38344
- } : {
38345
- ok: true,
38346
- value: toPayrollRun(authorized)
38347
- };
38348
- }
38349
- const AUTHORIZE_RUN = runs.authorize.name;
38350
- function executionDependencies(deps) {
38351
- return deps.actor === void 0 || deps.chainId === void 0 || deps.signer === void 0 ? null : {
38352
- actor: deps.actor,
38353
- chainId: deps.chainId,
38354
- convexCall: deps.convexCall,
38355
- runPromise: deps.runPromise,
38356
- signer: deps.signer,
38357
- ...deps.telemetry === void 0 ? {} : { telemetry: deps.telemetry }
38358
- };
38359
- }
38360
- //#endregion
38361
- //#region ../../packages/sdk/src/payroll/runs.ts
38362
- function makePayrollMethods(deps, orgId) {
38363
- const requestKeyScope = deps.requestKeyScope ?? `client-${crypto.randomUUID()}`;
38364
- /** One observed call of one payroll row, its reply projected inside the call, under the row's name. */
38365
- const call = (row, args, options, project) => {
38366
- const controls = deps.invocationControls?.(options) ?? options;
38367
- return runPortEffect(callOperation(deps.convexCall, row, copyInvocationObservation(controls, args)).pipe(Effect.map(project), Effect.mapError((publicError) => ({ publicError }))), controls, row.name, deps.runPromise);
38368
- };
38369
- return {
38370
- subscribeRun: (runId, listener, options) => subscribePayrollRun({
38371
- actor: deps.actor,
38372
- convexCall: deps.convexCall,
38373
- query: reference(runs.get),
38374
- runPromise: deps.runPromise,
38375
- invocationControls: deps.invocationControls,
38376
- decode: decodePayrollRunDetail,
38377
- validate: validatePayrollRunLookup
38378
- }, orgId, runId, listener, options),
38379
- getRun: (runId, options) => {
38380
- const controls = deps.invocationControls?.(options) ?? options;
38381
- const lifetime = deps.actor?.authLifetime();
38382
- const operation = runs.get.name;
38383
- return runCapxulEffect(Effect.gen(function* () {
38384
- const lookup = validatePayrollRunLookup(orgId, runId);
38385
- if (!lookup.ok) return yield* Effect.fail(lookup.error);
38386
- if (lifetime === void 0 || lifetime.authUserId === null || deps.actor === void 0) return yield* Effect.fail(Errors.notAuthenticated());
38387
- const current = () => deps.actor?.matchesAuthLifetime(lifetime, lifetime.authUserId) === true;
38388
- if (!current()) return yield* Effect.fail(Errors.notAuthenticated());
38389
- const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
38390
- const captured = carryInvocationParentSpan(controls, parent);
38391
- const run = yield* awaitCapxulResult(() => runIfActive(controls?.signal, operation, () => withInvocationParentSpan(Effect.suspend(() => callOperation(deps.convexCall, runs.get, copyInvocationObservation(captured, {
38392
- orgId,
38393
- runId
38394
- }))).pipe(Effect.mapError((publicError) => ({ publicError }))), captured), deps.runPromise));
38395
- if (!current()) return yield* Effect.fail(Errors.cancelled({ operation }));
38396
- const checked = checkPayrollRunDetail(run, orgId, runId);
38397
- return yield* checked.ok ? Effect.succeed(checked.value) : Effect.fail(checked.error);
38398
- }), observationOnlyControls(controls), operation, deps.runPromise);
38399
- },
38400
- runs: (options) => call(runs.list, { orgId }, options, toPayrollRuns),
38401
- authorizeRun: (input, options) => {
38402
- const controls = deps.invocationControls?.(options) ?? options;
38403
- return runCapxulEffect(Effect.gen(function* () {
38404
- if (controls?.signal?.aborted === true) return yield* Effect.fail(Errors.cancelled({ operation: AUTHORIZE_RUN }));
38405
- const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
38406
- return yield* awaitCapxulResult(() => authorizePayrollRun({
38407
- deps,
38408
- orgId,
38409
- requestKeyScope
38410
- }, input, carryInvocationParentSpan(controls, parent), options?.onRequestKey, options?.onResolved));
38411
- }), observationOnlyControls(controls), AUTHORIZE_RUN, deps.runPromise);
38412
- },
38413
- terms: (options) => call(terms.list, { orgId }, options, (rates) => rates),
38414
- groups: {
38415
- list: (options) => call(groups.list, { orgId }, options, (saved) => mapPage(saved, toPayrollGroup)),
38416
- save: (input, options) => call(groups.save, {
38417
- orgId,
38418
- ...input.id === void 0 ? {} : { id: String(input.id) },
38419
- name: input.name,
38420
- tone: input.tone,
38421
- members: input.members
38422
- }, options, toPayrollGroup),
38423
- remove: (id, options) => call(groups.remove, {
38424
- orgId,
38425
- id
38426
- }, options, () => void 0)
38427
- }
38428
- };
38429
- }
38430
- const payrollUnavailable = () => Promise.resolve({
38431
- ok: false,
38432
- error: Errors.notImplemented("payroll", "executionComposition")
38433
- });
38434
- /** The bundle an unconfigured client exposes — every verb refuses, none throws. */
38435
- function makeUnavailablePayrollMethods() {
38436
- return {
38437
- getRun: payrollUnavailable,
38438
- subscribeRun: payrollUnavailable,
38439
- runs: payrollUnavailable,
38440
- authorizeRun: payrollUnavailable,
38441
- terms: payrollUnavailable,
38442
- groups: {
38443
- list: payrollUnavailable,
38444
- save: payrollUnavailable,
38445
- remove: payrollUnavailable
38446
- }
38447
- };
38448
- }
38449
- //#endregion
38450
38581
  //#region ../../node_modules/.pnpm/axios@1.17.0/node_modules/axios/lib/helpers/bind.js
38451
38582
  /**
38452
38583
  * Create a bound version of a function with a specified `this` context
@@ -71068,7 +71199,7 @@ function stdioIdentity(env = process.env, options = {}) {
71068
71199
  }
71069
71200
  //#endregion
71070
71201
  //#region package.json
71071
- var version = "4.20.0-beta.26";
71202
+ var version = "4.20.0-beta.27";
71072
71203
  //#endregion
71073
71204
  //#region src/deps.ts
71074
71205
  const NO_IDENTITY = async () => void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capxul/mcp",
3
- "version": "4.20.0-beta.26",
3
+ "version": "4.20.0-beta.27",
4
4
  "private": false,
5
5
  "description": "Capxul MCP server for auth, Account readiness, identity, Organizations, relationships, requests, destinations, and testnet funding over Streamable HTTP.",
6
6
  "keywords": [
@@ -54,8 +54,8 @@
54
54
  "typescript": "npm:@typescript/typescript6@6.0.2",
55
55
  "vite": "npm:@voidzero-dev/vite-plus-core@1.0.0",
56
56
  "vite-plus": "1.0.0",
57
- "@capxul/protocol": "0.2.0-beta.0",
58
- "@capxul/sdk": "4.20.0-beta.26",
57
+ "@capxul/protocol": "0.2.0-beta.1",
58
+ "@capxul/sdk": "4.20.0-beta.27",
59
59
  "@capxul/typescript-config": "0.0.0"
60
60
  },
61
61
  "scripts": {