human2ai 0.1.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 (326) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/assets/quaternius/License_Standard.txt +22 -0
  4. package/assets/quaternius/README.md +31 -0
  5. package/assets/quaternius/Superhero_Female_FullBody.bin +0 -0
  6. package/assets/quaternius/Superhero_Female_FullBody.gltf +2056 -0
  7. package/assets/quaternius/Superhero_Male_FullBody.bin +0 -0
  8. package/assets/quaternius/Superhero_Male_FullBody.gltf +2018 -0
  9. package/dist/cli/integration.d.ts +39 -0
  10. package/dist/cli/integration.js +466 -0
  11. package/dist/cli/integration.js.map +1 -0
  12. package/dist/cli/main.d.ts +17 -0
  13. package/dist/cli/main.js +1455 -0
  14. package/dist/cli/main.js.map +1 -0
  15. package/dist/database/composition-session-repository.d.ts +37 -0
  16. package/dist/database/composition-session-repository.js +147 -0
  17. package/dist/database/composition-session-repository.js.map +1 -0
  18. package/dist/database/draft-version-errors.d.ts +29 -0
  19. package/dist/database/draft-version-errors.js +47 -0
  20. package/dist/database/draft-version-errors.js.map +1 -0
  21. package/dist/database/draft-version-store.d.ts +30 -0
  22. package/dist/database/draft-version-store.js +168 -0
  23. package/dist/database/draft-version-store.js.map +1 -0
  24. package/dist/database/image-asset-repository.d.ts +37 -0
  25. package/dist/database/image-asset-repository.js +101 -0
  26. package/dist/database/image-asset-repository.js.map +1 -0
  27. package/dist/database/image-input.d.ts +15 -0
  28. package/dist/database/image-input.js +28 -0
  29. package/dist/database/image-input.js.map +1 -0
  30. package/dist/database/migrate.d.ts +4 -0
  31. package/dist/database/migrate.js +45 -0
  32. package/dist/database/migrate.js.map +1 -0
  33. package/dist/database/project-session-repository.d.ts +72 -0
  34. package/dist/database/project-session-repository.js +291 -0
  35. package/dist/database/project-session-repository.js.map +1 -0
  36. package/dist/database/spatial-session-repository.d.ts +26 -0
  37. package/dist/database/spatial-session-repository.js +44 -0
  38. package/dist/database/spatial-session-repository.js.map +1 -0
  39. package/dist/database/style-library-repository.d.ts +70 -0
  40. package/dist/database/style-library-repository.js +290 -0
  41. package/dist/database/style-library-repository.js.map +1 -0
  42. package/dist/database/svg-input.d.ts +1 -0
  43. package/dist/database/svg-input.js +77 -0
  44. package/dist/database/svg-input.js.map +1 -0
  45. package/dist/database/ui-sketch-session-repository.d.ts +19 -0
  46. package/dist/database/ui-sketch-session-repository.js +35 -0
  47. package/dist/database/ui-sketch-session-repository.js.map +1 -0
  48. package/dist/domain/canvas-layer-order.d.ts +6 -0
  49. package/dist/domain/canvas-layer-order.js +40 -0
  50. package/dist/domain/canvas-layer-order.js.map +1 -0
  51. package/dist/domain/canvas-node-metadata.d.ts +20 -0
  52. package/dist/domain/canvas-node-metadata.js +17 -0
  53. package/dist/domain/canvas-node-metadata.js.map +1 -0
  54. package/dist/domain/canvas-states.d.ts +8 -0
  55. package/dist/domain/canvas-states.js +23 -0
  56. package/dist/domain/canvas-states.js.map +1 -0
  57. package/dist/domain/composition/analysis.d.ts +104 -0
  58. package/dist/domain/composition/analysis.js +337 -0
  59. package/dist/domain/composition/analysis.js.map +1 -0
  60. package/dist/domain/composition/camera-reference.d.ts +24 -0
  61. package/dist/domain/composition/camera-reference.js +34 -0
  62. package/dist/domain/composition/camera-reference.js.map +1 -0
  63. package/dist/domain/composition/draft.d.ts +50 -0
  64. package/dist/domain/composition/draft.js +609 -0
  65. package/dist/domain/composition/draft.js.map +1 -0
  66. package/dist/domain/composition/frame.d.ts +23 -0
  67. package/dist/domain/composition/frame.js +154 -0
  68. package/dist/domain/composition/frame.js.map +1 -0
  69. package/dist/domain/composition/geometry.d.ts +15 -0
  70. package/dist/domain/composition/geometry.js +262 -0
  71. package/dist/domain/composition/geometry.js.map +1 -0
  72. package/dist/domain/composition/index.d.ts +13 -0
  73. package/dist/domain/composition/index.js +10 -0
  74. package/dist/domain/composition/index.js.map +1 -0
  75. package/dist/domain/composition/layers.d.ts +4 -0
  76. package/dist/domain/composition/layers.js +12 -0
  77. package/dist/domain/composition/layers.js.map +1 -0
  78. package/dist/domain/composition/records.d.ts +14 -0
  79. package/dist/domain/composition/records.js +2 -0
  80. package/dist/domain/composition/records.js.map +1 -0
  81. package/dist/domain/composition/refinement/engine.d.ts +12 -0
  82. package/dist/domain/composition/refinement/engine.js +521 -0
  83. package/dist/domain/composition/refinement/engine.js.map +1 -0
  84. package/dist/domain/composition/refinement/relations.d.ts +16 -0
  85. package/dist/domain/composition/refinement/relations.js +293 -0
  86. package/dist/domain/composition/refinement/relations.js.map +1 -0
  87. package/dist/domain/composition/refinement/types.d.ts +181 -0
  88. package/dist/domain/composition/refinement/types.js +2 -0
  89. package/dist/domain/composition/refinement/types.js.map +1 -0
  90. package/dist/domain/composition/render.d.ts +5 -0
  91. package/dist/domain/composition/render.js +169 -0
  92. package/dist/domain/composition/render.js.map +1 -0
  93. package/dist/domain/composition/states.d.ts +9 -0
  94. package/dist/domain/composition/states.js +104 -0
  95. package/dist/domain/composition/states.js.map +1 -0
  96. package/dist/domain/composition/types.d.ts +149 -0
  97. package/dist/domain/composition/types.js +2 -0
  98. package/dist/domain/composition/types.js.map +1 -0
  99. package/dist/domain/composition/workflow.d.ts +15 -0
  100. package/dist/domain/composition/workflow.js +77 -0
  101. package/dist/domain/composition/workflow.js.map +1 -0
  102. package/dist/domain/fingerprint.d.ts +2 -0
  103. package/dist/domain/fingerprint.js +25 -0
  104. package/dist/domain/fingerprint.js.map +1 -0
  105. package/dist/domain/session/canvas-edit-history.d.ts +17 -0
  106. package/dist/domain/session/canvas-edit-history.js +53 -0
  107. package/dist/domain/session/canvas-edit-history.js.map +1 -0
  108. package/dist/domain/session/capabilities.d.ts +16 -0
  109. package/dist/domain/session/capabilities.js +84 -0
  110. package/dist/domain/session/capabilities.js.map +1 -0
  111. package/dist/domain/session/draft-version.d.ts +41 -0
  112. package/dist/domain/session/draft-version.js +2 -0
  113. package/dist/domain/session/draft-version.js.map +1 -0
  114. package/dist/domain/session/index.d.ts +5 -0
  115. package/dist/domain/session/index.js +3 -0
  116. package/dist/domain/session/index.js.map +1 -0
  117. package/dist/domain/session/types.d.ts +23 -0
  118. package/dist/domain/session/types.js +2 -0
  119. package/dist/domain/session/types.js.map +1 -0
  120. package/dist/domain/spatial/assets/quaternius-female-rig.json +799 -0
  121. package/dist/domain/spatial/assets/quaternius-rig.json +799 -0
  122. package/dist/domain/spatial/assets/quaternius-superhero-female.json +1 -0
  123. package/dist/domain/spatial/assets/quaternius-superhero.json +1 -0
  124. package/dist/domain/spatial/camera-box.d.ts +13 -0
  125. package/dist/domain/spatial/camera-box.js +52 -0
  126. package/dist/domain/spatial/camera-box.js.map +1 -0
  127. package/dist/domain/spatial/geometric-model.d.ts +4 -0
  128. package/dist/domain/spatial/geometric-model.js +101 -0
  129. package/dist/domain/spatial/geometric-model.js.map +1 -0
  130. package/dist/domain/spatial/hands.d.ts +36 -0
  131. package/dist/domain/spatial/hands.js +128 -0
  132. package/dist/domain/spatial/hands.js.map +1 -0
  133. package/dist/domain/spatial/index.d.ts +30 -0
  134. package/dist/domain/spatial/index.js +381 -0
  135. package/dist/domain/spatial/index.js.map +1 -0
  136. package/dist/domain/spatial/kinematics.d.ts +27 -0
  137. package/dist/domain/spatial/kinematics.js +285 -0
  138. package/dist/domain/spatial/kinematics.js.map +1 -0
  139. package/dist/domain/spatial/lighting.d.ts +35 -0
  140. package/dist/domain/spatial/lighting.js +173 -0
  141. package/dist/domain/spatial/lighting.js.map +1 -0
  142. package/dist/domain/spatial/model.d.ts +5 -0
  143. package/dist/domain/spatial/model.js +193 -0
  144. package/dist/domain/spatial/model.js.map +1 -0
  145. package/dist/domain/spatial/morph.d.ts +3 -0
  146. package/dist/domain/spatial/morph.js +187 -0
  147. package/dist/domain/spatial/morph.js.map +1 -0
  148. package/dist/domain/spatial/proportions.d.ts +46 -0
  149. package/dist/domain/spatial/proportions.js +59 -0
  150. package/dist/domain/spatial/proportions.js.map +1 -0
  151. package/dist/domain/spatial/reference-lines.d.ts +6 -0
  152. package/dist/domain/spatial/reference-lines.js +58 -0
  153. package/dist/domain/spatial/reference-lines.js.map +1 -0
  154. package/dist/domain/spatial/scene-cache.d.ts +15 -0
  155. package/dist/domain/spatial/scene-cache.js +69 -0
  156. package/dist/domain/spatial/scene-cache.js.map +1 -0
  157. package/dist/domain/spatial/scene.d.ts +8 -0
  158. package/dist/domain/spatial/scene.js +69 -0
  159. package/dist/domain/spatial/scene.js.map +1 -0
  160. package/dist/domain/spatial/types.d.ts +187 -0
  161. package/dist/domain/spatial/types.js +5 -0
  162. package/dist/domain/spatial/types.js.map +1 -0
  163. package/dist/domain/style/index.d.ts +1 -0
  164. package/dist/domain/style/index.js +2 -0
  165. package/dist/domain/style/index.js.map +1 -0
  166. package/dist/domain/style/prompt-summary.d.ts +2 -0
  167. package/dist/domain/style/prompt-summary.js +11 -0
  168. package/dist/domain/style/prompt-summary.js.map +1 -0
  169. package/dist/domain/style/types.d.ts +32 -0
  170. package/dist/domain/style/types.js +3 -0
  171. package/dist/domain/style/types.js.map +1 -0
  172. package/dist/domain/ui-sketch/draft.d.ts +12 -0
  173. package/dist/domain/ui-sketch/draft.js +424 -0
  174. package/dist/domain/ui-sketch/draft.js.map +1 -0
  175. package/dist/domain/ui-sketch/geometry.d.ts +7 -0
  176. package/dist/domain/ui-sketch/geometry.js +11 -0
  177. package/dist/domain/ui-sketch/geometry.js.map +1 -0
  178. package/dist/domain/ui-sketch/groups.d.ts +5 -0
  179. package/dist/domain/ui-sketch/groups.js +40 -0
  180. package/dist/domain/ui-sketch/groups.js.map +1 -0
  181. package/dist/domain/ui-sketch/index.d.ts +8 -0
  182. package/dist/domain/ui-sketch/index.js +8 -0
  183. package/dist/domain/ui-sketch/index.js.map +1 -0
  184. package/dist/domain/ui-sketch/layers.d.ts +4 -0
  185. package/dist/domain/ui-sketch/layers.js +11 -0
  186. package/dist/domain/ui-sketch/layers.js.map +1 -0
  187. package/dist/domain/ui-sketch/render.d.ts +2 -0
  188. package/dist/domain/ui-sketch/render.js +58 -0
  189. package/dist/domain/ui-sketch/render.js.map +1 -0
  190. package/dist/domain/ui-sketch/standardize.d.ts +17 -0
  191. package/dist/domain/ui-sketch/standardize.js +139 -0
  192. package/dist/domain/ui-sketch/standardize.js.map +1 -0
  193. package/dist/domain/ui-sketch/states.d.ts +5 -0
  194. package/dist/domain/ui-sketch/states.js +21 -0
  195. package/dist/domain/ui-sketch/states.js.map +1 -0
  196. package/dist/domain/ui-sketch/types.d.ts +73 -0
  197. package/dist/domain/ui-sketch/types.js +2 -0
  198. package/dist/domain/ui-sketch/types.js.map +1 -0
  199. package/dist/server/app.d.ts +18 -0
  200. package/dist/server/app.js +108 -0
  201. package/dist/server/app.js.map +1 -0
  202. package/dist/server/image-content-type-parser.d.ts +2 -0
  203. package/dist/server/image-content-type-parser.js +5 -0
  204. package/dist/server/image-content-type-parser.js.map +1 -0
  205. package/dist/server/routes/composition-sessions.d.ts +3 -0
  206. package/dist/server/routes/composition-sessions.js +190 -0
  207. package/dist/server/routes/composition-sessions.js.map +1 -0
  208. package/dist/server/routes/draft-version-routes.d.ts +10 -0
  209. package/dist/server/routes/draft-version-routes.js +201 -0
  210. package/dist/server/routes/draft-version-routes.js.map +1 -0
  211. package/dist/server/routes/image-assets.d.ts +3 -0
  212. package/dist/server/routes/image-assets.js +114 -0
  213. package/dist/server/routes/image-assets.js.map +1 -0
  214. package/dist/server/routes/project-sessions.d.ts +48 -0
  215. package/dist/server/routes/project-sessions.js +305 -0
  216. package/dist/server/routes/project-sessions.js.map +1 -0
  217. package/dist/server/routes/spatial-sessions.d.ts +3 -0
  218. package/dist/server/routes/spatial-sessions.js +80 -0
  219. package/dist/server/routes/spatial-sessions.js.map +1 -0
  220. package/dist/server/routes/style-library.d.ts +3 -0
  221. package/dist/server/routes/style-library.js +308 -0
  222. package/dist/server/routes/style-library.js.map +1 -0
  223. package/dist/server/routes/ui-sketch-sessions.d.ts +3 -0
  224. package/dist/server/routes/ui-sketch-sessions.js +14 -0
  225. package/dist/server/routes/ui-sketch-sessions.js.map +1 -0
  226. package/dist/server/runtime.d.ts +30 -0
  227. package/dist/server/runtime.js +123 -0
  228. package/dist/server/runtime.js.map +1 -0
  229. package/dist/server/spatial-render.d.ts +5 -0
  230. package/dist/server/spatial-render.js +360 -0
  231. package/dist/server/spatial-render.js.map +1 -0
  232. package/dist/server/start.d.ts +1 -0
  233. package/dist/server/start.js +3 -0
  234. package/dist/server/start.js.map +1 -0
  235. package/licenses/THIRD-PARTY-NOTICES.txt +16664 -0
  236. package/licenses/YisiUI-LICENSE +21 -0
  237. package/locales/en/common.json +671 -0
  238. package/migrations/0001_projects_and_sessions.sql +45 -0
  239. package/migrations/0002_composition_versions_and_refinements.sql +26 -0
  240. package/migrations/0003_ui_sketch_draft_versions.sql +12 -0
  241. package/migrations/0004_image_assets.sql +16 -0
  242. package/migrations/0005_style_library.sql +31 -0
  243. package/migrations/0006_session_styles.sql +6 -0
  244. package/migrations/0007_svg_image_assets.sql +19 -0
  245. package/migrations/0008_spatial_spaces.sql +20 -0
  246. package/package.json +82 -0
  247. package/schemas/composition-draft.schema.json +234 -0
  248. package/schemas/composition-refinement-plan.schema.json +758 -0
  249. package/schemas/spatial-draft.schema.json +517 -0
  250. package/schemas/spatial-operations.schema.json +1082 -0
  251. package/schemas/ui-layout-standardization-plan.schema.json +29 -0
  252. package/schemas/ui-sketch-draft.schema.json +197 -0
  253. package/skills/human2ai/SKILL.md +149 -0
  254. package/skills/human2ai/agents/openai.yaml +3 -0
  255. package/skills/human2ai/references/composition-projection.md +170 -0
  256. package/skills/human2ai/references/composition.md +79 -0
  257. package/skills/human2ai/references/spatial.md +188 -0
  258. package/skills/human2ai/references/svg-images.md +27 -0
  259. package/skills/human2ai/references/ui-layout.md +100 -0
  260. package/web/out/404/index.html +1 -0
  261. package/web/out/404.html +1 -0
  262. package/web/out/__next.__PAGE__.txt +26 -0
  263. package/web/out/__next._full.txt +21 -0
  264. package/web/out/__next._tree.txt +4 -0
  265. package/web/out/_next/static/TV-jgcACg6HANZAMZTE2S/_buildManifest.js +1 -0
  266. package/web/out/_next/static/TV-jgcACg6HANZAMZTE2S/_ssgManifest.js +1 -0
  267. package/web/out/_next/static/chunks/130-9fadd0432daff55d.js +1 -0
  268. package/web/out/_next/static/chunks/158-eb00456e1bab68b3.js +52 -0
  269. package/web/out/_next/static/chunks/20-0801fc297cda2a7a.js +1 -0
  270. package/web/out/_next/static/chunks/248-d4a79649dae2a3f8.js +259 -0
  271. package/web/out/_next/static/chunks/678-1305cadf8254d814.js +1 -0
  272. package/web/out/_next/static/chunks/728-eb8b667f79229443.js +1 -0
  273. package/web/out/_next/static/chunks/83607670-bc1279370476e59f.js +1 -0
  274. package/web/out/_next/static/chunks/app/_global-error/page-5eece43b8152c414.js +1 -0
  275. package/web/out/_next/static/chunks/app/_not-found/page-c0cd75ac39fbf9cf.js +1 -0
  276. package/web/out/_next/static/chunks/app/composition/page-051ee2fabb12110a.js +1 -0
  277. package/web/out/_next/static/chunks/app/layout-745ca27ef8830f4f.js +1 -0
  278. package/web/out/_next/static/chunks/app/page-0027378a269a6168.js +1 -0
  279. package/web/out/_next/static/chunks/app/spatial/page-266dedc81784d4f6.js +1 -0
  280. package/web/out/_next/static/chunks/app/styles/page-d5cb83af828ea9ed.js +1 -0
  281. package/web/out/_next/static/chunks/app/ui-sketch/page-2a8436e05a05c618.js +1 -0
  282. package/web/out/_next/static/chunks/c3f2cda1-9e279dab137b7272.js +342 -0
  283. package/web/out/_next/static/chunks/c7879cf7-7873c8afd9c9c666.js +1 -0
  284. package/web/out/_next/static/chunks/framework-6eacf80ec1e4c887.js +1 -0
  285. package/web/out/_next/static/chunks/main-5ee8fd93319f955c.js +5 -0
  286. package/web/out/_next/static/chunks/main-app-0cf10803ab17c700.js +1 -0
  287. package/web/out/_next/static/chunks/next/dist/client/components/builtin/app-error-5eece43b8152c414.js +1 -0
  288. package/web/out/_next/static/chunks/next/dist/client/components/builtin/forbidden-5eece43b8152c414.js +1 -0
  289. package/web/out/_next/static/chunks/next/dist/client/components/builtin/global-error-728204b7cccc4ed2.js +1 -0
  290. package/web/out/_next/static/chunks/next/dist/client/components/builtin/not-found-5eece43b8152c414.js +1 -0
  291. package/web/out/_next/static/chunks/next/dist/client/components/builtin/unauthorized-5eece43b8152c414.js +1 -0
  292. package/web/out/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  293. package/web/out/_next/static/chunks/webpack-97ae63c0e0b2a512.js +1 -0
  294. package/web/out/_next/static/css/3b7982b41ed8eccd.css +4 -0
  295. package/web/out/_next/static/css/81ae71f1d3e9a866.css +1 -0
  296. package/web/out/_next/static/css/8c3843f4951fa9f6.css +5 -0
  297. package/web/out/_next/static/css/c739d0131cdcc891.css +1 -0
  298. package/web/out/_next/static/css/ce1b4bb3ad3c6073.css +1 -0
  299. package/web/out/_next/static/css/db96ae2e88545d96.css +1 -0
  300. package/web/out/_not-found/__next._full.txt +18 -0
  301. package/web/out/_not-found/__next._not-found.__PAGE__.txt +24 -0
  302. package/web/out/_not-found/__next._tree.txt +3 -0
  303. package/web/out/_not-found/index.html +1 -0
  304. package/web/out/_not-found/index.txt +18 -0
  305. package/web/out/composition/__next._full.txt +25 -0
  306. package/web/out/composition/__next._tree.txt +6 -0
  307. package/web/out/composition/__next.composition.__PAGE__.txt +31 -0
  308. package/web/out/composition/index.html +1 -0
  309. package/web/out/composition/index.txt +25 -0
  310. package/web/out/index.html +1 -0
  311. package/web/out/index.txt +21 -0
  312. package/web/out/spatial/__next._full.txt +23 -0
  313. package/web/out/spatial/__next._tree.txt +4 -0
  314. package/web/out/spatial/__next.spatial.__PAGE__.txt +29 -0
  315. package/web/out/spatial/index.html +1 -0
  316. package/web/out/spatial/index.txt +23 -0
  317. package/web/out/styles/__next._full.txt +23 -0
  318. package/web/out/styles/__next._tree.txt +4 -0
  319. package/web/out/styles/__next.styles.__PAGE__.txt +29 -0
  320. package/web/out/styles/index.html +1 -0
  321. package/web/out/styles/index.txt +23 -0
  322. package/web/out/ui-sketch/__next._full.txt +25 -0
  323. package/web/out/ui-sketch/__next._tree.txt +6 -0
  324. package/web/out/ui-sketch/__next.ui-sketch.__PAGE__.txt +31 -0
  325. package/web/out/ui-sketch/index.html +1 -0
  326. package/web/out/ui-sketch/index.txt +25 -0
@@ -0,0 +1,37 @@
1
+ import type { DatabaseConnection } from "./migrate.ts";
2
+ export { MAX_IMAGE_ASSET_BYTES } from "./image-input.ts";
3
+ export interface ImageAsset {
4
+ id: string;
5
+ sessionId: string;
6
+ originalFilename: string;
7
+ mimeType: "image/png" | "image/jpeg" | "image/webp" | "image/svg+xml";
8
+ byteSize: number;
9
+ width: number;
10
+ height: number;
11
+ sha256: string;
12
+ createdAt: string;
13
+ }
14
+ export declare class InvalidImageAssetError extends Error {
15
+ readonly code = "INVALID_IMAGE_ASSET";
16
+ }
17
+ export declare class ImageAssetNotFoundError extends Error {
18
+ readonly sessionId: string;
19
+ readonly assetId: string;
20
+ readonly code = "IMAGE_ASSET_NOT_FOUND";
21
+ constructor(sessionId: string, assetId: string);
22
+ }
23
+ export declare class ImageAssetRepository {
24
+ private readonly database;
25
+ private readonly root;
26
+ constructor(database: DatabaseConnection, artifactsDirectory: string);
27
+ create(sessionId: string, input: {
28
+ filename: string;
29
+ data: Buffer;
30
+ }): Promise<ImageAsset>;
31
+ get(sessionId: string, assetId: string): {
32
+ asset: ImageAsset;
33
+ filePath: string;
34
+ };
35
+ private assertSession;
36
+ private filePath;
37
+ }
@@ -0,0 +1,101 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { basename, dirname, join, resolve, sep } from "node:path";
3
+ import { mkdir, unlink, writeFile } from "node:fs/promises";
4
+ import { existsSync } from "node:fs";
5
+ import { inspectImageInput, MAX_IMAGE_ASSET_BYTES } from "./image-input.js";
6
+ import { SessionNotFoundError } from "./project-session-repository.js";
7
+ export { MAX_IMAGE_ASSET_BYTES } from "./image-input.js";
8
+ export class InvalidImageAssetError extends Error {
9
+ code = "INVALID_IMAGE_ASSET";
10
+ }
11
+ export class ImageAssetNotFoundError extends Error {
12
+ sessionId;
13
+ assetId;
14
+ code = "IMAGE_ASSET_NOT_FOUND";
15
+ constructor(sessionId, assetId) {
16
+ super(`Image asset ${assetId} was not found in session ${sessionId}`);
17
+ this.sessionId = sessionId;
18
+ this.assetId = assetId;
19
+ }
20
+ }
21
+ export class ImageAssetRepository {
22
+ database;
23
+ root;
24
+ constructor(database, artifactsDirectory) {
25
+ this.database = database;
26
+ this.root = resolve(artifactsDirectory);
27
+ }
28
+ async create(sessionId, input) {
29
+ this.assertSession(sessionId);
30
+ const inspected = await inspectImageInput(input.data, { allowSvg: true });
31
+ if ("error" in inspected) {
32
+ throw new InvalidImageAssetError(inspected.error === "size"
33
+ ? `Image files must be between 1 byte and ${MAX_IMAGE_ASSET_BYTES} bytes.`
34
+ : "Only valid PNG, JPEG, WebP, and self-contained SVG images are supported.");
35
+ }
36
+ const { format, mimeType, width, height } = inspected.image;
37
+ const id = randomUUID();
38
+ const extension = format === "jpeg" ? "jpg" : format;
39
+ const relativePath = join(sessionId, "source", `${id}.${extension}`);
40
+ const filePath = this.filePath(relativePath);
41
+ const originalFilename = safeFilename(input.filename);
42
+ const sha256 = createHash("sha256").update(input.data).digest("hex");
43
+ const createdAt = new Date().toISOString();
44
+ await mkdir(dirname(filePath), { recursive: true, mode: 0o700 });
45
+ await writeFile(filePath, input.data, { flag: "wx", mode: 0o600 });
46
+ try {
47
+ this.database.prepare(`INSERT INTO image_assets
48
+ (id, session_id, relative_path, original_filename, mime_type,
49
+ byte_size, width, height, sha256, created_at)
50
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, sessionId, relativePath, originalFilename, mimeType, input.data.byteLength, width, height, sha256, createdAt);
51
+ }
52
+ catch (error) {
53
+ await unlink(filePath).catch(() => undefined);
54
+ throw error;
55
+ }
56
+ return this.get(sessionId, id).asset;
57
+ }
58
+ get(sessionId, assetId) {
59
+ this.assertSession(sessionId);
60
+ const row = this.database.prepare(`SELECT id, session_id, relative_path, original_filename, mime_type,
61
+ byte_size, width, height, sha256, created_at
62
+ FROM image_assets
63
+ WHERE session_id = ? AND id = ?`).get(sessionId, assetId);
64
+ if (!row)
65
+ throw new ImageAssetNotFoundError(sessionId, assetId);
66
+ const filePath = this.filePath(row.relative_path);
67
+ if (!existsSync(filePath))
68
+ throw new ImageAssetNotFoundError(sessionId, assetId);
69
+ return { asset: mapImageAsset(row), filePath };
70
+ }
71
+ assertSession(sessionId) {
72
+ const row = this.database.prepare("SELECT id FROM sessions WHERE id = ?").get(sessionId);
73
+ if (!row)
74
+ throw new SessionNotFoundError(sessionId);
75
+ }
76
+ filePath(relativePath) {
77
+ const filePath = resolve(this.root, relativePath);
78
+ if (filePath !== this.root && !filePath.startsWith(`${this.root}${sep}`)) {
79
+ throw new InvalidImageAssetError("Image asset path must stay inside the artifacts directory.");
80
+ }
81
+ return filePath;
82
+ }
83
+ }
84
+ function safeFilename(filename) {
85
+ const value = basename(filename.trim()).slice(0, 255);
86
+ return value || "image";
87
+ }
88
+ function mapImageAsset(row) {
89
+ return {
90
+ id: row.id,
91
+ sessionId: row.session_id,
92
+ originalFilename: row.original_filename,
93
+ mimeType: row.mime_type,
94
+ byteSize: row.byte_size,
95
+ width: row.width,
96
+ height: row.height,
97
+ sha256: row.sha256,
98
+ createdAt: row.created_at,
99
+ };
100
+ }
101
+ //# sourceMappingURL=image-asset-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-asset-repository.js","sourceRoot":"","sources":["../../src/database/image-asset-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export declare const MAX_IMAGE_ASSET_BYTES: number;
2
+ interface ImageInputMetadata {
3
+ format: "png" | "jpeg" | "webp" | "svg";
4
+ mimeType: "image/png" | "image/jpeg" | "image/webp" | "image/svg+xml";
5
+ width: number;
6
+ height: number;
7
+ }
8
+ export declare function inspectImageInput(data: Buffer, options?: {
9
+ allowSvg?: boolean;
10
+ }): Promise<{
11
+ image: ImageInputMetadata;
12
+ } | {
13
+ error: "size" | "format";
14
+ }>;
15
+ export {};
@@ -0,0 +1,28 @@
1
+ import sharp from "sharp";
2
+ import { isSelfContainedSvg } from "./svg-input.js";
3
+ export const MAX_IMAGE_ASSET_BYTES = 10 * 1024 * 1024;
4
+ export async function inspectImageInput(data, options = {}) {
5
+ if (data.byteLength === 0 || data.byteLength > MAX_IMAGE_ASSET_BYTES) {
6
+ return { error: "size" };
7
+ }
8
+ const xml = data.toString("utf8").trimStart().startsWith("<");
9
+ const svg = xml && options.allowSvg && isSelfContainedSvg(data);
10
+ if (xml && !svg)
11
+ return { error: "format" };
12
+ const metadata = await sharp(data, { animated: false }).metadata().catch(() => null);
13
+ const format = metadata?.format;
14
+ const width = metadata?.width;
15
+ const height = metadata?.height;
16
+ if ((format !== "png" && format !== "jpeg" && format !== "webp" && !(format === "svg" && svg)) || !width || !height) {
17
+ return { error: "format" };
18
+ }
19
+ return {
20
+ image: {
21
+ format,
22
+ mimeType: format === "svg" ? "image/svg+xml" : `image/${format}`,
23
+ width,
24
+ height,
25
+ },
26
+ };
27
+ }
28
+ //# sourceMappingURL=image-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-input.js","sourceRoot":"","sources":["../../src/database/image-input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAStD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY,EAAE,UAAkC,EAAE;IAGxF,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,GAAG,qBAAqB,EAAE,CAAC;QACrE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,GAAG,IAAI,OAAO,CAAC,QAAQ,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAChE,IAAI,GAAG,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,QAAQ,EAAE,MAAM,CAAC;IAChC,MAAM,KAAK,GAAG,QAAQ,EAAE,KAAK,CAAC;IAC9B,MAAM,MAAM,GAAG,QAAQ,EAAE,MAAM,CAAC;IAChC,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACpH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO;QACL,KAAK,EAAE;YACL,MAAM;YACN,QAAQ,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,MAAM,EAAE;YAChE,KAAK;YACL,MAAM;SACP;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import Database from "better-sqlite3";
2
+ export type DatabaseConnection = InstanceType<typeof Database>;
3
+ export declare function openDatabase(databasePath: string, migrationsDirectory: string): DatabaseConnection;
4
+ export declare function applyMigrations(database: DatabaseConnection, migrationsDirectory: string): string[];
@@ -0,0 +1,45 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import Database from "better-sqlite3";
4
+ const migrationFilePattern = /^\d{4}_[a-z0-9][a-z0-9_-]*\.sql$/;
5
+ export function openDatabase(databasePath, migrationsDirectory) {
6
+ const database = new Database(databasePath);
7
+ try {
8
+ database.pragma("foreign_keys = ON");
9
+ database.pragma("synchronous = FULL");
10
+ database.pragma("busy_timeout = 5000");
11
+ applyMigrations(database, migrationsDirectory);
12
+ return database;
13
+ }
14
+ catch (error) {
15
+ database.close();
16
+ throw error;
17
+ }
18
+ }
19
+ export function applyMigrations(database, migrationsDirectory) {
20
+ database.exec(`
21
+ CREATE TABLE IF NOT EXISTS schema_migrations (
22
+ name TEXT PRIMARY KEY,
23
+ applied_at TEXT NOT NULL
24
+ ) STRICT
25
+ `);
26
+ const applied = new Set(database
27
+ .prepare("SELECT name FROM schema_migrations")
28
+ .all()
29
+ .map(({ name }) => name));
30
+ const pending = readdirSync(migrationsDirectory, { withFileTypes: true })
31
+ .filter((entry) => entry.isFile() && migrationFilePattern.test(entry.name))
32
+ .map((entry) => entry.name)
33
+ .sort()
34
+ .filter((name) => !applied.has(name));
35
+ const insertMigration = database.prepare("INSERT INTO schema_migrations (name, applied_at) VALUES (?, ?)");
36
+ for (const name of pending) {
37
+ const sql = readFileSync(join(migrationsDirectory, name), "utf8");
38
+ database.transaction(() => {
39
+ database.exec(sql);
40
+ insertMigration.run(name, new Date().toISOString());
41
+ })();
42
+ }
43
+ return pending;
44
+ }
45
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/database/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,MAAM,oBAAoB,GAAG,kCAAkC,CAAC;AAEhE,MAAM,UAAU,YAAY,CAC1B,YAAoB,EACpB,mBAA2B;IAE3B,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC;IAE5C,IAAI,CAAC;QACH,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACrC,QAAQ,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACtC,QAAQ,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACvC,eAAe,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;QAC/C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,QAA4B,EAC5B,mBAA2B;IAE3B,QAAQ,CAAC,IAAI,CAAC;;;;;GAKb,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,QAAQ;SACL,OAAO,CAAuB,oCAAoC,CAAC;SACnE,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAC3B,CAAC;IACF,MAAM,OAAO,GAAG,WAAW,CAAC,mBAAmB,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACtE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SAC1E,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SAC1B,IAAI,EAAE;SACN,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CACtC,gEAAgE,CACjE,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QAClE,QAAQ,CAAC,WAAW,CAAC,GAAG,EAAE;YACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,72 @@
1
+ import { type Project, type Session, type SessionType } from "../domain/session/index.ts";
2
+ import type { DatabaseConnection } from "./migrate.ts";
3
+ export declare class ProjectNotFoundError extends Error {
4
+ readonly projectId: string;
5
+ readonly code = "PROJECT_NOT_FOUND";
6
+ constructor(projectId: string);
7
+ }
8
+ export declare class ProjectNameConflictError extends Error {
9
+ readonly name: string;
10
+ readonly code = "PROJECT_NAME_CONFLICT";
11
+ constructor(name: string);
12
+ }
13
+ export declare class ProjectNotEmptyError extends Error {
14
+ readonly projectId: string;
15
+ readonly sessionCount: number;
16
+ readonly code = "PROJECT_NOT_EMPTY";
17
+ constructor(projectId: string, sessionCount: number);
18
+ }
19
+ export declare class SessionNotFoundError extends Error {
20
+ readonly sessionId: string;
21
+ readonly code = "SESSION_NOT_FOUND";
22
+ constructor(sessionId: string);
23
+ }
24
+ export declare class RevisionConflictError extends Error {
25
+ readonly expectedRevision: number;
26
+ readonly actualRevision: number;
27
+ readonly code = "REVISION_CONFLICT";
28
+ constructor(expectedRevision: number, actualRevision: number);
29
+ }
30
+ export declare class InvalidRecordError extends Error {
31
+ readonly code = "INVALID_RECORD";
32
+ }
33
+ export declare class ProjectSessionRepository {
34
+ private readonly database;
35
+ constructor(database: DatabaseConnection);
36
+ listProjects(): Project[];
37
+ getProject(projectId: string): Project;
38
+ createProject(input: {
39
+ name: string;
40
+ description?: string | null;
41
+ }): Project;
42
+ updateProject(projectId: string, input: {
43
+ expectedRevision: number;
44
+ name?: string;
45
+ description?: string | null;
46
+ }): Project;
47
+ deleteProject(projectId: string, input: {
48
+ expectedRevision: number;
49
+ }): void;
50
+ listSessions(): Session[];
51
+ listUnassignedSessions(): Session[];
52
+ listProjectSessions(projectId: string): Session[];
53
+ getSession(sessionId: string): Session;
54
+ createSession(input: {
55
+ sessionType: SessionType;
56
+ title: string;
57
+ projectId?: string | null;
58
+ }): Session;
59
+ moveSession(sessionId: string, input: {
60
+ projectId: string | null;
61
+ expectedRevision: number;
62
+ }): Session;
63
+ renameSession(sessionId: string, input: {
64
+ title: string;
65
+ expectedRevision: number;
66
+ }): Session;
67
+ deleteSession(sessionId: string, input: {
68
+ expectedRevision: number;
69
+ }): void;
70
+ private selectSessions;
71
+ private assertProjectNameAvailable;
72
+ }
@@ -0,0 +1,291 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { SESSION_TYPES, } from "../domain/session/index.js";
3
+ export class ProjectNotFoundError extends Error {
4
+ projectId;
5
+ code = "PROJECT_NOT_FOUND";
6
+ constructor(projectId) {
7
+ super(`Project not found: ${projectId}`);
8
+ this.projectId = projectId;
9
+ }
10
+ }
11
+ export class ProjectNameConflictError extends Error {
12
+ name;
13
+ code = "PROJECT_NAME_CONFLICT";
14
+ constructor(name) {
15
+ super(`Project name already exists: ${name}`);
16
+ this.name = name;
17
+ }
18
+ }
19
+ export class ProjectNotEmptyError extends Error {
20
+ projectId;
21
+ sessionCount;
22
+ code = "PROJECT_NOT_EMPTY";
23
+ constructor(projectId, sessionCount) {
24
+ super(`Project contains ${sessionCount} session(s): ${projectId}`);
25
+ this.projectId = projectId;
26
+ this.sessionCount = sessionCount;
27
+ }
28
+ }
29
+ export class SessionNotFoundError extends Error {
30
+ sessionId;
31
+ code = "SESSION_NOT_FOUND";
32
+ constructor(sessionId) {
33
+ super(`Session not found: ${sessionId}`);
34
+ this.sessionId = sessionId;
35
+ }
36
+ }
37
+ export class RevisionConflictError extends Error {
38
+ expectedRevision;
39
+ actualRevision;
40
+ code = "REVISION_CONFLICT";
41
+ constructor(expectedRevision, actualRevision) {
42
+ super(`Expected revision ${expectedRevision}, received ${actualRevision}`);
43
+ this.expectedRevision = expectedRevision;
44
+ this.actualRevision = actualRevision;
45
+ }
46
+ }
47
+ export class InvalidRecordError extends Error {
48
+ code = "INVALID_RECORD";
49
+ }
50
+ export class ProjectSessionRepository {
51
+ database;
52
+ constructor(database) {
53
+ this.database = database;
54
+ }
55
+ listProjects() {
56
+ const rows = this.database
57
+ .prepare(`
58
+ SELECT
59
+ p.id,
60
+ p.name,
61
+ p.description,
62
+ p.revision,
63
+ p.created_at,
64
+ p.updated_at,
65
+ count(s.id) AS session_count
66
+ FROM projects p
67
+ LEFT JOIN sessions s ON s.project_id = p.id
68
+ GROUP BY p.id
69
+ ORDER BY p.updated_at DESC, p.id
70
+ `)
71
+ .all();
72
+ return rows.map(mapProject);
73
+ }
74
+ getProject(projectId) {
75
+ const row = this.database
76
+ .prepare(`
77
+ SELECT
78
+ p.id,
79
+ p.name,
80
+ p.description,
81
+ p.revision,
82
+ p.created_at,
83
+ p.updated_at,
84
+ count(s.id) AS session_count
85
+ FROM projects p
86
+ LEFT JOIN sessions s ON s.project_id = p.id
87
+ WHERE p.id = ?
88
+ GROUP BY p.id
89
+ `)
90
+ .get(projectId);
91
+ if (!row)
92
+ throw new ProjectNotFoundError(projectId);
93
+ return mapProject(row);
94
+ }
95
+ createProject(input) {
96
+ const name = requiredText(input.name, "Project name");
97
+ this.assertProjectNameAvailable(name);
98
+ const description = optionalText(input.description);
99
+ const id = randomUUID();
100
+ const now = new Date().toISOString();
101
+ this.database
102
+ .prepare(`INSERT INTO projects
103
+ (id, name, description, revision, created_at, updated_at)
104
+ VALUES (?, ?, ?, 1, ?, ?)`)
105
+ .run(id, name, description, now, now);
106
+ return this.getProject(id);
107
+ }
108
+ updateProject(projectId, input) {
109
+ const project = this.getProject(projectId);
110
+ assertRevision(input.expectedRevision, project.revision);
111
+ const name = input.name === undefined ? project.name : requiredText(input.name, "Project name");
112
+ if (name !== project.name)
113
+ this.assertProjectNameAvailable(name, projectId);
114
+ const description = input.description === undefined ? project.description : optionalText(input.description);
115
+ const now = new Date().toISOString();
116
+ this.database
117
+ .prepare(`UPDATE projects
118
+ SET name = ?, description = ?, revision = revision + 1, updated_at = ?
119
+ WHERE id = ? AND revision = ?`)
120
+ .run(name, description, now, projectId, input.expectedRevision);
121
+ return this.getProject(projectId);
122
+ }
123
+ deleteProject(projectId, input) {
124
+ const project = this.getProject(projectId);
125
+ assertRevision(input.expectedRevision, project.revision);
126
+ if (project.sessionCount > 0) {
127
+ throw new ProjectNotEmptyError(projectId, project.sessionCount);
128
+ }
129
+ this.database
130
+ .prepare(`DELETE FROM projects
131
+ WHERE id = ? AND revision = ?
132
+ AND NOT EXISTS (SELECT 1 FROM sessions WHERE project_id = ?)`)
133
+ .run(projectId, input.expectedRevision, projectId);
134
+ }
135
+ listSessions() {
136
+ return this.selectSessions("", []);
137
+ }
138
+ listUnassignedSessions() {
139
+ return this.selectSessions("WHERE project_id IS NULL", []);
140
+ }
141
+ listProjectSessions(projectId) {
142
+ this.getProject(projectId);
143
+ return this.selectSessions("WHERE project_id = ?", [projectId]);
144
+ }
145
+ getSession(sessionId) {
146
+ const row = this.database
147
+ .prepare(`${SESSION_SELECT} WHERE id = ?`)
148
+ .get(sessionId);
149
+ if (!row)
150
+ throw new SessionNotFoundError(sessionId);
151
+ return mapSession(row);
152
+ }
153
+ createSession(input) {
154
+ if (!SESSION_TYPES.includes(input.sessionType)) {
155
+ throw new InvalidRecordError(`Unsupported session type: ${input.sessionType}`);
156
+ }
157
+ const title = requiredText(input.title, "Session title");
158
+ const projectId = input.projectId ?? null;
159
+ if (projectId)
160
+ this.getProject(projectId);
161
+ const id = randomUUID();
162
+ const now = new Date().toISOString();
163
+ this.database.transaction(() => {
164
+ this.database
165
+ .prepare(`INSERT INTO sessions
166
+ (id, project_id, session_type, title, lifecycle_stage, revision, created_at, updated_at)
167
+ VALUES (?, ?, ?, ?, 'draft', 1, ?, ?)`)
168
+ .run(id, projectId, input.sessionType, title, now, now);
169
+ if (input.sessionType === "image-composition") {
170
+ this.database
171
+ .prepare("INSERT INTO composition_sessions (session_id) VALUES (?)")
172
+ .run(id);
173
+ }
174
+ else if (input.sessionType === "spatial") {
175
+ this.database.prepare("INSERT INTO spatial_sessions (session_id) VALUES (?)").run(id);
176
+ }
177
+ else {
178
+ this.database.prepare("INSERT INTO ui_sessions (session_id) VALUES (?)").run(id);
179
+ }
180
+ })();
181
+ return this.getSession(id);
182
+ }
183
+ moveSession(sessionId, input) {
184
+ const session = this.getSession(sessionId);
185
+ assertRevision(input.expectedRevision, session.revision);
186
+ if (input.projectId)
187
+ this.getProject(input.projectId);
188
+ if (session.projectId === input.projectId)
189
+ return session;
190
+ const now = new Date().toISOString();
191
+ this.database
192
+ .prepare(`UPDATE sessions
193
+ SET project_id = ?, revision = revision + 1, updated_at = ?
194
+ WHERE id = ? AND revision = ?`)
195
+ .run(input.projectId, now, sessionId, input.expectedRevision);
196
+ return this.getSession(sessionId);
197
+ }
198
+ renameSession(sessionId, input) {
199
+ const session = this.getSession(sessionId);
200
+ assertRevision(input.expectedRevision, session.revision);
201
+ const title = requiredText(input.title, "Session title");
202
+ if (session.title === title)
203
+ return session;
204
+ const now = new Date().toISOString();
205
+ this.database
206
+ .prepare(`UPDATE sessions
207
+ SET title = ?, revision = revision + 1, updated_at = ?
208
+ WHERE id = ? AND revision = ?`)
209
+ .run(title, now, sessionId, input.expectedRevision);
210
+ return this.getSession(sessionId);
211
+ }
212
+ deleteSession(sessionId, input) {
213
+ const session = this.getSession(sessionId);
214
+ assertRevision(input.expectedRevision, session.revision);
215
+ this.database
216
+ .prepare("DELETE FROM sessions WHERE id = ? AND revision = ?")
217
+ .run(sessionId, input.expectedRevision);
218
+ }
219
+ selectSessions(where, parameters) {
220
+ const rows = this.database
221
+ .prepare(`${SESSION_SELECT} ${where} ORDER BY updated_at DESC, id`)
222
+ .all(...parameters);
223
+ return rows.map(mapSession);
224
+ }
225
+ assertProjectNameAvailable(name, excludedProjectId) {
226
+ const existing = excludedProjectId
227
+ ? this.database
228
+ .prepare("SELECT id FROM projects WHERE name = ? AND id <> ? LIMIT 1")
229
+ .get(name, excludedProjectId)
230
+ : this.database
231
+ .prepare("SELECT id FROM projects WHERE name = ? LIMIT 1")
232
+ .get(name);
233
+ if (existing)
234
+ throw new ProjectNameConflictError(name);
235
+ }
236
+ }
237
+ const SESSION_SELECT = `
238
+ SELECT
239
+ id,
240
+ project_id,
241
+ style_id,
242
+ session_type,
243
+ title,
244
+ lifecycle_stage,
245
+ revision,
246
+ created_at,
247
+ updated_at
248
+ FROM sessions
249
+ `;
250
+ function mapProject(row) {
251
+ return {
252
+ id: row.id,
253
+ name: row.name,
254
+ description: row.description,
255
+ revision: row.revision,
256
+ sessionCount: row.session_count,
257
+ createdAt: row.created_at,
258
+ updatedAt: row.updated_at,
259
+ };
260
+ }
261
+ function mapSession(row) {
262
+ return {
263
+ id: row.id,
264
+ projectId: row.project_id,
265
+ styleId: row.style_id,
266
+ sessionType: row.session_type,
267
+ title: row.title,
268
+ lifecycleStage: row.lifecycle_stage,
269
+ revision: row.revision,
270
+ createdAt: row.created_at,
271
+ updatedAt: row.updated_at,
272
+ };
273
+ }
274
+ function requiredText(value, label) {
275
+ const trimmed = value.trim();
276
+ if (!trimmed)
277
+ throw new InvalidRecordError(`${label} cannot be empty`);
278
+ return trimmed;
279
+ }
280
+ function optionalText(value) {
281
+ if (value == null)
282
+ return null;
283
+ const trimmed = value.trim();
284
+ return trimmed || null;
285
+ }
286
+ function assertRevision(expectedRevision, actualRevision) {
287
+ if (expectedRevision !== actualRevision) {
288
+ throw new RevisionConflictError(expectedRevision, actualRevision);
289
+ }
290
+ }
291
+ //# sourceMappingURL=project-session-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-session-repository.js","sourceRoot":"","sources":["../../src/database/project-session-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { RestoreDraftVersionInput } from "../domain/session/index.ts";
2
+ import type { DatabaseConnection } from "./migrate.ts";
3
+ import type { CreateDraftVersionInput, UndoDraftVersionInput } from "../domain/session/index.ts";
4
+ import { type SpatialDraft, type SpatialOperation } from "../domain/spatial/index.ts";
5
+ export declare class SpatialSessionRepository {
6
+ private readonly database;
7
+ private readonly draftVersions;
8
+ private applyingOperations;
9
+ constructor(database: DatabaseConnection);
10
+ listDraftVersions(sessionId: string): import("../domain/session/draft-version.ts").DraftVersion<SpatialDraft>[];
11
+ getLatestDraftVersion(sessionId: string, knownRevision?: number): import("../domain/session/draft-version.ts").DraftVersion<SpatialDraft> | null;
12
+ getDraftVersion(sessionId: string, revision: number): import("../domain/session/draft-version.ts").DraftVersion<SpatialDraft>;
13
+ createDraftVersion(sessionId: string, input: CreateDraftVersionInput): import("../domain/session/draft-version.ts").DraftVersion<SpatialDraft>;
14
+ restoreDraftVersion(sessionId: string, input: RestoreDraftVersionInput): import("../domain/session/draft-version.ts").DraftVersion<SpatialDraft>;
15
+ undoDraftVersion(sessionId: string, input: UndoDraftVersionInput): import("../domain/session/draft-version.ts").DraftVersion<SpatialDraft>;
16
+ apply(sessionId: string, expectedLatestRevision: number, operations: SpatialOperation[]): {
17
+ constrained: boolean;
18
+ id: string;
19
+ sessionId: string;
20
+ revision: number;
21
+ fingerprint: string;
22
+ draft: SpatialDraft;
23
+ createdAt: string;
24
+ styleProcessing?: import("../domain/session/draft-version.ts").StyleProcessing;
25
+ };
26
+ }