okengine 0.17.2 → 0.18.4

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 (209) hide show
  1. package/AGENTS.md +5 -3
  2. package/README.md +14 -10
  3. package/manifest.v1.schema.json +61 -2
  4. package/package.json +19 -5
  5. package/site/content/docs/ai/index.mdx +1 -1
  6. package/site/content/docs/ai/mcp.mdx +10 -1
  7. package/site/content/docs/ai/skills.mdx +9 -9
  8. package/site/content/docs/elements/ai.mdx +1 -1
  9. package/site/content/docs/elements/clock.mdx +1 -1
  10. package/site/content/docs/elements/flow.mdx +25 -1
  11. package/site/content/docs/elements/gate.mdx +3 -2
  12. package/site/content/docs/elements/store.mdx +289 -341
  13. package/site/content/docs/elements/vault.mdx +5 -5
  14. package/site/content/docs/get-started/basic-usage.mdx +3 -10
  15. package/site/content/docs/get-started/index.mdx +1 -1
  16. package/site/content/docs/get-started/installation.mdx +2 -3
  17. package/site/content/docs/get-started/introduction.mdx +58 -121
  18. package/site/content/docs/get-started/meta.json +9 -1
  19. package/site/content/docs/get-started/project-structure.mdx +4 -11
  20. package/site/content/docs/get-started/testing.mdx +328 -0
  21. package/site/content/docs/get-started/why.mdx +93 -71
  22. package/site/content/docs/index.mdx +44 -11
  23. package/site/content/docs/meta.json +8 -5
  24. package/site/content/docs/plugins/apple.mdx +151 -0
  25. package/site/content/docs/plugins/discord.mdx +139 -0
  26. package/site/content/docs/plugins/facebook.mdx +134 -0
  27. package/site/content/docs/plugins/figma.mdx +138 -0
  28. package/site/content/docs/plugins/github.mdx +138 -0
  29. package/site/content/docs/plugins/google.mdx +153 -0
  30. package/site/content/docs/plugins/index.mdx +47 -1
  31. package/site/content/docs/plugins/meta.json +10 -0
  32. package/site/content/docs/plugins/microsoft.mdx +151 -0
  33. package/site/content/docs/plugins/oauth.mdx +188 -0
  34. package/site/content/docs/plugins/x.mdx +125 -0
  35. package/site/content/docs/providers/index.mdx +2 -0
  36. package/site/content/docs/recipes/index.mdx +2 -0
  37. package/site/content/docs/reference/cli.md +3 -2
  38. package/site/content/docs/reference/client.mdx +58 -1
  39. package/site/content/docs/reference/configuration.mdx +2 -4
  40. package/site/content/docs/reference/fx.mdx +3 -1
  41. package/site/content/docs/reference/index.mdx +0 -5
  42. package/site/content/docs/reference/meta.json +2 -2
  43. package/site/content/docs/reference/okid.mdx +137 -0
  44. package/src/auth/bindings.ts +1 -1
  45. package/src/auth/config.ts +9 -0
  46. package/src/auth/identity-sql.ts +314 -0
  47. package/src/auth/identity.ts +140 -2
  48. package/src/auth/index.ts +17 -1
  49. package/src/auth/method-context.ts +3 -0
  50. package/src/auth/oauth-as/cimd.ts +132 -0
  51. package/src/auth/oauth-as/crypto.test.ts +101 -0
  52. package/src/auth/oauth-as/crypto.ts +393 -0
  53. package/src/auth/oauth-as/errors.ts +68 -0
  54. package/src/auth/oauth-as/http.test.ts +419 -0
  55. package/src/auth/oauth-as/http.ts +842 -0
  56. package/src/auth/oauth-as/stores.ts +61 -0
  57. package/src/auth/oauth-as/tables.ts +142 -0
  58. package/src/auth/tables.ts +0 -11
  59. package/src/bench/README.md +83 -0
  60. package/src/bench/REPORT.md +176 -0
  61. package/src/bench/g01-rls-stamp.bench.ts +194 -0
  62. package/src/bench/g02-clock-per-tenant.bench.ts +158 -0
  63. package/src/bench/g03-signal-once.bench.ts +157 -0
  64. package/src/bench/g03-signal-reconnect.bench.ts +254 -0
  65. package/src/bench/g03-signal-sse-memory.bench.ts +191 -0
  66. package/src/bench/g04-auth-vault-hotpath.bench.ts +170 -0
  67. package/src/bench/g05-sustained-full.bench.ts +265 -0
  68. package/src/bench/g06-mixed-load.bench.ts +260 -0
  69. package/src/bench/g07-vault-crypto.bench.ts +100 -0
  70. package/src/bench/g07-vault-rotate-under-read.bench.ts +285 -0
  71. package/src/bench/g08-conn-oversubscribe.bench.ts +194 -0
  72. package/src/bench/g08-store-kv-durable.bench.ts +133 -0
  73. package/src/bench/g08-store-sql.bench.ts +178 -0
  74. package/src/bench/g09-journal-sustained.bench.ts +203 -0
  75. package/src/bench/g10-observability-contention.bench.ts +246 -0
  76. package/src/bench/g11-cold-start-cycle.bench.ts +164 -0
  77. package/src/bench/g13-elements.bench.ts +427 -0
  78. package/src/bench/g14-graceful-shutdown.bench.ts +244 -0
  79. package/src/bench/g15-postgres-degradation.bench.ts +264 -0
  80. package/src/bench/g16-live-query-fanout.bench.ts +206 -0
  81. package/src/bench/lib/event-loop-lag.ts +26 -0
  82. package/src/bench/lib/infra.ts +60 -0
  83. package/src/bench/lib/report.ts +52 -0
  84. package/src/bench/lib/rss-sampler.ts +61 -0
  85. package/src/bench/lib/signal-pg.ts +88 -0
  86. package/src/bench/load-app.ts +337 -0
  87. package/src/bench/load-child.ts +108 -0
  88. package/src/bench/smoke.bench.ts +43 -0
  89. package/src/cli/competitor-mention-removal.test.ts +28 -0
  90. package/src/cli/doctor-fd.ts +117 -0
  91. package/src/cli/doctor.test.ts +192 -0
  92. package/src/cli/doctor.ts +129 -1
  93. package/src/client/create.ts +95 -1
  94. package/src/client/index.ts +9 -2
  95. package/src/client/transport.ts +11 -4
  96. package/src/client/use-live-query.ts +154 -0
  97. package/src/client-react/index.ts +15 -1
  98. package/src/client-react/live-resource.ts +246 -0
  99. package/src/client-react/use-live-query.test.ts +475 -0
  100. package/src/client-react/use-live-query.ts +530 -0
  101. package/src/compiler/extract.test.ts +518 -0
  102. package/src/compiler/extract.ts +386 -19
  103. package/src/console/server/invoke-user-flow.ts +2 -1
  104. package/src/console/ui-next/dist/assets/{access-page-DnWbnGzq.js → access-page-De7Lc2JC.js} +1 -1
  105. package/src/console/ui-next/dist/assets/{flows-page-BiZ4-6yQ.js → flows-page-RGy7VEA_.js} +1 -1
  106. package/src/console/ui-next/dist/assets/{index-C8NRK2R-.js → index-_rgpdVzo.js} +3 -3
  107. package/src/console/ui-next/dist/assets/{observability-page-CrB6vd1T.js → observability-page-Ds6pcnh-.js} +1 -1
  108. package/src/console/ui-next/dist/assets/{store-page-CS5-aETQ.js → store-page-02xOiqIK.js} +3 -3
  109. package/src/console/ui-next/dist/assets/{units-page-CjtdlW8l.js → units-page-4rHOePuE.js} +1 -1
  110. package/src/console/ui-next/dist/assets/{vault-page-C6Xxm9SA.js → vault-page-DISPgxLM.js} +1 -1
  111. package/src/console/ui-next/dist/index.html +1 -1
  112. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +36 -2
  113. package/src/drivers/cdc-outbox.ts +389 -0
  114. package/src/drivers/memory.ts +20 -0
  115. package/src/drivers/oauth-apple.ts +156 -0
  116. package/src/drivers/oauth-discord.ts +79 -0
  117. package/src/drivers/oauth-facebook.ts +80 -0
  118. package/src/drivers/oauth-figma.ts +116 -0
  119. package/src/drivers/oauth-github.ts +92 -0
  120. package/src/drivers/oauth-google.ts +142 -0
  121. package/src/drivers/oauth-microsoft.ts +174 -0
  122. package/src/drivers/oauth-oidc.ts +293 -0
  123. package/src/drivers/oauth-shared.ts +326 -0
  124. package/src/drivers/oauth-types.ts +159 -0
  125. package/src/drivers/oauth-x.ts +77 -0
  126. package/src/drivers/oauth2-common.ts +95 -0
  127. package/src/drivers/oauth2-token.ts +61 -0
  128. package/src/drivers/pg-rls-row-passes.ts +251 -0
  129. package/src/drivers/pg-rls.ts +2 -0
  130. package/src/drivers/postgres.ts +45 -2
  131. package/src/drivers/signal-postgres.ts +2 -1
  132. package/src/elements/channel/runtime.ts +29 -2
  133. package/src/elements/channel.test.ts +52 -0
  134. package/src/elements/gate/boot.ts +29 -2
  135. package/src/elements/store/emit-drizzle.ts +147 -14
  136. package/src/elements/store/field-ddl.test.ts +118 -0
  137. package/src/elements/store/field-types.test.ts +455 -0
  138. package/src/elements/store/list-query.golden.json +777 -0
  139. package/src/elements/store/list-query.parity.test.ts +396 -0
  140. package/src/elements/store/list-query.ts +792 -0
  141. package/src/elements/store/live-default.test.ts +136 -0
  142. package/src/elements/store/live-http.test.ts +160 -0
  143. package/src/elements/store/live-isolation.test.ts +291 -0
  144. package/src/elements/store/live-query-runtime.test.ts +323 -0
  145. package/src/elements/store/live-query-runtime.ts +403 -0
  146. package/src/elements/store/live-query-server.test.ts +377 -0
  147. package/src/elements/store/live-query-server.ts +102 -0
  148. package/src/elements/store/live-query.ts +97 -0
  149. package/src/elements/store/resource.ts +189 -680
  150. package/src/elements/store/rls-row-passes-policies.parity.test.ts +665 -0
  151. package/src/elements/store/schema-decl.ts +539 -41
  152. package/src/elements/store/sql-rls-stamp.test.ts +27 -0
  153. package/src/elements/store/sql-session.ts +297 -35
  154. package/src/elements/store/table.ts +102 -21
  155. package/src/elements/store.test.ts +3 -1
  156. package/src/elements/store.ts +12 -1
  157. package/src/elements/vault/chaos-child.ts +74 -1
  158. package/src/elements/vault/chaos.test.ts +4 -2
  159. package/src/elements/vault/storage.ts +4 -2
  160. package/src/index.ts +5 -2
  161. package/src/kernel/app-auth.ts +1 -0
  162. package/src/kernel/app.ts +116 -2
  163. package/src/kernel/auth-sharing.test.ts +196 -0
  164. package/src/kernel/boot.test.ts +3 -3
  165. package/src/kernel/errors.ts +8 -0
  166. package/src/kernel/fx.test.ts +1 -0
  167. package/src/kernel/fx.ts +14 -2
  168. package/src/kernel/horizontal-child.ts +2 -1
  169. package/src/kernel/http-resource.ts +33 -7
  170. package/src/kernel/identity-host-persist.test.ts +119 -0
  171. package/src/kernel/instance-id.ts +4 -2
  172. package/src/kernel/journal.ts +2 -1
  173. package/src/kernel/mcp-tool.test.ts +95 -0
  174. package/src/kernel/on.ts +9 -0
  175. package/src/kernel/realtime-bind.ts +326 -0
  176. package/src/kernel/resource-live.ts +117 -0
  177. package/src/kernel/triggers.ts +86 -4
  178. package/src/manifest/diff.ts +37 -0
  179. package/src/manifest/types.ts +64 -2
  180. package/src/okid.bench.test.ts +64 -0
  181. package/src/okid.test.ts +338 -0
  182. package/src/okid.ts +245 -0
  183. package/src/plugins/anonymous.ts +19 -1
  184. package/src/plugins/auth/shared.ts +15 -0
  185. package/src/plugins/index.ts +2 -0
  186. package/src/plugins/magic-link.ts +10 -8
  187. package/src/plugins/mcp-oauth.ts +208 -0
  188. package/src/plugins/oauth/flow-store.ts +117 -0
  189. package/src/plugins/oauth/link.ts +69 -0
  190. package/src/plugins/oauth/shared.ts +108 -0
  191. package/src/plugins/oauth/token-vault.ts +100 -0
  192. package/src/plugins/oauth.security.test.ts +535 -0
  193. package/src/plugins/oauth.ts +532 -0
  194. package/src/plugins/otp.ts +48 -6
  195. package/src/plugins/passkey.ts +20 -1
  196. package/src/plugins/two-factor.ts +11 -0
  197. package/src/plugins/username.ts +40 -7
  198. package/src/release/build-lib.ts +7 -1
  199. package/src/release/measure.ts +1 -0
  200. package/src/release/official-plugins.ts +4 -1
  201. package/src/runs/collect.ts +2 -1
  202. package/src/runs/drivers/files.ts +2 -1
  203. package/src/test/create-test-app.ts +114 -5
  204. package/src/test/export-bundle.test.ts +33 -0
  205. package/src/test/live-signals.test.ts +83 -0
  206. package/src/test/tenant-isolation.test.ts +175 -0
  207. package/src/testing.ts +26 -0
  208. package/src/upgrade/codemods.ts +1 -1
  209. package/site/content/docs/reference/migrating-environments.mdx +0 -158
@@ -0,0 +1,777 @@
1
+ {
2
+ "offset:default (no params)": {
3
+ "ok": true,
4
+ "limit": 5,
5
+ "meta": {
6
+ "mode": "offset",
7
+ "limit": 5
8
+ }
9
+ },
10
+ "offset:eq": {
11
+ "ok": true,
12
+ "where": {
13
+ "clause": "\"status\" = ?",
14
+ "params": ["open"],
15
+ "predicates": [
16
+ {
17
+ "column": "status",
18
+ "op": "=",
19
+ "value": "open"
20
+ }
21
+ ]
22
+ },
23
+ "limit": 5,
24
+ "meta": {
25
+ "mode": "offset",
26
+ "limit": 5
27
+ }
28
+ },
29
+ "offset:neq": {
30
+ "ok": true,
31
+ "where": {
32
+ "clause": "\"status\" != ?",
33
+ "params": ["open"],
34
+ "predicates": [
35
+ {
36
+ "column": "status",
37
+ "op": "!=",
38
+ "value": "open"
39
+ }
40
+ ]
41
+ },
42
+ "limit": 5,
43
+ "meta": {
44
+ "mode": "offset",
45
+ "limit": 5
46
+ }
47
+ },
48
+ "offset:not.eq inversion": {
49
+ "ok": true,
50
+ "where": {
51
+ "clause": "\"status\" = ?",
52
+ "params": ["open"],
53
+ "predicates": [
54
+ {
55
+ "column": "status",
56
+ "op": "=",
57
+ "value": "open"
58
+ }
59
+ ]
60
+ },
61
+ "limit": 5,
62
+ "meta": {
63
+ "mode": "offset",
64
+ "limit": 5
65
+ }
66
+ },
67
+ "offset:gte": {
68
+ "ok": true,
69
+ "where": {
70
+ "clause": "\"priority\" >= ?",
71
+ "params": ["3"],
72
+ "predicates": [
73
+ {
74
+ "column": "priority",
75
+ "op": ">=",
76
+ "value": "3"
77
+ }
78
+ ]
79
+ },
80
+ "limit": 5,
81
+ "meta": {
82
+ "mode": "offset",
83
+ "limit": 5
84
+ }
85
+ },
86
+ "offset:lt": {
87
+ "ok": true,
88
+ "where": {
89
+ "clause": "\"priority\" < ?",
90
+ "params": ["5"],
91
+ "predicates": [
92
+ {
93
+ "column": "priority",
94
+ "op": "<",
95
+ "value": "5"
96
+ }
97
+ ]
98
+ },
99
+ "limit": 5,
100
+ "meta": {
101
+ "mode": "offset",
102
+ "limit": 5
103
+ }
104
+ },
105
+ "offset:like pattern": {
106
+ "ok": true,
107
+ "where": {
108
+ "clause": "\"title\" like ?",
109
+ "params": ["%task%"],
110
+ "predicates": [
111
+ {
112
+ "column": "title",
113
+ "op": "like",
114
+ "value": "%task%"
115
+ }
116
+ ]
117
+ },
118
+ "limit": 5,
119
+ "meta": {
120
+ "mode": "offset",
121
+ "limit": 5
122
+ }
123
+ },
124
+ "offset:ilike pattern": {
125
+ "ok": true,
126
+ "where": {
127
+ "clause": "\"title\" ilike ?",
128
+ "params": ["%URGENT%"],
129
+ "predicates": [
130
+ {
131
+ "column": "title",
132
+ "op": "ilike",
133
+ "value": "%URGENT%"
134
+ }
135
+ ]
136
+ },
137
+ "limit": 5,
138
+ "meta": {
139
+ "mode": "offset",
140
+ "limit": 5
141
+ }
142
+ },
143
+ "offset:in list": {
144
+ "ok": true,
145
+ "where": {
146
+ "clause": "\"status\" in (?, ?, ?)",
147
+ "params": ["open", "done", "in,review"],
148
+ "predicates": [
149
+ {
150
+ "column": "status",
151
+ "op": "in",
152
+ "value": ["open", "done", "in,review"]
153
+ }
154
+ ]
155
+ },
156
+ "limit": 5,
157
+ "meta": {
158
+ "mode": "offset",
159
+ "limit": 5
160
+ }
161
+ },
162
+ "offset:is null": {
163
+ "ok": true,
164
+ "where": {
165
+ "clause": "\"title\" is null",
166
+ "params": [],
167
+ "predicates": [
168
+ {
169
+ "column": "title",
170
+ "op": "is null"
171
+ }
172
+ ]
173
+ },
174
+ "limit": 5,
175
+ "meta": {
176
+ "mode": "offset",
177
+ "limit": 5
178
+ }
179
+ },
180
+ "offset:is true": {
181
+ "ok": true,
182
+ "where": {
183
+ "clause": "\"title\" = ?",
184
+ "params": [true],
185
+ "predicates": [
186
+ {
187
+ "column": "title",
188
+ "op": "=",
189
+ "value": true
190
+ }
191
+ ]
192
+ },
193
+ "limit": 5,
194
+ "meta": {
195
+ "mode": "offset",
196
+ "limit": 5
197
+ }
198
+ },
199
+ "offset:or group": {
200
+ "ok": true,
201
+ "where": {
202
+ "clause": "(\"status\" = ?) OR (\"priority\" > ?)",
203
+ "params": ["open", "5"],
204
+ "predicates": [
205
+ {
206
+ "column": "status",
207
+ "op": "=",
208
+ "value": "open"
209
+ },
210
+ {
211
+ "column": "priority",
212
+ "op": ">",
213
+ "value": "5"
214
+ }
215
+ ]
216
+ },
217
+ "limit": 5,
218
+ "meta": {
219
+ "mode": "offset",
220
+ "limit": 5
221
+ }
222
+ },
223
+ "offset:and group": {
224
+ "ok": true,
225
+ "where": {
226
+ "clause": "(\"status\" = ?) AND (\"title\" ilike ?)",
227
+ "params": ["open", "%urgent%"],
228
+ "predicates": [
229
+ {
230
+ "column": "status",
231
+ "op": "=",
232
+ "value": "open"
233
+ },
234
+ {
235
+ "column": "title",
236
+ "op": "ilike",
237
+ "value": "%urgent%"
238
+ }
239
+ ]
240
+ },
241
+ "limit": 5,
242
+ "meta": {
243
+ "mode": "offset",
244
+ "limit": 5
245
+ }
246
+ },
247
+ "offset:nested not.or group": {
248
+ "ok": true,
249
+ "where": {
250
+ "clause": "(\"status\" = ?) OR ((\"priority\" >= ?) AND (\"title\" != ?))",
251
+ "params": ["open", "1", "x"],
252
+ "predicates": [
253
+ {
254
+ "column": "status",
255
+ "op": "=",
256
+ "value": "open"
257
+ },
258
+ {
259
+ "column": "priority",
260
+ "op": ">=",
261
+ "value": "1"
262
+ },
263
+ {
264
+ "column": "title",
265
+ "op": "!=",
266
+ "value": "x"
267
+ }
268
+ ]
269
+ },
270
+ "limit": 5,
271
+ "meta": {
272
+ "mode": "offset",
273
+ "limit": 5
274
+ }
275
+ },
276
+ "offset:search": {
277
+ "ok": true,
278
+ "where": {
279
+ "clause": "\"title\" like ?",
280
+ "params": ["%task%"],
281
+ "predicates": [
282
+ {
283
+ "column": "title",
284
+ "op": "like",
285
+ "value": "%task%"
286
+ }
287
+ ]
288
+ },
289
+ "limit": 5,
290
+ "meta": {
291
+ "mode": "offset",
292
+ "limit": 5,
293
+ "search": "task"
294
+ }
295
+ },
296
+ "offset:q alias": {
297
+ "ok": true,
298
+ "where": {
299
+ "clause": "\"title\" like ?",
300
+ "params": ["%task%"],
301
+ "predicates": [
302
+ {
303
+ "column": "title",
304
+ "op": "like",
305
+ "value": "%task%"
306
+ }
307
+ ]
308
+ },
309
+ "limit": 5,
310
+ "meta": {
311
+ "mode": "offset",
312
+ "limit": 5,
313
+ "search": "task"
314
+ }
315
+ },
316
+ "offset:order multi desc": {
317
+ "ok": true,
318
+ "orderBy": ["[C(priority), T(\" desc\")]", "[C(createdAt), T(\" asc\")]"],
319
+ "limit": 5,
320
+ "meta": {
321
+ "mode": "offset",
322
+ "limit": 5,
323
+ "order": "priority.desc,createdAt.asc"
324
+ }
325
+ },
326
+ "offset:select projection": {
327
+ "ok": true,
328
+ "limit": 5,
329
+ "meta": {
330
+ "mode": "offset",
331
+ "limit": 5
332
+ },
333
+ "select": ["id", "title"]
334
+ },
335
+ "offset:limit": {
336
+ "ok": true,
337
+ "limit": 3,
338
+ "meta": {
339
+ "mode": "offset",
340
+ "limit": 3
341
+ }
342
+ },
343
+ "offset:offset": {
344
+ "ok": true,
345
+ "limit": 5,
346
+ "offset": 4,
347
+ "meta": {
348
+ "mode": "offset",
349
+ "limit": 5
350
+ }
351
+ },
352
+ "offset:offset cursor token": {
353
+ "ok": true,
354
+ "limit": 5,
355
+ "offset": 4,
356
+ "meta": {
357
+ "mode": "offset",
358
+ "limit": 5
359
+ }
360
+ },
361
+ "offset:combined": {
362
+ "ok": true,
363
+ "where": {
364
+ "clause": "\"status\" = ?",
365
+ "params": ["open"],
366
+ "predicates": [
367
+ {
368
+ "column": "status",
369
+ "op": "=",
370
+ "value": "open"
371
+ }
372
+ ]
373
+ },
374
+ "orderBy": ["[C(priority), T(\" desc\")]"],
375
+ "limit": 3,
376
+ "offset": 2,
377
+ "meta": {
378
+ "mode": "offset",
379
+ "limit": 3,
380
+ "order": "priority.desc"
381
+ },
382
+ "select": ["id", "status"]
383
+ },
384
+ "offset:headers/cookie ignored": {
385
+ "ok": true,
386
+ "where": {
387
+ "clause": "\"status\" = ?",
388
+ "params": ["open"],
389
+ "predicates": [
390
+ {
391
+ "column": "status",
392
+ "op": "=",
393
+ "value": "open"
394
+ }
395
+ ]
396
+ },
397
+ "limit": 5,
398
+ "meta": {
399
+ "mode": "offset",
400
+ "limit": 5
401
+ }
402
+ },
403
+ "cursor:default (cursor order implied)": {
404
+ "ok": true,
405
+ "orderBy": ["[C(createdAt), T(\" desc\")]", "[C(id), T(\" desc\")]"],
406
+ "limit": 6,
407
+ "meta": {
408
+ "mode": "cursor",
409
+ "limit": 5
410
+ }
411
+ },
412
+ "cursor:keyset after": {
413
+ "ok": true,
414
+ "orderBy": ["[C(createdAt), T(\" desc\")]", "[C(id), T(\" desc\")]"],
415
+ "limit": 6,
416
+ "after": "[[C(createdAt), T(\" < \"), ?[\"value\"]], T(\" or \"), [[C(createdAt), T(\" = \"), ?[\"value\"]], T(\" and \"), [C(id), T(\" < \"), ?[\"value\"]]]]",
417
+ "meta": {
418
+ "mode": "cursor",
419
+ "limit": 5,
420
+ "cursor": "eyJ2IjpbMTAwLCJpNSJdLCJkIjoiYWZ0ZXIifQ=="
421
+ },
422
+ "cursorDir": "after"
423
+ },
424
+ "cursor:keyset before (flipped)": {
425
+ "ok": true,
426
+ "orderBy": ["[C(createdAt), T(\" asc\")]", "[C(id), T(\" asc\")]"],
427
+ "limit": 6,
428
+ "before": "[[C(createdAt), T(\" > \"), ?[\"value\"]], T(\" or \"), [[C(createdAt), T(\" = \"), ?[\"value\"]], T(\" and \"), [C(id), T(\" > \"), ?[\"value\"]]]]",
429
+ "meta": {
430
+ "mode": "cursor",
431
+ "limit": 5,
432
+ "cursor": "eyJ2IjpbMTAwLCJpNSJdLCJkIjoiYmVmb3JlIn0="
433
+ },
434
+ "cursorDir": "before"
435
+ },
436
+ "cursor:bare array cursor (legacy after)": {
437
+ "ok": true,
438
+ "orderBy": ["[C(createdAt), T(\" desc\")]", "[C(id), T(\" desc\")]"],
439
+ "limit": 6,
440
+ "after": "[[C(createdAt), T(\" < \"), ?[\"value\"]], T(\" or \"), [[C(createdAt), T(\" = \"), ?[\"value\"]], T(\" and \"), [C(id), T(\" < \"), ?[\"value\"]]]]",
441
+ "meta": {
442
+ "mode": "cursor",
443
+ "limit": 5,
444
+ "cursor": "WzEwMCwiaTUiXQ=="
445
+ },
446
+ "cursorDir": "after"
447
+ },
448
+ "cursor:filter + cursor": {
449
+ "ok": true,
450
+ "where": {
451
+ "clause": "\"status\" = ?",
452
+ "params": ["open"],
453
+ "predicates": [
454
+ {
455
+ "column": "status",
456
+ "op": "=",
457
+ "value": "open"
458
+ }
459
+ ]
460
+ },
461
+ "orderBy": ["[C(createdAt), T(\" desc\")]", "[C(id), T(\" desc\")]"],
462
+ "limit": 6,
463
+ "after": "[[C(createdAt), T(\" < \"), ?[\"value\"]], T(\" or \"), [[C(createdAt), T(\" = \"), ?[\"value\"]], T(\" and \"), [C(id), T(\" < \"), ?[\"value\"]]]]",
464
+ "meta": {
465
+ "mode": "cursor",
466
+ "limit": 5,
467
+ "cursor": "eyJ2IjpbMTAwLCJpNSJdLCJkIjoiYWZ0ZXIifQ=="
468
+ },
469
+ "cursorDir": "after"
470
+ },
471
+ "offset-fail:unknown list param (filter none)": {
472
+ "ok": false,
473
+ "failure": {
474
+ "data": null,
475
+ "error": {
476
+ "code": "ValidationError",
477
+ "data": {
478
+ "issues": [
479
+ {
480
+ "message": "unknown or unfilterable column \"secret\"",
481
+ "path": ["secret"]
482
+ }
483
+ ]
484
+ },
485
+ "message": "The request failed validation."
486
+ }
487
+ }
488
+ },
489
+ "offset-fail:unknown or unfilterable column": {
490
+ "ok": false,
491
+ "failure": {
492
+ "data": null,
493
+ "error": {
494
+ "code": "ValidationError",
495
+ "data": {
496
+ "issues": [
497
+ {
498
+ "message": "unknown or unfilterable column \"ghost\"",
499
+ "path": ["ghost"]
500
+ }
501
+ ]
502
+ },
503
+ "message": "The request failed validation."
504
+ }
505
+ }
506
+ },
507
+ "offset-fail:unsupported filter op": {
508
+ "ok": false,
509
+ "failure": {
510
+ "data": null,
511
+ "error": {
512
+ "code": "ValidationError",
513
+ "data": {
514
+ "issues": [
515
+ {
516
+ "message": "unsupported filter op \"regex\"",
517
+ "path": ["status"]
518
+ }
519
+ ]
520
+ },
521
+ "message": "The request failed validation."
522
+ }
523
+ }
524
+ },
525
+ "offset-fail:missing op.value": {
526
+ "ok": false,
527
+ "failure": {
528
+ "data": null,
529
+ "error": {
530
+ "code": "ValidationError",
531
+ "data": {
532
+ "issues": [
533
+ {
534
+ "message": "expected \"op.value\" (e.g. status=eq.x)",
535
+ "path": ["status"]
536
+ }
537
+ ]
538
+ },
539
+ "message": "The request failed validation."
540
+ }
541
+ }
542
+ },
543
+ "offset-fail:bad is value": {
544
+ "ok": false,
545
+ "failure": {
546
+ "data": null,
547
+ "error": {
548
+ "code": "ValidationError",
549
+ "data": {
550
+ "issues": [
551
+ {
552
+ "message": "is expects null|not_null|true|false|unknown",
553
+ "path": ["title"]
554
+ }
555
+ ]
556
+ },
557
+ "message": "The request failed validation."
558
+ }
559
+ }
560
+ },
561
+ "offset-fail:in without parens": {
562
+ "ok": false,
563
+ "failure": {
564
+ "data": null,
565
+ "error": {
566
+ "code": "ValidationError",
567
+ "data": {
568
+ "issues": [
569
+ {
570
+ "message": "in expects (a,b,c)",
571
+ "path": ["status"]
572
+ }
573
+ ]
574
+ },
575
+ "message": "The request failed validation."
576
+ }
577
+ }
578
+ },
579
+ "offset-fail:in empty": {
580
+ "ok": false,
581
+ "failure": {
582
+ "data": null,
583
+ "error": {
584
+ "code": "ValidationError",
585
+ "data": {
586
+ "issues": [
587
+ {
588
+ "message": "in expects at least one value",
589
+ "path": ["status"]
590
+ }
591
+ ]
592
+ },
593
+ "message": "The request failed validation."
594
+ }
595
+ }
596
+ },
597
+ "offset-fail:search + q both": {
598
+ "ok": false,
599
+ "failure": {
600
+ "data": null,
601
+ "error": {
602
+ "code": "ValidationError",
603
+ "data": {
604
+ "issues": [
605
+ {
606
+ "message": "use either search or q, not both",
607
+ "path": ["search"]
608
+ }
609
+ ]
610
+ },
611
+ "message": "The request failed validation."
612
+ }
613
+ }
614
+ },
615
+ "offset-fail:bad limit": {
616
+ "ok": false,
617
+ "failure": {
618
+ "data": null,
619
+ "error": {
620
+ "code": "ValidationError",
621
+ "data": {
622
+ "issues": [
623
+ {
624
+ "message": "limit must be a positive integer",
625
+ "path": ["limit"]
626
+ }
627
+ ]
628
+ },
629
+ "message": "The request failed validation."
630
+ }
631
+ }
632
+ },
633
+ "offset-fail:bad offset": {
634
+ "ok": false,
635
+ "failure": {
636
+ "data": null,
637
+ "error": {
638
+ "code": "ValidationError",
639
+ "data": {
640
+ "issues": [
641
+ {
642
+ "message": "offset must be a non-negative integer",
643
+ "path": ["offset"]
644
+ }
645
+ ]
646
+ },
647
+ "message": "The request failed validation."
648
+ }
649
+ }
650
+ },
651
+ "offset-fail:invalid cursor": {
652
+ "ok": false,
653
+ "failure": {
654
+ "data": null,
655
+ "error": {
656
+ "code": "ValidationError",
657
+ "data": {
658
+ "issues": [
659
+ {
660
+ "message": "invalid cursor",
661
+ "path": ["cursor"]
662
+ }
663
+ ]
664
+ },
665
+ "message": "The request failed validation."
666
+ }
667
+ }
668
+ },
669
+ "offset-fail:bad order term": {
670
+ "ok": false,
671
+ "failure": {
672
+ "data": null,
673
+ "error": {
674
+ "code": "ValidationError",
675
+ "data": {
676
+ "issues": [
677
+ {
678
+ "message": "bad order term \"priority..desc\"",
679
+ "path": ["order"]
680
+ }
681
+ ]
682
+ },
683
+ "message": "The request failed validation."
684
+ }
685
+ }
686
+ },
687
+ "offset-fail:unknown order column": {
688
+ "ok": false,
689
+ "failure": {
690
+ "data": null,
691
+ "error": {
692
+ "code": "ValidationError",
693
+ "data": {
694
+ "issues": [
695
+ {
696
+ "message": "unknown or unorderable column \"ghost\"",
697
+ "path": ["order"]
698
+ }
699
+ ]
700
+ },
701
+ "message": "The request failed validation."
702
+ }
703
+ }
704
+ },
705
+ "offset-fail:unknown select column": {
706
+ "ok": false,
707
+ "failure": {
708
+ "data": null,
709
+ "error": {
710
+ "code": "ValidationError",
711
+ "data": {
712
+ "issues": [
713
+ {
714
+ "message": "unknown column \"ghost\"",
715
+ "path": ["select"]
716
+ }
717
+ ]
718
+ },
719
+ "message": "The request failed validation."
720
+ }
721
+ }
722
+ },
723
+ "cursor-fail:cursor pagination not configured": {
724
+ "ok": false,
725
+ "failure": {
726
+ "data": null,
727
+ "error": {
728
+ "code": "ValidationError",
729
+ "data": {
730
+ "issues": [
731
+ {
732
+ "message": "cursor pagination is not configured",
733
+ "path": ["cursor"]
734
+ }
735
+ ]
736
+ },
737
+ "message": "The request failed validation."
738
+ }
739
+ }
740
+ },
741
+ "cursor-fail:cursor with wrong arity": {
742
+ "ok": false,
743
+ "failure": {
744
+ "data": null,
745
+ "error": {
746
+ "code": "ValidationError",
747
+ "data": {
748
+ "issues": [
749
+ {
750
+ "message": "invalid cursor",
751
+ "path": ["cursor"]
752
+ }
753
+ ]
754
+ },
755
+ "message": "The request failed validation."
756
+ }
757
+ }
758
+ },
759
+ "cursor-fail:garbage cursor": {
760
+ "ok": false,
761
+ "failure": {
762
+ "data": null,
763
+ "error": {
764
+ "code": "ValidationError",
765
+ "data": {
766
+ "issues": [
767
+ {
768
+ "message": "invalid cursor",
769
+ "path": ["cursor"]
770
+ }
771
+ ]
772
+ },
773
+ "message": "The request failed validation."
774
+ }
775
+ }
776
+ }
777
+ }