@tool-bridge/server 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{airtable-QYTOPRFV.js → airtable-NOSOMOVB.js} +106 -114
- package/dist/{alt_text_generator_ai-2CFYNSZV.js → alt_text_generator_ai-BHIJ4LW5.js} +25 -16
- package/dist/{amap-HGOBOHSZ.js → amap-QRLP4TWZ.js} +114 -123
- package/dist/{anthropic-3OXOQNSR.js → anthropic-IEOI36EV.js} +34 -56
- package/dist/{apify-PUV2QGKL.js → apify-3CCYTQVK.js} +31 -49
- package/dist/{brave_search-DG75AVKA.js → brave_search-PZNYDQG7.js} +52 -77
- package/dist/chunk-JXHMDBAY.js +45 -0
- package/dist/chunk-LMLX3DJF.js +50 -0
- package/dist/{chunk-DXXYNIXV.js → chunk-RVWZN3CI.js} +3337 -1440
- package/dist/{chunk-NLPTB3IL.js → chunk-TLNUIPFZ.js} +1475 -277
- package/dist/chunk-U5UHT7CX.js +977 -0
- package/dist/chunk-U67V476Y.js +35 -0
- package/dist/chunk-WW2IMPQK.js +283 -0
- package/dist/{chunk-NQ67PIIS.js → chunk-YASUMV2K.js} +4 -6
- package/dist/{circleci-EFNLX5AW.js → circleci-VSJ4O5FC.js} +36 -55
- package/dist/{clerk-UWDLMZVM.js → clerk-CC2JZBZI.js} +60 -80
- package/dist/{cloudflare_dns-WQXVDSPU.js → cloudflare_dns-PJEBSEYQ.js} +90 -113
- package/dist/{cohere-VPDIKUDP.js → cohere-KBACYSPF.js} +33 -49
- package/dist/{confluence-NBOOQNTR.js → confluence-2PX3O7G5.js} +79 -115
- package/dist/{convertapi-6Z6OP25T.js → convertapi-BVOTD2PJ.js} +13 -16
- package/dist/{currencyapi-CAMUWCTV.js → currencyapi-6ZQ2VNQ7.js} +30 -53
- package/dist/{deepseek-GRALXYXR.js → deepseek-MB3WVVTB.js} +30 -38
- package/dist/{docker_hub-5AASF3TJ.js → docker_hub-7CLQL2IJ.js} +141 -157
- package/dist/{dropbox-HS3VGRD3.js → dropbox-VFYDVUNK.js} +134 -141
- package/dist/{dub-KHERUTW6.js → dub-QN3EETJY.js} +61 -93
- package/dist/{e2b-4MGHPFXY.js → e2b-NKC3Y776.js} +39 -69
- package/dist/{exa-O77PKTBT.js → exa-KKZ6F25K.js} +49 -77
- package/dist/{fal_ai-TX2TZFMP.js → fal_ai-25LYJD2O.js} +37 -44
- package/dist/{feishu-I7VPWO3C.js → feishu-NRT55B3Q.js} +4 -6
- package/dist/{feishu_custom_bot-D4XZDLES.js → feishu_custom_bot-3W3XXUG4.js} +4 -5
- package/dist/{figma-SW3HZCZ5.js → figma-4FLP35TC.js} +56 -81
- package/dist/{firehydrant-ND5DEW3L.js → firehydrant-BLXPLZ3X.js} +40 -53
- package/dist/{fixer-ZTSV7ZK3.js → fixer-4OR62TGE.js} +31 -43
- package/dist/{fly-RZ7SZKFT.js → fly-MYCKOZZK.js} +50 -66
- package/dist/{front-Q5MZVUGX.js → front-3DFYVMF3.js} +43 -66
- package/dist/{geocodio-QPHHODHG.js → geocodio-CXMD6VKA.js} +37 -63
- package/dist/{ghost-3Q6O7EWZ.js → ghost-4UUE737W.js} +51 -57
- package/dist/{github-LDMGJHXV.js → github-WFS2ON2N.js} +48 -41
- package/dist/{gmail-6QBCI3TT.js → gmail-KW7FXA7A.js} +26 -36
- package/dist/{googlecalendar-LLSYY4ZJ.js → googlecalendar-AMH5JQMC.js} +57 -78
- package/dist/{googledocs-KRGVBGWY.js → googledocs-R5VA6CKD.js} +14 -22
- package/dist/{grafana-OHPZMRHT.js → grafana-IT6DWIVB.js} +95 -122
- package/dist/{graphhopper-2PBY7OX4.js → graphhopper-TYFDJZWC.js} +32 -46
- package/dist/index.d.ts +199 -106
- package/dist/index.js +4 -3
- package/dist/{ip2proxy-GPBQZKKG.js → ip2proxy-GJ4HXVXO.js} +35 -42
- package/dist/{ipgeolocation_io-YNTOLOFH.js → ipgeolocation_io-OAGR6PRF.js} +40 -60
- package/dist/{ipqualityscore-CZLQUAQ7.js → ipqualityscore-BCKAMDGL.js} +30 -42
- package/dist/{jina_ai-JIFEYH5C.js → jina_ai-N3NXRVIZ.js} +32 -58
- package/dist/{jira-2DKTIWHK.js → jira-CHLBKWLO.js} +116 -126
- package/dist/{langsmith-UCX7NHKP.js → langsmith-OIKOTPY3.js} +101 -121
- package/dist/{lemlist-IS6K2VJG.js → lemlist-VAKYPKS3.js} +57 -68
- package/dist/{linear-AK6547ZS.js → linear-Q6QTPJ5R.js} +109 -118
- package/dist/{logsnag-EB5LICOH.js → logsnag-SQOQBTES.js} +31 -48
- package/dist/main.js +103 -102
- package/dist/{mattermost-YOSWUA3R.js → mattermost-G2KBEICM.js} +45 -62
- package/dist/{mem0-IICTSHLB.js → mem0-D2FPLYDX.js} +72 -98
- package/dist/{memos-DIV6MZPB.js → memos-76PTWV5V.js} +68 -122
- package/dist/{metabase-ZGHNTCAT.js → metabase-TWSIDVBM.js} +47 -60
- package/dist/{mistral_ai-IAG3WZYO.js → mistral_ai-TP7TQUEJ.js} +35 -40
- package/dist/{mother_duck-PYKG4ZHO.js → mother_duck-UXY5THYU.js} +42 -62
- package/dist/{ngrok-BXN3DGTK.js → ngrok-RZW2ISJK.js} +42 -58
- package/dist/{notes-L2UO36HQ.js → notes-B2I6FWK2.js} +3 -5
- package/dist/{notion-PVHVOV4R.js → notion-QOKRUE6M.js} +83 -97
- package/dist/{open_exchange_rates-DVMOPFNQ.js → open_exchange_rates-ODLFWEJ7.js} +35 -39
- package/dist/{openai-VW6F5YTK.js → openai-ZPBPPPGT.js} +51 -55
- package/dist/{opengraph_io-MQUREYWM.js → opengraph_io-EOI5UJKT.js} +61 -79
- package/dist/{openrouter-5MI3ODCU.js → openrouter-BUWLF3BG.js} +41 -55
- package/dist/{outline-B2U7NIVA.js → outline-NXS3QRXO.js} +89 -104
- package/dist/{paddle-LDZTVYQO.js → paddle-T4MSKQ76.js} +34 -49
- package/dist/{perplexity-P7BNWFMH.js → perplexity-WW5N2LW7.js} +33 -50
- package/dist/{pinecone-3Y67EJYP.js → pinecone-RY5AZPQM.js} +65 -91
- package/dist/{pipedrive-4KFLGCJW.js → pipedrive-OHYQNZTU.js} +37 -59
- package/dist/{polar-NIULQPUD.js → polar-XZIAHXS5.js} +43 -53
- package/dist/{posthog-UXGCIHRP.js → posthog-DTPTWORY.js} +58 -77
- package/dist/{postmark-XT77YNQM.js → postmark-F4UCQKC3.js} +52 -71
- package/dist/{prerender-37E6ZN6Z.js → prerender-P3Y2MLIC.js} +32 -50
- package/dist/{pubmed-BO2W4IR6.js → pubmed-RHU3GXFB.js} +28 -60
- package/dist/{railway-5BACZNYC.js → railway-VB6SRLI6.js} +32 -39
- package/dist/{readwise-DXABSDKY.js → readwise-DIMSKJZR.js} +62 -78
- package/dist/{render-4MCO6RLA.js → render-XCCDCEEK.js} +48 -64
- package/dist/{replicate-IVEPY4EP.js → replicate-IUEOQ4JC.js} +41 -58
- package/dist/{resend-XJBJO46B.js → resend-N5MJZH5E.js} +27 -37
- package/dist/{rootly-R6QDVF3D.js → rootly-25T4NBTU.js} +64 -76
- package/dist/{scrapfly-E24XNN32.js → scrapfly-PK4XFXUA.js} +45 -51
- package/dist/{scrapingbee-QT3O334C.js → scrapingbee-ITPBMWQU.js} +25 -33
- package/dist/{screenshot_fyi-MJNFPUFV.js → screenshot_fyi-5U6ZYPKR.js} +29 -47
- package/dist/{semantic_scholar-BVKWS72R.js → semantic_scholar-BJGCI2MU.js} +37 -56
- package/dist/{sentry-52T5XARK.js → sentry-63IC263P.js} +66 -85
- package/dist/{shodan-RTOTTCX2.js → shodan-2WBIFHFN.js} +42 -53
- package/dist/{shopify-3RVWQDZ6.js → shopify-XLLJRAGM.js} +32 -49
- package/dist/{stripe-M3T2K3EW.js → stripe-WLVCY3UN.js} +4 -5
- package/dist/{supabase-UUUXAEYR.js → supabase-BKNZ35ER.js} +69 -88
- package/dist/{tavily-LVOZQQKJ.js → tavily-YFSDEUTL.js} +37 -62
- package/dist/{telegram-WJQPCKQT.js → telegram-FC35W74G.js} +168 -177
- package/dist/{telnyx-THKSKAI2.js → telnyx-MI32XZUG.js} +30 -50
- package/dist/{todoist-YTRGFFRC.js → todoist-4ZFJKZC6.js} +77 -89
- package/dist/{trello-QBK6WKN2.js → trello-UOGFNMK4.js} +108 -122
- package/dist/{turso-EA44ZKLR.js → turso-YTSTW3ZS.js} +52 -64
- package/dist/{twilio-GSW3V55S.js → twilio-XAJDFUQH.js} +48 -55
- package/dist/{umami-DVZ7XUYC.js → umami-ZVIUBPAI.js} +49 -69
- package/dist/{unsplash-ZWUWQ7OS.js → unsplash-IU3PLDNS.js} +35 -52
- package/dist/{upstash_redis-BQIQB5NM.js → upstash_redis-3EYJW7SY.js} +28 -40
- package/dist/{uptimerobot-2OJHTUPV.js → uptimerobot-PJG2ASRU.js} +11 -12
- package/dist/{v2ex-IZF4BB4O.js → v2ex-KFQWWGFC.js} +36 -61
- package/dist/{vercel-PI3BJENX.js → vercel-I2ZDOQRL.js} +124 -150
- package/dist/{webapi-VLM4IKVB.js → webapi-GW5QXWXE.js} +1 -1
- package/dist/{wolfram_alpha_api-EYQ2QCHH.js → wolfram_alpha_api-BNXOJMB6.js} +26 -34
- package/dist/{wordpress-ETDA6XLX.js → wordpress-36D7BSMP.js} +87 -104
- package/dist/{workos-D7INO4Y4.js → workos-6X4JJRRC.js} +37 -56
- package/dist/{zhihu-Q7FNHEDM.js → zhihu-CIXKCHIU.js} +35 -57
- package/package.json +5 -5
- package/dist/chunk-KH663T3A.js +0 -183
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/chunk-UI4E4T5Q.js +0 -378
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createGuardedFetch
|
|
3
|
+
} from "./chunk-U5UHT7CX.js";
|
|
1
4
|
import {
|
|
2
5
|
AnnotationStore,
|
|
3
6
|
CONTEXT_CAPABILITIES,
|
|
4
7
|
CONTEXT_DIRECT_UPLOAD_CAPABILITY,
|
|
5
8
|
DEFAULT_MAX_NODES,
|
|
9
|
+
DEFAULT_STORE_DRIVER_KEY_ROOT,
|
|
6
10
|
DEVICE_CALL_TIMEOUT_MS,
|
|
7
11
|
DeviceGatewaySession,
|
|
8
12
|
FEEDBACK_HIDE_SCORE,
|
|
@@ -26,12 +30,12 @@ import {
|
|
|
26
30
|
PG_SEARCH_TOOLS_TABLE,
|
|
27
31
|
PG_SEARCH_WRITE_LOCK_KEY,
|
|
28
32
|
PRESIGN_TTL_SEC_DEFAULT,
|
|
29
|
-
PRESIGN_TTL_SEC_MAX,
|
|
30
33
|
RemoteAllowlistStore,
|
|
31
34
|
SKILLHUB_CAPABILITIES,
|
|
32
35
|
SKRegistryStore,
|
|
33
36
|
SecretStoreImpl,
|
|
34
37
|
SqlSearchIndex,
|
|
38
|
+
StoreService,
|
|
35
39
|
TBError,
|
|
36
40
|
TB_ERROR_CODES,
|
|
37
41
|
TOOL_SEARCH_AUDIT_NODE_LIMIT,
|
|
@@ -79,17 +83,31 @@ import {
|
|
|
79
83
|
createObjectContextProvider,
|
|
80
84
|
createObjectContextUploadGrant,
|
|
81
85
|
createSkillhubProvider,
|
|
86
|
+
createStoreModule,
|
|
82
87
|
decodeDeviceFrame,
|
|
83
88
|
derivePresence,
|
|
84
89
|
deviceDirectoryHelpModel,
|
|
85
90
|
deviceFsHelpModel,
|
|
86
91
|
deviceShellHelpModel,
|
|
87
92
|
discriminatedUnion,
|
|
93
|
+
dispatchContextCmd,
|
|
94
|
+
dispatchContextUploadCmd,
|
|
95
|
+
dispatchSkillhubCmd,
|
|
88
96
|
effectFor,
|
|
89
97
|
email,
|
|
90
98
|
encodeCallContext,
|
|
91
99
|
encodeDeviceFrame,
|
|
92
100
|
encodePluginCall,
|
|
101
|
+
external_exports,
|
|
102
|
+
feedbackDetailSchema,
|
|
103
|
+
feedbackListSchema,
|
|
104
|
+
feedbackRemoveResponseSchema,
|
|
105
|
+
feedbackSubmitRequestSchema,
|
|
106
|
+
feedbackSubmitResponseSchema,
|
|
107
|
+
feedbackViewSchema,
|
|
108
|
+
feedbackVoteRequestSchema,
|
|
109
|
+
healthResponseSchema,
|
|
110
|
+
helpJsonSchema,
|
|
93
111
|
identify,
|
|
94
112
|
intersection,
|
|
95
113
|
isContextExpired,
|
|
@@ -98,23 +116,30 @@ import {
|
|
|
98
116
|
iso_exports,
|
|
99
117
|
lazy,
|
|
100
118
|
literal,
|
|
119
|
+
livenessResponseSchema,
|
|
101
120
|
looseObject,
|
|
102
121
|
mintKey,
|
|
103
122
|
negotiate,
|
|
104
|
-
|
|
123
|
+
nodeInputSchema,
|
|
105
124
|
normalizeEntryPath,
|
|
106
125
|
normalizePath,
|
|
107
126
|
normalizeToolSearchLimit,
|
|
108
127
|
normalizeToolSearchPath,
|
|
109
128
|
normalizeUpstreamError,
|
|
110
129
|
number,
|
|
130
|
+
oauthAuthorizeRequestSchema,
|
|
131
|
+
oauthAuthorizeResponseSchema,
|
|
111
132
|
object,
|
|
112
133
|
objectBodyToBytes,
|
|
113
134
|
optional,
|
|
114
135
|
optionalMethodsForCapabilities,
|
|
136
|
+
parseContextCmdArgs,
|
|
115
137
|
parseCredentialValues,
|
|
116
138
|
parseFeedbackEntries,
|
|
117
139
|
parseNodeInput,
|
|
140
|
+
parseNonNegativeIntEnv,
|
|
141
|
+
parsePortEnv,
|
|
142
|
+
parseRuntimeEnv,
|
|
118
143
|
parseTokenResponse,
|
|
119
144
|
parseVia,
|
|
120
145
|
pgBulkInsertSql,
|
|
@@ -122,7 +147,9 @@ import {
|
|
|
122
147
|
pluginTokenSecretName,
|
|
123
148
|
prefixUpperBound,
|
|
124
149
|
preprocess,
|
|
150
|
+
readinessResponseSchema,
|
|
125
151
|
record,
|
|
152
|
+
registryNodeSchema,
|
|
126
153
|
renderHelpDsl,
|
|
127
154
|
renderHelpJson,
|
|
128
155
|
renderHelpMarkdown,
|
|
@@ -136,58 +163,41 @@ import {
|
|
|
136
163
|
shouldRefresh,
|
|
137
164
|
skillhubHelpModel,
|
|
138
165
|
skillhubScopeForCmd,
|
|
166
|
+
storeUri,
|
|
139
167
|
string,
|
|
168
|
+
tbErrorBodySchema,
|
|
140
169
|
toJSONSchema,
|
|
141
170
|
toolHelpModel,
|
|
171
|
+
toolSearchPageSchema,
|
|
172
|
+
toolSearchRequestSchema,
|
|
142
173
|
toolSearchSnapshotDigest,
|
|
143
174
|
toolsToHelpModel,
|
|
175
|
+
treeJsonSchema,
|
|
144
176
|
union,
|
|
145
177
|
unknown,
|
|
146
178
|
url,
|
|
147
179
|
validatePath,
|
|
148
180
|
virtualizeTools
|
|
149
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-RVWZN3CI.js";
|
|
150
182
|
|
|
151
183
|
// src/config.ts
|
|
152
184
|
var DEFAULT_PORT = 8787;
|
|
153
|
-
var DEFAULT_MAX_HOPS = 4;
|
|
154
185
|
var DEFAULT_DEVICE_RECLAIM_SEC = 24 * 60 * 60;
|
|
155
|
-
|
|
156
|
-
const n = Number(value);
|
|
157
|
-
return Number.isFinite(n) && n > 0 ? Math.floor(n) : void 0;
|
|
158
|
-
}
|
|
159
|
-
function presignTtlEnv(value) {
|
|
160
|
-
const ttl = positiveIntEnv(value);
|
|
161
|
-
return ttl === void 0 ? void 0 : Math.min(ttl, PRESIGN_TTL_SEC_MAX);
|
|
162
|
-
}
|
|
163
|
-
function portEnv(value) {
|
|
164
|
-
if (value === void 0 || value === "") return void 0;
|
|
165
|
-
const n = Number(value);
|
|
166
|
-
return Number.isInteger(n) && n >= 0 && n <= 65535 ? n : void 0;
|
|
167
|
-
}
|
|
186
|
+
var DEFAULT_STORE_CLEANUP_INTERVAL_SEC = 15 * 60;
|
|
168
187
|
function configFromEnv(env = process.env) {
|
|
169
|
-
const
|
|
170
|
-
const allowlist = (env.TB_REMOTE_ALLOWLIST ?? "").split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
188
|
+
const runtime = parseRuntimeEnv(env);
|
|
171
189
|
const config = {
|
|
190
|
+
...runtime,
|
|
172
191
|
// TB_PORT 优先,PORT 兜底:Railway / Fly / Cloud Run / CF Container 等 PaaS 只注入
|
|
173
192
|
// PORT,不认识 TB_PORT —— 不兜底的话容器会监听 8787 而平台探活另一个端口,部署直接失败。
|
|
174
|
-
port:
|
|
193
|
+
port: parsePortEnv(env.TB_PORT) ?? parsePortEnv(env.PORT) ?? DEFAULT_PORT,
|
|
175
194
|
host: env.TB_HOST !== void 0 && env.TB_HOST.length > 0 ? env.TB_HOST : "0.0.0.0",
|
|
176
195
|
dataDir: env.TB_DATA_DIR !== void 0 && env.TB_DATA_DIR.length > 0 ? env.TB_DATA_DIR : "./data",
|
|
177
|
-
allowInsecureHttp: allowInsecure,
|
|
178
196
|
allowInsecureBootstrap: env.TB_ALLOW_INSECURE_BOOTSTRAP === "true",
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
allowInsecure
|
|
184
|
-
},
|
|
185
|
-
deviceReclaimSec: positiveIntEnv(env.TB_DEVICE_RECLAIM_SEC) ?? DEFAULT_DEVICE_RECLAIM_SEC,
|
|
186
|
-
// 0 合法(立即关停,本地/单机默认);positiveIntEnv 拒 0,故单独解析。
|
|
187
|
-
shutdownDrainSec: (() => {
|
|
188
|
-
const n = Number(env.TB_SHUTDOWN_DRAIN_SEC);
|
|
189
|
-
return Number.isInteger(n) && n >= 0 ? n : 0;
|
|
190
|
-
})()
|
|
197
|
+
deviceReclaimSec: runtime.deviceReclaimSec ?? DEFAULT_DEVICE_RECLAIM_SEC,
|
|
198
|
+
storeCleanupIntervalSec: runtime.storeCleanupIntervalSec ?? DEFAULT_STORE_CLEANUP_INTERVAL_SEC,
|
|
199
|
+
// 0 合法(立即关停,本地/单机默认)。
|
|
200
|
+
shutdownDrainSec: parseNonNegativeIntEnv(env.TB_SHUTDOWN_DRAIN_SEC) ?? 0
|
|
191
201
|
};
|
|
192
202
|
if (env.TB_UI_DIR !== void 0 && env.TB_UI_DIR.length > 0) config.uiDir = env.TB_UI_DIR;
|
|
193
203
|
if (env.TB_DATABASE_URL !== void 0 && env.TB_DATABASE_URL.length > 0) {
|
|
@@ -224,19 +234,9 @@ function configFromEnv(env = process.env) {
|
|
|
224
234
|
if (env.TB_BOOTSTRAP_ADMIN_SK !== void 0 && env.TB_BOOTSTRAP_ADMIN_SK.length > 0) {
|
|
225
235
|
config.adminSk = env.TB_BOOTSTRAP_ADMIN_SK;
|
|
226
236
|
}
|
|
227
|
-
const canonicalOrigin = normalizeCanonicalOrigin(env.TB_CANONICAL_ORIGIN);
|
|
228
|
-
if (canonicalOrigin !== void 0) config.canonicalOrigin = canonicalOrigin;
|
|
229
237
|
if (env.TB_SECRET_ENCRYPTION_KEY !== void 0 && env.TB_SECRET_ENCRYPTION_KEY.length > 0) {
|
|
230
238
|
config.encryptionKey = env.TB_SECRET_ENCRYPTION_KEY;
|
|
231
239
|
}
|
|
232
|
-
const ttl = positiveIntEnv(env.TB_TOOL_CACHE_TTL);
|
|
233
|
-
if (ttl !== void 0) config.toolCacheTtlSec = ttl;
|
|
234
|
-
const refThreshold = positiveIntEnv(env.TB_REF_THRESHOLD_BYTES);
|
|
235
|
-
if (refThreshold !== void 0) config.refThresholdBytes = refThreshold;
|
|
236
|
-
const refTtl = presignTtlEnv(env.TB_REF_TTL_SEC);
|
|
237
|
-
if (refTtl !== void 0) config.refTtlSec = refTtl;
|
|
238
|
-
const uploadGrantTtl = presignTtlEnv(env.TB_UPLOAD_GRANT_TTL_SEC);
|
|
239
|
-
if (uploadGrantTtl !== void 0) config.uploadGrantTtlSec = uploadGrantTtl;
|
|
240
240
|
return config;
|
|
241
241
|
}
|
|
242
242
|
|
|
@@ -439,7 +439,8 @@ var BUILTIN_MODULES = [
|
|
|
439
439
|
"plugin",
|
|
440
440
|
"catalog",
|
|
441
441
|
"federation",
|
|
442
|
-
"annotation"
|
|
442
|
+
"annotation",
|
|
443
|
+
"store"
|
|
443
444
|
];
|
|
444
445
|
var BUILTIN_DESCRIPTIONS = {
|
|
445
446
|
sk: "SecretKey registry",
|
|
@@ -449,7 +450,8 @@ var BUILTIN_DESCRIPTIONS = {
|
|
|
449
450
|
plugin: "Plugin registry (external plugins)",
|
|
450
451
|
catalog: "Built-in integration catalog (read-only)",
|
|
451
452
|
federation: "Remote federation host allowlist",
|
|
452
|
-
annotation: "Admin notes shown in ~help of any path"
|
|
453
|
+
annotation: "Admin notes shown in ~help of any path",
|
|
454
|
+
store: "Deployment-level private object Store"
|
|
453
455
|
};
|
|
454
456
|
async function mintAdminWithPlaintext(store, plaintext, now) {
|
|
455
457
|
const { key } = await mintKey(adminBootstrapInput(), now);
|
|
@@ -554,10 +556,14 @@ async function presignS3Url(client, url2, ttlSec) {
|
|
|
554
556
|
}
|
|
555
557
|
async function presignS3Put(client, url2, ttlSec, opts) {
|
|
556
558
|
assertPresignTtlSec(ttlSec);
|
|
559
|
+
if ("contentLength" in opts && (!Number.isSafeInteger(opts.contentLength) || opts.contentLength < 0)) {
|
|
560
|
+
throw new TBError("invalid_argument", "presigned PUT contentLength \u5FC5\u987B\u662F\u975E\u8D1F\u5B89\u5168\u6574\u6570");
|
|
561
|
+
}
|
|
557
562
|
const target = new URL(url2);
|
|
558
563
|
target.searchParams.set("X-Amz-Expires", String(ttlSec));
|
|
559
564
|
const headers = {
|
|
560
565
|
"content-type": opts.contentType,
|
|
566
|
+
..."contentLength" in opts ? { "content-length": String(opts.contentLength) } : {},
|
|
561
567
|
...opts.ifNoneMatch === void 0 ? {} : { "if-none-match": opts.ifNoneMatch }
|
|
562
568
|
};
|
|
563
569
|
const signed = await client.sign(
|
|
@@ -567,6 +573,48 @@ async function presignS3Put(client, url2, ttlSec, opts) {
|
|
|
567
573
|
return { method: "PUT", url: signed.url, headers };
|
|
568
574
|
}
|
|
569
575
|
|
|
576
|
+
// ../app/src/objectBodyStream.ts
|
|
577
|
+
function toWebObjectBodyStream(source, options = {}) {
|
|
578
|
+
const reader = source.getReader();
|
|
579
|
+
let released = false;
|
|
580
|
+
const release = () => {
|
|
581
|
+
if (released) return;
|
|
582
|
+
released = true;
|
|
583
|
+
reader.releaseLock();
|
|
584
|
+
};
|
|
585
|
+
const strategy = options.highWaterMark === void 0 ? void 0 : { highWaterMark: options.highWaterMark };
|
|
586
|
+
return new ReadableStream({
|
|
587
|
+
async pull(controller) {
|
|
588
|
+
try {
|
|
589
|
+
const { done, value } = await reader.read();
|
|
590
|
+
if (done) {
|
|
591
|
+
release();
|
|
592
|
+
controller.close();
|
|
593
|
+
} else if (value !== void 0) {
|
|
594
|
+
controller.enqueue(value);
|
|
595
|
+
}
|
|
596
|
+
} catch (error) {
|
|
597
|
+
try {
|
|
598
|
+
release();
|
|
599
|
+
} catch {
|
|
600
|
+
}
|
|
601
|
+
controller.error(error);
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
async cancel(reason) {
|
|
605
|
+
try {
|
|
606
|
+
if (reader.cancel !== void 0) await reader.cancel(reason);
|
|
607
|
+
else await source.cancel?.(reason);
|
|
608
|
+
} finally {
|
|
609
|
+
try {
|
|
610
|
+
release();
|
|
611
|
+
} catch {
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}, strategy);
|
|
616
|
+
}
|
|
617
|
+
|
|
570
618
|
// ../app/src/providers/s3Object.ts
|
|
571
619
|
var META_HEADER_PREFIX = "x-amz-meta-";
|
|
572
620
|
function stripEtagQuotes(etag) {
|
|
@@ -600,14 +648,17 @@ function createS3ObjectStore(cfg, opts) {
|
|
|
600
648
|
accessKeyId: cfg.accessKeyId,
|
|
601
649
|
secretAccessKey: cfg.secretAccessKey,
|
|
602
650
|
service: "s3",
|
|
603
|
-
region: cfg.region ?? "auto"
|
|
651
|
+
region: cfg.region ?? "auto",
|
|
652
|
+
// Store 的重试由上层按操作幂等性统一决定。传输层不得自动重放写入,
|
|
653
|
+
// 也不能让读/删路径悄悄继承 aws4fetch 的默认 10 次重试。
|
|
654
|
+
retries: 0
|
|
604
655
|
});
|
|
605
656
|
const base = cfg.endpoint.replace(/\/+$/, "");
|
|
606
657
|
const bucketUrl = `${base}/${cfg.bucket}`;
|
|
607
658
|
const urlFor = (key) => `${bucketUrl}/${encodeObjectKey(key)}`;
|
|
608
|
-
const
|
|
659
|
+
const s3FetchWith = async (aws, url2, init) => {
|
|
609
660
|
try {
|
|
610
|
-
return await
|
|
661
|
+
return await aws.fetch(url2, init);
|
|
611
662
|
} catch (err) {
|
|
612
663
|
throw normalizeUpstreamError({
|
|
613
664
|
kind: "network",
|
|
@@ -615,6 +666,16 @@ function createS3ObjectStore(cfg, opts) {
|
|
|
615
666
|
});
|
|
616
667
|
}
|
|
617
668
|
};
|
|
669
|
+
const s3Fetch = async (url2, init) => {
|
|
670
|
+
return await s3FetchWith(client, url2, init);
|
|
671
|
+
};
|
|
672
|
+
const fetchBody = (body) => {
|
|
673
|
+
if (typeof body === "string" || body instanceof ArrayBuffer) return body;
|
|
674
|
+
if (body instanceof Uint8Array) {
|
|
675
|
+
return body.buffer instanceof ArrayBuffer ? new Uint8Array(body.buffer, body.byteOffset, body.byteLength) : new Uint8Array(body);
|
|
676
|
+
}
|
|
677
|
+
return toWebObjectBodyStream(body, { highWaterMark: 0 });
|
|
678
|
+
};
|
|
618
679
|
const metaFromHeaders = (key, headers) => {
|
|
619
680
|
const metadata = {};
|
|
620
681
|
headers.forEach((value, name) => {
|
|
@@ -633,13 +694,14 @@ function createS3ObjectStore(cfg, opts) {
|
|
|
633
694
|
if (contentType !== null) meta.contentType = contentType;
|
|
634
695
|
return meta;
|
|
635
696
|
};
|
|
697
|
+
const headObject = async (key) => {
|
|
698
|
+
const resp = await s3Fetch(urlFor(key), { method: "HEAD" });
|
|
699
|
+
if (resp.status === 404) return null;
|
|
700
|
+
if (!resp.ok) throw s3Error("head", resp.status);
|
|
701
|
+
return metaFromHeaders(key, resp.headers);
|
|
702
|
+
};
|
|
636
703
|
return {
|
|
637
|
-
|
|
638
|
-
const resp = await s3Fetch(urlFor(key), { method: "HEAD" });
|
|
639
|
-
if (resp.status === 404) return null;
|
|
640
|
-
if (!resp.ok) throw s3Error("head", resp.status);
|
|
641
|
-
return metaFromHeaders(key, resp.headers);
|
|
642
|
-
},
|
|
704
|
+
head: headObject,
|
|
643
705
|
async get(key) {
|
|
644
706
|
const resp = await s3Fetch(urlFor(key), { method: "GET" });
|
|
645
707
|
if (resp.status === 404) {
|
|
@@ -653,27 +715,31 @@ function createS3ObjectStore(cfg, opts) {
|
|
|
653
715
|
return { meta: metaFromHeaders(key, resp.headers), body: resp.body ?? EMPTY_STREAM };
|
|
654
716
|
},
|
|
655
717
|
async put(key, body, putOpts) {
|
|
656
|
-
const bytes = await objectBodyToBytes(body);
|
|
657
718
|
const headers = {};
|
|
719
|
+
headers["x-amz-content-sha256"] = "UNSIGNED-PAYLOAD";
|
|
658
720
|
if (putOpts?.contentType !== void 0) headers["content-type"] = putOpts.contentType;
|
|
659
721
|
for (const [name, value] of Object.entries(putOpts?.metadata ?? {})) {
|
|
660
722
|
headers[`${META_HEADER_PREFIX}${name}`] = value;
|
|
661
723
|
}
|
|
662
724
|
if (putOpts?.ifMatchEtag !== void 0) headers["if-match"] = `"${putOpts.ifMatchEtag}"`;
|
|
663
|
-
|
|
725
|
+
if (putOpts?.ifNoneMatch !== void 0) headers["if-none-match"] = putOpts.ifNoneMatch;
|
|
726
|
+
const resp = await s3Fetch(urlFor(key), {
|
|
727
|
+
method: "PUT",
|
|
728
|
+
headers,
|
|
729
|
+
body: fetchBody(body)
|
|
730
|
+
});
|
|
664
731
|
await resp.body?.cancel();
|
|
665
|
-
|
|
666
|
-
|
|
732
|
+
const conditional = putOpts?.ifMatchEtag !== void 0 || putOpts?.ifNoneMatch !== void 0;
|
|
733
|
+
if (conditional && (resp.status === 409 || resp.status === 412) || putOpts?.ifMatchEtag !== void 0 && resp.status === 404) {
|
|
734
|
+
throw new TBError("conflict", `\u5BF9\u8C61\u6761\u4EF6\u5199\u51B2\u7A81:'${key}'`);
|
|
667
735
|
}
|
|
668
736
|
if (!resp.ok) throw s3Error("put", resp.status);
|
|
669
|
-
const meta =
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
};
|
|
676
|
-
if (putOpts?.contentType !== void 0) meta.contentType = putOpts.contentType;
|
|
737
|
+
const meta = await headObject(key);
|
|
738
|
+
if (meta === null) {
|
|
739
|
+
throw new TBError("unavailable", "s3 put succeeded but HEAD did not observe the object", {
|
|
740
|
+
retryable: true
|
|
741
|
+
});
|
|
742
|
+
}
|
|
677
743
|
return meta;
|
|
678
744
|
},
|
|
679
745
|
async delete(key) {
|
|
@@ -730,6 +796,9 @@ function createS3ObjectStore(cfg, opts) {
|
|
|
730
796
|
},
|
|
731
797
|
presignPut(key, ttlSec, putOpts) {
|
|
732
798
|
return presignS3Put(client, urlFor(key), ttlSec, putOpts);
|
|
799
|
+
},
|
|
800
|
+
presignPutExact(key, ttlSec, putOpts) {
|
|
801
|
+
return presignS3Put(client, urlFor(key), ttlSec, putOpts);
|
|
733
802
|
}
|
|
734
803
|
};
|
|
735
804
|
}
|
|
@@ -1029,6 +1098,443 @@ var SearchSynchronizer = class {
|
|
|
1029
1098
|
// ../app/src/deps.ts
|
|
1030
1099
|
var TOOL_CACHE_TTL_DEFAULT = 300;
|
|
1031
1100
|
|
|
1101
|
+
// ../app/src/storeRefToken.ts
|
|
1102
|
+
async function hmacKey(secret) {
|
|
1103
|
+
const digest = await crypto.subtle.digest(
|
|
1104
|
+
"SHA-256",
|
|
1105
|
+
new TextEncoder().encode(`tb-store-read-ref:v1:${secret}`)
|
|
1106
|
+
);
|
|
1107
|
+
return crypto.subtle.importKey("raw", digest, { name: "HMAC", hash: "SHA-256" }, false, [
|
|
1108
|
+
"sign",
|
|
1109
|
+
"verify"
|
|
1110
|
+
]);
|
|
1111
|
+
}
|
|
1112
|
+
async function signStoreRefToken(payload, secret) {
|
|
1113
|
+
const body = base64urlEncode(new TextEncoder().encode(JSON.stringify(payload)));
|
|
1114
|
+
const mac = await crypto.subtle.sign(
|
|
1115
|
+
"HMAC",
|
|
1116
|
+
await hmacKey(secret),
|
|
1117
|
+
new TextEncoder().encode(body)
|
|
1118
|
+
);
|
|
1119
|
+
return `${body}.${base64urlEncode(new Uint8Array(mac))}`;
|
|
1120
|
+
}
|
|
1121
|
+
async function verifyStoreRefToken(token, secret) {
|
|
1122
|
+
const dot = token.indexOf(".");
|
|
1123
|
+
if (dot <= 0) return null;
|
|
1124
|
+
const body = token.slice(0, dot);
|
|
1125
|
+
let signature;
|
|
1126
|
+
try {
|
|
1127
|
+
signature = base64urlDecode(token.slice(dot + 1));
|
|
1128
|
+
} catch {
|
|
1129
|
+
return null;
|
|
1130
|
+
}
|
|
1131
|
+
const valid = await crypto.subtle.verify(
|
|
1132
|
+
"HMAC",
|
|
1133
|
+
await hmacKey(secret),
|
|
1134
|
+
signature,
|
|
1135
|
+
new TextEncoder().encode(body)
|
|
1136
|
+
);
|
|
1137
|
+
if (!valid) return null;
|
|
1138
|
+
try {
|
|
1139
|
+
const payload = JSON.parse(
|
|
1140
|
+
new TextDecoder().decode(base64urlDecode(body))
|
|
1141
|
+
);
|
|
1142
|
+
if (payload.v !== 1 || typeof payload.objectId !== "string" || payload.objectId.length < 1 || typeof payload.exp !== "number" || !Number.isSafeInteger(payload.exp)) return null;
|
|
1143
|
+
return payload;
|
|
1144
|
+
} catch {
|
|
1145
|
+
return null;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// ../app/src/store.ts
|
|
1150
|
+
var STORE_CALL_CAPABILITY_HEADER = "x-tb-store-capability";
|
|
1151
|
+
var STORE_UPLOAD_HEADER = "x-tb-store-upload";
|
|
1152
|
+
var KEY_STORE_TOKEN_SECRET = "sys:store-token-secret:v1";
|
|
1153
|
+
var KEY_STORE_CLEANUP_PROGRESS = "sys:store-cleanup-progress:v1";
|
|
1154
|
+
var STORE_READ_TTL_SEC_DEFAULT = 15 * 60;
|
|
1155
|
+
var STORE_CALL_MAX_OBJECTS_DEFAULT = 4;
|
|
1156
|
+
var STORE_CALL_MAX_OBJECT_BYTES_DEFAULT = 256 * 1024 * 1024;
|
|
1157
|
+
var STORE_CALL_MAX_BYTES_DEFAULT = 512 * 1024 * 1024;
|
|
1158
|
+
function positiveInt(value, fallback, field) {
|
|
1159
|
+
const actual = value ?? fallback;
|
|
1160
|
+
if (!Number.isSafeInteger(actual) || actual < 1) {
|
|
1161
|
+
throw new TBError("invalid_argument", `${field} must be a positive integer`);
|
|
1162
|
+
}
|
|
1163
|
+
return actual;
|
|
1164
|
+
}
|
|
1165
|
+
function randomSecret() {
|
|
1166
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
1167
|
+
let out = "";
|
|
1168
|
+
for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
|
|
1169
|
+
return out;
|
|
1170
|
+
}
|
|
1171
|
+
async function derivedTokenSecret(root) {
|
|
1172
|
+
const digest = await crypto.subtle.digest(
|
|
1173
|
+
"SHA-256",
|
|
1174
|
+
new TextEncoder().encode(`tb-store-capability-root:v1:${root}`)
|
|
1175
|
+
);
|
|
1176
|
+
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1177
|
+
}
|
|
1178
|
+
async function storeTokenSecret(state, configured) {
|
|
1179
|
+
if (configured !== void 0) {
|
|
1180
|
+
if (configured.length < 16) {
|
|
1181
|
+
throw new TBError("invalid_argument", "storeTokenSecret must contain at least 16 characters");
|
|
1182
|
+
}
|
|
1183
|
+
return await derivedTokenSecret(configured);
|
|
1184
|
+
}
|
|
1185
|
+
const current = await state.get(KEY_STORE_TOKEN_SECRET);
|
|
1186
|
+
if (typeof current === "string" && current.length >= 16) return current;
|
|
1187
|
+
if (current !== null) {
|
|
1188
|
+
throw new TBError("internal", "default Store token secret state is invalid", {
|
|
1189
|
+
retryable: false
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
if (state.compareAndSwap === void 0) {
|
|
1193
|
+
throw new TBError("unavailable", "default Store requires StateStore.compareAndSwap", {
|
|
1194
|
+
retryable: false
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
const candidate = randomSecret();
|
|
1198
|
+
if (await state.compareAndSwap(KEY_STORE_TOKEN_SECRET, null, candidate)) return candidate;
|
|
1199
|
+
const winner = await state.get(KEY_STORE_TOKEN_SECRET);
|
|
1200
|
+
if (typeof winner !== "string" || winner.length < 16) {
|
|
1201
|
+
throw new TBError("unavailable", "default Store token secret initialization conflicted", {
|
|
1202
|
+
retryable: true
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
return winner;
|
|
1206
|
+
}
|
|
1207
|
+
function serviceOptions(deps, tokenSecret) {
|
|
1208
|
+
return {
|
|
1209
|
+
tokenSecret,
|
|
1210
|
+
...deps.storeMaxObjectBytes === void 0 ? {} : { maxObjectBytes: deps.storeMaxObjectBytes },
|
|
1211
|
+
...deps.storeRelayMaxBytes === void 0 ? {} : { relayMaxBytes: deps.storeRelayMaxBytes },
|
|
1212
|
+
...deps.storeUploadTtlSec === void 0 ? {} : { uploadTtlSec: deps.storeUploadTtlSec },
|
|
1213
|
+
...deps.storeShareTtlSec === void 0 ? {} : { shareTtlSec: deps.storeShareTtlSec }
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
async function defaultStoreRuntime(deps) {
|
|
1217
|
+
if (deps.objects === void 0) {
|
|
1218
|
+
throw new TBError("unavailable", "default Store object driver is not configured", {
|
|
1219
|
+
retryable: false
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
const [objects, tokenSecret] = await Promise.all([
|
|
1223
|
+
deps.objects(),
|
|
1224
|
+
storeTokenSecret(deps.state, deps.storeTokenSecret ?? deps.encryptionKey)
|
|
1225
|
+
]);
|
|
1226
|
+
return {
|
|
1227
|
+
objects,
|
|
1228
|
+
tokenSecret,
|
|
1229
|
+
service: new StoreService(deps.state, objects, serviceOptions(deps, tokenSecret))
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
function resolveStoreRequestOrigin(rawRequestOrigin, canonicalOrigin) {
|
|
1233
|
+
const raw = rawRequestOrigin ?? canonicalOrigin;
|
|
1234
|
+
if (raw === void 0) {
|
|
1235
|
+
throw new TBError("unavailable", "request origin is unavailable", { retryable: false });
|
|
1236
|
+
}
|
|
1237
|
+
let url2;
|
|
1238
|
+
try {
|
|
1239
|
+
url2 = new URL(raw);
|
|
1240
|
+
} catch {
|
|
1241
|
+
throw new TBError("unavailable", "request origin is invalid", { retryable: false });
|
|
1242
|
+
}
|
|
1243
|
+
if (url2.protocol !== "https:" && url2.protocol !== "http:" || url2.username !== "" || url2.password !== "") {
|
|
1244
|
+
throw new TBError("unavailable", "request origin is invalid", { retryable: false });
|
|
1245
|
+
}
|
|
1246
|
+
if (rawRequestOrigin !== void 0 && canonicalOrigin !== void 0) {
|
|
1247
|
+
let canonical;
|
|
1248
|
+
try {
|
|
1249
|
+
canonical = new URL(canonicalOrigin);
|
|
1250
|
+
} catch {
|
|
1251
|
+
throw new TBError("unavailable", "canonical origin is invalid", { retryable: false });
|
|
1252
|
+
}
|
|
1253
|
+
if (canonical.protocol !== "https:" && canonical.protocol !== "http:" || canonical.username !== "" || canonical.password !== "") {
|
|
1254
|
+
throw new TBError("unavailable", "canonical origin is invalid", { retryable: false });
|
|
1255
|
+
}
|
|
1256
|
+
url2.protocol = canonical.protocol;
|
|
1257
|
+
}
|
|
1258
|
+
return url2.origin;
|
|
1259
|
+
}
|
|
1260
|
+
function requestOrigin(runtime, deps) {
|
|
1261
|
+
return resolveStoreRequestOrigin(runtime?.requestOrigin, deps.canonicalOrigin);
|
|
1262
|
+
}
|
|
1263
|
+
function storeUploadGrant(start, origin) {
|
|
1264
|
+
const useRelay = start.alreadyCompleted || start.signedRequest === void 0;
|
|
1265
|
+
const url2 = useRelay ? `${origin}/~store/uploads/${encodeURIComponent(start.uploadId)}` : start.signedRequest.url;
|
|
1266
|
+
const headers = useRelay ? { [STORE_UPLOAD_HEADER]: start.uploadToken } : start.signedRequest.headers;
|
|
1267
|
+
return {
|
|
1268
|
+
uploadId: start.uploadId,
|
|
1269
|
+
objectUri: start.objectUri,
|
|
1270
|
+
transport: useRelay ? "relay" : "presigned-put",
|
|
1271
|
+
method: "PUT",
|
|
1272
|
+
url: url2,
|
|
1273
|
+
headers,
|
|
1274
|
+
expiresAt: start.expiresAt,
|
|
1275
|
+
maxBytes: start.maxBytes,
|
|
1276
|
+
uploadToken: start.uploadToken,
|
|
1277
|
+
...start.alreadyCompleted && start.descriptor !== void 0 ? { alreadyCompleted: true, descriptor: start.descriptor } : {}
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
function readTtlSec(deps) {
|
|
1281
|
+
return positiveInt(
|
|
1282
|
+
deps.storeReadTtlSec,
|
|
1283
|
+
deps.refTtlSec ?? STORE_READ_TTL_SEC_DEFAULT,
|
|
1284
|
+
"storeReadTtlSec"
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
async function ownerReadGrant(object2, runtime, deps, tokenSecret) {
|
|
1288
|
+
if (object2.status !== "ready" || object2.size === void 0) {
|
|
1289
|
+
throw TBError.notFound("Store object not found");
|
|
1290
|
+
}
|
|
1291
|
+
const ttlSec = readTtlSec(deps);
|
|
1292
|
+
const expiresAt = new Date(Date.now() + ttlSec * 1e3).toISOString();
|
|
1293
|
+
const token = await signStoreRefToken({
|
|
1294
|
+
v: 1,
|
|
1295
|
+
objectId: object2.id,
|
|
1296
|
+
exp: Math.floor(Date.parse(expiresAt) / 1e3)
|
|
1297
|
+
}, tokenSecret);
|
|
1298
|
+
return {
|
|
1299
|
+
$ref: `${requestOrigin(runtime, deps)}/~store/refs/${encodeURIComponent(token)}`,
|
|
1300
|
+
uri: storeUri(object2.id),
|
|
1301
|
+
contentType: object2.contentType,
|
|
1302
|
+
size: object2.size,
|
|
1303
|
+
expiresAt
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
function shareReadGrant(result, runtime, deps) {
|
|
1307
|
+
return {
|
|
1308
|
+
shareId: result.shareId,
|
|
1309
|
+
uri: result.uri,
|
|
1310
|
+
expiresAt: result.expiresAt,
|
|
1311
|
+
$ref: `${requestOrigin(runtime, deps)}/~store/shares/${encodeURIComponent(result.token)}`
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
function defaultStoreModuleDeps(deps, store) {
|
|
1315
|
+
return {
|
|
1316
|
+
service: store.service,
|
|
1317
|
+
callbacks: {
|
|
1318
|
+
createUpload: (start, runtime) => storeUploadGrant(start, requestOrigin(runtime, deps)),
|
|
1319
|
+
read: async (object2, runtime) => await ownerReadGrant(
|
|
1320
|
+
object2,
|
|
1321
|
+
runtime,
|
|
1322
|
+
deps,
|
|
1323
|
+
store.tokenSecret
|
|
1324
|
+
),
|
|
1325
|
+
share: (result, runtime) => shareReadGrant(result, runtime, deps)
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
function lazyDefaultStoreModule(deps) {
|
|
1330
|
+
const helpOnly = createStoreModule({
|
|
1331
|
+
// createStoreModule.help is static and never reads these placeholders.
|
|
1332
|
+
service: void 0,
|
|
1333
|
+
callbacks: {
|
|
1334
|
+
createUpload: () => {
|
|
1335
|
+
throw new TBError("unavailable", "default Store is unavailable");
|
|
1336
|
+
},
|
|
1337
|
+
read: () => {
|
|
1338
|
+
throw new TBError("unavailable", "default Store is unavailable");
|
|
1339
|
+
},
|
|
1340
|
+
share: () => {
|
|
1341
|
+
throw new TBError("unavailable", "default Store is unavailable");
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
});
|
|
1345
|
+
return {
|
|
1346
|
+
module: helpOnly.module,
|
|
1347
|
+
description: helpOnly.description,
|
|
1348
|
+
help: (path) => helpOnly.help(path),
|
|
1349
|
+
async dispatch(cmd, args, ctx, runtime) {
|
|
1350
|
+
const store = await defaultStoreRuntime(deps);
|
|
1351
|
+
return await createStoreModule(defaultStoreModuleDeps(deps, store)).dispatch(
|
|
1352
|
+
cmd,
|
|
1353
|
+
args,
|
|
1354
|
+
ctx,
|
|
1355
|
+
runtime
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
async function beginCapabilityUpload(deps, input, capabilityToken, origin) {
|
|
1361
|
+
const store = await defaultStoreRuntime(deps);
|
|
1362
|
+
const start = await store.service.beginCallUpload(input, capabilityToken);
|
|
1363
|
+
return storeUploadGrant(start, origin);
|
|
1364
|
+
}
|
|
1365
|
+
async function completeCapabilityUpload(deps, uploadId2, uploadToken) {
|
|
1366
|
+
return await (await defaultStoreRuntime(deps)).service.completeUploadWithToken(
|
|
1367
|
+
uploadId2,
|
|
1368
|
+
uploadToken
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
async function abortCapabilityUpload(deps, uploadId2, uploadToken) {
|
|
1372
|
+
return await (await defaultStoreRuntime(deps)).service.abortUploadWithToken(
|
|
1373
|
+
uploadId2,
|
|
1374
|
+
uploadToken
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
async function relayStoreUpload(deps, uploadId2, uploadToken, body) {
|
|
1378
|
+
const store = await defaultStoreRuntime(deps);
|
|
1379
|
+
const session = await store.service.verifyUploadToken(uploadToken);
|
|
1380
|
+
if (session.id !== uploadId2) {
|
|
1381
|
+
throw new TBError("permission_denied", "upload capability does not match the URL");
|
|
1382
|
+
}
|
|
1383
|
+
return await store.service.commitRelayUpload({
|
|
1384
|
+
uploadToken,
|
|
1385
|
+
body: body ?? new Uint8Array()
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
async function storeObjectResponse(objects, object2) {
|
|
1389
|
+
const got = await objects.get(object2.driverKey);
|
|
1390
|
+
if (got === null) throw TBError.notFound("not found");
|
|
1391
|
+
const body = toWebObjectBodyStream(got.body);
|
|
1392
|
+
return new Response(body, {
|
|
1393
|
+
headers: {
|
|
1394
|
+
"content-type": object2.contentType,
|
|
1395
|
+
"content-length": String(got.meta.size),
|
|
1396
|
+
"cache-control": "private, no-store"
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
async function issueDeviceCallUpload(deps, deviceId, callId, context) {
|
|
1401
|
+
if (deps.objects === void 0) return null;
|
|
1402
|
+
const store = await defaultStoreRuntime(deps);
|
|
1403
|
+
const maxObjects = positiveInt(
|
|
1404
|
+
deps.storeCallMaxObjects,
|
|
1405
|
+
STORE_CALL_MAX_OBJECTS_DEFAULT,
|
|
1406
|
+
"storeCallMaxObjects"
|
|
1407
|
+
);
|
|
1408
|
+
const maxBytes = positiveInt(
|
|
1409
|
+
deps.storeCallMaxBytes,
|
|
1410
|
+
STORE_CALL_MAX_BYTES_DEFAULT,
|
|
1411
|
+
"storeCallMaxBytes"
|
|
1412
|
+
);
|
|
1413
|
+
const maxObjectBytes = Math.min(
|
|
1414
|
+
positiveInt(
|
|
1415
|
+
deps.storeCallMaxObjectBytes,
|
|
1416
|
+
deps.storeMaxObjectBytes ?? STORE_CALL_MAX_OBJECT_BYTES_DEFAULT,
|
|
1417
|
+
"storeCallMaxObjectBytes"
|
|
1418
|
+
),
|
|
1419
|
+
maxBytes
|
|
1420
|
+
);
|
|
1421
|
+
const issued = await store.service.issueCallUploadCapability({
|
|
1422
|
+
callId,
|
|
1423
|
+
owner: context.caller.owner,
|
|
1424
|
+
producer: `device:${deviceId}`,
|
|
1425
|
+
expiresAt: context.expiresAt,
|
|
1426
|
+
maxObjects,
|
|
1427
|
+
maxBytes,
|
|
1428
|
+
maxObjectBytes,
|
|
1429
|
+
allowedContentTypes: deps.storeCallAllowedContentTypes ?? ["*/*"]
|
|
1430
|
+
});
|
|
1431
|
+
return {
|
|
1432
|
+
context: {
|
|
1433
|
+
...context,
|
|
1434
|
+
upload: {
|
|
1435
|
+
token: issued.token,
|
|
1436
|
+
expiresAt: issued.capability.expiresAt,
|
|
1437
|
+
// The SDK uses this as an early per-object check; the server remains
|
|
1438
|
+
// authoritative for the aggregate call budget.
|
|
1439
|
+
maxBytes: issued.capability.maxObjectBytes,
|
|
1440
|
+
maxObjects: issued.capability.maxObjects
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
revoke: async () => await store.service.revokeCallUploadCapability(issued.token)
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
function cleanupProgress(value) {
|
|
1447
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
1448
|
+
throw new TBError("internal", "default Store cleanup progress is invalid");
|
|
1449
|
+
}
|
|
1450
|
+
const record2 = value;
|
|
1451
|
+
if (!Number.isSafeInteger(record2.revision) || record2.revision < 1) {
|
|
1452
|
+
throw new TBError("internal", "default Store cleanup progress is invalid");
|
|
1453
|
+
}
|
|
1454
|
+
const cursors = record2.cursors;
|
|
1455
|
+
if (cursors === null || typeof cursors !== "object" || Array.isArray(cursors)) {
|
|
1456
|
+
throw new TBError("internal", "default Store cleanup progress is invalid");
|
|
1457
|
+
}
|
|
1458
|
+
for (const field of [
|
|
1459
|
+
"uploads",
|
|
1460
|
+
"objects",
|
|
1461
|
+
"shares",
|
|
1462
|
+
"callCapabilities",
|
|
1463
|
+
"idempotencyBindings"
|
|
1464
|
+
]) {
|
|
1465
|
+
const cursor = cursors[field];
|
|
1466
|
+
if (cursor !== null && typeof cursor !== "string") {
|
|
1467
|
+
throw new TBError("internal", "default Store cleanup progress is invalid");
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
return value;
|
|
1471
|
+
}
|
|
1472
|
+
function emptyCleanupResult() {
|
|
1473
|
+
return {
|
|
1474
|
+
abandonedObjects: 0,
|
|
1475
|
+
deletedBytes: 0,
|
|
1476
|
+
deletedStaging: 0,
|
|
1477
|
+
expiredCallCapabilities: 0,
|
|
1478
|
+
expiredIdempotencyBindings: 0,
|
|
1479
|
+
expiredShares: 0,
|
|
1480
|
+
expiredUploads: 0
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
function addCleanupResult(target, page) {
|
|
1484
|
+
target.abandonedObjects += page.abandonedObjects;
|
|
1485
|
+
target.deletedBytes += page.deletedBytes;
|
|
1486
|
+
target.deletedStaging += page.deletedStaging;
|
|
1487
|
+
target.expiredCallCapabilities += page.expiredCallCapabilities;
|
|
1488
|
+
target.expiredIdempotencyBindings += page.expiredIdempotencyBindings;
|
|
1489
|
+
target.expiredShares += page.expiredShares;
|
|
1490
|
+
target.expiredUploads += page.expiredUploads;
|
|
1491
|
+
}
|
|
1492
|
+
async function cleanupDefaultStore(deps, opts = {}) {
|
|
1493
|
+
await deps.ensureReady?.();
|
|
1494
|
+
const store = await defaultStoreRuntime(deps);
|
|
1495
|
+
const maxPages = Math.min(positiveInt(opts.maxPages, 8, "maxPages"), 64);
|
|
1496
|
+
const limit = opts.limit === void 0 ? void 0 : positiveInt(opts.limit, 200, "limit");
|
|
1497
|
+
const rawProgress = await deps.state.get(KEY_STORE_CLEANUP_PROGRESS);
|
|
1498
|
+
let progress = rawProgress === null ? null : cleanupProgress(rawProgress);
|
|
1499
|
+
let cursors = progress?.cursors;
|
|
1500
|
+
const aggregate = emptyCleanupResult();
|
|
1501
|
+
for (let pageNumber = 0; pageNumber < maxPages; pageNumber++) {
|
|
1502
|
+
const page = await store.service.cleanup({
|
|
1503
|
+
...limit === void 0 ? {} : { limit },
|
|
1504
|
+
...cursors === void 0 ? {} : { cursors },
|
|
1505
|
+
// staging 不使用权威状态 cursor;同一 host tick 只运行一次,避免
|
|
1506
|
+
// maxPages 内重复扫描同一 driver maintenance 范围。
|
|
1507
|
+
runDriverMaintenance: pageNumber === 0
|
|
1508
|
+
});
|
|
1509
|
+
addCleanupResult(aggregate, page);
|
|
1510
|
+
if (page.cursors === void 0) {
|
|
1511
|
+
if (progress !== null) {
|
|
1512
|
+
await deps.state.compareAndSwap(
|
|
1513
|
+
KEY_STORE_CLEANUP_PROGRESS,
|
|
1514
|
+
progress.revision,
|
|
1515
|
+
null
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
return aggregate;
|
|
1519
|
+
}
|
|
1520
|
+
const next = {
|
|
1521
|
+
cursors: page.cursors,
|
|
1522
|
+
revision: (progress?.revision ?? 0) + 1
|
|
1523
|
+
};
|
|
1524
|
+
const advanced = await deps.state.compareAndSwap(
|
|
1525
|
+
KEY_STORE_CLEANUP_PROGRESS,
|
|
1526
|
+
progress?.revision ?? null,
|
|
1527
|
+
next
|
|
1528
|
+
);
|
|
1529
|
+
if (!advanced) {
|
|
1530
|
+
return aggregate;
|
|
1531
|
+
}
|
|
1532
|
+
progress = next;
|
|
1533
|
+
cursors = next.cursors;
|
|
1534
|
+
}
|
|
1535
|
+
return { ...aggregate, ...cursors === void 0 ? {} : { cursors } };
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1032
1538
|
// ../app/src/deviceNodes.ts
|
|
1033
1539
|
function tbErrorFromBody(body) {
|
|
1034
1540
|
return new TBError(body.code, body.message, { retryable: body.retryable });
|
|
@@ -1041,7 +1547,19 @@ function requireDevice(deps) {
|
|
|
1041
1547
|
}
|
|
1042
1548
|
async function invokeDevice(deps, deviceId, req) {
|
|
1043
1549
|
const id = crypto.randomUUID();
|
|
1044
|
-
const
|
|
1550
|
+
const upload = req.context === void 0 ? null : await issueDeviceCallUpload(deps, deviceId, id, req.context);
|
|
1551
|
+
let body;
|
|
1552
|
+
try {
|
|
1553
|
+
body = await requireDevice(deps).invoke(deviceId, {
|
|
1554
|
+
id,
|
|
1555
|
+
path: req.path,
|
|
1556
|
+
arguments: req.arguments,
|
|
1557
|
+
...req.context === void 0 ? {} : { context: upload?.context ?? req.context }
|
|
1558
|
+
});
|
|
1559
|
+
} finally {
|
|
1560
|
+
await upload?.revoke().catch(() => {
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1045
1563
|
if (!body || !("ok" in body)) {
|
|
1046
1564
|
throw new TBError("unavailable", "device session returned invalid result");
|
|
1047
1565
|
}
|
|
@@ -5241,8 +5759,8 @@ var LADDER_ERROR_HTTP_STATUS = {
|
|
|
5241
5759
|
function parseSchema(schema, data) {
|
|
5242
5760
|
return safeParse(schema, data);
|
|
5243
5761
|
}
|
|
5244
|
-
function shapeKeys(
|
|
5245
|
-
return new Set(
|
|
5762
|
+
function shapeKeys(schemas2) {
|
|
5763
|
+
return new Set(schemas2.flatMap((schema) => Object.keys(schema.shape)));
|
|
5246
5764
|
}
|
|
5247
5765
|
function isStandardSchema(schema) {
|
|
5248
5766
|
if (schema == null) return false;
|
|
@@ -7158,9 +7676,9 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7158
7676
|
const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
|
|
7159
7677
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
7160
7678
|
}
|
|
7161
|
-
optimizeNames(names,
|
|
7679
|
+
optimizeNames(names, constants2) {
|
|
7162
7680
|
if (!names[this.name.str]) return;
|
|
7163
|
-
if (this.rhs) this.rhs = optimizeExpr(this.rhs, names,
|
|
7681
|
+
if (this.rhs) this.rhs = optimizeExpr(this.rhs, names, constants2);
|
|
7164
7682
|
return this;
|
|
7165
7683
|
}
|
|
7166
7684
|
get names() {
|
|
@@ -7177,9 +7695,9 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7177
7695
|
render({ _n }) {
|
|
7178
7696
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
7179
7697
|
}
|
|
7180
|
-
optimizeNames(names,
|
|
7698
|
+
optimizeNames(names, constants2) {
|
|
7181
7699
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects) return;
|
|
7182
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
7700
|
+
this.rhs = optimizeExpr(this.rhs, names, constants2);
|
|
7183
7701
|
return this;
|
|
7184
7702
|
}
|
|
7185
7703
|
get names() {
|
|
@@ -7238,8 +7756,8 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7238
7756
|
optimizeNodes() {
|
|
7239
7757
|
return `${this.code}` ? this : void 0;
|
|
7240
7758
|
}
|
|
7241
|
-
optimizeNames(names,
|
|
7242
|
-
this.code = optimizeExpr(this.code, names,
|
|
7759
|
+
optimizeNames(names, constants2) {
|
|
7760
|
+
this.code = optimizeExpr(this.code, names, constants2);
|
|
7243
7761
|
return this;
|
|
7244
7762
|
}
|
|
7245
7763
|
get names() {
|
|
@@ -7265,12 +7783,12 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7265
7783
|
}
|
|
7266
7784
|
return nodes.length > 0 ? this : void 0;
|
|
7267
7785
|
}
|
|
7268
|
-
optimizeNames(names,
|
|
7786
|
+
optimizeNames(names, constants2) {
|
|
7269
7787
|
const { nodes } = this;
|
|
7270
7788
|
let i = nodes.length;
|
|
7271
7789
|
while (i--) {
|
|
7272
7790
|
const n = nodes[i];
|
|
7273
|
-
if (n.optimizeNames(names,
|
|
7791
|
+
if (n.optimizeNames(names, constants2)) continue;
|
|
7274
7792
|
subtractNames(names, n.names);
|
|
7275
7793
|
nodes.splice(i, 1);
|
|
7276
7794
|
}
|
|
@@ -7317,11 +7835,11 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7317
7835
|
if (cond === false || !this.nodes.length) return void 0;
|
|
7318
7836
|
return this;
|
|
7319
7837
|
}
|
|
7320
|
-
optimizeNames(names,
|
|
7838
|
+
optimizeNames(names, constants2) {
|
|
7321
7839
|
var _a;
|
|
7322
|
-
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
7323
|
-
if (!(super.optimizeNames(names,
|
|
7324
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
7840
|
+
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants2);
|
|
7841
|
+
if (!(super.optimizeNames(names, constants2) || this.else)) return;
|
|
7842
|
+
this.condition = optimizeExpr(this.condition, names, constants2);
|
|
7325
7843
|
return this;
|
|
7326
7844
|
}
|
|
7327
7845
|
get names() {
|
|
@@ -7343,9 +7861,9 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7343
7861
|
render(opts) {
|
|
7344
7862
|
return `for(${this.iteration})` + super.render(opts);
|
|
7345
7863
|
}
|
|
7346
|
-
optimizeNames(names,
|
|
7347
|
-
if (!super.optimizeNames(names,
|
|
7348
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
7864
|
+
optimizeNames(names, constants2) {
|
|
7865
|
+
if (!super.optimizeNames(names, constants2)) return;
|
|
7866
|
+
this.iteration = optimizeExpr(this.iteration, names, constants2);
|
|
7349
7867
|
return this;
|
|
7350
7868
|
}
|
|
7351
7869
|
get names() {
|
|
@@ -7380,9 +7898,9 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7380
7898
|
render(opts) {
|
|
7381
7899
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
7382
7900
|
}
|
|
7383
|
-
optimizeNames(names,
|
|
7384
|
-
if (!super.optimizeNames(names,
|
|
7385
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
7901
|
+
optimizeNames(names, constants2) {
|
|
7902
|
+
if (!super.optimizeNames(names, constants2)) return;
|
|
7903
|
+
this.iterable = optimizeExpr(this.iterable, names, constants2);
|
|
7386
7904
|
return this;
|
|
7387
7905
|
}
|
|
7388
7906
|
get names() {
|
|
@@ -7421,11 +7939,11 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7421
7939
|
(_b = this.finally) === null || _b === void 0 || _b.optimizeNodes();
|
|
7422
7940
|
return this;
|
|
7423
7941
|
}
|
|
7424
|
-
optimizeNames(names,
|
|
7942
|
+
optimizeNames(names, constants2) {
|
|
7425
7943
|
var _a, _b;
|
|
7426
|
-
super.optimizeNames(names,
|
|
7427
|
-
(_a = this.catch) === null || _a === void 0 || _a.optimizeNames(names,
|
|
7428
|
-
(_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names,
|
|
7944
|
+
super.optimizeNames(names, constants2);
|
|
7945
|
+
(_a = this.catch) === null || _a === void 0 || _a.optimizeNames(names, constants2);
|
|
7946
|
+
(_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names, constants2);
|
|
7429
7947
|
return this;
|
|
7430
7948
|
}
|
|
7431
7949
|
get names() {
|
|
@@ -7674,7 +8192,7 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7674
8192
|
function addExprNames(names, from) {
|
|
7675
8193
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
7676
8194
|
}
|
|
7677
|
-
function optimizeExpr(expr, names,
|
|
8195
|
+
function optimizeExpr(expr, names, constants2) {
|
|
7678
8196
|
if (expr instanceof code_1.Name) return replaceName(expr);
|
|
7679
8197
|
if (!canOptimize(expr)) return expr;
|
|
7680
8198
|
return new code_1._Code(expr._items.reduce((items, c) => {
|
|
@@ -7684,13 +8202,13 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7684
8202
|
return items;
|
|
7685
8203
|
}, []));
|
|
7686
8204
|
function replaceName(n) {
|
|
7687
|
-
const c =
|
|
8205
|
+
const c = constants2[n.str];
|
|
7688
8206
|
if (c === void 0 || names[n.str] !== 1) return n;
|
|
7689
8207
|
delete names[n.str];
|
|
7690
8208
|
return c;
|
|
7691
8209
|
}
|
|
7692
8210
|
function canOptimize(e) {
|
|
7693
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
8211
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants2[c.str] !== void 0);
|
|
7694
8212
|
}
|
|
7695
8213
|
}
|
|
7696
8214
|
function subtractNames(names, from) {
|
|
@@ -10417,14 +10935,14 @@ var require_core$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
10417
10935
|
}
|
|
10418
10936
|
return metaSchema;
|
|
10419
10937
|
}
|
|
10420
|
-
_removeAllSchemas(
|
|
10421
|
-
for (const keyRef in
|
|
10422
|
-
const sch =
|
|
10938
|
+
_removeAllSchemas(schemas2, regex3) {
|
|
10939
|
+
for (const keyRef in schemas2) {
|
|
10940
|
+
const sch = schemas2[keyRef];
|
|
10423
10941
|
if (!regex3 || regex3.test(keyRef)) {
|
|
10424
|
-
if (typeof sch == "string") delete
|
|
10942
|
+
if (typeof sch == "string") delete schemas2[keyRef];
|
|
10425
10943
|
else if (sch && !sch.meta) {
|
|
10426
10944
|
this._cache.delete(sch.schema);
|
|
10427
|
-
delete
|
|
10945
|
+
delete schemas2[keyRef];
|
|
10428
10946
|
}
|
|
10429
10947
|
}
|
|
10430
10948
|
}
|
|
@@ -19175,15 +19693,6 @@ async function clientCredential(secrets, authRef) {
|
|
|
19175
19693
|
...values.clientSecret === void 0 ? {} : { clientSecret: values.clientSecret }
|
|
19176
19694
|
};
|
|
19177
19695
|
}
|
|
19178
|
-
function parseTokenErrorMessage(payload) {
|
|
19179
|
-
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) return void 0;
|
|
19180
|
-
const record2 = payload;
|
|
19181
|
-
for (const key of ["error_description", "error", "msg", "message"]) {
|
|
19182
|
-
const value = record2[key];
|
|
19183
|
-
if (typeof value === "string" && value !== "") return value;
|
|
19184
|
-
}
|
|
19185
|
-
return void 0;
|
|
19186
|
-
}
|
|
19187
19696
|
async function writeTokens(store, nodePath, next, previous) {
|
|
19188
19697
|
const merged = {
|
|
19189
19698
|
...next,
|
|
@@ -19207,10 +19716,10 @@ async function requestTokens(opts) {
|
|
|
19207
19716
|
let response;
|
|
19208
19717
|
try {
|
|
19209
19718
|
response = await opts.fetcher(endpoint, { method: "POST", headers, body });
|
|
19210
|
-
} catch
|
|
19719
|
+
} catch {
|
|
19211
19720
|
throw new TBError(
|
|
19212
19721
|
"unavailable",
|
|
19213
|
-
|
|
19722
|
+
"\u4EE4\u724C\u7AEF\u70B9\u4E0D\u53EF\u8FBE",
|
|
19214
19723
|
{ retryable: true }
|
|
19215
19724
|
);
|
|
19216
19725
|
}
|
|
@@ -19222,14 +19731,20 @@ async function requestTokens(opts) {
|
|
|
19222
19731
|
payload = null;
|
|
19223
19732
|
}
|
|
19224
19733
|
if (!response.ok) {
|
|
19225
|
-
const
|
|
19226
|
-
const detail = parsed ?? `HTTP ${response.status}`;
|
|
19734
|
+
const detail = `HTTP ${response.status}`;
|
|
19227
19735
|
if (response.status >= 500) {
|
|
19228
19736
|
throw new TBError("unavailable", `\u4EE4\u724C\u7AEF\u70B9\u8FD4\u56DE ${detail}`, { retryable: true });
|
|
19229
19737
|
}
|
|
19230
19738
|
throw new TBError("invalid_argument", `\u4EE4\u724C\u7AEF\u70B9\u62D2\u7EDD\u4E86\u8BF7\u6C42:${detail}`);
|
|
19231
19739
|
}
|
|
19232
|
-
|
|
19740
|
+
try {
|
|
19741
|
+
return parseTokenResponse(payload, opts.config, opts.now);
|
|
19742
|
+
} catch (err) {
|
|
19743
|
+
if (isTBError(err) && err.code === "invalid_argument") {
|
|
19744
|
+
throw new TBError("invalid_argument", "\u4EE4\u724C\u7AEF\u70B9\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94");
|
|
19745
|
+
}
|
|
19746
|
+
throw err;
|
|
19747
|
+
}
|
|
19233
19748
|
}
|
|
19234
19749
|
function base64url(bytes) {
|
|
19235
19750
|
let binary = "";
|
|
@@ -19241,7 +19756,14 @@ async function createPkce() {
|
|
|
19241
19756
|
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
|
|
19242
19757
|
return { verifier, challenge: base64url(new Uint8Array(digest)) };
|
|
19243
19758
|
}
|
|
19759
|
+
function requireProviderOAuthFetch(fetcher) {
|
|
19760
|
+
if (fetcher === void 0) {
|
|
19761
|
+
throw new TBError("unavailable", "Provider OAuth \u51FA\u7AD9\u901A\u9053\u672A\u914D\u7F6E", { retryable: false });
|
|
19762
|
+
}
|
|
19763
|
+
return fetcher;
|
|
19764
|
+
}
|
|
19244
19765
|
async function startProviderAuthorization(opts) {
|
|
19766
|
+
const fetcher = requireProviderOAuthFetch(opts.fetcher);
|
|
19245
19767
|
const existing = await readTokens(opts.store, opts.nodePath);
|
|
19246
19768
|
if (existing !== void 0 && !shouldRefresh(existing, opts.now)) {
|
|
19247
19769
|
return { status: "authorized" };
|
|
@@ -19251,7 +19773,7 @@ async function startProviderAuthorization(opts) {
|
|
|
19251
19773
|
const client2 = await clientCredential(opts.secrets, opts.authRef);
|
|
19252
19774
|
const refreshed = await requestTokens({
|
|
19253
19775
|
config: opts.config,
|
|
19254
|
-
fetcher
|
|
19776
|
+
fetcher,
|
|
19255
19777
|
now: opts.now,
|
|
19256
19778
|
grant: { refreshToken: existing.refreshToken },
|
|
19257
19779
|
...client2
|
|
@@ -19284,10 +19806,11 @@ async function startProviderAuthorization(opts) {
|
|
|
19284
19806
|
};
|
|
19285
19807
|
}
|
|
19286
19808
|
async function finishProviderAuthorization(opts) {
|
|
19809
|
+
const fetcher = requireProviderOAuthFetch(opts.fetcher);
|
|
19287
19810
|
const client = await clientCredential(opts.secrets, opts.authRef);
|
|
19288
19811
|
const tokens = await requestTokens({
|
|
19289
19812
|
config: opts.config,
|
|
19290
|
-
fetcher
|
|
19813
|
+
fetcher,
|
|
19291
19814
|
now: opts.now,
|
|
19292
19815
|
grant: { code: opts.code, redirectUri: opts.origin + PROVIDER_OAUTH_CALLBACK_PATH },
|
|
19293
19816
|
...opts.codeVerifier === "" ? {} : { codeVerifier: opts.codeVerifier },
|
|
@@ -19296,6 +19819,7 @@ async function finishProviderAuthorization(opts) {
|
|
|
19296
19819
|
await writeTokens(opts.store, opts.nodePath, tokens);
|
|
19297
19820
|
}
|
|
19298
19821
|
async function resolveProviderAccessToken(opts) {
|
|
19822
|
+
const fetcher = requireProviderOAuthFetch(opts.fetcher);
|
|
19299
19823
|
const tokens = await readTokens(opts.store, opts.nodePath);
|
|
19300
19824
|
if (tokens === void 0) throw providerReauthorizeRequired(opts.nodePath);
|
|
19301
19825
|
if (opts.force !== true && !shouldRefresh(tokens, opts.now)) return tokens.accessToken;
|
|
@@ -19305,7 +19829,7 @@ async function resolveProviderAccessToken(opts) {
|
|
|
19305
19829
|
try {
|
|
19306
19830
|
refreshed = await requestTokens({
|
|
19307
19831
|
config: opts.config,
|
|
19308
|
-
fetcher
|
|
19832
|
+
fetcher,
|
|
19309
19833
|
now: opts.now,
|
|
19310
19834
|
grant: { refreshToken: tokens.refreshToken },
|
|
19311
19835
|
...client
|
|
@@ -19409,7 +19933,7 @@ async function providerAccessTokenFor(opts) {
|
|
|
19409
19933
|
config: opts.config,
|
|
19410
19934
|
encryptionKey,
|
|
19411
19935
|
...opts.force === true ? { force: true } : {},
|
|
19412
|
-
fetcher:
|
|
19936
|
+
fetcher: opts.deps.providerOAuthFetch,
|
|
19413
19937
|
nodePath: opts.nodePath,
|
|
19414
19938
|
now: /* @__PURE__ */ new Date(),
|
|
19415
19939
|
// 调用期不需要 origin(只在构造授权 URL 时用);传空串会被 buildAuthorizationUrl 用到,
|
|
@@ -19608,7 +20132,7 @@ async function assertToolConfig(config, deps, ctx, mountPath) {
|
|
|
19608
20132
|
}
|
|
19609
20133
|
|
|
19610
20134
|
// ../app/src/refToken.ts
|
|
19611
|
-
async function
|
|
20135
|
+
async function hmacKey2(secret) {
|
|
19612
20136
|
const digest = await crypto.subtle.digest(
|
|
19613
20137
|
"SHA-256",
|
|
19614
20138
|
new TextEncoder().encode(`tb-ref-token:${secret}`)
|
|
@@ -19622,7 +20146,7 @@ async function signRefToken(payload, secret) {
|
|
|
19622
20146
|
const body = base64urlEncode(new TextEncoder().encode(JSON.stringify(payload)));
|
|
19623
20147
|
const mac = await crypto.subtle.sign(
|
|
19624
20148
|
"HMAC",
|
|
19625
|
-
await
|
|
20149
|
+
await hmacKey2(secret),
|
|
19626
20150
|
new TextEncoder().encode(body)
|
|
19627
20151
|
);
|
|
19628
20152
|
return `${body}.${base64urlEncode(new Uint8Array(mac))}`;
|
|
@@ -19639,7 +20163,7 @@ async function verifyRefToken(token, secret) {
|
|
|
19639
20163
|
}
|
|
19640
20164
|
const ok = await crypto.subtle.verify(
|
|
19641
20165
|
"HMAC",
|
|
19642
|
-
await
|
|
20166
|
+
await hmacKey2(secret),
|
|
19643
20167
|
// Node 的 WebCrypto 类型要求 Uint8Array<ArrayBuffer>;base64urlDecode 的产物满足但类型面是 ArrayBufferLike。
|
|
19644
20168
|
sig,
|
|
19645
20169
|
new TextEncoder().encode(body)
|
|
@@ -19784,60 +20308,11 @@ async function skillhubProviderFor(node, cfg, deps, requestUrl) {
|
|
|
19784
20308
|
}
|
|
19785
20309
|
return createSkillhubProvider(objects, opts);
|
|
19786
20310
|
}
|
|
19787
|
-
async function
|
|
19788
|
-
|
|
19789
|
-
|
|
19790
|
-
|
|
19791
|
-
|
|
19792
|
-
return typeof args.file === "string" ? await provider.get_file(args.id, args.file) : await provider.get(args.id);
|
|
19793
|
-
case "search":
|
|
19794
|
-
return await provider.search(args.query, args.opts);
|
|
19795
|
-
case "publish":
|
|
19796
|
-
if (!Array.isArray(args.files)) {
|
|
19797
|
-
throw new TBError("invalid_argument", "publish \u9700\u8981\u6570\u7EC4 'files'");
|
|
19798
|
-
}
|
|
19799
|
-
return await provider.publish({
|
|
19800
|
-
...typeof args.id === "string" ? { id: args.id } : {},
|
|
19801
|
-
files: args.files
|
|
19802
|
-
});
|
|
19803
|
-
case "remove":
|
|
19804
|
-
return await provider.remove(args.id);
|
|
19805
|
-
default:
|
|
19806
|
-
throw new TBError("invalid_argument", `unknown cmd '${command}'`);
|
|
19807
|
-
}
|
|
19808
|
-
}
|
|
19809
|
-
async function dispatchContextCmd(provider, command, args) {
|
|
19810
|
-
const unimplemented = () => {
|
|
19811
|
-
throw new TBError("invalid_argument", `unknown cmd '${command}'(provider \u672A\u5B9E\u73B0)`);
|
|
19812
|
-
};
|
|
19813
|
-
switch (command.toLowerCase()) {
|
|
19814
|
-
case "list":
|
|
19815
|
-
if (provider.list === void 0) return unimplemented();
|
|
19816
|
-
return await provider.list(args.path ?? "", args.opts);
|
|
19817
|
-
case "get":
|
|
19818
|
-
if (provider.get === void 0) return unimplemented();
|
|
19819
|
-
return await provider.get(args.path);
|
|
19820
|
-
case "write":
|
|
19821
|
-
if (provider.write === void 0) return unimplemented();
|
|
19822
|
-
if (typeof args.entry !== "object" || args.entry === null) {
|
|
19823
|
-
throw new TBError("invalid_argument", "write \u9700\u8981\u5BF9\u8C61 'entry'");
|
|
19824
|
-
}
|
|
19825
|
-
return await provider.write(args.path, args.entry);
|
|
19826
|
-
case "update":
|
|
19827
|
-
if (provider.update === void 0) return unimplemented();
|
|
19828
|
-
if (typeof args.patch !== "object" || args.patch === null) {
|
|
19829
|
-
throw new TBError("invalid_argument", "update \u9700\u8981\u5BF9\u8C61 'patch'");
|
|
19830
|
-
}
|
|
19831
|
-
return await provider.update(args.path, args.patch);
|
|
19832
|
-
case "delete":
|
|
19833
|
-
if (provider.delete === void 0) return unimplemented();
|
|
19834
|
-
return await provider.delete(args.path);
|
|
19835
|
-
case "search":
|
|
19836
|
-
if (provider.search === void 0) return unimplemented();
|
|
19837
|
-
return await provider.search(args.query, args.opts);
|
|
19838
|
-
default:
|
|
19839
|
-
throw new TBError("invalid_argument", `unknown cmd '${command}'`);
|
|
19840
|
-
}
|
|
20311
|
+
async function dispatchSkillhubCmd2(provider, command, args) {
|
|
20312
|
+
return await dispatchSkillhubCmd(provider, command, args);
|
|
20313
|
+
}
|
|
20314
|
+
async function dispatchContextCmd2(provider, command, args) {
|
|
20315
|
+
return await dispatchContextCmd(provider, command, args);
|
|
19841
20316
|
}
|
|
19842
20317
|
async function assertContextAlive(node, cfg, registry) {
|
|
19843
20318
|
if (!isContextExpired(node.createdAt, cfg.ttl, Date.now())) return;
|
|
@@ -23496,8 +23971,8 @@ function modernOnlyStrictRejection(route, supportedVersions) {
|
|
|
23496
23971
|
function parseSchema2(schema, data) {
|
|
23497
23972
|
return safeParse(schema, data);
|
|
23498
23973
|
}
|
|
23499
|
-
function shapeKeys2(
|
|
23500
|
-
return new Set(
|
|
23974
|
+
function shapeKeys2(schemas2) {
|
|
23975
|
+
return new Set(schemas2.flatMap((schema) => Object.keys(schema.shape)));
|
|
23501
23976
|
}
|
|
23502
23977
|
function isStandardSchema2(schema) {
|
|
23503
23978
|
if (schema == null) return false;
|
|
@@ -25335,9 +25810,9 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25335
25810
|
const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
|
|
25336
25811
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
25337
25812
|
}
|
|
25338
|
-
optimizeNames(names,
|
|
25813
|
+
optimizeNames(names, constants2) {
|
|
25339
25814
|
if (!names[this.name.str]) return;
|
|
25340
|
-
if (this.rhs) this.rhs = optimizeExpr(this.rhs, names,
|
|
25815
|
+
if (this.rhs) this.rhs = optimizeExpr(this.rhs, names, constants2);
|
|
25341
25816
|
return this;
|
|
25342
25817
|
}
|
|
25343
25818
|
get names() {
|
|
@@ -25354,9 +25829,9 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25354
25829
|
render({ _n }) {
|
|
25355
25830
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
25356
25831
|
}
|
|
25357
|
-
optimizeNames(names,
|
|
25832
|
+
optimizeNames(names, constants2) {
|
|
25358
25833
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects) return;
|
|
25359
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
25834
|
+
this.rhs = optimizeExpr(this.rhs, names, constants2);
|
|
25360
25835
|
return this;
|
|
25361
25836
|
}
|
|
25362
25837
|
get names() {
|
|
@@ -25415,8 +25890,8 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25415
25890
|
optimizeNodes() {
|
|
25416
25891
|
return `${this.code}` ? this : void 0;
|
|
25417
25892
|
}
|
|
25418
|
-
optimizeNames(names,
|
|
25419
|
-
this.code = optimizeExpr(this.code, names,
|
|
25893
|
+
optimizeNames(names, constants2) {
|
|
25894
|
+
this.code = optimizeExpr(this.code, names, constants2);
|
|
25420
25895
|
return this;
|
|
25421
25896
|
}
|
|
25422
25897
|
get names() {
|
|
@@ -25442,12 +25917,12 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25442
25917
|
}
|
|
25443
25918
|
return nodes.length > 0 ? this : void 0;
|
|
25444
25919
|
}
|
|
25445
|
-
optimizeNames(names,
|
|
25920
|
+
optimizeNames(names, constants2) {
|
|
25446
25921
|
const { nodes } = this;
|
|
25447
25922
|
let i = nodes.length;
|
|
25448
25923
|
while (i--) {
|
|
25449
25924
|
const n = nodes[i];
|
|
25450
|
-
if (n.optimizeNames(names,
|
|
25925
|
+
if (n.optimizeNames(names, constants2)) continue;
|
|
25451
25926
|
subtractNames(names, n.names);
|
|
25452
25927
|
nodes.splice(i, 1);
|
|
25453
25928
|
}
|
|
@@ -25494,11 +25969,11 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25494
25969
|
if (cond === false || !this.nodes.length) return void 0;
|
|
25495
25970
|
return this;
|
|
25496
25971
|
}
|
|
25497
|
-
optimizeNames(names,
|
|
25972
|
+
optimizeNames(names, constants2) {
|
|
25498
25973
|
var _a;
|
|
25499
|
-
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
25500
|
-
if (!(super.optimizeNames(names,
|
|
25501
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
25974
|
+
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants2);
|
|
25975
|
+
if (!(super.optimizeNames(names, constants2) || this.else)) return;
|
|
25976
|
+
this.condition = optimizeExpr(this.condition, names, constants2);
|
|
25502
25977
|
return this;
|
|
25503
25978
|
}
|
|
25504
25979
|
get names() {
|
|
@@ -25520,9 +25995,9 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25520
25995
|
render(opts) {
|
|
25521
25996
|
return `for(${this.iteration})` + super.render(opts);
|
|
25522
25997
|
}
|
|
25523
|
-
optimizeNames(names,
|
|
25524
|
-
if (!super.optimizeNames(names,
|
|
25525
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
25998
|
+
optimizeNames(names, constants2) {
|
|
25999
|
+
if (!super.optimizeNames(names, constants2)) return;
|
|
26000
|
+
this.iteration = optimizeExpr(this.iteration, names, constants2);
|
|
25526
26001
|
return this;
|
|
25527
26002
|
}
|
|
25528
26003
|
get names() {
|
|
@@ -25557,9 +26032,9 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25557
26032
|
render(opts) {
|
|
25558
26033
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
25559
26034
|
}
|
|
25560
|
-
optimizeNames(names,
|
|
25561
|
-
if (!super.optimizeNames(names,
|
|
25562
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
26035
|
+
optimizeNames(names, constants2) {
|
|
26036
|
+
if (!super.optimizeNames(names, constants2)) return;
|
|
26037
|
+
this.iterable = optimizeExpr(this.iterable, names, constants2);
|
|
25563
26038
|
return this;
|
|
25564
26039
|
}
|
|
25565
26040
|
get names() {
|
|
@@ -25598,11 +26073,11 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25598
26073
|
(_b = this.finally) === null || _b === void 0 || _b.optimizeNodes();
|
|
25599
26074
|
return this;
|
|
25600
26075
|
}
|
|
25601
|
-
optimizeNames(names,
|
|
26076
|
+
optimizeNames(names, constants2) {
|
|
25602
26077
|
var _a, _b;
|
|
25603
|
-
super.optimizeNames(names,
|
|
25604
|
-
(_a = this.catch) === null || _a === void 0 || _a.optimizeNames(names,
|
|
25605
|
-
(_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names,
|
|
26078
|
+
super.optimizeNames(names, constants2);
|
|
26079
|
+
(_a = this.catch) === null || _a === void 0 || _a.optimizeNames(names, constants2);
|
|
26080
|
+
(_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names, constants2);
|
|
25606
26081
|
return this;
|
|
25607
26082
|
}
|
|
25608
26083
|
get names() {
|
|
@@ -25851,7 +26326,7 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25851
26326
|
function addExprNames(names, from) {
|
|
25852
26327
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
25853
26328
|
}
|
|
25854
|
-
function optimizeExpr(expr, names,
|
|
26329
|
+
function optimizeExpr(expr, names, constants2) {
|
|
25855
26330
|
if (expr instanceof code_1.Name) return replaceName(expr);
|
|
25856
26331
|
if (!canOptimize(expr)) return expr;
|
|
25857
26332
|
return new code_1._Code(expr._items.reduce((items, c) => {
|
|
@@ -25861,13 +26336,13 @@ var require_codegen2 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
25861
26336
|
return items;
|
|
25862
26337
|
}, []));
|
|
25863
26338
|
function replaceName(n) {
|
|
25864
|
-
const c =
|
|
26339
|
+
const c = constants2[n.str];
|
|
25865
26340
|
if (c === void 0 || names[n.str] !== 1) return n;
|
|
25866
26341
|
delete names[n.str];
|
|
25867
26342
|
return c;
|
|
25868
26343
|
}
|
|
25869
26344
|
function canOptimize(e) {
|
|
25870
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
26345
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants2[c.str] !== void 0);
|
|
25871
26346
|
}
|
|
25872
26347
|
}
|
|
25873
26348
|
function subtractNames(names, from) {
|
|
@@ -28594,14 +29069,14 @@ var require_core$32 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
28594
29069
|
}
|
|
28595
29070
|
return metaSchema;
|
|
28596
29071
|
}
|
|
28597
|
-
_removeAllSchemas(
|
|
28598
|
-
for (const keyRef in
|
|
28599
|
-
const sch =
|
|
29072
|
+
_removeAllSchemas(schemas2, regex3) {
|
|
29073
|
+
for (const keyRef in schemas2) {
|
|
29074
|
+
const sch = schemas2[keyRef];
|
|
28600
29075
|
if (!regex3 || regex3.test(keyRef)) {
|
|
28601
|
-
if (typeof sch == "string") delete
|
|
29076
|
+
if (typeof sch == "string") delete schemas2[keyRef];
|
|
28602
29077
|
else if (sch && !sch.meta) {
|
|
28603
29078
|
this._cache.delete(sch.schema);
|
|
28604
|
-
delete
|
|
29079
|
+
delete schemas2[keyRef];
|
|
28605
29080
|
}
|
|
28606
29081
|
}
|
|
28607
29082
|
}
|
|
@@ -32091,9 +32566,9 @@ function createListenRouter(options) {
|
|
|
32091
32566
|
const { bus, onerror } = options;
|
|
32092
32567
|
const maxSubscriptions = options.maxSubscriptions ?? DEFAULT_MAX_SUBSCRIPTIONS;
|
|
32093
32568
|
const keepAliveMs = options.keepAliveMs ?? DEFAULT_SSE_KEEP_ALIVE_MS;
|
|
32094
|
-
const
|
|
32569
|
+
const open2 = /* @__PURE__ */ new Set();
|
|
32095
32570
|
function serve2(message, signal, capabilities, serverInfo) {
|
|
32096
|
-
if (
|
|
32571
|
+
if (open2.size >= maxSubscriptions) {
|
|
32097
32572
|
onerror?.(/* @__PURE__ */ new Error(`subscriptions/listen refused: subscription limit reached (${maxSubscriptions})`));
|
|
32098
32573
|
return jsonRpcError(message.id, -32603, "Subscription limit reached");
|
|
32099
32574
|
}
|
|
@@ -32149,7 +32624,7 @@ data: ${JSON.stringify({
|
|
|
32149
32624
|
}
|
|
32150
32625
|
if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer);
|
|
32151
32626
|
abortCleanup?.();
|
|
32152
|
-
|
|
32627
|
+
open2.delete(teardown);
|
|
32153
32628
|
try {
|
|
32154
32629
|
controller.close();
|
|
32155
32630
|
} catch {
|
|
@@ -32169,7 +32644,7 @@ data: ${JSON.stringify({
|
|
|
32169
32644
|
writeNotification(note.method, note.params);
|
|
32170
32645
|
});
|
|
32171
32646
|
keepAliveTimer = armSseKeepAlive(keepAliveMs, () => writeFrame(": keepalive\n\n"));
|
|
32172
|
-
|
|
32647
|
+
open2.add(teardown);
|
|
32173
32648
|
},
|
|
32174
32649
|
cancel() {
|
|
32175
32650
|
teardown(false);
|
|
@@ -32194,10 +32669,10 @@ data: ${JSON.stringify({
|
|
|
32194
32669
|
return {
|
|
32195
32670
|
serve: serve2,
|
|
32196
32671
|
closeAll() {
|
|
32197
|
-
for (const teardown of
|
|
32672
|
+
for (const teardown of open2) teardown(true);
|
|
32198
32673
|
},
|
|
32199
32674
|
get openCount() {
|
|
32200
|
-
return
|
|
32675
|
+
return open2.size;
|
|
32201
32676
|
}
|
|
32202
32677
|
};
|
|
32203
32678
|
}
|
|
@@ -35960,6 +36435,273 @@ async function passthroughRemote(opts) {
|
|
|
35960
36435
|
// ../app/src/tbApp.ts
|
|
35961
36436
|
import { Hono } from "hono";
|
|
35962
36437
|
|
|
36438
|
+
// ../core/src/protocol/openapi.ts
|
|
36439
|
+
var schemaRegistry = external_exports.registry();
|
|
36440
|
+
var schemas = {
|
|
36441
|
+
Error: tbErrorBodySchema,
|
|
36442
|
+
FeedbackDetail: feedbackDetailSchema,
|
|
36443
|
+
FeedbackList: feedbackListSchema,
|
|
36444
|
+
FeedbackRemoveResponse: feedbackRemoveResponseSchema,
|
|
36445
|
+
FeedbackSubmitRequest: feedbackSubmitRequestSchema,
|
|
36446
|
+
FeedbackSubmitResponse: feedbackSubmitResponseSchema,
|
|
36447
|
+
FeedbackView: feedbackViewSchema,
|
|
36448
|
+
FeedbackVoteRequest: feedbackVoteRequestSchema,
|
|
36449
|
+
Health: healthResponseSchema,
|
|
36450
|
+
Help: helpJsonSchema,
|
|
36451
|
+
Liveness: livenessResponseSchema,
|
|
36452
|
+
NodeInput: nodeInputSchema,
|
|
36453
|
+
OAuthAuthorizeRequest: oauthAuthorizeRequestSchema,
|
|
36454
|
+
OAuthAuthorizeResponse: oauthAuthorizeResponseSchema,
|
|
36455
|
+
Readiness: readinessResponseSchema,
|
|
36456
|
+
RegistryNode: registryNodeSchema,
|
|
36457
|
+
SearchRequest: toolSearchRequestSchema,
|
|
36458
|
+
SearchResponse: toolSearchPageSchema,
|
|
36459
|
+
Tree: treeJsonSchema
|
|
36460
|
+
};
|
|
36461
|
+
for (const [id, schema] of Object.entries(schemas)) schemaRegistry.add(schema, { id });
|
|
36462
|
+
function asOpenApiSchema(value) {
|
|
36463
|
+
if (Array.isArray(value)) return value.map(asOpenApiSchema);
|
|
36464
|
+
if (value === null || typeof value !== "object") return value;
|
|
36465
|
+
const out = {};
|
|
36466
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
36467
|
+
if (key === "$schema") continue;
|
|
36468
|
+
if (key === "$ref" && typeof entry === "string" && !entry.startsWith("#/")) {
|
|
36469
|
+
out[key] = `#/components/schemas/${entry}`;
|
|
36470
|
+
} else {
|
|
36471
|
+
out[key] = asOpenApiSchema(entry);
|
|
36472
|
+
}
|
|
36473
|
+
}
|
|
36474
|
+
return out;
|
|
36475
|
+
}
|
|
36476
|
+
var generated = external_exports.toJSONSchema(schemaRegistry);
|
|
36477
|
+
var componentSchemas = Object.fromEntries(
|
|
36478
|
+
Object.entries(generated.schemas).map(([name, schema]) => [name, asOpenApiSchema(schema)])
|
|
36479
|
+
);
|
|
36480
|
+
var jsonContent = (schema) => ({
|
|
36481
|
+
"application/json": { schema: { $ref: `#/components/schemas/${schema}` } }
|
|
36482
|
+
});
|
|
36483
|
+
var jsonResponse = (description, schema) => ({
|
|
36484
|
+
description,
|
|
36485
|
+
content: jsonContent(schema)
|
|
36486
|
+
});
|
|
36487
|
+
var errorResponses = {
|
|
36488
|
+
400: jsonResponse("Invalid request", "Error"),
|
|
36489
|
+
401: jsonResponse("Unauthenticated", "Error"),
|
|
36490
|
+
403: jsonResponse("Permission denied", "Error"),
|
|
36491
|
+
404: jsonResponse("Not found or not visible", "Error"),
|
|
36492
|
+
409: jsonResponse("Conflict", "Error"),
|
|
36493
|
+
429: jsonResponse("Rate limited", "Error"),
|
|
36494
|
+
500: jsonResponse("Internal error", "Error"),
|
|
36495
|
+
503: jsonResponse("Unavailable", "Error")
|
|
36496
|
+
};
|
|
36497
|
+
var bearerSecurity = [{ bearerAuth: [] }];
|
|
36498
|
+
var pathParameter = {
|
|
36499
|
+
in: "path",
|
|
36500
|
+
name: "path",
|
|
36501
|
+
required: true,
|
|
36502
|
+
description: "Slash-delimited Tool Bridge tree path; each segment is URL encoded.",
|
|
36503
|
+
schema: { type: "string" }
|
|
36504
|
+
};
|
|
36505
|
+
var fixedControlPlaneOpenApi = {
|
|
36506
|
+
openapi: "3.1.0",
|
|
36507
|
+
info: {
|
|
36508
|
+
title: "Tool Bridge fixed control plane",
|
|
36509
|
+
version: "1.0.0"
|
|
36510
|
+
},
|
|
36511
|
+
components: {
|
|
36512
|
+
securitySchemes: {
|
|
36513
|
+
bearerAuth: { type: "http", scheme: "bearer" }
|
|
36514
|
+
},
|
|
36515
|
+
schemas: componentSchemas
|
|
36516
|
+
},
|
|
36517
|
+
paths: {
|
|
36518
|
+
"/healthz": {
|
|
36519
|
+
get: {
|
|
36520
|
+
operationId: "getHealth",
|
|
36521
|
+
security: [],
|
|
36522
|
+
responses: { 200: jsonResponse("Deployment health", "Health") }
|
|
36523
|
+
}
|
|
36524
|
+
},
|
|
36525
|
+
"/livez": {
|
|
36526
|
+
get: {
|
|
36527
|
+
operationId: "getLiveness",
|
|
36528
|
+
security: [],
|
|
36529
|
+
responses: { 200: jsonResponse("Process liveness", "Liveness") }
|
|
36530
|
+
}
|
|
36531
|
+
},
|
|
36532
|
+
"/readyz": {
|
|
36533
|
+
get: {
|
|
36534
|
+
operationId: "getReadiness",
|
|
36535
|
+
security: [],
|
|
36536
|
+
responses: {
|
|
36537
|
+
200: jsonResponse("Ready", "Readiness"),
|
|
36538
|
+
503: jsonResponse("Not ready", "Readiness")
|
|
36539
|
+
}
|
|
36540
|
+
}
|
|
36541
|
+
},
|
|
36542
|
+
"/~help": {
|
|
36543
|
+
get: {
|
|
36544
|
+
operationId: "getRootHelp",
|
|
36545
|
+
security: bearerSecurity,
|
|
36546
|
+
parameters: [{
|
|
36547
|
+
in: "query",
|
|
36548
|
+
name: "schemas",
|
|
36549
|
+
schema: { type: "string", enum: ["1"] }
|
|
36550
|
+
}],
|
|
36551
|
+
responses: { 200: jsonResponse("Root HTBP help", "Help"), ...errorResponses }
|
|
36552
|
+
}
|
|
36553
|
+
},
|
|
36554
|
+
"/{path}/~help": {
|
|
36555
|
+
get: {
|
|
36556
|
+
"operationId": "getHelp",
|
|
36557
|
+
"security": bearerSecurity,
|
|
36558
|
+
"parameters": [pathParameter, {
|
|
36559
|
+
in: "query",
|
|
36560
|
+
name: "schemas",
|
|
36561
|
+
schema: { type: "string", enum: ["1"] }
|
|
36562
|
+
}],
|
|
36563
|
+
"responses": { 200: jsonResponse("HTBP help", "Help"), ...errorResponses },
|
|
36564
|
+
"x-tool-bridge-greedy-path": true
|
|
36565
|
+
}
|
|
36566
|
+
},
|
|
36567
|
+
"/~tree": {
|
|
36568
|
+
get: {
|
|
36569
|
+
operationId: "getRootTree",
|
|
36570
|
+
security: bearerSecurity,
|
|
36571
|
+
parameters: [{ in: "query", name: "depth", schema: { type: "integer", minimum: 1, maximum: 8 } }],
|
|
36572
|
+
responses: { 200: jsonResponse("Root tree", "Tree"), ...errorResponses }
|
|
36573
|
+
}
|
|
36574
|
+
},
|
|
36575
|
+
"/{path}/~tree": {
|
|
36576
|
+
get: {
|
|
36577
|
+
"operationId": "getTree",
|
|
36578
|
+
"security": bearerSecurity,
|
|
36579
|
+
"parameters": [pathParameter, {
|
|
36580
|
+
in: "query",
|
|
36581
|
+
name: "depth",
|
|
36582
|
+
schema: { type: "integer", minimum: 1, maximum: 8 }
|
|
36583
|
+
}],
|
|
36584
|
+
"responses": { 200: jsonResponse("Subtree", "Tree"), ...errorResponses },
|
|
36585
|
+
"x-tool-bridge-greedy-path": true
|
|
36586
|
+
}
|
|
36587
|
+
},
|
|
36588
|
+
"/~search": {
|
|
36589
|
+
post: {
|
|
36590
|
+
operationId: "searchTools",
|
|
36591
|
+
security: bearerSecurity,
|
|
36592
|
+
requestBody: { required: true, content: jsonContent("SearchRequest") },
|
|
36593
|
+
responses: { 200: jsonResponse("Visible tool page", "SearchResponse"), ...errorResponses }
|
|
36594
|
+
}
|
|
36595
|
+
},
|
|
36596
|
+
"/{path}/~authorize": {
|
|
36597
|
+
post: {
|
|
36598
|
+
"operationId": "startOAuthAuthorization",
|
|
36599
|
+
"security": bearerSecurity,
|
|
36600
|
+
"parameters": [pathParameter],
|
|
36601
|
+
"requestBody": { required: false, content: jsonContent("OAuthAuthorizeRequest") },
|
|
36602
|
+
"responses": {
|
|
36603
|
+
200: jsonResponse("Authorization status or redirect", "OAuthAuthorizeResponse"),
|
|
36604
|
+
...errorResponses
|
|
36605
|
+
},
|
|
36606
|
+
"x-tool-bridge-greedy-path": true
|
|
36607
|
+
}
|
|
36608
|
+
},
|
|
36609
|
+
"/{path}/~register": {
|
|
36610
|
+
post: {
|
|
36611
|
+
"operationId": "registerNode",
|
|
36612
|
+
"security": bearerSecurity,
|
|
36613
|
+
"parameters": [pathParameter],
|
|
36614
|
+
"requestBody": { required: true, content: jsonContent("NodeInput") },
|
|
36615
|
+
"responses": {
|
|
36616
|
+
200: jsonResponse("Registered node", "RegistryNode"),
|
|
36617
|
+
...errorResponses
|
|
36618
|
+
},
|
|
36619
|
+
"x-tool-bridge-greedy-path": true
|
|
36620
|
+
}
|
|
36621
|
+
},
|
|
36622
|
+
"/{path}/~feedback": {
|
|
36623
|
+
get: {
|
|
36624
|
+
"operationId": "listFeedback",
|
|
36625
|
+
"security": bearerSecurity,
|
|
36626
|
+
"parameters": [pathParameter, {
|
|
36627
|
+
in: "query",
|
|
36628
|
+
name: "hidden",
|
|
36629
|
+
schema: { type: "string", enum: ["1"] }
|
|
36630
|
+
}],
|
|
36631
|
+
"responses": { 200: jsonResponse("Feedback list", "FeedbackList"), ...errorResponses },
|
|
36632
|
+
"x-tool-bridge-greedy-path": true
|
|
36633
|
+
},
|
|
36634
|
+
post: {
|
|
36635
|
+
"operationId": "submitFeedback",
|
|
36636
|
+
"security": bearerSecurity,
|
|
36637
|
+
"parameters": [pathParameter],
|
|
36638
|
+
"requestBody": { required: true, content: jsonContent("FeedbackSubmitRequest") },
|
|
36639
|
+
"responses": {
|
|
36640
|
+
200: jsonResponse("Submitted feedback", "FeedbackSubmitResponse"),
|
|
36641
|
+
...errorResponses
|
|
36642
|
+
},
|
|
36643
|
+
"x-tool-bridge-greedy-path": true
|
|
36644
|
+
}
|
|
36645
|
+
},
|
|
36646
|
+
"/{path}/~feedback/{id}": {
|
|
36647
|
+
get: {
|
|
36648
|
+
"operationId": "getFeedback",
|
|
36649
|
+
"security": bearerSecurity,
|
|
36650
|
+
"parameters": [pathParameter, { in: "path", name: "id", required: true, schema: { type: "string" } }],
|
|
36651
|
+
"responses": { 200: jsonResponse("Feedback detail", "FeedbackDetail"), ...errorResponses },
|
|
36652
|
+
"x-tool-bridge-greedy-path": true
|
|
36653
|
+
},
|
|
36654
|
+
post: {
|
|
36655
|
+
"operationId": "voteFeedback",
|
|
36656
|
+
"security": bearerSecurity,
|
|
36657
|
+
"parameters": [pathParameter, { in: "path", name: "id", required: true, schema: { type: "string" } }],
|
|
36658
|
+
"requestBody": { required: true, content: jsonContent("FeedbackVoteRequest") },
|
|
36659
|
+
"responses": { 200: jsonResponse("Updated feedback", "FeedbackView"), ...errorResponses },
|
|
36660
|
+
"x-tool-bridge-greedy-path": true
|
|
36661
|
+
},
|
|
36662
|
+
delete: {
|
|
36663
|
+
"operationId": "removeFeedback",
|
|
36664
|
+
"security": bearerSecurity,
|
|
36665
|
+
"parameters": [pathParameter, { in: "path", name: "id", required: true, schema: { type: "string" } }],
|
|
36666
|
+
"responses": {
|
|
36667
|
+
200: jsonResponse("Feedback removed", "FeedbackRemoveResponse"),
|
|
36668
|
+
...errorResponses
|
|
36669
|
+
},
|
|
36670
|
+
"x-tool-bridge-greedy-path": true
|
|
36671
|
+
}
|
|
36672
|
+
},
|
|
36673
|
+
"/{commandPath}": {
|
|
36674
|
+
post: {
|
|
36675
|
+
"operationId": "invoke",
|
|
36676
|
+
"security": bearerSecurity,
|
|
36677
|
+
"parameters": [{
|
|
36678
|
+
in: "path",
|
|
36679
|
+
name: "commandPath",
|
|
36680
|
+
required: true,
|
|
36681
|
+
schema: { type: "string" },
|
|
36682
|
+
description: "Complete HTBP command path, including the command/tool leaf."
|
|
36683
|
+
}],
|
|
36684
|
+
"requestBody": {
|
|
36685
|
+
required: true,
|
|
36686
|
+
description: "Raw command arguments; there is no {tool, arguments} envelope.",
|
|
36687
|
+
content: { "application/json": { schema: {} } }
|
|
36688
|
+
},
|
|
36689
|
+
"responses": {
|
|
36690
|
+
200: {
|
|
36691
|
+
description: "Raw JSON or Markdown according to Accept.",
|
|
36692
|
+
content: {
|
|
36693
|
+
"application/json": { schema: {} },
|
|
36694
|
+
"text/markdown": { schema: { type: "string" } }
|
|
36695
|
+
}
|
|
36696
|
+
},
|
|
36697
|
+
...errorResponses
|
|
36698
|
+
},
|
|
36699
|
+
"x-tool-bridge-greedy-path": true
|
|
36700
|
+
}
|
|
36701
|
+
}
|
|
36702
|
+
}
|
|
36703
|
+
};
|
|
36704
|
+
|
|
35963
36705
|
// ../app/src/paths.ts
|
|
35964
36706
|
function scopeForCmd(mod, nodePath, cmd) {
|
|
35965
36707
|
return mod.help(nodePath).cmds.find((c) => c.name === cmd);
|
|
@@ -36043,7 +36785,9 @@ function indexByParent(nodes) {
|
|
|
36043
36785
|
}
|
|
36044
36786
|
|
|
36045
36787
|
// ../app/src/routes/feedback.ts
|
|
36046
|
-
var feedbackJson = (value) => new Response(JSON.stringify(value), {
|
|
36788
|
+
var feedbackJson = (schema, value) => new Response(JSON.stringify(schema.parse(value)), {
|
|
36789
|
+
headers: { "content-type": contentTypeFor("json") }
|
|
36790
|
+
});
|
|
36047
36791
|
async function handleFeedbackGet(c) {
|
|
36048
36792
|
const target = splitFeedback(new URL(c.req.url).pathname);
|
|
36049
36793
|
if (target === null || target.path === "") throw TBError.notFound("no such path");
|
|
@@ -36052,7 +36796,7 @@ async function handleFeedbackGet(c) {
|
|
|
36052
36796
|
const fb = new FeedbackStore(c.get("store"));
|
|
36053
36797
|
if (target.id !== void 0) {
|
|
36054
36798
|
const e = await fb.get(target.path, target.id);
|
|
36055
|
-
return feedbackJson({
|
|
36799
|
+
return feedbackJson(feedbackDetailSchema, {
|
|
36056
36800
|
id: e.id,
|
|
36057
36801
|
path: target.path,
|
|
36058
36802
|
title: e.title,
|
|
@@ -36066,7 +36810,7 @@ async function handleFeedbackGet(c) {
|
|
|
36066
36810
|
}
|
|
36067
36811
|
const views = await fb.listViews(target.path);
|
|
36068
36812
|
const items = c.req.query("hidden") === "1" ? views : views.filter((v) => v.score > FEEDBACK_HIDE_SCORE);
|
|
36069
|
-
return feedbackJson({ items });
|
|
36813
|
+
return feedbackJson(feedbackListSchema, { items });
|
|
36070
36814
|
}
|
|
36071
36815
|
async function handleFeedbackPost(c, env) {
|
|
36072
36816
|
const { searchSync } = env;
|
|
@@ -36088,23 +36832,32 @@ async function handleFeedbackPost(c, env) {
|
|
|
36088
36832
|
await searchSync?.reconcileNodeQuietly(path, { feedback: entries, marker });
|
|
36089
36833
|
});
|
|
36090
36834
|
if (target.id !== void 0) {
|
|
36091
|
-
const
|
|
36092
|
-
if (
|
|
36835
|
+
const input2 = feedbackVoteRequestSchema.safeParse(body);
|
|
36836
|
+
if (!input2.success) {
|
|
36093
36837
|
throw new TBError("invalid_argument", `body.vote must be 'up' | 'down' | 'clear'`);
|
|
36094
36838
|
}
|
|
36095
|
-
return feedbackJson(
|
|
36839
|
+
return feedbackJson(
|
|
36840
|
+
feedbackViewSchema,
|
|
36841
|
+
await fb.vote(target.path, target.id, ctx.owner, input2.data.vote)
|
|
36842
|
+
);
|
|
36096
36843
|
}
|
|
36097
|
-
|
|
36844
|
+
const input = feedbackSubmitRequestSchema.safeParse(body);
|
|
36845
|
+
if (!input.success) {
|
|
36098
36846
|
throw new TBError("invalid_argument", "body must be { title: string, detail: string }");
|
|
36099
36847
|
}
|
|
36100
36848
|
await new NodeRegistryStore(store).resolve(target.path);
|
|
36101
36849
|
const entry = await fb.submit(
|
|
36102
36850
|
target.path,
|
|
36103
|
-
|
|
36851
|
+
input.data,
|
|
36104
36852
|
ctx.owner,
|
|
36105
36853
|
(/* @__PURE__ */ new Date()).toISOString()
|
|
36106
36854
|
);
|
|
36107
|
-
return feedbackJson(
|
|
36855
|
+
return feedbackJson(feedbackSubmitResponseSchema, {
|
|
36856
|
+
id: entry.id,
|
|
36857
|
+
path: target.path,
|
|
36858
|
+
title: entry.title,
|
|
36859
|
+
at: entry.at
|
|
36860
|
+
});
|
|
36108
36861
|
} catch (error) {
|
|
36109
36862
|
await searchSync?.abort(marker);
|
|
36110
36863
|
throw error;
|
|
@@ -36130,12 +36883,12 @@ async function handleFeedbackDelete(c, env) {
|
|
|
36130
36883
|
await searchSync?.abort(marker);
|
|
36131
36884
|
throw error;
|
|
36132
36885
|
}
|
|
36133
|
-
return feedbackJson({ ok: true });
|
|
36886
|
+
return feedbackJson(feedbackRemoveResponseSchema, { ok: true });
|
|
36134
36887
|
}
|
|
36135
36888
|
|
|
36136
36889
|
// ../app/src/responses.ts
|
|
36137
36890
|
function tbErrorResponse(err) {
|
|
36138
|
-
return new Response(JSON.stringify(err.toJSON()), {
|
|
36891
|
+
return new Response(JSON.stringify(tbErrorBodySchema.parse(err.toJSON())), {
|
|
36139
36892
|
status: err.httpStatus,
|
|
36140
36893
|
headers: { "content-type": "application/json; charset=utf-8" }
|
|
36141
36894
|
});
|
|
@@ -36172,7 +36925,7 @@ async function runHandler(fn) {
|
|
|
36172
36925
|
}
|
|
36173
36926
|
function renderHelp(model, rep) {
|
|
36174
36927
|
if (rep === "json") {
|
|
36175
|
-
return new Response(JSON.stringify(renderHelpJson(model)), {
|
|
36928
|
+
return new Response(JSON.stringify(helpJsonSchema.parse(renderHelpJson(model))), {
|
|
36176
36929
|
headers: { "content-type": contentTypeFor("json") }
|
|
36177
36930
|
});
|
|
36178
36931
|
}
|
|
@@ -36376,14 +37129,14 @@ async function authorizeToolNode(c, env, node, encryptionKey) {
|
|
|
36376
37129
|
authRef: config.authRef,
|
|
36377
37130
|
config: exported.oauth,
|
|
36378
37131
|
encryptionKey,
|
|
36379
|
-
fetcher:
|
|
37132
|
+
fetcher: deps.providerOAuthFetch,
|
|
36380
37133
|
nodePath: node.path,
|
|
36381
37134
|
now: /* @__PURE__ */ new Date(),
|
|
36382
37135
|
origin: deps.canonicalOrigin ?? new URL(c.req.url).origin,
|
|
36383
37136
|
secrets: deps.secrets,
|
|
36384
37137
|
store: deps.state
|
|
36385
37138
|
});
|
|
36386
|
-
return new Response(JSON.stringify(result), {
|
|
37139
|
+
return new Response(JSON.stringify(oauthAuthorizeResponseSchema.parse(result)), {
|
|
36387
37140
|
headers: { "content-type": contentTypeFor("json") }
|
|
36388
37141
|
});
|
|
36389
37142
|
}
|
|
@@ -36430,7 +37183,7 @@ async function handleRegister(c, env) {
|
|
|
36430
37183
|
await invalidateProviderOAuth(store, body.path);
|
|
36431
37184
|
await searchSync?.reconcileNodeQuietly(body.path, { marker });
|
|
36432
37185
|
if (await refreshDynamicSearchNode(node, ctx, deps)) await searchSync?.abort(marker);
|
|
36433
|
-
return new Response(JSON.stringify(node), {
|
|
37186
|
+
return new Response(JSON.stringify(registryNodeSchema.parse(node)), {
|
|
36434
37187
|
headers: { "content-type": contentTypeFor("json") }
|
|
36435
37188
|
});
|
|
36436
37189
|
}
|
|
@@ -36457,6 +37210,11 @@ async function handleAuthorize(c, env) {
|
|
|
36457
37210
|
} catch {
|
|
36458
37211
|
throw TBError.notFound("not found");
|
|
36459
37212
|
}
|
|
37213
|
+
const rawBody = await c.req.json().catch(() => ({}));
|
|
37214
|
+
const body = oauthAuthorizeRequestSchema.safeParse(rawBody);
|
|
37215
|
+
if (!body.success) {
|
|
37216
|
+
throw new TBError("invalid_argument", "body only accepts optional redirectUri string");
|
|
37217
|
+
}
|
|
36460
37218
|
if (node.kind === "tool" && node.config?.kind === "tool") {
|
|
36461
37219
|
return await authorizeToolNode(c, env, node, encKey);
|
|
36462
37220
|
}
|
|
@@ -36466,8 +37224,7 @@ async function handleAuthorize(c, env) {
|
|
|
36466
37224
|
`'${path}' \u65E2\u4E0D\u662F auth:'oauth' \u7684 mcp \u6302\u8F7D,\u4E5F\u4E0D\u662F\u58F0\u660E\u4E86 oauth \u7684 tool \u6302\u8F7D`
|
|
36467
37225
|
);
|
|
36468
37226
|
}
|
|
36469
|
-
const
|
|
36470
|
-
const redirectUri = body !== null && typeof body.redirectUri === "string" ? body.redirectUri : void 0;
|
|
37227
|
+
const redirectUri = body.data.redirectUri;
|
|
36471
37228
|
const result = await startMcpAuthorization({
|
|
36472
37229
|
store,
|
|
36473
37230
|
encryptionKey: encKey,
|
|
@@ -36476,7 +37233,7 @@ async function handleAuthorize(c, env) {
|
|
|
36476
37233
|
origin: deps.canonicalOrigin ?? new URL(c.req.url).origin,
|
|
36477
37234
|
...redirectUri !== void 0 ? { redirectUri } : {}
|
|
36478
37235
|
});
|
|
36479
|
-
return new Response(JSON.stringify(result), {
|
|
37236
|
+
return new Response(JSON.stringify(oauthAuthorizeResponseSchema.parse(result)), {
|
|
36480
37237
|
headers: { "content-type": contentTypeFor("json") }
|
|
36481
37238
|
});
|
|
36482
37239
|
}
|
|
@@ -36538,6 +37295,137 @@ async function handleDescribe(c, env) {
|
|
|
36538
37295
|
throw TBError.notFound(`no capabilities for kind '${node.kind}'`);
|
|
36539
37296
|
}
|
|
36540
37297
|
|
|
37298
|
+
// ../app/src/routes/store.ts
|
|
37299
|
+
var SECRET_BODY_FIELDS = [
|
|
37300
|
+
"callCapability",
|
|
37301
|
+
"capability",
|
|
37302
|
+
"uploadToken",
|
|
37303
|
+
"shareToken"
|
|
37304
|
+
];
|
|
37305
|
+
function hideCapabilityFailure(error) {
|
|
37306
|
+
if (isTBError(error) && error.code !== "permission_denied" && error.code !== "not_found") throw error;
|
|
37307
|
+
throw TBError.notFound("not found");
|
|
37308
|
+
}
|
|
37309
|
+
async function jsonObject(c) {
|
|
37310
|
+
const parsed = await c.req.json().catch(() => null);
|
|
37311
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
37312
|
+
throw new TBError("invalid_argument", "body must be a JSON object");
|
|
37313
|
+
}
|
|
37314
|
+
const body = parsed;
|
|
37315
|
+
for (const field of SECRET_BODY_FIELDS) {
|
|
37316
|
+
if (field in body) {
|
|
37317
|
+
throw new TBError(
|
|
37318
|
+
"invalid_argument",
|
|
37319
|
+
`${field} is not accepted in the request body; use the dedicated capability header`
|
|
37320
|
+
);
|
|
37321
|
+
}
|
|
37322
|
+
}
|
|
37323
|
+
return body;
|
|
37324
|
+
}
|
|
37325
|
+
function requiredHeader(c, name) {
|
|
37326
|
+
const value = c.req.header(name);
|
|
37327
|
+
if (value === void 0 || value.trim() === "") {
|
|
37328
|
+
throw new TBError("permission_denied", "Store capability is missing or invalid");
|
|
37329
|
+
}
|
|
37330
|
+
return value;
|
|
37331
|
+
}
|
|
37332
|
+
function uploadId(body) {
|
|
37333
|
+
if (typeof body.uploadId !== "string" || body.uploadId.trim() === "") {
|
|
37334
|
+
throw new TBError("invalid_argument", "uploadId must be a non-empty string");
|
|
37335
|
+
}
|
|
37336
|
+
return body.uploadId;
|
|
37337
|
+
}
|
|
37338
|
+
function registerStoreCapabilityRoutes(app, deps) {
|
|
37339
|
+
app.post("/system/store/create_upload", async (c, next) => {
|
|
37340
|
+
if (c.req.header(STORE_CALL_CAPABILITY_HEADER) === void 0) return await next();
|
|
37341
|
+
return await runHandler(async () => {
|
|
37342
|
+
await deps.ensureReady?.();
|
|
37343
|
+
const body = await jsonObject(c);
|
|
37344
|
+
const capability = requiredHeader(c, STORE_CALL_CAPABILITY_HEADER);
|
|
37345
|
+
const result = await beginCapabilityUpload(
|
|
37346
|
+
deps,
|
|
37347
|
+
body,
|
|
37348
|
+
capability,
|
|
37349
|
+
resolveStoreRequestOrigin(c.req.url, deps.canonicalOrigin)
|
|
37350
|
+
);
|
|
37351
|
+
return c.json(result);
|
|
37352
|
+
});
|
|
37353
|
+
});
|
|
37354
|
+
for (const command of ["complete_upload", "abort_upload"]) {
|
|
37355
|
+
app.post(`/system/store/${command}`, async (c, next) => {
|
|
37356
|
+
if (c.req.header(STORE_UPLOAD_HEADER) === void 0) return await next();
|
|
37357
|
+
return await runHandler(async () => {
|
|
37358
|
+
await deps.ensureReady?.();
|
|
37359
|
+
const body = await jsonObject(c);
|
|
37360
|
+
const token = requiredHeader(c, STORE_UPLOAD_HEADER);
|
|
37361
|
+
const result = command === "complete_upload" ? await completeCapabilityUpload(deps, uploadId(body), token) : await abortCapabilityUpload(deps, uploadId(body), token);
|
|
37362
|
+
return c.json(result);
|
|
37363
|
+
});
|
|
37364
|
+
});
|
|
37365
|
+
}
|
|
37366
|
+
app.put(
|
|
37367
|
+
"/~store/uploads/:uploadId",
|
|
37368
|
+
(c) => runHandler(async () => {
|
|
37369
|
+
await deps.ensureReady?.();
|
|
37370
|
+
const descriptor = await relayStoreUpload(
|
|
37371
|
+
deps,
|
|
37372
|
+
c.req.param("uploadId"),
|
|
37373
|
+
requiredHeader(c, STORE_UPLOAD_HEADER),
|
|
37374
|
+
c.req.raw.body
|
|
37375
|
+
);
|
|
37376
|
+
return c.json(descriptor);
|
|
37377
|
+
})
|
|
37378
|
+
);
|
|
37379
|
+
app.get(
|
|
37380
|
+
"/~store/refs/:token",
|
|
37381
|
+
(c) => runHandler(async () => {
|
|
37382
|
+
await deps.ensureReady?.();
|
|
37383
|
+
const store = await defaultStoreRuntime(deps);
|
|
37384
|
+
const payload = await verifyStoreRefToken(c.req.param("token"), store.tokenSecret);
|
|
37385
|
+
if (payload === null || payload.exp * 1e3 <= Date.now()) {
|
|
37386
|
+
throw TBError.notFound("not found");
|
|
37387
|
+
}
|
|
37388
|
+
let object2;
|
|
37389
|
+
try {
|
|
37390
|
+
object2 = await store.service.authorizeRead(storeUri(payload.objectId), {
|
|
37391
|
+
admin: true
|
|
37392
|
+
});
|
|
37393
|
+
} catch (error) {
|
|
37394
|
+
hideCapabilityFailure(error);
|
|
37395
|
+
}
|
|
37396
|
+
return await storeObjectResponse(store.objects, object2);
|
|
37397
|
+
})
|
|
37398
|
+
);
|
|
37399
|
+
app.get(
|
|
37400
|
+
"/~store/shares/:token",
|
|
37401
|
+
(c) => runHandler(async () => {
|
|
37402
|
+
await deps.ensureReady?.();
|
|
37403
|
+
const token = c.req.param("token");
|
|
37404
|
+
const store = await defaultStoreRuntime(deps);
|
|
37405
|
+
let object2;
|
|
37406
|
+
try {
|
|
37407
|
+
const grant = await store.service.verifyShareToken(token);
|
|
37408
|
+
const uri3 = storeUri(grant.objectId);
|
|
37409
|
+
object2 = await store.service.authorizeSharedRead(uri3, token);
|
|
37410
|
+
} catch (error) {
|
|
37411
|
+
hideCapabilityFailure(error);
|
|
37412
|
+
}
|
|
37413
|
+
return await storeObjectResponse(store.objects, object2);
|
|
37414
|
+
})
|
|
37415
|
+
);
|
|
37416
|
+
}
|
|
37417
|
+
function rejectStoreCapabilityBodyFields(module, args) {
|
|
37418
|
+
if (module !== "store") return;
|
|
37419
|
+
for (const field of SECRET_BODY_FIELDS) {
|
|
37420
|
+
if (field in args) {
|
|
37421
|
+
throw new TBError(
|
|
37422
|
+
"invalid_argument",
|
|
37423
|
+
`${field} is not accepted in the request body; use the dedicated capability header`
|
|
37424
|
+
);
|
|
37425
|
+
}
|
|
37426
|
+
}
|
|
37427
|
+
}
|
|
37428
|
+
|
|
36541
37429
|
// ../app/src/routes/publicRoutes.ts
|
|
36542
37430
|
async function finishToolAuthorization(opts) {
|
|
36543
37431
|
const config = opts.node.config;
|
|
@@ -36558,7 +37446,7 @@ async function finishToolAuthorization(opts) {
|
|
|
36558
37446
|
codeVerifier: opts.verifier,
|
|
36559
37447
|
config: exported.oauth,
|
|
36560
37448
|
encryptionKey: opts.encryptionKey,
|
|
36561
|
-
fetcher:
|
|
37449
|
+
fetcher: opts.deps.providerOAuthFetch,
|
|
36562
37450
|
nodePath: opts.node.path,
|
|
36563
37451
|
now: /* @__PURE__ */ new Date(),
|
|
36564
37452
|
origin: opts.origin,
|
|
@@ -36575,21 +37463,23 @@ function registerPublicRoutes(app, env) {
|
|
|
36575
37463
|
app.get("/healthz", async (c) => {
|
|
36576
37464
|
const catalog = deps.pluginCatalog;
|
|
36577
37465
|
const digest = await env.pluginCatalogDigest();
|
|
36578
|
-
return c.json({
|
|
37466
|
+
return c.json(healthResponseSchema.parse({
|
|
36579
37467
|
healthy: true,
|
|
36580
37468
|
version: deps.version,
|
|
36581
37469
|
...catalog !== void 0 && digest !== void 0 ? { catalog: { count: Object.keys(catalog).length, digest } } : {}
|
|
36582
|
-
});
|
|
37470
|
+
}));
|
|
36583
37471
|
});
|
|
36584
|
-
app.get("/livez", (c) => c.json({ live: true }));
|
|
37472
|
+
app.get("/livez", (c) => c.json(livenessResponseSchema.parse({ live: true })));
|
|
36585
37473
|
app.get("/readyz", async (c) => {
|
|
36586
37474
|
const probe = deps.readiness;
|
|
36587
|
-
if (probe === void 0)
|
|
37475
|
+
if (probe === void 0) {
|
|
37476
|
+
return c.json(readinessResponseSchema.parse({ checks: {}, ready: true }));
|
|
37477
|
+
}
|
|
36588
37478
|
try {
|
|
36589
|
-
const report = await probe();
|
|
37479
|
+
const report = readinessResponseSchema.parse(await probe());
|
|
36590
37480
|
return c.json(report, report.ready ? 200 : 503);
|
|
36591
37481
|
} catch {
|
|
36592
|
-
return c.json({ checks: {}, ready: false }, 503);
|
|
37482
|
+
return c.json(readinessResponseSchema.parse({ checks: {}, ready: false }), 503);
|
|
36593
37483
|
}
|
|
36594
37484
|
});
|
|
36595
37485
|
app.get(
|
|
@@ -36749,7 +37639,11 @@ function registerSearchRoute(app, env) {
|
|
|
36749
37639
|
if (opts.cursor !== void 0 && typeof opts.cursor !== "string") {
|
|
36750
37640
|
throw new TBError("invalid_argument", "opts.cursor must be a string");
|
|
36751
37641
|
}
|
|
36752
|
-
const
|
|
37642
|
+
const wireRequest = toolSearchRequestSchema.parse({
|
|
37643
|
+
query: body.query,
|
|
37644
|
+
...rawOpts === void 0 ? {} : { opts }
|
|
37645
|
+
});
|
|
37646
|
+
const query = wireRequest.query;
|
|
36753
37647
|
await searchSync?.ensureReady();
|
|
36754
37648
|
const ctx = c.get("ctx");
|
|
36755
37649
|
const registry = new NodeRegistryStore(c.get("store"));
|
|
@@ -36827,7 +37721,7 @@ function registerSearchRoute(app, env) {
|
|
|
36827
37721
|
}
|
|
36828
37722
|
if (items.length === 0) responseCursor = void 0;
|
|
36829
37723
|
const result = responseCursor === void 0 ? { items } : { items, cursor: responseCursor };
|
|
36830
|
-
return new Response(JSON.stringify(result), {
|
|
37724
|
+
return new Response(JSON.stringify(toolSearchPageSchema.parse(result)), {
|
|
36831
37725
|
headers: { "content-type": contentTypeFor("json") }
|
|
36832
37726
|
});
|
|
36833
37727
|
})
|
|
@@ -37398,27 +38292,27 @@ async function handleInvoke(c, env) {
|
|
|
37398
38292
|
throw new TBError("permission_denied", `readOnly \u6302\u8F7D\u62D2\u7EDD '${command}'`);
|
|
37399
38293
|
}
|
|
37400
38294
|
if (directUpload) {
|
|
37401
|
-
const result3 = await
|
|
37402
|
-
|
|
37403
|
-
cfg,
|
|
37404
|
-
deps,
|
|
37405
|
-
args2
|
|
38295
|
+
const result3 = await dispatchContextUploadCmd(
|
|
38296
|
+
args2,
|
|
38297
|
+
(input) => createContextUploadGrant(node, cfg, deps, input)
|
|
37406
38298
|
);
|
|
37407
38299
|
return renderResult(result3, negotiate(c.req.header("accept")));
|
|
37408
38300
|
}
|
|
37409
38301
|
if (cfg.provider === "device-fs") {
|
|
38302
|
+
const forwardedArgs = parseContextCmdArgs(command, args2);
|
|
37410
38303
|
const result3 = await invokeDevice(deps, deviceIdForDeviceFs(cfg), {
|
|
37411
38304
|
path: `fs/${command}`,
|
|
37412
|
-
arguments:
|
|
38305
|
+
arguments: forwardedArgs,
|
|
37413
38306
|
context: deviceCallContextFrom(ctx)
|
|
37414
38307
|
});
|
|
37415
38308
|
return renderResult(result3, negotiate(c.req.header("accept")));
|
|
37416
38309
|
}
|
|
37417
38310
|
const contextMarker = deviceMarkerOf(cfg.providerConfig);
|
|
37418
38311
|
if (cfg.provider !== "r2" && cfg.provider !== "s3" && contextMarker !== null) {
|
|
38312
|
+
const forwardedArgs = parseContextCmdArgs(command, args2);
|
|
37419
38313
|
const result3 = await invokeDevice(deps, contextMarker.deviceId, {
|
|
37420
38314
|
path: `${relativeDevicePath(node.path, contextMarker.mountPath)}/${command}`,
|
|
37421
|
-
arguments:
|
|
38315
|
+
arguments: forwardedArgs,
|
|
37422
38316
|
context: deviceCallContextFrom(ctx)
|
|
37423
38317
|
});
|
|
37424
38318
|
return renderResult(result3, negotiate(c.req.header("accept")));
|
|
@@ -37426,7 +38320,7 @@ async function handleInvoke(c, env) {
|
|
|
37426
38320
|
if (cfg.provider !== "r2" && cfg.provider !== "s3") {
|
|
37427
38321
|
const local = localContext(deps, node);
|
|
37428
38322
|
if (local !== null) {
|
|
37429
|
-
const result4 = await
|
|
38323
|
+
const result4 = await dispatchContextCmd2(local, command, args2);
|
|
37430
38324
|
return renderResult(result4, negotiate(c.req.header("accept")));
|
|
37431
38325
|
}
|
|
37432
38326
|
const { manifest, export: exported } = await requirePluginExport(
|
|
@@ -37446,11 +38340,11 @@ async function handleInvoke(c, env) {
|
|
|
37446
38340
|
...cfg.authRef !== void 0 ? { upstreamAuthRef: cfg.authRef } : {},
|
|
37447
38341
|
...deps.pluginBindings !== void 0 ? { bindings: deps.pluginBindings } : {}
|
|
37448
38342
|
});
|
|
37449
|
-
const result3 = await
|
|
38343
|
+
const result3 = await dispatchContextCmd2(provider2, command, args2);
|
|
37450
38344
|
return renderResult(result3, negotiate(c.req.header("accept")));
|
|
37451
38345
|
}
|
|
37452
38346
|
const provider = await contextProviderFor(node, cfg, deps, c.req.url);
|
|
37453
|
-
const result2 = await
|
|
38347
|
+
const result2 = await dispatchContextCmd2(provider, command, args2);
|
|
37454
38348
|
return renderResult(result2, negotiate(c.req.header("accept")));
|
|
37455
38349
|
}
|
|
37456
38350
|
if (node.kind === "skillhub" && node.config?.kind === "skillhub") {
|
|
@@ -37468,7 +38362,7 @@ async function handleInvoke(c, env) {
|
|
|
37468
38362
|
throw new TBError("permission_denied", `readOnly \u6302\u8F7D\u62D2\u7EDD '${command}'`);
|
|
37469
38363
|
}
|
|
37470
38364
|
const provider = await skillhubProviderFor(node, cfg, deps, c.req.url);
|
|
37471
|
-
const result2 = await
|
|
38365
|
+
const result2 = await dispatchSkillhubCmd2(provider, command, args2);
|
|
37472
38366
|
return renderResult(result2, negotiate(c.req.header("accept")));
|
|
37473
38367
|
}
|
|
37474
38368
|
if (node.kind !== "builtin" || node.config?.kind !== "builtin") {
|
|
@@ -37479,6 +38373,7 @@ async function handleInvoke(c, env) {
|
|
|
37479
38373
|
if (!mod) throw TBError.unimplemented(`builtin module '${node.config.module}' not available`);
|
|
37480
38374
|
const args = await readInvokeBody();
|
|
37481
38375
|
const cmd = command;
|
|
38376
|
+
rejectStoreCapabilityBodyFields(node.config.module, args);
|
|
37482
38377
|
const spec = scopeForCmd(mod, node.path, cmd);
|
|
37483
38378
|
if (!spec) throw new TBError("invalid_argument", `unknown cmd '${cmd}' on '${node.path}'`);
|
|
37484
38379
|
if (!check(ctx, node.path, spec.scope).allow) {
|
|
@@ -37522,7 +38417,9 @@ async function handleInvoke(c, env) {
|
|
|
37522
38417
|
const registryMarker = registryTarget === void 0 ? void 0 : await searchSync?.markNode(registryTarget);
|
|
37523
38418
|
let result;
|
|
37524
38419
|
try {
|
|
37525
|
-
result = await mod.dispatch(cmd, args, ctx
|
|
38420
|
+
result = await mod.dispatch(cmd, args, ctx, {
|
|
38421
|
+
requestOrigin: resolveStoreRequestOrigin(c.req.url, deps.canonicalOrigin)
|
|
38422
|
+
});
|
|
37526
38423
|
} catch (error) {
|
|
37527
38424
|
await searchSync?.abort(registryMarker);
|
|
37528
38425
|
await Promise.all(pluginMounts.map(async (mount) => await searchSync?.abort(mount.marker)));
|
|
@@ -37573,17 +38470,21 @@ async function handleInvoke(c, env) {
|
|
|
37573
38470
|
// ../app/src/routes/env.ts
|
|
37574
38471
|
function createRouteEnv(deps) {
|
|
37575
38472
|
const searchSync = isMutableSearchIndex(deps.search) ? new SearchSynchronizer(deps.state, deps.search) : void 0;
|
|
37576
|
-
const builtinsOf = (store) =>
|
|
37577
|
-
|
|
37578
|
-
|
|
37579
|
-
|
|
37580
|
-
|
|
37581
|
-
|
|
37582
|
-
|
|
37583
|
-
|
|
37584
|
-
|
|
37585
|
-
|
|
37586
|
-
|
|
38473
|
+
const builtinsOf = (store) => {
|
|
38474
|
+
const builtins = createBuiltins(
|
|
38475
|
+
buildDeps({
|
|
38476
|
+
store,
|
|
38477
|
+
secrets: deps.secrets,
|
|
38478
|
+
version: deps.version,
|
|
38479
|
+
allowInsecureHttp: deps.allowInsecureHttp,
|
|
38480
|
+
remoteAllowlistBase: deps.remote.allowlist,
|
|
38481
|
+
...deps.pluginBindings !== void 0 ? { pluginBindings: deps.pluginBindings } : {},
|
|
38482
|
+
...deps.pluginCatalog !== void 0 ? { pluginCatalog: deps.pluginCatalog } : {}
|
|
38483
|
+
})
|
|
38484
|
+
);
|
|
38485
|
+
builtins.set("store", lazyDefaultStoreModule(deps));
|
|
38486
|
+
return builtins;
|
|
38487
|
+
};
|
|
37587
38488
|
const globalSearchCapabilities = () => {
|
|
37588
38489
|
const declared = new Set(deps.search?.capabilities ?? []);
|
|
37589
38490
|
if (!declared.has("search")) return [];
|
|
@@ -37629,7 +38530,7 @@ async function handleHelp(c, env) {
|
|
|
37629
38530
|
if (remote) return remote;
|
|
37630
38531
|
const builtins = builtinsOf(store);
|
|
37631
38532
|
const refresh = c.req.query("refresh") === "1";
|
|
37632
|
-
const
|
|
38533
|
+
const schemas2 = c.req.query("schemas") === "1";
|
|
37633
38534
|
let node;
|
|
37634
38535
|
try {
|
|
37635
38536
|
node = await registry.get(path);
|
|
@@ -37638,14 +38539,14 @@ async function handleHelp(c, env) {
|
|
|
37638
38539
|
if (toolModel !== null) return renderHelp(await enrichHelp(toolModel, path, store), rep);
|
|
37639
38540
|
const cmdModel = await commandHelpModelFor(registry, ctx, builtins, deps, path, {
|
|
37640
38541
|
refresh,
|
|
37641
|
-
schemas
|
|
38542
|
+
schemas: schemas2
|
|
37642
38543
|
});
|
|
37643
38544
|
if (cmdModel !== null) return renderHelp(await enrichHelp(cmdModel, path, store), rep);
|
|
37644
38545
|
throw TBError.notFound("not found");
|
|
37645
38546
|
}
|
|
37646
38547
|
const model = await helpModelFor(node, registry, ctx, builtins, deps, {
|
|
37647
38548
|
refresh,
|
|
37648
|
-
schemas,
|
|
38549
|
+
schemas: schemas2,
|
|
37649
38550
|
now: (/* @__PURE__ */ new Date()).toISOString()
|
|
37650
38551
|
});
|
|
37651
38552
|
return renderHelp(await enrichHelp(model, path, store), rep);
|
|
@@ -37697,7 +38598,7 @@ async function handleTree(c, env) {
|
|
|
37697
38598
|
});
|
|
37698
38599
|
const rep = negotiate(c.req.header("accept"));
|
|
37699
38600
|
if (rep === "json") {
|
|
37700
|
-
return new Response(JSON.stringify(tree), {
|
|
38601
|
+
return new Response(JSON.stringify(treeJsonSchema.parse(tree)), {
|
|
37701
38602
|
headers: { "content-type": contentTypeFor("json") }
|
|
37702
38603
|
});
|
|
37703
38604
|
}
|
|
@@ -37724,6 +38625,7 @@ function createTbApp(deps) {
|
|
|
37724
38625
|
if (secured !== response) c.res = secured;
|
|
37725
38626
|
});
|
|
37726
38627
|
registerPublicRoutes(app, env);
|
|
38628
|
+
registerStoreCapabilityRoutes(app, deps);
|
|
37727
38629
|
app.use("*", async (c, next) => {
|
|
37728
38630
|
const store = deps.state;
|
|
37729
38631
|
try {
|
|
@@ -38250,6 +39152,19 @@ var DeviceRouter = class _DeviceRouter {
|
|
|
38250
39152
|
}
|
|
38251
39153
|
};
|
|
38252
39154
|
|
|
39155
|
+
// src/objects.ts
|
|
39156
|
+
import {
|
|
39157
|
+
link,
|
|
39158
|
+
mkdir as mkdir2,
|
|
39159
|
+
open,
|
|
39160
|
+
readdir as readdir2,
|
|
39161
|
+
realpath as realpath2,
|
|
39162
|
+
rename,
|
|
39163
|
+
rm as rm2,
|
|
39164
|
+
stat as stat2
|
|
39165
|
+
} from "fs/promises";
|
|
39166
|
+
import { constants, mkdirSync } from "fs";
|
|
39167
|
+
|
|
38253
39168
|
// ../core/src/node/fsObjectStore.ts
|
|
38254
39169
|
import { mkdir, readdir, readFile, realpath, rm, stat, writeFile } from "fs/promises";
|
|
38255
39170
|
import { basename, dirname, join, resolve, sep } from "path";
|
|
@@ -38349,6 +39264,9 @@ var FsObjectStore = class {
|
|
|
38349
39264
|
throw new TBError("invalid_argument", `\u975E\u6CD5 entry \u8DEF\u5F84 '${key}':\u672A\u77E5\u6839\u6216\u7F3A\u76F8\u5BF9\u8DEF\u5F84`);
|
|
38350
39265
|
}
|
|
38351
39266
|
await this.assertInRoot(r.root, r.full, key);
|
|
39267
|
+
if (opts?.ifMatchEtag !== void 0 && opts.ifNoneMatch !== void 0) {
|
|
39268
|
+
throw new TBError("invalid_argument", "ifMatchEtag \u4E0E ifNoneMatch \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
39269
|
+
}
|
|
38352
39270
|
if (opts?.ifMatchEtag !== void 0) {
|
|
38353
39271
|
const existing = await this.head(key);
|
|
38354
39272
|
if (opts.ifMatchEtag !== existing?.etag) {
|
|
@@ -38357,7 +39275,14 @@ var FsObjectStore = class {
|
|
|
38357
39275
|
}
|
|
38358
39276
|
const bytes = await objectBodyToBytes(body);
|
|
38359
39277
|
await mkdir(dirname(r.full), { recursive: true });
|
|
38360
|
-
|
|
39278
|
+
try {
|
|
39279
|
+
await writeFile(r.full, bytes, opts?.ifNoneMatch === "*" ? { flag: "wx" } : void 0);
|
|
39280
|
+
} catch (e) {
|
|
39281
|
+
if (opts?.ifNoneMatch === "*" && isErrnoCode(e, "EEXIST")) {
|
|
39282
|
+
throw new TBError("conflict", `\u5BF9\u8C61\u5DF2\u5B58\u5728:'${key}'`);
|
|
39283
|
+
}
|
|
39284
|
+
throw e;
|
|
39285
|
+
}
|
|
38361
39286
|
const st = await stat(r.full);
|
|
38362
39287
|
return this.metaOf(r.key, st);
|
|
38363
39288
|
}
|
|
@@ -38491,9 +39416,14 @@ import { spawn as nodeSpawn } from "child_process";
|
|
|
38491
39416
|
var SHELL_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
38492
39417
|
|
|
38493
39418
|
// src/objects.ts
|
|
38494
|
-
import {
|
|
38495
|
-
import {
|
|
39419
|
+
import { dirname as dirname2, join as join2, sep as sep2 } from "path";
|
|
39420
|
+
import { randomUUID } from "crypto";
|
|
39421
|
+
import { Readable } from "stream";
|
|
38496
39422
|
var INTERNAL_ROOT = "objects";
|
|
39423
|
+
var TEMP_PREFIX = ".tb-object-upload-";
|
|
39424
|
+
var STORE_KEY_PREFIX = `${DEFAULT_STORE_DRIVER_KEY_ROOT}/`;
|
|
39425
|
+
var STORE_STAGING_DIR = ".tb-store-staging-v1";
|
|
39426
|
+
var UPLOAD_TEMP_NAME_RE = /^\.tb-object-upload-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.tmp$/i;
|
|
38497
39427
|
function toInternal(key) {
|
|
38498
39428
|
return `${INTERNAL_ROOT}/${key}`;
|
|
38499
39429
|
}
|
|
@@ -38503,6 +39433,108 @@ function toExternal(key) {
|
|
|
38503
39433
|
function externalMeta(meta) {
|
|
38504
39434
|
return { ...meta, key: toExternal(meta.key) };
|
|
38505
39435
|
}
|
|
39436
|
+
function isErrnoCode2(error, code) {
|
|
39437
|
+
return typeof error === "object" && error !== null && error.code === code;
|
|
39438
|
+
}
|
|
39439
|
+
function isUploadTempKey(key) {
|
|
39440
|
+
return key.split("/").some((segment) => segment.startsWith(TEMP_PREFIX));
|
|
39441
|
+
}
|
|
39442
|
+
async function writeChunk(handle, chunk) {
|
|
39443
|
+
let offset = 0;
|
|
39444
|
+
while (offset < chunk.byteLength) {
|
|
39445
|
+
const { bytesWritten } = await handle.write(chunk, offset, chunk.byteLength - offset, null);
|
|
39446
|
+
if (bytesWritten === 0) throw new Error("\u5BF9\u8C61\u4E34\u65F6\u6587\u4EF6\u5199\u5165\u672A\u53D6\u5F97\u8FDB\u5C55");
|
|
39447
|
+
offset += bytesWritten;
|
|
39448
|
+
}
|
|
39449
|
+
}
|
|
39450
|
+
async function writeStream(handle, stream) {
|
|
39451
|
+
const reader = stream.getReader();
|
|
39452
|
+
try {
|
|
39453
|
+
for (; ; ) {
|
|
39454
|
+
const { done, value } = await reader.read();
|
|
39455
|
+
if (done) break;
|
|
39456
|
+
if (value !== void 0 && value.byteLength > 0) await writeChunk(handle, value);
|
|
39457
|
+
}
|
|
39458
|
+
} catch (error) {
|
|
39459
|
+
try {
|
|
39460
|
+
await reader.cancel?.(error);
|
|
39461
|
+
} catch {
|
|
39462
|
+
}
|
|
39463
|
+
throw error;
|
|
39464
|
+
} finally {
|
|
39465
|
+
reader.releaseLock();
|
|
39466
|
+
}
|
|
39467
|
+
}
|
|
39468
|
+
async function writeBody(handle, body) {
|
|
39469
|
+
if (typeof body === "string") {
|
|
39470
|
+
await writeChunk(handle, Buffer.from(body));
|
|
39471
|
+
return;
|
|
39472
|
+
}
|
|
39473
|
+
if (body instanceof Uint8Array) {
|
|
39474
|
+
await writeChunk(handle, body);
|
|
39475
|
+
return;
|
|
39476
|
+
}
|
|
39477
|
+
if (body instanceof ArrayBuffer) {
|
|
39478
|
+
await writeChunk(handle, new Uint8Array(body));
|
|
39479
|
+
return;
|
|
39480
|
+
}
|
|
39481
|
+
await writeStream(handle, body);
|
|
39482
|
+
}
|
|
39483
|
+
async function assertParentInRoot(root, full, key) {
|
|
39484
|
+
const rootReal = await realpath2(root);
|
|
39485
|
+
const parentReal = await realpath2(dirname2(full));
|
|
39486
|
+
if (parentReal !== rootReal && !parentReal.startsWith(rootReal + sep2)) {
|
|
39487
|
+
throw new TBError("invalid_argument", `\u975E\u6CD5 entry \u8DEF\u5F84 '${key}':symlink \u9003\u9038\u6839\u76EE\u5F55`);
|
|
39488
|
+
}
|
|
39489
|
+
}
|
|
39490
|
+
async function assertAncestorInRoot(root, full, key) {
|
|
39491
|
+
const rootReal = await realpath2(root);
|
|
39492
|
+
let probe = dirname2(full);
|
|
39493
|
+
for (; ; ) {
|
|
39494
|
+
try {
|
|
39495
|
+
const ancestorReal = await realpath2(probe);
|
|
39496
|
+
if (ancestorReal !== rootReal && !ancestorReal.startsWith(rootReal + sep2)) {
|
|
39497
|
+
throw new TBError("invalid_argument", `\u975E\u6CD5 entry \u8DEF\u5F84 '${key}':symlink \u9003\u9038\u6839\u76EE\u5F55`);
|
|
39498
|
+
}
|
|
39499
|
+
return;
|
|
39500
|
+
} catch (error) {
|
|
39501
|
+
if (error instanceof TBError) throw error;
|
|
39502
|
+
if (!isErrnoCode2(error, "ENOENT")) throw error;
|
|
39503
|
+
const parent = dirname2(probe);
|
|
39504
|
+
if (parent === probe) {
|
|
39505
|
+
throw new TBError("invalid_argument", `\u975E\u6CD5 entry \u8DEF\u5F84 '${key}':symlink \u9003\u9038\u6839\u76EE\u5F55`);
|
|
39506
|
+
}
|
|
39507
|
+
probe = parent;
|
|
39508
|
+
}
|
|
39509
|
+
}
|
|
39510
|
+
}
|
|
39511
|
+
async function cleanupStagingTree(dir, cutoffMs) {
|
|
39512
|
+
let entries;
|
|
39513
|
+
try {
|
|
39514
|
+
entries = await readdir2(dir, { withFileTypes: true });
|
|
39515
|
+
} catch (error) {
|
|
39516
|
+
if (isErrnoCode2(error, "ENOENT")) return 0;
|
|
39517
|
+
throw error;
|
|
39518
|
+
}
|
|
39519
|
+
let deleted = 0;
|
|
39520
|
+
for (const entry of entries) {
|
|
39521
|
+
const path = join2(dir, entry.name);
|
|
39522
|
+
if (entry.isDirectory()) {
|
|
39523
|
+
deleted += await cleanupStagingTree(path, cutoffMs);
|
|
39524
|
+
continue;
|
|
39525
|
+
}
|
|
39526
|
+
if (!entry.isFile() || !UPLOAD_TEMP_NAME_RE.test(entry.name)) continue;
|
|
39527
|
+
try {
|
|
39528
|
+
const info = await stat2(path);
|
|
39529
|
+
if (info.mtimeMs > cutoffMs) continue;
|
|
39530
|
+
await rm2(path);
|
|
39531
|
+
deleted++;
|
|
39532
|
+
} catch (error) {
|
|
39533
|
+
if (!isErrnoCode2(error, "ENOENT")) throw error;
|
|
39534
|
+
}
|
|
39535
|
+
}
|
|
39536
|
+
return deleted;
|
|
39537
|
+
}
|
|
38506
39538
|
function createDataObjectStore(dataDir) {
|
|
38507
39539
|
const root = join2(dataDir, INTERNAL_ROOT);
|
|
38508
39540
|
mkdirSync(root, { recursive: true });
|
|
@@ -38513,11 +39545,77 @@ function createDataObjectStore(dataDir) {
|
|
|
38513
39545
|
return meta === null ? null : externalMeta(meta);
|
|
38514
39546
|
},
|
|
38515
39547
|
async get(key) {
|
|
38516
|
-
const
|
|
38517
|
-
|
|
39548
|
+
const normalizedKey = normalizeEntryPath(key);
|
|
39549
|
+
const meta = await fs.head(toInternal(normalizedKey));
|
|
39550
|
+
if (meta === null) return null;
|
|
39551
|
+
const finalPath = join2(root, ...normalizedKey.split("/"));
|
|
39552
|
+
let handle;
|
|
39553
|
+
try {
|
|
39554
|
+
handle = await open(finalPath, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
39555
|
+
} catch (error) {
|
|
39556
|
+
if (isErrnoCode2(error, "ENOENT")) return null;
|
|
39557
|
+
if (isErrnoCode2(error, "ELOOP")) {
|
|
39558
|
+
throw new TBError("invalid_argument", `\u975E\u6CD5 entry \u8DEF\u5F84 '${key}':symlink \u9003\u9038\u6839\u76EE\u5F55`);
|
|
39559
|
+
}
|
|
39560
|
+
throw error;
|
|
39561
|
+
}
|
|
39562
|
+
const body = Readable.toWeb(handle.createReadStream());
|
|
39563
|
+
return { meta: externalMeta(meta), body };
|
|
38518
39564
|
},
|
|
38519
39565
|
async put(key, body, opts) {
|
|
38520
|
-
|
|
39566
|
+
const normalizedKey = normalizeEntryPath(key);
|
|
39567
|
+
const internalKey = toInternal(normalizedKey);
|
|
39568
|
+
const finalPath = join2(root, ...normalizedKey.split("/"));
|
|
39569
|
+
const existing = await fs.head(internalKey);
|
|
39570
|
+
if (opts?.ifMatchEtag !== void 0 && opts.ifNoneMatch !== void 0) {
|
|
39571
|
+
throw new TBError("invalid_argument", "ifMatchEtag \u4E0E ifNoneMatch \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
39572
|
+
}
|
|
39573
|
+
if (opts?.ifMatchEtag !== void 0) {
|
|
39574
|
+
if (opts.ifMatchEtag !== existing?.etag) {
|
|
39575
|
+
throw new TBError("conflict", `etag \u4E0D\u5339\u914D:'${key}'`);
|
|
39576
|
+
}
|
|
39577
|
+
}
|
|
39578
|
+
await assertAncestorInRoot(root, finalPath, key);
|
|
39579
|
+
await mkdir2(dirname2(finalPath), { recursive: true });
|
|
39580
|
+
await assertParentInRoot(root, finalPath, key);
|
|
39581
|
+
const tempDir = normalizedKey.startsWith(STORE_KEY_PREFIX) ? join2(root, STORE_STAGING_DIR) : dirname2(finalPath);
|
|
39582
|
+
await assertAncestorInRoot(root, join2(tempDir, "staging-probe"), key);
|
|
39583
|
+
await mkdir2(tempDir, { recursive: true });
|
|
39584
|
+
const tempPath = join2(tempDir, `${TEMP_PREFIX}${randomUUID()}.tmp`);
|
|
39585
|
+
await assertParentInRoot(root, tempPath, key);
|
|
39586
|
+
let handle;
|
|
39587
|
+
try {
|
|
39588
|
+
handle = await open(tempPath, "wx");
|
|
39589
|
+
await writeBody(handle, body);
|
|
39590
|
+
await handle.sync();
|
|
39591
|
+
await handle.close();
|
|
39592
|
+
handle = void 0;
|
|
39593
|
+
if (opts?.ifNoneMatch === "*") {
|
|
39594
|
+
try {
|
|
39595
|
+
await link(tempPath, finalPath);
|
|
39596
|
+
} catch (error) {
|
|
39597
|
+
if (isErrnoCode2(error, "EEXIST")) {
|
|
39598
|
+
throw new TBError("conflict", `\u5BF9\u8C61\u5DF2\u5B58\u5728:'${key}'`);
|
|
39599
|
+
}
|
|
39600
|
+
throw error;
|
|
39601
|
+
}
|
|
39602
|
+
await rm2(tempPath);
|
|
39603
|
+
} else {
|
|
39604
|
+
await rename(tempPath, finalPath);
|
|
39605
|
+
}
|
|
39606
|
+
} catch (error) {
|
|
39607
|
+
if (handle !== void 0) {
|
|
39608
|
+
try {
|
|
39609
|
+
await handle.close();
|
|
39610
|
+
} catch {
|
|
39611
|
+
}
|
|
39612
|
+
}
|
|
39613
|
+
await rm2(tempPath, { force: true });
|
|
39614
|
+
throw error;
|
|
39615
|
+
}
|
|
39616
|
+
const meta = await fs.head(internalKey);
|
|
39617
|
+
if (meta === null) throw new TBError("unavailable", `\u5BF9\u8C61\u63D0\u4EA4\u540E\u4E0D\u53EF\u89C1:'${key}'`);
|
|
39618
|
+
return externalMeta(meta);
|
|
38521
39619
|
},
|
|
38522
39620
|
async delete(key) {
|
|
38523
39621
|
await fs.delete(toInternal(key));
|
|
@@ -38527,9 +39625,24 @@ function createDataObjectStore(dataDir) {
|
|
|
38527
39625
|
return {
|
|
38528
39626
|
items: result.items.map(
|
|
38529
39627
|
(item) => "prefix" in item ? { prefix: toExternal(item.prefix) } : externalMeta(item)
|
|
38530
|
-
),
|
|
39628
|
+
).filter((item) => !isUploadTempKey("prefix" in item ? item.prefix : item.key)),
|
|
38531
39629
|
...result.cursor !== void 0 ? { cursor: result.cursor } : {}
|
|
38532
39630
|
};
|
|
39631
|
+
},
|
|
39632
|
+
async cleanupStaging(prefix, olderThan) {
|
|
39633
|
+
const cutoffMs = Date.parse(olderThan);
|
|
39634
|
+
if (!Number.isFinite(cutoffMs)) {
|
|
39635
|
+
throw new TBError("invalid_argument", "cleanupStaging olderThan \u5FC5\u987B\u662F ISO timestamp");
|
|
39636
|
+
}
|
|
39637
|
+
const normalizedPrefix = normalizeEntryPath(prefix.replace(/\/+$/, ""));
|
|
39638
|
+
const isDefaultStore = normalizedPrefix === STORE_KEY_PREFIX.slice(0, -1);
|
|
39639
|
+
const prefixDir = isDefaultStore ? join2(root, STORE_STAGING_DIR) : join2(root, ...normalizedPrefix.split("/"));
|
|
39640
|
+
await assertAncestorInRoot(root, join2(prefixDir, "staging-probe"), prefix);
|
|
39641
|
+
if (isDefaultStore) {
|
|
39642
|
+
await mkdir2(prefixDir, { recursive: true });
|
|
39643
|
+
await assertParentInRoot(root, join2(prefixDir, "staging-probe"), prefix);
|
|
39644
|
+
}
|
|
39645
|
+
return await cleanupStagingTree(prefixDir, cutoffMs);
|
|
38533
39646
|
}
|
|
38534
39647
|
};
|
|
38535
39648
|
}
|
|
@@ -38652,6 +39765,29 @@ var PgStateStore = class {
|
|
|
38652
39765
|
ON CONFLICT (key) DO UPDATE SET value = excluded.value
|
|
38653
39766
|
`;
|
|
38654
39767
|
}
|
|
39768
|
+
async compareAndSwap(key, expectedRevision, value) {
|
|
39769
|
+
if (expectedRevision === null) {
|
|
39770
|
+
if (value === null) return false;
|
|
39771
|
+
const result2 = await this.sql`
|
|
39772
|
+
INSERT INTO tb_kv (key, value) VALUES (${key}, ${this.sql.json(value)})
|
|
39773
|
+
ON CONFLICT (key) DO NOTHING
|
|
39774
|
+
`;
|
|
39775
|
+
return result2.count > 0;
|
|
39776
|
+
}
|
|
39777
|
+
if (!Number.isInteger(expectedRevision) || expectedRevision < 0) return false;
|
|
39778
|
+
const predicate = this.sql`
|
|
39779
|
+
key = ${key}
|
|
39780
|
+
AND jsonb_typeof(value) = 'object'
|
|
39781
|
+
AND jsonb_typeof(value -> 'revision') = 'number'
|
|
39782
|
+
AND (value ->> 'revision') ~ '^(0|[1-9][0-9]*)$'
|
|
39783
|
+
AND (value ->> 'revision')::numeric = ${expectedRevision}
|
|
39784
|
+
`;
|
|
39785
|
+
const result = value === null ? await this.sql`DELETE FROM tb_kv WHERE ${predicate}` : await this.sql`
|
|
39786
|
+
UPDATE tb_kv SET value = ${this.sql.json(value)}
|
|
39787
|
+
WHERE ${predicate}
|
|
39788
|
+
`;
|
|
39789
|
+
return result.count > 0;
|
|
39790
|
+
}
|
|
38655
39791
|
async putIfAbsent(key, value) {
|
|
38656
39792
|
const result = await this.sql`
|
|
38657
39793
|
INSERT INTO tb_kv (key, value) VALUES (${key}, ${this.sql.json(value)})
|
|
@@ -38834,6 +39970,20 @@ var SqliteStateStore = class {
|
|
|
38834
39970
|
async put(key, value) {
|
|
38835
39971
|
this.stmtPut.run(key, JSON.stringify(value));
|
|
38836
39972
|
}
|
|
39973
|
+
async compareAndSwap(key, expectedRevision, value) {
|
|
39974
|
+
if (expectedRevision === null) {
|
|
39975
|
+
if (value === null) return false;
|
|
39976
|
+
const info2 = this.db.prepare("INSERT OR IGNORE INTO kv (key, value) VALUES (?, ?)").run(key, JSON.stringify(value));
|
|
39977
|
+
return info2.changes > 0;
|
|
39978
|
+
}
|
|
39979
|
+
if (!Number.isInteger(expectedRevision) || expectedRevision < 0) return false;
|
|
39980
|
+
const predicate = `key = ?
|
|
39981
|
+
AND json_type(value) = 'object'
|
|
39982
|
+
AND json_type(value, '$.revision') = 'integer'
|
|
39983
|
+
AND json_extract(value, '$.revision') = ?`;
|
|
39984
|
+
const info = value === null ? this.db.prepare(`DELETE FROM kv WHERE ${predicate}`).run(key, expectedRevision) : this.db.prepare(`UPDATE kv SET value = ? WHERE ${predicate}`).run(JSON.stringify(value), key, expectedRevision);
|
|
39985
|
+
return info.changes > 0;
|
|
39986
|
+
}
|
|
38837
39987
|
async putIfAbsent(key, value) {
|
|
38838
39988
|
const info = this.db.prepare("INSERT OR IGNORE INTO kv (key, value) VALUES (?, ?)").run(key, JSON.stringify(value));
|
|
38839
39989
|
return info.changes > 0;
|
|
@@ -38881,7 +40031,7 @@ import { join as join4 } from "path";
|
|
|
38881
40031
|
// package.json
|
|
38882
40032
|
var package_default = {
|
|
38883
40033
|
name: "@tool-bridge/server",
|
|
38884
|
-
version: "0.
|
|
40034
|
+
version: "0.17.0",
|
|
38885
40035
|
description: "tool-bridge self-hosted server: run the HTBP gateway on Node with SQLite or PostgreSQL persistence, filesystem object storage and WebSocket device channel \u2014 single container via docker run",
|
|
38886
40036
|
type: "module",
|
|
38887
40037
|
license: "MIT",
|
|
@@ -38954,7 +40104,7 @@ var package_default = {
|
|
|
38954
40104
|
|
|
38955
40105
|
// src/assets.ts
|
|
38956
40106
|
import { brotliCompressSync, gzipSync, constants as zlibConstants } from "zlib";
|
|
38957
|
-
import { dirname as
|
|
40107
|
+
import { dirname as dirname3, join as join3, resolve as resolve2, sep as sep3 } from "path";
|
|
38958
40108
|
import { readFile as readFile2 } from "fs/promises";
|
|
38959
40109
|
import { createRequire } from "module";
|
|
38960
40110
|
import { existsSync } from "fs";
|
|
@@ -38987,7 +40137,7 @@ function resolveUiDir(uiDirOverride) {
|
|
|
38987
40137
|
try {
|
|
38988
40138
|
const require2 = createRequire(import.meta.url);
|
|
38989
40139
|
const pkgPath = require2.resolve("@tool-bridge/dashboard/package.json");
|
|
38990
|
-
const dist = join3(
|
|
40140
|
+
const dist = join3(dirname3(pkgPath), "dist");
|
|
38991
40141
|
return existsSync(join3(dist, "index.html")) ? dist : void 0;
|
|
38992
40142
|
} catch {
|
|
38993
40143
|
return void 0;
|
|
@@ -39014,7 +40164,7 @@ function uiAssetsFetcher(uiDir) {
|
|
|
39014
40164
|
let pathname = decodeURIComponent(url2.pathname);
|
|
39015
40165
|
if (pathname.endsWith("/")) pathname += "index.html";
|
|
39016
40166
|
const full = resolve2(join3(root, pathname));
|
|
39017
|
-
if (full !== root && !full.startsWith(root +
|
|
40167
|
+
if (full !== root && !full.startsWith(root + sep3)) {
|
|
39018
40168
|
return new Response("not found", { status: 404 });
|
|
39019
40169
|
}
|
|
39020
40170
|
let asset = cache.get(full);
|
|
@@ -39063,6 +40213,7 @@ function resolveUiAssets(uiDirOverride) {
|
|
|
39063
40213
|
}
|
|
39064
40214
|
|
|
39065
40215
|
// src/server.ts
|
|
40216
|
+
var providerOAuthFetch = createGuardedFetch({ crossOriginRedirect: "error" });
|
|
39066
40217
|
function pgBackends(databaseUrl) {
|
|
39067
40218
|
const sql = postgres(databaseUrl, { onnotice: () => {
|
|
39068
40219
|
} });
|
|
@@ -39176,6 +40327,7 @@ function createTbServer(config) {
|
|
|
39176
40327
|
const deps = {
|
|
39177
40328
|
state,
|
|
39178
40329
|
secrets,
|
|
40330
|
+
providerOAuthFetch,
|
|
39179
40331
|
version: package_default.version,
|
|
39180
40332
|
remote: config.remote,
|
|
39181
40333
|
search,
|
|
@@ -39196,8 +40348,49 @@ function createTbServer(config) {
|
|
|
39196
40348
|
if (config.uploadGrantTtlSec !== void 0) {
|
|
39197
40349
|
deps.uploadGrantTtlSec = config.uploadGrantTtlSec;
|
|
39198
40350
|
}
|
|
40351
|
+
if (config.storeTokenSecret !== void 0) deps.storeTokenSecret = config.storeTokenSecret;
|
|
40352
|
+
if (config.storeMaxObjectBytes !== void 0) {
|
|
40353
|
+
deps.storeMaxObjectBytes = config.storeMaxObjectBytes;
|
|
40354
|
+
}
|
|
40355
|
+
if (config.storeRelayMaxBytes !== void 0) {
|
|
40356
|
+
deps.storeRelayMaxBytes = config.storeRelayMaxBytes;
|
|
40357
|
+
}
|
|
40358
|
+
if (config.storeUploadTtlSec !== void 0) deps.storeUploadTtlSec = config.storeUploadTtlSec;
|
|
40359
|
+
if (config.storeShareTtlSec !== void 0) deps.storeShareTtlSec = config.storeShareTtlSec;
|
|
40360
|
+
if (config.storeReadTtlSec !== void 0) deps.storeReadTtlSec = config.storeReadTtlSec;
|
|
40361
|
+
if (config.storeCallMaxBytes !== void 0) deps.storeCallMaxBytes = config.storeCallMaxBytes;
|
|
40362
|
+
if (config.storeCallMaxObjectBytes !== void 0) {
|
|
40363
|
+
deps.storeCallMaxObjectBytes = config.storeCallMaxObjectBytes;
|
|
40364
|
+
}
|
|
40365
|
+
if (config.storeCallMaxObjects !== void 0) {
|
|
40366
|
+
deps.storeCallMaxObjects = config.storeCallMaxObjects;
|
|
40367
|
+
}
|
|
40368
|
+
if (config.storeCallAllowedContentTypes !== void 0) {
|
|
40369
|
+
deps.storeCallAllowedContentTypes = config.storeCallAllowedContentTypes;
|
|
40370
|
+
}
|
|
39199
40371
|
const app = createTbApp(deps);
|
|
39200
40372
|
let server;
|
|
40373
|
+
let storeCleanupTimer;
|
|
40374
|
+
let storeCleanupInFlight = false;
|
|
40375
|
+
const runStoreCleanup = async () => {
|
|
40376
|
+
if (storeCleanupInFlight) return;
|
|
40377
|
+
storeCleanupInFlight = true;
|
|
40378
|
+
try {
|
|
40379
|
+
await cleanupDefaultStore(deps);
|
|
40380
|
+
} finally {
|
|
40381
|
+
storeCleanupInFlight = false;
|
|
40382
|
+
}
|
|
40383
|
+
};
|
|
40384
|
+
const reportStoreCleanupFailure = () => {
|
|
40385
|
+
console.warn(JSON.stringify({ event: "tool_bridge_store_cleanup_failed" }));
|
|
40386
|
+
};
|
|
40387
|
+
const scheduleStoreCleanup = () => {
|
|
40388
|
+
void runStoreCleanup().catch(reportStoreCleanupFailure);
|
|
40389
|
+
storeCleanupTimer = setInterval(() => {
|
|
40390
|
+
void runStoreCleanup().catch(reportStoreCleanupFailure);
|
|
40391
|
+
}, config.storeCleanupIntervalSec * 1e3);
|
|
40392
|
+
storeCleanupTimer.unref?.();
|
|
40393
|
+
};
|
|
39201
40394
|
return {
|
|
39202
40395
|
app,
|
|
39203
40396
|
search,
|
|
@@ -39214,6 +40407,7 @@ function createTbServer(config) {
|
|
|
39214
40407
|
await hub.sweepOrphans();
|
|
39215
40408
|
return await new Promise((resolve3) => {
|
|
39216
40409
|
server = serve({ fetch: app.fetch, port: config.port, hostname: config.host }, (info) => {
|
|
40410
|
+
scheduleStoreCleanup();
|
|
39217
40411
|
resolve3({ port: info.port });
|
|
39218
40412
|
});
|
|
39219
40413
|
hub.attach(server);
|
|
@@ -39224,6 +40418,10 @@ function createTbServer(config) {
|
|
|
39224
40418
|
},
|
|
39225
40419
|
async close() {
|
|
39226
40420
|
draining = true;
|
|
40421
|
+
if (storeCleanupTimer !== void 0) {
|
|
40422
|
+
clearInterval(storeCleanupTimer);
|
|
40423
|
+
storeCleanupTimer = void 0;
|
|
40424
|
+
}
|
|
39227
40425
|
let closed;
|
|
39228
40426
|
if (server !== void 0) {
|
|
39229
40427
|
const s = server;
|