@tokenoftrust/storefront-runner 1.4.0 → 1.4.2-rc.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.
Files changed (193) hide show
  1. package/apps/storefront/astro.config.mjs +17 -1
  2. package/apps/storefront/integrations/materialize-guard.mjs +56 -0
  3. package/apps/storefront/migrations-apps/0001_woozy_lyja.sql +22 -0
  4. package/apps/storefront/migrations-apps/0002_good_switch.sql +26 -0
  5. package/apps/storefront/migrations-apps/0003_mute_marauders.sql +12 -0
  6. package/apps/storefront/migrations-apps/meta/0001_snapshot.json +990 -0
  7. package/apps/storefront/migrations-apps/meta/0002_snapshot.json +1160 -0
  8. package/apps/storefront/migrations-apps/meta/0003_snapshot.json +1235 -0
  9. package/apps/storefront/migrations-apps/meta/_journal.json +21 -0
  10. package/apps/storefront/package.json +0 -1
  11. package/apps/storefront/public/js/dashboard-team.js +38 -2
  12. package/apps/storefront/src/components/Seo.astro +65 -1
  13. package/apps/storefront/src/components/admin/AdminBlogDetailRail.astro +878 -0
  14. package/apps/storefront/src/components/admin/AdminBlogTab.astro +1432 -0
  15. package/apps/storefront/src/components/admin/AdminCustomersTab.astro +3 -7
  16. package/apps/storefront/src/components/admin/AdminPublishTab.astro +1756 -1382
  17. package/apps/storefront/src/components/admin/AdminSubscriptionsTab.astro +1 -3
  18. package/apps/storefront/src/components/blog/BlogPaywall.astro +87 -0
  19. package/apps/storefront/src/components/blog/PostAccessBadge.astro +43 -0
  20. package/apps/storefront/src/components/blog/PostGrid.astro +57 -0
  21. package/apps/storefront/src/components/blog/ReactionBar.astro +214 -0
  22. package/apps/storefront/src/layouts/Layout.astro +48 -3
  23. package/apps/storefront/src/lib/activity/alerts.ts +426 -0
  24. package/apps/storefront/src/lib/activity/changeActorAttribution.ts +85 -0
  25. package/apps/storefront/src/lib/activity/deployVersion.ts +120 -0
  26. package/apps/storefront/src/lib/activity/ingest.ts +188 -0
  27. package/apps/storefront/src/lib/activity/ingestAuth.ts +105 -0
  28. package/apps/storefront/src/lib/activity/killSwitch.ts +80 -0
  29. package/apps/storefront/src/lib/activity/query.ts +403 -0
  30. package/apps/storefront/src/lib/activity/recordActivity.ts +101 -0
  31. package/apps/storefront/src/lib/activity/store.ts +120 -0
  32. package/apps/storefront/src/lib/activity/uiActor.ts +150 -0
  33. package/apps/storefront/src/lib/activity/workerCommit.ts +70 -0
  34. package/apps/storefront/src/lib/admin/adminShell.ts +290 -0
  35. package/apps/storefront/src/lib/admin/ai/approvalMode.ts +2 -3
  36. package/apps/storefront/src/lib/admin/ai/audit.ts +3 -5
  37. package/apps/storefront/src/lib/admin/checkoutStyleInput.ts +7 -7
  38. package/apps/storefront/src/lib/admin/checkoutStyleTarget.ts +3 -3
  39. package/apps/storefront/src/lib/admin/orderClient.ts +3 -5
  40. package/apps/storefront/src/lib/admin/services/orders.ts +17 -19
  41. package/apps/storefront/src/lib/admin/viewmodels/aiWorkflows.ts +4 -6
  42. package/apps/storefront/src/lib/admin/viewmodels/settings.ts +1 -1
  43. package/apps/storefront/src/lib/apps/adminService.ts +4 -4
  44. package/apps/storefront/src/lib/apps/adminSession.ts +53 -44
  45. package/apps/storefront/src/lib/apps/apiAuth.ts +2 -2
  46. package/apps/storefront/src/lib/apps/apiRoute.ts +2 -2
  47. package/apps/storefront/src/lib/apps/catalogMapper.ts +1 -1
  48. package/apps/storefront/src/lib/apps/credentials.ts +2 -2
  49. package/apps/storefront/src/lib/apps/gatewayKeys.ts +4 -4
  50. package/apps/storefront/src/lib/apps/healthAggregate.ts +5 -5
  51. package/apps/storefront/src/lib/apps/orders/attributionService.ts +2 -2
  52. package/apps/storefront/src/lib/apps/orders/customerHash.ts +1 -1
  53. package/apps/storefront/src/lib/apps/orders/foxyOrderClient.ts +12 -12
  54. package/apps/storefront/src/lib/apps/orders/idempotency.ts +7 -7
  55. package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +1 -1
  56. package/apps/storefront/src/lib/apps/orders/orderMapper.ts +2 -2
  57. package/apps/storefront/src/lib/apps/orders/ordersStore.ts +6 -6
  58. package/apps/storefront/src/lib/apps/registryService.ts +6 -6
  59. package/apps/storefront/src/lib/apps/scopes.ts +2 -2
  60. package/apps/storefront/src/lib/apps/tokenIssuer.ts +4 -4
  61. package/apps/storefront/src/lib/apps/tokenVerifier.ts +6 -6
  62. package/apps/storefront/src/lib/apps/widgets/eligibility.ts +2 -2
  63. package/apps/storefront/src/lib/apps/widgets/frameProps.ts +3 -3
  64. package/apps/storefront/src/lib/apps/widgets/launchToken.ts +4 -4
  65. package/apps/storefront/src/lib/apps/widgets/placements.ts +2 -2
  66. package/apps/storefront/src/lib/apps/widgets/renderSlot.ts +1 -1
  67. package/apps/storefront/src/lib/auth/adminEntry.ts +9 -9
  68. package/apps/storefront/src/lib/auth/identityToken.ts +6 -14
  69. package/apps/storefront/src/lib/auth/loginGate.ts +75 -13
  70. package/apps/storefront/src/lib/auth/mcpClientAssertion.ts +6 -4
  71. package/apps/storefront/src/lib/auth/operatorSession.ts +113 -0
  72. package/apps/storefront/src/lib/auth/route.ts +44 -4
  73. package/apps/storefront/src/lib/auth/session.ts +7 -8
  74. package/apps/storefront/src/lib/auth/totAccessClient.ts +8 -18
  75. package/apps/storefront/src/lib/basePath.ts +9 -2
  76. package/apps/storefront/src/lib/blog/access.ts +29 -0
  77. package/apps/storefront/src/lib/blog/collection.ts +313 -0
  78. package/apps/storefront/src/lib/blog/markdown.ts +174 -0
  79. package/apps/storefront/src/lib/blog/provider.ts +5 -0
  80. package/apps/storefront/src/lib/blog/reactions.ts +87 -0
  81. package/apps/storefront/src/lib/blog/rss.ts +92 -0
  82. package/apps/storefront/src/lib/blog/teaser.ts +83 -0
  83. package/apps/storefront/src/lib/blog/types.ts +34 -0
  84. package/apps/storefront/src/lib/blog/viewCounts.ts +243 -0
  85. package/apps/storefront/src/lib/d1/catalog.ts +2 -2
  86. package/apps/storefront/src/lib/d1/schema-apps.ts +147 -14
  87. package/apps/storefront/src/lib/dev/activityIngestToken.ts +2 -4
  88. package/apps/storefront/src/lib/dev/activityStore.ts +3 -5
  89. package/apps/storefront/src/lib/dev/apiBase.ts +1 -4
  90. package/apps/storefront/src/lib/dev/cockpitStore.ts +1 -9
  91. package/apps/storefront/src/lib/dev/devDraft.ts +1 -1
  92. package/apps/storefront/src/lib/dev/previewStatus.ts +9 -21
  93. package/apps/storefront/src/lib/dev/rendezvousBroker.ts +9 -24
  94. package/apps/storefront/src/lib/edgeCache.ts +17 -0
  95. package/apps/storefront/src/lib/env.ts +51 -0
  96. package/apps/storefront/src/lib/http/fetchTransport.ts +63 -0
  97. package/apps/storefront/src/lib/i18n.ts +25 -0
  98. package/apps/storefront/src/lib/jsonld.ts +118 -0
  99. package/apps/storefront/src/lib/monitoring/manifest.ts +11 -11
  100. package/apps/storefront/src/lib/newsletter/confirmationEmail.ts +30 -0
  101. package/apps/storefront/src/lib/newsletter/consent.ts +23 -0
  102. package/apps/storefront/src/lib/newsletter/digest.ts +117 -0
  103. package/apps/storefront/src/lib/newsletter/resendClient.ts +79 -0
  104. package/apps/storefront/src/lib/newsletter/send.ts +265 -0
  105. package/apps/storefront/src/lib/newsletter/subscribers.ts +156 -0
  106. package/apps/storefront/src/lib/publish/adminPublishTab.ts +3519 -0
  107. package/apps/storefront/src/lib/publish/apex-readiness.ts +41 -18
  108. package/apps/storefront/src/lib/publish/dispatchHealth.ts +5 -7
  109. package/apps/storefront/src/lib/publish/domainState.ts +22 -13
  110. package/apps/storefront/src/lib/publish/panelPolling.ts +78 -0
  111. package/apps/storefront/src/lib/publish/shipWorkspace.ts +100 -42
  112. package/apps/storefront/src/lib/publish/stageBundleUpload.ts +215 -0
  113. package/apps/storefront/src/lib/rate/kvWindow.ts +53 -0
  114. package/apps/storefront/src/lib/search/index.ts +2 -2
  115. package/apps/storefront/src/lib/seo/alternates.ts +42 -0
  116. package/apps/storefront/src/lib/seo/meta.ts +65 -0
  117. package/apps/storefront/src/lib/social/golive.ts +212 -0
  118. package/apps/storefront/src/lib/social/notify.ts +32 -0
  119. package/apps/storefront/src/lib/social/tokenStore.ts +171 -0
  120. package/apps/storefront/src/lib/the-build/provider.ts +27 -0
  121. package/apps/storefront/src/lib/the-build/readingTime.ts +35 -0
  122. package/apps/storefront/src/lib/the-build/toc.ts +95 -0
  123. package/apps/storefront/src/lib/tot/ToTClient.ts +1 -1
  124. package/apps/storefront/src/lib/tot/d1Client.ts +2 -2
  125. package/apps/storefront/src/lib/tot/totClientInterface.ts +3 -4
  126. package/apps/storefront/src/lib/webhooks/deliveryStore.ts +16 -17
  127. package/apps/storefront/src/middleware/index.ts +130 -2
  128. package/apps/storefront/src/pages/admin/ops-timeline.astro +420 -0
  129. package/apps/storefront/src/pages/admin.astro +52 -1206
  130. package/apps/storefront/src/pages/api/activity.ts +137 -0
  131. package/apps/storefront/src/pages/api/admin/activity-alerts.ts +73 -0
  132. package/apps/storefront/src/pages/api/apps/admin/credentials/rotate.ts +27 -1
  133. package/apps/storefront/src/pages/api/apps/admin/install.ts +26 -1
  134. package/apps/storefront/src/pages/api/apps/admin/resume.ts +24 -1
  135. package/apps/storefront/src/pages/api/apps/admin/suspend.ts +24 -1
  136. package/apps/storefront/src/pages/api/apps/admin/uninstall.ts +25 -1
  137. package/apps/storefront/src/pages/api/apps/admin/update.ts +24 -1
  138. package/apps/storefront/src/pages/api/apps/admin/webhooks/deliveries/[deliveryId]/replay.ts +11 -0
  139. package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +11 -0
  140. package/apps/storefront/src/pages/api/apps/v1/attribution.ts +20 -0
  141. package/apps/storefront/src/pages/api/apps/v1/webhooks/deliveries/[deliveryId]/replay.ts +12 -0
  142. package/apps/storefront/src/pages/api/blog/[collection]/[slug]/react.ts +104 -0
  143. package/apps/storefront/src/pages/api/cache-purge.ts +11 -0
  144. package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +30 -0
  145. package/apps/storefront/src/pages/api/newsletter/[collection]/subscribe.ts +146 -0
  146. package/apps/storefront/src/pages/api/newsletter/confirm.ts +75 -0
  147. package/apps/storefront/src/pages/api/newsletter/unsubscribe.ts +90 -0
  148. package/apps/storefront/src/pages/api/publish/stage-bundle.ts +70 -0
  149. package/apps/storefront/src/pages/api/rum/vitals.ts +21 -2
  150. package/apps/storefront/src/pages/auth/login.astro +5 -4
  151. package/apps/storefront/src/pages/blog/[slug].astro +96 -16
  152. package/apps/storefront/src/pages/blog/author/[author].astro +140 -0
  153. package/apps/storefront/src/pages/blog/category/[category].astro +67 -0
  154. package/apps/storefront/src/pages/blog/index.astro +2 -0
  155. package/apps/storefront/src/pages/blog/tag/[tag].astro +65 -0
  156. package/apps/storefront/src/pages/cockpit.astro +74 -12
  157. package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +15 -11
  158. package/apps/storefront/src/pages/search.astro +1 -1
  159. package/apps/storefront/src/pages/sitemap.xml.ts +20 -0
  160. package/apps/storefront/src/pages/the-build/[slug].astro +129 -0
  161. package/apps/storefront/src/pages/the-build/index.astro +146 -0
  162. package/apps/storefront/src/pages/the-build/rss.xml.ts +33 -0
  163. package/apps/storefront/src/styles/admin.css +1080 -0
  164. package/apps/storefront/tsconfig.json +5 -0
  165. package/package.json +1 -1
  166. package/packages/public-runtime/package.json +1 -0
  167. package/packages/public-runtime/src/activity/README.md +146 -0
  168. package/packages/public-runtime/src/activity/catalog.ts +553 -0
  169. package/packages/public-runtime/src/activity/event.ts +168 -0
  170. package/packages/public-runtime/src/activity/index.ts +16 -0
  171. package/packages/public-runtime/src/activity/redaction.ts +263 -0
  172. package/packages/public-runtime/src/candidate-index.ts +13 -0
  173. package/packages/public-runtime/src/catalog-d1.ts +1 -1
  174. package/packages/public-runtime/src/customization-preview.ts +25 -2
  175. package/packages/public-runtime/src/customization-runtime.ts +125 -3
  176. package/packages/public-runtime/src/customization-versioning.ts +10 -0
  177. package/packages/public-runtime/src/index.ts +7 -0
  178. package/packages/public-runtime/src/static-bundle.ts +357 -0
  179. package/packages/public-runtime/src/tenant.ts +36 -8
  180. package/scripts/build/copy-tenant-assets.mjs +14 -4
  181. package/scripts/dev/ai-edit.mjs +1 -1
  182. package/scripts/dev/checkout-watch.mjs +2 -2
  183. package/scripts/dev/file-browser.mjs +2 -4
  184. package/scripts/dev/file-writer.mjs +1 -1
  185. package/scripts/dev/git-status.mjs +2 -2
  186. package/scripts/dev/locate-handler.mjs +3 -3
  187. package/scripts/dev/port-check.mjs +3 -3
  188. package/scripts/dev/publish.mjs +5 -9
  189. package/scripts/dev/shot.mjs +1 -1
  190. package/scripts/dev/unified-diff.mjs +8 -3
  191. package/scripts/tot-dev.mjs +6 -9
  192. package/apps/storefront/src/lib/webhooks/signing.ts +0 -29
  193. package/apps/storefront/src/lib/webhooks/webhookSigningKey.ts +0 -146
@@ -1,4 +1,9 @@
1
1
  {
2
+ // Unlike the packages/* configs (which extend the repo's ../../tsconfig.base.json),
3
+ // the storefront extends Astro's own preset: it wires up .astro type resolution
4
+ // (.astro/types.d.ts), Astro/Vite bundler module resolution, and the Preact JSX
5
+ // runtime the client islands compile against. verbatimModuleSyntax is turned off
6
+ // (the base sets it on) because the JSX/Preact + Astro compilation model needs it.
2
7
  "extends": "astro/tsconfigs/strict",
3
8
  "compilerOptions": {
4
9
  "strict": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "1.4.0",
3
+ "version": "1.4.2-rc.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
6
6
  "packageManager": "pnpm@11.9.0",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@tot/public-runtime",
3
3
  "version": "0.1.0",
4
+ "description": "Public, edge-shipped storefront runtime model — renderer-safe tenant/product/catalog types, the CSP builder, the customization read/apply runtime, and the activity-telemetry contract. Node-free and open-sourceable; bundles into the Cloudflare Worker and must not import @tot/private-controlplane.",
4
5
  "private": true,
5
6
  "license": "SEE LICENSE IN LICENSE",
6
7
  "type": "module",
@@ -0,0 +1,146 @@
1
+ # Operational activity telemetry — the actor×action contract (card D0)
2
+
3
+ The foundation the D1–D8 cards build on. Everything here is **pure types + pure
4
+ functions** in `@tot/public-runtime` (the node-free, dependency-free edge base),
5
+ so the storefront server, the Cloudflare Worker edge bundle, and the CLI's JS
6
+ mirror can all consume it. Nothing here does I/O or picks a store — the store
7
+ **decision** and cost model live in the repo-root `DECISIONS.md` §8; the
8
+ per-action store **routing** lives on each catalog entry (`sinks`).
9
+
10
+ Files:
11
+
12
+ | File | What |
13
+ |------|------|
14
+ | `event.ts` | The `ActivityEvent` envelope, `ACTIVITY_SCHEMA_VERSION`, `newEventId()`. |
15
+ | `catalog.ts` | The allowlisted `ACTION_CATALOG` registry + `ActionKey` + guards. |
16
+ | `redaction.ts` | Default-deny redaction contract + `createActivityEvent()` (the safe constructor). |
17
+
18
+ ## The envelope
19
+
20
+ One event says: **an ACTOR performed an ACTION, here is the OUTCOME**, scoped to
21
+ a tenant/change, from a source, at a time. The design invariant is a hard split
22
+ between two zones:
23
+
24
+ - **Core fields** (`v`, `id`, `at`, `actor`, `action`, `source`, `scope`,
25
+ `outcome`) — *always safe to store, never redacted*. They carry no free text
26
+ and no third-party PII **by construction**: `actor.id` is opaque, `action` is
27
+ an allowlisted catalog key, `outcome.errorClass` is a low-cardinality class
28
+ (never a raw message).
29
+ - **`payload`** (`args` + `rendered`) — the *extensible, always-redacted* zone.
30
+ Whatever a call site puts here is default-**denied**.
31
+
32
+ ```ts
33
+ import { createActivityEvent } from "@tot/public-runtime";
34
+
35
+ const { event, report } = createActivityEvent({
36
+ action: "cli.command.result", // must be a catalog key (compile-checked)
37
+ actor: { kind: "dev", id: hashedDevId },
38
+ source: "cli",
39
+ scope: { tenantId, traceId },
40
+ outcome:{ status: "succeeded", durationMs: 812 },
41
+ payload:{ args: { command: "ship", cliVersion: "1.4.0", exitCode: 0,
42
+ secretToken: "…" } }, // ← dropped: not allowlisted / key canary
43
+ });
44
+ // event.payload.args === { command: "ship", cliVersion: "1.4.0", exitCode: 0 }
45
+ ```
46
+
47
+ `createActivityEvent()` is the **only** sanctioned constructor: it fills
48
+ `v`/`id`/`at` and runs the raw payload through the redaction contract, so you
49
+ **cannot** produce an event whose payload skipped redaction.
50
+
51
+ ## The action catalog
52
+
53
+ `action` is never a free string — it is a key of `ACTION_CATALOG`. Each entry
54
+ declares `actors` (who may emit it), `source`, `sinks` (store routing), and the
55
+ default-deny `argsAllow` / `renderedAllow` payload allowlists. Adding a new
56
+ action = a deliberate edit to `catalog.ts` (+ the CLI mirror, below), never an
57
+ ad-hoc string at a call site. This is what keeps the D5 query surface and the
58
+ D6/D7 alert rules tractable.
59
+
60
+ ### The naming standard (two tiers)
61
+
62
+ Every key is dot-namespaced and its **first segment is a `<domain>`** — there are
63
+ **no un-namespaced keys**. The domain prefix is stable so dashboards and alert rules
64
+ can glob it (`change.*`, `preview.*`, …). Within that, the catalog uses **two shapes**,
65
+ chosen by whether the action is atomic or two-phase:
66
+
67
+ - **`<domain>.<verb>` (imperative)** — an **atomic** action that happens in one shot.
68
+ Examples: `change.ship`, `change.revert`, `change.go_live`, `grant.invite`,
69
+ `grant.revoke`, `store.connect`, `preview.override`.
70
+ - **`<domain>.<entity>.<verb|state>` (participle/state)** — a **two-phase / async**
71
+ action that **opens then closes** (an invoke/result pair, or a received→terminal span).
72
+ Examples: `cli.command.invoked` + `cli.command.result`, `preview.build.requested` +
73
+ `preview.build.completed`, `webhook.reconcile.received` + `reconcile.terminal`.
74
+
75
+ The **domain must be one of the closed set**: `cli`, `dev`, `preview`, `webhook`,
76
+ `reconcile`, `deploy`, `change`, `content`, `grant`, `store`, `app`, `agent`, `system`.
77
+ Adding a key with a new domain is a deliberate decision — widen this list here first.
78
+
79
+ **Two-phase pairing going forward:** a **new** two-phase action pairs `.invoked` /
80
+ `.result`. The pre-existing `.requested` / `.completed` (`preview.build.*`) and
81
+ `.received` / `.terminal` (`webhook.reconcile.received` + `reconcile.terminal`) pairs are
82
+ **grandfathered as-is — do not rename them** (`alerts.ts` hardcodes some of these literals,
83
+ so a rename would silently break the D7 detectors).
84
+
85
+ The initial catalog was reverse-engineered from the activity surfaces that **already
86
+ exist informally** in this repo (CLI dispatch + `~/.tot/activity.log`, the obstacle
87
+ beacon, the local→hosted dev bridge, preview/reconcile/webhook, deploy provenance, the
88
+ ShipLoop `CHANGE_STATES` + admin ship routes, app installs), so D1–D3 map onto it 1:1.
89
+
90
+ ## The redaction contract (the D8 attack surface)
91
+
92
+ Applied to `payload` for every event, in order:
93
+
94
+ 1. **Default-deny allowlist** — only the top-level keys named by the action's
95
+ `argsAllow`/`renderedAllow` are eligible. Everything else is **dropped**: not
96
+ stored, not logged, never "kept raw and redacted later".
97
+ 2. **Primitive-only values** — an allowlisted value must be string/number/bool.
98
+ Objects/arrays are dropped (nested structures are where secrets hide; we do
99
+ not walk them). Structured args flatten into named primitive keys at the call
100
+ site.
101
+ 3. **Canary scan** — allowlisted primitives are scanned for secret/PII **shapes**
102
+ (JWT, bearer, AWS/GitHub/Slack/OpenAI keys, private keys, email, card, phone,
103
+ high-entropy tokens) and secret-looking **key names** (`token`, `secret`,
104
+ `password`, `authorization`, …). A value hit → replaced with `«redacted»` and
105
+ reported (`report.canaryTripped`); a key-name hit → dropped outright.
106
+
107
+ The `RedactionReport` returned alongside the event carries **the fact of** each
108
+ drop/hit (lane, key, reason, canary label) — never the offending value. D4's
109
+ ingest logs it and emits `system.ingest.rejected` when a canary trips; D6/D7
110
+ alert on `canaryTripped`.
111
+
112
+ ## Consuming this from the downstream cards
113
+
114
+ - **D1 server `recordActivity()`** — import `createActivityEvent`, build the
115
+ event, fan out to the sinks named on the action's `spec.sinks` (start with
116
+ `logs`; supersede the interim `apps/storefront/src/lib/activity/recordActivity.ts`
117
+ slice, whose `candidate.reject` becomes `change.reject`).
118
+ - **D2 deploy provenance** — emit `deploy.version_observed`.
119
+ - **D3 CLI `emitActivity`** — the CLI is **pure JS and does not import TS
120
+ packages** (it publishes to npm standalone and mirrors TS contracts with
121
+ keep-in-step tests, e.g. `no-gitea-links.test.mjs`). So D3 ships a small JS
122
+ mirror of the `ActionKey` list + the safe-constructor shape, plus a
123
+ keep-in-step test that fails the build if the mirror drifts from
124
+ `catalog.ts`. **Do not** make the CLI depend on `@tot/public-runtime`.
125
+ - **D4 ingest + store** — validate with `isActionKey` + `isActorAllowed`, run
126
+ `redactPayload` (belt-and-suspenders even though emitters already redacted),
127
+ route by `spec.sinks`. See `DECISIONS.md` §8 for the D1 table (`activity_events`
128
+ in `STOREFRONT_APPS_DB`, alongside the existing `app_audit_log`) and the
129
+ Analytics Engine binding to provision.
130
+ - **D5 query/timeline UI** — reads the `timeline`-sink rows from D1.
131
+
132
+ ## Open questions deliberately left for downstream
133
+
134
+ - **Actor-id pseudonymization salt** (D1/D4). This module scrubs PII that leaks
135
+ into the *payload*, but `actor.id` in the core zone is the emitter's job to
136
+ pseudonymize. A shared salted non-reversible hash helper (salt as a Worker
137
+ secret) should land with D1/D4 — do **not** bake a weak unsalted hash into this
138
+ edge-shipped package.
139
+ - **Analytics Engine binding + D1 `activity_events` schema** (D4). Named in
140
+ `DECISIONS.md` §8; the actual `wrangler.toml` binding and the Drizzle migration
141
+ are D4's to write.
142
+ - **Retention/pruning job for the D1 timeline** (D4/D5). Arbitrary retention is
143
+ the reason the queryable cohort is in D1 not Analytics Engine; the pruning
144
+ cron is downstream.
145
+ - **Agent cohort payload** — `agent.action.*` keys are a placeholder spine with
146
+ minimal args until the agent-cohort card defines what an agent may record.