@jxsuite/studio 4.0.0 → 5.0.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.
- package/README.md +1 -1
- package/data/elements-meta.json +5 -15
- package/data/html-meta.json +51 -6
- package/dist/chunks/{2020-xp8vnwma.js → 2020-g79n01v9.js} +14 -14
- package/dist/chunks/action-group-sp6tna8v.js +118 -0
- package/dist/chunks/adapter-nj7tnjfn.js +13 -0
- package/dist/chunks/cf-account-picker-fyf63pmy.js +495 -0
- package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
- package/dist/chunks/color-area-v17df7b8.js +154 -0
- package/dist/chunks/color-field-anwybnkn.js +208 -0
- package/dist/chunks/color-slider-44ez96fc.js +79 -0
- package/dist/chunks/color-xgg3kfw7.js +35 -0
- package/dist/chunks/combobox-5e7jev23.js +236 -0
- package/dist/chunks/components-2w1f35qs.js +18 -0
- package/dist/chunks/content-source-3wqeas45.js +46 -0
- package/dist/chunks/convert-to-repeater-d0cgnb6d.js +639 -0
- package/dist/chunks/dialog-s890b918.js +85 -0
- package/dist/chunks/editor-3qhbg51x.js +35 -0
- package/dist/chunks/entry-commands-d6g50j7s.js +42 -0
- package/dist/chunks/extension-sections-fy7q4fe9.js +651 -0
- package/dist/chunks/file-ops-3btj6st0.js +47 -0
- package/dist/chunks/files-ef8fgs3w.js +72 -0
- package/dist/chunks/format-host-3c33nwr8.js +40 -0
- package/dist/chunks/fs-events-13tj6sex.js +18 -0
- package/dist/chunks/git-panel-4wp2rn9b.js +49 -0
- package/dist/chunks/icons-yy10wk9r.js +402 -0
- package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
- package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
- package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
- package/dist/chunks/iframe-host-jgesd924.js +115 -0
- package/dist/chunks/{index-nj44jpzj.js → index-mdmyx6s2.js} +11 -11
- package/dist/chunks/index-n4j7qxyr.js +109 -0
- package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
- package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
- package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
- package/dist/chunks/layers-1nq5evsh.js +29 -0
- package/dist/chunks/layers-panel-ar2gh90g.js +40 -0
- package/dist/chunks/listbox-6v2ac08j.js +44 -0
- package/dist/chunks/lit-html-m244w9nh.js +17 -0
- package/dist/chunks/media-picker-2qbetq73.js +33 -0
- package/dist/chunks/menu-q99sy9rf.js +285 -0
- package/dist/chunks/menu-rf7n72mf.js +14 -0
- package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
- package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
- package/dist/chunks/{monaco-setup-rws7k4br.js → monaco-setup-8r62fj6y.js} +27 -37
- package/dist/chunks/notify-628t0anh.js +21 -0
- package/dist/chunks/number-field-5cndyft8.js +72 -0
- package/dist/chunks/parse-0zx14y15.js +10 -0
- package/dist/chunks/platform-ts9cg1a4.js +15 -0
- package/dist/chunks/popover-47z3ytva.js +25 -0
- package/dist/chunks/publish-panel-98f7sr3g.js +27 -0
- package/dist/chunks/quick-search-srzz83k2.js +45 -0
- package/dist/chunks/references-n553f0e1.js +26 -0
- package/dist/chunks/right-panel-rrgx2dn3.js +45 -0
- package/dist/chunks/section-registry-5pq32t0q.js +25 -0
- package/dist/chunks/select-2r16ez41.js +49 -0
- package/dist/chunks/split-g7nm1rgb.js +191 -0
- package/dist/chunks/studio-0hqbpbd0.js +62 -0
- package/dist/chunks/studio-18avnhjp.js +2430 -0
- package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
- package/dist/chunks/{studio-hbtp0eh1.js → studio-25hkdrkw.js} +356 -85
- package/dist/chunks/studio-26d7myd1.js +258 -0
- package/dist/chunks/{studio-p8j86wag.js → studio-38emantv.js} +22 -5
- package/dist/chunks/studio-3gxv60tn.js +422 -0
- package/dist/chunks/{studio-8swrjbny.js → studio-3hxkd92t.js} +275 -163
- package/dist/chunks/studio-4m0haseg.js +185 -0
- package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
- package/dist/chunks/{studio-gv8vvshc.js → studio-5523bpzt.js} +11 -11
- package/dist/chunks/{studio-5q69gfag.js → studio-57mf66w2.js} +1753 -2484
- package/dist/chunks/studio-5jy81t3s.js +17463 -0
- package/dist/chunks/studio-5rt7sqa0.js +1168 -0
- package/dist/chunks/studio-5te5tqng.js +81 -0
- package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
- package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
- package/dist/chunks/studio-6xa21ej9.js +28 -0
- package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
- package/dist/chunks/{studio-eenfkt4e.js → studio-79y5sz51.js} +52 -38
- package/dist/chunks/{studio-4q0wznzf.js → studio-7e11jpa9.js} +461 -145
- package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
- package/dist/chunks/studio-7xptrg0j.js +954 -0
- package/dist/chunks/{studio-cft9r4r7.js → studio-81390n6f.js} +22 -22
- package/dist/chunks/{studio-q43a5y9h.js → studio-8jn5yhyn.js} +16 -16
- package/dist/chunks/studio-8qtrpzr3.js +839 -0
- package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
- package/dist/chunks/studio-9xxz1q69.js +1356 -0
- package/dist/chunks/studio-akbww0j5.js +13615 -0
- package/dist/chunks/studio-arfpe389.js +195 -0
- package/dist/chunks/{studio-2zkz8evn.js → studio-az3zd49t.js} +473 -281
- package/dist/chunks/studio-cpvb2ed1.js +1171 -0
- package/dist/chunks/{studio-9r6j5ev1.js → studio-d0300636.js} +5078 -19
- package/dist/chunks/{studio-bgxt93ga.js → studio-d055c37e.js} +13 -13
- package/dist/chunks/studio-d1ja2x9r.js +362 -0
- package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
- package/dist/chunks/{studio-4pqqxbrt.js → studio-em9nw8eh.js} +301 -112
- package/dist/chunks/studio-erdatzvp.js +1190 -0
- package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
- package/dist/chunks/studio-fabxk6r9.js +2811 -0
- package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
- package/dist/chunks/studio-hhvs4sdg.js +195 -0
- package/dist/chunks/{studio-68n67094.js → studio-kcgff4r0.js} +15 -18
- package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
- package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
- package/dist/chunks/studio-pm6hgy7r.js +4763 -0
- package/dist/chunks/studio-q0a3yk4n.js +33 -0
- package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
- package/dist/chunks/studio-qahxvnan.js +111 -0
- package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
- package/dist/chunks/{studio-kjjsjak4.js → studio-rkstz940.js} +3661 -6136
- package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
- package/dist/chunks/studio-rpyah2ew.js +2805 -0
- package/dist/chunks/studio-rs76k67r.js +12 -0
- package/dist/chunks/{studio-yxrkyv8a.js → studio-s6z853aq.js} +12108 -11766
- package/dist/chunks/{studio-sf7zjgv1.js → studio-sgdc5pfc.js} +8 -8
- package/dist/chunks/studio-tb3ev01j.js +763 -0
- package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
- package/dist/chunks/studio-vhv5tgxm.js +51 -0
- package/dist/chunks/{studio-htsf0w6m.js → studio-vz68yn9e.js} +31 -154
- package/dist/chunks/studio-wqpngpsk.js +174 -0
- package/dist/chunks/{studio-eesa1myv.js → studio-x3rty6tr.js} +58 -58
- package/dist/chunks/studio-xsykpvsh.js +8448 -0
- package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
- package/dist/chunks/studio-yxa81f45.js +12 -0
- package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
- package/dist/chunks/tabs-wbp1cdws.js +156 -0
- package/dist/chunks/textfield-abk6qyee.js +73 -0
- package/dist/chunks/toast-780pvfbv.js +27 -0
- package/dist/chunks/toast-host-3sqv46sn.js +116 -0
- package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
- package/dist/chunks/tooltip-eptb614w.js +369 -0
- package/dist/chunks/tree-a73p0pqm.js +367 -0
- package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
- package/dist/chunks/workspace-wrew8zk4.js +69 -0
- package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
- package/dist/iframe-entry.js +1812 -698
- package/dist/manifest.json +7 -0
- package/dist/studio.js +52900 -36573
- package/dist/workers/editor.worker.js +1040 -1085
- package/dist/workers/json.worker.js +1946 -1991
- package/dist/workers/ts.worker.js +4960 -5005
- package/favicon.ico +0 -0
- package/index.html +2 -0
- package/package.json +22 -55
- package/src/about/about-modal.ts +73 -123
- package/src/browse/library-commands.ts +20 -49
- package/src/browse/library-layouts.ts +87 -218
- package/src/browse/library-pane.ts +406 -438
- package/src/canvas/canvas-helpers.ts +0 -49
- package/src/canvas/canvas-live-render.ts +25 -2
- package/src/canvas/canvas-render.ts +666 -231
- package/src/canvas/canvas-surface.ts +0 -1
- package/src/canvas/canvas-utils.ts +310 -117
- package/src/canvas/dialog-path.ts +76 -0
- package/src/canvas/dialog-state.ts +67 -0
- package/src/canvas/diff-marks.ts +252 -0
- package/src/canvas/diff-toolbar.ts +349 -0
- package/src/canvas/diff-view.ts +123 -0
- package/src/canvas/edit-width-drag.ts +187 -0
- package/src/canvas/edit-width.ts +150 -0
- package/src/canvas/iframe-entry.ts +125 -8
- package/src/canvas/iframe-host.ts +271 -15
- package/src/canvas/iframe-interaction.ts +133 -13
- package/src/canvas/iframe-patch.ts +7 -1
- package/src/canvas/iframe-position.ts +5 -6
- package/src/canvas/iframe-protocol.ts +106 -5
- package/src/canvas/iframe-render.ts +373 -5
- package/src/canvas/iframe-slash.ts +2 -2
- package/src/canvas/iframe-subtree.ts +5 -8
- package/src/canvas/path-mapping.ts +25 -3
- package/src/canvas/popover-path.ts +106 -0
- package/src/canvas/popover-state.ts +155 -0
- package/src/canvas/surface-registry.ts +21 -10
- package/src/collab/presence-chips.ts +51 -73
- package/src/commands/app-commands.ts +10 -0
- package/src/commands/budget.ts +12 -0
- package/src/commands/command-args.ts +369 -6
- package/src/commands/defaults.ts +44 -14
- package/src/commands/live-context.ts +11 -5
- package/src/commands/reference.ts +12 -2
- package/src/commands/registry.ts +165 -8
- package/src/content/entry-commands.ts +16 -23
- package/src/content/entry-editor.ts +144 -101
- package/src/editor/canvas-slash-bridge.ts +2 -2
- package/src/editor/context-menu.ts +49 -200
- package/src/editor/convert-to-component.ts +42 -82
- package/src/editor/convert-to-repeater.ts +132 -173
- package/src/editor/inline-edit.ts +11 -0
- package/src/editor/shortcuts.ts +65 -26
- package/src/editor/slash-menu.ts +150 -157
- package/src/files/file-ops.ts +117 -11
- package/src/files/files.ts +949 -664
- package/src/files/json-layout.ts +474 -0
- package/src/files/media-paths.ts +13 -42
- package/src/files/media-usage.ts +41 -131
- package/src/files/serialize-document.ts +8 -1
- package/src/format/convert-file.ts +16 -10
- package/src/format/format-host.ts +50 -1
- package/src/github/github-auth.ts +71 -29
- package/src/github/github-publish.ts +57 -65
- package/src/grid/cell-editors.ts +46 -4
- package/src/grid/cell-popovers.ts +65 -62
- package/src/grid/grid-open.ts +86 -64
- package/src/grid/grid-panel.ts +390 -469
- package/src/grid/redirects-grid.ts +40 -44
- package/src/hosting/document.ts +2 -0
- package/src/hosting/layout.ts +10 -0
- package/src/i18n/i18n-commands.ts +127 -62
- package/src/media/media-pane.ts +83 -133
- package/src/new-project/add-repo-modal.ts +125 -176
- package/src/new-project/import-tab.ts +201 -250
- package/src/new-project/location-fields.ts +101 -165
- package/src/new-project/new-project-modal.ts +376 -367
- package/src/packages/jxsuite-update.ts +76 -18
- package/src/panels/activity-panel.ts +137 -104
- package/src/panels/ai-chat/chat-markdown.ts +15 -13
- package/src/panels/ai-chat/chat-view.ts +307 -472
- package/src/panels/ai-chat/composer.ts +175 -153
- package/src/panels/ai-chat/sessions-view.ts +31 -62
- package/src/panels/ai-panel.ts +210 -185
- package/src/panels/block-action-bar.ts +437 -643
- package/src/panels/bottom-dock.ts +112 -47
- package/src/panels/chat-panel.ts +19 -14
- package/src/panels/data-explorer.ts +141 -102
- package/src/panels/data-grid.ts +183 -150
- package/src/panels/dnd.ts +75 -20
- package/src/panels/editors.ts +26 -19
- package/src/panels/elements-panel.ts +243 -186
- package/src/panels/empty-state.ts +26 -42
- package/src/panels/events-panel.ts +950 -729
- package/src/panels/formula-workspace.ts +434 -207
- package/src/panels/frontmatter-fields.ts +185 -153
- package/src/panels/frontmatter-panel.ts +411 -187
- package/src/panels/git-diff-open.ts +148 -0
- package/src/panels/git-panel.ts +679 -605
- package/src/panels/head-panel.ts +617 -435
- package/src/panels/i18n-panel.ts +153 -133
- package/src/panels/imports-panel.ts +388 -414
- package/src/panels/jump-bar.ts +174 -147
- package/src/panels/layers-panel.ts +785 -671
- package/src/panels/left-panel.ts +166 -94
- package/src/panels/navigator-panels.ts +1 -1
- package/src/panels/pane-context.ts +529 -677
- package/src/panels/pane-grid.ts +265 -241
- package/src/panels/panel-registry.ts +15 -4
- package/src/panels/problems-panel.ts +177 -99
- package/src/panels/properties-panel.ts +1525 -966
- package/src/panels/provenance.ts +31 -113
- package/src/panels/quick-search.ts +217 -172
- package/src/panels/right-panel.ts +135 -169
- package/src/panels/seo-modal.ts +346 -167
- package/src/panels/settings-menu.ts +109 -646
- package/src/panels/settings-pane.ts +102 -86
- package/src/panels/signals-panel.ts +1318 -1172
- package/src/panels/statement-editor.ts +556 -428
- package/src/panels/style-panel.ts +1367 -630
- package/src/panels/style-utils.ts +36 -32
- package/src/panels/stylebook-doc.ts +30 -73
- package/src/panels/stylebook-layers-panel.ts +202 -109
- package/src/panels/stylebook-panel.ts +124 -88
- package/src/panels/tab-strip.ts +385 -287
- package/src/platforms/cloud.ts +347 -86
- package/src/platforms/devserver.ts +13 -0
- package/src/publish/deploy-checklist.ts +124 -78
- package/src/publish/publish-commands.ts +4 -12
- package/src/publish/publish-panel.ts +165 -299
- package/src/services/a11y-report.ts +100 -43
- package/src/services/ai-command-tools.ts +468 -0
- package/src/services/ai-import-tools.ts +50 -12
- package/src/services/ai-models.ts +108 -1
- package/src/services/ai-session-store.ts +6 -0
- package/src/services/ai-system-prompt.ts +110 -18
- package/src/services/ai-tools.ts +28 -143
- package/src/services/ai-write-report.ts +174 -0
- package/src/services/context-manager.ts +12 -1
- package/src/services/document-assistant.ts +50 -2
- package/src/services/idle.ts +16 -14
- package/src/services/live-surfaces.ts +237 -0
- package/src/services/model-uri.ts +75 -0
- package/src/services/notify.ts +63 -6
- package/src/services/popover-report.ts +325 -0
- package/src/services/surface-registry.ts +56 -0
- package/src/services/tool-executor.ts +17 -0
- package/src/settings/contexts-section.ts +301 -299
- package/src/settings/contributed-section.ts +361 -222
- package/src/settings/css-vars-editor.ts +320 -325
- package/src/settings/defs-editor.ts +572 -535
- package/src/settings/dependencies-editor.ts +79 -107
- package/src/settings/extension-commands.ts +379 -0
- package/src/settings/extension-rows.ts +113 -0
- package/src/settings/extensions-section.ts +287 -0
- package/src/settings/general-settings.ts +130 -181
- package/src/settings/head-editor.ts +10 -305
- package/src/settings/locales-section.ts +146 -196
- package/src/settings/preferences-accounts.ts +193 -12
- package/src/settings/preferences-dialog.ts +384 -307
- package/src/settings/project-sections.ts +108 -181
- package/src/settings/schema-field-ui.ts +11 -399
- package/src/settings/section-registry.ts +8 -1
- package/src/settings/settings-document.ts +31 -29
- package/src/shell/tree.ts +42 -87
- package/src/shell.ts +48 -36
- package/src/studio.ts +90 -67
- package/src/style/token-ref.ts +0 -39
- package/src/surfaces/about.json +263 -0
- package/src/surfaces/about.ts +163 -0
- package/src/surfaces/add-repo.json +486 -0
- package/src/surfaces/add-repo.ts +236 -0
- package/src/surfaces/ai-chat.json +2185 -0
- package/src/surfaces/ai-chat.ts +549 -0
- package/src/surfaces/ai-credentials-form.json +332 -0
- package/src/surfaces/ai-credentials-form.ts +151 -0
- package/src/surfaces/ai-managed-connect.json +108 -0
- package/src/surfaces/ai-managed-connect.ts +123 -0
- package/src/surfaces/ai-model-picker.json +114 -0
- package/src/surfaces/ai-model-picker.ts +139 -0
- package/src/surfaces/block-action-bar.json +640 -0
- package/src/surfaces/block-action-bar.ts +368 -0
- package/src/surfaces/bottom-dock.json +154 -0
- package/src/surfaces/bottom-dock.ts +125 -0
- package/src/surfaces/canvas-stage.json +444 -0
- package/src/surfaces/canvas-stage.ts +253 -0
- package/src/surfaces/cf-account-picker.json +300 -0
- package/src/surfaces/cf-account-picker.ts +214 -0
- package/src/surfaces/commandbar.json +984 -0
- package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
- package/src/surfaces/convert-repeater.json +309 -0
- package/src/surfaces/convert-repeater.ts +276 -0
- package/src/surfaces/data-actions.json +157 -0
- package/src/surfaces/data-actions.ts +115 -0
- package/src/surfaces/dialog.json +289 -0
- package/src/surfaces/dialog.ts +343 -0
- package/src/surfaces/diff-toolbar.json +266 -0
- package/src/surfaces/diff-toolbar.ts +139 -0
- package/src/surfaces/doc-header.json +739 -0
- package/src/surfaces/doc-header.ts +223 -0
- package/src/surfaces/empty-state.json +152 -0
- package/src/surfaces/empty-state.ts +173 -0
- package/src/surfaces/entry-editor.json +281 -0
- package/src/surfaces/entry-editor.ts +191 -0
- package/src/surfaces/expression-editor.json +977 -0
- package/src/surfaces/expression-editor.ts +266 -0
- package/src/surfaces/files-panel.json +592 -0
- package/src/surfaces/files-panel.ts +301 -0
- package/src/surfaces/formula-palette.json +364 -0
- package/src/surfaces/formula-palette.ts +340 -0
- package/src/surfaces/git-panel.json +1822 -0
- package/src/surfaces/git-panel.ts +272 -0
- package/src/surfaces/github-auth.json +112 -0
- package/src/surfaces/github-auth.ts +139 -0
- package/src/surfaces/github-publish.json +206 -0
- package/src/surfaces/github-publish.ts +169 -0
- package/src/surfaces/grid-cell.json +218 -0
- package/src/surfaces/grid-cell.ts +120 -0
- package/src/surfaces/grid-open.json +147 -0
- package/src/surfaces/grid-open.ts +87 -0
- package/src/surfaces/grid-panel.json +706 -0
- package/src/surfaces/grid-panel.ts +206 -0
- package/src/surfaces/grid-replace.json +179 -0
- package/src/surfaces/grid-replace.ts +89 -0
- package/src/surfaces/grid-views.json +446 -0
- package/src/surfaces/grid-views.ts +172 -0
- package/src/surfaces/inspector-dock.json +187 -0
- package/src/surfaces/inspector-dock.ts +161 -0
- package/src/surfaces/jump-bar.json +243 -0
- package/src/surfaces/jump-bar.ts +129 -0
- package/src/surfaces/jxsuite-update.json +146 -0
- package/src/surfaces/jxsuite-update.ts +149 -0
- package/src/surfaces/library-pane.json +1509 -0
- package/src/surfaces/library-pane.ts +363 -0
- package/src/surfaces/logic-panel.json +1949 -0
- package/src/surfaces/logic-panel.ts +369 -0
- package/src/surfaces/logic-workspace.json +685 -0
- package/src/surfaces/logic-workspace.ts +238 -0
- package/src/surfaces/media-browser.json +303 -0
- package/src/surfaces/media-browser.ts +145 -0
- package/src/surfaces/media-field.json +163 -0
- package/src/surfaces/media-field.ts +116 -0
- package/src/surfaces/media-pane.json +513 -0
- package/src/surfaces/media-pane.ts +197 -0
- package/src/surfaces/menu.json +232 -0
- package/src/surfaces/menu.ts +375 -0
- package/src/surfaces/navigator-dock.json +113 -0
- package/src/surfaces/navigator-dock.ts +130 -0
- package/src/surfaces/new-project.json +1654 -0
- package/src/surfaces/new-project.ts +411 -0
- package/src/surfaces/palette.json +535 -0
- package/src/surfaces/pane-context.json +1497 -0
- package/src/surfaces/pane-context.ts +513 -0
- package/src/surfaces/pane-grid.json +188 -0
- package/src/surfaces/pane-grid.ts +250 -0
- package/src/surfaces/panel-activity.json +563 -0
- package/src/surfaces/panel-activity.ts +187 -0
- package/src/surfaces/panel-data.json +141 -0
- package/src/surfaces/panel-data.ts +156 -0
- package/src/surfaces/panel-deploy-checklist.json +283 -0
- package/src/surfaces/panel-deploy-checklist.ts +175 -0
- package/src/surfaces/panel-elements.json +367 -0
- package/src/surfaces/panel-elements.ts +175 -0
- package/src/surfaces/panel-i18n.json +569 -0
- package/src/surfaces/panel-i18n.ts +212 -0
- package/src/surfaces/panel-imports.json +780 -0
- package/src/surfaces/panel-imports.ts +209 -0
- package/src/surfaces/panel-outline.json +734 -0
- package/src/surfaces/panel-outline.ts +326 -0
- package/src/surfaces/panel-page.json +1017 -0
- package/src/surfaces/panel-page.ts +240 -0
- package/src/surfaces/panel-problems.json +497 -0
- package/src/surfaces/panel-problems.ts +157 -0
- package/src/surfaces/panel-signals.json +1973 -0
- package/src/surfaces/panel-signals.ts +436 -0
- package/src/surfaces/panel-stylebook-layers.json +317 -0
- package/src/surfaces/panel-stylebook-layers.ts +155 -0
- package/src/surfaces/preferences.json +850 -0
- package/src/surfaces/preferences.ts +332 -0
- package/src/surfaces/progress-modal.json +110 -0
- package/src/surfaces/progress-modal.ts +150 -0
- package/src/surfaces/properties-panel.json +1578 -0
- package/src/surfaces/properties-panel.ts +337 -0
- package/src/surfaces/publish.json +945 -0
- package/src/surfaces/publish.ts +392 -0
- package/src/surfaces/push-plan.json +110 -0
- package/src/surfaces/push-plan.ts +87 -0
- package/src/surfaces/rail.json +255 -0
- package/src/surfaces/rail.ts +206 -0
- package/src/surfaces/reference-field.json +191 -0
- package/src/surfaces/reference-field.ts +168 -0
- package/src/surfaces/schema-builder.json +1011 -0
- package/src/surfaces/schema-builder.ts +181 -0
- package/src/surfaces/schema-form.json +1013 -0
- package/src/surfaces/schema-form.ts +287 -0
- package/src/surfaces/secret-field.json +60 -0
- package/src/surfaces/secret-field.ts +146 -0
- package/src/surfaces/seo.json +932 -0
- package/src/surfaces/seo.ts +334 -0
- package/src/surfaces/settings-contexts.json +538 -0
- package/src/surfaces/settings-contexts.ts +196 -0
- package/src/surfaces/settings-contributed.json +489 -0
- package/src/surfaces/settings-contributed.ts +199 -0
- package/src/surfaces/settings-css-vars.json +820 -0
- package/src/surfaces/settings-css-vars.ts +199 -0
- package/src/surfaces/settings-defs.json +1363 -0
- package/src/surfaces/settings-defs.ts +232 -0
- package/src/surfaces/settings-deploy.json +108 -0
- package/src/surfaces/settings-deploy.ts +135 -0
- package/src/surfaces/settings-extensions.json +486 -0
- package/src/surfaces/settings-extensions.ts +201 -0
- package/src/surfaces/settings-head.json +779 -0
- package/src/surfaces/settings-head.ts +397 -0
- package/src/surfaces/settings-locales.json +420 -0
- package/src/surfaces/settings-locales.ts +137 -0
- package/src/surfaces/settings-overview.json +423 -0
- package/src/surfaces/settings-overview.ts +218 -0
- package/src/surfaces/settings-packages.json +549 -0
- package/src/surfaces/settings-packages.ts +158 -0
- package/src/surfaces/settings-pane.json +147 -0
- package/src/surfaces/settings-pane.ts +150 -0
- package/src/surfaces/settings-rawjson.json +104 -0
- package/src/surfaces/settings-rawjson.ts +107 -0
- package/src/surfaces/shell.json +99 -0
- package/src/surfaces/shell.ts +30 -0
- package/src/surfaces/slash-menu.json +180 -0
- package/src/surfaces/slash-menu.ts +272 -0
- package/src/surfaces/statements.json +607 -0
- package/src/surfaces/statements.ts +238 -0
- package/src/surfaces/statusbar.json +94 -0
- package/src/{panels → surfaces}/statusbar.ts +163 -90
- package/src/surfaces/style-panel.json +1643 -0
- package/src/surfaces/style-panel.ts +338 -0
- package/src/surfaces/stylebook-chrome.json +122 -0
- package/src/surfaces/stylebook-chrome.ts +122 -0
- package/src/surfaces/tab-strip.json +448 -0
- package/src/surfaces/tab-strip.ts +200 -0
- package/src/surfaces/target-line.json +419 -0
- package/src/surfaces/target-line.ts +349 -0
- package/src/surfaces/toasts.json +189 -0
- package/src/surfaces/welcome.json +571 -0
- package/src/surfaces/welcome.ts +338 -0
- package/src/tabs/project-config.ts +71 -15
- package/src/tabs/tab.ts +52 -1
- package/src/types.ts +49 -3
- package/src/ui/ai-credentials-form.ts +104 -100
- package/src/ui/ai-managed-connect.ts +116 -49
- package/src/ui/ai-model-picker.ts +102 -47
- package/src/ui/cf-account-picker.ts +135 -0
- package/src/ui/color-selector.ts +80 -301
- package/src/ui/dynamic-slot.ts +43 -283
- package/src/ui/expression-editor.ts +797 -576
- package/src/ui/field-input.ts +8 -181
- package/src/ui/form-controls.ts +838 -366
- package/src/ui/formula-chips.ts +80 -85
- package/src/ui/kit.ts +33 -0
- package/src/ui/layers.ts +293 -593
- package/src/ui/media-picker.ts +203 -284
- package/src/ui/panel-resize.ts +251 -64
- package/src/ui/popover-surface.ts +153 -0
- package/src/ui/progress-modal.ts +22 -60
- package/src/ui/regions.ts +13 -7
- package/src/ui/schema-form.ts +906 -440
- package/src/ui/surface.ts +122 -0
- package/src/ui/unit-selector.ts +15 -131
- package/src/ui/value-source.ts +14 -0
- package/src/ui/virtual-window.ts +88 -9
- package/src/utils/canvas-media.ts +72 -0
- package/src/utils/edit-display.ts +7 -2
- package/src/utils/element-selectors.ts +69 -0
- package/src/utils/link-target.ts +2 -2
- package/src/utils/studio-utils.ts +0 -10
- package/src/view.ts +15 -0
- package/src/workspace/pane-derive.ts +36 -14
- package/src/workspace/workspace.ts +15 -6
- package/styles/canvas.css +72 -467
- package/styles/forced-colors.css +48 -82
- package/styles/forced-colors.json +41 -0
- package/styles/inspector.css +2 -1301
- package/styles/overlays.css +96 -2823
- package/styles/panels.css +6 -1423
- package/styles/shell-frame.css +272 -0
- package/styles/shell-frame.json +227 -0
- package/styles/shell.css +0 -1532
- package/styles/tokens.css +65 -136
- package/styles/tokens.json +84 -0
- package/dist/chunks/Overlay.dev-723bv0df.js +0 -23
- package/dist/chunks/adapter-jkcyhgtr.js +0 -14
- package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
- package/dist/chunks/components-zmx10t62.js +0 -21
- package/dist/chunks/content-source-t88vb2dr.js +0 -49
- package/dist/chunks/convert-to-repeater-dhw1nrz9.js +0 -268
- package/dist/chunks/editor-cptq5jp1.js +0 -37
- package/dist/chunks/entry-commands-6z6bhxg0.js +0 -46
- package/dist/chunks/extension-sections-3ydgjbdy.js +0 -311
- package/dist/chunks/file-ops-rskmhxyq.js +0 -48
- package/dist/chunks/files-0cratsr0.js +0 -92
- package/dist/chunks/flow-qbfgrpeh.js +0 -634
- package/dist/chunks/focus-trap.esm-ggawf1hy.js +0 -1024
- package/dist/chunks/focus-visible-6eg70z18.js +0 -167
- package/dist/chunks/format-host-tgcmfs4p.js +0 -43
- package/dist/chunks/fs-events-hrrg328g.js +0 -21
- package/dist/chunks/git-panel-0yywyk76.js +0 -58
- package/dist/chunks/index-zqxmqxmh.js +0 -109
- package/dist/chunks/jx-validate-8q2g05x1.js +0 -19
- package/dist/chunks/layers-panel-z3tqe5cd.js +0 -67
- package/dist/chunks/layers-q75tj2mf.js +0 -45
- package/dist/chunks/lit-html-j055mkh8.js +0 -22
- package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
- package/dist/chunks/notify-yjm79n4s.js +0 -30
- package/dist/chunks/parse-24d0gay3.js +0 -19
- package/dist/chunks/platform-ba1j1gbh.js +0 -16
- package/dist/chunks/publish-panel-54jvhskq.js +0 -28
- package/dist/chunks/quick-search-cgfmjwq5.js +0 -65
- package/dist/chunks/references-3qx8fkyp.js +0 -29
- package/dist/chunks/right-panel-cqp8bc4v.js +0 -46
- package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
- package/dist/chunks/sp-overlay.dev-yztmtrs1.js +0 -18
- package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
- package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
- package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +0 -15
- package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
- package/dist/chunks/studio-0a5qrh01.js +0 -3
- package/dist/chunks/studio-18j3bmcz.js +0 -14
- package/dist/chunks/studio-1hbqnt19.js +0 -1823
- package/dist/chunks/studio-4rzyrtjz.js +0 -426
- package/dist/chunks/studio-5rywrkxz.js +0 -1903
- package/dist/chunks/studio-7afd21nw.js +0 -67
- package/dist/chunks/studio-7nte2hj4.js +0 -613
- package/dist/chunks/studio-8jpzqk5s.js +0 -128
- package/dist/chunks/studio-8q517dfr.js +0 -24
- package/dist/chunks/studio-9c4k4vhv.js +0 -357
- package/dist/chunks/studio-9n4mrmnb.js +0 -184
- package/dist/chunks/studio-a0tswy0w.js +0 -58
- package/dist/chunks/studio-ahjfdy6e.js +0 -387
- package/dist/chunks/studio-ahnzd9rg.js +0 -23
- package/dist/chunks/studio-bw5dz6km.js +0 -608
- package/dist/chunks/studio-cb12yz9w.js +0 -15055
- package/dist/chunks/studio-d1ks410h.js +0 -175
- package/dist/chunks/studio-eqq1w638.js +0 -113
- package/dist/chunks/studio-ex8zyp98.js +0 -1813
- package/dist/chunks/studio-h4rxscfc.js +0 -10
- package/dist/chunks/studio-kyh9avvv.js +0 -28
- package/dist/chunks/studio-kyk2v92a.js +0 -659
- package/dist/chunks/studio-m3hwn7y1.js +0 -120
- package/dist/chunks/studio-mmv72a27.js +0 -4344
- package/dist/chunks/studio-n8b9wqwy.js +0 -291
- package/dist/chunks/studio-pdfjntbk.js +0 -6939
- package/dist/chunks/studio-qq6jym04.js +0 -53
- package/dist/chunks/studio-r1r7afxx.js +0 -1066
- package/dist/chunks/studio-rdx8jcxy.js +0 -83
- package/dist/chunks/studio-rn9ta2mz.js +0 -111
- package/dist/chunks/studio-t7qb9db8.js +0 -665
- package/dist/chunks/studio-tmc5emrw.js +0 -8
- package/dist/chunks/studio-txwkm6p9.js +0 -12
- package/dist/chunks/studio-v38hmvx1.js +0 -390
- package/dist/chunks/studio-vadzgkrz.js +0 -318
- package/dist/chunks/studio-wx5609xd.js +0 -341
- package/dist/chunks/studio-z6nw2ek2.js +0 -18
- package/dist/chunks/studio-zczps70q.js +0 -378
- package/dist/chunks/workspace-xpres40v.js +0 -89
- package/src/panels/activity-bar.ts +0 -251
- package/src/panels/panel-scheduler.ts +0 -219
- package/src/panels/style-inputs.ts +0 -237
- package/src/panels/target-line.ts +0 -274
- package/src/panels/welcome-screen.ts +0 -346
- package/src/ui/button-group.ts +0 -102
- package/src/ui/choice-field.ts +0 -72
- package/src/ui/field-row.ts +0 -249
- package/src/ui/formula-palette.ts +0 -213
- package/src/ui/icons.ts +0 -52
- package/src/ui/jx-theme.ts +0 -130
- package/src/ui/spectrum.ts +0 -340
- package/src/ui/value-selector.ts +0 -174
- package/src/ui/widgets.ts +0 -172
- /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
- /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
- /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
- /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
package/src/platforms/cloud.ts
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* `/api/v1/ai/chat`. The session is pre-bound to one (repo, branch) — the shell picks the project
|
|
7
7
|
* before Studio boots — while project-less mode (null) powers the /studio welcome screen.
|
|
8
8
|
*
|
|
9
|
-
* Cloud omissions (Studio degrades per @jxsuite/protocol's route table): pickDirectory
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Cloud omissions (Studio degrades per @jxsuite/protocol's route table): pickDirectory, package
|
|
10
|
+
* install/outdated/set-versions (package ops are manifest-only edits), multi-window, gitClone,
|
|
11
|
+
* resolveClass, component discovery, code services.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { negotiateCollab } from "@jxsuite/collab/negotiate";
|
|
@@ -16,16 +16,24 @@ import type { CollabNegotiation } from "@jxsuite/collab/negotiate";
|
|
|
16
16
|
import type { WsCollabConnection } from "@jxsuite/collab/client";
|
|
17
17
|
import type { ProjectConfig } from "@jxsuite/schema/types";
|
|
18
18
|
import { componentMetaFrom } from "@jxsuite/schema/component-meta";
|
|
19
|
+
import { streamImport } from "../services/import-client";
|
|
19
20
|
import type {
|
|
20
21
|
AccountStatus,
|
|
22
|
+
CfAccountSummary,
|
|
23
|
+
CfConnection,
|
|
24
|
+
CfConnectOutcome,
|
|
21
25
|
ComponentMeta,
|
|
22
26
|
CreateProjectDestination,
|
|
23
27
|
DirEntry,
|
|
28
|
+
ExtensionCatalogEntry,
|
|
24
29
|
ExtensionsInfo,
|
|
25
30
|
FsEvent,
|
|
26
31
|
GitBranchesResult,
|
|
27
32
|
GitLogEntry,
|
|
28
33
|
GitStatusResult,
|
|
34
|
+
ImportProgressEvent,
|
|
35
|
+
ImportReadyEvent,
|
|
36
|
+
ImportSiteOptions,
|
|
29
37
|
PackageInfo,
|
|
30
38
|
ProjectListEntry,
|
|
31
39
|
SiteBuildResult,
|
|
@@ -53,6 +61,15 @@ interface ProjectInfoWire {
|
|
|
53
61
|
projectConfig: Record<string, unknown> | null;
|
|
54
62
|
}
|
|
55
63
|
|
|
64
|
+
/** One row of the platform's project catalogue (`GET /api/v1/projects`). */
|
|
65
|
+
interface ProjectListWire {
|
|
66
|
+
fullName: string;
|
|
67
|
+
owner: string;
|
|
68
|
+
name: string;
|
|
69
|
+
defaultBranch: string;
|
|
70
|
+
permission: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
56
73
|
interface SessionEventWire {
|
|
57
74
|
kind: "fs" | "git";
|
|
58
75
|
events?: FsEvent[];
|
|
@@ -124,12 +141,16 @@ export function projectRootKey(project: CloudProject): string {
|
|
|
124
141
|
return `${project.owner}/${project.repo}@${project.branch}`;
|
|
125
142
|
}
|
|
126
143
|
|
|
127
|
-
/**
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Current hosted Cloudflare connection; null when none is brokered yet.
|
|
146
|
+
*
|
|
147
|
+
* A LAPSED row is not a healthy one. This reader used to answer `{connected: true}` for any body
|
|
148
|
+
* whose `connected` flag was set and drop `needsReconnect` on the floor, so a row whose grant had
|
|
149
|
+
* expired came back indistinguishable from one that works — which is how `cfConnect`'s poll came to
|
|
150
|
+
* close the popup the moment it opened, over a row from a previous session, while the user was
|
|
151
|
+
* still on Cloudflare's login page. Every diagnostic the broker sends now passes straight through.
|
|
152
|
+
*/
|
|
153
|
+
async function fetchCfConnection(): Promise<CfConnection | null> {
|
|
133
154
|
const res = await fetch("/api/v1/cf/connection", { credentials: "include" });
|
|
134
155
|
if (!res.ok) {
|
|
135
156
|
return null;
|
|
@@ -138,7 +159,15 @@ async function fetchCfConnection(): Promise<{
|
|
|
138
159
|
connected: boolean;
|
|
139
160
|
accountId?: string | null;
|
|
140
161
|
accountName?: string | null;
|
|
162
|
+
needsReconnect?: boolean;
|
|
163
|
+
needsAccount?: boolean;
|
|
164
|
+
code?: CfConnection["code"];
|
|
165
|
+
reason?: string;
|
|
166
|
+
hasRefreshToken?: boolean;
|
|
167
|
+
expiresAt?: number;
|
|
141
168
|
};
|
|
169
|
+
/* Cloud never emits {connected: false} to the PAL — no brokered row at all is `null`, and a row
|
|
170
|
+
that cannot be used arrives as connected + needsReconnect. See CfConnection. */
|
|
142
171
|
if (!body.connected) {
|
|
143
172
|
return null;
|
|
144
173
|
}
|
|
@@ -146,10 +175,131 @@ async function fetchCfConnection(): Promise<{
|
|
|
146
175
|
connected: true,
|
|
147
176
|
...(body.accountId ? { accountId: body.accountId } : {}),
|
|
148
177
|
...(body.accountName ? { accountName: body.accountName } : {}),
|
|
178
|
+
...(body.needsReconnect ? { needsReconnect: true } : {}),
|
|
179
|
+
...(body.needsAccount ? { needsAccount: true } : {}),
|
|
180
|
+
...(body.code ? { code: body.code } : {}),
|
|
181
|
+
...(body.reason ? { reason: body.reason } : {}),
|
|
182
|
+
...(body.hasRefreshToken === undefined ? {} : { hasRefreshToken: body.hasRefreshToken }),
|
|
183
|
+
...(body.expiresAt === undefined ? {} : { expiresAt: body.expiresAt }),
|
|
149
184
|
};
|
|
150
185
|
}
|
|
151
186
|
|
|
152
|
-
|
|
187
|
+
interface CfConnectFlow {
|
|
188
|
+
popup: Window | null;
|
|
189
|
+
promise: Promise<CfConnectOutcome | null>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The connect flow currently running, or null.
|
|
194
|
+
*
|
|
195
|
+
* Module-level rather than per-platform because the popup's TARGET NAME ("cf-connect") is global to
|
|
196
|
+
* the browsing context: a second `window.open` on that name re-uses the first flow's popup, and the
|
|
197
|
+
* first flow's cleanup then closes it out from under the second — the user watches their half-typed
|
|
198
|
+
* Cloudflare login vanish. Joining the in-flight promise is the only answer that leaves both
|
|
199
|
+
* callers correct.
|
|
200
|
+
*/
|
|
201
|
+
let cfConnectFlow: CfConnectFlow | null = null;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Drive one hosted OAuth connect to a {@link CfConnectOutcome}. See `cfConnect` for the semantics;
|
|
205
|
+
* this lives at module scope so the single-flight handle can too.
|
|
206
|
+
*/
|
|
207
|
+
async function runCfConnect(handle: CfConnectFlow): Promise<CfConnectOutcome | null> {
|
|
208
|
+
/* The baseline is read BEFORE the popup opens, and it is what keeps the poll honest: a row that
|
|
209
|
+
was already healthy proves nothing about THIS flow, so the poll must not settle on one. Reading
|
|
210
|
+
it after the popup opened would race the callback and could capture the new row as "old". */
|
|
211
|
+
const baseline = await fetchCfConnection().catch(() => null);
|
|
212
|
+
const healthyBaseline = Boolean(baseline?.connected && !baseline.needsReconnect);
|
|
213
|
+
const popup = window.open("/api/v1/cf/connect", "cf-connect", "width=980,height=780");
|
|
214
|
+
if (!popup) {
|
|
215
|
+
/* Popup blocked: the whole page is now navigating to the broker. Not a failure — the caller
|
|
216
|
+
must render nothing at all rather than an error it will never get to show. */
|
|
217
|
+
location.assign("/api/v1/cf/connect");
|
|
218
|
+
return { status: "redirect" };
|
|
219
|
+
}
|
|
220
|
+
handle.popup = popup;
|
|
221
|
+
const deadline = Date.now() + 180_000;
|
|
222
|
+
return new Promise<CfConnectOutcome>((resolve, reject) => {
|
|
223
|
+
let timer = 0;
|
|
224
|
+
const cleanup = () => {
|
|
225
|
+
window.removeEventListener("message", onMessage);
|
|
226
|
+
window.clearTimeout(timer);
|
|
227
|
+
if (!popup.closed) {
|
|
228
|
+
popup.close();
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
const settle = (outcome: CfConnectOutcome) => {
|
|
232
|
+
cleanup();
|
|
233
|
+
resolve(outcome);
|
|
234
|
+
};
|
|
235
|
+
const fail = (reason: string) => {
|
|
236
|
+
cleanup();
|
|
237
|
+
reject(new Error(reason));
|
|
238
|
+
};
|
|
239
|
+
/** A usable row: brokered, and its grant has not lapsed. */
|
|
240
|
+
const usable = (connection: CfConnection | null): connection is CfConnection =>
|
|
241
|
+
Boolean(connection?.connected && !connection.needsReconnect);
|
|
242
|
+
const onMessage = (event: MessageEvent) => {
|
|
243
|
+
if (event.origin !== location.origin) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const data = event.data as { source?: string; status?: string; reason?: string | null };
|
|
247
|
+
if (!data || data.source !== "jx-cf") {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (data.status === "error") {
|
|
251
|
+
fail(data.reason ?? "Cloudflare authorization failed");
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
/* Any other status — "connected", "pick-account", or one a shell of another vintage sends —
|
|
255
|
+
is a CLAIM that the callback ran, and the broker row is what adjudicates it. */
|
|
256
|
+
void fetchCfConnection().then(
|
|
257
|
+
(connection) => {
|
|
258
|
+
settle(usable(connection) ? { connection, status: "connected" } : { status: "timeout" });
|
|
259
|
+
},
|
|
260
|
+
/* This promise had no rejection handler, so one network blip left the listener installed,
|
|
261
|
+
the timer armed and the popup open forever. */
|
|
262
|
+
() => {
|
|
263
|
+
fail("Cloudflare connected, but the connection could not be confirmed");
|
|
264
|
+
},
|
|
265
|
+
);
|
|
266
|
+
};
|
|
267
|
+
window.addEventListener("message", onMessage);
|
|
268
|
+
const poll = async () => {
|
|
269
|
+
if (Date.now() > deadline) {
|
|
270
|
+
settle({ status: "timeout" });
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
let connection: CfConnection | null = null;
|
|
274
|
+
let answered = true;
|
|
275
|
+
try {
|
|
276
|
+
connection = await fetchCfConnection();
|
|
277
|
+
} catch {
|
|
278
|
+
answered = false; // A blip is not an answer: re-arm and ask again.
|
|
279
|
+
}
|
|
280
|
+
/* The poll is a FALLBACK for shells whose postMessage never arrives, so it may only settle on
|
|
281
|
+
proof that THIS flow stored a fresh token: a usable row that was NOT already usable at the
|
|
282
|
+
baseline. For a reconnect, `needsReconnect` flipping false is that proof; for a connection
|
|
283
|
+
that was healthy all along nothing the poll can see is, so it must never settle — the relay
|
|
284
|
+
or the popup-closed path answers that case instead. */
|
|
285
|
+
if (answered && usable(connection) && !healthyBaseline) {
|
|
286
|
+
settle({ connection, status: "connected" });
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (popup.closed) {
|
|
290
|
+
const final = await fetchCfConnection().catch(() => null);
|
|
291
|
+
settle(usable(final) ? { connection: final, status: "connected" } : { status: "canceled" });
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
timer = window.setTimeout(() => {
|
|
295
|
+
void poll();
|
|
296
|
+
}, 1500);
|
|
297
|
+
};
|
|
298
|
+
timer = window.setTimeout(() => {
|
|
299
|
+
void poll();
|
|
300
|
+
}, 1500);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
153
303
|
|
|
154
304
|
/** Parse an "owner/repo@branch" root key; null when malformed. */
|
|
155
305
|
export function parseRootKey(root: string): CloudProject | null {
|
|
@@ -164,6 +314,35 @@ export function parseRootKey(root: string): CloudProject | null {
|
|
|
164
314
|
return { owner, repo, branch };
|
|
165
315
|
}
|
|
166
316
|
|
|
317
|
+
/** Every project this account can open, straight off the wire; [] when the catalogue is unreachable. */
|
|
318
|
+
async function fetchProjects(): Promise<ProjectListWire[]> {
|
|
319
|
+
const res = await fetch("/api/v1/projects", { credentials: "include" });
|
|
320
|
+
return res.ok ? ((await res.json()) as ProjectListWire[]) : [];
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* The project a root key names, for the two members that navigate by one.
|
|
325
|
+
*
|
|
326
|
+
* Tolerates the branchless "owner/repo" keys older studios wrote into Recent: they cannot say which
|
|
327
|
+
* branch they meant, so the catalogue's default branch answers for them — the same branch that
|
|
328
|
+
* project's Projects row opens. Null when the key is neither form, or names nothing this account
|
|
329
|
+
* can reach.
|
|
330
|
+
*/
|
|
331
|
+
export async function resolveRootKey(rootKey: string): Promise<CloudProject | null> {
|
|
332
|
+
const parsed = parseRootKey(rootKey);
|
|
333
|
+
if (parsed) {
|
|
334
|
+
return parsed;
|
|
335
|
+
}
|
|
336
|
+
const legacy = /^([^/@]+)\/([^/@]+)$/.exec(rootKey);
|
|
337
|
+
if (!legacy) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
const [, owner, repo] = legacy;
|
|
341
|
+
const catalogue = await fetchProjects().catch(() => []);
|
|
342
|
+
const match = catalogue.find((p) => p.owner === owner && p.name === repo);
|
|
343
|
+
return match ? { owner: match.owner, repo: match.name, branch: match.defaultBranch } : null;
|
|
344
|
+
}
|
|
345
|
+
|
|
167
346
|
/**
|
|
168
347
|
* Bound mode (project non-null) drives one repo+branch session; project-less mode (null, the
|
|
169
348
|
* /studio route) exposes only the catalogue surface — listProjects/listStarters/createProject and
|
|
@@ -171,7 +350,17 @@ export function parseRootKey(root: string): CloudProject | null {
|
|
|
171
350
|
*/
|
|
172
351
|
export function createCloudPlatform(project: CloudProject | null): StudioPlatform {
|
|
173
352
|
const base = project ? sessionBase(project) : "";
|
|
174
|
-
|
|
353
|
+
/* The ROOT KEY, branch included — not a bare "owner/repo". This value is the project's identity
|
|
354
|
+
everywhere the shell keeps one: `probeRootProject` hands it to the recent-projects list, and
|
|
355
|
+
`setWindowProject` reopens a project by parsing it back with `parseRootKey`, which answers null
|
|
356
|
+
for a branchless key. So every Recent row a bound session had written was a click that did
|
|
357
|
+
nothing — no navigation, no error, and `deduped: true` telling the caller the open had been
|
|
358
|
+
handled — while the SAME project opened fine from the Projects catalogue, whose entries carry
|
|
359
|
+
the branch (`listProjects` below builds them with `projectRootKey`). Agreeing with the catalogue
|
|
360
|
+
also restores the welcome screen's dedupe (it matches the two lists by root, so the project
|
|
361
|
+
stopped appearing in both) and gives a branch its own Recent row, which is what a root key that
|
|
362
|
+
names a branch is for. */
|
|
363
|
+
const root = project ? projectRootKey(project) : "";
|
|
175
364
|
/**
|
|
176
365
|
* One multiplexed collab socket per session; per-doc handles come from openDoc. Memoized as a
|
|
177
366
|
* promise so concurrent first opens share the connection instead of racing two sockets.
|
|
@@ -489,6 +678,45 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
489
678
|
}
|
|
490
679
|
},
|
|
491
680
|
|
|
681
|
+
/**
|
|
682
|
+
* The extensions THIS WORKER bundles — not the shipped first-party catalogue.
|
|
683
|
+
*
|
|
684
|
+
* A Worker ships a fixed set of extension packages (specs/extensions.md §5.5), decided by the
|
|
685
|
+
* platform build rather than by this repository's `extensions/` tree, so the gateway is the
|
|
686
|
+
* only thing that knows. Everything it returns is therefore `bundled: true`: enabling one is a
|
|
687
|
+
* `project.json` write alone, and an extension the Worker does not bundle is dropped from the
|
|
688
|
+
* registry before composition — advertising it would promise a toggle that silently does
|
|
689
|
+
* nothing.
|
|
690
|
+
*
|
|
691
|
+
* `installed` here means DECLARED. Nothing resolves a module in a Worker: `addPackage` is a
|
|
692
|
+
* manifest edit and resolution happens later in Pages CI, so the manifest is the only fact this
|
|
693
|
+
* adapter has, and it is the one the reader is being asked about.
|
|
694
|
+
*
|
|
695
|
+
* Degrades to an EMPTY list, which is the whole contract: a session whose gateway predates this
|
|
696
|
+
* route must offer nothing rather than five extensions three of which it cannot load.
|
|
697
|
+
*/
|
|
698
|
+
async listExtensionCatalog(): Promise<ExtensionCatalogEntry[]> {
|
|
699
|
+
try {
|
|
700
|
+
const res = await api("/catalog");
|
|
701
|
+
if (!res.ok) {
|
|
702
|
+
return [];
|
|
703
|
+
}
|
|
704
|
+
const entries = (await res.json()) as ExtensionCatalogEntry[];
|
|
705
|
+
const pkg = await readPackageJson();
|
|
706
|
+
const declared = new Set([
|
|
707
|
+
...Object.keys((pkg["dependencies"] ?? {}) as Record<string, string>),
|
|
708
|
+
...Object.keys((pkg["devDependencies"] ?? {}) as Record<string, string>),
|
|
709
|
+
]);
|
|
710
|
+
for (const entry of entries) {
|
|
711
|
+
entry.bundled = true;
|
|
712
|
+
entry.installed = declared.has(entry.name);
|
|
713
|
+
}
|
|
714
|
+
return entries;
|
|
715
|
+
} catch {
|
|
716
|
+
return [];
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
|
|
492
720
|
/**
|
|
493
721
|
* The session's generated entry documents, composed server-side from the core schemas and each
|
|
494
722
|
* enabled extension's fragments (extensions.md §5.2) and returned PRE-BUNDLED — Monaco and the
|
|
@@ -788,17 +1016,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
788
1016
|
// ─── Project catalogue & navigation (Studio welcome / New Project UI) ──
|
|
789
1017
|
|
|
790
1018
|
async listProjects(): Promise<ProjectListEntry[]> {
|
|
791
|
-
const
|
|
792
|
-
if (!res.ok) {
|
|
793
|
-
return [];
|
|
794
|
-
}
|
|
795
|
-
const entries = (await res.json()) as {
|
|
796
|
-
fullName: string;
|
|
797
|
-
owner: string;
|
|
798
|
-
name: string;
|
|
799
|
-
defaultBranch: string;
|
|
800
|
-
permission: string;
|
|
801
|
-
}[];
|
|
1019
|
+
const entries = await fetchProjects();
|
|
802
1020
|
return entries.map((p) => ({
|
|
803
1021
|
name: p.fullName,
|
|
804
1022
|
root: projectRootKey({ owner: p.owner, repo: p.name, branch: p.defaultBranch }),
|
|
@@ -816,8 +1034,15 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
816
1034
|
|
|
817
1035
|
/** Welcome/recents open path: navigate this tab into the project's editor. */
|
|
818
1036
|
async setWindowProject(rootKey: string) {
|
|
819
|
-
const target =
|
|
820
|
-
|
|
1037
|
+
const target = await resolveRootKey(rootKey);
|
|
1038
|
+
/* Throw rather than fall through: `deduped` tells the caller the open was handled, so an
|
|
1039
|
+
unresolvable key answered "done" and left the user looking at the screen they clicked on.
|
|
1040
|
+
The throw reaches `openRecentProject`'s catch, which reports the failure and drops the
|
|
1041
|
+
entry — the right end for a row naming a project this account can no longer open. */
|
|
1042
|
+
if (!target) {
|
|
1043
|
+
throw new Error(`No project to open at ${rootKey}`);
|
|
1044
|
+
}
|
|
1045
|
+
if (typeof location !== "undefined") {
|
|
821
1046
|
location.assign(editUrl(target));
|
|
822
1047
|
}
|
|
823
1048
|
// Navigation unloads the page; deduped stops the caller's follow-up work.
|
|
@@ -825,8 +1050,13 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
825
1050
|
},
|
|
826
1051
|
|
|
827
1052
|
async openProjectInNewWindow(rootKey: string) {
|
|
828
|
-
const target =
|
|
829
|
-
|
|
1053
|
+
const target = await resolveRootKey(rootKey);
|
|
1054
|
+
// Same contract as setWindowProject: the caller reports "Opened in another window" on any
|
|
1055
|
+
// Resolved call, so a key that opens nothing has to fail rather than answer.
|
|
1056
|
+
if (!target) {
|
|
1057
|
+
throw new Error(`No project to open at ${rootKey}`);
|
|
1058
|
+
}
|
|
1059
|
+
if (typeof window !== "undefined") {
|
|
830
1060
|
window.open(editUrl(target), "_blank", "noopener");
|
|
831
1061
|
}
|
|
832
1062
|
// `_blank` always makes a tab; a browser tab already showing this project is not something
|
|
@@ -896,6 +1126,33 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
896
1126
|
};
|
|
897
1127
|
},
|
|
898
1128
|
|
|
1129
|
+
/**
|
|
1130
|
+
* AI-guided site import, streamed from the PLATFORM's import route rather than a session one.
|
|
1131
|
+
*
|
|
1132
|
+
* Deliberately not routed through `api()`: importing is how a cloud project comes into
|
|
1133
|
+
* existence, so the one mode it has to work in is the project-less hub, where `api()` rejects
|
|
1134
|
+
* before a request is ever made and `base` is "".
|
|
1135
|
+
*
|
|
1136
|
+
* The path is same-origin and relative, so `streamImport`'s plain `fetch` carries the session
|
|
1137
|
+
* cookie under the default `same-origin` credentials mode — the same authority every
|
|
1138
|
+
* `/api/v1/*` call here sends `credentials: "include"` for, with no cloud-shaped option added
|
|
1139
|
+
* to the shared client. A bring-your-own-key run rides on the headers that client already sets,
|
|
1140
|
+
* so the backend sees `X-Api-Key` / `X-Api-Base-URL` exactly as the OSS server does.
|
|
1141
|
+
*
|
|
1142
|
+
* `onReady` is forwarded and this backend never calls it, which is a difference worth naming:
|
|
1143
|
+
* adopting the project mid-run would navigate this page to the editor and abort the request
|
|
1144
|
+
* still writing the import, so the stream carries no `ready` line and the caller adopts on
|
|
1145
|
+
* `done`. That is the same path a backend older than `ready` has always taken.
|
|
1146
|
+
*/
|
|
1147
|
+
async importSite(
|
|
1148
|
+
opts: ImportSiteOptions,
|
|
1149
|
+
onProgress: (evt: ImportProgressEvent) => void,
|
|
1150
|
+
signal?: AbortSignal,
|
|
1151
|
+
onReady?: (evt: ImportReadyEvent) => void,
|
|
1152
|
+
) {
|
|
1153
|
+
return await streamImport("/api/v1/import/site", opts, onProgress, signal, onReady);
|
|
1154
|
+
},
|
|
1155
|
+
|
|
899
1156
|
// ─── Identity & Cloudflare publish surface ──────────────────────────────
|
|
900
1157
|
|
|
901
1158
|
async getUser() {
|
|
@@ -1001,71 +1258,75 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1001
1258
|
* OAuth errors (denial, invalid_scope misregistration) REJECT with the real reason instead of
|
|
1002
1259
|
* timing out. A 1.5s poll remains as fallback for older shells / blocked message delivery, and
|
|
1003
1260
|
* popup-blocked browsers fall back to a full-page redirect.
|
|
1261
|
+
*
|
|
1262
|
+
* Promise semantics, which are narrower than they look:
|
|
1263
|
+
*
|
|
1264
|
+
* - **Resolves `null`** only under the SSR guard, where there is no window to open.
|
|
1265
|
+
* - **Resolves an outcome** for all four real endings — `connected`, `redirect` (popup blocked,
|
|
1266
|
+
* page navigating away), `canceled` (popup closed with nothing stored), `timeout` (180s).
|
|
1267
|
+
* - **Rejects** only on a relayed OAuth error, or on a relayed success this platform could not
|
|
1268
|
+
* confirm against the broker.
|
|
1269
|
+
*
|
|
1270
|
+
* Concurrent calls JOIN the flow already running rather than starting a second one: both would
|
|
1271
|
+
* open the same "cf-connect" target, and the first one's cleanup would then close the popup the
|
|
1272
|
+
* second is waiting on.
|
|
1004
1273
|
*/
|
|
1005
|
-
|
|
1274
|
+
cfConnect() {
|
|
1006
1275
|
if (typeof window === "undefined" || typeof location === "undefined") {
|
|
1007
|
-
return null;
|
|
1276
|
+
return Promise.resolve(null);
|
|
1008
1277
|
}
|
|
1009
|
-
const
|
|
1010
|
-
if (
|
|
1011
|
-
|
|
1012
|
-
|
|
1278
|
+
const running = cfConnectFlow;
|
|
1279
|
+
if (running) {
|
|
1280
|
+
try {
|
|
1281
|
+
running.popup?.focus();
|
|
1282
|
+
} catch {
|
|
1283
|
+
// A cross-origin popup may refuse focus; joining the flow is what mattered.
|
|
1284
|
+
}
|
|
1285
|
+
return running.promise;
|
|
1013
1286
|
}
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
if (!popup.closed) {
|
|
1021
|
-
popup.close();
|
|
1022
|
-
}
|
|
1023
|
-
};
|
|
1024
|
-
const settle = (connection: CfConnectionInfo) => {
|
|
1025
|
-
cleanup();
|
|
1026
|
-
resolve(connection);
|
|
1027
|
-
};
|
|
1028
|
-
const fail = (reason: string) => {
|
|
1029
|
-
cleanup();
|
|
1030
|
-
reject(new Error(reason));
|
|
1031
|
-
};
|
|
1032
|
-
const onMessage = (event: MessageEvent) => {
|
|
1033
|
-
if (event.origin !== location.origin) {
|
|
1034
|
-
return;
|
|
1035
|
-
}
|
|
1036
|
-
const data = event.data as { source?: string; status?: string; reason?: string | null };
|
|
1037
|
-
if (!data || data.source !== "jx-cf") {
|
|
1038
|
-
return;
|
|
1039
|
-
}
|
|
1040
|
-
if (data.status === "error") {
|
|
1041
|
-
fail(data.reason ?? "Cloudflare authorization failed");
|
|
1042
|
-
return;
|
|
1043
|
-
}
|
|
1044
|
-
void fetchCfConnection().then(settle);
|
|
1045
|
-
};
|
|
1046
|
-
window.addEventListener("message", onMessage);
|
|
1047
|
-
const poll = async () => {
|
|
1048
|
-
if (Date.now() > deadline) {
|
|
1049
|
-
settle(null);
|
|
1050
|
-
return;
|
|
1051
|
-
}
|
|
1052
|
-
const connection = await fetchCfConnection();
|
|
1053
|
-
if (connection) {
|
|
1054
|
-
settle(connection);
|
|
1055
|
-
return;
|
|
1056
|
-
}
|
|
1057
|
-
if (popup.closed) {
|
|
1058
|
-
settle(await fetchCfConnection());
|
|
1059
|
-
return;
|
|
1060
|
-
}
|
|
1061
|
-
timer = window.setTimeout(() => {
|
|
1062
|
-
void poll();
|
|
1063
|
-
}, 1500);
|
|
1064
|
-
};
|
|
1065
|
-
timer = window.setTimeout(() => {
|
|
1066
|
-
void poll();
|
|
1067
|
-
}, 1500);
|
|
1287
|
+
const handle: CfConnectFlow = { popup: null, promise: Promise.resolve(null) };
|
|
1288
|
+
cfConnectFlow = handle;
|
|
1289
|
+
handle.promise = runCfConnect(handle).finally(() => {
|
|
1290
|
+
if (cfConnectFlow === handle) {
|
|
1291
|
+
cfConnectFlow = null;
|
|
1292
|
+
}
|
|
1068
1293
|
});
|
|
1294
|
+
return handle.promise;
|
|
1295
|
+
},
|
|
1296
|
+
|
|
1297
|
+
/**
|
|
1298
|
+
* Every Cloudflare account this connection can reach (the account picker's rows).
|
|
1299
|
+
*
|
|
1300
|
+
* A non-OK body is the broker's own unusable-connection payload — `{error, code}` naming a
|
|
1301
|
+
* lapsed grant or a connection that never existed — so its sentence is the one worth showing.
|
|
1302
|
+
*/
|
|
1303
|
+
async cfAccounts() {
|
|
1304
|
+
const res = await fetch("/api/v1/cf/accounts", { credentials: "include" });
|
|
1305
|
+
return okJson<CfAccountSummary[]>(res, "Failed to list Cloudflare accounts");
|
|
1306
|
+
},
|
|
1307
|
+
|
|
1308
|
+
/** Store the chosen account on the brokered connection. */
|
|
1309
|
+
async cfSelectAccount(account: { id: string; name?: string }) {
|
|
1310
|
+
const res = await fetch("/api/v1/cf/select-account", {
|
|
1311
|
+
body: JSON.stringify({ accountId: account.id, accountName: account.name }),
|
|
1312
|
+
credentials: "include",
|
|
1313
|
+
headers: { "Content-Type": "application/json" },
|
|
1314
|
+
method: "POST",
|
|
1315
|
+
});
|
|
1316
|
+
if (!res.ok) {
|
|
1317
|
+
throw new Error(await errorMessage(res, "Failed to select a Cloudflare account"));
|
|
1318
|
+
}
|
|
1319
|
+
},
|
|
1320
|
+
|
|
1321
|
+
/** Forget the brokered connection (the broker revokes its tokens upstream). */
|
|
1322
|
+
async cfDisconnect() {
|
|
1323
|
+
const res = await fetch("/api/v1/cf/connection", {
|
|
1324
|
+
credentials: "include",
|
|
1325
|
+
method: "DELETE",
|
|
1326
|
+
});
|
|
1327
|
+
if (!res.ok) {
|
|
1328
|
+
throw new Error(await errorMessage(res, "Failed to disconnect Cloudflare"));
|
|
1329
|
+
}
|
|
1069
1330
|
},
|
|
1070
1331
|
|
|
1071
1332
|
/** Allowlisted Cloudflare API passthrough (platform injects the OAuth token). */
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
DataRowsResult,
|
|
26
26
|
DataRowUpdate,
|
|
27
27
|
DirEntry,
|
|
28
|
+
ExtensionCatalogEntry,
|
|
28
29
|
ExtensionsInfo,
|
|
29
30
|
FsEvent,
|
|
30
31
|
ImportProgressEvent,
|
|
@@ -745,6 +746,18 @@ export function createDevServerPlatform() {
|
|
|
745
746
|
return body.extensions ?? [];
|
|
746
747
|
},
|
|
747
748
|
|
|
749
|
+
/**
|
|
750
|
+
* What this backend can offer, enabled or not.
|
|
751
|
+
*
|
|
752
|
+
* Its own route rather than a field on `formats`: that one builds the project's registry and
|
|
753
|
+
* fails when a declared extension does not resolve, which is exactly when a reader needs the
|
|
754
|
+
* catalogue to repair it.
|
|
755
|
+
*/
|
|
756
|
+
async listExtensionCatalog(): Promise<ExtensionCatalogEntry[]> {
|
|
757
|
+
const res = await fetch(`/__studio/catalog?dir=${encodeURIComponent(serverPath("."))}`);
|
|
758
|
+
return res.ok ? await readJson<ExtensionCatalogEntry[]>(res) : [];
|
|
759
|
+
},
|
|
760
|
+
|
|
748
761
|
/** Pre-bundled per-project entry schemas for Monaco registration (empty when unavailable). */
|
|
749
762
|
async fetchProjectSchemas(): Promise<ProjectSchemasResponse> {
|
|
750
763
|
const res = await fetch(
|