dsh-subscriptions 0.1.4 → 0.2.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.
Files changed (62) hide show
  1. package/README.md +31 -5
  2. package/lib/auth/device-flow.js +6 -3
  3. package/lib/auth/oauth-flow.js +41 -8
  4. package/lib/auth/rpc.d.ts +73 -2
  5. package/lib/auth/rpc.js +53 -3
  6. package/lib/client/ExternalUsageCards.js +1 -1
  7. package/lib/client/OllamaCard.d.ts +13 -0
  8. package/lib/client/OllamaCard.js +76 -0
  9. package/lib/client/OllamaSettingsManager.d.ts +24 -0
  10. package/lib/client/OllamaSettingsManager.js +246 -0
  11. package/lib/client/ProviderModelEditor.js +4 -2
  12. package/lib/client/SubscriptionUsageBadge.d.ts +1 -1
  13. package/lib/client/SubscriptionUsageBadge.js +3 -2
  14. package/lib/client/SubscriptionsSection.d.ts +2 -74
  15. package/lib/client/SubscriptionsSection.js +4 -67
  16. package/lib/client/UsageMeter.js +11 -7
  17. package/lib/client/locales.d.ts +68 -0
  18. package/lib/client/locales.js +77 -0
  19. package/lib/client/ollama-draft.d.ts +229 -0
  20. package/lib/client/ollama-draft.js +246 -0
  21. package/lib/client/usage-pace.d.ts +7 -0
  22. package/lib/client/usage-pace.js +15 -0
  23. package/lib/client.js +1385 -244
  24. package/lib/client.js.map +1 -1
  25. package/lib/index.d.ts +25 -0
  26. package/lib/index.js +11060 -9733
  27. package/lib/model-defaults.d.ts +4 -5
  28. package/lib/model-defaults.js +18 -14
  29. package/lib/provider-settings.d.ts +2 -1
  30. package/lib/provider-settings.js +6 -4
  31. package/lib/providers/antigravity.d.ts +0 -2
  32. package/lib/providers/antigravity.js +5 -9
  33. package/lib/providers/claude.d.ts +14 -1
  34. package/lib/providers/claude.js +25 -13
  35. package/lib/providers/codex-search.js +5 -2
  36. package/lib/providers/codex.js +7 -7
  37. package/lib/providers/common.d.ts +27 -0
  38. package/lib/providers/common.js +70 -0
  39. package/lib/providers/copilot.js +3 -3
  40. package/lib/providers/cursor-adapter.d.ts +35 -0
  41. package/lib/providers/cursor-adapter.js +245 -4
  42. package/lib/providers/cursor-auth.js +11 -4
  43. package/lib/providers/cursor-usage.js +2 -1
  44. package/lib/providers/external-usage-controller.d.ts +9 -2
  45. package/lib/providers/external-usage-controller.js +19 -5
  46. package/lib/providers/external-usage.d.ts +8 -0
  47. package/lib/providers/external-usage.js +93 -8
  48. package/lib/providers/grok.js +14 -9
  49. package/lib/providers/minimax-usage.js +2 -1
  50. package/lib/providers/ollama-settings.d.ts +90 -0
  51. package/lib/providers/ollama-settings.js +197 -0
  52. package/lib/providers/ollama-web.d.ts +46 -0
  53. package/lib/providers/ollama-web.js +213 -0
  54. package/lib/providers/ollama.d.ts +107 -0
  55. package/lib/providers/ollama.js +545 -0
  56. package/lib/tools/image-generate.js +2 -1
  57. package/lib/tools/video-generate.d.ts +0 -5
  58. package/lib/tools/video-generate.js +25 -14
  59. package/lib/tools/x-search.js +2 -2
  60. package/lib/translate/resolved.d.ts +5 -2
  61. package/lib/translate/resolved.js +5 -2
  62. package/package.json +1 -1
@@ -57,10 +57,6 @@ export declare function buildVideoGenerateBody(args: {
57
57
  resolution?: '480p' | '720p' | '1080p';
58
58
  image_url?: string;
59
59
  }): VideoGenerateRequestBody;
60
- /**
61
- * Extract the request id from the submit response. Throws when the payload
62
- * carries none.
63
- */
64
60
  export declare function parseVideoStartResponse(payload: unknown): string;
65
61
  /** One decoded poll response. */
66
62
  export type VideoStatus = {
@@ -71,7 +67,6 @@ export type VideoStatus = {
71
67
  duration?: number;
72
68
  } | {
73
69
  status: 'failed' | 'expired';
74
- detail?: string;
75
70
  };
76
71
  /**
77
72
  * Decode one poll response. A `done` payload without a video URL and an
@@ -12,7 +12,7 @@ import { mkdir, writeFile } from 'node:fs/promises';
12
12
  import { basename, join } from 'node:path';
13
13
  import { dshHomePath } from '@deepseek-ai/dsh-home-paths';
14
14
  import { defineTool } from '@deepseek-ai/dsh-tools';
15
- import { httpLlmError } from '../providers/common.js';
15
+ import { httpLlmError, parseProviderJson } from '../providers/common.js';
16
16
  import { AccountTokenManager } from '../providers/accounts.js';
17
17
  import { hostFetch } from '../http.js';
18
18
  /** Endpoint the generation request is posted to. */
@@ -60,10 +60,20 @@ function isRecord(value) {
60
60
  * Extract the request id from the submit response. Throws when the payload
61
61
  * carries none.
62
62
  */
63
+ /**
64
+ * A provider-assigned request id, accepted only in a bounded identifier shape.
65
+ * The value reaches a user-visible failure message, so an unchecked one would
66
+ * let a provider put arbitrary text there. The shape rules out prose, spaces
67
+ * and message excerpts; it does NOT prove the value is harmless, because a
68
+ * credential-shaped string such as `SHORT_SECRET` matches it. Treat this as a
69
+ * bounded, format-constrained provider value that is displayed for support
70
+ * correlation — not as the absence of provider-supplied content.
71
+ */
72
+ const REQUEST_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
63
73
  export function parseVideoStartResponse(payload) {
64
74
  const body = isRecord(payload) ? payload : {};
65
- if (typeof body.request_id !== 'string' || body.request_id.length === 0) {
66
- throw new Error('video_generate: the response carried no request_id');
75
+ if (typeof body.request_id !== 'string' || !REQUEST_ID_PATTERN.test(body.request_id)) {
76
+ throw new Error('video_generate: the response carried no usable request_id');
67
77
  }
68
78
  return body.request_id;
69
79
  }
@@ -89,15 +99,13 @@ export function parseVideoStatusResponse(payload) {
89
99
  };
90
100
  }
91
101
  case 'failed':
92
- case 'expired': {
93
- const error = isRecord(body.error) ? body.error : {};
94
- const detail = typeof error.message === 'string' && error.message.length > 0
95
- ? error.message
96
- : typeof body.error === 'string' && body.error.length > 0 ? body.error : undefined;
97
- return { status: body.status, ...detail === undefined ? {} : { detail } };
98
- }
102
+ case 'expired':
103
+ // Safe means this failure path carries no provider-controlled free text,
104
+ // not that no secret can exist elsewhere in the system.
105
+ return { status: body.status };
99
106
  default:
100
- throw new Error(`video_generate: unexpected status ${JSON.stringify(body.status)}`);
107
+ // Safe here also excludes provider-controlled free text, not all system secrets.
108
+ throw new Error('video_generate: unexpected status: [provider response body omitted]');
101
109
  }
102
110
  }
103
111
  /** Directory the downloaded MP4 files are written to. */
@@ -212,7 +220,7 @@ export function createVideoGenerateTool(options) {
212
220
  });
213
221
  if (!submit.ok)
214
222
  throw await httpLlmError(submit, 'video_generate');
215
- const requestId = parseVideoStartResponse(await submit.json());
223
+ const requestId = parseVideoStartResponse(await parseProviderJson(submit, 'video generate start'));
216
224
  const deadline = Date.now() + maxWaitMs;
217
225
  let done;
218
226
  for (;;) {
@@ -224,14 +232,17 @@ export function createVideoGenerateTool(options) {
224
232
  });
225
233
  if (!poll.ok)
226
234
  throw await httpLlmError(poll, 'video_generate');
227
- const status = parseVideoStatusResponse(await poll.json());
235
+ const status = parseVideoStatusResponse(await parseProviderJson(poll, 'video generate status poll'));
228
236
  if (status.status === 'done') {
229
237
  done = status;
230
238
  break;
231
239
  }
232
240
  if (status.status === 'failed' || status.status === 'expired') {
241
+ // No provider response text on this path. The request id is shaped like an
242
+ // opaque id before it is stored (see REQUEST_ID_PATTERN), so it is an
243
+ // identifier rather than provider prose; anything else was refused at parse.
233
244
  throw new Error(`video_generate: generation ${status.status} (request ${requestId})`
234
- + (status.detail === undefined ? '' : `: ${status.detail}`));
245
+ + ': [provider response body omitted]');
235
246
  }
236
247
  if (Date.now() >= deadline) {
237
248
  throw new Error(`video_generate: timed out after ${String(maxWaitMs)}ms waiting for request ${requestId}`);
@@ -5,7 +5,7 @@
5
5
  * output is `{ answer, citations }`.
6
6
  */
7
7
  import { defineTool } from '@deepseek-ai/dsh-tools';
8
- import { httpLlmError } from '../providers/common.js';
8
+ import { httpLlmError, parseProviderJson } from '../providers/common.js';
9
9
  import { AccountTokenManager } from '../providers/accounts.js';
10
10
  import { hostFetch } from '../http.js';
11
11
  /** Endpoint the search request is posted to. */
@@ -191,7 +191,7 @@ export function createXSearchTool(options) {
191
191
  });
192
192
  if (!response.ok)
193
193
  throw await httpLlmError(response, 'x_search');
194
- return parseXSearchResponse(await response.json());
194
+ return parseXSearchResponse(await parseProviderJson(response, 'x search'));
195
195
  },
196
196
  });
197
197
  }
@@ -52,8 +52,11 @@ export interface ImageRequestLimit {
52
52
  }
53
53
  /**
54
54
  * Failure code a host's image-offload executor answers by replacing the oldest
55
- * retained images with text and retrying (`IMAGE_OFFLOAD_REQUIRED_CODE` in
56
- * dsh-llm 0.2+). Spelled out so the build links against older hosts too.
55
+ * retained images with text and retrying. Every host in our support window
56
+ * exports the equivalent as `IMAGE_OFFLOAD_REQUIRED_CODE`, from the window floor
57
+ * `0.1.7-rc.2` up, so this is not a newer-host path. The value is spelled out
58
+ * rather than imported so the plugin keeps building if a host stops exporting
59
+ * it.
57
60
  */
58
61
  export declare const IMAGE_OFFLOAD_REQUIRED = "IMAGE_OFFLOAD_REQUIRED";
59
62
  /**
@@ -45,8 +45,11 @@ export function withToolResultImages(messages) {
45
45
  }
46
46
  /**
47
47
  * Failure code a host's image-offload executor answers by replacing the oldest
48
- * retained images with text and retrying (`IMAGE_OFFLOAD_REQUIRED_CODE` in
49
- * dsh-llm 0.2+). Spelled out so the build links against older hosts too.
48
+ * retained images with text and retrying. Every host in our support window
49
+ * exports the equivalent as `IMAGE_OFFLOAD_REQUIRED_CODE`, from the window floor
50
+ * `0.1.7-rc.2` up, so this is not a newer-host path. The value is spelled out
51
+ * rather than imported so the plugin keeps building if a host stops exporting
52
+ * it.
50
53
  */
51
54
  export const IMAGE_OFFLOAD_REQUIRED = 'IMAGE_OFFLOAD_REQUIRED';
52
55
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-subscriptions",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Unified subscription providers and usage dashboard for DeepSeek Harness",
5
5
  "icon": "./icon.svg",
6
6
  "license": "MIT",