@jxsuite/studio 2.3.0 → 2.4.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/dist/chunks/{content-source-56xpvx83.js → content-source-jrvn5vwy.js} +8 -8
- package/dist/chunks/{convert-to-repeater-0xh9wwek.js → convert-to-repeater-109dwcj7.js} +7 -7
- package/dist/chunks/{extension-sections-g34239vm.js → extension-sections-2zjyty05.js} +11 -11
- package/dist/chunks/{files-gkz202dp.js → files-jdbtammm.js} +12 -12
- package/dist/chunks/{format-host-pej3srnw.js → format-host-kq6963gs.js} +2 -2
- package/dist/chunks/{git-panel-4j6xbh8g.js → git-panel-2stf3ahg.js} +7 -7
- package/dist/chunks/{layers-panel-8mvn8sgd.js → layers-panel-a8wjsdjj.js} +10 -10
- package/dist/chunks/{publish-panel-ptddc3kg.js → publish-panel-2we6smjv.js} +5 -5
- package/dist/chunks/{quick-search-j88azfs2.js → quick-search-hmpwdgys.js} +13 -13
- package/dist/chunks/{right-panel-egkaxy89.js → right-panel-hn3y3j0j.js} +9 -9
- package/dist/chunks/{studio-0e4h32g6.js → studio-0evba9z5.js} +5 -5
- package/dist/chunks/{studio-4058pg09.js → studio-102jzb8r.js} +4 -4
- package/dist/chunks/{studio-ncnet0ba.js → studio-1dgqagzz.js} +10 -10
- package/dist/chunks/{studio-yxzgjq8q.js → studio-377bbhtz.js} +8 -8
- package/dist/chunks/{studio-5ne8mdx9.js → studio-53dn6e6t.js} +2 -2
- package/dist/chunks/{studio-50eed4c9.js → studio-6gcrk1bq.js} +2 -2
- package/dist/chunks/{studio-5amdrjm4.js → studio-8x4399kc.js} +7 -7
- package/dist/chunks/{studio-hk523hby.js → studio-ddgrc5hs.js} +3 -3
- package/dist/chunks/{studio-3q65xvzv.js → studio-eqyybj2e.js} +4 -4
- package/dist/chunks/{studio-cf4rk7kv.js → studio-kwavhmdr.js} +2 -2
- package/dist/chunks/{studio-zdkgwhkv.js → studio-ky68mp85.js} +3 -3
- package/dist/chunks/{studio-hs8x23fv.js → studio-ng5gbxkj.js} +8 -8
- package/dist/chunks/{studio-4enps87v.js → studio-q07vj7p9.js} +6 -6
- package/dist/chunks/{studio-bak2cyjr.js → studio-qd4k0h80.js} +4 -4
- package/dist/chunks/{studio-cv606rs1.js → studio-rdsvb808.js} +5 -5
- package/dist/chunks/{studio-vdpcpada.js → studio-tqr02xaa.js} +3 -3
- package/dist/chunks/{studio-x3etxs0s.js → studio-wxthr2x1.js} +8 -8
- package/dist/chunks/{studio-10s469da.js → studio-yk7037sg.js} +20 -10
- package/dist/chunks/{studio-a11d3a1b.js → studio-yz06mkfj.js} +5 -5
- package/dist/iframe-entry.js +7 -3
- package/dist/studio.js +46 -34
- package/package.json +6 -6
- package/src/canvas/canvas-live-render.ts +2 -4
- package/src/canvas/canvas-origin.ts +25 -0
- package/src/platforms/cloud.ts +9 -0
- package/src/services/ai-models.ts +14 -1
- package/src/types.ts +17 -0
- package/src/ui/ai-managed-connect.ts +18 -3
- package/styles/shell.css +7 -0
package/dist/studio.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
seedPublishConnected
|
|
3
|
-
} from "./chunks/studio-
|
|
3
|
+
} from "./chunks/studio-tqr02xaa.js";
|
|
4
4
|
import"./chunks/studio-wdt9y92a.js";
|
|
5
5
|
import {
|
|
6
6
|
ElementResolutionController,
|
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
registerStyleCommands,
|
|
68
68
|
render as render3,
|
|
69
69
|
setInspectorTab
|
|
70
|
-
} from "./chunks/studio-
|
|
70
|
+
} from "./chunks/studio-8x4399kc.js";
|
|
71
71
|
import {
|
|
72
72
|
CommandUnavailableError,
|
|
73
73
|
chordFromEvent,
|
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
showSlashMenu,
|
|
100
100
|
showSlashMenuAtRect,
|
|
101
101
|
suppressBlockActionBar
|
|
102
|
-
} from "./chunks/studio-
|
|
102
|
+
} from "./chunks/studio-377bbhtz.js";
|
|
103
103
|
import {
|
|
104
104
|
addableContexts,
|
|
105
105
|
defaultCommands,
|
|
@@ -111,7 +111,7 @@ import {
|
|
|
111
111
|
tokenLabel,
|
|
112
112
|
transposeStylebookStyle,
|
|
113
113
|
writeTokenOverride
|
|
114
|
-
} from "./chunks/studio-
|
|
114
|
+
} from "./chunks/studio-yz06mkfj.js";
|
|
115
115
|
import {
|
|
116
116
|
DERIVE_PRESETS,
|
|
117
117
|
JxColorPopover,
|
|
@@ -144,7 +144,7 @@ import {
|
|
|
144
144
|
spNumberField,
|
|
145
145
|
spTextArea,
|
|
146
146
|
spTextField
|
|
147
|
-
} from "./chunks/studio-
|
|
147
|
+
} from "./chunks/studio-ng5gbxkj.js";
|
|
148
148
|
import {
|
|
149
149
|
LitElement,
|
|
150
150
|
css
|
|
@@ -160,7 +160,7 @@ import {
|
|
|
160
160
|
import {
|
|
161
161
|
initQuickSearch,
|
|
162
162
|
openQuickSearch
|
|
163
|
-
} from "./chunks/studio-
|
|
163
|
+
} from "./chunks/studio-qd4k0h80.js";
|
|
164
164
|
import {
|
|
165
165
|
addRecentProject,
|
|
166
166
|
clearRecentProjects,
|
|
@@ -187,10 +187,10 @@ import {
|
|
|
187
187
|
removeRecentProject,
|
|
188
188
|
renderFilesTemplate,
|
|
189
189
|
seedEntry
|
|
190
|
-
} from "./chunks/studio-
|
|
190
|
+
} from "./chunks/studio-1dgqagzz.js";
|
|
191
191
|
import {
|
|
192
192
|
computeWindow
|
|
193
|
-
} from "./chunks/studio-
|
|
193
|
+
} from "./chunks/studio-kwavhmdr.js";
|
|
194
194
|
import {
|
|
195
195
|
autoSyncProjectOnOpen,
|
|
196
196
|
cleanupGitPanel,
|
|
@@ -211,13 +211,13 @@ import {
|
|
|
211
211
|
registerSourceControlCommands,
|
|
212
212
|
renderGitPanel,
|
|
213
213
|
stripRange
|
|
214
|
-
} from "./chunks/studio-
|
|
214
|
+
} from "./chunks/studio-q07vj7p9.js";
|
|
215
215
|
import {
|
|
216
216
|
createPanelScheduler
|
|
217
217
|
} from "./chunks/studio-8jpzqk5s.js";
|
|
218
218
|
import {
|
|
219
219
|
selectContributedEntry
|
|
220
|
-
} from "./chunks/studio-
|
|
220
|
+
} from "./chunks/studio-rdsvb808.js";
|
|
221
221
|
import {
|
|
222
222
|
notifySettingsDocument,
|
|
223
223
|
onSettingsDocumentChanged,
|
|
@@ -238,7 +238,7 @@ import {
|
|
|
238
238
|
renderForm,
|
|
239
239
|
renderProvenanceChip,
|
|
240
240
|
resolveContextPointer
|
|
241
|
-
} from "./chunks/studio-
|
|
241
|
+
} from "./chunks/studio-ky68mp85.js";
|
|
242
242
|
import {
|
|
243
243
|
validateDoc,
|
|
244
244
|
validateProjectConfig
|
|
@@ -263,7 +263,7 @@ import {
|
|
|
263
263
|
registerGridCommands,
|
|
264
264
|
scanLibrary,
|
|
265
265
|
uploadDirForCategory
|
|
266
|
-
} from "./chunks/studio-
|
|
266
|
+
} from "./chunks/studio-0evba9z5.js";
|
|
267
267
|
import {
|
|
268
268
|
live
|
|
269
269
|
} from "./chunks/studio-c31yb4t6.js";
|
|
@@ -307,7 +307,7 @@ import {
|
|
|
307
307
|
setIncludeDrafts,
|
|
308
308
|
startFsSync,
|
|
309
309
|
writesForTurn
|
|
310
|
-
} from "./chunks/studio-
|
|
310
|
+
} from "./chunks/studio-wxthr2x1.js";
|
|
311
311
|
import"./chunks/studio-2w11grav.js";
|
|
312
312
|
import"./chunks/studio-bw5dz6km.js";
|
|
313
313
|
import {
|
|
@@ -316,18 +316,18 @@ import {
|
|
|
316
316
|
isImage,
|
|
317
317
|
setMediaChangedHandler,
|
|
318
318
|
uploadAssets
|
|
319
|
-
} from "./chunks/studio-
|
|
319
|
+
} from "./chunks/studio-102jzb8r.js";
|
|
320
320
|
import {
|
|
321
321
|
beginActivity,
|
|
322
322
|
registerActivityPanel,
|
|
323
323
|
showProgressModal
|
|
324
|
-
} from "./chunks/studio-
|
|
324
|
+
} from "./chunks/studio-eqyybj2e.js";
|
|
325
325
|
import {
|
|
326
326
|
currentDeploy,
|
|
327
327
|
latestDeployment,
|
|
328
328
|
noteDeployment,
|
|
329
329
|
platformSupportsPublish
|
|
330
|
-
} from "./chunks/studio-
|
|
330
|
+
} from "./chunks/studio-53dn6e6t.js";
|
|
331
331
|
import {
|
|
332
332
|
CATEGORIES,
|
|
333
333
|
SPAN_FULL_RENDER,
|
|
@@ -439,7 +439,7 @@ import {
|
|
|
439
439
|
timeSpan,
|
|
440
440
|
timeSpanAsync,
|
|
441
441
|
updateActivePanelHeaders
|
|
442
|
-
} from "./chunks/studio-
|
|
442
|
+
} from "./chunks/studio-yk7037sg.js";
|
|
443
443
|
import {
|
|
444
444
|
BOTTOM_TAB_IDS,
|
|
445
445
|
BUFFER_COMMIT,
|
|
@@ -606,7 +606,7 @@ import {
|
|
|
606
606
|
updateSiteConfig,
|
|
607
607
|
view,
|
|
608
608
|
workspace
|
|
609
|
-
} from "./chunks/studio-
|
|
609
|
+
} from "./chunks/studio-ddgrc5hs.js";
|
|
610
610
|
import {
|
|
611
611
|
classMap,
|
|
612
612
|
ifDefined,
|
|
@@ -669,7 +669,7 @@ import {
|
|
|
669
669
|
mountStillWanted,
|
|
670
670
|
refreshExtensionUi,
|
|
671
671
|
refreshFormats
|
|
672
|
-
} from "./chunks/studio-
|
|
672
|
+
} from "./chunks/studio-6gcrk1bq.js";
|
|
673
673
|
import {
|
|
674
674
|
getPlatform,
|
|
675
675
|
hasPlatform,
|
|
@@ -16807,7 +16807,7 @@ function entryIdsFor(collection) {
|
|
|
16807
16807
|
if (known) {
|
|
16808
16808
|
return known;
|
|
16809
16809
|
}
|
|
16810
|
-
const pending = import("./chunks/content-source-
|
|
16810
|
+
const pending = import("./chunks/content-source-jrvn5vwy.js").then((m) => m.listCollectionEntryIds(collection));
|
|
16811
16811
|
entryIdCache.set(collection, pending);
|
|
16812
16812
|
return pending;
|
|
16813
16813
|
}
|
|
@@ -17068,7 +17068,7 @@ function renderEntryMode(surface, tab) {
|
|
|
17068
17068
|
});
|
|
17069
17069
|
}
|
|
17070
17070
|
async function openEntryEditor(path) {
|
|
17071
|
-
const { openFileInTab: openFileInTab2 } = await import("./chunks/files-
|
|
17071
|
+
const { openFileInTab: openFileInTab2 } = await import("./chunks/files-jdbtammm.js");
|
|
17072
17072
|
await openFileInTab2(path);
|
|
17073
17073
|
for (const [id, tab] of workspace.tabs.entries()) {
|
|
17074
17074
|
if (tab.documentPath !== path) {
|
|
@@ -17129,7 +17129,7 @@ async function createEntry(collectionName) {
|
|
|
17129
17129
|
});
|
|
17130
17130
|
return null;
|
|
17131
17131
|
}
|
|
17132
|
-
const { createFileIn: createFileIn2 } = await import("./chunks/files-
|
|
17132
|
+
const { createFileIn: createFileIn2 } = await import("./chunks/files-jdbtammm.js");
|
|
17133
17133
|
const created = await createFileIn2({
|
|
17134
17134
|
content,
|
|
17135
17135
|
dir: collection.dir,
|
|
@@ -22349,7 +22349,7 @@ function groupProblems(records = problems) {
|
|
|
22349
22349
|
return groups;
|
|
22350
22350
|
}
|
|
22351
22351
|
function openProblemPath(path) {
|
|
22352
|
-
import("./chunks/files-
|
|
22352
|
+
import("./chunks/files-jdbtammm.js").then((m) => m.openFileInTab(path));
|
|
22353
22353
|
}
|
|
22354
22354
|
function actionTpl(record) {
|
|
22355
22355
|
const id = record.action;
|
|
@@ -27264,6 +27264,7 @@ var cache2 = null;
|
|
|
27264
27264
|
var proxyConfigured = false;
|
|
27265
27265
|
var proxyManaged = false;
|
|
27266
27266
|
var proxyDefaultModel = "";
|
|
27267
|
+
var proxyCode;
|
|
27267
27268
|
var proxyProbe = null;
|
|
27268
27269
|
var probeListeners = new Set;
|
|
27269
27270
|
function invalidateModelCache() {
|
|
@@ -27271,6 +27272,7 @@ function invalidateModelCache() {
|
|
|
27271
27272
|
proxyConfigured = false;
|
|
27272
27273
|
proxyManaged = false;
|
|
27273
27274
|
proxyDefaultModel = "";
|
|
27275
|
+
proxyCode = undefined;
|
|
27274
27276
|
proxyProbe = null;
|
|
27275
27277
|
}
|
|
27276
27278
|
function ensureProxyProbe(onSettled) {
|
|
@@ -27292,6 +27294,9 @@ function isProxyConfigured() {
|
|
|
27292
27294
|
function isManagedProxy() {
|
|
27293
27295
|
return proxyManaged;
|
|
27294
27296
|
}
|
|
27297
|
+
function proxyStateCode() {
|
|
27298
|
+
return proxyCode;
|
|
27299
|
+
}
|
|
27295
27300
|
function siblingRoute(chatUrl, segment) {
|
|
27296
27301
|
let url;
|
|
27297
27302
|
try {
|
|
@@ -27326,6 +27331,7 @@ async function fetchAvailableModels(opts = {}) {
|
|
|
27326
27331
|
proxyConfigured = data.configured === true;
|
|
27327
27332
|
proxyManaged = data.managed === true;
|
|
27328
27333
|
proxyDefaultModel = data.defaultModel ?? "";
|
|
27334
|
+
proxyCode = data.code;
|
|
27329
27335
|
cache2 = (data.models || []).map((m) => ({ id: m.id, name: m.name || m.id }));
|
|
27330
27336
|
return cache2;
|
|
27331
27337
|
}
|
|
@@ -27490,17 +27496,22 @@ function createManagedConnect(opts) {
|
|
|
27490
27496
|
if (!canOffer()) {
|
|
27491
27497
|
return nothing;
|
|
27492
27498
|
}
|
|
27499
|
+
const lapsed = proxyStateCode() === "cf_reconnect_required";
|
|
27500
|
+
const busyLabel = lapsed ? "Reconnecting…" : "Connecting…";
|
|
27493
27501
|
return html`
|
|
27494
|
-
<div class="ai-managed-connect">
|
|
27495
|
-
<div
|
|
27502
|
+
<div class="ai-managed-connect" data-jx-recommended="cloudflare">
|
|
27503
|
+
<div class="ai-managed-connect-lede">
|
|
27504
|
+
${lapsed ? "Your Cloudflare connection has expired. Reconnect to keep using the assistant." : "Recommended — run the assistant on Workers AI in your own Cloudflare account. No API key to create, copy or rotate."}
|
|
27505
|
+
</div>
|
|
27496
27506
|
<sp-button
|
|
27497
27507
|
size="s"
|
|
27508
|
+
variant="accent"
|
|
27498
27509
|
?disabled=${busy}
|
|
27499
27510
|
@click=${() => {
|
|
27500
27511
|
connect();
|
|
27501
27512
|
}}
|
|
27502
27513
|
>
|
|
27503
|
-
${busy ? "
|
|
27514
|
+
${busy ? busyLabel : lapsed ? "Reconnect Cloudflare" : "Connect Cloudflare"}
|
|
27504
27515
|
</sp-button>
|
|
27505
27516
|
${connectError ? html`<div class="ai-managed-connect-error">${connectError}</div>` : nothing}
|
|
27506
27517
|
<div class="ai-managed-connect-divider">— or bring your own key —</div>
|
|
@@ -28900,6 +28911,7 @@ function createCloudPlatform(project) {
|
|
|
28900
28911
|
id: "cloud",
|
|
28901
28912
|
projectRoot: root,
|
|
28902
28913
|
canvasUrl: "/canvas.html",
|
|
28914
|
+
...base ? { documentBaseUrl: `${base}/raw/` } : {},
|
|
28903
28915
|
openProjectPicker: "repo-list",
|
|
28904
28916
|
createDestination: "repo",
|
|
28905
28917
|
async activate() {
|
|
@@ -58579,9 +58591,9 @@ function renderDefsEditor(container) {
|
|
|
58579
58591
|
|
|
58580
58592
|
// src/version.ts
|
|
58581
58593
|
var APP_NAME = "Jx Studio";
|
|
58582
|
-
var VERSION = "2.
|
|
58583
|
-
var BUILD_DATE = "2026-08-
|
|
58584
|
-
var GIT_COMMIT = "
|
|
58594
|
+
var VERSION = "2.4.0";
|
|
58595
|
+
var BUILD_DATE = "2026-08-23T19:11:17.175Z";
|
|
58596
|
+
var GIT_COMMIT = "bea72f9";
|
|
58585
58597
|
var LINKS = {
|
|
58586
58598
|
github: "https://github.com/jxsuite/jx",
|
|
58587
58599
|
docs: "https://github.com/jxsuite/jx#readme",
|
|
@@ -59658,7 +59670,7 @@ async function openProjectSettings(section) {
|
|
|
59658
59670
|
showSettingsDocument();
|
|
59659
59671
|
notifySettingsDocument();
|
|
59660
59672
|
try {
|
|
59661
|
-
const { syncExtensionSettingsSections } = await import("./chunks/extension-sections-
|
|
59673
|
+
const { syncExtensionSettingsSections } = await import("./chunks/extension-sections-2zjyty05.js");
|
|
59662
59674
|
await syncExtensionSettingsSections();
|
|
59663
59675
|
} catch (error) {
|
|
59664
59676
|
notify.warn(`Could not load extension settings sections — ${errorMessage(error)}`, {
|
|
@@ -60282,7 +60294,7 @@ function publishCommands() {
|
|
|
60282
60294
|
name: "set_up_publishing"
|
|
60283
60295
|
},
|
|
60284
60296
|
run: async () => {
|
|
60285
|
-
const { openPublishPanel } = await import("./chunks/publish-panel-
|
|
60297
|
+
const { openPublishPanel } = await import("./chunks/publish-panel-2we6smjv.js");
|
|
60286
60298
|
openPublishPanel();
|
|
60287
60299
|
},
|
|
60288
60300
|
title: "Set Up Publishing"
|
|
@@ -61004,7 +61016,7 @@ function i18nCommands() {
|
|
|
61004
61016
|
});
|
|
61005
61017
|
return;
|
|
61006
61018
|
}
|
|
61007
|
-
const { openFileInTab: openFileInTab2 } = await import("./chunks/files-
|
|
61019
|
+
const { openFileInTab: openFileInTab2 } = await import("./chunks/files-jdbtammm.js");
|
|
61008
61020
|
await openFileInTab2(path);
|
|
61009
61021
|
},
|
|
61010
61022
|
title: "Open Translation"
|
|
@@ -61051,7 +61063,7 @@ function i18nCommands() {
|
|
|
61051
61063
|
return;
|
|
61052
61064
|
}
|
|
61053
61065
|
const cut = path.lastIndexOf("/");
|
|
61054
|
-
const { createFileIn: createFileIn2, openFileInTab: openFileInTab2 } = await import("./chunks/files-
|
|
61066
|
+
const { createFileIn: createFileIn2, openFileInTab: openFileInTab2 } = await import("./chunks/files-jdbtammm.js");
|
|
61055
61067
|
const created = await createFileIn2({
|
|
61056
61068
|
content,
|
|
61057
61069
|
dir: cut === -1 ? "." : path.slice(0, cut),
|
|
@@ -61864,5 +61876,5 @@ export {
|
|
|
61864
61876
|
hasUnsavedTabs
|
|
61865
61877
|
};
|
|
61866
61878
|
|
|
61867
|
-
//# debugId=
|
|
61879
|
+
//# debugId=5769FAD30A86F19564756E2164756E21
|
|
61868
61880
|
//# sourceMappingURL=studio.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxsuite/studio",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Jx Studio — visual builder for Jx documents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@atlaskit/pragmatic-drag-and-drop": "^3.0.0",
|
|
59
59
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^2.1.0",
|
|
60
|
-
"@jxsuite/ai": "^0.36.
|
|
60
|
+
"@jxsuite/ai": "^0.36.2",
|
|
61
61
|
"@jxsuite/collab": "^0.8.1",
|
|
62
|
-
"@jxsuite/create": "^1.3.
|
|
63
|
-
"@jxsuite/formulas": "^0.0.
|
|
62
|
+
"@jxsuite/create": "^1.3.4",
|
|
63
|
+
"@jxsuite/formulas": "^0.0.10",
|
|
64
64
|
"@jxsuite/markup": "^0.4.5",
|
|
65
|
-
"@jxsuite/protocol": "^1.
|
|
66
|
-
"@jxsuite/runtime": "^2.0.
|
|
65
|
+
"@jxsuite/protocol": "^1.2.0",
|
|
66
|
+
"@jxsuite/runtime": "^2.0.3",
|
|
67
67
|
"@jxsuite/schema": "^1.8.0",
|
|
68
68
|
"@spectrum-web-components/accordion": "^1.12.2",
|
|
69
69
|
"@spectrum-web-components/action-bar": "1.12.2",
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
getEffectiveMedia,
|
|
20
20
|
resolveLayoutDoc,
|
|
21
21
|
} from "../site-context";
|
|
22
|
-
import {
|
|
22
|
+
import { documentBase } from "./canvas-origin";
|
|
23
23
|
import { componentRegistry, computeRelativePath } from "../files/components";
|
|
24
24
|
import { prepareForEditMode } from "../utils/edit-display";
|
|
25
25
|
import {
|
|
@@ -179,10 +179,8 @@ export async function resolveCanvasDocument(
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
const root = projectState?.projectRoot || "";
|
|
183
|
-
const docPrefix = root ? `${root}/` : "";
|
|
184
182
|
const docBase = S.documentPath
|
|
185
|
-
?
|
|
183
|
+
? new URL(S.documentPath, documentBase(projectState?.projectRoot)).href
|
|
186
184
|
: undefined;
|
|
187
185
|
|
|
188
186
|
// Substitute chosen dynamic route params ({$ref: "#/$params/x"} → literal), inject state.$page,
|
|
@@ -25,6 +25,31 @@ export function canvasBaseOrigin(): string {
|
|
|
25
25
|
return location.origin;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* The base the canvas fetches PROJECT FILES against — component `$ref`s, `$src` modules, images.
|
|
30
|
+
*
|
|
31
|
+
* Two shapes, and the platform chooses. Most hosts serve the project tree from their web root, so
|
|
32
|
+
* `<canvas origin>/<projectRoot>/` is a real URL: the dev server serves by path (absolute
|
|
33
|
+
* filesystem paths included) and the desktop loopback does the same. Those set nothing.
|
|
34
|
+
*
|
|
35
|
+
* A host whose `projectRoot` is an IDENTIFIER rather than a served path sets `documentBaseUrl`. Jx
|
|
36
|
+
* Cloud is one — its root is `owner/repo@branch`, and the default produced a URL nothing answered,
|
|
37
|
+
* so every `$ref` fetch fell through to the SPA fallback. That fallback returns the marketing page
|
|
38
|
+
* at **HTTP 200**, so `res.ok` passed and the runtime's `res.json()` died on `Unexpected token
|
|
39
|
+
* '<'`; images failed the same way and reported nothing.
|
|
40
|
+
*
|
|
41
|
+
* @param {string | undefined} projectRoot - The active project root, for the default shape.
|
|
42
|
+
* @returns {string} A base URL ending in `/`, safe to pass to `new URL(relativePath, base)`.
|
|
43
|
+
*/
|
|
44
|
+
export function documentBase(projectRoot?: string): string {
|
|
45
|
+
const declared = hasPlatform() ? getPlatform().documentBaseUrl : undefined;
|
|
46
|
+
if (declared) {
|
|
47
|
+
return declared.endsWith("/") ? declared : `${declared}/`;
|
|
48
|
+
}
|
|
49
|
+
const root = projectRoot || "";
|
|
50
|
+
return `${canvasBaseOrigin()}/${root ? `${root}/` : ""}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
28
53
|
/**
|
|
29
54
|
* Build an absolute loopback-origin src for a PROJECT asset path referenced by a PARENT-realm
|
|
30
55
|
* (shell) preview <img>. On the views:// shell a relative "/images/foo.png" resolves to
|
package/src/platforms/cloud.ts
CHANGED
|
@@ -223,6 +223,15 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
223
223
|
id: "cloud",
|
|
224
224
|
projectRoot: root,
|
|
225
225
|
canvasUrl: "/canvas.html",
|
|
226
|
+
/* The projectRoot here is the IDENTIFIER "owner/repo@branch", not a served path, so the canvas's
|
|
227
|
+
default base — <origin>/<projectRoot>/ — addressed nothing. Every component $ref fetch landed
|
|
228
|
+
on the SPA fallback, which answers the marketing page at HTTP 200, so res.ok passed and the
|
|
229
|
+
runtime's res.json() died on "Unexpected token '<'". Images failed the same way, silently.
|
|
230
|
+
The session serves the project tree at /raw.
|
|
231
|
+
|
|
232
|
+
Conditional because `base` is "" until a project is bound, and "/raw/" would be a confident
|
|
233
|
+
wrong answer — worse than the default, which at least fails visibly. */
|
|
234
|
+
...(base ? { documentBaseUrl: `${base}/raw/` } : {}),
|
|
226
235
|
/* Open Project routes through Studio's repo picker (write-access repos via listRepos +
|
|
227
236
|
importProject) — sessions are URL-bound, so openProject() below never opens a dialog. */
|
|
228
237
|
openProjectPicker: "repo-list",
|
|
@@ -24,6 +24,7 @@ let cache: AiModel[] | null = null;
|
|
|
24
24
|
let proxyConfigured = false;
|
|
25
25
|
let proxyManaged = false;
|
|
26
26
|
let proxyDefaultModel = "";
|
|
27
|
+
let proxyCode: AiModelsResponse["code"];
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* One-shot capability probe shared by every credentials gate, plus the hosts to repaint when it
|
|
@@ -39,7 +40,8 @@ export function invalidateModelCache() {
|
|
|
39
40
|
proxyConfigured = false;
|
|
40
41
|
proxyManaged = false;
|
|
41
42
|
proxyDefaultModel = "";
|
|
42
|
-
|
|
43
|
+
proxyCode = undefined;
|
|
44
|
+
/* The probe's result IS the flags above. Clearing them while keeping the settled promise
|
|
43
45
|
would strand every gate on a permanent "unconfigured, unmanaged" reading — ensureProxyProbe
|
|
44
46
|
would no-op forever and the managed option would vanish until a full reload. */
|
|
45
47
|
proxyProbe = null;
|
|
@@ -91,6 +93,16 @@ export function isManagedProxy(): boolean {
|
|
|
91
93
|
return proxyManaged;
|
|
92
94
|
}
|
|
93
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Why the proxy reported itself unconfigured, when it said so.
|
|
98
|
+
*
|
|
99
|
+
* Undefined on any backend that does not send one — every gate must treat that as "no reason given"
|
|
100
|
+
* and fall back to the plain connect wording.
|
|
101
|
+
*/
|
|
102
|
+
export function proxyStateCode(): AiModelsResponse["code"] {
|
|
103
|
+
return proxyCode;
|
|
104
|
+
}
|
|
105
|
+
|
|
94
106
|
/** The proxy's preferred model id ("" when it does not declare one). */
|
|
95
107
|
export function getProxyDefaultModel(): string {
|
|
96
108
|
return proxyDefaultModel;
|
|
@@ -161,6 +173,7 @@ export async function fetchAvailableModels(
|
|
|
161
173
|
proxyConfigured = data.configured === true;
|
|
162
174
|
proxyManaged = data.managed === true;
|
|
163
175
|
proxyDefaultModel = data.defaultModel ?? "";
|
|
176
|
+
proxyCode = data.code;
|
|
164
177
|
cache = (data.models || []).map((m) => ({ id: m.id, name: m.name || m.id }));
|
|
165
178
|
return cache;
|
|
166
179
|
}
|
package/src/types.ts
CHANGED
|
@@ -181,6 +181,23 @@ export interface StudioPlatform {
|
|
|
181
181
|
* Not keyed on `id`: chromium and electrobun both report `"desktop"`, and only electrobun defers.
|
|
182
182
|
*/
|
|
183
183
|
canvasUrlDeferred?: boolean;
|
|
184
|
+
/**
|
|
185
|
+
* Base URL the canvas fetches PROJECT FILES from — component `$ref`s, `$src` modules, images.
|
|
186
|
+
*
|
|
187
|
+
* The renderer resolves a `$ref` with `fetch(url).then(r => r.json())` from inside the iframe, so
|
|
188
|
+
* project files have to exist at a URL, not merely behind {@link readFile}. Hosts that serve the
|
|
189
|
+
* project tree from their web root need no value here: the default is `<canvas
|
|
190
|
+
* origin>/<projectRoot>/`, which is what the dev server and the desktop loopback both already
|
|
191
|
+
* answer.
|
|
192
|
+
*
|
|
193
|
+
* A host whose project files are NOT at a URL-shaped `projectRoot` must set this. Jx Cloud is
|
|
194
|
+
* one: its `projectRoot` is the identifier `owner/repo@branch`, nothing served the tree, and
|
|
195
|
+
* every `$ref` fetch landed on the SPA fallback — which answers HTML at **200**, so `res.ok`
|
|
196
|
+
* passed and the parse died on `Unexpected token '<'`. Images failed the same way in silence.
|
|
197
|
+
*
|
|
198
|
+
* Must end in `/`; a project-relative path is appended to it verbatim.
|
|
199
|
+
*/
|
|
200
|
+
documentBaseUrl?: string;
|
|
184
201
|
activate: (root?: string) => Promise<void>;
|
|
185
202
|
openProject: () => Promise<{
|
|
186
203
|
config: ProjectConfig;
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
fetchAvailableModels,
|
|
25
25
|
isManagedProxy,
|
|
26
26
|
isProxyConfigured,
|
|
27
|
+
proxyStateCode,
|
|
27
28
|
} from "../services/ai-models";
|
|
28
29
|
|
|
29
30
|
export interface ManagedConnectOptions {
|
|
@@ -91,17 +92,31 @@ export function createManagedConnect(opts: ManagedConnectOptions): ManagedConnec
|
|
|
91
92
|
if (!canOffer()) {
|
|
92
93
|
return nothing;
|
|
93
94
|
}
|
|
95
|
+
/*
|
|
96
|
+
* A lapsed grant and a fresh one get different words. The backend distinguishes them because
|
|
97
|
+
* "connect" is an invitation and "reconnect" is an explanation — and on a managed platform the
|
|
98
|
+
* lapsed case is the common one: a Cloudflare access token lives an hour.
|
|
99
|
+
*/
|
|
100
|
+
const lapsed = proxyStateCode() === "cf_reconnect_required";
|
|
101
|
+
const busyLabel = lapsed ? "Reconnecting…" : "Connecting…";
|
|
94
102
|
return html`
|
|
95
|
-
<div class="ai-managed-connect">
|
|
96
|
-
<div
|
|
103
|
+
<div class="ai-managed-connect" data-jx-recommended="cloudflare">
|
|
104
|
+
<div class="ai-managed-connect-lede">
|
|
105
|
+
${
|
|
106
|
+
lapsed
|
|
107
|
+
? "Your Cloudflare connection has expired. Reconnect to keep using the assistant."
|
|
108
|
+
: "Recommended — run the assistant on Workers AI in your own Cloudflare account. No API key to create, copy or rotate."
|
|
109
|
+
}
|
|
110
|
+
</div>
|
|
97
111
|
<sp-button
|
|
98
112
|
size="s"
|
|
113
|
+
variant="accent"
|
|
99
114
|
?disabled=${busy}
|
|
100
115
|
@click=${() => {
|
|
101
116
|
void connect();
|
|
102
117
|
}}
|
|
103
118
|
>
|
|
104
|
-
${busy ? "
|
|
119
|
+
${busy ? busyLabel : lapsed ? "Reconnect Cloudflare" : "Connect Cloudflare"}
|
|
105
120
|
</sp-button>
|
|
106
121
|
${connectError ? html`<div class="ai-managed-connect-error">${connectError}</div>` : nothing}
|
|
107
122
|
<div class="ai-managed-connect-divider">— or bring your own key —</div>
|
package/styles/shell.css
CHANGED
|
@@ -753,6 +753,13 @@
|
|
|
753
753
|
gap: 10px;
|
|
754
754
|
width: 100%;
|
|
755
755
|
}
|
|
756
|
+
/* The lede reads as the recommendation, so it carries weight the divider beneath it does not. */
|
|
757
|
+
.ai-managed-connect-lede {
|
|
758
|
+
color: var(--fg);
|
|
759
|
+
font-size: var(--spectrum-font-size-75, 12px);
|
|
760
|
+
max-width: 280px;
|
|
761
|
+
text-align: center;
|
|
762
|
+
}
|
|
756
763
|
.ai-managed-connect-error {
|
|
757
764
|
color: var(--danger);
|
|
758
765
|
font-size: var(--spectrum-font-size-50, 11px);
|