dsh-image-gen 0.10.1 → 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/lib/client.js CHANGED
@@ -125620,7 +125620,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
125620
125620
  `;
125621
125621
  //#endregion
125622
125622
  //#region lib/types/client/index.js
125623
- console.info(`[dsh-image-gen] canvas bundle 2026-11-01T16:40:54.993Z`);
125623
+ console.info(`[dsh-image-gen] canvas bundle 2026-11-02T02:55:48.656Z`);
125624
125624
  /** Right-sidebar tab-type registration id (DSH 0.1.5 `sidebarRightTabs`). */
125625
125625
  const SIDEBAR_STUDIO_TAB_ID = "dsh-image-gen/studio";
125626
125626
  /** The tab kind: a page type opened by kind, recognizing no resource address. */
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 text = await response.text().catch(() => "");
8887
- throw new Error(`token endpoint HTTP ${String(response.status)}${text.length > 0 ? `: ${text.slice(0, 200)}` : ""}`);
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
- throw new Error(`${vendor} HTTP ${String(response.status)}${detail !== void 0 ? `: ${detail.slice(0, 200)}` : ""}`);
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: "follow"
28813
+ redirect: "error"
28791
28814
  }).catch((error) => {
28792
28815
  throw new Error(error instanceof Error ? error.message : String(error));
28793
28816
  });
@@ -29109,19 +29132,24 @@ function apply(ctx, config = {}) {
29109
29132
  refreshImageToolContext();
29110
29133
  }
29111
29134
  });
29135
+ let webAdmission;
29136
+ ctx.inject(["connection"], (connectionCtx) => {
29137
+ webAdmission = (request) => connectionCtx.connection.requestRejection(request);
29138
+ });
29112
29139
  ctx.inject(["webServer"], (webCtx) => {
29113
- registerSubscriptionRoutes(webCtx, subscriptionManager);
29114
- webCtx.effect(() => webCtx.webServer.register({
29140
+ const register = (route) => webCtx.webServer.register(withWebAdmission(route, () => webAdmission));
29141
+ registerSubscriptionRoutes(webCtx, subscriptionManager, () => webAdmission);
29142
+ webCtx.effect(() => register({
29115
29143
  kind: "exact",
29116
29144
  path: SETTINGS_HEALTH_ROUTE,
29117
29145
  handler: (req, res) => serveSettingsHealth(req, res, settingsHealth())
29118
29146
  }), "dsh-image-gen: settings health");
29119
- webCtx.effect(() => webCtx.webServer.register({
29147
+ webCtx.effect(() => register({
29120
29148
  kind: "exact",
29121
29149
  path: IMAGE_ROUTE,
29122
29150
  handler: (req, res) => serveImage(req, res, { readImage: (ref) => ctx.attachments.readImage(ref) })
29123
29151
  }), "dsh-image-gen: image route");
29124
- webCtx.effect(() => webCtx.webServer.register({
29152
+ webCtx.effect(() => register({
29125
29153
  kind: "exact",
29126
29154
  path: IMPORT_ROUTE,
29127
29155
  handler: (req, res) => serveImport(req, res, {
@@ -29130,7 +29158,7 @@ function apply(ctx, config = {}) {
29130
29158
  mediaTypes: ctx.attachments.imageLimits.mediaTypes
29131
29159
  })
29132
29160
  }), "dsh-image-gen: import route");
29133
- webCtx.effect(() => webCtx.webServer.register({
29161
+ webCtx.effect(() => register({
29134
29162
  kind: "exact",
29135
29163
  path: DELETE_ROUTE,
29136
29164
  handler: (req, res) => serveDelete(req, res, { deleteWorkspaceImage: async (filePath) => {
@@ -29142,7 +29170,7 @@ function apply(ctx, config = {}) {
29142
29170
  ]));
29143
29171
  } })
29144
29172
  }), "dsh-image-gen: delete route");
29145
- webCtx.effect(() => webCtx.webServer.register({
29173
+ webCtx.effect(() => register({
29146
29174
  kind: "exact",
29147
29175
  path: SAVE_WORKSPACE_ROUTE,
29148
29176
  handler: (req, res) => serveSaveWorkspace(req, res, {
@@ -29169,7 +29197,7 @@ function apply(ctx, config = {}) {
29169
29197
  isSaveEnabled: () => current().saveToWorkspace !== false
29170
29198
  })
29171
29199
  }), "dsh-image-gen: save workspace route");
29172
- webCtx.effect(() => webCtx.webServer.register({
29200
+ webCtx.effect(() => register({
29173
29201
  kind: "exact",
29174
29202
  path: TEST_CONNECTION_ROUTE,
29175
29203
  handler: (req, res) => serveTestConnection(req, res, {
@@ -29178,7 +29206,7 @@ function apply(ctx, config = {}) {
29178
29206
  subscriptionManager
29179
29207
  })
29180
29208
  }), "dsh-image-gen: test connection route");
29181
- webCtx.effect(() => webCtx.webServer.register({
29209
+ webCtx.effect(() => register({
29182
29210
  kind: "exact",
29183
29211
  path: CANVAS_STATE_ROUTE,
29184
29212
  handler: (req, res) => serveCanvasState(req, res, {
@@ -29187,7 +29215,7 @@ function apply(ctx, config = {}) {
29187
29215
  maxImageBytes: ctx.attachments.imageLimits.maxImageBytes
29188
29216
  })
29189
29217
  }), "dsh-image-gen: canvas state route");
29190
- webCtx.effect(() => webCtx.webServer.register({
29218
+ webCtx.effect(() => register({
29191
29219
  kind: "exact",
29192
29220
  path: CANVAS_ASSET_ROUTE,
29193
29221
  handler: (req, res) => serveCanvasAsset(req, res, {
@@ -29223,7 +29251,8 @@ function apply(ctx, config = {}) {
29223
29251
  name: "canvas-selection"
29224
29252
  }) });
29225
29253
  ctx.inject(["webServer"], (webCtx) => {
29226
- webCtx.effect(() => webCtx.webServer.register({
29254
+ const register = (route) => webCtx.webServer.register(withWebAdmission(route, () => webAdmission));
29255
+ webCtx.effect(() => register({
29227
29256
  kind: "exact",
29228
29257
  path: STUDIO_ROUTE,
29229
29258
  handler: (req, res) => serveStudio(req, res, {
@@ -29246,7 +29275,7 @@ function apply(ctx, config = {}) {
29246
29275
  })
29247
29276
  }), "dsh-image-gen: studio route");
29248
29277
  const serveInspiration = createInspirationRoute();
29249
- webCtx.effect(() => webCtx.webServer.register({
29278
+ webCtx.effect(() => register({
29250
29279
  kind: "prefix",
29251
29280
  path: INSPIRATION_ROUTE,
29252
29281
  handler: (req, res) => {
@@ -1,5 +1,6 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
2
  import { SubscriptionManager } from './manager.js';
3
+ import { type WebAdmission } from '../web-route.js';
3
4
  export { SUBSCRIPTION_LOGIN_ROUTE, SUBSCRIPTION_STATUS_ROUTE } from '../shared.js';
4
5
  /** Register the login/status routes on the plugin's web server. */
5
- export declare function registerSubscriptionRoutes(ctx: Context, manager: SubscriptionManager): void;
6
+ export declare function registerSubscriptionRoutes(ctx: Context, manager: SubscriptionManager, admission?: () => WebAdmission | undefined): void;
@@ -0,0 +1,4 @@
1
+ import type { ConnectionRequestRejection, ConnectionTrustRequest } from '@deepseek-ai/dsh-client-connection';
2
+ import type { WebRoute } from '@deepseek-ai/dsh-host-webserver';
3
+ export type WebAdmission = (request: ConnectionTrustRequest) => ConnectionRequestRejection;
4
+ export declare function withWebAdmission(route: WebRoute, admission: () => WebAdmission | undefined): WebRoute;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-image-gen",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "Bring ChatGPT-like image generation to DeepSeek Harness — Gemini, OpenAI, Seedream, DashScope, local ComfyUI & more.",
5
5
  "type": "module",
6
6
  "author": "shanliuling",