@rayspec/spec 1.5.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 (62) hide show
  1. package/LICENSE +105 -0
  2. package/dist/brace-params.d.ts +32 -0
  3. package/dist/brace-params.d.ts.map +1 -0
  4. package/dist/brace-params.js +89 -0
  5. package/dist/brace-params.js.map +1 -0
  6. package/dist/detect.d.ts +44 -0
  7. package/dist/detect.d.ts.map +1 -0
  8. package/dist/detect.js +72 -0
  9. package/dist/detect.js.map +1 -0
  10. package/dist/errors.d.ts +204 -0
  11. package/dist/errors.d.ts.map +1 -0
  12. package/dist/errors.js +165 -0
  13. package/dist/errors.js.map +1 -0
  14. package/dist/export.d.ts +54 -0
  15. package/dist/export.d.ts.map +1 -0
  16. package/dist/export.js +121 -0
  17. package/dist/export.js.map +1 -0
  18. package/dist/grammar.d.ts +569 -0
  19. package/dist/grammar.d.ts.map +1 -0
  20. package/dist/grammar.js +503 -0
  21. package/dist/grammar.js.map +1 -0
  22. package/dist/index.d.ts +23 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +26 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/lint.d.ts +79 -0
  27. package/dist/lint.d.ts.map +1 -0
  28. package/dist/lint.js +823 -0
  29. package/dist/lint.js.map +1 -0
  30. package/dist/parse.d.ts +8 -0
  31. package/dist/parse.d.ts.map +1 -0
  32. package/dist/parse.js +118 -0
  33. package/dist/parse.js.map +1 -0
  34. package/dist/product-events.d.ts +73 -0
  35. package/dist/product-events.d.ts.map +1 -0
  36. package/dist/product-events.js +42 -0
  37. package/dist/product-events.js.map +1 -0
  38. package/dist/product-grammar.d.ts +948 -0
  39. package/dist/product-grammar.d.ts.map +1 -0
  40. package/dist/product-grammar.js +581 -0
  41. package/dist/product-grammar.js.map +1 -0
  42. package/dist/product-lint.d.ts +74 -0
  43. package/dist/product-lint.d.ts.map +1 -0
  44. package/dist/product-lint.js +821 -0
  45. package/dist/product-lint.js.map +1 -0
  46. package/dist/product-parse.d.ts +8 -0
  47. package/dist/product-parse.d.ts.map +1 -0
  48. package/dist/product-parse.js +119 -0
  49. package/dist/product-parse.js.map +1 -0
  50. package/dist/product-scope.d.ts +53 -0
  51. package/dist/product-scope.d.ts.map +1 -0
  52. package/dist/product-scope.js +55 -0
  53. package/dist/product-scope.js.map +1 -0
  54. package/dist/product-views-lint.d.ts +14 -0
  55. package/dist/product-views-lint.d.ts.map +1 -0
  56. package/dist/product-views-lint.js +669 -0
  57. package/dist/product-views-lint.js.map +1 -0
  58. package/dist/product-views.d.ts +426 -0
  59. package/dist/product-views.d.ts.map +1 -0
  60. package/dist/product-views.js +317 -0
  61. package/dist/product-views.js.map +1 -0
  62. package/package.json +34 -0
@@ -0,0 +1,503 @@
1
+ /**
2
+ * The RaySpec config grammar — `RaySpec` and its six sections.
3
+ *
4
+ * A deployed backend is ONE validated `RaySpec` — stores · api · agents ·
5
+ * tooling · triggers · handlers. This module defines ONLY the Zod grammar (shape). The
6
+ * two-phase parser (`parse.ts`), the semantic linter (`lint.ts`), and the JSON-Schema exporter
7
+ * (`export.ts`) build on top of it.
8
+ *
9
+ * FAIL-CLOSED BY CONSTRUCTION: every GRAMMAR object level is `.strict()`, so an
10
+ * unknown key is rejected — there is no silent passthrough of a typo'd or unrecognized field.
11
+ * Verified (zod 4.4.3, doc-first probe): `.omit().extend().strict()` composes so the wrap layer
12
+ * stays strict AND the exported JSON-Schema carries `additionalProperties:false` at every STRICT
13
+ * grammar level. The THREE embedded JSON-Schema slots (a tool's `parameters`/`outputSchema` and an
14
+ * agent's `outputSchema.schema`) are intentionally OPEN records — they ARE free-form JSON-Schema,
15
+ * validated separately by ajv (lint.ts), not by strict-key rejection.
16
+ *
17
+ * HYBRID WRAP:
18
+ * - `agents[]` and `tooling[]` WRAP the neutral `core` types (`AgentSpec`/`ToolSpec`) — the
19
+ * literal interpreter input — so there is ONE source of truth for the neutral fields. Honest
20
+ * limit of the wrap: a neutral REMOVAL or RENAME surfaces LOUDLY (a `.omit()`/`.extend()` on a
21
+ * missing key is a compile error); a neutral ADDITION is ABSORBED SILENTLY into the grammar.
22
+ * The `AgentSpecConfig`/`ToolSpecConfig` shape-key PIN TESTS (grammar.test.ts) are what make an
23
+ * addition deliberate — a new neutral key fails the pin and forces a conscious spec-bump call.
24
+ * - `stores[]`, `api[]`, `triggers[]`, `handlers[]` are INDEPENDENT Zod types (no neutral
25
+ * precedent exists for them).
26
+ *
27
+ * RUNTIME vs CONFIG (load-bearing): `core.AgentSpec` includes `input` — that is the RUNTIME task
28
+ * value supplied per request, NOT config. A declared agent MUST OMIT it (we `.omit({ input })`),
29
+ * and supplies it at request time. Likewise `core.AgentSpec.tools` is an INLINE
30
+ * neutral-tool array; in the config layer an agent references declared `tooling[]` entries BY ID,
31
+ * so we omit the inline array and add an `id`-reference list (`tools: string[]`) instead. The
32
+ * lint pass resolves those references against the `tooling[]` section.
33
+ */
34
+ import { BackendId, AgentSpec as NeutralAgentSpec, ToolSpec as NeutralToolSpec, } from '@rayspec/core';
35
+ import { z } from 'zod';
36
+ /** The supported spec major.minor. Parsed FIRST (two-phase) so an unknown major fails cleanly. */
37
+ export const SPEC_VERSION = '1.0';
38
+ // ---------------------------------------------------------------------------------------
39
+ // metadata
40
+ // ---------------------------------------------------------------------------------------
41
+ /** Minimal deployment metadata. `name` identifies the backend; extend later as needed. */
42
+ export const Metadata = z
43
+ .object({
44
+ name: z.string().min(1),
45
+ description: z.string().optional(),
46
+ })
47
+ .strict();
48
+ // ---------------------------------------------------------------------------------------
49
+ // deployment — independent grammar (deployment PROPERTY, not a backend capability)
50
+ // ---------------------------------------------------------------------------------------
51
+ /**
52
+ * Deployment-level properties of a backend. These describe HOW the
53
+ * deployment runs, NOT what any SDK can do — so `async`/off-request execution belongs HERE, on the
54
+ * spec, gated by "is a durable worker configured?", and is INVISIBLE to the neutral `Backend`
55
+ * interface and the per-backend `CapabilityDescriptor` (which must NOT be touched: whether a run
56
+ * executes off-request has no backend asymmetry to absorb — `runAgent` takes the same `ctx`
57
+ * in-request or off-request).
58
+ *
59
+ * - `durableWorker` — when true, the deployment runs a durable off-request worker (DBOS),
60
+ * so a per-request `async:true` run is enqueued onto it (202 + runId) rather than fail-closed-501.
61
+ * A lint rule (lint.ts) enforces it: a spec must not be deployed expecting async without it — but
62
+ * the LOAD-BEARING gate is the RUNTIME one (the run surface 501s if no executor is wired,
63
+ * regardless of this flag), so this is a declaration + a static best-effort check, defense-in-depth.
64
+ */
65
+ export const DeploymentSpec = z
66
+ .object({
67
+ durableWorker: z.boolean().optional(),
68
+ })
69
+ .strict();
70
+ // ---------------------------------------------------------------------------------------
71
+ // stores[] — independent grammar (DB-materialized product tables)
72
+ // ---------------------------------------------------------------------------------------
73
+ /**
74
+ * The closed set of column types an author may declare. Small + closed so the store generator
75
+ * can map each to a Drizzle/Postgres type deterministically and the migration gate sees a finite
76
+ * vocabulary. (Authors declare BUSINESS columns only — the tenancy/GDPR columns `tenant_id`,
77
+ * `id`, `created_at`, `deleted_at`, `retention_days`, `region` are INJECTED by the generator,
78
+ * never declared here.)
79
+ */
80
+ export const ColumnType = z.enum(['text', 'uuid', 'timestamp', 'integer', 'boolean', 'jsonb']);
81
+ /**
82
+ * A SAFE SQL/TS IDENTIFIER for a store name / column name / FK column-or-reference (TEN-1).
83
+ * Store/column names are interpolated VERBATIM into generated SQL (`CREATE TABLE "<name>"`)
84
+ * AND generated TS (`export const <camel> = pgTable('<name>', …)`) — so an unconstrained
85
+ * `z.string()` is an INJECTION seam (a name like `m" ); DROP …` lands in executable DDL, and the
86
+ * destructive scan is a closed blocklist that can never catch every form). Fail-closed at the
87
+ * SOURCE: a safe identifier is `[a-z_][a-z0-9_]*`, length 1..63 (the Postgres identifier limit),
88
+ * lowercase only (Postgres folds unquoted idents to lowercase; we keep snake_case author names and
89
+ * camelCase them for TS). `parseSpec` rejects a metacharacter/over-long name as `schema_violation`.
90
+ * The generators re-assert the SAME shape (defense-in-depth for a code-built spec bypassing parse).
91
+ */
92
+ export const SAFE_IDENTIFIER_RE = /^[a-z_][a-z0-9_]*$/;
93
+ export const MAX_IDENTIFIER_LENGTH = 63;
94
+ export const SafeIdentifier = z
95
+ .string()
96
+ .min(1)
97
+ .max(MAX_IDENTIFIER_LENGTH, `identifier must be <= ${MAX_IDENTIFIER_LENGTH} chars (Postgres limit)`)
98
+ .regex(SAFE_IDENTIFIER_RE, 'identifier must match /^[a-z_][a-z0-9_]*$/ (lowercase letters/digits/underscore, no metacharacters)');
99
+ /**
100
+ * Re-assert the safe-identifier shape OUTSIDE Zod (the generators call this on a spec that may have
101
+ * been built in code, bypassing parseSpec). THROWS — never returns a malformed identifier into
102
+ * generated SQL/TS. Single source of the rule shared by the grammar refine above + both generators.
103
+ */
104
+ export function assertSafeIdentifier(value, what) {
105
+ if (value.length === 0 ||
106
+ value.length > MAX_IDENTIFIER_LENGTH ||
107
+ !SAFE_IDENTIFIER_RE.test(value)) {
108
+ throw new Error(`unsafe identifier for ${what}: ${JSON.stringify(value)} — must match ` +
109
+ `/^[a-z_][a-z0-9_]*$/ and be <= ${MAX_IDENTIFIER_LENGTH} chars (injection guard, TEN-1)`);
110
+ }
111
+ }
112
+ /** One business column on a store. `nullable`/`unique` default false (the conservative shape). */
113
+ export const StoreColumn = z
114
+ .object({
115
+ name: SafeIdentifier,
116
+ type: ColumnType,
117
+ nullable: z.boolean().default(false),
118
+ unique: z.boolean().default(false),
119
+ /** Optional whitelist of allowed values for a text column (a stored value must be one of these). */
120
+ enum: z.array(z.string().min(1)).min(1).optional(),
121
+ })
122
+ .strict();
123
+ /**
124
+ * A child→parent foreign key (the throwaway has `transcripts` referencing `meetings`). The
125
+ * generator emits the FK + `ON DELETE` policy; the parent must be another declared store (the
126
+ * lint pass resolves `references`). This is a PRODUCT-to-PRODUCT FK; FK-to-core (e.g. orgs) is
127
+ * the injected tenancy column, not declared here.
128
+ */
129
+ export const StoreForeignKey = z
130
+ .object({
131
+ /** The local column carrying the FK (must be a DECLARED business column — lint-resolved). */
132
+ column: SafeIdentifier,
133
+ /** The referenced store name (must be a declared store — lint-resolved). */
134
+ references: SafeIdentifier,
135
+ /** When set, the FK targets this (unique) column of the referenced store instead of its id. */
136
+ referencesColumn: SafeIdentifier.optional(),
137
+ /** ON DELETE policy; `cascade` mirrors the tenancy cascade discipline. */
138
+ onDelete: z.enum(['cascade', 'restrict', 'set null']).default('cascade'),
139
+ })
140
+ .strict();
141
+ /**
142
+ * A declared product store. Authors declare a name + business columns (+ optional child→parent
143
+ * FKs). Tenancy is NON-OPTIONAL by construction — there is no opt-out field (a non-tenant store
144
+ * would be the spec-level analogue of `.unscoped()`, deliberately not expressible in v1.0).
145
+ */
146
+ export const StoreSpec = z
147
+ .object({
148
+ name: SafeIdentifier,
149
+ columns: z.array(StoreColumn).min(1),
150
+ foreignKeys: z.array(StoreForeignKey).default([]),
151
+ /** Opt-in soft delete: a delete marks the row deleted instead of removing it (default: hard delete). */
152
+ softDelete: z.boolean().optional(),
153
+ /** Opt-in full-text search: the store gets a generated tsvector column (over its text columns) + a
154
+ * GIN index, and a ranked search query surface. Default: substring (ILIKE) search only. */
155
+ fullTextSearch: z.boolean().optional(),
156
+ })
157
+ .strict();
158
+ // ---------------------------------------------------------------------------------------
159
+ // handlers[] — independent grammar (escape-hatch TS module references)
160
+ // ---------------------------------------------------------------------------------------
161
+ /**
162
+ * What a handler is wired into. A logical id maps to a TS module + export; `kind` declares the
163
+ * chokepoint it dispatches through (tool → dispatchTool; route → the api chokepoint; trigger →
164
+ * the triggers seam). The loader resolves the symbol from a path-jailed escape-hatch
165
+ * root — the grammar layer parses the mapping only.
166
+ */
167
+ export const HandlerKind = z.enum(['tool', 'route', 'trigger']);
168
+ export const HandlerSpec = z
169
+ .object({
170
+ /** Logical id referenced by tooling/api/triggers. */
171
+ id: z.string().min(1),
172
+ /** The escape-hatch TS module path (resolved under the jailed root at load). */
173
+ module: z.string().min(1),
174
+ /** The named export within that module. */
175
+ export: z.string().min(1),
176
+ kind: HandlerKind,
177
+ /**
178
+ * Opt-in: a route handler that only READS product stores. When true, its route is gated
179
+ * `store:read` instead of the default `store:write`, so a read-scoped credential can reach it.
180
+ */
181
+ readonly: z.boolean().optional(),
182
+ })
183
+ .strict();
184
+ // ---------------------------------------------------------------------------------------
185
+ // agents[] — WRAP core.AgentSpec
186
+ // ---------------------------------------------------------------------------------------
187
+ /**
188
+ * A declared agent. WRAPS `core.AgentSpec`:
189
+ * - `.omit({ input })` — `input` is the per-request RUNTIME value, never config.
190
+ * - `.omit({ tools })` — the neutral inline tool array is replaced by ID references into the
191
+ * `tooling[]` section (a config agent wires tools by id; lint resolves them).
192
+ * - `.extend(...)` — the wrap-layer fields the engine needs: a logical `id`, a `backend`
193
+ * selection, the `tools` id-reference list, and an optional `requireNativeStructuredOutput`
194
+ * flag so a capability violation (e.g. native structured output demanded on pi) is expressible
195
+ * and checked at config time (lint).
196
+ * - `.strict()` — fail-closed unknown-key rejection (applied last; verified to compose).
197
+ *
198
+ * Single source of truth: `name`/`instructions`/`model`/`outputSchema`/`maxTurns` come straight
199
+ * from the neutral type. If the neutral `AgentSpec` churns, this wrap is where the compat decision
200
+ * (minor vs major spec bump) is made — by design.
201
+ */
202
+ export const AgentSpecConfig = NeutralAgentSpec.omit({ input: true, tools: true })
203
+ .extend({
204
+ /** Logical id (unique within `agents[]`). */
205
+ id: z.string().min(1),
206
+ /** Which backend runs this agent. */
207
+ backend: BackendId,
208
+ /** Tool ids referenced from the `tooling[]` section (lint-resolved). */
209
+ tools: z.array(z.string().min(1)).default([]),
210
+ /**
211
+ * When true, an `outputSchema` DEMANDS native structured output — rejected at config time on
212
+ * a backend that lacks it (pi). Threaded into core `validateSpec` by the lint pass.
213
+ */
214
+ requireNativeStructuredOutput: z.boolean().default(false),
215
+ })
216
+ .strict();
217
+ // ---------------------------------------------------------------------------------------
218
+ // tooling[] — WRAP core.ToolSpec
219
+ // ---------------------------------------------------------------------------------------
220
+ /**
221
+ * A declared tool. WRAPS `core.ToolSpec` (name/description/parameters — the model-facing
222
+ * declaration) + the wrap-layer fields the resolver needs to build a `NeutralTool`:
223
+ * - `id` — logical id referenced from `agents[].tools` and unique within `tooling[]`.
224
+ * - `handler` — a logical handler id from the `handlers[]` section (lint-resolved).
225
+ * - `idempotent` — REQUIRED, NO DEFAULT. This is the reviewed replay-safety declaration the whole
226
+ * `dispatchTool` contract keys off (a `false` tool must never re-fire / return a cached output
227
+ * on replay). There is no platform-side verification of this boolean — it must be an explicit,
228
+ * reviewed author decision, so we give it no default.
229
+ * - `timeoutMs` — bounds the handler (AbortSignal in dispatchTool).
230
+ * - `outputSchema` — optional embedded JSON-Schema validating the handler output (Ajv-compiled
231
+ * at load by the lint pass). `parameters` (the input schema) is inherited from `ToolSpec`.
232
+ */
233
+ export const ToolSpecConfig = NeutralToolSpec.extend({
234
+ /** Logical id (unique within `tooling[]`; referenced from `agents[].tools`). */
235
+ id: z.string().min(1),
236
+ /** A declared handler id (lint-resolved against `handlers[]`). */
237
+ handler: z.string().min(1),
238
+ /**
239
+ * The replay-safety declaration — REQUIRED, no default (a reviewed author decision; the whole
240
+ * dispatchTool replay contract keys off it).
241
+ */
242
+ idempotent: z.boolean(),
243
+ /** Hard timeout for the handler (ms). */
244
+ timeoutMs: z.number().int().positive(),
245
+ /** Optional embedded JSON-Schema validating handler OUTPUT (Ajv-compiled at load). */
246
+ outputSchema: z.record(z.string(), z.unknown()).optional(),
247
+ }).strict();
248
+ // ---------------------------------------------------------------------------------------
249
+ // api[] — independent grammar (declared HTTP routes)
250
+ // ---------------------------------------------------------------------------------------
251
+ /** The HTTP method a route handles. */
252
+ export const HttpMethod = z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
253
+ /** A CRUD operation against a materialized store. */
254
+ export const StoreOp = z.enum(['list', 'get', 'create', 'update', 'delete']);
255
+ /**
256
+ * A `stream` route's runtime mode — discriminates the init shape the interpreter builds WITHIN the
257
+ * `kind:'stream'` arm (NOT a union discriminant — the union still discriminates on `kind`):
258
+ * - `ingest` — the binary write half: the interpreter reads the RAW request body.
259
+ * - `playback` — the media read half: Range/206 + conditional-GET from a `BlobStore`.
260
+ *
261
+ * `mode` is a per-arm field (like a store action's `op`), not a fourth `kind`: an ingest and a
262
+ * playback route are the SAME kind of action (a raw-Request/Response stream handler) differing only
263
+ * in runtime behavior, so one `kind` keeps the closed union minimal.
264
+ */
265
+ export const StreamMode = z.enum(['ingest', 'playback']);
266
+ /**
267
+ * A route action — a discriminated union over its `kind`:
268
+ * - `store` — CRUD over a materialized store via TenantDb.
269
+ * - `agent` — invoke a declared agent over the SSE/JSON run surface.
270
+ * - `handler` — a declared route-handler id.
271
+ * - `stream` — a raw binary ingest / Range-206 playback handler; `mode`
272
+ * discriminates ingest vs playback WITHIN this arm (the union still keys on `kind`).
273
+ *
274
+ * The discriminant `kind` is an explicit field (not inferred from which payload is set) so the union
275
+ * is unambiguous and fail-closed. The `stream` arm's `handler` resolves against a declared
276
+ * `route`-kind handler — the SAME chokepoint a `kind:'handler'` route uses (a stream handler is a
277
+ * route handler that receives a raw `Request` instead of parsed JSON; the raw-vs-JSON init shape is
278
+ * a RUNTIME concern, not a grammar-kind concern — so no new `HandlerKind` is introduced).
279
+ */
280
+ export const RouteAction = z.discriminatedUnion('kind', [
281
+ z
282
+ .object({
283
+ kind: z.literal('store'),
284
+ /** The declared store name (lint-resolved). */
285
+ store: z.string().min(1),
286
+ op: StoreOp,
287
+ })
288
+ .strict(),
289
+ z
290
+ .object({
291
+ kind: z.literal('agent'),
292
+ /** The declared agent id (lint-resolved). */
293
+ agent: z.string().min(1),
294
+ /**
295
+ * Optional: a declared store name (lint-resolved). When set, the agent's validated
296
+ * `outputSchema` output is written as one row into this store after a successful run —
297
+ * exactly-once across the sync and durable execution paths. Omitted ⇒ the run's output is
298
+ * returned/journaled but not persisted to a store.
299
+ */
300
+ persistTo: z.string().min(1).optional(),
301
+ })
302
+ .strict(),
303
+ z
304
+ .object({
305
+ kind: z.literal('handler'),
306
+ /** The declared handler id (lint-resolved; must be a `route`-kind handler). */
307
+ handler: z.string().min(1),
308
+ })
309
+ .strict(),
310
+ z
311
+ .object({
312
+ kind: z.literal('stream'),
313
+ /**
314
+ * The declared handler id (lint-resolved; must be a `route`-kind handler — a stream handler
315
+ * dispatches through the api chokepoint, like a `kind:'handler'` route).
316
+ */
317
+ handler: z.string().min(1),
318
+ /** ingest (raw binary write) vs playback (Range/206 media read) — see `StreamMode`. */
319
+ mode: StreamMode,
320
+ })
321
+ .strict(),
322
+ ]);
323
+ /** A declared HTTP route mounted on the existing auth chain. */
324
+ export const ApiRouteSpec = z
325
+ .object({
326
+ method: HttpMethod,
327
+ /** Route path (e.g. `/meetings/{id}`); interpreted by the api interpreter. */
328
+ path: z.string().min(1),
329
+ action: RouteAction,
330
+ })
331
+ .strict();
332
+ // ---------------------------------------------------------------------------------------
333
+ // triggers[] — independent grammar (parse/register only)
334
+ // ---------------------------------------------------------------------------------------
335
+ /**
336
+ * A trigger action — what fires when the trigger runs. A trigger fires an agent or a declared
337
+ * trigger-handler (lint-resolved). Parse/register only (the durable worker is a deployment
338
+ * property); a cron/async fire is fail-closed-rejected at runtime (not in this grammar).
339
+ */
340
+ export const TriggerAction = z.discriminatedUnion('kind', [
341
+ z
342
+ .object({
343
+ kind: z.literal('agent'),
344
+ agent: z.string().min(1),
345
+ /**
346
+ * Optional: a declared store name (lint-resolved). When set, the agent's validated
347
+ * `outputSchema` output is written as one row into this store after a successful run —
348
+ * exactly-once across a durable recovery re-dispatch of the same run.
349
+ */
350
+ persistTo: z.string().min(1).optional(),
351
+ })
352
+ .strict(),
353
+ z.object({ kind: z.literal('handler'), handler: z.string().min(1) }).strict(),
354
+ ]);
355
+ /**
356
+ * A declared trigger. `kind` selects the descriptor:
357
+ * - `cron` — requires `schedule` (a cron expression; not evaluated at the grammar level).
358
+ * - `webhook` — an inbound webhook (path interpreted later).
359
+ * - `event` — requires `event` (a logical event name).
360
+ * - `manual` — fired by an explicit call.
361
+ *
362
+ * `schedule`/`event` are optional at the GRAMMAR level (different kinds need different fields);
363
+ * the lint pass enforces the kind→field requirement (cron needs schedule, event needs event) so a
364
+ * malformed trigger fails fail-closed rather than parsing into a half-specified descriptor.
365
+ */
366
+ export const TriggerKind = z.enum(['cron', 'webhook', 'event', 'manual']);
367
+ export const TriggerSpec = z
368
+ .object({
369
+ name: z.string().min(1),
370
+ kind: TriggerKind,
371
+ /** Cron expression — REQUIRED for `kind:'cron'` (lint-enforced). */
372
+ schedule: z.string().min(1).optional(),
373
+ /** Logical event name — REQUIRED for `kind:'event'` (lint-enforced). */
374
+ event: z.string().min(1).optional(),
375
+ /** Opt-in cron CATCH-UP: on startup, replay every interval missed while the worker was down
376
+ * (bounded look-back). Valid ONLY for `kind:'cron'` (lint-enforced). Default: no catch-up. */
377
+ catchUp: z.boolean().optional(),
378
+ action: TriggerAction,
379
+ })
380
+ .strict();
381
+ // ---------------------------------------------------------------------------------------
382
+ // extensions[] — independent grammar (extension-pack references)
383
+ // ---------------------------------------------------------------------------------------
384
+ /**
385
+ * An EXACT semantic version pin ("zero caret/tilde"). An extension
386
+ * pack is product code authored + versioned in its OWN repo and named by reference here, so its
387
+ * version MUST be pinned exactly — any range/wildcard/floating/partial form would let the resolved
388
+ * pack drift silently between deploys, defeating the reviewed-deploy discipline.
389
+ *
390
+ * ALLOWLIST by construction (NOT a blocklist of range characters — a blocklist false-accepts forms
391
+ * it doesn't enumerate, e.g. uppercase-X wildcards or floating dist-tags, AND false-rejects legit
392
+ * exact pins whose prerelease/build metadata contains an `x`). We accept ONLY a strict-exact semver:
393
+ * `MAJOR.MINOR.PATCH` (each numeric, no leading zeros) with an OPTIONAL `-prerelease` and/or
394
+ * `+build` metadata segment (the canonical semver.org grammar, anchored). Everything else — every
395
+ * range (`^`/`~`/`>=`/`<`/`=`), wildcard (`*`/`1.2.x`/`1.X`/`X`), floating dist-tag
396
+ * (`latest`/`stable`/`beta`/`next`), partial version (`1`/`1.2`), set/hyphen range
397
+ * (`1.0.0 || 2.0.0` / `1.0.0 - 2.0.0`), `v`-prefix, leading zero, or surrounding whitespace — fails
398
+ * by NOT matching the allowlist, so no enumeration can leak a form.
399
+ *
400
+ * Accepted: `1.2.3`, `1.2.3-rc.1`, `1.0.0-linux.1`, `2.0.0+exp.sha`, `10.20.30` (exact prerelease/
401
+ * build metadata — including the letter `x` inside it — is still an exact pin). We do NOT resolve
402
+ * the pack here (its own loader resolves + validates the actual published version); this is the
403
+ * fail-closed "is it EXACTLY one version?" guard at the grammar boundary.
404
+ *
405
+ * Implemented as `.regex()` (NOT `.refine()`): a `.regex()` serializes into the exported JSON-Schema
406
+ * as a `pattern`, so the artifact (export.ts) ALSO enforces the exact-pin constraint — a `.refine()`
407
+ * is dropped by `z.toJSONSchema`, which would leave the exported schema with NO version constraint.
408
+ */
409
+ const EXACT_SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
410
+ export const ExactVersionPin = z
411
+ .string()
412
+ .min(1)
413
+ .regex(EXACT_SEMVER_RE, {
414
+ message: 'extension version must be an EXACT semver pin (MAJOR.MINOR.PATCH with optional -prerelease/' +
415
+ '+build) — ranges, wildcards (incl. uppercase X), floating dist-tags (latest/beta/…), and ' +
416
+ 'partial versions (1, 1.2) are rejected',
417
+ });
418
+ /**
419
+ * A reference to an extension pack to load. The pack carries ALL product code (its
420
+ * own stores/handlers/tooling/route fragments + capability impls); core validates ONLY this
421
+ * reference shape, never the pack's contents. `config` is an OPEN passthrough record whose CONTENTS
422
+ * are validated by the PACK's own Zod at load time, NEVER by core — but the ExtensionRef
423
+ * wrapper itself is `.strict()`, so an unknown key ON THE REF is fail-closed-rejected.
424
+ *
425
+ * - `id` — a logical id for the pack (unique within `extensions[]`; lint-resolvable later).
426
+ * - `module` — the pack module/directory reference (resolved + path-jailed by `loadExtensions`).
427
+ * - `version` — an EXACT version pin (no range — see `ExactVersionPin`).
428
+ * - `config` — optional opaque pack-validated config (passthrough; core does not inspect it).
429
+ */
430
+ export const ExtensionRef = z
431
+ .object({
432
+ id: z.string().min(1),
433
+ module: z.string().min(1),
434
+ version: ExactVersionPin,
435
+ config: z.record(z.string(), z.unknown()).optional(),
436
+ })
437
+ .strict();
438
+ // ---------------------------------------------------------------------------------------
439
+ // frontend[] — independent grammar (static frontend mounts served alongside the API)
440
+ // ---------------------------------------------------------------------------------------
441
+ /**
442
+ * One static frontend mount served alongside the backend's API. A backend may declare a list of
443
+ * these so a spec can ship its own web UI (built assets) next to the routes it exposes.
444
+ *
445
+ * - `route` — the URL prefix the mount is served under (e.g. `/` or `/app`); must start with `/`.
446
+ * - `dir` — the directory of built static assets, relative to the spec file.
447
+ * - `spa` — when true, an unmatched path under `route` falls back to `index.html` (the
448
+ * History-API single-page-app fallback); default false (plain static file serving).
449
+ *
450
+ * `.strict()` — fail-closed unknown-key rejection, consistent with every other grammar level.
451
+ */
452
+ export const FrontendSpec = z
453
+ .object({
454
+ route: z.string().min(1).regex(/^\//, 'route must start with "/"'),
455
+ dir: z.string().min(1),
456
+ spa: z.boolean().default(false),
457
+ })
458
+ .strict();
459
+ // ---------------------------------------------------------------------------------------
460
+ // RaySpec — the whole document
461
+ // ---------------------------------------------------------------------------------------
462
+ /**
463
+ * The full RaySpec config document. `version` is `z.literal('1.0')` — but the parser checks it
464
+ * FIRST (two-phase, see `parse.ts`) so an unsupported major yields a clean `unsupported_version`
465
+ * SpecError instead of a wall of strict-shape errors. `.strict()` at the top level rejects any
466
+ * unknown top-level section.
467
+ *
468
+ * Every section defaults to `[]` so a minimal spec (just `version` + `metadata`) is valid.
469
+ */
470
+ export const RaySpec = z
471
+ .object({
472
+ version: z.literal(SPEC_VERSION),
473
+ metadata: Metadata,
474
+ stores: z.array(StoreSpec).default([]),
475
+ api: z.array(ApiRouteSpec).default([]),
476
+ agents: z.array(AgentSpecConfig).default([]),
477
+ tooling: z.array(ToolSpecConfig).default([]),
478
+ triggers: z.array(TriggerSpec).default([]),
479
+ handlers: z.array(HandlerSpec).default([]),
480
+ /**
481
+ * OPTIONAL extension-pack references. Defaults to `[]` so a minimal spec (just
482
+ * `version` + `metadata`) and every existing fixture stays valid — absent = NO-OP (no packs
483
+ * loaded). Each entry's contents (`config`) are validated by the pack itself, never core;
484
+ * the ref wrapper is `.strict()` (fail-closed on an unknown key). The `loadExtensions` merge
485
+ * threads pack fragments into the other sections.
486
+ */
487
+ extensions: z.array(ExtensionRef).default([]),
488
+ /**
489
+ * OPTIONAL deployment properties. An object (not an array) — absent ⇒ no
490
+ * durable worker (the default; a per-request `async:true` then fail-closed-501s at the run
491
+ * surface). A minimal spec (just `version` + `metadata`) stays valid (deployment is omittable).
492
+ */
493
+ deployment: DeploymentSpec.optional(),
494
+ /**
495
+ * OPTIONAL static frontend mounts. A list of `{route, dir, spa?}` entries served alongside the
496
+ * API (see `FrontendSpec`). `.optional()` (NOT `.default([])`) so a spec that omits `frontend`
497
+ * parses byte-identically — absent = NO static mounts. A minimal spec (just `version` +
498
+ * `metadata`) stays valid (frontend is omittable).
499
+ */
500
+ frontend: z.array(FrontendSpec).optional(),
501
+ })
502
+ .strict();
503
+ //# sourceMappingURL=grammar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grammar.js","sourceRoot":"","sources":["../src/grammar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @rayspec/spec — the RaySpec config grammar, parser, linter, and JSON-Schema exporter.
3
+ *
4
+ * A deployed RaySpec backend is ONE validated `RaySpec` (stores · api · agents ·
5
+ * tooling · triggers · handlers). This package owns the GRAMMAR + the fail-closed validation
6
+ * pipeline; the interpreters that turn a validated spec into running infrastructure are built in
7
+ * the interpreter packages (and depend on this package).
8
+ */
9
+ export * from './brace-params.js';
10
+ export * from './detect.js';
11
+ export * from './errors.js';
12
+ export * from './export.js';
13
+ export * from './grammar.js';
14
+ export * from './lint.js';
15
+ export * from './parse.js';
16
+ export * from './product-events.js';
17
+ export * from './product-grammar.js';
18
+ export * from './product-lint.js';
19
+ export * from './product-parse.js';
20
+ export * from './product-scope.js';
21
+ export * from './product-views.js';
22
+ export * from './product-views-lint.js';
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @rayspec/spec — the RaySpec config grammar, parser, linter, and JSON-Schema exporter.
3
+ *
4
+ * A deployed RaySpec backend is ONE validated `RaySpec` (stores · api · agents ·
5
+ * tooling · triggers · handlers). This package owns the GRAMMAR + the fail-closed validation
6
+ * pipeline; the interpreters that turn a validated spec into running infrastructure are built in
7
+ * the interpreter packages (and depend on this package).
8
+ */
9
+ // Product-YAML family: the Product-YAML program document grammar/parser/linter + the
10
+ // dispatch layer that routes a raw spec to the right family. Additive — the RaySpec surface above
11
+ // is unchanged.
12
+ export * from './brace-params.js';
13
+ export * from './detect.js';
14
+ export * from './errors.js';
15
+ export * from './export.js';
16
+ export * from './grammar.js';
17
+ export * from './lint.js';
18
+ export * from './parse.js';
19
+ export * from './product-events.js';
20
+ export * from './product-grammar.js';
21
+ export * from './product-lint.js';
22
+ export * from './product-parse.js';
23
+ export * from './product-scope.js';
24
+ export * from './product-views.js';
25
+ export * from './product-views-lint.js';
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qFAAqF;AACrF,kGAAkG;AAClG,gBAAgB;AAChB,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC"}