@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.
- package/dist/main.mjs +551 -420
- 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: {
|
|
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: {
|
|
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.
|
|
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),
|
|
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),
|
|
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.
|
|
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.
|
|
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.
|
|
58
|
-
"@capxul/sdk": "4.20.0-beta.
|
|
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": {
|