Skip to content

Commit f219c42

Browse files
committed
docs(webhooks): correct the redeliver route's contract and regenerate the spec references (#8069)
The route table said "Re-queue a previously failed/dead delivery" and enumerated the failure codes as RESOURCE_NOT_FOUND / DELIVERY_NOT_ELIGIBLE. Both are now false for the population this card creates: a dead row with 0 attempts is a parked record, and redelivering it is refused with 409 DELIVERY_NEVER_SENT. content/docs/references/ is regenerated, not hand-edited. Every line of that diff flows from the one ledger entry: 132 lines are the rendered ErrorCode enum's cardinality counter (+265 more -> +266 more), and 2 list the new code. Verified NOT to be inherited drift — check:docs is green on this branch with only the ledger entry reverted and the json-schema tree regenerated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARidKDYSCD56LaygrvDPnk
1 parent 3c3604a commit f219c42

12 files changed

Lines changed: 78 additions & 69 deletions

File tree

‎content/docs/automation/webhooks.mdx‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,13 +504,20 @@ The plugin mounts exactly **one** custom endpoint:
504504

505505
| Method | Path | Body | Purpose |
506506
|--------|-----------------------------|-------------------|--------------------------------------------------|
507-
| POST | `/api/v1/webhooks/redeliver` | `{ deliveryId }` | Re-queue a previously failed/dead delivery. |
507+
| POST | `/api/v1/webhooks/redeliver` | `{ deliveryId }` | Re-queue a delivery that was **attempted** and failed. A row that was never attempted cannot be redelivered. |
508508

509509
It delegates to `messaging.redeliverHttp(deliveryId)` and is guarded by the
510510
better-auth session (any authenticated user). Failures answer in the declared
511511
envelope — `{ success: false, error: { code, message } }` — with `401`
512512
`UNAUTHENTICATED`, `400` `INVALID_REQUEST` or `MISSING_REQUIRED_FIELD`, `404`
513-
`RESOURCE_NOT_FOUND`, `409` `DELIVERY_NOT_ELIGIBLE` (ADR-0112). There are no
513+
`RESOURCE_NOT_FOUND`, `409` `DELIVERY_NOT_ELIGIBLE`, or `409`
514+
`DELIVERY_NEVER_SENT` (ADR-0112). The last one is the refusal behind the table
515+
row above: a row with `attempts = 0` is a durable record of a delivery that
516+
could never be prepared — its webhook's signing secret could not be decrypted —
517+
so it carries **no HMAC signature**, and re-queuing it would not replay
518+
anything, it would send the payload for the first time and send it unsigned.
519+
Fix the signing configuration instead; the subscription re-arms on its own and
520+
subsequent events are delivered signed. There are no
514521
`/webhooks/:id/test`, `/rotate`, `/deliveries`, or per-delivery redeliver routes.
515522

516523
## 9. Concurrency & rate-limiting

‎content/docs/references/api/analytics.mdx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const result = AnalyticsEndpoint.parse(data);
4444
| Property | Type | Required | Description |
4545
| :--- | :--- | :--- | :--- |
4646
| **success** | `boolean` | ✅ | Operation success status |
47-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
47+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
4848
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
4949
| **data** | `{ name: string; title?: string; measures: object[]; dimensions: object[] }[]` | ✅ | Available cubes, each as the `CubeMeta` discovery projection — the cube name, its title, and the measures/dimensions a client may name in a query. A bare array: there is no `cubes` wrapper object, and no cube `sql` is published. |
5050

@@ -79,7 +79,7 @@ const result = AnalyticsEndpoint.parse(data);
7979
| Property | Type | Required | Description |
8080
| :--- | :--- | :--- | :--- |
8181
| **success** | `boolean` | ✅ | Operation success status |
82-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
82+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
8383
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
8484
| **data** | `{ rows: Record<string, any>[]; fields: object[]; sql?: string }` | ✅ | |
8585

@@ -93,7 +93,7 @@ const result = AnalyticsEndpoint.parse(data);
9393
| Property | Type | Required | Description |
9494
| :--- | :--- | :--- | :--- |
9595
| **success** | `boolean` | ✅ | Operation success status |
96-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
96+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
9797
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
9898
| **data** | `{ sql: string; params: any[] }` | ✅ | |
9999

‎content/docs/references/api/auth.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ const result = AuthProvider.parse(data);
117117
| Property | Type | Required | Description |
118118
| :--- | :--- | :--- | :--- |
119119
| **success** | `boolean` | ✅ | Operation success status |
120-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
120+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
121121
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
122122
| **data** | `{ session: object; user: object; token?: string }` | ✅ | |
123123

@@ -153,7 +153,7 @@ const result = AuthProvider.parse(data);
153153
| Property | Type | Required | Description |
154154
| :--- | :--- | :--- | :--- |
155155
| **success** | `boolean` | ✅ | Operation success status |
156-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
156+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
157157
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
158158
| **data** | `{ id: string; email: string; emailVerified: boolean; name: string; … }` | ✅ | |
159159

‎content/docs/references/api/automation-api.mdx‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ const result = AutomationApiErrorCode.parse(data);
119119
| Property | Type | Required | Description |
120120
| :--- | :--- | :--- | :--- |
121121
| **success** | `boolean` | ✅ | Operation success status |
122-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
122+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
123123
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
124124
| **data** | `{ name: string; label: string; description?: string; successMessage?: string; … }` | ✅ | The created flow definition |
125125

@@ -144,7 +144,7 @@ const result = AutomationApiErrorCode.parse(data);
144144
| Property | Type | Required | Description |
145145
| :--- | :--- | :--- | :--- |
146146
| **success** | `boolean` | ✅ | Operation success status |
147-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
147+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
148148
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
149149
| **data** | `{ name: string; deleted: boolean }` | ✅ | |
150150

@@ -187,7 +187,7 @@ const result = AutomationApiErrorCode.parse(data);
187187
| Property | Type | Required | Description |
188188
| :--- | :--- | :--- | :--- |
189189
| **success** | `boolean` | ✅ | Operation success status |
190-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
190+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
191191
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
192192
| **data** | `{ name: string; label: string; description?: string; successMessage?: string; … }` | ✅ | Full flow definition |
193193

@@ -213,7 +213,7 @@ const result = AutomationApiErrorCode.parse(data);
213213
| Property | Type | Required | Description |
214214
| :--- | :--- | :--- | :--- |
215215
| **success** | `boolean` | ✅ | Operation success status |
216-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
216+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
217217
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
218218
| **data** | `{ id: string; flowName: string; flowVersion?: integer; status: Enum<'pending' \| 'running' \| 'paused' \| 'completed' \| 'failed' \| 'cancelled' \| … +2 more>; … }` | ✅ | Full execution log with step details |
219219

@@ -241,7 +241,7 @@ const result = AutomationApiErrorCode.parse(data);
241241
| Property | Type | Required | Description |
242242
| :--- | :--- | :--- | :--- |
243243
| **success** | `boolean` | ✅ | Operation success status |
244-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
244+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
245245
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
246246
| **data** | `{ flows: object[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | |
247247

@@ -269,7 +269,7 @@ const result = AutomationApiErrorCode.parse(data);
269269
| Property | Type | Required | Description |
270270
| :--- | :--- | :--- | :--- |
271271
| **success** | `boolean` | ✅ | Operation success status |
272-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
272+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
273273
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
274274
| **data** | `{ runs: object[]; total?: integer; nextCursor?: string; hasMore: boolean }` | ✅ | |
275275

@@ -295,7 +295,7 @@ const result = AutomationApiErrorCode.parse(data);
295295
| Property | Type | Required | Description |
296296
| :--- | :--- | :--- | :--- |
297297
| **success** | `boolean` | ✅ | Operation success status |
298-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
298+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
299299
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
300300
| **data** | `{ name: string; enabled: boolean }` | ✅ | |
301301

@@ -325,7 +325,7 @@ const result = AutomationApiErrorCode.parse(data);
325325
| Property | Type | Required | Description |
326326
| :--- | :--- | :--- | :--- |
327327
| **success** | `boolean` | ✅ | Operation success status |
328-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
328+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
329329
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
330330
| **data** | `{ success: boolean; output?: any; error?: string; durationMs?: number }` | ✅ | |
331331

@@ -351,7 +351,7 @@ const result = AutomationApiErrorCode.parse(data);
351351
| Property | Type | Required | Description |
352352
| :--- | :--- | :--- | :--- |
353353
| **success** | `boolean` | ✅ | Operation success status |
354-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
354+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
355355
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
356356
| **data** | `{ name: string; label: string; description?: string; successMessage?: string; … }` | ✅ | The updated flow definition |
357357

‎content/docs/references/api/batch.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const result = BatchConfigSchema.parse(data);
5555
| :--- | :--- | :--- | :--- |
5656
| **id** | `string` | optional | Record ID if operation succeeded |
5757
| **success** | `boolean` | ✅ | Whether this record was processed successfully |
58-
| **errors** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }[]` | optional | Array of errors if operation failed. Branch on `errors[0].code` — an atomic batch that rolled back marks rows that were written then undone with code ROLLED_BACK and rows never reached with NOT_ATTEMPTED, while the causal row keeps its own error (#4793). A NON-atomic batch that stopped (the `continueOnError: false` default) marks its un-attempted tail with the same NOT_ATTEMPTED code — rows before the failure stay written and keep reporting success, since nothing was rolled back (#7539). |
58+
| **errors** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }[]` | optional | Array of errors if operation failed. Branch on `errors[0].code` — an atomic batch that rolled back marks rows that were written then undone with code ROLLED_BACK and rows never reached with NOT_ATTEMPTED, while the causal row keeps its own error (#4793). A NON-atomic batch that stopped (the `continueOnError: false` default) marks its un-attempted tail with the same NOT_ATTEMPTED code — rows before the failure stay written and keep reporting success, since nothing was rolled back (#7539). |
5959
| **data** | `Record<string, any>` | optional | Full record data (if returnRecords=true) |
6060
| **index** | `number` | optional | Index of the record in the request array |
6161
| **droppedFields** | `{ object: string; fields: string[]; reason: Enum<'readonly' \| 'readonly_when' \| 'primary_key'> }[]` | optional | Write-observability (#3407/#3431/#3455): caller-supplied fields LEGALLY stripped from THIS row before it was written — static `readonly` (#2948) / TRUE `readonlyWhen` (#3042) on update, or the #3043 create-ingress strip. Per-row because a batch can drop different fields on different rows (`readonlyWhen` is record-state-dependent). Present ONLY when ≥1 field was dropped for this row; the row still succeeded (success unchanged). A single response header cannot express per-row drops, so this body field is the canonical bulk channel — REST does not emit `X-ObjectStack-Dropped-Fields` for batches. Optional — omit-when-empty keeps the shape backward-compatible. |
@@ -122,7 +122,7 @@ const result = BatchConfigSchema.parse(data);
122122
| Property | Type | Required | Description |
123123
| :--- | :--- | :--- | :--- |
124124
| **success** | `boolean` | ✅ | Operation success status |
125-
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +265 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
125+
| **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| … +266 more>; message: string; category?: string; httpStatus?: integer; … }` | optional | Error details if success is false |
126126
| **meta** | `{ timestamp: string; duration?: number; requestId?: string; traceId?: string }` | optional | Response metadata |
127127
| **operation** | `Enum<'create' \| 'update' \| 'upsert' \| 'delete'>` | optional | Operation type that was performed |
128128
| **total** | `number` | ✅ | Total number of records in the batch |

0 commit comments

Comments
 (0)