@tool-bridge/server 0.21.1 → 0.22.1

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 (178) hide show
  1. package/dist/admin.js +170 -0
  2. package/dist/airtable-ML2GIGCH.js +790 -0
  3. package/dist/{alt_text_generator_ai-W7O34SNG.js → alt_text_generator_ai-FGYQAF2A.js} +12 -11
  4. package/dist/{amap-VOX4T2AW.js → amap-G7V65NGK.js} +221 -220
  5. package/dist/anthropic-6ZK24TBB.js +203 -0
  6. package/dist/apify-VDGYHP6W.js +248 -0
  7. package/dist/brave_search-TAATLZOS.js +302 -0
  8. package/dist/chunk-2IAI3XQM.js +302 -0
  9. package/dist/chunk-7ISGFRC6.js +161 -0
  10. package/dist/{chunk-E6JCVKW6.js → chunk-BNMLA2RC.js} +3 -3
  11. package/dist/chunk-HA4BGL6C.js +8429 -0
  12. package/dist/{chunk-KMTT3I6D.js → chunk-RMAWSG7E.js} +19172 -25717
  13. package/dist/{chunk-XYBU3WZH.js → chunk-RTW5VRTK.js} +3 -3
  14. package/dist/chunk-U7PTOA3U.js +7320 -0
  15. package/dist/chunk-UY6ANCOY.js +378 -0
  16. package/dist/{chunk-ATK45BXV.js → chunk-X7ZUTKHR.js} +4 -2
  17. package/dist/circleci-BQ2UWXL2.js +389 -0
  18. package/dist/clerk-2JYWQNOI.js +1019 -0
  19. package/dist/cohere-6MI7AQM4.js +185 -0
  20. package/dist/{confluence-B3EWPZVE.js → confluence-6Y6GDETF.js} +105 -104
  21. package/dist/{convertapi-EUWSQYPF.js → convertapi-HBZCSWOX.js} +32 -31
  22. package/dist/{currencyapi-KVTIK3GL.js → currencyapi-337U5TGI.js} +71 -71
  23. package/dist/deepseek-OSPASO7O.js +210 -0
  24. package/dist/docker_hub-3ATQOY5L.js +933 -0
  25. package/dist/dropbox-LSA4GM2Y.js +1305 -0
  26. package/dist/dub-VZPJSPI6.js +680 -0
  27. package/dist/e2b-6SDYQZL2.js +278 -0
  28. package/dist/exa-B6EUYDVP.js +332 -0
  29. package/dist/{fal_ai-23E7JPNT.js → fal_ai-K4Q27IME.js} +81 -80
  30. package/dist/{feishu-7QRIDUV6.js → feishu-4TKXG4SU.js} +528 -572
  31. package/dist/{feishu_custom_bot-TJ4K7QNJ.js → feishu_custom_bot-7CTEAKRB.js} +57 -53
  32. package/dist/figma-OUKSZLD5.js +777 -0
  33. package/dist/firehydrant-7MOYL7QH.js +563 -0
  34. package/dist/{fixer-BWON27UO.js → fixer-H2BV2NO4.js} +34 -33
  35. package/dist/fly-PXKY6PNH.js +469 -0
  36. package/dist/{front-QCGXYEDJ.js → front-UZYIV5DW.js} +104 -104
  37. package/dist/geocodio-NSYO7TFP.js +213 -0
  38. package/dist/ghost-QBKKQQMF.js +338 -0
  39. package/dist/github-ENLSJ4CL.js +5421 -0
  40. package/dist/gmail-KQSDEB47.js +1887 -0
  41. package/dist/googlecalendar-5YCX4SZF.js +2524 -0
  42. package/dist/{googledocs-BUHL4J2H.js → googledocs-SSWIVFKA.js} +341 -340
  43. package/dist/{grafana-GLU2DWF2.js → grafana-TF2LXDQA.js} +221 -220
  44. package/dist/graphhopper-CURBVHYK.js +325 -0
  45. package/dist/index.d.ts +1132 -332
  46. package/dist/index.js +31 -14
  47. package/dist/{ip2proxy-EZ64Y4ZH.js → ip2proxy-YNVMTZEM.js} +28 -27
  48. package/dist/ipgeolocation_io-NAU7VJ4J.js +315 -0
  49. package/dist/ipqualityscore-OT63L4TI.js +279 -0
  50. package/dist/{jina_ai-EFBHTBXL.js → jina_ai-6WBMBGWM.js} +23 -23
  51. package/dist/{jira-HQSHAA5K.js → jira-DVDVTHNO.js} +118 -117
  52. package/dist/langsmith-IM5N4YAU.js +593 -0
  53. package/dist/lemlist-277SHUQF.js +289 -0
  54. package/dist/{linear-K7RYFYAD.js → linear-AEPH7B5V.js} +327 -326
  55. package/dist/logsnag-VEWRAGBG.js +150 -0
  56. package/dist/main.js +57 -280
  57. package/dist/{mattermost-S2BRCWLQ.js → mattermost-Q3A2BIZA.js} +59 -58
  58. package/dist/mem0-AXS7GZGI.js +544 -0
  59. package/dist/memos-7TXG4ZTU.js +744 -0
  60. package/dist/{metabase-MMSEPCOF.js → metabase-NSVACWQM.js} +90 -89
  61. package/dist/mistral_ai-YZ52RGD4.js +1196 -0
  62. package/dist/{mother_duck-H7PCQNZ2.js → mother_duck-XLLL6FVL.js} +94 -93
  63. package/dist/ngrok-4O4W3WZW.js +356 -0
  64. package/dist/{notes-PFMKRO33.js → notes-YTB3TJOO.js} +11 -9
  65. package/dist/notion-4W4O7J7V.js +940 -0
  66. package/dist/open_exchange_rates-23QJXVO5.js +215 -0
  67. package/dist/openai-ZS7GLSLH.js +800 -0
  68. package/dist/opengraph_io-PMVH7OYI.js +362 -0
  69. package/dist/openrouter-ONRGFNB6.js +441 -0
  70. package/dist/outline-UCUYZZ7J.js +599 -0
  71. package/dist/paddle-35HTKTUL.js +454 -0
  72. package/dist/perplexity-NVOBYN24.js +220 -0
  73. package/dist/pinecone-55CJY73C.js +571 -0
  74. package/dist/{pipedrive-Y2O7QGFF.js → pipedrive-WMCAKS72.js} +99 -98
  75. package/dist/polar-SM4ZM53B.js +395 -0
  76. package/dist/posthog-NWCXVXNJ.js +3464 -0
  77. package/dist/postmark-QJV5PHUQ.js +427 -0
  78. package/dist/{prerender-MENYM2TY.js → prerender-2W7UT4SC.js} +31 -30
  79. package/dist/{pubmed-GOXUVVH5.js → pubmed-VVV7XYLU.js} +239 -238
  80. package/dist/{railway-V2SID4WV.js → railway-KGI57S3O.js} +118 -117
  81. package/dist/readwise-AGHTQB42.js +470 -0
  82. package/dist/render-O4HBROCK.js +461 -0
  83. package/dist/{replicate-756MXPYX.js → replicate-KWBOMX7D.js} +81 -80
  84. package/dist/{resend-ZKH3BTBI.js → resend-DRH6Y6I4.js} +20 -16
  85. package/dist/rootly-XGCUDW6X.js +336 -0
  86. package/dist/{scrapfly-NSRHFDIQ.js → scrapfly-OIQ3OY6L.js} +62 -61
  87. package/dist/{scrapingbee-OQHLAVEY.js → scrapingbee-OCZO4FHX.js} +56 -56
  88. package/dist/{screenshot_fyi-DVWG3AXC.js → screenshot_fyi-CUNGFZOC.js} +16 -16
  89. package/dist/semantic_scholar-3UJRLKES.js +611 -0
  90. package/dist/{sentry-546MNDJG.js → sentry-5BWVZFJV.js} +208 -207
  91. package/dist/{shodan-C3OON3Z3.js → shodan-HI37CTEW.js} +62 -61
  92. package/dist/shopify-LJ2EV2HH.js +610 -0
  93. package/dist/stripe-3LHMV55K.js +585 -0
  94. package/dist/{supabase-U2SL4D63.js → supabase-H2KPX3Q2.js} +245 -244
  95. package/dist/tavily-FBEWGH3Z.js +326 -0
  96. package/dist/telegram-MYYO3JND.js +1767 -0
  97. package/dist/{telnyx-CXQ4EZUX.js → telnyx-H4ALEGAX.js} +57 -56
  98. package/dist/todoist-OBWICA5Q.js +664 -0
  99. package/dist/trello-GUFUJRWO.js +1080 -0
  100. package/dist/turso-NIAK4UMS.js +416 -0
  101. package/dist/{twilio-4PDBJKWX.js → twilio-K6SLK2CX.js} +70 -69
  102. package/dist/umami-42RS2EPS.js +389 -0
  103. package/dist/unsplash-V7TOTETT.js +351 -0
  104. package/dist/{upstash_redis-G4LQBYHA.js → upstash_redis-AWQMB6Y3.js} +51 -50
  105. package/dist/uptimerobot-AZC2DHOT.js +483 -0
  106. package/dist/v2ex-4TVRNMLS.js +667 -0
  107. package/dist/vercel-DPHTJ3XR.js +1076 -0
  108. package/dist/{wolfram_alpha_api-3G4PUJWB.js → wolfram_alpha_api-XAG7IXBW.js} +36 -35
  109. package/dist/wordpress-KMPKVGUX.js +812 -0
  110. package/dist/workos-PKB2YR7S.js +664 -0
  111. package/dist/zhihu-Y4H4XYPB.js +254 -0
  112. package/package.json +18 -9
  113. package/dist/airtable-LLZDFN7M.js +0 -789
  114. package/dist/anthropic-G23NN3X5.js +0 -202
  115. package/dist/apify-Y3SS734K.js +0 -247
  116. package/dist/brave_search-ZC7OAPSZ.js +0 -301
  117. package/dist/chunk-R6P4XAE5.js +0 -248
  118. package/dist/chunk-U7B6DS2O.js +0 -977
  119. package/dist/chunk-UZM2RXZH.js +0 -23436
  120. package/dist/circleci-3BAX5FCG.js +0 -388
  121. package/dist/clerk-6LEM6TNU.js +0 -1019
  122. package/dist/cloudflare_dns-KINYTJUD.js +0 -588
  123. package/dist/cohere-XCJ5AJ6B.js +0 -185
  124. package/dist/deepseek-PC5YGNC5.js +0 -209
  125. package/dist/docker_hub-C3MA5FU6.js +0 -932
  126. package/dist/dropbox-XBV7Z2IR.js +0 -1304
  127. package/dist/dub-LDOFG3HC.js +0 -679
  128. package/dist/e2b-JMCPSVBW.js +0 -277
  129. package/dist/exa-RAK7O7RD.js +0 -331
  130. package/dist/figma-E6IX5DTH.js +0 -773
  131. package/dist/firehydrant-ZBLPQREE.js +0 -562
  132. package/dist/fly-ZH3HFCZJ.js +0 -468
  133. package/dist/geocodio-YGNI7DA4.js +0 -212
  134. package/dist/ghost-EVSGKH2Q.js +0 -337
  135. package/dist/github-MA2BGRCJ.js +0 -5420
  136. package/dist/gmail-E5E6AADE.js +0 -1886
  137. package/dist/googlecalendar-BTLFPXTD.js +0 -2523
  138. package/dist/graphhopper-WSMB3TCD.js +0 -324
  139. package/dist/ipgeolocation_io-AA7HAS22.js +0 -315
  140. package/dist/ipqualityscore-BHJXVTJT.js +0 -277
  141. package/dist/langsmith-5W6SCT6F.js +0 -592
  142. package/dist/lemlist-HJWH6UMK.js +0 -288
  143. package/dist/logsnag-4KFOHL37.js +0 -150
  144. package/dist/mem0-CAW43CIC.js +0 -543
  145. package/dist/memos-TWEGPKFM.js +0 -740
  146. package/dist/mistral_ai-64BGZQHP.js +0 -1195
  147. package/dist/ngrok-GQCUGZKJ.js +0 -356
  148. package/dist/notion-DQWZWP4N.js +0 -936
  149. package/dist/open_exchange_rates-QMMD735E.js +0 -214
  150. package/dist/openai-W6PX32NZ.js +0 -799
  151. package/dist/opengraph_io-HNDBXYNW.js +0 -361
  152. package/dist/openrouter-JJYMEAUL.js +0 -437
  153. package/dist/outline-MCBNQZYY.js +0 -595
  154. package/dist/paddle-D2SKLUDN.js +0 -453
  155. package/dist/perplexity-XIFMKUAE.js +0 -219
  156. package/dist/pinecone-HUFTALV2.js +0 -570
  157. package/dist/polar-TYTOMOSR.js +0 -394
  158. package/dist/posthog-43JAR3VW.js +0 -3463
  159. package/dist/postmark-KL2QJYSG.js +0 -426
  160. package/dist/readwise-CI4GIMMJ.js +0 -469
  161. package/dist/render-SUBJ6YRZ.js +0 -460
  162. package/dist/rootly-CD2LJHPI.js +0 -336
  163. package/dist/semantic_scholar-T4A252KW.js +0 -610
  164. package/dist/shopify-Y2HN2MCQ.js +0 -609
  165. package/dist/stripe-VE3CD3AY.js +0 -584
  166. package/dist/tavily-KCZHK6HE.js +0 -326
  167. package/dist/telegram-3URFBCMY.js +0 -1766
  168. package/dist/todoist-HNPWNYTD.js +0 -663
  169. package/dist/trello-3W2MIXRP.js +0 -1079
  170. package/dist/turso-2EQF7C2Z.js +0 -415
  171. package/dist/umami-5REN7TGP.js +0 -388
  172. package/dist/unsplash-EIXL424F.js +0 -350
  173. package/dist/uptimerobot-KNJ3EYLY.js +0 -482
  174. package/dist/v2ex-RHJ234PZ.js +0 -666
  175. package/dist/vercel-AS6NCIC7.js +0 -1075
  176. package/dist/wordpress-KNDAAUV7.js +0 -811
  177. package/dist/workos-R6UITSJ7.js +0 -663
  178. package/dist/zhihu-AGK4HILK.js +0 -253
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import { z } from 'zod';
1
2
  import * as http from 'node:http';
2
3
  import { Sql } from 'postgres';
4
+ import * as hono_types from 'hono/types';
3
5
  import { Hono } from 'hono';
4
6
 
5
7
  /**
@@ -27,30 +29,6 @@ interface ListOptions {
27
29
  }
28
30
  /** "user:alice" | "agent:researcher" | "device:build-01"。 */
29
31
  type OwnerRef = string;
30
- interface CallContext {
31
- /** 平台→Plugin envelope 专用:本次调用命中该 plugin 的哪个 export(v2 多 export 路由)。 */
32
- exportId?: string;
33
- /** 本次调用使用的 SK 的 id(非明文)。 */
34
- keyId: string;
35
- /** 平台→Plugin envelope 专用:挂载节点 config.providerConfig 透传(每挂载非敏感配置)。 */
36
- mountConfig?: Record<string, unknown>;
37
- /** 平台→Plugin envelope 专用:本次调用来自哪个挂载节点(同一 plugin 可多路径挂载)。 */
38
- mountPath?: TreePath;
39
- owner: OwnerRef;
40
- /** 反向注册路径收紧规则;缺省按非保留根放行。 */
41
- registerPaths?: TreePath[];
42
- scopes: Scope[];
43
- /** 全链路观测。 */
44
- traceId: string;
45
- }
46
- type Action = 'read' | 'write' | 'call' | 'register' | 'admin';
47
- interface Scope {
48
- actions: Action[];
49
- /** 默认 allow;deny 优先于一切 allow。 */
50
- effect?: 'allow' | 'deny';
51
- /** 树路径 glob:"**" | "docs/**" | "device/build-01/**"。 */
52
- pattern: string;
53
- }
54
32
 
55
33
  /**
56
34
  * StateStore:宿主注入的状态存储接口。
@@ -126,15 +104,26 @@ interface TBErrorBody {
126
104
  retryable: boolean;
127
105
  }
128
106
 
107
+ /** Roots live in the host's protected bootstrap secret file, never in their own encrypted database. */
108
+ interface EncryptionKeyring {
109
+ activeKeyId: string;
110
+ keys: Record<string, string>;
111
+ }
112
+ /** Separate signing roots; encryption-root rotation must not invalidate outstanding capabilities. */
113
+ interface StoreTokenKeyring {
114
+ activeKeyId: string;
115
+ keys: Record<string, string>;
116
+ }
117
+
129
118
  /**
130
119
  * SecretStore:上游凭证的"只进不出"加密保管。
131
120
  *
132
121
  * 值经 AES-256-GCM 加密后写入注入的 StateStore(key 布局 `secret:<name>`,store.ts)。
133
- * 主密钥 `TB_SECRET_ENCRYPTION_KEY` 是部署期 env-only base64url(32 字节)——
134
- * 信任根不自举存储(spec-digest)。主密钥缺失/格式非法时能力禁用:Set 抛 unavailable。
122
+ * 版本化加密根由宿主受保护 bootstrap keyring 注入,密文保存 keyId revision。
123
+ * 信任根不存入被其加密的数据库;缺失/格式非法时能力禁用。
135
124
  *
136
125
  * 纯逻辑,仅依赖 WebCrypto(core 无宿主依赖)。`crypto` / `TextEncoder` / `TextDecoder`
137
- * Workers 与 Node 20+ 均为全局;类型经 webGlobals.ts 统一承接(不改 tsconfig、不污染全局)。
126
+ * 在支持的 JavaScript/Node 运行时均为全局;类型经 webGlobals.ts 统一承接(不改 tsconfig、不污染全局)。
138
127
  */
139
128
 
140
129
  /** system/secret list 的一行(名字与时间戳,永不含值);CLI/Dashboard 经 SDK 消费同一命名。 */
@@ -150,19 +139,13 @@ interface SecretEntrySummary {
150
139
  */
151
140
  declare class SecretStoreImpl {
152
141
  private readonly store;
153
- /** 32 字节主密钥;undefined 表示 unavailable 态。 */
154
- private readonly keyBytes;
155
- /** 惰性导入的 CryptoKey(仅可用时);首次加解密时创建并缓存。 */
156
- private importedKey;
157
- /**
158
- * @param masterKey base64url 编码的 32 字节(TB_SECRET_ENCRYPTION_KEY);
159
- * undefined / 解码失败 / 长度非 32 → 实例处于 unavailable 态。
160
- */
161
- constructor(store: StateStore, masterKey: string | undefined);
162
- private static decodeMasterKey;
163
- /** secret 能力是否可用(主密钥有效)。 */
142
+ private readonly keyring;
143
+ private readonly importedKeys;
144
+ constructor(store: StateStore, keys: EncryptionKeyring | string | undefined);
164
145
  get available(): boolean;
165
146
  private key;
147
+ private encrypt;
148
+ private decrypt;
166
149
  /**
167
150
  * 写入 / 替换 secret;明文仅在此请求中出现。
168
151
  * unavailable 态 → 抛 unavailable(retryable:false):主密钥缺失时 Set 不可用。
@@ -186,6 +169,14 @@ declare class SecretStoreImpl {
186
169
  * 各 Provider(remote/mcp/http/pluginClient)均按此实现。
187
170
  */
188
171
  resolve(name: string): Promise<string | undefined>;
172
+ /** Bounded, resumable re-encryption. Concurrent credential replacement wins over stale ciphertext. */
173
+ reencryptPage(opts?: {
174
+ cursor?: string;
175
+ limit?: number;
176
+ }): Promise<{
177
+ changed: number;
178
+ cursor?: string;
179
+ }>;
189
180
  }
190
181
 
191
182
  /**
@@ -374,9 +365,9 @@ type BuiltinCatalog = Record<string, BuiltinCatalogEntry>;
374
365
  /**
375
366
  * ObjectStore:对象存储抽象。
376
367
  *
377
- * r2(R2 binding)、s3(aws4fetch)与单测内存实现共用此接口;ContextProvider 的
368
+ * Node S3、设备本地目录与单测内存实现共用此接口;ContextProvider 的
378
369
  * 四动词语义全部落在 objectProvider.ts,后端只做本接口适配。core 无 DOM lib:
379
- * 流与 body 用最小结构类型声明,与 Workers / Node 的全局 ReadableStream 结构兼容。
370
+ * 流与 body 用最小结构类型声明,与标准 ReadableStream 结构兼容。
380
371
  */
381
372
  /** 最小读流(结构兼容全局 ReadableStream<Uint8Array>)。 */
382
373
  interface ObjectBodyStream {
@@ -421,7 +412,7 @@ interface ObjectListOptions {
421
412
  }
422
413
  interface ObjectListResult {
423
414
  cursor?: string;
424
- /** 文件与折叠前缀按字典序混排(与 R2/S3 行为一致)。 */
415
+ /** 文件与折叠前缀按字典序混排(与 S3/S3 行为一致)。 */
425
416
  items: Array<ObjectMeta | {
426
417
  prefix: string;
427
418
  }>;
@@ -445,11 +436,6 @@ interface ObjectPresignPutExactOptions extends ObjectPresignPutOptions {
445
436
  contentLength: number;
446
437
  }
447
438
  interface ObjectStore {
448
- /**
449
- * 可选宿主钩子:清理 prefix 下早于 olderThan 的未落位 staging 临时文件。
450
- * staging 不进入 list,且命名/mtime 属于 driver 私有实现;返回实际删除数量。
451
- */
452
- cleanupStaging?(prefix: string, olderThan: string): Promise<number>;
453
439
  /** 幂等:不存在静默。 */
454
440
  delete(key: string): Promise<void>;
455
441
  get(key: string): Promise<{
@@ -467,6 +453,475 @@ interface ObjectStore {
467
453
  put(key: string, body: ObjectBody, opts?: ObjectPutOptions): Promise<ObjectMeta>;
468
454
  }
469
455
 
456
+ declare const DEFAULT_STORE_NAME: "default";
457
+ type StoreObjectStatus = 'pending' | 'ready' | 'failed' | 'abandoned' | 'deleted';
458
+ type UploadSessionStatus = 'created' | 'completed' | 'aborted' | 'expired' | 'failed';
459
+ type StoreUploadTransport = 'relay' | 'presigned-put';
460
+ type CallUploadCapabilityStatus = 'active' | 'exhausted' | 'revoked' | 'expired';
461
+ type ShareGrantStatus = 'active' | 'revoked' | 'expired';
462
+ interface StoreChecksum {
463
+ algorithm: 'sha256';
464
+ value: string;
465
+ }
466
+ /** StoreRepository 内的权威对象记录;driverKey 绝不进入公开 descriptor。 */
467
+ interface StoreObject {
468
+ backendId: string;
469
+ /** terminal object 的 driver 字节已完成幂等删除;cleanup 以此避免每轮重复 DELETE。 */
470
+ bytesDeletedAt?: Timestamp;
471
+ checksum?: StoreChecksum;
472
+ contentType: string;
473
+ createdAt: Timestamp;
474
+ driverKey: string;
475
+ etag?: string;
476
+ expectedChecksum?: StoreChecksum;
477
+ expectedSize?: number;
478
+ expiresAt?: Timestamp;
479
+ filename?: string;
480
+ id: string;
481
+ originCallId?: string;
482
+ owner: OwnerRef;
483
+ producer?: OwnerRef;
484
+ readyAt?: Timestamp;
485
+ revision: number;
486
+ size?: number;
487
+ status: StoreObjectStatus;
488
+ store: typeof DEFAULT_STORE_NAME;
489
+ updatedAt: Timestamp;
490
+ uploadId: string;
491
+ }
492
+ /** 每个上传会话都有独立 bearer;StoreRepository 只保存其 sha256。 */
493
+ interface UploadSession {
494
+ backendId: string;
495
+ capabilityHash: string;
496
+ completedAt?: Timestamp;
497
+ contentType: string;
498
+ createdAt: Timestamp;
499
+ expectedChecksum?: StoreChecksum;
500
+ expectedSize?: number;
501
+ expiresAt: Timestamp;
502
+ id: string;
503
+ maxBytes: number;
504
+ objectId: string;
505
+ revision: number;
506
+ revokedAt?: Timestamp;
507
+ signingKeyId: string;
508
+ status: UploadSessionStatus;
509
+ /** 进入 completed/aborted/expired/failed 的时间,作为幂等保留窗口起点。 */
510
+ terminalAt?: Timestamp;
511
+ transport: StoreUploadTransport;
512
+ }
513
+ /** 远程设备调用的窄上传权限;owner 与 producer 都是稳定 OwnerRef,而不是 SK keyId。 */
514
+ interface CallUploadCapability {
515
+ allowedContentTypes: string[];
516
+ callId: string;
517
+ createdAt: Timestamp;
518
+ expiresAt: Timestamp;
519
+ id: string;
520
+ maxBytes: number;
521
+ maxObjectBytes: number;
522
+ maxObjects: number;
523
+ owner: OwnerRef;
524
+ producer: OwnerRef;
525
+ reservations: Array<{
526
+ maxBytes: number;
527
+ objectId: string;
528
+ }>;
529
+ reservedBytes: number;
530
+ revision: number;
531
+ signingKeyId: string;
532
+ status: CallUploadCapabilityStatus;
533
+ /** 进入 revoked/expired 的时间;exhausted 仍须保留到 expiresAt 供幂等 replay。 */
534
+ terminalAt?: Timestamp;
535
+ tokenHash: string;
536
+ }
537
+ /** 首期 share 是匿名、短期、可撤销的 read capability。 */
538
+ interface ShareGrant {
539
+ createdAt: Timestamp;
540
+ createdBy: OwnerRef;
541
+ expiresAt: Timestamp;
542
+ id: string;
543
+ objectId: string;
544
+ revision: number;
545
+ signingKeyId: string;
546
+ status: ShareGrantStatus;
547
+ /** 进入 revoked/expired 的时间,作为撤销传播后的安全保留窗口起点。 */
548
+ terminalAt?: Timestamp;
549
+ tokenHash: string;
550
+ }
551
+
552
+ interface StoreIdempotencyBinding {
553
+ createdAt: string;
554
+ domain: 'call' | 'owner';
555
+ expiresAt: string;
556
+ fingerprint: string;
557
+ objectId: string;
558
+ originCallId?: string;
559
+ owner: string;
560
+ producer: string;
561
+ revision: number;
562
+ uploadId: string;
563
+ }
564
+ /** Typed entity access; multi-record transitions belong to the domain operations below. */
565
+ interface StoreRecords<T extends {
566
+ revision: number;
567
+ }> {
568
+ compare(id: string, revision: number | null, next: T | null): Promise<boolean>;
569
+ get(id: string): Promise<T | null>;
570
+ list(opts: {
571
+ cursor?: string;
572
+ limit: number;
573
+ }): Promise<{
574
+ cursor?: string;
575
+ items: Array<{
576
+ key: string;
577
+ value: T;
578
+ }>;
579
+ }>;
580
+ }
581
+ interface BeginStoreUpload {
582
+ binding?: {
583
+ id: string;
584
+ record: StoreIdempotencyBinding;
585
+ };
586
+ capability?: {
587
+ id: string;
588
+ tokenHash: string;
589
+ };
590
+ now: string;
591
+ object: StoreObject;
592
+ session: UploadSession;
593
+ }
594
+ interface StoreRepository {
595
+ /** Atomically binds identity, checks/reserves cumulative quota and creates both records. */
596
+ beginUpload(input: BeginStoreUpload): Promise<{
597
+ object: StoreObject;
598
+ session: UploadSession;
599
+ } | 'backend_changed'>;
600
+ callCapabilities: StoreRecords<CallUploadCapability>;
601
+ /** Object readiness and session completion commit together; reservations remain consumed. */
602
+ finishUpload(object: StoreObject, session: UploadSession): Promise<StoreObject | null>;
603
+ idempotencyBindings: StoreRecords<StoreIdempotencyBinding>;
604
+ listReadyObjects(owner: string, opts: {
605
+ cursor?: string;
606
+ limit: number;
607
+ }): Promise<{
608
+ cursor?: string;
609
+ items: StoreObject[];
610
+ }>;
611
+ objects: StoreRecords<StoreObject>;
612
+ shares: StoreRecords<ShareGrant>;
613
+ /** Aborting/expiring/failing cannot race a ready object into an inconsistent session. */
614
+ terminateUpload(object: StoreObject, session: UploadSession): Promise<boolean>;
615
+ uploads: StoreRecords<UploadSession>;
616
+ }
617
+ interface StoreBackendResolver {
618
+ defaultBackend(): Promise<{
619
+ id: string;
620
+ objects: ObjectStore;
621
+ }>;
622
+ resolveBackend(id: string): Promise<ObjectStore>;
623
+ }
624
+
625
+ type KeyTarget = 'encryption' | 'signing';
626
+ interface KeyRotateInput {
627
+ expectedRevision: number;
628
+ revokeExisting?: boolean;
629
+ target: KeyTarget;
630
+ }
631
+ interface KeyRetireInput {
632
+ expectedRevision: number;
633
+ keyId: string;
634
+ target: KeyTarget;
635
+ }
636
+ interface KeyResumeInput {
637
+ jobId: string;
638
+ }
639
+ interface ManagedKeyView {
640
+ active: boolean;
641
+ keyId: string;
642
+ references: number;
643
+ retireAfter?: string;
644
+ }
645
+ interface KeyRingStatus {
646
+ activeKeyId: string;
647
+ keys: ManagedKeyView[];
648
+ }
649
+ interface KeyJobView {
650
+ changed: number;
651
+ error?: string;
652
+ id: string;
653
+ phase: 'secrets' | 'mailbox' | 'verify';
654
+ status: 'running' | 'failed' | 'completed';
655
+ targetKeyId: string;
656
+ }
657
+ interface KeyStatus {
658
+ encryption: KeyRingStatus;
659
+ instanceId: string;
660
+ jobId?: string;
661
+ jobs: KeyJobView[];
662
+ revision: number;
663
+ signing: KeyRingStatus;
664
+ }
665
+ /** Explicit secret export. Never put this result into generic command history or logs. */
666
+ interface KeyBackup {
667
+ exportedAt: string;
668
+ instanceId: string;
669
+ keyring: EncryptionKeyring;
670
+ oauthKey: string;
671
+ signingRetireAfter?: Record<string, string>;
672
+ storeTokenKeyring: StoreTokenKeyring;
673
+ version: 1;
674
+ }
675
+ interface KeyManagement {
676
+ backup(): Promise<KeyBackup>;
677
+ resume(input: KeyResumeInput): Promise<KeyStatus>;
678
+ retire(input: KeyRetireInput): Promise<KeyStatus>;
679
+ rotate(input: KeyRotateInput): Promise<KeyStatus>;
680
+ status(): Promise<KeyStatus>;
681
+ }
682
+
683
+ interface DeploymentSettings {
684
+ bindAddress: '127.0.0.1' | '0.0.0.0';
685
+ hostPort: number;
686
+ image: string;
687
+ stateDirectory?: string;
688
+ uiDirectory?: string;
689
+ }
690
+ interface DeploymentJobView {
691
+ createdAt: string;
692
+ error?: string;
693
+ id: string;
694
+ revision: number;
695
+ state: 'queued' | 'claimed' | 'succeeded' | 'failed';
696
+ }
697
+ interface DeploymentStatus {
698
+ agentConnected: boolean;
699
+ appliedRevision: number;
700
+ desired: DeploymentSettings | null;
701
+ effective: DeploymentSettings | null;
702
+ instanceId: string;
703
+ job?: DeploymentJobView;
704
+ revision: number;
705
+ state: 'unmanaged' | 'disconnected' | 'applied' | 'pending' | 'applying' | 'failed' | 'drifted';
706
+ }
707
+ interface DeploymentClaim {
708
+ desired: DeploymentSettings;
709
+ instanceId: string;
710
+ jobId: string;
711
+ leaseExpiresAt: string;
712
+ leaseToken: string;
713
+ previous: DeploymentSettings;
714
+ revision: number;
715
+ }
716
+ interface DeploymentManagement {
717
+ claim(input: {
718
+ agentId: string;
719
+ instanceId: string;
720
+ observed: DeploymentSettings;
721
+ }): Promise<{
722
+ job: DeploymentClaim | null;
723
+ }>;
724
+ complete(input: {
725
+ error?: 'preflight_failed' | 'apply_failed' | 'health_failed' | 'rollback_failed';
726
+ jobId: string;
727
+ leaseToken: string;
728
+ ok: boolean;
729
+ }): Promise<DeploymentStatus>;
730
+ get(): Promise<DeploymentStatus>;
731
+ update(input: {
732
+ expectedRevision: number;
733
+ settings: DeploymentSettings;
734
+ }): Promise<DeploymentStatus>;
735
+ }
736
+
737
+ declare const databaseMigrationSchema: z.ZodObject<{
738
+ expectedRevision: z.ZodNumber;
739
+ expectedInstanceId: z.ZodString;
740
+ databaseUrl: z.ZodString;
741
+ }, z.core.$strict>;
742
+ declare const databaseCredentialRotationSchema: z.ZodObject<{
743
+ databaseAdminUrl: z.ZodOptional<z.ZodString>;
744
+ expectedRevision: z.ZodNumber;
745
+ expectedInstanceId: z.ZodString;
746
+ password: z.ZodString;
747
+ }, z.core.$strict>;
748
+ declare const redisMaintenanceSchema: z.ZodObject<{
749
+ expectedRevision: z.ZodNumber;
750
+ redisUrl: z.ZodNullable<z.ZodString>;
751
+ }, z.core.$strict>;
752
+ interface MaintenanceJournal {
753
+ lastError?: string;
754
+ operation: 'database' | 'database_credentials' | 'redis';
755
+ phase: 'running' | 'failed' | 'complete';
756
+ startedAt: string;
757
+ step: string;
758
+ }
759
+ interface MaintenanceStatus {
760
+ database: {
761
+ host: string;
762
+ name: string;
763
+ port: number;
764
+ user: string;
765
+ };
766
+ journal?: MaintenanceJournal;
767
+ redisConfigured: boolean;
768
+ revision: number;
769
+ }
770
+ interface MaintenanceManagement {
771
+ database(input: z.infer<typeof databaseMigrationSchema>): Promise<MaintenanceStatus>;
772
+ redis(input: z.infer<typeof redisMaintenanceSchema>): Promise<MaintenanceStatus>;
773
+ rotate_database_credentials(input: z.infer<typeof databaseCredentialRotationSchema>): Promise<MaintenanceStatus>;
774
+ status(): Promise<MaintenanceStatus>;
775
+ }
776
+
777
+ /** Plain public output types; schema conformance is checked below without leaking Zod into SDK declarations. */
778
+ type RuntimeConfig = {
779
+ canonicalOrigin: string;
780
+ deviceReclaimSec: number;
781
+ maxHops: number;
782
+ refThresholdBytes: number;
783
+ refTtlSec: number;
784
+ remoteAllowlist: string[];
785
+ searchConcurrency: number;
786
+ searchDeadlineMs: number;
787
+ searchMaxResponseBytes: number;
788
+ searchMaxSources: number;
789
+ searchMinChildWorkMs: number;
790
+ searchReturnReserveMs: number;
791
+ searchSessionTtlSec: number;
792
+ shutdownDrainSec: number;
793
+ storeCallAllowedContentTypes: string[];
794
+ storeCallMaxBytes: number;
795
+ storeCallMaxObjectBytes: number;
796
+ storeCallMaxObjects: number;
797
+ storeCleanupIntervalSec: number;
798
+ storeMaxObjectBytes: number;
799
+ storeReadTtlSec: number;
800
+ storeRelayMaxBytes: number;
801
+ storeShareTtlSec: number;
802
+ storeUploadTtlSec: number;
803
+ toolCacheTtlSec: number;
804
+ uploadGrantTtlSec: number;
805
+ };
806
+ type SetupInput = {
807
+ databaseUrl?: string;
808
+ redisUrl?: string;
809
+ settings: RuntimeConfig;
810
+ storage?: {
811
+ accessKeyId: string;
812
+ bucket: string;
813
+ endpoint: string;
814
+ region: string;
815
+ secretAccessKey: string;
816
+ };
817
+ };
818
+ declare const configUpdateSchema: z.ZodObject<{
819
+ expectedRevision: z.ZodNumber;
820
+ settings: z.ZodObject<{
821
+ canonicalOrigin: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<"">, z.ZodURL]>>;
822
+ remoteAllowlist: z.ZodDefault<z.ZodArray<z.ZodString>>;
823
+ maxHops: z.ZodDefault<z.ZodNumber>;
824
+ deviceReclaimSec: z.ZodDefault<z.ZodNumber>;
825
+ toolCacheTtlSec: z.ZodDefault<z.ZodNumber>;
826
+ refThresholdBytes: z.ZodDefault<z.ZodNumber>;
827
+ refTtlSec: z.ZodDefault<z.ZodNumber>;
828
+ uploadGrantTtlSec: z.ZodDefault<z.ZodNumber>;
829
+ storeMaxObjectBytes: z.ZodDefault<z.ZodNumber>;
830
+ storeRelayMaxBytes: z.ZodDefault<z.ZodNumber>;
831
+ storeCallMaxBytes: z.ZodDefault<z.ZodNumber>;
832
+ storeCallMaxObjectBytes: z.ZodDefault<z.ZodNumber>;
833
+ storeCallMaxObjects: z.ZodDefault<z.ZodNumber>;
834
+ storeCallAllowedContentTypes: z.ZodDefault<z.ZodArray<z.ZodString>>;
835
+ storeUploadTtlSec: z.ZodDefault<z.ZodNumber>;
836
+ storeShareTtlSec: z.ZodDefault<z.ZodNumber>;
837
+ storeReadTtlSec: z.ZodDefault<z.ZodNumber>;
838
+ storeCleanupIntervalSec: z.ZodDefault<z.ZodNumber>;
839
+ searchConcurrency: z.ZodDefault<z.ZodNumber>;
840
+ searchDeadlineMs: z.ZodDefault<z.ZodNumber>;
841
+ searchMaxResponseBytes: z.ZodDefault<z.ZodNumber>;
842
+ searchMaxSources: z.ZodDefault<z.ZodNumber>;
843
+ searchMinChildWorkMs: z.ZodDefault<z.ZodNumber>;
844
+ searchReturnReserveMs: z.ZodDefault<z.ZodNumber>;
845
+ searchSessionTtlSec: z.ZodDefault<z.ZodNumber>;
846
+ shutdownDrainSec: z.ZodDefault<z.ZodNumber>;
847
+ }, z.core.$strict>;
848
+ }, z.core.$strict>;
849
+ declare const revisionSchema: z.ZodObject<{
850
+ expectedRevision: z.ZodNumber;
851
+ }, z.core.$strict>;
852
+ declare const storageWriteSchema: z.ZodObject<{
853
+ name: z.ZodString;
854
+ connection: z.ZodObject<{
855
+ endpoint: z.ZodURL;
856
+ bucket: z.ZodString;
857
+ region: z.ZodDefault<z.ZodString>;
858
+ accessKeyId: z.ZodString;
859
+ secretAccessKey: z.ZodString;
860
+ }, z.core.$strict>;
861
+ }, z.core.$strict>;
862
+ declare const storageIdSchema: z.ZodObject<{
863
+ id: z.ZodString;
864
+ }, z.core.$strict>;
865
+ declare const storageRevisionSchema: z.ZodObject<{
866
+ id: z.ZodString;
867
+ expectedRevision: z.ZodNumber;
868
+ }, z.core.$strict>;
869
+ declare const storageActivateSchema: z.ZodObject<{
870
+ id: z.ZodString;
871
+ expectedRevision: z.ZodNumber;
872
+ expectedActiveRevision: z.ZodNumber;
873
+ }, z.core.$strict>;
874
+ declare const storageRotateSchema: z.ZodObject<{
875
+ id: z.ZodString;
876
+ expectedRevision: z.ZodNumber;
877
+ accessKeyId: z.ZodString;
878
+ secretAccessKey: z.ZodString;
879
+ }, z.core.$strict>;
880
+ interface ConfigStatus {
881
+ appliedRevision: number;
882
+ desired: RuntimeConfig;
883
+ effective: RuntimeConfig;
884
+ lastError?: string;
885
+ revision: number;
886
+ state: 'applied' | 'pending' | 'applying' | 'failed';
887
+ }
888
+ interface StorageBackendView {
889
+ active: boolean;
890
+ activeRevision: number;
891
+ bucket: string;
892
+ credentialConfigured: boolean;
893
+ credentialGeneration: number;
894
+ endpoint: string;
895
+ id: string;
896
+ name: string;
897
+ region: string;
898
+ revision: number;
899
+ validated: boolean;
900
+ validation?: {
901
+ at: string;
902
+ checks: Record<string, boolean>;
903
+ cleanupSucceeded: boolean;
904
+ };
905
+ }
906
+ interface ConfigManagement {
907
+ apply(input: z.infer<typeof revisionSchema>): Promise<ConfigStatus>;
908
+ get(): Promise<ConfigStatus>;
909
+ update(input: z.infer<typeof configUpdateSchema>): Promise<ConfigStatus>;
910
+ }
911
+ interface StorageManagement {
912
+ activate(input: z.infer<typeof storageActivateSchema>): Promise<StorageBackendView>;
913
+ delete(input: z.infer<typeof storageRevisionSchema>): Promise<{
914
+ ok: true;
915
+ }>;
916
+ get(input: z.infer<typeof storageIdSchema>): Promise<StorageBackendView>;
917
+ list(): Promise<{
918
+ items: StorageBackendView[];
919
+ }>;
920
+ test(input: z.infer<typeof storageRevisionSchema>): Promise<StorageBackendView>;
921
+ update(input: z.infer<typeof storageRotateSchema>): Promise<StorageBackendView>;
922
+ write(input: z.infer<typeof storageWriteSchema>): Promise<StorageBackendView>;
923
+ }
924
+
470
925
  /**
471
926
  * Context Layer 类型(原样转写;方法签名异步化以兼容对象存储后端)。
472
927
  *
@@ -611,6 +1066,231 @@ interface DeviceCallContext {
611
1066
  };
612
1067
  }
613
1068
 
1069
+ interface MailboxQuery {
1070
+ /** Select only queued/expired-lease candidates for this device credential. */
1071
+ claimableBy?: string;
1072
+ cursor?: string;
1073
+ deviceId?: string;
1074
+ limit: number;
1075
+ now?: string;
1076
+ states?: DeviceOperationState[];
1077
+ }
1078
+ interface MailboxRepository {
1079
+ claimNext(record: DeviceOperationRecord, expectedRevision: number, now: string): Promise<boolean>;
1080
+ compare(operationId: string, revision: number, next: DeviceOperationRecord | null): Promise<boolean>;
1081
+ complete(record: DeviceOperationRecord, expectedRevision: number, now: string): Promise<boolean>;
1082
+ enqueue(record: DeviceOperationRecord, maxPendingPerDevice: number, now: string): Promise<DeviceOperationRecord>;
1083
+ get(operationId: string): Promise<DeviceOperationRecord | null>;
1084
+ list(query: MailboxQuery): Promise<{
1085
+ cursor?: string;
1086
+ items: Array<{
1087
+ key: string;
1088
+ value: DeviceOperationRecord;
1089
+ }>;
1090
+ }>;
1091
+ renew(record: DeviceOperationRecord, expectedRevision: number, now: string): Promise<boolean>;
1092
+ }
1093
+
1094
+ /**
1095
+ * Durable device mailbox authority.
1096
+ *
1097
+ * A domain repository atomically owns quota, candidate claims and valid-lease completion. Arguments and terminal data are
1098
+ * encrypted with a mailbox-specific HKDF child key; the deployment root is
1099
+ * never persisted and this is deliberately at-rest rather than E2E encryption.
1100
+ */
1101
+
1102
+ declare const DEVICE_OPERATION_STATES: readonly ["queued", "claimed", "succeeded", "rejected", "failed", "result_unknown", "cancelled", "expired"];
1103
+ type DeviceOperationState = typeof DEVICE_OPERATION_STATES[number];
1104
+ interface DeviceOperationCaller {
1105
+ keyId: string;
1106
+ owner: OwnerRef;
1107
+ }
1108
+ interface DeviceOperationSummary {
1109
+ attempt: number;
1110
+ caller: DeviceOperationCaller;
1111
+ cancelRequestedAt?: Timestamp;
1112
+ createdAt: Timestamp;
1113
+ deviceId: string;
1114
+ executionMayHaveOccurred: boolean;
1115
+ expiresAt: Timestamp;
1116
+ leaseUntil?: Timestamp;
1117
+ mountPath: TreePath;
1118
+ operationId: string;
1119
+ state: DeviceOperationState;
1120
+ targetPath: TreePath;
1121
+ terminalAt?: Timestamp;
1122
+ traceId: string;
1123
+ updatedAt: Timestamp;
1124
+ }
1125
+ interface DeviceOperationDetail extends DeviceOperationSummary {
1126
+ error?: TBErrorBody;
1127
+ result?: unknown;
1128
+ }
1129
+ interface DeviceOperationClaim {
1130
+ arguments: Record<string, unknown>;
1131
+ attempt: number;
1132
+ caller: DeviceOperationCaller;
1133
+ cancelRequestedAt?: Timestamp;
1134
+ createdAt: Timestamp;
1135
+ expiresAt: Timestamp;
1136
+ leaseId: string;
1137
+ leaseUntil: Timestamp;
1138
+ operationId: string;
1139
+ path: string;
1140
+ targetPath: TreePath;
1141
+ traceId: string;
1142
+ }
1143
+ type DeviceOperationCompletion = {
1144
+ outcome: 'succeeded';
1145
+ result: unknown;
1146
+ } | {
1147
+ error: TBErrorBody;
1148
+ outcome: 'rejected' | 'failed';
1149
+ } | {
1150
+ error?: TBErrorBody;
1151
+ outcome: 'result_unknown';
1152
+ };
1153
+ interface DeviceOperationEnqueueInput {
1154
+ arguments: Record<string, unknown>;
1155
+ caller: DeviceOperationCaller;
1156
+ deviceId: string;
1157
+ deviceKeyId: string;
1158
+ idempotencyKey?: string;
1159
+ mountPath: TreePath;
1160
+ path: string;
1161
+ targetPath: TreePath;
1162
+ traceId: string;
1163
+ ttlSeconds?: number;
1164
+ }
1165
+ interface DeviceOperationListInput {
1166
+ cursor?: string;
1167
+ deviceId: string;
1168
+ limit?: number;
1169
+ states?: readonly DeviceOperationState[];
1170
+ }
1171
+ interface DeviceOperationClaimInput {
1172
+ authorize?: (target: DeviceOperationAuthorizationTarget) => Promise<void> | void;
1173
+ cursor?: string;
1174
+ deviceId: string;
1175
+ deviceKeyId: string;
1176
+ limit?: number;
1177
+ }
1178
+ interface DeviceOperationLeaseInput {
1179
+ authorize?: (target: DeviceOperationAuthorizationTarget) => Promise<void> | void;
1180
+ deviceId: string;
1181
+ deviceKeyId: string;
1182
+ leaseId: string;
1183
+ operationId: string;
1184
+ }
1185
+ interface DeviceOperationAuthorizationTarget {
1186
+ deviceId: string;
1187
+ deviceKeyId: string;
1188
+ mountPath: TreePath;
1189
+ targetPath: TreePath;
1190
+ }
1191
+ interface DeviceMailboxPage<T> {
1192
+ cursor?: string;
1193
+ items: T[];
1194
+ }
1195
+ interface DeviceOperationClaimPage {
1196
+ cursor?: string;
1197
+ operation?: DeviceOperationClaim;
1198
+ serverNow: Timestamp;
1199
+ }
1200
+ interface DeviceOperationRenewResult {
1201
+ cancelRequestedAt?: Timestamp;
1202
+ leaseUntil: Timestamp;
1203
+ serverNow: Timestamp;
1204
+ }
1205
+ interface DeviceMailboxCleanupResult {
1206
+ cursor?: string;
1207
+ deleted: number;
1208
+ expired: number;
1209
+ scanned: number;
1210
+ }
1211
+ interface DeviceMailboxServiceOptions {
1212
+ defaultTtlSeconds?: number;
1213
+ leaseSeconds?: number;
1214
+ /** 分别约束入队 arguments 与终态 result/error 的 canonical JSON 明文字节数。 */
1215
+ maxPayloadBytes?: number;
1216
+ maxPendingPerDevice?: number;
1217
+ maxTtlSeconds?: number;
1218
+ now?: () => number;
1219
+ randomBytes?: (length: number) => Uint8Array;
1220
+ terminalRetentionSeconds?: number;
1221
+ }
1222
+ interface EncryptedMailboxValue {
1223
+ ciphertext: string;
1224
+ iv: string;
1225
+ keyId: string;
1226
+ v: 1;
1227
+ }
1228
+ interface DeviceOperationRecord {
1229
+ attempt: number;
1230
+ callerKeyId: string;
1231
+ callerOwner: OwnerRef;
1232
+ cancelRequestedAt?: Timestamp;
1233
+ completedLeaseId?: string;
1234
+ createdAt: Timestamp;
1235
+ deviceId: string;
1236
+ deviceKeyId: string;
1237
+ executionMayHaveOccurred: boolean;
1238
+ expiresAt: Timestamp;
1239
+ idempotencyFingerprint?: string;
1240
+ leaseId?: string;
1241
+ leaseUntil?: Timestamp;
1242
+ mountPath: TreePath;
1243
+ operationId: string;
1244
+ path: string;
1245
+ payload: EncryptedMailboxValue;
1246
+ revision: number;
1247
+ state: DeviceOperationState;
1248
+ targetPath: TreePath;
1249
+ terminalAt?: Timestamp;
1250
+ terminalData?: EncryptedMailboxValue;
1251
+ traceId: string;
1252
+ updatedAt: Timestamp;
1253
+ v: 1;
1254
+ }
1255
+ declare class DeviceMailboxService {
1256
+ private readonly cipher;
1257
+ private readonly defaultTtlSeconds;
1258
+ private readonly leaseSeconds;
1259
+ private readonly maxPayloadBytes;
1260
+ private readonly maxPendingPerDevice;
1261
+ private readonly maxTtlSeconds;
1262
+ private readonly now;
1263
+ private readonly randomBytes;
1264
+ private readonly terminalRetentionSeconds;
1265
+ private readonly repository;
1266
+ constructor(repository: MailboxRepository, encryptionRoot: EncryptionKeyring | string | undefined, opts?: DeviceMailboxServiceOptions);
1267
+ private nowIso;
1268
+ private read;
1269
+ private summary;
1270
+ private detail;
1271
+ private expireRecord;
1272
+ enqueue(input: DeviceOperationEnqueueInput): Promise<DeviceOperationDetail>;
1273
+ get(deviceId: string, operationId: string): Promise<DeviceOperationDetail>;
1274
+ list(input: DeviceOperationListInput): Promise<DeviceMailboxPage<DeviceOperationSummary>>;
1275
+ claim(input: DeviceOperationClaimInput): Promise<DeviceOperationClaimPage>;
1276
+ private activeLease;
1277
+ renew(input: DeviceOperationLeaseInput): Promise<DeviceOperationRenewResult>;
1278
+ complete(input: DeviceOperationLeaseInput, completionInput: DeviceOperationCompletion): Promise<DeviceOperationDetail>;
1279
+ cancel(deviceId: string, operationId: string): Promise<DeviceOperationDetail>;
1280
+ /** Re-encrypt only unchanged ledger revisions; concurrent lease/terminal transitions retain authority. */
1281
+ reencryptPage(opts?: {
1282
+ cursor?: string;
1283
+ limit?: number;
1284
+ }): Promise<{
1285
+ changed: number;
1286
+ cursor?: string;
1287
+ }>;
1288
+ cleanup(opts?: {
1289
+ cursor?: string;
1290
+ limit?: number;
1291
+ }): Promise<DeviceMailboxCleanupResult>;
1292
+ }
1293
+
614
1294
  /**
615
1295
  * 网关侧设备会话状态机(纯逻辑,I/O 与时间注入,DO 只做胶水)。
616
1296
  *
@@ -695,13 +1375,6 @@ interface ToolSearchOptions {
695
1375
  mode?: 'keyword';
696
1376
  pathPrefix?: TreePath;
697
1377
  }
698
- /** 会改变候选集合或分页档位的规范化约束;cursor 必须绑定其完整指纹。 */
699
- interface NormalizedToolSearchOptions {
700
- effects?: ToolSearchEffect[];
701
- matching: ToolSearchMatching;
702
- minCoverage?: number;
703
- pathPrefix?: TreePath;
704
- }
705
1378
  /** 宿主提供的全局工具索引;权限和虚拟化仍由 gateway 处理。 */
706
1379
  interface SearchIndex {
707
1380
  readonly capabilities: readonly SearchCapability[];
@@ -737,93 +1410,25 @@ interface MutableSearchIndex extends SearchIndex {
737
1410
  }): Promise<void>;
738
1411
  }
739
1412
 
740
- /**
741
- * SQL SearchIndex 的共享实现——D1、better-sqlite3 与 PostgreSQL 三个 adapter
742
- * 的编排与候选检索唯一真源。
743
- *
744
- * 此前两边各持一份逐行相同的 schema DDL、查询 SQL、material-change 判定与
745
- * cursor/分页逻辑(共 ~780 行,重合度 >85%),任何一侧改动都得靠人工纪律同步到另
746
- * 一侧。这里把**所有**与具体驱动无关的部分收进 `SqlSearchIndex`,宿主差异压缩成
747
- * `SqlSearchDriver` 的五个
748
- * 方法:
749
- *
750
- * - D1 全异步、写入走 `db.batch()`,且单请求有 50 查询预算 —— 故记录插入必须
751
- * 攒成 JSON1 块(`insertRecords` 返回少量语句)并声明 `assertInsertBudget`;
752
- * - better-sqlite3 全同步、写入走 `db.transaction()`,无查询预算 —— 逐条插入即可。
753
- *
754
- * core 是宿主中立层:这里只产出 SQL 文本与参数数组,不认识 D1Database 也不认识
755
- * better-sqlite3。
756
- */
1413
+ /** PostgreSQL search SQL: schema, bounded bulk writes and coverage-ranked candidate queries. */
757
1414
 
758
- /** 一条待执行语句:SQL 文本 + 按序绑定的参数,不含任何驱动对象。 */
1415
+ /** SQL text and ordered PostgreSQL parameters; no runtime driver dependencies. */
759
1416
  interface SqlSearchStatement {
760
1417
  readonly params: readonly unknown[];
761
1418
  readonly sql: string;
762
1419
  }
763
- /**
764
- * 固定形态语句:参数个数与语义在 core 编排里写死,方言只提供 SQL 文本。
765
- * 占位符语法(`?` / `$n`)与字符串函数由各方言自行决定。
766
- */
767
- interface SqlSearchStatements {
768
- readonly bumpRevision: string;
769
- readonly completeRebuild: string;
770
- readonly deleteAllSnapshots: string;
771
- readonly deleteAllTools: string;
772
- readonly deleteSnapshot: string;
773
- readonly deleteSnapshotPrefix: string;
774
- readonly deleteTools: string;
775
- readonly deleteToolsPrefix: string;
776
- /** 单 path 的 path→digest 快照插入(replace 内联使用)。 */
777
- readonly insertSnapshot: string;
778
- /** 读 meta 单例(revision/seeded/cursor_secret)。 */
779
- readonly meta: string;
780
- /** replace 前置探测:本 path 的 digest、是否残留 source 行、已用节点数。 */
781
- readonly pathState: string;
782
- /** 单 path 是否存在 source 行。 */
783
- readonly present: string;
784
- /** path 或其子树是否存在 source 行。 */
785
- readonly presentPrefix: string;
786
- /** 全量快照 digest,按 path 升序。 */
787
- readonly snapshotDigests: string;
788
- }
789
- /**
790
- * SQL 方言:把与具体引擎绑定的 SQL 文本从数据库无关的编排里分出来。
791
- *
792
- * `SqlSearchIndex` 只认识本接口——候选查询 + 一组固定语句 + 建表 DDL。
793
- * D1 与 better-sqlite3 同为 SQLite,共用 {@link sqliteSearchDialect};其它引擎
794
- * (如 Postgres)实现自己的方言,替换占位符与大小写折叠语法。方言只管 SQL 文本,
795
- * 具体驱动的同步/异步、批量预算、结果整形仍由 {@link SqlSearchDriver} 吸收。
796
- */
797
- interface SqlSearchDialect {
798
- /**
799
- * 把已 normalize 的 query 变成候选查询语句(含排序与分页)。三后端共用查询单元
800
- * 展开和评分形态,方言只选择占位符语法与 LIKE/ILIKE。
801
- */
802
- candidateStatement(query: string, limit: number, offset: number, constraints?: NormalizedToolSearchOptions): SqlSearchStatement;
803
- /** 建表(幂等),元素不带尾分号。 */
804
- readonly schemaStatements: readonly string[];
805
- /** 编排直接下发的固定语句。 */
806
- readonly statements: SqlSearchStatements;
807
- }
808
- /**
809
- * 宿主驱动:把 `SqlSearchStatement` 落到具体数据库上。
810
- *
811
- * `write` 必须原子(D1 `batch` / SQLite `transaction`)——revision bump 与数据变更
812
- * 分裂会让 cursor 指向不存在的 offset。
813
- */
1420
+
1421
+ /** PostgreSQL SearchIndex orchestration: atomic mutations, snapshot revisions and sealed cursors. */
1422
+
1423
+ /** PostgreSQL I/O boundary. All mutations execute in one transaction under the search write lock. */
814
1424
  interface SqlSearchDriver {
815
1425
  /** 多行只读查询。 */
816
1426
  all: <T>(statement: SqlSearchStatement) => Promise<T[]>;
817
- /**
818
- * 记录插入语句数上限(可选);只有查询预算受限的宿主(D1 50/请求)需要实现。
819
- * `count` 是本次 mutation 的记录 + 快照插入语句总数,不含固定的删除/bump。
820
- */
821
- assertInsertBudget?: (count: number) => void;
822
- /** 建表(幂等);构造时已建好的宿主实现成 no-op。 */
1427
+ /** 建表(幂等),初始化状态由 PG 驱动维护。 */
823
1428
  ensureSchema: () => Promise<void>;
824
1429
  /** 单行只读查询;无行返回 null。 */
825
1430
  first: <T>(statement: SqlSearchStatement) => Promise<T | null>;
826
- /** 把记录变成插入语句(JSON1 攒块 or 逐条绑定)。 */
1431
+ /** 把记录分成有界的 PostgreSQL 多行 VALUES 插入语句。 */
827
1432
  insertRecords: (records: readonly SerializedToolSearchRecord[]) => SqlSearchStatement[];
828
1433
  /** 把 path→digest 快照变成插入语句。 */
829
1434
  insertSnapshots: (digests: ReadonlyMap<TreePath, string>) => SqlSearchStatement[];
@@ -832,10 +1437,9 @@ interface SqlSearchDriver {
832
1437
  }
833
1438
  declare class SqlSearchIndex implements MutableSearchIndex {
834
1439
  readonly capabilities: readonly SearchCapability[];
835
- protected readonly dialect: SqlSearchDialect;
836
1440
  protected readonly driver: SqlSearchDriver;
837
- constructor(driver: SqlSearchDriver, dialect?: SqlSearchDialect);
838
- /** 容量 trigger 的 ABORT 在各驱动里错误形状不同,统一按标记串归一。 */
1441
+ constructor(driver: SqlSearchDriver);
1442
+ /** PG 容量触发器的失败按固定标记归一。 */
839
1443
  private writeOrCapacity;
840
1444
  private meta;
841
1445
  private snapshotDigests;
@@ -851,6 +1455,54 @@ declare class SqlSearchIndex implements MutableSearchIndex {
851
1455
  cursorFor(query: string, candidate: ToolSearchCandidate, mode?: 'keyword'): Promise<string>;
852
1456
  }
853
1457
 
1458
+ declare const stateSchema: z.ZodObject<{
1459
+ instanceId: z.ZodUUID;
1460
+ revision: z.ZodNumber;
1461
+ phase: z.ZodEnum<{
1462
+ setup: "setup";
1463
+ installing: "installing";
1464
+ initialized: "initialized";
1465
+ }>;
1466
+ databaseUrl: z.ZodOptional<z.ZodString>;
1467
+ redisUrl: z.ZodOptional<z.ZodString>;
1468
+ internalS3Origin: z.ZodOptional<z.ZodString>;
1469
+ port: z.ZodDefault<z.ZodNumber>;
1470
+ host: z.ZodDefault<z.ZodString>;
1471
+ }, z.core.$strict>;
1472
+ type BootstrapState = z.infer<typeof stateSchema>;
1473
+ interface BootstrapSecrets {
1474
+ adminSk: string;
1475
+ keyring: EncryptionKeyring;
1476
+ oauthKey: string;
1477
+ signingRetireAfter?: Record<string, string>;
1478
+ storeTokenKeyring: StoreTokenKeyring;
1479
+ }
1480
+ interface Pairing {
1481
+ expiresAt: number;
1482
+ instanceId: string;
1483
+ mode: 'setup' | 'recovery';
1484
+ tokenHash: string;
1485
+ }
1486
+ declare class BootstrapStateStore {
1487
+ readonly directory: string;
1488
+ constructor(directory: string);
1489
+ path(name: string): string;
1490
+ exclusive<T>(run: () => Promise<T>, retries?: number): Promise<T>;
1491
+ read<T>(name: string): Promise<T | undefined>;
1492
+ write(name: string, value: unknown): Promise<void>;
1493
+ state(): Promise<BootstrapState | undefined>;
1494
+ initialize(): Promise<BootstrapState>;
1495
+ private pair;
1496
+ createLocalPairing(mode: Pairing['mode']): Promise<string>;
1497
+ private hash;
1498
+ authorize(token: string | undefined, mode: Pairing['mode']): Promise<BootstrapState>;
1499
+ finish(state: BootstrapState): Promise<void>;
1500
+ defaults(): Promise<(SetupInput & {
1501
+ databaseAdminUrl?: string;
1502
+ }) | undefined>;
1503
+ secureDirectory(): Promise<void>;
1504
+ }
1505
+
854
1506
  /**
855
1507
  * Plugin 传输客户端:探活、契约抓取、envelope 调用。
856
1508
  *
@@ -932,6 +1584,14 @@ interface FederatedSearchSettings {
932
1584
  * 装配在 tbApp.ts。
933
1585
  */
934
1586
 
1587
+ /** Node S3 adapter configuration; this data type has no host dependencies. */
1588
+ interface S3StoreConfig {
1589
+ accessKeyId: string;
1590
+ bucket: string;
1591
+ endpoint: string;
1592
+ region?: string;
1593
+ secretAccessKey: string;
1594
+ }
935
1595
  /** 帧协议 call 转发的入参(id 由调用点生成,幂等键)。 */
936
1596
  interface DeviceInvokeRequest {
937
1597
  arguments: Record<string, unknown>;
@@ -941,7 +1601,7 @@ interface DeviceInvokeRequest {
941
1601
  /** 相对 mountPath 且含命令叶子段,如 "shell/exec"、"fs/get"。 */
942
1602
  path: string;
943
1603
  }
944
- /** 设备通道宿主(CF = DeviceSession DO / Docker = ws)。 */
1604
+ /** 宿主提供的设备通道,标准 Node 服务使用 WebSocket。 */
945
1605
  interface DeviceChannel {
946
1606
  /** HTTP→WS 调用转发,并显式报告是否已 dispatch,供安全 Mailbox fallback 判定。 */
947
1607
  invoke(deviceId: string, req: DeviceInvokeRequest): Promise<DeviceCallAttempt>;
@@ -969,30 +1629,49 @@ interface ReadinessReport {
969
1629
  }
970
1630
  /**
971
1631
  * tb app 的宿主注入面(数据/设备五注入点 + 安全出站通道 + 解析后的部署配置)。
972
- * 核心业务逻辑零分叉:Workers 适配层(app.ts)与 SDK(packages/sdk)都注入此形状。
1632
+ * Node 服务与嵌入式 SDK 共用此形状,业务规则由 app 层统一执行。
973
1633
  */
974
1634
  interface TbAppDeps {
1635
+ adminAudit?: (event: {
1636
+ action: string;
1637
+ actor: string;
1638
+ id: string;
1639
+ outcome: 'started' | 'succeeded' | 'failed';
1640
+ }) => Promise<void>;
975
1641
  /** 放行 http:// 上游(仅本地开发)。 */
976
1642
  allowInsecureHttp: boolean;
977
- /** Dashboard 静态资源(Workers Static Assets);缺省 → /ui 404。 */
1643
+ /** Dashboard 静态资源处理器;缺省 → /ui 404。 */
978
1644
  assets?: (request: Request) => Promise<Response>;
979
1645
  /**
980
1646
  * 规范网关 origin(如 `https://tool-bridge.example.com`)。配置后,OAuth 的
981
1647
  * redirect_uri 钉在此规范值上,而非每请求动态取 origin——防止实例经多域名
982
- * (自定义域 + *.workers.dev 等)访问时,授权 code 在不同域名间被互换。
1648
+ * (例如公开域名与内网域名)访问时,授权 code 在不同域名间被互换。
983
1649
  * 缺省 → 回退到请求期 origin(单域名部署行为不变)。
984
1650
  */
985
1651
  canonicalOrigin?: string;
1652
+ configManagement?: ConfigManagement;
1653
+ /** Snapshot the active backend for binding a newly mounted platform Context. */
1654
+ defaultObjectBackend?: () => Promise<{
1655
+ id: string;
1656
+ objects: ObjectStore;
1657
+ }>;
1658
+ deploymentManagement?: DeploymentManagement;
986
1659
  /** 设备通道;缺省 → device 能力禁用。 */
987
1660
  device?: DeviceChannel;
988
1661
  /** $ref 中转 token 签名密钥(TB_SECRET_ENCRYPTION_KEY);缺省 → /~ref 404、大对象走 presign 或 unavailable。 */
989
1662
  encryptionKey?: string;
1663
+ encryptionKeyring?: EncryptionKeyring;
990
1664
  /** 认证前的实例就绪钩子(引导/延迟注册 flush);每请求调用,幂等由宿主保证。 */
991
1665
  ensureReady?: () => Promise<void>;
1666
+ keyManagement?: KeyManagement;
992
1667
  /** SDK 进程内 Provider 表(缺省无)。 */
993
1668
  locals?: LocalProviderHooks;
994
- /** context 平台对象存储('r2' provider 的落点);缺省 → 该 provider unavailable。 */
1669
+ mailboxRepository?: MailboxRepository;
1670
+ maintenanceManagement?: MaintenanceManagement;
1671
+ /** context 平台对象存储('storage' provider 的落点);缺省 → 该 provider unavailable。 */
995
1672
  objects?: () => Promise<ObjectStore> | ObjectStore;
1673
+ /** Resolve an immutable backend identity; never substitute the active backend. */
1674
+ objectStoreForBackend?: (backendId: string) => Promise<ObjectStore> | ObjectStore;
996
1675
  /**
997
1676
  * 进程内插件装配表(binding 名 → fetch handler)。manifest.endpoint 为
998
1677
  * `binding:<name>` 的插件经此直调,零网络跳;未装配的 binding 注册/调用报 unavailable。
@@ -1001,7 +1680,7 @@ interface TbAppDeps {
1001
1680
  /**
1002
1681
  * 内置插件目录(descriptor)。**编译期常量**,由 `@tool-bridge/plugins` 的
1003
1682
  * `catalog.generated.ts` 求值生成 —— 内置插件的目录项与它的代码是同一份构建产物,
1004
- * 故不会陈旧、也不落库(见 `llmdoc/architecture/plugin-runtime.md`)。
1683
+ * 故不会陈旧、也不落库(见 `llmdoc/plugins/plugin-runtime.mdx`)。
1005
1684
  *
1006
1685
  * 与 {@link pluginBindings} **是一对**:catalog 说"声明了什么"(挂载校验、选 export、
1007
1686
  * 列凭证字段),bindings 说"代码在哪"(实际调用)。装配了 binding 却没给 catalog,
@@ -1016,8 +1695,8 @@ interface TbAppDeps {
1016
1695
  providerOAuthFetch?: typeof fetch;
1017
1696
  /**
1018
1697
  * 后端连通性探测(GET /readyz;k8s readiness)。宿主注入闭包,自行探测其长连接
1019
- * 后端(PG 池 / Redis)并叠加 draining 状态。缺省 → /readyz 恒 200:请求期绑定
1020
- * 宿主(Workers KV/D1/R2)无"断连"态,嵌入宿主自理。
1698
+ * 后端(PG 池 / Redis)并叠加 draining 状态。标准服务必须注入;嵌入式宿主
1699
+ * 自行承担后端就绪检查,缺省未注入时 /readyz 返回 200。
1021
1700
  */
1022
1701
  readiness?: () => Promise<ReadinessReport>;
1023
1702
  /** context Get 的 $ref 内联阈值(字节,缺省 1 MiB)。 */
@@ -1028,10 +1707,14 @@ interface TbAppDeps {
1028
1707
  remote: RemoteSettings;
1029
1708
  /** 追加保留根路径(在内置保留根之外额外声明)。 */
1030
1709
  reservedRoots?: string[];
1710
+ /** Host-owned S3 implementation. No signing or Node transport enters app. */
1711
+ s3Objects?: (config: S3StoreConfig) => Promise<ObjectStore> | ObjectStore;
1031
1712
  /** 全局工具搜索索引;缺省或未声明 search capability 时 /~search 不存在。 */
1032
1713
  search?: SearchIndex;
1033
1714
  secrets: SecretStoreImpl;
1034
1715
  state: StateStore;
1716
+ storageManagement?: StorageManagement;
1717
+ storeBackends?: StoreBackendResolver;
1035
1718
  /** call capability 允许的 MIME pattern;缺省 `*\/*`。 */
1036
1719
  storeCallAllowedContentTypes?: string[];
1037
1720
  /** 单次 device call 的聚合上传字节预算。 */
@@ -1046,8 +1729,10 @@ interface TbAppDeps {
1046
1729
  storeReadTtlSec?: number;
1047
1730
  /** relay transport 的有效 request-body 上限;direct 不受此值收紧。 */
1048
1731
  storeRelayMaxBytes?: number;
1732
+ storeRepository?: StoreRepository;
1049
1733
  /** 短期 share 的缺省有效期秒。 */
1050
1734
  storeShareTtlSec?: number;
1735
+ storeTokenKeyring?: StoreTokenKeyring;
1051
1736
  /** Store capability HMAC secret;缺省由 StateStore 原子生成并持久化。 */
1052
1737
  storeTokenSecret?: string;
1053
1738
  /** Store upload session 有效期秒。 */
@@ -1059,127 +1744,38 @@ interface TbAppDeps {
1059
1744
  /** healthz 与 system/status 回显的版本号(单一真源:宿主 package.json)。 */
1060
1745
  version: string;
1061
1746
  }
1062
- /** 请求期变量:认证中间件写入,handler 只读。 */
1063
- type Vars = {
1064
- ctx: CallContext;
1065
- store: StateStore;
1066
- };
1067
-
1068
- /**
1069
- * 构造 tool-bridge 的 Hono app(宿主中立;Workers 适配见 app.ts,SDK 装配见 packages/sdk)。
1070
- */
1071
- declare function createTbApp(deps: TbAppDeps): Hono<{
1072
- Variables: Vars;
1073
- }>;
1074
1747
 
1075
- /**
1076
- * Node 宿主的 env 配置面。变量名与语义对齐 CF 宿主(gateway/src/app.ts 的 Env),
1077
- * 仅新增宿主形态相关的 TB_PORT / TB_HOST / TB_DATA_DIR / TB_UI_DIR / TB_DATABASE_URL。
1078
- * 端口额外兜底平台注入的 PORT(PaaS 通行约定)。
1079
- * Node/Workers 共用字段由 core runtimeEnv Zod schema 解析,本文件只保留 Node 宿主字段。
1080
- */
1081
-
1082
- interface ServerConfig {
1083
- /** 首次引导的 Admin SK 明文(须经 TB_BOOTSTRAP_ADMIN_SK 预置;缺省且未开 insecure bootstrap 则 fail closed)。 */
1748
+ /** Explicit embedding API. The executable loads managed bootstrap + PG configuration. */
1749
+ interface ServerConfig extends Partial<RuntimeConfig> {
1750
+ adminAudit?: TbAppDeps['adminAudit'];
1084
1751
  adminSk?: string;
1085
- /**
1086
- * 逃生阀:显式放行"缺 Admin SK 时随机生成并打印明文"的旧行为(仅本地/一次性开发)。
1087
- * 默认 false → 生产/Docker 缺 TB_BOOTSTRAP_ADMIN_SK 时拒绝启动,不把最高权限凭证写日志。
1088
- */
1089
- allowInsecureBootstrap: boolean;
1090
1752
  allowInsecureHttp: boolean;
1091
- /**
1092
- * 规范网关 origin(TB_CANONICAL_ORIGIN):多域名访问时钉死 OAuth redirect_uri。
1093
- * 与 Workers 宿主同一解析真源(core normalizeCanonicalOrigin);配置了但非法 →
1094
- * configFromEnv 抛错,进程拒绝启动(fail closed,不静默回退到请求期 origin)。
1095
- */
1096
- canonicalOrigin?: string;
1097
- /**
1098
- * Postgres 连接串(TB_DATABASE_URL)。给出则 StateStore 与 SearchIndex 都走 PG
1099
- * (ILIKE 子串检索,无扩展依赖);缺省回退到 dataDir 下的 SQLite。
1100
- */
1101
- databaseUrl?: string;
1102
- /** SQLite 库与 fs 对象根所在目录(state.sqlite3 + objects/)。 */
1753
+ databaseUrl: string;
1103
1754
  dataDir: string;
1104
- /** 设备断线后未重连的回收秒数(缺省 24h)。 */
1105
1755
  deviceReclaimSec: number;
1106
- /** SecretStore 主密钥 + $ref 中转 token 签名密钥(base64url 32B)。 */
1107
- encryptionKey?: string;
1756
+ encryptionKey: string;
1757
+ encryptionKeyring?: EncryptionKeyring;
1108
1758
  host: string;
1109
- /**
1110
- * 平台对象存储(default Store + context `$ref` 大对象落点)。给出则用 S3/R2 兼容端点,
1111
- * 缺省回退 dataDir 下的本地 FS。配 S3 后容器可无状态横向扩容 —— FS 落点
1112
- * 在多副本间互不可见、容器重建即丢。
1113
- */
1114
- objectStore?: {
1115
- accessKeyId: string;
1116
- bucket: string;
1117
- endpoint: string;
1118
- region?: string;
1119
- secretAccessKey: string;
1120
- };
1121
- /**
1122
- * 进程内插件装配表(binding 名 → fetch handler)。缺省时 bin 入口装配**全量内置目录**
1123
- * (见 `main.ts`);程序化嵌入方可给自己的表来覆盖或裁剪。
1124
- */
1759
+ instanceId?: string;
1760
+ internalS3Origin?: string;
1761
+ keyManagement?: TbAppDeps['keyManagement'];
1762
+ maintenanceManagement?: TbAppDeps['maintenanceManagement'];
1763
+ managedSettings?: RuntimeConfig;
1764
+ oauthKey?: string;
1765
+ objectStore?: S3StoreConfig;
1125
1766
  pluginBindings?: PluginBindings;
1126
- /**
1127
- * 内置插件目录的 descriptor。与 {@link pluginBindings} 同源装配 —— 只给 bindings
1128
- * 的话插件调得动但解析不出 export(挂载校验会报"未知 provider")。
1129
- */
1130
1767
  pluginCatalog?: BuiltinCatalog;
1131
1768
  port: number;
1132
- /**
1133
- * 多副本设备通道路由的 Redis 连接串(TB_REDIS_URL)。
1134
- *
1135
- * 设备的 WebSocket 是活 socket、只存在于接受它的进程里,故多副本时打给"连在别的
1136
- * 副本上的设备"的调用必须跨副本转发。配上即启用路由表 + pub/sub 转发;
1137
- * 单副本部署不需要配(本地直连恒命中)。
1138
- */
1139
1769
  redisUrl?: string;
1140
- refThresholdBytes?: number;
1141
- refTtlSec?: number;
1142
1770
  remote: RuntimeRemoteSettings;
1143
- /**
1144
- * 本副本标识(TB_REPLICA_ID),路由表的 value。缺省用 hostname —— 容器平台上
1145
- * 每个副本的 hostname 天然唯一;同机多进程需显式区分。
1146
- */
1147
1771
  replicaId?: string;
1148
- /**
1149
- * SIGTERM 后先置 draining(/readyz 转 503)再关停的等待秒数(TB_SHUTDOWN_DRAIN_SEC,
1150
- * 缺省 0)。k8s 滚动更新时 endpoint 摘除有传播延迟,不等一拍就关会把仍被路由过来的
1151
- * 请求吃闭门羹;单机/本地开发保持 0,关停立即进行。
1152
- */
1153
- shutdownDrainSec?: number;
1154
- /** 设备调用允许上传的 MIME pattern;缺省由应用使用安全默认值。 */
1155
- storeCallAllowedContentTypes?: string[];
1156
- /** 设备调用所签发 Store capability 的总字节上限。 */
1157
- storeCallMaxBytes?: number;
1158
- /** 设备调用单个 Store 对象的字节上限。 */
1159
- storeCallMaxObjectBytes?: number;
1160
- /** 设备调用最多可创建的 Store 对象数。 */
1161
- storeCallMaxObjects?: number;
1162
- /** Store 孤儿字节、过期 session/share/call capability 的周期清理间隔。 */
1163
1772
  storeCleanupIntervalSec: number;
1164
- /** Store 对象统一上限;direct upload 可使用完整值。 */
1165
- storeMaxObjectBytes?: number;
1166
- /** Store owner read ref 的有效期。 */
1167
- storeReadTtlSec?: number;
1168
- /** relay upload 的宿主有效上限;缺省等于对象统一上限。 */
1169
- storeRelayMaxBytes?: number;
1170
- /** Store 匿名可撤销 share 的有效期。 */
1171
- storeShareTtlSec?: number;
1172
- /** 显式 Store token 根密钥;缺省由应用在 StateStore 原子生成并持久化。 */
1773
+ storeTokenKeyring?: StoreTokenKeyring;
1173
1774
  storeTokenSecret?: string;
1174
- /** Store upload session 的有效期。 */
1175
- storeUploadTtlSec?: number;
1176
- toolCacheTtlSec?: number;
1177
- /** Dashboard 静态资源目录覆盖(缺省经 @tool-bridge/dashboard 包解析)。 */
1178
1775
  uiDir?: string;
1179
- /** create_upload 写入 grant 有效期秒;缺省 min(refTtlSec, 900)。 */
1180
- uploadGrantTtlSec?: number;
1181
1776
  }
1182
- declare function configFromEnv(env?: NodeJS.ProcessEnv): ServerConfig;
1777
+ /** A request receives one immutable settings snapshot; old grants retain their own limits. */
1778
+ declare function runtimeAppSettings(settings: RuntimeConfig, instanceId?: string): Partial<TbAppDeps>;
1183
1779
 
1184
1780
  /**
1185
1781
  * DeviceRouter:多副本部署下的设备调用路由。
@@ -1197,8 +1793,7 @@ declare function configFromEnv(env?: NodeJS.ProcessEnv): ServerConfig;
1197
1793
  * 本副本自己持有连接时**完全不经这里**(DeviceHub 先查本地 Map),故单副本部署零额外
1198
1794
  * 开销、也不需要配 Redis。
1199
1795
  *
1200
- * CF 宿主的对照:那边用 Durable Object,天然"每设备一个单点",不存在这个问题。
1201
- * 本模块是 Node 多副本的等价物。
1796
+ * 本模块为多副本 Node 服务提供统一的连接所有权与跨进程转发。
1202
1797
  */
1203
1798
 
1204
1799
  /** 路由条目 TTL;续期周期取其 1/3,保证正常情况下不会因抖动过期。 */
@@ -1288,9 +1883,11 @@ declare class DeviceRouter {
1288
1883
  type DeviceLocalCall = (deviceId: string, req: DeviceInvokeRequest) => Promise<DeviceCallAttempt>;
1289
1884
  declare const DEVICE_WS_PATH = "/system/device/ws";
1290
1885
  declare class DeviceHub {
1886
+ private attachedServer;
1887
+ private readonly upgradeHandler;
1291
1888
  private readonly store;
1292
1889
  private readonly search;
1293
- private readonly reclaimSec;
1890
+ private reclaimSec;
1294
1891
  private readonly wss;
1295
1892
  private readonly activeByDevice;
1296
1893
  private readonly connections;
@@ -1306,6 +1903,7 @@ declare class DeviceHub {
1306
1903
  search?: MutableSearchIndex;
1307
1904
  store: StateStore;
1308
1905
  });
1906
+ setReclaimSec(value: number): Promise<void>;
1309
1907
  /**
1310
1908
  * 启动多副本路由(订阅本副本频道 + 路由续期)。单副本时是 no-op。
1311
1909
  * 必须在开始服务前完成:订阅没建好时转发进来的调用会丢。
@@ -1349,28 +1947,156 @@ declare class DeviceHub {
1349
1947
  private pingConnections;
1350
1948
  }
1351
1949
 
1352
- /**
1353
- * createDataObjectStore:平台对象存储('r2' provider 落点)的 Node 实现。
1354
- *
1355
- * core FsObjectStore 是多根语义(key 首段必须等于某 root 的 basename),而平台
1356
- * 对象存储的 key 是平坦任意前缀(默认 ctx/<nodePath>/...)——本模块做薄前缀适配:
1357
- * 出入口统一加/剥内部根段 'objects/',穿越防护复用 FsObjectStore 的两层防护
1358
- * (normalizeEntryPath + realpath-in-root),不重写。cursor 是内部形态原样透传
1359
- * (消费方视 cursor 为不透明串)。无 presign → $ref 走 /~ref 网关中转(现有降级)。
1360
- */
1950
+ interface KeyManagementSnapshot {
1951
+ databaseUrl: string;
1952
+ instanceId: string;
1953
+ replicaId: string;
1954
+ revision: number;
1955
+ }
1956
+ interface KeyManagementHooks {
1957
+ exclusive<T>(run: () => Promise<T>): Promise<T>;
1958
+ quiesce(): Promise<{
1959
+ resume(): Promise<void>;
1960
+ }>;
1961
+ readKeys(): Promise<BootstrapSecrets>;
1962
+ readSnapshot(): Promise<KeyManagementSnapshot>;
1963
+ /** Reload the stopped local runtime from the persisted bootstrap keys. */
1964
+ reload(): Promise<void>;
1965
+ /** Atomically persist the key file and advance bootstrap revision. */
1966
+ writeKeys(keys: BootstrapSecrets): Promise<number>;
1967
+ }
1968
+ interface KeyManagerOptions {
1969
+ /** Injection is only for isolated local-PG integration schemas. */
1970
+ connect?: (databaseUrl: string) => Sql;
1971
+ now?: () => Date;
1972
+ }
1973
+ /** Admin-only key lifecycle. The business pool may be closed during every mutation. */
1974
+ declare class KeyManager implements KeyManagement {
1975
+ private readonly hooks;
1976
+ private readonly now;
1977
+ private readonly connect;
1978
+ constructor(hooks: KeyManagementHooks, options?: KeyManagerOptions);
1979
+ private ensure;
1980
+ private rotation;
1981
+ status(): Promise<KeyStatus>;
1982
+ private statusUnderLock;
1983
+ private mutate;
1984
+ rotate(input: Parameters<KeyManagement['rotate']>[0]): Promise<KeyStatus>;
1985
+ resume(input: Parameters<KeyManagement['resume']>[0]): Promise<KeyStatus>;
1986
+ retire(input: Parameters<KeyManagement['retire']>[0]): Promise<KeyStatus>;
1987
+ private revokeSigning;
1988
+ backup(): Promise<KeyBackup>;
1989
+ }
1990
+
1991
+ interface MaintenanceSnapshot {
1992
+ databaseUrl: string;
1993
+ instanceId: string;
1994
+ redisUrl?: string;
1995
+ replicaId: string;
1996
+ revision: number;
1997
+ }
1998
+ interface MaintenanceHooks {
1999
+ commit(next: {
2000
+ databaseUrl?: string;
2001
+ expectedRevision: number;
2002
+ redisUrl?: string | null;
2003
+ }): Promise<{
2004
+ revision: number;
2005
+ }>;
2006
+ exclusive<T>(run: () => Promise<T>): Promise<T>;
2007
+ quiesce(): Promise<{
2008
+ resume(): Promise<void>;
2009
+ }>;
2010
+ readDatabaseAdminUrl?(): Promise<string | undefined>;
2011
+ readJournal(): Promise<MaintenanceJournal | undefined>;
2012
+ readSnapshot(): Promise<MaintenanceSnapshot>;
2013
+ writeJournal(journal: MaintenanceJournal): Promise<void>;
2014
+ }
2015
+ interface PgCommandOptions {
2016
+ /** Explicit executable paths; command strings are never evaluated by a shell. */
2017
+ pgDump?: string;
2018
+ pgRestore?: string;
2019
+ /** Local container integration tests may inject the same official binaries via docker exec. */
2020
+ runCommand?: (program: 'pg_dump' | 'pg_restore', args: string[], env: NodeJS.ProcessEnv) => Promise<void>;
2021
+ }
2022
+ declare class MaintenanceManager implements MaintenanceManagement {
2023
+ private readonly hooks;
2024
+ private readonly commands;
2025
+ constructor(hooks: MaintenanceHooks, commands?: PgCommandOptions);
2026
+ status(): Promise<MaintenanceStatus>;
2027
+ private execute;
2028
+ private command;
2029
+ database(input: Parameters<MaintenanceManagement['database']>[0]): Promise<MaintenanceStatus>;
2030
+ redis(input: Parameters<MaintenanceManagement['redis']>[0]): Promise<MaintenanceStatus>;
2031
+ rotate_database_credentials(input: Parameters<MaintenanceManagement['rotate_database_credentials']>[0]): Promise<MaintenanceStatus>;
2032
+ }
1361
2033
 
1362
- declare function createDataObjectStore(dataDir: string): ObjectStore;
2034
+ interface ManagedServerOptions {
2035
+ directory: string;
2036
+ host?: string;
2037
+ port?: number;
2038
+ uiDir?: string;
2039
+ }
2040
+ /** A limited bootstrap listener exists independently from the database and business app. */
2041
+ declare function createManagedServer(options: ManagedServerOptions): Promise<{
2042
+ app: Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
2043
+ store: BootstrapStateStore;
2044
+ start(): Promise<{
2045
+ port: number;
2046
+ }>;
2047
+ startDraining: () => void;
2048
+ close: () => Promise<void>;
2049
+ shutdown(): Promise<void>;
2050
+ }>;
1363
2051
 
1364
- /**
1365
- * PgSearchIndex:postgres.js 驱动的 SearchIndex(ILIKE 子串检索)。
1366
- *
1367
- * 方言(SQL 文本、$n 占位符、ILIKE 检索)在 core 的 pgSearchDialect;
1368
- * 本文件只吸收 postgres.js 的驱动差异:全异步、写入走 sql.begin() 事务、多行 VALUES
1369
- * 批量插入(PG D1 的 50 查询预算,故不实现 assertInsertBudget)。
1370
- *
1371
- * 不需要任何 PG 扩展:检索是纯 ILIKE,cursor_secret 用内置 gen_random_uuid()。
1372
- * 因此连接角色无需建扩展权限(受限托管环境常不给),只要能建表。
1373
- */
2052
+ interface KeyRotationJob {
2053
+ changed: number;
2054
+ cursor: string | null;
2055
+ error: string | null;
2056
+ id: string;
2057
+ phase: 'secrets' | 'mailbox' | 'verify';
2058
+ status: 'running' | 'failed' | 'completed';
2059
+ targetKeyId: string;
2060
+ }
2061
+ /** Database holds progress only. Keyring material is injected from the protected host secret file. */
2062
+ declare class PgKeyRotation {
2063
+ private readonly sql;
2064
+ private readonly secrets;
2065
+ private readonly mailbox;
2066
+ private readonly activeKeyId;
2067
+ constructor(sql: Sql, secrets: SecretStoreImpl, mailbox: DeviceMailboxService, activeKeyId: string);
2068
+ ensureSchema(): Promise<void>;
2069
+ start(targetKeyId?: string): Promise<KeyRotationJob>;
2070
+ get(id: string): Promise<KeyRotationJob>;
2071
+ runBatch(id: string, limit?: number): Promise<KeyRotationJob>;
2072
+ encryptionReferences(keyId: string): Promise<number>;
2073
+ signingReferences(keyId: string, now: string): Promise<number>;
2074
+ countOtherEncryptionReferences(targetKeyId: string): Promise<number>;
2075
+ }
2076
+
2077
+ /** Indexed operation ledger;
2078
+ encrypted payload/result stay opaque to persistence. */
2079
+ declare class PgMailboxRepository implements MailboxRepository {
2080
+ private readonly sql;
2081
+ constructor(sql: Sql);
2082
+ ensureSchema(): Promise<void>;
2083
+ get(id: string): Promise<DeviceOperationRecord | null>;
2084
+ list(query: MailboxQuery): Promise<{
2085
+ cursor?: string;
2086
+ items: Array<{
2087
+ key: string;
2088
+ value: DeviceOperationRecord;
2089
+ }>;
2090
+ }>;
2091
+ compare(id: string, revision: number, next: DeviceOperationRecord | null): Promise<boolean>;
2092
+ enqueue(record: DeviceOperationRecord, maxPending: number, now: string): Promise<DeviceOperationRecord>;
2093
+ claimNext(record: DeviceOperationRecord, revision: number, now: string): Promise<boolean>;
2094
+ renew(record: DeviceOperationRecord, revision: number, now: string): Promise<boolean>;
2095
+ complete(record: DeviceOperationRecord, revision: number, now: string): Promise<boolean>;
2096
+ private writeUnderLease;
2097
+ }
2098
+
2099
+ /** PostgreSQL driver: transactions and bounded VALUES batches; search SQL is owned by core/pgSearchSql. */
1374
2100
 
1375
2101
  /** Node 自托管宿主的 postgres.js SearchIndex。 */
1376
2102
  declare class PgSearchIndex extends SqlSearchIndex {
@@ -1380,22 +2106,24 @@ declare class PgSearchIndex extends SqlSearchIndex {
1380
2106
  /**
1381
2107
  * PgStateStore:postgres.js 实现的 StateStore(自托管 Node 宿主的 PG 后端)。
1382
2108
  *
1383
- * SqliteStateStore 同形:单表 kv(key text primary key, value jsonb),值以
2109
+ * 通用状态以单表 kv(key text primary key, value jsonb)保存,值以
1384
2110
  * JSON 存取,强一致。list 用 key 范围扫描(>= prefix AND < successor(prefix)),
1385
2111
  * 不用 LIKE——key 里的路径段可含 '_'/'%',通配符转义是坑。
1386
2112
  *
1387
2113
  * 关键差异——排序 collation:PG 默认按 libc locale 排序,`<` 与 `ORDER BY` 的
1388
- * 顺序会和 JS(UTF-16 code unit)/SQLite(UTF-8 字节)不一致,直接让前缀范围扫描和
2114
+ * 顺序会和 JS(UTF-16 code unit)不一致,直接让前缀范围扫描和
1389
2115
  * cursor 分页错行漏行。故 key 列显式 `COLLATE "C"`(纯字节序),与 core
1390
- * MemoryStateStore / SqliteStateStore 的 cursor 语义对齐。防御性地对返回行再做
2116
+ * MemoryStateStore 的 cursor 语义对齐。防御性地对返回行再做
1391
2117
  * startsWith 过滤。
1392
2118
  */
1393
2119
 
1394
2120
  declare class PgStateStore implements StateStore {
1395
2121
  private readonly sql;
2122
+ private contextRefsEnabled;
1396
2123
  constructor(sql: Sql);
1397
2124
  /** 建表(幂等)。key COLLATE "C" 是字节序正确性的前提,不能省。 */
1398
2125
  ensureSchema(): Promise<void>;
2126
+ ensureContextReferencesSchema(): Promise<void>;
1399
2127
  get(key: string): Promise<unknown | null>;
1400
2128
  getMany(keys: readonly string[]): Promise<Map<string, unknown>>;
1401
2129
  put(key: string, value: unknown): Promise<void>;
@@ -1414,6 +2142,31 @@ declare class PgStateStore implements StateStore {
1414
2142
  }>;
1415
2143
  }
1416
2144
 
2145
+ /** PG-only metadata authority. No operation accepts callbacks or performs object/network I/O. */
2146
+ declare class PgStoreRepository implements StoreRepository {
2147
+ private readonly sql;
2148
+ readonly objects: StoreRecords<StoreObject>;
2149
+ readonly uploads: StoreRecords<UploadSession>;
2150
+ readonly shares: StoreRecords<ShareGrant>;
2151
+ readonly callCapabilities: StoreRecords<CallUploadCapability>;
2152
+ readonly idempotencyBindings: StoreRecords<StoreIdempotencyBinding>;
2153
+ constructor(sql: Sql);
2154
+ ensureSchema(): Promise<void>;
2155
+ beginUpload(candidate: BeginStoreUpload): Promise<{
2156
+ object: StoreObject;
2157
+ session: UploadSession;
2158
+ } | 'backend_changed'>;
2159
+ finishUpload(object: StoreObject, session: UploadSession): Promise<StoreObject | null>;
2160
+ terminateUpload(object: StoreObject, session: UploadSession): Promise<boolean>;
2161
+ listReadyObjects(owner: string, opts: {
2162
+ cursor?: string;
2163
+ limit: number;
2164
+ }): Promise<{
2165
+ cursor?: string;
2166
+ items: StoreObject[];
2167
+ }>;
2168
+ }
2169
+
1417
2170
  /**
1418
2171
  * DeviceRouterBackend 的 Redis(ioredis)实现。
1419
2172
  *
@@ -1441,81 +2194,128 @@ declare class RedisDeviceRouterBackend implements DeviceRouterBackend {
1441
2194
  close(): Promise<void>;
1442
2195
  }
1443
2196
 
1444
- /**
1445
- * createTbServer:Node 宿主装配(对位 gateway/src/app.ts 的 depsFromEnv)。
1446
- *
1447
- * StateStore/SearchIndex 后端二选一:给 TB_DATABASE_URL 走 Postgres,
1448
- * 否则走 dataDir 下的 SQLite。ObjectStore 始终是 fs。HTTP 用 @hono/node-server;
1449
- * 引导在 start() 时直调宿主中立 runBootstrap(Node 有真实启动点,不需要 Workers 的
1450
- * per-request once,故不注入 deps.ensureReady)。设备通道(DeviceHub)与 /ui 静态托管
1451
- * 由后续装配点注入(deps.device / deps.assets)。
1452
- */
2197
+ interface S3NetworkOptions {
2198
+ /** Deployment-owned exact origin. Never derive this exception from a user endpoint. */
2199
+ internalOrigin?: string;
2200
+ }
2201
+
2202
+ interface S3ObjectStoreOptions extends S3NetworkOptions {
2203
+ maxObjectBytes?: number;
2204
+ requestTimeoutMs?: number;
2205
+ }
2206
+ interface S3ObjectStore extends ObjectStore {
2207
+ close(): void;
2208
+ }
2209
+ declare function createS3ObjectStore(config: S3StoreConfig, options?: S3ObjectStoreOptions): S3ObjectStore;
2210
+
2211
+ interface S3ProbeResult {
2212
+ checks: Record<string, boolean>;
2213
+ cleanupSucceeded: boolean;
2214
+ }
2215
+ /** Destructive only inside a fresh, unguessable probe namespace in the selected bucket. */
2216
+ declare function probeS3ObjectStore(config: S3StoreConfig, options?: S3ObjectStoreOptions): Promise<S3ProbeResult>;
2217
+
2218
+ /** The location is immutable. Only the verified credential generation may be replaced. */
2219
+ declare class StorageManager implements StorageManagement, StoreBackendResolver {
2220
+ private readonly sql;
2221
+ private readonly secrets;
2222
+ private readonly options;
2223
+ private readonly drivers;
2224
+ constructor(sql: Sql, secrets: SecretStoreImpl, options?: S3ObjectStoreOptions);
2225
+ private record;
2226
+ private view;
2227
+ get({ id }: {
2228
+ id: string;
2229
+ }): Promise<StorageBackendView>;
2230
+ list(): Promise<{
2231
+ items: StorageBackendView[];
2232
+ }>;
2233
+ private connection;
2234
+ resolveBackend(id: string): Promise<ObjectStore>;
2235
+ defaultBackend(): Promise<{
2236
+ id: string;
2237
+ objects: ObjectStore;
2238
+ }>;
2239
+ write(input: Parameters<StorageManagement['write']>[0]): Promise<StorageBackendView>;
2240
+ private assertRevision;
2241
+ test(input: Parameters<StorageManagement['test']>[0]): Promise<StorageBackendView>;
2242
+ activate(input: Parameters<StorageManagement['activate']>[0]): Promise<StorageBackendView>;
2243
+ update(input: Parameters<StorageManagement['update']>[0]): Promise<StorageBackendView>;
2244
+ delete(input: Parameters<StorageManagement['delete']>[0]): Promise<{
2245
+ ok: true;
2246
+ }>;
2247
+ close(): void;
2248
+ }
2249
+
2250
+ /** PG holds the requested/applied snapshots. A replica reports only successful local application. */
2251
+ declare class ConfigManager implements ConfigManagement {
2252
+ private readonly sql;
2253
+ private readonly onApply;
2254
+ private localRevision;
2255
+ private localEffective;
2256
+ private localError;
2257
+ private serial;
2258
+ constructor(sql: Sql, onApply: (settings: RuntimeConfig) => Promise<void>);
2259
+ ensureSchema(defaults?: {
2260
+ canonicalOrigin: string;
2261
+ remoteAllowlist: string[];
2262
+ maxHops: number;
2263
+ deviceReclaimSec: number;
2264
+ toolCacheTtlSec: number;
2265
+ refThresholdBytes: number;
2266
+ refTtlSec: number;
2267
+ uploadGrantTtlSec: number;
2268
+ storeMaxObjectBytes: number;
2269
+ storeRelayMaxBytes: number;
2270
+ storeCallMaxBytes: number;
2271
+ storeCallMaxObjectBytes: number;
2272
+ storeCallMaxObjects: number;
2273
+ storeCallAllowedContentTypes: string[];
2274
+ storeUploadTtlSec: number;
2275
+ storeShareTtlSec: number;
2276
+ storeReadTtlSec: number;
2277
+ storeCleanupIntervalSec: number;
2278
+ searchConcurrency: number;
2279
+ searchDeadlineMs: number;
2280
+ searchMaxResponseBytes: number;
2281
+ searchMaxSources: number;
2282
+ searchMinChildWorkMs: number;
2283
+ searchReturnReserveMs: number;
2284
+ searchSessionTtlSec: number;
2285
+ shutdownDrainSec: number;
2286
+ }): Promise<void>;
2287
+ private row;
2288
+ private exclusive;
2289
+ private install;
2290
+ sync(): Promise<void>;
2291
+ get(): Promise<ConfigStatus>;
2292
+ update(input: Parameters<ConfigManagement['update']>[0]): Promise<ConfigStatus>;
2293
+ apply(input: Parameters<ConfigManagement['apply']>[0]): Promise<ConfigStatus>;
2294
+ }
1453
2295
 
1454
2296
  interface TbServer {
1455
- app: ReturnType<typeof createTbApp>;
1456
- close(): Promise<void>;
2297
+ app: Hono;
2298
+ close(options?: {
2299
+ excludeCurrentRequest?: boolean;
2300
+ }): Promise<void>;
1457
2301
  deviceHub: DeviceHub;
2302
+ prepare(): Promise<void>;
1458
2303
  search: MutableSearchIndex;
2304
+ settings: ConfigManager;
2305
+ readonly shutdownDrainSec: number;
1459
2306
  /** 引导(幂等)+ 孤儿设备回收排程 + 监听;返回实际端口(config.port=0 时由系统分配)。 */
1460
2307
  start(): Promise<{
1461
2308
  port: number;
1462
2309
  }>;
1463
2310
  /**
1464
2311
  * 进入 draining:/readyz 立即转 503(编排器摘流量),但继续服务既有与新到请求。
1465
- * SIGTERM 处理器先调它、等一拍(TB_SHUTDOWN_DRAIN_SEC)再 close(),避免 k8s
2312
+ * SIGTERM 处理器先调它、等已应用的 shutdownDrainSec 再 close(),避免 k8s
1466
2313
  * endpoint 摘除传播期间仍被路由过来的请求吃闭门羹。幂等。
1467
2314
  */
1468
2315
  startDraining(): void;
1469
2316
  state: StateStore;
2317
+ storage: StorageManager;
1470
2318
  }
1471
2319
  declare function createTbServer(config: ServerConfig): TbServer;
1472
2320
 
1473
- /** Node 宿主的 better-sqlite3 LIKE SearchIndex。 */
1474
- declare class SqliteSearchIndex extends SqlSearchIndex {
1475
- private readonly db;
1476
- constructor(dbPath: string);
1477
- close(): void;
1478
- }
1479
-
1480
- /**
1481
- * SqliteStateStore:better-sqlite3 实现的 StateStore(Docker/Node 宿主)。
1482
- *
1483
- * 单表 kv(key TEXT PRIMARY KEY, value TEXT)——StateStore 本身就是 kv 语义,
1484
- * 拆表只会复制 key 布局知识。值 JSON 序列化存取(与 KvStateStore 同形)。
1485
- * 强一致:吊销/写入即时可见,无 KV 的最终一致窗口(kvStateStore.ts 的跳 null
1486
- * 与逐 key get 负担在此宿主不存在)。
1487
- *
1488
- * list 用 key 范围扫描(>= prefix AND < successor(prefix)),不用 LIKE/GLOB——
1489
- * key 里的路径段可含 '_'/'%'/'[',通配符转义是坑。cursor/排序语义与
1490
- * core MemoryStateStore 对拍(cursor = 上页末 key,仅在还有更多时返回)。
1491
- * 注意:SQLite TEXT 按 UTF-8 字节序比较,JS 按 UTF-16 code unit 比较,
1492
- * 二者在 ASCII 与 BMP 码点上一致;key 由本项目生成(ASCII 前缀 + 树路径),
1493
- * 防御性地对返回行再做 startsWith 过滤。
1494
- */
1495
-
1496
- declare class SqliteStateStore implements StateStore {
1497
- private readonly db;
1498
- private readonly stmtGet;
1499
- private readonly stmtPut;
1500
- private readonly stmtDelete;
1501
- constructor(dbPath: string);
1502
- get(key: string): Promise<unknown | null>;
1503
- getMany(keys: readonly string[]): Promise<Map<string, unknown>>;
1504
- put(key: string, value: unknown): Promise<void>;
1505
- compareAndSwap(key: string, expectedRevision: number | null, value: unknown | null): Promise<boolean>;
1506
- putIfAbsent(key: string, value: unknown): Promise<boolean>;
1507
- delete(key: string): Promise<void>;
1508
- list(prefix: string, opts?: {
1509
- cursor?: string;
1510
- limit?: number;
1511
- }): Promise<{
1512
- cursor?: string;
1513
- items: Array<{
1514
- key: string;
1515
- value: unknown;
1516
- }>;
1517
- }>;
1518
- close(): void;
1519
- }
1520
-
1521
- export { DEVICE_FORWARD_TIMEOUT_MS, DEVICE_ROUTE_TTL_SEC, DEVICE_WS_PATH, DeviceHub, type DeviceLocalCall, DeviceRouter, type DeviceRouterBackend, PgSearchIndex, PgStateStore, RedisDeviceRouterBackend, type ServerConfig, SqliteSearchIndex, SqliteStateStore, type TbServer, configFromEnv, createDataObjectStore, createTbServer };
2321
+ export { BootstrapStateStore, DEVICE_FORWARD_TIMEOUT_MS, DEVICE_ROUTE_TTL_SEC, DEVICE_WS_PATH, DeviceHub, type DeviceLocalCall, DeviceRouter, type DeviceRouterBackend, type KeyManagementHooks, KeyManager, type MaintenanceHooks, MaintenanceManager, type ManagedServerOptions, PgKeyRotation, PgMailboxRepository, PgSearchIndex, PgStateStore, PgStoreRepository, RedisDeviceRouterBackend, type S3ObjectStore, type S3ObjectStoreOptions, type S3ProbeResult, type ServerConfig, StorageManager, type TbServer, createManagedServer, createS3ObjectStore, createTbServer, probeS3ObjectStore, runtimeAppSettings };