@jxsuite/studio 2.0.1 → 2.1.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/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-799jpvhm.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-799jpvhm.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-8jxwts2p.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-gs6kqdt1.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-esrewxap.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-v7jkjqng.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-jm0z592w.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +21080 -32585
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +7 -0
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +221 -245
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -53
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +30 -1
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +7 -1
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qr3drkkw.js +0 -531
- package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
- package/dist/chunks/files-j8a1t06k.js +0 -50
- package/dist/chunks/files-j8a1t06k.js.map +0 -9
- package/dist/chunks/git-panel-xtq5z81x.js +0 -28
- package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
- package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
- package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
- package/dist/chunks/settings-modal-17ttr96g.js +0 -29
- package/dist/chunks/settings-modal-17ttr96g.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-0xgs7xrs.js +0 -429
- package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
- package/dist/chunks/studio-4d8hzcz5.js +0 -3427
- package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-jm0z592w.js.map +0 -115
- package/dist/chunks/studio-m2t4mdg5.js +0 -1854
- package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
- package/dist/chunks/studio-n4p11dfy.js +0 -853
- package/dist/chunks/studio-n4p11dfy.js.map +0 -12
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-sjh1wt1a.js +0 -3744
- package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
- package/dist/chunks/studio-v7jkjqng.js.map +0 -46
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-yfcstdzy.js +0 -399
- package/dist/chunks/studio-yfcstdzy.js.map +0 -12
- package/dist/chunks/studio-zp7jncs8.js +0 -469
- package/dist/chunks/studio-zp7jncs8.js.map +0 -14
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-8jxwts2p.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-esrewxap.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
|
@@ -1,17 +1,140 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* GitHub
|
|
3
|
+
* GitHub sign-in for Jx Studio: the desktop's loopback redirect, and the browser's device flow.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* redirect
|
|
5
|
+
* **Which flow runs depends on what the build has, not on preference.** A desktop launcher exposes
|
|
6
|
+
* `githubAuth` on `globalThis.__jxPlatform`, backed by an RFC 8252 loopback redirect with PKCE —
|
|
7
|
+
* the user signs in on GitHub's own page in their own browser, the authorization code comes back to
|
|
8
|
+
* a loopback server, and the token is stored in the app's config folder at `0600`. A page in a
|
|
9
|
+
* browser has no loopback server to redirect to, so it keeps the Device Flow below.
|
|
10
|
+
*
|
|
11
|
+
* The Device Flow needs no server-side redirect endpoint, which is exactly why it was chosen here
|
|
12
|
+
* and exactly why it is the wrong tool for a desktop app: RFC 8628 designed it for devices that
|
|
13
|
+
* cannot show a browser or take typed input, and it costs the user a code copied between windows.
|
|
14
|
+
*
|
|
15
|
+
* **This flow fails, and until now it failed silently.** `https://github.com/login/device/code`
|
|
16
|
+
* sends no `Access-Control-Allow-Origin`, so a browser cannot call it: in Studio-in-a-browser the
|
|
17
|
+
* very first request rejects with a bare `TypeError`. That rejection used to become a thrown
|
|
18
|
+
* `Error` out of {@link authenticateGithub}, into `void createGithubRepository(…)` in
|
|
19
|
+
* `panels/git-panel.ts`, and from there into an unhandled promise rejection — the user clicked
|
|
20
|
+
* "Create GitHub repository" and the app did nothing at all, forever, with no message anywhere.
|
|
21
|
+
*
|
|
22
|
+
* Three failures now reach a surface, each as the kind of record §16 says it is:
|
|
23
|
+
*
|
|
24
|
+
* - **Unreachable** (CORS, offline, DNS) → a **Problem**, because it must be fixed and the fix is not
|
|
25
|
+
* in this dialog, carrying `git.signInToGithub` as its Retry;
|
|
26
|
+
* - **Refused by GitHub** (an HTTP error, `access_denied`, `expired_token`) → a **toast**, because
|
|
27
|
+
* the state is now correct and there is nothing to fix — the user declined, or waited too long;
|
|
28
|
+
* - **A poll that keeps failing** → a Problem after {@link MAX_POLL_FAILURES} consecutive rejections,
|
|
29
|
+
* rather than the previous empty catch that re-armed the timer forever. A dialog that says
|
|
30
|
+
* "Waiting for authorization…" against a network that will never answer is the exact dishonesty
|
|
31
|
+
* the feedback system exists to end.
|
|
32
|
+
*
|
|
33
|
+
* **What it cannot tell you.** A cross-origin block and an unplugged cable are the same `TypeError`
|
|
34
|
+
* here — the browser withholds the reason on purpose — so the detail names both rather than
|
|
35
|
+
* guessing between them.
|
|
36
|
+
*
|
|
37
|
+
* The token is returned to callers and never rendered. In a browser it is stored in `localStorage`;
|
|
38
|
+
* on the desktop it is in the launcher's `0600` credential store and this module holds it only in
|
|
39
|
+
* memory for the session. `settings/preferences-accounts.ts` lists it as _stored or not_ and is the
|
|
40
|
+
* only place it can be revoked (`studio.md` §15 rule 1).
|
|
7
41
|
*/
|
|
8
42
|
|
|
9
43
|
import { html } from "lit-html";
|
|
44
|
+
import { errorMessage } from "@jxsuite/schema/parse";
|
|
45
|
+
import { notify } from "../services/notify";
|
|
10
46
|
import { showDialog } from "../ui/layers";
|
|
11
47
|
|
|
12
48
|
const CLIENT_ID = "Ov23liYVlMFpgjOEPXJH";
|
|
13
49
|
const STORAGE_KEY = "jx_github_token";
|
|
14
50
|
|
|
51
|
+
/**
|
|
52
|
+
* The desktop launcher's RFC 8252 sign-in, when this build is running inside one.
|
|
53
|
+
*
|
|
54
|
+
* Launcher-only, like `updater` and `windowControls`, and reached the same way — a loopback
|
|
55
|
+
* redirect needs a loopback server, which a page in a browser does not have.
|
|
56
|
+
*/
|
|
57
|
+
interface NativeGithubAuth {
|
|
58
|
+
signIn: (force?: boolean) => Promise<{ token: string }>;
|
|
59
|
+
signOut: () => Promise<{ ok: boolean }>;
|
|
60
|
+
status: () => Promise<{ stored: boolean }>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function nativeAuth(): NativeGithubAuth | null {
|
|
64
|
+
return (
|
|
65
|
+
(globalThis as unknown as { __jxPlatform?: { githubAuth?: NativeGithubAuth } }).__jxPlatform
|
|
66
|
+
?.githubAuth ?? null
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The token the desktop store handed us this session.
|
|
72
|
+
*
|
|
73
|
+
* On the desktop the token at rest is a `0600` file in the user's config directory, **not**
|
|
74
|
+
* `localStorage` — so it is not readable by script in the webview between sessions, and it does not
|
|
75
|
+
* survive in a place a stray extension or a copied profile can reach. Holding it in a module
|
|
76
|
+
* variable is what keeps {@link getGithubToken} synchronous for its callers.
|
|
77
|
+
*/
|
|
78
|
+
let nativeToken: string | null = null;
|
|
79
|
+
|
|
80
|
+
/** Whether the desktop store holds a token, as of the last time it was asked. */
|
|
81
|
+
let nativeStored = false;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Record that the desktop's credential store does (or does not) hold a token.
|
|
85
|
+
*
|
|
86
|
+
* The launcher calls this once at startup. It carries a **boolean, not the token**: the accounts
|
|
87
|
+
* pane only needs to know whether one exists, and handing the webview a credential it has not been
|
|
88
|
+
* asked to use is the exposure the 0600 store exists to remove. When a sign-in does happen the
|
|
89
|
+
* token arrives through {@link authenticateGithub} and lives in memory for that session.
|
|
90
|
+
*
|
|
91
|
+
* @param {boolean} stored
|
|
92
|
+
*/
|
|
93
|
+
export function hydrateGithubToken(stored: boolean): void {
|
|
94
|
+
nativeStored = stored;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Whether a GitHub credential exists, wherever it lives.
|
|
99
|
+
*
|
|
100
|
+
* Separate from {@link getGithubToken} because the two questions genuinely differ on the desktop: a
|
|
101
|
+
* token can be stored on disk and not yet in this session's memory, and the accounts pane asks
|
|
102
|
+
* "signed in?" while rendering — synchronously — where an API caller asks for the credential itself
|
|
103
|
+
* and can await it.
|
|
104
|
+
*
|
|
105
|
+
* @returns {boolean}
|
|
106
|
+
*/
|
|
107
|
+
export function githubTokenStored(): boolean {
|
|
108
|
+
return nativeToken !== null || nativeStored || localStorage.getItem(STORAGE_KEY) !== null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Where the credential this build would use actually lives, for text that says so. */
|
|
112
|
+
export function githubTokenLocation(): "desktop" | "browser" {
|
|
113
|
+
return nativeAuth() ? "desktop" : "browser";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** One key for the whole sign-in, so a second attempt REPLACES the first report. */
|
|
117
|
+
const NOTIFY_KEY = "github.auth";
|
|
118
|
+
|
|
119
|
+
const SOURCE = "Source Control";
|
|
120
|
+
|
|
121
|
+
/** The Retry every report carries — one command, so the button's label comes off the record. */
|
|
122
|
+
const RETRY = "git.signInToGithub";
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* How many consecutive poll rejections end the wait.
|
|
126
|
+
*
|
|
127
|
+
* Three, not one: the device flow legitimately polls across a laptop's sleep and a Wi-Fi hop, and
|
|
128
|
+
* failing on the first blip would abandon a sign-in the user is in the middle of completing.
|
|
129
|
+
*/
|
|
130
|
+
export const MAX_POLL_FAILURES = 3;
|
|
131
|
+
|
|
132
|
+
/** Both halves of what a browser will not tell us, said once. */
|
|
133
|
+
const UNREACHABLE_DETAIL =
|
|
134
|
+
"The request never reached GitHub. GitHub's device-flow endpoints send no CORS headers, so a " +
|
|
135
|
+
"browser cannot call them directly — the desktop app can. A machine that is offline fails " +
|
|
136
|
+
"identically, and the browser does not say which happened.";
|
|
137
|
+
|
|
15
138
|
interface DeviceCodeResponse {
|
|
16
139
|
device_code: string;
|
|
17
140
|
user_code: string;
|
|
@@ -25,18 +148,73 @@ interface TokenResponse {
|
|
|
25
148
|
}
|
|
26
149
|
|
|
27
150
|
export function getGithubToken() {
|
|
28
|
-
return localStorage.getItem(STORAGE_KEY);
|
|
151
|
+
return nativeToken ?? localStorage.getItem(STORAGE_KEY);
|
|
29
152
|
}
|
|
30
153
|
|
|
31
154
|
export function clearGithubToken() {
|
|
155
|
+
nativeToken = null;
|
|
156
|
+
nativeStored = false;
|
|
32
157
|
localStorage.removeItem(STORAGE_KEY);
|
|
158
|
+
// Fire-and-forget: the accounts pane's revoke is synchronous, and a store that failed to forget
|
|
159
|
+
// The token is not something the user can act on from there.
|
|
160
|
+
void nativeAuth()
|
|
161
|
+
?.signOut()
|
|
162
|
+
.catch(() => {});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** The request never completed — a Problem, with the one sentence that covers both causes. */
|
|
166
|
+
function reportUnreachable(error: unknown): void {
|
|
167
|
+
notify.error("Could not reach GitHub to sign in.", {
|
|
168
|
+
action: RETRY,
|
|
169
|
+
detail: `${UNREACHABLE_DETAIL}\n\n${errorMessage(error)}`,
|
|
170
|
+
key: NOTIFY_KEY,
|
|
171
|
+
source: SOURCE,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** GitHub answered, and said no. Nothing is broken, so this rests rather than persists. */
|
|
176
|
+
function reportRefused(message: string, detail: string): void {
|
|
177
|
+
notify.warn(message, { action: RETRY, detail, key: NOTIFY_KEY, source: SOURCE });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Start the device flow.
|
|
182
|
+
*
|
|
183
|
+
* @returns The device code payload, or null when the request failed — reported, never thrown, so a
|
|
184
|
+
* caller that forgot to catch cannot turn a network error back into silence.
|
|
185
|
+
*/
|
|
186
|
+
async function requestDeviceCode(): Promise<DeviceCodeResponse | null> {
|
|
187
|
+
let codeRes: Response;
|
|
188
|
+
try {
|
|
189
|
+
codeRes = await fetch("https://github.com/login/device/code", {
|
|
190
|
+
body: JSON.stringify({ client_id: CLIENT_ID, scope: "repo" }),
|
|
191
|
+
headers: {
|
|
192
|
+
Accept: "application/json",
|
|
193
|
+
"Content-Type": "application/json",
|
|
194
|
+
},
|
|
195
|
+
method: "POST",
|
|
196
|
+
});
|
|
197
|
+
} catch (error) {
|
|
198
|
+
reportUnreachable(error);
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!codeRes.ok) {
|
|
203
|
+
reportRefused(
|
|
204
|
+
"GitHub refused to start the sign-in.",
|
|
205
|
+
`GitHub answered ${codeRes.status}${codeRes.statusText ? ` ${codeRes.statusText}` : ""}.`,
|
|
206
|
+
);
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return (await codeRes.json()) as DeviceCodeResponse;
|
|
33
210
|
}
|
|
34
211
|
|
|
35
212
|
/**
|
|
36
213
|
* Authenticate with GitHub via the Device Flow. Shows a dialog with the user code and polls until
|
|
37
214
|
* the user completes authorization or cancels.
|
|
38
215
|
*
|
|
39
|
-
* @returns {Promise<string | null>} The access token, or null if cancelled.
|
|
216
|
+
* @returns {Promise<string | null>} The access token, or null if it failed or was cancelled. Every
|
|
217
|
+
* `null` that is not a cancellation has already been reported.
|
|
40
218
|
*/
|
|
41
219
|
export async function authenticateGithub() {
|
|
42
220
|
const existing = getGithubToken();
|
|
@@ -44,25 +222,43 @@ export async function authenticateGithub() {
|
|
|
44
222
|
return existing;
|
|
45
223
|
}
|
|
46
224
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
225
|
+
/*
|
|
226
|
+
* The desktop takes the loopback redirect (RFC 8252): its browser opens the provider's own page,
|
|
227
|
+
* the code comes back to a loopback server, and PKCE binds the exchange. The device flow below is
|
|
228
|
+
* for the browser Studio, which has no loopback server to redirect to — and whose first request
|
|
229
|
+
* to GitHub's device endpoint is refused by CORS anyway.
|
|
230
|
+
*/
|
|
231
|
+
const native = nativeAuth();
|
|
232
|
+
if (native) {
|
|
233
|
+
try {
|
|
234
|
+
const { token } = await native.signIn();
|
|
235
|
+
nativeToken = token;
|
|
236
|
+
return token;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
reportRefused("GitHub sign-in was not completed.", errorMessage(error));
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
55
242
|
|
|
56
|
-
|
|
57
|
-
|
|
243
|
+
const codeData = await requestDeviceCode();
|
|
244
|
+
if (!codeData) {
|
|
245
|
+
return null;
|
|
58
246
|
}
|
|
59
|
-
const codeData = (await codeRes.json()) as DeviceCodeResponse;
|
|
60
247
|
|
|
61
248
|
const { device_code, user_code, verification_uri, interval = 5 } = codeData;
|
|
62
249
|
|
|
63
|
-
return showDialog((done) => {
|
|
250
|
+
return showDialog<string | null>((done) => {
|
|
64
251
|
let cancelled = false;
|
|
65
252
|
let pollTimer: ReturnType<typeof setTimeout> | null = null;
|
|
253
|
+
let failures = 0;
|
|
254
|
+
|
|
255
|
+
const stop = () => {
|
|
256
|
+
cancelled = true;
|
|
257
|
+
if (pollTimer) {
|
|
258
|
+
clearTimeout(pollTimer);
|
|
259
|
+
}
|
|
260
|
+
done(null);
|
|
261
|
+
};
|
|
66
262
|
|
|
67
263
|
const poll = async () => {
|
|
68
264
|
if (cancelled) {
|
|
@@ -82,6 +278,7 @@ export async function authenticateGithub() {
|
|
|
82
278
|
method: "POST",
|
|
83
279
|
});
|
|
84
280
|
const tokenData = (await tokenRes.json()) as TokenResponse;
|
|
281
|
+
failures = 0;
|
|
85
282
|
|
|
86
283
|
if (tokenData.access_token) {
|
|
87
284
|
localStorage.setItem(STORAGE_KEY, tokenData.access_token);
|
|
@@ -99,9 +296,26 @@ export async function authenticateGithub() {
|
|
|
99
296
|
return;
|
|
100
297
|
}
|
|
101
298
|
|
|
102
|
-
// Expired_token or
|
|
299
|
+
// Expired_token, access_denied, or anything else GitHub decides to answer. The state is
|
|
300
|
+
// Correct — there is no token because the user did not grant one — so this rests.
|
|
301
|
+
reportRefused(
|
|
302
|
+
"GitHub sign-in was not completed.",
|
|
303
|
+
tokenData.error === "access_denied"
|
|
304
|
+
? "The authorization was declined on GitHub."
|
|
305
|
+
: tokenData.error === "expired_token"
|
|
306
|
+
? "The device code expired before it was entered."
|
|
307
|
+
: `GitHub answered "${tokenData.error ?? "an unrecognised response"}".`,
|
|
308
|
+
);
|
|
309
|
+
cancelled = true;
|
|
103
310
|
done(null);
|
|
104
|
-
} catch {
|
|
311
|
+
} catch (error) {
|
|
312
|
+
failures += 1;
|
|
313
|
+
if (failures >= MAX_POLL_FAILURES) {
|
|
314
|
+
reportUnreachable(error);
|
|
315
|
+
cancelled = true;
|
|
316
|
+
done(null);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
105
319
|
pollTimer = setTimeout(poll, interval * 1000);
|
|
106
320
|
}
|
|
107
321
|
};
|
|
@@ -113,20 +327,8 @@ export async function authenticateGithub() {
|
|
|
113
327
|
open
|
|
114
328
|
headline="Sign in to GitHub"
|
|
115
329
|
cancel-label="Cancel"
|
|
116
|
-
@cancel=${
|
|
117
|
-
|
|
118
|
-
if (pollTimer) {
|
|
119
|
-
clearTimeout(pollTimer);
|
|
120
|
-
}
|
|
121
|
-
done(null);
|
|
122
|
-
}}
|
|
123
|
-
@close=${() => {
|
|
124
|
-
cancelled = true;
|
|
125
|
-
if (pollTimer) {
|
|
126
|
-
clearTimeout(pollTimer);
|
|
127
|
-
}
|
|
128
|
-
done(null);
|
|
129
|
-
}}
|
|
330
|
+
@cancel=${stop}
|
|
331
|
+
@close=${stop}
|
|
130
332
|
>
|
|
131
333
|
<div class="github-auth-dialog">
|
|
132
334
|
<p>Enter this code on GitHub to authorize Jx Studio:</p>
|
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Create a GitHub repository for a local project, add it as `origin`, and push.
|
|
4
|
+
*
|
|
5
|
+
* **This is not publishing, and it used to say it was.** Two unrelated operations shared the verb
|
|
6
|
+
* (plan §9.5): this one creates a git repository, and `publish/publish-panel.ts` connects a hosting
|
|
7
|
+
* provider that then builds the site. A user who wanted the second and found the first got a GitHub
|
|
8
|
+
* repository and no site, and a user who wanted the first read "Publish to GitHub" and reasonably
|
|
9
|
+
* expected a URL. The function, the dialog headline, the activity title and the notification source
|
|
10
|
+
* now all say _Create GitHub Repository_; `Publish:` belongs to `publish/publish-commands.ts`.
|
|
11
|
+
*
|
|
12
|
+
* **It is an Activity, not three toasts.** Three `notify.info` lines sharing one key replaced each
|
|
13
|
+
* other in a corner while a multi-second, three-request, partially-committing operation ran with no
|
|
14
|
+
* log and no cancel — and its middle step (`gitAddRemote`) had no error path at all, so a remote
|
|
15
|
+
* that already existed failed the push with a message about pushing. `beginActivity` gives it the
|
|
16
|
+
* ordered steps, the captured log, and `fail()`, which raises the Problem the failure needs and
|
|
17
|
+
* carries the log as its detail (§7.3). The caller therefore never also notifies.
|
|
18
|
+
*/
|
|
3
19
|
|
|
4
20
|
import { html } from "lit-html";
|
|
5
21
|
import { errorMessage } from "@jxsuite/schema/parse";
|
|
6
22
|
import { ref } from "lit-html/directives/ref.js";
|
|
7
23
|
import { showDialog } from "../ui/layers";
|
|
8
24
|
import { authenticateGithub } from "./github-auth";
|
|
25
|
+
import { beginActivity } from "../panels/activity-panel";
|
|
9
26
|
import { getPlatform } from "../platform";
|
|
10
|
-
import {
|
|
27
|
+
import { notify } from "../services/notify";
|
|
11
28
|
|
|
12
29
|
interface GithubErrorResponse {
|
|
13
30
|
errors?: { message?: string }[];
|
|
@@ -19,24 +36,34 @@ interface GithubRepoResponse {
|
|
|
19
36
|
html_url: string;
|
|
20
37
|
}
|
|
21
38
|
|
|
39
|
+
/** What the dialog collects. */
|
|
40
|
+
export interface RepoOptions {
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
isPrivate: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The ordered steps, named once so the activity and its tests cannot disagree. */
|
|
47
|
+
export const REPO_STEPS = ["Create the repository", "Add the remote", "Push"] as const;
|
|
48
|
+
|
|
22
49
|
/**
|
|
23
|
-
* Full "
|
|
24
|
-
* visibility 3. Create the repo via GitHub API 4. Add remote + push
|
|
50
|
+
* Full "Create GitHub Repository" flow: 1. Authenticate (or reuse a stored token) 2. Prompt for
|
|
51
|
+
* repo name / visibility 3. Create the repo via the GitHub API 4. Add remote + push
|
|
52
|
+
*
|
|
53
|
+
* A failed sign-in returns `false` having already reported itself — `github-auth.ts` owns that
|
|
54
|
+
* message, because "GitHub is unreachable from a browser" is not a fact about creating a
|
|
55
|
+
* repository.
|
|
25
56
|
*
|
|
26
57
|
* @param {{ projectName: string }} opts
|
|
27
|
-
* @returns {Promise<boolean>} True if
|
|
58
|
+
* @returns {Promise<boolean>} True if the repository was created and pushed.
|
|
28
59
|
*/
|
|
29
|
-
export async function
|
|
60
|
+
export async function createGithubRepository({ projectName }: { projectName: string }) {
|
|
30
61
|
const token = await authenticateGithub();
|
|
31
62
|
if (!token) {
|
|
32
63
|
return false;
|
|
33
64
|
}
|
|
34
65
|
|
|
35
|
-
const repoOpts = await showDialog<{
|
|
36
|
-
name: string;
|
|
37
|
-
description: string;
|
|
38
|
-
isPrivate: boolean;
|
|
39
|
-
} | null>((done) => {
|
|
66
|
+
const repoOpts = await showDialog<RepoOptions | null>((done) => {
|
|
40
67
|
let _nameInput: HTMLInputElement | null = null;
|
|
41
68
|
let _descInput: HTMLInputElement | null = null;
|
|
42
69
|
let _privateToggle: HTMLInputElement | null = null;
|
|
@@ -44,7 +71,7 @@ export async function publishToGithub({ projectName }: { projectName: string })
|
|
|
44
71
|
return html`
|
|
45
72
|
<sp-dialog-wrapper
|
|
46
73
|
open
|
|
47
|
-
headline="
|
|
74
|
+
headline="Create GitHub Repository"
|
|
48
75
|
confirm-label="Create Repository"
|
|
49
76
|
cancel-label="Cancel"
|
|
50
77
|
@confirm=${() => {
|
|
@@ -97,8 +124,14 @@ export async function publishToGithub({ projectName }: { projectName: string })
|
|
|
97
124
|
return false;
|
|
98
125
|
}
|
|
99
126
|
|
|
100
|
-
|
|
127
|
+
const activity = beginActivity({
|
|
128
|
+
source: "Source Control",
|
|
129
|
+
status: `Creating ${repoOpts.name}…`,
|
|
130
|
+
steps: [...REPO_STEPS],
|
|
131
|
+
title: "Create GitHub repository",
|
|
132
|
+
});
|
|
101
133
|
|
|
134
|
+
activity.step(REPO_STEPS[0]);
|
|
102
135
|
const createRes = await fetch("https://api.github.com/user/repos", {
|
|
103
136
|
body: JSON.stringify({
|
|
104
137
|
auto_init: false,
|
|
@@ -112,33 +145,59 @@ export async function publishToGithub({ projectName }: { projectName: string })
|
|
|
112
145
|
"Content-Type": "application/json",
|
|
113
146
|
},
|
|
114
147
|
method: "POST",
|
|
148
|
+
}).catch((error: unknown) => {
|
|
149
|
+
activity.log(errorMessage(error));
|
|
150
|
+
return null;
|
|
115
151
|
});
|
|
116
152
|
|
|
153
|
+
if (!createRes) {
|
|
154
|
+
activity.fail("Could not reach GitHub to create the repository.", {
|
|
155
|
+
action: "git.createGithubRepository",
|
|
156
|
+
});
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
117
160
|
if (!createRes.ok) {
|
|
118
161
|
const err = (await createRes.json()) as GithubErrorResponse;
|
|
119
|
-
|
|
120
|
-
|
|
162
|
+
activity.log(err.errors?.[0]?.message || err.message || `GitHub answered ${createRes.status}.`);
|
|
163
|
+
activity.fail("Could not create the GitHub repository.", {
|
|
164
|
+
action: "git.createGithubRepository",
|
|
165
|
+
});
|
|
121
166
|
return false;
|
|
122
167
|
}
|
|
123
168
|
|
|
124
169
|
const repo = (await createRes.json()) as GithubRepoResponse;
|
|
170
|
+
activity.log(`Created ${repo.html_url}`);
|
|
125
171
|
const platform = getPlatform();
|
|
126
172
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
173
|
+
activity.step(REPO_STEPS[1]);
|
|
174
|
+
try {
|
|
175
|
+
await platform.gitAddRemote("origin", repo.clone_url);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
// The remote had no error path at all before this, so an `origin` that already existed
|
|
178
|
+
// Surfaced as a push failure describing the push.
|
|
179
|
+
activity.log(errorMessage(error));
|
|
180
|
+
activity.fail("The repository was created, but the remote could not be added.", {
|
|
181
|
+
action: "panel.focus.git",
|
|
182
|
+
});
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
130
185
|
|
|
131
|
-
|
|
186
|
+
activity.step(REPO_STEPS[2]);
|
|
132
187
|
try {
|
|
133
188
|
await platform.gitPush({ setUpstream: true });
|
|
134
189
|
} catch (error) {
|
|
135
|
-
|
|
190
|
+
activity.log(errorMessage(error));
|
|
191
|
+
activity.fail("The repository was created, but the push failed.", {
|
|
192
|
+
action: "git.push",
|
|
193
|
+
});
|
|
136
194
|
return false;
|
|
137
195
|
}
|
|
138
196
|
|
|
139
197
|
// Lazy import breaks the github-publish ↔ git-panel module cycle
|
|
140
198
|
const { refreshGitStatus } = await import("../panels/git-panel");
|
|
141
199
|
await refreshGitStatus();
|
|
142
|
-
|
|
200
|
+
activity.done(repo.html_url);
|
|
201
|
+
notify.success(`Repository created: ${repo.html_url}`, { key: "github.repo" });
|
|
143
202
|
return true;
|
|
144
203
|
}
|