ultimabase 0.0.0-stage → 0.1.1

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 +13 -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 +15 -0
  37. package/dist/cli-main.d.ts.map +1 -0
  38. package/dist/cli-main.js +155 -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 +166 -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
@@ -0,0 +1,71 @@
1
+ // How a transport finds who sends a request (D-49, D-106, D-112): Master with
2
+ // the master key, then the first plugin that knows it, anonymous otherwise.
3
+ import { createHash, timingSafeEqual } from 'node:crypto';
4
+ import { PublicError, Refused } from './errors.js';
5
+ import { createMaster } from './rules.js';
6
+ /** The header a transport reads the master key from. */
7
+ export const masterKeyHeader = 'x-ultimabase-master-key';
8
+ const anonymous = Object.freeze({ kind: 'anonymous' });
9
+ const keyMaster = createMaster('key');
10
+ // Digests have one length, so the comparison takes the same time for any key.
11
+ const digest = (text) => createHash('sha256').update(text).digest();
12
+ /** Why a request sending a key is refused before it is compared, if so. */
13
+ function refusalOf(masterKey) {
14
+ const key = typeof masterKey === 'object' ? masterKey.key : masterKey;
15
+ // An empty variable is unset: an empty header must not open Master.
16
+ if (key === undefined || key === '')
17
+ return 'No master key is configured.';
18
+ if (process.env['NODE_ENV'] === 'production' &&
19
+ typeof masterKey !== 'object') {
20
+ return 'The master key is refused in production.';
21
+ }
22
+ return undefined;
23
+ }
24
+ /**
25
+ * Reads the master key and `NODE_ENV` once, when the application starts.
26
+ * `plugins` is read on each request: it is filled once their contexts exist.
27
+ * The caller a plugin knows is completed (D-121).
28
+ */
29
+ export function identifier(masterKey, logger, plugins, complete) {
30
+ const refusal = refusalOf(masterKey);
31
+ const key = typeof masterKey === 'object' ? masterKey.key : masterKey;
32
+ // A header drops the spaces around a value and mangles what is not ASCII:
33
+ // such a key could never match.
34
+ if (key !== undefined && key !== '' && !/^[\x21-\x7e]+$/.test(key)) {
35
+ throw new Refused('The master key holds a space or a character outside ASCII, which a header cannot carry: use letters, digits and symbols only.');
36
+ }
37
+ const expected = digest(key ?? '');
38
+ // Outside production, the HTTP plugin's development log already shows
39
+ // each request (D-108); a use of the key is an audit line in production.
40
+ const audited = process.env['NODE_ENV'] === 'production';
41
+ // Nothing limits the keys a client tries: one that opens Master in
42
+ // production must not be guessed.
43
+ if (audited &&
44
+ refusal === undefined &&
45
+ key !== undefined &&
46
+ key.length < 32) {
47
+ throw new Refused(`The master key is ${key.length} characters long; production needs 32 at least: \`openssl rand -base64 32\` gives one.`);
48
+ }
49
+ return async (request) => {
50
+ const sent = request.headers.get(masterKeyHeader);
51
+ if (sent === null) {
52
+ for (const identify of plugins) {
53
+ const caller = await identify(request);
54
+ if (caller !== undefined)
55
+ return complete(caller);
56
+ }
57
+ return anonymous;
58
+ }
59
+ const refused = refusal ??
60
+ (timingSafeEqual(digest(sent), expected)
61
+ ? undefined
62
+ : 'The master key is wrong.');
63
+ if (refused !== undefined) {
64
+ logger.warn(`A request sent the master key, refused: ${refused}`);
65
+ throw new PublicError('ACCESS_DENIED', refused);
66
+ }
67
+ if (audited)
68
+ logger.info('A request acts as Master with the master key.');
69
+ return keyMaster;
70
+ };
71
+ }
@@ -0,0 +1,25 @@
1
+ export type { Adapter, Aggregate, AggregateRead, Arithmetic, Change, Changed, Check, Condition, CountRead, Feed, Filter, GroupKey, ListUpdate, Migration, Migrations, Nested, Order, Read, Row, Run, ScalarType, Schema, SchemaField, SchemaModel, Sort, Statement, Stored, Transaction, Write, } from './adapter.ts';
2
+ export { CheckFailed, feedFields, feedIds, MigrationFailed, OutOfRange, RelationViolation, UniqueViolation, } from './adapter.ts';
3
+ export type { Logger, MasterKey } from './app-options.ts';
4
+ export { defineApp } from './define-app.ts';
5
+ export { defineEnum } from './define-enum.ts';
6
+ export type { FieldShapes, ModelFields, ModelIndexes, ModelOf, } from './define-model.ts';
7
+ export { defineModel } from './define-model.ts';
8
+ export type { ErrorCode, Issue } from './errors.ts';
9
+ export { InvalidQuery, PublicError, Refused } from './errors.ts';
10
+ export type { DecimalOptions, Enum, Field, FieldBuilders, JsonOptions, JsonValue, ListOptions, Many, ManyOptions, One, ScalarOptions, SingleOptions, StringOptions, } from './fields.ts';
11
+ export { defineFunction, defineType } from './define-function.ts';
12
+ export type { FieldType, FieldTypeDefinition, FieldTypeOptions, } from './field-type.ts';
13
+ export { defineFieldType } from './field-type.ts';
14
+ export { isLocalHost } from './hosts.ts';
15
+ export type { Client, CookieOptions, FunctionPlugin, FunctionShape, Nullable, ObjectType, OutputSpec, ServerFunction, } from './function.ts';
16
+ export { memory } from './memory.ts';
17
+ export type { App, FindOperation, IndexShape, Model } from './model.ts';
18
+ export type { ExposedFunction, ExposedModel, ExposedOutput, ExposedVirtual, ExposedType, ModelQueries, ModelUse, OutputForm, PluginOf, PluginTypes, UseOf, } from './plugin.ts';
19
+ export type { Payload, Queries } from './query.ts';
20
+ export { definePlugin } from './plugin.ts';
21
+ export type { Caller, CallerRule, Identity, Register, UserCallerKeys, UserOf, } from './rules.ts';
22
+ export { allOf, allow, anyOf, isMaster, master } from './rules.ts';
23
+ export { transaction } from './transaction.ts';
24
+ export type { ArgsOf, CreateDataOf, IncludeOf, InputOf, OrderByOf, OutputOf, RecordOf, SelectOf, UpdateDataOf, WhereOf, } from './types.ts';
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACX,OAAO,EACP,SAAS,EACT,aAAa,EACb,UAAU,EACV,MAAM,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,SAAS,EACT,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,UAAU,EACV,SAAS,EACT,UAAU,EACV,MAAM,EACN,KAAK,EACL,IAAI,EACJ,GAAG,EACH,GAAG,EACH,UAAU,EACV,MAAM,EACN,WAAW,EACX,WAAW,EACX,IAAI,EACJ,SAAS,EACT,MAAM,EACN,WAAW,EACX,KAAK,GACL,MAAM,cAAc,CAAA;AACrB,OAAO,EACN,WAAW,EACX,UAAU,EACV,OAAO,EACP,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,eAAe,GACf,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,OAAO,GACP,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAChE,YAAY,EACX,cAAc,EACd,IAAI,EACJ,KAAK,EACL,aAAa,EACb,WAAW,EACX,SAAS,EACT,WAAW,EACX,IAAI,EACJ,WAAW,EACX,GAAG,EACH,aAAa,EACb,aAAa,EACb,aAAa,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjE,YAAY,EACX,SAAS,EACT,mBAAmB,EACnB,gBAAgB,GAChB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,YAAY,EACX,MAAM,EACN,aAAa,EACb,cAAc,EACd,aAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,EACV,cAAc,GACd,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACvE,YAAY,EACX,eAAe,EACf,YAAY,EACZ,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,WAAW,EACX,KAAK,GACL,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EACX,MAAM,EACN,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,MAAM,GACN,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,YAAY,EACX,MAAM,EACN,YAAY,EACZ,SAAS,EACT,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,OAAO,GACP,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export { CheckFailed, feedFields, feedIds, MigrationFailed, OutOfRange, RelationViolation, UniqueViolation, } from './adapter.js';
2
+ export { defineApp } from './define-app.js';
3
+ export { defineEnum } from './define-enum.js';
4
+ export { defineModel } from './define-model.js';
5
+ export { InvalidQuery, PublicError, Refused } from './errors.js';
6
+ export { defineFunction, defineType } from './define-function.js';
7
+ export { defineFieldType } from './field-type.js';
8
+ export { isLocalHost } from './hosts.js';
9
+ export { memory } from './memory.js';
10
+ export { definePlugin } from './plugin.js';
11
+ export { allOf, allow, anyOf, isMaster, master } from './rules.js';
12
+ export { transaction } from './transaction.js';
@@ -0,0 +1,28 @@
1
+ import type { Adapter } from './adapter.ts';
2
+ import type { Lifecycle } from './lifecycle.ts';
3
+ export type { Lifecycle };
4
+ export type { Scratch } from './scratch.ts';
5
+ export { scratchable, scratchOf } from './scratch.ts';
6
+ export { isRow } from './field-codec.ts';
7
+ export { joining } from './transaction.ts';
8
+ export { issueOf } from './write-data.ts';
9
+ export { decimalPattern } from './decimal.ts';
10
+ export type { Recorded } from './recorder.ts';
11
+ export { recording } from './recorder.ts';
12
+ export type { LivePlan } from './live.ts';
13
+ export { inMemory, liveSchema, livePlan, matches, servedRows, sortKeys, storedRows, } from './live.ts';
14
+ export { compareKeys } from './memory-values.ts';
15
+ /** The application's database, and new runs of it on another (D-130). */
16
+ export type QuietRuns = {
17
+ readonly declared: Adapter;
18
+ /** A run on `database`, without info lines. */
19
+ readonly on: (database: Adapter) => Lifecycle;
20
+ };
21
+ /**
22
+ * Runs of the application `defineApp` returned as `app`, or `undefined` for
23
+ * another value.
24
+ */
25
+ export declare function quietRuns(app: unknown): QuietRuns | undefined;
26
+ /** The running application's plugin API named `name`, if any. */
27
+ export declare function runningApi(name: string): unknown;
28
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAI3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI/C,YAAY,EAAE,SAAS,EAAE,CAAA;AACzB,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EACN,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAO,EACP,UAAU,EACV,QAAQ,EACR,UAAU,GACV,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAYhD,yEAAyE;AACzE,MAAM,MAAM,SAAS,GAAG;IACvB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,SAAS,CAAA;CAC7C,CAAA;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAQ7D;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD"}
@@ -0,0 +1,39 @@
1
+ import { internalsOf } from './app-internals.js';
2
+ import { consoleLogger } from './console-logger.js';
3
+ import { lifecycle } from './lifecycle.js';
4
+ import { current } from './running.js';
5
+ export { scratchable, scratchOf } from './scratch.js';
6
+ export { isRow } from './field-codec.js';
7
+ export { joining } from './transaction.js';
8
+ export { issueOf } from './write-data.js';
9
+ export { decimalPattern } from './decimal.js';
10
+ export { recording } from './recorder.js';
11
+ export { inMemory, liveSchema, livePlan, matches, servedRows, sortKeys, storedRows, } from './live.js';
12
+ export { compareKeys } from './memory-values.js';
13
+ /** `logger` without its info lines. */
14
+ function quieted(logger) {
15
+ return {
16
+ info: () => undefined,
17
+ warn: logger.warn.bind(logger),
18
+ error: logger.error.bind(logger),
19
+ child: (bindings) => quieted(logger.child(bindings)),
20
+ };
21
+ }
22
+ /**
23
+ * Runs of the application `defineApp` returned as `app`, or `undefined` for
24
+ * another value.
25
+ */
26
+ export function quietRuns(app) {
27
+ const options = internalsOf(app)?.options;
28
+ if (options === undefined)
29
+ return undefined;
30
+ const logger = quieted(options.logger ?? consoleLogger());
31
+ return {
32
+ declared: options.database,
33
+ on: (database) => lifecycle({ ...options, database, logger }),
34
+ };
35
+ }
36
+ /** The running application's plugin API named `name`, if any. */
37
+ export function runningApi(name) {
38
+ return current()?.apis.get(name);
39
+ }
@@ -0,0 +1,21 @@
1
+ import type { Adapter, Schema } from './adapter.ts';
2
+ import type { Logger, MasterKey } from './app-options.ts';
3
+ export type Lifecycle = {
4
+ readonly start: () => Promise<void>;
5
+ readonly stop: () => Promise<void>;
6
+ };
7
+ export type LifecycleOptions = {
8
+ readonly database: Adapter;
9
+ readonly plugins?: readonly unknown[];
10
+ /** The application's `defineFunction` values (D-27). */
11
+ readonly functions?: readonly unknown[];
12
+ readonly models: readonly unknown[];
13
+ readonly logger?: Logger;
14
+ readonly masterKey?: MasterKey;
15
+ };
16
+ /** The application's schema, or a message on what is wrong with it. */
17
+ export declare function schemaOf(options: LifecycleOptions): Schema;
18
+ /** The kernel's logger: the application's, or JSON lines. */
19
+ export declare const kernelLogger: (options: LifecycleOptions) => Logger;
20
+ export declare function lifecycle(options: LifecycleOptions): Lifecycle;
21
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAqBzD,MAAM,MAAM,SAAS,GAAG;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAClC,CAAA;AAuBD,MAAM,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IACrC,wDAAwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAC9B,CAAA;AAUD,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAM1D;AAED,6DAA6D;AAC7D,eAAO,MAAM,YAAY,YAAa,gBAAgB,KAAG,MACS,CAAA;AAkBlE,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAoH9D"}
@@ -0,0 +1,149 @@
1
+ import { completer } from './complete.js';
2
+ import { consoleLogger } from './console-logger.js';
3
+ import { feedOf } from './feed.js';
4
+ import { identifier } from './identify.js';
5
+ import { checkVersions } from './manifest.js';
6
+ import { checked, synced } from './migrate.js';
7
+ import { buildApis, installed, pluginCallers, pluginIdentifiers, withContexts, } from './plugin-app.js';
8
+ import { register, unregister, Work } from './running.js';
9
+ import { resolve } from './schema.js';
10
+ /** Stops `plugins` in reverse order, each even when another fails. */
11
+ async function stopped(plugins) {
12
+ const errors = [];
13
+ for (const { code, context } of plugins.toReversed()) {
14
+ if (code.stop === undefined)
15
+ continue;
16
+ try {
17
+ await Reflect.apply(code.stop, undefined, [context]);
18
+ }
19
+ catch (error) {
20
+ context.logger.error({ err: error }, 'The plugin failed to stop.');
21
+ errors.push(error);
22
+ }
23
+ }
24
+ return errors;
25
+ }
26
+ /** Once stdout and stderr have written what they were given. */
27
+ const written = () => Promise.all([process.stdout, process.stderr].map((stream) => new Promise((done) => stream.write('', done))));
28
+ /** The application's schema, or a message on what is wrong with it. */
29
+ export function schemaOf(options) {
30
+ const { plugins } = installed(options.plugins ?? []);
31
+ return resolve(options.models, plugins.map((plugin) => plugin.code)).schema;
32
+ }
33
+ /** The kernel's logger: the application's, or JSON lines. */
34
+ export const kernelLogger = (options) => (options.logger ?? consoleLogger()).child({ name: 'ultimabase' });
35
+ /** Syncs a development database, or checks a production one (D-105). */
36
+ async function follow(database, schema, logger) {
37
+ try {
38
+ await (process.env['NODE_ENV'] === 'production'
39
+ ? checked(database, schema, logger)
40
+ : synced(database, schema, logger, false));
41
+ }
42
+ catch (error) {
43
+ await database.stop();
44
+ throw error;
45
+ }
46
+ }
47
+ export function lifecycle(options) {
48
+ const { database, models } = options;
49
+ let started;
50
+ let stopping;
51
+ let starting = false;
52
+ const shutDown = async ({ app, plugins, onSigterm }) => {
53
+ process.off('SIGTERM', onSigterm);
54
+ const errors = await stopped(plugins);
55
+ // A plugin's stop may still query; the database closes last.
56
+ await app.work.settled();
57
+ unregister(app);
58
+ started = undefined;
59
+ await database.stop();
60
+ app.logger.info('Application stopped.');
61
+ if (errors.length > 0)
62
+ throw errors[0];
63
+ };
64
+ const stop = async () => {
65
+ if (stopping !== undefined)
66
+ return stopping;
67
+ if (started === undefined)
68
+ return;
69
+ stopping = shutDown(started).finally(() => {
70
+ stopping = undefined;
71
+ });
72
+ return stopping;
73
+ };
74
+ const start = async () => {
75
+ if (started !== undefined || starting) {
76
+ throw new Error('The application is running.');
77
+ }
78
+ // Set before the first await: a second start meanwhile is refused.
79
+ starting = true;
80
+ try {
81
+ await launch();
82
+ }
83
+ finally {
84
+ starting = false;
85
+ }
86
+ };
87
+ const launch = async () => {
88
+ const { plugins: records, apiOrder } = installed(options.plugins ?? []);
89
+ const resolved = resolve(models, records.map((plugin) => plugin.code));
90
+ const base = options.logger ?? consoleLogger();
91
+ const logger = base.child({ name: 'ultimabase' });
92
+ checkVersions(records, logger);
93
+ // Plugins identify with their contexts, which hold identify.
94
+ const identifiers = [];
95
+ const callers = [];
96
+ const complete = completer(callers);
97
+ const identify = identifier(options.masterKey, logger, identifiers, complete);
98
+ const { plugins, functions } = withContexts(apiOrder, base, identify, resolved, options.functions ?? []);
99
+ identifiers.push(...pluginIdentifiers(records, plugins));
100
+ callers.push(...pluginCallers(records, plugins));
101
+ await database.start(resolved.schema, logger, feedOf(records, plugins));
102
+ const apis = new Map();
103
+ const app = {
104
+ resolved,
105
+ adapter: database,
106
+ logger,
107
+ apis,
108
+ functions: functions.definitions,
109
+ work: new Work(),
110
+ complete,
111
+ };
112
+ const ran = [];
113
+ try {
114
+ await follow(database, resolved.schema, logger);
115
+ register(app);
116
+ // An API may read the APIs it needs as it is built (D-89).
117
+ buildApis(plugins, apis);
118
+ for (const plugin of plugins) {
119
+ const { code, context } = plugin;
120
+ if (code.start !== undefined) {
121
+ await Reflect.apply(code.start, undefined, [context]);
122
+ }
123
+ ran.push(plugin);
124
+ }
125
+ }
126
+ catch (error) {
127
+ await stopped(ran);
128
+ unregister(app);
129
+ await database.stop();
130
+ throw error;
131
+ }
132
+ const onSigterm = () => {
133
+ void stop()
134
+ .catch((error) => {
135
+ logger.error({ err: error }, 'The application stopped with an error.');
136
+ })
137
+ // The last lines first: a pipe may write them later.
138
+ .then(written)
139
+ .finally(() => {
140
+ // Its listener is gone: the signal now ends the process.
141
+ process.kill(process.pid, 'SIGTERM');
142
+ });
143
+ };
144
+ process.once('SIGTERM', onSigterm);
145
+ started = { app, plugins, onSigterm };
146
+ logger.info('Application started.');
147
+ };
148
+ return { start, stop };
149
+ }
@@ -0,0 +1,12 @@
1
+ import type { ListUpdate } from './adapter.ts';
2
+ import type { ModelInfo } from './schema.ts';
3
+ import type { Draft } from './write-data.ts';
4
+ /**
5
+ * Takes the operations out of an update's draft: `{ set }` becomes its
6
+ * list, an operation by `undefined` leaves its field as it is (D-84), and
7
+ * each other one comes back to be computed on the row.
8
+ */
9
+ export declare function listUpdates(model: ModelInfo, draft: Draft, at?: readonly (string | number)[]): Map<string, ListUpdate>;
10
+ /** A list update's result on `current`, the elements in their order. */
11
+ export declare function listed(current: unknown, { operation, elements }: ListUpdate): unknown[];
12
+ //# sourceMappingURL=list-update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-update.d.ts","sourceRoot":"","sources":["../src/list-update.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAS5C;;;;GAIG;AACH,wBAAgB,WAAW,CAC1B,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,KAAK,EACZ,EAAE,GAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAO,GACnC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CA6BzB;AAED,wEAAwE;AACxE,wBAAgB,MAAM,CACrB,OAAO,EAAE,OAAO,EAChB,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,UAAU,GACjC,OAAO,EAAE,CAUX"}
@@ -0,0 +1,52 @@
1
+ import { InvalidQuery } from './errors.js';
2
+ import { isObject } from './query-where.js';
3
+ import { invalid, issueOf } from './write-data.js';
4
+ const operations = ['set', 'push', 'pushUnique', 'remove'];
5
+ const isOperation = (key) => operations.some((operation) => operation === key);
6
+ /**
7
+ * Takes the operations out of an update's draft: `{ set }` becomes its
8
+ * list, an operation by `undefined` leaves its field as it is (D-84), and
9
+ * each other one comes back to be computed on the row.
10
+ */
11
+ export function listUpdates(model, draft, at = []) {
12
+ const lists = new Map();
13
+ for (const [name, value] of Object.entries(draft)) {
14
+ const field = model.fields.get(name);
15
+ // A field type's value is its own, as for numbers (D-132).
16
+ const plain = field?.kind === 'scalar' && field.list && !field.codec;
17
+ if (!plain || !isObject(value))
18
+ continue;
19
+ const keys = Object.keys(value);
20
+ const used = operations.filter((key) => value[key] !== undefined);
21
+ if (keys.length === 0 || used.length > 1 || !keys.every(isOperation)) {
22
+ const path = ['data', ...at, name].join('.');
23
+ throw new InvalidQuery(path, `${path} takes a list or one of ${operations.join(', ')}.`);
24
+ }
25
+ delete draft[name];
26
+ const [operation] = used;
27
+ if (operation === undefined)
28
+ continue;
29
+ const given = value[operation];
30
+ const elements = Array.isArray(given) ? given : [given];
31
+ const issue = issueOf(elements, field);
32
+ if (issue !== undefined) {
33
+ throw invalid([{ path: [...at, name], message: issue }]);
34
+ }
35
+ if (operation === 'set')
36
+ draft[name] = elements;
37
+ else
38
+ lists.set(name, { operation, elements });
39
+ }
40
+ return lists;
41
+ }
42
+ /** A list update's result on `current`, the elements in their order. */
43
+ export function listed(current, { operation, elements }) {
44
+ const from = Array.isArray(current) ? current : [];
45
+ if (operation === 'push')
46
+ return [...from, ...elements];
47
+ if (operation === 'remove') {
48
+ return from.filter((item) => !elements.includes(item));
49
+ }
50
+ const added = elements.filter((item, index) => !from.includes(item) && elements.indexOf(item) === index);
51
+ return [...from, ...added];
52
+ }
package/dist/live.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ import type { Filter, Nested, Order, Row, Schema } from './adapter.ts';
2
+ import type { Caller } from './rules.ts';
3
+ /**
4
+ * The rows a live read follows, and their order, ending with `id`; `filter`
5
+ * is the read's own part of `where`, `rights` the part the caller's read
6
+ * rules and `beforeFind` add, and
7
+ * `include`, `count` and `fields` what its selection reads, as the adapter
8
+ * receives them.
9
+ */
10
+ export type LivePlan = Pick<Nested, 'include' | 'count' | 'fields'> & {
11
+ readonly where: Filter | undefined;
12
+ readonly filter: Filter | undefined;
13
+ readonly rights: Filter | undefined;
14
+ readonly orderBy: readonly Order[];
15
+ };
16
+ /**
17
+ * `args` as `caller` reads `model`: its read rules and every `beforeFind`
18
+ * included. A live row's `where` names one row, as `findUnique`'s.
19
+ */
20
+ export declare function livePlan(model: string, args: unknown, caller: Caller, row?: boolean): Promise<LivePlan>;
21
+ /** The stored rows `read` finds, as Master, plugin fields undecoded. */
22
+ export declare function storedRows(model: string, read: Nested): Promise<readonly Row[]>;
23
+ /** The running application's schema, its plugins' models included. */
24
+ export declare function liveSchema(): Schema;
25
+ /** Whether `filter` reads `model`'s row alone, so `matches` can test it. */
26
+ export declare function inMemory(model: string, filter: Filter | undefined): boolean;
27
+ /** Whether the stored `row` of `model` passes `filter`, which `inMemory` takes. */
28
+ export declare function matches(model: string, row: Row, filter: Filter | undefined): boolean;
29
+ /**
30
+ * `findMany(args)` on `model` as `caller`, its rows taken from the stored
31
+ * `rows` when they alone answer it, else from the database. `rows` holds
32
+ * every row its `where` finds.
33
+ */
34
+ export declare function servedRows(model: string, args: unknown, caller: Caller, rows: ReadonlyMap<string, Row>): Promise<readonly Row[]>;
35
+ /** The sort keys of the stored `row`, for an order on its own fields. */
36
+ export declare function sortKeys(model: string, row: Row, orderBy: readonly Order[]): unknown[];
37
+ //# sourceMappingURL=live.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAQ,GAAG,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAS5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAKxC;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC,GAAG;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,KAAK,EAAE,CAAA;CAClC,CAAA;AAYD;;;GAGG;AACH,wBAAsB,QAAQ,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,EACd,GAAG,UAAQ,GACT,OAAO,CAAC,QAAQ,CAAC,CA4BnB;AAED,wEAAwE;AACxE,wBAAsB,UAAU,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC,CAGzB;AAED,sEAAsE;AACtE,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAY3E;AAkBD,mFAAmF;AACnF,wBAAgB,OAAO,CACtB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAET;AA4BD;;;;GAIG;AACH,wBAAsB,UAAU,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC,CAYzB;AAED,yEAAyE;AACzE,wBAAgB,QAAQ,CACvB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,SAAS,KAAK,EAAE,GACvB,OAAO,EAAE,CAQX"}
package/dist/live.js ADDED
@@ -0,0 +1,139 @@
1
+ // What the realtime plugin asks the kernel (D-154): a live read's effective
2
+ // filter and order, planned once for its caller, and, on a stored row, that
3
+ // filter and the row's sort keys, tested as `memory()` reads.
4
+ import { accessFor, and } from './access.js';
5
+ import { rootFind } from './engine.js';
6
+ import { decoded, isRow } from './field-codec.js';
7
+ import { Reader } from './memory-read.js';
8
+ import { compareKeys, sortable } from './memory-values.js';
9
+ import { isFilters } from './memory-conditions.js';
10
+ import { plan, uniqueWhere } from './query-args.js';
11
+ import { modelOf } from './query-where.js';
12
+ import { isObject } from './query-values.js';
13
+ import { current } from './running.js';
14
+ import { QueryScope, planned } from './scope.js';
15
+ function started() {
16
+ const app = current();
17
+ if (app === undefined)
18
+ throw new Error('No application is running.');
19
+ return app;
20
+ }
21
+ const shapeKeys = ['select', 'include', 'omit'];
22
+ const liveKeys = new Set(['where', 'orderBy', ...shapeKeys]);
23
+ const rowKeys = new Set(shapeKeys);
24
+ /**
25
+ * `args` as `caller` reads `model`: its read rules and every `beforeFind`
26
+ * included. A live row's `where` names one row, as `findUnique`'s.
27
+ */
28
+ export async function livePlan(model, args, caller, row = false) {
29
+ const app = started();
30
+ const { models } = app.resolved;
31
+ const info = modelOf(models, model);
32
+ const access = accessFor(models, caller, app.logger);
33
+ const scope = new QueryScope(models, caller, access);
34
+ const { where: unique, ...shape } = isObject(args) ? args : {};
35
+ return app.work.run(async () => planned(scope, () => {
36
+ const { read } = row
37
+ ? plan(models, info, shape, '', 'many', rowKeys, scope)
38
+ : plan(models, info, args, '', 'many', liveKeys, scope);
39
+ const rights = scope.readable(model);
40
+ const where = row
41
+ ? uniqueWhere(models, info, unique, 'where', scope)
42
+ : read.where;
43
+ const { include, count, fields } = read;
44
+ return {
45
+ ...(include && { include }),
46
+ ...(count && { count }),
47
+ ...(fields && { fields }),
48
+ where: and(where, rights),
49
+ filter: where,
50
+ rights,
51
+ orderBy: read.orderBy ?? [{ field: 'id', direction: 'asc' }],
52
+ };
53
+ }));
54
+ }
55
+ /** The stored rows `read` finds, as Master, plugin fields undecoded. */
56
+ export async function storedRows(model, read) {
57
+ const app = started();
58
+ return app.work.run(async () => app.adapter.find({ ...read, model }));
59
+ }
60
+ /** The running application's schema, its plugins' models included. */
61
+ export function liveSchema() {
62
+ return started().resolved.schema;
63
+ }
64
+ /** Whether `filter` reads `model`'s row alone, so `matches` can test it. */
65
+ export function inMemory(model, filter) {
66
+ const fields = modelOf(started().resolved.models, model).fields;
67
+ return Object.entries(filter ?? {}).every(([key, value]) => {
68
+ if (value === undefined)
69
+ return true;
70
+ if (isFilters(value))
71
+ return value.every((part) => inMemory(model, part));
72
+ // A search ranks as each database does (D-148).
73
+ if (value.search !== undefined || value.removedBy !== undefined) {
74
+ return false;
75
+ }
76
+ const field = fields.get(key);
77
+ return field === undefined || field.kind === 'scalar';
78
+ });
79
+ }
80
+ const readers = new WeakMap();
81
+ function readerOf(app) {
82
+ const known = readers.get(app);
83
+ if (known !== undefined)
84
+ return known;
85
+ const fields = new Map(app.resolved.schema.models.map((model) => [
86
+ model.name,
87
+ new Map(model.fields.map((field) => [field.name, field])),
88
+ ]));
89
+ const reader = new Reader({ tables: new Map(), joins: new Map() }, fields);
90
+ readers.set(app, reader);
91
+ return reader;
92
+ }
93
+ /** Whether the stored `row` of `model` passes `filter`, which `inMemory` takes. */
94
+ export function matches(model, row, filter) {
95
+ return readerOf(started()).matches(model, row, filter) === true;
96
+ }
97
+ /** Whether rows alone answer `read`: one level, unpaged, read in memory. */
98
+ const servable = (read) => read.include === undefined &&
99
+ read.count === undefined &&
100
+ read.distinct === undefined &&
101
+ read.cursor === undefined &&
102
+ read.skip === undefined &&
103
+ read.take === undefined &&
104
+ (read.orderBy ?? []).every((order) => (order.through ?? order.count ?? order.relevance) === undefined) &&
105
+ inMemory(read.model, read.where);
106
+ /**
107
+ * The stored `rows` that pass `read`, in its order; the find that asked for
108
+ * them keeps the fields its shape selects.
109
+ */
110
+ function served(read, rows) {
111
+ const { model, orderBy = [] } = read;
112
+ const kept = [...rows].filter((row) => matches(model, row, read.where));
113
+ const keys = new Map(kept.map((row) => [row, sortKeys(model, row, orderBy)]));
114
+ const key = (row) => keys.get(row) ?? [];
115
+ kept.sort((a, b) => compareKeys(key(a), key(b), orderBy));
116
+ return kept;
117
+ }
118
+ /**
119
+ * `findMany(args)` on `model` as `caller`, its rows taken from the stored
120
+ * `rows` when they alone answer it, else from the database. `rows` holds
121
+ * every row its `where` finds.
122
+ */
123
+ export async function servedRows(model, args, caller, rows) {
124
+ const { models } = started().resolved;
125
+ const found = await rootFind(model, args, { as: caller }, async (store, read) => servable(read)
126
+ ? decoded(models, read, served(read, rows.values()))
127
+ : store.find(read));
128
+ return Array.isArray(found) ? found.filter(isRow) : [];
129
+ }
130
+ /** The sort keys of the stored `row`, for an order on its own fields. */
131
+ export function sortKeys(model, row, orderBy) {
132
+ const reader = readerOf(started());
133
+ return orderBy.map((order) => {
134
+ if (order.through ?? order.count ?? order.relevance) {
135
+ throw new Error(`The order by ${order.field} reads another row.`);
136
+ }
137
+ return sortable(row[order.field] ?? null, reader.field(model, order.field));
138
+ });
139
+ }
@@ -0,0 +1,11 @@
1
+ import type { Logger } from './app-options.ts';
2
+ import type { PluginRecord } from './definition.ts';
3
+ import type { Manifest } from './plugin.ts';
4
+ /** Checks a plugin's `manifest`: a name, a version and valid ranges. */
5
+ export declare function manifestOf(value: unknown, plugin: string): Manifest;
6
+ /**
7
+ * Refuses a plugin whose ranges exclude the running kernel or an installed
8
+ * plugin, naming both versions; warns of one that gives the kernel no range.
9
+ */
10
+ export declare function checkVersions(plugins: readonly PluginRecord[], logger: Logger): void;
11
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CA4BnE;AAMD;;;GAGG;AACH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,MAAM,EAAE,MAAM,GACZ,IAAI,CAkBN"}