@sprigr/apps-app-sdk 0.8.6 → 0.8.8
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/index.d.ts +69 -1
- package/dist/index.js +66 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -902,6 +902,15 @@ interface AppApprovalEnvelope {
|
|
|
902
902
|
* retry silently discards the tap. See `approvalHash`.
|
|
903
903
|
*/
|
|
904
904
|
hash?: string;
|
|
905
|
+
/**
|
|
906
|
+
* How many records this ONE call touches, as you count them. Required for a
|
|
907
|
+
* workflow step's standing approval to cover the call on an unattended run
|
|
908
|
+
* (sprigr-team decision 0039): the platform cannot see inside your write,
|
|
909
|
+
* so an envelope with no count gets a person or nothing. The wrappers set
|
|
910
|
+
* it to 1 for a single-target spec; a batch action supplies
|
|
911
|
+
* `ApprovalSpec.count`.
|
|
912
|
+
*/
|
|
913
|
+
count?: number;
|
|
905
914
|
}
|
|
906
915
|
/**
|
|
907
916
|
* Platform-stamped marker telling an app that a human approved this call. The
|
|
@@ -1105,6 +1114,14 @@ interface ApprovalSpec<P = unknown> {
|
|
|
1105
1114
|
* Use `set()` / `seq()` from `approval-hash`. Never include `confirm`.
|
|
1106
1115
|
*/
|
|
1107
1116
|
hash?: (args: ToolArgs) => Array<string | number | undefined | null>;
|
|
1117
|
+
/**
|
|
1118
|
+
* How many records this call touches, for `_approval.count`. Omit for a
|
|
1119
|
+
* single-target tool (the wrapper reports 1 when a `keys` id resolved, and
|
|
1120
|
+
* nothing when none did). A batch action (delete these ids, tag these
|
|
1121
|
+
* products) MUST supply it, or it reports nothing and no standing approval
|
|
1122
|
+
* can ever cover it, which is the safe side but not the useful one.
|
|
1123
|
+
*/
|
|
1124
|
+
count?: (args: ToolArgs) => number;
|
|
1108
1125
|
/** Present only for tools whose write can be (partly) reversed. */
|
|
1109
1126
|
undo?: UndoCaptureSpec<P>;
|
|
1110
1127
|
}
|
|
@@ -1489,6 +1506,57 @@ declare function manifestIsFresh(manifest: ManifestLike, opts: ApplyPoliciesOpti
|
|
|
1489
1506
|
/** The manifest, serialised the way the repo commits it (2-space, trailing newline). */
|
|
1490
1507
|
declare function serializeManifest(manifest: ManifestLike): string;
|
|
1491
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* Derive a confirmation policy from an action registry by NAME, for apps
|
|
1511
|
+
* whose registry carries no destructive flag: the verb prefix says what an
|
|
1512
|
+
* action does (`delete_`, `void_`, `cancel_`, `archive_`), so the policy
|
|
1513
|
+
* follows from a small table of verb rules instead of a hand-kept list
|
|
1514
|
+
* that drifts the moment an action is added.
|
|
1515
|
+
*
|
|
1516
|
+
* Each rule names a prefix (or regex), the tier it lands in, and how to
|
|
1517
|
+
* phrase the describe from the rest of the name. The first matching rule
|
|
1518
|
+
* wins, so put the specific ones first.
|
|
1519
|
+
*/
|
|
1520
|
+
|
|
1521
|
+
interface VerbRule {
|
|
1522
|
+
/** A name prefix (`'delete_'`) or a regex tested against the whole name. */
|
|
1523
|
+
match: string | RegExp;
|
|
1524
|
+
/** `irreversible` marks the card "cannot be undone"; `always` is a plain confirmation. */
|
|
1525
|
+
tier: 'irreversible' | 'always';
|
|
1526
|
+
/**
|
|
1527
|
+
* Describe for a matching action. Receives the full name and `rest`: the
|
|
1528
|
+
* name with the matched prefix removed and underscores turned to spaces
|
|
1529
|
+
* (for a regex match, the whole name spaced). No trailing period.
|
|
1530
|
+
*/
|
|
1531
|
+
describe: (name: string, rest: string) => string;
|
|
1532
|
+
}
|
|
1533
|
+
interface DerivePolicyOptions {
|
|
1534
|
+
/** Verb rules, most specific first. */
|
|
1535
|
+
rules: readonly VerbRule[];
|
|
1536
|
+
/** Actions to leave ungated even though a rule matches (returned in `ungated`). */
|
|
1537
|
+
exempt?: readonly string[];
|
|
1538
|
+
/** Explicit rules that win over the verb table (e.g. a hand-written describe). */
|
|
1539
|
+
overrides?: Readonly<Record<string, ConfirmRule>>;
|
|
1540
|
+
}
|
|
1541
|
+
interface DerivedPolicy {
|
|
1542
|
+
policy: ConfirmationPolicy & {
|
|
1543
|
+
actions: Record<string, ConfirmRule>;
|
|
1544
|
+
};
|
|
1545
|
+
/** Registry names a rule matched but `exempt` kept ungated. */
|
|
1546
|
+
ungated: string[];
|
|
1547
|
+
/** Registry names no rule matched (reads and writes the table does not classify). */
|
|
1548
|
+
unmatched: string[];
|
|
1549
|
+
}
|
|
1550
|
+
/** Build a policy over `registry` from the verb table; see the file comment. */
|
|
1551
|
+
declare function deriveConfirmationPolicy(registry: Iterable<string>, opts: DerivePolicyOptions): DerivedPolicy;
|
|
1552
|
+
/**
|
|
1553
|
+
* The verb table most registries need: hard deletes, voids, refunds and
|
|
1554
|
+
* cancellations cannot be undone; archives, removals from a parent and
|
|
1555
|
+
* unassignments are plain confirmations. `subject` names the system for
|
|
1556
|
+
* the describe ("in Xero").
|
|
1557
|
+
*/
|
|
1558
|
+
declare function commonDestructiveVerbs(subject: string): VerbRule[];
|
|
1559
|
+
|
|
1492
1560
|
/**
|
|
1493
1561
|
* @sprigr/apps-app-sdk
|
|
1494
1562
|
*
|
|
@@ -1889,4 +1957,4 @@ interface ExecutionContextLike {
|
|
|
1889
1957
|
}
|
|
1890
1958
|
type HandlerFn<TArgs, TResult> = (args: TArgs, env: Record<string, unknown>, ctx?: ExecutionContextLike) => Promise<TResult>;
|
|
1891
1959
|
|
|
1892
|
-
export { APPROVAL_GRANTED_KEY, type Actor, type AppApprovalEnvelope, type AppFileListItem, type AppFileUrlArgs, type AppFileUrlResult, type AppFilesEnv, type AppUndoEnvelope, type ApplyPoliciesOptions, type ApprovalGateOptions, type ApprovalSpec, type ArchiveOfferOptions, type ArchiveOfferRefusal, type CaptureJournal, type ConfirmCondition, type ConfirmRule, type ConfirmationPolicy, type D1Like, type D1PreparedStatementLike, DEFAULT_EMIT_TIMEOUT_MS, DEFAULT_MAX_FILE_BYTES, DEFAULT_MONEY_FIELDS, DEFAULT_WRITE_PREFIXES, type DispatcherApprovalGate, type DispatcherApprovalOptions, type EmitMarketplaceEventOptions, type EmitResult, type EmitTransport, type EventArgs, type ExecutionContextLike, type FetchFileResult, type FetchWithRetryOptions, type GetAppFileResult, type HandlerFn, type InboxOwner, type InstallBridge, InvalidUndoEnvelopeError, type JournalRowLike, type ManifestDispatchBlock, type ManifestLike, type ManifestToolLike, type MarketplaceEventEmitOpts, type MarketplaceEventSourceIntegration, NotConnectedError, type OAuthBouncerSignals, type OAuthState, type OfferUndoArgs, type PlatformHostEnv, type PolicyCheckInput, type PolicySource, type PutAppFileArgs, type PutAppFileResult, type PutAppFileStreamArgs, type RequireApprovalOptions, type RestoreResult, type RestoreSpec, type ScheduleArgs, type SprigrDataAggregationCell, type SprigrDataAggregationResult, type SprigrDataAggregationSpec, type SprigrDataApi, type SprigrDataIndexOpts, type SprigrDataSearchOpts, type SprigrDataSearchResult, type SprigrFilesApi, type SprigrFilesApiWithEdit, type SprigrFilesCreateInput, type SprigrFilesCreateResult, type SprigrFilesEditInput, type SprigrFilesEditResult, type SprigrFilesJobResult, type ToolArgs, type ToolHandler, type ToolResult, type ToolWrapperOptions, UNIT_SEP, type UndoApplyOptions, type UndoApplyResult, type UndoCaptureSpec, type UndoFidelity, type WebhookArgs, type WfpBridgeEnv, type WfpEmitReply, actorKey, actorTool, appFileUrl, applyConfirmationPolicies, approvalHash, archiveOfferRefusal, base64ToBytes, buildConfirmationPolicy, buildMarketplaceWebhookUrl, bytesToBase64, canEmit, checkConfirmationPolicy, constantTimeEqual, createMarketplaceEmitter, createToolWrappers, decodeState, deleteAppFile, describeMissingBridge, dispatcherApproval, emitMarketplaceEvent, encodeState, fetchFileAsBase64, fetchFileBytes, fetchWithRetry, fullWarning, getAppFile, hmacSha256Hex, installTokenPost, isNotConnectedError, isStagingHost, listAppFiles, manifestIsFresh, offerUndo, overlaySprigr, ownerFromActorKey, parseActor, putAppFile, putAppFileStream, randomHex, recreatedWarning, refuseWithoutForce, requireApproval, resolveInstallBridge, resolveOAuthBouncerBase, resolveOAuthBouncerCallbackUrl, resolvePlatformWebhookBase, runUndoApply, safeCapture, seq, serializeManifest, set, tool, undoEnvelope, withSprigrEmitFallback };
|
|
1960
|
+
export { APPROVAL_GRANTED_KEY, type Actor, type AppApprovalEnvelope, type AppFileListItem, type AppFileUrlArgs, type AppFileUrlResult, type AppFilesEnv, type AppUndoEnvelope, type ApplyPoliciesOptions, type ApprovalGateOptions, type ApprovalSpec, type ArchiveOfferOptions, type ArchiveOfferRefusal, type CaptureJournal, type ConfirmCondition, type ConfirmRule, type ConfirmationPolicy, type D1Like, type D1PreparedStatementLike, DEFAULT_EMIT_TIMEOUT_MS, DEFAULT_MAX_FILE_BYTES, DEFAULT_MONEY_FIELDS, DEFAULT_WRITE_PREFIXES, type DerivePolicyOptions, type DerivedPolicy, type DispatcherApprovalGate, type DispatcherApprovalOptions, type EmitMarketplaceEventOptions, type EmitResult, type EmitTransport, type EventArgs, type ExecutionContextLike, type FetchFileResult, type FetchWithRetryOptions, type GetAppFileResult, type HandlerFn, type InboxOwner, type InstallBridge, InvalidUndoEnvelopeError, type JournalRowLike, type ManifestDispatchBlock, type ManifestLike, type ManifestToolLike, type MarketplaceEventEmitOpts, type MarketplaceEventSourceIntegration, NotConnectedError, type OAuthBouncerSignals, type OAuthState, type OfferUndoArgs, type PlatformHostEnv, type PolicyCheckInput, type PolicySource, type PutAppFileArgs, type PutAppFileResult, type PutAppFileStreamArgs, type RequireApprovalOptions, type RestoreResult, type RestoreSpec, type ScheduleArgs, type SprigrDataAggregationCell, type SprigrDataAggregationResult, type SprigrDataAggregationSpec, type SprigrDataApi, type SprigrDataIndexOpts, type SprigrDataSearchOpts, type SprigrDataSearchResult, type SprigrFilesApi, type SprigrFilesApiWithEdit, type SprigrFilesCreateInput, type SprigrFilesCreateResult, type SprigrFilesEditInput, type SprigrFilesEditResult, type SprigrFilesJobResult, type ToolArgs, type ToolHandler, type ToolResult, type ToolWrapperOptions, UNIT_SEP, type UndoApplyOptions, type UndoApplyResult, type UndoCaptureSpec, type UndoFidelity, type VerbRule, type WebhookArgs, type WfpBridgeEnv, type WfpEmitReply, actorKey, actorTool, appFileUrl, applyConfirmationPolicies, approvalHash, archiveOfferRefusal, base64ToBytes, buildConfirmationPolicy, buildMarketplaceWebhookUrl, bytesToBase64, canEmit, checkConfirmationPolicy, commonDestructiveVerbs, constantTimeEqual, createMarketplaceEmitter, createToolWrappers, decodeState, deleteAppFile, deriveConfirmationPolicy, describeMissingBridge, dispatcherApproval, emitMarketplaceEvent, encodeState, fetchFileAsBase64, fetchFileBytes, fetchWithRetry, fullWarning, getAppFile, hmacSha256Hex, installTokenPost, isNotConnectedError, isStagingHost, listAppFiles, manifestIsFresh, offerUndo, overlaySprigr, ownerFromActorKey, parseActor, putAppFile, putAppFileStream, randomHex, recreatedWarning, refuseWithoutForce, requireApproval, resolveInstallBridge, resolveOAuthBouncerBase, resolveOAuthBouncerCallbackUrl, resolvePlatformWebhookBase, runUndoApply, safeCapture, seq, serializeManifest, set, tool, undoEnvelope, withSprigrEmitFallback };
|
package/dist/index.js
CHANGED
|
@@ -614,6 +614,17 @@ function rawIdOf(args, keys) {
|
|
|
614
614
|
}
|
|
615
615
|
return "";
|
|
616
616
|
}
|
|
617
|
+
function countOf(spec, params, rawId) {
|
|
618
|
+
if (spec.count) {
|
|
619
|
+
try {
|
|
620
|
+
const n = spec.count(params);
|
|
621
|
+
return Number.isFinite(n) && n >= 0 ? Math.floor(n) : void 0;
|
|
622
|
+
} catch {
|
|
623
|
+
return void 0;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return rawId ? 1 : void 0;
|
|
627
|
+
}
|
|
617
628
|
function isOk(result) {
|
|
618
629
|
return !!result && typeof result === "object" && result.ok !== false;
|
|
619
630
|
}
|
|
@@ -635,11 +646,13 @@ async function askPass(name, spec, params, env, opts, hashPrefix) {
|
|
|
635
646
|
const pinned = await pin(opts, env, connection);
|
|
636
647
|
const target = rawId && opts.describeTarget ? await safeLabel(opts.describeTarget, pinned, rawId, name) : rawId || "(unknown id)";
|
|
637
648
|
const extra = spec.hash ? spec.hash(params) : [];
|
|
649
|
+
const count = countOf(spec, params, rawId);
|
|
638
650
|
return {
|
|
639
651
|
ok: false,
|
|
640
652
|
_approval: {
|
|
641
653
|
...spec.describe(target, params, connection),
|
|
642
|
-
hash: approvalHash(...hashPrefix, rawId, connection, ...extra)
|
|
654
|
+
hash: approvalHash(...hashPrefix, rawId, connection, ...extra),
|
|
655
|
+
...count !== void 0 ? { count } : {}
|
|
643
656
|
}
|
|
644
657
|
};
|
|
645
658
|
}
|
|
@@ -982,6 +995,56 @@ function serializeManifest(manifest) {
|
|
|
982
995
|
return `${JSON.stringify(manifest, null, 2)}
|
|
983
996
|
`;
|
|
984
997
|
}
|
|
998
|
+
|
|
999
|
+
// src/write-protection/derive-policy.ts
|
|
1000
|
+
function spaced(s) {
|
|
1001
|
+
return s.replace(/_/g, " ");
|
|
1002
|
+
}
|
|
1003
|
+
function matchRule(name, rule) {
|
|
1004
|
+
if (typeof rule.match === "string") {
|
|
1005
|
+
return name.startsWith(rule.match) ? spaced(name.slice(rule.match.length)) : null;
|
|
1006
|
+
}
|
|
1007
|
+
return rule.match.test(name) ? spaced(name) : null;
|
|
1008
|
+
}
|
|
1009
|
+
function deriveConfirmationPolicy(registry, opts) {
|
|
1010
|
+
const exempt = new Set(opts.exempt ?? []);
|
|
1011
|
+
const irreversible = {};
|
|
1012
|
+
const always = {};
|
|
1013
|
+
const ungated = [];
|
|
1014
|
+
const unmatched = [];
|
|
1015
|
+
const overrides = opts.overrides ?? {};
|
|
1016
|
+
for (const name of registry) {
|
|
1017
|
+
if (overrides[name]) continue;
|
|
1018
|
+
let hit = false;
|
|
1019
|
+
for (const rule of opts.rules) {
|
|
1020
|
+
const rest = matchRule(name, rule);
|
|
1021
|
+
if (rest == null) continue;
|
|
1022
|
+
hit = true;
|
|
1023
|
+
if (exempt.has(name)) ungated.push(name);
|
|
1024
|
+
else (rule.tier === "irreversible" ? irreversible : always)[name] = rule.describe(name, rest);
|
|
1025
|
+
break;
|
|
1026
|
+
}
|
|
1027
|
+
if (!hit) unmatched.push(name);
|
|
1028
|
+
}
|
|
1029
|
+
const policy = buildConfirmationPolicy({ irreversible, always, rules: overrides });
|
|
1030
|
+
return { policy, ungated, unmatched };
|
|
1031
|
+
}
|
|
1032
|
+
function commonDestructiveVerbs(subject) {
|
|
1033
|
+
const where = subject ? ` ${subject}` : "";
|
|
1034
|
+
return [
|
|
1035
|
+
{ match: "delete_", tier: "irreversible", describe: (_n, rest) => `Delete ${rest}${where}` },
|
|
1036
|
+
{ match: "void_", tier: "irreversible", describe: (_n, rest) => `Void ${rest}${where}` },
|
|
1037
|
+
{ match: "refund_", tier: "irreversible", describe: (_n, rest) => `Refund ${rest}${where}` },
|
|
1038
|
+
{ match: "cancel_", tier: "irreversible", describe: (_n, rest) => `Cancel ${rest}${where}` },
|
|
1039
|
+
{ match: "destroy_", tier: "irreversible", describe: (_n, rest) => `Destroy ${rest}${where}` },
|
|
1040
|
+
{ match: "purge_", tier: "irreversible", describe: (_n, rest) => `Purge ${rest}${where}` },
|
|
1041
|
+
{ match: "revoke_", tier: "irreversible", describe: (_n, rest) => `Revoke ${rest}${where}` },
|
|
1042
|
+
{ match: "archive_", tier: "always", describe: (_n, rest) => `Archive ${rest}${where}` },
|
|
1043
|
+
{ match: "remove_", tier: "always", describe: (_n, rest) => `Remove ${rest}${where}` },
|
|
1044
|
+
{ match: "unassign_", tier: "always", describe: (_n, rest) => `Unassign ${rest}${where}` },
|
|
1045
|
+
{ match: "deactivate_", tier: "always", describe: (_n, rest) => `Deactivate ${rest}${where}` }
|
|
1046
|
+
];
|
|
1047
|
+
}
|
|
985
1048
|
export {
|
|
986
1049
|
APPROVAL_GRANTED_KEY,
|
|
987
1050
|
DEFAULT_EMIT_TIMEOUT_MS,
|
|
@@ -1003,11 +1066,13 @@ export {
|
|
|
1003
1066
|
bytesToBase64,
|
|
1004
1067
|
canEmit,
|
|
1005
1068
|
checkConfirmationPolicy,
|
|
1069
|
+
commonDestructiveVerbs,
|
|
1006
1070
|
constantTimeEqual,
|
|
1007
1071
|
createMarketplaceEmitter,
|
|
1008
1072
|
createToolWrappers,
|
|
1009
1073
|
decodeState,
|
|
1010
1074
|
deleteAppFile,
|
|
1075
|
+
deriveConfirmationPolicy,
|
|
1011
1076
|
describeMissingBridge,
|
|
1012
1077
|
dispatcherApproval,
|
|
1013
1078
|
emitMarketplaceEvent,
|