@hazem3500/palette 0.9.111 → 0.9.112

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/NODE.md CHANGED
@@ -191,3 +191,68 @@ grant are refused behind the proxy even after opt-in. Bounded, explicitly scoped
191
191
  existing tokens remain usable. Nonproxy token policy is unchanged. Snapshot GET
192
192
  requires `comments:read`, the granted project and an allowed Origin. No deployment
193
193
  is enabled by this configuration example.
194
+
195
+ ### Webhook delivery and snapshot readiness
196
+
197
+ Apply PostgreSQL migration 008 (automatic at Node startup) or D1 migration
198
+ 0022 before running this version. Comment creation, replies and resolution
199
+ commit their selected webhook into `webhook_outbox` in the same transaction as
200
+ the mutation. No destination is configured by default. The outbox pins the URL,
201
+ encrypted signing secret, event ID and exact JSON bytes at creation. Changing or
202
+ disabling project webhook settings affects future events; queued events retain
203
+ their destination. Keep old encryption keys available until those entries drain.
204
+
205
+ Node drains every 10 seconds. Workers must configure a recurring Cron Trigger
206
+ (for example every minute); the exported Worker `scheduled` handler drains the
207
+ outbox. Custom runtimes can import `drainWebhooks` from the server export and
208
+ call `await drainWebhooks(env)` periodically. Request `waitUntil` only accelerates
209
+ these committed deliveries. Worker deployments must supply their existing
210
+ `PALETTE_WEBHOOK_SEND` transport; it must reject non-2xx responses, reject within
211
+ 5 seconds, validate DNS against private addresses, pin the validated address,
212
+ and never follow redirects. No unsafe fetch transport is installed implicitly.
213
+ The built-in Node transport enforces public DNS/IP pinning and bounded DNS/send
214
+ timeouts, and now rejects all non-2xx responses.
215
+
216
+ Each drain claims at most 20 entries, one at a time, with an atomic conditional
217
+ UPDATE and a 30-second lease. Six attempts maximum, including interrupted
218
+ attempts; failed attempts wait 10, 20, 40, 80 and 160 seconds (plus scheduling
219
+ latency). Expired claims can be recovered by another process. Completion uses
220
+ the claim token so a stale worker cannot acknowledge a newer claim. The drain
221
+ stops waiting for an attempt after 5 seconds. Custom transports must enforce
222
+ that bound themselves: a Promise timeout cannot cancel their network effects.
223
+ Delivery is at least once: a crash after remote acceptance can cause duplicates.
224
+ Deduplicate by `X-Palette-Delivery` (legacy `X-Komo-Delivery` is identical).
225
+ Each attempt signs the stored body with a fresh current Unix-second timestamp;
226
+ header aliases and the `timestamp + "." + body` HMAC format are unchanged.
227
+
228
+ Operators can inspect `id,project,attempts,state,next_attempt,claim_until` in
229
+ `webhook_outbox`; attempt/lease times are Unix milliseconds.
230
+ `delivered` and `exhausted` are retained; no automatic purge or
231
+ external delivery-management endpoint is provided. After fixing a receiver,
232
+ explicitly reset an exhausted entry's `attempts=0,state='pending',next_attempt=0,
233
+ claim_until=0,claim_token=''` to replay its same ID/body. Do not reset an active
234
+ lease. Purge retained entries using your database retention policy; bodies may
235
+ contain comment content. Outbox rows are independent of thread deletion.
236
+
237
+ `config.snapshots.readiness: true` advertises this protocol; clients omit new
238
+ intent fields and terminal reports on older servers.
239
+ `POST /threads` accepts optional boolean `snapshotIntent`. Its `comment.created`
240
+ event gains `snapshotStatus: 'pending'` for true or `'skipped'` for false.
241
+ Omitting intent leaves status unknown and preserves the existing event fields,
242
+ so older clients can still upload later without claiming an intentional skip.
243
+ Legacy intent is never inferred from an image 404. There is no new snapshot event.
244
+
245
+ Authenticated `GET /threads/:id/snapshot` returns `{status,kinds}`. `status` is
246
+ `pending`, `ready`, `skipped`, `failed`, or `unknown` (legacy/imported threads).
247
+ `kinds` lists stored `image`/`html` captures. Any successfully stored kind means
248
+ ready; it does not promise both kinds. The upload transaction sets ready.
249
+ Pending capture older than ten minutes reads as failed, bounding abandoned
250
+ client captures. A later successful upload can still make it ready.
251
+ `POST /threads/:id/snapshot` with JSON `{status:'skipped'}` or `{status:'failed'}`
252
+ terminates a pending capture; clients report intentional omissions and upload
253
+ failures this way. A failed status report falls back to the ten-minute deadline.
254
+ Deleting the final stored kind makes status skipped. Kind-specific GET routes
255
+ retain their existing 404 semantics. Snapshot status reads use existing
256
+ project/repo/branch authentication and PAT `comments:read`; writes retain guest
257
+ consent and author/reviewer checks and PAT `comments:write`. No token enablement
258
+ policy changes are included.