opendevbrowser 0.0.16 → 0.0.17

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 (210) hide show
  1. package/README.md +51 -27
  2. package/dist/browser/annotation-manager.d.ts +3 -0
  3. package/dist/browser/annotation-manager.d.ts.map +1 -1
  4. package/dist/browser/browser-manager.d.ts +6 -1
  5. package/dist/browser/browser-manager.d.ts.map +1 -1
  6. package/dist/browser/canvas-client.d.ts +53 -0
  7. package/dist/browser/canvas-client.d.ts.map +1 -0
  8. package/dist/browser/canvas-code-sync-manager.d.ts +79 -0
  9. package/dist/browser/canvas-code-sync-manager.d.ts.map +1 -0
  10. package/dist/browser/canvas-manager.d.ts +94 -0
  11. package/dist/browser/canvas-manager.d.ts.map +1 -0
  12. package/dist/browser/canvas-runtime-preview-bridge.d.ts +20 -0
  13. package/dist/browser/canvas-runtime-preview-bridge.d.ts.map +1 -0
  14. package/dist/browser/canvas-session-sync-manager.d.ts +21 -0
  15. package/dist/browser/canvas-session-sync-manager.d.ts.map +1 -0
  16. package/dist/browser/manager-types.d.ts +13 -1
  17. package/dist/browser/manager-types.d.ts.map +1 -1
  18. package/dist/browser/ops-browser-manager.d.ts +11 -1
  19. package/dist/browser/ops-browser-manager.d.ts.map +1 -1
  20. package/dist/canvas/code-sync/apply-tsx.d.ts +23 -0
  21. package/dist/canvas/code-sync/apply-tsx.d.ts.map +1 -0
  22. package/dist/canvas/code-sync/graph.d.ts +5 -0
  23. package/dist/canvas/code-sync/graph.d.ts.map +1 -0
  24. package/dist/canvas/code-sync/hash.d.ts +3 -0
  25. package/dist/canvas/code-sync/hash.d.ts.map +1 -0
  26. package/dist/canvas/code-sync/import.d.ts +18 -0
  27. package/dist/canvas/code-sync/import.d.ts.map +1 -0
  28. package/dist/canvas/code-sync/manifest.d.ts +5 -0
  29. package/dist/canvas/code-sync/manifest.d.ts.map +1 -0
  30. package/dist/canvas/code-sync/tsx-adapter.d.ts +8 -0
  31. package/dist/canvas/code-sync/tsx-adapter.d.ts.map +1 -0
  32. package/dist/canvas/code-sync/types.d.ts +152 -0
  33. package/dist/canvas/code-sync/types.d.ts.map +1 -0
  34. package/dist/canvas/code-sync/write.d.ts +9 -0
  35. package/dist/canvas/code-sync/write.d.ts.map +1 -0
  36. package/dist/canvas/document-store.d.ts +81 -0
  37. package/dist/canvas/document-store.d.ts.map +1 -0
  38. package/dist/canvas/export.d.ts +12 -0
  39. package/dist/canvas/export.d.ts.map +1 -0
  40. package/dist/canvas/repo-store.d.ts +10 -0
  41. package/dist/canvas/repo-store.d.ts.map +1 -0
  42. package/dist/canvas/surface-palette.d.ts +15 -0
  43. package/dist/canvas/surface-palette.d.ts.map +1 -0
  44. package/dist/canvas/types.d.ts +255 -0
  45. package/dist/canvas/types.d.ts.map +1 -0
  46. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js +7 -0
  47. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js.map +1 -0
  48. package/dist/{chunk-ST7CO5FA.js → chunk-5J3IFL3X.js} +11577 -13539
  49. package/dist/chunk-5J3IFL3X.js.map +1 -0
  50. package/dist/chunk-D633UO34.js +8149 -0
  51. package/dist/chunk-D633UO34.js.map +1 -0
  52. package/dist/{chunk-7W3SPXIB.js → chunk-FUSXMW3G.js} +4 -1
  53. package/dist/chunk-TBUCZX4A.js +34 -0
  54. package/dist/chunk-TBUCZX4A.js.map +1 -0
  55. package/dist/chunk-V7KUDHDG.js +276 -0
  56. package/dist/chunk-V7KUDHDG.js.map +1 -0
  57. package/dist/chunk-Y2KL55OG.js +59 -0
  58. package/dist/chunk-Y2KL55OG.js.map +1 -0
  59. package/dist/cli/args.d.ts +3 -3
  60. package/dist/cli/args.d.ts.map +1 -1
  61. package/dist/cli/commands/annotate.d.ts +11 -0
  62. package/dist/cli/commands/annotate.d.ts.map +1 -1
  63. package/dist/cli/commands/canvas.d.ts +45 -0
  64. package/dist/cli/commands/canvas.d.ts.map +1 -0
  65. package/dist/cli/commands/devtools/perf.d.ts.map +1 -1
  66. package/dist/cli/commands/devtools/screenshot.d.ts +1 -0
  67. package/dist/cli/commands/devtools/screenshot.d.ts.map +1 -1
  68. package/dist/cli/commands/dom/attr.d.ts.map +1 -1
  69. package/dist/cli/commands/dom/checked.d.ts.map +1 -1
  70. package/dist/cli/commands/dom/enabled.d.ts.map +1 -1
  71. package/dist/cli/commands/dom/html.d.ts.map +1 -1
  72. package/dist/cli/commands/dom/text.d.ts.map +1 -1
  73. package/dist/cli/commands/dom/value.d.ts.map +1 -1
  74. package/dist/cli/commands/dom/visible.d.ts.map +1 -1
  75. package/dist/cli/commands/export/clone-component.d.ts +9 -0
  76. package/dist/cli/commands/export/clone-component.d.ts.map +1 -1
  77. package/dist/cli/commands/export/clone-page.d.ts +8 -0
  78. package/dist/cli/commands/export/clone-page.d.ts.map +1 -1
  79. package/dist/cli/commands/interact/check.d.ts.map +1 -1
  80. package/dist/cli/commands/interact/click.d.ts.map +1 -1
  81. package/dist/cli/commands/interact/hover.d.ts.map +1 -1
  82. package/dist/cli/commands/interact/press.d.ts.map +1 -1
  83. package/dist/cli/commands/interact/scroll-into-view.d.ts.map +1 -1
  84. package/dist/cli/commands/interact/scroll.d.ts.map +1 -1
  85. package/dist/cli/commands/interact/select.d.ts.map +1 -1
  86. package/dist/cli/commands/interact/type.d.ts.map +1 -1
  87. package/dist/cli/commands/interact/uncheck.d.ts.map +1 -1
  88. package/dist/cli/commands/native.d.ts +12 -1
  89. package/dist/cli/commands/native.d.ts.map +1 -1
  90. package/dist/cli/commands/nav/goto.d.ts.map +1 -1
  91. package/dist/cli/commands/nav/snapshot.d.ts.map +1 -1
  92. package/dist/cli/commands/nav/wait.d.ts.map +1 -1
  93. package/dist/cli/commands/serve.d.ts +5 -0
  94. package/dist/cli/commands/serve.d.ts.map +1 -1
  95. package/dist/cli/commands/session/connect.d.ts.map +1 -1
  96. package/dist/cli/commands/status.d.ts +5 -0
  97. package/dist/cli/commands/status.d.ts.map +1 -1
  98. package/dist/cli/daemon-commands.d.ts.map +1 -1
  99. package/dist/cli/help.d.ts +5 -0
  100. package/dist/cli/help.d.ts.map +1 -1
  101. package/dist/cli/index.js +724 -163
  102. package/dist/cli/index.js.map +1 -1
  103. package/dist/cli/remote-canvas-manager.d.ts +8 -0
  104. package/dist/cli/remote-canvas-manager.d.ts.map +1 -0
  105. package/dist/cli/remote-manager.d.ts +3 -1
  106. package/dist/cli/remote-manager.d.ts.map +1 -1
  107. package/dist/cli/remote-relay.d.ts +2 -0
  108. package/dist/cli/remote-relay.d.ts.map +1 -1
  109. package/dist/cli/utils/parse.d.ts +1 -0
  110. package/dist/cli/utils/parse.d.ts.map +1 -1
  111. package/dist/core/bootstrap.d.ts.map +1 -1
  112. package/dist/core/types.d.ts +2 -0
  113. package/dist/core/types.d.ts.map +1 -1
  114. package/dist/fs-UMRKOBNN.js +7 -0
  115. package/dist/fs-UMRKOBNN.js.map +1 -0
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +192 -67
  118. package/dist/index.js.map +1 -1
  119. package/dist/{macros-NUBRM44Y.js → macros-ND2M7LWU.js} +2 -2
  120. package/dist/opendevbrowser.d.ts.map +1 -1
  121. package/dist/opendevbrowser.js +192 -67
  122. package/dist/opendevbrowser.js.map +1 -1
  123. package/dist/providers/index.d.ts.map +1 -1
  124. package/dist/providers/shopping/index.d.ts.map +1 -1
  125. package/dist/providers-G3LRHQXX.js +121 -0
  126. package/dist/providers-G3LRHQXX.js.map +1 -0
  127. package/dist/relay/protocol.d.ts +85 -3
  128. package/dist/relay/protocol.d.ts.map +1 -1
  129. package/dist/relay/relay-server.d.ts +14 -1
  130. package/dist/relay/relay-server.d.ts.map +1 -1
  131. package/dist/relay/relay-types.d.ts +3 -0
  132. package/dist/relay/relay-types.d.ts.map +1 -1
  133. package/dist/runtime-factory-BICHDPE7.js +13 -0
  134. package/dist/runtime-factory-BICHDPE7.js.map +1 -0
  135. package/dist/tools/annotate.d.ts.map +1 -1
  136. package/dist/tools/canvas.d.ts +4 -0
  137. package/dist/tools/canvas.d.ts.map +1 -0
  138. package/dist/tools/check.d.ts.map +1 -1
  139. package/dist/tools/click.d.ts.map +1 -1
  140. package/dist/tools/clone_component.d.ts.map +1 -1
  141. package/dist/tools/clone_page.d.ts.map +1 -1
  142. package/dist/tools/connect.d.ts.map +1 -1
  143. package/dist/tools/deps.d.ts +2 -0
  144. package/dist/tools/deps.d.ts.map +1 -1
  145. package/dist/tools/dom_get_html.d.ts.map +1 -1
  146. package/dist/tools/dom_get_text.d.ts.map +1 -1
  147. package/dist/tools/get_attr.d.ts.map +1 -1
  148. package/dist/tools/get_value.d.ts.map +1 -1
  149. package/dist/tools/goto.d.ts.map +1 -1
  150. package/dist/tools/hover.d.ts.map +1 -1
  151. package/dist/tools/index.d.ts.map +1 -1
  152. package/dist/tools/is_checked.d.ts.map +1 -1
  153. package/dist/tools/is_enabled.d.ts.map +1 -1
  154. package/dist/tools/is_visible.d.ts.map +1 -1
  155. package/dist/tools/launch.d.ts.map +1 -1
  156. package/dist/tools/macro_resolve.d.ts.map +1 -1
  157. package/dist/tools/perf.d.ts.map +1 -1
  158. package/dist/tools/press.d.ts.map +1 -1
  159. package/dist/tools/product_video_run.d.ts.map +1 -1
  160. package/dist/tools/research_run.d.ts.map +1 -1
  161. package/dist/tools/response.d.ts +4 -1
  162. package/dist/tools/response.d.ts.map +1 -1
  163. package/dist/tools/screenshot.d.ts.map +1 -1
  164. package/dist/tools/scroll.d.ts.map +1 -1
  165. package/dist/tools/scroll_into_view.d.ts.map +1 -1
  166. package/dist/tools/select.d.ts.map +1 -1
  167. package/dist/tools/shopping_run.d.ts.map +1 -1
  168. package/dist/tools/snapshot.d.ts.map +1 -1
  169. package/dist/tools/type.d.ts.map +1 -1
  170. package/dist/tools/uncheck.d.ts.map +1 -1
  171. package/dist/tools/wait.d.ts.map +1 -1
  172. package/dist/tools/workflow-runtime.d.ts +1 -2
  173. package/dist/tools/workflow-runtime.d.ts.map +1 -1
  174. package/extension/canvas.html +636 -0
  175. package/extension/dist/annotate-content.css +15 -6
  176. package/extension/dist/annotate-content.js +119 -9
  177. package/extension/dist/annotation-payload.js +163 -0
  178. package/extension/dist/background.js +148 -18
  179. package/extension/dist/canvas/canvas-runtime.js +1061 -0
  180. package/extension/dist/canvas/model.js +213 -0
  181. package/extension/dist/canvas/viewport-fit.js +67 -0
  182. package/extension/dist/canvas-page.js +1801 -0
  183. package/extension/dist/ops/dom-bridge.js +116 -3
  184. package/extension/dist/ops/ops-runtime.js +508 -44
  185. package/extension/dist/ops/ops-session-store.js +21 -114
  186. package/extension/dist/ops/target-session-coordinator.js +157 -0
  187. package/extension/dist/popup.js +155 -31
  188. package/extension/dist/services/ConnectionManager.js +17 -0
  189. package/extension/dist/services/RelayClient.js +9 -0
  190. package/extension/dist/services/TabManager.js +35 -12
  191. package/extension/dist/types.js +2 -0
  192. package/extension/manifest.json +1 -1
  193. package/extension/popup.html +52 -0
  194. package/package.json +6 -4
  195. package/skills/AGENTS.md +5 -2
  196. package/skills/opendevbrowser-best-practices/SKILL.md +71 -3
  197. package/skills/opendevbrowser-best-practices/artifacts/canvas-governance-playbook.md +141 -0
  198. package/skills/opendevbrowser-best-practices/artifacts/command-channel-reference.md +113 -17
  199. package/skills/opendevbrowser-best-practices/assets/templates/canvas-blocker-checklist.json +70 -0
  200. package/skills/opendevbrowser-best-practices/assets/templates/canvas-feedback-eval.json +73 -0
  201. package/skills/opendevbrowser-best-practices/assets/templates/canvas-generation-plan.v1.json +67 -0
  202. package/skills/opendevbrowser-best-practices/assets/templates/canvas-handshake-example.json +126 -0
  203. package/skills/opendevbrowser-best-practices/assets/templates/robustness-checklist.json +57 -0
  204. package/skills/opendevbrowser-best-practices/assets/templates/surface-audit-checklist.json +7 -3
  205. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +26 -0
  206. package/skills/opendevbrowser-best-practices/scripts/run-robustness-audit.sh +82 -1
  207. package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +225 -84
  208. package/dist/chunk-ST7CO5FA.js.map +0 -1
  209. /package/dist/{chunk-7W3SPXIB.js.map → chunk-FUSXMW3G.js.map} +0 -0
  210. /package/dist/{macros-NUBRM44Y.js.map → macros-ND2M7LWU.js.map} +0 -0
@@ -0,0 +1,213 @@
1
+ const CODE_SYNC_STATES = new Set([
2
+ "idle",
3
+ "session_join_pending",
4
+ "pull_pending",
5
+ "push_pending",
6
+ "in_sync",
7
+ "drift_detected",
8
+ "conflict",
9
+ "unsupported",
10
+ "lease_lost",
11
+ "projection_fallback"
12
+ ]);
13
+ const CODE_SYNC_DRIFT_STATES = new Set([
14
+ "clean",
15
+ "source_changed",
16
+ "document_changed",
17
+ "conflict"
18
+ ]);
19
+ const CODE_SYNC_WATCH_STATES = new Set(["idle", "watching", "stopped"]);
20
+ const CODE_SYNC_PROJECTIONS = new Set(["canvas_html", "bound_app_runtime"]);
21
+ const CODE_SYNC_FALLBACK_REASONS = new Set([
22
+ "runtime_bridge_unavailable",
23
+ "runtime_projection_unsupported",
24
+ "runtime_projection_failed",
25
+ "runtime_instrumentation_missing",
26
+ "fallback_canvas_html"
27
+ ]);
28
+ const ATTACHED_CLIENT_ROLES = new Set(["lease_holder", "observer"]);
29
+ export function normalizeCanvasSessionSummary(value) {
30
+ const summary = isRecord(value) ? { ...value } : {};
31
+ return {
32
+ ...summary,
33
+ canvasSessionId: optionalString(summary.canvasSessionId) ?? undefined,
34
+ mode: optionalString(summary.mode) ?? undefined,
35
+ planStatus: optionalString(summary.planStatus) ?? undefined,
36
+ preflightState: optionalString(summary.preflightState) ?? undefined,
37
+ libraryPolicy: isRecord(summary.libraryPolicy) ? summary.libraryPolicy : undefined,
38
+ componentInventoryCount: optionalNumber(summary.componentInventoryCount) ?? undefined,
39
+ componentSourceKinds: readStringArray(summary.componentSourceKinds),
40
+ attachedClients: Array.isArray(summary.attachedClients)
41
+ ? summary.attachedClients.flatMap((entry) => normalizeAttachedClient(entry))
42
+ : [],
43
+ leaseHolderClientId: optionalString(summary.leaseHolderClientId),
44
+ watchState: isCodeSyncWatchState(summary.watchState) ? summary.watchState : undefined,
45
+ codeSyncState: isCodeSyncState(summary.codeSyncState) ? summary.codeSyncState : undefined,
46
+ boundFiles: readStringArray(summary.boundFiles),
47
+ conflictCount: optionalNumber(summary.conflictCount) ?? undefined,
48
+ driftState: isCodeSyncDriftState(summary.driftState) ? summary.driftState : undefined,
49
+ lastImportAt: optionalString(summary.lastImportAt) ?? undefined,
50
+ lastPushAt: optionalString(summary.lastPushAt) ?? undefined,
51
+ bindings: Array.isArray(summary.bindings)
52
+ ? summary.bindings.flatMap((entry) => normalizeCodeSyncBindingStatus(entry))
53
+ : []
54
+ };
55
+ }
56
+ export function normalizeCanvasTargetStateSummaries(value) {
57
+ if (!Array.isArray(value)) {
58
+ return [];
59
+ }
60
+ return value.flatMap((entry) => {
61
+ if (!isRecord(entry)) {
62
+ return [];
63
+ }
64
+ const targetId = optionalString(entry.targetId);
65
+ const previewMode = normalizePreviewState(entry.previewMode);
66
+ const previewState = normalizePreviewState(entry.previewState);
67
+ if (!targetId || !previewMode || !previewState) {
68
+ return [];
69
+ }
70
+ return [{
71
+ targetId,
72
+ prototypeId: optionalString(entry.prototypeId),
73
+ previewMode,
74
+ previewState,
75
+ renderStatus: normalizeRenderStatus(entry.renderStatus) ?? undefined,
76
+ degradeReason: optionalString(entry.degradeReason),
77
+ lastRenderedAt: optionalString(entry.lastRenderedAt) ?? undefined,
78
+ projection: isCodeSyncProjectionMode(entry.projection) ? entry.projection : undefined,
79
+ fallbackReason: isCodeSyncFallbackReason(entry.fallbackReason) ? entry.fallbackReason : null,
80
+ parityArtifact: normalizeParityArtifact(entry.parityArtifact)
81
+ }];
82
+ });
83
+ }
84
+ export function summarizeCanvasProjectionState(summary, targets) {
85
+ const activeProjections = uniqueStrings([
86
+ ...targets.flatMap((entry) => entry.projection ? [entry.projection] : []),
87
+ ...summary.bindings.flatMap((entry) => entry.projection ? [entry.projection] : [])
88
+ ]);
89
+ const fallbackReasons = uniqueStrings(targets.flatMap((entry) => entry.fallbackReason ? [entry.fallbackReason] : []));
90
+ const conflictCount = typeof summary.conflictCount === "number"
91
+ ? summary.conflictCount
92
+ : summary.bindings.reduce((sum, entry) => sum + entry.conflictCount, 0);
93
+ return {
94
+ activeProjections,
95
+ fallbackReasons,
96
+ conflictCount,
97
+ watchConflict: summary.watchState === "watching" && (summary.driftState === "conflict" || conflictCount > 0)
98
+ };
99
+ }
100
+ function normalizeAttachedClient(value) {
101
+ if (!isRecord(value)) {
102
+ return [];
103
+ }
104
+ const clientId = optionalString(value.clientId);
105
+ const attachedAt = optionalString(value.attachedAt);
106
+ const lastSeenAt = optionalString(value.lastSeenAt);
107
+ if (!clientId || !attachedAt || !lastSeenAt) {
108
+ return [];
109
+ }
110
+ return [{
111
+ clientId,
112
+ role: ATTACHED_CLIENT_ROLES.has(value.role)
113
+ ? value.role
114
+ : "observer",
115
+ attachedAt,
116
+ lastSeenAt
117
+ }];
118
+ }
119
+ function normalizeCodeSyncBindingStatus(value) {
120
+ if (!isRecord(value)) {
121
+ return [];
122
+ }
123
+ const bindingId = optionalString(value.bindingId);
124
+ const nodeId = optionalString(value.nodeId);
125
+ const repoPath = optionalString(value.repoPath);
126
+ const adapter = optionalString(value.adapter);
127
+ const syncMode = optionalString(value.syncMode);
128
+ const projection = isCodeSyncProjectionMode(value.projection) ? value.projection : null;
129
+ const state = isCodeSyncState(value.state) ? value.state : null;
130
+ const driftState = isCodeSyncDriftState(value.driftState) ? value.driftState : null;
131
+ if (!bindingId || !nodeId || !repoPath || !adapter || !syncMode || !projection || !state || !driftState) {
132
+ return [];
133
+ }
134
+ return [{
135
+ bindingId,
136
+ nodeId,
137
+ repoPath,
138
+ adapter,
139
+ syncMode,
140
+ projection,
141
+ state,
142
+ driftState,
143
+ watchEnabled: value.watchEnabled === true,
144
+ lastImportedAt: optionalString(value.lastImportedAt) ?? undefined,
145
+ lastPushedAt: optionalString(value.lastPushedAt) ?? undefined,
146
+ conflictCount: optionalNumber(value.conflictCount) ?? 0,
147
+ unsupportedCount: optionalNumber(value.unsupportedCount) ?? 0
148
+ }];
149
+ }
150
+ function normalizeParityArtifact(value) {
151
+ if (!isRecord(value)) {
152
+ return null;
153
+ }
154
+ const projection = isCodeSyncProjectionMode(value.projection) ? value.projection : null;
155
+ const rootBindingId = optionalString(value.rootBindingId);
156
+ const capturedAt = optionalString(value.capturedAt);
157
+ const hierarchyHash = optionalString(value.hierarchyHash);
158
+ if (!projection || !rootBindingId || !capturedAt || !hierarchyHash) {
159
+ return null;
160
+ }
161
+ const nodeCount = Array.isArray(value.nodes)
162
+ ? value.nodes.length
163
+ : optionalNumber(value.nodeCount) ?? 0;
164
+ return {
165
+ projection,
166
+ rootBindingId,
167
+ capturedAt,
168
+ hierarchyHash,
169
+ nodeCount
170
+ };
171
+ }
172
+ function normalizePreviewState(value) {
173
+ return value === "focused" || value === "pinned" || value === "background" || value === "degraded"
174
+ ? value
175
+ : null;
176
+ }
177
+ function normalizeRenderStatus(value) {
178
+ return value === "idle" || value === "rendered" || value === "degraded"
179
+ ? value
180
+ : null;
181
+ }
182
+ function isCodeSyncState(value) {
183
+ return typeof value === "string" && CODE_SYNC_STATES.has(value);
184
+ }
185
+ function isCodeSyncDriftState(value) {
186
+ return typeof value === "string" && CODE_SYNC_DRIFT_STATES.has(value);
187
+ }
188
+ function isCodeSyncWatchState(value) {
189
+ return typeof value === "string" && CODE_SYNC_WATCH_STATES.has(value);
190
+ }
191
+ function isCodeSyncProjectionMode(value) {
192
+ return typeof value === "string" && CODE_SYNC_PROJECTIONS.has(value);
193
+ }
194
+ function isCodeSyncFallbackReason(value) {
195
+ return typeof value === "string" && CODE_SYNC_FALLBACK_REASONS.has(value);
196
+ }
197
+ function readStringArray(value) {
198
+ return Array.isArray(value)
199
+ ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0)
200
+ : [];
201
+ }
202
+ function uniqueStrings(values) {
203
+ return [...new Set(values)];
204
+ }
205
+ function optionalString(value) {
206
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
207
+ }
208
+ function optionalNumber(value) {
209
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
210
+ }
211
+ function isRecord(value) {
212
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
213
+ }
@@ -0,0 +1,67 @@
1
+ export const DEFAULT_EDITOR_VIEWPORT = {
2
+ x: 120,
3
+ y: 96,
4
+ zoom: 1
5
+ };
6
+ const MIN_ZOOM = 0.35;
7
+ const MAX_ZOOM = 2.4;
8
+ const DEFAULT_STAGE_WIDTH = 960;
9
+ const DEFAULT_STAGE_HEIGHT = 640;
10
+ const FIT_PADDING = 48;
11
+ const clamp = (value, min, max) => {
12
+ return Math.min(Math.max(value, min), max);
13
+ };
14
+ const roundZoom = (value) => {
15
+ return Math.round(value * 100) / 100;
16
+ };
17
+ const resolveStageSize = (value, fallback) => {
18
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
19
+ };
20
+ export const isDefaultEditorViewport = (viewport) => {
21
+ return viewport.x === DEFAULT_EDITOR_VIEWPORT.x
22
+ && viewport.y === DEFAULT_EDITOR_VIEWPORT.y
23
+ && viewport.zoom === DEFAULT_EDITOR_VIEWPORT.zoom;
24
+ };
25
+ export const computeViewportCanvasCenter = (viewport, stageWidth, stageHeight) => {
26
+ const safeStageWidth = resolveStageSize(stageWidth, DEFAULT_STAGE_WIDTH);
27
+ const safeStageHeight = resolveStageSize(stageHeight, DEFAULT_STAGE_HEIGHT);
28
+ return {
29
+ x: (safeStageWidth / 2 - viewport.x) / viewport.zoom,
30
+ y: (safeStageHeight / 2 - viewport.y) / viewport.zoom
31
+ };
32
+ };
33
+ const computeNodeBounds = (nodes) => {
34
+ if (nodes.length === 0) {
35
+ return null;
36
+ }
37
+ const minX = Math.min(...nodes.map((node) => node.rect.x));
38
+ const minY = Math.min(...nodes.map((node) => node.rect.y));
39
+ const maxX = Math.max(...nodes.map((node) => node.rect.x + node.rect.width));
40
+ const maxY = Math.max(...nodes.map((node) => node.rect.y + node.rect.height));
41
+ return {
42
+ minX,
43
+ minY,
44
+ width: Math.max(maxX - minX, 1),
45
+ height: Math.max(maxY - minY, 1)
46
+ };
47
+ };
48
+ export const computeFittedViewport = (nodes, stageWidth, stageHeight) => {
49
+ const bounds = computeNodeBounds(nodes);
50
+ if (!bounds) {
51
+ return { ...DEFAULT_EDITOR_VIEWPORT };
52
+ }
53
+ const safeStageWidth = resolveStageSize(stageWidth, DEFAULT_STAGE_WIDTH);
54
+ const safeStageHeight = resolveStageSize(stageHeight, DEFAULT_STAGE_HEIGHT);
55
+ const availableWidth = Math.max(safeStageWidth - FIT_PADDING * 2, 160);
56
+ const availableHeight = Math.max(safeStageHeight - FIT_PADDING * 2, 160);
57
+ const nextZoom = clamp(Math.min(availableWidth / bounds.width, availableHeight / bounds.height, 1), MIN_ZOOM, MAX_ZOOM);
58
+ const zoom = roundZoom(nextZoom);
59
+ const centeredX = (safeStageWidth - bounds.width * zoom) / 2 - bounds.minX * zoom;
60
+ const centeredY = (safeStageHeight - bounds.height * zoom) / 2 - bounds.minY * zoom;
61
+ const anchoredY = DEFAULT_EDITOR_VIEWPORT.y - bounds.minY * zoom;
62
+ return {
63
+ x: Math.round(centeredX),
64
+ y: Math.round(Math.min(centeredY, anchoredY)),
65
+ zoom
66
+ };
67
+ };