@slopware/sloppy-darwin-x64 0.1.0-alpha.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 (434) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +5 -0
  3. package/bin/sloppy +0 -0
  4. package/bin/sloppyc +0 -0
  5. package/docs/KNOWN_LIMITATIONS.md +16 -0
  6. package/docs/LICENSES.md +6 -0
  7. package/docs/NOTICE.md +8 -0
  8. package/examples/README.md +140 -0
  9. package/examples/auth-api/README.md +20 -0
  10. package/examples/auth-api/app.js +61 -0
  11. package/examples/auth-api/appsettings.json +7 -0
  12. package/examples/auth-api/sloppy.json +5 -0
  13. package/examples/cache-basic/README.md +9 -0
  14. package/examples/cache-basic/app.js +32 -0
  15. package/examples/cache-hybrid-postgres/README.md +10 -0
  16. package/examples/cache-hybrid-postgres/app.js +27 -0
  17. package/examples/cache-output-api/README.md +10 -0
  18. package/examples/cache-output-api/app.js +35 -0
  19. package/examples/codec-base64-hex/README.md +14 -0
  20. package/examples/codec-base64-hex/app.js +15 -0
  21. package/examples/codec-checksums/README.md +15 -0
  22. package/examples/codec-checksums/app.js +8 -0
  23. package/examples/codec-compression/README.md +13 -0
  24. package/examples/codec-compression/app.js +9 -0
  25. package/examples/codec-streaming-compression/README.md +19 -0
  26. package/examples/codec-streaming-compression/app.js +16 -0
  27. package/examples/codec-text-binary/README.md +16 -0
  28. package/examples/codec-text-binary/app.js +17 -0
  29. package/examples/compiler-hello/README.md +71 -0
  30. package/examples/compiler-hello/app.js +7 -0
  31. package/examples/compiler-hello/expected/app.js +8 -0
  32. package/examples/compiler-hello/expected/app.js.map +53 -0
  33. package/examples/compiler-hello/expected/app.plan.json +229 -0
  34. package/examples/compiler-hello/expected/routes.slrt +0 -0
  35. package/examples/config-basic/README.md +13 -0
  36. package/examples/config-basic/app.js +13 -0
  37. package/examples/config-basic/appsettings.json +7 -0
  38. package/examples/config-secrets-redaction/README.md +9 -0
  39. package/examples/config-secrets-redaction/app.js +9 -0
  40. package/examples/config-secrets-redaction/appsettings.json +5 -0
  41. package/examples/config-strict-mode/README.md +7 -0
  42. package/examples/config-strict-mode/app.js +10 -0
  43. package/examples/config-strict-mode/appsettings.json +7 -0
  44. package/examples/configured-api/README.md +38 -0
  45. package/examples/configured-api/app.js +12 -0
  46. package/examples/configured-api/appsettings.Development.json +5 -0
  47. package/examples/configured-api/appsettings.json +6 -0
  48. package/examples/configured-api/sloppy.json +5 -0
  49. package/examples/core-config-secrets/README.md +10 -0
  50. package/examples/core-config-secrets/app.js +15 -0
  51. package/examples/core-fs-time-codec/README.md +9 -0
  52. package/examples/core-fs-time-codec/app.js +8 -0
  53. package/examples/core-network-time-codec/README.md +11 -0
  54. package/examples/core-network-time-codec/app.js +20 -0
  55. package/examples/core-policy-audit/README.md +7 -0
  56. package/examples/core-policy-audit/app.js +22 -0
  57. package/examples/core-process-time-codec/README.md +8 -0
  58. package/examples/core-process-time-codec/app.js +28 -0
  59. package/examples/core-worker-time/README.md +8 -0
  60. package/examples/core-worker-time/app.js +17 -0
  61. package/examples/crypto-hash-hmac/README.md +17 -0
  62. package/examples/crypto-hash-hmac/app.js +29 -0
  63. package/examples/crypto-password/README.md +21 -0
  64. package/examples/crypto-password/app.js +12 -0
  65. package/examples/crypto-random-token/README.md +16 -0
  66. package/examples/crypto-random-token/app.js +12 -0
  67. package/examples/crypto-secret-constant-time/README.md +21 -0
  68. package/examples/crypto-secret-constant-time/app.js +15 -0
  69. package/examples/data-foundation/README.md +39 -0
  70. package/examples/data-foundation/app.js +63 -0
  71. package/examples/dependency-graph/README.md +19 -0
  72. package/examples/dependency-graph/fixtures/graph-helper/index.js +3 -0
  73. package/examples/dependency-graph/fixtures/graph-helper/package.json +6 -0
  74. package/examples/dependency-graph/package.json +7 -0
  75. package/examples/dependency-graph/public/message.txt +1 -0
  76. package/examples/dependency-graph/sloppy.json +9 -0
  77. package/examples/dependency-graph/src/main.ts +8 -0
  78. package/examples/dogfood/README.md +23 -0
  79. package/examples/dogfood/dogfood.json +136 -0
  80. package/examples/dynamic-module-include/README.md +20 -0
  81. package/examples/dynamic-module-include/public/readme.txt +1 -0
  82. package/examples/dynamic-module-include/sloppy.json +12 -0
  83. package/examples/dynamic-module-include/src/main.ts +6 -0
  84. package/examples/dynamic-module-include/src/plugins/alpha.js +3 -0
  85. package/examples/dynamic-module-include/src/plugins/beta.js +3 -0
  86. package/examples/ergonomics/README.md +42 -0
  87. package/examples/ergonomics/app.js +38 -0
  88. package/examples/framework-controller/README.md +12 -0
  89. package/examples/framework-controller/app.js +31 -0
  90. package/examples/framework-di-services/README.md +17 -0
  91. package/examples/framework-di-services/app.ts +40 -0
  92. package/examples/framework-explicit-binding/README.md +12 -0
  93. package/examples/framework-explicit-binding/app.ts +34 -0
  94. package/examples/framework-hello/README.md +16 -0
  95. package/examples/framework-hello/app.ts +16 -0
  96. package/examples/framework-postgres-crud/README.md +73 -0
  97. package/examples/framework-postgres-crud/app.ts +64 -0
  98. package/examples/framework-sqlite-crud/README.md +52 -0
  99. package/examples/framework-sqlite-crud/app.ts +90 -0
  100. package/examples/framework-sqlite-crud/appsettings.json +11 -0
  101. package/examples/framework-sqlserver-crud/README.md +73 -0
  102. package/examples/framework-sqlserver-crud/app.ts +64 -0
  103. package/examples/framework-validation-errors/README.md +12 -0
  104. package/examples/framework-validation-errors/app.ts +16 -0
  105. package/examples/fs-basic/README.md +24 -0
  106. package/examples/fs-basic/app.js +12 -0
  107. package/examples/fs-roots-policy/README.md +14 -0
  108. package/examples/fs-roots-policy/app.js +4 -0
  109. package/examples/fs-streams/README.md +18 -0
  110. package/examples/fs-streams/app.js +11 -0
  111. package/examples/fs-watch/README.md +19 -0
  112. package/examples/fs-watch/app.js +11 -0
  113. package/examples/hello/README.md +63 -0
  114. package/examples/hello/app.js +19 -0
  115. package/examples/hello-minimal/README.md +51 -0
  116. package/examples/hello-minimal/sloppy.json +5 -0
  117. package/examples/hello-minimal/src/main.ts +9 -0
  118. package/examples/http-client-basic/README.md +11 -0
  119. package/examples/http-client-basic/app.js +46 -0
  120. package/examples/http-client-generated/README.md +22 -0
  121. package/examples/http-client-generated/openapi.json +45 -0
  122. package/examples/http-client-resilience/README.md +4 -0
  123. package/examples/http-client-resilience/app.js +38 -0
  124. package/examples/http-client-runtime-loopback/README.md +24 -0
  125. package/examples/http-client-testhost/README.md +4 -0
  126. package/examples/http-client-testhost/app.js +27 -0
  127. package/examples/http-client-testhost-package-mock/README.md +26 -0
  128. package/examples/http-client-typed/README.md +5 -0
  129. package/examples/http-client-typed/app.js +33 -0
  130. package/examples/modules-api/README.md +30 -0
  131. package/examples/modules-api/app.js +9 -0
  132. package/examples/modules-api/modules/routes.js +16 -0
  133. package/examples/modules-api/sloppy.json +5 -0
  134. package/examples/modules-basic/README.md +32 -0
  135. package/examples/modules-basic/app.js +41 -0
  136. package/examples/net-deadline-cancel/README.md +13 -0
  137. package/examples/net-deadline-cancel/app.js +34 -0
  138. package/examples/net-local-ipc/README.md +12 -0
  139. package/examples/net-local-ipc/app.js +46 -0
  140. package/examples/net-policy-strict/README.md +12 -0
  141. package/examples/net-policy-strict/app.js +34 -0
  142. package/examples/net-tcp-client/README.md +10 -0
  143. package/examples/net-tcp-client/app.js +23 -0
  144. package/examples/net-tcp-echo/README.md +11 -0
  145. package/examples/net-tcp-echo/app.js +45 -0
  146. package/examples/net-tcp-server/README.md +10 -0
  147. package/examples/net-tcp-server/app.js +28 -0
  148. package/examples/node-compat-path-events/README.md +15 -0
  149. package/examples/node-compat-path-events/sloppy.json +6 -0
  150. package/examples/node-compat-path-events/src/main.ts +15 -0
  151. package/examples/ops-compiler/README.md +9 -0
  152. package/examples/ops-compiler/app.js +26 -0
  153. package/examples/ops-health-metrics-management/README.md +14 -0
  154. package/examples/ops-health-metrics-management/app.js +24 -0
  155. package/examples/orm-basic/README.md +17 -0
  156. package/examples/orm-basic/app.js +82 -0
  157. package/examples/orm-cursor-export/README.md +16 -0
  158. package/examples/orm-cursor-export/app.js +28 -0
  159. package/examples/orm-migrations/README.md +14 -0
  160. package/examples/orm-migrations/migrations/.gitkeep +1 -0
  161. package/examples/orm-migrations/sloppy.json +9 -0
  162. package/examples/orm-migrations/src/app.ts +34 -0
  163. package/examples/orm-relations-includes/README.md +10 -0
  164. package/examples/orm-relations-includes/app.js +47 -0
  165. package/examples/orm-testservices/README.md +37 -0
  166. package/examples/orm-testservices/test.mjs +32 -0
  167. package/examples/os-runtime-api/README.md +11 -0
  168. package/examples/os-runtime-api/app.js +44 -0
  169. package/examples/package-zod-like/README.md +28 -0
  170. package/examples/package-zod-like/fixtures/zod-like/index.js +48 -0
  171. package/examples/package-zod-like/fixtures/zod-like/package.json +12 -0
  172. package/examples/package-zod-like/package.json +7 -0
  173. package/examples/package-zod-like/sloppy.json +6 -0
  174. package/examples/package-zod-like/src/main.ts +16 -0
  175. package/examples/postgres-basic/README.md +31 -0
  176. package/examples/postgres-basic/app.js +50 -0
  177. package/examples/prealpha-control-plane/README.md +50 -0
  178. package/examples/prealpha-control-plane/appsettings.Development.json +11 -0
  179. package/examples/prealpha-control-plane/appsettings.json +15 -0
  180. package/examples/prealpha-control-plane/sloppy.json +5 -0
  181. package/examples/prealpha-control-plane/src/db/schema.js +7 -0
  182. package/examples/prealpha-control-plane/src/db/seed.js +6 -0
  183. package/examples/prealpha-control-plane/src/main.js +21 -0
  184. package/examples/prealpha-control-plane/src/routes/apps.js +34 -0
  185. package/examples/prealpha-control-plane/src/routes/builds.js +25 -0
  186. package/examples/prealpha-control-plane/src/routes/deployments.js +19 -0
  187. package/examples/prealpha-control-plane/src/routes/diagnostics.js +11 -0
  188. package/examples/prealpha-control-plane/src/routes/health.js +27 -0
  189. package/examples/prealpha-control-plane/src/routes/projects.js +38 -0
  190. package/examples/prealpha-control-plane/src/services/diagnosticsSink.js +11 -0
  191. package/examples/prealpha-control-plane/src/services/repositories.js +9 -0
  192. package/examples/prealpha-control-plane/src/validation/schemas.js +6 -0
  193. package/examples/program-fs-process/README.md +31 -0
  194. package/examples/program-fs-process/sloppy.json +9 -0
  195. package/examples/program-fs-process/src/main.ts +27 -0
  196. package/examples/program-hello/README.md +32 -0
  197. package/examples/program-hello/main.ts +8 -0
  198. package/examples/program-hello/message.ts +1 -0
  199. package/examples/program-hello/sloppy.json +5 -0
  200. package/examples/rate-limit-auth/README.md +3 -0
  201. package/examples/rate-limit-auth/app.js +14 -0
  202. package/examples/rate-limit-basic/README.md +3 -0
  203. package/examples/rate-limit-basic/app.js +13 -0
  204. package/examples/rate-limit-redis/README.md +5 -0
  205. package/examples/rate-limit-redis/app.js +20 -0
  206. package/examples/rate-limit-testhost/README.md +4 -0
  207. package/examples/rate-limit-testhost/app.js +13 -0
  208. package/examples/rate-limit-websocket/README.md +3 -0
  209. package/examples/rate-limit-websocket/app.js +16 -0
  210. package/examples/realtime-auth/README.md +8 -0
  211. package/examples/realtime-auth/app.js +25 -0
  212. package/examples/realtime-auth/test.mjs +43 -0
  213. package/examples/realtime-chat/README.md +8 -0
  214. package/examples/realtime-chat/app.js +32 -0
  215. package/examples/realtime-chat/test.mjs +52 -0
  216. package/examples/realtime-dashboard/README.md +20 -0
  217. package/examples/realtime-dashboard/app.js +37 -0
  218. package/examples/realtime-presence/README.md +8 -0
  219. package/examples/realtime-presence/app.js +32 -0
  220. package/examples/realtime-presence/test.mjs +50 -0
  221. package/examples/realtime-testhost/README.md +8 -0
  222. package/examples/realtime-testhost/test.mjs +31 -0
  223. package/examples/redis-basic/README.md +17 -0
  224. package/examples/redis-basic/app.js +39 -0
  225. package/examples/redis-cache/README.md +14 -0
  226. package/examples/redis-cache/app.js +36 -0
  227. package/examples/redis-locks/README.md +13 -0
  228. package/examples/redis-locks/app.js +49 -0
  229. package/examples/request-context/README.md +32 -0
  230. package/examples/request-context/app.js +15 -0
  231. package/examples/sqlite-basic/README.md +52 -0
  232. package/examples/sqlite-basic/app.js +56 -0
  233. package/examples/sqlserver-basic/README.md +36 -0
  234. package/examples/sqlserver-basic/app.js +59 -0
  235. package/examples/static-files-basic/README.md +11 -0
  236. package/examples/static-files-basic/app.js +12 -0
  237. package/examples/static-files-basic/public/app.js +1 -0
  238. package/examples/static-files-basic/public/site.css +3 -0
  239. package/examples/static-files-package/README.md +12 -0
  240. package/examples/static-files-package/app.js +10 -0
  241. package/examples/static-files-package/public/index.html +2 -0
  242. package/examples/static-files-precompressed/README.md +12 -0
  243. package/examples/static-files-precompressed/app.js +11 -0
  244. package/examples/static-files-precompressed/public/app.js +1 -0
  245. package/examples/static-files-precompressed/public/app.js.br +0 -0
  246. package/examples/static-files-precompressed/public/app.js.gz +0 -0
  247. package/examples/static-files-spa/README.md +12 -0
  248. package/examples/static-files-spa/app.js +16 -0
  249. package/examples/static-files-spa/dist/assets/app.js +1 -0
  250. package/examples/static-files-spa/dist/index.html +4 -0
  251. package/examples/static-files-testhost/README.md +8 -0
  252. package/examples/static-files-testhost/app.js +13 -0
  253. package/examples/static-files-testhost/public/app.js +1 -0
  254. package/examples/static-files-testhost/public/app.js.gz +0 -0
  255. package/examples/static-files-testhost/test.mjs +38 -0
  256. package/examples/testhost-basic/README.md +26 -0
  257. package/examples/testhost-db/README.md +31 -0
  258. package/examples/testservices-postgres/README.md +68 -0
  259. package/examples/testservices-redis/README.md +71 -0
  260. package/examples/testservices-sqlserver/README.md +75 -0
  261. package/examples/time-basic/README.md +18 -0
  262. package/examples/time-basic/app.js +12 -0
  263. package/examples/time-deadline-cancellation/README.md +11 -0
  264. package/examples/time-deadline-cancellation/app.js +27 -0
  265. package/examples/time-fake-clock/README.md +14 -0
  266. package/examples/time-fake-clock/app.js +25 -0
  267. package/examples/time-interval-schedule/README.md +13 -0
  268. package/examples/time-interval-schedule/app.js +60 -0
  269. package/examples/users-api-sqlite/README.md +74 -0
  270. package/examples/users-api-sqlite/app.js +11 -0
  271. package/examples/users-api-sqlite/appsettings.Development.json +11 -0
  272. package/examples/users-api-sqlite/appsettings.json +11 -0
  273. package/examples/users-api-sqlite/modules/users.js +40 -0
  274. package/examples/users-api-sqlite/sloppy.json +5 -0
  275. package/examples/validation-errors/README.md +36 -0
  276. package/examples/validation-errors/app.js +14 -0
  277. package/examples/validation-errors/invalid-user.http +6 -0
  278. package/examples/validation-errors/sloppy.json +5 -0
  279. package/examples/web-dynamic-routes/README.md +17 -0
  280. package/examples/web-dynamic-routes/app.ts +27 -0
  281. package/examples/webhooks-basic/README.md +11 -0
  282. package/examples/webhooks-basic/app.js +48 -0
  283. package/examples/websocket-auth/README.md +8 -0
  284. package/examples/websocket-auth/app.js +16 -0
  285. package/examples/websocket-echo/README.md +9 -0
  286. package/examples/websocket-echo/app.js +36 -0
  287. package/examples/websocket-json-schema/README.md +5 -0
  288. package/examples/websocket-json-schema/app.js +25 -0
  289. package/examples/websocket-testhost/README.md +11 -0
  290. package/examples/websocket-testhost/test.mjs +49 -0
  291. package/examples/workers-background-service/README.md +7 -0
  292. package/examples/workers-background-service/app.js +16 -0
  293. package/examples/workers-js-isolate/README.md +8 -0
  294. package/examples/workers-js-isolate/app.js +19 -0
  295. package/examples/workers-js-isolate/workers/parser.ts +11 -0
  296. package/examples/workers-shutdown/README.md +6 -0
  297. package/examples/workers-shutdown/app.js +26 -0
  298. package/examples/workers-workerpool/README.md +6 -0
  299. package/examples/workers-workerpool/app.js +23 -0
  300. package/examples/workers-workqueue/README.md +8 -0
  301. package/examples/workers-workqueue/app.js +24 -0
  302. package/manifest.json +59 -0
  303. package/package.json +31 -0
  304. package/stdlib/sloppy/README.md +177 -0
  305. package/stdlib/sloppy/app.js +2142 -0
  306. package/stdlib/sloppy/auth.js +1813 -0
  307. package/stdlib/sloppy/bootstrap.manifest.json +83 -0
  308. package/stdlib/sloppy/cache.js +1542 -0
  309. package/stdlib/sloppy/codec.js +1153 -0
  310. package/stdlib/sloppy/config.js +61 -0
  311. package/stdlib/sloppy/crypto.js +312 -0
  312. package/stdlib/sloppy/data.js +2945 -0
  313. package/stdlib/sloppy/ffi.js +185 -0
  314. package/stdlib/sloppy/fs.js +795 -0
  315. package/stdlib/sloppy/health.js +603 -0
  316. package/stdlib/sloppy/http.js +1595 -0
  317. package/stdlib/sloppy/index.js +59 -0
  318. package/stdlib/sloppy/internal/bytes.js +31 -0
  319. package/stdlib/sloppy/internal/capabilities.js +155 -0
  320. package/stdlib/sloppy/internal/config.js +640 -0
  321. package/stdlib/sloppy/internal/disposable.js +31 -0
  322. package/stdlib/sloppy/internal/headers.js +63 -0
  323. package/stdlib/sloppy/internal/intrinsics.js +2 -0
  324. package/stdlib/sloppy/internal/json.js +20 -0
  325. package/stdlib/sloppy/internal/logging.js +278 -0
  326. package/stdlib/sloppy/internal/modules.js +405 -0
  327. package/stdlib/sloppy/internal/redaction.js +87 -0
  328. package/stdlib/sloppy/internal/routes.js +2279 -0
  329. package/stdlib/sloppy/internal/runtime-classic.js +19837 -0
  330. package/stdlib/sloppy/internal/services.js +690 -0
  331. package/stdlib/sloppy/internal/shared.js +32 -0
  332. package/stdlib/sloppy/internal/testhost-diagnostics.js +88 -0
  333. package/stdlib/sloppy/internal/testhost-http-server.js +238 -0
  334. package/stdlib/sloppy/internal/testhost-http.js +118 -0
  335. package/stdlib/sloppy/internal/testhost-loopback.js +50 -0
  336. package/stdlib/sloppy/internal/testservices-docker.js +154 -0
  337. package/stdlib/sloppy/internal/validation.js +117 -0
  338. package/stdlib/sloppy/metrics.js +427 -0
  339. package/stdlib/sloppy/net.js +5208 -0
  340. package/stdlib/sloppy/node/assert/strict.js +39 -0
  341. package/stdlib/sloppy/node/assert.js +228 -0
  342. package/stdlib/sloppy/node/buffer.js +247 -0
  343. package/stdlib/sloppy/node/console.js +33 -0
  344. package/stdlib/sloppy/node/constants.js +9 -0
  345. package/stdlib/sloppy/node/crypto.js +89 -0
  346. package/stdlib/sloppy/node/diagnostics_channel.js +41 -0
  347. package/stdlib/sloppy/node/events.js +113 -0
  348. package/stdlib/sloppy/node/fs/promises.js +27 -0
  349. package/stdlib/sloppy/node/fs.js +280 -0
  350. package/stdlib/sloppy/node/http.js +11 -0
  351. package/stdlib/sloppy/node/https.js +11 -0
  352. package/stdlib/sloppy/node/module.js +40 -0
  353. package/stdlib/sloppy/node/os.js +22 -0
  354. package/stdlib/sloppy/node/path.js +78 -0
  355. package/stdlib/sloppy/node/perf_hooks.js +12 -0
  356. package/stdlib/sloppy/node/process.js +129 -0
  357. package/stdlib/sloppy/node/querystring.js +21 -0
  358. package/stdlib/sloppy/node/stream/promises.js +3 -0
  359. package/stdlib/sloppy/node/stream.js +132 -0
  360. package/stdlib/sloppy/node/string_decoder.js +23 -0
  361. package/stdlib/sloppy/node/timers.js +26 -0
  362. package/stdlib/sloppy/node/tty.js +18 -0
  363. package/stdlib/sloppy/node/url.js +17 -0
  364. package/stdlib/sloppy/node/util.js +95 -0
  365. package/stdlib/sloppy/node/zlib.js +72 -0
  366. package/stdlib/sloppy/orm.js +2188 -0
  367. package/stdlib/sloppy/os.js +580 -0
  368. package/stdlib/sloppy/problem-details.js +29 -0
  369. package/stdlib/sloppy/providers/sqlite.js +26 -0
  370. package/stdlib/sloppy/rate-limit.js +856 -0
  371. package/stdlib/sloppy/realtime.js +1508 -0
  372. package/stdlib/sloppy/redis.js +1272 -0
  373. package/stdlib/sloppy/request-id.js +184 -0
  374. package/stdlib/sloppy/request-logging.js +101 -0
  375. package/stdlib/sloppy/results.js +933 -0
  376. package/stdlib/sloppy/schema.js +546 -0
  377. package/stdlib/sloppy/testing.js +4081 -0
  378. package/stdlib/sloppy/testservices.js +1041 -0
  379. package/stdlib/sloppy/time.js +894 -0
  380. package/stdlib/sloppy/webhooks.js +1330 -0
  381. package/stdlib/sloppy/workers.js +986 -0
  382. package/templates/api/README.md +82 -0
  383. package/templates/api/appsettings.Development.json +14 -0
  384. package/templates/api/appsettings.json +13 -0
  385. package/templates/api/data/.gitkeep +1 -0
  386. package/templates/api/gitignore +4 -0
  387. package/templates/api/migrations/0001_create_users.sql +1 -0
  388. package/templates/api/package.json +16 -0
  389. package/templates/api/public/hello.txt +1 -0
  390. package/templates/api/sloppy.json +14 -0
  391. package/templates/api/src/config.ts +1 -0
  392. package/templates/api/src/db/migrate.ts +14 -0
  393. package/templates/api/src/db/schema.ts +4 -0
  394. package/templates/api/src/db/usersRepository.ts +23 -0
  395. package/templates/api/src/main.ts +18 -0
  396. package/templates/api/src/models/user.ts +7 -0
  397. package/templates/api/src/routes/health.ts +20 -0
  398. package/templates/api/src/routes/users.ts +40 -0
  399. package/templates/api/src/services/usersService.ts +21 -0
  400. package/templates/api/tsconfig.json +15 -0
  401. package/templates/cli/README.md +16 -0
  402. package/templates/cli/gitignore +2 -0
  403. package/templates/cli/package.json +13 -0
  404. package/templates/cli/sloppy.json +6 -0
  405. package/templates/cli/src/commands/echo.ts +9 -0
  406. package/templates/cli/src/commands/inspect.ts +20 -0
  407. package/templates/cli/src/main.ts +50 -0
  408. package/templates/cli/tsconfig.json +15 -0
  409. package/templates/minimal-api/README.md +14 -0
  410. package/templates/minimal-api/gitignore +3 -0
  411. package/templates/minimal-api/package.json +14 -0
  412. package/templates/minimal-api/sloppy.json +5 -0
  413. package/templates/minimal-api/src/main.ts +9 -0
  414. package/templates/minimal-api/tsconfig.json +15 -0
  415. package/templates/node-compat/README.md +40 -0
  416. package/templates/node-compat/gitignore +2 -0
  417. package/templates/node-compat/package.json +11 -0
  418. package/templates/node-compat/sloppy.json +6 -0
  419. package/templates/node-compat/src/main.ts +40 -0
  420. package/templates/package-api/README.md +44 -0
  421. package/templates/package-api/fixtures/validator-lite/index.js +7 -0
  422. package/templates/package-api/fixtures/validator-lite/package.json +6 -0
  423. package/templates/package-api/gitignore +3 -0
  424. package/templates/package-api/package.json +17 -0
  425. package/templates/package-api/sloppy.json +5 -0
  426. package/templates/package-api/src/main.ts +10 -0
  427. package/templates/package-api/src/routes/health.ts +5 -0
  428. package/templates/package-api/src/routes/users.ts +12 -0
  429. package/templates/package-api/tsconfig.json +15 -0
  430. package/templates/program/README.md +12 -0
  431. package/templates/program/gitignore +1 -0
  432. package/templates/program/package.json +10 -0
  433. package/templates/program/sloppy.json +6 -0
  434. package/templates/program/src/main.ts +9 -0
@@ -0,0 +1,2945 @@
1
+ import { isPlainObject } from "./internal/validation.js";
2
+ import { Directory, File } from "./fs.js";
3
+
4
+ const QUERY_MARKER = "__sloppyQuery";
5
+ const DB_VALUE_MARKER = Symbol("sloppyDbValue");
6
+ const DB_BRIDGE_VALUE_MARKER = "__sloppyDbValue";
7
+ const DB_RESULT_MODES = Object.freeze({
8
+ object: true,
9
+ raw: true,
10
+ });
11
+ const POSTGRES_MAX_POOL_CONNECTIONS = 256;
12
+ const SQLSERVER_MAX_POOL_CONNECTIONS = 256;
13
+ const DB_VALUE_KINDS = Object.freeze({
14
+ decimal: true,
15
+ uuid: true,
16
+ date: true,
17
+ time: true,
18
+ localDateTime: true,
19
+ instant: true,
20
+ offsetDateTime: true,
21
+ json: true,
22
+ rawJson: true,
23
+ bytes: true,
24
+ });
25
+ const LOWERED_QUERIES = new WeakSet();
26
+ const REAL_PROVIDER_HANDLES = new WeakMap();
27
+ const PLACEHOLDER_STYLES = Object.freeze({
28
+ question: (index) => ({
29
+ text: "?",
30
+ name: null,
31
+ position: index,
32
+ }),
33
+ postgres: (index) => ({
34
+ text: `$${index}`,
35
+ name: null,
36
+ position: index,
37
+ }),
38
+ named: (index) => ({
39
+ text: `@p${index}`,
40
+ name: `p${index}`,
41
+ position: index,
42
+ }),
43
+ });
44
+ const MIGRATIONS_TABLE = "_sloppy_migrations";
45
+ const MIGRATION_HASH_PREFIX = "fnv1a32:";
46
+ const MIGRATION_PROVIDER_KINDS = Object.freeze({
47
+ sqlite: true,
48
+ postgres: true,
49
+ sqlserver: true,
50
+ });
51
+
52
+ function dbValueToString(kind, value) {
53
+ if (kind === "json") {
54
+ return JSON.stringify(value);
55
+ }
56
+ return String(value);
57
+ }
58
+
59
+ function isKnownDbValueKind(kind) {
60
+ return typeof kind === "string"
61
+ && Object.prototype.hasOwnProperty.call(DB_VALUE_KINDS, kind);
62
+ }
63
+
64
+ function createDbValue(kind, value) {
65
+ if (!isKnownDbValueKind(kind)) {
66
+ throw new TypeError("Sloppy sql value wrapper kind is not supported.");
67
+ }
68
+ const storedValue = kind === "bytes" ? new Uint8Array(value) : value;
69
+ const wrapper = {
70
+ kind,
71
+ toString() {
72
+ return dbValueToString(kind, storedValue);
73
+ },
74
+ };
75
+ Object.defineProperties(wrapper, {
76
+ [DB_VALUE_MARKER]: {
77
+ value: true,
78
+ },
79
+ [DB_BRIDGE_VALUE_MARKER]: {
80
+ value: true,
81
+ },
82
+ value: {
83
+ enumerable: true,
84
+ get() {
85
+ return kind === "bytes" ? new Uint8Array(storedValue) : storedValue;
86
+ },
87
+ },
88
+ });
89
+ return Object.freeze(wrapper);
90
+ }
91
+
92
+ function isDbValue(value) {
93
+ return value !== null
94
+ && typeof value === "object"
95
+ && Object.isFrozen(value)
96
+ && isKnownDbValueKind(value.kind)
97
+ && (
98
+ value[DB_VALUE_MARKER] === true
99
+ || (
100
+ value[DB_BRIDGE_VALUE_MARKER] === true
101
+ && Object.prototype.toString.call(value) === "[object String]"
102
+ )
103
+ );
104
+ }
105
+
106
+ function requireStringValue(value, operation) {
107
+ if (typeof value !== "string" || value.length === 0) {
108
+ throw new TypeError(`Sloppy ${operation} value must be a non-empty string.`);
109
+ }
110
+ return value;
111
+ }
112
+
113
+ function normalizeMigrationOptions(options) {
114
+ if (!isPlainObject(options)) {
115
+ throw new TypeError("Sloppy Migrations options must be a plain object.");
116
+ }
117
+ const provider = options.provider;
118
+ const path = options.path;
119
+ if (typeof provider !== "string" || provider.length === 0) {
120
+ throw new TypeError("Sloppy Migrations provider must be a non-empty string.");
121
+ }
122
+ if (MIGRATION_PROVIDER_KINDS[provider] !== true) {
123
+ throw new TypeError("Sloppy Migrations provider must be sqlite, postgres, or sqlserver.");
124
+ }
125
+ if (typeof path !== "string" || path.length === 0) {
126
+ throw new TypeError("Sloppy Migrations path must be a non-empty string.");
127
+ }
128
+ const slash = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
129
+ const directory = slash < 0 ? "." : path.slice(0, slash);
130
+ const pattern = slash < 0 ? path : path.slice(slash + 1);
131
+ const parts = path.split(/[\\/]/);
132
+ if (
133
+ pattern !== "*.sql" ||
134
+ directory === "." ||
135
+ path.startsWith("/") ||
136
+ path.startsWith("\\") ||
137
+ path.startsWith("./") ||
138
+ path.startsWith("../") ||
139
+ /^[A-Za-z]:[\\/]/.test(path) ||
140
+ path.includes("://") ||
141
+ parts.includes(".") ||
142
+ parts.includes("..")
143
+ ) {
144
+ throw new Error(`sloppy: migration path is unsupported
145
+
146
+ Provider:
147
+ ${provider}
148
+
149
+ Path:
150
+ ${path}
151
+
152
+ Fix:
153
+ Use a project-relative directory glob ending in *.sql, for example migrations/*.sql.`);
154
+ }
155
+ return { provider, path, directory };
156
+ }
157
+
158
+ function migrationFsPath(path) {
159
+ if (
160
+ path === "." ||
161
+ path.startsWith("/") ||
162
+ /^[A-Za-z]:[\\/]/.test(path) ||
163
+ path.startsWith("./") ||
164
+ path.startsWith("../") ||
165
+ path.includes("://")
166
+ ) {
167
+ return path;
168
+ }
169
+ return `./${path}`;
170
+ }
171
+
172
+ function migrationHash(text) {
173
+ let hash = 0x811c9dc5;
174
+ const addByte = (value) => {
175
+ hash ^= value & 0xff;
176
+ hash = Math.imul(hash, 0x01000193) >>> 0;
177
+ };
178
+ for (let index = 0; index < text.length; index += 1) {
179
+ const code = text.codePointAt(index);
180
+ if (code > 0xffff) {
181
+ index += 1;
182
+ }
183
+ if (code <= 0x7f) {
184
+ addByte(code);
185
+ } else if (code <= 0x7ff) {
186
+ addByte(0xc0 | (code >> 6));
187
+ addByte(0x80 | (code & 0x3f));
188
+ } else if (code <= 0xffff) {
189
+ addByte(0xe0 | (code >> 12));
190
+ addByte(0x80 | ((code >> 6) & 0x3f));
191
+ addByte(0x80 | (code & 0x3f));
192
+ } else {
193
+ addByte(0xf0 | (code >> 18));
194
+ addByte(0x80 | ((code >> 12) & 0x3f));
195
+ addByte(0x80 | ((code >> 6) & 0x3f));
196
+ addByte(0x80 | (code & 0x3f));
197
+ }
198
+ }
199
+ return `${MIGRATION_HASH_PREFIX}${hash.toString(16).padStart(8, "0")}`;
200
+ }
201
+
202
+ function connectionProviderKind(db, operation) {
203
+ const debug = typeof db?.__debug === "function" ? db.__debug() : undefined;
204
+ if (debug?.kind === "sqlite-connection") {
205
+ return "sqlite";
206
+ }
207
+ if (debug?.kind === "postgres-connection") {
208
+ return "postgres";
209
+ }
210
+ if (debug?.kind === "sqlserver-connection") {
211
+ return "sqlserver";
212
+ }
213
+ throw new TypeError(
214
+ `Sloppy ${operation} only supports sqlite, postgres, and sqlserver connections created by sloppy/data.`,
215
+ );
216
+ }
217
+
218
+ function migrationProviderKind(db) {
219
+ return connectionProviderKind(db, "Migrations");
220
+ }
221
+
222
+ function resolveMigrationProviderKind(db, options) {
223
+ const providerKind = migrationProviderKind(db);
224
+ if (options.provider !== providerKind) {
225
+ throw new TypeError(
226
+ `Sloppy Migrations provider '${options.provider}' does not match connection provider '${providerKind}'.`,
227
+ );
228
+ }
229
+ return providerKind;
230
+ }
231
+
232
+ const MIGRATION_SQL = Object.freeze({
233
+ sqlite: Object.freeze({
234
+ ensure:
235
+ `create table if not exists ${MIGRATIONS_TABLE} (` +
236
+ "id integer primary key autoincrement, " +
237
+ "name text not null unique, " +
238
+ "hash text not null, " +
239
+ "appliedAt text not null)",
240
+ select:
241
+ `select name, hash, appliedAt as "appliedAt" from ${MIGRATIONS_TABLE} order by id`,
242
+ insert: `insert into ${MIGRATIONS_TABLE} (name, hash, appliedAt) values (?, ?, ?)`,
243
+ appliedAt: () => new Date().toISOString(),
244
+ }),
245
+ postgres: Object.freeze({
246
+ ensure:
247
+ `create table if not exists ${MIGRATIONS_TABLE} (` +
248
+ "id bigint generated by default as identity primary key, " +
249
+ "name text not null unique, " +
250
+ "hash text not null, " +
251
+ "appliedAt text not null)",
252
+ select:
253
+ `select name, hash, appliedAt as "appliedAt" from ${MIGRATIONS_TABLE} order by id`,
254
+ insert:
255
+ `insert into ${MIGRATIONS_TABLE} (name, hash, appliedAt) values (` +
256
+ "$1, $2, to_char(clock_timestamp() at time zone 'UTC', " +
257
+ `'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'))`,
258
+ appliedAt: () => undefined,
259
+ }),
260
+ sqlserver: Object.freeze({
261
+ ensure:
262
+ "if object_id(N'dbo._sloppy_migrations', N'U') is null create table " +
263
+ "dbo._sloppy_migrations (id bigint identity(1,1) primary key, " +
264
+ "name nvarchar(450) not null unique, hash nvarchar(64) not null, " +
265
+ "appliedAt nvarchar(64) not null)",
266
+ select: "select name, hash, appliedAt from dbo._sloppy_migrations order by id",
267
+ insert:
268
+ "insert into dbo._sloppy_migrations (name, hash, appliedAt) values " +
269
+ "(?, ?, convert(nvarchar(64), sysutcdatetime(), 127) + N'Z')",
270
+ appliedAt: () => undefined,
271
+ }),
272
+ });
273
+
274
+ async function listMigrationFiles(options) {
275
+ let entries;
276
+ try {
277
+ entries = await Directory.list(migrationFsPath(options.directory));
278
+ } catch (error) {
279
+ throw new Error(`sloppy: migration directory is missing or unreadable
280
+
281
+ Provider:
282
+ ${options.provider}
283
+
284
+ Path:
285
+ ${options.path}
286
+
287
+ Fix:
288
+ Create the configured migration directory before applying migrations.`, { cause: error });
289
+ }
290
+ return entries
291
+ .filter((entry) => entry.kind === "file" && entry.name.endsWith(".sql"))
292
+ .map((entry) => entry.name)
293
+ .sort((left, right) => (left === right ? 0 : left < right ? -1 : 1))
294
+ .map((name) => ({
295
+ name,
296
+ path: options.directory === "." ? name : `${options.directory}/${name}`,
297
+ }));
298
+ }
299
+
300
+ async function ensureMigrationsTable(db, providerKind) {
301
+ await db.exec(MIGRATION_SQL[providerKind].ensure, []);
302
+ }
303
+
304
+ function isMissingMigrationsTableError(error) {
305
+ const message = String(error?.message ?? error).toLowerCase();
306
+ return message.includes("_sloppy_migrations")
307
+ && (message.includes("no such table")
308
+ || message.includes("does not exist")
309
+ || message.includes("invalid object name")
310
+ || message.includes("undefined_table")
311
+ || message.includes("42p01"));
312
+ }
313
+
314
+ async function readAppliedMigrations(db, providerKind, options = {}) {
315
+ if (options.ensure !== false) {
316
+ await ensureMigrationsTable(db, providerKind);
317
+ }
318
+ let rows;
319
+ try {
320
+ rows = await db.query(MIGRATION_SQL[providerKind].select, []);
321
+ } catch (error) {
322
+ if (options.ensure === false && isMissingMigrationsTableError(error)) {
323
+ return new Map();
324
+ }
325
+ throw error;
326
+ }
327
+ const applied = new Map();
328
+ for (const row of rows) {
329
+ applied.set(row.name, row);
330
+ }
331
+ return applied;
332
+ }
333
+
334
+ function migrationStatusFor(files, applied) {
335
+ return files.map((file) => {
336
+ const appliedRow = applied.get(file.name) ?? null;
337
+ if (appliedRow === null) {
338
+ return Object.freeze({ name: file.name, path: file.path, status: "pending" });
339
+ }
340
+ if (appliedRow.hash !== file.hash) {
341
+ return Object.freeze({
342
+ name: file.name,
343
+ path: file.path,
344
+ status: "changed",
345
+ appliedHash: appliedRow.hash,
346
+ currentHash: file.hash,
347
+ appliedAt: appliedRow.appliedAt,
348
+ });
349
+ }
350
+ return Object.freeze({
351
+ name: file.name,
352
+ path: file.path,
353
+ status: "applied",
354
+ hash: file.hash,
355
+ appliedAt: appliedRow.appliedAt,
356
+ });
357
+ });
358
+ }
359
+
360
+ async function migrationFilesWithContent(options) {
361
+ const files = await listMigrationFiles(options);
362
+ const withContent = [];
363
+ for (const file of files) {
364
+ const sqlText = await File.readText(migrationFsPath(file.path));
365
+ withContent.push({
366
+ ...file,
367
+ sql: sqlText,
368
+ hash: migrationHash(sqlText),
369
+ });
370
+ }
371
+ return withContent;
372
+ }
373
+
374
+ function assertMigrationHashNotChanged(record) {
375
+ if (record.status !== "changed") {
376
+ return;
377
+ }
378
+ throw new Error(`sloppy: applied migration hash changed
379
+
380
+ Migration:
381
+ ${record.name}
382
+
383
+ Applied hash:
384
+ ${record.appliedHash}
385
+
386
+ Current hash:
387
+ ${record.currentHash}
388
+
389
+ Fix:
390
+ Create a new migration file instead of editing an already-applied migration.`);
391
+ }
392
+
393
+ async function migrationStatus(db, options) {
394
+ const checked = normalizeMigrationOptions(options);
395
+ const providerKind = resolveMigrationProviderKind(db, checked);
396
+ const files = await migrationFilesWithContent(checked);
397
+ const applied = await readAppliedMigrations(db, providerKind, { ensure: false });
398
+ const migrations = migrationStatusFor(files, applied);
399
+ const changed = migrations.some((migration) => migration.status === "changed");
400
+ const pending = migrations.filter((migration) => migration.status === "pending").length;
401
+ return Object.freeze({
402
+ provider: providerKind,
403
+ path: checked.path,
404
+ status: changed ? "changed" : pending > 0 ? "pending" : "current",
405
+ pending,
406
+ applied: migrations.filter((migration) => migration.status === "applied").length,
407
+ migrations: Object.freeze(migrations),
408
+ });
409
+ }
410
+
411
+ async function applyMigrations(db, options) {
412
+ const checked = normalizeMigrationOptions(options);
413
+ const providerKind = resolveMigrationProviderKind(db, checked);
414
+ const dialect = MIGRATION_SQL[providerKind];
415
+ const files = await migrationFilesWithContent(checked);
416
+ const applied = await readAppliedMigrations(db, providerKind);
417
+ const records = migrationStatusFor(files, applied);
418
+ for (const record of records) {
419
+ assertMigrationHashNotChanged(record);
420
+ }
421
+
422
+ let appliedCount = 0;
423
+ for (const file of files) {
424
+ if (applied.has(file.name)) {
425
+ continue;
426
+ }
427
+ let didApply = false;
428
+ try {
429
+ didApply = await db.transaction(async (tx) => {
430
+ const current = await readAppliedMigrations(tx, providerKind);
431
+ const record = migrationStatusFor([file], current)[0];
432
+ assertMigrationHashNotChanged(record);
433
+ if (current.has(file.name)) {
434
+ return false;
435
+ }
436
+ const appliedAt = dialect.appliedAt();
437
+ const params = appliedAt === undefined
438
+ ? [file.name, file.hash]
439
+ : [file.name, file.hash, appliedAt];
440
+ await tx.exec(dialect.insert, params);
441
+ await tx.exec(file.sql, []);
442
+ return true;
443
+ });
444
+ } catch (error) {
445
+ const current = await readAppliedMigrations(db, providerKind);
446
+ const record = migrationStatusFor([file], current)[0];
447
+ assertMigrationHashNotChanged(record);
448
+ if (current.has(file.name)) {
449
+ applied.set(file.name, current.get(file.name));
450
+ continue;
451
+ }
452
+ throw error;
453
+ }
454
+ if (didApply) {
455
+ applied.set(file.name, { name: file.name, hash: file.hash });
456
+ appliedCount += 1;
457
+ }
458
+ }
459
+
460
+ return Object.freeze({
461
+ provider: providerKind,
462
+ path: checked.path,
463
+ applied: appliedCount,
464
+ skipped: files.length - appliedCount,
465
+ });
466
+ }
467
+
468
+ async function checkProviderHealth(db, options = {}) {
469
+ if (!isPlainObject(options)) {
470
+ throw new TypeError("Sloppy ProviderHealth options must be a plain object.");
471
+ }
472
+ const provider = connectionProviderKind(db, "ProviderHealth");
473
+ if (options.provider !== undefined && (typeof options.provider !== "string" || options.provider.length === 0)) {
474
+ throw new TypeError("Sloppy ProviderHealth provider must be a non-empty string.");
475
+ }
476
+ if (options.provider !== undefined && options.provider !== provider) {
477
+ throw new TypeError(
478
+ `Sloppy ProviderHealth provider '${options.provider}' does not match connection provider '${provider}'.`,
479
+ );
480
+ }
481
+ await db.queryOne("select 1 as ok", []);
482
+ return Object.freeze({ provider, ok: true });
483
+ }
484
+
485
+ function decimal(value) {
486
+ const text = requireStringValue(value, "sql.decimal");
487
+ if (!/^[+-]?(?:\d+|\d+\.\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(text)) {
488
+ throw new TypeError("Sloppy sql.decimal value must be a finite decimal string.");
489
+ }
490
+ return createDbValue("decimal", text);
491
+ }
492
+
493
+ function uuid(value) {
494
+ const text = requireStringValue(value, "sql.uuid").toLowerCase();
495
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(text)) {
496
+ throw new TypeError("Sloppy sql.uuid value must be a canonical UUID string.");
497
+ }
498
+ return createDbValue("uuid", text);
499
+ }
500
+
501
+ function date(value) {
502
+ const text = requireStringValue(value, "sql.date");
503
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(text)) {
504
+ throw new TypeError("Sloppy sql.date value must be YYYY-MM-DD.");
505
+ }
506
+ return createDbValue("date", text);
507
+ }
508
+
509
+ function time(value) {
510
+ const text = requireStringValue(value, "sql.time");
511
+ if (!/^\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?$/.test(text)) {
512
+ throw new TypeError("Sloppy sql.time value must be HH:MM:SS with optional fractional seconds.");
513
+ }
514
+ return createDbValue("time", text);
515
+ }
516
+
517
+ function timestamp(value) {
518
+ const text = requireStringValue(value, "sql.timestamp");
519
+ if (!/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?$/.test(text)) {
520
+ throw new TypeError("Sloppy sql.timestamp value must be a local date-time string.");
521
+ }
522
+ return createDbValue("localDateTime", text);
523
+ }
524
+
525
+ function instant(value) {
526
+ const text = requireStringValue(value, "sql.instant");
527
+ if (!/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/.test(text)) {
528
+ throw new TypeError("Sloppy sql.instant value must be a UTC timestamp ending in Z.");
529
+ }
530
+ return createDbValue("instant", text);
531
+ }
532
+
533
+ function offsetDateTime(value) {
534
+ const text = requireStringValue(value, "sql.offsetDateTime");
535
+ if (!/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?[+-]\d{2}:\d{2}$/.test(text)) {
536
+ throw new TypeError("Sloppy sql.offsetDateTime value must include an explicit UTC offset.");
537
+ }
538
+ return createDbValue("offsetDateTime", text);
539
+ }
540
+
541
+ function json(value) {
542
+ if (value === undefined || typeof value === "function" || typeof value === "symbol") {
543
+ throw new TypeError("Sloppy sql.json value must be JSON-serializable.");
544
+ }
545
+ try {
546
+ const encoded = JSON.stringify(value);
547
+ if (encoded === undefined) {
548
+ throw new TypeError("not serializable");
549
+ }
550
+ } catch {
551
+ throw new TypeError("Sloppy sql.json value must be JSON-serializable.");
552
+ }
553
+ return createDbValue("json", value);
554
+ }
555
+
556
+ function rawJson(value) {
557
+ const text = requireStringValue(value, "sql.rawJson");
558
+ try {
559
+ JSON.parse(text);
560
+ } catch {
561
+ throw new TypeError("Sloppy sql.rawJson value must be valid JSON text.");
562
+ }
563
+ return createDbValue("rawJson", text);
564
+ }
565
+
566
+ function bytes(value) {
567
+ if (value instanceof Uint8Array) {
568
+ return createDbValue("bytes", value);
569
+ }
570
+ if (value instanceof ArrayBuffer) {
571
+ return createDbValue("bytes", new Uint8Array(value));
572
+ }
573
+ throw new TypeError("Sloppy sql.bytes value must be a Uint8Array or ArrayBuffer.");
574
+ }
575
+
576
+ const values = Object.freeze({
577
+ decimal,
578
+ uuid,
579
+ date,
580
+ time,
581
+ timestamp,
582
+ instant,
583
+ offsetDateTime,
584
+ json,
585
+ rawJson,
586
+ bytes,
587
+ isDbValue,
588
+ });
589
+
590
+ function validatePlaceholderStyle(style) {
591
+ if (!Object.prototype.hasOwnProperty.call(PLACEHOLDER_STYLES, style)) {
592
+ throw new TypeError(
593
+ "Sloppy data placeholderStyle must be one of question, postgres, or named.",
594
+ );
595
+ }
596
+ }
597
+
598
+ function normalizeLoweringOptions(options) {
599
+ if (options === undefined) {
600
+ return {
601
+ placeholderStyle: "question",
602
+ };
603
+ }
604
+
605
+ if (!isPlainObject(options)) {
606
+ throw new TypeError("Sloppy query lowering options must be a plain object.");
607
+ }
608
+
609
+ const placeholderStyle = options.placeholderStyle ?? "question";
610
+ validatePlaceholderStyle(placeholderStyle);
611
+ return { placeholderStyle };
612
+ }
613
+
614
+ function validateTemplateStrings(strings, operation) {
615
+ if (!Array.isArray(strings)) {
616
+ throw new TypeError(
617
+ `Sloppy data ${operation} must be called as a tagged template or with a lowered query object.`,
618
+ );
619
+ }
620
+
621
+ for (const segment of strings) {
622
+ if (typeof segment !== "string") {
623
+ throw new TypeError(`Sloppy data ${operation} template segments must be strings.`);
624
+ }
625
+ }
626
+ }
627
+
628
+ function createLoweredQuery(strings, values, options) {
629
+ validateTemplateStrings(strings, "sql");
630
+
631
+ if (strings.length !== values.length + 1) {
632
+ throw new TypeError("Sloppy sql tag received an invalid template segment/value count.");
633
+ }
634
+
635
+ const normalized = normalizeLoweringOptions(options);
636
+ const placeholders = [];
637
+ let text = strings[0];
638
+
639
+ for (let index = 0; index < values.length; index += 1) {
640
+ const placeholder = PLACEHOLDER_STYLES[normalized.placeholderStyle](index + 1);
641
+ placeholders.push(Object.freeze({
642
+ index,
643
+ text: placeholder.text,
644
+ name: placeholder.name,
645
+ position: placeholder.position,
646
+ }));
647
+ text += placeholder.text + strings[index + 1];
648
+ }
649
+
650
+ const lowered = Object.freeze({
651
+ [QUERY_MARKER]: true,
652
+ text,
653
+ parameters: Object.freeze([...values]),
654
+ parameterCount: values.length,
655
+ placeholderStyle: normalized.placeholderStyle,
656
+ placeholders: Object.freeze(placeholders),
657
+ });
658
+
659
+ LOWERED_QUERIES.add(lowered);
660
+ return lowered;
661
+ }
662
+
663
+ function isLoweredQuery(value) {
664
+ return value !== null && typeof value === "object" && LOWERED_QUERIES.has(value);
665
+ }
666
+
667
+ function createOperationCancelledError(operation, reason) {
668
+ const detail = reason === undefined || reason === null || reason === ""
669
+ ? "operation cancellation was requested"
670
+ : String(reason);
671
+ return new Error(`SLOPPY_E_CANCELLED: Sloppy data ${operation} was cancelled
672
+
673
+ Operation:
674
+ ${operation}
675
+
676
+ Reason:
677
+ ${detail}`);
678
+ }
679
+
680
+ function createOperationDeadlineError(operation) {
681
+ return new Error(`SLOPPY_E_DEADLINE_EXCEEDED: Sloppy data ${operation} deadline was exceeded
682
+
683
+ Operation:
684
+ ${operation}
685
+
686
+ Reason:
687
+ The operation deadline was already expired before provider dispatch.`);
688
+ }
689
+
690
+ function normalizeOperationOptions(
691
+ options,
692
+ operation,
693
+ allowResultMode = false,
694
+ allowMaxRows = false,
695
+ allowCursorOptions = false,
696
+ ) {
697
+ if (options === undefined) {
698
+ return undefined;
699
+ }
700
+ if (!isPlainObject(options)) {
701
+ throw new TypeError(`Sloppy data ${operation} options must be a plain object.`);
702
+ }
703
+ const allowedKeys = new Set(["deadline", "signal", "timeoutMs"]);
704
+ if (allowResultMode) {
705
+ allowedKeys.add("mode");
706
+ }
707
+ if (allowMaxRows) {
708
+ allowedKeys.add("maxRows");
709
+ }
710
+ if (allowCursorOptions) {
711
+ allowedKeys.add("batchSize");
712
+ }
713
+ const keys = Object.keys(options);
714
+ for (const key of keys) {
715
+ if (!allowedKeys.has(key)) {
716
+ throw new TypeError(
717
+ `Sloppy data ${operation} option '${key}' is not supported by the current runtime bridge.`,
718
+ );
719
+ }
720
+ }
721
+
722
+ const signal = options.signal;
723
+ if (
724
+ signal !== undefined
725
+ && signal !== null
726
+ && (typeof signal !== "object" || Array.isArray(signal))
727
+ ) {
728
+ throw new TypeError(`Sloppy data ${operation} signal option must be an object.`);
729
+ }
730
+
731
+ const deadline = options.deadline;
732
+ if (
733
+ deadline !== undefined
734
+ && deadline !== null
735
+ && (typeof deadline !== "object" || Array.isArray(deadline))
736
+ ) {
737
+ throw new TypeError(`Sloppy data ${operation} deadline option must be an object or null.`);
738
+ }
739
+
740
+ let timeoutMs = options.timeoutMs;
741
+ if (timeoutMs !== undefined) {
742
+ if (!Number.isInteger(timeoutMs) || timeoutMs < 0 || timeoutMs > 0xffffffff) {
743
+ throw new TypeError(
744
+ `Sloppy data ${operation} timeoutMs option must be an integer from 0 to 4294967295.`,
745
+ );
746
+ }
747
+ }
748
+
749
+ const maxRows = options.maxRows;
750
+ if (maxRows !== undefined) {
751
+ if (!Number.isInteger(maxRows) || maxRows < 1 || maxRows > 0xffffffff) {
752
+ throw new TypeError(
753
+ `Sloppy data ${operation} maxRows option must be an integer from 1 to 4294967295.`,
754
+ );
755
+ }
756
+ }
757
+
758
+ const batchSize = options.batchSize;
759
+ if (batchSize !== undefined) {
760
+ if (!Number.isInteger(batchSize) || batchSize < 1 || batchSize > 4096) {
761
+ throw new TypeError(
762
+ `Sloppy data ${operation} batchSize option must be an integer from 1 to 4096.`,
763
+ );
764
+ }
765
+ }
766
+
767
+ if (deadline !== undefined && deadline !== null) {
768
+ if (deadline.expired === true) {
769
+ throw createOperationDeadlineError(operation);
770
+ }
771
+ if (deadline.remainingMs !== undefined) {
772
+ if (typeof deadline.remainingMs !== "function") {
773
+ throw new TypeError(
774
+ `Sloppy data ${operation} deadline.remainingMs must be a function when supplied.`,
775
+ );
776
+ }
777
+ const remaining = deadline.remainingMs();
778
+ if (typeof remaining !== "number" || Number.isNaN(remaining)) {
779
+ throw new TypeError(
780
+ `Sloppy data ${operation} deadline.remainingMs must return a number.`,
781
+ );
782
+ }
783
+ if (remaining <= 0) {
784
+ throw createOperationDeadlineError(operation);
785
+ }
786
+ if (Number.isFinite(remaining)) {
787
+ const rounded = Math.ceil(remaining);
788
+ timeoutMs = timeoutMs === undefined ? rounded : Math.min(timeoutMs, rounded);
789
+ }
790
+ }
791
+ }
792
+
793
+ const mode = allowResultMode ? normalizeResultMode(options.mode, operation) : undefined;
794
+ const normalized = Object.freeze({
795
+ deadline: deadline ?? undefined,
796
+ batchSize,
797
+ maxRows,
798
+ mode: mode === "raw" ? mode : undefined,
799
+ signal: signal ?? undefined,
800
+ timeoutMs,
801
+ });
802
+ return normalized.deadline === undefined
803
+ && normalized.batchSize === undefined
804
+ && normalized.maxRows === undefined
805
+ && normalized.mode === undefined
806
+ && normalized.signal === undefined
807
+ && normalized.timeoutMs === undefined
808
+ ? undefined
809
+ : normalized;
810
+ }
811
+
812
+ function throwIfOperationCancelled(options, operation) {
813
+ if (options === undefined) {
814
+ return;
815
+ }
816
+ if (options.signal !== undefined) {
817
+ if (options.signal.aborted === true) {
818
+ throw createOperationCancelledError(operation, options.signal.reason);
819
+ }
820
+ if (typeof options.signal.throwIfAborted === "function") {
821
+ try {
822
+ options.signal.throwIfAborted();
823
+ } catch {
824
+ throw createOperationCancelledError(operation, options.signal.reason);
825
+ }
826
+ }
827
+ }
828
+ if (options.timeoutMs === 0) {
829
+ throw createOperationDeadlineError(operation);
830
+ }
831
+ if (options.deadline !== undefined) {
832
+ if (options.deadline.expired === true) {
833
+ throw createOperationDeadlineError(operation);
834
+ }
835
+ if (typeof options.deadline.remainingMs === "function") {
836
+ const remaining = options.deadline.remainingMs();
837
+ if (typeof remaining !== "number" || Number.isNaN(remaining)) {
838
+ throw new TypeError(
839
+ `Sloppy data ${operation} deadline.remainingMs must return a number.`,
840
+ );
841
+ }
842
+ if (remaining <= 0) {
843
+ throw createOperationDeadlineError(operation);
844
+ }
845
+ }
846
+ }
847
+ }
848
+
849
+ function invokeProviderOperation(operation, options, callback) {
850
+ throwIfOperationCancelled(options, operation);
851
+ return callback();
852
+ }
853
+
854
+ function operationAllowsResultMode(operation) {
855
+ return operation === "query"
856
+ || operation === "queryCursor"
857
+ || operation === "stream"
858
+ || operation.endsWith(".query")
859
+ || operation.endsWith(".queryCursor")
860
+ || operation.endsWith(".transaction.query");
861
+ }
862
+
863
+ function operationAllowsMaxRows(operation) {
864
+ return operation === "query"
865
+ || operation === "queryRaw"
866
+ || operation === "queryCursor"
867
+ || operation === "queryRawCursor"
868
+ || operation === "stream"
869
+ || operation.endsWith(".query")
870
+ || operation.endsWith(".queryRaw")
871
+ || operation.endsWith(".queryCursor")
872
+ || operation.endsWith(".queryRawCursor");
873
+ }
874
+
875
+ function operationAllowsCursorOptions(operation) {
876
+ return operation === "queryCursor"
877
+ || operation === "queryRawCursor"
878
+ || operation === "stream"
879
+ || operation.endsWith(".queryCursor")
880
+ || operation.endsWith(".queryRawCursor");
881
+ }
882
+
883
+ function nativeQueryOptions(options, includeTimeout = false, includeCursorOptions = false) {
884
+ if (
885
+ options?.maxRows === undefined
886
+ && (!includeTimeout || options?.timeoutMs === undefined)
887
+ && (!includeCursorOptions || options?.batchSize === undefined)
888
+ ) {
889
+ return undefined;
890
+ }
891
+ const native = {};
892
+ if (includeCursorOptions && options.batchSize !== undefined) {
893
+ native.batchSize = options.batchSize;
894
+ }
895
+ if (options.maxRows !== undefined) {
896
+ native.maxRows = options.maxRows;
897
+ }
898
+ if (includeTimeout && options.timeoutMs !== undefined) {
899
+ native.timeoutMs = options.timeoutMs;
900
+ }
901
+ return Object.freeze(native);
902
+ }
903
+
904
+ function invokeNativeQuery(method, handle, query, includeTimeout = false) {
905
+ const nativeOptions = nativeQueryOptions(query.options, includeTimeout);
906
+ return nativeOptions === undefined
907
+ ? method(handle, query.text, query.parameters)
908
+ : method(handle, query.text, query.parameters, nativeOptions);
909
+ }
910
+
911
+ function invokeNativeCursorOpen(method, handle, query, includeTimeout = false) {
912
+ if (typeof method !== "function") {
913
+ throw new Error("sloppy: provider cursor bridge is unavailable");
914
+ }
915
+ const nativeOptions = nativeQueryOptions(query.options, includeTimeout, true);
916
+ return nativeOptions === undefined
917
+ ? method(handle, query.text, query.parameters)
918
+ : method(handle, query.text, query.parameters, nativeOptions);
919
+ }
920
+
921
+ function requireCursorBridgeMethod(nativeBridge, method, provider) {
922
+ if (typeof nativeBridge?.[method] !== "function") {
923
+ throw new Error(`sloppy: ${provider} cursor bridge is unavailable`);
924
+ }
925
+ return nativeBridge[method];
926
+ }
927
+
928
+ function createDataCursor(provider, nativeBridge, nativeCursor, mode, operationOptions, registry) {
929
+ if (!isPlainObject(nativeCursor)) {
930
+ throw new TypeError(`Sloppy ${provider} cursor bridge returned an invalid cursor handle.`);
931
+ }
932
+
933
+ let closed = nativeCursor.closed === true;
934
+ let started = false;
935
+ let rowsSeen = 0;
936
+ let cursor = null;
937
+ const metadata = Object.freeze({
938
+ columns: Array.isArray(nativeCursor.columns) ? Object.freeze([...nativeCursor.columns]) : Object.freeze([]),
939
+ mode,
940
+ provider,
941
+ });
942
+
943
+ async function close() {
944
+ if (closed) {
945
+ registry?.delete(cursor);
946
+ return;
947
+ }
948
+ closed = true;
949
+ registry?.delete(cursor);
950
+ await requireCursorBridgeMethod(nativeBridge, "cursorClose", provider)(nativeCursor);
951
+ }
952
+
953
+ async function next() {
954
+ if (closed) {
955
+ throw new Error(`sloppy: ${provider} cursor is closed`);
956
+ }
957
+ throwIfOperationCancelled(operationOptions, `${provider}.cursor.next`);
958
+ started = true;
959
+ let result;
960
+ try {
961
+ result = await requireCursorBridgeMethod(nativeBridge, "cursorNext", provider)(nativeCursor);
962
+ } catch (error) {
963
+ try {
964
+ await close();
965
+ } catch {
966
+ // Preserve the provider error while still making a best-effort cleanup attempt.
967
+ }
968
+ throw error;
969
+ }
970
+ if (!isPlainObject(result) || typeof result.done !== "boolean") {
971
+ await close();
972
+ throw new TypeError(`Sloppy ${provider} cursor bridge returned an invalid iterator result.`);
973
+ }
974
+ if (result.done) {
975
+ await close();
976
+ return Object.freeze({ done: true, value: undefined });
977
+ }
978
+ rowsSeen += 1;
979
+ return Object.freeze({ done: false, value: result.value });
980
+ }
981
+
982
+ cursor = {
983
+ get closed() {
984
+ return closed;
985
+ },
986
+ get columns() {
987
+ return metadata.columns;
988
+ },
989
+ get mode() {
990
+ return metadata.mode;
991
+ },
992
+ get provider() {
993
+ return metadata.provider;
994
+ },
995
+ async close() {
996
+ await close();
997
+ },
998
+ async next() {
999
+ return next();
1000
+ },
1001
+ async return() {
1002
+ await close();
1003
+ return Object.freeze({ done: true, value: undefined });
1004
+ },
1005
+ async throw(error) {
1006
+ await close();
1007
+ throw error;
1008
+ },
1009
+ [Symbol.asyncIterator]() {
1010
+ if (started) {
1011
+ throw new Error(`sloppy: ${provider} cursor is single-use`);
1012
+ }
1013
+ return this;
1014
+ },
1015
+ __debug() {
1016
+ return Object.freeze({
1017
+ kind: "data-cursor",
1018
+ closed,
1019
+ mode,
1020
+ provider,
1021
+ rowsSeen,
1022
+ });
1023
+ },
1024
+ };
1025
+
1026
+ registry?.add(cursor);
1027
+ return Object.freeze(cursor);
1028
+ }
1029
+
1030
+ function closeActiveCursors(cursors) {
1031
+ if (!(cursors instanceof Set) || cursors.size === 0) {
1032
+ return;
1033
+ }
1034
+ for (const cursor of Array.from(cursors)) {
1035
+ try {
1036
+ const result = cursor.close();
1037
+ if (result !== undefined && typeof result.catch === "function") {
1038
+ result.catch(() => {});
1039
+ }
1040
+ } catch {
1041
+ }
1042
+ }
1043
+ cursors.clear();
1044
+ }
1045
+
1046
+ function markRealDataProvider(provider, kind) {
1047
+ REAL_PROVIDER_HANDLES.set(provider, kind);
1048
+ return provider;
1049
+ }
1050
+
1051
+ function isRealDataProvider(provider, kind = undefined) {
1052
+ const actual = REAL_PROVIDER_HANDLES.get(provider);
1053
+ return kind === undefined ? actual !== undefined : actual === kind;
1054
+ }
1055
+
1056
+ function normalizeResultMode(value, operation) {
1057
+ if (value === undefined) {
1058
+ return "object";
1059
+ }
1060
+ if (!Object.prototype.hasOwnProperty.call(DB_RESULT_MODES, value)) {
1061
+ throw new TypeError(`Sloppy data ${operation} mode must be object or raw.`);
1062
+ }
1063
+ return value;
1064
+ }
1065
+
1066
+ function hasInlineOperationOptions(args) {
1067
+ return args.length === 2 && isPlainObject(args[1]);
1068
+ }
1069
+
1070
+ function normalizeProviderCallArguments(operation, placeholderStyle, args) {
1071
+ const allowResultMode = operationAllowsResultMode(operation);
1072
+ const allowMaxRows = operationAllowsMaxRows(operation);
1073
+ const allowCursorOptions = operationAllowsCursorOptions(operation);
1074
+ if (args.length === 2 && isLoweredQuery(args[0])) {
1075
+ const options = normalizeOperationOptions(
1076
+ args[1],
1077
+ operation,
1078
+ allowResultMode,
1079
+ allowMaxRows,
1080
+ allowCursorOptions,
1081
+ );
1082
+ return {
1083
+ query: args[0],
1084
+ options,
1085
+ mode: allowResultMode ? options?.mode ?? "object" : undefined,
1086
+ };
1087
+ }
1088
+ if (args.length === 1 && isLoweredQuery(args[0])) {
1089
+ return {
1090
+ query: args[0],
1091
+ options: undefined,
1092
+ mode: allowResultMode ? "object" : undefined,
1093
+ };
1094
+ }
1095
+ return {
1096
+ query: normalizeQueryArguments(operation, placeholderStyle, args),
1097
+ options: undefined,
1098
+ mode: allowResultMode ? "object" : undefined,
1099
+ };
1100
+ }
1101
+
1102
+ function validateOperationOptions(
1103
+ options,
1104
+ operation,
1105
+ allowResultMode = false,
1106
+ allowMaxRows = false,
1107
+ ) {
1108
+ const normalized = normalizeOperationOptions(
1109
+ options,
1110
+ operation,
1111
+ allowResultMode,
1112
+ allowMaxRows,
1113
+ );
1114
+ if (normalized !== undefined) {
1115
+ throwIfOperationCancelled(normalized, operation);
1116
+ }
1117
+ }
1118
+
1119
+ function normalizeQueryArguments(operation, placeholderStyle, args) {
1120
+ if (args.length === 1 && isLoweredQuery(args[0])) {
1121
+ return args[0];
1122
+ }
1123
+ if (args.length === 2 && isLoweredQuery(args[0])) {
1124
+ validateOperationOptions(args[1], operation);
1125
+ return args[0];
1126
+ }
1127
+
1128
+ const strings = args[0];
1129
+ const values = args.slice(1);
1130
+ validateTemplateStrings(strings, operation);
1131
+ return createLoweredQuery(strings, values, { placeholderStyle });
1132
+ }
1133
+
1134
+ function validateProviderDefinition(definition) {
1135
+ if (!isPlainObject(definition)) {
1136
+ throw new TypeError("Sloppy fake data provider definition must be a plain object.");
1137
+ }
1138
+
1139
+ for (const method of ["query", "queryRaw", "queryOne", "exec"]) {
1140
+ if (definition[method] !== undefined && typeof definition[method] !== "function") {
1141
+ throw new TypeError(`Sloppy fake data provider '${method}' handler must be a function.`);
1142
+ }
1143
+ }
1144
+
1145
+ if (
1146
+ definition.transaction !== undefined
1147
+ && typeof definition.transaction !== "function"
1148
+ && !isPlainObject(definition.transaction)
1149
+ ) {
1150
+ throw new TypeError(
1151
+ "Sloppy fake data provider transaction handler must be a function or plain object.",
1152
+ );
1153
+ }
1154
+ }
1155
+
1156
+ function validateSqliteOpenOptions(options) {
1157
+ if (!isPlainObject(options)) {
1158
+ throw new TypeError("Sloppy sqlite.open options must be a plain object.");
1159
+ }
1160
+
1161
+ const allowedKeys = new Set(["database", "path", "capability", "access"]);
1162
+ for (const key of Object.keys(options)) {
1163
+ if (!allowedKeys.has(key)) {
1164
+ throw new TypeError(`Sloppy sqlite.open option '${key}' is not supported.`);
1165
+ }
1166
+ }
1167
+
1168
+ const database = options.database ?? options.path;
1169
+ if (typeof database !== "string" || database.length === 0 || database.includes("\0")) {
1170
+ throw new TypeError("Sloppy sqlite.open database must be a non-empty string without NUL.");
1171
+ }
1172
+
1173
+ if (
1174
+ typeof options.database === "string"
1175
+ && typeof options.path === "string"
1176
+ && options.database !== options.path
1177
+ ) {
1178
+ throw new TypeError("Sloppy sqlite.open database and path must match when both are supplied.");
1179
+ }
1180
+
1181
+ if (typeof options.capability !== "string" || options.capability.length === 0 || options.capability.includes("\0")) {
1182
+ throw new TypeError("Sloppy sqlite.open capability must be a non-empty string without NUL.");
1183
+ }
1184
+
1185
+ const access = options.access ?? "readwrite";
1186
+ if (access !== "read" && access !== "write" && access !== "readwrite") {
1187
+ throw new TypeError("Sloppy sqlite.open access must be read, write, or readwrite.");
1188
+ }
1189
+
1190
+ return Object.freeze({
1191
+ provider: "sqlite",
1192
+ database,
1193
+ path: database,
1194
+ capability: options.capability,
1195
+ access,
1196
+ placeholderStyle: "question",
1197
+ });
1198
+ }
1199
+
1200
+ function normalizeSqliteProviderToken(name) {
1201
+ if (typeof name !== "string" || name.length === 0 || name.includes("\0")) {
1202
+ throw new TypeError("Sloppy data.sqlite provider name must be a non-empty string without NUL.");
1203
+ }
1204
+
1205
+ return name.includes(".") ? name : `data.${name}`;
1206
+ }
1207
+
1208
+ function sqliteNativeBridge() {
1209
+ return globalThis.__sloppy?.data?.sqlite ?? null;
1210
+ }
1211
+
1212
+ function createSqliteClosedError(operation) {
1213
+ return new Error(`sloppy: sqlite connection is closed
1214
+
1215
+ Provider:
1216
+ sqlite
1217
+
1218
+ Operation:
1219
+ ${operation}
1220
+
1221
+ Fix:
1222
+ Open a new SQLite connection before using ${operation}.`);
1223
+ }
1224
+
1225
+ function createSqliteTransactionClosedError(operation) {
1226
+ return new Error(`sloppy: sqlite transaction scope is closed
1227
+
1228
+ Provider:
1229
+ sqlite
1230
+
1231
+ Operation:
1232
+ ${operation}
1233
+
1234
+ Fix:
1235
+ Do not use the transaction object after transaction(...) resolves or rejects.`);
1236
+ }
1237
+
1238
+ function createSqliteNestedTransactionError() {
1239
+ return new Error(`sloppy: sqlite nested transactions are not supported
1240
+
1241
+ Provider:
1242
+ sqlite
1243
+
1244
+ Operation:
1245
+ transaction
1246
+
1247
+ Fix:
1248
+ Use the transaction object passed to the current callback, or start a new transaction after it settles.`);
1249
+ }
1250
+
1251
+ function createSqliteTransactionActiveError(operation) {
1252
+ return new Error(`sloppy: sqlite transaction is active
1253
+
1254
+ Provider:
1255
+ sqlite
1256
+
1257
+ Operation:
1258
+ ${operation}
1259
+
1260
+ Fix:
1261
+ Let the active transaction settle before closing this SQLite connection.`);
1262
+ }
1263
+
1264
+ function validateSqliteParams(params, operation) {
1265
+ if (params === undefined) {
1266
+ return [];
1267
+ }
1268
+
1269
+ if (!Array.isArray(params)) {
1270
+ throw new TypeError(`Sloppy sqlite.${operation} parameters must be an array.`);
1271
+ }
1272
+
1273
+ return params.map((param) => {
1274
+ if (isDbValue(param)) {
1275
+ if (param.kind === "json") {
1276
+ return JSON.stringify(param.value);
1277
+ }
1278
+ if (param.kind === "rawJson") {
1279
+ return param.value;
1280
+ }
1281
+ if (param.kind === "bytes") {
1282
+ return param.value;
1283
+ }
1284
+ if (
1285
+ param.kind === "decimal"
1286
+ || param.kind === "uuid"
1287
+ || param.kind === "date"
1288
+ || param.kind === "time"
1289
+ || param.kind === "localDateTime"
1290
+ || param.kind === "instant"
1291
+ || param.kind === "offsetDateTime"
1292
+ ) {
1293
+ return param.toString();
1294
+ }
1295
+ }
1296
+ if (param !== null && typeof param === "object" && param[DB_BRIDGE_VALUE_MARKER] === true) {
1297
+ throw new TypeError(
1298
+ `Sloppy sqlite.${operation} parameter uses an unsupported sql value wrapper.`,
1299
+ );
1300
+ }
1301
+ const type = typeof param;
1302
+ if (
1303
+ param !== null
1304
+ && type !== "string"
1305
+ && type !== "number"
1306
+ && type !== "bigint"
1307
+ && type !== "boolean"
1308
+ && !(param instanceof Uint8Array)
1309
+ ) {
1310
+ throw new TypeError(
1311
+ `Sloppy sqlite.${operation} parameters support only null, string, number, bigint, boolean, Uint8Array, and explicit sql value wrappers.`,
1312
+ );
1313
+ }
1314
+ return param;
1315
+ });
1316
+ }
1317
+
1318
+ function normalizeSqliteOperation(operation, args) {
1319
+ const allowResultMode = operation === "query" || operation === "queryCursor";
1320
+ const allowMaxRows = operation === "query" || operation === "queryRaw"
1321
+ || operation === "queryCursor" || operation === "queryRawCursor";
1322
+ const allowCursorOptions = operation === "queryCursor" || operation === "queryRawCursor";
1323
+ if (args.length === 1 && isLoweredQuery(args[0])) {
1324
+ return {
1325
+ text: args[0].text,
1326
+ parameters: validateSqliteParams(args[0].parameters, operation),
1327
+ options: undefined,
1328
+ mode: allowResultMode ? "object" : undefined,
1329
+ };
1330
+ }
1331
+ if (args.length === 2 && isLoweredQuery(args[0])) {
1332
+ const options = normalizeOperationOptions(
1333
+ args[1],
1334
+ `sqlite.${operation}`,
1335
+ allowResultMode,
1336
+ allowMaxRows,
1337
+ allowCursorOptions,
1338
+ );
1339
+ return {
1340
+ text: args[0].text,
1341
+ parameters: validateSqliteParams(args[0].parameters, operation),
1342
+ options,
1343
+ mode: allowResultMode ? options?.mode ?? "object" : undefined,
1344
+ };
1345
+ }
1346
+
1347
+ if (typeof args[0] === "string") {
1348
+ if (args.length > 3) {
1349
+ throw new TypeError(`Sloppy sqlite.${operation} accepts sql, optional params, and optional options.`);
1350
+ }
1351
+ const inlineOptions = hasInlineOperationOptions(args);
1352
+ const params = inlineOptions ? undefined : args[1];
1353
+ const options = normalizeOperationOptions(
1354
+ inlineOptions ? args[1] : args[2],
1355
+ `sqlite.${operation}`,
1356
+ allowResultMode,
1357
+ allowMaxRows,
1358
+ allowCursorOptions,
1359
+ );
1360
+
1361
+ if (args[0].length === 0) {
1362
+ throw new TypeError(`Sloppy sqlite.${operation} SQL must be a non-empty string.`);
1363
+ }
1364
+
1365
+ return {
1366
+ text: args[0],
1367
+ parameters: validateSqliteParams(params, operation),
1368
+ options,
1369
+ mode: allowResultMode ? options?.mode ?? "object" : undefined,
1370
+ };
1371
+ }
1372
+
1373
+ const call = normalizeProviderCallArguments(`sqlite.${operation}`, "question", args);
1374
+ return {
1375
+ text: call.query.text,
1376
+ parameters: validateSqliteParams(call.query.parameters, operation),
1377
+ options: call.options,
1378
+ mode: allowResultMode ? call.mode ?? "object" : undefined,
1379
+ };
1380
+ }
1381
+
1382
+ async function openProviderCursor(provider, nativeBridge, handle, query, mode, methodName, registry) {
1383
+ const method = requireCursorBridgeMethod(nativeBridge, methodName, provider);
1384
+ const nativeCursor = await invokeNativeCursorOpen(method, handle, query, true);
1385
+ return createDataCursor(provider, nativeBridge, nativeCursor, mode, query.options, registry);
1386
+ }
1387
+
1388
+ function createSqliteConnection(nativeBridge, handle) {
1389
+ const state = {
1390
+ closed: false,
1391
+ handle,
1392
+ transactionActive: false,
1393
+ activeCursors: new Set(),
1394
+ };
1395
+
1396
+ function assertOpen(operation) {
1397
+ if (state.closed) {
1398
+ throw createSqliteClosedError(operation);
1399
+ }
1400
+ }
1401
+
1402
+ function createSqliteTransaction() {
1403
+ const txState = {
1404
+ closed: false,
1405
+ activeCursors: new Set(),
1406
+ };
1407
+
1408
+ function assertTransactionOpen(operation) {
1409
+ assertOpen(operation);
1410
+ if (txState.closed) {
1411
+ throw createSqliteTransactionClosedError(operation);
1412
+ }
1413
+ }
1414
+
1415
+ const tx = Object.freeze({
1416
+ query(...args) {
1417
+ assertTransactionOpen("transaction.query");
1418
+ const query = normalizeSqliteOperation("query", args);
1419
+ const method = query.mode === "raw"
1420
+ ? nativeBridge.transactionQueryRaw
1421
+ : nativeBridge.transactionQuery;
1422
+ return invokeProviderOperation("sqlite.transaction.query", query.options, () =>
1423
+ invokeNativeQuery(method, state.handle, query, true));
1424
+ },
1425
+
1426
+ queryRaw(...args) {
1427
+ assertTransactionOpen("transaction.queryRaw");
1428
+ const query = normalizeSqliteOperation("queryRaw", args);
1429
+ return invokeProviderOperation("sqlite.transaction.queryRaw", query.options, () =>
1430
+ invokeNativeQuery(nativeBridge.transactionQueryRaw, state.handle, query, true));
1431
+ },
1432
+
1433
+ async queryCursor(...args) {
1434
+ assertTransactionOpen("transaction.queryCursor");
1435
+ const query = normalizeSqliteOperation("queryCursor", args);
1436
+ const methodName = query.mode === "raw"
1437
+ ? "transactionQueryRawCursor"
1438
+ : "transactionQueryCursor";
1439
+ return invokeProviderOperation("sqlite.transaction.queryCursor", query.options, () =>
1440
+ openProviderCursor("sqlite", nativeBridge, state.handle, query, query.mode, methodName, txState.activeCursors));
1441
+ },
1442
+
1443
+ async queryRawCursor(...args) {
1444
+ assertTransactionOpen("transaction.queryRawCursor");
1445
+ const query = normalizeSqliteOperation("queryRawCursor", args);
1446
+ return invokeProviderOperation("sqlite.transaction.queryRawCursor", query.options, () =>
1447
+ openProviderCursor("sqlite", nativeBridge, state.handle, query, "raw", "transactionQueryRawCursor", txState.activeCursors));
1448
+ },
1449
+
1450
+ queryOne(...args) {
1451
+ assertTransactionOpen("transaction.queryOne");
1452
+ const query = normalizeSqliteOperation("queryOne", args);
1453
+ return invokeProviderOperation("sqlite.transaction.queryOne", query.options, () =>
1454
+ nativeBridge.transactionQueryOne(state.handle, query.text, query.parameters));
1455
+ },
1456
+
1457
+ exec(...args) {
1458
+ assertTransactionOpen("transaction.exec");
1459
+ const query = normalizeSqliteOperation("exec", args);
1460
+ return invokeProviderOperation("sqlite.transaction.exec", query.options, () =>
1461
+ nativeBridge.transactionExec(state.handle, query.text, query.parameters));
1462
+ },
1463
+
1464
+ transaction() {
1465
+ throw createSqliteNestedTransactionError();
1466
+ },
1467
+ });
1468
+
1469
+ return {
1470
+ tx,
1471
+ close() {
1472
+ closeActiveCursors(txState.activeCursors);
1473
+ txState.closed = true;
1474
+ },
1475
+ };
1476
+ }
1477
+
1478
+ async function rollbackAfterCallbackError(error, transaction) {
1479
+ try {
1480
+ if (transaction !== undefined) {
1481
+ transaction.close();
1482
+ }
1483
+ await nativeBridge.transactionRollback(state.handle);
1484
+ } catch {
1485
+ if (transaction !== undefined) {
1486
+ transaction.close();
1487
+ }
1488
+ state.closed = true;
1489
+ try {
1490
+ nativeBridge.close(state.handle);
1491
+ } catch {
1492
+ // Preserve the original callback or thenable error while preventing reuse.
1493
+ }
1494
+ throw error;
1495
+ }
1496
+ state.transactionActive = false;
1497
+ throw error;
1498
+ }
1499
+
1500
+ async function commitTransaction(transaction) {
1501
+ try {
1502
+ transaction.close();
1503
+ await nativeBridge.transactionCommit(state.handle);
1504
+ } catch (error) {
1505
+ transaction.close();
1506
+ state.transactionActive = false;
1507
+ state.closed = true;
1508
+ try {
1509
+ nativeBridge.close(state.handle);
1510
+ } catch {
1511
+ // Keep the commit failure as the observable error.
1512
+ }
1513
+ throw error;
1514
+ }
1515
+ state.transactionActive = false;
1516
+ }
1517
+
1518
+ const connection = {
1519
+ query(...args) {
1520
+ assertOpen("query");
1521
+ const query = normalizeSqliteOperation("query", args);
1522
+ const method = query.mode === "raw" ? nativeBridge.queryRaw : nativeBridge.query;
1523
+ return invokeProviderOperation("sqlite.query", query.options, () =>
1524
+ invokeNativeQuery(method, state.handle, query, true));
1525
+ },
1526
+
1527
+ queryRaw(...args) {
1528
+ assertOpen("queryRaw");
1529
+ const query = normalizeSqliteOperation("queryRaw", args);
1530
+ return invokeProviderOperation("sqlite.queryRaw", query.options, () =>
1531
+ invokeNativeQuery(nativeBridge.queryRaw, state.handle, query, true));
1532
+ },
1533
+
1534
+ async queryCursor(...args) {
1535
+ assertOpen("queryCursor");
1536
+ const query = normalizeSqliteOperation("queryCursor", args);
1537
+ const methodName = query.mode === "raw" ? "queryRawCursor" : "queryCursor";
1538
+ return invokeProviderOperation("sqlite.queryCursor", query.options, () =>
1539
+ openProviderCursor("sqlite", nativeBridge, state.handle, query, query.mode, methodName, state.activeCursors));
1540
+ },
1541
+
1542
+ async queryRawCursor(...args) {
1543
+ assertOpen("queryRawCursor");
1544
+ const query = normalizeSqliteOperation("queryRawCursor", args);
1545
+ return invokeProviderOperation("sqlite.queryRawCursor", query.options, () =>
1546
+ openProviderCursor("sqlite", nativeBridge, state.handle, query, "raw", "queryRawCursor", state.activeCursors));
1547
+ },
1548
+
1549
+ stream(...args) {
1550
+ return this.queryCursor(...args);
1551
+ },
1552
+
1553
+ queryOne(...args) {
1554
+ assertOpen("queryOne");
1555
+ const query = normalizeSqliteOperation("queryOne", args);
1556
+ return invokeProviderOperation("sqlite.queryOne", query.options, () =>
1557
+ nativeBridge.queryOne(state.handle, query.text, query.parameters));
1558
+ },
1559
+
1560
+ exec(...args) {
1561
+ assertOpen("exec");
1562
+ const query = normalizeSqliteOperation("exec", args);
1563
+ return invokeProviderOperation("sqlite.exec", query.options, () =>
1564
+ nativeBridge.exec(state.handle, query.text, query.parameters));
1565
+ },
1566
+
1567
+ async transaction(callback) {
1568
+ assertOpen("transaction");
1569
+ if (typeof callback !== "function") {
1570
+ throw new TypeError("Sloppy sqlite.transaction callback must be a function.");
1571
+ }
1572
+ if (state.transactionActive) {
1573
+ throw createSqliteNestedTransactionError();
1574
+ }
1575
+
1576
+ state.transactionActive = true;
1577
+ try {
1578
+ await nativeBridge.transactionBegin(state.handle);
1579
+ } catch (error) {
1580
+ state.transactionActive = false;
1581
+ throw error;
1582
+ }
1583
+
1584
+ const transaction = createSqliteTransaction();
1585
+ let value;
1586
+ try {
1587
+ value = await callback(transaction.tx);
1588
+ } catch (error) {
1589
+ return rollbackAfterCallbackError(error, transaction);
1590
+ }
1591
+ await commitTransaction(transaction);
1592
+ return value;
1593
+ },
1594
+
1595
+ close() {
1596
+ if (state.closed) {
1597
+ return;
1598
+ }
1599
+ if (state.transactionActive) {
1600
+ throw createSqliteTransactionActiveError("close");
1601
+ }
1602
+
1603
+ closeActiveCursors(state.activeCursors);
1604
+ nativeBridge.close(state.handle);
1605
+ state.closed = true;
1606
+ },
1607
+
1608
+ __debug() {
1609
+ return Object.freeze({
1610
+ kind: "sqlite-connection",
1611
+ closed: state.closed,
1612
+ transactionActive: state.transactionActive,
1613
+ resource: "opaque",
1614
+ });
1615
+ },
1616
+ };
1617
+ return Object.freeze(markRealDataProvider(connection, "sqlite"));
1618
+ }
1619
+
1620
+ function redactConnectionString(value) {
1621
+ return value
1622
+ .replace(
1623
+ /(^|[\s;?&])(password\s*=\s*)(?:'(?:\\.|[^'])*'|"(?:\\.|[^"])*"|[^\s;?&]*)/gi,
1624
+ (_match, prefix, key) => `${prefix}${key}<redacted>`,
1625
+ )
1626
+ .replace(/(postgres(?:ql)?:\/\/[^:\s/@]+:)[^@\s/]+(@)/gi, "$1<redacted>$2");
1627
+ }
1628
+
1629
+ function validatePostgresOpenOptions(options) {
1630
+ if (!isPlainObject(options)) {
1631
+ throw new TypeError("Sloppy postgres.open options must be a plain object.");
1632
+ }
1633
+
1634
+ if (typeof options.connectionString !== "string" || options.connectionString.length === 0 || options.connectionString.includes("\0")) {
1635
+ throw new TypeError("Sloppy postgres.open connectionString must be a non-empty string without NUL.");
1636
+ }
1637
+ const capability = options.capability ?? "data.postgres";
1638
+ if (typeof capability !== "string" || capability.length === 0 || capability.includes("\0")) {
1639
+ throw new TypeError("Sloppy postgres.open capability must be a non-empty string without NUL.");
1640
+ }
1641
+
1642
+ const access = options.access ?? "readwrite";
1643
+ if (access !== "read" && access !== "readwrite") {
1644
+ throw new TypeError("Sloppy postgres.open access must be read or readwrite.");
1645
+ }
1646
+
1647
+ const maxConnections = options.maxConnections ?? 1;
1648
+ if (!Number.isInteger(maxConnections) || maxConnections < 1 ||
1649
+ maxConnections > POSTGRES_MAX_POOL_CONNECTIONS)
1650
+ {
1651
+ throw new TypeError(
1652
+ `Sloppy postgres.open maxConnections must be an integer from 1 to ${POSTGRES_MAX_POOL_CONNECTIONS}.`,
1653
+ );
1654
+ }
1655
+
1656
+ return Object.freeze({
1657
+ provider: "postgres",
1658
+ connectionString: options.connectionString,
1659
+ redactedConnectionString: redactConnectionString(options.connectionString),
1660
+ access,
1661
+ maxConnections,
1662
+ capability,
1663
+ placeholderStyle: "postgres",
1664
+ });
1665
+ }
1666
+
1667
+ function postgresNativeBridge() {
1668
+ return globalThis.__sloppy?.data?.postgres ?? null;
1669
+ }
1670
+
1671
+ function sqlserverNativeBridge() {
1672
+ return globalThis.__sloppy?.data?.sqlserver ?? null;
1673
+ }
1674
+
1675
+ function redactOdbcConnectionString(value) {
1676
+ return value.replace(
1677
+ /(^|;)(\s*)(password|pwd|access token|accesstoken)(\s*)=(\s*)({(?:}}|[^}])*}|[^;]*)/gi,
1678
+ (_match, prefix, leading, key, beforeEquals, afterEquals) =>
1679
+ `${prefix}${leading}${key}${beforeEquals}=${afterEquals}<redacted>`,
1680
+ );
1681
+ }
1682
+
1683
+ function extractOdbcDriverName(connectionString) {
1684
+ const match = /(?:^|;)\s*driver\s*=\s*({(?:}}|[^}])*}|[^;]*)/i.exec(connectionString);
1685
+
1686
+ if (!match) {
1687
+ return "";
1688
+ }
1689
+ const value = match[1];
1690
+ if (value.startsWith("{") && value.endsWith("}")) {
1691
+ return value.slice(1, -1).replaceAll("}}", "}");
1692
+ }
1693
+ return value;
1694
+ }
1695
+
1696
+ function validateSqlServerOpenOptions(options) {
1697
+ if (!isPlainObject(options)) {
1698
+ throw new TypeError("Sloppy sqlserver.open options must be a plain object.");
1699
+ }
1700
+
1701
+ if (typeof options.connectionString !== "string" || options.connectionString.length === 0 || options.connectionString.includes("\0")) {
1702
+ throw new TypeError("Sloppy sqlserver.open connectionString must be a non-empty string without NUL.");
1703
+ }
1704
+ const capability = options.capability ?? "data.sqlserver";
1705
+ if (typeof capability !== "string" || capability.length === 0 || capability.includes("\0")) {
1706
+ throw new TypeError("Sloppy sqlserver.open capability must be a non-empty string without NUL.");
1707
+ }
1708
+
1709
+ const access = options.access ?? "readwrite";
1710
+ if (access !== "read" && access !== "readwrite") {
1711
+ throw new TypeError("Sloppy sqlserver.open access must be read or readwrite.");
1712
+ }
1713
+
1714
+ const maxConnections = options.maxConnections ?? 1;
1715
+ if (!Number.isInteger(maxConnections) || maxConnections < 1 ||
1716
+ maxConnections > SQLSERVER_MAX_POOL_CONNECTIONS)
1717
+ {
1718
+ throw new TypeError(
1719
+ `Sloppy sqlserver.open maxConnections must be an integer from 1 to ${SQLSERVER_MAX_POOL_CONNECTIONS}.`,
1720
+ );
1721
+ }
1722
+
1723
+ return Object.freeze({
1724
+ provider: "sqlserver",
1725
+ connectionString: options.connectionString,
1726
+ redactedConnectionString: redactOdbcConnectionString(options.connectionString),
1727
+ driver: extractOdbcDriverName(options.connectionString),
1728
+ capability,
1729
+ access,
1730
+ maxConnections,
1731
+ placeholderStyle: "question",
1732
+ });
1733
+ }
1734
+
1735
+ function missingProviderMethod(method) {
1736
+ throw new Error(`sloppy: fake data provider method missing
1737
+
1738
+ Method:
1739
+ ${method}
1740
+
1741
+ Fix:
1742
+ Pass a '${method}' function to data.createFakeProvider(...) for this test or example.`);
1743
+ }
1744
+
1745
+ function createSqliteUnavailableError(operation) {
1746
+ return new Error(`SLOPPY_E_UNAVAILABLE_RUNTIME_FEATURE: runtime feature provider.sqlite is inactive or unavailable
1747
+
1748
+ Provider:
1749
+ sqlite
1750
+
1751
+ Feature:
1752
+ provider.sqlite
1753
+
1754
+ Operation:
1755
+ ${operation}
1756
+
1757
+ Reason:
1758
+ The active Sloppy Plan did not enable the __sloppy.data.sqlite V8 intrinsic namespace.
1759
+
1760
+ Fix:
1761
+ Add SQLite provider metadata to the Plan, or keep SQLite usage behind a documented deferral.`);
1762
+ }
1763
+
1764
+ function createPostgresUnavailableError(operation, options) {
1765
+ const safeOptions = validatePostgresOpenOptions(options);
1766
+ return new Error(`SLOPPY_E_UNAVAILABLE_RUNTIME_FEATURE: runtime feature provider.postgres is unavailable
1767
+
1768
+ Provider:
1769
+ postgres
1770
+
1771
+ Feature:
1772
+ provider.postgres
1773
+
1774
+ Operation:
1775
+ ${operation}
1776
+
1777
+ Connection:
1778
+ ${safeOptions.redactedConnectionString}
1779
+
1780
+ Reason:
1781
+ The active Sloppy Plan did not enable the __sloppy.data.postgres V8 intrinsic namespace.
1782
+
1783
+ Fix:
1784
+ Add PostgreSQL provider metadata to the Plan, or keep PostgreSQL usage behind a documented capability boundary.`);
1785
+ }
1786
+
1787
+ function createSqlServerUnavailableError(operation, options) {
1788
+ const safeOptions = validateSqlServerOpenOptions(options);
1789
+ return new Error(`SLOPPY_E_UNAVAILABLE_RUNTIME_FEATURE: runtime feature provider.sqlserver is unavailable
1790
+
1791
+ Provider:
1792
+ sqlserver
1793
+
1794
+ Feature:
1795
+ provider.sqlserver
1796
+
1797
+ Operation:
1798
+ ${operation}
1799
+
1800
+ Connection:
1801
+ ${safeOptions.redactedConnectionString}
1802
+
1803
+ Reason:
1804
+ The active Sloppy Plan did not enable the __sloppy.data.sqlserver V8 intrinsic namespace.
1805
+
1806
+ Fix:
1807
+ Add SQL Server provider metadata to the Plan, or keep SQL Server usage behind a documented capability boundary.`);
1808
+ }
1809
+
1810
+ function openSqlite(options) {
1811
+ const safeOptions = validateSqliteOpenOptions(options);
1812
+ const nativeBridge = sqliteNativeBridge();
1813
+
1814
+ if (nativeBridge === null) {
1815
+ throw createSqliteUnavailableError("open");
1816
+ }
1817
+
1818
+ return createSqliteConnection(nativeBridge, nativeBridge.open(safeOptions));
1819
+ }
1820
+
1821
+ function openSqliteProvider(name) {
1822
+ const provider = normalizeSqliteProviderToken(name);
1823
+ const nativeBridge = sqliteNativeBridge();
1824
+
1825
+ if (nativeBridge === null) {
1826
+ throw createSqliteUnavailableError("open");
1827
+ }
1828
+
1829
+ return createSqliteConnection(nativeBridge, nativeBridge.open({
1830
+ provider,
1831
+ }));
1832
+ }
1833
+
1834
+ function createPostgresClosedError(operation) {
1835
+ return new Error(`sloppy: postgres connection is closed
1836
+
1837
+ Provider:
1838
+ postgres
1839
+
1840
+ Operation:
1841
+ ${operation}
1842
+
1843
+ Fix:
1844
+ Open a new PostgreSQL connection before using ${operation}.`);
1845
+ }
1846
+
1847
+ function createPostgresTransactionClosedError(operation) {
1848
+ return new Error(`sloppy: postgres transaction scope is closed
1849
+
1850
+ Provider:
1851
+ postgres
1852
+
1853
+ Operation:
1854
+ ${operation}
1855
+
1856
+ Fix:
1857
+ Do not use the transaction object after transaction(...) resolves or rejects.`);
1858
+ }
1859
+
1860
+ function createPostgresNestedTransactionError() {
1861
+ return new Error(`sloppy: postgres nested transactions are not supported
1862
+
1863
+ Provider:
1864
+ postgres
1865
+
1866
+ Operation:
1867
+ transaction
1868
+
1869
+ Fix:
1870
+ Use the transaction object passed to the current callback, or start a new transaction after it settles.`);
1871
+ }
1872
+
1873
+ function normalizePostgresOperation(operation, args) {
1874
+ const allowResultMode = operation === "query" || operation === "queryCursor";
1875
+ const allowMaxRows = operation === "query" || operation === "queryRaw"
1876
+ || operation === "queryCursor" || operation === "queryRawCursor";
1877
+ const allowCursorOptions = operation === "queryCursor" || operation === "queryRawCursor";
1878
+ if (args.length === 1 && isLoweredQuery(args[0])) {
1879
+ return {
1880
+ text: args[0].text,
1881
+ parameters: args[0].parameters,
1882
+ options: undefined,
1883
+ mode: allowResultMode ? "object" : undefined,
1884
+ };
1885
+ }
1886
+ if (args.length === 2 && isLoweredQuery(args[0])) {
1887
+ const options = normalizeOperationOptions(
1888
+ args[1],
1889
+ `postgres.${operation}`,
1890
+ allowResultMode,
1891
+ allowMaxRows,
1892
+ allowCursorOptions,
1893
+ );
1894
+ return {
1895
+ text: args[0].text,
1896
+ parameters: args[0].parameters,
1897
+ options,
1898
+ mode: allowResultMode ? options?.mode ?? "object" : undefined,
1899
+ };
1900
+ }
1901
+
1902
+ if (typeof args[0] === "string") {
1903
+ if (args.length > 3) {
1904
+ throw new TypeError(`Sloppy postgres.${operation} accepts sql, optional params, and optional options.`);
1905
+ }
1906
+ const inlineOptions = hasInlineOperationOptions(args);
1907
+ const params = inlineOptions ? undefined : args[1];
1908
+ const options = normalizeOperationOptions(
1909
+ inlineOptions ? args[1] : args[2],
1910
+ `postgres.${operation}`,
1911
+ allowResultMode,
1912
+ allowMaxRows,
1913
+ allowCursorOptions,
1914
+ );
1915
+ if (args[0].length === 0) {
1916
+ throw new TypeError(`Sloppy postgres.${operation} SQL must be a non-empty string.`);
1917
+ }
1918
+ if (params !== undefined && !Array.isArray(params)) {
1919
+ throw new TypeError(`Sloppy postgres.${operation} parameters must be an array.`);
1920
+ }
1921
+ return {
1922
+ text: args[0],
1923
+ parameters: params ?? [],
1924
+ options,
1925
+ mode: allowResultMode ? options?.mode ?? "object" : undefined,
1926
+ };
1927
+ }
1928
+
1929
+ const call = normalizeProviderCallArguments(`postgres.${operation}`, "postgres", args);
1930
+ return {
1931
+ text: call.query.text,
1932
+ parameters: call.query.parameters,
1933
+ options: call.options,
1934
+ mode: allowResultMode ? call.mode ?? "object" : undefined,
1935
+ };
1936
+ }
1937
+
1938
+ function createPostgresConnection(nativeBridge, handle) {
1939
+ const state = {
1940
+ closed: false,
1941
+ handle,
1942
+ transactionActive: false,
1943
+ activeCursors: new Set(),
1944
+ };
1945
+
1946
+ function assertOpen(operation) {
1947
+ if (state.closed) {
1948
+ throw createPostgresClosedError(operation);
1949
+ }
1950
+ }
1951
+
1952
+ function createTransaction() {
1953
+ const txState = { closed: false, activeCursors: new Set() };
1954
+ function assertTransactionOpen(operation) {
1955
+ assertOpen(operation);
1956
+ if (txState.closed) {
1957
+ throw createPostgresTransactionClosedError(operation);
1958
+ }
1959
+ }
1960
+
1961
+ const tx = Object.freeze({
1962
+ query(...args) {
1963
+ assertTransactionOpen("transaction.query");
1964
+ const query = normalizePostgresOperation("query", args);
1965
+ const method = query.mode === "raw"
1966
+ ? nativeBridge.transactionQueryRaw
1967
+ : nativeBridge.transactionQuery;
1968
+ return invokeProviderOperation("postgres.transaction.query", query.options, () =>
1969
+ invokeNativeQuery(method, state.handle, query, true));
1970
+ },
1971
+ queryRaw(...args) {
1972
+ assertTransactionOpen("transaction.queryRaw");
1973
+ const query = normalizePostgresOperation("queryRaw", args);
1974
+ return invokeProviderOperation("postgres.transaction.queryRaw", query.options, () =>
1975
+ invokeNativeQuery(nativeBridge.transactionQueryRaw, state.handle, query, true));
1976
+ },
1977
+ async queryCursor(...args) {
1978
+ assertTransactionOpen("transaction.queryCursor");
1979
+ const query = normalizePostgresOperation("queryCursor", args);
1980
+ const methodName = query.mode === "raw"
1981
+ ? "transactionQueryRawCursor"
1982
+ : "transactionQueryCursor";
1983
+ return invokeProviderOperation("postgres.transaction.queryCursor", query.options, () =>
1984
+ openProviderCursor("postgres", nativeBridge, state.handle, query, query.mode, methodName, txState.activeCursors));
1985
+ },
1986
+ async queryRawCursor(...args) {
1987
+ assertTransactionOpen("transaction.queryRawCursor");
1988
+ const query = normalizePostgresOperation("queryRawCursor", args);
1989
+ return invokeProviderOperation("postgres.transaction.queryRawCursor", query.options, () =>
1990
+ openProviderCursor("postgres", nativeBridge, state.handle, query, "raw", "transactionQueryRawCursor", txState.activeCursors));
1991
+ },
1992
+ queryOne(...args) {
1993
+ assertTransactionOpen("transaction.queryOne");
1994
+ const query = normalizePostgresOperation("queryOne", args);
1995
+ return invokeProviderOperation("postgres.transaction.queryOne", query.options, () =>
1996
+ nativeBridge.transactionQueryOne(state.handle, query.text, query.parameters));
1997
+ },
1998
+ exec(...args) {
1999
+ assertTransactionOpen("transaction.exec");
2000
+ const query = normalizePostgresOperation("exec", args);
2001
+ return invokeProviderOperation("postgres.transaction.exec", query.options, () =>
2002
+ nativeBridge.transactionExec(state.handle, query.text, query.parameters));
2003
+ },
2004
+ transaction() {
2005
+ throw createPostgresNestedTransactionError();
2006
+ },
2007
+ });
2008
+
2009
+ return {
2010
+ tx,
2011
+ close() {
2012
+ closeActiveCursors(txState.activeCursors);
2013
+ txState.closed = true;
2014
+ },
2015
+ };
2016
+ }
2017
+
2018
+ async function rollbackAfterCallbackError(error, transaction) {
2019
+ try {
2020
+ transaction.close();
2021
+ await nativeBridge.transactionRollback(state.handle);
2022
+ } catch {
2023
+ transaction.close();
2024
+ state.closed = true;
2025
+ try {
2026
+ nativeBridge.close(state.handle);
2027
+ } catch {
2028
+ // Preserve the original callback error while preventing reuse.
2029
+ }
2030
+ throw error;
2031
+ }
2032
+ state.transactionActive = false;
2033
+ throw error;
2034
+ }
2035
+
2036
+ async function commitTransaction(transaction) {
2037
+ try {
2038
+ transaction.close();
2039
+ await nativeBridge.transactionCommit(state.handle);
2040
+ } catch (error) {
2041
+ transaction.close();
2042
+ state.transactionActive = false;
2043
+ state.closed = true;
2044
+ try {
2045
+ nativeBridge.close(state.handle);
2046
+ } catch {
2047
+ // Keep the commit failure as the observable error.
2048
+ }
2049
+ throw error;
2050
+ }
2051
+ state.transactionActive = false;
2052
+ }
2053
+
2054
+ const connection = {
2055
+ query(...args) {
2056
+ assertOpen("query");
2057
+ const query = normalizePostgresOperation("query", args);
2058
+ const method = query.mode === "raw" ? nativeBridge.queryRaw : nativeBridge.query;
2059
+ return invokeProviderOperation("postgres.query", query.options, () =>
2060
+ invokeNativeQuery(method, state.handle, query, true));
2061
+ },
2062
+ queryRaw(...args) {
2063
+ assertOpen("queryRaw");
2064
+ const query = normalizePostgresOperation("queryRaw", args);
2065
+ return invokeProviderOperation("postgres.queryRaw", query.options, () =>
2066
+ invokeNativeQuery(nativeBridge.queryRaw, state.handle, query, true));
2067
+ },
2068
+ async queryCursor(...args) {
2069
+ assertOpen("queryCursor");
2070
+ const query = normalizePostgresOperation("queryCursor", args);
2071
+ const methodName = query.mode === "raw" ? "queryRawCursor" : "queryCursor";
2072
+ return invokeProviderOperation("postgres.queryCursor", query.options, () =>
2073
+ openProviderCursor("postgres", nativeBridge, state.handle, query, query.mode, methodName, state.activeCursors));
2074
+ },
2075
+ async queryRawCursor(...args) {
2076
+ assertOpen("queryRawCursor");
2077
+ const query = normalizePostgresOperation("queryRawCursor", args);
2078
+ return invokeProviderOperation("postgres.queryRawCursor", query.options, () =>
2079
+ openProviderCursor("postgres", nativeBridge, state.handle, query, "raw", "queryRawCursor", state.activeCursors));
2080
+ },
2081
+ stream(...args) {
2082
+ return this.queryCursor(...args);
2083
+ },
2084
+ queryOne(...args) {
2085
+ assertOpen("queryOne");
2086
+ const query = normalizePostgresOperation("queryOne", args);
2087
+ return invokeProviderOperation("postgres.queryOne", query.options, () =>
2088
+ nativeBridge.queryOne(state.handle, query.text, query.parameters));
2089
+ },
2090
+ exec(...args) {
2091
+ assertOpen("exec");
2092
+ const query = normalizePostgresOperation("exec", args);
2093
+ return invokeProviderOperation("postgres.exec", query.options, () =>
2094
+ nativeBridge.exec(state.handle, query.text, query.parameters));
2095
+ },
2096
+ async transaction(callback) {
2097
+ assertOpen("transaction");
2098
+ if (typeof callback !== "function") {
2099
+ throw new TypeError("Sloppy postgres.transaction callback must be a function.");
2100
+ }
2101
+ if (state.transactionActive) {
2102
+ throw createPostgresNestedTransactionError();
2103
+ }
2104
+ state.transactionActive = true;
2105
+ try {
2106
+ await nativeBridge.transactionBegin(state.handle);
2107
+ } catch (error) {
2108
+ state.transactionActive = false;
2109
+ throw error;
2110
+ }
2111
+
2112
+ const transaction = createTransaction();
2113
+ let value;
2114
+ try {
2115
+ value = await callback(transaction.tx);
2116
+ } catch (error) {
2117
+ return rollbackAfterCallbackError(error, transaction);
2118
+ }
2119
+ await commitTransaction(transaction);
2120
+ return value;
2121
+ },
2122
+ close() {
2123
+ if (state.closed) {
2124
+ return;
2125
+ }
2126
+ if (state.transactionActive) {
2127
+ throw new Error("sloppy: postgres transaction is active");
2128
+ }
2129
+ closeActiveCursors(state.activeCursors);
2130
+ nativeBridge.close(state.handle);
2131
+ state.closed = true;
2132
+ },
2133
+ __debug() {
2134
+ return Object.freeze({
2135
+ kind: "postgres-connection",
2136
+ closed: state.closed,
2137
+ transactionActive: state.transactionActive,
2138
+ resource: "opaque",
2139
+ });
2140
+ },
2141
+ };
2142
+ return Object.freeze(markRealDataProvider(connection, "postgres"));
2143
+ }
2144
+
2145
+ function createSqlServerClosedError(operation) {
2146
+ return new Error(`sloppy: sqlserver connection is closed
2147
+
2148
+ Provider:
2149
+ sqlserver
2150
+
2151
+ Operation:
2152
+ ${operation}
2153
+
2154
+ Fix:
2155
+ Open a new SQL Server connection before using ${operation}.`);
2156
+ }
2157
+
2158
+ function createSqlServerTransactionClosedError(operation) {
2159
+ return new Error(`sloppy: sqlserver transaction scope is closed
2160
+
2161
+ Provider:
2162
+ sqlserver
2163
+
2164
+ Operation:
2165
+ ${operation}
2166
+
2167
+ Fix:
2168
+ Do not use the transaction object after transaction(...) resolves or rejects.`);
2169
+ }
2170
+
2171
+ function createSqlServerNestedTransactionError() {
2172
+ return new Error(`sloppy: sqlserver nested transactions are not supported
2173
+
2174
+ Provider:
2175
+ sqlserver
2176
+
2177
+ Operation:
2178
+ transaction
2179
+
2180
+ Fix:
2181
+ Use the transaction object passed to the current callback, or start a new transaction after it settles.`);
2182
+ }
2183
+
2184
+ function normalizeSqlServerOperation(operation, args) {
2185
+ const allowResultMode = operation === "query" || operation === "queryCursor";
2186
+ const allowMaxRows = operation === "query" || operation === "queryRaw"
2187
+ || operation === "queryCursor" || operation === "queryRawCursor";
2188
+ const allowCursorOptions = operation === "queryCursor" || operation === "queryRawCursor";
2189
+ if (args.length === 1 && isLoweredQuery(args[0])) {
2190
+ return {
2191
+ text: args[0].text,
2192
+ parameters: args[0].parameters,
2193
+ options: undefined,
2194
+ mode: allowResultMode ? "object" : undefined,
2195
+ };
2196
+ }
2197
+ if (args.length === 2 && isLoweredQuery(args[0])) {
2198
+ const options = normalizeOperationOptions(
2199
+ args[1],
2200
+ `sqlserver.${operation}`,
2201
+ allowResultMode,
2202
+ allowMaxRows,
2203
+ allowCursorOptions,
2204
+ );
2205
+ return {
2206
+ text: args[0].text,
2207
+ parameters: args[0].parameters,
2208
+ options,
2209
+ mode: allowResultMode ? options?.mode ?? "object" : undefined,
2210
+ };
2211
+ }
2212
+
2213
+ if (typeof args[0] === "string") {
2214
+ if (args.length > 3) {
2215
+ throw new TypeError(`Sloppy sqlserver.${operation} accepts sql, optional params, and optional options.`);
2216
+ }
2217
+ const inlineOptions = hasInlineOperationOptions(args);
2218
+ const params = inlineOptions ? undefined : args[1];
2219
+ const options = normalizeOperationOptions(
2220
+ inlineOptions ? args[1] : args[2],
2221
+ `sqlserver.${operation}`,
2222
+ allowResultMode,
2223
+ allowMaxRows,
2224
+ allowCursorOptions,
2225
+ );
2226
+ if (args[0].length === 0) {
2227
+ throw new TypeError(`Sloppy sqlserver.${operation} SQL must be a non-empty string.`);
2228
+ }
2229
+ if (params !== undefined && !Array.isArray(params)) {
2230
+ throw new TypeError(`Sloppy sqlserver.${operation} parameters must be an array.`);
2231
+ }
2232
+ return {
2233
+ text: args[0],
2234
+ parameters: params ?? [],
2235
+ options,
2236
+ mode: allowResultMode ? options?.mode ?? "object" : undefined,
2237
+ };
2238
+ }
2239
+
2240
+ const call = normalizeProviderCallArguments(`sqlserver.${operation}`, "question", args);
2241
+ return {
2242
+ text: call.query.text,
2243
+ parameters: call.query.parameters,
2244
+ options: call.options,
2245
+ mode: allowResultMode ? call.mode ?? "object" : undefined,
2246
+ };
2247
+ }
2248
+
2249
+ function createSqlServerConnection(nativeBridge, handle) {
2250
+ const state = {
2251
+ closed: false,
2252
+ handle,
2253
+ transactionActive: false,
2254
+ activeCursors: new Set(),
2255
+ };
2256
+
2257
+ function assertOpen(operation) {
2258
+ if (state.closed) {
2259
+ throw createSqlServerClosedError(operation);
2260
+ }
2261
+ }
2262
+
2263
+ function createTransaction() {
2264
+ const txState = { closed: false, activeCursors: new Set() };
2265
+ function assertTransactionOpen(operation) {
2266
+ assertOpen(operation);
2267
+ if (txState.closed) {
2268
+ throw createSqlServerTransactionClosedError(operation);
2269
+ }
2270
+ }
2271
+
2272
+ const tx = Object.freeze({
2273
+ query(...args) {
2274
+ assertTransactionOpen("transaction.query");
2275
+ const query = normalizeSqlServerOperation("query", args);
2276
+ const method = query.mode === "raw"
2277
+ ? nativeBridge.transactionQueryRaw
2278
+ : nativeBridge.transactionQuery;
2279
+ return invokeProviderOperation("sqlserver.transaction.query", query.options, () =>
2280
+ invokeNativeQuery(method, state.handle, query, true));
2281
+ },
2282
+ queryRaw(...args) {
2283
+ assertTransactionOpen("transaction.queryRaw");
2284
+ const query = normalizeSqlServerOperation("queryRaw", args);
2285
+ return invokeProviderOperation("sqlserver.transaction.queryRaw", query.options, () =>
2286
+ invokeNativeQuery(nativeBridge.transactionQueryRaw, state.handle, query, true));
2287
+ },
2288
+ async queryCursor(...args) {
2289
+ assertTransactionOpen("transaction.queryCursor");
2290
+ const query = normalizeSqlServerOperation("queryCursor", args);
2291
+ const methodName = query.mode === "raw"
2292
+ ? "transactionQueryRawCursor"
2293
+ : "transactionQueryCursor";
2294
+ return invokeProviderOperation("sqlserver.transaction.queryCursor", query.options, () =>
2295
+ openProviderCursor("sqlserver", nativeBridge, state.handle, query, query.mode, methodName, txState.activeCursors));
2296
+ },
2297
+ async queryRawCursor(...args) {
2298
+ assertTransactionOpen("transaction.queryRawCursor");
2299
+ const query = normalizeSqlServerOperation("queryRawCursor", args);
2300
+ return invokeProviderOperation("sqlserver.transaction.queryRawCursor", query.options, () =>
2301
+ openProviderCursor("sqlserver", nativeBridge, state.handle, query, "raw", "transactionQueryRawCursor", txState.activeCursors));
2302
+ },
2303
+ queryOne(...args) {
2304
+ assertTransactionOpen("transaction.queryOne");
2305
+ const query = normalizeSqlServerOperation("queryOne", args);
2306
+ return invokeProviderOperation("sqlserver.transaction.queryOne", query.options, () =>
2307
+ nativeBridge.transactionQueryOne(state.handle, query.text, query.parameters));
2308
+ },
2309
+ exec(...args) {
2310
+ assertTransactionOpen("transaction.exec");
2311
+ const query = normalizeSqlServerOperation("exec", args);
2312
+ return invokeProviderOperation("sqlserver.transaction.exec", query.options, () =>
2313
+ nativeBridge.transactionExec(state.handle, query.text, query.parameters));
2314
+ },
2315
+ transaction() {
2316
+ throw createSqlServerNestedTransactionError();
2317
+ },
2318
+ });
2319
+
2320
+ return {
2321
+ tx,
2322
+ close() {
2323
+ closeActiveCursors(txState.activeCursors);
2324
+ txState.closed = true;
2325
+ },
2326
+ };
2327
+ }
2328
+
2329
+ async function rollbackAfterCallbackError(error, transaction) {
2330
+ try {
2331
+ transaction.close();
2332
+ await nativeBridge.transactionRollback(state.handle);
2333
+ } catch {
2334
+ transaction.close();
2335
+ state.closed = true;
2336
+ try {
2337
+ nativeBridge.close(state.handle);
2338
+ } catch {
2339
+ // Preserve the original callback error while preventing reuse.
2340
+ }
2341
+ throw error;
2342
+ }
2343
+ state.transactionActive = false;
2344
+ throw error;
2345
+ }
2346
+
2347
+ async function commitTransaction(transaction) {
2348
+ try {
2349
+ transaction.close();
2350
+ await nativeBridge.transactionCommit(state.handle);
2351
+ } catch (error) {
2352
+ transaction.close();
2353
+ state.transactionActive = false;
2354
+ state.closed = true;
2355
+ try {
2356
+ nativeBridge.close(state.handle);
2357
+ } catch {
2358
+ // Keep the commit failure as the observable error.
2359
+ }
2360
+ throw error;
2361
+ }
2362
+ state.transactionActive = false;
2363
+ }
2364
+
2365
+ const connection = {
2366
+ query(...args) {
2367
+ assertOpen("query");
2368
+ const query = normalizeSqlServerOperation("query", args);
2369
+ const method = query.mode === "raw" ? nativeBridge.queryRaw : nativeBridge.query;
2370
+ return invokeProviderOperation("sqlserver.query", query.options, () =>
2371
+ invokeNativeQuery(method, state.handle, query, true));
2372
+ },
2373
+ queryRaw(...args) {
2374
+ assertOpen("queryRaw");
2375
+ const query = normalizeSqlServerOperation("queryRaw", args);
2376
+ return invokeProviderOperation("sqlserver.queryRaw", query.options, () =>
2377
+ invokeNativeQuery(nativeBridge.queryRaw, state.handle, query, true));
2378
+ },
2379
+ async queryCursor(...args) {
2380
+ assertOpen("queryCursor");
2381
+ const query = normalizeSqlServerOperation("queryCursor", args);
2382
+ const methodName = query.mode === "raw" ? "queryRawCursor" : "queryCursor";
2383
+ return invokeProviderOperation("sqlserver.queryCursor", query.options, () =>
2384
+ openProviderCursor("sqlserver", nativeBridge, state.handle, query, query.mode, methodName, state.activeCursors));
2385
+ },
2386
+ async queryRawCursor(...args) {
2387
+ assertOpen("queryRawCursor");
2388
+ const query = normalizeSqlServerOperation("queryRawCursor", args);
2389
+ return invokeProviderOperation("sqlserver.queryRawCursor", query.options, () =>
2390
+ openProviderCursor("sqlserver", nativeBridge, state.handle, query, "raw", "queryRawCursor", state.activeCursors));
2391
+ },
2392
+ stream(...args) {
2393
+ return this.queryCursor(...args);
2394
+ },
2395
+ queryOne(...args) {
2396
+ assertOpen("queryOne");
2397
+ const query = normalizeSqlServerOperation("queryOne", args);
2398
+ return invokeProviderOperation("sqlserver.queryOne", query.options, () =>
2399
+ nativeBridge.queryOne(state.handle, query.text, query.parameters));
2400
+ },
2401
+ exec(...args) {
2402
+ assertOpen("exec");
2403
+ const query = normalizeSqlServerOperation("exec", args);
2404
+ return invokeProviderOperation("sqlserver.exec", query.options, () =>
2405
+ nativeBridge.exec(state.handle, query.text, query.parameters));
2406
+ },
2407
+ async transaction(callback) {
2408
+ assertOpen("transaction");
2409
+ if (typeof callback !== "function") {
2410
+ throw new TypeError("Sloppy sqlserver.transaction callback must be a function.");
2411
+ }
2412
+ if (state.transactionActive) {
2413
+ throw createSqlServerNestedTransactionError();
2414
+ }
2415
+ state.transactionActive = true;
2416
+ try {
2417
+ await nativeBridge.transactionBegin(state.handle);
2418
+ } catch (error) {
2419
+ state.transactionActive = false;
2420
+ throw error;
2421
+ }
2422
+ const transaction = createTransaction();
2423
+ let value;
2424
+ try {
2425
+ value = await callback(transaction.tx);
2426
+ } catch (error) {
2427
+ return rollbackAfterCallbackError(error, transaction);
2428
+ }
2429
+ await commitTransaction(transaction);
2430
+ return value;
2431
+ },
2432
+ close() {
2433
+ if (state.closed) {
2434
+ return;
2435
+ }
2436
+ if (state.transactionActive) {
2437
+ throw new Error("sloppy: sqlserver transaction is active");
2438
+ }
2439
+ closeActiveCursors(state.activeCursors);
2440
+ nativeBridge.close(state.handle);
2441
+ state.closed = true;
2442
+ },
2443
+ __debug() {
2444
+ return Object.freeze({
2445
+ kind: "sqlserver-connection",
2446
+ closed: state.closed,
2447
+ transactionActive: state.transactionActive,
2448
+ resource: "opaque",
2449
+ });
2450
+ },
2451
+ };
2452
+ return Object.freeze(markRealDataProvider(connection, "sqlserver"));
2453
+ }
2454
+
2455
+ function openPostgres(options) {
2456
+ const safeOptions = validatePostgresOpenOptions(options);
2457
+ const nativeBridge = postgresNativeBridge();
2458
+
2459
+ if (nativeBridge === null) {
2460
+ throw createPostgresUnavailableError("open", options);
2461
+ }
2462
+
2463
+ return createPostgresConnection(nativeBridge, nativeBridge.open(safeOptions));
2464
+ }
2465
+
2466
+ function openSqlServer(options) {
2467
+ const safeOptions = validateSqlServerOpenOptions(options);
2468
+ const nativeBridge = sqlserverNativeBridge();
2469
+
2470
+ if (nativeBridge === null) {
2471
+ throw createSqlServerUnavailableError("open", options);
2472
+ }
2473
+
2474
+ return createSqlServerConnection(nativeBridge, nativeBridge.open(safeOptions));
2475
+ }
2476
+
2477
+ function doctorSqlServer(options = {}) {
2478
+ const connectionString = typeof options.connectionString === "string"
2479
+ ? options.connectionString
2480
+ : "";
2481
+ const driver = connectionString.length > 0 ? extractOdbcDriverName(connectionString) : "";
2482
+
2483
+ return Object.freeze({
2484
+ ok: false,
2485
+ provider: "sqlserver",
2486
+ driverManager: "native-check-unavailable",
2487
+ driver: driver.length > 0 ? "unchecked" : "unknown",
2488
+ message: "SQL Server doctor metadata is redacted here; live driver/service validation runs only in the opt-in native or V8 live-provider lanes.",
2489
+ connectionString: connectionString.length > 0
2490
+ ? redactOdbcConnectionString(connectionString)
2491
+ : undefined,
2492
+ hints: Object.freeze([
2493
+ "install Microsoft ODBC Driver 18 for SQL Server",
2494
+ "check driver name",
2495
+ "check connection string",
2496
+ "use TrustServerCertificate=yes for local dev only when appropriate",
2497
+ ]),
2498
+ });
2499
+ }
2500
+
2501
+ const sqliteSupports = {
2502
+ memory: true,
2503
+ file: true,
2504
+ queryTemplates: true,
2505
+ parameters: Object.freeze([
2506
+ "null",
2507
+ "string",
2508
+ "integer",
2509
+ "bigint",
2510
+ "float",
2511
+ "boolean",
2512
+ "bytes",
2513
+ "explicit-json-text",
2514
+ "explicit-date-time-text",
2515
+ ]),
2516
+ transactions: true,
2517
+ transactionsMode: "callback",
2518
+ cursors: true,
2519
+ cursorModes: Object.freeze(["object", "raw"]),
2520
+ responseStreamingAdapter: false,
2521
+ preparedStatements: false,
2522
+ pooling: false,
2523
+ migrations: true,
2524
+ orm: false,
2525
+ };
2526
+
2527
+ Object.defineProperty(sqliteSupports, "nativeStdlibBridge", {
2528
+ enumerable: true,
2529
+ get() {
2530
+ return sqliteNativeBridge() !== null;
2531
+ },
2532
+ });
2533
+
2534
+ const postgresSupports = {
2535
+ connectionString: true,
2536
+ queryTemplates: true,
2537
+ parameters: Object.freeze([
2538
+ "null",
2539
+ "string",
2540
+ "integer",
2541
+ "float",
2542
+ "boolean",
2543
+ "bigint",
2544
+ "decimal",
2545
+ "bytes",
2546
+ "uuid",
2547
+ "json",
2548
+ "date",
2549
+ "time",
2550
+ "timestamp",
2551
+ "instant",
2552
+ "offsetDateTime",
2553
+ "array",
2554
+ ]),
2555
+ transactions: true,
2556
+ cursors: true,
2557
+ cursorModes: Object.freeze(["object", "raw"]),
2558
+ responseStreamingAdapter: false,
2559
+ pooling: true,
2560
+ maxPoolConnections: POSTGRES_MAX_POOL_CONNECTIONS,
2561
+ executionMode: "TRUE_ASYNC",
2562
+ migrations: true,
2563
+ orm: false,
2564
+ };
2565
+
2566
+ Object.defineProperty(postgresSupports, "nativeStdlibBridge", {
2567
+ enumerable: true,
2568
+ get() {
2569
+ return postgresNativeBridge() !== null;
2570
+ },
2571
+ });
2572
+
2573
+ const sqlserverSupports = {
2574
+ connectionString: true,
2575
+ odbc: true,
2576
+ queryTemplates: true,
2577
+ parameters: Object.freeze([
2578
+ "null",
2579
+ "string",
2580
+ "integer",
2581
+ "float",
2582
+ "boolean",
2583
+ "bigint",
2584
+ "decimal",
2585
+ "bytes",
2586
+ "uuid",
2587
+ "date",
2588
+ "time",
2589
+ "timestamp",
2590
+ "offsetDateTime",
2591
+ "explicit-json-text",
2592
+ ]),
2593
+ transactions: true,
2594
+ cursors: true,
2595
+ cursorModes: Object.freeze(["object", "raw"]),
2596
+ responseStreamingAdapter: false,
2597
+ pooling: true,
2598
+ maxPoolConnections: SQLSERVER_MAX_POOL_CONNECTIONS,
2599
+ executionMode: "TRUE_ASYNC",
2600
+ migrations: true,
2601
+ orm: false,
2602
+ };
2603
+
2604
+ Object.defineProperty(sqlserverSupports, "nativeStdlibBridge", {
2605
+ enumerable: true,
2606
+ get() {
2607
+ return sqlserverNativeBridge() !== null;
2608
+ },
2609
+ });
2610
+
2611
+ function sqlite(name) {
2612
+ return openSqliteProvider(name);
2613
+ }
2614
+
2615
+ Object.defineProperties(sqlite, {
2616
+ provider: {
2617
+ enumerable: true,
2618
+ value: "sqlite",
2619
+ },
2620
+ placeholderStyle: {
2621
+ enumerable: true,
2622
+ value: "question",
2623
+ },
2624
+ supports: {
2625
+ enumerable: true,
2626
+ value: Object.freeze(sqliteSupports),
2627
+ },
2628
+ open: {
2629
+ enumerable: true,
2630
+ value: openSqlite,
2631
+ },
2632
+ __debug: {
2633
+ enumerable: true,
2634
+ value() {
2635
+ return Object.freeze({
2636
+ provider: "sqlite",
2637
+ placeholderStyle: "question",
2638
+ nativeStdlibBridge: sqliteNativeBridge() !== null,
2639
+ });
2640
+ },
2641
+ },
2642
+ });
2643
+
2644
+ Object.freeze(sqlite);
2645
+
2646
+ const postgres = Object.freeze({
2647
+ provider: "postgres",
2648
+ placeholderStyle: "postgres",
2649
+ supports: Object.freeze(postgresSupports),
2650
+ open: openPostgres,
2651
+ redactConnectionString,
2652
+ __debug() {
2653
+ return Object.freeze({
2654
+ provider: "postgres",
2655
+ placeholderStyle: "postgres",
2656
+ nativeStdlibBridge: postgresNativeBridge() !== null,
2657
+ maxPoolConnections: POSTGRES_MAX_POOL_CONNECTIONS,
2658
+ executionMode: "TRUE_ASYNC",
2659
+ });
2660
+ },
2661
+ });
2662
+
2663
+ const sqlserver = Object.freeze({
2664
+ provider: "sqlserver",
2665
+ placeholderStyle: "question",
2666
+ supports: Object.freeze(sqlserverSupports),
2667
+ open: openSqlServer,
2668
+ doctor: doctorSqlServer,
2669
+ redactConnectionString: redactOdbcConnectionString,
2670
+ __debug() {
2671
+ return Object.freeze({
2672
+ provider: "sqlserver",
2673
+ placeholderStyle: "question",
2674
+ nativeStdlibBridge: sqlserverNativeBridge() !== null,
2675
+ maxPoolConnections: SQLSERVER_MAX_POOL_CONNECTIONS,
2676
+ executionMode: "TRUE_ASYNC",
2677
+ });
2678
+ },
2679
+ });
2680
+
2681
+ function createTransactionState(provider) {
2682
+ return {
2683
+ provider,
2684
+ closed: false,
2685
+ };
2686
+ }
2687
+
2688
+ function assertTransactionOpen(state, operation) {
2689
+ if (state.closed) {
2690
+ throw new Error(`sloppy: transaction scope is closed
2691
+
2692
+ Operation:
2693
+ ${operation}
2694
+
2695
+ Fix:
2696
+ Do not use the transaction object after transaction(...) resolves or rejects.`);
2697
+ }
2698
+ }
2699
+
2700
+ function createTransactionProvider(state, placeholderStyle) {
2701
+ return Object.freeze({
2702
+ query(...args) {
2703
+ assertTransactionOpen(state, "query");
2704
+ const call = normalizeProviderCallArguments("query", placeholderStyle, args);
2705
+ const method = call.mode === "raw" ? state.provider.queryRaw : state.provider.query;
2706
+ return invokeProviderOperation("query", call.options, () =>
2707
+ method(call.query, call.options));
2708
+ },
2709
+
2710
+ queryRaw(...args) {
2711
+ assertTransactionOpen(state, "queryRaw");
2712
+ const call = normalizeProviderCallArguments("queryRaw", placeholderStyle, args);
2713
+ return invokeProviderOperation("queryRaw", call.options, () =>
2714
+ state.provider.queryRaw(call.query, call.options));
2715
+ },
2716
+
2717
+ queryOne(...args) {
2718
+ assertTransactionOpen(state, "queryOne");
2719
+ const call = normalizeProviderCallArguments("queryOne", placeholderStyle, args);
2720
+ return invokeProviderOperation("queryOne", call.options, () =>
2721
+ state.provider.queryOne(call.query, call.options));
2722
+ },
2723
+
2724
+ exec(...args) {
2725
+ assertTransactionOpen(state, "exec");
2726
+ const call = normalizeProviderCallArguments("exec", placeholderStyle, args);
2727
+ return invokeProviderOperation("exec", call.options, () =>
2728
+ state.provider.exec(call.query, call.options));
2729
+ },
2730
+
2731
+ transaction() {
2732
+ throw new Error(`sloppy: nested transactions are not supported yet
2733
+
2734
+ Operation:
2735
+ transaction
2736
+
2737
+ Fix:
2738
+ Use the transaction object passed to the current callback, or start a new transaction after it settles.`);
2739
+ },
2740
+ });
2741
+ }
2742
+
2743
+ function createFakeProvider(definition = {}) {
2744
+ validateProviderDefinition(definition);
2745
+
2746
+ const events = [];
2747
+ const placeholderStyle = definition.placeholderStyle ?? "question";
2748
+ let transactionActive = false;
2749
+ validatePlaceholderStyle(placeholderStyle);
2750
+
2751
+ const backend = {
2752
+ query(query, options) {
2753
+ if (definition.query === undefined) {
2754
+ missingProviderMethod("query");
2755
+ }
2756
+
2757
+ return definition.query(query, options);
2758
+ },
2759
+
2760
+ queryRaw(query, options) {
2761
+ if (definition.queryRaw === undefined) {
2762
+ missingProviderMethod("queryRaw");
2763
+ }
2764
+
2765
+ return definition.queryRaw(query, options);
2766
+ },
2767
+
2768
+ queryOne(query, options) {
2769
+ if (definition.queryOne !== undefined) {
2770
+ return definition.queryOne(query, options);
2771
+ }
2772
+
2773
+ if (definition.query === undefined) {
2774
+ missingProviderMethod("queryOne");
2775
+ }
2776
+
2777
+ return Promise.resolve(definition.query(query, options)).then((rows) => {
2778
+ if (rows == null) {
2779
+ return null;
2780
+ }
2781
+
2782
+ if (!Array.isArray(rows)) {
2783
+ throw new TypeError("Sloppy fake data provider queryOne fallback expected query() to return an array.");
2784
+ }
2785
+
2786
+ return rows[0] ?? null;
2787
+ });
2788
+ },
2789
+
2790
+ exec(query, options) {
2791
+ if (definition.exec === undefined) {
2792
+ missingProviderMethod("exec");
2793
+ }
2794
+
2795
+ return definition.exec(query, options);
2796
+ },
2797
+ };
2798
+
2799
+ const transactionHooks = isPlainObject(definition.transaction) ? definition.transaction : {};
2800
+
2801
+ async function runTransaction(callback) {
2802
+ if (typeof callback !== "function") {
2803
+ throw new TypeError("Sloppy data transaction callback must be a function.");
2804
+ }
2805
+
2806
+ if (transactionActive) {
2807
+ throw new Error(`sloppy: nested transactions are not supported yet
2808
+
2809
+ Operation:
2810
+ transaction
2811
+
2812
+ Fix:
2813
+ Use the transaction object passed to the current callback, or start a new transaction after it settles.`);
2814
+ }
2815
+
2816
+ transactionActive = true;
2817
+ events.push("begin");
2818
+
2819
+ const state = createTransactionState(backend);
2820
+
2821
+ try {
2822
+ if (typeof transactionHooks.begin === "function") {
2823
+ await transactionHooks.begin();
2824
+ } else if (typeof definition.transaction === "function") {
2825
+ await definition.transaction("begin");
2826
+ }
2827
+
2828
+ const tx = createTransactionProvider(state, placeholderStyle);
2829
+ const result = await callback(tx);
2830
+
2831
+ state.closed = true;
2832
+ events.push("commit");
2833
+
2834
+ if (typeof transactionHooks.commit === "function") {
2835
+ await transactionHooks.commit();
2836
+ } else if (typeof definition.transaction === "function") {
2837
+ await definition.transaction("commit");
2838
+ }
2839
+
2840
+ return result;
2841
+ } catch (error) {
2842
+ state.closed = true;
2843
+ events.push("rollback");
2844
+
2845
+ if (typeof transactionHooks.rollback === "function") {
2846
+ await transactionHooks.rollback(error);
2847
+ } else if (typeof definition.transaction === "function") {
2848
+ await definition.transaction("rollback", error);
2849
+ }
2850
+
2851
+ throw error;
2852
+ } finally {
2853
+ transactionActive = false;
2854
+ }
2855
+ }
2856
+
2857
+ const provider = {
2858
+ query(...args) {
2859
+ const call = normalizeProviderCallArguments("query", placeholderStyle, args);
2860
+ const method = call.mode === "raw" ? backend.queryRaw : backend.query;
2861
+ return invokeProviderOperation("query", call.options, () =>
2862
+ method(call.query, call.options));
2863
+ },
2864
+
2865
+ queryRaw(...args) {
2866
+ const call = normalizeProviderCallArguments("queryRaw", placeholderStyle, args);
2867
+ return invokeProviderOperation("queryRaw", call.options, () =>
2868
+ backend.queryRaw(call.query, call.options));
2869
+ },
2870
+
2871
+ queryOne(...args) {
2872
+ const call = normalizeProviderCallArguments("queryOne", placeholderStyle, args);
2873
+ return invokeProviderOperation("queryOne", call.options, () =>
2874
+ backend.queryOne(call.query, call.options));
2875
+ },
2876
+
2877
+ exec(...args) {
2878
+ const call = normalizeProviderCallArguments("exec", placeholderStyle, args);
2879
+ return invokeProviderOperation("exec", call.options, () =>
2880
+ backend.exec(call.query, call.options));
2881
+ },
2882
+
2883
+ transaction(callback) {
2884
+ return runTransaction(callback);
2885
+ },
2886
+
2887
+ __debug() {
2888
+ return Object.freeze({
2889
+ kind: "fake-data-provider",
2890
+ placeholderStyle,
2891
+ events: Object.freeze([...events]),
2892
+ });
2893
+ },
2894
+ };
2895
+
2896
+ return Object.freeze(provider);
2897
+ }
2898
+
2899
+ function sql(strings, ...values) {
2900
+ return createLoweredQuery(strings, values, { placeholderStyle: "question" });
2901
+ }
2902
+
2903
+ sql.lower = function lower(strings, values = [], options) {
2904
+ if (!Array.isArray(values)) {
2905
+ throw new TypeError("Sloppy sql.lower values must be an array.");
2906
+ }
2907
+
2908
+ return createLoweredQuery(strings, values, options);
2909
+ };
2910
+
2911
+ sql.decimal = decimal;
2912
+ sql.uuid = uuid;
2913
+ sql.date = date;
2914
+ sql.time = time;
2915
+ sql.timestamp = timestamp;
2916
+ sql.instant = instant;
2917
+ sql.offsetDateTime = offsetDateTime;
2918
+ sql.json = json;
2919
+ sql.rawJson = rawJson;
2920
+ sql.bytes = bytes;
2921
+
2922
+ Object.freeze(sql);
2923
+
2924
+ const Migrations = Object.freeze({
2925
+ apply: applyMigrations,
2926
+ status: migrationStatus,
2927
+ });
2928
+
2929
+ const ProviderHealth = Object.freeze({
2930
+ check: checkProviderHealth,
2931
+ });
2932
+
2933
+ export { Migrations, ProviderHealth, isRealDataProvider, sql };
2934
+
2935
+ export const data = Object.freeze({
2936
+ createFakeProvider,
2937
+ lowerQueryTemplate: createLoweredQuery,
2938
+ isQuery: isLoweredQuery,
2939
+ values,
2940
+ migrations: Migrations,
2941
+ providerHealth: ProviderHealth,
2942
+ sqlite,
2943
+ postgres,
2944
+ sqlserver,
2945
+ });