lecodes-sdk 0.19.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 (367) hide show
  1. package/README.md +114 -0
  2. package/dist/global.d.ts +503 -0
  3. package/dist/host.d.ts +61 -0
  4. package/dist/inject.js +4730 -0
  5. package/dist/types/animate/animate.d.ts +20 -0
  6. package/dist/types/animate/bezier.d.ts +2 -0
  7. package/dist/types/animate/easings.d.ts +21 -0
  8. package/dist/types/canvas/Canvas.d.ts +168 -0
  9. package/dist/types/core/Aspect.d.ts +171 -0
  10. package/dist/types/core/InspectorUI.d.ts +88 -0
  11. package/dist/types/core/StateMachine.d.ts +81 -0
  12. package/dist/types/core/color.d.ts +13 -0
  13. package/dist/types/core/compWrite.d.ts +11 -0
  14. package/dist/types/core/events.d.ts +11 -0
  15. package/dist/types/core/fields.d.ts +58 -0
  16. package/dist/types/core/registry.d.ts +7 -0
  17. package/dist/types/core/signals.d.ts +29 -0
  18. package/dist/types/core/time.d.ts +31 -0
  19. package/dist/types/g2/Camera2D.d.ts +19 -0
  20. package/dist/types/g2/CharacterController2D.d.ts +134 -0
  21. package/dist/types/g2/Node2D.d.ts +91 -0
  22. package/dist/types/g2/OneWay2D.d.ts +24 -0
  23. package/dist/types/g2/Physics2D.d.ts +147 -0
  24. package/dist/types/g2/Scene2D.d.ts +72 -0
  25. package/dist/types/g2/Shape2D.d.ts +58 -0
  26. package/dist/types/g2/Sprite.d.ts +51 -0
  27. package/dist/types/g2/SpriteAnimation.d.ts +50 -0
  28. package/dist/types/g2/SpriteSheet.d.ts +69 -0
  29. package/dist/types/g2/Texture2D.d.ts +16 -0
  30. package/dist/types/g2/Tilemap.d.ts +20 -0
  31. package/dist/types/g2/Tileset.d.ts +32 -0
  32. package/dist/types/g2/Trigger2D.d.ts +20 -0
  33. package/dist/types/g2/autotile.d.ts +133 -0
  34. package/dist/types/g2/cells.d.ts +14 -0
  35. package/dist/types/g2/defineScene2d.d.ts +141 -0
  36. package/dist/types/g2/groups2d.d.ts +16 -0
  37. package/dist/types/g2/loop.d.ts +4 -0
  38. package/dist/types/g2/scenarios2d.d.ts +30 -0
  39. package/dist/types/g2/touch.d.ts +2 -0
  40. package/dist/types/gl/Camera.d.ts +79 -0
  41. package/dist/types/gl/CameraPlace.d.ts +26 -0
  42. package/dist/types/gl/CharacterController.d.ts +98 -0
  43. package/dist/types/gl/Gearbox.d.ts +86 -0
  44. package/dist/types/gl/Geometry.d.ts +39 -0
  45. package/dist/types/gl/IK.d.ts +53 -0
  46. package/dist/types/gl/InstancedMesh.d.ts +46 -0
  47. package/dist/types/gl/Light.d.ts +73 -0
  48. package/dist/types/gl/Lightmap.d.ts +85 -0
  49. package/dist/types/gl/Locomotion.d.ts +279 -0
  50. package/dist/types/gl/Material.d.ts +100 -0
  51. package/dist/types/gl/Mesh.d.ts +33 -0
  52. package/dist/types/gl/Model.d.ts +53 -0
  53. package/dist/types/gl/NavAgent.d.ts +99 -0
  54. package/dist/types/gl/NavMesh.d.ts +169 -0
  55. package/dist/types/gl/Node.d.ts +99 -0
  56. package/dist/types/gl/Noise.d.ts +20 -0
  57. package/dist/types/gl/Particles.d.ts +277 -0
  58. package/dist/types/gl/Physics.d.ts +91 -0
  59. package/dist/types/gl/Plane.d.ts +19 -0
  60. package/dist/types/gl/Ragdoll.d.ts +86 -0
  61. package/dist/types/gl/Ray.d.ts +8 -0
  62. package/dist/types/gl/Scene.d.ts +221 -0
  63. package/dist/types/gl/Shape.d.ts +122 -0
  64. package/dist/types/gl/Terrain.d.ts +280 -0
  65. package/dist/types/gl/Texture.d.ts +27 -0
  66. package/dist/types/gl/Trigger.d.ts +10 -0
  67. package/dist/types/gl/Vehicle.d.ts +191 -0
  68. package/dist/types/gl/Wheel.d.ts +95 -0
  69. package/dist/types/gl/animation/AnimationClip.d.ts +60 -0
  70. package/dist/types/gl/animation/Animator.d.ts +219 -0
  71. package/dist/types/gl/animation/Layer.d.ts +31 -0
  72. package/dist/types/gl/animation/Loop.d.ts +17 -0
  73. package/dist/types/gl/animation/Playback.d.ts +36 -0
  74. package/dist/types/gl/animation/core.d.ts +367 -0
  75. package/dist/types/gl/controls.d.ts +19 -0
  76. package/dist/types/gl/physicsEvents.d.ts +1 -0
  77. package/dist/types/gl/scenarios.d.ts +98 -0
  78. package/dist/types/gl/state.d.ts +5 -0
  79. package/dist/types/gl/terrainMesh.d.ts +46 -0
  80. package/dist/types/gl/touch.d.ts +2 -0
  81. package/dist/types/inject.d.ts +123 -0
  82. package/dist/types/math/Mathf.d.ts +39 -0
  83. package/dist/types/math/mat4.d.ts +66 -0
  84. package/dist/types/math/quat.d.ts +53 -0
  85. package/dist/types/math/vec.d.ts +129 -0
  86. package/dist/types/net/codec.d.ts +25 -0
  87. package/dist/types/net/core.d.ts +106 -0
  88. package/dist/types/net/index.d.ts +80 -0
  89. package/dist/types/net/replication.d.ts +101 -0
  90. package/dist/types/plugins/camera.d.ts +25 -0
  91. package/dist/types/plugins/geolocation.d.ts +39 -0
  92. package/dist/types/plugins/oauth.d.ts +25 -0
  93. package/dist/types/plugins/permission.d.ts +1 -0
  94. package/dist/types/plugins/push.d.ts +46 -0
  95. package/dist/types/plugins/qr.d.ts +21 -0
  96. package/dist/types/plugins/service.d.ts +33 -0
  97. package/dist/types/runtime/app.d.ts +67 -0
  98. package/dist/types/runtime/appEvents.d.ts +7 -0
  99. package/dist/types/runtime/channel.d.ts +1 -0
  100. package/dist/types/runtime/clipboard.d.ts +7 -0
  101. package/dist/types/runtime/datetime.d.ts +80 -0
  102. package/dist/types/runtime/device.d.ts +126 -0
  103. package/dist/types/runtime/fetch.d.ts +31 -0
  104. package/dist/types/runtime/files.d.ts +33 -0
  105. package/dist/types/runtime/input.d.ts +121 -0
  106. package/dist/types/runtime/media.d.ts +46 -0
  107. package/dist/types/runtime/misc.d.ts +11 -0
  108. package/dist/types/runtime/net.d.ts +15 -0
  109. package/dist/types/runtime/rpc.d.ts +44 -0
  110. package/dist/types/runtime/service.d.ts +1 -0
  111. package/dist/types/runtime/share.d.ts +2 -0
  112. package/dist/types/runtime/storage.d.ts +5 -0
  113. package/dist/types/runtime/touch.d.ts +56 -0
  114. package/dist/types/scene/defineScene.d.ts +296 -0
  115. package/dist/types/scene/editorPlugins.d.ts +82 -0
  116. package/dist/types/scene/gizmos.d.ts +56 -0
  117. package/dist/types/scene/grammar.d.ts +56 -0
  118. package/dist/types/scene/level.d.ts +98 -0
  119. package/dist/types/scene/material.d.ts +76 -0
  120. package/dist/types/server/auth/appConfig.d.ts +16 -0
  121. package/dist/types/server/auth/global.d.ts +56 -0
  122. package/dist/types/server/auth/models.d.ts +164 -0
  123. package/dist/types/server/auth/types.d.ts +56 -0
  124. package/dist/types/server/channel.d.ts +28 -0
  125. package/dist/types/server/context.d.ts +27 -0
  126. package/dist/types/server/db/defineDb.d.ts +36 -0
  127. package/dist/types/server/db/fields.d.ts +146 -0
  128. package/dist/types/server/db/index.d.ts +6 -0
  129. package/dist/types/server/db/marci/query.d.ts +326 -0
  130. package/dist/types/server/db/types.d.ts +163 -0
  131. package/dist/types/server/errors.d.ts +8 -0
  132. package/dist/types/server/inject.d.ts +5 -0
  133. package/dist/types/ui/NativeView.d.ts +38 -0
  134. package/dist/types/ui/UI.d.ts +27 -0
  135. package/dist/types/ui/UIBottomSheet.d.ts +71 -0
  136. package/dist/types/ui/UIButton.d.ts +30 -0
  137. package/dist/types/ui/UIContainer.d.ts +33 -0
  138. package/dist/types/ui/UIImage.d.ts +35 -0
  139. package/dist/types/ui/UIInput.d.ts +110 -0
  140. package/dist/types/ui/UIModal.d.ts +70 -0
  141. package/dist/types/ui/UINode.d.ts +363 -0
  142. package/dist/types/ui/UIPager.d.ts +123 -0
  143. package/dist/types/ui/UIPopover.d.ts +39 -0
  144. package/dist/types/ui/UIScreen.d.ts +57 -0
  145. package/dist/types/ui/UIScrollable.d.ts +40 -0
  146. package/dist/types/ui/UISpacer.d.ts +9 -0
  147. package/dist/types/ui/UITabs.d.ts +96 -0
  148. package/dist/types/ui/UIText.d.ts +19 -0
  149. package/dist/types/ui/UIVideo.d.ts +28 -0
  150. package/dist/types/ui/UIVirtualizedList.d.ts +97 -0
  151. package/dist/types/ui/UIWidget.d.ts +65 -0
  152. package/dist/types/ui/fonts.d.ts +9 -0
  153. package/dist/types/ui/presentable.d.ts +68 -0
  154. package/dist/types/ui/router.d.ts +40 -0
  155. package/dist/types/ui/theme.d.ts +26 -0
  156. package/dist/types.json +1 -0
  157. package/package.json +46 -0
  158. package/prompts/2d.md +395 -0
  159. package/prompts/3d-scene-files.md +113 -0
  160. package/prompts/3d-scene.md +119 -0
  161. package/prompts/3d.md +303 -0
  162. package/prompts/README.md +142 -0
  163. package/prompts/ar.md +109 -0
  164. package/prompts/canvas.md +27 -0
  165. package/prompts/compose.ts +46 -0
  166. package/prompts/concept.md +49 -0
  167. package/prompts/core-design.md +75 -0
  168. package/prompts/core.md +264 -0
  169. package/prompts/design.md +218 -0
  170. package/prompts/dist/2d-game.md +1530 -0
  171. package/prompts/dist/3d-app.md +1672 -0
  172. package/prompts/dist/ar-app.md +1548 -0
  173. package/prompts/dist/concept.md +49 -0
  174. package/prompts/dist/design.md +498 -0
  175. package/prompts/dist/ui-app.md +1134 -0
  176. package/prompts/index.md +37 -0
  177. package/prompts/intake-prompt.md +33 -0
  178. package/prompts/namer-prompt.md +12 -0
  179. package/prompts/router-prompt.md +50 -0
  180. package/prompts/select.ts +111 -0
  181. package/prompts/ui-design.md +203 -0
  182. package/prompts/ui.md +803 -0
  183. package/src/animate/animate.ts +238 -0
  184. package/src/animate/bezier.ts +138 -0
  185. package/src/animate/easings.ts +126 -0
  186. package/src/bridges.d.ts +1345 -0
  187. package/src/canvas/Canvas.ts +305 -0
  188. package/src/compile/__tests__/assetIconMacro.test.ts +219 -0
  189. package/src/compile/__tests__/assetMacro.test.ts +74 -0
  190. package/src/compile/__tests__/assetName.test.ts +55 -0
  191. package/src/compile/__tests__/compile.test.ts +287 -0
  192. package/src/compile/__tests__/detectEntry.test.ts +132 -0
  193. package/src/compile/__tests__/fontMacro.test.ts +199 -0
  194. package/src/compile/aspectMacro.ts +86 -0
  195. package/src/compile/assetIconMacro.ts +384 -0
  196. package/src/compile/assetMacro.ts +146 -0
  197. package/src/compile/assetName.ts +50 -0
  198. package/src/compile/bundler.ts +287 -0
  199. package/src/compile/compileProject.ts +127 -0
  200. package/src/compile/detectEntry.ts +128 -0
  201. package/src/compile/fontMacro.ts +459 -0
  202. package/src/compile/fontRegistry.ts +78 -0
  203. package/src/compile/header.ts +67 -0
  204. package/src/compile/index.ts +100 -0
  205. package/src/compile/libraryImports.ts +52 -0
  206. package/src/compile/liteMaterial.ts +247 -0
  207. package/src/compile/sceneEditor.ts +88 -0
  208. package/src/compile/serverSplit.ts +233 -0
  209. package/src/compile/serverTypes.ts +227 -0
  210. package/src/compile/sfnt.ts +98 -0
  211. package/src/compile/shaderSchema.ts +202 -0
  212. package/src/compile/shaderTargets.ts +77 -0
  213. package/src/compile/sourcemap.ts +25 -0
  214. package/src/core/Aspect.ts +568 -0
  215. package/src/core/InspectorUI.ts +212 -0
  216. package/src/core/StateMachine.ts +308 -0
  217. package/src/core/__tests__/stateMachine.test.ts +132 -0
  218. package/src/core/color.ts +66 -0
  219. package/src/core/compWrite.ts +42 -0
  220. package/src/core/events.ts +38 -0
  221. package/src/core/fields.ts +120 -0
  222. package/src/core/registry.ts +23 -0
  223. package/src/core/signals.ts +277 -0
  224. package/src/core/time.ts +84 -0
  225. package/src/g2/Camera2D.ts +40 -0
  226. package/src/g2/CharacterController2D.ts +276 -0
  227. package/src/g2/Node2D.ts +267 -0
  228. package/src/g2/OneWay2D.ts +66 -0
  229. package/src/g2/Physics2D.ts +346 -0
  230. package/src/g2/Scene2D.ts +209 -0
  231. package/src/g2/Shape2D.ts +259 -0
  232. package/src/g2/Sprite.ts +89 -0
  233. package/src/g2/SpriteAnimation.ts +171 -0
  234. package/src/g2/SpriteSheet.ts +166 -0
  235. package/src/g2/Texture2D.ts +47 -0
  236. package/src/g2/Tilemap.ts +41 -0
  237. package/src/g2/Tileset.ts +71 -0
  238. package/src/g2/Trigger2D.ts +77 -0
  239. package/src/g2/autotile.ts +433 -0
  240. package/src/g2/cells.ts +91 -0
  241. package/src/g2/defineScene2d.ts +381 -0
  242. package/src/g2/groups2d.ts +106 -0
  243. package/src/g2/loop.ts +50 -0
  244. package/src/g2/scenarios2d.ts +69 -0
  245. package/src/g2/touch.ts +83 -0
  246. package/src/gl/Camera.ts +160 -0
  247. package/src/gl/CameraPlace.ts +52 -0
  248. package/src/gl/CharacterController.ts +238 -0
  249. package/src/gl/Gearbox.ts +212 -0
  250. package/src/gl/Geometry.ts +279 -0
  251. package/src/gl/IK.ts +193 -0
  252. package/src/gl/InstancedMesh.ts +132 -0
  253. package/src/gl/Light.ts +135 -0
  254. package/src/gl/Lightmap.ts +402 -0
  255. package/src/gl/Locomotion.ts +498 -0
  256. package/src/gl/Material.ts +279 -0
  257. package/src/gl/Mesh.ts +83 -0
  258. package/src/gl/Model.ts +124 -0
  259. package/src/gl/NavAgent.ts +337 -0
  260. package/src/gl/NavMesh.ts +397 -0
  261. package/src/gl/Node.ts +350 -0
  262. package/src/gl/Noise.ts +30 -0
  263. package/src/gl/Particles.ts +676 -0
  264. package/src/gl/Physics.ts +222 -0
  265. package/src/gl/Plane.ts +53 -0
  266. package/src/gl/Ragdoll.ts +270 -0
  267. package/src/gl/Ray.ts +16 -0
  268. package/src/gl/Scene.ts +505 -0
  269. package/src/gl/Shape.ts +409 -0
  270. package/src/gl/Terrain.ts +1092 -0
  271. package/src/gl/Texture.ts +63 -0
  272. package/src/gl/Trigger.ts +45 -0
  273. package/src/gl/Vehicle.ts +473 -0
  274. package/src/gl/Wheel.ts +240 -0
  275. package/src/gl/animation/AnimationClip.ts +204 -0
  276. package/src/gl/animation/Animator.ts +329 -0
  277. package/src/gl/animation/Layer.ts +39 -0
  278. package/src/gl/animation/Loop.ts +31 -0
  279. package/src/gl/animation/Playback.ts +52 -0
  280. package/src/gl/animation/core.ts +670 -0
  281. package/src/gl/controls.ts +95 -0
  282. package/src/gl/physicsEvents.ts +20 -0
  283. package/src/gl/scenarios.ts +291 -0
  284. package/src/gl/state.ts +6 -0
  285. package/src/gl/terrainMesh.ts +219 -0
  286. package/src/gl/touch.ts +68 -0
  287. package/src/host.d.ts +61 -0
  288. package/src/inject.ts +203 -0
  289. package/src/math/Mathf.ts +118 -0
  290. package/src/math/mat4.ts +278 -0
  291. package/src/math/quat.ts +232 -0
  292. package/src/math/vec.ts +255 -0
  293. package/src/net/codec.ts +119 -0
  294. package/src/net/core.ts +384 -0
  295. package/src/net/index.ts +181 -0
  296. package/src/net/replication.ts +622 -0
  297. package/src/plugins/camera.ts +81 -0
  298. package/src/plugins/geolocation.ts +123 -0
  299. package/src/plugins/oauth.ts +61 -0
  300. package/src/plugins/permission.ts +7 -0
  301. package/src/plugins/push.ts +132 -0
  302. package/src/plugins/qr.ts +73 -0
  303. package/src/plugins/service.ts +47 -0
  304. package/src/runtime/app.ts +101 -0
  305. package/src/runtime/appEvents.ts +54 -0
  306. package/src/runtime/channel.ts +61 -0
  307. package/src/runtime/clipboard.ts +20 -0
  308. package/src/runtime/datetime.ts +329 -0
  309. package/src/runtime/device.ts +293 -0
  310. package/src/runtime/fetch.ts +77 -0
  311. package/src/runtime/files.ts +108 -0
  312. package/src/runtime/input.ts +175 -0
  313. package/src/runtime/media.ts +111 -0
  314. package/src/runtime/misc.ts +16 -0
  315. package/src/runtime/net.ts +36 -0
  316. package/src/runtime/rpc.ts +218 -0
  317. package/src/runtime/service.ts +83 -0
  318. package/src/runtime/share.ts +9 -0
  319. package/src/runtime/storage.ts +13 -0
  320. package/src/runtime/touch.ts +76 -0
  321. package/src/scene/defineScene.ts +1396 -0
  322. package/src/scene/editorPlugins.ts +110 -0
  323. package/src/scene/gizmos.ts +148 -0
  324. package/src/scene/grammar.ts +120 -0
  325. package/src/scene/level.ts +296 -0
  326. package/src/scene/material.ts +188 -0
  327. package/src/server/auth/appConfig.ts +12 -0
  328. package/src/server/auth/global.ts +80 -0
  329. package/src/server/auth/host.ts +318 -0
  330. package/src/server/auth/models.ts +83 -0
  331. package/src/server/auth/types.ts +50 -0
  332. package/src/server/channel.ts +56 -0
  333. package/src/server/context.ts +36 -0
  334. package/src/server/db/defineDb.ts +237 -0
  335. package/src/server/db/fields.ts +132 -0
  336. package/src/server/db/httpTransport.ts +93 -0
  337. package/src/server/db/index.ts +7 -0
  338. package/src/server/db/marci/query.ts +412 -0
  339. package/src/server/db/types.ts +202 -0
  340. package/src/server/errors.ts +12 -0
  341. package/src/server/host.ts +74 -0
  342. package/src/server/inject.ts +13 -0
  343. package/src/server/runtime.ts +133 -0
  344. package/src/server/validate.ts +87 -0
  345. package/src/ui/NativeView.ts +142 -0
  346. package/src/ui/UI.ts +39 -0
  347. package/src/ui/UIBottomSheet.ts +139 -0
  348. package/src/ui/UIButton.ts +101 -0
  349. package/src/ui/UIContainer.ts +60 -0
  350. package/src/ui/UIImage.ts +83 -0
  351. package/src/ui/UIInput.ts +185 -0
  352. package/src/ui/UIModal.ts +139 -0
  353. package/src/ui/UINode.ts +830 -0
  354. package/src/ui/UIPager.ts +362 -0
  355. package/src/ui/UIPopover.ts +100 -0
  356. package/src/ui/UIScreen.ts +123 -0
  357. package/src/ui/UIScrollable.ts +87 -0
  358. package/src/ui/UISpacer.ts +14 -0
  359. package/src/ui/UITabs.ts +236 -0
  360. package/src/ui/UIText.ts +51 -0
  361. package/src/ui/UIVideo.ts +88 -0
  362. package/src/ui/UIVirtualizedList.ts +241 -0
  363. package/src/ui/UIWidget.ts +127 -0
  364. package/src/ui/fonts.ts +13 -0
  365. package/src/ui/presentable.ts +117 -0
  366. package/src/ui/router.ts +132 -0
  367. package/src/ui/theme.ts +84 -0
@@ -0,0 +1,93 @@
1
+ /**
2
+ * `MarciTransport` over marcidb-server's HTTP API (docs/HTTP-API.md in the marci-db repo) — the
3
+ * transport the runner installs in every project worker (`setDbTransport(marciHttpTransport(url))`).
4
+ * Host-side code (Bun/Node): uses the platform `fetch`, never the SDK bridge. Mirrors marcidb's own
5
+ * `httpTransport` (crates/marcidb-ts/src/prefix.js) minus the binary read fast path.
6
+ *
7
+ * `baseUrl` = `http://host:port/<db>`; an optional bearer token (marcidb-server `MARCI_TOKEN`) is sent
8
+ * on every request. Pass `fetch` explicitly when the global one might be monkey-patched by untrusted
9
+ * code running in the same realm (the runner captures it before evaluating a project bundle).
10
+ */
11
+
12
+ import type { MarciOp, MarciTransport } from "./marci/query"
13
+
14
+ /** A failed marcidb request: `status` is the HTTP status (0 = network failure), `message` its body. */
15
+ export class MarciHttpError extends Error {
16
+ readonly status: number
17
+ constructor(status: number, message: string) {
18
+ super(message)
19
+ this.name = "MarciHttpError"
20
+ this.status = status
21
+ }
22
+ }
23
+
24
+ export type MarciHttpOptions = {
25
+ token?: string | null
26
+ fetch?: typeof fetch
27
+ }
28
+
29
+ /** `update/:id` and `delete/:id` take the key in the path: a bare value, or `k=v&k2=v2` for composite keys
30
+ * (nested ids flatten with dots — `{ chat: { id: 1 } }` → `chat.id=1`). */
31
+ export const encodeMarciId = (id: unknown): string => {
32
+ if (typeof id === "object" && id !== null) {
33
+ const parts: string[] = []
34
+ const walk = (obj: Record<string, unknown>, prefix: string) => {
35
+ for (const [k, v] of Object.entries(obj)) {
36
+ const key = prefix ? `${prefix}.${k}` : k
37
+ if (typeof v === "object" && v !== null) walk(v as Record<string, unknown>, key)
38
+ else parts.push(`${key}=${encodeURIComponent(String(v))}`)
39
+ }
40
+ }
41
+ walk(id as Record<string, unknown>, "")
42
+ return parts.join("&")
43
+ }
44
+ return encodeURIComponent(String(id))
45
+ }
46
+
47
+ /** Low-level request helper (also used by the runner's admin calls: `$sync`, `DELETE /:db`). */
48
+ export const marciRequest = async (
49
+ url: string,
50
+ init: { method?: string, body?: unknown, rawBody?: string, token?: string | null, fetch?: typeof fetch } = {},
51
+ ): Promise<any> => {
52
+ const f = init.fetch ?? fetch
53
+ const headers: Record<string, string> = {}
54
+ if (init.token) headers.authorization = `Bearer ${init.token}`
55
+ let body: string | undefined
56
+ if (init.rawBody !== undefined) { body = init.rawBody; headers["content-type"] = "text/plain" }
57
+ else if (init.body !== undefined) { body = JSON.stringify(init.body); headers["content-type"] = "application/json" }
58
+ let res: Response
59
+ try {
60
+ res = await f(url, { method: init.method ?? "POST", headers, body })
61
+ } catch (e) {
62
+ throw new MarciHttpError(0, `marcidb unreachable: ${(e as Error)?.message ?? e}`)
63
+ }
64
+ const text = await res.text()
65
+ if (!res.ok) throw new MarciHttpError(res.status, text || `HTTP ${res.status}`)
66
+ if (!text) return undefined
67
+ try { return JSON.parse(text) } catch { return text }
68
+ }
69
+
70
+ export const marciHttpTransport = (baseUrl: string, options: MarciHttpOptions = {}): MarciTransport => {
71
+ const url = baseUrl.replace(/\/+$/, "")
72
+ const call = (path: string, body?: unknown) => marciRequest(`${url}/${path}`, { body, token: options.token, fetch: options.fetch })
73
+ return {
74
+ exec(op: MarciOp) {
75
+ switch (op.action) {
76
+ case "findMany": return call(`${op.model}/findMany`, op.query ?? {})
77
+ case "findFirst": return call(`${op.model}/findFirst`, op.query ?? {})
78
+ case "insert": return call(`${op.model}/insert`, op.data)
79
+ case "update": return call(`${op.model}/update/${encodeMarciId(op.id)}`, op.data).then(() => null)
80
+ // no id in the path — the filter and the payload travel together in the body
81
+ case "updateMany": return call(`${op.model}/updateMany`, { ...(op.query ?? {}), data: op.data })
82
+ case "delete": return call(`${op.model}/delete/${encodeMarciId(op.id)}`).then(() => null)
83
+ case "deleteMany": return call(`${op.model}/deleteMany`, op.query ?? {})
84
+ case "count": return call(`${op.model}/count`, op.query ?? {})
85
+ case "aggregate": return call(`${op.model}/aggregate`, op.query ?? {})
86
+ default: return Promise.reject(new Error(`marcidb: unknown action '${op.action}'`))
87
+ }
88
+ },
89
+ batch(ops: MarciOp[]) {
90
+ return call("$transaction", ops)
91
+ },
92
+ }
93
+ }
@@ -0,0 +1,7 @@
1
+ // Server-side db layer (phase 0 prototype of docs/backend-plan.md §3.1). Not yet part of inject.ts.
2
+ export { t } from "./fields"
3
+ export type { Field, FieldDef, FieldMeta } from "./fields"
4
+ export { model, defineDb, ref, setDbTransport, toMarci } from "./defineDb"
5
+ export type { DefineDbOptions } from "./defineDb"
6
+ export type { Db, Model, Schema, Row, Id, Insert, Update, Select, Where, Query, QueryObject, Result, Collection, ScalarSelect, Types } from "./types"
7
+ export type { Op, MarciOp, MarciTransport, JsonValue, Sub } from "./marci/query"
@@ -0,0 +1,412 @@
1
+ // GENERATED by scripts/sync-marcidb.ts from marci-db packages/marcidb-client/src/query.ts — do not edit here.
2
+ // Change it in the marci-db repo, then `bun run sync:marcidb`.
3
+
4
+ // The generic query layer of the marcidb client: the query-language types every generated client is built
5
+ // on (where / update operators, `GetResult`, `Op`, the query builder `Query<T>`) and the builder runtime
6
+ // (`createQueryLayer`). Everything here is schema-agnostic — the codegen (crates/marcidb-ts) emits the
7
+ // per-model type bags and MODELS metadata this file is parametrised by.
8
+ //
9
+ // Keep it dependency-free: besides shipping in `marcidb-client/runtime`, this file is vendored verbatim
10
+ // into the lecodes SDK (`packages/sdk/src/server/db/marci/query.ts`, `bun run sync:marcidb` there), which
11
+ // derives its model types from TS builders instead of codegen and plugs them into the same generics.
12
+
13
+ // ───────────────────────────── query language types ─────────────────────────────
14
+
15
+ export type ServiceKeys = "$where" | "$order" | "$limit" | "$skip" | "$cursor";
16
+
17
+ // A `Json` field: any JSON value. Stored as a JSONB binary blob server-side; on the wire it is a plain
18
+ // decoded JSON value.
19
+ export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
20
+
21
+ // Aggregate query over related records inside select
22
+ export type AggregateKeys = { $count: true } | { $sum: string } | { $avg: string } | { $min: string } | { $max: string }
23
+
24
+ // Distributive over union models (discriminated union for payload enums):
25
+ // keys not present in the current union branch are dropped
26
+ export type GetResult<TModel, TSelect> = TModel extends any ? {
27
+ -readonly [K in keyof Omit<TSelect, ServiceKeys> as TSelect[K] extends false | undefined ? never : K extends keyof TModel ? K : never]:
28
+ K extends keyof TModel
29
+ ? TSelect[K] extends true
30
+ ? TModel[K] // selected the whole field
31
+ : TSelect[K] extends Record<string, any>
32
+ ? TModel[K] extends readonly object[]
33
+ ? TSelect[K] extends AggregateKeys
34
+ ? AggregateResult<NonNullable<TModel[K][number]>, TSelect[K]> // aggregate over the relation
35
+ : GetResult<NonNullable<TModel[K][number]>, TSelect[K]>[]
36
+ : GetResult<NonNullable<TModel[K]>, TSelect[K]> | Extract<TModel[K], null>
37
+ : TModel[K] // fallback
38
+ : never
39
+ } : never
40
+
41
+ export type RefUpdate<I> = {
42
+ "$connect"?: I
43
+ }
44
+
45
+ export type RefUpdateStruct<I,U> = {
46
+ "$update"?: U,
47
+ "$ensure"?: I,
48
+ "$set"?: I
49
+ }
50
+
51
+ /** Relation to independent rows — link operations only, the rows themselves are never created
52
+ * or deleted. `$set` replaces link membership with exactly the given set (missing links are
53
+ * disconnected, new ones connected); `$connect` links (idempotent); `$remove` unlinks. */
54
+ export type RefListUpdate<I> = {
55
+ "$set"?: I[],
56
+ "$connect"?: I | I[],
57
+ "$remove"?: I | I[],
58
+ }
59
+
60
+ /** `@list` relation: an ordered inline id array — a sequence, so the same id may appear several
61
+ * times. `$set` replaces the whole array (also the reorder operation); `$connect` appends at the
62
+ * end (an already-present id gains another occurrence); `$connectUnique` appends only ids not
63
+ * already present; `$remove` removes every occurrence. */
64
+ export type RefListUpdateOrdered<I> = {
65
+ "$set"?: I[],
66
+ "$connect"?: I | I[],
67
+ "$connectUnique"?: I | I[],
68
+ "$remove"?: I | I[],
69
+ }
70
+
71
+ /** Owned (struct) list: the children live and die with the parent. `$push` creates children,
72
+ * `$update` edits single children in place (each item is the child's id fields — the shape
73
+ * query results return — plus the changes under `data`), `$remove` deletes children by id,
74
+ * `$set` replaces all children (deletes the current ones, creates the new). */
75
+ export type RefListUpdateStruct<I,U,Id> = {
76
+ "$push"?: I | I[],
77
+ "$update"?: (Id & { data: U }) | (Id & { data: U })[],
78
+ "$remove"?: Id | Id[],
79
+ "$set"?: I[]
80
+ }
81
+
82
+ /** Variable-length primitive array — a sequence, so the same value may appear several times.
83
+ * `$push` appends at the end (duplicates kept); `$pushUnique` appends only values not already
84
+ * present; `$remove` removes every occurrence; `$set` replaces the whole array (also the
85
+ * positional-edit path — send the full new array). One operator per update. */
86
+ export type PrimitiveListUpdate<T> = {
87
+ "$set"?: T[],
88
+ "$push"?: T | T[],
89
+ "$pushUnique"?: T | T[],
90
+ "$remove"?: T | T[],
91
+ }
92
+
93
+ // Marks a set of keys as forbidden. Needed because TypeScript's excess-property check against a *union*
94
+ // permits any key present in some member: a plain union of single-key objects accepts `{ $gte, $lt }`,
95
+ // and a plain `T | { $and: T[] }` accepts a field sitting next to `$and`. Both are runtime errors or
96
+ // silently-wrong queries, so every branch below spells out the keys it excludes.
97
+ export type Never<T> = { [K in keyof T]?: never }
98
+
99
+ // Every field-level operator, so a field's condition can exclude the ones its type doesn't support.
100
+ export type FieldOps = {
101
+ "$eq": unknown, "$ne": unknown, "$not": unknown, "$in": unknown, "$notIn": unknown,
102
+ "$gt": unknown, "$gte": unknown, "$lt": unknown, "$lte": unknown,
103
+ "$startsWith": unknown, "$includes": unknown,
104
+ "$every": unknown, "$some": unknown, "$none": unknown,
105
+ "$near": unknown, "$search": unknown
106
+ }
107
+ export type Only<K extends keyof FieldOps, V> = { [P in K]: V } & Never<Omit<FieldOps, K>>
108
+
109
+ // A `$where` is either a set of field conditions or exactly one boolean combinator wrapping more of the
110
+ // same. Conditions belong *inside* the array: the engine returns on the first combinator it finds, so a
111
+ // sibling key next to `$and`/`$or` would be silently ignored — here it is a type error instead.
112
+ export type WhereValue<T> =
113
+ | (T & Never<{ "$and": unknown, "$or": unknown, "$not": unknown }>)
114
+ | ({ "$and": WhereValue<T>[] } & Never<T> & Never<{ "$or": unknown, "$not": unknown }>)
115
+ | ({ "$or": WhereValue<T>[] } & Never<T> & Never<{ "$and": unknown, "$not": unknown }>)
116
+ | ({ "$not": WhereValue<T> } & Never<T> & Never<{ "$and": unknown, "$or": unknown }>)
117
+
118
+ // Operators on one field are ANDed, so they combine freely: `{ $gte: 18, $lt: 65 }` is a half-open
119
+ // range and `{ $gte: 18, $ne: 30 }` punches a hole in one. Each group below is all-optional; a field's
120
+ // condition type intersects the groups its type supports and marks every remaining operator forbidden,
121
+ // so a string operator on a number is still a type error.
122
+ export type ValueOps<T> = { "$eq"?: T, "$ne"?: T, "$not"?: T, "$in"?: T[], "$notIn"?: T[] }
123
+ export type NumOps<T> = { "$gt"?: T, "$gte"?: T, "$lt"?: T, "$lte"?: T }
124
+ export type StrOps = { "$includes"?: string, "$startsWith"?: string }
125
+
126
+ // The numeric and string variants re-admit the type-agnostic operators, so a mixed condition such as
127
+ // `{ $gte: 18, $ne: 30 }` still matches a single member of the union the field's type resolves to.
128
+ export type CompareValue<T> = T | (ValueOps<T> & Never<Omit<FieldOps, keyof ValueOps<T>>>)
129
+ export type CompareNumValue<T> = ValueOps<T> & NumOps<T> & Never<Omit<FieldOps, keyof ValueOps<T> | keyof NumOps<T>>>
130
+ export type CompareStrValue<T> = ValueOps<T> & StrOps & Never<Omit<FieldOps, keyof ValueOps<T> | keyof StrOps>>
131
+
132
+ // A numeric field can also be updated in place: `{ balance: { $increment: -800 } }` reads, adds and writes
133
+ // inside the update's own transaction, so it is atomic against concurrent writers. The delta is signed, so
134
+ // decrementing requires a signed field (`Int`) — a negative delta on an unsigned field is rejected.
135
+ // Incrementing a field that is currently null is a no-op.
136
+ export type UpdateNumValue = { "$increment": number }
137
+
138
+ // Filtering into a Json field by dot-path. Keys are JSON paths (e.g. "address.city", "items.0"); a numeric
139
+ // segment indexes an array. A bare value is shorthand for `$eq` (a plain object matches the whole subtree).
140
+ // Path keys must not start with `$`. A missing leaf or a type mismatch simply doesn't match.
141
+ export type JsonType = "string" | "number" | "boolean" | "object" | "array" | "null"
142
+ // As on scalar fields, operators on one path are ANDed and may be combined.
143
+ export type JsonCondition =
144
+ | JsonValue
145
+ | {
146
+ "$eq"?: JsonValue, "$ne"?: JsonValue, "$not"?: JsonValue,
147
+ "$gt"?: number | string, "$gte"?: number | string,
148
+ "$lt"?: number | string, "$lte"?: number | string,
149
+ "$in"?: JsonValue[], "$notIn"?: JsonValue[],
150
+ "$startsWith"?: string, "$includes"?: string,
151
+ "$contains"?: JsonValue,
152
+ "$exists"?: boolean,
153
+ "$type"?: JsonType
154
+ }
155
+ export type JsonPathWhere = { [path: string]: JsonCondition }
156
+ export type CompareRefValue<T> = T | Only<"$not", T>
157
+ export type CompareRefListValue<T> = Only<"$every", T> | Only<"$some", T> | Only<"$none", T>
158
+
159
+ // Module-index search (@custom): $near/$search hand a raw payload to the field's index provider.
160
+ export type VectorSearch = { vector: number[], k?: number, threshold?: number } // @custom(vector, …)
161
+ export type FullTextSearch = string | { query: string, limit?: number } // @custom(fulltext, …)
162
+ export type CustomSearch = Record<string, any> // other providers
163
+ export type CustomSearchValue<P> = Only<"$near", P> | Only<"$search", P>
164
+
165
+ // Aggregate result: only the requested keys; an empty set yields null (except count)
166
+ export type AggregateResult<TModel, T> =
167
+ (T extends { $count: true } ? { count: number } : {}) &
168
+ (T extends { $sum: string } ? { sum: number | null } : {}) &
169
+ (T extends { $avg: string } ? { avg: number | null } : {}) &
170
+ (T extends { $min: infer F } ? { min: (F extends keyof TModel ? TModel[F] : never) | null } : {}) &
171
+ (T extends { $max: infer F } ? { max: (F extends keyof TModel ? TModel[F] : never) | null } : {})
172
+
173
+ // A lazily-executed operation. `await` runs it as a single request;
174
+ // passing it into `db.$transaction([...])` bundles it into one atomic transaction
175
+ declare const __op: unique symbol
176
+ export type Op<T> = PromiseLike<T> & { readonly [__op]: T }
177
+
178
+ // A transport-neutral operation descriptor and the pluggable transport that runs it. The HTTP transport
179
+ // is selected by passing a URL string; marcidb-embedded provides an in-process FFI transport.
180
+ export type MarciOp = { model: string, action: string, query?: any, data?: any, id?: any }
181
+ export type MarciTransport = {
182
+ exec(op: MarciOp): Promise<any>
183
+ batch(ops: MarciOp[]): Promise<any[]>
184
+ }
185
+
186
+ // ───────────────────────────── query builder ─────────────────────────────
187
+
188
+ // The per-model type bag the codegen emits (`UserTypes`) and `Query<T>` below is parametrised by.
189
+ export type ModelTypes = {
190
+ name: string
191
+ model: any
192
+ id: Record<string, any>
193
+ /** What an empty select returns: id + every scalar field, as a `{ field: true }` shape. */
194
+ scalars: Record<string, true>
195
+ select: Record<string, any>
196
+ query: Record<string, any>
197
+ where: any
198
+ order: Record<string, any>
199
+ insert: any
200
+ update: any
201
+ aggregate: Record<string, any>
202
+ reindex: boolean
203
+ }
204
+
205
+ // A sub-query placed as a value in a select shape — a builder, `count()` or `aggregate()` of the relation's
206
+ // model (`posts: db.post.order("id", "desc").limit(5)`). Branded by model name so a builder of the wrong model
207
+ // is a type error; `[__sel]` is the shape it resolves to (see `Resolve`).
208
+ declare const __sub: unique symbol
209
+ declare const __sel: unique symbol
210
+ export type Sub<Name extends string, Shape = any> = { readonly [__sub]: Name, readonly [__sel]: Shape }
211
+
212
+ // A shape without field keys (only `$`-clauses, or nothing) selects id + every scalar — same rule as the engine.
213
+ export type Effective<T extends ModelTypes, S> = [Exclude<keyof S, ServiceKeys>] extends [never] ? T["scalars"] : S
214
+ // Sub-queries inside a shape resolve to the shape they carry, recursively; `$`-clauses are left alone.
215
+ export type Resolve<S> =
216
+ S extends { readonly [__sel]: infer X } ? Resolve<X>
217
+ : S extends object ? { [K in keyof S]: K extends `$${string}` ? S[K] : Resolve<S[K]> }
218
+ : S
219
+ export type Rows<T extends ModelTypes, Sel> = GetResult<T["model"], Resolve<Effective<T, Sel>>>
220
+ // The bare key value, accepted wherever an id object is (`after(42)` = `after({ id: 42 })`, `delete(42)`).
221
+ export type BareId<I> = I extends { id: infer V } ? V : never
222
+ export type IdArg<I> = I | BareId<I>
223
+
224
+ /**
225
+ * A lazy, immutable query over one model — `db.user` itself is one. Every clause returns a new query, so
226
+ * queries compose (`const active = db.user.where({ active: true })`). `await` runs it as `findMany`; passing
227
+ * it to `$transaction` batches it; placing it in another query's select makes it a sub-select. `Sel` is the
228
+ * projection: id + scalars until `select(...)` sets a shape.
229
+ */
230
+ export interface Query<T extends ModelTypes, Sel = T["scalars"]> extends PromiseLike<Rows<T, Sel>[]> {
231
+ readonly [__op]: Rows<T, Sel>[]
232
+ readonly [__sub]: T["name"]
233
+ readonly [__sel]: Effective<T, Sel>
234
+ /** Filter (marcidb `$where`). Repeated calls are ANDed. */
235
+ where(where: T["where"]): Query<T, Sel>
236
+ /** Sort by one field: `order("age", "desc")` or `order({ age: "desc" })`. */
237
+ order(field: keyof T["order"] & string, direction?: "asc" | "desc"): Query<T, Sel>
238
+ order(order: T["order"]): Query<T, Sel>
239
+ limit(n: number): Query<T, Sel>
240
+ skip(n: number): Query<T, Sel>
241
+ /** Keyset cursor: rows strictly after this id in the current order (`$cursor`). */
242
+ after(id: IdArg<T["id"]>): Query<T, Sel>
243
+ /**
244
+ * The projection. Values are `true`, a nested shape, or a sub-query of the relation's model
245
+ * (`posts: db.post.limit(5)`, `posts: db.post.where({ published: true }).count()`). No argument, or no
246
+ * field keys, selects id + every scalar. `$`-clauses are accepted here too (the object form).
247
+ */
248
+ select<S extends T["query"] = T["scalars"]>(shape?: S): Query<T, S>
249
+ /** The first matching row or `null`. */
250
+ first(): Op<Rows<T, Sel> | null>
251
+ /** Row count; inside a select it becomes `{ count }` for the relation. */
252
+ count(): Op<number> & Sub<T["name"], { $count: true }>
253
+ /** @deprecated pass the filter through the chain: `db.user.where(w).count()` (removed in the next minor). */
254
+ count(query: { $where?: T["where"] }): Op<number> & Sub<T["name"], { $count: true }>
255
+ // `NoInfer`: as a select value the contextual type is `Sub<Name, any>`, which would otherwise win the inference of `A`
256
+ aggregate<A extends T["aggregate"]>(query: A): Op<AggregateResult<T["model"], A>> & Sub<T["name"], NoInfer<A>>
257
+
258
+ insert(data: T["insert"]): Op<T["id"]>
259
+ update(id: IdArg<T["id"]>, data: T["update"]): Op<void>
260
+ /** Applies `data` to every row the chain's `where` matches (all rows without one); resolves to the number of rows. */
261
+ updateMany(data: T["update"]): Op<number>
262
+ /** @deprecated pass the filter through the chain: `db.user.where(w).updateMany(data)` (removed in the next minor). */
263
+ updateMany(query: { $where?: T["where"] }, data: T["update"]): Op<number>
264
+ delete(id: IdArg<T["id"]>): Op<void>
265
+ /**
266
+ * Deletes every row the chain's `where` matches (cascades apply, as for `delete`); resolves to the number
267
+ * deleted. Refuses to run without a `where` — write `.where({})` to mean "every row".
268
+ */
269
+ deleteMany(): Op<number>
270
+
271
+ // ── object form (deprecated): one query object (select shape + $where/$order/$limit/$skip/$cursor)
272
+ /** @deprecated use `.select(query)` — it takes the same object, merged with the chain (removed in the next minor). */
273
+ findMany<Q extends T["query"] = {}>(query?: Q): Op<Rows<T, Q>[]>
274
+ /** @deprecated use `.select(query).first()` (removed in the next minor). */
275
+ findFirst<Q extends T["query"] = {}>(query?: Q): Op<Rows<T, Q> | null>
276
+ }
277
+
278
+ /** `db.<model>`: the root query, plus `reindex()` for models with a `@custom` (vector / full-text) index. */
279
+ export type Collection<T extends ModelTypes> = Query<T> & (T["reindex"] extends true ? { reindex(): Op<{ ok: boolean, indexed: number }> } : {})
280
+
281
+ // ───────────────────────────── builder runtime ─────────────────────────────
282
+
283
+ /** One field of a model, in slot order: `n` name, `k` key | body | one | many, `m` the relation's target model. */
284
+ export type FieldDesc = { n: string; k: "key" | "body" | "one" | "many"; t?: string | null; m?: string };
285
+ /** Model name → its field descriptors (structs included, as relation targets). */
286
+ export type ModelsMeta = Record<string, readonly FieldDesc[]>;
287
+
288
+ export type QueryLayerOptions = {
289
+ models: ModelsMeta;
290
+ /** Runs one operation (a query, or a write) and resolves its result. */
291
+ run(op: MarciOp): Promise<any>;
292
+ /** Hook for `insert` payloads (the lecodes SDK generates uuid ids here). */
293
+ prepareInsert?(model: string, data: any): any;
294
+ };
295
+
296
+ const AGGREGATE_KEYS = ["$count", "$sum", "$avg", "$min", "$max"];
297
+ const and = (a: any, b: any): any => (a ? (b ? { $and: [a, b] } : a) : b);
298
+
299
+ type QueryState = { shape?: Record<string, any>; where?: any; order?: any; limit?: number; skip?: number; cursor?: any };
300
+
301
+ /**
302
+ * The query builder over a set of models and a `run` function. Returns `op(descriptor)` — a lazy operation
303
+ * (`await` runs it, `$transaction` takes its `__op`) — and `collection(model)`, the immutable `db.<model>`
304
+ * root query. Transport-agnostic: the generated client and the embedded/HTTP transports supply `run`.
305
+ */
306
+ export function createQueryLayer(options: QueryLayerOptions): { op: (descriptor: MarciOp) => any; collection: (model: string) => any } {
307
+ const { models, run } = options;
308
+
309
+ // Lazily-executed operation: `await` runs it through the transport as a single op,
310
+ // while `$transaction` takes only the `__op` descriptor and sends them as one batch.
311
+ const op = (descriptor: MarciOp): any => ({
312
+ __op: descriptor,
313
+ then: (onFulfilled?: any, onRejected?: any) => run(descriptor).then(onFulfilled, onRejected),
314
+ catch: (onRejected?: any) => run(descriptor).catch(onRejected),
315
+ finally: (onFinally?: any) => run(descriptor).finally(onFinally),
316
+ });
317
+
318
+ // A field key is anything that isn't a `$`-clause. A shape without field keys selects id + every scalar
319
+ // (the engine's rule too — the client applies it so the binary decoder and older servers see explicit fields).
320
+ const scalarSelect = (model: string): Record<string, true> => {
321
+ const out: Record<string, true> = {};
322
+ for (const f of models[model] ?? []) if (f.k === "key" || f.k === "body") out[f.n] = true;
323
+ return out;
324
+ };
325
+ const keyField = (model: string): string => (models[model] ?? []).find((f) => f.k === "key")?.n ?? "id";
326
+ // `42` → `{ id: 42 }` (the bare value of a single-field key), an object passes through
327
+ const idObject = (model: string, id: any): any => (id !== null && typeof id === "object" ? id : { [keyField(model)]: id });
328
+ // Resolves sub-queries (values carrying `__select`) and fills empty projections, recursively along relations.
329
+ const resolveShape = (model: string, shape: Record<string, any>): Record<string, any> => {
330
+ const out: Record<string, any> = {};
331
+ let fields = 0;
332
+ for (const k in shape) {
333
+ const v = shape[k];
334
+ if (k.charCodeAt(0) === 36 /* $ */) { out[k] = v; continue; }
335
+ if (v !== undefined && v !== false) fields++;
336
+ if (v !== null && typeof v === "object") {
337
+ if ("__select" in v) { out[k] = v.__select; continue; }
338
+ const desc = (models[model] ?? []).find((f) => f.n === k);
339
+ out[k] = desc && desc.m && !AGGREGATE_KEYS.some((a) => a in v) ? resolveShape(desc.m, v) : v;
340
+ continue;
341
+ }
342
+ out[k] = v;
343
+ }
344
+ if (fields === 0) Object.assign(out, scalarSelect(model));
345
+ return out;
346
+ };
347
+
348
+ // `db.<model>` — an immutable builder; each clause returns a new one over the same `run`.
349
+ const collection = (model: string): any => {
350
+ const make = (st: QueryState): any => {
351
+ // The wire query: the (object-form) `query` merged over the chain's state.
352
+ const build = (query?: Record<string, any>): Record<string, any> => {
353
+ const q = resolveShape(model, { ...(st.shape ?? {}), ...(query ?? {}) });
354
+ const where = and(st.where, q.$where);
355
+ if (where) q.$where = where; else delete q.$where;
356
+ if (st.order && !q.$order) q.$order = st.order;
357
+ if (st.limit !== undefined && q.$limit === undefined) q.$limit = st.limit;
358
+ if (st.skip !== undefined && q.$skip === undefined) q.$skip = st.skip;
359
+ if (st.cursor !== undefined && q.$cursor === undefined) q.$cursor = st.cursor;
360
+ return q;
361
+ };
362
+ const whereOnly = (query?: Record<string, any>): Record<string, any> => {
363
+ const w = and(st.where, query && query.$where);
364
+ return w ? { $where: w } : {};
365
+ };
366
+ const findMany = (): MarciOp => ({ model, action: "findMany", query: build() });
367
+ return {
368
+ get __op() { return findMany(); },
369
+ get __select() { return build(); },
370
+ then: (onFulfilled?: any, onRejected?: any) => run(findMany()).then(onFulfilled, onRejected),
371
+ catch: (onRejected?: any) => run(findMany()).catch(onRejected),
372
+ finally: (onFinally?: any) => run(findMany()).finally(onFinally),
373
+
374
+ where: (where: any) => make({ ...st, where: and(st.where, where) }),
375
+ order: (field: any, direction?: "asc" | "desc") => make({ ...st, order: typeof field === "string" ? { [field]: direction ?? "asc" } : field }),
376
+ limit: (n: number) => make({ ...st, limit: n }),
377
+ skip: (n: number) => make({ ...st, skip: n }),
378
+ after: (id: any) => make({ ...st, cursor: idObject(model, id) }),
379
+ select: (shape?: Record<string, any>) => make({ ...st, shape: shape ?? {} }),
380
+ first: () => op({ model, action: "findFirst", query: build() }),
381
+ count: (query?: Record<string, any>) => {
382
+ const q = whereOnly(query);
383
+ return Object.assign(op({ model, action: "count", query: q }), { __select: { $count: true, ...q } });
384
+ },
385
+ aggregate: (query: Record<string, any>) => {
386
+ const q = { ...(query ?? {}), ...whereOnly(query) };
387
+ if (!q.$where) delete q.$where;
388
+ return Object.assign(op({ model, action: "aggregate", query: q }), { __select: q });
389
+ },
390
+
391
+ insert: (data: any) => op({ model, action: "insert", data: options.prepareInsert ? options.prepareInsert(model, data) : data }),
392
+ update: (id: any, data: any) => op({ model, action: "update", id: idObject(model, id), data }),
393
+ // `updateMany(data)`; the deprecated `updateMany(query, data)` form is told apart by arity
394
+ updateMany: (a: any, b?: any) => (b === undefined
395
+ ? op({ model, action: "updateMany", query: whereOnly(), data: a })
396
+ : op({ model, action: "updateMany", query: whereOnly(a), data: b })),
397
+ delete: (id: any) => op({ model, action: "delete", id: idObject(model, id) }),
398
+ deleteMany: () => {
399
+ if (st.where === undefined) throw new Error(`marcidb: ${model}.deleteMany() needs a where — use .where({}) to delete every row`);
400
+ return op({ model, action: "deleteMany", query: whereOnly() });
401
+ },
402
+ reindex: () => op({ model, action: "$reindex" }),
403
+
404
+ findMany: (query?: Record<string, any>) => op({ model, action: "findMany", query: build(query) }),
405
+ findFirst: (query?: Record<string, any>) => op({ model, action: "findFirst", query: build(query) }),
406
+ };
407
+ };
408
+ return make({});
409
+ };
410
+
411
+ return { op, collection };
412
+ }