@tool-bridge/server 0.19.0 → 0.20.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.
- package/dist/{airtable-23JBIM6X.js → airtable-ZNWHIJMO.js} +4 -4
- package/dist/{alt_text_generator_ai-ADWBTCIH.js → alt_text_generator_ai-X7RMDDM5.js} +4 -4
- package/dist/{amap-CYQCYW2Z.js → amap-3VER75VH.js} +4 -4
- package/dist/{anthropic-5P62HDNR.js → anthropic-N7NTB3UC.js} +4 -4
- package/dist/{apify-54RZUAGW.js → apify-JB5P5AJI.js} +4 -4
- package/dist/{brave_search-AHJ6FTD5.js → brave_search-USL5OOBS.js} +4 -4
- package/dist/{chunk-SWBNHIO4.js → chunk-3WL6EXYX.js} +1 -1
- package/dist/{chunk-B4P6YZFS.js → chunk-6ANLYNFB.js} +1 -1
- package/dist/{chunk-VLOIDU5U.js → chunk-6X55ALDX.js} +3 -3
- package/dist/{chunk-CLEZ6YQ6.js → chunk-RVUERWUZ.js} +584 -60
- package/dist/{chunk-OKRZPQ3R.js → chunk-WIGQCP6O.js} +869 -74
- package/dist/{circleci-UM3NSQJ3.js → circleci-LBGB25LP.js} +4 -4
- package/dist/{clerk-FE5LQ2CZ.js → clerk-6RX37CNZ.js} +4 -4
- package/dist/{cloudflare_dns-KEZABKUT.js → cloudflare_dns-NQGW7FHV.js} +4 -4
- package/dist/{cohere-4IPJADXP.js → cohere-XPC2NAEW.js} +4 -4
- package/dist/{confluence-56QEKNQI.js → confluence-ZUG2LT5A.js} +4 -4
- package/dist/{convertapi-3QRM5K5T.js → convertapi-ZLXKWV3L.js} +3 -3
- package/dist/{currencyapi-L6G4OND5.js → currencyapi-T3A3HSOD.js} +4 -4
- package/dist/{deepseek-LGC6HBFG.js → deepseek-NJMOD23E.js} +4 -4
- package/dist/{docker_hub-XDMK3BIU.js → docker_hub-D2MQCSJ7.js} +4 -4
- package/dist/{dropbox-4QARMFZU.js → dropbox-MI6U3SOT.js} +4 -4
- package/dist/{dub-C6JSJKOT.js → dub-P2BYBYV4.js} +4 -4
- package/dist/{e2b-6A6TVACJ.js → e2b-BGKIAE54.js} +4 -4
- package/dist/{exa-SIWWW6AA.js → exa-EUY7VV4C.js} +4 -4
- package/dist/{fal_ai-3IJXOKSP.js → fal_ai-AAOG5FYJ.js} +4 -4
- package/dist/{feishu-L4KDA4DC.js → feishu-AN5IJYOW.js} +2 -2
- package/dist/{feishu_custom_bot-SDM75H4P.js → feishu_custom_bot-BWGMNVXF.js} +3 -3
- package/dist/{figma-6DD436DN.js → figma-SJSWYCGD.js} +4 -4
- package/dist/{firehydrant-SYSGYB3R.js → firehydrant-MOXK2PST.js} +4 -4
- package/dist/{fixer-FZG7ASTF.js → fixer-ISIDUDZU.js} +4 -4
- package/dist/{fly-HMRCZBUC.js → fly-U4KPSGBF.js} +4 -4
- package/dist/{front-FAFSD7I3.js → front-ZHM2YX2E.js} +4 -4
- package/dist/{geocodio-4D3TWENM.js → geocodio-SVCCAXAV.js} +4 -4
- package/dist/{ghost-OSO2FOZS.js → ghost-INTR7FIY.js} +4 -4
- package/dist/{github-OR4I4RHE.js → github-T275VVWR.js} +4 -4
- package/dist/{gmail-5AOPJ63E.js → gmail-KSSPOE67.js} +4 -4
- package/dist/{googlecalendar-SOJIJUWH.js → googlecalendar-JB5RW27L.js} +4 -4
- package/dist/{googledocs-QSKN5TLN.js → googledocs-G522PUGW.js} +3 -3
- package/dist/{grafana-R3AIZM7M.js → grafana-44ZPIV5P.js} +4 -4
- package/dist/{graphhopper-4CR3QOAX.js → graphhopper-2MORXLOW.js} +4 -4
- package/dist/index.d.ts +21 -6
- package/dist/index.js +3 -3
- package/dist/{ip2proxy-OBCG6X6J.js → ip2proxy-R4K4KEMI.js} +4 -4
- package/dist/{ipgeolocation_io-NHH3DTQW.js → ipgeolocation_io-H4J55OGI.js} +4 -4
- package/dist/{ipqualityscore-7POMCBEC.js → ipqualityscore-XGID4OHA.js} +4 -4
- package/dist/{jina_ai-YXVKROV4.js → jina_ai-7ZVDOR3Z.js} +4 -4
- package/dist/{jira-LADO3VJU.js → jira-CTIYZTT3.js} +4 -4
- package/dist/{langsmith-XZ6UAQFU.js → langsmith-ISP567FS.js} +4 -4
- package/dist/{lemlist-P74GLNE7.js → lemlist-OGKK272F.js} +4 -4
- package/dist/{linear-CXJ7D37A.js → linear-6JX4E3JI.js} +3 -3
- package/dist/{logsnag-EVVHWFLK.js → logsnag-BVB36ZCL.js} +4 -4
- package/dist/main.js +102 -102
- package/dist/{mattermost-WG2MRGBD.js → mattermost-UECVPZGY.js} +4 -4
- package/dist/{mem0-HQWUKG6U.js → mem0-EUA7S2OO.js} +4 -4
- package/dist/{memos-SQMJIFOE.js → memos-BYSBJRWZ.js} +4 -4
- package/dist/{metabase-E27G2DZI.js → metabase-4JXZH3YG.js} +4 -4
- package/dist/{mistral_ai-MIL63NIT.js → mistral_ai-2C5BTBKW.js} +4 -4
- package/dist/{mother_duck-AIZVCBNR.js → mother_duck-ZGNNNR3X.js} +4 -4
- package/dist/{ngrok-XS4DVIQS.js → ngrok-NTPGMRXI.js} +4 -4
- package/dist/{notes-JEOUSL2Y.js → notes-KGYXX6N6.js} +1 -1
- package/dist/{notion-U4EZVDW2.js → notion-EX3X2G7G.js} +4 -4
- package/dist/{open_exchange_rates-AZSQEYEJ.js → open_exchange_rates-2V2LIGPS.js} +4 -4
- package/dist/{openai-HW3SYMTQ.js → openai-KQFQPK7Z.js} +4 -4
- package/dist/{opengraph_io-QX74MAEL.js → opengraph_io-B63SEYJY.js} +4 -4
- package/dist/{openrouter-OXSKYL6N.js → openrouter-62A4H62Q.js} +4 -4
- package/dist/{outline-CCQAPDSW.js → outline-QC33XLCK.js} +4 -4
- package/dist/{paddle-6KQPSSCK.js → paddle-HDZG35Y7.js} +4 -4
- package/dist/{perplexity-2TXO7IQE.js → perplexity-M7LOMJWA.js} +4 -4
- package/dist/{pinecone-YOO7NULI.js → pinecone-Y7YCJRZM.js} +4 -4
- package/dist/{pipedrive-Q6RIFIFP.js → pipedrive-FLJA62UX.js} +4 -4
- package/dist/{polar-KUMGCES3.js → polar-AE55Q425.js} +4 -4
- package/dist/{posthog-VXQHBSMB.js → posthog-IAY5D3YW.js} +4 -4
- package/dist/{postmark-YLIPF52S.js → postmark-NMKAXDXZ.js} +4 -4
- package/dist/{prerender-CRY7UJN5.js → prerender-CDJM7I7N.js} +4 -4
- package/dist/{pubmed-3Z4T5AM7.js → pubmed-N437ZJOR.js} +3 -3
- package/dist/{railway-BP37IGFL.js → railway-NBWYXCUM.js} +3 -3
- package/dist/{readwise-HTKICF4K.js → readwise-QRO3UC3R.js} +4 -4
- package/dist/{render-WIVTUXJH.js → render-NEW7SROG.js} +4 -4
- package/dist/{replicate-JJYPA43D.js → replicate-73YQLRTY.js} +4 -4
- package/dist/{resend-TKHZVG7A.js → resend-R5BAZFHZ.js} +4 -4
- package/dist/{rootly-FRSZLG5U.js → rootly-5BLALPCS.js} +4 -4
- package/dist/{scrapfly-M5WXGQWE.js → scrapfly-EHFLNNUZ.js} +4 -4
- package/dist/{scrapingbee-PMXNLLBK.js → scrapingbee-UXLYS72S.js} +4 -4
- package/dist/{screenshot_fyi-HFW4TAOH.js → screenshot_fyi-KC3NLTJ6.js} +4 -4
- package/dist/{semantic_scholar-KXVH2VZQ.js → semantic_scholar-SA5OIUWA.js} +4 -4
- package/dist/{sentry-WWOT2LRX.js → sentry-BAE3XLJN.js} +4 -4
- package/dist/{shodan-FY635H35.js → shodan-FJR6MKKW.js} +4 -4
- package/dist/{shopify-HQLBVSA5.js → shopify-7OA6SLN5.js} +4 -4
- package/dist/{stripe-GJN2GOHB.js → stripe-MUWDZGGF.js} +3 -3
- package/dist/{supabase-BBNZGQU6.js → supabase-SWWGNWYR.js} +4 -4
- package/dist/{tavily-DPENIBOG.js → tavily-XQNJ5EDI.js} +4 -4
- package/dist/{telegram-L4NONG6H.js → telegram-RR6JPZOG.js} +4 -4
- package/dist/{telnyx-H67MAEZS.js → telnyx-7PKXOWSO.js} +4 -4
- package/dist/{todoist-G2BSP4DX.js → todoist-63X5IUJE.js} +4 -4
- package/dist/{trello-7WMVFDG2.js → trello-MOG63DAI.js} +4 -4
- package/dist/{turso-ZUAESFC2.js → turso-ENWTSHDL.js} +4 -4
- package/dist/{twilio-EYFYIX3B.js → twilio-FDXUN7VX.js} +3 -3
- package/dist/{umami-AXAUDUVF.js → umami-TM7PROWF.js} +4 -4
- package/dist/{unsplash-UCQAWPLR.js → unsplash-NWXLKSOW.js} +4 -4
- package/dist/{upstash_redis-ZPZ4ASU6.js → upstash_redis-CUTQ5L2N.js} +4 -4
- package/dist/{uptimerobot-4QVKKUD5.js → uptimerobot-NNO32M3I.js} +3 -3
- package/dist/{v2ex-VGEFJTYC.js → v2ex-24KMSWS7.js} +4 -4
- package/dist/{vercel-JME4TSCN.js → vercel-B45LPF6I.js} +4 -4
- package/dist/{wolfram_alpha_api-TRGU2MDG.js → wolfram_alpha_api-DKJWVR6G.js} +4 -4
- package/dist/{wordpress-WRUKLCZR.js → wordpress-XYFSDZXY.js} +4 -4
- package/dist/{workos-ZDW4EHS4.js → workos-BEM7EPHM.js} +4 -4
- package/dist/{zhihu-4VI67CWU.js → zhihu-CFHZ4NC7.js} +4 -4
- package/package.json +5 -5
|
@@ -1328,16 +1328,16 @@ function cleanEnum(obj) {
|
|
|
1328
1328
|
}
|
|
1329
1329
|
function base64ToUint8Array(base644) {
|
|
1330
1330
|
const binaryString = atob(base644);
|
|
1331
|
-
const
|
|
1331
|
+
const bytes2 = new Uint8Array(binaryString.length);
|
|
1332
1332
|
for (let i = 0; i < binaryString.length; i++) {
|
|
1333
|
-
|
|
1333
|
+
bytes2[i] = binaryString.charCodeAt(i);
|
|
1334
1334
|
}
|
|
1335
|
-
return
|
|
1335
|
+
return bytes2;
|
|
1336
1336
|
}
|
|
1337
|
-
function uint8ArrayToBase64(
|
|
1337
|
+
function uint8ArrayToBase64(bytes2) {
|
|
1338
1338
|
let binaryString = "";
|
|
1339
|
-
for (let i = 0; i <
|
|
1340
|
-
binaryString += String.fromCharCode(
|
|
1339
|
+
for (let i = 0; i < bytes2.length; i++) {
|
|
1340
|
+
binaryString += String.fromCharCode(bytes2[i]);
|
|
1341
1341
|
}
|
|
1342
1342
|
return btoa(binaryString);
|
|
1343
1343
|
}
|
|
@@ -1346,22 +1346,22 @@ function base64urlToUint8Array(base64url3) {
|
|
|
1346
1346
|
const padding = "=".repeat((4 - base644.length % 4) % 4);
|
|
1347
1347
|
return base64ToUint8Array(base644 + padding);
|
|
1348
1348
|
}
|
|
1349
|
-
function uint8ArrayToBase64url(
|
|
1350
|
-
return uint8ArrayToBase64(
|
|
1349
|
+
function uint8ArrayToBase64url(bytes2) {
|
|
1350
|
+
return uint8ArrayToBase64(bytes2).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1351
1351
|
}
|
|
1352
1352
|
function hexToUint8Array(hex3) {
|
|
1353
1353
|
const cleanHex = hex3.replace(/^0x/, "");
|
|
1354
1354
|
if (cleanHex.length % 2 !== 0) {
|
|
1355
1355
|
throw new Error("Invalid hex string length");
|
|
1356
1356
|
}
|
|
1357
|
-
const
|
|
1357
|
+
const bytes2 = new Uint8Array(cleanHex.length / 2);
|
|
1358
1358
|
for (let i = 0; i < cleanHex.length; i += 2) {
|
|
1359
|
-
|
|
1359
|
+
bytes2[i / 2] = Number.parseInt(cleanHex.slice(i, i + 2), 16);
|
|
1360
1360
|
}
|
|
1361
|
-
return
|
|
1361
|
+
return bytes2;
|
|
1362
1362
|
}
|
|
1363
|
-
function uint8ArrayToHex(
|
|
1364
|
-
return Array.from(
|
|
1363
|
+
function uint8ArrayToHex(bytes2) {
|
|
1364
|
+
return Array.from(bytes2).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1365
1365
|
}
|
|
1366
1366
|
var Class = class {
|
|
1367
1367
|
constructor(..._args) {
|
|
@@ -14893,17 +14893,17 @@ function assertSecretRefUse(scopes, config2) {
|
|
|
14893
14893
|
|
|
14894
14894
|
// ../core/src/encoding/base64url.ts
|
|
14895
14895
|
var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
14896
|
-
function base64urlEncode(
|
|
14896
|
+
function base64urlEncode(bytes2) {
|
|
14897
14897
|
let out = "";
|
|
14898
|
-
for (let i = 0; i <
|
|
14899
|
-
const a =
|
|
14900
|
-
const b =
|
|
14901
|
-
const c =
|
|
14898
|
+
for (let i = 0; i < bytes2.length; i += 3) {
|
|
14899
|
+
const a = bytes2[i] ?? 0;
|
|
14900
|
+
const b = bytes2[i + 1] ?? 0;
|
|
14901
|
+
const c = bytes2[i + 2] ?? 0;
|
|
14902
14902
|
const n = a << 16 | b << 8 | c;
|
|
14903
14903
|
out += ALPHABET[n >>> 18 & 63];
|
|
14904
14904
|
out += ALPHABET[n >>> 12 & 63];
|
|
14905
|
-
if (i + 1 <
|
|
14906
|
-
if (i + 2 <
|
|
14905
|
+
if (i + 1 < bytes2.length) out += ALPHABET[n >>> 6 & 63];
|
|
14906
|
+
if (i + 2 < bytes2.length) out += ALPHABET[n & 63];
|
|
14907
14907
|
}
|
|
14908
14908
|
return out;
|
|
14909
14909
|
}
|
|
@@ -14911,7 +14911,7 @@ function base64urlDecode(input) {
|
|
|
14911
14911
|
if (input.length % 4 === 1 || !/^[A-Za-z0-9_-]*$/.test(input)) {
|
|
14912
14912
|
throw new Error("base64urlDecode: malformed base64url input");
|
|
14913
14913
|
}
|
|
14914
|
-
const
|
|
14914
|
+
const bytes2 = [];
|
|
14915
14915
|
for (let i = 0; i < input.length; i += 4) {
|
|
14916
14916
|
const chunk = input.slice(i, i + 4);
|
|
14917
14917
|
const a = ALPHABET.indexOf(chunk[0] ?? "");
|
|
@@ -14919,11 +14919,11 @@ function base64urlDecode(input) {
|
|
|
14919
14919
|
const c = chunk.length >= 3 ? ALPHABET.indexOf(chunk[2] ?? "") : 0;
|
|
14920
14920
|
const d = chunk.length >= 4 ? ALPHABET.indexOf(chunk[3] ?? "") : 0;
|
|
14921
14921
|
const n = a << 18 | b << 12 | c << 6 | d;
|
|
14922
|
-
|
|
14923
|
-
if (chunk.length >= 3)
|
|
14924
|
-
if (chunk.length >= 4)
|
|
14922
|
+
bytes2.push(n >>> 16 & 255);
|
|
14923
|
+
if (chunk.length >= 3) bytes2.push(n >>> 8 & 255);
|
|
14924
|
+
if (chunk.length >= 4) bytes2.push(n & 255);
|
|
14925
14925
|
}
|
|
14926
|
-
return new Uint8Array(
|
|
14926
|
+
return new Uint8Array(bytes2);
|
|
14927
14927
|
}
|
|
14928
14928
|
|
|
14929
14929
|
// ../core/src/omit.ts
|
|
@@ -14942,8 +14942,8 @@ async function sha256Hex(text) {
|
|
|
14942
14942
|
return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
14943
14943
|
}
|
|
14944
14944
|
function generateSecret() {
|
|
14945
|
-
const
|
|
14946
|
-
return `${SECRET_PREFIX}${base64urlEncode(
|
|
14945
|
+
const bytes2 = crypto.getRandomValues(new Uint8Array(16));
|
|
14946
|
+
return `${SECRET_PREFIX}${base64urlEncode(bytes2)}`;
|
|
14947
14947
|
}
|
|
14948
14948
|
function normalizeExpiresAt(value) {
|
|
14949
14949
|
const parsed = ISO_TIMESTAMP.safeParse(value);
|
|
@@ -15000,10 +15000,10 @@ function clampLimit(limit) {
|
|
|
15000
15000
|
return Math.min(Math.max(1, limit), LIST_LIMIT_MAX);
|
|
15001
15001
|
}
|
|
15002
15002
|
var SKRegistryStore = class {
|
|
15003
|
+
store;
|
|
15003
15004
|
constructor(store) {
|
|
15004
15005
|
this.store = store;
|
|
15005
15006
|
}
|
|
15006
|
-
store;
|
|
15007
15007
|
async recordById(id) {
|
|
15008
15008
|
const hash2 = await this.store.get(KEY_SK_ID + id);
|
|
15009
15009
|
if (typeof hash2 !== "string") return null;
|
|
@@ -15115,6 +15115,7 @@ var OperationRegistry = class {
|
|
|
15115
15115
|
const schema = spec.inputSchema !== void 0 ? normalizeSchema(spec.inputSchema) : void 0;
|
|
15116
15116
|
const toolSpec = { name };
|
|
15117
15117
|
if (spec.description !== void 0) toolSpec.description = spec.description;
|
|
15118
|
+
if (spec.delivery !== void 0) toolSpec.delivery = spec.delivery;
|
|
15118
15119
|
if (spec.effect !== void 0) toolSpec.effect = spec.effect;
|
|
15119
15120
|
if (spec.confirm !== void 0) toolSpec.confirm = spec.confirm;
|
|
15120
15121
|
if (schema !== void 0) toolSpec.inputSchema = toJsonSchema(schema);
|
|
@@ -16617,6 +16618,661 @@ function createFederationModule(deps) {
|
|
|
16617
16618
|
return COMMANDS5.module(deps);
|
|
16618
16619
|
}
|
|
16619
16620
|
|
|
16621
|
+
// ../core/src/device/mailbox.ts
|
|
16622
|
+
var KEY_DEVICE_OPERATION = "deviceop:";
|
|
16623
|
+
var DEVICE_OPERATION_STATES = [
|
|
16624
|
+
"queued",
|
|
16625
|
+
"claimed",
|
|
16626
|
+
"succeeded",
|
|
16627
|
+
"rejected",
|
|
16628
|
+
"failed",
|
|
16629
|
+
"result_unknown",
|
|
16630
|
+
"cancelled",
|
|
16631
|
+
"expired"
|
|
16632
|
+
];
|
|
16633
|
+
var DEFAULT_TTL_SECONDS = 24 * 60 * 60;
|
|
16634
|
+
var MAX_TTL_SECONDS = 7 * 24 * 60 * 60;
|
|
16635
|
+
var DEFAULT_LEASE_SECONDS = 60;
|
|
16636
|
+
var DEFAULT_MAX_PAYLOAD_BYTES = 256 * 1024;
|
|
16637
|
+
var DEFAULT_MAX_PENDING_PER_DEVICE = 1e3;
|
|
16638
|
+
var DEFAULT_TERMINAL_RETENTION_SECONDS = 7 * 24 * 60 * 60;
|
|
16639
|
+
var MAX_CAS_ATTEMPTS = 8;
|
|
16640
|
+
var LIST_LIMIT_DEFAULT2 = 50;
|
|
16641
|
+
var LIST_LIMIT_MAX2 = 200;
|
|
16642
|
+
var HKDF_SALT = new TextEncoder().encode("tool-bridge:device-mailbox:v1");
|
|
16643
|
+
var HKDF_INFO = new TextEncoder().encode("aes-256-gcm:operation-payload-and-result:v1");
|
|
16644
|
+
function mailboxUnavailable(message) {
|
|
16645
|
+
return new TBError("unavailable", message, { retryable: false });
|
|
16646
|
+
}
|
|
16647
|
+
function finiteTimestamp(value) {
|
|
16648
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
16649
|
+
}
|
|
16650
|
+
function nonEmpty(value) {
|
|
16651
|
+
return typeof value === "string" && value !== "";
|
|
16652
|
+
}
|
|
16653
|
+
function positiveInteger(value, fallback, field) {
|
|
16654
|
+
const actual = value ?? fallback;
|
|
16655
|
+
if (!Number.isSafeInteger(actual) || actual < 1) {
|
|
16656
|
+
throw new TBError("invalid_argument", `${field} must be a positive integer`);
|
|
16657
|
+
}
|
|
16658
|
+
return actual;
|
|
16659
|
+
}
|
|
16660
|
+
function clampLimit3(value) {
|
|
16661
|
+
if (value === void 0) return LIST_LIMIT_DEFAULT2;
|
|
16662
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
16663
|
+
throw new TBError("invalid_argument", "limit must be a positive integer");
|
|
16664
|
+
}
|
|
16665
|
+
return Math.min(value, LIST_LIMIT_MAX2);
|
|
16666
|
+
}
|
|
16667
|
+
function isState(value) {
|
|
16668
|
+
return typeof value === "string" && DEVICE_OPERATION_STATES.includes(value);
|
|
16669
|
+
}
|
|
16670
|
+
function isTerminal(state) {
|
|
16671
|
+
return state !== "queued" && state !== "claimed";
|
|
16672
|
+
}
|
|
16673
|
+
function parseEncrypted(value) {
|
|
16674
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("invalid encrypted value");
|
|
16675
|
+
const raw = value;
|
|
16676
|
+
if (raw.v !== 1 || !nonEmpty(raw.iv) || !nonEmpty(raw.ciphertext)) {
|
|
16677
|
+
throw new Error("invalid encrypted value");
|
|
16678
|
+
}
|
|
16679
|
+
return { v: 1, iv: raw.iv, ciphertext: raw.ciphertext };
|
|
16680
|
+
}
|
|
16681
|
+
function parseRecord(value) {
|
|
16682
|
+
try {
|
|
16683
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error();
|
|
16684
|
+
const raw = value;
|
|
16685
|
+
if (raw.v !== 1 || !Number.isSafeInteger(raw.revision) || raw.revision < 1 || !nonEmpty(raw.operationId) || raw.commandId !== raw.operationId || !nonEmpty(raw.deviceId) || !nonEmpty(raw.deviceKeyId) || !nonEmpty(raw.mountPath) || !nonEmpty(raw.targetPath) || !nonEmpty(raw.path) || !nonEmpty(raw.callerKeyId) || !nonEmpty(raw.callerOwner) || !nonEmpty(raw.traceId) || !finiteTimestamp(raw.createdAt) || !finiteTimestamp(raw.updatedAt) || !finiteTimestamp(raw.expiresAt) || !isState(raw.state) || !Number.isSafeInteger(raw.attempt) || raw.attempt < 0 || typeof raw.executionMayHaveOccurred !== "boolean") throw new Error();
|
|
16686
|
+
if (raw.leaseId === void 0 !== (raw.leaseUntil === void 0)) throw new Error();
|
|
16687
|
+
if (raw.leaseId !== void 0 && (!nonEmpty(raw.leaseId) || !finiteTimestamp(raw.leaseUntil))) {
|
|
16688
|
+
throw new Error();
|
|
16689
|
+
}
|
|
16690
|
+
if (raw.cancelRequestedAt !== void 0 && !finiteTimestamp(raw.cancelRequestedAt)) throw new Error();
|
|
16691
|
+
if (raw.terminalAt !== void 0 && !finiteTimestamp(raw.terminalAt)) throw new Error();
|
|
16692
|
+
if (isTerminal(raw.state) && raw.terminalAt === void 0) throw new Error();
|
|
16693
|
+
return {
|
|
16694
|
+
v: 1,
|
|
16695
|
+
revision: raw.revision,
|
|
16696
|
+
operationId: raw.operationId,
|
|
16697
|
+
commandId: raw.commandId,
|
|
16698
|
+
deviceId: raw.deviceId,
|
|
16699
|
+
deviceKeyId: raw.deviceKeyId,
|
|
16700
|
+
mountPath: raw.mountPath,
|
|
16701
|
+
targetPath: raw.targetPath,
|
|
16702
|
+
path: raw.path,
|
|
16703
|
+
callerKeyId: raw.callerKeyId,
|
|
16704
|
+
callerOwner: raw.callerOwner,
|
|
16705
|
+
traceId: raw.traceId,
|
|
16706
|
+
createdAt: raw.createdAt,
|
|
16707
|
+
updatedAt: raw.updatedAt,
|
|
16708
|
+
expiresAt: raw.expiresAt,
|
|
16709
|
+
state: raw.state,
|
|
16710
|
+
attempt: raw.attempt,
|
|
16711
|
+
executionMayHaveOccurred: raw.executionMayHaveOccurred,
|
|
16712
|
+
payload: parseEncrypted(raw.payload),
|
|
16713
|
+
...raw.leaseId === void 0 ? {} : { leaseId: raw.leaseId, leaseUntil: raw.leaseUntil },
|
|
16714
|
+
...raw.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: raw.cancelRequestedAt },
|
|
16715
|
+
...raw.completedLeaseId === void 0 ? {} : { completedLeaseId: String(raw.completedLeaseId) },
|
|
16716
|
+
...raw.terminalAt === void 0 ? {} : { terminalAt: raw.terminalAt },
|
|
16717
|
+
...raw.terminalData === void 0 ? {} : { terminalData: parseEncrypted(raw.terminalData) },
|
|
16718
|
+
...raw.idempotencyFingerprint === void 0 ? {} : { idempotencyFingerprint: String(raw.idempotencyFingerprint) }
|
|
16719
|
+
};
|
|
16720
|
+
} catch {
|
|
16721
|
+
throw new TBError("internal", "device mailbox record is invalid", { retryable: false });
|
|
16722
|
+
}
|
|
16723
|
+
}
|
|
16724
|
+
function canonicalJson(value) {
|
|
16725
|
+
if (value === null) return "null";
|
|
16726
|
+
if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
|
|
16727
|
+
if (typeof value === "number") {
|
|
16728
|
+
if (!Number.isFinite(value)) throw new TBError("invalid_argument", "mailbox data must be valid JSON");
|
|
16729
|
+
return JSON.stringify(value);
|
|
16730
|
+
}
|
|
16731
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
16732
|
+
if (typeof value !== "object") {
|
|
16733
|
+
throw new TBError("invalid_argument", "mailbox data must be valid JSON");
|
|
16734
|
+
}
|
|
16735
|
+
const object2 = value;
|
|
16736
|
+
const keys = Object.keys(object2).sort();
|
|
16737
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(object2[key])}`).join(",")}}`;
|
|
16738
|
+
}
|
|
16739
|
+
function safeError(value) {
|
|
16740
|
+
if (typeof value !== "object" || value === null || typeof value.code !== "string" || typeof value.message !== "string" || typeof value.retryable !== "boolean") throw new TBError("invalid_argument", "completion error is invalid");
|
|
16741
|
+
return { code: value.code, message: value.message, retryable: value.retryable };
|
|
16742
|
+
}
|
|
16743
|
+
function normalizeCompletion(value) {
|
|
16744
|
+
if (value.outcome === "succeeded") {
|
|
16745
|
+
canonicalJson(value.result);
|
|
16746
|
+
return { outcome: "succeeded", result: value.result };
|
|
16747
|
+
}
|
|
16748
|
+
if (value.outcome === "rejected" || value.outcome === "failed") {
|
|
16749
|
+
return { outcome: value.outcome, error: safeError(value.error) };
|
|
16750
|
+
}
|
|
16751
|
+
return {
|
|
16752
|
+
outcome: "result_unknown",
|
|
16753
|
+
...value.error === void 0 ? {} : { error: safeError(value.error) }
|
|
16754
|
+
};
|
|
16755
|
+
}
|
|
16756
|
+
function bytes(value) {
|
|
16757
|
+
return new TextEncoder().encode(value).byteLength;
|
|
16758
|
+
}
|
|
16759
|
+
function randomId(randomBytes) {
|
|
16760
|
+
const value = randomBytes(18);
|
|
16761
|
+
if (!(value instanceof Uint8Array) || value.length !== 18) {
|
|
16762
|
+
throw mailboxUnavailable("device mailbox randomness is unavailable");
|
|
16763
|
+
}
|
|
16764
|
+
return `dop_${base64urlEncode(value)}`;
|
|
16765
|
+
}
|
|
16766
|
+
async function digestBytes(value) {
|
|
16767
|
+
return new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value)));
|
|
16768
|
+
}
|
|
16769
|
+
async function deterministicOperationId(binding) {
|
|
16770
|
+
return `dop_${base64urlEncode((await digestBytes(binding)).slice(0, 18))}`;
|
|
16771
|
+
}
|
|
16772
|
+
async function devicePrefix(deviceId) {
|
|
16773
|
+
return `${KEY_DEVICE_OPERATION}${await sha256Hex(deviceId)}:`;
|
|
16774
|
+
}
|
|
16775
|
+
async function stateKey(deviceId, operationId) {
|
|
16776
|
+
if (!/^dop_[A-Za-z0-9_-]{24}$/.test(operationId)) {
|
|
16777
|
+
throw new TBError("invalid_argument", "operationId is invalid");
|
|
16778
|
+
}
|
|
16779
|
+
return await devicePrefix(deviceId) + operationId;
|
|
16780
|
+
}
|
|
16781
|
+
var DeviceMailboxCipher = class {
|
|
16782
|
+
root;
|
|
16783
|
+
keyPromise;
|
|
16784
|
+
constructor(masterKey) {
|
|
16785
|
+
let decoded;
|
|
16786
|
+
try {
|
|
16787
|
+
decoded = base64urlDecode(masterKey);
|
|
16788
|
+
} catch {
|
|
16789
|
+
throw mailboxUnavailable("device mailbox encryption key is invalid");
|
|
16790
|
+
}
|
|
16791
|
+
if (decoded.length !== 32) {
|
|
16792
|
+
throw mailboxUnavailable("device mailbox encryption key is invalid");
|
|
16793
|
+
}
|
|
16794
|
+
this.root = decoded;
|
|
16795
|
+
}
|
|
16796
|
+
key() {
|
|
16797
|
+
this.keyPromise ??= (async () => {
|
|
16798
|
+
const rootKey = await crypto.subtle.importKey("raw", this.root, "HKDF", false, ["deriveKey"]);
|
|
16799
|
+
return await crypto.subtle.deriveKey(
|
|
16800
|
+
{ name: "HKDF", hash: "SHA-256", salt: HKDF_SALT, info: HKDF_INFO },
|
|
16801
|
+
rootKey,
|
|
16802
|
+
{ name: "AES-GCM", length: 256 },
|
|
16803
|
+
false,
|
|
16804
|
+
["encrypt", "decrypt"]
|
|
16805
|
+
);
|
|
16806
|
+
})();
|
|
16807
|
+
return this.keyPromise;
|
|
16808
|
+
}
|
|
16809
|
+
async encrypt(operationId, field, value) {
|
|
16810
|
+
const plaintext = canonicalJson(value);
|
|
16811
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
16812
|
+
const additionalData = new TextEncoder().encode(`tool-bridge:device-mailbox:v1:${operationId}:${field}`);
|
|
16813
|
+
const ciphertext = await crypto.subtle.encrypt(
|
|
16814
|
+
{ name: "AES-GCM", iv, additionalData },
|
|
16815
|
+
await this.key(),
|
|
16816
|
+
new TextEncoder().encode(plaintext)
|
|
16817
|
+
);
|
|
16818
|
+
return {
|
|
16819
|
+
v: 1,
|
|
16820
|
+
iv: base64urlEncode(iv),
|
|
16821
|
+
ciphertext: base64urlEncode(new Uint8Array(ciphertext))
|
|
16822
|
+
};
|
|
16823
|
+
}
|
|
16824
|
+
async decrypt(operationId, field, value) {
|
|
16825
|
+
try {
|
|
16826
|
+
const iv = base64urlDecode(value.iv);
|
|
16827
|
+
const ciphertext = base64urlDecode(value.ciphertext);
|
|
16828
|
+
if (iv.length !== 12) throw new Error("invalid iv");
|
|
16829
|
+
const additionalData = new TextEncoder().encode(`tool-bridge:device-mailbox:v1:${operationId}:${field}`);
|
|
16830
|
+
const plaintext = await crypto.subtle.decrypt(
|
|
16831
|
+
{ name: "AES-GCM", iv, additionalData },
|
|
16832
|
+
await this.key(),
|
|
16833
|
+
ciphertext
|
|
16834
|
+
);
|
|
16835
|
+
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
16836
|
+
} catch {
|
|
16837
|
+
throw new TBError("internal", "device mailbox data cannot be decrypted", { retryable: false });
|
|
16838
|
+
}
|
|
16839
|
+
}
|
|
16840
|
+
};
|
|
16841
|
+
var DeviceMailboxService = class {
|
|
16842
|
+
cas;
|
|
16843
|
+
cipher;
|
|
16844
|
+
defaultTtlSeconds;
|
|
16845
|
+
leaseSeconds;
|
|
16846
|
+
maxPayloadBytes;
|
|
16847
|
+
maxPendingPerDevice;
|
|
16848
|
+
maxTtlSeconds;
|
|
16849
|
+
now;
|
|
16850
|
+
randomBytes;
|
|
16851
|
+
state;
|
|
16852
|
+
terminalRetentionSeconds;
|
|
16853
|
+
constructor(state, encryptionRoot, opts = {}) {
|
|
16854
|
+
if (state.compareAndSwap === void 0) {
|
|
16855
|
+
throw mailboxUnavailable("device mailbox requires StateStore.compareAndSwap");
|
|
16856
|
+
}
|
|
16857
|
+
if (encryptionRoot === void 0) {
|
|
16858
|
+
throw mailboxUnavailable("device mailbox requires TB_SECRET_ENCRYPTION_KEY");
|
|
16859
|
+
}
|
|
16860
|
+
this.cas = state.compareAndSwap.bind(state);
|
|
16861
|
+
this.state = state;
|
|
16862
|
+
this.cipher = new DeviceMailboxCipher(encryptionRoot);
|
|
16863
|
+
this.defaultTtlSeconds = positiveInteger(
|
|
16864
|
+
opts.defaultTtlSeconds,
|
|
16865
|
+
DEFAULT_TTL_SECONDS,
|
|
16866
|
+
"defaultTtlSeconds"
|
|
16867
|
+
);
|
|
16868
|
+
this.maxTtlSeconds = positiveInteger(opts.maxTtlSeconds, MAX_TTL_SECONDS, "maxTtlSeconds");
|
|
16869
|
+
if (this.defaultTtlSeconds > this.maxTtlSeconds) {
|
|
16870
|
+
throw new TBError("invalid_argument", "defaultTtlSeconds cannot exceed maxTtlSeconds");
|
|
16871
|
+
}
|
|
16872
|
+
this.leaseSeconds = positiveInteger(opts.leaseSeconds, DEFAULT_LEASE_SECONDS, "leaseSeconds");
|
|
16873
|
+
this.maxPayloadBytes = positiveInteger(
|
|
16874
|
+
opts.maxPayloadBytes,
|
|
16875
|
+
DEFAULT_MAX_PAYLOAD_BYTES,
|
|
16876
|
+
"maxPayloadBytes"
|
|
16877
|
+
);
|
|
16878
|
+
this.maxPendingPerDevice = positiveInteger(
|
|
16879
|
+
opts.maxPendingPerDevice,
|
|
16880
|
+
DEFAULT_MAX_PENDING_PER_DEVICE,
|
|
16881
|
+
"maxPendingPerDevice"
|
|
16882
|
+
);
|
|
16883
|
+
this.terminalRetentionSeconds = positiveInteger(
|
|
16884
|
+
opts.terminalRetentionSeconds,
|
|
16885
|
+
DEFAULT_TERMINAL_RETENTION_SECONDS,
|
|
16886
|
+
"terminalRetentionSeconds"
|
|
16887
|
+
);
|
|
16888
|
+
this.now = opts.now ?? (() => Date.now());
|
|
16889
|
+
this.randomBytes = opts.randomBytes ?? ((length) => crypto.getRandomValues(new Uint8Array(length)));
|
|
16890
|
+
}
|
|
16891
|
+
nowIso() {
|
|
16892
|
+
return new Date(this.now()).toISOString();
|
|
16893
|
+
}
|
|
16894
|
+
async read(deviceId, operationId) {
|
|
16895
|
+
const key = await stateKey(deviceId, operationId);
|
|
16896
|
+
const value = await this.state.get(key);
|
|
16897
|
+
if (value === null) throw TBError.notFound("device operation not found");
|
|
16898
|
+
const record2 = parseRecord(value);
|
|
16899
|
+
if (record2.deviceId !== deviceId || record2.operationId !== operationId) {
|
|
16900
|
+
throw new TBError("internal", "device mailbox record identity mismatch", { retryable: false });
|
|
16901
|
+
}
|
|
16902
|
+
return { key, record: record2 };
|
|
16903
|
+
}
|
|
16904
|
+
summary(record2) {
|
|
16905
|
+
return {
|
|
16906
|
+
operationId: record2.operationId,
|
|
16907
|
+
commandId: record2.commandId,
|
|
16908
|
+
deviceId: record2.deviceId,
|
|
16909
|
+
mountPath: record2.mountPath,
|
|
16910
|
+
targetPath: record2.targetPath,
|
|
16911
|
+
caller: { keyId: record2.callerKeyId, owner: record2.callerOwner },
|
|
16912
|
+
traceId: record2.traceId,
|
|
16913
|
+
createdAt: record2.createdAt,
|
|
16914
|
+
updatedAt: record2.updatedAt,
|
|
16915
|
+
expiresAt: record2.expiresAt,
|
|
16916
|
+
state: record2.state,
|
|
16917
|
+
attempt: record2.attempt,
|
|
16918
|
+
executionMayHaveOccurred: record2.executionMayHaveOccurred,
|
|
16919
|
+
...record2.leaseUntil === void 0 ? {} : { leaseUntil: record2.leaseUntil },
|
|
16920
|
+
...record2.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: record2.cancelRequestedAt },
|
|
16921
|
+
...record2.terminalAt === void 0 ? {} : { terminalAt: record2.terminalAt }
|
|
16922
|
+
};
|
|
16923
|
+
}
|
|
16924
|
+
async detail(record2) {
|
|
16925
|
+
const summary = this.summary(record2);
|
|
16926
|
+
if (record2.terminalData === void 0) return summary;
|
|
16927
|
+
const terminal = await this.cipher.decrypt(
|
|
16928
|
+
record2.operationId,
|
|
16929
|
+
"terminal",
|
|
16930
|
+
record2.terminalData
|
|
16931
|
+
);
|
|
16932
|
+
if (record2.state === "succeeded") return { ...summary, result: terminal.result };
|
|
16933
|
+
const error51 = terminal.error;
|
|
16934
|
+
if (error51 === void 0) return summary;
|
|
16935
|
+
return { ...summary, error: safeError(error51) };
|
|
16936
|
+
}
|
|
16937
|
+
async expireRecord(key, record2) {
|
|
16938
|
+
let current = record2;
|
|
16939
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
|
|
16940
|
+
if (isTerminal(current.state) || Date.parse(current.expiresAt) > this.now()) return current;
|
|
16941
|
+
const now = this.nowIso();
|
|
16942
|
+
const next = {
|
|
16943
|
+
...current,
|
|
16944
|
+
revision: current.revision + 1,
|
|
16945
|
+
state: "expired",
|
|
16946
|
+
updatedAt: now,
|
|
16947
|
+
terminalAt: now,
|
|
16948
|
+
executionMayHaveOccurred: current.state === "claimed"
|
|
16949
|
+
};
|
|
16950
|
+
if (await this.cas(key, current.revision, next)) return next;
|
|
16951
|
+
const winner = await this.state.get(key);
|
|
16952
|
+
if (winner === null) throw TBError.notFound("device operation not found");
|
|
16953
|
+
current = parseRecord(winner);
|
|
16954
|
+
}
|
|
16955
|
+
throw new TBError("unavailable", "device operation expiry is busy", { retryable: true });
|
|
16956
|
+
}
|
|
16957
|
+
async enforcePendingCap(deviceId) {
|
|
16958
|
+
const prefix = await devicePrefix(deviceId);
|
|
16959
|
+
let cursor;
|
|
16960
|
+
let pending = 0;
|
|
16961
|
+
do {
|
|
16962
|
+
const page = await this.state.list(prefix, {
|
|
16963
|
+
limit: LIST_LIMIT_MAX2,
|
|
16964
|
+
...cursor === void 0 ? {} : { cursor }
|
|
16965
|
+
});
|
|
16966
|
+
for (const item of page.items) {
|
|
16967
|
+
let record2 = parseRecord(item.value);
|
|
16968
|
+
if (record2.deviceId !== deviceId) continue;
|
|
16969
|
+
record2 = await this.expireRecord(item.key, record2);
|
|
16970
|
+
if (!isTerminal(record2.state)) pending++;
|
|
16971
|
+
if (pending >= this.maxPendingPerDevice) {
|
|
16972
|
+
throw new TBError("rate_limited", "device mailbox pending limit reached", {
|
|
16973
|
+
retryable: true
|
|
16974
|
+
});
|
|
16975
|
+
}
|
|
16976
|
+
}
|
|
16977
|
+
cursor = page.cursor;
|
|
16978
|
+
} while (cursor !== void 0);
|
|
16979
|
+
}
|
|
16980
|
+
async enqueue(input) {
|
|
16981
|
+
const ttlSeconds = input.ttlSeconds ?? this.defaultTtlSeconds;
|
|
16982
|
+
if (!Number.isSafeInteger(ttlSeconds) || ttlSeconds < 1 || ttlSeconds > this.maxTtlSeconds) {
|
|
16983
|
+
throw new TBError("invalid_argument", `ttlSeconds must be between 1 and ${this.maxTtlSeconds}`);
|
|
16984
|
+
}
|
|
16985
|
+
const payloadText = canonicalJson({ arguments: input.arguments });
|
|
16986
|
+
if (bytes(payloadText) > this.maxPayloadBytes) {
|
|
16987
|
+
throw new TBError("rate_limited", "device mailbox payload is too large", { retryable: false });
|
|
16988
|
+
}
|
|
16989
|
+
if (input.idempotencyKey !== void 0 && (input.idempotencyKey.length < 1 || input.idempotencyKey.length > 255 || /[\r\n\0]/.test(input.idempotencyKey))) throw new TBError("invalid_argument", "idempotency key is invalid");
|
|
16990
|
+
const binding = input.idempotencyKey === void 0 ? void 0 : canonicalJson({
|
|
16991
|
+
callerOwner: input.caller.owner,
|
|
16992
|
+
deviceId: input.deviceId,
|
|
16993
|
+
targetPath: input.targetPath,
|
|
16994
|
+
idempotencyKey: input.idempotencyKey
|
|
16995
|
+
});
|
|
16996
|
+
const operationId = binding === void 0 ? randomId(this.randomBytes) : await deterministicOperationId(binding);
|
|
16997
|
+
const fingerprint = binding === void 0 ? void 0 : await sha256Hex(canonicalJson({
|
|
16998
|
+
arguments: input.arguments,
|
|
16999
|
+
deviceKeyId: input.deviceKeyId,
|
|
17000
|
+
path: input.path,
|
|
17001
|
+
ttlSeconds
|
|
17002
|
+
}));
|
|
17003
|
+
const key = await stateKey(input.deviceId, operationId);
|
|
17004
|
+
if (binding !== void 0) {
|
|
17005
|
+
const existing2 = await this.state.get(key);
|
|
17006
|
+
if (existing2 !== null) {
|
|
17007
|
+
const record3 = parseRecord(existing2);
|
|
17008
|
+
if (record3.callerOwner !== input.caller.owner || record3.deviceId !== input.deviceId || record3.targetPath !== input.targetPath || record3.idempotencyFingerprint !== fingerprint) throw new TBError("conflict", "idempotency key is bound to another operation");
|
|
17009
|
+
return await this.detail(record3);
|
|
17010
|
+
}
|
|
17011
|
+
}
|
|
17012
|
+
await this.enforcePendingCap(input.deviceId);
|
|
17013
|
+
const now = this.nowIso();
|
|
17014
|
+
const record2 = {
|
|
17015
|
+
v: 1,
|
|
17016
|
+
revision: 1,
|
|
17017
|
+
operationId,
|
|
17018
|
+
commandId: operationId,
|
|
17019
|
+
deviceId: input.deviceId,
|
|
17020
|
+
deviceKeyId: input.deviceKeyId,
|
|
17021
|
+
mountPath: input.mountPath,
|
|
17022
|
+
targetPath: input.targetPath,
|
|
17023
|
+
path: input.path,
|
|
17024
|
+
callerKeyId: input.caller.keyId,
|
|
17025
|
+
callerOwner: input.caller.owner,
|
|
17026
|
+
traceId: input.traceId,
|
|
17027
|
+
createdAt: now,
|
|
17028
|
+
updatedAt: now,
|
|
17029
|
+
expiresAt: new Date(this.now() + ttlSeconds * 1e3).toISOString(),
|
|
17030
|
+
state: "queued",
|
|
17031
|
+
attempt: 0,
|
|
17032
|
+
executionMayHaveOccurred: false,
|
|
17033
|
+
payload: await this.cipher.encrypt(operationId, "payload", { arguments: input.arguments }),
|
|
17034
|
+
...fingerprint === void 0 ? {} : { idempotencyFingerprint: fingerprint }
|
|
17035
|
+
};
|
|
17036
|
+
if (await this.cas(key, null, record2)) return await this.detail(record2);
|
|
17037
|
+
if (binding === void 0) {
|
|
17038
|
+
throw new TBError("conflict", "device operation id collision", { retryable: true });
|
|
17039
|
+
}
|
|
17040
|
+
const winner = await this.state.get(key);
|
|
17041
|
+
if (winner === null) throw new TBError("conflict", "device operation enqueue conflicted");
|
|
17042
|
+
const existing = parseRecord(winner);
|
|
17043
|
+
if (existing.idempotencyFingerprint !== fingerprint) {
|
|
17044
|
+
throw new TBError("conflict", "idempotency key is bound to another operation");
|
|
17045
|
+
}
|
|
17046
|
+
return await this.detail(existing);
|
|
17047
|
+
}
|
|
17048
|
+
async get(deviceId, operationId) {
|
|
17049
|
+
const { key, record: record2 } = await this.read(deviceId, operationId);
|
|
17050
|
+
return await this.detail(await this.expireRecord(key, record2));
|
|
17051
|
+
}
|
|
17052
|
+
async list(input) {
|
|
17053
|
+
const limit = clampLimit3(input.limit);
|
|
17054
|
+
const states = input.states === void 0 ? void 0 : new Set(input.states);
|
|
17055
|
+
if (states !== void 0 && [...states].some((state) => !isState(state))) {
|
|
17056
|
+
throw new TBError("invalid_argument", "states contains an invalid operation state");
|
|
17057
|
+
}
|
|
17058
|
+
const page = await this.state.list(await devicePrefix(input.deviceId), {
|
|
17059
|
+
limit,
|
|
17060
|
+
...input.cursor === void 0 ? {} : { cursor: input.cursor }
|
|
17061
|
+
});
|
|
17062
|
+
const items = [];
|
|
17063
|
+
for (const item of page.items) {
|
|
17064
|
+
let record2 = parseRecord(item.value);
|
|
17065
|
+
if (record2.deviceId !== input.deviceId) continue;
|
|
17066
|
+
record2 = await this.expireRecord(item.key, record2);
|
|
17067
|
+
if (states !== void 0 && !states.has(record2.state)) continue;
|
|
17068
|
+
items.push(this.summary(record2));
|
|
17069
|
+
}
|
|
17070
|
+
return { items, ...page.cursor === void 0 ? {} : { cursor: page.cursor } };
|
|
17071
|
+
}
|
|
17072
|
+
async claim(input) {
|
|
17073
|
+
const serverNow = this.nowIso();
|
|
17074
|
+
const page = await this.state.list(await devicePrefix(input.deviceId), {
|
|
17075
|
+
limit: clampLimit3(input.limit),
|
|
17076
|
+
...input.cursor === void 0 ? {} : { cursor: input.cursor }
|
|
17077
|
+
});
|
|
17078
|
+
for (const item of page.items) {
|
|
17079
|
+
let record2 = parseRecord(item.value);
|
|
17080
|
+
if (record2.deviceId !== input.deviceId || record2.deviceKeyId !== input.deviceKeyId) continue;
|
|
17081
|
+
record2 = await this.expireRecord(item.key, record2);
|
|
17082
|
+
const reclaimable = record2.state === "claimed" && record2.leaseUntil !== void 0 && Date.parse(record2.leaseUntil) <= this.now();
|
|
17083
|
+
if (record2.state !== "queued" && !reclaimable) continue;
|
|
17084
|
+
await input.authorize?.({
|
|
17085
|
+
deviceId: record2.deviceId,
|
|
17086
|
+
deviceKeyId: record2.deviceKeyId,
|
|
17087
|
+
mountPath: record2.mountPath,
|
|
17088
|
+
targetPath: record2.targetPath
|
|
17089
|
+
});
|
|
17090
|
+
const leaseId = randomId(this.randomBytes);
|
|
17091
|
+
const leaseUntil = new Date(Math.min(
|
|
17092
|
+
this.now() + this.leaseSeconds * 1e3,
|
|
17093
|
+
Date.parse(record2.expiresAt)
|
|
17094
|
+
)).toISOString();
|
|
17095
|
+
const next = {
|
|
17096
|
+
...record2,
|
|
17097
|
+
revision: record2.revision + 1,
|
|
17098
|
+
state: "claimed",
|
|
17099
|
+
attempt: record2.attempt + 1,
|
|
17100
|
+
leaseId,
|
|
17101
|
+
leaseUntil,
|
|
17102
|
+
updatedAt: serverNow
|
|
17103
|
+
};
|
|
17104
|
+
if (!await this.cas(item.key, record2.revision, next)) continue;
|
|
17105
|
+
const payload = await this.cipher.decrypt(
|
|
17106
|
+
record2.operationId,
|
|
17107
|
+
"payload",
|
|
17108
|
+
record2.payload
|
|
17109
|
+
);
|
|
17110
|
+
if (typeof payload !== "object" || payload === null || typeof payload.arguments !== "object" || payload.arguments === null || Array.isArray(payload.arguments)) throw new TBError("internal", "device mailbox payload is invalid", { retryable: false });
|
|
17111
|
+
return {
|
|
17112
|
+
serverNow,
|
|
17113
|
+
...page.cursor === void 0 ? {} : { cursor: page.cursor },
|
|
17114
|
+
operation: {
|
|
17115
|
+
operationId: next.operationId,
|
|
17116
|
+
commandId: next.commandId,
|
|
17117
|
+
targetPath: next.targetPath,
|
|
17118
|
+
path: next.path,
|
|
17119
|
+
arguments: payload.arguments,
|
|
17120
|
+
caller: { keyId: next.callerKeyId, owner: next.callerOwner },
|
|
17121
|
+
traceId: next.traceId,
|
|
17122
|
+
createdAt: next.createdAt,
|
|
17123
|
+
expiresAt: next.expiresAt,
|
|
17124
|
+
attempt: next.attempt,
|
|
17125
|
+
leaseId,
|
|
17126
|
+
leaseUntil,
|
|
17127
|
+
...next.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: next.cancelRequestedAt }
|
|
17128
|
+
}
|
|
17129
|
+
};
|
|
17130
|
+
}
|
|
17131
|
+
return {
|
|
17132
|
+
serverNow,
|
|
17133
|
+
...page.cursor === void 0 ? {} : { cursor: page.cursor }
|
|
17134
|
+
};
|
|
17135
|
+
}
|
|
17136
|
+
async activeLease(input) {
|
|
17137
|
+
const current = await this.read(input.deviceId, input.operationId);
|
|
17138
|
+
const record2 = await this.expireRecord(current.key, current.record);
|
|
17139
|
+
if (record2.deviceKeyId !== input.deviceKeyId || record2.state !== "claimed" || record2.leaseId !== input.leaseId || record2.leaseUntil === void 0 || Date.parse(record2.leaseUntil) <= this.now()) throw new TBError("conflict", "device operation lease is no longer active");
|
|
17140
|
+
await input.authorize?.({
|
|
17141
|
+
deviceId: record2.deviceId,
|
|
17142
|
+
deviceKeyId: record2.deviceKeyId,
|
|
17143
|
+
mountPath: record2.mountPath,
|
|
17144
|
+
targetPath: record2.targetPath
|
|
17145
|
+
});
|
|
17146
|
+
return { key: current.key, record: record2 };
|
|
17147
|
+
}
|
|
17148
|
+
async renew(input) {
|
|
17149
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
|
|
17150
|
+
const { key, record: record2 } = await this.activeLease(input);
|
|
17151
|
+
const serverNow = this.nowIso();
|
|
17152
|
+
const leaseUntil = new Date(Math.min(
|
|
17153
|
+
this.now() + this.leaseSeconds * 1e3,
|
|
17154
|
+
Date.parse(record2.expiresAt)
|
|
17155
|
+
)).toISOString();
|
|
17156
|
+
const next = {
|
|
17157
|
+
...record2,
|
|
17158
|
+
revision: record2.revision + 1,
|
|
17159
|
+
leaseUntil,
|
|
17160
|
+
updatedAt: serverNow
|
|
17161
|
+
};
|
|
17162
|
+
if (await this.cas(key, record2.revision, next)) {
|
|
17163
|
+
return {
|
|
17164
|
+
serverNow,
|
|
17165
|
+
leaseUntil,
|
|
17166
|
+
...next.cancelRequestedAt === void 0 ? {} : { cancelRequestedAt: next.cancelRequestedAt }
|
|
17167
|
+
};
|
|
17168
|
+
}
|
|
17169
|
+
}
|
|
17170
|
+
throw new TBError("unavailable", "device operation lease is busy", { retryable: true });
|
|
17171
|
+
}
|
|
17172
|
+
async complete(input, completionInput) {
|
|
17173
|
+
const completion = normalizeCompletion(completionInput);
|
|
17174
|
+
const terminalData = completion.outcome === "succeeded" ? { result: completion.result } : completion.error === void 0 ? {} : { error: completion.error };
|
|
17175
|
+
if (bytes(canonicalJson(terminalData)) > this.maxPayloadBytes) {
|
|
17176
|
+
throw new TBError("rate_limited", "device mailbox terminal payload is too large", {
|
|
17177
|
+
retryable: false
|
|
17178
|
+
});
|
|
17179
|
+
}
|
|
17180
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
|
|
17181
|
+
const current = await this.read(input.deviceId, input.operationId);
|
|
17182
|
+
let record2 = await this.expireRecord(current.key, current.record);
|
|
17183
|
+
if (record2.deviceKeyId !== input.deviceKeyId) {
|
|
17184
|
+
throw new TBError("conflict", "device operation credential does not match");
|
|
17185
|
+
}
|
|
17186
|
+
await input.authorize?.({
|
|
17187
|
+
deviceId: record2.deviceId,
|
|
17188
|
+
deviceKeyId: record2.deviceKeyId,
|
|
17189
|
+
mountPath: record2.mountPath,
|
|
17190
|
+
targetPath: record2.targetPath
|
|
17191
|
+
});
|
|
17192
|
+
if (isTerminal(record2.state)) {
|
|
17193
|
+
if (record2.completedLeaseId !== input.leaseId || record2.state !== completion.outcome || record2.terminalData === void 0) throw new TBError("conflict", "device operation is already terminal");
|
|
17194
|
+
const existing = await this.cipher.decrypt(
|
|
17195
|
+
record2.operationId,
|
|
17196
|
+
"terminal",
|
|
17197
|
+
record2.terminalData
|
|
17198
|
+
);
|
|
17199
|
+
const requested = completion.outcome === "succeeded" ? { result: completion.result } : completion.error === void 0 ? {} : { error: completion.error };
|
|
17200
|
+
if (canonicalJson(existing) !== canonicalJson(requested)) {
|
|
17201
|
+
throw new TBError("conflict", "device operation completion differs from terminal result");
|
|
17202
|
+
}
|
|
17203
|
+
return await this.detail(record2);
|
|
17204
|
+
}
|
|
17205
|
+
const active = await this.activeLease(input);
|
|
17206
|
+
record2 = active.record;
|
|
17207
|
+
const now = this.nowIso();
|
|
17208
|
+
const next = {
|
|
17209
|
+
...record2,
|
|
17210
|
+
revision: record2.revision + 1,
|
|
17211
|
+
state: completion.outcome,
|
|
17212
|
+
terminalAt: now,
|
|
17213
|
+
terminalData: await this.cipher.encrypt(record2.operationId, "terminal", terminalData),
|
|
17214
|
+
completedLeaseId: input.leaseId,
|
|
17215
|
+
updatedAt: now
|
|
17216
|
+
};
|
|
17217
|
+
if (await this.cas(active.key, record2.revision, next)) return await this.detail(next);
|
|
17218
|
+
}
|
|
17219
|
+
throw new TBError("unavailable", "device operation completion is busy", { retryable: true });
|
|
17220
|
+
}
|
|
17221
|
+
async cancel(deviceId, operationId) {
|
|
17222
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {
|
|
17223
|
+
const current = await this.read(deviceId, operationId);
|
|
17224
|
+
const record2 = await this.expireRecord(current.key, current.record);
|
|
17225
|
+
if (isTerminal(record2.state) || record2.cancelRequestedAt !== void 0) {
|
|
17226
|
+
return await this.detail(record2);
|
|
17227
|
+
}
|
|
17228
|
+
const now = this.nowIso();
|
|
17229
|
+
const next = record2.state === "queued" ? {
|
|
17230
|
+
...record2,
|
|
17231
|
+
revision: record2.revision + 1,
|
|
17232
|
+
state: "cancelled",
|
|
17233
|
+
cancelRequestedAt: now,
|
|
17234
|
+
terminalAt: now,
|
|
17235
|
+
updatedAt: now
|
|
17236
|
+
} : {
|
|
17237
|
+
...record2,
|
|
17238
|
+
revision: record2.revision + 1,
|
|
17239
|
+
cancelRequestedAt: now,
|
|
17240
|
+
updatedAt: now
|
|
17241
|
+
};
|
|
17242
|
+
if (await this.cas(current.key, record2.revision, next)) return await this.detail(next);
|
|
17243
|
+
}
|
|
17244
|
+
throw new TBError("unavailable", "device operation cancellation is busy", { retryable: true });
|
|
17245
|
+
}
|
|
17246
|
+
async cleanup(opts = {}) {
|
|
17247
|
+
const page = await this.state.list(KEY_DEVICE_OPERATION, {
|
|
17248
|
+
limit: clampLimit3(opts.limit),
|
|
17249
|
+
...opts.cursor === void 0 ? {} : { cursor: opts.cursor }
|
|
17250
|
+
});
|
|
17251
|
+
let deleted = 0;
|
|
17252
|
+
let expired = 0;
|
|
17253
|
+
for (const item of page.items) {
|
|
17254
|
+
let record2;
|
|
17255
|
+
try {
|
|
17256
|
+
record2 = parseRecord(item.value);
|
|
17257
|
+
} catch {
|
|
17258
|
+
continue;
|
|
17259
|
+
}
|
|
17260
|
+
if (!isTerminal(record2.state) && Date.parse(record2.expiresAt) <= this.now()) {
|
|
17261
|
+
const next = await this.expireRecord(item.key, record2);
|
|
17262
|
+
if (next.state === "expired") expired++;
|
|
17263
|
+
record2 = next;
|
|
17264
|
+
}
|
|
17265
|
+
if (isTerminal(record2.state) && record2.terminalAt !== void 0 && Date.parse(record2.terminalAt) + this.terminalRetentionSeconds * 1e3 <= this.now() && await this.cas(item.key, record2.revision, null)) deleted++;
|
|
17266
|
+
}
|
|
17267
|
+
return {
|
|
17268
|
+
scanned: page.items.length,
|
|
17269
|
+
expired,
|
|
17270
|
+
deleted,
|
|
17271
|
+
...page.cursor === void 0 ? {} : { cursor: page.cursor }
|
|
17272
|
+
};
|
|
17273
|
+
}
|
|
17274
|
+
};
|
|
17275
|
+
|
|
16620
17276
|
// ../core/src/protocol/errorWire.ts
|
|
16621
17277
|
var tbErrorCodeSchema = external_exports.enum(TB_ERROR_CODES);
|
|
16622
17278
|
var tbErrorBodySchema = external_exports.object({
|
|
@@ -16663,6 +17319,7 @@ var helpChildSchema = external_exports.object({
|
|
|
16663
17319
|
});
|
|
16664
17320
|
var helpCommandSchema = external_exports.object({
|
|
16665
17321
|
confirm: external_exports.boolean().optional(),
|
|
17322
|
+
delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
|
|
16666
17323
|
effect: external_exports.string().optional(),
|
|
16667
17324
|
h: external_exports.string().optional(),
|
|
16668
17325
|
inputSchema: external_exports.unknown().optional(),
|
|
@@ -16696,6 +17353,7 @@ var treeJsonSchema = external_exports.lazy(() => external_exports.object({
|
|
|
16696
17353
|
}));
|
|
16697
17354
|
var toolSpecSchema = external_exports.object({
|
|
16698
17355
|
confirm: external_exports.boolean().optional(),
|
|
17356
|
+
delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
|
|
16699
17357
|
description: external_exports.string().optional(),
|
|
16700
17358
|
effect: external_exports.string().optional(),
|
|
16701
17359
|
inputSchema: external_exports.unknown().optional(),
|
|
@@ -16733,6 +17391,12 @@ var toolSearchItemSchema = external_exports.strictObject({
|
|
|
16733
17391
|
source: toolSearchSourceSchema.optional(),
|
|
16734
17392
|
tool: toolSpecSchema
|
|
16735
17393
|
});
|
|
17394
|
+
function pageSchema(itemSchema) {
|
|
17395
|
+
return external_exports.object({
|
|
17396
|
+
cursor: external_exports.string().optional(),
|
|
17397
|
+
items: external_exports.array(itemSchema)
|
|
17398
|
+
});
|
|
17399
|
+
}
|
|
16736
17400
|
var toolSearchPageSchema = external_exports.strictObject({
|
|
16737
17401
|
cursor: external_exports.string().optional(),
|
|
16738
17402
|
items: external_exports.array(toolSearchItemSchema),
|
|
@@ -16754,10 +17418,115 @@ var toolSearchRequestSchema = external_exports.strictObject({
|
|
|
16754
17418
|
}).optional(),
|
|
16755
17419
|
query: external_exports.string().trim().min(1)
|
|
16756
17420
|
});
|
|
17421
|
+
var deviceOperationStateSchema = external_exports.enum(
|
|
17422
|
+
DEVICE_OPERATION_STATES
|
|
17423
|
+
);
|
|
17424
|
+
var deviceOperationCallerSchema = external_exports.object({
|
|
17425
|
+
keyId: external_exports.string().min(1),
|
|
17426
|
+
owner: external_exports.string().min(1)
|
|
17427
|
+
});
|
|
17428
|
+
var deviceOperationSummaryShape = {
|
|
17429
|
+
attempt: external_exports.number().int().nonnegative(),
|
|
17430
|
+
caller: deviceOperationCallerSchema,
|
|
17431
|
+
cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
|
|
17432
|
+
commandId: external_exports.string().min(1),
|
|
17433
|
+
createdAt: external_exports.iso.datetime({ offset: true }),
|
|
17434
|
+
deviceId: external_exports.string().min(1),
|
|
17435
|
+
executionMayHaveOccurred: external_exports.boolean(),
|
|
17436
|
+
expiresAt: external_exports.iso.datetime({ offset: true }),
|
|
17437
|
+
leaseUntil: external_exports.iso.datetime({ offset: true }).optional(),
|
|
17438
|
+
mountPath: external_exports.string().min(1),
|
|
17439
|
+
operationId: external_exports.string().min(1),
|
|
17440
|
+
state: deviceOperationStateSchema,
|
|
17441
|
+
targetPath: external_exports.string().min(1),
|
|
17442
|
+
terminalAt: external_exports.iso.datetime({ offset: true }).optional(),
|
|
17443
|
+
traceId: external_exports.string().min(1),
|
|
17444
|
+
updatedAt: external_exports.iso.datetime({ offset: true })
|
|
17445
|
+
};
|
|
17446
|
+
var deviceOperationSummarySchema = external_exports.object(
|
|
17447
|
+
deviceOperationSummaryShape
|
|
17448
|
+
);
|
|
17449
|
+
var deviceOperationDetailSchema = external_exports.object({
|
|
17450
|
+
...deviceOperationSummaryShape,
|
|
17451
|
+
error: tbErrorBodySchema.optional(),
|
|
17452
|
+
result: external_exports.json().optional()
|
|
17453
|
+
});
|
|
17454
|
+
var deviceOperationListRequestSchema = external_exports.strictObject({
|
|
17455
|
+
deviceId: external_exports.string().min(1),
|
|
17456
|
+
opts: external_exports.strictObject({
|
|
17457
|
+
cursor: external_exports.string().min(1).optional(),
|
|
17458
|
+
limit: external_exports.number().int().positive().optional(),
|
|
17459
|
+
states: external_exports.array(deviceOperationStateSchema).min(1).optional()
|
|
17460
|
+
}).optional()
|
|
17461
|
+
});
|
|
17462
|
+
var deviceOperationListResponseSchema = pageSchema(deviceOperationSummarySchema);
|
|
17463
|
+
var deviceOperationIdentityRequestSchema = external_exports.strictObject({
|
|
17464
|
+
deviceId: external_exports.string().min(1),
|
|
17465
|
+
operationId: external_exports.string().min(1)
|
|
17466
|
+
});
|
|
17467
|
+
var deviceOperationClaimRequestSchema = external_exports.strictObject({
|
|
17468
|
+
cursor: external_exports.string().min(1).optional(),
|
|
17469
|
+
deviceId: external_exports.string().min(1),
|
|
17470
|
+
limit: external_exports.number().int().positive().optional()
|
|
17471
|
+
});
|
|
17472
|
+
var deviceOperationClaimSchema = external_exports.object({
|
|
17473
|
+
arguments: external_exports.record(external_exports.string(), external_exports.json()),
|
|
17474
|
+
attempt: external_exports.number().int().positive(),
|
|
17475
|
+
caller: deviceOperationCallerSchema,
|
|
17476
|
+
cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
|
|
17477
|
+
commandId: external_exports.string().min(1),
|
|
17478
|
+
createdAt: external_exports.iso.datetime({ offset: true }),
|
|
17479
|
+
expiresAt: external_exports.iso.datetime({ offset: true }),
|
|
17480
|
+
leaseId: external_exports.string().min(1),
|
|
17481
|
+
leaseUntil: external_exports.iso.datetime({ offset: true }),
|
|
17482
|
+
operationId: external_exports.string().min(1),
|
|
17483
|
+
path: external_exports.string().min(1),
|
|
17484
|
+
targetPath: external_exports.string().min(1),
|
|
17485
|
+
traceId: external_exports.string().min(1)
|
|
17486
|
+
});
|
|
17487
|
+
var deviceOperationClaimResponseSchema = external_exports.object({
|
|
17488
|
+
cursor: external_exports.string().optional(),
|
|
17489
|
+
operation: deviceOperationClaimSchema.optional(),
|
|
17490
|
+
serverNow: external_exports.iso.datetime({ offset: true })
|
|
17491
|
+
});
|
|
17492
|
+
var deviceOperationLeaseShape = {
|
|
17493
|
+
deviceId: external_exports.string().min(1),
|
|
17494
|
+
leaseId: external_exports.string().min(1),
|
|
17495
|
+
operationId: external_exports.string().min(1)
|
|
17496
|
+
};
|
|
17497
|
+
var deviceOperationRenewRequestSchema = external_exports.strictObject(deviceOperationLeaseShape);
|
|
17498
|
+
var deviceOperationRenewResponseSchema = external_exports.object({
|
|
17499
|
+
cancelRequestedAt: external_exports.iso.datetime({ offset: true }).optional(),
|
|
17500
|
+
leaseUntil: external_exports.iso.datetime({ offset: true }),
|
|
17501
|
+
serverNow: external_exports.iso.datetime({ offset: true })
|
|
17502
|
+
});
|
|
17503
|
+
var deviceOperationCompleteRequestSchema = external_exports.discriminatedUnion("outcome", [
|
|
17504
|
+
external_exports.strictObject({
|
|
17505
|
+
...deviceOperationLeaseShape,
|
|
17506
|
+
outcome: external_exports.literal("succeeded"),
|
|
17507
|
+
result: external_exports.json()
|
|
17508
|
+
}),
|
|
17509
|
+
external_exports.strictObject({
|
|
17510
|
+
...deviceOperationLeaseShape,
|
|
17511
|
+
error: tbErrorBodySchema,
|
|
17512
|
+
outcome: external_exports.literal("rejected")
|
|
17513
|
+
}),
|
|
17514
|
+
external_exports.strictObject({
|
|
17515
|
+
...deviceOperationLeaseShape,
|
|
17516
|
+
error: tbErrorBodySchema,
|
|
17517
|
+
outcome: external_exports.literal("failed")
|
|
17518
|
+
}),
|
|
17519
|
+
external_exports.strictObject({
|
|
17520
|
+
...deviceOperationLeaseShape,
|
|
17521
|
+
error: tbErrorBodySchema.optional(),
|
|
17522
|
+
outcome: external_exports.literal("result_unknown")
|
|
17523
|
+
})
|
|
17524
|
+
]);
|
|
16757
17525
|
var registryNodeSchema = external_exports.object({
|
|
16758
17526
|
config: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
16759
17527
|
createdAt: external_exports.string().optional(),
|
|
16760
17528
|
description: external_exports.string(),
|
|
17529
|
+
deviceId: external_exports.string().optional(),
|
|
16761
17530
|
kind: nodeKindSchema,
|
|
16762
17531
|
lastSeenAt: external_exports.string().optional(),
|
|
16763
17532
|
online: external_exports.boolean().optional(),
|
|
@@ -17206,7 +17975,7 @@ async function objectBodyToBytes(body) {
|
|
|
17206
17975
|
if (body instanceof ArrayBuffer) return new Uint8Array(body);
|
|
17207
17976
|
return readStreamBytes(body);
|
|
17208
17977
|
}
|
|
17209
|
-
function bytesToObjectStream(
|
|
17978
|
+
function bytesToObjectStream(bytes2) {
|
|
17210
17979
|
return {
|
|
17211
17980
|
getReader() {
|
|
17212
17981
|
let done = false;
|
|
@@ -17214,7 +17983,7 @@ function bytesToObjectStream(bytes) {
|
|
|
17214
17983
|
async read() {
|
|
17215
17984
|
if (done) return { done: true };
|
|
17216
17985
|
done = true;
|
|
17217
|
-
return { done: false, value:
|
|
17986
|
+
return { done: false, value: bytes2 };
|
|
17218
17987
|
},
|
|
17219
17988
|
releaseLock() {
|
|
17220
17989
|
},
|
|
@@ -17339,7 +18108,7 @@ async function createObjectContextUploadGrant(store, opts, input) {
|
|
|
17339
18108
|
expiresAt
|
|
17340
18109
|
};
|
|
17341
18110
|
}
|
|
17342
|
-
function
|
|
18111
|
+
function clampLimit4(limit) {
|
|
17343
18112
|
if (limit === void 0) return LIST_LIMIT_DEFAULT;
|
|
17344
18113
|
if (!Number.isInteger(limit) || limit < 1) {
|
|
17345
18114
|
throw new TBError("invalid_argument", `limit \u975E\u6CD5:${limit}`);
|
|
@@ -17413,7 +18182,7 @@ function createObjectContextProvider(store, opts) {
|
|
|
17413
18182
|
return {
|
|
17414
18183
|
async list(path, listOpts) {
|
|
17415
18184
|
rejectFilter(listOpts);
|
|
17416
|
-
const limit =
|
|
18185
|
+
const limit = clampLimit4(listOpts?.limit);
|
|
17417
18186
|
const rel = path === "" ? "" : `${normalizeEntryPath(path)}/`;
|
|
17418
18187
|
const full = keyPrefix + rel;
|
|
17419
18188
|
assertContextKeyAllowed(full.slice(0, -1), path, false);
|
|
@@ -17523,7 +18292,7 @@ function createObjectContextProvider(store, opts) {
|
|
|
17523
18292
|
throw new TBError("invalid_argument", "query \u4E0D\u80FD\u4E3A\u7A7A");
|
|
17524
18293
|
}
|
|
17525
18294
|
rejectFilter(searchOpts);
|
|
17526
|
-
const limit =
|
|
18295
|
+
const limit = clampLimit4(searchOpts?.limit);
|
|
17527
18296
|
const q = query.toLowerCase();
|
|
17528
18297
|
const after = searchOpts?.cursor;
|
|
17529
18298
|
const items = [];
|
|
@@ -17580,6 +18349,7 @@ function isContextExpired(createdAt, ttlSec, now) {
|
|
|
17580
18349
|
// ../core/src/device/frames.ts
|
|
17581
18350
|
var deviceNodeCmdSchema = external_exports.object({
|
|
17582
18351
|
name: external_exports.string().min(1),
|
|
18352
|
+
delivery: external_exports.enum(["realtime", "mailbox", "both"]).optional(),
|
|
17583
18353
|
description: external_exports.string().optional(),
|
|
17584
18354
|
inputSchema: external_exports.unknown().optional(),
|
|
17585
18355
|
outputSchema: external_exports.unknown().optional(),
|
|
@@ -17846,7 +18616,7 @@ var DeviceGatewaySession = class {
|
|
|
17846
18616
|
call(req, done) {
|
|
17847
18617
|
const cached2 = this.results.get(req.id);
|
|
17848
18618
|
if (cached2 !== void 0) {
|
|
17849
|
-
done(cached2);
|
|
18619
|
+
done(cached2, "completed");
|
|
17850
18620
|
return;
|
|
17851
18621
|
}
|
|
17852
18622
|
const inflight = this.pending.get(req.id);
|
|
@@ -17855,19 +18625,28 @@ var DeviceGatewaySession = class {
|
|
|
17855
18625
|
return;
|
|
17856
18626
|
}
|
|
17857
18627
|
if (this.phase_ !== "ready") {
|
|
17858
|
-
done({ ok: false, error: TBError.deviceOffline().toJSON() });
|
|
18628
|
+
done({ ok: false, error: TBError.deviceOffline().toJSON() }, "not_dispatched");
|
|
17859
18629
|
return;
|
|
17860
18630
|
}
|
|
17861
18631
|
const cancelTimer = this.opts.setTimer(() => this.onCallTimeout(req.id), this.timeoutMs);
|
|
17862
18632
|
this.pending.set(req.id, { waiters: [done], cancelTimer });
|
|
17863
|
-
|
|
17864
|
-
|
|
17865
|
-
|
|
17866
|
-
|
|
17867
|
-
|
|
17868
|
-
|
|
17869
|
-
|
|
17870
|
-
|
|
18633
|
+
try {
|
|
18634
|
+
this.io.send({
|
|
18635
|
+
type: "call",
|
|
18636
|
+
id: req.id,
|
|
18637
|
+
path: req.path,
|
|
18638
|
+
arguments: req.arguments,
|
|
18639
|
+
// undefined 经 JSON.stringify 丢弃:老网关不带 context 时帧形状不变。
|
|
18640
|
+
...req.context !== void 0 ? { context: req.context } : {}
|
|
18641
|
+
});
|
|
18642
|
+
} catch {
|
|
18643
|
+
this.pending.delete(req.id);
|
|
18644
|
+
cancelTimer();
|
|
18645
|
+
done({
|
|
18646
|
+
ok: false,
|
|
18647
|
+
error: new TBError("unavailable", "\u8BBE\u5907\u8C03\u7528\u53D1\u9001\u5931\u8D25", { retryable: true }).toJSON()
|
|
18648
|
+
}, "unknown");
|
|
18649
|
+
}
|
|
17871
18650
|
}
|
|
17872
18651
|
/** 幂等表回放种子(DO 从 ctx.storage 恢复时用);已有同 id 结果则忽略。 */
|
|
17873
18652
|
seedResult(id, result) {
|
|
@@ -17887,7 +18666,7 @@ var DeviceGatewaySession = class {
|
|
|
17887
18666
|
};
|
|
17888
18667
|
for (const entry of entries) {
|
|
17889
18668
|
entry.cancelTimer();
|
|
17890
|
-
for (const waiter of entry.waiters) waiter(result);
|
|
18669
|
+
for (const waiter of entry.waiters) waiter(result, "unknown");
|
|
17891
18670
|
}
|
|
17892
18671
|
}
|
|
17893
18672
|
protocolReject(message) {
|
|
@@ -17901,7 +18680,7 @@ var DeviceGatewaySession = class {
|
|
|
17901
18680
|
if (entry === void 0) return;
|
|
17902
18681
|
this.pending.delete(id);
|
|
17903
18682
|
entry.cancelTimer();
|
|
17904
|
-
for (const waiter of entry.waiters) waiter(result);
|
|
18683
|
+
for (const waiter of entry.waiters) waiter(result, "completed");
|
|
17905
18684
|
}
|
|
17906
18685
|
onCallTimeout(id) {
|
|
17907
18686
|
const entry = this.pending.get(id);
|
|
@@ -17914,7 +18693,7 @@ var DeviceGatewaySession = class {
|
|
|
17914
18693
|
retryable: true
|
|
17915
18694
|
}).toJSON()
|
|
17916
18695
|
};
|
|
17917
|
-
for (const waiter of entry.waiters) waiter(result);
|
|
18696
|
+
for (const waiter of entry.waiters) waiter(result, "unknown");
|
|
17918
18697
|
}
|
|
17919
18698
|
};
|
|
17920
18699
|
|
|
@@ -17988,10 +18767,10 @@ function toView(entry) {
|
|
|
17988
18767
|
}
|
|
17989
18768
|
var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
17990
18769
|
function randomFeedbackId() {
|
|
17991
|
-
const
|
|
17992
|
-
crypto.getRandomValues(
|
|
18770
|
+
const bytes2 = new Uint8Array(6);
|
|
18771
|
+
crypto.getRandomValues(bytes2);
|
|
17993
18772
|
let out = "fb_";
|
|
17994
|
-
for (const b of
|
|
18773
|
+
for (const b of bytes2) out += ID_ALPHABET[b % ID_ALPHABET.length];
|
|
17995
18774
|
return out;
|
|
17996
18775
|
}
|
|
17997
18776
|
function requireShort(value, field, max) {
|
|
@@ -18136,6 +18915,7 @@ function renderHelpDsl(model) {
|
|
|
18136
18915
|
if (cmd.outputSchema !== void 0) lines.push(` result ${JSON.stringify(cmd.outputSchema)}`);
|
|
18137
18916
|
if (cmd.returns !== void 0) lines.push(...attrLines("returns", cmd.returns));
|
|
18138
18917
|
lines.push(` scope ${cmd.scope}`);
|
|
18918
|
+
if (cmd.delivery !== void 0) lines.push(` delivery ${cmd.delivery}`);
|
|
18139
18919
|
if (cmd.effect !== void 0) lines.push(` effect ${cmd.effect}`);
|
|
18140
18920
|
if (cmd.confirm) lines.push(" confirm");
|
|
18141
18921
|
}
|
|
@@ -18168,6 +18948,7 @@ function renderHelpJson(model) {
|
|
|
18168
18948
|
if (cmd.inputSchema !== void 0) out.inputSchema = cmd.inputSchema;
|
|
18169
18949
|
if (cmd.outputSchema !== void 0) out.outputSchema = cmd.outputSchema;
|
|
18170
18950
|
if (cmd.returns !== void 0) out.returns = cmd.returns;
|
|
18951
|
+
if (cmd.delivery !== void 0) out.delivery = cmd.delivery;
|
|
18171
18952
|
if (cmd.effect !== void 0) out.effect = cmd.effect;
|
|
18172
18953
|
if (cmd.confirm) out.confirm = cmd.confirm;
|
|
18173
18954
|
return out;
|
|
@@ -18207,6 +18988,7 @@ function cmdSection(cmd, index) {
|
|
|
18207
18988
|
}
|
|
18208
18989
|
lines.push(`- Invoke: \`POST ${cmd.path}\` with body \`{...arguments}\``);
|
|
18209
18990
|
lines.push(`- Required scope: \`${cmd.scope}\``);
|
|
18991
|
+
if (cmd.delivery !== void 0) lines.push(`- Delivery: \`${cmd.delivery}\``);
|
|
18210
18992
|
if (cmd.effect !== void 0) {
|
|
18211
18993
|
lines.push(
|
|
18212
18994
|
`- Effect: \`${cmd.effect}\`${cmd.confirm ? " \u2014 **ask the user to confirm before calling**" : ""}`
|
|
@@ -18424,7 +19206,7 @@ var KEY_STORE_IDEMPOTENCY = "store:idempotency:";
|
|
|
18424
19206
|
var UPLOAD_TTL_SEC_DEFAULT = 15 * 60;
|
|
18425
19207
|
var SHARE_TTL_SEC_DEFAULT = 15 * 60;
|
|
18426
19208
|
var MAX_OBJECT_BYTES_DEFAULT = 256 * 1024 * 1024;
|
|
18427
|
-
var
|
|
19209
|
+
var MAX_CAS_ATTEMPTS2 = 32;
|
|
18428
19210
|
var CAPABILITY_TTL_SEC_MAX = 7 * 24 * 60 * 60;
|
|
18429
19211
|
var TOKEN_PREFIX = {
|
|
18430
19212
|
call: "tbc",
|
|
@@ -18774,7 +19556,7 @@ var StoreService = class {
|
|
|
18774
19556
|
}
|
|
18775
19557
|
async revokeCallUploadCapability(token) {
|
|
18776
19558
|
const id = this.tokenId(token, "call");
|
|
18777
|
-
for (let attempt = 0; attempt <
|
|
19559
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
|
|
18778
19560
|
const raw = await this.state.get(`${KEY_STORE_CALL_CAPABILITY}${id}`);
|
|
18779
19561
|
if (raw === null) throw new TBError("permission_denied", "call upload capability \u65E0\u6548");
|
|
18780
19562
|
const capability = parseCallCapability(raw);
|
|
@@ -18988,7 +19770,7 @@ var StoreService = class {
|
|
|
18988
19770
|
}
|
|
18989
19771
|
async delete(uri, actor) {
|
|
18990
19772
|
const { objectId } = parseStoreUri(uri);
|
|
18991
|
-
for (let attempt = 0; attempt <
|
|
19773
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
|
|
18992
19774
|
const object2 = await this.requireObject(objectId);
|
|
18993
19775
|
if (!actor.admin && object2.owner !== actor.owner) {
|
|
18994
19776
|
throw new TBError("not_found", "Store \u5BF9\u8C61\u4E0D\u5B58\u5728");
|
|
@@ -19052,7 +19834,7 @@ var StoreService = class {
|
|
|
19052
19834
|
}
|
|
19053
19835
|
async revokeShare(shareId, actor) {
|
|
19054
19836
|
const owner = requireOwner(actor);
|
|
19055
|
-
for (let attempt = 0; attempt <
|
|
19837
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
|
|
19056
19838
|
const raw = await this.state.get(`${KEY_STORE_SHARE}${shareId}`);
|
|
19057
19839
|
if (raw === null) throw new TBError("not_found", "share grant \u4E0D\u5B58\u5728");
|
|
19058
19840
|
const grant = parseShare(raw);
|
|
@@ -19376,7 +20158,7 @@ var StoreService = class {
|
|
|
19376
20158
|
await this.compareRecord(resolved.key, resolved.binding, null);
|
|
19377
20159
|
}
|
|
19378
20160
|
async reserveCallCapability(token, objectId, input, transportMaxBytes) {
|
|
19379
|
-
for (let attempt = 0; attempt <
|
|
20161
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
|
|
19380
20162
|
const capability = await this.verifyCallUploadCapability(token);
|
|
19381
20163
|
const previous = capability.reservations.find((r) => r.objectId === objectId);
|
|
19382
20164
|
if (previous !== void 0) {
|
|
@@ -19498,7 +20280,7 @@ var StoreService = class {
|
|
|
19498
20280
|
}
|
|
19499
20281
|
/** driver DELETE 成功后持久化证据;后续 cleanup 只收 tombstone,不再重复外部 DELETE。 */
|
|
19500
20282
|
async markBytesDeleted(objectId, expectedDriverKey) {
|
|
19501
|
-
for (let attempt = 0; attempt <
|
|
20283
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
|
|
19502
20284
|
const raw = await this.state.get(`${KEY_STORE_OBJECT}${objectId}`);
|
|
19503
20285
|
if (raw === null) return;
|
|
19504
20286
|
const object2 = parseObject(raw);
|
|
@@ -19598,7 +20380,7 @@ var StoreService = class {
|
|
|
19598
20380
|
}
|
|
19599
20381
|
async markReady(sessionInput, meta3) {
|
|
19600
20382
|
const actualChecksum = sessionInput.expectedChecksum !== void 0 && meta3.metadata?.["checksum-sha256"]?.toLowerCase() === sessionInput.expectedChecksum.value ? sessionInput.expectedChecksum : void 0;
|
|
19601
|
-
for (let attempt = 0; attempt <
|
|
20383
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
|
|
19602
20384
|
const object2 = await this.requireObject(sessionInput.objectId);
|
|
19603
20385
|
if (object2.status === "ready") {
|
|
19604
20386
|
await this.completeSessionBestEffort(await this.requireSession(sessionInput.id));
|
|
@@ -19628,7 +20410,7 @@ var StoreService = class {
|
|
|
19628
20410
|
throw new TBError("conflict", "\u5BF9\u8C61\u5E76\u53D1\u72B6\u6001\u51B2\u7A81:pending");
|
|
19629
20411
|
}
|
|
19630
20412
|
async completeSessionBestEffort(sessionInput) {
|
|
19631
|
-
for (let attempt = 0; attempt <
|
|
20413
|
+
for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS2; attempt++) {
|
|
19632
20414
|
const session = await this.requireSession(sessionInput.id);
|
|
19633
20415
|
if (session.status === "completed" || session.status !== "created") return;
|
|
19634
20416
|
const completedAt = this.nowIso();
|
|
@@ -19804,8 +20586,8 @@ function canonicalCatalogJson(value) {
|
|
|
19804
20586
|
return JSON.stringify(normalize(value));
|
|
19805
20587
|
}
|
|
19806
20588
|
async function catalogDigest(value) {
|
|
19807
|
-
const
|
|
19808
|
-
const hash2 = await crypto.subtle.digest("SHA-256",
|
|
20589
|
+
const bytes2 = new TextEncoder().encode(canonicalCatalogJson(value));
|
|
20590
|
+
const hash2 = await crypto.subtle.digest("SHA-256", bytes2);
|
|
19809
20591
|
return [...new Uint8Array(hash2)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
19810
20592
|
}
|
|
19811
20593
|
async function catalogSetDigest(catalog) {
|
|
@@ -19999,11 +20781,11 @@ var pluginCallSchema = external_exports.object({
|
|
|
19999
20781
|
arguments: external_exports.record(external_exports.string(), external_exports.unknown())
|
|
20000
20782
|
});
|
|
20001
20783
|
function assertPluginPayloadSize(payload) {
|
|
20002
|
-
const
|
|
20003
|
-
if (
|
|
20784
|
+
const bytes2 = new TextEncoder().encode(payload).length;
|
|
20785
|
+
if (bytes2 > PLUGIN_PAYLOAD_MAX_BYTES) {
|
|
20004
20786
|
throw new TBError(
|
|
20005
20787
|
"invalid_argument",
|
|
20006
|
-
`payload ${
|
|
20788
|
+
`payload ${bytes2} \u5B57\u8282\u8D85\u8FC7\u4E0A\u9650 ${PLUGIN_PAYLOAD_MAX_BYTES}(\u2264 1 MiB;\u66F4\u5927\u5185\u5BB9\u7ECF $ref)`
|
|
20007
20789
|
);
|
|
20008
20790
|
}
|
|
20009
20791
|
}
|
|
@@ -20181,9 +20963,9 @@ function searchUnitAllowsPath(unit) {
|
|
|
20181
20963
|
return !/^%[A-Za-z0-9]{1,2}%$/u.test(unit.pattern);
|
|
20182
20964
|
}
|
|
20183
20965
|
function stableDigest(value) {
|
|
20184
|
-
const
|
|
20966
|
+
const bytes2 = new TextEncoder().encode(JSON.stringify(value));
|
|
20185
20967
|
let hash2 = 0xcbf29ce484222325n;
|
|
20186
|
-
for (const byte of
|
|
20968
|
+
for (const byte of bytes2) {
|
|
20187
20969
|
hash2 ^= BigInt(byte);
|
|
20188
20970
|
hash2 = BigInt.asUintN(64, hash2 * 0x100000001b3n);
|
|
20189
20971
|
}
|
|
@@ -20193,12 +20975,12 @@ function truncateUtf8(value, maxBytes) {
|
|
|
20193
20975
|
const encoder = new TextEncoder();
|
|
20194
20976
|
if (encoder.encode(value).length <= maxBytes) return value;
|
|
20195
20977
|
let result = "";
|
|
20196
|
-
let
|
|
20978
|
+
let bytes2 = 0;
|
|
20197
20979
|
for (const char of value) {
|
|
20198
20980
|
const size = encoder.encode(char).length;
|
|
20199
|
-
if (
|
|
20981
|
+
if (bytes2 + size > maxBytes) break;
|
|
20200
20982
|
result += char;
|
|
20201
|
-
|
|
20983
|
+
bytes2 += size;
|
|
20202
20984
|
}
|
|
20203
20985
|
return result;
|
|
20204
20986
|
}
|
|
@@ -21387,7 +22169,7 @@ function guessContentType(path) {
|
|
|
21387
22169
|
if (dot < 0) return "text/plain";
|
|
21388
22170
|
return CONTENT_TYPE_BY_EXT[path.slice(dot + 1).toLowerCase()] ?? "text/plain";
|
|
21389
22171
|
}
|
|
21390
|
-
function
|
|
22172
|
+
function clampLimit5(limit) {
|
|
21391
22173
|
if (limit === void 0) return LIST_LIMIT_DEFAULT;
|
|
21392
22174
|
if (!Number.isInteger(limit) || limit < 1) {
|
|
21393
22175
|
throw new TBError("invalid_argument", `limit \u975E\u6CD5:${limit}`);
|
|
@@ -21442,7 +22224,7 @@ function createSkillhubProvider(store, opts) {
|
|
|
21442
22224
|
};
|
|
21443
22225
|
return {
|
|
21444
22226
|
async list(listOpts) {
|
|
21445
|
-
const limit =
|
|
22227
|
+
const limit = clampLimit5(listOpts?.limit);
|
|
21446
22228
|
const res = await store.list(keyPrefix, {
|
|
21447
22229
|
delimiter: "/",
|
|
21448
22230
|
cursor: listOpts?.cursor,
|
|
@@ -21502,7 +22284,7 @@ function createSkillhubProvider(store, opts) {
|
|
|
21502
22284
|
if (typeof query !== "string" || query === "") {
|
|
21503
22285
|
throw new TBError("invalid_argument", "query \u4E0D\u80FD\u4E3A\u7A7A");
|
|
21504
22286
|
}
|
|
21505
|
-
const limit =
|
|
22287
|
+
const limit = clampLimit5(searchOpts?.limit);
|
|
21506
22288
|
const q = query.toLowerCase();
|
|
21507
22289
|
const after = searchOpts?.cursor;
|
|
21508
22290
|
const items = [];
|
|
@@ -21677,6 +22459,7 @@ function toolToCmd(nodePath, tool, index) {
|
|
|
21677
22459
|
if (tool.description !== void 0) {
|
|
21678
22460
|
cmd.h = index ? summarizeOneLine(tool.description) : tool.description;
|
|
21679
22461
|
}
|
|
22462
|
+
if (tool.delivery !== void 0) cmd.delivery = tool.delivery;
|
|
21680
22463
|
if (!index && tool.inputSchema !== void 0) cmd.inputSchema = tool.inputSchema;
|
|
21681
22464
|
if (!index && tool.outputSchema !== void 0) cmd.outputSchema = tool.outputSchema;
|
|
21682
22465
|
if (tool.effect !== void 0) cmd.effect = tool.effect;
|
|
@@ -21808,7 +22591,7 @@ function resolveUpstreamTool(v, source, virtualName2) {
|
|
|
21808
22591
|
}
|
|
21809
22592
|
|
|
21810
22593
|
// ../core/src/tree/registry.ts
|
|
21811
|
-
function
|
|
22594
|
+
function clampLimit6(limit) {
|
|
21812
22595
|
if (limit === void 0 || limit < 1) return LIST_LIMIT_DEFAULT;
|
|
21813
22596
|
return limit > LIST_LIMIT_MAX ? LIST_LIMIT_MAX : limit;
|
|
21814
22597
|
}
|
|
@@ -21909,7 +22692,7 @@ var NodeRegistryStore = class {
|
|
|
21909
22692
|
*/
|
|
21910
22693
|
async list(prefix, opts) {
|
|
21911
22694
|
const normPrefix = prefix === void 0 ? "" : canonicalizePath(prefix);
|
|
21912
|
-
const limit =
|
|
22695
|
+
const limit = clampLimit6(opts?.limit);
|
|
21913
22696
|
const all = (await this.scanAll()).filter((n) => isPrefixOf(normPrefix, n.path)).sort(byPath);
|
|
21914
22697
|
const cursor = opts?.cursor;
|
|
21915
22698
|
const start = cursor ? all.findIndex((n) => n.path === cursor) + 1 : 0;
|
|
@@ -21998,6 +22781,7 @@ var NodeRegistryStore = class {
|
|
|
21998
22781
|
description: node.description,
|
|
21999
22782
|
...node.config !== void 0 ? { config: node.config } : {},
|
|
22000
22783
|
...node.virtualize !== void 0 ? { virtualize: node.virtualize } : {},
|
|
22784
|
+
...opts.deviceId !== void 0 ? { deviceId: opts.deviceId } : {},
|
|
22001
22785
|
...opts.online !== void 0 ? { online: opts.online } : {},
|
|
22002
22786
|
...opts.lastSeenAt !== void 0 ? { lastSeenAt: opts.lastSeenAt } : {},
|
|
22003
22787
|
registeredBy,
|
|
@@ -22218,8 +23002,8 @@ function createPlugin(opts = {}) {
|
|
|
22218
23002
|
const b64 = raw.replaceAll("-", "+").replaceAll("_", "/");
|
|
22219
23003
|
const padded = b64.padEnd(b64.length + (4 - b64.length % 4) % 4, "=");
|
|
22220
23004
|
try {
|
|
22221
|
-
const
|
|
22222
|
-
return new TextDecoder().decode(
|
|
23005
|
+
const bytes2 = Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
|
|
23006
|
+
return new TextDecoder().decode(bytes2);
|
|
22223
23007
|
} catch {
|
|
22224
23008
|
throw new TBError("invalid_argument", `${HEADER_TB_UPSTREAM_AUTH} is not valid base64url`);
|
|
22225
23009
|
}
|
|
@@ -22545,6 +23329,7 @@ export {
|
|
|
22545
23329
|
pluginTokenSecretName,
|
|
22546
23330
|
createStoreModule,
|
|
22547
23331
|
RemoteAllowlistStore,
|
|
23332
|
+
DeviceMailboxService,
|
|
22548
23333
|
tbErrorBodySchema,
|
|
22549
23334
|
nodeInputSchema,
|
|
22550
23335
|
helpJsonSchema,
|
|
@@ -22554,6 +23339,16 @@ export {
|
|
|
22554
23339
|
toolSearchSourceResultSchema,
|
|
22555
23340
|
toolSearchPageSchema,
|
|
22556
23341
|
toolSearchRequestSchema,
|
|
23342
|
+
deviceOperationSummarySchema,
|
|
23343
|
+
deviceOperationDetailSchema,
|
|
23344
|
+
deviceOperationListRequestSchema,
|
|
23345
|
+
deviceOperationListResponseSchema,
|
|
23346
|
+
deviceOperationIdentityRequestSchema,
|
|
23347
|
+
deviceOperationClaimRequestSchema,
|
|
23348
|
+
deviceOperationClaimResponseSchema,
|
|
23349
|
+
deviceOperationRenewRequestSchema,
|
|
23350
|
+
deviceOperationRenewResponseSchema,
|
|
23351
|
+
deviceOperationCompleteRequestSchema,
|
|
22557
23352
|
registryNodeSchema,
|
|
22558
23353
|
feedbackViewSchema,
|
|
22559
23354
|
feedbackDetailSchema,
|