ultimabase 0.0.0-stage → 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 (411) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +4 -2
  3. package/dist/access.d.ts +62 -0
  4. package/dist/access.d.ts.map +1 -0
  5. package/dist/access.js +258 -0
  6. package/dist/adapter-errors.d.ts +43 -0
  7. package/dist/adapter-errors.d.ts.map +1 -0
  8. package/dist/adapter-errors.js +72 -0
  9. package/dist/adapter-json.d.ts +20 -0
  10. package/dist/adapter-json.d.ts.map +1 -0
  11. package/dist/adapter-json.js +2 -0
  12. package/dist/adapter-migrations.d.ts +90 -0
  13. package/dist/adapter-migrations.d.ts.map +1 -0
  14. package/dist/adapter-migrations.js +1 -0
  15. package/dist/adapter.d.ts +333 -0
  16. package/dist/adapter.d.ts.map +1 -0
  17. package/dist/adapter.js +5 -0
  18. package/dist/aggregate.d.ts +31 -0
  19. package/dist/aggregate.d.ts.map +1 -0
  20. package/dist/aggregate.js +99 -0
  21. package/dist/app-internals.d.ts +10 -0
  22. package/dist/app-internals.d.ts.map +1 -0
  23. package/dist/app-internals.js +12 -0
  24. package/dist/app-options.d.ts +22 -0
  25. package/dist/app-options.d.ts.map +1 -0
  26. package/dist/app-options.js +3 -0
  27. package/dist/cascade.d.ts +47 -0
  28. package/dist/cascade.d.ts.map +1 -0
  29. package/dist/cascade.js +209 -0
  30. package/dist/cli-config.d.ts +6 -0
  31. package/dist/cli-config.d.ts.map +1 -0
  32. package/dist/cli-config.js +45 -0
  33. package/dist/cli-deploy.d.ts +14 -0
  34. package/dist/cli-deploy.d.ts.map +1 -0
  35. package/dist/cli-deploy.js +193 -0
  36. package/dist/cli-main.d.ts +16 -0
  37. package/dist/cli-main.d.ts.map +1 -0
  38. package/dist/cli-main.js +151 -0
  39. package/dist/cli-migrate.d.ts +20 -0
  40. package/dist/cli-migrate.d.ts.map +1 -0
  41. package/dist/cli-migrate.js +105 -0
  42. package/dist/cli.d.ts +3 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +4 -0
  45. package/dist/complete.d.ts +13 -0
  46. package/dist/complete.d.ts.map +1 -0
  47. package/dist/complete.js +60 -0
  48. package/dist/console-logger.d.ts +3 -0
  49. package/dist/console-logger.d.ts.map +1 -0
  50. package/dist/console-logger.js +62 -0
  51. package/dist/create-many.d.ts +7 -0
  52. package/dist/create-many.d.ts.map +1 -0
  53. package/dist/create-many.js +88 -0
  54. package/dist/decimal.d.ts +23 -0
  55. package/dist/decimal.d.ts.map +1 -0
  56. package/dist/decimal.js +50 -0
  57. package/dist/define-app.d.ts +59 -0
  58. package/dist/define-app.d.ts.map +1 -0
  59. package/dist/define-app.js +5 -0
  60. package/dist/define-enum.d.ts +6 -0
  61. package/dist/define-enum.d.ts.map +1 -0
  62. package/dist/define-enum.js +18 -0
  63. package/dist/define-function.d.ts +25 -0
  64. package/dist/define-function.d.ts.map +1 -0
  65. package/dist/define-function.js +111 -0
  66. package/dist/define-model.d.ts +48 -0
  67. package/dist/define-model.d.ts.map +1 -0
  68. package/dist/define-model.js +85 -0
  69. package/dist/definition.d.ts +179 -0
  70. package/dist/definition.d.ts.map +1 -0
  71. package/dist/definition.js +165 -0
  72. package/dist/delete-many.d.ts +13 -0
  73. package/dist/delete-many.d.ts.map +1 -0
  74. package/dist/delete-many.js +58 -0
  75. package/dist/engine.d.ts +16 -0
  76. package/dist/engine.d.ts.map +1 -0
  77. package/dist/engine.js +174 -0
  78. package/dist/errors.d.ts +50 -0
  79. package/dist/errors.d.ts.map +1 -0
  80. package/dist/errors.js +43 -0
  81. package/dist/exact.d.ts +20 -0
  82. package/dist/exact.d.ts.map +1 -0
  83. package/dist/exact.js +1 -0
  84. package/dist/feed.d.ts +6 -0
  85. package/dist/feed.d.ts.map +1 -0
  86. package/dist/feed.js +33 -0
  87. package/dist/field-codec.d.ts +11 -0
  88. package/dist/field-codec.d.ts.map +1 -0
  89. package/dist/field-codec.js +48 -0
  90. package/dist/field-rules.d.ts +57 -0
  91. package/dist/field-rules.d.ts.map +1 -0
  92. package/dist/field-rules.js +1 -0
  93. package/dist/field-type.d.ts +51 -0
  94. package/dist/field-type.d.ts.map +1 -0
  95. package/dist/field-type.js +106 -0
  96. package/dist/fields.d.ts +295 -0
  97. package/dist/fields.d.ts.map +1 -0
  98. package/dist/fields.js +1 -0
  99. package/dist/function.d.ts +126 -0
  100. package/dist/function.d.ts.map +1 -0
  101. package/dist/function.js +1 -0
  102. package/dist/functions.d.ts +18 -0
  103. package/dist/functions.d.ts.map +1 -0
  104. package/dist/functions.js +99 -0
  105. package/dist/group-by.d.ts +10 -0
  106. package/dist/group-by.d.ts.map +1 -0
  107. package/dist/group-by.js +145 -0
  108. package/dist/group-having.d.ts +8 -0
  109. package/dist/group-having.d.ts.map +1 -0
  110. package/dist/group-having.js +97 -0
  111. package/dist/hooks.d.ts +41 -0
  112. package/dist/hooks.d.ts.map +1 -0
  113. package/dist/hooks.js +149 -0
  114. package/dist/hosts.d.ts +3 -0
  115. package/dist/hosts.d.ts.map +1 -0
  116. package/dist/hosts.js +8 -0
  117. package/dist/identify.d.ts +15 -0
  118. package/dist/identify.d.ts.map +1 -0
  119. package/dist/identify.js +71 -0
  120. package/dist/index.d.ts +25 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +12 -0
  123. package/dist/internal.d.ts +28 -0
  124. package/dist/internal.d.ts.map +1 -0
  125. package/dist/internal.js +39 -0
  126. package/dist/lifecycle.d.ts +21 -0
  127. package/dist/lifecycle.d.ts.map +1 -0
  128. package/dist/lifecycle.js +149 -0
  129. package/dist/list-update.d.ts +12 -0
  130. package/dist/list-update.d.ts.map +1 -0
  131. package/dist/list-update.js +52 -0
  132. package/dist/live.d.ts +37 -0
  133. package/dist/live.d.ts.map +1 -0
  134. package/dist/live.js +139 -0
  135. package/dist/manifest.d.ts +11 -0
  136. package/dist/manifest.d.ts.map +1 -0
  137. package/dist/manifest.js +60 -0
  138. package/dist/memory-aggregate.d.ts +7 -0
  139. package/dist/memory-aggregate.d.ts.map +1 -0
  140. package/dist/memory-aggregate.js +107 -0
  141. package/dist/memory-conditions.d.ts +8 -0
  142. package/dist/memory-conditions.d.ts.map +1 -0
  143. package/dist/memory-conditions.js +82 -0
  144. package/dist/memory-draft.d.ts +34 -0
  145. package/dist/memory-draft.d.ts.map +1 -0
  146. package/dist/memory-draft.js +255 -0
  147. package/dist/memory-json.d.ts +6 -0
  148. package/dist/memory-json.d.ts.map +1 -0
  149. package/dist/memory-json.js +86 -0
  150. package/dist/memory-read.d.ts +45 -0
  151. package/dist/memory-read.d.ts.map +1 -0
  152. package/dist/memory-read.js +244 -0
  153. package/dist/memory-search.d.ts +16 -0
  154. package/dist/memory-search.d.ts.map +1 -0
  155. package/dist/memory-search.js +110 -0
  156. package/dist/memory-values.d.ts +23 -0
  157. package/dist/memory-values.d.ts.map +1 -0
  158. package/dist/memory-values.js +82 -0
  159. package/dist/memory.d.ts +4 -0
  160. package/dist/memory.d.ts.map +1 -0
  161. package/dist/memory.js +157 -0
  162. package/dist/migrate.d.ts +22 -0
  163. package/dist/migrate.d.ts.map +1 -0
  164. package/dist/migrate.js +131 -0
  165. package/dist/model.d.ts +239 -0
  166. package/dist/model.d.ts.map +1 -0
  167. package/dist/model.js +1 -0
  168. package/dist/nested-write.d.ts +64 -0
  169. package/dist/nested-write.d.ts.map +1 -0
  170. package/dist/nested-write.js +274 -0
  171. package/dist/number-update.d.ts +18 -0
  172. package/dist/number-update.d.ts.map +1 -0
  173. package/dist/number-update.js +96 -0
  174. package/dist/plugin-app.d.ts +48 -0
  175. package/dist/plugin-app.d.ts.map +1 -0
  176. package/dist/plugin-app.js +230 -0
  177. package/dist/plugin-code.d.ts +17 -0
  178. package/dist/plugin-code.d.ts.map +1 -0
  179. package/dist/plugin-code.js +125 -0
  180. package/dist/plugin-use.d.ts +22 -0
  181. package/dist/plugin-use.d.ts.map +1 -0
  182. package/dist/plugin-use.js +161 -0
  183. package/dist/plugin.d.ts +357 -0
  184. package/dist/plugin.d.ts.map +1 -0
  185. package/dist/plugin.js +17 -0
  186. package/dist/query-aggregate.d.ts +82 -0
  187. package/dist/query-aggregate.d.ts.map +1 -0
  188. package/dist/query-aggregate.js +1 -0
  189. package/dist/query-args.d.ts +41 -0
  190. package/dist/query-args.d.ts.map +1 -0
  191. package/dist/query-args.js +263 -0
  192. package/dist/query-bulk.d.ts +35 -0
  193. package/dist/query-bulk.d.ts.map +1 -0
  194. package/dist/query-bulk.js +1 -0
  195. package/dist/query-conditions.d.ts +9 -0
  196. package/dist/query-conditions.d.ts.map +1 -0
  197. package/dist/query-conditions.js +46 -0
  198. package/dist/query-context.d.ts +32 -0
  199. package/dist/query-context.d.ts.map +1 -0
  200. package/dist/query-context.js +55 -0
  201. package/dist/query-filter.d.ts +46 -0
  202. package/dist/query-filter.d.ts.map +1 -0
  203. package/dist/query-filter.js +1 -0
  204. package/dist/query-group.d.ts +82 -0
  205. package/dist/query-group.d.ts.map +1 -0
  206. package/dist/query-group.js +1 -0
  207. package/dist/query-json.d.ts +9 -0
  208. package/dist/query-json.d.ts.map +1 -0
  209. package/dist/query-json.js +66 -0
  210. package/dist/query-order.d.ts +15 -0
  211. package/dist/query-order.d.ts.map +1 -0
  212. package/dist/query-order.js +115 -0
  213. package/dist/query-project.d.ts +15 -0
  214. package/dist/query-project.d.ts.map +1 -0
  215. package/dist/query-project.js +45 -0
  216. package/dist/query-search.d.ts +24 -0
  217. package/dist/query-search.d.ts.map +1 -0
  218. package/dist/query-search.js +2 -0
  219. package/dist/query-values.d.ts +28 -0
  220. package/dist/query-values.d.ts.map +1 -0
  221. package/dist/query-values.js +91 -0
  222. package/dist/query-where.d.ts +46 -0
  223. package/dist/query-where.d.ts.map +1 -0
  224. package/dist/query-where.js +200 -0
  225. package/dist/query-write.d.ts +14 -0
  226. package/dist/query-write.d.ts.map +1 -0
  227. package/dist/query-write.js +260 -0
  228. package/dist/query.d.ts +254 -0
  229. package/dist/query.d.ts.map +1 -0
  230. package/dist/query.js +1 -0
  231. package/dist/record.d.ts +257 -0
  232. package/dist/record.d.ts.map +1 -0
  233. package/dist/record.js +1 -0
  234. package/dist/recorder.d.ts +32 -0
  235. package/dist/recorder.d.ts.map +1 -0
  236. package/dist/recorder.js +152 -0
  237. package/dist/relation-write.d.ts +41 -0
  238. package/dist/relation-write.d.ts.map +1 -0
  239. package/dist/relation-write.js +112 -0
  240. package/dist/relations.d.ts +42 -0
  241. package/dist/relations.d.ts.map +1 -0
  242. package/dist/relations.js +119 -0
  243. package/dist/rules.d.ts +97 -0
  244. package/dist/rules.d.ts.map +1 -0
  245. package/dist/rules.js +71 -0
  246. package/dist/running.d.ts +29 -0
  247. package/dist/running.d.ts.map +1 -0
  248. package/dist/running.js +39 -0
  249. package/dist/schema-indexes.d.ts +11 -0
  250. package/dist/schema-indexes.d.ts.map +1 -0
  251. package/dist/schema-indexes.js +59 -0
  252. package/dist/schema-virtuals.d.ts +19 -0
  253. package/dist/schema-virtuals.d.ts.map +1 -0
  254. package/dist/schema-virtuals.js +100 -0
  255. package/dist/schema.d.ts +35 -0
  256. package/dist/schema.d.ts.map +1 -0
  257. package/dist/schema.js +267 -0
  258. package/dist/scope.d.ts +46 -0
  259. package/dist/scope.d.ts.map +1 -0
  260. package/dist/scope.js +82 -0
  261. package/dist/scratch.d.ts +14 -0
  262. package/dist/scratch.d.ts.map +1 -0
  263. package/dist/scratch.js +10 -0
  264. package/dist/serve.d.ts +2 -0
  265. package/dist/serve.d.ts.map +1 -0
  266. package/dist/serve.js +4 -0
  267. package/dist/symbols.d.ts +10 -0
  268. package/dist/symbols.d.ts.map +1 -0
  269. package/dist/symbols.js +1 -0
  270. package/dist/transaction.d.ts +28 -0
  271. package/dist/transaction.d.ts.map +1 -0
  272. package/dist/transaction.js +156 -0
  273. package/dist/types.d.ts +58 -0
  274. package/dist/types.d.ts.map +1 -0
  275. package/dist/types.js +1 -0
  276. package/dist/update-many.d.ts +7 -0
  277. package/dist/update-many.d.ts.map +1 -0
  278. package/dist/update-many.js +182 -0
  279. package/dist/uuid.d.ts +7 -0
  280. package/dist/uuid.d.ts.map +1 -0
  281. package/dist/uuid.js +48 -0
  282. package/dist/validation.d.ts +24 -0
  283. package/dist/validation.d.ts.map +1 -0
  284. package/dist/validation.js +72 -0
  285. package/dist/virtual-read.d.ts +9 -0
  286. package/dist/virtual-read.d.ts.map +1 -0
  287. package/dist/virtual-read.js +145 -0
  288. package/dist/virtual.d.ts +142 -0
  289. package/dist/virtual.d.ts.map +1 -0
  290. package/dist/virtual.js +1 -0
  291. package/dist/write-context.d.ts +46 -0
  292. package/dist/write-context.d.ts.map +1 -0
  293. package/dist/write-context.js +102 -0
  294. package/dist/write-data.d.ts +26 -0
  295. package/dist/write-data.d.ts.map +1 -0
  296. package/dist/write-data.js +144 -0
  297. package/dist/write-plan.d.ts +107 -0
  298. package/dist/write-plan.d.ts.map +1 -0
  299. package/dist/write-plan.js +170 -0
  300. package/dist/write-target.d.ts +17 -0
  301. package/dist/write-target.d.ts.map +1 -0
  302. package/dist/write-target.js +59 -0
  303. package/dist/writes.d.ts +23 -0
  304. package/dist/writes.d.ts.map +1 -0
  305. package/dist/writes.js +246 -0
  306. package/dist/writing.d.ts +10 -0
  307. package/dist/writing.d.ts.map +1 -0
  308. package/dist/writing.js +66 -0
  309. package/package.json +42 -3
  310. package/src/access.ts +329 -0
  311. package/src/adapter-errors.ts +89 -0
  312. package/src/adapter-json.ts +21 -0
  313. package/src/adapter-migrations.ts +98 -0
  314. package/src/adapter.ts +363 -0
  315. package/src/aggregate.ts +136 -0
  316. package/src/app-internals.ts +26 -0
  317. package/src/app-options.ts +24 -0
  318. package/src/cascade.ts +297 -0
  319. package/src/cli-config.ts +45 -0
  320. package/src/cli-deploy.ts +235 -0
  321. package/src/cli-main.ts +165 -0
  322. package/src/cli-migrate.ts +143 -0
  323. package/src/cli.ts +5 -0
  324. package/src/complete.ts +73 -0
  325. package/src/console-logger.ts +87 -0
  326. package/src/create-many.ts +126 -0
  327. package/src/decimal.ts +74 -0
  328. package/src/define-app.ts +108 -0
  329. package/src/define-enum.ts +26 -0
  330. package/src/define-function.ts +188 -0
  331. package/src/define-model.ts +220 -0
  332. package/src/definition.ts +352 -0
  333. package/src/delete-many.ts +76 -0
  334. package/src/engine.ts +281 -0
  335. package/src/errors.ts +97 -0
  336. package/src/exact.ts +49 -0
  337. package/src/feed.ts +39 -0
  338. package/src/field-codec.ts +72 -0
  339. package/src/field-rules.ts +77 -0
  340. package/src/field-type.ts +219 -0
  341. package/src/fields.ts +383 -0
  342. package/src/function.ts +143 -0
  343. package/src/functions.ts +154 -0
  344. package/src/group-by.ts +186 -0
  345. package/src/group-having.ts +143 -0
  346. package/src/hooks.ts +215 -0
  347. package/src/hosts.ts +11 -0
  348. package/src/identify.ts +95 -0
  349. package/src/index.ts +125 -0
  350. package/src/internal.ts +68 -0
  351. package/src/lifecycle.ts +214 -0
  352. package/src/list-update.ts +71 -0
  353. package/src/live.ts +199 -0
  354. package/src/manifest.ts +71 -0
  355. package/src/memory-aggregate.ts +162 -0
  356. package/src/memory-conditions.ts +88 -0
  357. package/src/memory-draft.ts +319 -0
  358. package/src/memory-json.ts +91 -0
  359. package/src/memory-read.ts +311 -0
  360. package/src/memory-search.ts +149 -0
  361. package/src/memory-values.ts +106 -0
  362. package/src/memory.ts +173 -0
  363. package/src/migrate.ts +152 -0
  364. package/src/model.ts +312 -0
  365. package/src/nested-write.ts +390 -0
  366. package/src/number-update.ts +142 -0
  367. package/src/plugin-app.ts +308 -0
  368. package/src/plugin-code.ts +158 -0
  369. package/src/plugin-use.ts +217 -0
  370. package/src/plugin.ts +400 -0
  371. package/src/query-aggregate.ts +96 -0
  372. package/src/query-args.ts +375 -0
  373. package/src/query-bulk.ts +53 -0
  374. package/src/query-conditions.ts +53 -0
  375. package/src/query-context.ts +104 -0
  376. package/src/query-filter.ts +54 -0
  377. package/src/query-group.ts +137 -0
  378. package/src/query-json.ts +90 -0
  379. package/src/query-order.ts +158 -0
  380. package/src/query-project.ts +73 -0
  381. package/src/query-search.ts +31 -0
  382. package/src/query-values.ts +131 -0
  383. package/src/query-where.ts +318 -0
  384. package/src/query-write.ts +360 -0
  385. package/src/query.ts +400 -0
  386. package/src/record.ts +379 -0
  387. package/src/recorder.ts +212 -0
  388. package/src/relation-write.ts +176 -0
  389. package/src/relations.ts +165 -0
  390. package/src/rules.ts +188 -0
  391. package/src/running.ts +62 -0
  392. package/src/schema-indexes.ts +88 -0
  393. package/src/schema-virtuals.ts +134 -0
  394. package/src/schema.ts +367 -0
  395. package/src/scope.ts +123 -0
  396. package/src/scratch.ts +28 -0
  397. package/src/serve.ts +5 -0
  398. package/src/symbols.ts +11 -0
  399. package/src/transaction.ts +211 -0
  400. package/src/types.ts +79 -0
  401. package/src/update-many.ts +268 -0
  402. package/src/uuid.ts +51 -0
  403. package/src/validation.ts +107 -0
  404. package/src/virtual-read.ts +198 -0
  405. package/src/virtual.ts +187 -0
  406. package/src/write-context.ts +170 -0
  407. package/src/write-data.ts +188 -0
  408. package/src/write-plan.ts +273 -0
  409. package/src/write-target.ts +92 -0
  410. package/src/writes.ts +361 -0
  411. package/src/writing.ts +93 -0
package/src/errors.ts ADDED
@@ -0,0 +1,97 @@
1
+ // The errors a client may see (D-28, D-72). Any other error is masked as
2
+ // `INTERNAL` with a correlation id. `Refused` is for the developer (D-119).
3
+ import type { JsonValue } from './fields.ts'
4
+
5
+ /** The kernel's codes; a transport gives each its own status (D-72). */
6
+ export type ErrorCode =
7
+ | 'ACCESS_DENIED'
8
+ | 'NOT_FOUND'
9
+ | 'VALIDATION_FAILED'
10
+ | 'UNIQUE_VIOLATION'
11
+ | 'RELATION_RESTRICTED'
12
+ | 'UNAUTHENTICATED'
13
+ | 'INVALID_CREDENTIALS'
14
+ | 'TOO_MANY_ATTEMPTS'
15
+ | 'INTERNAL'
16
+
17
+ /** One failing value, as Standard Schema reports it (D-23). */
18
+ export type Issue = {
19
+ readonly path: readonly (string | number)[]
20
+ readonly message: string
21
+ }
22
+
23
+ type Details<C> = C extends 'VALIDATION_FAILED'
24
+ ? { readonly issues: readonly Issue[] }
25
+ : C extends 'TOO_MANY_ATTEMPTS'
26
+ ? { /** In seconds (D-113). */ readonly retryAfter: number }
27
+ : JsonValue
28
+
29
+ /** An error whose code, message and details reach the client. */
30
+ export interface PublicError extends Error {
31
+ readonly code: ErrorCode | Uppercase<string>
32
+ readonly details?: JsonValue
33
+ }
34
+
35
+ type PublicErrorConstructor = {
36
+ new <const C extends string>(
37
+ code: C extends Uppercase<C> ? C : Uppercase<C>,
38
+ message: string,
39
+ options?: { readonly details?: Details<C>; readonly cause?: unknown },
40
+ ): PublicError
41
+ readonly prototype: PublicError
42
+ }
43
+
44
+ class PublicErrorClass extends Error {
45
+ readonly code: string
46
+ readonly details?: JsonValue
47
+
48
+ constructor(
49
+ code: string,
50
+ message: string,
51
+ options?: { readonly details?: JsonValue; readonly cause?: unknown },
52
+ ) {
53
+ super(
54
+ message,
55
+ options && 'cause' in options ? { cause: options.cause } : {},
56
+ )
57
+ this.name = 'PublicError'
58
+ this.code = code
59
+ if (options?.details !== undefined) this.details = options.details
60
+ }
61
+ }
62
+
63
+ /**
64
+ * The code is a kernel code, which keeps its meaning, or the application's
65
+ * own, in capitals. Only the constructor is generic: `instanceof` would type
66
+ * a generic class's members as `any`.
67
+ */
68
+ export const PublicError: PublicErrorConstructor =
69
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the class is the constructor; only its generic signature is added.
70
+ PublicErrorClass as unknown as PublicErrorConstructor
71
+
72
+ /**
73
+ * A query argument the kernel does not know (D-20): a bug of the server
74
+ * code, never public.
75
+ */
76
+ export class InvalidQuery extends Error {
77
+ readonly code = 'INVALID_QUERY'
78
+ readonly path: string
79
+
80
+ constructor(path: string, message: string) {
81
+ super(message)
82
+ this.name = 'InvalidQuery'
83
+ this.path = path
84
+ }
85
+ }
86
+
87
+ /**
88
+ * A configuration refused while the application is defined or starts, whose
89
+ * message says what is wrong and how to fix it: a command prints it without
90
+ * its stack (D-119).
91
+ */
92
+ export class Refused extends Error {
93
+ constructor(message: string, options?: ErrorOptions) {
94
+ super(message, options)
95
+ this.name = 'Refused'
96
+ }
97
+ }
package/src/exact.ts ADDED
@@ -0,0 +1,49 @@
1
+ // Query arguments are inferred (`const A`), so TypeScript skips the excess
2
+ // property check: a misspelled key next to a valid one would pass. `Exact`
3
+ // walks the written arguments against their schema and turns every unknown
4
+ // key into a message, reported on that key's line. It is `unknown` where the
5
+ // arguments fit, so a valid query costs one walk and no comparison.
6
+ type Leaf =
7
+ string | number | boolean | bigint | symbol | Date | null | undefined
8
+ type Shapes<S> = Exclude<
9
+ Extract<S, object>,
10
+ Date | readonly unknown[] | ((...args: never[]) => unknown)
11
+ >
12
+ type Keys<S> = S extends unknown ? keyof S : never
13
+ type At<S, K> = S extends unknown ? (K extends keyof S ? S[K] : never) : never
14
+ type Items<S> = Extract<S, readonly unknown[]>[number]
15
+ // Identical, not only assignable both ways: an index signature is not.
16
+ type Same<A, S> =
17
+ // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- `T` probes how each type relates, the usual identity test.
18
+ (<T>() => T extends A ? 1 : 2) extends <T>() => T extends S ? 1 : 2
19
+ ? true
20
+ : false
21
+ type Fine<O> = [keyof O] extends [never] ? unknown : O
22
+ // Only the misspelled keys, and the keys whose value holds one, are kept.
23
+ type Fields<A, S> = Fine<{
24
+ readonly [
25
+ K in keyof A as K extends Keys<S>
26
+ ? unknown extends Exact<A[K], At<S, K>>
27
+ ? never
28
+ : K
29
+ : K
30
+ ]: K extends Keys<S>
31
+ ? Exact<A[K], At<S, K>>
32
+ : { readonly error: `'${K & string}' is not a key here` }
33
+ }>
34
+ // A written key is required; a type whose keys are all optional, such as a
35
+ // variable typed `Where<F>`, was checked where it was written. Walking it
36
+ // would recurse through every relation. So would arguments inferred as their
37
+ // own schema, as on a failed call.
38
+ export type Exact<A, S> = [A] extends [Leaf]
39
+ ? unknown
40
+ : {} extends A
41
+ ? unknown
42
+ : Same<A, S> extends true
43
+ ? unknown
44
+ : A extends readonly unknown[]
45
+ ? Fits<A, { readonly [I in keyof A]: Exact<A[I], Items<S>> }>
46
+ : Fields<A, Shapes<S>>
47
+ // A list whose every item fits is `unknown`, like an object: a list of rows
48
+ // to create sits inside another one (D-128).
49
+ type Fits<A, E> = { readonly [I in keyof A]: unknown } extends E ? unknown : E
package/src/feed.ts ADDED
@@ -0,0 +1,39 @@
1
+ // The change feed (D-154): what each commit changed, to the plugins that
2
+ // take it. The adapter feeds nothing when none does.
3
+ import { AsyncLocalStorage } from 'node:async_hooks'
4
+ import type { Feed } from './adapter.ts'
5
+ import type { PluginRecord } from './definition.ts'
6
+ import { inOrder, type Installed } from './plugin-app.ts'
7
+
8
+ // Outside every async context: an adapter may deliver from within the write,
9
+ // whose transaction and recording a hook's queries must not join.
10
+ const outside = AsyncLocalStorage.snapshot()
11
+
12
+ /** Calls each plugin's `changed` and `missed`, in declaration order. */
13
+ export function feedOf(
14
+ records: readonly PluginRecord[],
15
+ plugins: readonly Installed[],
16
+ ): Feed | undefined {
17
+ const takers = inOrder(records, plugins).filter(
18
+ ({ code }) => code.changed !== undefined,
19
+ )
20
+ if (takers.length === 0) return undefined
21
+ // A plugin failing on a change must not stop the others nor the write.
22
+ const each = (hook: 'changed' | 'missed', args: readonly unknown[]): void => {
23
+ for (const { code, context } of takers) {
24
+ const run = code[hook]
25
+ if (run === undefined) continue
26
+ try {
27
+ outside(() => {
28
+ Reflect.apply(run, undefined, [...args, context])
29
+ })
30
+ } catch (error) {
31
+ context.logger.error({ err: error }, `The plugin's ${hook} failed.`)
32
+ }
33
+ }
34
+ }
35
+ return {
36
+ changed: (changes) => each('changed', [changes]),
37
+ missed: () => each('missed', []),
38
+ }
39
+ }
@@ -0,0 +1,72 @@
1
+ // Plugin field values decoded as rows leave the adapter (D-122): code, rules
2
+ // and hooks read the value, the adapter its stored form.
3
+ import type { Nested, Row } from './adapter.ts'
4
+ import type { Codec } from './definition.ts'
5
+ import { isObject } from './query-where.ts'
6
+ import type { ModelInfo } from './schema.ts'
7
+
8
+ type Models = ReadonlyMap<string, ModelInfo>
9
+ type Codecs = readonly (readonly [string, Codec])[]
10
+
11
+ const known = new WeakMap<ModelInfo, Codecs>()
12
+
13
+ function codecsOf(model: ModelInfo): Codecs {
14
+ const found = known.get(model)
15
+ if (found !== undefined) return found
16
+ const codecs = [...model.fields.values()].flatMap((field) =>
17
+ field.kind === 'scalar' && field.codec !== undefined
18
+ ? [[field.name, field.codec] as const]
19
+ : [],
20
+ )
21
+ known.set(model, codecs)
22
+ return codecs
23
+ }
24
+
25
+ /** The row with its plugin fields decoded, its included rows' too. */
26
+ function decodedRow(
27
+ models: Models,
28
+ model: ModelInfo,
29
+ read: Nested,
30
+ row: Row,
31
+ ): Row {
32
+ const changed: { [field: string]: unknown } = {}
33
+ // `null` is stored as is, never decoded.
34
+ for (const [name, codec] of codecsOf(model)) {
35
+ const value = row[name]
36
+ if (value !== undefined && value !== null) {
37
+ changed[name] = codec.decode(value)
38
+ }
39
+ }
40
+ for (const [name, nested] of Object.entries(read.include ?? {})) {
41
+ const field = model.fields.get(name)
42
+ const target =
43
+ field === undefined || field.kind === 'scalar'
44
+ ? undefined
45
+ : models.get(field.target)
46
+ const value = row[name]
47
+ if (target === undefined) continue
48
+ if (Array.isArray(value)) {
49
+ changed[name] = value.map((item: unknown) =>
50
+ isRow(item) ? decodedRow(models, target, nested, item) : item,
51
+ )
52
+ } else if (isRow(value)) {
53
+ changed[name] = decodedRow(models, target, nested, value)
54
+ }
55
+ }
56
+ return Object.keys(changed).length === 0 ? row : { ...row, ...changed }
57
+ }
58
+
59
+ /** A value the kernel reads as a row: an object with a string `id`. */
60
+ export const isRow = (value: unknown): value is Row =>
61
+ isObject(value) && typeof value['id'] === 'string'
62
+
63
+ /** The rows `read` returned, decoded. */
64
+ export function decoded(
65
+ models: Models,
66
+ read: (Nested & { readonly model: string }) | undefined,
67
+ rows: Row[],
68
+ ): Row[] {
69
+ const model = read === undefined ? undefined : models.get(read.model)
70
+ if (read === undefined || model === undefined) return rows
71
+ return rows.map((row) => decodedRow(models, model, read, row))
72
+ }
@@ -0,0 +1,77 @@
1
+ // The rules a field's `.with` takes (D-44), and the plugins' own (D-57).
2
+ import type { RecordFor } from './record.ts'
3
+ import type { Caller } from './rules.ts'
4
+ import type { declaredRecord } from './symbols.ts'
5
+
6
+ // `R` is the record type the developer declares for the rules (D-44). It
7
+ // never derives from the model, which is still being typed here: that would
8
+ // be a cycle (TS7022).
9
+ type ReadFacts<R extends object> = {
10
+ readonly caller: Caller
11
+ readonly operation: 'read'
12
+ readonly record: RecordFor<R>
13
+ }
14
+ type CreateFacts<V> = {
15
+ readonly caller: Caller
16
+ readonly operation: 'create'
17
+ readonly value: V
18
+ }
19
+ type UpdateFacts<R extends object, V> = {
20
+ readonly caller: Caller
21
+ readonly operation: 'update'
22
+ readonly record: RecordFor<R>
23
+ readonly value: V
24
+ }
25
+ type Rule<F> = (facts: F) => boolean
26
+ // Named, so a type error shows the rule the developer wrote.
27
+ type FieldReadRule<R extends object> = Rule<ReadFacts<R>>
28
+ type FieldCreateRule<V> = Rule<CreateFacts<V>>
29
+ type FieldUpdateRule<R extends object, V> = Rule<UpdateFacts<R, V>>
30
+ type FieldWriteRule<R extends object, V> = Rule<
31
+ CreateFacts<V> | UpdateFacts<R, V>
32
+ >
33
+ type FieldRule<R extends object, V> = Rule<
34
+ ReadFacts<R> | CreateFacts<V> | UpdateFacts<R, V>
35
+ >
36
+
37
+ /** A field keeps its declared record type, which `defineModel` checks. */
38
+ // Each declared field is kept as `(value: T) => T`, which only the same `T`
39
+ // fits: a wider or a narrower type fails, and the error shows the model's.
40
+ export type Declared<R> = [R] extends [never]
41
+ ? unknown
42
+ : {
43
+ readonly [declaredRecord]: {
44
+ readonly [P in keyof R]: (value: R[P]) => R[P]
45
+ }
46
+ }
47
+
48
+ /** One rule, or one rule per operation (D-44). */
49
+ export type FieldAccess<R extends object, V> =
50
+ | FieldRule<R, V>
51
+ | {
52
+ readonly read?: FieldReadRule<R>
53
+ readonly create?: FieldCreateRule<V>
54
+ readonly update?: FieldUpdateRule<R, V>
55
+ readonly write?: FieldWriteRule<R, V>
56
+ }
57
+
58
+ /**
59
+ * The rules of the model's plugins for one field, each under the plugin's
60
+ * name and typed by the field's value (D-12, D-57).
61
+ */
62
+ type PluginFieldRules<T, V> = {
63
+ readonly [
64
+ X in T as X extends {
65
+ readonly name: infer N extends string
66
+ readonly fieldWith: object
67
+ }
68
+ ? N
69
+ : never
70
+ ]?: X extends { readonly fieldWith: object }
71
+ ? (X & { readonly value: V })['fieldWith']
72
+ : never
73
+ }
74
+
75
+ export type FieldWith<R extends object, V, T = never> = {
76
+ readonly access?: FieldAccess<R, V>
77
+ } & PluginFieldRules<T, V>
@@ -0,0 +1,219 @@
1
+ // `defineFieldType` (D-32, D-122): a plugin's field type, stored through a
2
+ // kernel field and seen by code as the value its `decode` gives.
3
+ import type { Codec, FieldDefinition, FieldOptions } from './definition.ts'
4
+ import { build, fieldBuilders, fieldDefinitions } from './definition.ts'
5
+ import type {
6
+ DefaultFunction,
7
+ Described,
8
+ Field,
9
+ FieldBuilders,
10
+ JsonValue,
11
+ SchemaTypes,
12
+ StandardSchema,
13
+ } from './fields.ts'
14
+ import type { fieldType } from './symbols.ts'
15
+ import { standardOf } from './validation.ts'
16
+
17
+ /** A kernel scalar field, as `stored` returns it. */
18
+ type Stored = {
19
+ readonly [fieldType]: {
20
+ readonly kind: 'scalar'
21
+ readonly value: unknown
22
+ readonly options: unknown
23
+ }
24
+ }
25
+ type StoredValue<S> = S extends {
26
+ readonly [fieldType]: { readonly value: infer V }
27
+ }
28
+ ? V
29
+ : never
30
+ type StoredOptions<S> = S extends {
31
+ readonly [fieldType]: { readonly options: infer O }
32
+ }
33
+ ? O
34
+ : never
35
+
36
+ /** What `defineFieldType` takes (D-122), each function given the options. */
37
+ export type FieldTypeDefinition<P extends string, S, V, X, O extends object> = {
38
+ /** The plugin that provides the field type, which `plugins` lists (D-32). */
39
+ readonly plugin: P
40
+ /** The names of the field type's own options, beside `default` (D-152). */
41
+ readonly options?: readonly NoInfer<keyof O & string>[]
42
+ /** The kernel field that stores, filters and indexes the value. */
43
+ readonly stored: (f: FieldBuilders<never>, options: O) => S
44
+ readonly decode: (stored: StoredValue<S>, options: O) => V
45
+ readonly encode: (value: V, options: O) => StoredValue<S>
46
+ /** Takes the value or its JSON, and gives the value. */
47
+ readonly schema: X | ((options: O) => X)
48
+ /** What a client reads. */
49
+ readonly toJSON: (value: V, options: O) => JsonValue
50
+ /** What `toJSON` gives, which types it for clients (D-152). */
51
+ readonly shape?: StandardSchema | ((options: O) => StandardSchema)
52
+ }
53
+
54
+ /** A field type's options: the stored field says whether it may be `null`. */
55
+ export type FieldTypeOptions<I> = Described & {
56
+ readonly default?: I | DefaultFunction<I>
57
+ }
58
+
59
+ /** The builder `defineFieldType` returns (D-122). */
60
+ export type FieldType<
61
+ P extends string,
62
+ S,
63
+ V,
64
+ I,
65
+ // Weak, as `Described` is, so a name it lacks fails to compile.
66
+ O extends object = Described,
67
+ > = <const G extends FieldTypeOptions<I> & Partial<O> = {}>(
68
+ options?: G,
69
+ ) => Field<V, StoredOptions<S> & G, P, never, I, true, S>
70
+
71
+ const storedOptions = new Set(['list', 'optional', 'precision', 'scale'])
72
+ const kernelOptions = new Set(['default', 'description'])
73
+ type Options = { readonly [key: string]: unknown }
74
+
75
+ /**
76
+ * The stored field `stored` returns, a scalar with no rules; a value as its
77
+ * default fills the rows stored before the field (D-152).
78
+ */
79
+ function storedOf(
80
+ plugin: string,
81
+ stored: unknown,
82
+ options: Options,
83
+ ): FieldDefinition & { readonly kind: 'scalar' } {
84
+ if (typeof stored !== 'function') {
85
+ throw new TypeError(`defineFieldType(${plugin}): stored is a function.`)
86
+ }
87
+ const field: unknown = Reflect.apply(stored, undefined, [
88
+ fieldBuilders,
89
+ options,
90
+ ])
91
+ const definition =
92
+ typeof field === 'object' && field !== null
93
+ ? fieldDefinitions.get(field)
94
+ : undefined
95
+ if (definition?.kind !== 'scalar' || definition.rules !== undefined) {
96
+ throw new TypeError(
97
+ `defineFieldType(${plugin}): stored returns a kernel scalar field, without .with.`,
98
+ )
99
+ }
100
+ for (const [option, value] of Object.entries(definition.options)) {
101
+ const filled = option === 'default' && typeof value !== 'function'
102
+ if (!storedOptions.has(option) && !filled) {
103
+ throw new Error(
104
+ `defineFieldType(${plugin}): the stored field takes list, optional, precision, scale or a value as its default only, not ${option}.`,
105
+ )
106
+ }
107
+ }
108
+ return definition
109
+ }
110
+
111
+ function functionOf(
112
+ plugin: string,
113
+ definition: Options,
114
+ key: string,
115
+ options: Options,
116
+ ): (value: unknown) => unknown {
117
+ const value = definition[key]
118
+ if (typeof value !== 'function') {
119
+ throw new TypeError(`defineFieldType(${plugin}): ${key} is a function.`)
120
+ }
121
+ return (given) => {
122
+ const result: unknown = Reflect.apply(value, undefined, [given, options])
123
+ return result
124
+ }
125
+ }
126
+
127
+ /** One field's codec, its functions given that field's options. */
128
+ function codecOf(plugin: string, definition: Options, options: Options): Codec {
129
+ const schemaOf = (key: string) => {
130
+ const given = definition[key]
131
+ const standard = standardOf(
132
+ typeof given === 'function'
133
+ ? Reflect.apply(given, undefined, [options])
134
+ : given,
135
+ )
136
+ if (standard === undefined) {
137
+ throw new TypeError(
138
+ `defineFieldType(${plugin}): ${key} is a Standard Schema.`,
139
+ )
140
+ }
141
+ return standard
142
+ }
143
+ const shape =
144
+ definition['shape'] === undefined ? undefined : schemaOf('shape').schema
145
+ return Object.freeze({
146
+ plugin,
147
+ options,
148
+ decode: functionOf(plugin, definition, 'decode', options),
149
+ encode: functionOf(plugin, definition, 'encode', options),
150
+ schema: schemaOf('schema'),
151
+ toJSON: functionOf(plugin, definition, 'toJSON', options),
152
+ ...(shape === undefined ? {} : { shape }),
153
+ })
154
+ }
155
+
156
+ /** The names a builder takes, `default`, `description` and the type's own. */
157
+ function namesOf(plugin: string, definition: Options): ReadonlySet<string> {
158
+ const names = definition['options'] ?? []
159
+ if (
160
+ !Array.isArray(names) ||
161
+ !names.every((name) => typeof name === 'string')
162
+ ) {
163
+ throw new TypeError(
164
+ `defineFieldType(${plugin}): options is a list of option names.`,
165
+ )
166
+ }
167
+ return new Set([...kernelOptions, ...names])
168
+ }
169
+
170
+ /**
171
+ * A plugin's field type (D-122): its builder takes `default`, `description`
172
+ * (D-150) and the type's own options (D-152), and its value is stored through
173
+ * `stored`, encoded after the hooks and decoded on each read.
174
+ */
175
+ export function defineFieldType<
176
+ const P extends string,
177
+ S extends Stored,
178
+ V,
179
+ X extends StandardSchema<unknown, V>,
180
+ O extends object = Described,
181
+ >(
182
+ definition: FieldTypeDefinition<P, S, V, X, O>,
183
+ ): FieldType<P, S, V, SchemaTypes<X>['input'], O>
184
+ export function defineFieldType(
185
+ definition: Options,
186
+ ): (options?: FieldOptions) => object {
187
+ const plugin = definition['plugin']
188
+ if (typeof plugin !== 'string' || plugin === '') {
189
+ throw new TypeError('defineFieldType takes the name of its plugin.')
190
+ }
191
+ const names = namesOf(plugin, definition)
192
+ // A definition fails at once, not at its first field.
193
+ codecOf(plugin, definition, {})
194
+ storedOf(plugin, definition['stored'], {})
195
+ return (given = {}) => {
196
+ const own: Record<string, unknown> = {}
197
+ const kernel: Record<string, unknown> = {}
198
+ for (const [option, value] of Object.entries(given)) {
199
+ if (!names.has(option)) {
200
+ throw new Error(
201
+ names.size === kernelOptions.size
202
+ ? `A ${plugin} field takes default and description only, not ${option}: its stored field says the rest.`
203
+ : `A ${plugin} field takes ${[...names].join(', ')} only, not ${option}.`,
204
+ )
205
+ }
206
+ if (kernelOptions.has(option)) kernel[option] = value
207
+ else own[option] = value
208
+ }
209
+ const options = Object.freeze(own)
210
+ const stored = storedOf(plugin, definition['stored'], options)
211
+ const { default: filled, ...rest } = stored.options
212
+ const codec = codecOf(plugin, definition, options)
213
+ return build({
214
+ ...stored,
215
+ options: { ...rest, ...kernel },
216
+ codec: filled === undefined ? codec : Object.freeze({ ...codec, filled }),
217
+ })
218
+ }
219
+ }