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.
- package/LICENSE +21 -21
- package/PROTOCOL.md +1545 -1486
- package/README.md +503 -464
- package/THIRD-PARTY-NOTICES/dsh-cost-meter.txt +31 -31
- package/bin/setup-ip.mjs +474 -474
- package/cordis.patch.yml +50 -50
- package/docs/agent-team-app-integration.md +945 -0
- package/docs/blog-mobile-gateway.md +542 -542
- package/docs/dsh-0.1.5-rc.2-compatibility-audit.md +255 -255
- package/docs/dsh-0.1.6-alpha.1-compatibility-audit.md +122 -122
- package/docs/dsh-0.1.7-rc.1-compatibility-audit.md +52 -52
- package/docs/dsh-0.2.0-rc.2-plugin-management-mobile-integration.md +109 -109
- package/docs/dsh-rc2-mobile-integration.md +155 -155
- package/docs/file-upload-app-integration.md +250 -0
- package/docs/multi-gateway-app-integration.md +141 -125
- package/docs/multi-gateway-phase1-acceptance.md +179 -179
- package/docs/multi-gateway-todo.md +137 -137
- package/docs/remote-gateway-refactor-plan.md +52 -52
- package/docs/runtime-architecture.architecture.json +264 -264
- package/docs/runtime-architecture.html +15001 -15001
- package/docs/runtime-architecture.visual-check.html +32 -32
- package/docs/runtime-architecture.visual-check.json +548 -548
- package/docs/session-agent-preset-app-integration.md +93 -93
- package/docs/turn-outline-app-integration.md +196 -0
- package/docs/typert-remote-gateway-feature-checklist.md +294 -294
- package/docs/voice-input-implementation.md +219 -219
- package/docs/workspace-changes-mobile-integration.md +32 -32
- package/helper/dsh_mobile_gateway_helper.py +227 -227
- package/lib/account-bridge.mjs +57 -57
- package/lib/client.js +1409 -1361
- package/lib/cloudflare-tunnel.mjs +314 -314
- package/lib/cloudflared-binary.mjs +135 -135
- package/lib/context-bridge.mjs +3338 -1715
- package/lib/cost-meter-bridge.mjs +794 -794
- package/lib/cost-meter-dashboard-bridge.mjs +1655 -1449
- package/lib/devices.js +273 -245
- package/lib/dsh-host-adapter.mjs +508 -426
- package/lib/file-upload.mjs +205 -0
- package/lib/gateway-probe.mjs +6 -6
- package/lib/gateway-state.mjs +57 -57
- package/lib/gateway-tools.mjs +36 -36
- package/lib/history-cache.mjs +66 -0
- package/lib/index.mjs +4390 -3803
- package/lib/plugin-management.mjs +251 -233
- package/lib/public-endpoint-check.mjs +61 -61
- package/lib/relay-connector.mjs +213 -181
- package/lib/relay-state.mjs +83 -76
- package/lib/session-follower.mjs +140 -136
- package/lib/session-resume-bridge.mjs +86 -0
- package/lib/session-target.mjs +29 -0
- package/lib/speech-input.mjs +192 -192
- package/lib/vendor/cost-meter/aliyun-balance.mjs +123 -123
- package/lib/vendor/cost-meter/coding-plans.mjs +1668 -1668
- package/lib/vendor/cost-meter/credentials-shim.mjs +8 -8
- package/lib/vendor/cost-meter/custom-balance.mjs +281 -281
- package/lib/vendor/cost-meter/factory-quota.mjs +69 -69
- package/lib/vendor/cost-meter/gateway-quota-adapters.mjs +1006 -1006
- package/lib/vendor/cost-meter/gateway-quotas.mjs +664 -664
- package/lib/vendor/cost-meter/home-paths-shim.mjs +13 -13
- package/lib/vendor/cost-meter/net.mjs +183 -183
- package/lib/vendor/cost-meter/opendesign.mjs +204 -204
- package/lib/vendor/cost-meter/tokenrhythm-balance.mjs +95 -95
- package/lib/vendor/cost-meter/workbuddy-accounts.mjs +44 -44
- package/lib/vendor/cost-meter/workbuddy-transport.mjs +38 -38
- package/lib/vendor/cost-meter/workbuddy.mjs +356 -356
- package/lib/web-restart.mjs +47 -47
- package/lib/wire-json.mjs +7 -7
- package/lib/workspace-changes-bridge.mjs +32 -32
- package/package.json +54 -54
- package/relay/agent-connector.js +588 -569
- 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
|
+
}
|