@sprigr/apps-app-sdk 0.8.6 → 0.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1489,6 +1489,57 @@ declare function manifestIsFresh(manifest: ManifestLike, opts: ApplyPoliciesOpti
1489
1489
  /** The manifest, serialised the way the repo commits it (2-space, trailing newline). */
1490
1490
  declare function serializeManifest(manifest: ManifestLike): string;
1491
1491
 
1492
+ /**
1493
+ * Derive a confirmation policy from an action registry by NAME, for apps
1494
+ * whose registry carries no destructive flag: the verb prefix says what an
1495
+ * action does (`delete_`, `void_`, `cancel_`, `archive_`), so the policy
1496
+ * follows from a small table of verb rules instead of a hand-kept list
1497
+ * that drifts the moment an action is added.
1498
+ *
1499
+ * Each rule names a prefix (or regex), the tier it lands in, and how to
1500
+ * phrase the describe from the rest of the name. The first matching rule
1501
+ * wins, so put the specific ones first.
1502
+ */
1503
+
1504
+ interface VerbRule {
1505
+ /** A name prefix (`'delete_'`) or a regex tested against the whole name. */
1506
+ match: string | RegExp;
1507
+ /** `irreversible` marks the card "cannot be undone"; `always` is a plain confirmation. */
1508
+ tier: 'irreversible' | 'always';
1509
+ /**
1510
+ * Describe for a matching action. Receives the full name and `rest`: the
1511
+ * name with the matched prefix removed and underscores turned to spaces
1512
+ * (for a regex match, the whole name spaced). No trailing period.
1513
+ */
1514
+ describe: (name: string, rest: string) => string;
1515
+ }
1516
+ interface DerivePolicyOptions {
1517
+ /** Verb rules, most specific first. */
1518
+ rules: readonly VerbRule[];
1519
+ /** Actions to leave ungated even though a rule matches (returned in `ungated`). */
1520
+ exempt?: readonly string[];
1521
+ /** Explicit rules that win over the verb table (e.g. a hand-written describe). */
1522
+ overrides?: Readonly<Record<string, ConfirmRule>>;
1523
+ }
1524
+ interface DerivedPolicy {
1525
+ policy: ConfirmationPolicy & {
1526
+ actions: Record<string, ConfirmRule>;
1527
+ };
1528
+ /** Registry names a rule matched but `exempt` kept ungated. */
1529
+ ungated: string[];
1530
+ /** Registry names no rule matched (reads and writes the table does not classify). */
1531
+ unmatched: string[];
1532
+ }
1533
+ /** Build a policy over `registry` from the verb table; see the file comment. */
1534
+ declare function deriveConfirmationPolicy(registry: Iterable<string>, opts: DerivePolicyOptions): DerivedPolicy;
1535
+ /**
1536
+ * The verb table most registries need: hard deletes, voids, refunds and
1537
+ * cancellations cannot be undone; archives, removals from a parent and
1538
+ * unassignments are plain confirmations. `subject` names the system for
1539
+ * the describe ("in Xero").
1540
+ */
1541
+ declare function commonDestructiveVerbs(subject: string): VerbRule[];
1542
+
1492
1543
  /**
1493
1544
  * @sprigr/apps-app-sdk
1494
1545
  *
@@ -1889,4 +1940,4 @@ interface ExecutionContextLike {
1889
1940
  }
1890
1941
  type HandlerFn<TArgs, TResult> = (args: TArgs, env: Record<string, unknown>, ctx?: ExecutionContextLike) => Promise<TResult>;
1891
1942
 
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 };
1943
+ 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
@@ -982,6 +982,56 @@ function serializeManifest(manifest) {
982
982
  return `${JSON.stringify(manifest, null, 2)}
983
983
  `;
984
984
  }
985
+
986
+ // src/write-protection/derive-policy.ts
987
+ function spaced(s) {
988
+ return s.replace(/_/g, " ");
989
+ }
990
+ function matchRule(name, rule) {
991
+ if (typeof rule.match === "string") {
992
+ return name.startsWith(rule.match) ? spaced(name.slice(rule.match.length)) : null;
993
+ }
994
+ return rule.match.test(name) ? spaced(name) : null;
995
+ }
996
+ function deriveConfirmationPolicy(registry, opts) {
997
+ const exempt = new Set(opts.exempt ?? []);
998
+ const irreversible = {};
999
+ const always = {};
1000
+ const ungated = [];
1001
+ const unmatched = [];
1002
+ const overrides = opts.overrides ?? {};
1003
+ for (const name of registry) {
1004
+ if (overrides[name]) continue;
1005
+ let hit = false;
1006
+ for (const rule of opts.rules) {
1007
+ const rest = matchRule(name, rule);
1008
+ if (rest == null) continue;
1009
+ hit = true;
1010
+ if (exempt.has(name)) ungated.push(name);
1011
+ else (rule.tier === "irreversible" ? irreversible : always)[name] = rule.describe(name, rest);
1012
+ break;
1013
+ }
1014
+ if (!hit) unmatched.push(name);
1015
+ }
1016
+ const policy = buildConfirmationPolicy({ irreversible, always, rules: overrides });
1017
+ return { policy, ungated, unmatched };
1018
+ }
1019
+ function commonDestructiveVerbs(subject) {
1020
+ const where = subject ? ` ${subject}` : "";
1021
+ return [
1022
+ { match: "delete_", tier: "irreversible", describe: (_n, rest) => `Delete ${rest}${where}` },
1023
+ { match: "void_", tier: "irreversible", describe: (_n, rest) => `Void ${rest}${where}` },
1024
+ { match: "refund_", tier: "irreversible", describe: (_n, rest) => `Refund ${rest}${where}` },
1025
+ { match: "cancel_", tier: "irreversible", describe: (_n, rest) => `Cancel ${rest}${where}` },
1026
+ { match: "destroy_", tier: "irreversible", describe: (_n, rest) => `Destroy ${rest}${where}` },
1027
+ { match: "purge_", tier: "irreversible", describe: (_n, rest) => `Purge ${rest}${where}` },
1028
+ { match: "revoke_", tier: "irreversible", describe: (_n, rest) => `Revoke ${rest}${where}` },
1029
+ { match: "archive_", tier: "always", describe: (_n, rest) => `Archive ${rest}${where}` },
1030
+ { match: "remove_", tier: "always", describe: (_n, rest) => `Remove ${rest}${where}` },
1031
+ { match: "unassign_", tier: "always", describe: (_n, rest) => `Unassign ${rest}${where}` },
1032
+ { match: "deactivate_", tier: "always", describe: (_n, rest) => `Deactivate ${rest}${where}` }
1033
+ ];
1034
+ }
985
1035
  export {
986
1036
  APPROVAL_GRANTED_KEY,
987
1037
  DEFAULT_EMIT_TIMEOUT_MS,
@@ -1003,11 +1053,13 @@ export {
1003
1053
  bytesToBase64,
1004
1054
  canEmit,
1005
1055
  checkConfirmationPolicy,
1056
+ commonDestructiveVerbs,
1006
1057
  constantTimeEqual,
1007
1058
  createMarketplaceEmitter,
1008
1059
  createToolWrappers,
1009
1060
  decodeState,
1010
1061
  deleteAppFile,
1062
+ deriveConfirmationPolicy,
1011
1063
  describeMissingBridge,
1012
1064
  dispatcherApproval,
1013
1065
  emitMarketplaceEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sprigr/apps-app-sdk",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",