@jxsuite/studio 6.1.1 → 8.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 +5 -5
- package/dist/chunks/2020-5wtzce5g.js +4 -0
- package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- package/dist/chunks/adapter-5tphg7xe.js +4 -0
- package/dist/chunks/add-new-flow-psym14sn.js +4 -0
- package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
- package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
- package/dist/chunks/color-area-6rbra5dy.js +4 -0
- package/dist/chunks/color-field-gy56c94g.js +4 -0
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/color-slider-sqqdyf6c.js +4 -0
- package/dist/chunks/combobox-72h32ejk.js +4 -0
- package/dist/chunks/components-r22xca09.js +4 -0
- package/dist/chunks/content-source-mmppmcyg.js +4 -0
- package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
- package/dist/chunks/dialog-c4x05vyx.js +4 -0
- package/dist/chunks/editor-ccd9jwsa.js +4 -0
- package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
- package/dist/chunks/extension-sections-0egb88dm.js +4 -0
- package/dist/chunks/file-ops-qnab36ek.js +4 -0
- package/dist/chunks/files-rcn56qvm.js +4 -0
- package/dist/chunks/format-host-yxz0kjjs.js +4 -0
- package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
- package/dist/chunks/grid-open-4z1g062t.js +4 -0
- package/dist/chunks/grid-view-qg1b5eqx.js +51 -0
- package/dist/chunks/icons-63bjtbs7.js +4 -0
- package/dist/chunks/iframe-entry-2zggzajv.js +5 -0
- package/dist/chunks/iframe-entry-76j8vwwx.js +5 -0
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/iframe-entry-pkgmcgp0.js +5 -0
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-2veqmnhr.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-8nbvs12s.js → javascript-pjp734q4.js} +3 -3
- package/dist/chunks/jsonMode-njkvsa02.js +13 -0
- package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
- package/dist/chunks/layers-bgyr11tr.js +4 -0
- package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
- package/dist/chunks/listbox-c421cf8c.js +4 -0
- package/dist/chunks/lit-html-v9gh687x.js +4 -0
- package/dist/chunks/media-library-sq468wts.js +4 -0
- package/dist/chunks/media-picker-shfe59pt.js +4 -0
- package/dist/chunks/menu-bdpzbfvs.js +4 -0
- package/dist/chunks/monaco-binding-vq1hgnn0.js +4 -0
- package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
- package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
- package/dist/chunks/notify-kzrjr3fv.js +4 -0
- package/dist/chunks/number-field-y62xq0ty.js +4 -0
- package/dist/chunks/parse-v77xtwv7.js +4 -0
- package/dist/chunks/platform-7v4rtd7m.js +4 -0
- package/dist/chunks/popover-b89sfej7.js +4 -0
- package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
- package/dist/chunks/publish-quick-qx2455cj.js +4 -0
- package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
- package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
- package/dist/chunks/references-9547rg5s.js +4 -0
- package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
- package/dist/chunks/select-rzds841e.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/split-c9zfdgxf.js +4 -0
- package/dist/chunks/studio-03ct6yfv.js +9 -0
- package/dist/chunks/studio-07rcfje3.js +5 -0
- package/dist/chunks/studio-3e54qh39.js +7 -0
- package/dist/chunks/studio-3exxhz5g.js +5 -0
- package/dist/chunks/studio-3q40e3rj.js +5 -0
- package/dist/chunks/studio-3qeh9t0h.js +6 -0
- package/dist/chunks/studio-3qqjeep5.js +6 -0
- package/dist/chunks/studio-43sd2mam.js +4 -0
- package/dist/chunks/studio-4hp8pkyt.js +5 -0
- package/dist/chunks/studio-58xg6j2q.js +9 -0
- package/dist/chunks/studio-5g0rprdt.js +7 -0
- package/dist/chunks/studio-6m380wp7.js +5 -0
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-kggey1jt.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/studio-8tr6cfrc.js +5 -0
- package/dist/chunks/studio-8vcvfs7r.js +6 -0
- package/dist/chunks/studio-9tmebf0s.js +5 -0
- package/dist/chunks/studio-a2bvaptz.js +5 -0
- package/dist/chunks/studio-b7y5mr30.js +5 -0
- package/dist/chunks/studio-bavb31r0.js +5 -0
- package/dist/chunks/studio-bbe4c90a.js +5 -0
- package/dist/chunks/studio-c05wdnt3.js +5 -0
- package/dist/chunks/studio-ccv2svc6.js +5 -0
- package/dist/chunks/studio-d5grtb9e.js +16 -0
- package/dist/chunks/studio-df0baea9.js +5 -0
- package/dist/chunks/studio-dgk4dqtx.js +7 -0
- package/dist/chunks/studio-e1g64q43.js +5 -0
- package/dist/chunks/studio-ed1hp6zf.js +6 -0
- package/dist/chunks/studio-ed3xx40h.js +7 -0
- package/dist/chunks/studio-f14e1zdj.js +5 -0
- package/dist/chunks/studio-fbhxxc5f.js +5 -0
- package/dist/chunks/studio-fyh0jc96.js +5 -0
- package/dist/chunks/studio-gcxk20n7.js +5 -0
- package/dist/chunks/studio-jaaz8ce9.js +5 -0
- package/dist/chunks/{studio-8grwxtqk.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-1q1sh2ax.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/studio-k7evxqh4.js +5 -0
- package/dist/chunks/studio-kt3pjkwd.js +5 -0
- package/dist/chunks/studio-m8g16bgz.js +5 -0
- package/dist/chunks/studio-mn0476ag.js +5 -0
- package/dist/chunks/studio-mx1smyq0.js +5 -0
- package/dist/chunks/studio-n0c5h6mf.js +5 -0
- package/dist/chunks/{studio-rv11kfwa.js → studio-nh6d342n.js} +7 -7
- package/dist/chunks/studio-nqxqf8p2.js +4 -0
- package/dist/chunks/studio-p4nrkvqr.js +5 -0
- package/dist/chunks/{studio-h46vtzk8.js → studio-pbxa5fpc.js} +4 -4
- package/dist/chunks/studio-pgmvdv7z.js +7 -0
- package/dist/chunks/studio-ph84avkf.js +5 -0
- package/dist/chunks/{studio-wszjyh0j.js → studio-q0mvbaq6.js} +4 -4
- package/dist/chunks/studio-q0tccd43.js +5 -0
- package/dist/chunks/studio-q7rtx6zq.js +14 -0
- package/dist/chunks/{studio-pre0skq6.js → studio-qgh13jtz.js} +4 -4
- package/dist/chunks/studio-qmn1xc24.js +5 -0
- package/dist/chunks/studio-qwdqwkj0.js +5 -0
- package/dist/chunks/{studio-t6b6qe31.js → studio-r5qy30vx.js} +4 -4
- package/dist/chunks/studio-rj9eamf8.js +5 -0
- package/dist/chunks/studio-rptgsk96.js +5 -0
- package/dist/chunks/studio-rthyg42z.js +928 -0
- package/dist/chunks/studio-s19tp1xr.js +5 -0
- package/dist/chunks/studio-s32578pn.js +5 -0
- package/dist/chunks/studio-svb7yyve.js +5 -0
- package/dist/chunks/studio-syreb644.js +5 -0
- package/dist/chunks/studio-tf9jryb1.js +10 -0
- package/dist/chunks/studio-tfkznv39.js +5 -0
- package/dist/chunks/studio-tft6r105.js +5 -0
- package/dist/chunks/studio-txf2kysx.js +5 -0
- package/dist/chunks/studio-v8867ddv.js +12 -0
- package/dist/chunks/studio-vxq7fcvv.js +5 -0
- package/dist/chunks/studio-w4rz9hdk.js +5 -0
- package/dist/chunks/studio-wbcjbhy1.js +9 -0
- package/dist/chunks/studio-wc649wss.js +5 -0
- package/dist/chunks/studio-wys23mxz.js +5 -0
- package/dist/chunks/studio-x1x167jh.js +5 -0
- package/dist/chunks/studio-x9hsze61.js +5 -0
- package/dist/chunks/studio-y0n7yxea.js +9 -0
- package/dist/chunks/studio-y3ahhdpx.js +5 -0
- package/dist/chunks/studio-z97c48fk.js +5 -0
- package/dist/chunks/studio-zat62m0c.js +5 -0
- package/dist/chunks/studio-zcd2e7yz.js +5 -0
- package/dist/chunks/studio-zz9qe3rw.js +64 -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-1gv0h53h.js +4 -0
- package/dist/chunks/toast-host-1yg5ar8d.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-yypz28gq.js +4 -0
- package/dist/chunks/tree-9xa4hm7n.js +4 -0
- package/dist/chunks/tsMode-epyfz1hv.js +14 -0
- package/dist/chunks/workspace-dz7nxfhv.js +4 -0
- package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
- package/dist/chunks/ws-client-bv552sfx.js +4 -0
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +106 -107
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +17 -16
- 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/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +270 -53
- package/src/browse/library-model.ts +194 -134
- package/src/browse/library-pane.ts +748 -440
- package/src/browse/library-preview.ts +161 -26
- package/src/browse/library-source.ts +308 -41
- package/src/browse/preview-root.ts +78 -0
- package/src/browse/preview-style.ts +155 -0
- package/src/canvas/asset-refs.ts +40 -10
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +260 -77
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +175 -148
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +147 -61
- 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 +120 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +104 -75
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +269 -158
- package/src/canvas/iframe-inline-edit.ts +49 -30
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +30 -25
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +25 -21
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +36 -21
- package/src/canvas/iframe-render.ts +84 -35
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +10 -3
- package/src/canvas/npm-modules.ts +22 -0
- 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/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +7 -2
- package/src/canvas/surface-registry.ts +27 -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/app-commands.ts +16 -6
- package/src/commands/budget.ts +13 -11
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +55 -28
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +56 -43
- package/src/commands/levels.ts +14 -8
- package/src/commands/live-context.ts +9 -7
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +22 -11
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +11 -9
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +54 -62
- package/src/content/entry-editor.ts +137 -32
- package/src/content/entry-fields.ts +25 -8
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +38 -15
- package/src/content/entry-open.ts +80 -0
- package/src/content/entry-summaries.ts +440 -0
- package/src/content/file-record-ids.ts +80 -0
- package/src/content/file-records.ts +125 -0
- package/src/content/page-summaries.ts +129 -0
- package/src/content/record-entry.ts +201 -0
- package/src/content/writing-banner.ts +177 -0
- package/src/create/add-new-commands.ts +185 -0
- package/src/create/add-new-flow.ts +1116 -0
- package/src/create/add-new.ts +1014 -0
- package/src/create/element-name.ts +121 -0
- 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 +78 -48
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +29 -22
- package/src/editor/inline-edit-apply.ts +79 -17
- package/src/editor/inline-edit.ts +76 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +14 -5
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +76 -42
- package/src/editor/slash-menu.ts +52 -14
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +89 -20
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +92 -41
- package/src/files/files.ts +248 -239
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +97 -2
- package/src/files/media-paths.ts +3 -0
- package/src/files/media-types.ts +55 -0
- package/src/files/media-upload.ts +209 -52
- package/src/files/new-file-name.ts +156 -0
- package/src/files/serialize-document.ts +15 -5
- 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 +91 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +21 -11
- package/src/github/github-publish.ts +28 -23
- 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 +25 -23
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -33
- package/src/grid/grid-panel.ts +65 -6
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +9 -31
- package/src/grid/grid-view.ts +45 -23
- 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 +100 -31
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +61 -34
- package/src/hosting/document.ts +2 -2
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +3 -3
- package/src/media/media-commands.ts +181 -0
- package/src/media/media-library-model.ts +232 -0
- package/src/media/media-library.ts +1283 -0
- package/src/media/media-pane.ts +51 -20
- 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 +38 -14
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- 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 +57 -46
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +36 -26
- package/src/panels/chat-panel.ts +6 -6
- package/src/panels/collections-panel.ts +306 -0
- package/src/panels/component-preview.ts +35 -13
- package/src/panels/data-explorer.ts +63 -26
- package/src/panels/data-grid.ts +18 -11
- package/src/panels/dnd.ts +115 -138
- package/src/panels/editors.ts +52 -21
- package/src/panels/elements-panel.ts +19 -5
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +78 -54
- package/src/panels/frontmatter-fields.ts +33 -28
- package/src/panels/git-diff-open.ts +10 -6
- package/src/panels/head-panel.ts +488 -202
- package/src/panels/i18n-panel.ts +20 -12
- package/src/panels/imports-panel.ts +25 -47
- package/src/panels/jump-bar.ts +75 -31
- package/src/panels/layers-panel.ts +130 -101
- package/src/panels/left-panel.ts +25 -11
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +140 -49
- package/src/panels/pane-grid.ts +55 -26
- package/src/panels/panel-registry.ts +36 -46
- package/src/panels/properties-panel.ts +182 -124
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +201 -45
- package/src/panels/seo-modal.ts +54 -125
- package/src/panels/settings-menu.ts +63 -61
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +156 -135
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +253 -206
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +195 -60
- package/src/panels/stylebook-layers-panel.ts +48 -89
- package/src/panels/stylebook-panel.ts +60 -27
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +143 -49
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +59 -31
- package/src/platforms/cloud.ts +373 -176
- package/src/platforms/default-platform.ts +14 -8
- package/src/platforms/devserver.ts +180 -142
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +20 -9
- package/src/publish/pages-service.ts +66 -27
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +88 -22
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-panel.ts +10 -6
- package/src/publish/publish-quick.ts +148 -0
- package/src/publish/publish-workspace.ts +926 -0
- package/src/publish/source-control.ts +907 -0
- 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 +74 -51
- package/src/services/cem-export.ts +149 -58
- package/src/services/cf-settings.ts +4 -4
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/connection.ts +2 -2
- 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 +20 -14
- 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 +29 -9
- package/src/services/settings/definitions.ts +25 -14
- 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 +128 -70
- package/src/settings/css-vars-editor.ts +119 -32
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +42 -14
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +101 -28
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +17 -7
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +28 -11
- package/src/settings/schema-field-ui.ts +12 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +186 -166
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +536 -477
- package/src/site-context.ts +101 -32
- package/src/state.ts +68 -57
- package/src/store.ts +54 -34
- package/src/studio.ts +219 -116
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +40 -7
- package/src/style/stylebook-specimens.ts +89 -0
- package/src/style/stylebook-target.ts +26 -0
- package/src/style/tag-inheritance.ts +105 -0
- package/src/style/token-ref.ts +5 -4
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +33 -38
- 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.json +4 -3
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +17 -16
- package/src/surfaces/cf-account-picker.ts +17 -18
- package/src/surfaces/collections-panel.json +615 -0
- package/src/surfaces/collections-panel.ts +168 -0
- package/src/surfaces/commandbar.json +241 -96
- package/src/surfaces/commandbar.ts +145 -105
- 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/empty-state.json +1 -1
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +35 -11
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- 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/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.json +162 -14
- package/src/surfaces/inspector-dock.ts +59 -31
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +111 -77
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +26 -11
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +47 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +44 -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.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +8 -7
- 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.json +72 -2
- package/src/surfaces/panel-page.ts +49 -25
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +25 -39
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +5 -29
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +29 -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-quick.json +428 -0
- package/src/surfaces/publish-quick.ts +165 -0
- package/src/surfaces/publish-workspace.json +2892 -0
- package/src/surfaces/publish-workspace.ts +391 -0
- package/src/surfaces/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +22 -79
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +17 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +32 -12
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +82 -16
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +9 -16
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- 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.json +3 -3
- package/src/surfaces/settings-overview.ts +14 -8
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +88 -36
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/shell.ts +1 -2
- package/src/surfaces/site-panel.json +1029 -0
- package/src/surfaces/site-panel.ts +233 -0
- package/src/surfaces/slash-menu.json +63 -21
- package/src/surfaces/slash-menu.ts +42 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +56 -29
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- package/src/surfaces/styles-panel.json +735 -0
- package/src/surfaces/styles-panel.ts +195 -0
- package/src/surfaces/styles-variables.json +149 -0
- package/src/surfaces/styles-variables.ts +145 -0
- package/src/surfaces/tab-strip.json +4 -4
- package/src/surfaces/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +6 -8
- package/src/surfaces/writing-banner.json +94 -0
- package/src/surfaces/writing-banner.ts +80 -0
- package/src/tabs/bare-repeaters.ts +101 -0
- 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 +99 -48
- package/src/tabs/transact.ts +98 -53
- package/src/types.ts +53 -43
- 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 +104 -56
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +57 -31
- package/src/ui/media-picker.ts +300 -47
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +14 -12
- package/src/ui/schema-form.ts +372 -97
- 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 +29 -3
- package/src/utils/base64.ts +6 -4
- package/src/utils/edit-display.ts +366 -111
- 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/local-day.ts +18 -0
- 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 +14 -16
- package/src/workspace/session.ts +81 -50
- package/src/workspace/tab-workspace.ts +137 -0
- package/src/workspace/workspace-back.ts +189 -0
- package/src/workspace/workspace-home.ts +133 -0
- package/src/workspace/workspace-ids.ts +129 -0
- package/src/workspace/workspace-switch.ts +372 -0
- package/src/workspace/workspace.ts +165 -47
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-va2wwra4.js +0 -4
- package/dist/chunks/adapter-f93pafd7.js +0 -4
- package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
- package/dist/chunks/cf-settings-125tdm0w.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-ax2f1fnn.js +0 -4
- package/dist/chunks/content-source-108aqtk1.js +0 -4
- package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-pfgdmkb0.js +0 -4
- package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
- package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
- package/dist/chunks/file-ops-meej5mqf.js +0 -4
- package/dist/chunks/files-44vp8a2s.js +0 -4
- package/dist/chunks/format-host-7q1petb9.js +0 -4
- package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
- package/dist/chunks/git-panel-zngbymvd.js +0 -4
- package/dist/chunks/grid-view-sx9vynsp.js +0 -51
- package/dist/chunks/icons-p44xhjf0.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-qk3ycq87.js +0 -4
- package/dist/chunks/index-wkyfjeqz.js +0 -4
- package/dist/chunks/jsonMode-s8kt9dsj.js +0 -13
- package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
- package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
- package/dist/chunks/layers-xd92fg8d.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
- package/dist/chunks/media-picker-0svzkdyb.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/menu-5c55ea3d.js +0 -4
- package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
- package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
- package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
- package/dist/chunks/notify-0xgtn8q1.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-v1qctbe6.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
- package/dist/chunks/quick-search-a54e6t5n.js +0 -4
- package/dist/chunks/references-gmqp82fs.js +0 -4
- package/dist/chunks/right-panel-v7t9awbk.js +0 -4
- package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0bhx5hz6.js +0 -5
- package/dist/chunks/studio-0k1ddnyy.js +0 -6
- package/dist/chunks/studio-1b04pd0j.js +0 -64
- package/dist/chunks/studio-4dwbj6gb.js +0 -5
- package/dist/chunks/studio-4tanh828.js +0 -5
- package/dist/chunks/studio-55h4mstj.js +0 -4
- package/dist/chunks/studio-5tnvjkz4.js +0 -5
- package/dist/chunks/studio-60dqgb0c.js +0 -5
- package/dist/chunks/studio-61dp09qg.js +0 -9
- package/dist/chunks/studio-63epcrj2.js +0 -5
- package/dist/chunks/studio-74k29dy9.js +0 -5
- package/dist/chunks/studio-7vg6jcd3.js +0 -5
- package/dist/chunks/studio-7zx31knw.js +0 -9
- package/dist/chunks/studio-8bxk97km.js +0 -5
- package/dist/chunks/studio-933e30n4.js +0 -5
- package/dist/chunks/studio-98wnwhbg.js +0 -5
- package/dist/chunks/studio-9mccjwjh.js +0 -14
- package/dist/chunks/studio-a2ke1e4t.js +0 -5
- package/dist/chunks/studio-e3a2a6v3.js +0 -4
- package/dist/chunks/studio-e81q1vb9.js +0 -5
- package/dist/chunks/studio-epgrmqqm.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-g1shz58g.js +0 -5
- package/dist/chunks/studio-gf0fz03c.js +0 -5
- package/dist/chunks/studio-gjtpe62q.js +0 -6
- package/dist/chunks/studio-gkskhg7m.js +0 -5
- package/dist/chunks/studio-gx4dnjzd.js +0 -5
- package/dist/chunks/studio-j03zga3y.js +0 -9
- package/dist/chunks/studio-jhpxeckz.js +0 -5
- package/dist/chunks/studio-k01r7ykp.js +0 -5
- package/dist/chunks/studio-kk7h30ne.js +0 -7
- package/dist/chunks/studio-kt1zqney.js +0 -5
- package/dist/chunks/studio-m3cwhvye.js +0 -5
- package/dist/chunks/studio-mcayt6hz.js +0 -5
- package/dist/chunks/studio-myjcghv3.js +0 -5
- package/dist/chunks/studio-n8bxwc3y.js +0 -4
- package/dist/chunks/studio-ngm8gvpb.js +0 -5
- package/dist/chunks/studio-nj5a01jy.js +0 -928
- package/dist/chunks/studio-pcgz8heb.js +0 -5
- package/dist/chunks/studio-qcsq0t15.js +0 -5
- package/dist/chunks/studio-qkstvve9.js +0 -5
- package/dist/chunks/studio-qv1pwd3c.js +0 -5
- package/dist/chunks/studio-rc6dvxjb.js +0 -7
- package/dist/chunks/studio-s8dmmz66.js +0 -5
- package/dist/chunks/studio-sp5xzbj4.js +0 -6
- package/dist/chunks/studio-szsjbj0g.js +0 -5
- package/dist/chunks/studio-t1xzawhr.js +0 -16
- package/dist/chunks/studio-tdcprbqb.js +0 -5
- package/dist/chunks/studio-vrmcjf9g.js +0 -7
- package/dist/chunks/studio-vyc0b4he.js +0 -10
- package/dist/chunks/studio-w0cgf6jg.js +0 -5
- package/dist/chunks/studio-w3hskzqk.js +0 -5
- package/dist/chunks/studio-xgrgcdyh.js +0 -9
- package/dist/chunks/studio-xz2yxfcb.js +0 -5
- package/dist/chunks/studio-y6n42tgs.js +0 -5
- package/dist/chunks/studio-yb560vxr.js +0 -5
- package/dist/chunks/studio-yn9f8vtx.js +0 -5
- package/dist/chunks/studio-yw05w8f0.js +0 -7
- package/dist/chunks/studio-z16sgavc.js +0 -5
- package/dist/chunks/studio-zey7zsdw.js +0 -12
- package/dist/chunks/studio-zyqn40w4.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-2frah6h1.js +0 -14
- package/dist/chunks/workspace-zt81g1ms.js +0 -4
- package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -701
- package/src/panels/git-panel.ts +0 -1120
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -231
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -272
package/src/platforms/cloud.ts
CHANGED
|
@@ -16,7 +16,8 @@ import type { CollabNegotiation } from "@jxsuite/collab/negotiate";
|
|
|
16
16
|
// Static, and free to be: `reconnect.ts` imports nothing, so no Yjs reaches the initial bundle.
|
|
17
17
|
import { createReconnectScheduler } from "@jxsuite/collab/reconnect";
|
|
18
18
|
import type { WsCollabConnection } from "@jxsuite/collab/client";
|
|
19
|
-
import
|
|
19
|
+
import { isBoolean, isJsonObject, isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
20
|
+
import type { JsonObject, JsonValue, JxMutableNode, ProjectConfig } from "@jxsuite/schema/types";
|
|
20
21
|
import { componentMetaFrom } from "@jxsuite/schema/component-meta";
|
|
21
22
|
import { streamImport } from "../services/import-client";
|
|
22
23
|
import type {
|
|
@@ -55,7 +56,9 @@ import type {
|
|
|
55
56
|
import { problemDetail, problemSlug } from "@jxsuite/protocol";
|
|
56
57
|
import type { ReadFilesRequest, ReadFilesResult, UploadResult } from "@jxsuite/protocol";
|
|
57
58
|
import { reportActionRequired } from "../account/action-required";
|
|
59
|
+
import type { ActionRequiredReport } from "../account/action-required";
|
|
58
60
|
import { offeredActions, retryHint } from "../platform-errors";
|
|
61
|
+
import type { PlatformErrorInfo } from "../platform-errors";
|
|
59
62
|
import { createReadBatcher } from "./read-batcher";
|
|
60
63
|
import { normalizeProjectDir } from "../utils/project-dir";
|
|
61
64
|
import type { BatchAnswer } from "./read-batcher";
|
|
@@ -79,7 +82,7 @@ interface ProjectInfoWire {
|
|
|
79
82
|
name: string;
|
|
80
83
|
defaultBranch: string;
|
|
81
84
|
permission: "admin" | "write" | "read" | "none";
|
|
82
|
-
projectConfig:
|
|
85
|
+
projectConfig: ProjectConfig | null;
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
/** One row of the platform's project catalogue (`GET /api/v1/projects`). */
|
|
@@ -91,6 +94,64 @@ interface ProjectListWire {
|
|
|
91
94
|
permission: string;
|
|
92
95
|
}
|
|
93
96
|
|
|
97
|
+
/**
|
|
98
|
+
* True when a `POST /files/read` body is the route answering: a JSON object whose `files` is an
|
|
99
|
+
* array. Only that much is checked here, because the batcher checks every row, and `omitted`,
|
|
100
|
+
* before it trusts any of them (read-batcher.ts `settleAnswer`).
|
|
101
|
+
*/
|
|
102
|
+
function isReadFilesAnswer(body: JsonValue): body is JsonObject & ReadFilesResult {
|
|
103
|
+
return isJsonObject(body) && Array.isArray(body["files"]);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** The options object {@link StudioPlatform.formatAction} hands through to `POST /format`. */
|
|
107
|
+
type FormatActionPayload = Parameters<NonNullable<StudioPlatform["formatAction"]>>[0];
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* A Cloudflare proxy reply (`/api/v1/cf/proxy` here, `/__studio/cf/proxy` on the dev server):
|
|
111
|
+
* Cloudflare's v4 envelope, or the proxy's own `error`.
|
|
112
|
+
*/
|
|
113
|
+
export interface CfProxyEnvelope extends JsonObject {
|
|
114
|
+
success?: boolean;
|
|
115
|
+
result?: JsonValue;
|
|
116
|
+
errors?: { message: string }[];
|
|
117
|
+
error?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Where a session file sits in its project, as `resolveSiteContext` reports it. */
|
|
121
|
+
interface SiteContext {
|
|
122
|
+
sitePath: string | null;
|
|
123
|
+
projectConfig?: ProjectConfig;
|
|
124
|
+
fileRelPath?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The signed-in GitHub user, as `getUser` reports them. */
|
|
128
|
+
interface SignedInUser {
|
|
129
|
+
login: string;
|
|
130
|
+
name?: string;
|
|
131
|
+
avatarUrl?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Body of `POST /api/v1/projects/import`: the repository, and the project folder when not its root. */
|
|
135
|
+
interface ImportProjectRequest {
|
|
136
|
+
owner: string;
|
|
137
|
+
name: string;
|
|
138
|
+
dir?: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* A manifest's `dependencies` or `devDependencies` block, `{}` when absent. The object itself, not
|
|
143
|
+
* a copy, so `addPackage` can write into it.
|
|
144
|
+
*/
|
|
145
|
+
function dependencyBlock(
|
|
146
|
+
pkg: JsonObject,
|
|
147
|
+
key: "dependencies" | "devDependencies",
|
|
148
|
+
): Record<string, string> {
|
|
149
|
+
/* SAFETY: npm's package.json format defines both blocks as an object of package name → version
|
|
150
|
+
range string, and every member here that writes one (`addPackage`, `removePackage`) keeps it
|
|
151
|
+
that way. */
|
|
152
|
+
return (pkg[key] ?? {}) as Record<string, string>;
|
|
153
|
+
}
|
|
154
|
+
|
|
94
155
|
interface SessionEventWire {
|
|
95
156
|
kind: "fs" | "git";
|
|
96
157
|
events?: FsEvent[];
|
|
@@ -110,9 +171,24 @@ interface ErrorBody {
|
|
|
110
171
|
code?: string;
|
|
111
172
|
}
|
|
112
173
|
|
|
174
|
+
/** Parse a fetch Response body as JSON, asserting the expected shape at the boundary. */
|
|
175
|
+
async function readJson<T>(res: Response): Promise<T> {
|
|
176
|
+
/* SAFETY: every response read here comes from a Studio Backend Protocol session route or one of
|
|
177
|
+
the platform's own `/api/v1/*` routes, whose bodies have the shapes @jxsuite/protocol, ../types
|
|
178
|
+
and the wire interfaces in this file describe; each caller names the type of the route it
|
|
179
|
+
called, and a JSON parse always yields a JsonValue. */
|
|
180
|
+
return (await res.json()) as T;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Parse JSON text a session read returned; JSON.parse only ever produces JSON values. */
|
|
184
|
+
function parseJson(text: string): JsonValue {
|
|
185
|
+
// SAFETY: JSON.parse returns exactly the JSON value the text encodes, or throws.
|
|
186
|
+
return JSON.parse(text) as JsonValue;
|
|
187
|
+
}
|
|
188
|
+
|
|
113
189
|
async function errorMessage(res: Response, fallback: string): Promise<string> {
|
|
114
190
|
try {
|
|
115
|
-
return problemDetail(await res
|
|
191
|
+
return problemDetail(await readJson<JsonValue>(res)) ?? fallback;
|
|
116
192
|
} catch {
|
|
117
193
|
return fallback;
|
|
118
194
|
}
|
|
@@ -124,9 +200,9 @@ async function errorMessage(res: Response, fallback: string): Promise<string> {
|
|
|
124
200
|
* says the same. Any other 403 (an expired grant, a revoked share) is not that verdict.
|
|
125
201
|
*/
|
|
126
202
|
async function isReadOnlyRefusal(res: Response): Promise<boolean> {
|
|
127
|
-
let body:
|
|
203
|
+
let body: StructuredBody | null;
|
|
128
204
|
try {
|
|
129
|
-
body =
|
|
205
|
+
body = await readJson<StructuredBody | null>(res);
|
|
130
206
|
} catch {
|
|
131
207
|
return false;
|
|
132
208
|
}
|
|
@@ -136,16 +212,22 @@ async function isReadOnlyRefusal(res: Response): Promise<boolean> {
|
|
|
136
212
|
|
|
137
213
|
/** A failure body's machine-readable members, each one optional and none of them trusted. */
|
|
138
214
|
interface StructuredBody extends ErrorBody {
|
|
139
|
-
type?:
|
|
140
|
-
installUrl?:
|
|
141
|
-
actions?:
|
|
142
|
-
heading?:
|
|
143
|
-
retry?:
|
|
215
|
+
type?: JsonValue;
|
|
216
|
+
installUrl?: JsonValue;
|
|
217
|
+
actions?: JsonValue;
|
|
218
|
+
heading?: JsonValue;
|
|
219
|
+
retry?: JsonValue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** What {@link platformError} carries on the Error it returns: the HTTP status, plus what it found. */
|
|
223
|
+
interface PlatformErrorDetails extends PlatformErrorInfo {
|
|
224
|
+
status: number;
|
|
144
225
|
}
|
|
145
226
|
|
|
146
227
|
/** The refusal's heading, when the body carries a usable one. */
|
|
147
228
|
function headingOf(body: StructuredBody | null): string | undefined {
|
|
148
|
-
|
|
229
|
+
const heading = body?.heading;
|
|
230
|
+
return isString(heading) && heading ? heading : undefined;
|
|
149
231
|
}
|
|
150
232
|
|
|
151
233
|
/**
|
|
@@ -161,7 +243,7 @@ function headingOf(body: StructuredBody | null): string | undefined {
|
|
|
161
243
|
async function platformError(res: Response, fallback: string): Promise<Error> {
|
|
162
244
|
let body: StructuredBody | null;
|
|
163
245
|
try {
|
|
164
|
-
body =
|
|
246
|
+
body = await readJson<StructuredBody | null>(res);
|
|
165
247
|
} catch {
|
|
166
248
|
body = null;
|
|
167
249
|
}
|
|
@@ -169,21 +251,31 @@ async function platformError(res: Response, fallback: string): Promise<Error> {
|
|
|
169
251
|
const actions = offeredActions(body?.actions);
|
|
170
252
|
const heading = headingOf(body);
|
|
171
253
|
const retry = retryHint(body?.retry);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
254
|
+
const installUrl = body?.installUrl;
|
|
255
|
+
const details: PlatformErrorDetails = { status: res.status };
|
|
256
|
+
if (code) {
|
|
257
|
+
details.code = code;
|
|
258
|
+
}
|
|
259
|
+
if (isString(installUrl)) {
|
|
260
|
+
details.installUrl = installUrl;
|
|
261
|
+
}
|
|
262
|
+
if (actions.length > 0) {
|
|
263
|
+
details.actions = actions;
|
|
264
|
+
}
|
|
265
|
+
if (heading !== undefined) {
|
|
266
|
+
details.heading = heading;
|
|
267
|
+
}
|
|
268
|
+
if (retry !== undefined) {
|
|
269
|
+
details.retry = retry;
|
|
270
|
+
}
|
|
271
|
+
return Object.assign(new Error(problemDetail(body) ?? fallback), details);
|
|
180
272
|
}
|
|
181
273
|
|
|
182
274
|
async function okJson<T>(res: Response, fallback: string): Promise<T> {
|
|
183
275
|
if (!res.ok) {
|
|
184
276
|
throw await platformError(res, fallback);
|
|
185
277
|
}
|
|
186
|
-
return (
|
|
278
|
+
return readJson<T>(res);
|
|
187
279
|
}
|
|
188
280
|
|
|
189
281
|
/** Whether a failure body is an `action-required` refusal, by problem type or legacy code. */
|
|
@@ -201,7 +293,7 @@ function isActionRequiredBody(body: StructuredBody | null): boolean {
|
|
|
201
293
|
async function reportRefusal(res: Response): Promise<void> {
|
|
202
294
|
let body: StructuredBody | null;
|
|
203
295
|
try {
|
|
204
|
-
body =
|
|
296
|
+
body = await readJson<StructuredBody | null>(res);
|
|
205
297
|
} catch {
|
|
206
298
|
return;
|
|
207
299
|
}
|
|
@@ -215,12 +307,17 @@ async function reportRefusal(res: Response): Promise<void> {
|
|
|
215
307
|
const detail = problemDetail(body);
|
|
216
308
|
const heading = headingOf(body);
|
|
217
309
|
const retry = retryHint(body?.retry);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
310
|
+
const report: ActionRequiredReport = { actions };
|
|
311
|
+
if (detail !== null) {
|
|
312
|
+
report.detail = detail;
|
|
313
|
+
}
|
|
314
|
+
if (heading !== undefined) {
|
|
315
|
+
report.heading = heading;
|
|
316
|
+
}
|
|
317
|
+
if (retry !== undefined) {
|
|
318
|
+
report.retry = retry;
|
|
319
|
+
}
|
|
320
|
+
reportActionRequired(report);
|
|
224
321
|
}
|
|
225
322
|
|
|
226
323
|
/**
|
|
@@ -298,6 +395,34 @@ export function projectRootKey(project: CloudProject): string {
|
|
|
298
395
|
return `${project.owner}/${project.repo}@${revisionSpec(project)}`;
|
|
299
396
|
}
|
|
300
397
|
|
|
398
|
+
/** `GET /api/v1/cf/connection`: the broker's row, with every diagnostic it may send. */
|
|
399
|
+
interface CfConnectionWire {
|
|
400
|
+
connected: boolean;
|
|
401
|
+
accountId?: string | null;
|
|
402
|
+
accountName?: string | null;
|
|
403
|
+
needsReconnect?: boolean;
|
|
404
|
+
needsAccount?: boolean;
|
|
405
|
+
code?: CfConnection["code"];
|
|
406
|
+
reason?: string;
|
|
407
|
+
hasRefreshToken?: boolean;
|
|
408
|
+
expiresAt?: number;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* A same-origin window relay (`{source, status, reason?}`) that a broker or action window posts
|
|
413
|
+
* back. Only `source` is checked; `status` and `reason` are read as the relay protocol sends them.
|
|
414
|
+
*/
|
|
415
|
+
interface WindowRelay {
|
|
416
|
+
source?: string;
|
|
417
|
+
status?: string;
|
|
418
|
+
reason?: string | null;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** True when a `message` event carries a relay from `source` (`"jx-cf"`, `"jx-action"`). */
|
|
422
|
+
function isRelayEvent(event: MessageEvent, source: string): event is MessageEvent<WindowRelay> {
|
|
423
|
+
return isNonNullObject(event.data) && "source" in event.data && event.data.source === source;
|
|
424
|
+
}
|
|
425
|
+
|
|
301
426
|
/**
|
|
302
427
|
* Current hosted Cloudflare connection; null when none is brokered yet.
|
|
303
428
|
*
|
|
@@ -312,33 +437,38 @@ async function fetchCfConnection(): Promise<CfConnection | null> {
|
|
|
312
437
|
if (!res.ok) {
|
|
313
438
|
return null;
|
|
314
439
|
}
|
|
315
|
-
const body =
|
|
316
|
-
connected: boolean;
|
|
317
|
-
accountId?: string | null;
|
|
318
|
-
accountName?: string | null;
|
|
319
|
-
needsReconnect?: boolean;
|
|
320
|
-
needsAccount?: boolean;
|
|
321
|
-
code?: CfConnection["code"];
|
|
322
|
-
reason?: string;
|
|
323
|
-
hasRefreshToken?: boolean;
|
|
324
|
-
expiresAt?: number;
|
|
325
|
-
};
|
|
440
|
+
const body = await readJson<CfConnectionWire>(res);
|
|
326
441
|
/* Cloud never emits {connected: false} to the PAL — no brokered row at all is `null`, and a row
|
|
327
442
|
that cannot be used arrives as connected + needsReconnect. See CfConnection. */
|
|
328
443
|
if (!body.connected) {
|
|
329
444
|
return null;
|
|
330
445
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
446
|
+
const connection: CfConnection = { connected: true };
|
|
447
|
+
if (body.accountId) {
|
|
448
|
+
connection.accountId = body.accountId;
|
|
449
|
+
}
|
|
450
|
+
if (body.accountName) {
|
|
451
|
+
connection.accountName = body.accountName;
|
|
452
|
+
}
|
|
453
|
+
if (body.needsReconnect) {
|
|
454
|
+
connection.needsReconnect = true;
|
|
455
|
+
}
|
|
456
|
+
if (body.needsAccount) {
|
|
457
|
+
connection.needsAccount = true;
|
|
458
|
+
}
|
|
459
|
+
if (body.code) {
|
|
460
|
+
connection.code = body.code;
|
|
461
|
+
}
|
|
462
|
+
if (body.reason) {
|
|
463
|
+
connection.reason = body.reason;
|
|
464
|
+
}
|
|
465
|
+
if (body.hasRefreshToken !== undefined) {
|
|
466
|
+
connection.hasRefreshToken = body.hasRefreshToken;
|
|
467
|
+
}
|
|
468
|
+
if (body.expiresAt !== undefined) {
|
|
469
|
+
connection.expiresAt = body.expiresAt;
|
|
470
|
+
}
|
|
471
|
+
return connection;
|
|
342
472
|
}
|
|
343
473
|
|
|
344
474
|
interface CfConnectFlow {
|
|
@@ -403,10 +533,10 @@ async function runCfConnect(
|
|
|
403
533
|
if (event.origin !== location.origin) {
|
|
404
534
|
return;
|
|
405
535
|
}
|
|
406
|
-
|
|
407
|
-
if (!data || data.source !== "jx-cf") {
|
|
536
|
+
if (!isRelayEvent(event, "jx-cf")) {
|
|
408
537
|
return;
|
|
409
538
|
}
|
|
539
|
+
const { data } = event;
|
|
410
540
|
if (data.status === "error") {
|
|
411
541
|
fail(data.reason ?? "Cloudflare authorization failed");
|
|
412
542
|
return;
|
|
@@ -467,68 +597,76 @@ async function runCfConnect(
|
|
|
467
597
|
interface MeWire {
|
|
468
598
|
installations?: { id: number; account: string | null; manageUrl?: string }[];
|
|
469
599
|
appInstallUrl?: string;
|
|
470
|
-
entries?:
|
|
471
|
-
notices?:
|
|
600
|
+
entries?: JsonValue;
|
|
601
|
+
notices?: JsonValue;
|
|
472
602
|
}
|
|
473
603
|
|
|
474
604
|
/** A wire value as a non-empty string, or undefined. */
|
|
475
|
-
function wireText(value:
|
|
476
|
-
return
|
|
605
|
+
function wireText(value: JsonValue | undefined): string | undefined {
|
|
606
|
+
return isString(value) && value ? value : undefined;
|
|
477
607
|
}
|
|
478
608
|
|
|
479
609
|
/**
|
|
480
610
|
* The account rows a `/me` body holds, each one checked. A row needs an id, a label and a detail to
|
|
481
611
|
* be drawn at all; a malformed one is dropped rather than drawn half-empty.
|
|
482
612
|
*/
|
|
483
|
-
function accountEntries(value:
|
|
613
|
+
function accountEntries(value: JsonValue | undefined): AccountEntry[] {
|
|
484
614
|
if (!Array.isArray(value)) {
|
|
485
615
|
return [];
|
|
486
616
|
}
|
|
487
|
-
return value.flatMap((raw
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
617
|
+
return value.flatMap((raw): AccountEntry[] => {
|
|
618
|
+
// A row that is not an object has no id, label or detail to draw.
|
|
619
|
+
if (!isJsonObject(raw)) {
|
|
620
|
+
return [];
|
|
621
|
+
}
|
|
622
|
+
const id = wireText(raw["id"]);
|
|
623
|
+
const label = wireText(raw["label"]);
|
|
624
|
+
const detail = wireText(raw["detail"]);
|
|
491
625
|
if (!id || !label || !detail) {
|
|
492
626
|
return [];
|
|
493
627
|
}
|
|
494
|
-
const actions = offeredActions(raw
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
];
|
|
628
|
+
const actions = offeredActions(raw["actions"]);
|
|
629
|
+
const { connected } = raw;
|
|
630
|
+
const entry: AccountEntry = { detail, id, label };
|
|
631
|
+
if (isBoolean(connected)) {
|
|
632
|
+
entry.connected = connected;
|
|
633
|
+
}
|
|
634
|
+
if (actions.length > 0) {
|
|
635
|
+
entry.actions = actions;
|
|
636
|
+
}
|
|
637
|
+
return [entry];
|
|
504
638
|
});
|
|
505
639
|
}
|
|
506
640
|
|
|
507
641
|
/** The notices a `/me` body holds, each one checked, on the same terms as the rows. */
|
|
508
|
-
function accountNotices(value:
|
|
642
|
+
function accountNotices(value: JsonValue | undefined): AccountNotice[] {
|
|
509
643
|
if (!Array.isArray(value)) {
|
|
510
644
|
return [];
|
|
511
645
|
}
|
|
512
|
-
return value.flatMap((raw
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
646
|
+
return value.flatMap((raw): AccountNotice[] => {
|
|
647
|
+
// A notice that is not an object has no id, title or message to show.
|
|
648
|
+
if (!isJsonObject(raw)) {
|
|
649
|
+
return [];
|
|
650
|
+
}
|
|
651
|
+
const id = wireText(raw["id"]);
|
|
652
|
+
const title = wireText(raw["title"]);
|
|
653
|
+
const message = wireText(raw["message"]);
|
|
516
654
|
if (!id || !title || !message) {
|
|
517
655
|
return [];
|
|
518
656
|
}
|
|
519
|
-
const actions = offeredActions(raw
|
|
520
|
-
const level = raw
|
|
521
|
-
const
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
];
|
|
657
|
+
const actions = offeredActions(raw["actions"]);
|
|
658
|
+
const { display, level } = raw;
|
|
659
|
+
const notice: AccountNotice = { id, message, title };
|
|
660
|
+
if (level === "info" || level === "warning") {
|
|
661
|
+
notice.level = level;
|
|
662
|
+
}
|
|
663
|
+
if (display === "banner" || display === "toast") {
|
|
664
|
+
notice.display = display;
|
|
665
|
+
}
|
|
666
|
+
if (actions.length > 0) {
|
|
667
|
+
notice.actions = actions;
|
|
668
|
+
}
|
|
669
|
+
return [notice];
|
|
532
670
|
});
|
|
533
671
|
}
|
|
534
672
|
|
|
@@ -578,10 +716,10 @@ function awaitAction(popup: Window): Promise<ActionOutcome> {
|
|
|
578
716
|
if (event.origin !== location.origin) {
|
|
579
717
|
return;
|
|
580
718
|
}
|
|
581
|
-
|
|
582
|
-
if (!data || data.source !== "jx-action") {
|
|
719
|
+
if (!isRelayEvent(event, "jx-action")) {
|
|
583
720
|
return;
|
|
584
721
|
}
|
|
722
|
+
const { data } = event;
|
|
585
723
|
if (data.status === "done" || data.status === "canceled") {
|
|
586
724
|
settle({ status: data.status });
|
|
587
725
|
} else if (data.status === "error") {
|
|
@@ -624,7 +762,7 @@ export function parseRootKey(root: string): CloudProject | null {
|
|
|
624
762
|
/** Every project this account can open, straight off the wire; [] when the catalogue is unreachable. */
|
|
625
763
|
async function fetchProjects(): Promise<ProjectListWire[]> {
|
|
626
764
|
const res = await fetch("/api/v1/projects", { credentials: "include" });
|
|
627
|
-
return res.ok ?
|
|
765
|
+
return res.ok ? readJson<ProjectListWire[]>(res) : [];
|
|
628
766
|
}
|
|
629
767
|
|
|
630
768
|
/**
|
|
@@ -705,7 +843,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
705
843
|
*/
|
|
706
844
|
const projectHint = project ? `${project.owner}/${project.repo}` : null;
|
|
707
845
|
|
|
708
|
-
function postJson(path: string, body:
|
|
846
|
+
function postJson(path: string, body: JsonValue | FormatActionPayload): Promise<Response> {
|
|
709
847
|
return api(path, {
|
|
710
848
|
method: "POST",
|
|
711
849
|
headers: { "Content-Type": "application/json" },
|
|
@@ -717,6 +855,21 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
717
855
|
return okJson<ProjectInfoWire>(await api("/project-info"), "Failed to load project");
|
|
718
856
|
}
|
|
719
857
|
|
|
858
|
+
/* The repository's default branch, asked once per session: it is what Send for review must never
|
|
859
|
+
commit to here, because a commit on this host lands on GitHub as it is made. A failed ask is
|
|
860
|
+
forgotten, so the next branch listing asks again. */
|
|
861
|
+
let defaultBranch: Promise<string> | null = null;
|
|
862
|
+
function repositoryDefaultBranch(): Promise<string> {
|
|
863
|
+
defaultBranch ??= projectInfo().then(
|
|
864
|
+
(info) => info.defaultBranch || "",
|
|
865
|
+
() => {
|
|
866
|
+
defaultBranch = null;
|
|
867
|
+
return "";
|
|
868
|
+
},
|
|
869
|
+
);
|
|
870
|
+
return defaultBranch;
|
|
871
|
+
}
|
|
872
|
+
|
|
720
873
|
/** One file the old way: `GET /file`. What a single read, and the batch fallback, goes through. */
|
|
721
874
|
async function readOne(path: string): Promise<string> {
|
|
722
875
|
const data = await okJson<{ content: string }>(
|
|
@@ -752,16 +905,16 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
752
905
|
if (!res.ok) {
|
|
753
906
|
return "retry-singly";
|
|
754
907
|
}
|
|
755
|
-
let body:
|
|
908
|
+
let body: JsonValue;
|
|
756
909
|
try {
|
|
757
|
-
body = await res
|
|
910
|
+
body = await readJson<JsonValue>(res);
|
|
758
911
|
} catch {
|
|
759
912
|
return "unsupported";
|
|
760
913
|
}
|
|
761
|
-
if (!
|
|
914
|
+
if (!isReadFilesAnswer(body)) {
|
|
762
915
|
return "unsupported";
|
|
763
916
|
}
|
|
764
|
-
return body
|
|
917
|
+
return body;
|
|
765
918
|
},
|
|
766
919
|
fetchOne: readOne,
|
|
767
920
|
});
|
|
@@ -774,7 +927,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
774
927
|
*/
|
|
775
928
|
let packageJsonRead: Promise<string> | null = null;
|
|
776
929
|
|
|
777
|
-
async function readPackageJson(): Promise<
|
|
930
|
+
async function readPackageJson(): Promise<JsonObject> {
|
|
778
931
|
let text: string;
|
|
779
932
|
try {
|
|
780
933
|
packageJsonRead ??= reader.read("package.json").finally(() => {
|
|
@@ -786,13 +939,15 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
786
939
|
}
|
|
787
940
|
// Parsed per caller: the members mutate what they get, and must not mutate each other's copy.
|
|
788
941
|
try {
|
|
789
|
-
|
|
942
|
+
// A manifest that is not a JSON object is as unusable as one that is not JSON at all.
|
|
943
|
+
const pkg = parseJson(text);
|
|
944
|
+
return isJsonObject(pkg) ? pkg : {};
|
|
790
945
|
} catch {
|
|
791
946
|
return {};
|
|
792
947
|
}
|
|
793
948
|
}
|
|
794
949
|
|
|
795
|
-
async function writePackageJson(pkg:
|
|
950
|
+
async function writePackageJson(pkg: JsonObject): Promise<void> {
|
|
796
951
|
const res = await api("/file", {
|
|
797
952
|
method: "PUT",
|
|
798
953
|
headers: { "Content-Type": "application/json" },
|
|
@@ -803,9 +958,20 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
803
958
|
}
|
|
804
959
|
}
|
|
805
960
|
|
|
961
|
+
// The bound session's /raw tree; see `documentBaseUrl` below for why both members ride together.
|
|
962
|
+
const repoAssets: Pick<StudioPlatform, "assetSpace" | "documentBaseUrl"> = {};
|
|
963
|
+
if (base) {
|
|
964
|
+
repoAssets.assetSpace = "repo";
|
|
965
|
+
repoAssets.documentBaseUrl = `${base}/raw/`;
|
|
966
|
+
}
|
|
967
|
+
|
|
806
968
|
const platform: StudioPlatform = {
|
|
807
969
|
id: "cloud",
|
|
808
970
|
projectRoot: root,
|
|
971
|
+
/* Commits land on GitHub as they are made (`gitCommit`), a push is a sync check, and a branch
|
|
972
|
+
is a sibling session (`gitCheckout`), which is what the Publish workspace says before it
|
|
973
|
+
switches one (studio.md §22.8). */
|
|
974
|
+
gitHosted: true,
|
|
809
975
|
canvasUrl: "/canvas.html",
|
|
810
976
|
/* The projectRoot here is the IDENTIFIER "owner/repo@branch", not a served path, so the canvas's
|
|
811
977
|
default base — <origin>/<projectRoot>/ — addressed nothing. Every component $ref fetch landed
|
|
@@ -822,7 +988,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
822
988
|
broken, and logs nothing. Declaring "repo" tells Studio to resolve each reference to the
|
|
823
989
|
project file it names and address it under /raw. Until a project is bound there is no /raw to
|
|
824
990
|
address, so the project-less hub declares neither and stays exactly as it was. */
|
|
825
|
-
...
|
|
991
|
+
...repoAssets,
|
|
826
992
|
/* Open Project routes through Studio's repo picker (write-access repos via listRepos +
|
|
827
993
|
importProject) — sessions are URL-bound, so openProject() below never opens a dialog. */
|
|
828
994
|
openProjectPicker: "repo-list",
|
|
@@ -851,7 +1017,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
851
1017
|
return null;
|
|
852
1018
|
}
|
|
853
1019
|
const info = await projectInfo();
|
|
854
|
-
const config =
|
|
1020
|
+
const config: ProjectConfig = info.projectConfig ?? {};
|
|
855
1021
|
return {
|
|
856
1022
|
config,
|
|
857
1023
|
handle: { root, name: config.name || info.name, projectConfig: config },
|
|
@@ -868,7 +1034,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
868
1034
|
meta: { root, name: info.name },
|
|
869
1035
|
info: {
|
|
870
1036
|
isSiteProject: info.projectConfig !== null,
|
|
871
|
-
projectConfig:
|
|
1037
|
+
projectConfig: info.projectConfig ?? null,
|
|
872
1038
|
},
|
|
873
1039
|
};
|
|
874
1040
|
} catch {
|
|
@@ -920,7 +1086,11 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
920
1086
|
const body = await okJson<Partial<UploadResult>>(res, `Upload failed: ${path}`);
|
|
921
1087
|
// The session echoes the path today; falling back to the request keeps a backend that says
|
|
922
1088
|
// Nothing working rather than writing `undefined` into a document.
|
|
923
|
-
|
|
1089
|
+
const uploaded: UploadResult = { path: body.path ?? path };
|
|
1090
|
+
if (body.size !== undefined) {
|
|
1091
|
+
uploaded.size = body.size;
|
|
1092
|
+
}
|
|
1093
|
+
return uploaded;
|
|
924
1094
|
},
|
|
925
1095
|
|
|
926
1096
|
async deleteFile(path: string) {
|
|
@@ -979,7 +1149,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
979
1149
|
}
|
|
980
1150
|
collabNegotiation ??= api("/collab")
|
|
981
1151
|
.then(async (res) =>
|
|
982
|
-
res.ok ? negotiateCollab(await res
|
|
1152
|
+
res.ok ? negotiateCollab(await readJson<JsonValue>(res)) : { offer: [], refused: null },
|
|
983
1153
|
)
|
|
984
1154
|
.catch(() => ({ offer: [], refused: null }));
|
|
985
1155
|
const negotiated = await collabNegotiation;
|
|
@@ -1040,10 +1210,12 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1040
1210
|
const scheme = location.protocol === "https:" ? "wss" : "ws";
|
|
1041
1211
|
const ws = new WebSocket(`${scheme}://${location.host}${base}/events`);
|
|
1042
1212
|
socket = ws;
|
|
1043
|
-
ws.addEventListener("message", (ev: MessageEvent) => {
|
|
1213
|
+
ws.addEventListener("message", (ev: MessageEvent<string>) => {
|
|
1044
1214
|
let payload: SessionEventWire;
|
|
1045
1215
|
try {
|
|
1046
|
-
|
|
1216
|
+
/* SAFETY: the session's /events socket sends only text frames, each one a JSON
|
|
1217
|
+
SessionEventWire (`kind` "fs" with its events, or "git" with the git event). */
|
|
1218
|
+
payload = JSON.parse(ev.data) as SessionEventWire;
|
|
1047
1219
|
} catch {
|
|
1048
1220
|
return;
|
|
1049
1221
|
}
|
|
@@ -1086,7 +1258,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1086
1258
|
if (!res.ok) {
|
|
1087
1259
|
return [];
|
|
1088
1260
|
}
|
|
1089
|
-
const body =
|
|
1261
|
+
const body = await readJson<{ formats?: JsonObject[] }>(res);
|
|
1090
1262
|
return body.formats ?? [];
|
|
1091
1263
|
} catch {
|
|
1092
1264
|
return [];
|
|
@@ -1100,7 +1272,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1100
1272
|
if (!res.ok) {
|
|
1101
1273
|
return [];
|
|
1102
1274
|
}
|
|
1103
|
-
const body =
|
|
1275
|
+
const body = await readJson<{ extensions?: ExtensionsInfo[] }>(res);
|
|
1104
1276
|
return body.extensions ?? [];
|
|
1105
1277
|
} catch {
|
|
1106
1278
|
return [];
|
|
@@ -1130,11 +1302,11 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1130
1302
|
if (!res.ok) {
|
|
1131
1303
|
return [];
|
|
1132
1304
|
}
|
|
1133
|
-
const entries =
|
|
1305
|
+
const entries = await readJson<ExtensionCatalogEntry[]>(res);
|
|
1134
1306
|
const pkg = await readPackageJson();
|
|
1135
1307
|
const declared = new Set([
|
|
1136
|
-
...Object.keys((pkg
|
|
1137
|
-
...Object.keys((pkg
|
|
1308
|
+
...Object.keys(dependencyBlock(pkg, "dependencies")),
|
|
1309
|
+
...Object.keys(dependencyBlock(pkg, "devDependencies")),
|
|
1138
1310
|
]);
|
|
1139
1311
|
for (const entry of entries) {
|
|
1140
1312
|
entry.bundled = true;
|
|
@@ -1161,7 +1333,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1161
1333
|
if (!res.ok) {
|
|
1162
1334
|
return {};
|
|
1163
1335
|
}
|
|
1164
|
-
return
|
|
1336
|
+
return await readJson<ProjectSchemasResponse>(res);
|
|
1165
1337
|
} catch {
|
|
1166
1338
|
return {};
|
|
1167
1339
|
}
|
|
@@ -1173,7 +1345,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1173
1345
|
* backends without the route surface the error below instead of silently mangling format
|
|
1174
1346
|
* documents.
|
|
1175
1347
|
*/
|
|
1176
|
-
async formatAction(payload
|
|
1348
|
+
async formatAction(payload) {
|
|
1177
1349
|
const res = await postJson("/format", payload);
|
|
1178
1350
|
if (!res.ok) {
|
|
1179
1351
|
throw new Error(
|
|
@@ -1183,7 +1355,8 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1183
1355
|
),
|
|
1184
1356
|
);
|
|
1185
1357
|
}
|
|
1186
|
-
|
|
1358
|
+
// A successful answer is `{ result }`: the parsed document, or the serialized text.
|
|
1359
|
+
const data = await readJson<{ result: JxMutableNode | string }>(res);
|
|
1187
1360
|
return data.result;
|
|
1188
1361
|
},
|
|
1189
1362
|
|
|
@@ -1242,12 +1415,15 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1242
1415
|
const metas = await Promise.all(
|
|
1243
1416
|
jsonPaths.map(async (path) => {
|
|
1244
1417
|
try {
|
|
1245
|
-
return componentMetaFrom(
|
|
1418
|
+
return componentMetaFrom(parseJson(await platform.readFile(path)), path);
|
|
1246
1419
|
} catch {
|
|
1247
1420
|
return null; // Not JSON, not readable, or not a component — all the same answer here.
|
|
1248
1421
|
}
|
|
1249
1422
|
}),
|
|
1250
1423
|
);
|
|
1424
|
+
/* SAFETY: the two Bun backends answer discoverComponents with this same componentMetaFrom
|
|
1425
|
+
output, so ComponentMeta's narrower prop typing describes exactly what Studio already
|
|
1426
|
+
receives for these documents everywhere else. */
|
|
1251
1427
|
return metas.filter((m): m is NonNullable<typeof m> => m !== null) as ComponentMeta[];
|
|
1252
1428
|
},
|
|
1253
1429
|
|
|
@@ -1263,36 +1439,34 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1263
1439
|
|
|
1264
1440
|
async addPackage(name: string) {
|
|
1265
1441
|
const pkg = await readPackageJson();
|
|
1266
|
-
const deps = (pkg
|
|
1442
|
+
const deps = dependencyBlock(pkg, "dependencies");
|
|
1267
1443
|
const at = name.lastIndexOf("@");
|
|
1268
1444
|
const [pkgName, version] =
|
|
1269
1445
|
at > 0 ? [name.slice(0, at), name.slice(at + 1)] : [name, "latest"];
|
|
1270
1446
|
deps[pkgName] = version;
|
|
1271
1447
|
pkg["dependencies"] = deps;
|
|
1272
1448
|
await writePackageJson(pkg);
|
|
1273
|
-
return { ok: true, name: pkgName, version };
|
|
1274
1449
|
},
|
|
1275
1450
|
|
|
1276
1451
|
async removePackage(name: string) {
|
|
1277
1452
|
const pkg = await readPackageJson();
|
|
1278
1453
|
for (const key of ["dependencies", "devDependencies"]) {
|
|
1279
|
-
const deps = pkg[key]
|
|
1280
|
-
if (deps && name in deps) {
|
|
1454
|
+
const deps = pkg[key];
|
|
1455
|
+
if (isJsonObject(deps) && name in deps) {
|
|
1281
1456
|
pkg[key] = Object.fromEntries(Object.entries(deps).filter(([dep]) => dep !== name));
|
|
1282
1457
|
}
|
|
1283
1458
|
}
|
|
1284
1459
|
await writePackageJson(pkg);
|
|
1285
|
-
return { ok: true, name };
|
|
1286
1460
|
},
|
|
1287
1461
|
|
|
1288
1462
|
async listPackages(): Promise<PackageInfo[]> {
|
|
1289
1463
|
const pkg = await readPackageJson();
|
|
1290
1464
|
const out: PackageInfo[] = [];
|
|
1291
|
-
const deps = (pkg
|
|
1465
|
+
const deps = dependencyBlock(pkg, "dependencies");
|
|
1292
1466
|
for (const [name, version] of Object.entries(deps)) {
|
|
1293
1467
|
out.push({ name, version });
|
|
1294
1468
|
}
|
|
1295
|
-
const devDeps = (pkg
|
|
1469
|
+
const devDeps = dependencyBlock(pkg, "devDependencies");
|
|
1296
1470
|
for (const [name, version] of Object.entries(devDeps)) {
|
|
1297
1471
|
out.push({ name, version, dev: true });
|
|
1298
1472
|
}
|
|
@@ -1304,12 +1478,15 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1304
1478
|
async resolveSiteContext(filePath: string) {
|
|
1305
1479
|
try {
|
|
1306
1480
|
const info = await projectInfo();
|
|
1307
|
-
const config =
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1481
|
+
const config = info.projectConfig ?? undefined;
|
|
1482
|
+
const context: SiteContext = { sitePath: root };
|
|
1483
|
+
if (config !== undefined) {
|
|
1484
|
+
context.projectConfig = config;
|
|
1485
|
+
}
|
|
1486
|
+
if (filePath !== root) {
|
|
1487
|
+
context.fileRelPath = filePath;
|
|
1488
|
+
}
|
|
1489
|
+
return context;
|
|
1313
1490
|
} catch {
|
|
1314
1491
|
return { sitePath: null };
|
|
1315
1492
|
}
|
|
@@ -1319,7 +1496,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1319
1496
|
try {
|
|
1320
1497
|
const res = await api(`/locate?name=${encodeURIComponent(name)}`);
|
|
1321
1498
|
if (res.ok) {
|
|
1322
|
-
const body =
|
|
1499
|
+
const body = await readJson<{ path?: string | null }>(res);
|
|
1323
1500
|
return body.path ?? null;
|
|
1324
1501
|
}
|
|
1325
1502
|
} catch {
|
|
@@ -1336,7 +1513,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1336
1513
|
if (!res.ok) {
|
|
1337
1514
|
return [];
|
|
1338
1515
|
}
|
|
1339
|
-
return
|
|
1516
|
+
return await readJson<DirEntry[]>(res);
|
|
1340
1517
|
},
|
|
1341
1518
|
|
|
1342
1519
|
// ─── Git (virtual engine in the ProjectSession DO) ─────────────────────
|
|
@@ -1346,7 +1523,15 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1346
1523
|
},
|
|
1347
1524
|
|
|
1348
1525
|
async gitBranches() {
|
|
1349
|
-
|
|
1526
|
+
const listed = await okJson<GitBranchesResult>(
|
|
1527
|
+
await api("/git/branches"),
|
|
1528
|
+
"Failed to list branches",
|
|
1529
|
+
);
|
|
1530
|
+
if (listed.defaultBranch) {
|
|
1531
|
+
return listed;
|
|
1532
|
+
}
|
|
1533
|
+
const name = await repositoryDefaultBranch();
|
|
1534
|
+
return name ? { ...listed, defaultBranch: name } : listed;
|
|
1350
1535
|
},
|
|
1351
1536
|
|
|
1352
1537
|
async gitLog(limit?: number) {
|
|
@@ -1458,7 +1643,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1458
1643
|
if (!res.ok) {
|
|
1459
1644
|
return [];
|
|
1460
1645
|
}
|
|
1461
|
-
return
|
|
1646
|
+
return await readJson<StarterInfo[]>(res);
|
|
1462
1647
|
},
|
|
1463
1648
|
|
|
1464
1649
|
/** Welcome/recents open path: navigate this tab into the project's editor. */
|
|
@@ -1531,14 +1716,14 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1531
1716
|
missing App installation, the offered actions of an `action-required` refusal. */
|
|
1532
1717
|
throw await platformError(res, "Failed to create project");
|
|
1533
1718
|
}
|
|
1534
|
-
const created =
|
|
1719
|
+
const created = await readJson<{ owner: string; name: string; defaultBranch: string }>(res);
|
|
1535
1720
|
return {
|
|
1536
1721
|
root: projectRootKey({
|
|
1537
1722
|
owner: created.owner,
|
|
1538
1723
|
repo: created.name,
|
|
1539
1724
|
branch: created.defaultBranch,
|
|
1540
1725
|
}),
|
|
1541
|
-
config: { name: opts.name }
|
|
1726
|
+
config: { name: opts.name } satisfies ProjectConfig,
|
|
1542
1727
|
};
|
|
1543
1728
|
},
|
|
1544
1729
|
|
|
@@ -1576,17 +1761,20 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1576
1761
|
if (!res.ok) {
|
|
1577
1762
|
return null;
|
|
1578
1763
|
}
|
|
1579
|
-
const me =
|
|
1764
|
+
const me = await readJson<{
|
|
1580
1765
|
user: { login: string; name: string | null; avatar_url: string | null } | null;
|
|
1581
|
-
};
|
|
1766
|
+
}>(res);
|
|
1582
1767
|
if (!me.user) {
|
|
1583
1768
|
return null;
|
|
1584
1769
|
}
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1770
|
+
const user: SignedInUser = { login: me.user.login };
|
|
1771
|
+
if (me.user.name) {
|
|
1772
|
+
user.name = me.user.name;
|
|
1773
|
+
}
|
|
1774
|
+
if (me.user.avatar_url) {
|
|
1775
|
+
user.avatarUrl = me.user.avatar_url;
|
|
1776
|
+
}
|
|
1777
|
+
return user;
|
|
1590
1778
|
},
|
|
1591
1779
|
|
|
1592
1780
|
/** Repositories reachable through the user's Jx Suite App installations (user + org). */
|
|
@@ -1595,7 +1783,7 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1595
1783
|
if (!res.ok) {
|
|
1596
1784
|
throw new Error(await errorMessage(res, "Failed to list repositories"));
|
|
1597
1785
|
}
|
|
1598
|
-
const entries =
|
|
1786
|
+
const entries = await readJson<(RepoInfo & { repoId: number })[]>(res);
|
|
1599
1787
|
return entries.map((r) => ({
|
|
1600
1788
|
owner: r.owner,
|
|
1601
1789
|
name: r.name,
|
|
@@ -1636,24 +1824,29 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1636
1824
|
if (dir === null) {
|
|
1637
1825
|
throw new Error("The project folder must stay inside the repository.");
|
|
1638
1826
|
}
|
|
1827
|
+
const importRequest: ImportProjectRequest = { owner: opts.owner, name: opts.name };
|
|
1828
|
+
if (dir) {
|
|
1829
|
+
importRequest.dir = dir;
|
|
1830
|
+
}
|
|
1639
1831
|
const res = await fetch("/api/v1/projects/import", {
|
|
1640
1832
|
method: "POST",
|
|
1641
1833
|
credentials: "include",
|
|
1642
1834
|
headers: { "Content-Type": "application/json" },
|
|
1643
|
-
body: JSON.stringify(
|
|
1835
|
+
body: JSON.stringify(importRequest),
|
|
1644
1836
|
});
|
|
1645
1837
|
const imported = await okJson<{ owner: string; name: string; defaultBranch: string }>(
|
|
1646
1838
|
res,
|
|
1647
1839
|
"Failed to import repository",
|
|
1648
1840
|
);
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
branch: imported.defaultBranch,
|
|
1654
|
-
...(dir ? { dir } : {}),
|
|
1655
|
-
}),
|
|
1841
|
+
const importedProject: CloudProject = {
|
|
1842
|
+
owner: imported.owner,
|
|
1843
|
+
repo: imported.name,
|
|
1844
|
+
branch: imported.defaultBranch,
|
|
1656
1845
|
};
|
|
1846
|
+
if (dir) {
|
|
1847
|
+
importedProject.dir = dir;
|
|
1848
|
+
}
|
|
1849
|
+
return { root: projectRootKey(importedProject) };
|
|
1657
1850
|
},
|
|
1658
1851
|
|
|
1659
1852
|
/**
|
|
@@ -1667,10 +1860,10 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1667
1860
|
if (!res.ok) {
|
|
1668
1861
|
return null;
|
|
1669
1862
|
}
|
|
1670
|
-
const me =
|
|
1863
|
+
const me = await readJson<MeWire>(res);
|
|
1671
1864
|
const entries = accountEntries(me.entries);
|
|
1672
1865
|
const notices = accountNotices(me.notices);
|
|
1673
|
-
|
|
1866
|
+
const status: AccountStatus = {
|
|
1674
1867
|
installations: (me.installations ?? []).map((entry) => {
|
|
1675
1868
|
const installation: AccountStatus["installations"][number] = {
|
|
1676
1869
|
id: entry.id,
|
|
@@ -1681,10 +1874,17 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1681
1874
|
}
|
|
1682
1875
|
return installation;
|
|
1683
1876
|
}),
|
|
1684
|
-
...(me.appInstallUrl ? { appInstallUrl: me.appInstallUrl } : {}),
|
|
1685
|
-
...(entries.length > 0 ? { entries } : {}),
|
|
1686
|
-
...(notices.length > 0 ? { notices } : {}),
|
|
1687
1877
|
};
|
|
1878
|
+
if (me.appInstallUrl) {
|
|
1879
|
+
status.appInstallUrl = me.appInstallUrl;
|
|
1880
|
+
}
|
|
1881
|
+
if (entries.length > 0) {
|
|
1882
|
+
status.entries = entries;
|
|
1883
|
+
}
|
|
1884
|
+
if (notices.length > 0) {
|
|
1885
|
+
status.notices = notices;
|
|
1886
|
+
}
|
|
1887
|
+
return status;
|
|
1688
1888
|
},
|
|
1689
1889
|
|
|
1690
1890
|
/**
|
|
@@ -1823,34 +2023,31 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
1823
2023
|
async cfApi(apiPath: string, init?: { method?: string; body?: unknown }) {
|
|
1824
2024
|
/* The project rides in a HEADER, never the query: the platform forwards this path's query
|
|
1825
2025
|
string to Cloudflare verbatim. */
|
|
1826
|
-
const headers: Record<string, string> = {
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
2026
|
+
const headers: Record<string, string> = {};
|
|
2027
|
+
if (projectHint) {
|
|
2028
|
+
headers["X-Jx-Project"] = projectHint;
|
|
2029
|
+
}
|
|
2030
|
+
if (init?.body !== undefined) {
|
|
2031
|
+
headers["Content-Type"] = "application/json";
|
|
2032
|
+
}
|
|
2033
|
+
const request: RequestInit = { method: init?.method ?? "GET", credentials: "include" };
|
|
2034
|
+
if (Object.keys(headers).length > 0) {
|
|
2035
|
+
request.headers = headers;
|
|
2036
|
+
}
|
|
2037
|
+
if (init?.body !== undefined) {
|
|
2038
|
+
request.body = JSON.stringify(init.body);
|
|
2039
|
+
}
|
|
2040
|
+
const res = await fetch(`/api/v1/cf/proxy${apiPath}`, request);
|
|
1836
2041
|
/* An `action-required` refusal is the platform's answer, not Cloudflare's, so it is not
|
|
1837
2042
|
dressed as one: it keeps its own sentence and the actions the publish flow offers. Read
|
|
1838
2043
|
from a clone, because every other 403 is Cloudflare's own and is parsed below. */
|
|
1839
2044
|
if (res.status === 403) {
|
|
1840
|
-
const refusal =
|
|
1841
|
-
.clone()
|
|
1842
|
-
.json()
|
|
1843
|
-
.catch(() => null)) as StructuredBody | null;
|
|
2045
|
+
const refusal = await readJson<StructuredBody | null>(res.clone()).catch(() => null);
|
|
1844
2046
|
if (isActionRequiredBody(refusal)) {
|
|
1845
2047
|
throw await platformError(res, "Publishing was refused");
|
|
1846
2048
|
}
|
|
1847
2049
|
}
|
|
1848
|
-
const envelope =
|
|
1849
|
-
success?: boolean;
|
|
1850
|
-
result?: unknown;
|
|
1851
|
-
errors?: { message: string }[];
|
|
1852
|
-
error?: string;
|
|
1853
|
-
};
|
|
2050
|
+
const envelope = await readJson<CfProxyEnvelope>(res);
|
|
1854
2051
|
if (!res.ok || envelope.success === false) {
|
|
1855
2052
|
const message =
|
|
1856
2053
|
envelope.errors?.map((e) => e.message).join("; ") ?? envelope.error ?? res.statusText;
|