@vxil/config 0.5.1 → 0.7.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 +40 -1
- package/package.json +2 -2
- package/src/index.ts +40 -6
package/dist/index.d.ts
CHANGED
|
@@ -106,18 +106,45 @@ export interface CollectionDef {
|
|
|
106
106
|
* session.revoked — auth.session.revoked { user_id, session_id, reason }
|
|
107
107
|
* signin.failure — auth.signin.failure { email_hash | user_id, reason } */
|
|
108
108
|
export type AuthHookEvent = 'user.created' | 'session.created' | 'session.revoked' | 'signin.failure';
|
|
109
|
+
/** The opt-in re-delivery of a platform-delivered trigger (F33, 2026-09-25).
|
|
110
|
+
* DEFAULT OFF: the platform acknowledges every delivery with a 200 whatever
|
|
111
|
+
* the handler returned — an application error is observed (`functions.run.failed`),
|
|
112
|
+
* never re-delivered. With `retry` set on a `queue` / `webhook` / `cmsHook` /
|
|
113
|
+
* `authHook` trigger, a non-2xx answer of the handler is handed back to the
|
|
114
|
+
* jobs retry ladder instead (60 s, 120 s, … backoff) and the last failed
|
|
115
|
+
* attempt dead-letters the run (`job.dead_lettered`, replayable from the
|
|
116
|
+
* Jobs page). Each attempt is a billed invocation and carries the SAME
|
|
117
|
+
* `idempotency_key` — dedupe on it. Effective attempts =
|
|
118
|
+
* min(maxAttempts, the project's `jobs.retry.defaultMaxAttempts`, default 5).
|
|
119
|
+
* A handler that partially writes and then fails re-fires its downstream
|
|
120
|
+
* events on EVERY attempt, so the chain is a tree (up to maxAttempts children
|
|
121
|
+
* per hop): the causal-depth guard bounds its length (32 hops), not its size —
|
|
122
|
+
* the breaker, the loop guard, the dead-letter quota and the daily share do.
|
|
123
|
+
* Write only once you will return 2xx, or dedupe on idempotency_key. Not accepted on `http` (it returns its
|
|
124
|
+
* real status to its caller) or `cron` (a retry would overlap the next tick). */
|
|
125
|
+
export interface FunctionTriggerRetry {
|
|
126
|
+
/** 1–5 attempts in all (1 = a failed attempt dead-letters at once, no re-delivery) */
|
|
127
|
+
maxAttempts: number;
|
|
128
|
+
}
|
|
109
129
|
/** A function trigger (the §7.3 crossing). cmsHook fires on a CMS write;
|
|
110
130
|
* authHook fires on ONE auth lifecycle event (default `user.created` — the
|
|
111
131
|
* post-signup hook; at-least-once, ~1min fanout latency). */
|
|
112
132
|
export type FunctionTrigger = {
|
|
113
133
|
kind: 'http';
|
|
114
134
|
path?: string;
|
|
115
|
-
}
|
|
135
|
+
}
|
|
136
|
+
/** `overlap: 'skip'` (2026-10-01): a due tick fires nothing while the
|
|
137
|
+
* previous tick's run is still open (queued / running / retrying / waiting /
|
|
138
|
+
* delayed) — the slot is counted, never caught up. Default `'allow'`. Every
|
|
139
|
+
* cron envelope carries `scheduled_for`, the slot it was due for. */
|
|
140
|
+
| {
|
|
116
141
|
kind: 'cron';
|
|
117
142
|
schedule: string;
|
|
143
|
+
overlap?: 'allow' | 'skip';
|
|
118
144
|
} | {
|
|
119
145
|
kind: 'queue';
|
|
120
146
|
source: string;
|
|
147
|
+
retry?: FunctionTriggerRetry;
|
|
121
148
|
}
|
|
122
149
|
/** `webhook`: the function is woken by a webhook_subscription fan-out whose
|
|
123
150
|
* target_url is `<edge>/v1/internal/fn/trigger/<name>?tenant=<id>`. That
|
|
@@ -132,6 +159,7 @@ export type FunctionTrigger = {
|
|
|
132
159
|
| {
|
|
133
160
|
kind: 'webhook';
|
|
134
161
|
source: string;
|
|
162
|
+
retry?: FunctionTriggerRetry;
|
|
135
163
|
}
|
|
136
164
|
/** `cmsHook`: fires after a CMS write in `collection`. The platform filters
|
|
137
165
|
* deliveries on the binding (2026-09-19): `beforeCreate` → created only,
|
|
@@ -142,15 +170,26 @@ export type FunctionTrigger = {
|
|
|
142
170
|
kind: 'cmsHook';
|
|
143
171
|
collection: string;
|
|
144
172
|
event: 'beforeCreate' | 'beforeUpdate' | 'beforeWrite';
|
|
173
|
+
retry?: FunctionTriggerRetry;
|
|
145
174
|
} | {
|
|
146
175
|
kind: 'authHook';
|
|
147
176
|
event?: AuthHookEvent;
|
|
177
|
+
retry?: FunctionTriggerRetry;
|
|
148
178
|
};
|
|
149
179
|
/** A deployed tenant function — source in functions/, deployed on `vxil push`. */
|
|
150
180
|
export interface FunctionDef {
|
|
151
181
|
/** path to the ES-module entrypoint, e.g. ./functions/<name>.ts */
|
|
152
182
|
entry: string;
|
|
153
183
|
trigger?: FunctionTrigger;
|
|
184
|
+
/** Further bindings beside `trigger` (2026-09-25): a function is code + a SET
|
|
185
|
+
* of trigger bindings, so one bundle can be reached by several front doors —
|
|
186
|
+
* a webhook AND a cron, an http door AND a cmsHook. `trigger` and `triggers`
|
|
187
|
+
* may both be present; the deploy carries them in that order as
|
|
188
|
+
* `bindings[]`, at most 8 in all (the CLI refuses a 9th before the wire).
|
|
189
|
+
* Every binding lands the same isolate; only the envelope's `trigger` /
|
|
190
|
+
* `payload` differ. Each platform-delivered binding is billed per
|
|
191
|
+
* invocation and bounded by the loop guard and the breaker. */
|
|
192
|
+
triggers?: FunctionTrigger[];
|
|
154
193
|
/** clamped by DENY_FUNCTION_SCOPES at deploy (admin, wildcard, features:write,
|
|
155
194
|
* functions:write, secrets:write rejected; payments:write / notifications:send /
|
|
156
195
|
* users:* allowed as owner-granted business scopes). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vxil/config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"src"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@vxil/feature-configs": "0.
|
|
25
|
+
"@vxil/feature-configs": "0.7.0"
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// types); the control plane never executes this file. This keeps config-as-code
|
|
7
7
|
// §7.3-consistent — config is DATA; the only tenant CODE that crosses into vxil
|
|
8
8
|
// is (a) the Lane-A hook expressions (a closed sandbox) and (b) the functions/
|
|
9
|
-
// sources (the
|
|
9
|
+
// sources (the opt-in, plan-limited, egress-guarded crossing). Everything here is
|
|
10
10
|
// declarative. See https://vxil.com/docs/guide/05-typed-sdk-and-cli.
|
|
11
11
|
import type {
|
|
12
12
|
NotificationsConfig, JobsConfig, AuthConfig, RateLimitsConfig, FilesConfig,
|
|
@@ -130,13 +130,38 @@ export interface CollectionDef {
|
|
|
130
130
|
* signin.failure — auth.signin.failure { email_hash | user_id, reason } */
|
|
131
131
|
export type AuthHookEvent = 'user.created' | 'session.created' | 'session.revoked' | 'signin.failure';
|
|
132
132
|
|
|
133
|
+
/** The opt-in re-delivery of a platform-delivered trigger (F33, 2026-09-25).
|
|
134
|
+
* DEFAULT OFF: the platform acknowledges every delivery with a 200 whatever
|
|
135
|
+
* the handler returned — an application error is observed (`functions.run.failed`),
|
|
136
|
+
* never re-delivered. With `retry` set on a `queue` / `webhook` / `cmsHook` /
|
|
137
|
+
* `authHook` trigger, a non-2xx answer of the handler is handed back to the
|
|
138
|
+
* jobs retry ladder instead (60 s, 120 s, … backoff) and the last failed
|
|
139
|
+
* attempt dead-letters the run (`job.dead_lettered`, replayable from the
|
|
140
|
+
* Jobs page). Each attempt is a billed invocation and carries the SAME
|
|
141
|
+
* `idempotency_key` — dedupe on it. Effective attempts =
|
|
142
|
+
* min(maxAttempts, the project's `jobs.retry.defaultMaxAttempts`, default 5).
|
|
143
|
+
* A handler that partially writes and then fails re-fires its downstream
|
|
144
|
+
* events on EVERY attempt, so the chain is a tree (up to maxAttempts children
|
|
145
|
+
* per hop): the causal-depth guard bounds its length (32 hops), not its size —
|
|
146
|
+
* the breaker, the loop guard, the dead-letter quota and the daily share do.
|
|
147
|
+
* Write only once you will return 2xx, or dedupe on idempotency_key. Not accepted on `http` (it returns its
|
|
148
|
+
* real status to its caller) or `cron` (a retry would overlap the next tick). */
|
|
149
|
+
export interface FunctionTriggerRetry {
|
|
150
|
+
/** 1–5 attempts in all (1 = a failed attempt dead-letters at once, no re-delivery) */
|
|
151
|
+
maxAttempts: number;
|
|
152
|
+
}
|
|
153
|
+
|
|
133
154
|
/** A function trigger (the §7.3 crossing). cmsHook fires on a CMS write;
|
|
134
155
|
* authHook fires on ONE auth lifecycle event (default `user.created` — the
|
|
135
156
|
* post-signup hook; at-least-once, ~1min fanout latency). */
|
|
136
157
|
export type FunctionTrigger =
|
|
137
158
|
| { kind: 'http'; path?: string }
|
|
138
|
-
|
|
139
|
-
|
|
159
|
+
/** `overlap: 'skip'` (2026-10-01): a due tick fires nothing while the
|
|
160
|
+
* previous tick's run is still open (queued / running / retrying / waiting /
|
|
161
|
+
* delayed) — the slot is counted, never caught up. Default `'allow'`. Every
|
|
162
|
+
* cron envelope carries `scheduled_for`, the slot it was due for. */
|
|
163
|
+
| { kind: 'cron'; schedule: string; overlap?: 'allow' | 'skip' }
|
|
164
|
+
| { kind: 'queue'; source: string; retry?: FunctionTriggerRetry }
|
|
140
165
|
/** `webhook`: the function is woken by a webhook_subscription fan-out whose
|
|
141
166
|
* target_url is `<edge>/v1/internal/fn/trigger/<name>?tenant=<id>`. That
|
|
142
167
|
* subscription is AUTO-WIRED on deploy (2026-09-19): the platform reconciles
|
|
@@ -147,20 +172,29 @@ export type FunctionTrigger =
|
|
|
147
172
|
* also enforced at delivery: a non-matching event is ACK-200 skipped.
|
|
148
173
|
* Declaring the binding is what opts the function into event delivery; a
|
|
149
174
|
* receiver that declares only `cron` keeps the older cron+{} wake. */
|
|
150
|
-
| { kind: 'webhook'; source: string }
|
|
175
|
+
| { kind: 'webhook'; source: string; retry?: FunctionTriggerRetry }
|
|
151
176
|
/** `cmsHook`: fires after a CMS write in `collection`. The platform filters
|
|
152
177
|
* deliveries on the binding (2026-09-19): `beforeCreate` → created only,
|
|
153
178
|
* `beforeUpdate` → updated only, `beforeWrite` → created|updated; a write to
|
|
154
179
|
* another collection never wakes the function. Deleted/bulk events are not
|
|
155
180
|
* delivered to a cmsHook binding. */
|
|
156
|
-
| { kind: 'cmsHook'; collection: string; event: 'beforeCreate' | 'beforeUpdate' | 'beforeWrite' }
|
|
157
|
-
| { kind: 'authHook'; event?: AuthHookEvent };
|
|
181
|
+
| { kind: 'cmsHook'; collection: string; event: 'beforeCreate' | 'beforeUpdate' | 'beforeWrite'; retry?: FunctionTriggerRetry }
|
|
182
|
+
| { kind: 'authHook'; event?: AuthHookEvent; retry?: FunctionTriggerRetry };
|
|
158
183
|
|
|
159
184
|
/** A deployed tenant function — source in functions/, deployed on `vxil push`. */
|
|
160
185
|
export interface FunctionDef {
|
|
161
186
|
/** path to the ES-module entrypoint, e.g. ./functions/<name>.ts */
|
|
162
187
|
entry: string;
|
|
163
188
|
trigger?: FunctionTrigger;
|
|
189
|
+
/** Further bindings beside `trigger` (2026-09-25): a function is code + a SET
|
|
190
|
+
* of trigger bindings, so one bundle can be reached by several front doors —
|
|
191
|
+
* a webhook AND a cron, an http door AND a cmsHook. `trigger` and `triggers`
|
|
192
|
+
* may both be present; the deploy carries them in that order as
|
|
193
|
+
* `bindings[]`, at most 8 in all (the CLI refuses a 9th before the wire).
|
|
194
|
+
* Every binding lands the same isolate; only the envelope's `trigger` /
|
|
195
|
+
* `payload` differ. Each platform-delivered binding is billed per
|
|
196
|
+
* invocation and bounded by the loop guard and the breaker. */
|
|
197
|
+
triggers?: FunctionTrigger[];
|
|
164
198
|
/** clamped by DENY_FUNCTION_SCOPES at deploy (admin, wildcard, features:write,
|
|
165
199
|
* functions:write, secrets:write rejected; payments:write / notifications:send /
|
|
166
200
|
* users:* allowed as owner-granted business scopes). */
|