@lovrozagar/oat 0.1.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 (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +401 -0
  3. package/bin/oat.js +2 -0
  4. package/dist/cli.js +386 -0
  5. package/dist/config/define-config.d.ts +165 -0
  6. package/dist/config/define-config.d.ts.map +1 -0
  7. package/dist/config/define-config.js +24 -0
  8. package/dist/config/define-config.js.map +1 -0
  9. package/dist/config/load.d.ts +10 -0
  10. package/dist/config/load.d.ts.map +1 -0
  11. package/dist/config/load.js +61 -0
  12. package/dist/config/load.js.map +1 -0
  13. package/dist/index.d.ts +17 -0
  14. package/dist/index.js +9 -0
  15. package/dist/reference/defects.d.ts +254 -0
  16. package/dist/reference/defects.d.ts.map +1 -0
  17. package/dist/reference/defects.js +265 -0
  18. package/dist/reference/defects.js.map +1 -0
  19. package/dist/reference/dialect.d.ts +104 -0
  20. package/dist/reference/dialect.d.ts.map +1 -0
  21. package/dist/reference/dialect.js +174 -0
  22. package/dist/reference/dialect.js.map +1 -0
  23. package/dist/reference/http.d.ts +79 -0
  24. package/dist/reference/http.d.ts.map +1 -0
  25. package/dist/reference/http.js +889 -0
  26. package/dist/reference/http.js.map +1 -0
  27. package/dist/reference/model.d.ts +56 -0
  28. package/dist/reference/model.d.ts.map +1 -0
  29. package/dist/reference/model.js +156 -0
  30. package/dist/reference/model.js.map +1 -0
  31. package/dist/reference/query.d.ts +45 -0
  32. package/dist/reference/query.d.ts.map +1 -0
  33. package/dist/reference/query.js +353 -0
  34. package/dist/reference/query.js.map +1 -0
  35. package/dist/reference/spec.d.ts +13 -0
  36. package/dist/reference/spec.d.ts.map +1 -0
  37. package/dist/reference/spec.js +547 -0
  38. package/dist/reference/spec.js.map +1 -0
  39. package/dist/reference/store-api.d.ts +59 -0
  40. package/dist/reference/store-api.d.ts.map +1 -0
  41. package/dist/reference/store-api.js +76 -0
  42. package/dist/reference/store-api.js.map +1 -0
  43. package/dist/reference/stores/memory.d.ts +27 -0
  44. package/dist/reference/stores/memory.d.ts.map +1 -0
  45. package/dist/reference/stores/memory.js +97 -0
  46. package/dist/reference/stores/memory.js.map +1 -0
  47. package/dist/reference/stores/postgres.d.ts +61 -0
  48. package/dist/reference/stores/postgres.d.ts.map +1 -0
  49. package/dist/reference/stores/postgres.js +406 -0
  50. package/dist/reference/stores/postgres.js.map +1 -0
  51. package/dist/reference/stores/sqlite-driver.d.ts +54 -0
  52. package/dist/reference/stores/sqlite-driver.d.ts.map +1 -0
  53. package/dist/reference/stores/sqlite-driver.js +99 -0
  54. package/dist/reference/stores/sqlite-driver.js.map +1 -0
  55. package/dist/reference/stores/sqlite.d.ts +68 -0
  56. package/dist/reference/stores/sqlite.d.ts.map +1 -0
  57. package/dist/reference/stores/sqlite.js +464 -0
  58. package/dist/reference/stores/sqlite.js.map +1 -0
  59. package/dist/report/console.d.ts +33 -0
  60. package/dist/report/console.d.ts.map +1 -0
  61. package/dist/report/console.js +237 -0
  62. package/dist/report/console.js.map +1 -0
  63. package/dist/report/matrix.d.ts +131 -0
  64. package/dist/report/matrix.d.ts.map +1 -0
  65. package/dist/report/matrix.js +865 -0
  66. package/dist/report/matrix.js.map +1 -0
  67. package/dist/report/render.d.ts +66 -0
  68. package/dist/report/render.d.ts.map +1 -0
  69. package/dist/report/render.js +423 -0
  70. package/dist/report/render.js.map +1 -0
  71. package/dist/runtime/async.d.ts +34 -0
  72. package/dist/runtime/async.d.ts.map +1 -0
  73. package/dist/runtime/async.js +130 -0
  74. package/dist/runtime/async.js.map +1 -0
  75. package/dist/runtime/auth.d.ts +46 -0
  76. package/dist/runtime/auth.d.ts.map +1 -0
  77. package/dist/runtime/auth.js +236 -0
  78. package/dist/runtime/auth.js.map +1 -0
  79. package/dist/runtime/checks.d.ts +89 -0
  80. package/dist/runtime/checks.d.ts.map +1 -0
  81. package/dist/runtime/checks.js +3400 -0
  82. package/dist/runtime/checks.js.map +1 -0
  83. package/dist/runtime/client.d.ts +65 -0
  84. package/dist/runtime/client.d.ts.map +1 -0
  85. package/dist/runtime/client.js +122 -0
  86. package/dist/runtime/client.js.map +1 -0
  87. package/dist/runtime/finding.d.ts +50 -0
  88. package/dist/runtime/finding.d.ts.map +1 -0
  89. package/dist/runtime/finding.js +50 -0
  90. package/dist/runtime/finding.js.map +1 -0
  91. package/dist/runtime/fixture.d.ts +20 -0
  92. package/dist/runtime/fixture.d.ts.map +1 -0
  93. package/dist/runtime/fixture.js +175 -0
  94. package/dist/runtime/fixture.js.map +1 -0
  95. package/dist/runtime/progress.d.ts +41 -0
  96. package/dist/runtime/progress.d.ts.map +1 -0
  97. package/dist/runtime/progress.js +186 -0
  98. package/dist/runtime/progress.js.map +1 -0
  99. package/dist/runtime/run.d.ts +69 -0
  100. package/dist/runtime/run.d.ts.map +1 -0
  101. package/dist/runtime/run.js +575 -0
  102. package/dist/runtime/run.js.map +1 -0
  103. package/dist/runtime/teardown.d.ts +38 -0
  104. package/dist/runtime/teardown.d.ts.map +1 -0
  105. package/dist/runtime/teardown.js +129 -0
  106. package/dist/runtime/teardown.js.map +1 -0
  107. package/dist/runtime/validate.d.ts +31 -0
  108. package/dist/runtime/validate.d.ts.map +1 -0
  109. package/dist/runtime/validate.js +111 -0
  110. package/dist/runtime/validate.js.map +1 -0
  111. package/dist/runtime/world.d.ts +49 -0
  112. package/dist/runtime/world.d.ts.map +1 -0
  113. package/dist/runtime/world.js +119 -0
  114. package/dist/runtime/world.js.map +1 -0
  115. package/dist/spec/collection.d.ts +31 -0
  116. package/dist/spec/collection.d.ts.map +1 -0
  117. package/dist/spec/collection.js +121 -0
  118. package/dist/spec/collection.js.map +1 -0
  119. package/dist/spec/conventions.d.ts +103 -0
  120. package/dist/spec/conventions.d.ts.map +1 -0
  121. package/dist/spec/conventions.js +275 -0
  122. package/dist/spec/conventions.js.map +1 -0
  123. package/dist/spec/extensions.d.ts +74 -0
  124. package/dist/spec/extensions.d.ts.map +1 -0
  125. package/dist/spec/extensions.js +335 -0
  126. package/dist/spec/extensions.js.map +1 -0
  127. package/dist/spec/graph.d.ts +89 -0
  128. package/dist/spec/graph.d.ts.map +1 -0
  129. package/dist/spec/graph.js +318 -0
  130. package/dist/spec/graph.js.map +1 -0
  131. package/dist/spec/load.d.ts +36 -0
  132. package/dist/spec/load.d.ts.map +1 -0
  133. package/dist/spec/load.js +166 -0
  134. package/dist/spec/load.js.map +1 -0
  135. package/dist/spec/types.d.ts +57 -0
  136. package/dist/spec/types.d.ts.map +1 -0
  137. package/dist/spec/types.js +24 -0
  138. package/dist/spec/types.js.map +1 -0
  139. package/labs/README.md +130 -0
  140. package/labs/annotated-openapi.yaml +311 -0
  141. package/labs/anyrow.config.ts +107 -0
  142. package/labs/demo.mjs +124 -0
  143. package/labs/local.config.ts +41 -0
  144. package/labs/minimal.config.ts +32 -0
  145. package/package.json +80 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The conventions a reference backend speaks.
3
+ *
4
+ * Everything oat had quietly hardcoded — what the page-size parameter is called, where the total
5
+ * lives in the envelope, how a filter expression is spelled — varies wildly between real APIs
6
+ * and not at all between two instances of the same fixture. A single-dialect fixture therefore
7
+ * proves that the checks work on *one* shape, which is a much weaker claim than it appears.
8
+ *
9
+ * Two dialects, differing in every name and in the filter grammar, turn that into a real test:
10
+ * the defects and the checks are identical, so anything that passes on one and fails on the
11
+ * other was reading a convention rather than the contract.
12
+ */
13
+ export interface Dialect {
14
+ name: string;
15
+ /** Query parameter names, by role. */
16
+ params: {
17
+ filter: string;
18
+ order: string;
19
+ select: string;
20
+ search: string;
21
+ limit: string;
22
+ /** Page number, where the API counts pages. Absent when it counts rows skipped. */
23
+ page?: string;
24
+ /** Rows to skip, where the API pages by offset rather than page number. */
25
+ offset?: string;
26
+ cursor?: string;
27
+ };
28
+ /**
29
+ * Envelope property names, by role.
30
+ *
31
+ * `null` for the whole object means the response *is* the array and pagination facts travel in
32
+ * a `Link` header instead — the GitHub shape. That is a different pagination model, not a
33
+ * different spelling of one, which is precisely why it belongs in the fixture: a tool that
34
+ * only ever saw facts in a body may be reading conventions rather than the contract.
35
+ */
36
+ envelope: {
37
+ /** Property holding the array. `null` means "named after the entity" — `tables`, `rows`. */
38
+ collection: string | null;
39
+ total: string;
40
+ hasMore: string;
41
+ nextCursor?: string;
42
+ page: string;
43
+ limit: string;
44
+ } | null;
45
+ /**
46
+ * How filter expressions are written.
47
+ *
48
+ * `equality` has no filter parameter at all: each filterable field is its own query parameter,
49
+ * and only equality is expressible. It is the most common shape in the wild and the one where
50
+ * oat can say the least — which makes it the real test of whether "I cannot express this" is
51
+ * reported honestly rather than silently skipped.
52
+ */
53
+ grammar: "postgrest" | "colon" | "equality";
54
+ /** How sort directions are written. Defaults to the dotted form when unset. */
55
+ sortGrammar?: "dotted" | "prefixed" | "colon" | "spaced";
56
+ /** How a sparse fieldset is written. Defaults to comma-separated names. */
57
+ selectGrammar?: "csv" | "bracketed";
58
+ }
59
+ /** `field.op.value` with cursor pagination and entity-named collections. */
60
+ export declare const POSTGREST: Dialect;
61
+ /**
62
+ * A deliberately unrelated spelling: `per_page`, `sort`, `fields`, `search`, a `data` envelope
63
+ * with `total_count`/`has_more`, no cursor at all, and `field=op:value` filters.
64
+ *
65
+ * Nothing here shares a name with the other dialect, so a check that still works is working from
66
+ * the document rather than from familiarity.
67
+ */
68
+ export declare const CLASSIC: Dialect;
69
+ /**
70
+ * Root array, `Link` header pagination, `offset`/`limit`.
71
+ *
72
+ * No envelope at all: the body is the array, there is no total, no `hasMore`, and no page number.
73
+ * Whether more pages exist is answered by `rel="next"` in a header. Nothing about a check should
74
+ * have to change for this, and where something does, the check was reading the fixture's habits.
75
+ */
76
+ export declare const LINKED: Dialect;
77
+ /**
78
+ * JSON:API-flavoured: `sort=-name` for descending, `fields[table]=id,name` for projection.
79
+ *
80
+ * The parameter *names* here are unremarkable — `sort`, `fields`, `page`, `filter` — which is the
81
+ * point. Everything oat had generalised was the name; the value grammars stayed hardcoded to one
82
+ * spelling. A shape that renames nothing but writes its values differently is the sharpest test
83
+ * of whether that generalisation was real.
84
+ */
85
+ export declare const JSONAPI: Dialect;
86
+ /**
87
+ * The plainest shape there is: `?status=active&page=2`, no filter expression language at all.
88
+ *
89
+ * Half of oat's query checks cannot be expressed here — there is no way to write a negation, a
90
+ * range, or a pattern — and that is precisely the point. Every one of them must report what it
91
+ * could not test and why, because a run that goes quiet against the most common API shape in the
92
+ * world is the single most damaging way this tool could fail.
93
+ */
94
+ export declare const PLAIN: Dialect;
95
+ export declare const DIALECTS: Record<string, Dialect>;
96
+ /**
97
+ * Rewrites a filter expression from a dialect's grammar into the canonical `field.op.value` the
98
+ * stores parse, so the storage layer never has to know which dialect it is serving.
99
+ *
100
+ * Returns `null` when the expression is malformed, which the caller surfaces as a 400 — the same
101
+ * treatment the canonical grammar gets.
102
+ */
103
+ export declare function toCanonicalFilter(expression: string, dialect: Dialect): string | null;
104
+ //# sourceMappingURL=dialect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialect.d.ts","sourceRoot":"","sources":["../../src/reference/dialect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,sCAAsC;IACtC,MAAM,EAAE;QACP,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;QACb,mFAAmF;QACnF,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,2EAA2E;QAC3E,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;IACD;;;;;;;OAOG;IACH,QAAQ,EAAE;QACT,4FAA4F;QAC5F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;QACzB,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;KACb,GAAG,IAAI,CAAA;IACR;;;;;;;OAOG;IACH,OAAO,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,CAAA;IAC3C,+EAA+E;IAC/E,WAAW,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;IACxD,2EAA2E;IAC3E,aAAa,CAAC,EAAE,KAAK,GAAG,WAAW,CAAA;CACnC;AAED,4EAA4E;AAC5E,eAAO,MAAM,SAAS,EAAE,OAoBvB,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAE,OAkBrB,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,EAAE,OAYpB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,EAAE,OAoBrB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,EAAE,OAqBnB,CAAA;AAED,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAM5C,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAkBrF"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * The conventions a reference backend speaks.
3
+ *
4
+ * Everything oat had quietly hardcoded — what the page-size parameter is called, where the total
5
+ * lives in the envelope, how a filter expression is spelled — varies wildly between real APIs
6
+ * and not at all between two instances of the same fixture. A single-dialect fixture therefore
7
+ * proves that the checks work on *one* shape, which is a much weaker claim than it appears.
8
+ *
9
+ * Two dialects, differing in every name and in the filter grammar, turn that into a real test:
10
+ * the defects and the checks are identical, so anything that passes on one and fails on the
11
+ * other was reading a convention rather than the contract.
12
+ */
13
+ /** `field.op.value` with cursor pagination and entity-named collections. */
14
+ export const POSTGREST = {
15
+ envelope: {
16
+ collection: null,
17
+ hasMore: "hasMore",
18
+ limit: "limit",
19
+ nextCursor: "nextCursor",
20
+ page: "page",
21
+ total: "count",
22
+ },
23
+ grammar: "postgrest",
24
+ name: "postgrest",
25
+ params: {
26
+ cursor: "cursor",
27
+ filter: "filter",
28
+ limit: "limit",
29
+ order: "order",
30
+ page: "page",
31
+ search: "q",
32
+ select: "select",
33
+ },
34
+ };
35
+ /**
36
+ * A deliberately unrelated spelling: `per_page`, `sort`, `fields`, `search`, a `data` envelope
37
+ * with `total_count`/`has_more`, no cursor at all, and `field=op:value` filters.
38
+ *
39
+ * Nothing here shares a name with the other dialect, so a check that still works is working from
40
+ * the document rather than from familiarity.
41
+ */
42
+ export const CLASSIC = {
43
+ envelope: {
44
+ collection: "data",
45
+ hasMore: "has_more",
46
+ limit: "per_page",
47
+ page: "page",
48
+ total: "total_count",
49
+ },
50
+ grammar: "colon",
51
+ name: "classic",
52
+ params: {
53
+ filter: "filter",
54
+ limit: "per_page",
55
+ order: "sort",
56
+ page: "page",
57
+ search: "search",
58
+ select: "fields",
59
+ },
60
+ };
61
+ /**
62
+ * Root array, `Link` header pagination, `offset`/`limit`.
63
+ *
64
+ * No envelope at all: the body is the array, there is no total, no `hasMore`, and no page number.
65
+ * Whether more pages exist is answered by `rel="next"` in a header. Nothing about a check should
66
+ * have to change for this, and where something does, the check was reading the fixture's habits.
67
+ */
68
+ export const LINKED = {
69
+ envelope: null,
70
+ grammar: "postgrest",
71
+ name: "linked",
72
+ params: {
73
+ filter: "filter",
74
+ limit: "limit",
75
+ offset: "offset",
76
+ order: "order",
77
+ search: "q",
78
+ select: "fields",
79
+ },
80
+ };
81
+ /**
82
+ * JSON:API-flavoured: `sort=-name` for descending, `fields[table]=id,name` for projection.
83
+ *
84
+ * The parameter *names* here are unremarkable — `sort`, `fields`, `page`, `filter` — which is the
85
+ * point. Everything oat had generalised was the name; the value grammars stayed hardcoded to one
86
+ * spelling. A shape that renames nothing but writes its values differently is the sharpest test
87
+ * of whether that generalisation was real.
88
+ */
89
+ export const JSONAPI = {
90
+ envelope: {
91
+ collection: "data",
92
+ hasMore: "has_more",
93
+ limit: "size",
94
+ page: "number",
95
+ total: "total",
96
+ },
97
+ grammar: "postgrest",
98
+ name: "jsonapi",
99
+ params: {
100
+ filter: "filter",
101
+ limit: "size",
102
+ order: "sort",
103
+ page: "page",
104
+ search: "q",
105
+ select: "fields",
106
+ },
107
+ selectGrammar: "bracketed",
108
+ sortGrammar: "prefixed",
109
+ };
110
+ /**
111
+ * The plainest shape there is: `?status=active&page=2`, no filter expression language at all.
112
+ *
113
+ * Half of oat's query checks cannot be expressed here — there is no way to write a negation, a
114
+ * range, or a pattern — and that is precisely the point. Every one of them must report what it
115
+ * could not test and why, because a run that goes quiet against the most common API shape in the
116
+ * world is the single most damaging way this tool could fail.
117
+ */
118
+ export const PLAIN = {
119
+ envelope: {
120
+ collection: "items",
121
+ hasMore: "has_more",
122
+ limit: "limit",
123
+ page: "page",
124
+ total: "total",
125
+ },
126
+ grammar: "equality",
127
+ name: "plain",
128
+ params: {
129
+ /* Declared for completeness; the equality grammar never sends it, and the fixture never
130
+ * reads it. A parameter a backend accepts and ignores is itself a defect oat reports. */
131
+ filter: "filter",
132
+ limit: "limit",
133
+ order: "sort",
134
+ page: "page",
135
+ search: "q",
136
+ select: "fields",
137
+ },
138
+ sortGrammar: "colon",
139
+ };
140
+ export const DIALECTS = {
141
+ jsonapi: JSONAPI,
142
+ plain: PLAIN,
143
+ classic: CLASSIC,
144
+ linked: LINKED,
145
+ postgrest: POSTGREST,
146
+ };
147
+ /**
148
+ * Rewrites a filter expression from a dialect's grammar into the canonical `field.op.value` the
149
+ * stores parse, so the storage layer never has to know which dialect it is serving.
150
+ *
151
+ * Returns `null` when the expression is malformed, which the caller surfaces as a 400 — the same
152
+ * treatment the canonical grammar gets.
153
+ */
154
+ export function toCanonicalFilter(expression, dialect) {
155
+ /* Already canonical: the postgrest grammar *is* the canonical form, and the equality grammar
156
+ * has no expression of its own — the per-field parameters were assembled into canonical terms
157
+ * before reaching here. Re-parsing that would reject a well-formed expression. */
158
+ if (dialect.grammar === "postgrest" || dialect.grammar === "equality")
159
+ return expression;
160
+ /* `status=eq:active`, joined by commas. No grouping: the point of a second dialect is
161
+ * different spelling, not a second expression language to maintain. */
162
+ const terms = expression.split(",").map((term) => term.trim()).filter(Boolean);
163
+ if (terms.length === 0)
164
+ return null;
165
+ const canonical = [];
166
+ for (const term of terms) {
167
+ const match = /^([^=]+)=([a-z]+):(.*)$/s.exec(term);
168
+ if (match?.[1] === undefined || match[2] === undefined || match[3] === undefined)
169
+ return null;
170
+ canonical.push(`${match[1]}.${match[2]}.${match[3]}`);
171
+ }
172
+ return canonical.length === 1 ? canonical[0] : `and(${canonical.join(",")})`;
173
+ }
174
+ //# sourceMappingURL=dialect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialect.js","sourceRoot":"","sources":["../../src/reference/dialect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The reference backend's HTTP layer — one implementation, any store.
3
+ *
4
+ * Routing, auth, tenancy, validation and the defect behaviours that live above storage are
5
+ * written once here. Each engine supplies only a `Store`, so a defect is defined in one place
6
+ * and exercised identically on every backend; when two engines then disagree about what that
7
+ * defect *does*, the disagreement is real rather than an artefact of two implementations
8
+ * drifting apart.
9
+ *
10
+ * Backends: `createMemoryServer` (no dependencies), `createSqliteServer` (`node:sqlite`),
11
+ * `createD1Server` (Cloudflare D1 over HTTP),
12
+ * `createPostgresServer` (a reachable server). Every store is imported lazily — a static import
13
+ * would load one engine's driver for all of them, and an optional runtime such as `node:sqlite`
14
+ * would take down paths that never touch it.
15
+ *
16
+ * This is a test fixture. It is excluded from the published package; oat itself never talks to
17
+ * a database.
18
+ */
19
+ import { type Server } from "node:http";
20
+ import { type DefectSet } from "./defects.ts";
21
+ import { type Store } from "./store-api.ts";
22
+ interface Principal {
23
+ key: string;
24
+ token: string;
25
+ projectId: string;
26
+ /** Higher can do everything a lower rank can. Viewer 0, member 1, owner 2. */
27
+ rank: number;
28
+ }
29
+ export interface ReferenceServer {
30
+ server: Server;
31
+ url: string;
32
+ defects: DefectSet;
33
+ close: () => Promise<void>;
34
+ principals: Principal[];
35
+ }
36
+ /**
37
+ * One server, any store. Defining a defect once and exercising it on every engine is what makes
38
+ * a disagreement between engines meaningful rather than an artefact of two implementations.
39
+ */
40
+ export declare function createReferenceServer(options: {
41
+ defects?: string[];
42
+ untagged?: boolean;
43
+ dialect?: string;
44
+ }, createStore: (defects: DefectSet) => Promise<Store>): Promise<ReferenceServer>;
45
+ /** In-memory reference server — no dependencies, no flags, nothing to have running. */
46
+ export declare function createMemoryServer(options?: {
47
+ defects?: string[];
48
+ untagged?: boolean;
49
+ dialect?: string;
50
+ }): Promise<ReferenceServer>;
51
+ /** SQLite-backed reference server, in-process via `node:sqlite`. */
52
+ export declare function createSqliteServer(options?: {
53
+ defects?: string[];
54
+ untagged?: boolean;
55
+ dialect?: string;
56
+ }): Promise<ReferenceServer>;
57
+ /**
58
+ * Cloudflare D1 reference server — the same SQL over the network, against someone else's build.
59
+ *
60
+ * Credentials come from the environment rather than config so a token never reaches a file that
61
+ * could be committed. Tables are prefixed per run and dropped on close, because D1 persists: two
62
+ * runs sharing one database would otherwise contaminate each other's results.
63
+ */
64
+ export declare function createD1Server(options?: {
65
+ defects?: string[];
66
+ untagged?: boolean;
67
+ dialect?: string;
68
+ accountId?: string;
69
+ databaseId?: string;
70
+ apiToken?: string;
71
+ }): Promise<ReferenceServer>;
72
+ /** Postgres-backed reference server. Imported lazily so the driver is only loaded when used. */
73
+ export declare function createPostgresServer(options?: {
74
+ defects?: string[];
75
+ untagged?: boolean;
76
+ dialect?: string;
77
+ }): Promise<ReferenceServer>;
78
+ export {};
79
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/reference/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAA;AAEhG,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAInE,OAAO,EAAsB,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAE/D,UAAU,SAAS;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAA;CACZ;AAoJD,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,SAAS,CAAA;IAClB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,UAAU,EAAE,SAAS,EAAE,CAAA;CACvB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAIrE,WAAW,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,OAAO,CAAC,KAAK,CAAC,GACjD,OAAO,CAAC,eAAe,CAAC,CAwlB1B;AAmKD,uFAAuF;AACvF,wBAAsB,kBAAkB,CACvC,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACxE,OAAO,CAAC,eAAe,CAAC,CAG1B;AAED,oEAAoE;AACpE,wBAAsB,kBAAkB,CACvC,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACxE,OAAO,CAAC,eAAe,CAAC,CAM1B;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CACnC,OAAO,GAAE;IACR,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;CACZ,GACJ,OAAO,CAAC,eAAe,CAAC,CA2B1B;AAED,gGAAgG;AAChG,wBAAsB,oBAAoB,CACzC,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACxE,OAAO,CAAC,eAAe,CAAC,CAG1B"}