dsh-plugin-weapp-gateway 0.8.23 → 0.8.34

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 (71) hide show
  1. package/LICENSE +21 -21
  2. package/PROTOCOL.md +1545 -1486
  3. package/README.md +503 -464
  4. package/THIRD-PARTY-NOTICES/dsh-cost-meter.txt +31 -31
  5. package/bin/setup-ip.mjs +474 -474
  6. package/cordis.patch.yml +50 -50
  7. package/docs/agent-team-app-integration.md +945 -0
  8. package/docs/blog-mobile-gateway.md +542 -542
  9. package/docs/dsh-0.1.5-rc.2-compatibility-audit.md +255 -255
  10. package/docs/dsh-0.1.6-alpha.1-compatibility-audit.md +122 -122
  11. package/docs/dsh-0.1.7-rc.1-compatibility-audit.md +52 -52
  12. package/docs/dsh-0.2.0-rc.2-plugin-management-mobile-integration.md +109 -109
  13. package/docs/dsh-rc2-mobile-integration.md +155 -155
  14. package/docs/file-upload-app-integration.md +250 -0
  15. package/docs/multi-gateway-app-integration.md +141 -125
  16. package/docs/multi-gateway-phase1-acceptance.md +179 -179
  17. package/docs/multi-gateway-todo.md +137 -137
  18. package/docs/remote-gateway-refactor-plan.md +52 -52
  19. package/docs/runtime-architecture.architecture.json +264 -264
  20. package/docs/runtime-architecture.html +15001 -15001
  21. package/docs/runtime-architecture.visual-check.html +32 -32
  22. package/docs/runtime-architecture.visual-check.json +548 -548
  23. package/docs/session-agent-preset-app-integration.md +93 -93
  24. package/docs/turn-outline-app-integration.md +196 -0
  25. package/docs/typert-remote-gateway-feature-checklist.md +294 -294
  26. package/docs/voice-input-implementation.md +219 -219
  27. package/docs/workspace-changes-mobile-integration.md +32 -32
  28. package/helper/dsh_mobile_gateway_helper.py +227 -227
  29. package/lib/account-bridge.mjs +57 -57
  30. package/lib/client.js +1409 -1361
  31. package/lib/cloudflare-tunnel.mjs +314 -314
  32. package/lib/cloudflared-binary.mjs +135 -135
  33. package/lib/context-bridge.mjs +3338 -1715
  34. package/lib/cost-meter-bridge.mjs +794 -794
  35. package/lib/cost-meter-dashboard-bridge.mjs +1655 -1449
  36. package/lib/devices.js +273 -245
  37. package/lib/dsh-host-adapter.mjs +508 -426
  38. package/lib/file-upload.mjs +205 -0
  39. package/lib/gateway-probe.mjs +6 -6
  40. package/lib/gateway-state.mjs +57 -57
  41. package/lib/gateway-tools.mjs +36 -36
  42. package/lib/history-cache.mjs +66 -0
  43. package/lib/index.mjs +4390 -3803
  44. package/lib/plugin-management.mjs +251 -233
  45. package/lib/public-endpoint-check.mjs +61 -61
  46. package/lib/relay-connector.mjs +213 -181
  47. package/lib/relay-state.mjs +83 -76
  48. package/lib/session-follower.mjs +140 -136
  49. package/lib/session-resume-bridge.mjs +86 -0
  50. package/lib/session-target.mjs +29 -0
  51. package/lib/speech-input.mjs +192 -192
  52. package/lib/vendor/cost-meter/aliyun-balance.mjs +123 -123
  53. package/lib/vendor/cost-meter/coding-plans.mjs +1668 -1668
  54. package/lib/vendor/cost-meter/credentials-shim.mjs +8 -8
  55. package/lib/vendor/cost-meter/custom-balance.mjs +281 -281
  56. package/lib/vendor/cost-meter/factory-quota.mjs +69 -69
  57. package/lib/vendor/cost-meter/gateway-quota-adapters.mjs +1006 -1006
  58. package/lib/vendor/cost-meter/gateway-quotas.mjs +664 -664
  59. package/lib/vendor/cost-meter/home-paths-shim.mjs +13 -13
  60. package/lib/vendor/cost-meter/net.mjs +183 -183
  61. package/lib/vendor/cost-meter/opendesign.mjs +204 -204
  62. package/lib/vendor/cost-meter/tokenrhythm-balance.mjs +95 -95
  63. package/lib/vendor/cost-meter/workbuddy-accounts.mjs +44 -44
  64. package/lib/vendor/cost-meter/workbuddy-transport.mjs +38 -38
  65. package/lib/vendor/cost-meter/workbuddy.mjs +356 -356
  66. package/lib/web-restart.mjs +47 -47
  67. package/lib/wire-json.mjs +7 -7
  68. package/lib/workspace-changes-bridge.mjs +32 -32
  69. package/package.json +54 -54
  70. package/relay/agent-connector.js +588 -569
  71. package/relay/vendor/tweetnacl.js +2391 -2391
@@ -1,69 +1,69 @@
1
- /** Factory billing limits (#263); fixed read-only endpoint, no model requests.
2
- * Protocol reference: Dalizi2026/dsh-factory-provider@801c3a2, lib/quota.js.
3
- */
4
- import { fetchWithRetry, readJsonBounded } from './net.mjs'
5
-
6
- export const FACTORY_QUOTA_URL = 'https://api.factory.ai/api/billing/limits'
7
- const record = value => value !== null && typeof value === 'object' && !Array.isArray(value)
8
- export const normalizeFactoryOrgId = value => {
9
- if (value == null || value === '') return ''
10
- if (typeof value !== 'string') return null
11
- const text = value.trim()
12
- return text === '' || /^[A-Za-z0-9_.:-]{1,128}$/.test(text) ? text : null
13
- }
14
-
15
- export function parseFactoryQuota(payload, pool = 'standard', nowMs = Date.now()) {
16
- if (!record(payload?.limits)) return null
17
- const windows = {}
18
- for (const bucket of pool === 'both' ? ['standard', 'core'] : [pool === 'core' ? 'core' : 'standard']) {
19
- const limits = payload.limits[bucket]
20
- if (!record(limits)) continue
21
- for (const name of ['fiveHour', 'weekly', 'monthly']) {
22
- const raw = limits[name]
23
- if (!record(raw) || typeof raw.usedPercent !== 'number' || !Number.isFinite(raw.usedPercent) || raw.usedPercent < 0 || raw.usedPercent > 100) continue
24
- let resetsAt = ''
25
- const end = typeof raw.windowEnd === 'string' ? Date.parse(raw.windowEnd) : NaN
26
- if (Number.isFinite(end)) resetsAt = new Date(end).toISOString()
27
- else if (typeof raw.secondsRemaining === 'number' && Number.isFinite(raw.secondsRemaining) && raw.secondsRemaining >= 0) {
28
- const reset = nowMs + raw.secondsRemaining * 1000
29
- if (Number.isFinite(reset) && Math.abs(reset) <= 8640000000000000) resetsAt = new Date(reset).toISOString()
30
- }
31
- windows[bucket === 'core' ? 'core_' + name : name] = { percent: raw.usedPercent, resetsAt }
32
- }
33
- }
34
- return Object.keys(windows).length ? windows : null
35
- }
36
-
37
- export async function queryFactoryQuota(key, locale, t, { orgId, factoryPool, signal } = {}) {
38
- const provider = 'Factory (Droid)'
39
- const failure = (code, vars = {}, soft = false) => Object.assign(new Error(t(locale, code, { provider, ...vars })), { soft })
40
- if (typeof key !== 'string' || !key.trim()) throw failure('codingPlanKeyMissing', {}, true)
41
- const org = normalizeFactoryOrgId(orgId)
42
- if (org === null) throw failure('factoryOrgInvalid')
43
- const headers = {
44
- authorization: `Bearer ${key.trim()}`, 'x-client-version': '0.231.0',
45
- 'x-factory-client': 'cli', accept: 'application/json', 'accept-encoding': 'identity',
46
- }
47
- if (org) headers['x-factory-org-id'] = org
48
- let response
49
- try {
50
- response = await fetchWithRetry(FACTORY_QUOTA_URL, { method: 'GET', headers, redirect: 'manual', signal }, { timeoutMs: 15000, attempts: 2 })
51
- } catch {
52
- signal?.throwIfAborted()
53
- throw failure('factoryQueryFailed')
54
- }
55
- if (!response.ok) {
56
- try { await response.body?.cancel?.() } catch {}
57
- if (response.status === 401 || response.status === 403) throw failure('factoryUnauthorized', {}, true)
58
- throw failure('codingPlanHttp', { code: String(response.status), url: FACTORY_QUOTA_URL })
59
- }
60
- let payload
61
- try { payload = await readJsonBounded(response) } catch {
62
- signal?.throwIfAborted()
63
- throw failure('codingPlanNoUsage')
64
- }
65
- signal?.throwIfAborted()
66
- const windows = parseFactoryQuota(payload, factoryPool)
67
- if (windows === null) throw failure('codingPlanNoUsage')
68
- return { windows, endpoint: FACTORY_QUOTA_URL }
69
- }
1
+ /** Factory billing limits (#263); fixed read-only endpoint, no model requests.
2
+ * Protocol reference: Dalizi2026/dsh-factory-provider@801c3a2, lib/quota.js.
3
+ */
4
+ import { fetchWithRetry, readJsonBounded } from './net.mjs'
5
+
6
+ export const FACTORY_QUOTA_URL = 'https://api.factory.ai/api/billing/limits'
7
+ const record = value => value !== null && typeof value === 'object' && !Array.isArray(value)
8
+ export const normalizeFactoryOrgId = value => {
9
+ if (value == null || value === '') return ''
10
+ if (typeof value !== 'string') return null
11
+ const text = value.trim()
12
+ return text === '' || /^[A-Za-z0-9_.:-]{1,128}$/.test(text) ? text : null
13
+ }
14
+
15
+ export function parseFactoryQuota(payload, pool = 'standard', nowMs = Date.now()) {
16
+ if (!record(payload?.limits)) return null
17
+ const windows = {}
18
+ for (const bucket of pool === 'both' ? ['standard', 'core'] : [pool === 'core' ? 'core' : 'standard']) {
19
+ const limits = payload.limits[bucket]
20
+ if (!record(limits)) continue
21
+ for (const name of ['fiveHour', 'weekly', 'monthly']) {
22
+ const raw = limits[name]
23
+ if (!record(raw) || typeof raw.usedPercent !== 'number' || !Number.isFinite(raw.usedPercent) || raw.usedPercent < 0 || raw.usedPercent > 100) continue
24
+ let resetsAt = ''
25
+ const end = typeof raw.windowEnd === 'string' ? Date.parse(raw.windowEnd) : NaN
26
+ if (Number.isFinite(end)) resetsAt = new Date(end).toISOString()
27
+ else if (typeof raw.secondsRemaining === 'number' && Number.isFinite(raw.secondsRemaining) && raw.secondsRemaining >= 0) {
28
+ const reset = nowMs + raw.secondsRemaining * 1000
29
+ if (Number.isFinite(reset) && Math.abs(reset) <= 8640000000000000) resetsAt = new Date(reset).toISOString()
30
+ }
31
+ windows[bucket === 'core' ? 'core_' + name : name] = { percent: raw.usedPercent, resetsAt }
32
+ }
33
+ }
34
+ return Object.keys(windows).length ? windows : null
35
+ }
36
+
37
+ export async function queryFactoryQuota(key, locale, t, { orgId, factoryPool, signal } = {}) {
38
+ const provider = 'Factory (Droid)'
39
+ const failure = (code, vars = {}, soft = false) => Object.assign(new Error(t(locale, code, { provider, ...vars })), { soft })
40
+ if (typeof key !== 'string' || !key.trim()) throw failure('codingPlanKeyMissing', {}, true)
41
+ const org = normalizeFactoryOrgId(orgId)
42
+ if (org === null) throw failure('factoryOrgInvalid')
43
+ const headers = {
44
+ authorization: `Bearer ${key.trim()}`, 'x-client-version': '0.231.0',
45
+ 'x-factory-client': 'cli', accept: 'application/json', 'accept-encoding': 'identity',
46
+ }
47
+ if (org) headers['x-factory-org-id'] = org
48
+ let response
49
+ try {
50
+ response = await fetchWithRetry(FACTORY_QUOTA_URL, { method: 'GET', headers, redirect: 'manual', signal }, { timeoutMs: 15000, attempts: 2 })
51
+ } catch {
52
+ signal?.throwIfAborted()
53
+ throw failure('factoryQueryFailed')
54
+ }
55
+ if (!response.ok) {
56
+ try { await response.body?.cancel?.() } catch {}
57
+ if (response.status === 401 || response.status === 403) throw failure('factoryUnauthorized', {}, true)
58
+ throw failure('codingPlanHttp', { code: String(response.status), url: FACTORY_QUOTA_URL })
59
+ }
60
+ let payload
61
+ try { payload = await readJsonBounded(response) } catch {
62
+ signal?.throwIfAborted()
63
+ throw failure('codingPlanNoUsage')
64
+ }
65
+ signal?.throwIfAborted()
66
+ const windows = parseFactoryQuota(payload, factoryPool)
67
+ if (windows === null) throw failure('codingPlanNoUsage')
68
+ return { windows, endpoint: FACTORY_QUOTA_URL }
69
+ }