@tool-bridge/server 0.21.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/admin.js +170 -0
  2. package/dist/airtable-VMQVXLHK.js +790 -0
  3. package/dist/{alt_text_generator_ai-W7O34SNG.js → alt_text_generator_ai-FTWY4RU4.js} +12 -11
  4. package/dist/{amap-VOX4T2AW.js → amap-OK5VBHYC.js} +221 -220
  5. package/dist/anthropic-S67AZFZ3.js +203 -0
  6. package/dist/apify-ZE6MYQI3.js +248 -0
  7. package/dist/brave_search-TG2M2KOD.js +302 -0
  8. package/dist/chunk-2JNAI4OC.js +161 -0
  9. package/dist/{chunk-KMTT3I6D.js → chunk-4XJPN3DY.js} +19392 -26136
  10. package/dist/chunk-5ICRY3VU.js +8432 -0
  11. package/dist/chunk-7CTWGTDU.js +302 -0
  12. package/dist/chunk-BADVCN6K.js +378 -0
  13. package/dist/{chunk-XYBU3WZH.js → chunk-TDAWLMDE.js} +3 -3
  14. package/dist/chunk-U7PTOA3U.js +7320 -0
  15. package/dist/{chunk-E6JCVKW6.js → chunk-VWRUGUSU.js} +3 -3
  16. package/dist/{chunk-ATK45BXV.js → chunk-WJHG6OK7.js} +4 -2
  17. package/dist/circleci-3L3WJVSK.js +389 -0
  18. package/dist/clerk-EZPF2V7T.js +1019 -0
  19. package/dist/cohere-U27DPO64.js +185 -0
  20. package/dist/{confluence-B3EWPZVE.js → confluence-G2KL6ERH.js} +105 -104
  21. package/dist/{convertapi-EUWSQYPF.js → convertapi-L4CLJ2M3.js} +32 -31
  22. package/dist/{currencyapi-KVTIK3GL.js → currencyapi-YPYXG7YY.js} +71 -71
  23. package/dist/deepseek-6HT6WF3M.js +210 -0
  24. package/dist/docker_hub-LPE3PCVB.js +933 -0
  25. package/dist/dropbox-V56ABHTA.js +1305 -0
  26. package/dist/dub-6OKQ7MHT.js +680 -0
  27. package/dist/e2b-JS2U2QFU.js +278 -0
  28. package/dist/exa-DPWVYXSP.js +332 -0
  29. package/dist/{fal_ai-23E7JPNT.js → fal_ai-DK6Y27ZF.js} +81 -80
  30. package/dist/{feishu-7QRIDUV6.js → feishu-K7EGSRF3.js} +528 -572
  31. package/dist/{feishu_custom_bot-TJ4K7QNJ.js → feishu_custom_bot-2JUGFYNG.js} +57 -53
  32. package/dist/figma-FT5I7ITD.js +777 -0
  33. package/dist/firehydrant-EIKLKHX2.js +563 -0
  34. package/dist/{fixer-BWON27UO.js → fixer-U5QXIAKD.js} +34 -33
  35. package/dist/fly-T3JYFZ2M.js +469 -0
  36. package/dist/{front-QCGXYEDJ.js → front-D72MGVOR.js} +104 -104
  37. package/dist/geocodio-BOTD5TI5.js +213 -0
  38. package/dist/ghost-KYP7SZGB.js +338 -0
  39. package/dist/github-AGMZT3VY.js +5421 -0
  40. package/dist/gmail-BLJNJOBG.js +1887 -0
  41. package/dist/googlecalendar-GTHWNCF6.js +2524 -0
  42. package/dist/{googledocs-BUHL4J2H.js → googledocs-6EEDMEBQ.js} +341 -340
  43. package/dist/{grafana-GLU2DWF2.js → grafana-GMW6EKSQ.js} +221 -220
  44. package/dist/graphhopper-6OLGBDGB.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-4QN42E6T.js} +28 -27
  48. package/dist/ipgeolocation_io-SK4XKDA2.js +315 -0
  49. package/dist/ipqualityscore-6ANBPXKT.js +279 -0
  50. package/dist/{jina_ai-EFBHTBXL.js → jina_ai-IHPSVRM5.js} +23 -23
  51. package/dist/{jira-HQSHAA5K.js → jira-46KKM4LC.js} +118 -117
  52. package/dist/langsmith-JZA345I5.js +593 -0
  53. package/dist/lemlist-43IV7DK6.js +289 -0
  54. package/dist/{linear-K7RYFYAD.js → linear-5LFH7XNL.js} +327 -326
  55. package/dist/logsnag-5RMYAHIL.js +150 -0
  56. package/dist/main.js +57 -280
  57. package/dist/{mattermost-S2BRCWLQ.js → mattermost-XFL6SHGG.js} +59 -58
  58. package/dist/mem0-NYO4DTP6.js +544 -0
  59. package/dist/memos-37MPQOLV.js +744 -0
  60. package/dist/{metabase-MMSEPCOF.js → metabase-KYBKZFMG.js} +90 -89
  61. package/dist/mistral_ai-6PL3K4PM.js +1196 -0
  62. package/dist/{mother_duck-H7PCQNZ2.js → mother_duck-2NH7W5M5.js} +94 -93
  63. package/dist/ngrok-UO6CDYCA.js +356 -0
  64. package/dist/{notes-PFMKRO33.js → notes-I3P32WP4.js} +11 -9
  65. package/dist/notion-BEAJFUOE.js +940 -0
  66. package/dist/open_exchange_rates-CMF62JB4.js +215 -0
  67. package/dist/openai-IHOMKVND.js +800 -0
  68. package/dist/opengraph_io-ZQ2FGLHX.js +362 -0
  69. package/dist/openrouter-HXLW3NR5.js +441 -0
  70. package/dist/outline-ELCP4NEU.js +599 -0
  71. package/dist/paddle-O77LALVN.js +454 -0
  72. package/dist/perplexity-JCU654QV.js +220 -0
  73. package/dist/pinecone-W5W4LRKL.js +571 -0
  74. package/dist/{pipedrive-Y2O7QGFF.js → pipedrive-ITMJLLPZ.js} +99 -98
  75. package/dist/polar-R33XU4L3.js +395 -0
  76. package/dist/posthog-JVNTOLTV.js +3464 -0
  77. package/dist/postmark-6SBG7HWV.js +427 -0
  78. package/dist/{prerender-MENYM2TY.js → prerender-GPNKTNFC.js} +31 -30
  79. package/dist/{pubmed-GOXUVVH5.js → pubmed-UP6ZEEIH.js} +239 -238
  80. package/dist/{railway-V2SID4WV.js → railway-KWEWXHTY.js} +118 -117
  81. package/dist/readwise-BLATSMC3.js +470 -0
  82. package/dist/render-QYRVIXII.js +461 -0
  83. package/dist/{replicate-756MXPYX.js → replicate-JYTWH4NF.js} +81 -80
  84. package/dist/{resend-ZKH3BTBI.js → resend-L5N75SZM.js} +20 -16
  85. package/dist/rootly-MHCPEQ26.js +336 -0
  86. package/dist/{scrapfly-NSRHFDIQ.js → scrapfly-PTPGYSJM.js} +62 -61
  87. package/dist/{scrapingbee-OQHLAVEY.js → scrapingbee-JN6UH5PY.js} +56 -56
  88. package/dist/{screenshot_fyi-DVWG3AXC.js → screenshot_fyi-4QRVSV55.js} +16 -16
  89. package/dist/semantic_scholar-LRSWA2GE.js +611 -0
  90. package/dist/{sentry-546MNDJG.js → sentry-2G6PF5W6.js} +208 -207
  91. package/dist/{shodan-C3OON3Z3.js → shodan-WKKPP5C6.js} +62 -61
  92. package/dist/shopify-64YDK5T2.js +610 -0
  93. package/dist/stripe-QAIGGOTF.js +585 -0
  94. package/dist/{supabase-U2SL4D63.js → supabase-WHTGR6ND.js} +245 -244
  95. package/dist/tavily-QIXCDDWO.js +326 -0
  96. package/dist/telegram-E6G7CWI6.js +1767 -0
  97. package/dist/{telnyx-CXQ4EZUX.js → telnyx-ZDVVS7PK.js} +57 -56
  98. package/dist/todoist-DMYF3G7J.js +664 -0
  99. package/dist/trello-HY2RYIRP.js +1080 -0
  100. package/dist/turso-HAQWMGRP.js +416 -0
  101. package/dist/{twilio-4PDBJKWX.js → twilio-MLXYPHJE.js} +70 -69
  102. package/dist/umami-DZHBLPVG.js +389 -0
  103. package/dist/unsplash-GS2OPXKE.js +351 -0
  104. package/dist/{upstash_redis-G4LQBYHA.js → upstash_redis-XMXWTNAJ.js} +51 -50
  105. package/dist/uptimerobot-TF5WRZ4G.js +483 -0
  106. package/dist/v2ex-2BVXAPDF.js +667 -0
  107. package/dist/vercel-YMJGQYJE.js +1076 -0
  108. package/dist/{wolfram_alpha_api-3G4PUJWB.js → wolfram_alpha_api-I56SXWFZ.js} +36 -35
  109. package/dist/wordpress-R7TDFZ2P.js +812 -0
  110. package/dist/workos-HDNHWVMS.js +664 -0
  111. package/dist/zhihu-LX6AGGDS.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
@@ -0,0 +1,302 @@
1
+ import {
2
+ TBError,
3
+ createEncryptionKeyring
4
+ } from "./chunk-5ICRY3VU.js";
5
+
6
+ // src/bootstrapState.ts
7
+ import {
8
+ createHash,
9
+ randomBytes,
10
+ randomUUID,
11
+ timingSafeEqual
12
+ } from "crypto";
13
+ import { chmod, mkdir, readFile, stat, unlink } from "fs/promises";
14
+ import writeFileAtomic from "write-file-atomic";
15
+ import lockfile from "proper-lockfile";
16
+ import { join } from "path";
17
+ import { z } from "zod";
18
+ var stateSchema = z.strictObject({
19
+ instanceId: z.uuid(),
20
+ revision: z.number().int().positive(),
21
+ phase: z.enum(["setup", "installing", "initialized"]),
22
+ databaseUrl: z.string().optional(),
23
+ redisUrl: z.string().optional(),
24
+ internalS3Origin: z.string().optional(),
25
+ port: z.number().int().min(0).max(65535).default(8787),
26
+ host: z.string().default("0.0.0.0")
27
+ });
28
+ var BootstrapStateStore = class {
29
+ constructor(directory) {
30
+ this.directory = directory;
31
+ }
32
+ directory;
33
+ path(name) {
34
+ return join(this.directory, name);
35
+ }
36
+ async exclusive(run, retries = 0) {
37
+ await mkdir(this.directory, { recursive: true, mode: 448 });
38
+ const release = await lockfile.lock(this.directory, {
39
+ retries,
40
+ stale: 6e4,
41
+ update: 1e4
42
+ }).catch((error) => {
43
+ if (error.code === "ELOCKED") {
44
+ throw new TBError("conflict", "another local maintenance operation is running");
45
+ }
46
+ throw error;
47
+ });
48
+ try {
49
+ return await run();
50
+ } finally {
51
+ await release();
52
+ }
53
+ }
54
+ async read(name) {
55
+ try {
56
+ const path = this.path(name);
57
+ const info = await stat(path);
58
+ if (process.platform !== "win32" && (info.mode & 63) !== 0) {
59
+ throw new TBError(
60
+ "unavailable",
61
+ "bootstrap files must be readable only by their owner"
62
+ );
63
+ }
64
+ return JSON.parse(await readFile(path, "utf8"));
65
+ } catch (error) {
66
+ if (error.code === "ENOENT") return void 0;
67
+ throw error;
68
+ }
69
+ }
70
+ async write(name, value) {
71
+ await writeFileAtomic(this.path(name), JSON.stringify(value) + "\n", {
72
+ mode: 384,
73
+ fsync: true
74
+ });
75
+ }
76
+ async state() {
77
+ const value = await this.read("bootstrap.json");
78
+ return value === void 0 ? void 0 : stateSchema.parse(value);
79
+ }
80
+ async initialize() {
81
+ return this.exclusive(async () => {
82
+ const current = await this.state();
83
+ if (current) {
84
+ if (await this.read("initialized.json"))
85
+ return { ...current, phase: "initialized" };
86
+ return current;
87
+ }
88
+ if (await this.read("identity.json"))
89
+ throw new TBError(
90
+ "unavailable",
91
+ "bootstrap state requires local recovery"
92
+ );
93
+ const state = {
94
+ instanceId: randomUUID(),
95
+ revision: 1,
96
+ phase: "setup",
97
+ port: 8787,
98
+ host: "0.0.0.0"
99
+ };
100
+ await this.write("identity.json", { instanceId: state.instanceId });
101
+ await this.write("keys.json", {
102
+ keyring: createEncryptionKeyring(randomBytes(32).toString("base64url")),
103
+ storeTokenKeyring: createEncryptionKeyring(
104
+ randomBytes(32).toString("base64url")
105
+ ),
106
+ oauthKey: randomBytes(32).toString("base64url"),
107
+ adminSk: `tb_sk_${randomBytes(32).toString("base64url")}`
108
+ });
109
+ await this.write("bootstrap.json", state);
110
+ await this.pair(state.instanceId, "setup");
111
+ return state;
112
+ }, 5);
113
+ }
114
+ async pair(instanceId, mode) {
115
+ const token = randomBytes(32).toString("base64url");
116
+ await this.write("pairing.json", {
117
+ instanceId,
118
+ mode,
119
+ tokenHash: this.hash(token),
120
+ expiresAt: Date.now() + 36e5
121
+ });
122
+ await writeFileAtomic(this.path("pairing-token"), token + "\n", {
123
+ mode: 384
124
+ });
125
+ return token;
126
+ }
127
+ async createLocalPairing(mode) {
128
+ return this.exclusive(async () => {
129
+ let state;
130
+ try {
131
+ state = await this.state();
132
+ } catch {
133
+ }
134
+ if (!state && mode === "recovery") {
135
+ const identity = await this.read(
136
+ "identity.json"
137
+ );
138
+ if (!identity || !z.uuid().safeParse(identity.instanceId).success)
139
+ throw new TBError(
140
+ "unavailable",
141
+ "instance identity requires a local backup"
142
+ );
143
+ const initialized = await this.read("initialized.json");
144
+ let keys = await this.read("keys.json");
145
+ if (!keys && !initialized) {
146
+ keys = {
147
+ keyring: createEncryptionKeyring(
148
+ randomBytes(32).toString("base64url")
149
+ ),
150
+ storeTokenKeyring: createEncryptionKeyring(
151
+ randomBytes(32).toString("base64url")
152
+ ),
153
+ oauthKey: randomBytes(32).toString("base64url"),
154
+ adminSk: `tb_sk_${randomBytes(32).toString("base64url")}`
155
+ };
156
+ await this.write("keys.json", keys);
157
+ }
158
+ state = {
159
+ instanceId: identity.instanceId,
160
+ phase: initialized ? "initialized" : "installing",
161
+ revision: 1,
162
+ port: 8787,
163
+ host: "0.0.0.0"
164
+ };
165
+ await this.write("bootstrap.json", state);
166
+ }
167
+ if (!state)
168
+ throw new TBError("unavailable", "bootstrap state unavailable");
169
+ if (mode === "setup" && (state.phase === "initialized" || await this.read("initialized.json")))
170
+ throw new TBError("permission_denied", "initial setup is closed");
171
+ return this.pair(state.instanceId, mode);
172
+ });
173
+ }
174
+ hash(value) {
175
+ return createHash("sha256").update(value).digest("hex");
176
+ }
177
+ async authorize(token, mode) {
178
+ const state = await this.state();
179
+ const pair = await this.read("pairing.json");
180
+ const initialized = await this.read(
181
+ "initialized.json"
182
+ );
183
+ if (!token || !state || !pair || pair.instanceId !== state.instanceId || pair.mode !== mode || pair.expiresAt <= Date.now() || initialized && initialized.instanceId !== state.instanceId || mode === "setup" && (state.phase === "initialized" || initialized !== void 0) || !/^[0-9a-f]{64}$/.test(pair.tokenHash) || !timingSafeEqual(
184
+ Buffer.from(this.hash(token)),
185
+ Buffer.from(pair.tokenHash)
186
+ )) {
187
+ throw new TBError(
188
+ "permission_denied",
189
+ "a valid local pairing credential is required"
190
+ );
191
+ }
192
+ return initialized ? { ...state, phase: "initialized" } : state;
193
+ }
194
+ async finish(state) {
195
+ await this.write("initialized.json", { instanceId: state.instanceId });
196
+ await this.write("bootstrap.json", {
197
+ ...state,
198
+ phase: "initialized",
199
+ revision: state.revision + 1
200
+ });
201
+ await unlink(this.path("pairing.json")).catch(() => {
202
+ });
203
+ await unlink(this.path("pairing-token")).catch(() => {
204
+ });
205
+ }
206
+ async defaults() {
207
+ return this.read(
208
+ "install-defaults.json"
209
+ );
210
+ }
211
+ async secureDirectory() {
212
+ await chmod(this.directory, 448);
213
+ }
214
+ };
215
+
216
+ // package.json
217
+ var package_default = {
218
+ name: "@tool-bridge/server",
219
+ version: "0.23.0",
220
+ description: "Self-hosted Tool Bridge Node server with PostgreSQL, S3 object storage and WebSocket device channels",
221
+ type: "module",
222
+ license: "MIT",
223
+ main: "src/index.ts",
224
+ exports: {
225
+ ".": "./src/index.ts"
226
+ },
227
+ bin: {
228
+ "tool-bridge-server": "./dist/main.js",
229
+ "tool-bridge-admin": "./dist/admin.js"
230
+ },
231
+ files: [
232
+ "dist"
233
+ ],
234
+ engines: {
235
+ node: ">=22"
236
+ },
237
+ publishConfig: {
238
+ access: "public",
239
+ main: "./dist/index.js",
240
+ types: "./dist/index.d.ts",
241
+ exports: {
242
+ ".": {
243
+ types: "./dist/index.d.ts",
244
+ import: "./dist/index.js"
245
+ }
246
+ }
247
+ },
248
+ keywords: [
249
+ "self-hosted",
250
+ "docker",
251
+ "mcp",
252
+ "htbp",
253
+ "tool-bridge",
254
+ "agent-tools"
255
+ ],
256
+ scripts: {
257
+ typecheck: "tsc --noEmit",
258
+ test: "vitest run",
259
+ build: "tsup",
260
+ start: "tsx src/main.ts"
261
+ },
262
+ dependencies: {
263
+ "@hono/node-server": "catalog:",
264
+ "@tool-bridge/dashboard": "workspace:*",
265
+ hono: "catalog:",
266
+ ioredis: "^6.0.0",
267
+ postgres: "^3.4.9",
268
+ ws: "catalog:",
269
+ "@aws-sdk/client-s3": "^3.1127.0",
270
+ "@smithy/node-http-handler": "^4.12.1",
271
+ "ipaddr.js": "^2.5.0",
272
+ "write-file-atomic": "^7.0.0",
273
+ "proper-lockfile": "^4.1.2",
274
+ zod: "catalog:",
275
+ commander: "~15.0.0",
276
+ "p-retry": "^7.1.1",
277
+ negotiator: "^1.0.0"
278
+ },
279
+ devDependencies: {
280
+ "@tool-bridge/app": "workspace:*",
281
+ "@tool-bridge/core": "workspace:*",
282
+ "@tool-bridge/plugins": "workspace:*",
283
+ "@types/node": "catalog:",
284
+ "@types/ws": "catalog:",
285
+ tsup: "catalog:",
286
+ tsx: "catalog:",
287
+ vitest: "catalog:",
288
+ "@types/write-file-atomic": "^4.0.3",
289
+ "@types/proper-lockfile": "^4.1.4",
290
+ "@types/negotiator": "^0.6.4"
291
+ },
292
+ repository: {
293
+ type: "git",
294
+ url: "git+https://github.com/TokenRollAI/tool-bridge.git",
295
+ directory: "packages/server"
296
+ }
297
+ };
298
+
299
+ export {
300
+ BootstrapStateStore,
301
+ package_default
302
+ };
@@ -0,0 +1,378 @@
1
+ import {
2
+ HEADER_TB_CONTEXT,
3
+ HEADER_TB_REQUEST_ID,
4
+ HEADER_TB_UPSTREAM_AUTH,
5
+ OperationRegistry,
6
+ RequestDedupe,
7
+ TBError,
8
+ decodeCallContext,
9
+ decodePluginCall,
10
+ isTBError,
11
+ parseCredentialValues,
12
+ toToolResult
13
+ } from "./chunk-5ICRY3VU.js";
14
+
15
+ // ../plugin-sdk/src/index.ts
16
+ var CONTEXT_HANDLER_VERBS = ["list", "get", "write", "update", "delete", "search"];
17
+ var CAPABILITY_BY_VERB = { search: "search", delete: "delete" };
18
+ var PROTOCOL_VERSION = "plugin/v2";
19
+ function json(value, status = 200) {
20
+ return new Response(JSON.stringify(value), {
21
+ status,
22
+ headers: { "content-type": "application/json; charset=utf-8" }
23
+ });
24
+ }
25
+ function errorResponse(err) {
26
+ if (isTBError(err)) return json(err.toJSON(), err.httpStatus);
27
+ return json(new TBError("internal", "internal plugin error").toJSON(), 500);
28
+ }
29
+ function contextVerbs(handlers) {
30
+ const verbs = [];
31
+ for (const verb of CONTEXT_HANDLER_VERBS) {
32
+ if (typeof handlers[verb] === "function") verbs.push(verb);
33
+ }
34
+ return verbs;
35
+ }
36
+ function helpCmds(state) {
37
+ if (state.kind === "tools") return state.registry.list();
38
+ if (state.kind === "proxyTools") return [];
39
+ return contextVerbs(state.handlers).map((name) => ({ name }));
40
+ }
41
+ function createPlugin(opts = {}) {
42
+ const healthPath = opts.healthPath ?? "/healthz";
43
+ const exports = /* @__PURE__ */ new Map();
44
+ const dedupe = new RequestDedupe();
45
+ const assertFreshId = (id) => {
46
+ if (id.length === 0) throw new TBError("invalid_argument", "export id must be non-empty");
47
+ if (exports.has(id)) {
48
+ throw new TBError("invalid_argument", `export '${id}' is already declared`);
49
+ }
50
+ };
51
+ function describe() {
52
+ return {
53
+ protocolVersion: PROTOCOL_VERSION,
54
+ exports: [...exports.values()].map((state) => {
55
+ if (state.kind === "tools" || state.kind === "proxyTools") {
56
+ return {
57
+ id: state.id,
58
+ profile: "tools/v1",
59
+ ...state.description !== void 0 ? { description: state.description } : {},
60
+ ...state.auth !== void 0 ? { auth: state.auth } : {},
61
+ ...state.kind === "tools" && state.credentialProbe !== void 0 ? { credentialProbe: state.credentialProbe } : {},
62
+ ...state.credentialFields !== void 0 ? { credentialFields: state.credentialFields } : {},
63
+ ...state.kind === "tools" && state.mountConfigFields !== void 0 ? { mountConfigFields: state.mountConfigFields } : {},
64
+ ...state.kind === "tools" && state.oauth !== void 0 ? { oauth: state.oauth } : {}
65
+ };
66
+ }
67
+ const methods = contextVerbs(state.handlers);
68
+ const capabilities = methods.map((verb) => CAPABILITY_BY_VERB[verb]).filter((c) => c !== void 0);
69
+ return {
70
+ id: state.id,
71
+ profile: "context/v1",
72
+ ...state.description !== void 0 ? { description: state.description } : {},
73
+ ...state.auth !== void 0 ? { auth: state.auth } : {},
74
+ methods,
75
+ ...capabilities.length > 0 ? { capabilities } : {},
76
+ ...state.mountConfigFields !== void 0 ? { mountConfigFields: state.mountConfigFields } : {}
77
+ };
78
+ })
79
+ };
80
+ }
81
+ function help() {
82
+ return {
83
+ protocolVersion: PROTOCOL_VERSION,
84
+ exports: [...exports.values()].map((state) => ({
85
+ id: state.id,
86
+ ...state.kind === "proxyTools" ? { dynamic: true } : {},
87
+ cmds: helpCmds(state)
88
+ }))
89
+ };
90
+ }
91
+ function assertAuthorized(request, env) {
92
+ if (env?.TB_PLUGIN_IN_PROCESS === true) {
93
+ return;
94
+ }
95
+ const header = request.headers.get("authorization") ?? "";
96
+ const presented = header.startsWith("Bearer ") ? header.slice("Bearer ".length) : "";
97
+ const expected = opts.token?.(env);
98
+ if (expected === void 0) {
99
+ const devBypass = env?.TB_PLUGIN_ALLOW_ANY_TOKEN;
100
+ if (devBypass !== "true") {
101
+ throw new TBError(
102
+ "unavailable",
103
+ "plugin \u672A\u914D\u7F6E PLUGIN_TOKEN:\u751F\u4EA7\u90E8\u7F72\u5FC5\u987B\u914D\u7F6E;\u672C\u5730\u5F00\u53D1\u53EF\u8BBE TB_PLUGIN_ALLOW_ANY_TOKEN=true",
104
+ { retryable: false }
105
+ );
106
+ }
107
+ if (presented.length === 0) throw TBError.unauthenticated();
108
+ return;
109
+ }
110
+ if (presented !== expected) throw TBError.unauthenticated();
111
+ }
112
+ function decodeUpstreamAuth(request) {
113
+ const raw = request.headers.get(HEADER_TB_UPSTREAM_AUTH);
114
+ if (raw === null || raw.length === 0) return void 0;
115
+ const b64 = raw.replaceAll("-", "+").replaceAll("_", "/");
116
+ const padded = b64.padEnd(b64.length + (4 - b64.length % 4) % 4, "=");
117
+ try {
118
+ const bytes = Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
119
+ return new TextDecoder().decode(bytes);
120
+ } catch {
121
+ throw new TBError("invalid_argument", `${HEADER_TB_UPSTREAM_AUTH} is not valid base64url`);
122
+ }
123
+ }
124
+ async function dispatchTools(state, method, args, ctx) {
125
+ switch (method.toLowerCase()) {
126
+ case "list":
127
+ return state.registry.list();
128
+ case "call": {
129
+ const name = args.name;
130
+ if (typeof name !== "string") {
131
+ throw new TBError("invalid_argument", "call requires a string 'name'");
132
+ }
133
+ const callArgs = args.args ?? {};
134
+ return await state.registry.call(name, callArgs, ctx);
135
+ }
136
+ default:
137
+ throw new TBError("invalid_argument", `unknown method '${method}' on a tools export`);
138
+ }
139
+ }
140
+ async function dispatchProxyTools(state, method, args, ctx) {
141
+ switch (method.toLowerCase()) {
142
+ case "list":
143
+ return await state.handlers.list(ctx);
144
+ case "call": {
145
+ const name = args.name;
146
+ if (typeof name !== "string" || name === "") {
147
+ throw new TBError("invalid_argument", "call requires a non-empty string 'name'");
148
+ }
149
+ const callArgs = typeof args.args === "object" && args.args !== null ? args.args : {};
150
+ return toToolResult(await state.handlers.call({ name, args: callArgs }, ctx));
151
+ }
152
+ default:
153
+ throw new TBError("invalid_argument", `unknown method '${method}' on a tools export`);
154
+ }
155
+ }
156
+ async function dispatchContext(state, method, args, ctx) {
157
+ const handlers = state.handlers;
158
+ switch (method.toLowerCase()) {
159
+ case "list":
160
+ if (handlers.list === void 0) break;
161
+ return await handlers.list(
162
+ { path: String(args.path ?? ""), ...args.opts !== void 0 ? { opts: args.opts } : {} },
163
+ ctx
164
+ );
165
+ case "get":
166
+ if (handlers.get === void 0) break;
167
+ return await handlers.get({ path: String(args.path ?? "") }, ctx);
168
+ case "write":
169
+ if (handlers.write === void 0) break;
170
+ return await handlers.write(
171
+ { path: String(args.path ?? ""), entry: args.entry ?? {} },
172
+ ctx
173
+ );
174
+ case "update":
175
+ if (handlers.update === void 0) break;
176
+ return await handlers.update(
177
+ { path: String(args.path ?? ""), patch: args.patch ?? {} },
178
+ ctx
179
+ );
180
+ case "delete":
181
+ if (handlers.delete === void 0) break;
182
+ return await handlers.delete({ path: String(args.path ?? "") }, ctx);
183
+ case "search":
184
+ if (handlers.search === void 0) break;
185
+ return await handlers.search(
186
+ { query: String(args.query ?? ""), ...args.opts !== void 0 ? { opts: args.opts } : {} },
187
+ ctx
188
+ );
189
+ default:
190
+ throw new TBError("invalid_argument", `unknown method '${method}' on a context export`);
191
+ }
192
+ throw new TBError("invalid_argument", `method '${method}' is not implemented by export '${state.id}'`);
193
+ }
194
+ async function handleEnvelope(request, env) {
195
+ assertAuthorized(request, env);
196
+ const ctxHeader = request.headers.get(HEADER_TB_CONTEXT);
197
+ if (ctxHeader === null) {
198
+ throw new TBError("invalid_argument", `missing ${HEADER_TB_CONTEXT}`);
199
+ }
200
+ const caller = decodeCallContext(ctxHeader);
201
+ const call = decodePluginCall(await request.text());
202
+ const exportId = caller.exportId ?? (exports.size === 1 ? [...exports.keys()][0] : void 0);
203
+ if (exportId === void 0) {
204
+ throw new TBError("invalid_argument", "call context carries no exportId and this plugin declares multiple exports");
205
+ }
206
+ const state = exports.get(exportId);
207
+ if (state === void 0) throw new TBError("invalid_argument", `unknown export '${exportId}'`);
208
+ const upstreamAuth = decodeUpstreamAuth(request);
209
+ const credentialFields = state.kind === "context" ? void 0 : state.credentialFields;
210
+ const ctx = {
211
+ env,
212
+ caller,
213
+ exportId,
214
+ mountPath: caller.mountPath,
215
+ mountConfig: caller.mountConfig,
216
+ upstreamAuth,
217
+ credentials: credentialFields !== void 0 && upstreamAuth !== void 0 ? parseCredentialValues(upstreamAuth, credentialFields) : void 0
218
+ };
219
+ const requestId = request.headers.get(HEADER_TB_REQUEST_ID);
220
+ const run = async () => {
221
+ if (state.kind === "tools") return await dispatchTools(state, call.tool, call.arguments, ctx);
222
+ if (state.kind === "proxyTools") {
223
+ return await dispatchProxyTools(state, call.tool, call.arguments, ctx);
224
+ }
225
+ return await dispatchContext(state, call.tool, call.arguments, ctx);
226
+ };
227
+ const value = requestId === null ? await run() : await dedupe.run(requestId, run);
228
+ return json(value ?? null);
229
+ }
230
+ const plugin = {
231
+ tools(id, meta) {
232
+ assertFreshId(id);
233
+ const state = {
234
+ auth: void 0,
235
+ kind: "tools",
236
+ id,
237
+ description: meta?.description,
238
+ credentialProbe: void 0,
239
+ credentialFields: void 0,
240
+ mountConfigFields: void 0,
241
+ oauth: void 0,
242
+ registry: new OperationRegistry()
243
+ };
244
+ exports.set(id, state);
245
+ const surface = {
246
+ auth(config) {
247
+ if (state.oauth !== void 0 || state.credentialFields !== void 0) {
248
+ throw new TBError(
249
+ "invalid_argument",
250
+ `export '${id}' \u5DF2\u58F0\u660E oauth/credentials(),\u4E0D\u80FD\u518D\u58F0\u660E auth`
251
+ );
252
+ }
253
+ if (config.kind === "none" && state.credentialProbe !== void 0) {
254
+ throw new TBError(
255
+ "invalid_argument",
256
+ `export '${id}' \u5DF2\u58F0\u660E credentialProbe,\u4E0D\u80FD\u518D\u58F0\u660E auth:none`
257
+ );
258
+ }
259
+ state.auth = config;
260
+ return surface;
261
+ },
262
+ register(name, spec, handler) {
263
+ state.registry.register(name, spec, handler);
264
+ return surface;
265
+ },
266
+ credentials(fields) {
267
+ if (fields.length === 0) {
268
+ throw new TBError("invalid_argument", "credentials() \u81F3\u5C11\u8981\u58F0\u660E\u4E00\u4E2A\u5B57\u6BB5");
269
+ }
270
+ if (state.oauth !== void 0) {
271
+ throw new TBError(
272
+ "invalid_argument",
273
+ `export '${id}' \u5DF2\u58F0\u660E oauth,\u4E0D\u80FD\u518D\u58F0\u660E credentials()(oauth \u6A21\u5F0F\u4E0B authRef \u6307\u5411\u7684 secret \u56FA\u5B9A\u5B58 clientId/clientSecret)`
274
+ );
275
+ }
276
+ if (state.auth !== void 0) {
277
+ throw new TBError("invalid_argument", `export '${id}' \u5DF2\u58F0\u660E auth,\u4E0D\u80FD\u518D\u58F0\u660E credentials()`);
278
+ }
279
+ state.credentialFields = fields;
280
+ return surface;
281
+ },
282
+ mountConfig(fields) {
283
+ if (fields.length === 0) {
284
+ throw new TBError("invalid_argument", "mountConfig() \u81F3\u5C11\u8981\u58F0\u660E\u4E00\u4E2A\u5B57\u6BB5");
285
+ }
286
+ state.mountConfigFields = fields;
287
+ return surface;
288
+ },
289
+ oauth(config) {
290
+ if (state.credentialFields !== void 0) {
291
+ throw new TBError(
292
+ "invalid_argument",
293
+ `export '${id}' \u5DF2\u58F0\u660E credentials(),\u4E0D\u80FD\u518D\u58F0\u660E oauth(oauth \u6A21\u5F0F\u4E0B authRef \u6307\u5411\u7684 secret \u56FA\u5B9A\u5B58 clientId/clientSecret)`
294
+ );
295
+ }
296
+ if (state.auth !== void 0) {
297
+ throw new TBError("invalid_argument", `export '${id}' \u5DF2\u58F0\u660E auth,\u4E0D\u80FD\u518D\u58F0\u660E oauth`);
298
+ }
299
+ if (state.credentialProbe !== void 0) {
300
+ throw new TBError(
301
+ "invalid_argument",
302
+ `export '${id}' \u5DF2\u58F0\u660E credentialProbe,\u4E0D\u80FD\u518D\u58F0\u660E oauth(\u51ED\u8BC1\u53EF\u7528\u6027\u7531\u6388\u6743\u6D41\u7A0B\u672C\u8EAB\u8BC1\u660E;\u62FF client \u51ED\u8BC1\u53BB\u8C03\u63A2\u9488\u65E2\u8BC1\u660E\u4E0D\u4E86\u4EC0\u4E48,\u53C8\u4F1A\u628A clientSecret \u9001\u8FDB\u63D2\u4EF6)`
303
+ );
304
+ }
305
+ state.oauth = config;
306
+ return surface;
307
+ },
308
+ probeCredentialWith(name) {
309
+ if (!state.registry.list().some((tool) => tool.name === name)) {
310
+ throw new TBError(
311
+ "invalid_argument",
312
+ `credentialProbe '${name}' \u4E0D\u662F export '${id}' \u5DF2\u6CE8\u518C\u7684\u5DE5\u5177`
313
+ );
314
+ }
315
+ if (state.oauth !== void 0) {
316
+ throw new TBError(
317
+ "invalid_argument",
318
+ `export '${id}' \u5DF2\u58F0\u660E oauth,\u4E0D\u80FD\u518D\u58F0\u660E credentialProbe(\u51ED\u8BC1\u53EF\u7528\u6027\u7531\u6388\u6743\u6D41\u7A0B\u672C\u8EAB\u8BC1\u660E;\u62FF client \u51ED\u8BC1\u53BB\u8C03\u63A2\u9488\u65E2\u8BC1\u660E\u4E0D\u4E86\u4EC0\u4E48,\u53C8\u4F1A\u628A clientSecret \u9001\u8FDB\u63D2\u4EF6)`
319
+ );
320
+ }
321
+ if (state.auth?.kind === "none") {
322
+ throw new TBError("invalid_argument", `export '${id}' \u58F0\u660E auth:none,\u4E0D\u80FD\u518D\u58F0\u660E credentialProbe`);
323
+ }
324
+ state.credentialProbe = name;
325
+ return surface;
326
+ }
327
+ };
328
+ return surface;
329
+ },
330
+ proxyTools(id, handlers) {
331
+ assertFreshId(id);
332
+ if (handlers.auth !== void 0 && handlers.credentialFields !== void 0) {
333
+ throw new TBError("invalid_argument", `export '${id}' \u7684 auth \u4E0D\u80FD\u4E0E credentialFields \u540C\u65F6\u58F0\u660E`);
334
+ }
335
+ exports.set(id, {
336
+ auth: handlers.auth,
337
+ kind: "proxyTools",
338
+ id,
339
+ description: handlers.description,
340
+ credentialFields: handlers.credentialFields,
341
+ handlers
342
+ });
343
+ return plugin;
344
+ },
345
+ context(id, handlers) {
346
+ assertFreshId(id);
347
+ exports.set(id, {
348
+ auth: handlers.auth,
349
+ kind: "context",
350
+ id,
351
+ description: handlers.description,
352
+ handlers,
353
+ mountConfigFields: handlers.mountConfigFields
354
+ });
355
+ return plugin;
356
+ },
357
+ async fetch(request, env) {
358
+ try {
359
+ const url = new URL(request.url);
360
+ if (request.method === "GET") {
361
+ if (url.pathname === healthPath) return json({ healthy: true });
362
+ if (url.pathname === "/~describe") return json(describe());
363
+ if (url.pathname === "/~help") return json(help());
364
+ throw TBError.notFound("no such path");
365
+ }
366
+ if (request.method !== "POST") throw TBError.notFound("no such path");
367
+ return await handleEnvelope(request, env);
368
+ } catch (err) {
369
+ return errorResponse(err);
370
+ }
371
+ }
372
+ };
373
+ return plugin;
374
+ }
375
+
376
+ export {
377
+ createPlugin
378
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createProviderHttpClient
3
- } from "./chunk-E6JCVKW6.js";
3
+ } from "./chunk-VWRUGUSU.js";
4
4
  import {
5
5
  asJsonObject,
6
6
  trimmedText
@@ -8,10 +8,10 @@ import {
8
8
  import {
9
9
  requireApiKey,
10
10
  upstreamError
11
- } from "./chunk-ATK45BXV.js";
11
+ } from "./chunk-WJHG6OK7.js";
12
12
  import {
13
13
  TBError
14
- } from "./chunk-UZM2RXZH.js";
14
+ } from "./chunk-5ICRY3VU.js";
15
15
 
16
16
  // ../plugins/src/_runtime/authedClient.ts
17
17
  function extractErrorMessage(payload, keys) {