@async/db 0.2.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 (398) hide show
  1. package/CHANGELOG.md +167 -0
  2. package/README.md +431 -0
  3. package/SPEC.md +1429 -0
  4. package/db.config.example.mjs +128 -0
  5. package/dist/cli/args.d.ts +8 -0
  6. package/dist/cli/args.js +16 -0
  7. package/dist/cli/commands/create.d.ts +3 -0
  8. package/dist/cli/commands/create.js +13 -0
  9. package/dist/cli/commands/doctor.d.ts +3 -0
  10. package/dist/cli/commands/doctor.js +31 -0
  11. package/dist/cli/commands/generate.d.ts +6 -0
  12. package/dist/cli/commands/generate.js +24 -0
  13. package/dist/cli/commands/operations.d.ts +12 -0
  14. package/dist/cli/commands/operations.js +61 -0
  15. package/dist/cli/commands/schema.d.ts +11 -0
  16. package/dist/cli/commands/schema.js +1086 -0
  17. package/dist/cli/commands/serve.d.ts +9 -0
  18. package/dist/cli/commands/serve.js +18 -0
  19. package/dist/cli/commands/sync.d.ts +3 -0
  20. package/dist/cli/commands/sync.js +11 -0
  21. package/dist/cli/commands/types.d.ts +7 -0
  22. package/dist/cli/commands/types.js +37 -0
  23. package/dist/cli/commands/viewer.d.ts +6 -0
  24. package/dist/cli/commands/viewer.js +29 -0
  25. package/dist/cli/index.d.ts +2 -0
  26. package/dist/cli/index.js +108 -0
  27. package/dist/cli/output.d.ts +25 -0
  28. package/dist/cli/output.js +149 -0
  29. package/dist/cli/schema-prompt.d.ts +20 -0
  30. package/dist/cli/schema-prompt.js +66 -0
  31. package/dist/cli.d.ts +2 -0
  32. package/dist/cli.js +3 -0
  33. package/dist/client-cache.d.ts +105 -0
  34. package/dist/client-cache.js +916 -0
  35. package/dist/client.d.ts +64 -0
  36. package/dist/client.js +405 -0
  37. package/dist/config-public.d.ts +1 -0
  38. package/dist/config-public.js +1 -0
  39. package/dist/config.d.ts +54 -0
  40. package/dist/config.js +2 -0
  41. package/dist/csv.d.ts +1 -0
  42. package/dist/csv.js +1 -0
  43. package/dist/db.d.ts +3 -0
  44. package/dist/db.js +3 -0
  45. package/dist/doctor.d.ts +1 -0
  46. package/dist/doctor.js +1 -0
  47. package/dist/errors.d.ts +1 -0
  48. package/dist/errors.js +1 -0
  49. package/dist/features/config/defaults.d.ts +98 -0
  50. package/dist/features/config/defaults.js +95 -0
  51. package/dist/features/config/load.d.ts +11 -0
  52. package/dist/features/config/load.js +265 -0
  53. package/dist/features/config/public.d.ts +17 -0
  54. package/dist/features/config/public.js +75 -0
  55. package/dist/features/doctor/duplicate-ids.d.ts +18 -0
  56. package/dist/features/doctor/duplicate-ids.js +79 -0
  57. package/dist/features/doctor/field-consistency.d.ts +17 -0
  58. package/dist/features/doctor/field-consistency.js +48 -0
  59. package/dist/features/doctor/index.d.ts +39 -0
  60. package/dist/features/doctor/index.js +177 -0
  61. package/dist/features/doctor/relations.d.ts +22 -0
  62. package/dist/features/doctor/relations.js +90 -0
  63. package/dist/features/doctor/schema-guidance.d.ts +35 -0
  64. package/dist/features/doctor/schema-guidance.js +184 -0
  65. package/dist/features/generate/registry.d.ts +14 -0
  66. package/dist/features/generate/registry.js +37 -0
  67. package/dist/features/http/registry.d.ts +46 -0
  68. package/dist/features/http/registry.js +86 -0
  69. package/dist/features/operations/index.d.ts +49 -0
  70. package/dist/features/operations/index.js +199 -0
  71. package/dist/features/operations/maps.d.ts +1 -0
  72. package/dist/features/operations/maps.js +10 -0
  73. package/dist/features/operations/readiness.d.ts +30 -0
  74. package/dist/features/operations/readiness.js +228 -0
  75. package/dist/features/operations/runtime.d.ts +57 -0
  76. package/dist/features/operations/runtime.js +288 -0
  77. package/dist/features/runtime/collection.d.ts +51 -0
  78. package/dist/features/runtime/collection.js +198 -0
  79. package/dist/features/runtime/db.d.ts +152 -0
  80. package/dist/features/runtime/db.js +824 -0
  81. package/dist/features/runtime/document.d.ts +43 -0
  82. package/dist/features/runtime/document.js +111 -0
  83. package/dist/features/runtime/fanout.d.ts +24 -0
  84. package/dist/features/runtime/fanout.js +77 -0
  85. package/dist/features/runtime/json-pointer.d.ts +5 -0
  86. package/dist/features/runtime/json-pointer.js +49 -0
  87. package/dist/features/runtime/scope-state.d.ts +44 -0
  88. package/dist/features/runtime/scope-state.js +185 -0
  89. package/dist/features/runtime/state.d.ts +1 -0
  90. package/dist/features/runtime/state.js +1 -0
  91. package/dist/features/schema/api.d.ts +107 -0
  92. package/dist/features/schema/api.js +460 -0
  93. package/dist/features/schema/builders.d.ts +86 -0
  94. package/dist/features/schema/builders.js +110 -0
  95. package/dist/features/schema/fields.d.ts +38 -0
  96. package/dist/features/schema/fields.js +296 -0
  97. package/dist/features/schema/generated.d.ts +29 -0
  98. package/dist/features/schema/generated.js +32 -0
  99. package/dist/features/schema/locator.d.ts +16 -0
  100. package/dist/features/schema/locator.js +135 -0
  101. package/dist/features/schema/manifest.d.ts +91 -0
  102. package/dist/features/schema/manifest.js +384 -0
  103. package/dist/features/schema/metadata.d.ts +30 -0
  104. package/dist/features/schema/metadata.js +75 -0
  105. package/dist/features/schema/project.d.ts +46 -0
  106. package/dist/features/schema/project.js +442 -0
  107. package/dist/features/schema/relations.d.ts +38 -0
  108. package/dist/features/schema/relations.js +109 -0
  109. package/dist/features/schema/resolvers.d.ts +36 -0
  110. package/dist/features/schema/resolvers.js +111 -0
  111. package/dist/features/schema/resource.d.ts +75 -0
  112. package/dist/features/schema/resource.js +253 -0
  113. package/dist/features/schema/source-definitions.d.ts +21 -0
  114. package/dist/features/schema/source-definitions.js +29 -0
  115. package/dist/features/schema/sources.d.ts +83 -0
  116. package/dist/features/schema/sources.js +689 -0
  117. package/dist/features/schema/standard-schema.d.ts +57 -0
  118. package/dist/features/schema/standard-schema.js +232 -0
  119. package/dist/features/schema/validation.d.ts +69 -0
  120. package/dist/features/schema/validation.js +434 -0
  121. package/dist/features/storage/events.d.ts +12 -0
  122. package/dist/features/storage/events.js +30 -0
  123. package/dist/features/storage/json.d.ts +112 -0
  124. package/dist/features/storage/json.js +239 -0
  125. package/dist/features/storage/memory.d.ts +30 -0
  126. package/dist/features/storage/memory.js +44 -0
  127. package/dist/features/storage/resource-json.d.ts +31 -0
  128. package/dist/features/storage/resource-json.js +76 -0
  129. package/dist/features/storage/runtime.d.ts +37 -0
  130. package/dist/features/storage/runtime.js +184 -0
  131. package/dist/features/storage/source-metadata.d.ts +20 -0
  132. package/dist/features/storage/source-metadata.js +25 -0
  133. package/dist/features/storage/source.d.ts +37 -0
  134. package/dist/features/storage/source.js +60 -0
  135. package/dist/features/storage/static.d.ts +29 -0
  136. package/dist/features/storage/static.js +42 -0
  137. package/dist/features/sync/defaults.d.ts +21 -0
  138. package/dist/features/sync/defaults.js +21 -0
  139. package/dist/features/sync/index.d.ts +35 -0
  140. package/dist/features/sync/index.js +85 -0
  141. package/dist/features/sync/mirror-state.d.ts +14 -0
  142. package/dist/features/sync/mirror-state.js +4 -0
  143. package/dist/features/sync/runtime-dirs.d.ts +5 -0
  144. package/dist/features/sync/runtime-dirs.js +9 -0
  145. package/dist/features/sync/source-writes.d.ts +15 -0
  146. package/dist/features/sync/source-writes.js +27 -0
  147. package/dist/features/sync/synthetic-seed.d.ts +26 -0
  148. package/dist/features/sync/synthetic-seed.js +83 -0
  149. package/dist/features/viewer/manifest.d.ts +148 -0
  150. package/dist/features/viewer/manifest.js +165 -0
  151. package/dist/fs-utils.d.ts +1 -0
  152. package/dist/fs-utils.js +1 -0
  153. package/dist/generate/hono/app.d.ts +6 -0
  154. package/dist/generate/hono/app.js +51 -0
  155. package/dist/generate/hono/graphql.d.ts +7 -0
  156. package/dist/generate/hono/graphql.js +53 -0
  157. package/dist/generate/hono/index.d.ts +55 -0
  158. package/dist/generate/hono/index.js +140 -0
  159. package/dist/generate/hono/package.d.ts +6 -0
  160. package/dist/generate/hono/package.js +44 -0
  161. package/dist/generate/hono/readme.d.ts +13 -0
  162. package/dist/generate/hono/readme.js +28 -0
  163. package/dist/generate/hono/repository.d.ts +1 -0
  164. package/dist/generate/hono/repository.js +27 -0
  165. package/dist/generate/hono/rest.d.ts +1 -0
  166. package/dist/generate/hono/rest.js +38 -0
  167. package/dist/generate/hono/schema.d.ts +13 -0
  168. package/dist/generate/hono/schema.js +18 -0
  169. package/dist/generate/hono/sqlite.d.ts +20 -0
  170. package/dist/generate/hono/sqlite.js +266 -0
  171. package/dist/generate/hono/validators.d.ts +1 -0
  172. package/dist/generate/hono/validators.js +141 -0
  173. package/dist/generate/hono.d.ts +1 -0
  174. package/dist/generate/hono.js +1 -0
  175. package/dist/graphql/execute.d.ts +14 -0
  176. package/dist/graphql/execute.js +719 -0
  177. package/dist/graphql/http.d.ts +15 -0
  178. package/dist/graphql/http.js +29 -0
  179. package/dist/graphql/index.d.ts +3 -0
  180. package/dist/graphql/index.js +3 -0
  181. package/dist/graphql/parser.d.ts +54 -0
  182. package/dist/graphql/parser.js +433 -0
  183. package/dist/hono.d.ts +77 -0
  184. package/dist/hono.js +1 -0
  185. package/dist/index.d.ts +1065 -0
  186. package/dist/index.js +14 -0
  187. package/dist/integrations/hono.d.ts +136 -0
  188. package/dist/integrations/hono.js +508 -0
  189. package/dist/integrations/kv.d.ts +69 -0
  190. package/dist/integrations/kv.js +69 -0
  191. package/dist/integrations/postgres.d.ts +52 -0
  192. package/dist/integrations/postgres.js +113 -0
  193. package/dist/integrations/sqlite.d.ts +112 -0
  194. package/dist/integrations/sqlite.js +489 -0
  195. package/dist/integrations/vite.d.ts +45 -0
  196. package/dist/integrations/vite.js +111 -0
  197. package/dist/json.d.ts +48 -0
  198. package/dist/json.js +1 -0
  199. package/dist/jsonc.d.ts +1 -0
  200. package/dist/jsonc.js +1 -0
  201. package/dist/kv.d.ts +24 -0
  202. package/dist/kv.js +1 -0
  203. package/dist/mock.d.ts +1 -0
  204. package/dist/mock.js +1 -0
  205. package/dist/names.d.ts +1 -0
  206. package/dist/names.js +1 -0
  207. package/dist/operations.d.ts +3 -0
  208. package/dist/operations.js +3 -0
  209. package/dist/postgres.d.ts +24 -0
  210. package/dist/postgres.js +1 -0
  211. package/dist/redis.d.ts +14 -0
  212. package/dist/redis.js +1 -0
  213. package/dist/rest/formats.d.ts +80 -0
  214. package/dist/rest/formats.js +318 -0
  215. package/dist/rest/handler.d.ts +111 -0
  216. package/dist/rest/handler.js +833 -0
  217. package/dist/rest/shape.d.ts +33 -0
  218. package/dist/rest/shape.js +218 -0
  219. package/dist/schema-builders.d.ts +1 -0
  220. package/dist/schema-builders.js +1 -0
  221. package/dist/schema-manifest.d.ts +1 -0
  222. package/dist/schema-manifest.js +1 -0
  223. package/dist/schema.d.ts +193 -0
  224. package/dist/schema.js +6 -0
  225. package/dist/server.d.ts +116 -0
  226. package/dist/server.js +601 -0
  227. package/dist/shared/csv.d.ts +8 -0
  228. package/dist/shared/csv.js +149 -0
  229. package/dist/shared/errors.d.ts +40 -0
  230. package/dist/shared/errors.js +55 -0
  231. package/dist/shared/fs-utils.d.ts +4 -0
  232. package/dist/shared/fs-utils.js +30 -0
  233. package/dist/shared/jsonc.d.ts +2 -0
  234. package/dist/shared/jsonc.js +99 -0
  235. package/dist/shared/mock.d.ts +40 -0
  236. package/dist/shared/mock.js +83 -0
  237. package/dist/shared/names.d.ts +28 -0
  238. package/dist/shared/names.js +127 -0
  239. package/dist/shared/operations.d.ts +32 -0
  240. package/dist/shared/operations.js +302 -0
  241. package/dist/sqlite.d.ts +24 -0
  242. package/dist/sqlite.js +1 -0
  243. package/dist/state.d.ts +1 -0
  244. package/dist/state.js +1 -0
  245. package/dist/sync.d.ts +1 -0
  246. package/dist/sync.js +1 -0
  247. package/dist/tracing.d.ts +95 -0
  248. package/dist/tracing.js +260 -0
  249. package/dist/types.d.ts +51 -0
  250. package/dist/types.js +285 -0
  251. package/dist/viewer-manifest.d.ts +1 -0
  252. package/dist/viewer-manifest.js +1 -0
  253. package/dist/vite.d.ts +59 -0
  254. package/dist/vite.js +1 -0
  255. package/dist/web/json-viewer.d.ts +5 -0
  256. package/dist/web/json-viewer.js +176 -0
  257. package/dist/web/viewer.d.ts +12 -0
  258. package/dist/web/viewer.js +1015 -0
  259. package/docs/README.md +42 -0
  260. package/docs/architecture.md +112 -0
  261. package/docs/ci-and-release.md +177 -0
  262. package/docs/cms-storage-patterns.md +108 -0
  263. package/docs/concepts.md +141 -0
  264. package/docs/configuration.md +552 -0
  265. package/docs/fixtures-and-schemas.md +527 -0
  266. package/docs/fork-branch-workflows.md +108 -0
  267. package/docs/generated-files.md +174 -0
  268. package/docs/getting-started.md +165 -0
  269. package/docs/integrations.md +206 -0
  270. package/docs/json-production.md +120 -0
  271. package/docs/package-api.md +418 -0
  272. package/docs/prototype-to-production.md +378 -0
  273. package/docs/server-and-viewer.md +466 -0
  274. package/docs/store-graduation.md +120 -0
  275. package/docs/typescript-schema-sources.md +79 -0
  276. package/examples/advanced/README.md +55 -0
  277. package/examples/advanced/db/projects.schema.jsonc +44 -0
  278. package/examples/advanced/db/settings.jsonc +9 -0
  279. package/examples/advanced/db/users.json +23 -0
  280. package/examples/advanced/db/users.schema.mjs +31 -0
  281. package/examples/advanced/db.config.mjs +18 -0
  282. package/examples/advanced/example.json +5 -0
  283. package/examples/advanced/src/generated/db.types.d.ts +64 -0
  284. package/examples/basic/README.md +95 -0
  285. package/examples/basic/db/operations/get-user.jsonc +8 -0
  286. package/examples/basic/db/settings.json +7 -0
  287. package/examples/basic/db/users.schema.jsonc +36 -0
  288. package/examples/basic/db.config.mjs +68 -0
  289. package/examples/basic/example.json +5 -0
  290. package/examples/basic/src/generated/db.types.d.ts +39 -0
  291. package/examples/cms-json-publish/README.md +21 -0
  292. package/examples/cms-json-publish/db/navigation.json +7 -0
  293. package/examples/cms-json-publish/db/pages.json +18 -0
  294. package/examples/cms-json-publish/example.json +5 -0
  295. package/examples/cms-json-publish/src/cms.mjs +104 -0
  296. package/examples/computed-fields/README.md +93 -0
  297. package/examples/computed-fields/db/orders.schema.mjs +62 -0
  298. package/examples/computed-fields/db/posts.schema.mjs +59 -0
  299. package/examples/computed-fields/db/products.schema.mjs +39 -0
  300. package/examples/computed-fields/db/users.schema.mjs +43 -0
  301. package/examples/computed-fields/db.config.mjs +15 -0
  302. package/examples/computed-fields/example.json +5 -0
  303. package/examples/computed-fields/src/generated/db.types.d.ts +81 -0
  304. package/examples/content-collections/README.md +91 -0
  305. package/examples/content-collections/db/authors.json +12 -0
  306. package/examples/content-collections/db/authors.schema.mjs +20 -0
  307. package/examples/content-collections/db/blog/draft-roadmap.mdx +12 -0
  308. package/examples/content-collections/db/blog/index.schema.mjs +61 -0
  309. package/examples/content-collections/db/blog/launch-notes.mdx +15 -0
  310. package/examples/content-collections/db/docs/index.schema.mjs +32 -0
  311. package/examples/content-collections/db/docs/intro.mdx +11 -0
  312. package/examples/content-collections/db/docs/schema-workflow.mdx +10 -0
  313. package/examples/content-collections/db/site.schema.jsonc +21 -0
  314. package/examples/content-collections/db.config.mjs +26 -0
  315. package/examples/content-collections/example.json +5 -0
  316. package/examples/content-collections/src/content-preview.mjs +66 -0
  317. package/examples/content-collections/src/generated/db.types.d.ts +81 -0
  318. package/examples/csv/README.md +52 -0
  319. package/examples/csv/db/customers.csv +4 -0
  320. package/examples/csv/db.config.mjs +13 -0
  321. package/examples/csv/example.json +5 -0
  322. package/examples/data-first/README.md +54 -0
  323. package/examples/data-first/db/posts.json +16 -0
  324. package/examples/data-first/db/settings.json +8 -0
  325. package/examples/data-first/db/users.json +14 -0
  326. package/examples/data-first/db.config.mjs +13 -0
  327. package/examples/data-first/example.json +5 -0
  328. package/examples/diagnostics/README.md +55 -0
  329. package/examples/diagnostics/db/projects.schema.jsonc +27 -0
  330. package/examples/diagnostics/db/users.json +9 -0
  331. package/examples/diagnostics/db/users.schema.jsonc +23 -0
  332. package/examples/diagnostics/db.config.mjs +16 -0
  333. package/examples/diagnostics/example.json +5 -0
  334. package/examples/free-plan-upgrade/README.md +22 -0
  335. package/examples/free-plan-upgrade/db/appSettings.json +4 -0
  336. package/examples/free-plan-upgrade/db/projects.json +7 -0
  337. package/examples/free-plan-upgrade/example.json +5 -0
  338. package/examples/free-plan-upgrade/src/upgrade-tenant-to-paid.mjs +105 -0
  339. package/examples/hono-auth/README.md +74 -0
  340. package/examples/hono-auth/db/pages.schema.jsonc +44 -0
  341. package/examples/hono-auth/db/users.schema.jsonc +42 -0
  342. package/examples/hono-auth/db.config.mjs +17 -0
  343. package/examples/hono-auth/example.json +5 -0
  344. package/examples/hono-auth/package.json +14 -0
  345. package/examples/hono-auth/src/app.mjs +79 -0
  346. package/examples/hono-auth/src/server.mjs +13 -0
  347. package/examples/production-json/README.md +102 -0
  348. package/examples/production-json/db/appSettings.schema.jsonc +41 -0
  349. package/examples/production-json/db/featureFlags.schema.jsonc +84 -0
  350. package/examples/production-json/db/operations/get-control-plane.jsonc +6 -0
  351. package/examples/production-json/db/operations/get-feature-flag.jsonc +9 -0
  352. package/examples/production-json/db/operations/list-feature-flags.jsonc +8 -0
  353. package/examples/production-json/db/operations/read-public-settings.jsonc +8 -0
  354. package/examples/production-json/db.config.mjs +33 -0
  355. package/examples/production-json/example.json +5 -0
  356. package/examples/production-json/src/client-demo.mjs +28 -0
  357. package/examples/production-json/src/generated/db.types.d.ts +60 -0
  358. package/examples/relations/README.md +56 -0
  359. package/examples/relations/db/posts.schema.jsonc +46 -0
  360. package/examples/relations/db/users.schema.jsonc +34 -0
  361. package/examples/relations/db.config.mjs +13 -0
  362. package/examples/relations/example.json +5 -0
  363. package/examples/rest-client/README.md +54 -0
  364. package/examples/rest-client/db/settings.json +5 -0
  365. package/examples/rest-client/db/users.schema.jsonc +42 -0
  366. package/examples/rest-client/db.config.mjs +13 -0
  367. package/examples/rest-client/example.json +5 -0
  368. package/examples/rest-client/src/client-demo.mjs +24 -0
  369. package/examples/schema-first/README.md +55 -0
  370. package/examples/schema-first/db/auditEvents.schema.jsonc +24 -0
  371. package/examples/schema-first/db/settings.schema.jsonc +29 -0
  372. package/examples/schema-first/db/users.schema.jsonc +36 -0
  373. package/examples/schema-first/db.config.mjs +15 -0
  374. package/examples/schema-first/example.json +5 -0
  375. package/examples/schema-first/src/generated/db.types.d.ts +47 -0
  376. package/examples/schema-manifest/README.md +50 -0
  377. package/examples/schema-manifest/db/projects.schema.jsonc +48 -0
  378. package/examples/schema-manifest/db/users.schema.jsonc +35 -0
  379. package/examples/schema-manifest/db.config.mjs +41 -0
  380. package/examples/schema-manifest/example.json +5 -0
  381. package/examples/schema-manifest/src/generated/db.schema.json +130 -0
  382. package/examples/schema-manifest/src/generated/db.types.d.ts +50 -0
  383. package/examples/schema-ui/README.md +103 -0
  384. package/examples/schema-ui/db/pages.schema.jsonc +53 -0
  385. package/examples/schema-ui/db/users.schema.jsonc +30 -0
  386. package/examples/schema-ui/db.config.mjs +55 -0
  387. package/examples/schema-ui/example.json +5 -0
  388. package/examples/schema-ui/src/cms-ssr.mjs +276 -0
  389. package/examples/schema-ui/src/generated/db.schema.json +133 -0
  390. package/examples/schema-ui/src/generated/db.types.d.ts +46 -0
  391. package/examples/schema-ui/src/render-admin.mjs +175 -0
  392. package/examples/schema-ui/src/schema-ui-ssr-handler.mjs +149 -0
  393. package/examples/schema-ui/src/start-schema-ui-server.mjs +140 -0
  394. package/examples/standard-schema/README.md +55 -0
  395. package/examples/standard-schema/db/settings.schema.mjs +22 -0
  396. package/examples/standard-schema/db/users.schema.mjs +72 -0
  397. package/examples/standard-schema/example.json +5 -0
  398. package/package.json +108 -0
@@ -0,0 +1,149 @@
1
+ import {
2
+ renderCollectionListPage,
3
+ renderHomePage,
4
+ renderRecordDetailPage,
5
+ } from './cms-ssr.mjs';
6
+ import { readManifest, renderSchemaUiHtml } from './render-admin.mjs';
7
+
8
+ /**
9
+ * Handles Schema UI SSR routes (`/`, `/templates`, `/cms/...`).
10
+ * Returns true when the response was fully handled (including SSR 404s).
11
+ *
12
+ * @param {import('node:http').IncomingMessage} request
13
+ * @param {import('node:http').ServerResponse} response
14
+ * @param {{ cwd: string; db: object; basePath?: string; manifestUrl: URL }} context
15
+ */
16
+ export async function handleSchemaUiSsrRequest(request, response, context) {
17
+ if (request.method !== 'GET') {
18
+ return false;
19
+ }
20
+
21
+ const host = request.headers.host ?? 'localhost';
22
+ const url = new URL(request.url ?? '/', `http://${host}`);
23
+ const basePath = normalizeBasePath(context.basePath);
24
+ const route = parsePath(url.pathname, basePath);
25
+
26
+ if (!route) {
27
+ return false;
28
+ }
29
+
30
+ try {
31
+ const { db, manifestUrl } = context;
32
+ const manifest = await readManifest(manifestUrl);
33
+
34
+ if (route.type === 'templates') {
35
+ const html = renderSchemaUiHtml(manifest);
36
+ sendHtml(response, html);
37
+ return true;
38
+ }
39
+
40
+ const recordsByCollection = await loadRecordsByCollection(db, manifest);
41
+
42
+ if (route.type === 'home') {
43
+ sendHtml(response, renderHomePage(manifest, recordsByCollection, { basePath }));
44
+ return true;
45
+ }
46
+
47
+ if (route.type === 'list') {
48
+ const html = renderCollectionListPage(manifest, route.collection, recordsByCollection[route.collection] ?? [], { basePath });
49
+ if (!html) {
50
+ response.writeHead(404, { 'content-type': 'text/html; charset=utf-8' });
51
+ response.end('<!doctype html><meta charset="utf-8"><title>404</title><p>Unknown collection</p>');
52
+ return true;
53
+ }
54
+ sendHtml(response, html);
55
+ return true;
56
+ }
57
+
58
+ const record = await db.collection(route.collection).get(route.id);
59
+ const html = renderRecordDetailPage(manifest, route.collection, record, recordsByCollection, { basePath });
60
+ if (!html) {
61
+ response.writeHead(404, { 'content-type': 'text/html; charset=utf-8' });
62
+ response.end('<!doctype html><meta charset="utf-8"><title>404</title><p>Record not found</p>');
63
+ return true;
64
+ }
65
+
66
+ sendHtml(response, html);
67
+ return true;
68
+ } catch (error) {
69
+ const message = error instanceof Error ? error.message : String(error);
70
+ response.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' });
71
+ response.end(message);
72
+ return true;
73
+ }
74
+ }
75
+
76
+ function sendHtml(response, html) {
77
+ response.writeHead(200, {
78
+ 'content-type': 'text/html; charset=utf-8',
79
+ 'cache-control': 'no-store',
80
+ });
81
+ response.end(html);
82
+ }
83
+
84
+ function parsePath(pathname, basePath = '') {
85
+ const strippedPathname = stripBasePath(pathname, basePath);
86
+ if (strippedPathname === null) {
87
+ return null;
88
+ }
89
+
90
+ const normalized = strippedPathname === '' ? '/' : strippedPathname;
91
+ if (normalized === '/' || normalized === '/index.html') {
92
+ return { type: 'home' };
93
+ }
94
+
95
+ if (normalized === '/templates') {
96
+ return { type: 'templates' };
97
+ }
98
+
99
+ const segments = normalized.replace(/^\/+|\/+$/gu, '').split('/').filter(Boolean);
100
+ if (segments[0] === 'cms' && segments.length === 2) {
101
+ return { type: 'list', collection: segments[1] };
102
+ }
103
+
104
+ if (segments[0] === 'cms' && segments.length === 3) {
105
+ return { type: 'detail', collection: segments[1], id: decodeURIComponent(segments[2]) };
106
+ }
107
+
108
+ return null;
109
+ }
110
+
111
+ function stripBasePath(pathname, basePath) {
112
+ const normalizedBasePath = normalizeBasePath(basePath);
113
+ if (!normalizedBasePath) {
114
+ return pathname;
115
+ }
116
+
117
+ if (pathname === normalizedBasePath) {
118
+ return '/';
119
+ }
120
+
121
+ if (pathname.startsWith(`${normalizedBasePath}/`)) {
122
+ return pathname.slice(normalizedBasePath.length) || '/';
123
+ }
124
+
125
+ return null;
126
+ }
127
+
128
+ function normalizeBasePath(basePath) {
129
+ if (!basePath || basePath === '/') {
130
+ return '';
131
+ }
132
+ return `/${String(basePath).replace(/^\/+|\/+$/gu, '')}`;
133
+ }
134
+
135
+ async function loadRecordsByCollection(db, manifest) {
136
+ /** @type {Record<string, unknown[]>} */
137
+ const out = {};
138
+
139
+ for (const name of Object.keys(manifest.collections ?? {})) {
140
+ const meta = manifest.collections[name];
141
+ if (meta?.kind !== 'collection') {
142
+ continue;
143
+ }
144
+
145
+ out[name] = await db.collection(name).all();
146
+ }
147
+
148
+ return out;
149
+ }
@@ -0,0 +1,140 @@
1
+ import http from 'node:http';
2
+ import path from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { openDb } from '../../../dist/index.js';
5
+ import { serializeError } from '../../../dist/errors.js';
6
+ import { sendJson } from '../../../dist/rest/handler.js';
7
+ import {
8
+ createDbRequestHandler,
9
+ createViewerEventHub,
10
+ watchSourceDir,
11
+ } from '../../../dist/server.js';
12
+ import { handleSchemaUiSsrRequest } from './schema-ui-ssr-handler.mjs';
13
+
14
+ /**
15
+ * Schema UI demo runtime: SSR CMS routes composed ahead of the stock db REST / viewer stack.
16
+ *
17
+ * @param {{ cwd: string; basePath?: string; skipSync?: boolean }} options
18
+ */
19
+ export async function createSchemaUiRuntime(options) {
20
+ const {
21
+ cwd,
22
+ basePath = '',
23
+ skipSync = false,
24
+ } = options;
25
+ const normalizedBasePath = normalizeBasePath(basePath);
26
+
27
+ const db = await openDb({
28
+ cwd,
29
+ allowSourceErrors: true,
30
+ syncOnOpen: !skipSync,
31
+ });
32
+
33
+ if (skipSync) {
34
+ await db.runtime.hydrate();
35
+ }
36
+
37
+ const events = createViewerEventHub();
38
+ const dbHandler = createDbRequestHandler(db, {
39
+ events,
40
+ rootRoutes: true,
41
+ apiBase: joinPaths(normalizedBasePath, '/__db'),
42
+ dataPath: joinPaths(normalizedBasePath, '/db'),
43
+ graphqlPath: joinPaths(normalizedBasePath, '/graphql'),
44
+ });
45
+ const manifestUrl = pathToFileURL(path.join(cwd, 'src/generated/db.schema.json'));
46
+ let watcher;
47
+ let closed = false;
48
+
49
+ try {
50
+ watcher = await watchSourceDir(db, events);
51
+ } catch (error) {
52
+ events.close();
53
+ await db.close?.();
54
+ throw error;
55
+ }
56
+
57
+ return {
58
+ db,
59
+ async handleRequest(request, response) {
60
+ try {
61
+ const handled = await handleSchemaUiSsrRequest(request, response, {
62
+ cwd,
63
+ db,
64
+ basePath: normalizedBasePath,
65
+ manifestUrl,
66
+ });
67
+ if (handled) {
68
+ return;
69
+ }
70
+
71
+ await dbHandler(request, response);
72
+ } catch (error) {
73
+ sendJson(response, error.status ?? 500, serializeError(error, 'SERVER_ERROR'));
74
+ }
75
+ },
76
+ async close() {
77
+ if (closed) {
78
+ return;
79
+ }
80
+ closed = true;
81
+ watcher?.close();
82
+ events.close();
83
+ await db.close?.();
84
+ },
85
+ };
86
+ }
87
+
88
+ function normalizeBasePath(basePath) {
89
+ if (!basePath || basePath === '/') {
90
+ return '';
91
+ }
92
+ return `/${String(basePath).replace(/^\/+|\/+$/gu, '')}`;
93
+ }
94
+
95
+ function joinPaths(basePath, childPath) {
96
+ const normalizedBase = normalizeBasePath(basePath);
97
+ const normalizedChild = `/${String(childPath).replace(/^\/+/u, '')}`;
98
+ return `${normalizedBase}${normalizedChild}`;
99
+ }
100
+
101
+ /**
102
+ * Backward-compatible standalone HTTP server wrapper for this example.
103
+ *
104
+ * @param {{ cwd: string; host?: string; port: number; skipSync?: boolean }} options
105
+ */
106
+ export async function startSchemaUiServer(options) {
107
+ const {
108
+ host = '127.0.0.1',
109
+ port,
110
+ } = options;
111
+ const runtime = await createSchemaUiRuntime(options);
112
+ const server = http.createServer((request, response) => {
113
+ runtime.handleRequest(request, response).catch((error) => {
114
+ sendJson(response, error.status ?? 500, serializeError(error, 'SERVER_ERROR'));
115
+ });
116
+ });
117
+
118
+ server.once('close', () => {
119
+ void runtime.close();
120
+ });
121
+
122
+ try {
123
+ await new Promise((resolve, reject) => {
124
+ server.once('error', reject);
125
+ server.listen(port, host, resolve);
126
+ });
127
+ } catch (error) {
128
+ await runtime.close();
129
+ throw error;
130
+ }
131
+
132
+ const address = server.address();
133
+ const boundPort = address && typeof address === 'object' ? address.port : port;
134
+
135
+ return {
136
+ server,
137
+ db: runtime.db,
138
+ url: `http://${host}:${boundPort}`,
139
+ };
140
+ }
@@ -0,0 +1,55 @@
1
+ # Standard Schema Example
2
+
3
+ This example shows the dependency-free integration path for validators that implement the Standard Schema v1 contract. The validator object lives in trusted project code; @async/db imports the schema module, recognizes `~standard.validate`, and calls it during schema helpers and runtime writes without bundling a validator-library dependency.
4
+
5
+ Run it:
6
+
7
+ ```bash
8
+ npm run db -- sync --cwd ./examples/standard-schema
9
+ npm run db -- serve --cwd ./examples/standard-schema
10
+ ```
11
+
12
+ `db/users.schema.mjs` uses a small local Standard Schema-compatible validator. It lowercases email addresses during writes, exposes a Standard JSON Schema converter for field inference, and then layers Async DB metadata on top.
13
+
14
+ You can keep Async DB's object-first schema shape and mix the validator in:
15
+
16
+ ```js
17
+ export default collection({
18
+ validator: UserSchema,
19
+ fields: {
20
+ email: field.string({ required: true, unique: true }),
21
+ displayName: field.computed(field.string(), ({ record }) => record.email),
22
+ },
23
+ });
24
+ ```
25
+
26
+ The validator-first shorthand is also supported when the external schema owns the field shape:
27
+
28
+ ```js
29
+ export default collection(UserSchema, {
30
+ idField: 'id',
31
+ fields: {
32
+ email: field.meta({ unique: true }),
33
+ displayName: field.computed(field.string(), {
34
+ resolveMany({ records }) {
35
+ return new Map(records.map((record) => [
36
+ record.id,
37
+ `${record.firstName} ${record.lastName}`,
38
+ ]));
39
+ },
40
+ }),
41
+ },
42
+ });
43
+ ```
44
+
45
+ `field.meta(...)` is for Async DB metadata such as `unique`, `description`, defaults, relations, and manifest hints. `field.computed(...)` remains the resolver entrypoint, and resolver functions are not written to generated schema or manifest output.
46
+
47
+ The validator can be async. Package API, REST, and GraphQL writes await it and store the returned `value`.
48
+
49
+ ```bash
50
+ npm run db -- create users '{"id":"u_2","email":" GRACE@EXAMPLE.COM ","firstName":"Grace","lastName":"Hopper"}' --cwd ./examples/standard-schema
51
+ ```
52
+
53
+ The stored email becomes `grace@example.com`.
54
+
55
+ `db/settings.schema.mjs` intentionally uses an opaque Standard Schema validator with no JSON Schema converter and no field overlay. In that case generated TypeScript falls back to a conservative index signature, and diagnostics ask you to add `field.meta(...)` overlays or provide a JSON Schema converter when you want richer generated metadata.
@@ -0,0 +1,22 @@
1
+ import { document } from '@async/db/schema';
2
+
3
+ const SettingsSchema = {
4
+ '~standard': {
5
+ version: 1,
6
+ vendor: 'opaque-standard-schema',
7
+ validate(value) {
8
+ return value && typeof value === 'object' && !Array.isArray(value)
9
+ ? { value }
10
+ : { issues: [{ message: 'Expected settings object' }] };
11
+ },
12
+ },
13
+ };
14
+
15
+ export default document(SettingsSchema, {
16
+ seed: {
17
+ theme: 'light',
18
+ flags: {
19
+ preview: true,
20
+ },
21
+ },
22
+ });
@@ -0,0 +1,72 @@
1
+ import { collection, field } from '@async/db/schema';
2
+
3
+ const UserSchema = {
4
+ '~standard': {
5
+ version: 1,
6
+ vendor: 'example-standard-schema',
7
+ async validate(value) {
8
+ await Promise.resolve();
9
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
10
+ return { issues: [{ message: 'Expected an object' }] };
11
+ }
12
+ if (typeof value.email !== 'string' || !value.email.includes('@')) {
13
+ return {
14
+ issues: [
15
+ {
16
+ message: 'Email must include @',
17
+ path: ['email'],
18
+ },
19
+ ],
20
+ };
21
+ }
22
+ return {
23
+ value: {
24
+ ...value,
25
+ email: value.email.trim().toLowerCase(),
26
+ },
27
+ };
28
+ },
29
+ jsonSchema: {
30
+ output() {
31
+ return {
32
+ type: 'object',
33
+ required: ['email', 'firstName', 'lastName'],
34
+ properties: {
35
+ id: { type: 'string' },
36
+ email: { type: 'string', description: 'Email address used for sign-in.' },
37
+ firstName: { type: 'string' },
38
+ lastName: { type: 'string' },
39
+ },
40
+ };
41
+ },
42
+ },
43
+ },
44
+ };
45
+
46
+ export default collection({
47
+ idField: 'id',
48
+ validator: UserSchema,
49
+ fields: {
50
+ email: field.string({
51
+ required: true,
52
+ unique: true,
53
+ description: 'Normalized login email.',
54
+ }),
55
+ displayName: field.computed(field.string(), {
56
+ resolveMany({ records }) {
57
+ return new Map(records.map((record) => [
58
+ record.id,
59
+ `${record.firstName} ${record.lastName}`,
60
+ ]));
61
+ },
62
+ }),
63
+ },
64
+ seed: [
65
+ {
66
+ id: 'u_1',
67
+ email: ' ADA@EXAMPLE.COM ',
68
+ firstName: 'Ada',
69
+ lastName: 'Lovelace',
70
+ },
71
+ ],
72
+ });
@@ -0,0 +1,5 @@
1
+ {
2
+ "title": "Standard Schema",
3
+ "description": "Use any Standard Schema-compatible validator as the resource contract, then layer Async DB metadata and computed fields on top.",
4
+ "tags": ["schema", "validation", "computed"]
5
+ }
package/package.json ADDED
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "@async/db",
3
+ "version": "0.2.0",
4
+ "description": "The Async data workflow package for fixtures, generated types, local APIs, runtime stores, and database-backed graduation.",
5
+ "packageManager": "pnpm@10.20.0",
6
+ "scripts": {
7
+ "build": "tsc -p tsconfig.build.json && cp src/*.d.ts dist/",
8
+ "build:test": "tsc -p tsconfig.test.json",
9
+ "check": "npm run build && npm run build:test && node ./.tmp/test-build/scripts/check-syntax.js",
10
+ "test": "npm run build && npm run build:test && node ./.tmp/test-build/scripts/run-tests.js",
11
+ "release:check": "npm run check && npm test && npm pack --dry-run",
12
+ "release:pack": "npm pack",
13
+ "release:publish": "npm publish --access public",
14
+ "dev": "node ./scripts/tasks/dev.js",
15
+ "watch": "node ./scripts/tasks/watch.js",
16
+ "examples": "npm run build && npm run build:test && node ./.tmp/test-build/scripts/serve-examples.js",
17
+ "view:examples": "npm run examples",
18
+ "cli": "node ./dist/cli.js",
19
+ "db": "npm run build --silent && node ./dist/cli.js",
20
+ "prepack": "npm run build"
21
+ },
22
+ "bin": {
23
+ "async-db": "./dist/cli.js"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "24.12.4",
27
+ "typescript": "6.0.3"
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "default": "./dist/index.js"
33
+ },
34
+ "./schema": {
35
+ "types": "./dist/schema.d.ts",
36
+ "default": "./dist/schema-builders.js"
37
+ },
38
+ "./config": {
39
+ "types": "./dist/config.d.ts",
40
+ "default": "./dist/config-public.js"
41
+ },
42
+ "./client": {
43
+ "types": "./dist/index.d.ts",
44
+ "default": "./dist/client.js"
45
+ },
46
+ "./json": {
47
+ "types": "./dist/json.d.ts",
48
+ "default": "./dist/json.js"
49
+ },
50
+ "./hono": {
51
+ "types": "./dist/hono.d.ts",
52
+ "default": "./dist/hono.js"
53
+ },
54
+ "./sqlite": {
55
+ "types": "./dist/sqlite.d.ts",
56
+ "default": "./dist/sqlite.js"
57
+ },
58
+ "./postgres": {
59
+ "types": "./dist/postgres.d.ts",
60
+ "default": "./dist/postgres.js"
61
+ },
62
+ "./kv": {
63
+ "types": "./dist/kv.d.ts",
64
+ "default": "./dist/kv.js"
65
+ },
66
+ "./redis": {
67
+ "types": "./dist/redis.d.ts",
68
+ "default": "./dist/redis.js"
69
+ },
70
+ "./vite": {
71
+ "types": "./dist/vite.d.ts",
72
+ "default": "./dist/vite.js"
73
+ }
74
+ },
75
+ "files": [
76
+ "dist/**/*.js",
77
+ "dist/**/*.d.ts",
78
+ "!dist/**/*.test.js",
79
+ "examples/*/README.md",
80
+ "examples/*/example.json",
81
+ "examples/*/package.json",
82
+ "examples/*/db/**",
83
+ "examples/*/db.config.mjs",
84
+ "examples/*/src/**",
85
+ "docs/**/*.md",
86
+ "!docs/goals/**",
87
+ "db.config.example.mjs",
88
+ "CHANGELOG.md",
89
+ "README.md",
90
+ "SPEC.md"
91
+ ],
92
+ "type": "module",
93
+ "repository": {
94
+ "type": "git",
95
+ "url": "git+https://github.com/async-framework/async-db.git"
96
+ },
97
+ "bugs": {
98
+ "url": "https://github.com/async-framework/async-db/issues"
99
+ },
100
+ "homepage": "https://github.com/async-framework/async-db#readme",
101
+ "publishConfig": {
102
+ "access": "public"
103
+ },
104
+ "engines": {
105
+ "node": ">=20"
106
+ },
107
+ "license": "MIT"
108
+ }