dsh-image-gen 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +454 -454
- package/README.md +454 -454
- package/lib/client.js +53 -64
- package/lib/index.js +81 -28
- package/lib/types/client/studio-view.d.ts +1 -0
- package/lib/types/client/tl/tl-trace-bridge.d.ts +55 -0
- package/lib/types/client/tl/trace-playback.d.ts +101 -0
- package/lib/types/image-tool-context.d.ts +1 -1
- package/lib/types/subscription/subscription-route.d.ts +2 -1
- package/lib/types/trace-drawing.d.ts +102 -0
- package/lib/types/trace-route.d.ts +12 -0
- package/lib/types/trace-sketch.d.ts +26 -0
- package/lib/types/trace-store.d.ts +23 -0
- package/lib/types/vendor/drawai/raster.d.ts +43 -0
- package/lib/types/vendor/drawai/trace-image.d.ts +257 -0
- package/lib/types/web-route.d.ts +4 -0
- package/package.json +139 -139
- package/skills/install-dsh-image-gen/SKILL.md +22 -22
package/lib/client.js
CHANGED
|
@@ -122983,7 +122983,6 @@ img.ProseMirror-separator {
|
|
|
122983
122983
|
};
|
|
122984
122984
|
}, []);
|
|
122985
122985
|
const [previewLoading, setPreviewLoading] = (0, react.useState)(false);
|
|
122986
|
-
const blobCache = (0, react.useMemo)(() => /* @__PURE__ */ new Map(), []);
|
|
122987
122986
|
const abortControllerRef = (0, react.useRef)(null);
|
|
122988
122987
|
const filteredItems = (0, react.useMemo)(() => {
|
|
122989
122988
|
return items.filter((item) => {
|
|
@@ -123039,7 +123038,6 @@ img.ProseMirror-separator {
|
|
|
123039
123038
|
}
|
|
123040
123039
|
setPreviewItem(item);
|
|
123041
123040
|
if (blob) {
|
|
123042
|
-
blobCache.set(item.id, blob);
|
|
123043
123041
|
const url = URL.createObjectURL(blob);
|
|
123044
123042
|
previewUrlRef.current = url;
|
|
123045
123043
|
setPreviewBlob(blob);
|
|
@@ -123047,15 +123045,6 @@ img.ProseMirror-separator {
|
|
|
123047
123045
|
setPreviewLoading(false);
|
|
123048
123046
|
return;
|
|
123049
123047
|
}
|
|
123050
|
-
const cached = blobCache.get(item.id);
|
|
123051
|
-
if (cached) {
|
|
123052
|
-
const url = URL.createObjectURL(cached);
|
|
123053
|
-
previewUrlRef.current = url;
|
|
123054
|
-
setPreviewBlob(cached);
|
|
123055
|
-
setPreviewUrl(url);
|
|
123056
|
-
setPreviewLoading(false);
|
|
123057
|
-
return;
|
|
123058
|
-
}
|
|
123059
123048
|
setPreviewLoading(true);
|
|
123060
123049
|
setPreviewBlob(null);
|
|
123061
123050
|
setPreviewUrl(null);
|
|
@@ -123063,7 +123052,6 @@ img.ProseMirror-separator {
|
|
|
123063
123052
|
abortControllerRef.current = controller;
|
|
123064
123053
|
fetchAttachmentBlob(item.attachment).then((fetchedBlob) => {
|
|
123065
123054
|
if (controller.signal.aborted) return;
|
|
123066
|
-
blobCache.set(item.id, fetchedBlob);
|
|
123067
123055
|
const url = URL.createObjectURL(fetchedBlob);
|
|
123068
123056
|
previewUrlRef.current = url;
|
|
123069
123057
|
setPreviewBlob(fetchedBlob);
|
|
@@ -123327,11 +123315,7 @@ img.ProseMirror-separator {
|
|
|
123327
123315
|
if (itemsToDownload.length === 1) {
|
|
123328
123316
|
const single = itemsToDownload[0];
|
|
123329
123317
|
if (!single) return;
|
|
123330
|
-
|
|
123331
|
-
if (!blob) {
|
|
123332
|
-
blob = await fetchAttachmentBlob(single.attachment);
|
|
123333
|
-
blobCache.set(single.id, blob);
|
|
123334
|
-
}
|
|
123318
|
+
const blob = await fetchAttachmentBlob(single.attachment);
|
|
123335
123319
|
const objectUrl = URL.createObjectURL(blob);
|
|
123336
123320
|
downloadBlobUrl(objectUrl, `dsh-${single.provider}-${single.id}.png`);
|
|
123337
123321
|
URL.revokeObjectURL(objectUrl);
|
|
@@ -123344,11 +123328,7 @@ img.ProseMirror-separator {
|
|
|
123344
123328
|
const it = itemsToDownload[i];
|
|
123345
123329
|
if (!it) continue;
|
|
123346
123330
|
setBatchDownloadProgress(`${i + 1}/${itemsToDownload.length}`);
|
|
123347
|
-
|
|
123348
|
-
if (!blob) {
|
|
123349
|
-
blob = await fetchAttachmentBlob(it.attachment);
|
|
123350
|
-
blobCache.set(it.id, blob);
|
|
123351
|
-
}
|
|
123331
|
+
const blob = await fetchAttachmentBlob(it.attachment);
|
|
123352
123332
|
const arrayBuffer = await blob.arrayBuffer();
|
|
123353
123333
|
const ext = blob.type === "image/jpeg" ? "jpg" : blob.type === "image/webp" ? "webp" : "png";
|
|
123354
123334
|
let baseName = `dsh-${it.provider}-${it.id.slice(0, 8)}.${ext}`;
|
|
@@ -123752,7 +123732,6 @@ img.ProseMirror-separator {
|
|
|
123752
123732
|
onToggleSelect: (e) => handleToggleSelect(item.id, idx, e),
|
|
123753
123733
|
onRequestDelete: () => requestSingleDelete(item),
|
|
123754
123734
|
onPreview: (blob) => openPreviewItem(item, blob),
|
|
123755
|
-
onBlobLoaded: (b) => blobCache.set(item.id, b),
|
|
123756
123735
|
onToast: showToast
|
|
123757
123736
|
}, item.id))
|
|
123758
123737
|
}) : activeTab === "inspiration" ? (0, react_jsx_runtime.jsx)(InspirationView, {
|
|
@@ -124127,39 +124106,37 @@ img.ProseMirror-separator {
|
|
|
124127
124106
|
]
|
|
124128
124107
|
});
|
|
124129
124108
|
};
|
|
124130
|
-
const GalleryCard = ({ lang, item, index: _index, isManageMode, isSelected, t, onClick, onToggleSelect, onRequestDelete, onPreview: _onPreview,
|
|
124109
|
+
const GalleryCard = ({ lang, item, index: _index, isManageMode, isSelected, t, onClick, onToggleSelect, onRequestDelete, onPreview: _onPreview, onToast }) => {
|
|
124110
|
+
const [setCardRef, inView] = useInView();
|
|
124131
124111
|
const [url, setUrl] = (0, react.useState)();
|
|
124132
124112
|
const [blob, setBlob] = (0, react.useState)();
|
|
124133
124113
|
const [loading, setLoading] = (0, react.useState)(true);
|
|
124134
124114
|
const [error, setError] = (0, react.useState)();
|
|
124135
124115
|
(0, react.useEffect)(() => {
|
|
124136
|
-
|
|
124116
|
+
if (!inView) return;
|
|
124117
|
+
let active = true;
|
|
124137
124118
|
let objectUrl;
|
|
124138
|
-
|
|
124139
|
-
|
|
124140
|
-
|
|
124141
|
-
|
|
124142
|
-
|
|
124143
|
-
|
|
124144
|
-
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
124145
|
-
const resBlob = await response.blob();
|
|
124146
|
-
if (controller.signal.aborted) return;
|
|
124119
|
+
setUrl(void 0);
|
|
124120
|
+
setBlob(void 0);
|
|
124121
|
+
setError(void 0);
|
|
124122
|
+
setLoading(true);
|
|
124123
|
+
fetchAttachmentBlob(item.attachment).then((resBlob) => {
|
|
124124
|
+
if (!active) return;
|
|
124147
124125
|
setBlob(resBlob);
|
|
124148
|
-
onBlobLoaded?.(resBlob);
|
|
124149
124126
|
objectUrl = URL.createObjectURL(resBlob);
|
|
124150
124127
|
setUrl(objectUrl);
|
|
124151
124128
|
setLoading(false);
|
|
124152
124129
|
}).catch((err) => {
|
|
124153
|
-
if (
|
|
124130
|
+
if (active) {
|
|
124154
124131
|
setError(err instanceof Error ? err.message : String(err));
|
|
124155
124132
|
setLoading(false);
|
|
124156
124133
|
}
|
|
124157
124134
|
});
|
|
124158
124135
|
return () => {
|
|
124159
|
-
|
|
124136
|
+
active = false;
|
|
124160
124137
|
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
124161
124138
|
};
|
|
124162
|
-
}, [item.attachment]);
|
|
124139
|
+
}, [item.attachment.attachmentId, inView]);
|
|
124163
124140
|
const copyPrompt = async (e) => {
|
|
124164
124141
|
e.stopPropagation();
|
|
124165
124142
|
try {
|
|
@@ -124190,6 +124167,7 @@ img.ProseMirror-separator {
|
|
|
124190
124167
|
};
|
|
124191
124168
|
const badgeLabel = item.model || item.provider;
|
|
124192
124169
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
124170
|
+
ref: setCardRef,
|
|
124193
124171
|
className: `dsh-ig-gallery-card ${isSelected ? "is-selected" : ""} ${isManageMode ? "is-manage-mode" : ""}`,
|
|
124194
124172
|
onClick: (e) => onClick(e, blob),
|
|
124195
124173
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -125642,7 +125620,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125642
125620
|
`;
|
|
125643
125621
|
//#endregion
|
|
125644
125622
|
//#region lib/types/client/index.js
|
|
125645
|
-
console.info(`[dsh-image-gen] canvas bundle 2026-
|
|
125623
|
+
console.info(`[dsh-image-gen] canvas bundle 2026-11-02T02:55:48.656Z`);
|
|
125646
125624
|
/** Right-sidebar tab-type registration id (DSH 0.1.5 `sidebarRightTabs`). */
|
|
125647
125625
|
const SIDEBAR_STUDIO_TAB_ID = "dsh-image-gen/studio";
|
|
125648
125626
|
/** The tab kind: a page type opened by kind, recognizing no resource address. */
|
|
@@ -126062,23 +126040,26 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126062
126040
|
.dsh-ig-save:disabled{opacity:.4;cursor:default}
|
|
126063
126041
|
|
|
126064
126042
|
/* Provider list: one expandable row per provider, each saving independently. */
|
|
126065
|
-
.dsh-ig-providers{display:flex;flex-direction:column;margin-top:
|
|
126066
|
-
.dsh-ig-provider-row{border:0;background:none;padding:14px
|
|
126067
|
-
.dsh-ig-provider-row + .dsh-ig-provider-row{border-top:
|
|
126068
|
-
.dsh-ig-provider-head-row{display:flex;align-items:center;gap:
|
|
126069
|
-
.dsh-ig-provider-head{flex:1;min-width:0;width:100%;appearance:none;border:0;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer;display:flex;align-items:center;gap:10px;padding:0}
|
|
126070
|
-
.dsh-ig-channel-add{flex:none;width:
|
|
126043
|
+
.dsh-ig-providers{display:flex;flex-direction:column;margin-top:12px;overflow:hidden;border:1px solid var(--dsw-alias-border-l2,#e8ebf0);border-radius:10px;background:var(--dsw-alias-bg-layer-3,transparent)}
|
|
126044
|
+
.dsh-ig-provider-row{border:0;background:none;padding:0 14px}
|
|
126045
|
+
.dsh-ig-provider-row + .dsh-ig-provider-row{border-top:1px solid var(--dsw-alias-border-l2,#e8ebf0)}
|
|
126046
|
+
.dsh-ig-provider-head-row{display:flex;align-items:center;gap:8px;min-height:48px}
|
|
126047
|
+
.dsh-ig-provider-head{flex:1;min-width:0;width:100%;min-height:48px;appearance:none;border:0;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer;display:flex;align-items:center;gap:10px;padding:0}
|
|
126048
|
+
.dsh-ig-channel-add.dsh-ig-btn-secondary{display:inline-flex;align-items:center;justify-content:center;flex:none;box-sizing:border-box;width:26px;height:26px;padding:0;border:0;border-radius:7px;background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-tertiary,#7b818b);line-height:1;transition:background .15s,color .15s}
|
|
126049
|
+
.dsh-ig-channel-add.dsh-ig-btn-secondary:hover:not(:disabled){border:0;background:var(--dsw-alias-bg-layer-1,#e5e7eb);color:var(--dsw-alias-label-primary,inherit)}
|
|
126050
|
+
.dsh-ig-channel-add svg{width:14px;height:14px}
|
|
126071
126051
|
.dsh-ig-provider-head:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4c78ff);outline-offset:2px;border-radius:var(--dsw-radius-sm,4px)}
|
|
126072
|
-
.dsh-ig-provider-head:hover .dsh-ig-provider-name{color:var(--dsw-alias-label-
|
|
126073
|
-
.dsh-ig-provider-
|
|
126074
|
-
.dsh-ig-provider-
|
|
126052
|
+
.dsh-ig-provider-head:hover .dsh-ig-provider-name{color:var(--dsw-alias-label-primary,inherit)}
|
|
126053
|
+
.dsh-ig-provider-head:hover .dsh-ig-provider-chevron{color:var(--dsw-alias-label-primary,inherit)}
|
|
126054
|
+
.dsh-ig-provider-name{flex:1;min-width:0;font-size:13px;font-weight:550;line-height:20px;color:var(--dsw-alias-label-primary,inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
126055
|
+
.dsh-ig-provider-chevron{display:inline-flex;align-items:center;justify-content:center;flex:none;width:20px;height:20px;color:var(--dsw-alias-label-tertiary,#7b818b);transition:transform .16s,color .15s}
|
|
126075
126056
|
.dsh-ig-provider-chevron-open{transform:rotate(180deg)}
|
|
126076
|
-
.dsh-ig-provider-body{border-top:0;padding:
|
|
126077
|
-
.dsh-ig-badge{flex:none;display:inline-flex;align-items:center;gap:5px;
|
|
126078
|
-
.dsh-ig-badge-dot{width:
|
|
126079
|
-
.dsh-ig-badge-ok{border-color:rgba(34,197,94,.
|
|
126080
|
-
.dsh-ig-badge-missing{border-color:rgba(239,68,68,.
|
|
126081
|
-
.dsh-ig-badge-neutral{color:var(--dsw-alias-label-tertiary,#7b818b)}
|
|
126057
|
+
.dsh-ig-provider-body{border-top:0;padding:0 0 14px}
|
|
126058
|
+
.dsh-ig-badge{flex:none;display:inline-flex;align-items:center;gap:5px;box-sizing:border-box;min-height:22px;padding:1px 8px;border:1px solid transparent;border-radius:6px;font-size:11px;font-weight:500;line-height:18px;color:var(--dsw-alias-label-secondary,inherit);white-space:nowrap;max-width:60%;overflow:hidden;text-overflow:ellipsis}
|
|
126059
|
+
.dsh-ig-badge-dot{width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
|
|
126060
|
+
.dsh-ig-badge-ok{border-color:rgba(34,197,94,.2);color:#15803d;background:rgba(34,197,94,.08)}
|
|
126061
|
+
.dsh-ig-badge-missing{border-color:rgba(239,68,68,.18);color:#b91c1c;background:rgba(239,68,68,.06)}
|
|
126062
|
+
.dsh-ig-badge-neutral{border-color:var(--dsw-alias-border-l2,#e8ebf0);color:var(--dsw-alias-label-tertiary,#7b818b);background:var(--dsw-alias-bg-layer-2,transparent)}
|
|
126082
126063
|
.dsh-ig-badge-checking .dsh-ig-badge-dot{animation:dsh-ig-pulse 1s ease-in-out infinite}
|
|
126083
126064
|
@keyframes dsh-ig-pulse{50%{opacity:.25}}
|
|
126084
126065
|
|
|
@@ -128414,15 +128395,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
128414
128395
|
className: "dsh-ig-provider-row",
|
|
128415
128396
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
128416
128397
|
className: "dsh-ig-provider-head-row",
|
|
128417
|
-
children: [
|
|
128418
|
-
type: "button",
|
|
128419
|
-
className: "dsh-ig-btn-secondary dsh-ig-channel-add",
|
|
128420
|
-
title: t("addCompatChannel"),
|
|
128421
|
-
"aria-label": t("addCompatChannel"),
|
|
128422
|
-
onClick: addCompatChannel,
|
|
128423
|
-
disabled: !settingsWritable,
|
|
128424
|
-
children: "+"
|
|
128425
|
-
}) : null, (0, react_jsx_runtime.jsxs)("button", {
|
|
128398
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
128426
128399
|
type: "button",
|
|
128427
128400
|
className: "dsh-ig-provider-head",
|
|
128428
128401
|
"aria-expanded": row.expanded,
|
|
@@ -128458,7 +128431,23 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
128458
128431
|
})
|
|
128459
128432
|
})
|
|
128460
128433
|
]
|
|
128461
|
-
})
|
|
128434
|
+
}), provider === "openai-compat" ? (0, react_jsx_runtime.jsx)("button", {
|
|
128435
|
+
type: "button",
|
|
128436
|
+
className: "dsh-ig-btn-secondary dsh-ig-channel-add",
|
|
128437
|
+
title: t("addCompatChannel"),
|
|
128438
|
+
"aria-label": t("addCompatChannel"),
|
|
128439
|
+
onClick: addCompatChannel,
|
|
128440
|
+
disabled: !settingsWritable,
|
|
128441
|
+
children: (0, react_jsx_runtime.jsx)("svg", {
|
|
128442
|
+
viewBox: "0 0 16 16",
|
|
128443
|
+
fill: "none",
|
|
128444
|
+
stroke: "currentColor",
|
|
128445
|
+
strokeWidth: "1.6",
|
|
128446
|
+
strokeLinecap: "round",
|
|
128447
|
+
"aria-hidden": "true",
|
|
128448
|
+
children: (0, react_jsx_runtime.jsx)("path", { d: "M8 3v10M3 8h10" })
|
|
128449
|
+
})
|
|
128450
|
+
}) : null]
|
|
128462
128451
|
}), row.expanded ? provider === "comfyui" ? renderComfyUIBody() : isSubscriptionProvider(provider) ? renderSubscriptionBody(provider) : renderCloudBody(provider) : null]
|
|
128463
128452
|
}, provider);
|
|
128464
128453
|
};
|
package/lib/index.js
CHANGED
|
@@ -8614,12 +8614,13 @@ async function downloadImage$1(url, provider, input) {
|
|
|
8614
8614
|
mediaType: detectImageMediaType(data) ?? imageMediaType$2(parsed.mediaType) ?? "image/png"
|
|
8615
8615
|
};
|
|
8616
8616
|
}
|
|
8617
|
+
const sameOrigin = new URL(url).origin === new URL(input.baseURL).origin;
|
|
8617
8618
|
let response = await guardedFetch(`${provider} image download`, input.signal, () => fetch(url, {
|
|
8618
8619
|
redirect: "follow",
|
|
8619
8620
|
signal: input.signal,
|
|
8620
|
-
...input.apiKey === void 0 ? {} : { headers: { authorization: `Bearer ${input.apiKey}` } }
|
|
8621
|
+
...input.apiKey === void 0 || !sameOrigin ? {} : { headers: { authorization: `Bearer ${input.apiKey}` } }
|
|
8621
8622
|
}), input.apiKey);
|
|
8622
|
-
if (!response.ok && input.apiKey !== void 0) response = await guardedFetch(`${provider} image download`, input.signal, () => fetch(url, {
|
|
8623
|
+
if (!response.ok && input.apiKey !== void 0 && sameOrigin) response = await guardedFetch(`${provider} image download`, input.signal, () => fetch(url, {
|
|
8623
8624
|
redirect: "follow",
|
|
8624
8625
|
signal: input.signal
|
|
8625
8626
|
}), input.apiKey);
|
|
@@ -8875,6 +8876,7 @@ function emailFromToken(token) {
|
|
|
8875
8876
|
async function formTokenRequest(url, params, fetchImpl) {
|
|
8876
8877
|
const response = await fetchImpl(url, {
|
|
8877
8878
|
method: "POST",
|
|
8879
|
+
redirect: "error",
|
|
8878
8880
|
headers: {
|
|
8879
8881
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
8880
8882
|
Accept: "application/json"
|
|
@@ -8883,8 +8885,15 @@ async function formTokenRequest(url, params, fetchImpl) {
|
|
|
8883
8885
|
signal: AbortSignal.timeout(25e3)
|
|
8884
8886
|
});
|
|
8885
8887
|
if (!response.ok) {
|
|
8886
|
-
const
|
|
8887
|
-
|
|
8888
|
+
const detail = redactSecrets(await response.text().catch(() => ""), ...Object.entries(params).flatMap(([key, value]) => [
|
|
8889
|
+
"access_token",
|
|
8890
|
+
"refresh_token",
|
|
8891
|
+
"id_token",
|
|
8892
|
+
"code",
|
|
8893
|
+
"code_verifier",
|
|
8894
|
+
"client_secret"
|
|
8895
|
+
].includes(key) ? [value] : [])).slice(0, 200);
|
|
8896
|
+
throw new Error(`token endpoint HTTP ${String(response.status)}${detail.length > 0 ? `: ${detail}` : ""}`);
|
|
8888
8897
|
}
|
|
8889
8898
|
try {
|
|
8890
8899
|
const parsed = await response.json();
|
|
@@ -9928,7 +9937,8 @@ var SubscriptionManager = class {
|
|
|
9928
9937
|
const payload = await response.json().catch(() => ({}));
|
|
9929
9938
|
if (!response.ok) {
|
|
9930
9939
|
const detail = extractErrorMessage(payload);
|
|
9931
|
-
|
|
9940
|
+
const safeDetail = detail === void 0 ? void 0 : redactSecrets(detail, session.accessToken, session.refreshToken, session.accountId, session.email).slice(0, 200);
|
|
9941
|
+
throw new Error(`${vendor} HTTP ${String(response.status)}${safeDetail !== void 0 ? `: ${safeDetail}` : ""}`);
|
|
9932
9942
|
}
|
|
9933
9943
|
return parseImages(payload);
|
|
9934
9944
|
}
|
|
@@ -10244,6 +10254,19 @@ const SUBSCRIPTION_CAPABILITIES = {
|
|
|
10244
10254
|
}], "auto", "standard")
|
|
10245
10255
|
};
|
|
10246
10256
|
//#endregion
|
|
10257
|
+
//#region lib/types/web-route.js
|
|
10258
|
+
function withWebAdmission(route, admission) {
|
|
10259
|
+
return {
|
|
10260
|
+
...route,
|
|
10261
|
+
handler: (req, res) => {
|
|
10262
|
+
const rejection = admission()?.(req);
|
|
10263
|
+
if (rejection === void 0) return route.handler(req, res);
|
|
10264
|
+
res.writeHead(rejection, { "content-type": "application/json; charset=utf-8" });
|
|
10265
|
+
res.end(JSON.stringify({ error: rejection === 401 ? "unauthorized" : "forbidden" }));
|
|
10266
|
+
}
|
|
10267
|
+
};
|
|
10268
|
+
}
|
|
10269
|
+
//#endregion
|
|
10247
10270
|
//#region lib/types/subscription/subscription-route.js
|
|
10248
10271
|
const MAX_BODY_BYTES$1 = 16384;
|
|
10249
10272
|
/** The vendor each subscription provider logs in as. */
|
|
@@ -10253,21 +10276,21 @@ function vendorOfProvider(provider) {
|
|
|
10253
10276
|
return "grok";
|
|
10254
10277
|
}
|
|
10255
10278
|
/** Register the login/status routes on the plugin's web server. */
|
|
10256
|
-
function registerSubscriptionRoutes(ctx, manager) {
|
|
10257
|
-
ctx.effect(() => ctx.webServer.register({
|
|
10279
|
+
function registerSubscriptionRoutes(ctx, manager, admission = () => void 0) {
|
|
10280
|
+
ctx.effect(() => ctx.webServer.register(withWebAdmission({
|
|
10258
10281
|
kind: "exact",
|
|
10259
10282
|
path: SUBSCRIPTION_LOGIN_ROUTE,
|
|
10260
10283
|
handler: (req, res) => {
|
|
10261
10284
|
serveLogin(req, res, manager);
|
|
10262
10285
|
}
|
|
10263
|
-
}), "dsh-image-gen: subscription login route");
|
|
10264
|
-
ctx.effect(() => ctx.webServer.register({
|
|
10286
|
+
}, admission)), "dsh-image-gen: subscription login route");
|
|
10287
|
+
ctx.effect(() => ctx.webServer.register(withWebAdmission({
|
|
10265
10288
|
kind: "exact",
|
|
10266
10289
|
path: SUBSCRIPTION_STATUS_ROUTE,
|
|
10267
10290
|
handler: (req, res) => {
|
|
10268
10291
|
serveStatus(req, res, manager);
|
|
10269
10292
|
}
|
|
10270
|
-
}), "dsh-image-gen: subscription status route");
|
|
10293
|
+
}, admission)), "dsh-image-gen: subscription status route");
|
|
10271
10294
|
}
|
|
10272
10295
|
async function serveLogin(req, res, manager) {
|
|
10273
10296
|
if (!sameOrigin$3(req)) return jsonError$3(res, 403, "origin-rejected");
|
|
@@ -28787,7 +28810,7 @@ async function fetchClassifiedJson(url, headers, apiKey, signal) {
|
|
|
28787
28810
|
method: "GET",
|
|
28788
28811
|
headers,
|
|
28789
28812
|
signal: signal ?? AbortSignal.timeout(PROBE_TIMEOUT_MS),
|
|
28790
|
-
redirect: "
|
|
28813
|
+
redirect: "error"
|
|
28791
28814
|
}).catch((error) => {
|
|
28792
28815
|
throw new Error(error instanceof Error ? error.message : String(error));
|
|
28793
28816
|
});
|
|
@@ -29021,8 +29044,10 @@ function serveSettingsHealth(req, res, health) {
|
|
|
29021
29044
|
//#endregion
|
|
29022
29045
|
//#region lib/types/image-tool-context.js
|
|
29023
29046
|
/** Live, credential-free instructions for the conversation model's image tools. */
|
|
29024
|
-
function imageToolContext(config) {
|
|
29047
|
+
function imageToolContext(config, configuredProviders) {
|
|
29025
29048
|
const provider = config.provider ?? "google";
|
|
29049
|
+
const configured = configuredProviders === void 0 ? void 0 : [...configuredProviders];
|
|
29050
|
+
if (configured !== void 0 && !configured.includes("comfyui") && resolveComfyUIWorkflows(config).length > 0) configured.push("comfyui");
|
|
29026
29051
|
let model = "not configured";
|
|
29027
29052
|
let editModel = model;
|
|
29028
29053
|
try {
|
|
@@ -29033,6 +29058,7 @@ function imageToolContext(config) {
|
|
|
29033
29058
|
} catch {}
|
|
29034
29059
|
return [
|
|
29035
29060
|
`Image tools current default provider: ${provider}; generation model: ${JSON.stringify(model)}; editing model: ${JSON.stringify(editModel)}.`,
|
|
29061
|
+
...configured === void 0 ? [] : [`Configured image providers (credential saved, subscription logged in, or ComfyUI workflow present): ${configured.length > 0 ? configured.join(", ") : "none"}. Do not select unlisted providers; configuration presence does not guarantee service reachability.`],
|
|
29036
29062
|
"Unless the user explicitly requests a different image provider or model, OMIT provider and model from generate_image, generate_images and edit_image. Do not guess a channel or switch channels after an error.",
|
|
29037
29063
|
"Omit unused optional arguments entirely; never fill them with empty strings. size and aspect_ratio are alternatives: provide at most one.",
|
|
29038
29064
|
"Subscription parameters: chatgpt-sub accepts size OR aspect_ratio, but NOT image_size. grok-sub image_size: 1K or 2K. google-sub image_size: 1K or 4K. Do not copy parameters from another provider.",
|
|
@@ -29088,25 +29114,42 @@ function apply(ctx, config = {}) {
|
|
|
29088
29114
|
const knownWorkspaceRoots = /* @__PURE__ */ new Set();
|
|
29089
29115
|
const canvasMirror = new CanvasMirror();
|
|
29090
29116
|
const subscriptionManager = new SubscriptionManager(ctx);
|
|
29117
|
+
let configuredImageProviders;
|
|
29118
|
+
let imageContextRevision = 0;
|
|
29119
|
+
const refreshImageToolContext = async () => {
|
|
29120
|
+
const revision = ++imageContextRevision;
|
|
29121
|
+
const config = current();
|
|
29122
|
+
try {
|
|
29123
|
+
const providers = (await describeStudio(ctx, config, subscriptionManager)).providers.filter((profile) => profile.configured).map((profile) => profile.provider === "openai-compat" && profile.channel !== void 0 ? `${profile.provider} (channel: ${profile.channel})` : profile.provider);
|
|
29124
|
+
if (revision === imageContextRevision) configuredImageProviders = providers;
|
|
29125
|
+
} catch {}
|
|
29126
|
+
};
|
|
29091
29127
|
const settingsHealth = installImageSettings(ctx, current(), {
|
|
29092
29128
|
setSource: (source) => {
|
|
29093
29129
|
current = () => migrateOpenAICompatConfig(plainConfig(source()));
|
|
29094
29130
|
},
|
|
29095
|
-
onChange: () => {
|
|
29131
|
+
onChange: () => {
|
|
29132
|
+
refreshImageToolContext();
|
|
29133
|
+
}
|
|
29134
|
+
});
|
|
29135
|
+
let webAdmission;
|
|
29136
|
+
ctx.inject(["connection"], (connectionCtx) => {
|
|
29137
|
+
webAdmission = (request) => connectionCtx.connection.requestRejection(request);
|
|
29096
29138
|
});
|
|
29097
29139
|
ctx.inject(["webServer"], (webCtx) => {
|
|
29098
|
-
|
|
29099
|
-
webCtx
|
|
29140
|
+
const register = (route) => webCtx.webServer.register(withWebAdmission(route, () => webAdmission));
|
|
29141
|
+
registerSubscriptionRoutes(webCtx, subscriptionManager, () => webAdmission);
|
|
29142
|
+
webCtx.effect(() => register({
|
|
29100
29143
|
kind: "exact",
|
|
29101
29144
|
path: SETTINGS_HEALTH_ROUTE,
|
|
29102
29145
|
handler: (req, res) => serveSettingsHealth(req, res, settingsHealth())
|
|
29103
29146
|
}), "dsh-image-gen: settings health");
|
|
29104
|
-
webCtx.effect(() =>
|
|
29147
|
+
webCtx.effect(() => register({
|
|
29105
29148
|
kind: "exact",
|
|
29106
29149
|
path: IMAGE_ROUTE,
|
|
29107
29150
|
handler: (req, res) => serveImage(req, res, { readImage: (ref) => ctx.attachments.readImage(ref) })
|
|
29108
29151
|
}), "dsh-image-gen: image route");
|
|
29109
|
-
webCtx.effect(() =>
|
|
29152
|
+
webCtx.effect(() => register({
|
|
29110
29153
|
kind: "exact",
|
|
29111
29154
|
path: IMPORT_ROUTE,
|
|
29112
29155
|
handler: (req, res) => serveImport(req, res, {
|
|
@@ -29115,7 +29158,7 @@ function apply(ctx, config = {}) {
|
|
|
29115
29158
|
mediaTypes: ctx.attachments.imageLimits.mediaTypes
|
|
29116
29159
|
})
|
|
29117
29160
|
}), "dsh-image-gen: import route");
|
|
29118
|
-
webCtx.effect(() =>
|
|
29161
|
+
webCtx.effect(() => register({
|
|
29119
29162
|
kind: "exact",
|
|
29120
29163
|
path: DELETE_ROUTE,
|
|
29121
29164
|
handler: (req, res) => serveDelete(req, res, { deleteWorkspaceImage: async (filePath) => {
|
|
@@ -29127,7 +29170,7 @@ function apply(ctx, config = {}) {
|
|
|
29127
29170
|
]));
|
|
29128
29171
|
} })
|
|
29129
29172
|
}), "dsh-image-gen: delete route");
|
|
29130
|
-
webCtx.effect(() =>
|
|
29173
|
+
webCtx.effect(() => register({
|
|
29131
29174
|
kind: "exact",
|
|
29132
29175
|
path: SAVE_WORKSPACE_ROUTE,
|
|
29133
29176
|
handler: (req, res) => serveSaveWorkspace(req, res, {
|
|
@@ -29154,7 +29197,7 @@ function apply(ctx, config = {}) {
|
|
|
29154
29197
|
isSaveEnabled: () => current().saveToWorkspace !== false
|
|
29155
29198
|
})
|
|
29156
29199
|
}), "dsh-image-gen: save workspace route");
|
|
29157
|
-
webCtx.effect(() =>
|
|
29200
|
+
webCtx.effect(() => register({
|
|
29158
29201
|
kind: "exact",
|
|
29159
29202
|
path: TEST_CONNECTION_ROUTE,
|
|
29160
29203
|
handler: (req, res) => serveTestConnection(req, res, {
|
|
@@ -29163,7 +29206,7 @@ function apply(ctx, config = {}) {
|
|
|
29163
29206
|
subscriptionManager
|
|
29164
29207
|
})
|
|
29165
29208
|
}), "dsh-image-gen: test connection route");
|
|
29166
|
-
webCtx.effect(() =>
|
|
29209
|
+
webCtx.effect(() => register({
|
|
29167
29210
|
kind: "exact",
|
|
29168
29211
|
path: CANVAS_STATE_ROUTE,
|
|
29169
29212
|
handler: (req, res) => serveCanvasState(req, res, {
|
|
@@ -29172,7 +29215,7 @@ function apply(ctx, config = {}) {
|
|
|
29172
29215
|
maxImageBytes: ctx.attachments.imageLimits.maxImageBytes
|
|
29173
29216
|
})
|
|
29174
29217
|
}), "dsh-image-gen: canvas state route");
|
|
29175
|
-
webCtx.effect(() =>
|
|
29218
|
+
webCtx.effect(() => register({
|
|
29176
29219
|
kind: "exact",
|
|
29177
29220
|
path: CANVAS_ASSET_ROUTE,
|
|
29178
29221
|
handler: (req, res) => serveCanvasAsset(req, res, {
|
|
@@ -29182,10 +29225,19 @@ function apply(ctx, config = {}) {
|
|
|
29182
29225
|
}), "dsh-image-gen: canvas asset route");
|
|
29183
29226
|
});
|
|
29184
29227
|
ctx.inject(["systemPrompt"], (promptCtx) => {
|
|
29228
|
+
refreshImageToolContext();
|
|
29229
|
+
ctx.inject(["credentials"], (credentialCtx) => {
|
|
29230
|
+
credentialCtx.on("credentials/reference-updated", () => {
|
|
29231
|
+
refreshImageToolContext();
|
|
29232
|
+
});
|
|
29233
|
+
credentialCtx.on("credentials/record-updated", () => {
|
|
29234
|
+
refreshImageToolContext();
|
|
29235
|
+
});
|
|
29236
|
+
});
|
|
29185
29237
|
promptCtx.effect(() => promptCtx.systemPrompt.context({
|
|
29186
29238
|
name: "dsh-image-gen:image-defaults",
|
|
29187
29239
|
order: 59,
|
|
29188
|
-
text: () => imageToolContext(current())
|
|
29240
|
+
text: () => imageToolContext(current(), configuredImageProviders)
|
|
29189
29241
|
}), "dsh-image-gen: image tool context");
|
|
29190
29242
|
promptCtx.effect(() => promptCtx.systemPrompt.context({
|
|
29191
29243
|
name: "dsh-image-gen:canvas",
|
|
@@ -29199,7 +29251,8 @@ function apply(ctx, config = {}) {
|
|
|
29199
29251
|
name: "canvas-selection"
|
|
29200
29252
|
}) });
|
|
29201
29253
|
ctx.inject(["webServer"], (webCtx) => {
|
|
29202
|
-
|
|
29254
|
+
const register = (route) => webCtx.webServer.register(withWebAdmission(route, () => webAdmission));
|
|
29255
|
+
webCtx.effect(() => register({
|
|
29203
29256
|
kind: "exact",
|
|
29204
29257
|
path: STUDIO_ROUTE,
|
|
29205
29258
|
handler: (req, res) => serveStudio(req, res, {
|
|
@@ -29222,7 +29275,7 @@ function apply(ctx, config = {}) {
|
|
|
29222
29275
|
})
|
|
29223
29276
|
}), "dsh-image-gen: studio route");
|
|
29224
29277
|
const serveInspiration = createInspirationRoute();
|
|
29225
|
-
webCtx.effect(() =>
|
|
29278
|
+
webCtx.effect(() => register({
|
|
29226
29279
|
kind: "prefix",
|
|
29227
29280
|
path: INSPIRATION_ROUTE,
|
|
29228
29281
|
handler: (req, res) => {
|
|
@@ -29360,7 +29413,7 @@ function apply(ctx, config = {}) {
|
|
|
29360
29413
|
},
|
|
29361
29414
|
model: {
|
|
29362
29415
|
type: "string",
|
|
29363
|
-
description: "
|
|
29416
|
+
description: "OMIT unless the user explicitly requests a specific model; omission uses the configured model. Optional override for this call only. Not used by ComfyUI (use workflow instead) nor by the subscription providers (model fixed by the subscription)."
|
|
29364
29417
|
},
|
|
29365
29418
|
channel: {
|
|
29366
29419
|
type: "string",
|
|
@@ -29439,7 +29492,7 @@ function apply(ctx, config = {}) {
|
|
|
29439
29492
|
},
|
|
29440
29493
|
model: {
|
|
29441
29494
|
type: "string",
|
|
29442
|
-
description: "
|
|
29495
|
+
description: "OMIT unless the user explicitly requests a specific model for every item; omission uses the configured model."
|
|
29443
29496
|
},
|
|
29444
29497
|
channel: {
|
|
29445
29498
|
type: "string",
|
|
@@ -29667,7 +29720,7 @@ function apply(ctx, config = {}) {
|
|
|
29667
29720
|
},
|
|
29668
29721
|
model: {
|
|
29669
29722
|
type: "string",
|
|
29670
|
-
description: "
|
|
29723
|
+
description: "OMIT unless the user explicitly requests a specific model; omission uses the configured model. Optional override for this call only. Not used by ComfyUI (use workflow instead) nor by the subscription providers (model fixed by the subscription)."
|
|
29671
29724
|
},
|
|
29672
29725
|
channel: {
|
|
29673
29726
|
type: "string",
|
|
@@ -40,6 +40,7 @@ export declare const StudioView: FC<{
|
|
|
40
40
|
onInitialReferenceApplied?(): void;
|
|
41
41
|
onOpenInspiration?(): void;
|
|
42
42
|
}>;
|
|
43
|
+
export declare function useInView<T extends HTMLElement>(): [(node: T | null) => void, boolean];
|
|
43
44
|
export declare function useAttachmentImage(attachment: ImageAttachmentRef | undefined, shouldLoad?: boolean): {
|
|
44
45
|
url: string | null;
|
|
45
46
|
blob: Blob | null;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delivery of a drawing plan to the workbench canvases.
|
|
3
|
+
*
|
|
4
|
+
* The `draw_reference` tool cannot put path data inline: the plan is tens of
|
|
5
|
+
* kilobytes and the conversation is persisted, so the tool result carries only
|
|
6
|
+
* a `traceId` (see presentationMeta) and this bridge hands that id to whichever
|
|
7
|
+
* canvas is mounted. The canvas then fetches the plan from the trace-plan route
|
|
8
|
+
* and plays it.
|
|
9
|
+
*
|
|
10
|
+
* A trace that arrives while no canvas is mounted is held, not dropped: the
|
|
11
|
+
* canvas surfaces are tab-scoped and unmount when the user looks elsewhere, so
|
|
12
|
+
* dropping on absence would mean the drawing only ever plays if the user
|
|
13
|
+
* happened to be staring at the infinite canvas at that exact second. The
|
|
14
|
+
* queue holds the newest trace only — a drawing is a one-shot show, and an
|
|
15
|
+
* older plan is stale by the time a newer one exists.
|
|
16
|
+
*/
|
|
17
|
+
/** The identifying part of a trace result, as it arrives on a tool event. */
|
|
18
|
+
export interface TlTraceItem {
|
|
19
|
+
traceId: string;
|
|
20
|
+
/** Source pixel size, for the overlay's initial aspect box. */
|
|
21
|
+
sourceWidth: number;
|
|
22
|
+
sourceHeight: number;
|
|
23
|
+
/** Region count, for the "N blocks" caption. */
|
|
24
|
+
steps: number;
|
|
25
|
+
}
|
|
26
|
+
type TlTraceConsumer = (item: TlTraceItem) => void;
|
|
27
|
+
/** Whether any canvas is mounted to play a plan. */
|
|
28
|
+
export declare function hasTlTraceConsumer(): boolean;
|
|
29
|
+
/** The trace waiting for a canvas, if any. */
|
|
30
|
+
export declare function pendingTlTrace(): TlTraceItem | null;
|
|
31
|
+
/**
|
|
32
|
+
* Register a canvas surface; returns its disposer. A trace that arrived while
|
|
33
|
+
* nothing was mounted plays immediately, so opening the canvas after asking
|
|
34
|
+
* for a drawing still shows it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function registerTlTraceConsumer(consumer: TlTraceConsumer): () => void;
|
|
37
|
+
/** Hand a plan to every mounted canvas, or hold the newest one until one is. */
|
|
38
|
+
export declare function pushTlTrace(item: TlTraceItem): void;
|
|
39
|
+
/** Test seam: clear every consumer and the pending slot. */
|
|
40
|
+
export declare function resetTlTraceBridge(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Parse the plugin-owned trace metadata off a Tool result. Returns undefined
|
|
43
|
+
* for anything that is not a draw_reference result, so callers can share one
|
|
44
|
+
* event subscription with the image landings.
|
|
45
|
+
*/
|
|
46
|
+
export declare function traceResultFromMeta(value: unknown): TlTraceItem | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Recover a trace from a `tool/ptc-dispatch` event, when the model called
|
|
49
|
+
* draw_reference through run_code instead of directly.
|
|
50
|
+
*/
|
|
51
|
+
export declare function traceResultFromPtcDispatch(event: {
|
|
52
|
+
readonly type: string;
|
|
53
|
+
readonly data: Record<string, unknown>;
|
|
54
|
+
}): TlTraceItem | undefined;
|
|
55
|
+
export {};
|