openplanr 2.2640.8 → 2.2641.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 (192) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/dashboard/.vite/manifest.json +1 -1
  3. package/dist/dashboard/assets/{index-COZ36pFn.js → index-D7R6tnlX.js} +2 -2
  4. package/dist/dashboard/assets/{index-COZ36pFn.js.map → index-D7R6tnlX.js.map} +1 -1
  5. package/dist/dashboard/dashboard-manifest.json +8 -8
  6. package/dist/dashboard/index.html +1 -1
  7. package/lib/host-packages/adapter-registry.json +5 -5
  8. package/lib/host-packages/capability-map.json +1 -1
  9. package/lib/host-packages/claude/.claude-plugin/marketplace.json +2 -2
  10. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +1 -1
  11. package/lib/host-packages/claude/openplanr/.openplanr-content.json +167 -35
  12. package/lib/host-packages/claude/openplanr/README.md +22 -1
  13. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-artifact-shell.mjs +3 -11
  14. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +555 -0
  15. package/lib/host-packages/claude/openplanr/runtime/design/scripts/{design-pako-esm.mjs → design-compression.mjs} +2 -1521
  16. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-document.mjs +133 -12
  17. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +647 -0
  18. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-entities.mjs +17 -67
  19. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-handoff.mjs +14 -16
  20. package/lib/host-packages/claude/openplanr/runtime/design/scripts/{design-planr-home.mjs → design-loopback-server.mjs} +15 -36
  21. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-owner-custody.mjs +121 -0
  22. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-resource-pack.mjs +698 -0
  23. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review.mjs +798 -796
  24. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-home.mjs +39 -0
  25. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-support-5cb7531bede8.mjs +24 -0
  26. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share.mjs +138 -765
  27. package/lib/host-packages/claude/openplanr/runtime/design/scripts/{design-escape.mjs → design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs} +158 -156
  28. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-artifact-sources.mjs → claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs} +1 -1
  29. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-bounded-json-data.mjs → claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-31a760fc.mjs} +241 -454
  30. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +222 -0
  31. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-upload-spool.mjs +198 -0
  32. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design.mjs +12 -5
  33. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  34. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +18 -0
  35. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +809 -0
  36. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +5193 -0
  37. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +4175 -0
  38. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +65 -0
  39. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +1755 -0
  40. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +62 -0
  41. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +2600 -0
  42. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +123 -0
  43. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  44. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +3 -3
  45. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +34 -0
  46. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +992 -0
  47. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +2513 -0
  48. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +1919 -0
  49. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +1759 -0
  50. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +1551 -0
  51. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +1121 -0
  52. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +2183 -0
  53. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +705 -0
  54. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +27 -0
  55. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +13 -0
  56. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +3561 -0
  57. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +184 -0
  58. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +5045 -0
  59. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +1698 -0
  60. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +455 -0
  61. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +1844 -0
  62. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +257 -0
  63. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +1 -1
  64. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +4966 -0
  65. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design.mjs +240 -5192
  66. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +1 -1
  67. package/lib/host-packages/claude/openplanr/skills/delegate/scripts/backend-diagnostics.mjs +6 -2
  68. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +166 -34
  69. package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
  70. package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/backend-diagnostics.mjs +6 -2
  71. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-artifact-shell.mjs +3 -11
  72. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +555 -0
  73. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-pako-esm.mjs → cursor/openplanr/runtime/design/scripts/design-compression.mjs} +2 -1521
  74. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-document.mjs +133 -12
  75. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +647 -0
  76. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-entities.mjs +17 -67
  77. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-handoff.mjs +14 -16
  78. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-planr-home.mjs → cursor/openplanr/runtime/design/scripts/design-loopback-server.mjs} +15 -36
  79. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-owner-custody.mjs +121 -0
  80. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-resource-pack.mjs +698 -0
  81. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review.mjs +798 -796
  82. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-home.mjs +39 -0
  83. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-support-5cb7531bede8.mjs +24 -0
  84. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share.mjs +138 -765
  85. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-escape.mjs → cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs} +158 -156
  86. package/lib/host-packages/{claude/openplanr/runtime/design/scripts/design-artifact-sources.mjs → cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs} +1 -1
  87. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/{design-bounded-json-data.mjs → design-shared-protocol-contracts-31a760fc.mjs} +241 -454
  88. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +222 -0
  89. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-upload-spool.mjs +198 -0
  90. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design.mjs +12 -5
  91. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  92. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +18 -0
  93. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +809 -0
  94. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +5193 -0
  95. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +4175 -0
  96. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +65 -0
  97. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +1755 -0
  98. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +62 -0
  99. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +2600 -0
  100. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +123 -0
  101. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  102. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +3 -3
  103. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +34 -0
  104. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +992 -0
  105. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +2513 -0
  106. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +1919 -0
  107. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +1759 -0
  108. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +1551 -0
  109. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +1121 -0
  110. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +2183 -0
  111. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +705 -0
  112. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +27 -0
  113. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +13 -0
  114. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +3561 -0
  115. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +184 -0
  116. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +5045 -0
  117. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +1698 -0
  118. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +455 -0
  119. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +1844 -0
  120. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +257 -0
  121. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +1 -1
  122. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +4966 -0
  123. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design.mjs +240 -5192
  124. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +1 -1
  125. package/lib/host-packages/openai/.claude-plugin/marketplace.json +2 -2
  126. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +1 -1
  127. package/lib/host-packages/openai/openplanr/.openplanr-content.json +166 -34
  128. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-artifact-shell.mjs +3 -11
  129. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +555 -0
  130. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/design-pako-esm.mjs → openai/openplanr/runtime/design/scripts/design-compression.mjs} +2 -1521
  131. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-document.mjs +133 -12
  132. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +647 -0
  133. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-entities.mjs +17 -67
  134. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-handoff.mjs +14 -16
  135. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/design-planr-home.mjs → openai/openplanr/runtime/design/scripts/design-loopback-server.mjs} +15 -36
  136. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-owner-custody.mjs +121 -0
  137. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-resource-pack.mjs +698 -0
  138. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review.mjs +798 -796
  139. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-home.mjs +39 -0
  140. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-support-5cb7531bede8.mjs +24 -0
  141. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share.mjs +138 -765
  142. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/design-escape.mjs → openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs} +158 -156
  143. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/design-artifact-sources.mjs → openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs} +1 -1
  144. package/lib/host-packages/{claude/openplanr/runtime/design/scripts/design-bounded-json-data.mjs → openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-31a760fc.mjs} +241 -454
  145. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +222 -0
  146. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-upload-spool.mjs +198 -0
  147. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design.mjs +12 -5
  148. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/lib/artifact/ui/studio-shell.css +1 -1
  149. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/01-module-runtime.js +18 -0
  150. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +809 -0
  151. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +5193 -0
  152. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +4175 -0
  153. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +65 -0
  154. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +1755 -0
  155. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +62 -0
  156. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +2600 -0
  157. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +123 -0
  158. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +3 -3
  159. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.css +3 -3
  160. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/01-module-runtime.js +34 -0
  161. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +992 -0
  162. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/03-react-dom-client-fiber-foundations.js +2513 -0
  163. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/04-react-dom-client-reconciliation-hooks.js +1919 -0
  164. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/05-react-dom-client-render-phases.js +1759 -0
  165. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/06-react-dom-client-commit-effects.js +1551 -0
  166. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/07-react-dom-client-work-loop-scheduling.js +1121 -0
  167. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/08-react-dom-client-dom-events-properties-hydration.js +2183 -0
  168. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +705 -0
  169. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/10-react.js +27 -0
  170. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/11-artifact-review-ui.js +13 -0
  171. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-design-review-experience.js +3561 -0
  172. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-studio-shell.js +184 -0
  173. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/14-interface-primitives.js +5045 -0
  174. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-interface-primitives.js +1698 -0
  175. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/16-studio-shell.js +455 -0
  176. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/17-design-studio.js +1844 -0
  177. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +257 -0
  178. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +1 -1
  179. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +4966 -0
  180. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design.mjs +240 -5192
  181. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +1 -1
  182. package/lib/host-packages/openai/openplanr/skills/delegate/scripts/backend-diagnostics.mjs +6 -2
  183. package/package.json +2 -2
  184. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-generated-b0798298053515fd.mjs +0 -18
  185. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +0 -5
  186. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js +0 -25597
  187. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-generated-b0798298053515fd.mjs +0 -18
  188. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +0 -5
  189. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js +0 -25597
  190. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-generated-b0798298053515fd.mjs +0 -18
  191. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js +0 -5
  192. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js +0 -25597
@@ -1,26 +1,3 @@
1
- import {
2
- LARGE_OBJECT_CHUNK_CONTEXT,
3
- LARGE_OBJECT_LIMITS,
4
- RESOURCE_HTML_SEGMENT_ENCODING,
5
- assertLargeObjectContract,
6
- canonicalizeJson,
7
- sha256Hex
8
- } from "./design-bounded-json-data.mjs";
9
-
10
- // packages/artifact/lib/artifact/upload-spool.mjs
11
- import {
12
- closeSync as closeSync2,
13
- constants as constants2,
14
- existsSync as existsSync2,
15
- fstatSync,
16
- fsyncSync as fsyncSync2,
17
- lstatSync as lstatSync2,
18
- openSync as openSync2,
19
- readSync,
20
- writeFileSync as writeFileSync2
21
- } from "node:fs";
22
- import { dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
23
-
24
1
  // node_modules/pako/dist/pako.esm.mjs
25
2
  /*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) */
26
3
  var Z_FIXED$1 = 4;
@@ -4197,1503 +4174,7 @@ var { Inflate, inflate, inflateRaw, ungzip } = inflate_1$1;
4197
4174
  var deflateRaw_1 = deflateRaw;
4198
4175
  var Inflate_1 = Inflate;
4199
4176
 
4200
- // packages/artifact/lib/artifact/resource-pack.mjs
4201
- var encoder = new TextEncoder();
4202
- var decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
4203
- var htmlSegmentMagic = encoder.encode(`\0${RESOURCE_HTML_SEGMENT_ENCODING}\0`);
4204
- var blockPattern = /(<(script|style)\b[^>]*>)([\s\S]*?)<\/\2\s*>/gi;
4205
- function encodeResourceBytes(bytes) {
4206
- let binary = "";
4207
- for (let offset = 0; offset < bytes.length; offset += 8192)
4208
- binary += String.fromCharCode(...bytes.subarray(offset, offset + 8192));
4209
- return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
4210
- }
4211
- function decodeResourceBytes(value, maxBytes = 65536) {
4212
- if (typeof value !== "string" || !/^[A-Za-z0-9_-]+$/u.test(value) || value.length > Math.ceil(maxBytes * 4 / 3))
4213
- throw new TypeError("Invalid encoded resource value.");
4214
- const bytes = Uint8Array.from(
4215
- atob(value.replaceAll("-", "+").replaceAll("_", "/")),
4216
- (char) => char.charCodeAt(0)
4217
- );
4218
- if (bytes.byteLength > maxBytes || encodeResourceBytes(bytes) !== value)
4219
- throw new TypeError("Noncanonical resource encoding.");
4220
- return bytes;
4221
- }
4222
- async function resourceSha256(bytes) {
4223
- return [...new Uint8Array(await crypto.subtle.digest("SHA-256", bytes))].map((part) => part.toString(16).padStart(2, "0")).join("");
4224
- }
4225
- function encodeResource(bytes) {
4226
- const compressed = deflateRaw_1(bytes);
4227
- return compressed.byteLength < bytes.byteLength ? { bytes: compressed, codec: "deflate-raw" } : { bytes, codec: "identity" };
4228
- }
4229
- function decodeResource(bytes, descriptor, maxBytes = LARGE_OBJECT_LIMITS.decodedBytes) {
4230
- if (descriptor.encodedBytes !== bytes.byteLength || descriptor.decodedBytes > maxBytes || descriptor.decodedBytes < 1)
4231
- throw new RangeError("Resource size is invalid.");
4232
- if (descriptor.codec === "identity") {
4233
- if (bytes.byteLength !== descriptor.decodedBytes)
4234
- throw new TypeError("Identity resource length differs.");
4235
- return bytes;
4236
- }
4237
- if (descriptor.codec !== "deflate-raw") throw new TypeError("Unsupported resource codec.");
4238
- const inflater = new Inflate_1({ raw: true, chunkSize: 65536 });
4239
- const chunks = [];
4240
- let size = 0;
4241
- inflater.onData = (part) => {
4242
- size += part.byteLength;
4243
- if (size > descriptor.decodedBytes || size > maxBytes)
4244
- throw new RangeError("Resource expands beyond its declared limit.");
4245
- chunks.push(part);
4246
- };
4247
- inflater.push(bytes, true);
4248
- if (!inflater.ended && !inflater.err && inflater.strm?.avail_in === 0)
4249
- inflater.push(new Uint8Array(0), true);
4250
- if (!inflater.ended || inflater.err || size !== descriptor.decodedBytes || inflater.strm?.avail_in)
4251
- throw new TypeError("Compressed resource is corrupt or has trailing data.");
4252
- const output = new Uint8Array(size);
4253
- let offset = 0;
4254
- for (const part of chunks) {
4255
- output.set(part, offset);
4256
- offset += part.byteLength;
4257
- }
4258
- return output;
4259
- }
4260
- function jsonStringByteLength(value, maxBytes) {
4261
- let bytes = 2;
4262
- for (let index = 0; index < value.length; index++) {
4263
- const code = value.charCodeAt(index);
4264
- if (code === 34 || code === 92) bytes += 2;
4265
- else if (code < 32) bytes += [8, 9, 10, 12, 13].includes(code) ? 2 : 6;
4266
- else if (code < 128) bytes++;
4267
- else if (code < 2048) bytes += 2;
4268
- else if (code >= 55296 && code <= 56319) {
4269
- const next = value.charCodeAt(index + 1);
4270
- if (next >= 56320 && next <= 57343) {
4271
- bytes += 4;
4272
- index++;
4273
- } else bytes += 6;
4274
- } else bytes += code >= 56320 && code <= 57343 ? 6 : 3;
4275
- if (bytes > maxBytes) throw new RangeError("Resource pack exceeds its decoded byte limit.");
4276
- }
4277
- return bytes;
4278
- }
4279
- function utf8SegmentInfo(text, maximum) {
4280
- let bytes = 0, wellFormed = true;
4281
- for (let index = 0; index < text.length; index++) {
4282
- const code = text.charCodeAt(index);
4283
- if (code < 128) bytes++;
4284
- else if (code < 2048) bytes += 2;
4285
- else if (code >= 55296 && code <= 56319) {
4286
- const next = text.charCodeAt(index + 1);
4287
- if (next >= 56320 && next <= 57343) {
4288
- bytes += 4;
4289
- index++;
4290
- } else {
4291
- bytes += 3;
4292
- wellFormed = false;
4293
- }
4294
- } else {
4295
- bytes += 3;
4296
- if (code >= 56320 && code <= 57343) wellFormed = false;
4297
- }
4298
- if (bytes > maximum) throw new RangeError("Resource pack exceeds its decoded byte limit.");
4299
- }
4300
- return { bytes, wellFormed };
4301
- }
4302
- function segmentText(segment) {
4303
- if (typeof segment === "string") return { type: 0, text: segment };
4304
- if (!segment || typeof segment !== "object" || Array.isArray(segment))
4305
- throw new TypeError("Source segment is invalid.");
4306
- const descriptors = Object.getOwnPropertyDescriptors(segment);
4307
- if (Reflect.ownKeys(descriptors).length !== 1 || !Object.hasOwn(descriptors, "resourceId") || !Object.hasOwn(descriptors.resourceId, "value") || typeof descriptors.resourceId.value !== "string" || !/^r[0-9]{1,4}$/u.test(descriptors.resourceId.value))
4308
- throw new TypeError("Source segment is invalid.");
4309
- return { type: 1, text: descriptors.resourceId.value };
4310
- }
4311
- function encodeHtmlSegments(segments, maxBytes = LARGE_OBJECT_LIMITS.decodedBytes) {
4312
- if (!Array.isArray(segments) || !segments.length || segments.length > LARGE_OBJECT_LIMITS.resources * 2 + 1 || !Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > LARGE_OBJECT_LIMITS.decodedBytes)
4313
- throw new RangeError("Source segment count or byte limit is invalid.");
4314
- let byteLength = htmlSegmentMagic.byteLength + 4, wellFormed = true;
4315
- const parts = [];
4316
- for (const segment of segments) {
4317
- const part = segmentText(segment);
4318
- byteLength += 5;
4319
- if (byteLength > maxBytes)
4320
- throw new RangeError("Resource pack exceeds its decoded byte limit.");
4321
- const info = utf8SegmentInfo(part.text, maxBytes - byteLength);
4322
- byteLength += info.bytes;
4323
- wellFormed &&= info.wellFormed;
4324
- parts.push({ ...part, byteLength: info.bytes });
4325
- }
4326
- if (!wellFormed) throw new TypeError("Source segment text is not valid Unicode.");
4327
- const bytes = new Uint8Array(byteLength), view = new DataView(bytes.buffer);
4328
- bytes.set(htmlSegmentMagic);
4329
- view.setUint32(htmlSegmentMagic.byteLength, parts.length);
4330
- let cursor = htmlSegmentMagic.byteLength + 4;
4331
- for (const part of parts) {
4332
- bytes[cursor++] = part.type;
4333
- view.setUint32(cursor, part.byteLength);
4334
- cursor += 4;
4335
- const encoded = encoder.encodeInto(part.text, bytes.subarray(cursor, cursor + part.byteLength));
4336
- if (encoded.read !== part.text.length || encoded.written !== part.byteLength)
4337
- throw new TypeError("Source segment byte accounting differs.");
4338
- cursor += part.byteLength;
4339
- }
4340
- return bytes;
4341
- }
4342
- function decodeHtmlSegments(bytes, maxBytes = LARGE_OBJECT_LIMITS.decodedBytes) {
4343
- if (!(bytes instanceof Uint8Array) || !bytes.byteLength || bytes.byteLength > maxBytes || !Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > LARGE_OBJECT_LIMITS.decodedBytes)
4344
- throw new RangeError("Source segment bytes exceed their limit.");
4345
- if (bytes[0] !== 0) {
4346
- const segments2 = JSON.parse(decoder.decode(bytes));
4347
- if (!Array.isArray(segments2) || !segments2.length || segments2.length > LARGE_OBJECT_LIMITS.resources * 2 + 1)
4348
- throw new TypeError("Source segment count is invalid.");
4349
- for (const segment of segments2) segmentText(segment);
4350
- return segments2;
4351
- }
4352
- if (bytes.byteLength < htmlSegmentMagic.byteLength + 4 || htmlSegmentMagic.some((byte, index) => byte !== bytes[index]))
4353
- throw new TypeError("Source segment encoding is unsupported or corrupt.");
4354
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
4355
- const count = view.getUint32(htmlSegmentMagic.byteLength);
4356
- if (!count || count > LARGE_OBJECT_LIMITS.resources * 2 + 1)
4357
- throw new TypeError("Source segment count is invalid.");
4358
- const segments = [];
4359
- let cursor = htmlSegmentMagic.byteLength + 4;
4360
- for (let index = 0; index < count; index++) {
4361
- if (bytes.byteLength - cursor < 5) throw new TypeError("Source segment span is truncated.");
4362
- const type = bytes[cursor++], length = view.getUint32(cursor);
4363
- cursor += 4;
4364
- if (![0, 1].includes(type) || length > bytes.byteLength - cursor || type === 1 && length > 128)
4365
- throw new TypeError("Source segment span is invalid.");
4366
- const text = decoder.decode(bytes.subarray(cursor, cursor + length));
4367
- cursor += length;
4368
- const segment = type === 0 ? text : { resourceId: text };
4369
- segmentText(segment);
4370
- segments.push(segment);
4371
- }
4372
- if (cursor !== bytes.byteLength) throw new TypeError("Source segment bytes have trailing data.");
4373
- return segments;
4374
- }
4375
- async function packResourceBundle(bundle, { reviewOf } = {}) {
4376
- if (reviewOf !== void 0 && !/^[a-f0-9]{64}$/u.test(reviewOf))
4377
- throw new TypeError("Invalid full review identity.");
4378
- const diagram = bundle?.kind === "openplanr-diagram-review-bundle";
4379
- const envelope = diagram ? { schemaVersion: "1.0.0", artifacts: [{ id: "diagram", html: bundle.scene?.svg }] } : bundle?.envelope;
4380
- const views = envelope?.artifacts;
4381
- if (!Array.isArray(views) || !views.length || views.length > LARGE_OBJECT_LIMITS.views || new Set(views.map((view) => view.id)).size !== views.length)
4382
- throw new RangeError("Resource pack view count or identity is invalid.");
4383
- const pooled = envelope.schemaVersion === "1.1.0";
4384
- let sources;
4385
- const viewSources = /* @__PURE__ */ Object.create(null);
4386
- if (pooled) {
4387
- sources = envelope.sources;
4388
- if (!Array.isArray(sources) || !sources.length || sources.length > LARGE_OBJECT_LIMITS.sources || new Set(sources.map((source) => source.id)).size !== sources.length)
4389
- throw new RangeError("Resource pack source count or identity is invalid.");
4390
- const sourceIds = new Set(sources.map((source) => source.id));
4391
- for (const view of views) {
4392
- if (!sourceIds.has(view.sourceId)) throw new TypeError("View references an unknown source.");
4393
- viewSources[view.id] = view.sourceId;
4394
- }
4395
- } else {
4396
- sources = [];
4397
- const pages = /* @__PURE__ */ new Map();
4398
- for (const view of views) {
4399
- if (typeof view.html !== "string") throw new TypeError("View has no HTML source.");
4400
- if (!pages.has(view.html)) {
4401
- const id = `source-${sources.length}`;
4402
- pages.set(view.html, id);
4403
- sources.push({ id, html: view.html });
4404
- }
4405
- viewSources[view.id] = pages.get(view.html);
4406
- }
4407
- }
4408
- if (sources.length > LARGE_OBJECT_LIMITS.sources)
4409
- throw new RangeError("Resource pack exceeds its source limit.");
4410
- const blocks = /* @__PURE__ */ new Map();
4411
- const resources = [];
4412
- const encodedResources = [];
4413
- let encodedBytes = 0, decodedBytes = 0, uniqueHtmlBytes = 0;
4414
- async function addResource(type, bytes) {
4415
- if (!bytes.byteLength || resources.length >= LARGE_OBJECT_LIMITS.resources)
4416
- throw new RangeError("Resource count exceeds its limit.");
4417
- if (bytes.byteLength > LARGE_OBJECT_LIMITS.decodedBytes - decodedBytes)
4418
- throw new RangeError("Resource pack exceeds its decoded byte limit.");
4419
- const encoded = encodeResource(bytes);
4420
- const descriptor = {
4421
- id: `r${resources.length}`,
4422
- type,
4423
- offset: encodedBytes,
4424
- encodedBytes: encoded.bytes.byteLength,
4425
- decodedBytes: bytes.byteLength,
4426
- codec: encoded.codec,
4427
- sha256: await resourceSha256(bytes)
4428
- };
4429
- encodedBytes += descriptor.encodedBytes;
4430
- decodedBytes += descriptor.decodedBytes;
4431
- if (decodedBytes > LARGE_OBJECT_LIMITS.decodedBytes || encodedBytes > LARGE_OBJECT_LIMITS.decodedBytes)
4432
- throw new RangeError("Resource pack exceeds its decoded byte limit.");
4433
- resources.push(descriptor);
4434
- encodedResources.push(encoded.bytes);
4435
- return descriptor.id;
4436
- }
4437
- const sourceRecords = [];
4438
- for (const source of sources) {
4439
- if (typeof source.html !== "string" || !source.html.length)
4440
- throw new TypeError("Source HTML is invalid.");
4441
- let info;
4442
- try {
4443
- info = utf8SegmentInfo(source.html, LARGE_OBJECT_LIMITS.uniqueHtmlBytes - uniqueHtmlBytes);
4444
- } catch {
4445
- throw new RangeError("Resource pack exceeds its unique HTML limit.");
4446
- }
4447
- if (!info.wellFormed) throw new TypeError("Source HTML is not valid Unicode.");
4448
- uniqueHtmlBytes += info.bytes;
4449
- const htmlBytes = encoder.encode(source.html);
4450
- const sha256 = await resourceSha256(htmlBytes);
4451
- if (source.sha256 && source.sha256 !== sha256)
4452
- throw new TypeError("Source digest does not match its HTML.");
4453
- const segments = [];
4454
- let offset = 0;
4455
- for (const match of source.html.matchAll(blockPattern)) {
4456
- const body = match[3];
4457
- if (segments.length >= LARGE_OBJECT_LIMITS.resources * 2 || body.length < 2048 || !blocks.has(body) && blocks.size >= 512)
4458
- continue;
4459
- const start = match.index + match[1].length;
4460
- segments.push(source.html.slice(offset, start));
4461
- if (!blocks.has(body))
4462
- blocks.set(body, await addResource("shared-block", encoder.encode(body)));
4463
- segments.push({ resourceId: blocks.get(body) });
4464
- offset = start + body.length;
4465
- }
4466
- segments.push(source.html.slice(offset));
4467
- const resourceId = await addResource(
4468
- "html-segments",
4469
- encodeHtmlSegments(segments, LARGE_OBJECT_LIMITS.decodedBytes - decodedBytes)
4470
- );
4471
- sourceRecords.push({ id: source.id, resourceId, htmlBytes: htmlBytes.byteLength, sha256 });
4472
- }
4473
- const withoutHtml = ({ html: _html, ...value }) => value;
4474
- const metadata = diagram ? { ...bundle, scene: { ...bundle.scene, svg: "" } } : {
4475
- ...bundle,
4476
- envelope: {
4477
- ...envelope,
4478
- artifacts: views.map(withoutHtml),
4479
- ...pooled ? { sources: sources.map(withoutHtml) } : {}
4480
- }
4481
- };
4482
- const catalog = {
4483
- schemaVersion: "1.0.0",
4484
- kind: "openplanr-resource-catalog",
4485
- ...reviewOf === void 0 ? {} : { reviewOf },
4486
- bundle: metadata,
4487
- uniqueHtmlBytes,
4488
- totalDecodedBytes: decodedBytes,
4489
- resources,
4490
- sources: sourceRecords,
4491
- viewSources
4492
- };
4493
- let catalogBytes;
4494
- for (let attempt = 0; attempt < 4; attempt++) {
4495
- catalogBytes = encoder.encode(canonicalizeJson(catalog));
4496
- const total = decodedBytes + catalogBytes.byteLength;
4497
- if (catalog.totalDecodedBytes === total) break;
4498
- catalog.totalDecodedBytes = total;
4499
- }
4500
- catalogBytes = encoder.encode(canonicalizeJson(catalog));
4501
- if (decodedBytes + catalogBytes.byteLength !== catalog.totalDecodedBytes || catalog.totalDecodedBytes > LARGE_OBJECT_LIMITS.decodedBytes)
4502
- throw new RangeError("Resource pack total exceeds its decoded limit.");
4503
- assertLargeObjectContract(catalog, "resource-catalog");
4504
- const encodedCatalog = encodeResource(catalogBytes);
4505
- const catalogSpan = {
4506
- offset: encodedBytes,
4507
- encodedBytes: encodedCatalog.bytes.byteLength,
4508
- decodedBytes: catalogBytes.byteLength,
4509
- codec: encodedCatalog.codec
4510
- };
4511
- return {
4512
- catalog,
4513
- catalogSpan,
4514
- encodedResources: [...encodedResources, encodedCatalog.bytes],
4515
- plaintextBytes: encodedBytes + encodedCatalog.bytes.byteLength
4516
- };
4517
- }
4518
- function resourceChunkAAD(manifest, index) {
4519
- return encoder.encode(
4520
- canonicalizeJson({
4521
- context: LARGE_OBJECT_CHUNK_CONTEXT,
4522
- workspaceId: manifest.workspaceId,
4523
- revisionId: manifest.revisionId,
4524
- epoch: manifest.epoch,
4525
- index
4526
- })
4527
- );
4528
- }
4529
- async function encryptResourcePack(pack, { workspaceId, revisionId, epoch, rawKey, sign, createdAt = (/* @__PURE__ */ new Date()).toISOString() }) {
4530
- const header = {
4531
- schemaVersion: "2.0.0",
4532
- kind: "openplanr-encrypted-resource-manifest",
4533
- workspaceId,
4534
- revisionId,
4535
- epoch,
4536
- createdAt,
4537
- plaintextBytes: pack.plaintextBytes,
4538
- catalog: pack.catalogSpan
4539
- };
4540
- const key = await crypto.subtle.importKey("raw", rawKey, "AES-GCM", false, ["encrypt"]);
4541
- const chunks = [];
4542
- const descriptors = [];
4543
- const ivs = /* @__PURE__ */ new Set();
4544
- let part = new Uint8Array(LARGE_OBJECT_LIMITS.chunkPlaintextBytes), filled = 0;
4545
- async function flush() {
4546
- if (!filled) return;
4547
- let iv, encodedIv;
4548
- do {
4549
- iv = crypto.getRandomValues(new Uint8Array(12));
4550
- encodedIv = encodeResourceBytes(iv);
4551
- } while (ivs.has(encodedIv));
4552
- ivs.add(encodedIv);
4553
- const index = chunks.length;
4554
- const cipher = new Uint8Array(
4555
- await crypto.subtle.encrypt(
4556
- { name: "AES-GCM", iv, additionalData: resourceChunkAAD(header, index), tagLength: 128 },
4557
- key,
4558
- part.subarray(0, filled)
4559
- )
4560
- );
4561
- if (chunks.length >= LARGE_OBJECT_LIMITS.chunks)
4562
- throw new RangeError("Encrypted pack exceeds its chunk limit.");
4563
- chunks.push(cipher);
4564
- descriptors.push({
4565
- index,
4566
- iv: encodedIv,
4567
- byteLength: cipher.byteLength,
4568
- sha256: await resourceSha256(cipher)
4569
- });
4570
- filled = 0;
4571
- }
4572
- for (const bytes of pack.encodedResources) {
4573
- for (let offset = 0; offset < bytes.byteLength; ) {
4574
- const take = Math.min(part.byteLength - filled, bytes.byteLength - offset);
4575
- part.set(bytes.subarray(offset, offset + take), filled);
4576
- filled += take;
4577
- offset += take;
4578
- if (filled === part.byteLength) await flush();
4579
- }
4580
- }
4581
- await flush();
4582
- part.fill(0);
4583
- const manifest = await sign({
4584
- ...header,
4585
- ciphertextBytes: chunks.reduce((sum, value) => sum + value.byteLength, 0),
4586
- chunks: descriptors
4587
- });
4588
- assertLargeObjectContract(manifest, "encrypted-resource-manifest");
4589
- return { manifest, chunks };
4590
- }
4591
- async function openResourcePack(manifest, { rawKey, verify, fetchChunk, maxCachedBytes = 8 * 1024 * 1024 }) {
4592
- assertLargeObjectContract(manifest, "encrypted-resource-manifest");
4593
- if (!await verify(manifest)) throw new TypeError("Resource manifest signature is invalid.");
4594
- const key = await crypto.subtle.importKey("raw", rawKey, "AES-GCM", false, ["decrypt"]);
4595
- const cache = /* @__PURE__ */ new Map();
4596
- let cacheBytes = 0, disposed = false;
4597
- if (!Number.isSafeInteger(maxCachedBytes) || maxCachedBytes < LARGE_OBJECT_LIMITS.chunkBytes || maxCachedBytes > LARGE_OBJECT_LIMITS.decodedBytes)
4598
- throw new RangeError("Resource cache bound is invalid.");
4599
- async function chunkAt(index) {
4600
- if (disposed) throw new Error("Resource pack has been disposed.");
4601
- if (cache.has(index)) {
4602
- const bytes2 = cache.get(index);
4603
- cache.delete(index);
4604
- cache.set(index, bytes2);
4605
- return bytes2;
4606
- }
4607
- const descriptor = manifest.chunks[index];
4608
- const bytes = await fetchChunk(index, descriptor);
4609
- if (!(bytes instanceof Uint8Array) || bytes.byteLength !== descriptor.byteLength || await resourceSha256(bytes) !== descriptor.sha256)
4610
- throw new TypeError("Ciphertext chunk integrity check failed.");
4611
- const plaintext = new Uint8Array(
4612
- await crypto.subtle.decrypt(
4613
- {
4614
- name: "AES-GCM",
4615
- iv: decodeResourceBytes(descriptor.iv, 12),
4616
- additionalData: resourceChunkAAD(manifest, index),
4617
- tagLength: 128
4618
- },
4619
- key,
4620
- bytes
4621
- )
4622
- );
4623
- if (disposed) {
4624
- plaintext.fill(0);
4625
- throw new Error("Resource pack has been disposed.");
4626
- }
4627
- cache.set(index, plaintext);
4628
- cacheBytes += plaintext.byteLength;
4629
- while (cacheBytes > maxCachedBytes && cache.size > 1) {
4630
- const first = cache.keys().next().value;
4631
- cacheBytes -= cache.get(first).byteLength;
4632
- cache.delete(first);
4633
- }
4634
- return plaintext;
4635
- }
4636
- return openPackedResources({
4637
- catalogSpan: manifest.catalog,
4638
- plaintextBytes: manifest.plaintextBytes,
4639
- chunkPlaintextBytes: LARGE_OBJECT_LIMITS.chunkPlaintextBytes,
4640
- chunkAt,
4641
- dispose() {
4642
- disposed = true;
4643
- for (const bytes of cache.values()) bytes.fill(0);
4644
- cache.clear();
4645
- cacheBytes = 0;
4646
- }
4647
- });
4648
- }
4649
- async function openPackedResources({
4650
- catalogSpan,
4651
- plaintextBytes,
4652
- chunkPlaintextBytes,
4653
- chunkAt,
4654
- dispose = () => {
4655
- }
4656
- }) {
4657
- async function spanBytes(span) {
4658
- if (!Number.isSafeInteger(span.offset) || !Number.isSafeInteger(span.encodedBytes) || span.offset < 0 || span.encodedBytes < 1 || span.offset + span.encodedBytes > plaintextBytes)
4659
- throw new TypeError("Resource span is invalid.");
4660
- const bytes = new Uint8Array(span.encodedBytes);
4661
- for (let copied = 0; copied < bytes.byteLength; ) {
4662
- const absolute = span.offset + copied, index = Math.floor(absolute / chunkPlaintextBytes), within = absolute % chunkPlaintextBytes;
4663
- const chunk = await chunkAt(index);
4664
- const take = Math.min(chunk.byteLength - within, bytes.byteLength - copied);
4665
- if (take < 1) throw new TypeError("Resource span exceeds its chunks.");
4666
- bytes.set(chunk.subarray(within, within + take), copied);
4667
- copied += take;
4668
- }
4669
- return bytes;
4670
- }
4671
- const catalogBytes = decodeResource(
4672
- await spanBytes(catalogSpan),
4673
- catalogSpan,
4674
- LARGE_OBJECT_LIMITS.catalogBytes
4675
- );
4676
- const catalog = assertLargeObjectContract(
4677
- JSON.parse(decoder.decode(catalogBytes)),
4678
- "resource-catalog"
4679
- );
4680
- const resourceBytes = catalog.resources.reduce((sum, part) => sum + part.decodedBytes, 0);
4681
- const encodedBytes = catalog.resources.reduce((sum, part) => sum + part.encodedBytes, 0);
4682
- if (resourceBytes + catalogBytes.byteLength !== catalog.totalDecodedBytes || encodedBytes !== catalogSpan.offset)
4683
- throw new TypeError("Catalog and manifest byte accounting differ.");
4684
- const resources = new Map(catalog.resources.map((resource) => [resource.id, resource]));
4685
- const sourceRecords = new Map(catalog.sources.map((source) => [source.id, source]));
4686
- async function resourceAt(id, expectedType, maxBytes = LARGE_OBJECT_LIMITS.decodedBytes) {
4687
- const descriptor = resources.get(id);
4688
- if (!descriptor || descriptor.type !== expectedType || descriptor.offset + descriptor.encodedBytes > catalogSpan.offset)
4689
- throw new TypeError("Resource reference is invalid.");
4690
- if (descriptor.decodedBytes > maxBytes || descriptor.encodedBytes > maxBytes)
4691
- throw new RangeError("Selected source resource exceeds its read limit.");
4692
- const decoded = decodeResource(await spanBytes(descriptor), descriptor, maxBytes);
4693
- if (await resourceSha256(decoded) !== descriptor.sha256)
4694
- throw new TypeError("Decoded resource integrity check failed.");
4695
- return decoded;
4696
- }
4697
- async function loadSource(id, { maxSourceBytes } = {}) {
4698
- const source = sourceRecords.get(id);
4699
- if (!source) throw new TypeError("Unknown source.");
4700
- if (maxSourceBytes !== void 0 && (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes < 1 || maxSourceBytes > LARGE_OBJECT_LIMITS.uniqueHtmlBytes))
4701
- throw new RangeError("Selected source read limit is invalid.");
4702
- if (maxSourceBytes !== void 0 && source.htmlBytes > maxSourceBytes)
4703
- throw new RangeError("Selected source exceeds its read limit.");
4704
- const segmentLimit = maxSourceBytes === void 0 ? LARGE_OBJECT_LIMITS.decodedBytes : Math.min(
4705
- LARGE_OBJECT_LIMITS.decodedBytes,
4706
- maxSourceBytes * 6 + (LARGE_OBJECT_LIMITS.resources * 2 + 1) * 160 + htmlSegmentMagic.byteLength + 4
4707
- );
4708
- const segments = decodeHtmlSegments(
4709
- await resourceAt(source.resourceId, "html-segments", segmentLimit),
4710
- segmentLimit
4711
- );
4712
- if (!Array.isArray(segments) || segments.length > LARGE_OBJECT_LIMITS.resources * 2 + 1)
4713
- throw new TypeError("Source segment count is invalid.");
4714
- const parts = [];
4715
- let htmlBytes = 0;
4716
- for (const segment of segments) {
4717
- let text;
4718
- if (typeof segment === "string") text = segment;
4719
- else if (segment && Object.keys(segment).length === 1 && typeof segment.resourceId === "string")
4720
- text = decoder.decode(
4721
- await resourceAt(
4722
- segment.resourceId,
4723
- "shared-block",
4724
- maxSourceBytes ?? LARGE_OBJECT_LIMITS.decodedBytes
4725
- )
4726
- );
4727
- else throw new TypeError("Source segment is invalid.");
4728
- htmlBytes += encoder.encode(text).byteLength;
4729
- if (htmlBytes > source.htmlBytes)
4730
- throw new RangeError("Source expands beyond its declared limit.");
4731
- parts.push(text);
4732
- }
4733
- const html = parts.join("");
4734
- if (htmlBytes !== source.htmlBytes || await resourceSha256(encoder.encode(html)) !== source.sha256)
4735
- throw new TypeError("Reconstructed HTML integrity check failed.");
4736
- return html;
4737
- }
4738
- async function loadView(viewId, options) {
4739
- if (catalog.bundle.kind === "openplanr-diagram-review-bundle") {
4740
- if (viewId !== "diagram") throw new TypeError("Unknown diagram view.");
4741
- return { id: "diagram", html: await loadSource(catalog.viewSources.diagram, options) };
4742
- }
4743
- const view = catalog.bundle.envelope.artifacts.find((item) => item.id === viewId);
4744
- if (!view || !Object.hasOwn(catalog.viewSources, viewId)) throw new TypeError("Unknown view.");
4745
- return { ...view, html: await loadSource(catalog.viewSources[viewId], options) };
4746
- }
4747
- async function loadBundle({ sourcePool = false } = {}) {
4748
- const metadataBytes = encoder.encode(canonicalizeJson(catalog.bundle)).byteLength;
4749
- const poolInline = sourcePool && catalog.bundle.kind === "openplanr-design-review-bundle" && catalog.bundle.envelope.schemaVersion !== "1.1.0";
4750
- const references = catalog.bundle.kind === "openplanr-diagram-review-bundle" ? [{ id: catalog.viewSources.diagram, field: null }] : catalog.bundle.envelope.schemaVersion === "1.1.0" ? catalog.bundle.envelope.sources.map((source) => ({ id: source.id, field: "html" })) : poolInline ? catalog.sources.map((source) => ({ id: source.id, field: "html" })) : catalog.bundle.envelope.artifacts.map((view) => ({
4751
- id: catalog.viewSources[view.id],
4752
- field: "html"
4753
- }));
4754
- const counts = /* @__PURE__ */ new Map();
4755
- let serializedBytes = metadataBytes;
4756
- for (const { id, field } of references) {
4757
- const source = sourceRecords.get(id);
4758
- if (!source) throw new TypeError("Unknown source.");
4759
- serializedBytes += source.htmlBytes + (field === null ? 0 : field.length + 6);
4760
- if (serializedBytes > LARGE_OBJECT_LIMITS.decodedBytes)
4761
- throw new RangeError(
4762
- "Complete bundle reconstruction exceeds its serialized byte limit. Use lazy views."
4763
- );
4764
- counts.set(id, (counts.get(id) ?? 0) + 1);
4765
- }
4766
- const uniqueRepresentation = [...counts.values()].every((count) => count === 1);
4767
- const htmlBySource = /* @__PURE__ */ new Map();
4768
- for (const [id, count] of counts) {
4769
- const html = await loadSource(id);
4770
- const source = sourceRecords.get(id);
4771
- if (!uniqueRepresentation) {
4772
- const escapedBytes = jsonStringByteLength(html, LARGE_OBJECT_LIMITS.decodedBytes);
4773
- serializedBytes += count * (escapedBytes - source.htmlBytes - 2);
4774
- }
4775
- if (serializedBytes > LARGE_OBJECT_LIMITS.decodedBytes)
4776
- throw new RangeError(
4777
- "Complete bundle reconstruction exceeds its serialized byte limit. Use lazy views."
4778
- );
4779
- htmlBySource.set(id, html);
4780
- }
4781
- const bundle = structuredClone(catalog.bundle);
4782
- if (poolInline) {
4783
- if (bundle.schemaVersion === "1.1.0") bundle.schemaVersion = "1.2.0";
4784
- bundle.envelope.schemaVersion = "1.1.0";
4785
- bundle.envelope.sources = catalog.sources.map((source) => ({
4786
- id: source.id,
4787
- kind: "html",
4788
- sha256: source.sha256,
4789
- html: htmlBySource.get(source.id)
4790
- }));
4791
- bundle.envelope.artifacts = bundle.envelope.artifacts.map((view) => ({
4792
- ...view,
4793
- sourceId: catalog.viewSources[view.id]
4794
- }));
4795
- const actualMetadata = {
4796
- ...bundle,
4797
- envelope: {
4798
- ...bundle.envelope,
4799
- sources: bundle.envelope.sources.map(({ html: _html, ...source }) => source)
4800
- }
4801
- };
4802
- const extraMetadata = encoder.encode(canonicalizeJson(actualMetadata)).byteLength - metadataBytes;
4803
- if (serializedBytes + extraMetadata > LARGE_OBJECT_LIMITS.decodedBytes)
4804
- throw new RangeError("Complete pooled reconstruction exceeds its serialized byte limit.");
4805
- return bundle;
4806
- }
4807
- if (bundle.kind === "openplanr-diagram-review-bundle")
4808
- bundle.scene.svg = htmlBySource.get(catalog.viewSources.diagram);
4809
- else if (bundle.envelope.schemaVersion === "1.1.0") {
4810
- for (const source of bundle.envelope.sources) source.html = htmlBySource.get(source.id);
4811
- } else
4812
- for (const view of bundle.envelope.artifacts)
4813
- view.html = htmlBySource.get(catalog.viewSources[view.id]);
4814
- return bundle;
4815
- }
4816
- return {
4817
- catalog: structuredClone(catalog),
4818
- bundle: structuredClone(catalog.bundle),
4819
- reviewOf: catalog.reviewOf,
4820
- loadSource,
4821
- loadView,
4822
- loadBundle,
4823
- assertMatchesBundle: (value) => assertResourceBundleMatchesCatalog(value, catalog),
4824
- dispose
4825
- };
4826
- }
4827
- async function assertResourceBundleMatchesCatalog(bundle, catalog) {
4828
- assertLargeObjectContract(catalog, "resource-catalog");
4829
- const diagram = bundle?.kind === "openplanr-diagram-review-bundle";
4830
- const envelope = diagram ? { schemaVersion: "1.0.0", artifacts: [{ id: "diagram", html: bundle.scene?.svg }] } : bundle?.envelope;
4831
- if (!Array.isArray(envelope?.artifacts))
4832
- throw new TypeError("Saved content differs from resource catalog.");
4833
- const sources = [], viewSources = /* @__PURE__ */ Object.create(null), pages = /* @__PURE__ */ new Map();
4834
- if (envelope.schemaVersion === "1.1.0") {
4835
- if (!Array.isArray(envelope.sources))
4836
- throw new TypeError("Saved content differs from resource catalog.");
4837
- sources.push(...envelope.sources);
4838
- for (const view of envelope.artifacts) viewSources[view.id] = view.sourceId;
4839
- } else
4840
- for (const view of envelope.artifacts) {
4841
- if (typeof view.html !== "string")
4842
- throw new TypeError("Saved content differs from resource catalog.");
4843
- if (!pages.has(view.html)) {
4844
- const id = `source-${sources.length}`;
4845
- pages.set(view.html, id);
4846
- sources.push({ id, html: view.html });
4847
- }
4848
- viewSources[view.id] = pages.get(view.html);
4849
- }
4850
- const withoutHtml = ({ html: _html, ...value }) => value;
4851
- const metadata = diagram ? { ...bundle, scene: { ...bundle.scene, svg: "" } } : {
4852
- ...bundle,
4853
- envelope: {
4854
- ...envelope,
4855
- artifacts: envelope.artifacts.map(withoutHtml),
4856
- ...envelope.schemaVersion === "1.1.0" ? { sources: sources.map(withoutHtml) } : {}
4857
- }
4858
- };
4859
- if (canonicalizeJson(metadata) !== canonicalizeJson(catalog.bundle) || canonicalizeJson(viewSources) !== canonicalizeJson(catalog.viewSources) || sources.length !== catalog.sources.length)
4860
- throw new TypeError("Saved content differs from resource catalog.");
4861
- const saved = new Map(catalog.sources.map((source) => [source.id, source]));
4862
- for (const source of sources) {
4863
- const record = saved.get(source.id);
4864
- if (!record || typeof source.html !== "string")
4865
- throw new TypeError("Saved source differs from resource catalog.");
4866
- const info = utf8SegmentInfo(source.html, record.htmlBytes);
4867
- if (!info.wellFormed || info.bytes !== record.htmlBytes)
4868
- throw new TypeError("Saved source differs from resource catalog.");
4869
- const bytes = encoder.encode(source.html);
4870
- if (await resourceSha256(bytes) !== record.sha256)
4871
- throw new TypeError("Saved source differs from resource catalog.");
4872
- }
4873
- return bundle;
4874
- }
4875
-
4876
- // packages/artifact/lib/artifact/chunked-workspace-client.mjs
4877
- var encoder2 = new TextEncoder();
4878
- var decoder2 = new TextDecoder("utf-8", { fatal: true });
4879
- var preparedChunks = /* @__PURE__ */ new WeakMap();
4880
- async function boundedResponseBytes(response, limit) {
4881
- const declared = response.headers?.get("content-length");
4882
- if (declared !== void 0 && declared !== null && (!/^[0-9]+$/.test(declared) || BigInt(declared) > BigInt(limit))) {
4883
- await response.body?.cancel();
4884
- throw new RangeError("The sharing response declared size exceeds its byte limit.");
4885
- }
4886
- const reader = response.body?.getReader();
4887
- if (!reader) throw new TypeError("The sharing service returned an empty response.");
4888
- const chunks = [];
4889
- let size = 0;
4890
- try {
4891
- for (; ; ) {
4892
- const { done, value } = await reader.read();
4893
- if (done) break;
4894
- size += value.byteLength;
4895
- if (size > limit) {
4896
- await reader.cancel();
4897
- throw new RangeError("The sharing response exceeds its byte limit.");
4898
- }
4899
- chunks.push(value);
4900
- }
4901
- } finally {
4902
- reader.releaseLock();
4903
- }
4904
- const bytes = new Uint8Array(size);
4905
- let offset = 0;
4906
- for (const chunk of chunks) {
4907
- bytes.set(chunk, offset);
4908
- offset += chunk.byteLength;
4909
- }
4910
- return bytes;
4911
- }
4912
- function unsupported() {
4913
- return Object.assign(
4914
- new Error(
4915
- "This sharing service does not support bounded resource uploads. Upgrade the hosted service before sharing this design; your local work is saved."
4916
- ),
4917
- { code: "E_WORKSPACE_TRANSPORT_UNSUPPORTED", status: 426 }
4918
- );
4919
- }
4920
- function uploadChunksFor(custody) {
4921
- const body = custody.pendingCreate ?? (custody.pendingMutation?.action === "publish" ? custody.pendingMutation.body : null);
4922
- return body && preparedChunks.get(body);
4923
- }
4924
- function createChunkedWorkspaceClient({
4925
- legacy,
4926
- domain,
4927
- apiPath,
4928
- assertBundle,
4929
- assertFeedback,
4930
- digestInput = (value) => value,
4931
- digestBundle
4932
- }) {
4933
- const api = apiPath.replace("/api/v1/", "/api/v2/");
4934
- const idPattern = /^[A-Za-z0-9_-]{22,64}$/u;
4935
- const tokenPattern = /^[A-Za-z0-9_-]{43}$/u;
4936
- function validateAccess(access) {
4937
- legacy.normalizeWorkspaceBase(access.baseUrl);
4938
- if (!idPattern.test(access.id)) throw new TypeError("Workspace identity is invalid.");
4939
- }
4940
- async function keyMaterial(token, id, purpose) {
4941
- if (!tokenPattern.test(token) || !idPattern.test(id))
4942
- throw new TypeError("Workspace token is invalid.");
4943
- const imported = await crypto.subtle.importKey(
4944
- "raw",
4945
- decodeResourceBytes(token, 32),
4946
- "HKDF",
4947
- false,
4948
- ["deriveBits"]
4949
- );
4950
- return new Uint8Array(
4951
- await crypto.subtle.deriveBits(
4952
- {
4953
- name: "HKDF",
4954
- hash: "SHA-256",
4955
- salt: encoder2.encode(id),
4956
- info: encoder2.encode(`${domain}/${purpose}`)
4957
- },
4958
- imported,
4959
- 256
4960
- )
4961
- );
4962
- }
4963
- async function seal(value, rawKey, context, limit = 65536) {
4964
- const bytes = encoder2.encode(canonicalizeJson(value));
4965
- if (bytes.byteLength + 16 > limit)
4966
- throw new RangeError("Encrypted metadata exceeds its byte limit.");
4967
- const key = await crypto.subtle.importKey("raw", rawKey, "AES-GCM", false, ["encrypt"]);
4968
- const iv = crypto.getRandomValues(new Uint8Array(12));
4969
- const cipher = await crypto.subtle.encrypt(
4970
- {
4971
- name: "AES-GCM",
4972
- iv,
4973
- additionalData: encoder2.encode(canonicalizeJson(context)),
4974
- tagLength: 128
4975
- },
4976
- key,
4977
- bytes
4978
- );
4979
- return { iv: encodeResourceBytes(iv), ciphertext: encodeResourceBytes(new Uint8Array(cipher)) };
4980
- }
4981
- async function unseal(value, rawKey, context, limit = 65536) {
4982
- const key = await crypto.subtle.importKey("raw", rawKey, "AES-GCM", false, ["decrypt"]);
4983
- const bytes = await crypto.subtle.decrypt(
4984
- {
4985
- name: "AES-GCM",
4986
- iv: decodeResourceBytes(value.iv, 12),
4987
- additionalData: encoder2.encode(canonicalizeJson(context)),
4988
- tagLength: 128
4989
- },
4990
- key,
4991
- decodeResourceBytes(value.ciphertext, limit)
4992
- );
4993
- return JSON.parse(decoder2.decode(bytes));
4994
- }
4995
- async function wrap(custody, token = custody.token, epoch = custody.epoch, keys = custody.keys) {
4996
- return seal(
4997
- { keys, ownerPublicKey: custody.ownerPublicKey },
4998
- await keyMaterial(token, custody.id, "key-wrap"),
4999
- { type: "keyring", workspaceId: custody.id, epoch }
5000
- );
5001
- }
5002
- async function network(url, init, fetchImpl = globalThis.fetch) {
5003
- let response;
5004
- try {
5005
- response = await fetchImpl(url, {
5006
- redirect: "error",
5007
- credentials: "omit",
5008
- cache: "no-store",
5009
- signal: AbortSignal.timeout(2e4),
5010
- ...init
5011
- });
5012
- } catch (cause) {
5013
- throw Object.assign(
5014
- new Error(
5015
- "Sharing was interrupted. Retry the saved operation; its identity and bytes are retained."
5016
- ),
5017
- { code: "E_WORKSPACE_NETWORK", cause }
5018
- );
5019
- }
5020
- if (!response.ok) {
5021
- const error = Object.assign(
5022
- new Error(`Sharing failed (${response.status}). Retry the saved operation.`),
5023
- { status: response.status, code: `E_WORKSPACE_HTTP_${response.status}` }
5024
- );
5025
- try {
5026
- const value = JSON.parse(decoder2.decode(await boundedResponseBytes(response, 4096)));
5027
- if (/^[A-Za-z][A-Za-z0-9_-]{0,127}$/u.test(value.error ?? "")) error.code = value.error;
5028
- } catch {
5029
- }
5030
- const seconds = Number(response.headers.get("retry-after"));
5031
- if (response.status === 429 && Number.isFinite(seconds) && seconds > 0)
5032
- error.retryAfterSeconds = Math.min(3600, Math.ceil(seconds));
5033
- throw error;
5034
- }
5035
- return response;
5036
- }
5037
- async function capabilities({ baseUrl, fetchImpl } = {}) {
5038
- const response = await network(
5039
- `${legacy.normalizeWorkspaceBase(baseUrl)}/.well-known/openplanr-sharing`,
5040
- { method: "GET", headers: { Accept: "application/json" } },
5041
- fetchImpl
5042
- );
5043
- const value = JSON.parse(decoder2.decode(await boundedResponseBytes(response, 65536)));
5044
- if (!Array.isArray(value.workspaceTransports) || !value.workspaceTransports.includes("2"))
5045
- throw unsupported();
5046
- return value;
5047
- }
5048
- async function request(access, suffix = "", { method = "GET", body, binary, limit = 128 * 1024, fetchImpl, signal } = {}) {
5049
- validateAccess(access);
5050
- const auth = access.ownerAuth ?? await legacy.deriveWorkspaceAuthentication(access.token, access.id);
5051
- const headers = {
5052
- Authorization: `Bearer ${auth}`,
5053
- Accept: binary ? "application/octet-stream" : "application/json"
5054
- };
5055
- if (body !== void 0)
5056
- headers["Content-Type"] = binary ? "application/octet-stream" : "application/json";
5057
- const response = await network(
5058
- `${legacy.normalizeWorkspaceBase(access.baseUrl)}${api}/${access.id}${suffix}`,
5059
- {
5060
- method,
5061
- headers,
5062
- body: body === void 0 ? void 0 : binary ? body : canonicalizeJson(body),
5063
- ...signal ? { signal } : {}
5064
- },
5065
- fetchImpl
5066
- );
5067
- if (response.status === 204) return {};
5068
- const bytes = await boundedResponseBytes(response, limit);
5069
- return binary ? bytes : JSON.parse(decoder2.decode(bytes));
5070
- }
5071
- async function prepareUpload(custody, bundle) {
5072
- assertBundle(bundle);
5073
- const reviewOf = digestBundle ? digestBundle(bundle) : legacy.workspaceEnvelopeDigest(digestInput(bundle));
5074
- const encrypted = await encryptResourcePack(await packResourceBundle(bundle, { reviewOf }), {
5075
- workspaceId: custody.id,
5076
- revisionId: legacy.newWorkspaceId(),
5077
- epoch: custody.epoch,
5078
- rawKey: decodeResourceBytes(custody.keys[custody.epoch], 32),
5079
- sign: (value) => legacy.signWorkspaceValue(value, custody.ownerPrivateKey)
5080
- });
5081
- const body = await legacy.signWorkspaceValue(
5082
- {
5083
- schemaVersion: "2.0.0",
5084
- workspaceId: custody.id,
5085
- operationId: legacy.newWorkspaceId(),
5086
- expectedVersion: custody.version,
5087
- epoch: custody.epoch,
5088
- ownerPublicKey: custody.ownerPublicKey,
5089
- ownerAuthHash: sha256Hex(custody.ownerAuth),
5090
- reviewerAuthHash: sha256Hex(
5091
- await legacy.deriveWorkspaceAuthentication(custody.token, custody.id)
5092
- ),
5093
- keyring: custody.keyring,
5094
- manifest: encrypted.manifest
5095
- },
5096
- custody.ownerPrivateKey
5097
- );
5098
- assertLargeObjectContract(body, "encrypted-upload-prepare");
5099
- preparedChunks.set(body, encrypted.chunks);
5100
- return body;
5101
- }
5102
- async function prepareWorkspace(bundle, { baseUrl } = {}) {
5103
- const signer = await legacy.createWorkspaceSigner();
5104
- const custody = {
5105
- schemaVersion: "2.0.0",
5106
- id: legacy.newWorkspaceId(),
5107
- baseUrl: legacy.normalizeWorkspaceBase(baseUrl),
5108
- token: legacy.newWorkspaceToken(),
5109
- ownerAuth: legacy.newWorkspaceToken(),
5110
- ownerPrivateKey: signer.privateKey,
5111
- ownerPublicKey: signer.publicKey,
5112
- epoch: 1,
5113
- keys: { 1: legacy.newWorkspaceToken() },
5114
- version: 0
5115
- };
5116
- custody.keyring = await wrap(custody);
5117
- custody.pendingCreate = await prepareUpload(custody, bundle);
5118
- return custody;
5119
- }
5120
- function verifyReceipt(custody, body, receipt) {
5121
- assertLargeObjectContract(receipt, "encrypted-upload-receipt");
5122
- if (receipt.workspaceId !== custody.id || receipt.operationId !== body.operationId || receipt.revisionId !== body.manifest.revisionId || receipt.manifestSha256 !== sha256Hex(canonicalizeJson(body.manifest)) || receipt.version !== body.expectedVersion + 1)
5123
- throw new TypeError("Publication receipt differs from the saved operation.");
5124
- return receipt;
5125
- }
5126
- async function commitUpload(custody, body, options = {}) {
5127
- if (!options.readChunk)
5128
- throw new Error("Persist the exact upload spool before contacting the sharing service.");
5129
- const readChunk = options.readChunk;
5130
- const status = assertLargeObjectContract(
5131
- await request(custody, `/uploads/${body.operationId}`, { ...options, method: "PUT", body }),
5132
- "encrypted-upload-status"
5133
- );
5134
- const manifestSha256 = sha256Hex(canonicalizeJson(body.manifest));
5135
- if (status.workspaceId !== custody.id || status.operationId !== body.operationId || status.revisionId !== body.manifest.revisionId || status.manifestSha256 !== manifestSha256)
5136
- throw new TypeError("Upload status differs from the saved operation.");
5137
- if (status.status === "committed") return verifyReceipt(custody, body, status.receipt);
5138
- const received = /* @__PURE__ */ new Set();
5139
- for (const part of status.receivedChunks) {
5140
- const expected = body.manifest.chunks[part.index];
5141
- if (!expected || expected.byteLength !== part.byteLength || expected.sha256 !== part.sha256)
5142
- throw new TypeError("Uploaded chunk identity differs.");
5143
- received.add(part.index);
5144
- }
5145
- for (const part of body.manifest.chunks) {
5146
- if (received.has(part.index)) continue;
5147
- const bytes = await readChunk(part.index);
5148
- if (bytes.byteLength !== part.byteLength || await resourceSha256(bytes) !== part.sha256)
5149
- throw new TypeError("Saved upload chunk is corrupt.");
5150
- await request(custody, `/uploads/${body.operationId}/chunks/${part.index}`, {
5151
- ...options,
5152
- method: "PUT",
5153
- body: bytes,
5154
- binary: true,
5155
- limit: 65536
5156
- });
5157
- }
5158
- const commit = await legacy.signWorkspaceValue(
5159
- {
5160
- schemaVersion: "2.0.0",
5161
- workspaceId: custody.id,
5162
- operationId: body.operationId,
5163
- manifestSha256
5164
- },
5165
- custody.ownerPrivateKey
5166
- );
5167
- return verifyReceipt(
5168
- custody,
5169
- body,
5170
- await request(custody, `/uploads/${body.operationId}/commit`, {
5171
- ...options,
5172
- method: "POST",
5173
- body: commit
5174
- })
5175
- );
5176
- }
5177
- async function commitWorkspace(custody, options) {
5178
- if (!custody.pendingCreate) return getWorkspace(custody, options);
5179
- const receipt = await commitUpload(custody, custody.pendingCreate, options);
5180
- custody.version = receipt.version;
5181
- custody.currentRevision = receipt.revisionId;
5182
- delete custody.pendingCreate;
5183
- delete custody.spoolDirectory;
5184
- return receipt;
5185
- }
5186
- async function getWorkspace(access, options) {
5187
- const result = assertLargeObjectContract(
5188
- await request(access, "", options),
5189
- "encrypted-workspace-v2"
5190
- );
5191
- if (result.id !== access.id) throw new TypeError("Workspace identity differs.");
5192
- const ring = await unseal(
5193
- result.keyring,
5194
- await keyMaterial(access.token, access.id, "key-wrap"),
5195
- { type: "keyring", workspaceId: access.id, epoch: result.epoch }
5196
- );
5197
- if (canonicalizeJson(ring.ownerPublicKey) !== canonicalizeJson(result.ownerPublicKey) || access.ownerPublicKey && canonicalizeJson(access.ownerPublicKey) !== canonicalizeJson(result.ownerPublicKey) || !ring.keys?.[result.epoch] || Object.entries(ring.keys).some(
5198
- ([epoch, key]) => !/^[1-9][0-9]*$/u.test(epoch) || !tokenPattern.test(key)
5199
- ))
5200
- throw new TypeError("Workspace key history or owner identity differs.");
5201
- Object.assign(access, result, { keys: ring.keys });
5202
- return result;
5203
- }
5204
- async function openRevision(access, revisionId = access.currentRevision, options = {}) {
5205
- if (!access.keys) await getWorkspace(access, options);
5206
- if (!idPattern.test(revisionId)) throw new TypeError("Revision identity is invalid.");
5207
- const manifest = assertLargeObjectContract(
5208
- await request(access, `/revisions/${revisionId}/manifest`, {
5209
- ...options,
5210
- limit: LARGE_OBJECT_LIMITS.manifestBytes
5211
- }),
5212
- "encrypted-resource-manifest"
5213
- );
5214
- if (manifest.workspaceId !== access.id || manifest.revisionId !== revisionId || !access.keys[manifest.epoch])
5215
- throw new TypeError("Revision identity or key epoch differs.");
5216
- return openResourcePack(manifest, {
5217
- rawKey: decodeResourceBytes(access.keys[manifest.epoch], 32),
5218
- verify: (value) => legacy.verifyWorkspaceSignature(value, access.ownerPublicKey),
5219
- fetchChunk: (index) => request(access, `/revisions/${revisionId}/chunks/${index}`, {
5220
- ...options,
5221
- binary: true,
5222
- limit: LARGE_OBJECT_LIMITS.chunkBytes
5223
- })
5224
- });
5225
- }
5226
- async function decryptWorkspaceRevision(access, revisionId, options) {
5227
- const pack = await openRevision(access, revisionId, options);
5228
- try {
5229
- const bundle = assertBundle(await pack.loadBundle());
5230
- const reviewOf = digestBundle ? digestBundle(bundle) : legacy.workspaceEnvelopeDigest(digestInput(bundle));
5231
- if (pack.reviewOf !== void 0 && pack.reviewOf !== reviewOf)
5232
- throw new TypeError("Full review basis differs from authenticated catalog.");
5233
- return { ...bundle, workspaceRevision: revisionId ?? access.currentRevision, reviewOf };
5234
- } finally {
5235
- pack.dispose();
5236
- }
5237
- }
5238
- async function prepareWorkspaceMutation(custody, action, payload) {
5239
- if (custody.pendingCreate || custody.pendingMutation)
5240
- throw new Error("Retry the pending sharing operation before preparing another.");
5241
- if (action === "publish")
5242
- custody.pendingMutation = { action, body: await prepareUpload(custody, payload), next: {} };
5243
- else {
5244
- let body = {
5245
- operationId: legacy.newWorkspaceId(),
5246
- expectedVersion: custody.version,
5247
- epoch: custody.epoch
5248
- }, next = {};
5249
- if (action === "rotate") {
5250
- const token = legacy.newWorkspaceToken(), epoch = custody.epoch + 1, keys = { ...custody.keys, [epoch]: legacy.newWorkspaceToken() };
5251
- const keyring = await wrap(custody, token, epoch, keys);
5252
- body = {
5253
- ...body,
5254
- epoch,
5255
- reviewerAuthHash: sha256Hex(
5256
- await legacy.deriveWorkspaceAuthentication(token, custody.id)
5257
- ),
5258
- keyring
5259
- };
5260
- next = { token, epoch, keys, keyring };
5261
- } else if (["pause", "resume", "revoke", "delete"].includes(action)) body.action = action;
5262
- else throw new TypeError("Unknown sharing action.");
5263
- custody.pendingMutation = {
5264
- action,
5265
- body: await legacy.signWorkspaceValue(body, custody.ownerPrivateKey),
5266
- next
5267
- };
5268
- }
5269
- return custody.pendingMutation;
5270
- }
5271
- async function commitWorkspaceMutation(custody, options) {
5272
- const pending = custody.pendingMutation;
5273
- if (!pending) throw new Error("No sharing operation is pending.");
5274
- let result;
5275
- if (pending.action === "publish") result = await commitUpload(custody, pending.body, options);
5276
- else {
5277
- result = await request(custody, pending.action === "rotate" ? "/rotate" : "/manage", {
5278
- ...options,
5279
- method: "POST",
5280
- body: pending.body
5281
- });
5282
- if (pending.action === "delete") {
5283
- if (result.id !== custody.id || result.deleted !== true || result.schemaVersion !== "2.0.0" || Object.keys(result).some((key) => !["id", "deleted", "schemaVersion"].includes(key)))
5284
- throw new TypeError("Deletion receipt is invalid.");
5285
- } else {
5286
- assertLargeObjectContract(result, "encrypted-workspace-v2");
5287
- if (["pause", "resume"].includes(pending.action) && result.commentsPaused !== (pending.action === "pause"))
5288
- throw new TypeError("Management state differs.");
5289
- if (result.id !== custody.id || result.version !== pending.body.expectedVersion + 1 || result.epoch !== pending.body.epoch || result.currentRevision !== custody.currentRevision || canonicalizeJson(result.ownerPublicKey) !== canonicalizeJson(custody.ownerPublicKey) || canonicalizeJson(result.keyring) !== canonicalizeJson(pending.next.keyring ?? custody.keyring))
5290
- throw new TypeError("Management receipt is invalid.");
5291
- }
5292
- }
5293
- Object.assign(custody, pending.next, { version: pending.body.expectedVersion + 1 });
5294
- if (pending.action === "publish") {
5295
- custody.currentRevision = result.revisionId;
5296
- delete custody.spoolDirectory;
5297
- }
5298
- if (["pause", "resume"].includes(pending.action))
5299
- custody.commentsPaused = pending.action === "pause";
5300
- if (["revoke", "delete"].includes(pending.action))
5301
- custody.status = pending.action === "revoke" ? "revoked" : "deleted";
5302
- delete custody.pendingMutation;
5303
- return result;
5304
- }
5305
- async function prepareWorkspaceEvent(access, payload, { revisionId = access.currentRevision, reviewOf, signer } = {}) {
5306
- assertFeedback(payload);
5307
- if (!access.keys) throw new Error("Load the workspace before preparing feedback.");
5308
- signer ??= await legacy.createWorkspaceSigner();
5309
- const header = {
5310
- id: legacy.newWorkspaceId(),
5311
- epoch: access.epoch,
5312
- revisionId,
5313
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5314
- authorPublicKey: signer.publicKey
5315
- };
5316
- const context = {
5317
- context: "openplanr.workspace-event.v2",
5318
- workspaceId: access.id,
5319
- id: header.id,
5320
- epoch: header.epoch,
5321
- revisionId
5322
- };
5323
- const event = await legacy.signWorkspaceValue(
5324
- {
5325
- ...header,
5326
- ...await seal(
5327
- { payload, reviewOf: reviewOf ?? payload.reviewOf },
5328
- decodeResourceBytes(access.keys[header.epoch], 32),
5329
- context,
5330
- LARGE_OBJECT_LIMITS.eventBytes
5331
- )
5332
- },
5333
- signer.privateKey
5334
- );
5335
- return assertLargeObjectContract(event, "encrypted-workspace-event-v2");
5336
- }
5337
- async function appendWorkspaceEvent(access, event, options) {
5338
- assertLargeObjectContract(event, "encrypted-workspace-event-v2");
5339
- const result = await request(access, "/events", { ...options, method: "POST", body: event });
5340
- if (result.id !== event.id || !Number.isSafeInteger(result.sequence) || result.sequence < 1)
5341
- throw new TypeError("Feedback receipt differs.");
5342
- return result;
5343
- }
5344
- async function readWorkspaceEvents(access, { after = 0, ...options } = {}) {
5345
- if (!Number.isSafeInteger(after) || after < 0) throw new TypeError("Invalid feedback cursor.");
5346
- if (!access.keys) await getWorkspace(access, options);
5347
- const page = await request(access, `/events?after=${after}`, {
5348
- ...options,
5349
- limit: LARGE_OBJECT_LIMITS.eventPageBytes
5350
- });
5351
- if (!Array.isArray(page.events) || page.events.length > LARGE_OBJECT_LIMITS.eventPageCount || !Number.isSafeInteger(page.cursor) || page.cursor < after || page.hasMore && page.cursor === after || typeof page.hasMore !== "boolean")
5352
- throw new TypeError("Feedback page is invalid.");
5353
- const events = [], issues = [];
5354
- let previous = after;
5355
- for (const entry of page.events) {
5356
- try {
5357
- const { sequence, ...event } = entry;
5358
- if (!Number.isSafeInteger(sequence) || sequence <= previous || sequence > page.cursor)
5359
- throw new TypeError("Feedback sequence is invalid.");
5360
- previous = sequence;
5361
- assertLargeObjectContract(event, "encrypted-workspace-event-v2");
5362
- if (!await legacy.verifyWorkspaceSignature(event, event.authorPublicKey) || !access.keys[event.epoch])
5363
- throw new TypeError("Feedback signature or key epoch is invalid.");
5364
- const value = await unseal(
5365
- event,
5366
- decodeResourceBytes(access.keys[event.epoch], 32),
5367
- {
5368
- context: "openplanr.workspace-event.v2",
5369
- workspaceId: access.id,
5370
- id: event.id,
5371
- epoch: event.epoch,
5372
- revisionId: event.revisionId
5373
- },
5374
- LARGE_OBJECT_LIMITS.eventBytes
5375
- );
5376
- assertFeedback(value.payload);
5377
- if (value.payload.reviewOf !== void 0 && value.payload.reviewOf !== value.reviewOf)
5378
- throw new TypeError("Feedback payload identity differs.");
5379
- if (!/^[a-f0-9]{64}$/u.test(value.reviewOf ?? ""))
5380
- throw new TypeError("Feedback review identity is invalid.");
5381
- events.push({
5382
- ...event,
5383
- publicKey: event.authorPublicKey,
5384
- sequence,
5385
- reviewOf: value.reviewOf,
5386
- payload: value.payload
5387
- });
5388
- } catch (error) {
5389
- issues.push({ id: entry.id, sequence: entry.sequence, reason: error.message });
5390
- }
5391
- }
5392
- return { ...page, events, issues };
5393
- }
5394
- return {
5395
- capabilities,
5396
- prepareWorkspace,
5397
- commitWorkspace,
5398
- getWorkspace,
5399
- openRevision,
5400
- decryptWorkspaceRevision,
5401
- listWorkspaceRevisions: (access, options) => request(access, "/revisions", options),
5402
- prepareWorkspaceMutation,
5403
- commitWorkspaceMutation,
5404
- prepareWorkspaceEvent,
5405
- appendWorkspaceEvent,
5406
- readWorkspaceEvents
5407
- };
5408
- }
5409
-
5410
- // packages/artifact/lib/artifact/owner-custody.mjs
5411
- import { randomBytes } from "node:crypto";
5412
- import {
5413
- chmodSync,
5414
- closeSync,
5415
- existsSync,
5416
- fsyncSync,
5417
- linkSync,
5418
- lstatSync,
5419
- mkdirSync,
5420
- openSync,
5421
- readFileSync,
5422
- realpathSync,
5423
- renameSync,
5424
- unlinkSync,
5425
- writeFileSync
5426
- } from "node:fs";
5427
- import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
5428
- function custodyError(message, code = "E_OWNER_CUSTODY_LOCATION") {
5429
- return Object.assign(new Error(message), { code, status: 400 });
5430
- }
5431
- function pathExists(path) {
5432
- try {
5433
- lstatSync(path);
5434
- return true;
5435
- } catch (error) {
5436
- if (error.code === "ENOENT") return false;
5437
- throw error;
5438
- }
5439
- }
5440
- function assertDirectoryAncestry(root, label) {
5441
- for (let path = root; dirname(path) !== path; path = dirname(path)) {
5442
- if (pathExists(path) && lstatSync(path).isSymbolicLink())
5443
- throw custodyError(`${label} custody directory must not contain symbolic links.`);
5444
- }
5445
- }
5446
- function assertPrivateFile(path, label) {
5447
- const stat = lstatSync(path);
5448
- if (!stat.isFile() || stat.isSymbolicLink() || process.platform !== "win32" && (stat.mode & 63 || stat.uid !== process.getuid()))
5449
- throw custodyError(
5450
- `${label} owner custody must be a private 0600 file.`,
5451
- "E_OWNER_CUSTODY_INVALID"
5452
- );
5453
- }
5454
- function physicalDirectoryPath(directory) {
5455
- let existing = resolve(directory);
5456
- const missing = [];
5457
- while (!existsSync(existing) && dirname(existing) !== existing) {
5458
- missing.unshift(basename(existing));
5459
- existing = dirname(existing);
5460
- }
5461
- return join(realpathSync(existing), ...missing);
5462
- }
5463
- function assertPrivateDirectory(root, label, recoveryOutput = false) {
5464
- const stat = lstatSync(root);
5465
- if (!stat.isDirectory() || stat.isSymbolicLink() || !recoveryOutput && process.platform !== "win32" && (stat.mode & 63 || stat.uid !== process.getuid()))
5466
- throw custodyError(`${label} custody must use a private local directory.`);
5467
- }
5468
- function ensurePrivateDirectory(root, { label = "Owner", recoveryOutput = false } = {}) {
5469
- if (recoveryOutput) root = physicalDirectoryPath(root);
5470
- assertDirectoryAncestry(root, label);
5471
- mkdirSync(root, { recursive: true, mode: 448 });
5472
- assertPrivateDirectory(root, label, recoveryOutput);
5473
- }
5474
- function readCustody(path, { label = "Owner", format, recoveryInput = false } = {}) {
5475
- if (recoveryInput && existsSync(path)) {
5476
- assertPrivateFile(path, label);
5477
- path = realpathSync(path);
5478
- }
5479
- assertDirectoryAncestry(dirname(path), label);
5480
- if (!pathExists(path)) return null;
5481
- assertPrivateDirectory(dirname(path), label, recoveryInput);
5482
- assertPrivateFile(path, label);
5483
- let record;
5484
- try {
5485
- record = JSON.parse(readFileSync(path, "utf8"));
5486
- } catch {
5487
- throw custodyError(`${label} owner custody is invalid.`, "E_OWNER_CUSTODY_INVALID");
5488
- }
5489
- if (record?.kind !== format || record.schemaVersion !== "1.0.0" || !record.custody)
5490
- throw custodyError(`${label} owner custody is invalid.`, "E_OWNER_CUSTODY_INVALID");
5491
- return record;
5492
- }
5493
- function writeCustody(path, record, { label = "Owner" } = {}) {
5494
- assertDirectoryAncestry(dirname(path), label);
5495
- assertPrivateDirectory(dirname(path), label);
5496
- if (existsSync(path)) assertPrivateFile(path, label);
5497
- const temp = `${path}.${randomBytes(8).toString("hex")}.tmp`;
5498
- const fd = openSync(temp, "wx", 384);
5499
- try {
5500
- writeFileSync(fd, `${JSON.stringify(record)}
5501
- `);
5502
- fsyncSync(fd);
5503
- } finally {
5504
- closeSync(fd);
5505
- }
5506
- try {
5507
- renameSync(temp, path);
5508
- if (process.platform !== "win32") {
5509
- chmodSync(path, 384);
5510
- const directory = openSync(dirname(path), "r");
5511
- try {
5512
- fsyncSync(directory);
5513
- } finally {
5514
- closeSync(directory);
5515
- }
5516
- }
5517
- } catch (error) {
5518
- try {
5519
- unlinkSync(temp);
5520
- } catch {
5521
- }
5522
- throw error;
5523
- }
5524
- }
5525
-
5526
- // packages/artifact/lib/artifact/upload-spool.mjs
5527
- function privateRead(path, limit) {
5528
- const fd = openSync2(path, constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
5529
- try {
5530
- const stat = fstatSync(fd);
5531
- if (!stat.isFile() || stat.isSymbolicLink() || stat.size > limit || process.platform !== "win32" && (stat.mode & 63 || stat.uid !== process.getuid()))
5532
- throw new TypeError("Upload spool must contain bounded private regular files.");
5533
- const bytes = new Uint8Array(Math.min(limit + 1, stat.size + 1));
5534
- let size = 0;
5535
- while (size < bytes.byteLength) {
5536
- const count = readSync(fd, bytes, size, bytes.byteLength - size, null);
5537
- if (!count) break;
5538
- size += count;
5539
- }
5540
- const after = fstatSync(fd);
5541
- if (size !== stat.size || after.size !== stat.size || after.mtimeMs !== stat.mtimeMs || after.ctimeMs !== stat.ctimeMs) {
5542
- throw new TypeError("Upload spool changed during its bounded private read.");
5543
- }
5544
- return bytes.subarray(0, size);
5545
- } finally {
5546
- closeSync2(fd);
5547
- }
5548
- }
5549
- function writePrivate(path, bytes) {
5550
- const fd = openSync2(
5551
- path,
5552
- constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | (constants2.O_NOFOLLOW ?? 0),
5553
- 384
5554
- );
5555
- try {
5556
- writeFileSync2(fd, bytes);
5557
- fsyncSync2(fd);
5558
- } finally {
5559
- closeSync2(fd);
5560
- }
5561
- }
5562
- function readPreparedUploadRequest(directory) {
5563
- directory = resolve2(directory);
5564
- try {
5565
- lstatSync2(directory);
5566
- } catch (cause) {
5567
- const error = new TypeError("Prepared upload spool is missing or inaccessible.");
5568
- if (cause?.code === "ENOENT") error.code = "ENOENT";
5569
- throw error;
5570
- }
5571
- ensurePrivateDirectory(directory, { label: "Upload" });
5572
- try {
5573
- const body = JSON.parse(
5574
- new TextDecoder("utf-8", { fatal: true }).decode(
5575
- privateRead(join2(directory, "request.json"), 256 * 1024)
5576
- )
5577
- );
5578
- return assertLargeObjectContract(
5579
- body,
5580
- body?.manifest?.kind === "openplanr-company-resource-manifest" ? "company-resource-upload-prepare" : "encrypted-upload-prepare"
5581
- );
5582
- } catch (cause) {
5583
- const error = new TypeError("Prepared upload request is invalid or inaccessible.");
5584
- if (cause?.code === "ENOENT") error.code = "ENOENT";
5585
- throw error;
5586
- }
5587
- }
5588
- function spoolChunkReader(directory, body) {
5589
- assertLargeObjectContract(
5590
- body,
5591
- body?.manifest?.kind === "openplanr-company-resource-manifest" ? "company-resource-upload-prepare" : "encrypted-upload-prepare"
5592
- );
5593
- directory = resolve2(directory);
5594
- ensurePrivateDirectory(directory, { label: "Upload" });
5595
- const saved = readPreparedUploadRequest(directory);
5596
- if (canonicalizeJson(saved) !== canonicalizeJson(body))
5597
- throw new TypeError("Upload spool request differs from owner custody.");
5598
- return async (index) => {
5599
- const expected = body.manifest.chunks[index];
5600
- if (!expected || expected.index !== index) throw new TypeError("Invalid spool chunk index.");
5601
- const bytes = privateRead(join2(directory, `${index}.bin`), expected.byteLength);
5602
- if (bytes.byteLength !== expected.byteLength || await resourceSha256(bytes) !== expected.sha256)
5603
- throw new TypeError("Upload spool chunk is corrupt.");
5604
- return bytes;
5605
- };
5606
- }
5607
- var preparedUploadChunkReader = spoolChunkReader;
5608
- async function persistPreparedUploadSpool(body, chunks, directory) {
5609
- assertLargeObjectContract(
5610
- body,
5611
- body?.manifest?.kind === "openplanr-company-resource-manifest" ? "company-resource-upload-prepare" : "encrypted-upload-prepare"
5612
- );
5613
- if (!Array.isArray(chunks) || chunks.length !== body.manifest.chunks.length)
5614
- throw new TypeError("Prepared upload chunk count differs.");
5615
- directory = resolve2(directory);
5616
- ensurePrivateDirectory(directory, { label: "Upload" });
5617
- for (const part of body.manifest.chunks) {
5618
- const path2 = join2(directory, `${part.index}.bin`), bytes = chunks[part.index];
5619
- if (!(bytes instanceof Uint8Array) || bytes.byteLength !== part.byteLength || await resourceSha256(bytes) !== part.sha256)
5620
- throw new TypeError("Prepared upload bytes differ.");
5621
- if (existsSync2(path2)) {
5622
- const existing = privateRead(path2, part.byteLength);
5623
- if (existing.byteLength !== part.byteLength || await resourceSha256(existing) !== part.sha256)
5624
- throw new TypeError("Existing upload spool will not be overwritten.");
5625
- } else writePrivate(path2, bytes);
5626
- }
5627
- const path = join2(directory, "request.json"), serialized = canonicalizeJson(body);
5628
- if (existsSync2(path)) {
5629
- if (new TextDecoder("utf-8", { fatal: true }).decode(privateRead(path, 256 * 1024)) !== serialized)
5630
- throw new TypeError("Existing spool request will not be overwritten.");
5631
- } else writePrivate(path, new TextEncoder().encode(serialized));
5632
- for (const ancestor of [directory, dirname2(directory)]) {
5633
- const fd = openSync2(ancestor, "r");
5634
- try {
5635
- fsyncSync2(fd);
5636
- } finally {
5637
- closeSync2(fd);
5638
- }
5639
- }
5640
- return directory;
5641
- }
5642
- async function persistUploadSpool(custody, root) {
5643
- const body = custody.pendingCreate ?? (custody.pendingMutation?.action === "publish" ? custody.pendingMutation.body : null);
5644
- if (!body) return;
5645
- if (custody.spoolDirectory) {
5646
- const reader = spoolChunkReader(custody.spoolDirectory, body);
5647
- for (const part of body.manifest.chunks) await reader(part.index);
5648
- return custody.spoolDirectory;
5649
- }
5650
- const chunks = uploadChunksFor(custody);
5651
- if (!chunks)
5652
- throw new TypeError("The pending upload has no durable spool; restore its recovery package.");
5653
- const directory = await persistPreparedUploadSpool(
5654
- body,
5655
- chunks,
5656
- join2(resolve2(root), custody.id, body.operationId)
5657
- );
5658
- for (let ancestor = dirname2(directory); ; ancestor = dirname2(ancestor)) {
5659
- const fd = openSync2(ancestor, "r");
5660
- try {
5661
- fsyncSync2(fd);
5662
- } finally {
5663
- closeSync2(fd);
5664
- }
5665
- if (ancestor === dirname2(resolve2(root))) break;
5666
- }
5667
- custody.spoolDirectory = directory;
5668
- return directory;
5669
- }
5670
- async function copyUploadSpool(custody, destination) {
5671
- const body = custody.pendingCreate ?? (custody.pendingMutation?.action === "publish" ? custody.pendingMutation.body : null);
5672
- if (!body) return null;
5673
- if (existsSync2(destination)) throw new TypeError("Recovery upload directory already exists.");
5674
- const reader = spoolChunkReader(custody.spoolDirectory, body);
5675
- ensurePrivateDirectory(destination, { label: "Recovery upload" });
5676
- for (const part of body.manifest.chunks)
5677
- writePrivate(join2(destination, `${part.index}.bin`), await reader(part.index));
5678
- writePrivate(join2(destination, "request.json"), new TextEncoder().encode(canonicalizeJson(body)));
5679
- const fd = openSync2(destination, "r");
5680
- try {
5681
- fsyncSync2(fd);
5682
- } finally {
5683
- closeSync2(fd);
5684
- }
5685
- return destination;
5686
- }
5687
-
5688
4177
  export {
5689
- ensurePrivateDirectory,
5690
- readCustody,
5691
- writeCustody,
5692
- createChunkedWorkspaceClient,
5693
- readPreparedUploadRequest,
5694
- spoolChunkReader,
5695
- preparedUploadChunkReader,
5696
- persistPreparedUploadSpool,
5697
- persistUploadSpool,
5698
- copyUploadSpool
4178
+ deflateRaw_1,
4179
+ Inflate_1
5699
4180
  };