@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,302 @@
1
+ import { dbError } from './errors.js';
2
+ const HTTP_METHODS = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
3
+ export function normalizeOperationTemplate(input) {
4
+ if (typeof input === 'string') {
5
+ return normalizeStringOperation(input);
6
+ }
7
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
8
+ throw dbError('OPERATION_INVALID_TEMPLATE', 'Registered operation must be a REST or GraphQL template.', {
9
+ hint: 'Use "/users/{id}.json?select=id,name", { method: "GET", path: "/users/{id}.json", query: { select: "id,name" } }, or { query: "{ users { id } }" }.',
10
+ });
11
+ }
12
+ const template = input;
13
+ if (template.ref && !template.path && !template.query) {
14
+ return {
15
+ name: stringValue(template.name),
16
+ ref: String(template.ref),
17
+ };
18
+ }
19
+ if (template.kind === 'graphql' || isGraphqlTemplateObject(template)) {
20
+ return normalizeGraphqlOperation(template);
21
+ }
22
+ const method = normalizeMethod(template.method ?? 'GET');
23
+ const operationPath = normalizePath(template.path ?? '/');
24
+ const query = normalizeQuery(template.query);
25
+ const normalized = {
26
+ method,
27
+ path: operationPath,
28
+ };
29
+ if (template.name) {
30
+ normalized.name = String(template.name);
31
+ }
32
+ if (template.ref) {
33
+ normalized.ref = String(template.ref);
34
+ }
35
+ if (query && Object.keys(query).length > 0) {
36
+ normalized.query = query;
37
+ }
38
+ if ('body' in template) {
39
+ normalized.body = template.body;
40
+ }
41
+ if (template.variables && typeof template.variables === 'object' && !Array.isArray(template.variables)) {
42
+ normalized.variables = stableObject(template.variables);
43
+ }
44
+ return normalized;
45
+ }
46
+ export function canonicalOperation(input) {
47
+ const operation = normalizeOperationTemplate(input);
48
+ if (operation.kind === 'graphql') {
49
+ const canonical = {
50
+ kind: 'graphql',
51
+ query: String(operation.query ?? ''),
52
+ };
53
+ if (operation.operationName) {
54
+ canonical.operationName = operation.operationName;
55
+ }
56
+ if (operation.variables) {
57
+ canonical.variables = stableObject(operation.variables);
58
+ }
59
+ return canonical;
60
+ }
61
+ const canonical = {
62
+ method: operation.method,
63
+ path: operation.path,
64
+ };
65
+ if (operation.query) {
66
+ canonical.query = typeof operation.query === 'string'
67
+ ? operation.query
68
+ : stableObject(operation.query);
69
+ }
70
+ if ('body' in operation) {
71
+ canonical.body = operation.body;
72
+ }
73
+ return canonical;
74
+ }
75
+ export function operationRequest(input, variables = {}) {
76
+ const operation = normalizeOperationTemplate(input);
77
+ if (operation.ref && !operation.path && operation.kind !== 'graphql') {
78
+ return {
79
+ ref: operation.ref,
80
+ };
81
+ }
82
+ if (operation.kind === 'graphql') {
83
+ return graphqlOperationRequest(operation, variables);
84
+ }
85
+ const placeholders = placeholdersForOperation(operation);
86
+ const provided = Object.keys(variables ?? {});
87
+ const missing = [...placeholders].filter((name) => !(name in (variables ?? {})));
88
+ const extra = provided.filter((name) => !placeholders.has(name));
89
+ if (missing.length > 0) {
90
+ throw dbError('OPERATION_VARIABLE_MISSING', `Operation is missing variable "${missing[0]}".`, {
91
+ status: 400,
92
+ hint: `Pass variables for: ${[...placeholders].join(', ')}.`,
93
+ details: { missing, expectedVariables: [...placeholders] },
94
+ });
95
+ }
96
+ if (extra.length > 0) {
97
+ throw dbError('OPERATION_VARIABLE_UNKNOWN', `Operation received unknown variable "${extra[0]}".`, {
98
+ status: 400,
99
+ hint: `Only pass variables used by this operation: ${[...placeholders].join(', ')}.`,
100
+ details: { extra, expectedVariables: [...placeholders] },
101
+ });
102
+ }
103
+ const operationPath = substitutePath(String(operation.path ?? '/'), variables);
104
+ const query = substituteValue(operation.query ?? {}, variables);
105
+ const body = 'body' in operation ? substituteValue(operation.body, variables) : undefined;
106
+ return {
107
+ method: operation.method,
108
+ path: pathWithQuery(operationPath, query),
109
+ body,
110
+ };
111
+ }
112
+ export function stableStringify(value) {
113
+ if (Array.isArray(value)) {
114
+ return `[${value.map(stableStringify).join(',')}]`;
115
+ }
116
+ if (value && typeof value === 'object') {
117
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`).join(',')}}`;
118
+ }
119
+ return JSON.stringify(value);
120
+ }
121
+ function normalizeStringOperation(input) {
122
+ const trimmed = input.trim();
123
+ const [maybeMethod, ...rest] = trimmed.split(/\s+/);
124
+ const hasMethod = HTTP_METHODS.has(maybeMethod.toUpperCase());
125
+ const method = hasMethod ? maybeMethod.toUpperCase() : 'GET';
126
+ const target = hasMethod ? rest.join(' ') : trimmed;
127
+ const url = new URL(target, 'http://db.local');
128
+ const query = Object.fromEntries([...url.searchParams.entries()].sort(([left], [right]) => left.localeCompare(right)));
129
+ const normalized = {
130
+ method,
131
+ path: normalizePath(decodeURIComponent(url.pathname)),
132
+ };
133
+ if (Object.keys(query).length > 0) {
134
+ normalized.query = query;
135
+ }
136
+ return normalized;
137
+ }
138
+ function normalizeGraphqlOperation(input) {
139
+ if (typeof input.query !== 'string' || input.query.trim() === '') {
140
+ throw dbError('OPERATION_INVALID_GRAPHQL_QUERY', 'GraphQL operation query must be a non-empty string.', {
141
+ status: 400,
142
+ hint: 'Use { query: "query GetUser { users { id } }" }.',
143
+ });
144
+ }
145
+ const normalized = {
146
+ kind: 'graphql',
147
+ query: input.query,
148
+ };
149
+ if (input.name) {
150
+ normalized.name = String(input.name);
151
+ }
152
+ if (input.ref) {
153
+ normalized.ref = String(input.ref);
154
+ }
155
+ if (input.operationName !== undefined && input.operationName !== null) {
156
+ normalized.operationName = String(input.operationName);
157
+ }
158
+ if (input.variables !== undefined) {
159
+ if (!input.variables || typeof input.variables !== 'object' || Array.isArray(input.variables)) {
160
+ throw dbError('OPERATION_INVALID_GRAPHQL_VARIABLES', 'GraphQL operation variables must be an object.', {
161
+ status: 400,
162
+ hint: 'Use variables such as { id: "{id}" }.',
163
+ });
164
+ }
165
+ normalized.variables = stableObject(input.variables);
166
+ }
167
+ return normalized;
168
+ }
169
+ function isGraphqlTemplateObject(input) {
170
+ return !input.path && typeof input.query === 'string' && !input.method && !('body' in input);
171
+ }
172
+ function graphqlOperationRequest(operation, variables = {}) {
173
+ const placeholders = new Set();
174
+ if (operation.variables) {
175
+ collectPlaceholders(operation.variables, placeholders);
176
+ }
177
+ const provided = Object.keys(variables ?? {});
178
+ const missing = [...placeholders].filter((name) => !(name in (variables ?? {})));
179
+ const extra = operation.variables
180
+ ? provided.filter((name) => placeholders.size > 0 && !placeholders.has(name))
181
+ : [];
182
+ if (missing.length > 0) {
183
+ throw dbError('OPERATION_VARIABLE_MISSING', `Operation is missing variable "${missing[0]}".`, {
184
+ status: 400,
185
+ hint: `Pass variables for: ${[...placeholders].join(', ')}.`,
186
+ details: { missing, expectedVariables: [...placeholders] },
187
+ });
188
+ }
189
+ if (extra.length > 0) {
190
+ throw dbError('OPERATION_VARIABLE_UNKNOWN', `Operation received unknown variable "${extra[0]}".`, {
191
+ status: 400,
192
+ hint: `Only pass variables used by this operation: ${[...placeholders].join(', ')}.`,
193
+ details: { extra, expectedVariables: [...placeholders] },
194
+ });
195
+ }
196
+ return {
197
+ kind: 'graphql',
198
+ query: String(operation.query ?? ''),
199
+ variables: operation.variables ? substituteValue(operation.variables, variables) : (variables ?? {}),
200
+ operationName: operation.operationName ?? null,
201
+ };
202
+ }
203
+ function normalizeMethod(value) {
204
+ const method = String(value ?? 'GET').toUpperCase();
205
+ if (!HTTP_METHODS.has(method)) {
206
+ throw dbError('OPERATION_UNSUPPORTED_METHOD', `Operation method "${method}" is not supported.`, {
207
+ status: 400,
208
+ hint: 'Use GET, POST, PUT, PATCH, or DELETE.',
209
+ details: { method },
210
+ });
211
+ }
212
+ return method;
213
+ }
214
+ function normalizePath(value) {
215
+ const path = String(value ?? '/');
216
+ return path.startsWith('/') ? path : `/${path}`;
217
+ }
218
+ function normalizeQuery(value) {
219
+ if (value === undefined || value === null) {
220
+ return undefined;
221
+ }
222
+ if (typeof value === 'string') {
223
+ return Object.fromEntries([...new URLSearchParams(value).entries()].sort(([left], [right]) => left.localeCompare(right)));
224
+ }
225
+ if (typeof value === 'object' && !Array.isArray(value)) {
226
+ return stableObject(value);
227
+ }
228
+ throw dbError('OPERATION_INVALID_QUERY', 'Operation query must be an object or query string.', {
229
+ status: 400,
230
+ hint: 'Use { select: "id,name" } or "select=id,name".',
231
+ });
232
+ }
233
+ function stableObject(value) {
234
+ return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
235
+ }
236
+ function placeholdersForOperation(operation) {
237
+ const names = new Set();
238
+ collectPlaceholders(operation.path, names);
239
+ collectPlaceholders(operation.query, names);
240
+ collectPlaceholders(operation.body, names);
241
+ return names;
242
+ }
243
+ function collectPlaceholders(value, names) {
244
+ if (typeof value === 'string') {
245
+ for (const match of value.matchAll(/\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g)) {
246
+ names.add(match[1] ?? match[2]);
247
+ }
248
+ return;
249
+ }
250
+ if (Array.isArray(value)) {
251
+ for (const item of value) {
252
+ collectPlaceholders(item, names);
253
+ }
254
+ return;
255
+ }
256
+ if (value && typeof value === 'object') {
257
+ for (const item of Object.values(value)) {
258
+ collectPlaceholders(item, names);
259
+ }
260
+ }
261
+ }
262
+ function substitutePath(path, variables) {
263
+ return path.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_match, name) => encodeURIComponent(String(variables[name])));
264
+ }
265
+ function substituteValue(value, variables) {
266
+ if (typeof value === 'string') {
267
+ const exactVariable = value.match(/^\$([A-Za-z_][A-Za-z0-9_]*)$/) ?? value.match(/^\{([A-Za-z_][A-Za-z0-9_]*)\}$/);
268
+ if (exactVariable) {
269
+ return variables[exactVariable[1]];
270
+ }
271
+ return value
272
+ .replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_match, name) => String(variables[name]))
273
+ .replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (_match, name) => String(variables[name]));
274
+ }
275
+ if (Array.isArray(value)) {
276
+ return value.map((item) => substituteValue(item, variables));
277
+ }
278
+ if (value && typeof value === 'object') {
279
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, substituteValue(item, variables)]));
280
+ }
281
+ return value;
282
+ }
283
+ function pathWithQuery(path, query) {
284
+ const entries = Object.entries(query ?? {}).filter(([, value]) => value !== undefined);
285
+ if (entries.length === 0) {
286
+ return path;
287
+ }
288
+ const params = new URLSearchParams();
289
+ for (const [key, value] of entries) {
290
+ if (Array.isArray(value)) {
291
+ for (const item of value) {
292
+ params.append(key, String(item));
293
+ }
294
+ continue;
295
+ }
296
+ params.set(key, String(value));
297
+ }
298
+ return `${path}?${params.toString().replaceAll('%2C', ',')}`;
299
+ }
300
+ function stringValue(value) {
301
+ return value === undefined || value === null ? undefined : String(value);
302
+ }
@@ -0,0 +1,24 @@
1
+ import type { DbOptions, Db } from './index.d.ts';
2
+
3
+ export type SqliteDbOptions = DbOptions & {
4
+ file?: string;
5
+ storage?: {
6
+ kind?: 'sqlite';
7
+ file?: string;
8
+ };
9
+ };
10
+
11
+ export function openSqliteDb(options?: SqliteDbOptions): Promise<Db>;
12
+ export function sqliteStore(options?: { file?: string }): unknown;
13
+ export const sqliteStoreCapabilities: {
14
+ writable: true;
15
+ persistence: 'local-sqlite';
16
+ atomicity: 'resource';
17
+ liveEvents: true;
18
+ staticExport: false;
19
+ production: 'small-local';
20
+ };
21
+ export function migrateSqliteDb(database: unknown, resources: unknown[]): void;
22
+ export class SqliteDb {}
23
+ export class SqliteDbCollection {}
24
+ export class SqliteDbDocument {}
package/dist/sqlite.js ADDED
@@ -0,0 +1 @@
1
+ export { migrateSqliteDb, openSqliteDb, sqliteStore, sqliteStoreCapabilities, SqliteDb, SqliteDbCollection, SqliteDbDocument, } from './integrations/sqlite.js';
@@ -0,0 +1 @@
1
+ export { readJsonState, statePathForResource, withJsonStateWrite, writeJsonState } from './features/runtime/state.js';
package/dist/state.js ADDED
@@ -0,0 +1 @@
1
+ export { readJsonState, statePathForResource, withJsonStateWrite, writeJsonState } from './features/runtime/state.js';
package/dist/sync.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { applyDefaultsToRecord, applyDefaultsToSeed, syncDb, } from './features/sync/index.js';
package/dist/sync.js ADDED
@@ -0,0 +1 @@
1
+ export { applyDefaultsToRecord, applyDefaultsToSeed, syncDb, } from './features/sync/index.js';
@@ -0,0 +1,95 @@
1
+ type TraceConfig = {
2
+ enabled?: boolean;
3
+ slowMs?: number;
4
+ console?: boolean;
5
+ events?: boolean;
6
+ header?: string;
7
+ };
8
+ type TraceSource = boolean | TraceConfig | null | undefined;
9
+ type ResolvedTraceOptions = {
10
+ enabled: true;
11
+ slowMs: number;
12
+ console: boolean;
13
+ events: boolean;
14
+ header: string;
15
+ };
16
+ type TraceDetails = Record<string, unknown>;
17
+ type TracePhase = TraceDetails & {
18
+ name: string;
19
+ durationMs: number;
20
+ };
21
+ type TraceError = {
22
+ code: string;
23
+ message: string;
24
+ };
25
+ type TraceEvent = TraceDetails & {
26
+ type: 'request-trace';
27
+ requestId: string;
28
+ timestamp: string;
29
+ method: string;
30
+ pathname: string;
31
+ queryKeys: string[];
32
+ route: string | null;
33
+ resource: string | null;
34
+ operation: string | null;
35
+ id: string | null;
36
+ status: number | null;
37
+ handled: boolean;
38
+ durationMs: number;
39
+ slow: boolean;
40
+ phases: TracePhase[];
41
+ error?: TraceError;
42
+ };
43
+ type TraceRequest = {
44
+ method?: string;
45
+ url?: string;
46
+ };
47
+ type TraceResponse = {
48
+ body?: unknown;
49
+ status?: number;
50
+ statusCode?: number;
51
+ setHeader?: (name: string, value: string) => unknown;
52
+ writeHead?: (status: number, ...args: unknown[]) => unknown;
53
+ };
54
+ type HonoHeaderContext = {
55
+ header?: (name: string, value: string) => unknown;
56
+ };
57
+ type DbWithTrace = {
58
+ config?: {
59
+ server?: {
60
+ trace?: TraceSource;
61
+ };
62
+ };
63
+ events?: {
64
+ emit?: (event: TraceEvent) => unknown;
65
+ };
66
+ };
67
+ type ErrorWithStatus = {
68
+ code?: unknown;
69
+ status?: unknown;
70
+ };
71
+ export declare function resolveTraceOptions(explicitTrace: TraceSource, configTrace?: TraceSource): ResolvedTraceOptions | null;
72
+ export declare function createRequestTrace(db: DbWithTrace | null | undefined, request: TraceRequest, options?: {
73
+ trace?: TraceSource;
74
+ }): RequestTrace | null;
75
+ export declare class RequestTrace {
76
+ options: ResolvedTraceOptions;
77
+ start: number;
78
+ headerAttached: boolean;
79
+ event: TraceEvent;
80
+ constructor(options: ResolvedTraceOptions, request: TraceRequest, url: URL);
81
+ markHandled(response: TraceResponse): void;
82
+ setRoute(details?: TraceDetails): void;
83
+ addPhase(name: string, durationMs: number, details?: TraceDetails): void;
84
+ timeSync<Result>(name: string, fn: () => Result, details?: TraceDetails): Result;
85
+ time<Result>(name: string, fn: () => Result | Promise<Result>, details?: TraceDetails): Promise<Result>;
86
+ setError(error: ErrorWithStatus | null | undefined): void;
87
+ finish(db: DbWithTrace | null | undefined, response: TraceResponse): TraceEvent | null;
88
+ attachResponseHeader(response: TraceResponse | null | undefined): void;
89
+ attachHonoHeader(c: HonoHeaderContext | null | undefined): void;
90
+ captureSerializedError(response: TraceResponse | null | undefined): void;
91
+ }
92
+ export declare function responseStatus(response: TraceResponse | null | undefined): number | null;
93
+ export declare function tracePhase<Result>(trace: RequestTrace | null | undefined, name: string, fn: () => Result | Promise<Result>, details?: TraceDetails): Result | Promise<Result>;
94
+ export declare function tracePhaseSync<Result>(trace: RequestTrace | null | undefined, name: string, fn: () => Result, details?: TraceDetails): Result;
95
+ export {};
@@ -0,0 +1,260 @@
1
+ const DEFAULT_TRACE_HEADER = 'x-async-db-request-id';
2
+ export function resolveTraceOptions(explicitTrace, configTrace) {
3
+ const source = explicitTrace === undefined ? configTrace : explicitTrace;
4
+ if (source === false || source === undefined || source === null) {
5
+ return null;
6
+ }
7
+ const options = source === true
8
+ ? {}
9
+ : typeof source === 'object'
10
+ ? source
11
+ : {};
12
+ if (options.enabled === false) {
13
+ return null;
14
+ }
15
+ return {
16
+ enabled: true,
17
+ slowMs: Math.max(0, Number(options.slowMs ?? 0)),
18
+ console: options.console !== false,
19
+ events: options.events !== false,
20
+ header: typeof options.header === 'string' && options.header.trim()
21
+ ? options.header.trim().toLowerCase()
22
+ : DEFAULT_TRACE_HEADER,
23
+ };
24
+ }
25
+ export function createRequestTrace(db, request, options = {}) {
26
+ const traceOptions = resolveTraceOptions(options.trace, db?.config?.server?.trace);
27
+ if (!traceOptions) {
28
+ return null;
29
+ }
30
+ const url = new URL(request.url ?? '/', 'http://db.local');
31
+ return new RequestTrace(traceOptions, request, url);
32
+ }
33
+ export class RequestTrace {
34
+ options;
35
+ start;
36
+ headerAttached;
37
+ event;
38
+ constructor(options, request, url) {
39
+ this.options = options;
40
+ this.start = now();
41
+ this.headerAttached = false;
42
+ this.event = {
43
+ type: 'request-trace',
44
+ requestId: requestId(),
45
+ timestamp: new Date().toISOString(),
46
+ method: String(request.method ?? 'GET').toUpperCase(),
47
+ pathname: url.pathname,
48
+ queryKeys: [...new Set([...url.searchParams.keys()])].sort(),
49
+ route: null,
50
+ resource: null,
51
+ operation: null,
52
+ id: null,
53
+ status: null,
54
+ handled: false,
55
+ durationMs: 0,
56
+ slow: false,
57
+ phases: [],
58
+ };
59
+ }
60
+ markHandled(response) {
61
+ this.event.handled = true;
62
+ this.attachResponseHeader(response);
63
+ }
64
+ setRoute(details = {}) {
65
+ for (const [key, value] of Object.entries(details)) {
66
+ if (value !== undefined && value !== null && value !== '') {
67
+ this.event[key] = value;
68
+ }
69
+ }
70
+ }
71
+ addPhase(name, durationMs, details = {}) {
72
+ const phase = {
73
+ name,
74
+ durationMs: roundMs(durationMs),
75
+ };
76
+ for (const [key, value] of Object.entries(details)) {
77
+ if (value !== undefined && value !== null) {
78
+ phase[key] = value;
79
+ }
80
+ }
81
+ this.event.phases.push(phase);
82
+ }
83
+ timeSync(name, fn, details = {}) {
84
+ const start = now();
85
+ try {
86
+ return fn();
87
+ }
88
+ finally {
89
+ this.addPhase(name, now() - start, details);
90
+ }
91
+ }
92
+ async time(name, fn, details = {}) {
93
+ const start = now();
94
+ try {
95
+ return await fn();
96
+ }
97
+ finally {
98
+ this.addPhase(name, now() - start, details);
99
+ }
100
+ }
101
+ setError(error) {
102
+ if (!error) {
103
+ return;
104
+ }
105
+ if (typeof error.status === 'number') {
106
+ this.event.status = error.status;
107
+ }
108
+ const code = error.code ? String(error.code) : 'ERROR';
109
+ this.event.error = {
110
+ code,
111
+ message: safeErrorMessage(code),
112
+ };
113
+ }
114
+ finish(db, response) {
115
+ if (!this.event.handled) {
116
+ return null;
117
+ }
118
+ const status = responseStatus(response);
119
+ if (status !== null) {
120
+ this.event.status = status;
121
+ }
122
+ this.captureSerializedError(response);
123
+ this.event.durationMs = roundMs(now() - this.start);
124
+ this.event.slow = this.event.durationMs >= this.options.slowMs;
125
+ const traceEvent = compactEvent(this.event);
126
+ if (this.options.events && typeof db?.events?.emit === 'function') {
127
+ db.events.emit(traceEvent);
128
+ }
129
+ if (this.options.console) {
130
+ writeConsoleTrace(traceEvent);
131
+ }
132
+ return traceEvent;
133
+ }
134
+ attachResponseHeader(response) {
135
+ if (this.headerAttached || !response || !this.options.header) {
136
+ return;
137
+ }
138
+ this.headerAttached = true;
139
+ if (typeof response.setHeader === 'function') {
140
+ response.setHeader(this.options.header, this.event.requestId);
141
+ return;
142
+ }
143
+ if (typeof response.writeHead !== 'function') {
144
+ return;
145
+ }
146
+ const originalWriteHead = response.writeHead.bind(response);
147
+ response.writeHead = (status, ...args) => {
148
+ return originalWriteHead(status, ...withHeader(args, this.options.header, this.event.requestId));
149
+ };
150
+ }
151
+ attachHonoHeader(c) {
152
+ if (!this.options.header || typeof c?.header !== 'function') {
153
+ return;
154
+ }
155
+ c.header(this.options.header, this.event.requestId);
156
+ }
157
+ captureSerializedError(response) {
158
+ if (this.event.error || typeof response?.body !== 'string' || response.body.trim() === '') {
159
+ return;
160
+ }
161
+ try {
162
+ const parsed = JSON.parse(response.body);
163
+ const error = parsed?.error;
164
+ if (error && typeof error === 'object') {
165
+ const code = error.code ? String(error.code) : 'ERROR';
166
+ this.event.error = {
167
+ code,
168
+ message: safeErrorMessage(code),
169
+ };
170
+ }
171
+ }
172
+ catch {
173
+ // Response bodies are not part of trace data; this only observes tests' serialized error envelope.
174
+ }
175
+ }
176
+ }
177
+ export function responseStatus(response) {
178
+ if (typeof response?.status === 'number') {
179
+ return response.status;
180
+ }
181
+ if (typeof response?.statusCode === 'number') {
182
+ return response.statusCode;
183
+ }
184
+ return null;
185
+ }
186
+ export function tracePhase(trace, name, fn, details) {
187
+ return trace ? trace.time(name, fn, details) : fn();
188
+ }
189
+ export function tracePhaseSync(trace, name, fn, details) {
190
+ return trace ? trace.timeSync(name, fn, details) : fn();
191
+ }
192
+ function withHeader(args, name, value) {
193
+ if (args.length === 0) {
194
+ return [{ [name]: value }];
195
+ }
196
+ if (typeof args[0] === 'string') {
197
+ return [
198
+ args[0],
199
+ {
200
+ ...headerObject(args[1]),
201
+ [name]: value,
202
+ },
203
+ ...args.slice(2),
204
+ ];
205
+ }
206
+ return [
207
+ {
208
+ ...headerObject(args[0]),
209
+ [name]: value,
210
+ },
211
+ ...args.slice(1),
212
+ ];
213
+ }
214
+ function compactEvent(event) {
215
+ const next = {};
216
+ for (const [key, value] of Object.entries(event)) {
217
+ if (value === null || value === undefined) {
218
+ continue;
219
+ }
220
+ if (Array.isArray(value) && value.length === 0) {
221
+ continue;
222
+ }
223
+ next[key] = value;
224
+ }
225
+ return next;
226
+ }
227
+ function writeConsoleTrace(event) {
228
+ const prefix = event.slow ? '[async-db:slow]' : '[async-db]';
229
+ const fields = [
230
+ event.route ? `route=${event.route}` : null,
231
+ event.resource ? `resource=${event.resource}` : null,
232
+ event.operation ? `op=${event.operation}` : null,
233
+ event.hook ? `hook=${event.hook}` : null,
234
+ event.shortCircuit ? 'shortCircuit=true' : null,
235
+ `requestId=${event.requestId}`,
236
+ ].filter(Boolean);
237
+ console.log(`${prefix} ${event.method} ${event.pathname} ${event.status ?? '-'} ${event.durationMs}ms ${fields.join(' ')}`);
238
+ }
239
+ function headerObject(value) {
240
+ return value && typeof value === 'object' && !Array.isArray(value)
241
+ ? value
242
+ : {};
243
+ }
244
+ function safeErrorMessage(code) {
245
+ return code ? `Request failed (${code})` : 'Request failed';
246
+ }
247
+ function requestId() {
248
+ if (typeof globalThis.crypto?.randomUUID === 'function') {
249
+ return globalThis.crypto.randomUUID();
250
+ }
251
+ return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
252
+ }
253
+ function now() {
254
+ return typeof globalThis.performance?.now === 'function'
255
+ ? globalThis.performance.now()
256
+ : Date.now();
257
+ }
258
+ function roundMs(value) {
259
+ return Math.round(Number(value) * 1000) / 1000;
260
+ }