@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
package/dist/lint.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ import { type SpecError, type SpecWarning } from './errors.js';
2
+ import { type RaySpec } from './grammar.js';
3
+ /**
4
+ * Column names the table generator INJECTS on every product table (the tenancy/GDPR pattern —
5
+ * see packages/db/src/schema.ts). An author-declared business column with one of these names
6
+ * would shadow/collide with the injected column, so the linter rejects it fail-closed.
7
+ */
8
+ export declare const RESERVED_COLUMN_NAMES: ReadonlySet<string>;
9
+ /**
10
+ * The list-query CONTROL keywords — the reserved query-string keys the declarative `list` route
11
+ * uses to steer sorting, keyset pagination, and substring search (mirrors `CONTROL_KEYS` in the compose
12
+ * package's store-query.ts; @rayspec/spec cannot import the compose package, so this is the KEEP-IN-SYNC
13
+ * copy).
14
+ *
15
+ * A declared BUSINESS column of one of these names is a config error, because at the `list` route it is
16
+ * (a) silently un-equality-filterable — `buildListQuery` routes `?order=`/`?after=`/`?limit=`/`?search=`
17
+ * to the control parsers and never reaches the per-column equality lookup — AND (b) it makes the emitted
18
+ * OpenAPI document carry a DUPLICATE query parameter (the hard-coded control param + the per-column
19
+ * filter param share a `name`+`in`), which is an INVALID OpenAPI 3.1 doc. This is a SEPARATE set from
20
+ * `RESERVED_COLUMN_NAMES` on purpose — that Set is meta-test-locked to equal the injected columns
21
+ * (`INJECTED_COLUMN_NAMES`); these keywords are not injected columns, they are query controls.
22
+ */
23
+ export declare const RESERVED_QUERY_KEYWORDS: ReadonlySet<string>;
24
+ /**
25
+ * The name of the GENERATED tsvector column the store generator injects when a store declares
26
+ * `fullTextSearch: true` (a GENERATED-ALWAYS-STORED `to_tsvector('simple', …)` column over the store's
27
+ * text columns, backed by a GIN index — see @rayspec/db generate-product-sql). It is a DB-level search
28
+ * structure (NOT represented in the Drizzle ORM twins, exactly like the injected `<table>_tenant_idx`
29
+ * and the idempotency unique index), so it never surfaces in a list response. Reserved: an FTS store may
30
+ * not declare a business column of this name (the FTS coherence check below rejects the clash).
31
+ */
32
+ export declare const FTS_COLUMN_NAME = "search_vector";
33
+ /**
34
+ * The ranked full-text-search list-query control key (`?__search=<term>`). Distinct from the substring
35
+ * `search` control key: `__search` is available ONLY on a store that declares `fullTextSearch: true`,
36
+ * runs a `search_vector @@ websearch_to_tsquery('simple', term)` match, and orders by `ts_rank` DESC.
37
+ * A store WITHOUT full-text search rejects the param fail-closed. Mirrored in the compose package's
38
+ * store-query.ts `CONTROL_KEYS` (this package cannot import compose — a KEEP-IN-SYNC copy, guarded by
39
+ * the reserved-keyword membership above).
40
+ */
41
+ export declare const FTS_SEARCH_PARAM = "__search";
42
+ /**
43
+ * Route prefixes the PLATFORM owns — a declared static frontend mount may neither claim one nor nest
44
+ * under one (the frontend lint rule below), and the static runtime declines any request under one so a
45
+ * platform miss falls through to the uniform JSON 404 rather than a served file / SPA shell
46
+ * (serve-static.ts consumes this SAME constant so the two never drift). Root `/` is NOT here: it is a
47
+ * legitimate static catch-all that coexists with `/v1/*` via registration order + fall-through.
48
+ */
49
+ export declare const RESERVED_ROUTE_PREFIXES: readonly ["/v1", "/health", "/oidc"];
50
+ /**
51
+ * snake_case -> camelCase, IDENTICAL to the generator's `toCamel` (generate-product-schema.ts), so
52
+ * the collision check here predicts the exact JS identifier the generator would emit. (TEN-3)
53
+ *
54
+ * EXPORTED for the product-store column-collision check in `product-lint.ts` —
55
+ * the ONE spec-side copy of the rule. KEEP-IN-SYNC (honest replication, dependency direction:
56
+ * spec must not import platform/db): the SAME rule also lives in
57
+ * - packages/db/src/generated/generate-product-schema.ts (`toCamel`) + build-product-tables.ts,
58
+ * - packages/platform/src/handlers/store-facade.ts (`snakeToCamel`),
59
+ * - packages/api-auth/src/engine/injected-columns-view.ts (`snakeToCamel`).
60
+ * A literal-example pin test (product-stores.test.ts, "snake→camel pin") guards this copy against
61
+ * drift; if the rule ever changes, ALL copies + the pin must move together.
62
+ */
63
+ export declare function toJsIdentifier(name: string): string;
64
+ /** The full semantic pass. Input is already shape-valid (post-Zod-parse). */
65
+ export declare function lintSpec(spec: RaySpec): SpecError[];
66
+ /**
67
+ * The NON-FATAL semantic-warning pass — advisory findings that do NOT fail a parse (unlike `lintSpec`).
68
+ * Pure over an already-shape-valid `RaySpec`. `doctor`/`plan` surface these alongside the `ok` result so
69
+ * an author sees a documented interaction without being blocked.
70
+ *
71
+ * Today it flags ONE interaction: a `softDelete` store that is the TARGET of a `restrict` foreign key —
72
+ * EITHER an id-target FK (referencing the parent's injected `id`) OR a business-key FK
73
+ * (`referencesColumn`). Both carry the identical footgun: soft-deleting such a parent is an
74
+ * `UPDATE(deleted_at)` that does NOT fire the database ON DELETE restrict, so the referencing rows keep
75
+ * pointing at the (tombstoned) parent — the restrict guarantee only binds on a HARD delete. This is a
76
+ * permitted, documented interaction, so it is a WARNING, not a fail-closed error.
77
+ */
78
+ export declare function lintSpecWarnings(spec: RaySpec): SpecWarning[];
79
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AA8CA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAA0B,MAAM,aAAa,CAAC;AACvF,OAAO,EAA0C,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAOpF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAUpD,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAStD,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,kBAAkB,CAAC;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAE3C;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,sCAAuC,CAAC;AA+B5E;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAoSD,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,CAitBnD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE,CAqD7D"}