@sprigr/apps-app-sdk 0.8.4 → 0.8.5

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/README.md CHANGED
@@ -73,7 +73,7 @@ Three platform tiers, and they are not substitutes for each other. Full guide: [
73
73
  - `undoEnvelope({...})` throws on a blank field. The platform drops the whole envelope on a blank and mints nothing, silently.
74
74
  - `refuseWithoutForce(name, handler, opts)` / `archiveOfferRefusal(...)`: a delete refuses once and offers the vendor's native archive unless `force: true`.
75
75
  - `buildConfirmationPolicy({ irreversible, always, rules })` declares a dispatcher's policy beside its action registry; `checkConfirmationPolicy({ policy, registry, ungated, requiredInput })` returns every silent failure (dead rule, `(unset)` placeholder, money threshold, unclassified write) for a one-line test.
76
- - `runUndoApply(args, { env, journal, specs, pin })` is the body of your `internal: true` reverse tool: load, re-pin to the journalled connection, restore, drop. `pin` may hand `restore` a different type from the env (a per-actor token state), may throw (`connection_unavailable`) or return null to refuse (`connection_mismatch`); a restore that throws is `restore_failed` and the copy is kept.
76
+ - `runUndoApply(args, { env, journal, specs, pin })` is the body of your `internal: true` reverse tool: load, re-pin to the journalled connection, restore, drop. `pin` may hand `restore` a different type from the env (a per-actor token state), may throw (`connection_unavailable`) or return null to refuse (`connection_mismatch`); a restore that throws is `restore_failed` and the copy is kept; a successful restore may return `newId`, `notRestored`, `extra` (spread into the payload) and `note` (appended after the fidelity sentence).
77
77
  - `safeCapture(scope, name, id, read)` and `offerUndo({ journal, entity, id, before, connection, fidelity, resource, describe, warning })`: the capture-then-offer halves for a write that is not behind an approval card (a dispatcher `update_*` action). `requireApproval` uses the same two on its granted pass.
78
78
  - `sprigr-check-write-protection` (bin): every destructive-by-name tool or enumerated dispatcher action must carry a policy, or a reason in `apps/<app>/write-protection.json`; ratchets on `tools/write-protection-baseline.json`.
79
79
 
package/dist/index.d.ts CHANGED
@@ -1153,9 +1153,11 @@ interface ApprovalGateOptions<E, P = E> {
1153
1153
  /**
1154
1154
  * Human label for a raw id, looked up THROUGH the pinned connection. Fall
1155
1155
  * back to the id on any miss; never guess, a confidently wrong card is worse
1156
- * than a terse one. Omit to always show the raw id.
1156
+ * than a terse one. Omit to always show the raw id. `name` is the tool, or
1157
+ * for a dispatcher the action, so a lookup can route by resource type when
1158
+ * the id alone does not say what it is (an Asana gid).
1157
1159
  */
1158
- describeTarget?: (pinned: P, id: string) => Promise<string>;
1160
+ describeTarget?: (pinned: P, id: string, name: string) => Promise<string>;
1159
1161
  /**
1160
1162
  * Where before-images go. Required when any spec declares `undo`. The
1161
1163
  * journal's own capture returns null rather than throwing, and this wrapper
@@ -1269,6 +1271,13 @@ interface RestoreResult {
1269
1271
  error?: string;
1270
1272
  notRestored?: string;
1271
1273
  extra?: Record<string, unknown>;
1274
+ /**
1275
+ * Free-form detail appended to the runner's note (the new gid, rows it
1276
+ * could not refile, a sticker the vendor will not remove). The runner's own
1277
+ * sentence on fidelity stays first so the model reads "replacement, not an
1278
+ * undo" before the detail.
1279
+ */
1280
+ note?: string;
1272
1281
  }
1273
1282
  interface JournalRowLike<T = unknown> {
1274
1283
  entity: string;
package/dist/index.js CHANGED
@@ -617,9 +617,9 @@ function rawIdOf(args, keys) {
617
617
  function isOk(result) {
618
618
  return !!result && typeof result === "object" && result.ok !== false;
619
619
  }
620
- async function safeLabel(fn, pinned, id) {
620
+ async function safeLabel(fn, pinned, id, name) {
621
621
  try {
622
- const label = await fn(pinned, id);
622
+ const label = await fn(pinned, id, name);
623
623
  return label && label.trim() ? label : id;
624
624
  } catch {
625
625
  return id;
@@ -629,11 +629,11 @@ async function pin(opts, env, connection) {
629
629
  if (!connection || !opts.pinEnv) return env;
630
630
  return opts.pinEnv(env, connection);
631
631
  }
632
- async function askPass(spec, params, env, opts, hashPrefix) {
632
+ async function askPass(name, spec, params, env, opts, hashPrefix) {
633
633
  const connection = await opts.resolveConnection(env, params);
634
634
  const rawId = rawIdOf(params, spec.keys);
635
635
  const pinned = await pin(opts, env, connection);
636
- const target = rawId && opts.describeTarget ? await safeLabel(opts.describeTarget, pinned, rawId) : rawId || "(unknown id)";
636
+ const target = rawId && opts.describeTarget ? await safeLabel(opts.describeTarget, pinned, rawId, name) : rawId || "(unknown id)";
637
637
  const extra = spec.hash ? spec.hash(params) : [];
638
638
  return {
639
639
  ok: false,
@@ -688,7 +688,7 @@ function requireApproval(handlers, specs, opts) {
688
688
  const { [APPROVAL_GRANTED_KEY]: _granted, ...rest } = a;
689
689
  return grantedPass(name, spec, rest, env, opts, () => inner(rest, env, ctx));
690
690
  }
691
- return askPass(spec, a, env, opts, []);
691
+ return askPass(name, spec, a, env, opts, []);
692
692
  };
693
693
  }
694
694
  return gated;
@@ -707,7 +707,7 @@ function dispatcherApproval(specs, opts) {
707
707
  if (a[APPROVAL_GRANTED_KEY] === true) {
708
708
  return grantedPass(action, spec, params, env, opts, write);
709
709
  }
710
- return askPass(spec, params, env, opts, [action]);
710
+ return askPass(action, spec, params, env, opts, [action]);
711
711
  }
712
712
  };
713
713
  }
@@ -733,7 +733,7 @@ async function runUndoApply(args, opts) {
733
733
  };
734
734
  }
735
735
  const before = row.before;
736
- if (!before || typeof before !== "object") {
736
+ if (!before || typeof before !== "object" || Array.isArray(before)) {
737
737
  return { ok: false, error: "before_image_unreadable", note: "The saved copy could not be read back. Nothing was changed." };
738
738
  }
739
739
  let pinned;
@@ -769,6 +769,7 @@ async function runUndoApply(args, opts) {
769
769
  await opts.journal.dropBefore(ref);
770
770
  const recreated = spec.fidelity === "recreated";
771
771
  const notRestored = result.notRestored ?? spec.notRestored;
772
+ const suffix = result.note && result.note.trim() ? ` ${result.note.trim()}` : "";
772
773
  return {
773
774
  ok: true,
774
775
  ...result.extra ?? {},
@@ -778,7 +779,7 @@ async function runUndoApply(args, opts) {
778
779
  new_id: result.newId ?? null,
779
780
  fidelity: spec.fidelity,
780
781
  ...notRestored ? { not_restored: notRestored } : {},
781
- note: recreated ? `Created a NEW ${spec.resource}${result.newId ? ` (${result.newId})` : ""} from the saved copy. The original ${row.original_id} is still gone and its id will never be reissued.${notRestored ? ` Not restored: ${notRestored}.` : ""} Report this as a replacement, not as an undo.` : `Restored ${spec.resource} ${row.original_id} to its saved values.${notRestored ? ` Not restored: ${notRestored}.` : ""} Anything changed since the capture was overwritten.`
782
+ note: recreated ? `Created a NEW ${spec.resource}${result.newId ? ` (${result.newId})` : ""} from the saved copy. The original ${row.original_id} is still gone and its id will never be reissued.${notRestored ? ` Not restored: ${notRestored}.` : ""} Report this as a replacement, not as an undo.${suffix}` : `Restored ${spec.resource} ${row.original_id} to its saved values.${notRestored ? ` Not restored: ${notRestored}.` : ""} Anything changed since the capture was overwritten.${suffix}`
782
783
  };
783
784
  }
784
785
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sprigr/apps-app-sdk",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",