@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,384 @@
1
+ import path from 'node:path';
2
+ import { resolveFrom, writeText } from '../../fs-utils.js';
3
+ import { loadProjectSchema } from './project.js';
4
+ const FIELD_MANIFEST_PROPERTIES = [
5
+ 'description',
6
+ 'default',
7
+ 'computed',
8
+ 'readOnly',
9
+ 'values',
10
+ 'relation',
11
+ 'unique',
12
+ 'min',
13
+ 'max',
14
+ 'minLength',
15
+ 'maxLength',
16
+ 'pattern',
17
+ 'additionalProperties',
18
+ 'discriminator',
19
+ ];
20
+ const ITEM_MANIFEST_PROPERTIES = [
21
+ 'description',
22
+ 'default',
23
+ 'values',
24
+ 'relation',
25
+ 'unique',
26
+ 'min',
27
+ 'max',
28
+ 'minLength',
29
+ 'maxLength',
30
+ 'pattern',
31
+ 'additionalProperties',
32
+ 'discriminator',
33
+ ];
34
+ export async function generateSchemaManifest(config, options = {}) {
35
+ const project = (options.project ?? await loadProjectSchema(config));
36
+ const manifest = renderSchemaManifest(project.resources, config);
37
+ const content = `${JSON.stringify(manifest, null, 2)}\n`;
38
+ const outFiles = outputFiles(config, options);
39
+ for (const outFile of outFiles) {
40
+ await writeText(outFile, content);
41
+ }
42
+ return {
43
+ manifest,
44
+ content,
45
+ outFiles,
46
+ diagnostics: project.diagnostics,
47
+ };
48
+ }
49
+ export function renderSchemaManifest(resources, config = {}) {
50
+ const diagnostics = [];
51
+ const manifest = {
52
+ version: 1,
53
+ collections: {},
54
+ documents: {},
55
+ };
56
+ for (const resource of resources) {
57
+ const bucket = resource.kind === 'document' ? manifest.documents : manifest.collections;
58
+ bucket[resource.name] = resourceManifest(resource, config, diagnostics);
59
+ }
60
+ if (diagnostics.length > 0) {
61
+ throw manifestDiagnosticsError(diagnostics);
62
+ }
63
+ return manifest;
64
+ }
65
+ function outputFiles(config, options) {
66
+ const outFile = options.outFile
67
+ ? resolveFrom(config.cwd, options.outFile)
68
+ : config.schemaOutFile;
69
+ return outFile ? [outFile] : [];
70
+ }
71
+ function resourceManifest(resource, config, diagnostics) {
72
+ const defaultManifest = {
73
+ kind: resource.kind,
74
+ name: resource.name,
75
+ fields: renderFieldMap(resource.fields ?? {}, resource, config, diagnostics, ''),
76
+ };
77
+ if (resource.description) {
78
+ defaultManifest.description = resource.description;
79
+ }
80
+ if (resource.kind === 'collection') {
81
+ defaultManifest.idField = resource.idField;
82
+ }
83
+ return customizeResourceManifest(resource, config, diagnostics, defaultManifest);
84
+ }
85
+ function customizeResourceManifest(resource, config, diagnostics, defaultManifest) {
86
+ const customizeResource = config.schemaManifest?.customizeResource;
87
+ const sourceFile = resource.schemaPath ?? resource.dataPath ?? null;
88
+ if (typeof customizeResource !== 'function') {
89
+ return defaultManifest;
90
+ }
91
+ let customized;
92
+ try {
93
+ customized = customizeResource({
94
+ resource,
95
+ resourceName: resource.name,
96
+ file: sourceFile ? path.relative(config.cwd, sourceFile) : null,
97
+ sourceFile,
98
+ defaultManifest: structuredClone(defaultManifest),
99
+ });
100
+ }
101
+ catch (error) {
102
+ diagnostics.push({
103
+ code: 'SCHEMA_MANIFEST_RESOURCE_CUSTOMIZE_FAILED',
104
+ severity: 'error',
105
+ resource: resource.name,
106
+ message: `Could not customize schema manifest resource "${resource.name}": ${error.message}`,
107
+ hint: 'Update schemaManifest.customizeResource so it returns a JSON-serializable resource manifest.',
108
+ details: {
109
+ resource: resource.name,
110
+ },
111
+ });
112
+ return defaultManifest;
113
+ }
114
+ const serializablePath = firstNonSerializablePath(customized);
115
+ if (serializablePath) {
116
+ diagnostics.push(nonSerializableResourceDiagnostic(resource, serializablePath));
117
+ return defaultManifest;
118
+ }
119
+ return customized;
120
+ }
121
+ function renderFieldMap(fields, resource, config, diagnostics, parentPath) {
122
+ const output = {};
123
+ for (const [fieldName, field] of Object.entries(fields)) {
124
+ const fieldPath = parentPath ? `${parentPath}.${fieldName}` : fieldName;
125
+ const fieldManifest = renderFieldManifest(fieldName, field, resource, config, diagnostics, fieldPath);
126
+ if (fieldManifest !== null) {
127
+ output[fieldName] = fieldManifest;
128
+ }
129
+ }
130
+ return output;
131
+ }
132
+ function renderFieldManifest(fieldName, field, resource, config, diagnostics, fieldPath) {
133
+ const defaultManifest = defaultFieldManifest(fieldName, field, resource, config, diagnostics, fieldPath);
134
+ const customizeField = config.schemaManifest?.customizeField;
135
+ const sourceFile = resource.schemaPath ?? resource.dataPath ?? null;
136
+ if (typeof customizeField !== 'function') {
137
+ return defaultManifest;
138
+ }
139
+ let customized;
140
+ try {
141
+ customized = customizeField({
142
+ field,
143
+ fieldName,
144
+ resource,
145
+ resourceName: resource.name,
146
+ path: fieldPath,
147
+ file: sourceFile ? path.relative(config.cwd, sourceFile) : null,
148
+ sourceFile,
149
+ defaultManifest: structuredClone(defaultManifest),
150
+ });
151
+ }
152
+ catch (error) {
153
+ diagnostics.push({
154
+ code: 'SCHEMA_MANIFEST_FIELD_CUSTOMIZE_FAILED',
155
+ severity: 'error',
156
+ resource: resource.name,
157
+ field: fieldPath,
158
+ message: `Could not customize schema manifest field "${resource.name}.${fieldPath}": ${error.message}`,
159
+ hint: 'Update schemaManifest.customizeField so it returns a JSON-serializable field manifest or null.',
160
+ details: {
161
+ resource: resource.name,
162
+ field: fieldPath,
163
+ },
164
+ });
165
+ return defaultManifest;
166
+ }
167
+ if (customized === null) {
168
+ return null;
169
+ }
170
+ const serializablePath = firstNonSerializablePath(customized);
171
+ if (serializablePath) {
172
+ diagnostics.push(nonSerializableDiagnostic(resource, fieldPath, serializablePath));
173
+ return defaultManifest;
174
+ }
175
+ return customized;
176
+ }
177
+ function defaultFieldManifest(fieldName, field, resource, config, diagnostics, fieldPath) {
178
+ const manifest = {
179
+ type: field.type ?? 'unknown',
180
+ required: Boolean(field.required),
181
+ nullable: Boolean(field.nullable),
182
+ };
183
+ for (const property of FIELD_MANIFEST_PROPERTIES) {
184
+ if (property in field) {
185
+ manifest[property] = structuredClone(field[property]);
186
+ }
187
+ }
188
+ if (field.type === 'array') {
189
+ manifest.items = itemManifest(field.items ?? { type: 'unknown' }, resource, config, diagnostics, fieldPath);
190
+ }
191
+ if (field.type === 'object' && field.fields && typeof field.fields === 'object') {
192
+ manifest.fields = renderFieldMap(field.fields, resource, config, diagnostics, fieldPath);
193
+ }
194
+ if (field.type === 'object' && field.variants && typeof field.variants === 'object') {
195
+ manifest.variants = variantManifestMap(field.variants, resource, config, diagnostics, fieldPath);
196
+ }
197
+ manifest.ui = inferFieldUi(fieldName, field, resource, fieldPath);
198
+ return manifest;
199
+ }
200
+ function itemManifest(field, resource, config, diagnostics, fieldPath) {
201
+ const manifest = {
202
+ type: field.type ?? 'unknown',
203
+ required: Boolean(field.required),
204
+ nullable: Boolean(field.nullable),
205
+ };
206
+ for (const property of ITEM_MANIFEST_PROPERTIES) {
207
+ if (property in field) {
208
+ manifest[property] = structuredClone(field[property]);
209
+ }
210
+ }
211
+ if (field.type === 'array') {
212
+ manifest.items = itemManifest(field.items ?? { type: 'unknown' }, resource, config, diagnostics, fieldPath);
213
+ }
214
+ if (field.type === 'object' && field.fields && typeof field.fields === 'object') {
215
+ manifest.fields = renderFieldMap(field.fields, resource, config, diagnostics, fieldPath);
216
+ }
217
+ if (field.type === 'object' && field.variants && typeof field.variants === 'object') {
218
+ manifest.variants = variantManifestMap(field.variants, resource, config, diagnostics, fieldPath);
219
+ }
220
+ return manifest;
221
+ }
222
+ function variantManifestMap(variants, resource, config, diagnostics, fieldPath) {
223
+ return Object.fromEntries(Object.entries(variants).map(([variantName, variant]) => {
224
+ const manifest = {
225
+ fields: renderFieldMap(variant.fields ?? {}, resource, config, diagnostics, `${fieldPath}.${variantName}`),
226
+ };
227
+ if ('additionalProperties' in variant) {
228
+ manifest.additionalProperties = Boolean(variant.additionalProperties);
229
+ }
230
+ return [variantName, manifest];
231
+ }));
232
+ }
233
+ function inferFieldUi(fieldName, field, resource, fieldPath) {
234
+ const ui = {
235
+ label: labelFromFieldName(fieldName),
236
+ component: componentForField(fieldName, field),
237
+ };
238
+ if ((resource.kind === 'collection' && fieldPath === resource.idField) || field.readOnly) {
239
+ ui.readonly = true;
240
+ }
241
+ if (field.relation?.to) {
242
+ ui.optionsFrom = field.relation.to;
243
+ }
244
+ return ui;
245
+ }
246
+ function componentForField(fieldName, field) {
247
+ if (field.relation) {
248
+ return 'relationSelect';
249
+ }
250
+ switch (field.type) {
251
+ case 'boolean':
252
+ return 'toggle';
253
+ case 'enum':
254
+ return Array.isArray(field.values) && field.values.length > 0 && field.values.length <= 3
255
+ ? 'radio'
256
+ : 'select';
257
+ case 'datetime':
258
+ return 'datetime';
259
+ case 'number':
260
+ return 'number';
261
+ case 'array':
262
+ return componentForArray(field.items);
263
+ case 'object':
264
+ return field.fields && Object.keys(field.fields).length > 0 ? 'fieldset' : 'json';
265
+ case 'string':
266
+ return componentForString(fieldName, field);
267
+ default:
268
+ return 'json';
269
+ }
270
+ }
271
+ function componentForArray(itemField = { type: 'unknown' }) {
272
+ if (itemField.type === 'enum') {
273
+ return 'multiSelect';
274
+ }
275
+ if (itemField.type === 'string') {
276
+ return 'tags';
277
+ }
278
+ return 'list';
279
+ }
280
+ function componentForString(fieldName, field) {
281
+ const normalized = normalizeName(fieldName);
282
+ if (/(^|[^a-z])email([^a-z]|$)/.test(normalized) || normalized.endsWith('email')) {
283
+ return 'email';
284
+ }
285
+ if (/(image|avatar|photo|picture|thumbnail|logo|icon)/.test(normalized)) {
286
+ return 'image';
287
+ }
288
+ if (/(^|[^a-z])(url|uri|website|link)([^a-z]|$)/.test(normalized) || normalized.endsWith('url')) {
289
+ return 'url';
290
+ }
291
+ if (/(description|body|content|notes|note|bio|summary|markdown)/.test(normalized)) {
292
+ return 'textarea';
293
+ }
294
+ const maxLength = field.maxLength;
295
+ if (typeof maxLength === 'number' && Number.isFinite(maxLength) && maxLength >= 240) {
296
+ return 'textarea';
297
+ }
298
+ return 'text';
299
+ }
300
+ function normalizeName(fieldName) {
301
+ return String(fieldName)
302
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
303
+ .replace(/[_-]+/g, ' ')
304
+ .toLowerCase();
305
+ }
306
+ function labelFromFieldName(fieldName) {
307
+ const words = normalizeName(fieldName)
308
+ .split(/\s+/)
309
+ .filter(Boolean);
310
+ if (words.length === 0) {
311
+ return String(fieldName);
312
+ }
313
+ return words.map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(' ');
314
+ }
315
+ function firstNonSerializablePath(value, currentPath = '') {
316
+ if (value === null) {
317
+ return null;
318
+ }
319
+ const valueType = typeof value;
320
+ if (valueType === 'string' || valueType === 'boolean') {
321
+ return null;
322
+ }
323
+ if (valueType === 'number') {
324
+ return Number.isFinite(value) ? null : currentPath || '<root>';
325
+ }
326
+ if (valueType === 'undefined' || valueType === 'function' || valueType === 'symbol' || valueType === 'bigint') {
327
+ return currentPath || '<root>';
328
+ }
329
+ if (Array.isArray(value)) {
330
+ for (let index = 0; index < value.length; index += 1) {
331
+ const childPath = firstNonSerializablePath(value[index], `${currentPath}[${index}]`);
332
+ if (childPath) {
333
+ return childPath;
334
+ }
335
+ }
336
+ return null;
337
+ }
338
+ if (typeof value === 'object') {
339
+ const prototype = Object.getPrototypeOf(value);
340
+ if (prototype !== Object.prototype && prototype !== null) {
341
+ return currentPath || '<root>';
342
+ }
343
+ for (const [key, childValue] of Object.entries(value)) {
344
+ const childPath = firstNonSerializablePath(childValue, currentPath ? `${currentPath}.${key}` : key);
345
+ if (childPath) {
346
+ return childPath;
347
+ }
348
+ }
349
+ }
350
+ return null;
351
+ }
352
+ function nonSerializableDiagnostic(resource, fieldPath, serializablePath) {
353
+ return {
354
+ code: 'SCHEMA_MANIFEST_FIELD_NOT_SERIALIZABLE',
355
+ severity: 'error',
356
+ resource: resource.name,
357
+ field: fieldPath,
358
+ message: `schemaManifest.customizeField returned non-serializable output for "${resource.name}.${fieldPath}" at "${serializablePath}".`,
359
+ hint: 'Return JSON-serializable values such as strings, numbers, booleans, arrays, plain objects, null, or return null to omit the field.',
360
+ details: {
361
+ resource: resource.name,
362
+ field: fieldPath,
363
+ path: serializablePath,
364
+ },
365
+ };
366
+ }
367
+ function nonSerializableResourceDiagnostic(resource, serializablePath) {
368
+ return {
369
+ code: 'SCHEMA_MANIFEST_RESOURCE_NOT_SERIALIZABLE',
370
+ severity: 'error',
371
+ resource: resource.name,
372
+ message: `schemaManifest.customizeResource returned non-serializable output for "${resource.name}" at "${serializablePath}".`,
373
+ hint: 'Return JSON-serializable values such as strings, numbers, booleans, arrays, plain objects, null, or omit the custom resource hook.',
374
+ details: {
375
+ resource: resource.name,
376
+ path: serializablePath,
377
+ },
378
+ };
379
+ }
380
+ function manifestDiagnosticsError(diagnostics) {
381
+ const error = new Error(diagnostics.map((diagnostic) => diagnostic.message).join('\n'));
382
+ error.diagnostics = diagnostics;
383
+ return error;
384
+ }
@@ -0,0 +1,30 @@
1
+ export type SchemaField = {
2
+ type?: string;
3
+ required?: boolean;
4
+ description?: string;
5
+ [key: string]: unknown;
6
+ };
7
+ export type SchemaResource = {
8
+ kind?: 'collection' | 'document' | string;
9
+ name: string;
10
+ typeName: string;
11
+ routePath: string;
12
+ idField?: string;
13
+ fields: Record<string, SchemaField>;
14
+ [key: string]: unknown;
15
+ };
16
+ export type SchemaDiagnostic = {
17
+ code?: string;
18
+ severity?: string;
19
+ message?: string;
20
+ [key: string]: unknown;
21
+ };
22
+ export type GeneratedSchemaMetadataContext = {
23
+ resources: SchemaResource[];
24
+ diagnostics: SchemaDiagnostic[];
25
+ };
26
+ export type GeneratedSchemaMetadataContributor = (context: GeneratedSchemaMetadataContext) => Record<string, unknown> | null | undefined;
27
+ export declare function generatedSchemaMetadata(resources: SchemaResource[], diagnostics: SchemaDiagnostic[], contributors?: GeneratedSchemaMetadataContributor[]): Record<string, unknown>;
28
+ export declare function defaultGeneratedSchemaMetadataContributors(): GeneratedSchemaMetadataContributor[];
29
+ export declare function restSchemaMetadata({ resources }: GeneratedSchemaMetadataContext): Record<string, unknown>;
30
+ export declare function graphqlSchemaMetadata({ resources }: GeneratedSchemaMetadataContext): Record<string, unknown>;
@@ -0,0 +1,75 @@
1
+ export function generatedSchemaMetadata(resources, diagnostics, contributors = defaultGeneratedSchemaMetadataContributors()) {
2
+ return Object.assign({}, ...contributors.map((contributor) => contributor({ resources, diagnostics }) ?? {}));
3
+ }
4
+ export function defaultGeneratedSchemaMetadataContributors() {
5
+ return [
6
+ restSchemaMetadata,
7
+ graphqlSchemaMetadata,
8
+ ];
9
+ }
10
+ export function restSchemaMetadata({ resources }) {
11
+ return {
12
+ rest: Object.fromEntries(resources.map((resource) => [resource.name, restRoutes(resource)])),
13
+ };
14
+ }
15
+ export function graphqlSchemaMetadata({ resources }) {
16
+ return {
17
+ graphql: generateGraphqlSdl(resources),
18
+ };
19
+ }
20
+ function restRoutes(resource) {
21
+ if (resource.kind === 'document') {
22
+ return [
23
+ `GET ${resource.routePath}`,
24
+ `PUT ${resource.routePath}`,
25
+ `PATCH ${resource.routePath}`,
26
+ ];
27
+ }
28
+ return [
29
+ `GET ${resource.routePath}`,
30
+ `GET ${resource.routePath}/:${resource.idField}`,
31
+ `POST ${resource.routePath}`,
32
+ `PATCH ${resource.routePath}/:${resource.idField}`,
33
+ `DELETE ${resource.routePath}/:${resource.idField}`,
34
+ ];
35
+ }
36
+ function generateGraphqlSdl(resources) {
37
+ const lines = ['scalar JSON', ''];
38
+ for (const resource of resources) {
39
+ lines.push(...graphqlType(resource), '');
40
+ }
41
+ return lines.join('\n').trimEnd();
42
+ }
43
+ function graphqlType(resource) {
44
+ const lines = [`type ${resource.typeName} {`];
45
+ for (const [fieldName, field] of Object.entries(resource.fields)) {
46
+ if (field.description) {
47
+ lines.push(` "${String(field.description).replaceAll('"', '\\"')}"`);
48
+ }
49
+ lines.push(` ${fieldName}: ${graphqlFieldType(field, fieldName === resource.idField)}`);
50
+ }
51
+ lines.push('}');
52
+ return lines;
53
+ }
54
+ function graphqlFieldType(field, isIdField = false) {
55
+ if (isIdField) {
56
+ return field.required ? 'ID!' : 'ID';
57
+ }
58
+ const suffix = field.required ? '!' : '';
59
+ switch (field.type) {
60
+ case 'string':
61
+ case 'datetime':
62
+ case 'enum':
63
+ return `String${suffix}`;
64
+ case 'number':
65
+ return `Float${suffix}`;
66
+ case 'boolean':
67
+ return `Boolean${suffix}`;
68
+ case 'array':
69
+ return `[JSON]${suffix}`;
70
+ case 'object':
71
+ case 'unknown':
72
+ default:
73
+ return `JSON${suffix}`;
74
+ }
75
+ }
@@ -0,0 +1,46 @@
1
+ import { buildResource } from './resource.js';
2
+ type SchemaDiagnostic = {
3
+ code: string;
4
+ severity: 'error' | 'warn' | 'info';
5
+ resource?: string;
6
+ field?: string;
7
+ file?: string;
8
+ message: string;
9
+ hint?: string;
10
+ details?: unknown;
11
+ [key: string]: unknown;
12
+ };
13
+ type SchemaLoadMode = 'data' | 'schema' | 'runtime' | string;
14
+ type SchemaLocator = {
15
+ mode?: string;
16
+ file?: string;
17
+ [key: string]: unknown;
18
+ };
19
+ type ProjectConfig = {
20
+ cwd?: string;
21
+ sourceDir?: string;
22
+ schemaLoadMode?: SchemaLoadMode;
23
+ schemaLocator?: SchemaLocator | null;
24
+ schema?: {
25
+ source?: string;
26
+ unknownFields?: string;
27
+ [key: string]: unknown;
28
+ };
29
+ [key: string]: unknown;
30
+ };
31
+ type ProjectResource = ReturnType<typeof buildResource>;
32
+ type ProjectResult = {
33
+ resources: ProjectResource[];
34
+ diagnostics: SchemaDiagnostic[];
35
+ schema: unknown;
36
+ loadMode: SchemaLoadMode;
37
+ locator: SchemaLocator | null;
38
+ rootSchema: {
39
+ found: boolean;
40
+ file: string | null;
41
+ };
42
+ };
43
+ export declare function loadProjectSchema(config: ProjectConfig, options?: {
44
+ load?: SchemaLoadMode;
45
+ }): Promise<ProjectResult>;
46
+ export {};