@vxil/config 0.9.0 → 0.10.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/dist/index.d.ts CHANGED
@@ -129,14 +129,22 @@ export type AuthHookEvent = 'user.created' | 'session.created' | 'session.revoke
129
129
  * jobs retry ladder instead (60 s, 120 s, … backoff) and the last failed
130
130
  * attempt dead-letters the run (`job.dead_lettered`, replayable from the
131
131
  * Jobs page). Each attempt is a billed invocation and carries the SAME
132
- * `idempotency_key` — dedupe on it. Effective attempts =
133
- * min(maxAttempts, the project's `jobs.retry.defaultMaxAttempts`, default 5).
132
+ * `idempotency_key` — dedupe on it. Effective attempts on queue / webhook /
133
+ * cmsHook / authHook = min(maxAttempts, the project's
134
+ * `jobs.retry.defaultMaxAttempts`, default 5); on `cron` and the async `http`
135
+ * lane the binding's maxAttempts IS the budget (it becomes the schedule's /
136
+ * the async run's own max_attempts), whatever the project default.
134
137
  * A handler that partially writes and then fails re-fires its downstream
135
138
  * events on EVERY attempt, so the chain is a tree (up to maxAttempts children
136
139
  * per hop): the causal-depth guard bounds its length (32 hops), not its size —
137
140
  * the breaker, the loop guard, the dead-letter quota and the daily share do.
138
- * Write only once you will return 2xx, or dedupe on idempotency_key. Not accepted on `http` (it returns its
139
- * real status to its caller) or `cron` (a retry would overlap the next tick). */
141
+ * Write only once you will return 2xx, or dedupe on idempotency_key.
142
+ * On `cron` (2026-10-03) a failed tick is re-delivered the same way — set
143
+ * `overlap: 'skip'` beside it so a tick that is still retrying never runs
144
+ * next to the following one. On `http` it applies to the ASYNC lane only
145
+ * (`X-Vxil-Async: 1`): a 408 / 429 / 5xx answer is re-delivered up to
146
+ * maxAttempts; a synchronous invoke always returns the function's own status
147
+ * to its caller and is never retried. */
140
148
  export interface FunctionTriggerRetry {
141
149
  /** 1–5 attempts in all (1 = a failed attempt dead-letters at once, no re-delivery) */
142
150
  maxAttempts: number;
@@ -147,6 +155,7 @@ export interface FunctionTriggerRetry {
147
155
  export type FunctionTrigger = {
148
156
  kind: 'http';
149
157
  path?: string;
158
+ retry?: FunctionTriggerRetry;
150
159
  }
151
160
  /** `overlap: 'skip'` (2026-10-01): a due tick fires nothing while the
152
161
  * previous tick's run is still open (queued / running / retrying / waiting /
@@ -156,6 +165,7 @@ export type FunctionTrigger = {
156
165
  kind: 'cron';
157
166
  schedule: string;
158
167
  overlap?: 'allow' | 'skip';
168
+ retry?: FunctionTriggerRetry;
159
169
  } | {
160
170
  kind: 'queue';
161
171
  source: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vxil/config",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Typed vxil.config.ts authoring for the vxil backend platform — defineConfig, feature and cms field definitions (published for @vxil/cli).",
5
5
  "license": "MIT",
6
6
  "homepage": "https://vxil.com",
@@ -23,7 +23,7 @@
23
23
  "!src/**/*.test.ts"
24
24
  ],
25
25
  "dependencies": {
26
- "@vxil/feature-configs": "0.8.0"
26
+ "@vxil/feature-configs": "0.9.0"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"
package/src/index.ts CHANGED
@@ -170,14 +170,22 @@ export type AuthHookEvent = 'user.created' | 'session.created' | 'session.revoke
170
170
  * jobs retry ladder instead (60 s, 120 s, … backoff) and the last failed
171
171
  * attempt dead-letters the run (`job.dead_lettered`, replayable from the
172
172
  * Jobs page). Each attempt is a billed invocation and carries the SAME
173
- * `idempotency_key` — dedupe on it. Effective attempts =
174
- * min(maxAttempts, the project's `jobs.retry.defaultMaxAttempts`, default 5).
173
+ * `idempotency_key` — dedupe on it. Effective attempts on queue / webhook /
174
+ * cmsHook / authHook = min(maxAttempts, the project's
175
+ * `jobs.retry.defaultMaxAttempts`, default 5); on `cron` and the async `http`
176
+ * lane the binding's maxAttempts IS the budget (it becomes the schedule's /
177
+ * the async run's own max_attempts), whatever the project default.
175
178
  * A handler that partially writes and then fails re-fires its downstream
176
179
  * events on EVERY attempt, so the chain is a tree (up to maxAttempts children
177
180
  * per hop): the causal-depth guard bounds its length (32 hops), not its size —
178
181
  * the breaker, the loop guard, the dead-letter quota and the daily share do.
179
- * Write only once you will return 2xx, or dedupe on idempotency_key. Not accepted on `http` (it returns its
180
- * real status to its caller) or `cron` (a retry would overlap the next tick). */
182
+ * Write only once you will return 2xx, or dedupe on idempotency_key.
183
+ * On `cron` (2026-10-03) a failed tick is re-delivered the same way — set
184
+ * `overlap: 'skip'` beside it so a tick that is still retrying never runs
185
+ * next to the following one. On `http` it applies to the ASYNC lane only
186
+ * (`X-Vxil-Async: 1`): a 408 / 429 / 5xx answer is re-delivered up to
187
+ * maxAttempts; a synchronous invoke always returns the function's own status
188
+ * to its caller and is never retried. */
181
189
  export interface FunctionTriggerRetry {
182
190
  /** 1–5 attempts in all (1 = a failed attempt dead-letters at once, no re-delivery) */
183
191
  maxAttempts: number;
@@ -187,12 +195,12 @@ export interface FunctionTriggerRetry {
187
195
  * authHook fires on ONE auth lifecycle event (default `user.created` — the
188
196
  * post-signup hook; at-least-once, ~1min fanout latency). */
189
197
  export type FunctionTrigger =
190
- | { kind: 'http'; path?: string }
198
+ | { kind: 'http'; path?: string; retry?: FunctionTriggerRetry }
191
199
  /** `overlap: 'skip'` (2026-10-01): a due tick fires nothing while the
192
200
  * previous tick's run is still open (queued / running / retrying / waiting /
193
201
  * delayed) — the slot is counted, never caught up. Default `'allow'`. Every
194
202
  * cron envelope carries `scheduled_for`, the slot it was due for. */
195
- | { kind: 'cron'; schedule: string; overlap?: 'allow' | 'skip' }
203
+ | { kind: 'cron'; schedule: string; overlap?: 'allow' | 'skip'; retry?: FunctionTriggerRetry }
196
204
  | { kind: 'queue'; source: string; retry?: FunctionTriggerRetry }
197
205
  /** `webhook`: the function is woken by a webhook_subscription fan-out whose
198
206
  * target_url is `<edge>/v1/internal/fn/trigger/<name>?tenant=<id>`. That