@jxsuite/studio 6.1.0 → 6.1.2
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.
- package/dist/chunks/2020-f2gkpy8d.js +4 -0
- package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- package/dist/chunks/adapter-4912g339.js +4 -0
- package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
- package/dist/chunks/cf-settings-br6105tr.js +4 -0
- package/dist/chunks/color-28ksk2qm.js +4 -0
- package/dist/chunks/color-area-0fj8a4ga.js +4 -0
- package/dist/chunks/color-field-xch8kx2g.js +4 -0
- package/dist/chunks/color-slider-jxd8v350.js +4 -0
- package/dist/chunks/combobox-p0efwjke.js +4 -0
- package/dist/chunks/components-db68vsn7.js +4 -0
- package/dist/chunks/content-source-1449qesq.js +4 -0
- package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
- package/dist/chunks/dialog-c4x05vyx.js +4 -0
- package/dist/chunks/editor-x9jn86a7.js +4 -0
- package/dist/chunks/entry-commands-may24cpt.js +4 -0
- package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
- package/dist/chunks/file-ops-x9v54pcj.js +4 -0
- package/dist/chunks/files-j3knqf0s.js +4 -0
- package/dist/chunks/format-host-tyre2trb.js +4 -0
- package/dist/chunks/fs-events-64ma9htc.js +4 -0
- package/dist/chunks/git-panel-84ps5dex.js +4 -0
- package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
- package/dist/chunks/icons-pnfz478q.js +4 -0
- package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
- package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
- package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
- package/dist/chunks/iframe-entry-zap785cw.js +5 -0
- package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
- package/dist/chunks/index-b8xw3vy9.js +4 -0
- package/dist/chunks/{index-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
- package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
- package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
- package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
- package/dist/chunks/layers-h4xp1pss.js +4 -0
- package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
- package/dist/chunks/listbox-e74qjyq6.js +4 -0
- package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
- package/dist/chunks/media-picker-2cweexc5.js +4 -0
- package/dist/chunks/menu-n6yzswmy.js +4 -0
- package/dist/chunks/menu-ynw13y0s.js +4 -0
- package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
- package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
- package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
- package/dist/chunks/notify-cj5zbrs2.js +4 -0
- package/dist/chunks/number-field-y62xq0ty.js +4 -0
- package/dist/chunks/parse-b7ddhr8m.js +4 -0
- package/dist/chunks/platform-3dfws9js.js +4 -0
- package/dist/chunks/popover-jt2gxmzs.js +4 -0
- package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
- package/dist/chunks/quick-search-0dajrwqg.js +4 -0
- package/dist/chunks/references-49qgt404.js +4 -0
- package/dist/chunks/right-panel-jm1bwe53.js +4 -0
- package/dist/chunks/section-registry-6kwc4fky.js +4 -0
- package/dist/chunks/select-rzds841e.js +4 -0
- package/dist/chunks/split-n2gfpm5m.js +4 -0
- package/dist/chunks/{studio-5g0ag7c0.js → studio-0q988f9w.js} +3 -3
- package/dist/chunks/studio-0rt52vpq.js +5 -0
- package/dist/chunks/studio-18vgbhs5.js +5 -0
- package/dist/chunks/{studio-pxg4ap1e.js → studio-1fxkaaea.js} +4 -4
- package/dist/chunks/studio-24mccdrj.js +5 -0
- package/dist/chunks/studio-2eh507zk.js +9 -0
- package/dist/chunks/studio-2hcbccfv.js +5 -0
- package/dist/chunks/studio-2j1cb95x.js +5 -0
- package/dist/chunks/studio-2jbs3rxv.js +5 -0
- package/dist/chunks/{studio-qbj760tx.js → studio-485046te.js} +7 -7
- package/dist/chunks/studio-4h8k4dw9.js +5 -0
- package/dist/chunks/studio-5f6n18kx.js +5 -0
- package/dist/chunks/studio-5gthpky6.js +5 -0
- package/dist/chunks/studio-5ve6bbep.js +5 -0
- package/dist/chunks/studio-6ep3js6b.js +9 -0
- package/dist/chunks/studio-6wkmf3wz.js +9 -0
- package/dist/chunks/studio-841rf3cg.js +5 -0
- package/dist/chunks/studio-8gmwgheg.js +5 -0
- package/dist/chunks/studio-8qm0ep50.js +5 -0
- package/dist/chunks/{studio-anyrgzvb.js → studio-90pq9km1.js} +4 -4
- package/dist/chunks/studio-924p1tm1.js +6 -0
- package/dist/chunks/{studio-v2bvmbjj.js → studio-a3g98wjr.js} +4 -4
- package/dist/chunks/studio-a3shpz9y.js +5 -0
- package/dist/chunks/studio-amsbaaar.js +6 -0
- package/dist/chunks/studio-at5spjbc.js +7 -0
- package/dist/chunks/studio-b2xv945e.js +5 -0
- package/dist/chunks/studio-bn5nkafw.js +5 -0
- package/dist/chunks/studio-bw6q5xjf.js +9 -0
- package/dist/chunks/studio-c7q0t9x1.js +5 -0
- package/dist/chunks/studio-camnhc96.js +6 -0
- package/dist/chunks/studio-cffqvnzd.js +5 -0
- package/dist/chunks/studio-d81xfh1g.js +5 -0
- package/dist/chunks/studio-dgz8d0c1.js +5 -0
- package/dist/chunks/studio-efvfrsf8.js +5 -0
- package/dist/chunks/studio-er30bpcx.js +5 -0
- package/dist/chunks/studio-ezscgr64.js +5 -0
- package/dist/chunks/studio-ffrrncvz.js +5 -0
- package/dist/chunks/studio-fpphgn8y.js +10 -0
- package/dist/chunks/studio-j1kvhdjk.js +4 -0
- package/dist/chunks/{studio-txjjzrsm.js → studio-j430n16g.js} +5 -5
- package/dist/chunks/studio-jjkg84nj.js +5 -0
- package/dist/chunks/studio-m0q32ars.js +4 -0
- package/dist/chunks/studio-m6bdst11.js +5 -0
- package/dist/chunks/studio-nv2cptd4.js +64 -0
- package/dist/chunks/studio-nwfrc98n.js +5 -0
- package/dist/chunks/studio-p1wgvp7r.js +5 -0
- package/dist/chunks/studio-pag2wncm.js +5 -0
- package/dist/chunks/studio-qvanvzfd.js +5 -0
- package/dist/chunks/studio-qwa64kt7.js +5 -0
- package/dist/chunks/studio-rk1zc4x3.js +928 -0
- package/dist/chunks/studio-se2r3ptc.js +5 -0
- package/dist/chunks/studio-sg2a0dh0.js +5 -0
- package/dist/chunks/studio-tjzjhe68.js +5 -0
- package/dist/chunks/{studio-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
- package/dist/chunks/{studio-cpxkgjrj.js → studio-v0jzqdjm.js} +4 -4
- package/dist/chunks/studio-v2w7q8r1.js +7 -0
- package/dist/chunks/studio-v5vjq1h0.js +4 -0
- package/dist/chunks/studio-v8aga3vp.js +14 -0
- package/dist/chunks/studio-vfcdrfmv.js +5 -0
- package/dist/chunks/studio-vmfkgdjf.js +5 -0
- package/dist/chunks/studio-wt1816jj.js +5 -0
- package/dist/chunks/studio-wz73q5kq.js +4 -0
- package/dist/chunks/studio-y04qtxvp.js +7 -0
- package/dist/chunks/studio-y21g8zzg.js +5 -0
- package/dist/chunks/studio-y64hrt8p.js +12 -0
- package/dist/chunks/studio-ynn90f58.js +16 -0
- package/dist/chunks/studio-yxz682sx.js +5 -0
- package/dist/chunks/studio-zp7snvkq.js +5 -0
- package/dist/chunks/studio-zq4z6tm6.js +5 -0
- package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
- package/dist/chunks/tabs-f5cw3tgp.js +4 -0
- package/dist/chunks/textfield-wewc8rq2.js +4 -0
- package/dist/chunks/toast-c9fn075p.js +4 -0
- package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
- package/dist/chunks/tree-mdq3v5cw.js +4 -0
- package/dist/chunks/tsMode-sf49ee9x.js +14 -0
- package/dist/chunks/workspace-jtfahpee.js +4 -0
- package/dist/chunks/ws-client-nze0k6mv.js +4 -0
- package/dist/iframe-entry.js +16 -16
- package/dist/manifest.json +63 -63
- package/dist/studio.js +98 -98
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +11 -11
- package/src/about/about-modal.ts +4 -3
- package/src/account/action-flow.ts +45 -38
- package/src/account-status.ts +7 -2
- package/src/browse/library-layouts.ts +8 -5
- package/src/browse/library-model.ts +18 -6
- package/src/browse/library-pane.ts +37 -21
- package/src/browse/library-preview.ts +14 -9
- package/src/browse/library-source.ts +1 -1
- package/src/canvas/asset-refs.ts +24 -9
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +44 -53
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +66 -42
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +163 -64
- package/src/canvas/dialog-path.ts +9 -4
- package/src/canvas/dialog-state.ts +1 -2
- package/src/canvas/diff-marks.ts +9 -16
- package/src/canvas/diff-toolbar.ts +8 -7
- package/src/canvas/edit-width-drag.ts +4 -1
- package/src/canvas/edit-width.ts +1 -3
- package/src/canvas/iframe-channel.ts +27 -13
- package/src/canvas/iframe-drop.ts +13 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +80 -63
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +203 -118
- package/src/canvas/iframe-inline-edit.ts +69 -32
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +37 -26
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +18 -15
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +15 -16
- package/src/canvas/iframe-render.ts +41 -36
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +6 -2
- package/src/canvas/path-mapping.ts +19 -12
- package/src/canvas/popover-path.ts +7 -3
- package/src/canvas/popover-state.ts +1 -2
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +2 -1
- package/src/canvas/surface-registry.ts +21 -3
- package/src/collab/collab-commands.ts +7 -2
- package/src/collab/collab-session.ts +84 -45
- package/src/collab/collab-state.ts +4 -3
- package/src/collab/monaco-binding.ts +16 -13
- package/src/collab/monaco-cursors.ts +5 -2
- package/src/commands/budget.ts +3 -3
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +22 -20
- package/src/commands/defaults.ts +4 -1
- package/src/commands/keymap.ts +47 -43
- package/src/commands/levels.ts +3 -3
- package/src/commands/live-context.ts +10 -8
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +12 -10
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +5 -4
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +3 -2
- package/src/content/entry-editor.ts +29 -17
- package/src/content/entry-fields.ts +12 -7
- package/src/content/entry-model.ts +21 -12
- package/src/editor/canvas-context-menu.ts +1 -2
- package/src/editor/canvas-slash-bridge.ts +3 -6
- package/src/editor/content-slice.ts +16 -14
- package/src/editor/context-menu.ts +35 -22
- package/src/editor/convert-targets.ts +30 -35
- package/src/editor/convert-to-component.ts +11 -5
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +21 -22
- package/src/editor/inline-edit-apply.ts +35 -17
- package/src/editor/inline-edit.ts +66 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +87 -47
- package/src/editor/slash-menu.ts +1 -6
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +15 -10
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +77 -36
- package/src/files/files.ts +90 -95
- package/src/files/media-meta.ts +2 -1
- package/src/files/media-paths.ts +6 -1
- package/src/files/serialize-document.ts +2 -2
- package/src/format/constraints.ts +1 -1
- package/src/format/convert-file.ts +27 -13
- package/src/format/format-choices.ts +2 -1
- package/src/format/format-host.ts +76 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +19 -9
- package/src/github/github-publish.ts +24 -20
- package/src/grid/cell-editors.ts +46 -31
- package/src/grid/cell-popovers.ts +5 -3
- package/src/grid/edit-buffer.ts +10 -9
- package/src/grid/grid-controller.ts +20 -22
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -6
- package/src/grid/grid-panel.ts +11 -4
- package/src/grid/grid-source.ts +8 -8
- package/src/grid/grid-view.ts +14 -17
- package/src/grid/redirects-grid.ts +14 -5
- package/src/grid/redirects.ts +16 -14
- package/src/grid/schema-columns.ts +25 -19
- package/src/grid/sources/connector-source.ts +47 -20
- package/src/grid/sources/content-source.ts +25 -24
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +55 -34
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +1 -2
- package/src/media/media-pane.ts +4 -1
- package/src/new-project/add-repo-modal.ts +20 -19
- package/src/new-project/import-tab.ts +10 -14
- package/src/new-project/location-fields.ts +2 -1
- package/src/new-project/new-project-modal.ts +12 -9
- package/src/packages/jxsuite-update.ts +4 -3
- package/src/packages/pull-package-sync.ts +26 -25
- package/src/page-params.ts +97 -68
- package/src/panels/activity-panel.ts +17 -9
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-view.ts +80 -73
- package/src/panels/ai-chat/composer.ts +30 -33
- package/src/panels/ai-chat/sessions-view.ts +1 -2
- package/src/panels/ai-panel.ts +23 -20
- package/src/panels/block-action-bar.ts +46 -35
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +31 -24
- package/src/panels/data-explorer.ts +62 -25
- package/src/panels/data-grid.ts +14 -11
- package/src/panels/dnd.ts +108 -118
- package/src/panels/editors.ts +55 -22
- package/src/panels/elements-panel.ts +10 -3
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +76 -51
- package/src/panels/frontmatter-fields.ts +24 -19
- package/src/panels/frontmatter-panel.ts +44 -34
- package/src/panels/git-diff-open.ts +4 -4
- package/src/panels/git-panel.ts +49 -61
- package/src/panels/head-panel.ts +131 -111
- package/src/panels/i18n-panel.ts +10 -3
- package/src/panels/imports-panel.ts +23 -47
- package/src/panels/jump-bar.ts +48 -29
- package/src/panels/layers-panel.ts +97 -74
- package/src/panels/left-panel.ts +3 -3
- package/src/panels/pane-context.ts +31 -22
- package/src/panels/pane-grid.ts +49 -20
- package/src/panels/panel-registry.ts +22 -37
- package/src/panels/properties-panel.ts +175 -121
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +3 -3
- package/src/panels/seo-modal.ts +13 -17
- package/src/panels/settings-menu.ts +15 -15
- package/src/panels/signals-panel.ts +153 -131
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +254 -216
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +57 -54
- package/src/panels/stylebook-layers-panel.ts +9 -9
- package/src/panels/stylebook-panel.ts +13 -17
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +36 -26
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +58 -30
- package/src/platforms/cloud.ts +345 -175
- package/src/platforms/default-platform.ts +10 -4
- package/src/platforms/devserver.ts +174 -127
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +8 -2
- package/src/publish/pages-service.ts +28 -13
- package/src/publish/publish-commands.ts +5 -4
- package/src/publish/publish-panel.ts +10 -6
- package/src/recent-projects.ts +15 -8
- package/src/resize-edges.ts +26 -36
- package/src/services/a11y-report.ts +26 -19
- package/src/services/agent-seed.ts +23 -11
- package/src/services/ai-ask.ts +9 -12
- package/src/services/ai-command-tools.ts +68 -62
- package/src/services/ai-import-tools.ts +80 -67
- package/src/services/ai-models.ts +17 -13
- package/src/services/ai-project-tools.ts +68 -32
- package/src/services/ai-session-store.ts +19 -10
- package/src/services/ai-system-prompt.ts +46 -20
- package/src/services/ai-tools.ts +71 -27
- package/src/services/ai-write-report.ts +20 -12
- package/src/services/ai-writes.ts +4 -4
- package/src/services/automation.ts +58 -31
- package/src/services/cem-export.ts +149 -58
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/context-manager.ts +14 -10
- package/src/services/context-resolver.ts +20 -8
- package/src/services/data-service.ts +19 -15
- package/src/services/directory-picker.ts +18 -12
- package/src/services/document-assistant.ts +39 -19
- package/src/services/gated-registry.ts +10 -6
- package/src/services/harness/chat-reducer.ts +23 -1
- package/src/services/import-client.ts +91 -38
- package/src/services/import-seed.ts +8 -2
- package/src/services/jx-validate.ts +28 -31
- package/src/services/live-preview.ts +0 -0
- package/src/services/live-surfaces.ts +6 -3
- package/src/services/model-uri.ts +10 -2
- package/src/services/module-preloads.ts +12 -8
- package/src/services/monaco-buffer.ts +43 -24
- package/src/services/monaco-lazy.ts +7 -8
- package/src/services/monaco-setup.ts +23 -16
- package/src/services/notify.ts +44 -17
- package/src/services/popover-report.ts +25 -10
- package/src/services/preview-eval.ts +20 -8
- package/src/services/profile.ts +13 -6
- package/src/services/project-path.ts +13 -10
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +8 -7
- package/src/services/settings/kernel.ts +13 -4
- package/src/services/settings/write-queue.ts +9 -9
- package/src/services/token-lint.ts +12 -10
- package/src/services/tool-executor.ts +17 -5
- package/src/services/tool-outcomes.ts +44 -24
- package/src/services/trusted-types.ts +24 -7
- package/src/settings/contexts-section.ts +11 -8
- package/src/settings/contributed-section.ts +79 -60
- package/src/settings/css-vars-editor.ts +37 -16
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +23 -13
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +11 -8
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +9 -6
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +1 -1
- package/src/settings/schema-field-ui.ts +9 -0
- package/src/settings/settings-document.ts +5 -5
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +104 -81
- package/src/site-context.ts +37 -22
- package/src/state.ts +41 -49
- package/src/store.ts +54 -34
- package/src/studio.ts +39 -77
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +6 -7
- package/src/style/token-ref.ts +5 -4
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +31 -36
- package/src/surfaces/ai-credentials-form.ts +6 -16
- package/src/surfaces/ai-managed-connect.ts +3 -4
- package/src/surfaces/ai-model-picker.ts +3 -5
- package/src/surfaces/block-action-bar.ts +22 -11
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.ts +12 -11
- package/src/surfaces/cf-account-picker.ts +17 -18
- package/src/surfaces/commandbar.ts +14 -9
- package/src/surfaces/convert-repeater.ts +17 -19
- package/src/surfaces/data-actions.ts +9 -7
- package/src/surfaces/dialog.ts +26 -28
- package/src/surfaces/diff-toolbar.ts +9 -7
- package/src/surfaces/doc-header.ts +10 -19
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.ts +14 -11
- package/src/surfaces/expression-editor.ts +11 -25
- package/src/surfaces/files-panel.ts +27 -14
- package/src/surfaces/formula-palette.ts +4 -5
- package/src/surfaces/git-panel.ts +7 -15
- package/src/surfaces/github-auth.ts +16 -20
- package/src/surfaces/github-publish.ts +17 -22
- package/src/surfaces/grid-cell.ts +30 -31
- package/src/surfaces/grid-open.ts +10 -14
- package/src/surfaces/grid-panel.ts +13 -9
- package/src/surfaces/grid-replace.ts +13 -13
- package/src/surfaces/grid-views.ts +15 -18
- package/src/surfaces/inspector-dock.ts +13 -12
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.ts +25 -20
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.ts +11 -10
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/menu.ts +29 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.ts +20 -25
- package/src/surfaces/pane-grid.ts +15 -10
- package/src/surfaces/panel-activity.ts +5 -6
- package/src/surfaces/panel-data.ts +3 -4
- package/src/surfaces/panel-deploy-checklist.ts +5 -6
- package/src/surfaces/panel-elements.ts +5 -7
- package/src/surfaces/panel-i18n.ts +5 -7
- package/src/surfaces/panel-imports.ts +6 -13
- package/src/surfaces/panel-outline.ts +25 -19
- package/src/surfaces/panel-page.ts +11 -18
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.ts +20 -34
- package/src/surfaces/panel-stylebook-layers.ts +5 -8
- package/src/surfaces/preferences.ts +21 -11
- package/src/surfaces/progress-modal.ts +15 -9
- package/src/surfaces/properties-panel.json +1 -1
- package/src/surfaces/properties-panel.ts +20 -42
- package/src/surfaces/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +126 -73
- package/src/surfaces/rail.ts +38 -12
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.ts +15 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.ts +14 -10
- package/src/surfaces/settings-css-vars.ts +5 -12
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.ts +8 -15
- package/src/surfaces/settings-extensions.ts +5 -6
- package/src/surfaces/settings-head.ts +33 -39
- package/src/surfaces/settings-locales.ts +8 -20
- package/src/surfaces/settings-overview.ts +5 -6
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.ts +9 -18
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.ts +1 -2
- package/src/surfaces/slash-menu.ts +19 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +17 -14
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- package/src/surfaces/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +5 -7
- package/src/tabs/patch-ops.ts +4 -3
- package/src/tabs/project-config.ts +32 -21
- package/src/tabs/selection.ts +36 -8
- package/src/tabs/tab.ts +52 -41
- package/src/tabs/transact.ts +98 -53
- package/src/tabs/typing.ts +31 -0
- package/src/types.ts +32 -17
- package/src/ui/ai-credentials-form.ts +10 -13
- package/src/ui/ai-model-picker.ts +3 -3
- package/src/ui/cf-account-picker.ts +7 -9
- package/src/ui/color-selector.ts +9 -5
- package/src/ui/dynamic-slot.ts +7 -8
- package/src/ui/expression-editor.ts +112 -105
- package/src/ui/form-controls.ts +57 -48
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +44 -31
- package/src/ui/media-picker.ts +18 -9
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +7 -6
- package/src/ui/schema-form.ts +113 -70
- package/src/ui/surface.ts +71 -8
- package/src/ui/timing.ts +9 -0
- package/src/ui/value-source.ts +44 -31
- package/src/ui/virtual-window.ts +3 -2
- package/src/utils/base64.ts +3 -1
- package/src/utils/edit-display.ts +103 -74
- package/src/utils/element-selectors.ts +3 -2
- package/src/utils/google-fonts.ts +15 -14
- package/src/utils/inherited-style.ts +18 -20
- package/src/utils/link-target.ts +1 -1
- package/src/utils/preview-format.ts +25 -3
- package/src/utils/strip-events.ts +49 -22
- package/src/utils/studio-utils.ts +29 -14
- package/src/view.ts +2 -3
- package/src/workspace/pane-derive.ts +10 -12
- package/src/workspace/session.ts +53 -43
- package/src/workspace/workspace.ts +47 -36
- package/dist/chunks/2020-nkxms0ay.js +0 -4
- package/dist/chunks/adapter-m948ab5f.js +0 -4
- package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
- package/dist/chunks/cf-settings-356xdtne.js +0 -4
- package/dist/chunks/color-area-jqhna8zy.js +0 -4
- package/dist/chunks/color-field-embq5ctg.js +0 -4
- package/dist/chunks/color-fpezvnkt.js +0 -4
- package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
- package/dist/chunks/combobox-773hdzyj.js +0 -4
- package/dist/chunks/components-yk3t844e.js +0 -4
- package/dist/chunks/content-source-bawmyc09.js +0 -4
- package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-6sc8nacq.js +0 -4
- package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
- package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
- package/dist/chunks/file-ops-gye0qw56.js +0 -4
- package/dist/chunks/files-dmc2xvcq.js +0 -4
- package/dist/chunks/format-host-t76b53f8.js +0 -4
- package/dist/chunks/fs-events-cg4tpz06.js +0 -4
- package/dist/chunks/git-panel-yef7bshy.js +0 -4
- package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
- package/dist/chunks/icons-qbh8akb1.js +0 -4
- package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
- package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
- package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
- package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
- package/dist/chunks/index-nag78a9h.js +0 -4
- package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
- package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
- package/dist/chunks/layers-fvz99859.js +0 -4
- package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-9agdspkt.js +0 -4
- package/dist/chunks/media-picker-rhjvyy00.js +0 -4
- package/dist/chunks/menu-2e4y9j7b.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
- package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
- package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
- package/dist/chunks/notify-h3www560.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-hz34wcd7.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
- package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
- package/dist/chunks/references-2cgdxnb8.js +0 -4
- package/dist/chunks/right-panel-jf856w5w.js +0 -4
- package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0f55h9ye.js +0 -5
- package/dist/chunks/studio-0sqdhnew.js +0 -12
- package/dist/chunks/studio-19x1c75w.js +0 -5
- package/dist/chunks/studio-2sqcndak.js +0 -5
- package/dist/chunks/studio-3aey7dd3.js +0 -5
- package/dist/chunks/studio-3bpdkq2s.js +0 -5
- package/dist/chunks/studio-47y6fbpf.js +0 -5
- package/dist/chunks/studio-4m3826v2.js +0 -5
- package/dist/chunks/studio-4nx2dj1g.js +0 -4
- package/dist/chunks/studio-4xv5s47r.js +0 -9
- package/dist/chunks/studio-5g4t8v6w.js +0 -5
- package/dist/chunks/studio-5py436sf.js +0 -5
- package/dist/chunks/studio-77kt594t.js +0 -5
- package/dist/chunks/studio-8f87n763.js +0 -10
- package/dist/chunks/studio-8mb00b84.js +0 -5
- package/dist/chunks/studio-8p51gq2h.js +0 -6
- package/dist/chunks/studio-954ds834.js +0 -5
- package/dist/chunks/studio-9ft45c83.js +0 -9
- package/dist/chunks/studio-a2138x5k.js +0 -7
- package/dist/chunks/studio-a9yzstqj.js +0 -5
- package/dist/chunks/studio-acdksxx6.js +0 -5
- package/dist/chunks/studio-ar8jcf2y.js +0 -5
- package/dist/chunks/studio-bmn4mn9j.js +0 -7
- package/dist/chunks/studio-e7xxa0sj.js +0 -5
- package/dist/chunks/studio-ecaz25vk.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-fzdywr6p.js +0 -9
- package/dist/chunks/studio-g5fmf0c1.js +0 -5
- package/dist/chunks/studio-g7nse7zb.js +0 -5
- package/dist/chunks/studio-geq1ea6k.js +0 -14
- package/dist/chunks/studio-ghkb32r8.js +0 -5
- package/dist/chunks/studio-ghrhy2y7.js +0 -5
- package/dist/chunks/studio-grawhey1.js +0 -5
- package/dist/chunks/studio-h0xgswew.js +0 -5
- package/dist/chunks/studio-h9c4p2tx.js +0 -5
- package/dist/chunks/studio-jyzj5cxs.js +0 -5
- package/dist/chunks/studio-mgx8yhnz.js +0 -64
- package/dist/chunks/studio-mpb04y1d.js +0 -6
- package/dist/chunks/studio-n17mty64.js +0 -5
- package/dist/chunks/studio-nwh2eqsk.js +0 -6
- package/dist/chunks/studio-q1h883bt.js +0 -16
- package/dist/chunks/studio-q4tv82h7.js +0 -9
- package/dist/chunks/studio-qpqa7vk3.js +0 -5
- package/dist/chunks/studio-qqz8e5gk.js +0 -5
- package/dist/chunks/studio-qvasen3f.js +0 -5
- package/dist/chunks/studio-rggdb3hm.js +0 -5
- package/dist/chunks/studio-sghy936h.js +0 -4
- package/dist/chunks/studio-skprc6ef.js +0 -5
- package/dist/chunks/studio-tt2nactf.js +0 -5
- package/dist/chunks/studio-tyasmc39.js +0 -5
- package/dist/chunks/studio-vk9ezads.js +0 -5
- package/dist/chunks/studio-vzacdfsc.js +0 -4
- package/dist/chunks/studio-w4c0xmrw.js +0 -5
- package/dist/chunks/studio-wfjqhhbk.js +0 -5
- package/dist/chunks/studio-wgh5kxpj.js +0 -5
- package/dist/chunks/studio-xasj0796.js +0 -5
- package/dist/chunks/studio-y78s8r2n.js +0 -5
- package/dist/chunks/studio-z8w183sh.js +0 -5
- package/dist/chunks/studio-zscd9ty4.js +0 -928
- package/dist/chunks/studio-zxp13sss.js +0 -7
- package/dist/chunks/studio-zygnmm01.js +0 -5
- package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
- package/dist/chunks/tabs-jwthg40w.js +0 -4
- package/dist/chunks/textfield-spy3hc77.js +0 -4
- package/dist/chunks/toast-4d35zd64.js +0 -4
- package/dist/chunks/toast-host-8sjmfed3.js +0 -4
- package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
- package/dist/chunks/tree-h19v1jfz.js +0 -4
- package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
- package/dist/chunks/workspace-m15qtcqp.js +0 -4
- package/dist/chunks/ws-client-nf61frr1.js +0 -4
|
@@ -38,6 +38,11 @@ export interface CloudSignal {
|
|
|
38
38
|
project: CloudProject | null;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
declare global {
|
|
42
|
+
/** Published by the cloud shell's boot module before the studio bundle evaluates. */
|
|
43
|
+
var __jxCloud: CloudSignal | undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
/**
|
|
42
47
|
* Why Studio will not fall back to the dev-server adapter, most specific evidence first.
|
|
43
48
|
*
|
|
@@ -86,13 +91,14 @@ const BACKENDLESS_SCHEMES: ReadonlySet<string> = new Set(["views:", "file:"]);
|
|
|
86
91
|
|
|
87
92
|
/** Read the boot environment from the live globals and document. */
|
|
88
93
|
export function bootEnvironment(): BootEnvironment {
|
|
89
|
-
|
|
94
|
+
// A DOM-less host (a test runner, a worker) has no document or location to read.
|
|
95
|
+
const doc = typeof document === "undefined" ? undefined : document;
|
|
90
96
|
const meta = `meta[name="${BOOT_META.name}"][content="${BOOT_META.content}"]`;
|
|
91
97
|
return {
|
|
92
|
-
cloud:
|
|
98
|
+
cloud: globalThis.__jxCloud != null,
|
|
93
99
|
declared: doc?.querySelector(meta) != null,
|
|
94
100
|
launcher: launcherSignal(),
|
|
95
|
-
protocol:
|
|
101
|
+
protocol: typeof location === "undefined" ? "" : location.protocol,
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
104
|
|
|
@@ -159,6 +165,6 @@ export function resolveDefaultPlatform(): StudioPlatform {
|
|
|
159
165
|
if (refusal) {
|
|
160
166
|
throw new PlatformUnavailableError(refusal);
|
|
161
167
|
}
|
|
162
|
-
const cloud =
|
|
168
|
+
const cloud = globalThis.__jxCloud;
|
|
163
169
|
return cloud ? createCloudPlatform(cloud.project) : createDevServerPlatform();
|
|
164
170
|
}
|
|
@@ -13,9 +13,9 @@ import { canPickDirectory, pickDirectoryPath } from "../services/directory-picke
|
|
|
13
13
|
import { negotiateCollab } from "@jxsuite/collab/negotiate";
|
|
14
14
|
import type { CollabNegotiation } from "@jxsuite/collab/negotiate";
|
|
15
15
|
import type { WsCollabConnection } from "@jxsuite/collab/client";
|
|
16
|
-
import
|
|
16
|
+
import { isFunction } from "@jxsuite/schema/guards";
|
|
17
|
+
import type { JsonObject, JsonValue, JxMutableNode, ProjectConfig } from "@jxsuite/schema/types";
|
|
17
18
|
import type {
|
|
18
|
-
CreateProjectDestination,
|
|
19
19
|
DataConnectionsResponse,
|
|
20
20
|
DataConnectionTestResult,
|
|
21
21
|
DataPushResult,
|
|
@@ -35,20 +35,22 @@ import type {
|
|
|
35
35
|
ProjectSchemasResponse,
|
|
36
36
|
ReferencesResult,
|
|
37
37
|
RenameResult,
|
|
38
|
-
|
|
38
|
+
KeyValuePatch,
|
|
39
39
|
SecretsSetResponse,
|
|
40
40
|
SiteBuildResult,
|
|
41
41
|
SitePreviewResult,
|
|
42
42
|
StarterInfo,
|
|
43
|
+
StudioPlatform,
|
|
43
44
|
} from "../types";
|
|
44
45
|
import { problemDetail, problemMessage } from "@jxsuite/protocol";
|
|
46
|
+
import type { CfProxyEnvelope } from "./cloud";
|
|
45
47
|
import type { UploadResult } from "@jxsuite/protocol";
|
|
46
48
|
|
|
47
|
-
/** A directory entry from the server, tolerating extra wire fields. */
|
|
48
|
-
type WireDirEntry = DirEntry & Record<string, unknown>;
|
|
49
|
-
|
|
50
49
|
/** Parse a fetch Response body as JSON, asserting the expected shape at the boundary. */
|
|
51
50
|
async function readJson<T>(res: Response): Promise<T> {
|
|
51
|
+
/* SAFETY: every route read here is a `/__studio/*` route of @jxsuite/server (specs/server.md §4),
|
|
52
|
+
whose replies have the shapes ../types and the wire interfaces in this file describe, and each
|
|
53
|
+
caller names the type of the route it called. */
|
|
52
54
|
return (await res.json()) as T;
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -56,11 +58,46 @@ interface ErrorBody {
|
|
|
56
58
|
error?: string;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
/** One entry of the `/__studio/sites` glob: a site's folder and its parsed project.json. */
|
|
59
62
|
interface SiteEntry {
|
|
60
|
-
config:
|
|
63
|
+
config: ProjectConfig | null;
|
|
61
64
|
path: string;
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
/**
|
|
68
|
+
* `GET /__studio/project-info`: what the server knows about a folder. The route sends more than
|
|
69
|
+
* Studio reads (`projectRoot` among them), and those members ride along untouched.
|
|
70
|
+
*/
|
|
71
|
+
interface ProjectInfoReply {
|
|
72
|
+
isSiteProject: boolean;
|
|
73
|
+
projectConfig?: ProjectConfig | null;
|
|
74
|
+
directories?: string[];
|
|
75
|
+
[member: string]: JsonValue | ProjectConfig | undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** The body of an `fs` event on the `/__reload` stream (the server's watcher batches them). */
|
|
79
|
+
interface FsEventBatch {
|
|
80
|
+
events?: FsEvent[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** `showDirectoryPicker()` (WICG File System Access), which only Chromium-based browsers expose. */
|
|
84
|
+
type ShowDirectoryPicker = (options: { mode: string }) => Promise<FileSystemDirectoryHandle>;
|
|
85
|
+
|
|
86
|
+
/** True when the window implements the File System Access directory picker. */
|
|
87
|
+
function hasDirectoryPicker(
|
|
88
|
+
host: Window,
|
|
89
|
+
): host is Window & { showDirectoryPicker: ShowDirectoryPicker } {
|
|
90
|
+
return "showDirectoryPicker" in host && isFunction(host.showDirectoryPicker);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** The options object {@link StudioPlatform.createProject} takes. */
|
|
94
|
+
type CreateProjectOptions = Parameters<StudioPlatform["createProject"]>[0];
|
|
95
|
+
|
|
96
|
+
/** What a row insert or update answers: the row as stored. */
|
|
97
|
+
interface DataRowWrite {
|
|
98
|
+
row: JsonObject;
|
|
99
|
+
}
|
|
100
|
+
|
|
64
101
|
/**
|
|
65
102
|
* Create a DevServerPlatform instance.
|
|
66
103
|
*
|
|
@@ -98,6 +135,50 @@ export function createDevServerPlatform() {
|
|
|
98
135
|
*/
|
|
99
136
|
let _collabConnection: Promise<WsCollabConnection> | null = null;
|
|
100
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Bind the server to `root` — the binding its rootless routes and its static fallback (every
|
|
140
|
+
* media thumbnail, every canvas image) resolve against.
|
|
141
|
+
*
|
|
142
|
+
* **The binding is one per SERVER, not per tab.** So an empty root posts nothing: a Studio tab
|
|
143
|
+
* opened with no project used to post `{ root: "" }` at boot, which unbound the server for every
|
|
144
|
+
* other tab and turned their images into 404s. And a tab re-claims it (see
|
|
145
|
+
* {@link reclaimBinding}) whenever it could have been taken.
|
|
146
|
+
*/
|
|
147
|
+
async function postActivate(root: string): Promise<void> {
|
|
148
|
+
if (!root) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const res = await fetch("/__studio/activate", {
|
|
152
|
+
body: JSON.stringify({ root }),
|
|
153
|
+
headers: { "Content-Type": "application/json" },
|
|
154
|
+
method: "POST",
|
|
155
|
+
});
|
|
156
|
+
if (!res.ok) {
|
|
157
|
+
const body = await readJson<ErrorBody>(res).catch((): ErrorBody => ({}));
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Could not open ${root}: ${problemDetail(body) ?? `activation failed (${res.status})`}`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Re-bind the server to this tab's project. Two events can take the binding away without this tab
|
|
166
|
+
* hearing of it: another Studio tab activating ITS project, and a restarted `bun run dev`, which
|
|
167
|
+
* comes back bound to nothing. So a tab re-claims it when the author comes back to it (focus) and
|
|
168
|
+
* when the reload stream reconnects (a restart). Only a tab with a project claims anything.
|
|
169
|
+
*/
|
|
170
|
+
function reclaimBinding(): void {
|
|
171
|
+
if (!_projectRoot) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
_activation = postActivate(_projectRoot).catch((error) => {
|
|
175
|
+
console.error("Project re-activation failed:", error);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
if (typeof window !== "undefined") {
|
|
179
|
+
window.addEventListener("focus", reclaimBinding);
|
|
180
|
+
}
|
|
181
|
+
|
|
101
182
|
/**
|
|
102
183
|
* Prefix a project-relative path with the active project root for server API calls.
|
|
103
184
|
*
|
|
@@ -127,6 +208,36 @@ export function createDevServerPlatform() {
|
|
|
127
208
|
return p.startsWith(`${_projectRoot}/`) ? p.slice(_projectRoot.length + 1) : p;
|
|
128
209
|
}
|
|
129
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Native folder chooser for the New Project modal's Browse… button. Present only when the browser
|
|
213
|
+
* implements `showDirectoryPicker` (Chromium-based); elsewhere the member stays undefined and the
|
|
214
|
+
* modal falls back to a typed Location field.
|
|
215
|
+
*
|
|
216
|
+
* The picked handle carries no filesystem path, so it is resolved by the id the picker tags the
|
|
217
|
+
* folder with (see `@jxsuite/studio/directory-picker`). Resolves `null` only when the user
|
|
218
|
+
* dismisses the chooser; every other failure rejects with a sentence the modal shows under
|
|
219
|
+
* Location. So `locate` keeps the helper's contract: `null` is "no folder holds this id" (the
|
|
220
|
+
* route's 200 `{ path: null }`), and a non-ok answer throws the problem the server sent rather
|
|
221
|
+
* than posing as a miss. A network failure (`TypeError: Failed to fetch`, e.g. a page that is not
|
|
222
|
+
* being served by the dev server at all) propagates as is, and the picker names it.
|
|
223
|
+
*/
|
|
224
|
+
const directoryPicking: Pick<StudioPlatform, "pickDirectory"> = {};
|
|
225
|
+
if (canPickDirectory()) {
|
|
226
|
+
directoryPicking.pickDirectory = async (): Promise<string | null> =>
|
|
227
|
+
pickDirectoryPath(async ({ id, name }) => {
|
|
228
|
+
const res = await fetch(
|
|
229
|
+
`/__studio/locate-directory?name=${encodeURIComponent(name)}&id=${encodeURIComponent(id)}`,
|
|
230
|
+
);
|
|
231
|
+
if (!res.ok) {
|
|
232
|
+
// A proxy, or a `views://` host with no dev server behind it, may answer in HTML.
|
|
233
|
+
const body = await readJson<JsonValue>(res).catch(() => null);
|
|
234
|
+
throw new Error(problemMessage(body, res.status));
|
|
235
|
+
}
|
|
236
|
+
const found = await readJson<{ path?: string | null }>(res);
|
|
237
|
+
return found.path ?? null;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
130
241
|
return {
|
|
131
242
|
id: "devserver",
|
|
132
243
|
|
|
@@ -145,7 +256,7 @@ export function createDevServerPlatform() {
|
|
|
145
256
|
// Fire-and-forget: callers that need the binding in place before reading await activate()
|
|
146
257
|
// Themselves. The rejection is reported rather than dropped — an unactivated root leaves
|
|
147
258
|
// Every rootless endpoint (git especially) operating on the server's OWN root.
|
|
148
|
-
_activation = this.activate(_projectRoot).catch((error
|
|
259
|
+
_activation = this.activate(_projectRoot).catch((error) => {
|
|
149
260
|
console.error("Project activation failed:", error);
|
|
150
261
|
});
|
|
151
262
|
}
|
|
@@ -162,35 +273,21 @@ export function createDevServerPlatform() {
|
|
|
162
273
|
* @param {string} [root]
|
|
163
274
|
*/
|
|
164
275
|
async activate(root?: string) {
|
|
165
|
-
|
|
166
|
-
const res = await fetch("/__studio/activate", {
|
|
167
|
-
body: JSON.stringify({ root: r }),
|
|
168
|
-
headers: { "Content-Type": "application/json" },
|
|
169
|
-
method: "POST",
|
|
170
|
-
});
|
|
171
|
-
if (!res.ok) {
|
|
172
|
-
const body = (await readJson<ErrorBody>(res).catch(() => ({}))) as ErrorBody;
|
|
173
|
-
throw new Error(
|
|
174
|
-
`Could not open ${r}: ${problemDetail(body) ?? `activation failed (${res.status})`}`,
|
|
175
|
-
);
|
|
176
|
-
}
|
|
276
|
+
await postActivate(root ?? _projectRoot);
|
|
177
277
|
},
|
|
178
278
|
|
|
179
279
|
// ─── Project opening ──────────────────────────────────────────────────
|
|
180
280
|
|
|
181
281
|
async openProject() {
|
|
182
282
|
// Use Chrome's showDirectoryPicker API
|
|
183
|
-
|
|
283
|
+
const host = window;
|
|
284
|
+
if (!hasDirectoryPicker(host)) {
|
|
184
285
|
throw new Error("showDirectoryPicker not available — use a Chromium-based browser");
|
|
185
286
|
}
|
|
186
287
|
|
|
187
288
|
let dirHandle;
|
|
188
289
|
try {
|
|
189
|
-
dirHandle = await (
|
|
190
|
-
window as unknown as {
|
|
191
|
-
showDirectoryPicker: (opts: { mode: string }) => Promise<FileSystemDirectoryHandle>;
|
|
192
|
-
}
|
|
193
|
-
).showDirectoryPicker({ mode: "readwrite" });
|
|
290
|
+
dirHandle = await host.showDirectoryPicker({ mode: "readwrite" });
|
|
194
291
|
} catch (error) {
|
|
195
292
|
// User cancelled the picker
|
|
196
293
|
if (error instanceof Error && error.name === "AbortError") {
|
|
@@ -208,6 +305,9 @@ export function createDevServerPlatform() {
|
|
|
208
305
|
}
|
|
209
306
|
|
|
210
307
|
const file = await siteHandle.getFile();
|
|
308
|
+
/* SAFETY: the user picked this folder as a project, and project.json is that project's own
|
|
309
|
+
config file; it is matched below against the server's parse of the same file, and every
|
|
310
|
+
adapter hands project.json to Studio as the ProjectConfig the session edits. */
|
|
211
311
|
const config = JSON.parse(await file.text()) as ProjectConfig;
|
|
212
312
|
|
|
213
313
|
// Resolve server-relative path by matching against known sites
|
|
@@ -264,12 +364,7 @@ export function createDevServerPlatform() {
|
|
|
264
364
|
? await readJson<{ name: string; root: string }>(projectRes)
|
|
265
365
|
: { name: "project", root: "." };
|
|
266
366
|
const info = infoRes.ok
|
|
267
|
-
? await readJson<
|
|
268
|
-
isSiteProject: boolean;
|
|
269
|
-
projectConfig?: ProjectConfig | null;
|
|
270
|
-
directories?: string[];
|
|
271
|
-
[key: string]: unknown;
|
|
272
|
-
}>(infoRes)
|
|
367
|
+
? await readJson<ProjectInfoReply>(infoRes)
|
|
273
368
|
: { isSiteProject: false };
|
|
274
369
|
return { info, meta };
|
|
275
370
|
} catch {
|
|
@@ -282,27 +377,8 @@ export function createDevServerPlatform() {
|
|
|
282
377
|
/**
|
|
283
378
|
* Scaffold a project at `destination.parent/directory`. The dev server refuses the request
|
|
284
379
|
* outright when no destination is supplied — it will not fall back to its own root.
|
|
285
|
-
*
|
|
286
|
-
* @param {{
|
|
287
|
-
* name: string;
|
|
288
|
-
* description?: string;
|
|
289
|
-
* url?: string;
|
|
290
|
-
* adapter?: string;
|
|
291
|
-
* directory: string;
|
|
292
|
-
* destination: CreateProjectDestination;
|
|
293
|
-
* }} opts
|
|
294
380
|
*/
|
|
295
|
-
async createProject(opts: {
|
|
296
|
-
name: string;
|
|
297
|
-
description?: string;
|
|
298
|
-
url?: string;
|
|
299
|
-
adapter?: string;
|
|
300
|
-
directory: string;
|
|
301
|
-
destination: CreateProjectDestination;
|
|
302
|
-
starter?: string;
|
|
303
|
-
template?: string;
|
|
304
|
-
design?: Record<string, unknown>;
|
|
305
|
-
}) {
|
|
381
|
+
async createProject(opts: CreateProjectOptions) {
|
|
306
382
|
const res = await fetch("/__studio/create-project", {
|
|
307
383
|
body: JSON.stringify(opts),
|
|
308
384
|
headers: { "Content-Type": "application/json" },
|
|
@@ -315,37 +391,7 @@ export function createDevServerPlatform() {
|
|
|
315
391
|
return await res.json();
|
|
316
392
|
},
|
|
317
393
|
|
|
318
|
-
|
|
319
|
-
* Native folder chooser for the New Project modal's Browse… button. Present only when the
|
|
320
|
-
* browser implements `showDirectoryPicker` (Chromium-based); elsewhere the member stays
|
|
321
|
-
* undefined and the modal falls back to a typed Location field.
|
|
322
|
-
*
|
|
323
|
-
* The picked handle carries no filesystem path, so it is resolved by the id the picker tags the
|
|
324
|
-
* folder with (see `@jxsuite/studio/directory-picker`). Resolves `null` only when the user
|
|
325
|
-
* dismisses the chooser; every other failure rejects with a sentence the modal shows under
|
|
326
|
-
* Location. So `locate` keeps the helper's contract: `null` is "no folder holds this id" (the
|
|
327
|
-
* route's 200 `{ path: null }`), and a non-ok answer throws the problem the server sent rather
|
|
328
|
-
* than posing as a miss. A network failure (`TypeError: Failed to fetch`, e.g. a page that is
|
|
329
|
-
* not being served by the dev server at all) propagates as is, and the picker names it.
|
|
330
|
-
*/
|
|
331
|
-
...(canPickDirectory()
|
|
332
|
-
? {
|
|
333
|
-
async pickDirectory(): Promise<string | null> {
|
|
334
|
-
return pickDirectoryPath(async ({ id, name }) => {
|
|
335
|
-
const res = await fetch(
|
|
336
|
-
`/__studio/locate-directory?name=${encodeURIComponent(name)}&id=${encodeURIComponent(id)}`,
|
|
337
|
-
);
|
|
338
|
-
if (!res.ok) {
|
|
339
|
-
// A proxy, or a `views://` host with no dev server behind it, may answer in HTML.
|
|
340
|
-
const body: unknown = await res.json().catch(() => null);
|
|
341
|
-
throw new Error(problemMessage(body, res.status));
|
|
342
|
-
}
|
|
343
|
-
const found = await readJson<{ path?: string | null }>(res);
|
|
344
|
-
return found.path ?? null;
|
|
345
|
-
});
|
|
346
|
-
},
|
|
347
|
-
}
|
|
348
|
-
: {}),
|
|
394
|
+
...directoryPicking,
|
|
349
395
|
|
|
350
396
|
/** List starter templates from the dev server. */
|
|
351
397
|
async listStarters(): Promise<StarterInfo[]> {
|
|
@@ -374,7 +420,7 @@ export function createDevServerPlatform() {
|
|
|
374
420
|
if (!res.ok) {
|
|
375
421
|
throw new Error(`Failed to list directory: ${dir}`);
|
|
376
422
|
}
|
|
377
|
-
const entries = await readJson<
|
|
423
|
+
const entries = await readJson<DirEntry[]>(res);
|
|
378
424
|
for (const e of entries) {
|
|
379
425
|
e.path = stripRoot(e.path);
|
|
380
426
|
}
|
|
@@ -432,10 +478,14 @@ export function createDevServerPlatform() {
|
|
|
432
478
|
if (!res.ok) {
|
|
433
479
|
throw new Error(`Upload failed: ${path}`);
|
|
434
480
|
}
|
|
435
|
-
const body =
|
|
481
|
+
const body = await readJson<Partial<UploadResult>>(res);
|
|
436
482
|
// The dev server echoes the path today; falling back to the request keeps a backend that says
|
|
437
483
|
// Nothing working rather than writing `undefined` into a document.
|
|
438
|
-
|
|
484
|
+
const uploaded: UploadResult = { path: body.path ?? path };
|
|
485
|
+
if (body.size !== undefined) {
|
|
486
|
+
uploaded.size = body.size;
|
|
487
|
+
}
|
|
488
|
+
return uploaded;
|
|
439
489
|
},
|
|
440
490
|
|
|
441
491
|
/** @param {string} path */
|
|
@@ -514,13 +564,17 @@ export function createDevServerPlatform() {
|
|
|
514
564
|
es.addEventListener("open", () => {
|
|
515
565
|
opens += 1;
|
|
516
566
|
if (opens > 1) {
|
|
567
|
+
// A reconnect is usually a restarted server, which comes back bound to no project.
|
|
568
|
+
reclaimBinding();
|
|
517
569
|
options?.onResync?.("reconnect");
|
|
518
570
|
}
|
|
519
571
|
});
|
|
520
|
-
es.addEventListener("fs", (ev: MessageEvent) => {
|
|
521
|
-
let payload:
|
|
572
|
+
es.addEventListener("fs", (ev: MessageEvent<string>) => {
|
|
573
|
+
let payload: FsEventBatch;
|
|
522
574
|
try {
|
|
523
|
-
|
|
575
|
+
/* SAFETY: `fs` events on /__reload are sent only by @jxsuite/server's watcher, as
|
|
576
|
+
broadcastEvent("fs", { events }) over its batched FsEvent buffer (server watch.ts). */
|
|
577
|
+
payload = JSON.parse(ev.data) as FsEventBatch;
|
|
524
578
|
} catch {
|
|
525
579
|
return;
|
|
526
580
|
}
|
|
@@ -562,7 +616,7 @@ export function createDevServerPlatform() {
|
|
|
562
616
|
}
|
|
563
617
|
if (_collabProbe === null) {
|
|
564
618
|
_collabProbe = fetch("/__studio/collab")
|
|
565
|
-
.then(async (res) => (res.ok ? negotiateCollab(await res
|
|
619
|
+
.then(async (res) => (res.ok ? negotiateCollab(await readJson<JsonValue>(res)) : null))
|
|
566
620
|
.catch(() => null);
|
|
567
621
|
}
|
|
568
622
|
const negotiation = await _collabProbe;
|
|
@@ -659,7 +713,7 @@ export function createDevServerPlatform() {
|
|
|
659
713
|
if (!res.ok) {
|
|
660
714
|
return false;
|
|
661
715
|
}
|
|
662
|
-
const data =
|
|
716
|
+
const data = await readJson<{ needsInstall?: boolean }>(res);
|
|
663
717
|
return Boolean(data.needsInstall);
|
|
664
718
|
},
|
|
665
719
|
|
|
@@ -686,11 +740,8 @@ export function createDevServerPlatform() {
|
|
|
686
740
|
|
|
687
741
|
// ─── Code services (optional) ─────────────────────────────────────────
|
|
688
742
|
|
|
689
|
-
/**
|
|
690
|
-
|
|
691
|
-
* @param {unknown} payload
|
|
692
|
-
*/
|
|
693
|
-
async codeService(action: string, payload: unknown) {
|
|
743
|
+
/** Run one code-service action on the server; null when the route fails or is absent. */
|
|
744
|
+
async codeService(action: string, payload: Parameters<StudioPlatform["codeService"]>[1]) {
|
|
694
745
|
try {
|
|
695
746
|
const res = await fetch(`/__studio/code/${action}`, {
|
|
696
747
|
body: JSON.stringify(payload),
|
|
@@ -753,7 +804,7 @@ export function createDevServerPlatform() {
|
|
|
753
804
|
if (!res.ok) {
|
|
754
805
|
return [];
|
|
755
806
|
}
|
|
756
|
-
const entries = await readJson<
|
|
807
|
+
const entries = await readJson<DirEntry[]>(res);
|
|
757
808
|
for (const e of entries) {
|
|
758
809
|
e.path = stripRoot(e.path);
|
|
759
810
|
}
|
|
@@ -876,26 +927,26 @@ export function createDevServerPlatform() {
|
|
|
876
927
|
return data;
|
|
877
928
|
},
|
|
878
929
|
|
|
879
|
-
async dataInsertRow(req: DataRowInsert): Promise<
|
|
930
|
+
async dataInsertRow(req: DataRowInsert): Promise<DataRowWrite> {
|
|
880
931
|
const res = await fetch(`/__studio/data/rows?dir=${encodeURIComponent(serverPath("."))}`, {
|
|
881
932
|
body: JSON.stringify(req),
|
|
882
933
|
headers: { "Content-Type": "application/json" },
|
|
883
934
|
method: "POST",
|
|
884
935
|
});
|
|
885
|
-
const data = await readJson<
|
|
936
|
+
const data = await readJson<DataRowWrite & ErrorBody>(res);
|
|
886
937
|
if (!res.ok) {
|
|
887
938
|
throw new Error(problemDetail(data) ?? "Insert failed");
|
|
888
939
|
}
|
|
889
940
|
return data;
|
|
890
941
|
},
|
|
891
942
|
|
|
892
|
-
async dataUpdateRow(req: DataRowUpdate): Promise<
|
|
943
|
+
async dataUpdateRow(req: DataRowUpdate): Promise<DataRowWrite> {
|
|
893
944
|
const res = await fetch(`/__studio/data/rows?dir=${encodeURIComponent(serverPath("."))}`, {
|
|
894
945
|
body: JSON.stringify(req),
|
|
895
946
|
headers: { "Content-Type": "application/json" },
|
|
896
947
|
method: "PUT",
|
|
897
948
|
});
|
|
898
|
-
const data = await readJson<
|
|
949
|
+
const data = await readJson<DataRowWrite & ErrorBody>(res);
|
|
899
950
|
if (!res.ok) {
|
|
900
951
|
throw new Error(problemDetail(data) ?? "Update failed");
|
|
901
952
|
}
|
|
@@ -931,7 +982,7 @@ export function createDevServerPlatform() {
|
|
|
931
982
|
},
|
|
932
983
|
|
|
933
984
|
/** Write/remove secrets in the dev server's .dev.vars; names-only response. */
|
|
934
|
-
async setSecrets(req:
|
|
985
|
+
async setSecrets(req: KeyValuePatch): Promise<SecretsSetResponse> {
|
|
935
986
|
const res = await fetch(`/__studio/secrets?dir=${encodeURIComponent(serverPath("."))}`, {
|
|
936
987
|
body: JSON.stringify(req),
|
|
937
988
|
headers: { "Content-Type": "application/json" },
|
|
@@ -947,15 +998,17 @@ export function createDevServerPlatform() {
|
|
|
947
998
|
/**
|
|
948
999
|
* Invoke a format capability (parse/serialize) server-side.
|
|
949
1000
|
*
|
|
950
|
-
* @param
|
|
1001
|
+
* @param payload — { format, action, source?, doc?, options? }
|
|
951
1002
|
*/
|
|
952
|
-
async formatAction(payload:
|
|
1003
|
+
async formatAction(payload: Parameters<NonNullable<StudioPlatform["formatAction"]>>[0]) {
|
|
953
1004
|
const res = await fetch("/__studio/format", {
|
|
954
1005
|
body: JSON.stringify({ ...payload, dir: serverPath(".") }),
|
|
955
1006
|
headers: { "Content-Type": "application/json" },
|
|
956
1007
|
method: "POST",
|
|
957
1008
|
});
|
|
958
|
-
|
|
1009
|
+
/* The format route answers `{ result }` on success (the document a format class's `parse`
|
|
1010
|
+
built, or the text its `serialize` wrote) and a problem document otherwise. */
|
|
1011
|
+
const data = await readJson<JsonObject & { result: JxMutableNode | string }>(res);
|
|
959
1012
|
if (!res.ok) {
|
|
960
1013
|
throw new Error(problemDetail(data) ?? "Format action failed");
|
|
961
1014
|
}
|
|
@@ -981,14 +1034,13 @@ export function createDevServerPlatform() {
|
|
|
981
1034
|
if (!res.ok) {
|
|
982
1035
|
return null;
|
|
983
1036
|
}
|
|
984
|
-
const { schema } = await readJson<{ schema:
|
|
1037
|
+
const { schema } = await readJson<{ schema: JsonValue }>(res);
|
|
985
1038
|
return schema;
|
|
986
1039
|
},
|
|
987
1040
|
|
|
988
1041
|
// ─── Class resolution (dev-proxy) ─────────────────────────────────────
|
|
989
1042
|
|
|
990
|
-
|
|
991
|
-
async resolveClass(body: Record<string, unknown>) {
|
|
1043
|
+
async resolveClass(body: Parameters<NonNullable<StudioPlatform["resolveClass"]>>[0]) {
|
|
992
1044
|
const res = await fetch("/__jx_resolve__", {
|
|
993
1045
|
body: JSON.stringify(body),
|
|
994
1046
|
headers: { "content-type": "application/json" },
|
|
@@ -997,7 +1049,7 @@ export function createDevServerPlatform() {
|
|
|
997
1049
|
if (!res.ok) {
|
|
998
1050
|
throw new Error(`Class resolution failed: ${res.status}`);
|
|
999
1051
|
}
|
|
1000
|
-
return await readJson<
|
|
1052
|
+
return await readJson<JsonValue>(res);
|
|
1001
1053
|
},
|
|
1002
1054
|
|
|
1003
1055
|
// ─── Git operations ──────────────────────────────────────────────────
|
|
@@ -1194,7 +1246,7 @@ export function createDevServerPlatform() {
|
|
|
1194
1246
|
const body = await readJson<ErrorBody>(res);
|
|
1195
1247
|
throw new Error(problemDetail(body) ?? "The site could not be built.");
|
|
1196
1248
|
}
|
|
1197
|
-
return
|
|
1249
|
+
return await readJson<SiteBuildResult>(res);
|
|
1198
1250
|
},
|
|
1199
1251
|
|
|
1200
1252
|
/**
|
|
@@ -1213,7 +1265,7 @@ export function createDevServerPlatform() {
|
|
|
1213
1265
|
const body = await readJson<ErrorBody>(res);
|
|
1214
1266
|
throw new Error(problemDetail(body) ?? "The site could not be previewed.");
|
|
1215
1267
|
}
|
|
1216
|
-
return
|
|
1268
|
+
return await readJson<SitePreviewResult>(res);
|
|
1217
1269
|
},
|
|
1218
1270
|
|
|
1219
1271
|
async setPreviewOverlay(path: string, contents: string) {
|
|
@@ -1265,12 +1317,7 @@ export function createDevServerPlatform() {
|
|
|
1265
1317
|
headers: { "Content-Type": "application/json", "X-CF-Token": token },
|
|
1266
1318
|
body: JSON.stringify({ path: apiPath, method: init?.method ?? "GET", body: init?.body }),
|
|
1267
1319
|
});
|
|
1268
|
-
const envelope =
|
|
1269
|
-
success?: boolean;
|
|
1270
|
-
result?: unknown;
|
|
1271
|
-
errors?: { message: string }[];
|
|
1272
|
-
error?: string;
|
|
1273
|
-
};
|
|
1320
|
+
const envelope = await readJson<CfProxyEnvelope>(res);
|
|
1274
1321
|
if (!res.ok || envelope.success === false) {
|
|
1275
1322
|
const message =
|
|
1276
1323
|
envelope.errors?.map((e) => e.message).join("; ") ?? envelope.error ?? res.statusText;
|
|
@@ -1287,10 +1334,13 @@ export function createDevServerPlatform() {
|
|
|
1287
1334
|
return null;
|
|
1288
1335
|
}
|
|
1289
1336
|
try {
|
|
1290
|
-
const
|
|
1291
|
-
if (!
|
|
1337
|
+
const result = await this.cfApi("/accounts");
|
|
1338
|
+
if (!Array.isArray(result) || result.length === 0) {
|
|
1292
1339
|
return { connected: false };
|
|
1293
1340
|
}
|
|
1341
|
+
/* SAFETY: cfApi resolved the v4 envelope's `result`, and Cloudflare documents GET /accounts
|
|
1342
|
+
as answering an array of account objects, each with a string `id` and `name`. */
|
|
1343
|
+
const accounts = result as { id: string; name: string }[];
|
|
1294
1344
|
const chosen = accounts.find((a) => a.id === getCfAccountId()) ?? accounts[0]!;
|
|
1295
1345
|
setCfAccountId(chosen.id);
|
|
1296
1346
|
return { connected: true, accountId: chosen.id, accountName: chosen.name };
|
|
@@ -1308,14 +1358,11 @@ export function createDevServerPlatform() {
|
|
|
1308
1358
|
return [];
|
|
1309
1359
|
}
|
|
1310
1360
|
const sites = await readJson<SiteEntry[]>(res);
|
|
1311
|
-
return sites.map((site) => {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
description: site.path,
|
|
1317
|
-
};
|
|
1318
|
-
});
|
|
1361
|
+
return sites.map((site) => ({
|
|
1362
|
+
name: site.config?.name || site.path.split("/").at(-1) || site.path,
|
|
1363
|
+
root: site.path,
|
|
1364
|
+
description: site.path,
|
|
1365
|
+
}));
|
|
1319
1366
|
},
|
|
1320
1367
|
|
|
1321
1368
|
// ─── AI Assistant (Stack B: OpenAI-compatible SSE proxy) ───────────────────
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
import { READ_FILES_MAX_PATHS } from "@jxsuite/protocol";
|
|
23
23
|
import type { ReadFilesResult } from "@jxsuite/protocol";
|
|
24
|
+
import { isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* What one batch request came back as.
|
|
@@ -57,14 +58,20 @@ export interface ReadBatcher {
|
|
|
57
58
|
|
|
58
59
|
interface Waiter {
|
|
59
60
|
resolve: (content: string) => void;
|
|
60
|
-
|
|
61
|
+
/** Rejects with whatever the transport or `fetchOne` rejected with, unchanged. */
|
|
62
|
+
reject: (cause: unknown) => void;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
/** Path → every caller waiting on it. Same-path reads in one window share ONE request and result. */
|
|
64
66
|
type Pending = Map<string, Waiter[]>;
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
/**
|
|
69
|
+
* A row's outcome as the batcher reads it. Every protocol outcome fits it, but the rows come off
|
|
70
|
+
* the wire unchecked, so `content` may be any value and either member may be missing.
|
|
71
|
+
*/
|
|
72
|
+
interface WireOutcome {
|
|
73
|
+
content?: unknown;
|
|
74
|
+
error?: { message?: string } | undefined;
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
/**
|
|
@@ -108,7 +115,7 @@ export function createReadBatcher(options: ReadBatcherOptions): ReadBatcher {
|
|
|
108
115
|
waiter.resolve(content);
|
|
109
116
|
}
|
|
110
117
|
},
|
|
111
|
-
(error
|
|
118
|
+
(error) => {
|
|
112
119
|
for (const waiter of waiters) {
|
|
113
120
|
waiter.reject(error);
|
|
114
121
|
}
|
|
@@ -182,7 +189,7 @@ export function createReadBatcher(options: ReadBatcherOptions): ReadBatcher {
|
|
|
182
189
|
}
|
|
183
190
|
/* Anything that is not an object cannot be a ReadFilesResult (a `null` body, a bare string).
|
|
184
191
|
The route did not answer this chunk, so it is served singly — the same as a failed call. */
|
|
185
|
-
if (answer === "retry-singly" || answer === "unsupported" || !
|
|
192
|
+
if (answer === "retry-singly" || answer === "unsupported" || !isNonNullObject(answer)) {
|
|
186
193
|
if (answer === "unsupported") {
|
|
187
194
|
batching = false;
|
|
188
195
|
}
|
|
@@ -213,14 +220,15 @@ export function createReadBatcher(options: ReadBatcherOptions): ReadBatcher {
|
|
|
213
220
|
}
|
|
214
221
|
chunk.delete(path);
|
|
215
222
|
answered += 1;
|
|
216
|
-
|
|
217
|
-
|
|
223
|
+
const wire: WireOutcome | undefined = outcome;
|
|
224
|
+
const content = wire?.content;
|
|
225
|
+
if (isString(content)) {
|
|
218
226
|
for (const waiter of waiters) {
|
|
219
227
|
waiter.resolve(content);
|
|
220
228
|
}
|
|
221
229
|
} else {
|
|
222
230
|
// Per path: one missing file (404), one binary file (415) fails ITS readers and no others.
|
|
223
|
-
const message =
|
|
231
|
+
const message = wire?.error?.message;
|
|
224
232
|
const error = new Error(message || `Failed to read file: ${path}`);
|
|
225
233
|
for (const waiter of waiters) {
|
|
226
234
|
waiter.reject(error);
|
package/src/project-list.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* member (dev server sites, cloud platforms). Hydrated once at boot (studio.ts) like the
|
|
4
4
|
* recent-projects cache; the welcome screen reads it synchronously.
|
|
5
5
|
*/
|
|
6
|
+
import { isFunction } from "@jxsuite/schema/guards";
|
|
6
7
|
import { getPlatform, hasPlatform } from "./platform";
|
|
7
8
|
import type { ProjectListEntry } from "./types";
|
|
8
9
|
|
|
@@ -10,7 +11,7 @@ let cache: ProjectListEntry[] = [];
|
|
|
10
11
|
|
|
11
12
|
/** True when the active platform exposes a project catalogue. */
|
|
12
13
|
export function platformListsProjects(): boolean {
|
|
13
|
-
return hasPlatform() &&
|
|
14
|
+
return hasPlatform() && isFunction(getPlatform().listProjects);
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/** Refresh the cache from the platform; resolves to [] when unsupported or failing. */
|