@forumone/throughline-approvals 0.2.7 → 0.3.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,69 @@
1
1
  # @forumone/throughline-approvals
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d20f909: Bind an approval to the document's content rather than to its `updatedAt`.
8
+
9
+ `request_approval` stored `String(document['updatedAt'] ?? …)` as `targetVersion`,
10
+ and publishing's approval step recomputed the same expression at publish time. So
11
+ an approval was tied to a timestamp that moves on **every** save. An editor fixing
12
+ a typo between an approver opening the request and clicking approve invalidated the
13
+ approval — and the approver spent that time reading a version that no longer
14
+ existed.
15
+
16
+ Requiring re-approval after an edit is a defensible rule. Inheriting it from
17
+ whichever timestamp field happened to be nearby is not, and it is why **autosave
18
+ could not be turned on** anywhere the approvals plugin is installed: autosave moves
19
+ `updatedAt` every couple of seconds of typing, so a pending approval would be
20
+ invalidated continuously.
21
+
22
+ Both sides now call `documentContentHash(document)`, new in
23
+ `@forumone/throughline-core`. It hashes the document with the metadata that moves
24
+ without the content moving stripped at every level — `id`, `createdAt`,
25
+ `updatedAt`, `_status`, `__v`, `_id`, `globalType` — over keys in sorted order,
26
+ since blocks come back out of JSONB in no promised order. Array order is preserved,
27
+ because that is the order of the blocks on the page. `{ exclude }` adds
28
+ app-specific bookkeeping fields to the strip list.
29
+
30
+ The rule is now the one that was wanted all along: a save that changed nothing
31
+ keeps a granted approval, a save that changed something invalidates it, and an edit
32
+ that is reverted brings the approval back. That last one is why this is a content
33
+ hash rather than a version id — a version id moves whether or not the content did.
34
+
35
+ The two sides only agree because they load the document identically, with
36
+ `payload.findByID({ collection, id, draft: true })` at the config's default depth.
37
+ A populated relationship and a bare relationship id are different values and no
38
+ normalising makes them one, so a caller hashing a document fetched at some other
39
+ depth gets a hash that matches nothing. That is stated on the function.
40
+
41
+ **Approvals pending at upgrade must be re-requested.** Their `targetVersion` holds
42
+ an ISO timestamp; the publish step now computes a hash, so nothing matches and
43
+ those documents report `approval-required` until a fresh request is granted. No
44
+ migration is offered, because the old value cannot be converted — the content it
45
+ was granted against is not recoverable from a timestamp. Grant a moment for
46
+ in-flight requests to clear before upgrading, or expect approvers to be asked once
47
+ more.
48
+
49
+ Also exports `isDraftWrite` from `@forumone/throughline-publishing`. It is the
50
+ predicate the plugin's own trust boundary uses to tell a "Save draft" apart from
51
+ an unpublish, and it is unavailable to host code that needs the same answer: an
52
+ `afterChange` hook cannot work it out, because Payload sets `data._status =
53
+ 'draft'` on any `draft: true` update before the hooks run and `previousDoc` is the
54
+ latest _version_ rather than the live document. With autosave on, a host hook that
55
+ drops a cache or sends a notification fires every few seconds of typing unless it
56
+ asks this first.
57
+
58
+ Minor rather than patch on all three: `documentContentHash` and `isDraftWrite` are
59
+ new public API, and the stored meaning of `targetVersion` changes.
60
+
61
+ ### Patch Changes
62
+
63
+ - Updated dependencies [d20f909]
64
+ - @forumone/throughline-core@0.3.0
65
+ - @forumone/throughline-publishing@0.4.0
66
+
3
67
  ## 0.2.7
4
68
 
5
69
  ### Patch Changes
package/README.md CHANGED
@@ -77,7 +77,11 @@ If you need a custom resolver (e.g. you store approvals in an external system),
77
77
  ## Phase 1 semantics
78
78
 
79
79
  - **First-decision-wins.** Multi-party approvals (e.g. legal AND communications must both approve) are deferred to Phase 2. The Phase 1 model handles "any one approver from the configured groups," which covers the most common case.
80
- - **Approvals are tied to versions.** An approval granted against one draft does not apply to a subsequent edit. The resolver checks `targetVersion` against the document version under consideration.
80
+ - **Approvals are tied to content, not to a timestamp.** `request_approval` stores `documentContentHash(document)` in `targetVersion`, and publishing's approval step recomputes the same hash from the document it is about to publish. So an approval granted against one draft does not apply to a subsequent edit but it does survive a save that changed nothing, and it comes back if an edit is reverted.
81
+
82
+ This is what lets **autosave and approvals both be on**. The binding used to be `updatedAt`, which moves on every save: an editor fixing a typo while an approver read the request invalidated the approval, and autosave did that every couple of seconds. See the note under `documentContentHash` in `@forumone/throughline-core` for what counts as content — in short, everything except `id`, `createdAt`, `updatedAt`, `_status` and the other storage bookkeeping, at every level of the document.
83
+
84
+ Both sides must load the document the same way for the hashes to agree; both use `payload.findByID({ collection, id, draft: true })`. A populated relationship and a bare relationship id are different values, so a caller hashing a document fetched at a different depth would match nothing.
81
85
  - **Action tokens are single-use, 14-day validity.** Once an approver clicks an action link, the token is appended to the request's `consumedTokens` array; reusing it returns an error.
82
86
  - **Self-approval is blocked.** The respond_to_approval tool refuses if the caller is the requester.
83
87
  - **Group resolution is configurable.** Clients define what "editorial" or "legal" means via the `groupResolver.resolveUsers` callback. Core does not hardcode group membership logic.
@@ -1 +1 @@
1
- {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,MAAM,WAAW,gCAAgC;IAC/C,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qGAAqG;IACrG,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qHAAqH;IACrH,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,eAAO,MAAM,sBAAsB,cAAc,CAAA;AAEjD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,gBAAgB,CA4FlB"}
1
+ {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,MAAM,WAAW,gCAAgC;IAC/C,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qGAAqG;IACrG,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qHAAqH;IACrH,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,eAAO,MAAM,sBAAsB,cAAc,CAAA;AAEjD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,gBAAgB,CA+FlB"}
@@ -33,7 +33,9 @@ export function createApprovalsCollection(options) {
33
33
  name: 'targetVersion',
34
34
  type: 'text',
35
35
  required: true,
36
- admin: { description: 'Document version at request time. Approvals are tied to this version.' },
36
+ admin: {
37
+ description: 'Hash of the document content at request time. An approval resolves only against a document that still hashes to this, so a save that changed nothing keeps it and a save that changed something invalidates it.',
38
+ },
37
39
  },
38
40
  { name: 'previewUrl', type: 'text' },
39
41
  // Request
@@ -1 +1 @@
1
- {"version":3,"file":"collection.js","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collection.js","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"request-approval.d.ts","sourceRoot":"","sources":["../../src/tools/request-approval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,KAAK,WAAW,EAAY,MAAM,4BAA4B,CAAA;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAE9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAE3D,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,sBAAsB,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,WAAW,EAAE,WAAW,CAAA;CACzB;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,mBAAmB,GAAG,iBAAiB,CA8HtF"}
1
+ {"version":3,"file":"request-approval.d.ts","sourceRoot":"","sources":["../../src/tools/request-approval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,KAAK,WAAW,EAAiC,MAAM,4BAA4B,CAAA;AAC5F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAE9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAE3D,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,sBAAsB,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,WAAW,EAAE,WAAW,CAAA;CACzB;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,mBAAmB,GAAG,iBAAiB,CAuItF"}
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { withMeta } from '@forumone/throughline-core';
2
+ import { documentContentHash, withMeta } from '@forumone/throughline-core';
3
3
  import { DEFAULT_APPROVALS_SLUG } from '../collection.js';
4
4
  export function createRequestApprovalTool(deps) {
5
5
  const inputSchema = withMeta({
@@ -45,7 +45,16 @@ export function createRequestApprovalTool(deps) {
45
45
  error: `No approvers found in groups: ${approverGroups.join(', ')}`,
46
46
  };
47
47
  }
48
- const targetVersion = String(document['updatedAt'] ?? document['id'] ?? input.id);
48
+ /*
49
+ What the approval is bound to. A hash of the document's content, not of
50
+ its `updatedAt` — so a save that changed nothing leaves a granted
51
+ approval standing, and one that changed something invalidates it.
52
+
53
+ Publishing's approval step hashes the same document the same way, with
54
+ the same function, from a `findByID` with the same arguments. That is
55
+ the only reason the two agree; see `documentContentHash`.
56
+ */
57
+ const targetVersion = await documentContentHash(document);
49
58
  const targetTitle = typeof document['title'] === 'string' ? document['title'] : input.id;
50
59
  const slug = typeof document['slug'] === 'string' ? document['slug'] : input.id;
51
60
  const previewUrl = buildPreviewUrl(deps.options, input.collection, slug);
@@ -1 +1 @@
1
- {"version":3,"file":"request-approval.js","sourceRoot":"","sources":["../../src/tools/request-approval.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request-approval.js","sourceRoot":"","sources":["../../src/tools/request-approval.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forumone/throughline-approvals",
3
- "version": "0.2.7",
3
+ "version": "0.3.0",
4
4
  "description": "Conversational approval workflow server for Throughline. Provides the approval resolver the publishing server consumes plus MCP tools for requesting and responding to approvals.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -42,9 +42,9 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "zod": "^3.23.0",
45
- "@forumone/throughline-core": "0.2.2",
45
+ "@forumone/throughline-core": "0.3.0",
46
46
  "@forumone/throughline-plugin-contract": "0.2.1",
47
- "@forumone/throughline-publishing": "0.3.4"
47
+ "@forumone/throughline-publishing": "0.4.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/node": "^20.17.0",