target-supabase-sdk 0.1.9 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/README.md +184 -1
  2. package/dist/browser.d.ts +60 -0
  3. package/dist/browser.d.ts.map +1 -0
  4. package/dist/browser.js +6 -0
  5. package/dist/browser.js.map +1 -0
  6. package/dist/chunks/create-logger-DyH3mZ8p.js +1028 -0
  7. package/dist/chunks/create-logger-DyH3mZ8p.js.map +1 -0
  8. package/dist/chunks/enable-log-persist-C_bSw6Kx.js +1362 -0
  9. package/dist/chunks/enable-log-persist-C_bSw6Kx.js.map +1 -0
  10. package/dist/chunks/word.interface-DLgRobKV.js +1973 -0
  11. package/dist/chunks/word.interface-DLgRobKV.js.map +1 -0
  12. package/dist/command/command.api.d.ts +1 -1
  13. package/dist/command/command.api.d.ts.map +1 -1
  14. package/dist/command/command.interface.d.ts +1 -1
  15. package/dist/command/command.interface.d.ts.map +1 -1
  16. package/dist/core.api.d.ts +10 -6
  17. package/dist/core.api.d.ts.map +1 -1
  18. package/dist/core.interface.d.ts +3 -2
  19. package/dist/core.interface.d.ts.map +1 -1
  20. package/dist/core.utils.d.ts +1 -1
  21. package/dist/core.utils.d.ts.map +1 -1
  22. package/dist/idea/idea.interface.d.ts +1 -1
  23. package/dist/idea/idea.interface.d.ts.map +1 -1
  24. package/dist/index.d.ts +2 -48
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/link/link.api.d.ts +1 -1
  27. package/dist/link/link.api.d.ts.map +1 -1
  28. package/dist/link/link.interface.d.ts +3 -3
  29. package/dist/link/link.interface.d.ts.map +1 -1
  30. package/dist/list/list.api.d.ts +3 -1
  31. package/dist/list/list.api.d.ts.map +1 -1
  32. package/dist/list/list.interface.d.ts +2 -2
  33. package/dist/list/list.interface.d.ts.map +1 -1
  34. package/dist/node/env/env-parsers.d.ts +19 -0
  35. package/dist/node/env/env-parsers.d.ts.map +1 -0
  36. package/dist/node/env/index.d.ts +11 -0
  37. package/dist/node/env/index.d.ts.map +1 -0
  38. package/dist/node/env/init-supabase-from-env.d.ts +17 -0
  39. package/dist/node/env/init-supabase-from-env.d.ts.map +1 -0
  40. package/dist/node/env/load-env.d.ts +20 -0
  41. package/dist/node/env/load-env.d.ts.map +1 -0
  42. package/dist/node/env/project-root.d.ts +11 -0
  43. package/dist/node/env/project-root.d.ts.map +1 -0
  44. package/dist/node/env/public-base-url.d.ts +10 -0
  45. package/dist/node/env/public-base-url.d.ts.map +1 -0
  46. package/dist/node/env/require-env.d.ts +3 -0
  47. package/dist/node/env/require-env.d.ts.map +1 -0
  48. package/dist/node/fs/json-state-store.d.ts +19 -0
  49. package/dist/node/fs/json-state-store.d.ts.map +1 -0
  50. package/dist/node/fs/read-source-file.d.ts +19 -0
  51. package/dist/node/fs/read-source-file.d.ts.map +1 -0
  52. package/dist/node/node-liveness.d.ts +30 -0
  53. package/dist/node/node-liveness.d.ts.map +1 -0
  54. package/dist/node/node-runtime.base.d.ts +60 -0
  55. package/dist/node/node-runtime.base.d.ts.map +1 -0
  56. package/dist/node/node.api.d.ts +4 -4
  57. package/dist/node/node.api.d.ts.map +1 -1
  58. package/dist/node/node.interface.d.ts +1 -6
  59. package/dist/node/node.interface.d.ts.map +1 -1
  60. package/dist/node/preload/run-service-preload.d.ts +14 -0
  61. package/dist/node/preload/run-service-preload.d.ts.map +1 -0
  62. package/dist/node/preload/service-preload.interface.d.ts +15 -0
  63. package/dist/node/preload/service-preload.interface.d.ts.map +1 -0
  64. package/dist/node/process/index.d.ts +5 -0
  65. package/dist/node/process/index.d.ts.map +1 -0
  66. package/dist/node/process/managed-child-processes.d.ts +37 -0
  67. package/dist/node/process/managed-child-processes.d.ts.map +1 -0
  68. package/dist/node/process/process-spawn.d.ts +27 -0
  69. package/dist/node/process/process-spawn.d.ts.map +1 -0
  70. package/dist/node/readiness/index.d.ts +9 -0
  71. package/dist/node/readiness/index.d.ts.map +1 -0
  72. package/dist/node/readiness/poll-until.d.ts +11 -0
  73. package/dist/node/readiness/poll-until.d.ts.map +1 -0
  74. package/dist/node/readiness/readiness-checks.d.ts +22 -0
  75. package/dist/node/readiness/readiness-checks.d.ts.map +1 -0
  76. package/dist/node/readiness/readiness.types.d.ts +12 -0
  77. package/dist/node/readiness/readiness.types.d.ts.map +1 -0
  78. package/dist/node/readiness/run-readiness-checks.d.ts +4 -0
  79. package/dist/node/readiness/run-readiness-checks.d.ts.map +1 -0
  80. package/dist/node/readiness/service-ready-gate.d.ts +26 -0
  81. package/dist/node/readiness/service-ready-gate.d.ts.map +1 -0
  82. package/dist/node.d.ts +36 -0
  83. package/dist/node.d.ts.map +1 -0
  84. package/dist/node.js +2483 -0
  85. package/dist/node.js.map +1 -0
  86. package/dist/parcel/chunk-fetch-registry.d.ts +14 -0
  87. package/dist/parcel/chunk-fetch-registry.d.ts.map +1 -0
  88. package/dist/parcel/chunk-url.utils.d.ts +9 -0
  89. package/dist/parcel/chunk-url.utils.d.ts.map +1 -0
  90. package/dist/parcel/parcel-manager.d.ts +44 -20
  91. package/dist/parcel/parcel-manager.d.ts.map +1 -1
  92. package/dist/parcel/parcel.api.d.ts +306 -0
  93. package/dist/parcel/parcel.api.d.ts.map +1 -0
  94. package/dist/parcel/parcel.interface.d.ts +26 -5
  95. package/dist/parcel/parcel.interface.d.ts.map +1 -1
  96. package/dist/parcel/parcel.service.d.ts +38 -0
  97. package/dist/parcel/parcel.service.d.ts.map +1 -0
  98. package/dist/parcel/storage-provider-registry.d.ts +17 -0
  99. package/dist/parcel/storage-provider-registry.d.ts.map +1 -0
  100. package/dist/parcel/storage-provider.types.d.ts +31 -0
  101. package/dist/parcel/storage-provider.types.d.ts.map +1 -0
  102. package/dist/preload.d.ts +7 -0
  103. package/dist/preload.d.ts.map +1 -0
  104. package/dist/preload.js +47 -0
  105. package/dist/preload.js.map +1 -0
  106. package/dist/repo/repo-context.utils.d.ts.map +1 -1
  107. package/dist/repo/repo-manager.d.ts +14 -3
  108. package/dist/repo/repo-manager.d.ts.map +1 -1
  109. package/dist/repo/repo.api.d.ts +1 -1
  110. package/dist/repo/repo.api.d.ts.map +1 -1
  111. package/dist/repo/repo.interface.d.ts +1 -1
  112. package/dist/repo/repo.interface.d.ts.map +1 -1
  113. package/dist/repo/repo.script-loader.d.ts +5 -5
  114. package/dist/repo/repo.script-loader.d.ts.map +1 -1
  115. package/dist/service/base.interface.d.ts +54 -57
  116. package/dist/service/base.interface.d.ts.map +1 -1
  117. package/dist/service/index.d.ts +21 -0
  118. package/dist/service/index.d.ts.map +1 -0
  119. package/dist/service/service.api.d.ts +503 -0
  120. package/dist/service/service.api.d.ts.map +1 -0
  121. package/dist/service/service.interface.d.ts +36 -9
  122. package/dist/service/service.interface.d.ts.map +1 -1
  123. package/dist/shared/http/fetch-retry.d.ts +21 -0
  124. package/dist/shared/http/fetch-retry.d.ts.map +1 -0
  125. package/dist/shared/log/create-logger.d.ts +27 -0
  126. package/dist/shared/log/create-logger.d.ts.map +1 -0
  127. package/dist/shared/log/enable-log-persist.d.ts +28 -0
  128. package/dist/shared/log/enable-log-persist.d.ts.map +1 -0
  129. package/dist/shared/log/index.d.ts +10 -0
  130. package/dist/shared/log/index.d.ts.map +1 -0
  131. package/dist/shared/log/log-manager.d.ts +37 -60
  132. package/dist/shared/log/log-manager.d.ts.map +1 -1
  133. package/dist/shared/log/log-persist-batch-id.d.ts +13 -0
  134. package/dist/shared/log/log-persist-batch-id.d.ts.map +1 -0
  135. package/dist/shared/log/log-persist-flush.d.ts +8 -0
  136. package/dist/shared/log/log-persist-flush.d.ts.map +1 -0
  137. package/dist/shared/log/log-persist-hook.d.ts +6 -0
  138. package/dist/shared/log/log-persist-hook.d.ts.map +1 -0
  139. package/dist/shared/log/log-persist-logger.d.ts +15 -0
  140. package/dist/shared/log/log-persist-logger.d.ts.map +1 -0
  141. package/dist/shared/log/log-persist-registry.d.ts +17 -0
  142. package/dist/shared/log/log-persist-registry.d.ts.map +1 -0
  143. package/dist/shared/log/log-persist.config.d.ts +10 -0
  144. package/dist/shared/log/log-persist.config.d.ts.map +1 -0
  145. package/dist/shared/log/log-persist.d.ts +55 -0
  146. package/dist/shared/log/log-persist.d.ts.map +1 -0
  147. package/dist/shared/log/log-persist.interface.d.ts +116 -0
  148. package/dist/shared/log/log-persist.interface.d.ts.map +1 -0
  149. package/dist/shared/log/log-scope.d.ts +56 -0
  150. package/dist/shared/log/log-scope.d.ts.map +1 -0
  151. package/dist/shared/utils/fetch-url.d.ts +3 -0
  152. package/dist/shared/utils/fetch-url.d.ts.map +1 -0
  153. package/dist/shared/utils/network-error.d.ts +14 -0
  154. package/dist/shared/utils/network-error.d.ts.map +1 -0
  155. package/dist/shared/utils/safe-file-name.d.ts +14 -0
  156. package/dist/shared/utils/safe-file-name.d.ts.map +1 -0
  157. package/dist/shared/utils/sha256.d.ts +3 -0
  158. package/dist/shared/utils/sha256.d.ts.map +1 -0
  159. package/dist/supabase.d.ts +7 -2
  160. package/dist/supabase.d.ts.map +1 -1
  161. package/dist/task/index.d.ts +16 -0
  162. package/dist/task/index.d.ts.map +1 -0
  163. package/dist/task/local-task-registry.d.ts +11 -1
  164. package/dist/task/local-task-registry.d.ts.map +1 -1
  165. package/dist/task/task-manager.d.ts +21 -11
  166. package/dist/task/task-manager.d.ts.map +1 -1
  167. package/dist/task/task-node.d.ts +19 -0
  168. package/dist/task/task-node.d.ts.map +1 -0
  169. package/dist/task/task-post-validated.api.d.ts +19 -0
  170. package/dist/task/task-post-validated.api.d.ts.map +1 -0
  171. package/dist/task/task-post.api.d.ts +54 -0
  172. package/dist/task/task-post.api.d.ts.map +1 -0
  173. package/dist/task/task-queue.d.ts +7 -0
  174. package/dist/task/task-queue.d.ts.map +1 -0
  175. package/dist/task/task-repo-context.d.ts +2 -0
  176. package/dist/task/task-repo-context.d.ts.map +1 -1
  177. package/dist/task/task-repo-validation.d.ts +46 -0
  178. package/dist/task/task-repo-validation.d.ts.map +1 -0
  179. package/dist/task/task.api.d.ts +5 -47
  180. package/dist/task/task.api.d.ts.map +1 -1
  181. package/dist/task/task.constant.d.ts +4 -0
  182. package/dist/task/task.constant.d.ts.map +1 -0
  183. package/dist/task/task.interface.d.ts +3 -1
  184. package/dist/task/task.interface.d.ts.map +1 -1
  185. package/dist/trigger/trigger-manager.d.ts +25 -0
  186. package/dist/trigger/trigger-manager.d.ts.map +1 -0
  187. package/dist/trigger/trigger-node.d.ts +23 -0
  188. package/dist/trigger/trigger-node.d.ts.map +1 -0
  189. package/dist/trigger/trigger.api.d.ts +140 -0
  190. package/dist/trigger/trigger.api.d.ts.map +1 -0
  191. package/dist/trigger/trigger.constant.d.ts +8 -0
  192. package/dist/trigger/trigger.constant.d.ts.map +1 -0
  193. package/dist/trigger/trigger.interface.d.ts +87 -0
  194. package/dist/trigger/trigger.interface.d.ts.map +1 -0
  195. package/dist/trigger/trigger.utils.d.ts +6 -0
  196. package/dist/trigger/trigger.utils.d.ts.map +1 -0
  197. package/dist/word/word.api.d.ts +1 -1
  198. package/dist/word/word.api.d.ts.map +1 -1
  199. package/dist/word/word.interface.d.ts +2 -2
  200. package/dist/word/word.interface.d.ts.map +1 -1
  201. package/package.json +91 -61
  202. package/src/browser.ts +165 -0
  203. package/src/command/command.api.ts +20 -18
  204. package/src/command/command.interface.ts +2 -3
  205. package/src/core.api.ts +466 -477
  206. package/src/core.interface.ts +63 -62
  207. package/src/core.utils.ts +64 -64
  208. package/src/idea/idea.interface.ts +3 -3
  209. package/src/index.ts +2 -79
  210. package/src/link/link.api.ts +28 -30
  211. package/src/link/link.interface.ts +4 -5
  212. package/src/list/list.api.ts +50 -29
  213. package/src/list/list.interface.ts +3 -4
  214. package/src/node/env/env-parsers.ts +77 -0
  215. package/src/node/env/index.ts +10 -0
  216. package/src/node/env/init-supabase-from-env.ts +38 -0
  217. package/src/node/env/load-env.ts +67 -0
  218. package/src/node/env/project-root.ts +34 -0
  219. package/src/node/env/public-base-url.ts +18 -0
  220. package/src/node/env/require-env.ts +15 -0
  221. package/src/node/fs/json-state-store.ts +97 -0
  222. package/src/node/fs/read-source-file.ts +75 -0
  223. package/src/node/node-liveness.ts +80 -0
  224. package/src/node/node-runtime.base.ts +481 -0
  225. package/src/node/node.api.ts +12 -11
  226. package/src/node/node.interface.ts +1 -8
  227. package/src/node/node.utils.ts +1 -1
  228. package/src/node/preload/run-service-preload.ts +48 -0
  229. package/src/node/preload/service-preload.interface.ts +14 -0
  230. package/src/node/process/index.ts +8 -0
  231. package/src/node/process/managed-child-processes.ts +121 -0
  232. package/src/node/process/process-spawn.ts +61 -0
  233. package/src/node/readiness/index.ts +20 -0
  234. package/src/node/readiness/poll-until.ts +27 -0
  235. package/src/node/readiness/readiness-checks.ts +79 -0
  236. package/src/node/readiness/readiness.types.ts +13 -0
  237. package/src/node/readiness/run-readiness-checks.ts +20 -0
  238. package/src/node/readiness/service-ready-gate.ts +65 -0
  239. package/src/node.ts +153 -0
  240. package/src/parcel/chunk-fetch-registry.ts +96 -0
  241. package/src/parcel/chunk-url.utils.ts +30 -0
  242. package/src/parcel/parcel-manager.ts +431 -173
  243. package/src/parcel/parcel.api.ts +103 -0
  244. package/src/parcel/parcel.interface.ts +44 -23
  245. package/src/parcel/parcel.service.ts +79 -0
  246. package/src/parcel/storage-provider-registry.ts +49 -0
  247. package/src/parcel/storage-provider.types.ts +45 -0
  248. package/src/preload.ts +7 -0
  249. package/src/repo/repo-context.utils.ts +3 -4
  250. package/src/repo/repo-manager.ts +54 -39
  251. package/src/repo/repo.api.ts +5 -5
  252. package/src/repo/repo.interface.ts +1 -2
  253. package/src/repo/repo.script-loader.ts +16 -20
  254. package/src/service/base.interface.ts +81 -90
  255. package/src/service/index.ts +173 -0
  256. package/src/service/service.api.ts +294 -0
  257. package/src/service/service.interface.ts +49 -17
  258. package/src/shared/http/fetch-retry.ts +145 -0
  259. package/src/shared/log/create-logger.ts +51 -0
  260. package/src/shared/log/enable-log-persist.ts +225 -0
  261. package/src/shared/log/index.ts +31 -0
  262. package/src/shared/log/log-manager.ts +112 -121
  263. package/src/shared/log/log-persist-batch-id.ts +43 -0
  264. package/src/shared/log/log-persist-flush.ts +128 -0
  265. package/src/shared/log/log-persist-hook.ts +13 -0
  266. package/src/shared/log/log-persist-logger.ts +33 -0
  267. package/src/shared/log/log-persist-registry.ts +109 -0
  268. package/src/shared/log/log-persist.config.ts +97 -0
  269. package/src/shared/log/log-persist.interface.ts +132 -0
  270. package/src/shared/log/log-persist.ts +704 -0
  271. package/src/shared/log/log-scope.ts +123 -0
  272. package/src/shared/utils/config-path.utils.ts +1 -1
  273. package/src/shared/utils/fetch-url.ts +13 -0
  274. package/src/shared/utils/network-error.ts +152 -0
  275. package/src/shared/utils/safe-file-name.ts +37 -0
  276. package/src/shared/utils/sha256.ts +15 -0
  277. package/src/supabase.ts +125 -119
  278. package/src/task/index.ts +45 -0
  279. package/src/task/local-task-registry.ts +115 -36
  280. package/src/task/task-manager.ts +101 -113
  281. package/src/task/task-node.ts +302 -0
  282. package/src/task/task-post-validated.api.ts +47 -0
  283. package/src/task/task-post.api.ts +99 -0
  284. package/src/task/task-queue.ts +18 -0
  285. package/src/task/task-repo-context.ts +4 -1
  286. package/src/task/task-repo-validation.ts +169 -0
  287. package/src/task/task.api.ts +68 -92
  288. package/src/task/task.constant.ts +4 -0
  289. package/src/task/task.interface.ts +6 -7
  290. package/src/trigger/trigger-manager.ts +287 -0
  291. package/src/trigger/trigger-node.ts +80 -0
  292. package/src/trigger/trigger.api.ts +166 -0
  293. package/src/trigger/trigger.constant.ts +10 -0
  294. package/src/trigger/trigger.interface.ts +100 -0
  295. package/src/trigger/trigger.utils.ts +56 -0
  296. package/src/word/word.api.ts +28 -30
  297. package/src/word/word.interface.ts +3 -4
  298. package/dist/auth/auth.api.d.ts +0 -28
  299. package/dist/auth/auth.api.d.ts.map +0 -1
  300. package/dist/auth/auth.api.js +0 -51
  301. package/dist/auth/auth.api.js.map +0 -1
  302. package/dist/command/command.api.js +0 -58
  303. package/dist/command/command.api.js.map +0 -1
  304. package/dist/command/command.interface.js +0 -9
  305. package/dist/command/command.interface.js.map +0 -1
  306. package/dist/core.api.js +0 -412
  307. package/dist/core.api.js.map +0 -1
  308. package/dist/core.interface.js +0 -46
  309. package/dist/core.interface.js.map +0 -1
  310. package/dist/core.utils.js +0 -81
  311. package/dist/core.utils.js.map +0 -1
  312. package/dist/feed/feed.interface.d.ts +0 -27
  313. package/dist/feed/feed.interface.d.ts.map +0 -1
  314. package/dist/feed/feed.interface.js +0 -17
  315. package/dist/feed/feed.interface.js.map +0 -1
  316. package/dist/file/file-manager.d.ts +0 -24
  317. package/dist/file/file-manager.d.ts.map +0 -1
  318. package/dist/file/file-manager.js +0 -109
  319. package/dist/file/file-manager.js.map +0 -1
  320. package/dist/file/file.api.d.ts +0 -15
  321. package/dist/file/file.api.d.ts.map +0 -1
  322. package/dist/file/file.api.js +0 -30
  323. package/dist/file/file.api.js.map +0 -1
  324. package/dist/file/file.interface.d.ts +0 -25
  325. package/dist/file/file.interface.d.ts.map +0 -1
  326. package/dist/file/file.interface.js +0 -9
  327. package/dist/file/file.interface.js.map +0 -1
  328. package/dist/file-list/file-list.api.d.ts +0 -15
  329. package/dist/file-list/file-list.api.d.ts.map +0 -1
  330. package/dist/file-list/file-list.api.js +0 -54
  331. package/dist/file-list/file-list.api.js.map +0 -1
  332. package/dist/file-list/file-list.interface.d.ts +0 -22
  333. package/dist/file-list/file-list.interface.d.ts.map +0 -1
  334. package/dist/file-list/file-list.interface.js +0 -5
  335. package/dist/file-list/file-list.interface.js.map +0 -1
  336. package/dist/idea/idea.interface.js +0 -15
  337. package/dist/idea/idea.interface.js.map +0 -1
  338. package/dist/index.js +0 -42
  339. package/dist/index.js.map +0 -1
  340. package/dist/link/link.api.js +0 -30
  341. package/dist/link/link.api.js.map +0 -1
  342. package/dist/link/link.interface.js +0 -7
  343. package/dist/link/link.interface.js.map +0 -1
  344. package/dist/list/list.api.js +0 -30
  345. package/dist/list/list.api.js.map +0 -1
  346. package/dist/list/list.interface.js +0 -6
  347. package/dist/list/list.interface.js.map +0 -1
  348. package/dist/node/node-manager.d.ts +0 -48
  349. package/dist/node/node-manager.d.ts.map +0 -1
  350. package/dist/node/node-manager.js +0 -619
  351. package/dist/node/node-manager.js.map +0 -1
  352. package/dist/node/node-task.preset.d.ts +0 -1
  353. package/dist/node/node-task.preset.d.ts.map +0 -1
  354. package/dist/node/node-task.preset.js +0 -14
  355. package/dist/node/node-task.preset.js.map +0 -1
  356. package/dist/node/node.api.js +0 -100
  357. package/dist/node/node.api.js.map +0 -1
  358. package/dist/node/node.interface.js +0 -19
  359. package/dist/node/node.interface.js.map +0 -1
  360. package/dist/node/node.utils.js +0 -36
  361. package/dist/node/node.utils.js.map +0 -1
  362. package/dist/parcel/parcel-manager.js +0 -156
  363. package/dist/parcel/parcel-manager.js.map +0 -1
  364. package/dist/parcel/parcel.interface.js +0 -11
  365. package/dist/parcel/parcel.interface.js.map +0 -1
  366. package/dist/question-list/question-list.api.d.ts +0 -13
  367. package/dist/question-list/question-list.api.d.ts.map +0 -1
  368. package/dist/question-list/question-list.api.js +0 -35
  369. package/dist/question-list/question-list.api.js.map +0 -1
  370. package/dist/question-list/question-list.interface.d.ts +0 -18
  371. package/dist/question-list/question-list.interface.d.ts.map +0 -1
  372. package/dist/question-list/question-list.interface.js +0 -5
  373. package/dist/question-list/question-list.interface.js.map +0 -1
  374. package/dist/repo/repo-context.utils.js +0 -81
  375. package/dist/repo/repo-context.utils.js.map +0 -1
  376. package/dist/repo/repo-manager.js +0 -156
  377. package/dist/repo/repo-manager.js.map +0 -1
  378. package/dist/repo/repo.api.js +0 -40
  379. package/dist/repo/repo.api.js.map +0 -1
  380. package/dist/repo/repo.interface.js +0 -8
  381. package/dist/repo/repo.interface.js.map +0 -1
  382. package/dist/repo/repo.script-loader.js +0 -108
  383. package/dist/repo/repo.script-loader.js.map +0 -1
  384. package/dist/review/review.api.d.ts +0 -14
  385. package/dist/review/review.api.d.ts.map +0 -1
  386. package/dist/review/review.api.js +0 -133
  387. package/dist/review/review.api.js.map +0 -1
  388. package/dist/review/review.interface.d.ts +0 -24
  389. package/dist/review/review.interface.d.ts.map +0 -1
  390. package/dist/review/review.interface.js +0 -10
  391. package/dist/review/review.interface.js.map +0 -1
  392. package/dist/review-v2/apis/post-review-setting.api.d.ts +0 -12
  393. package/dist/review-v2/apis/post-review-setting.api.d.ts.map +0 -1
  394. package/dist/review-v2/apis/post-review-setting.api.js +0 -27
  395. package/dist/review-v2/apis/post-review-setting.api.js.map +0 -1
  396. package/dist/review-v2/apis/post-review.api.d.ts +0 -13
  397. package/dist/review-v2/apis/post-review.api.d.ts.map +0 -1
  398. package/dist/review-v2/apis/post-review.api.js +0 -46
  399. package/dist/review-v2/apis/post-review.api.js.map +0 -1
  400. package/dist/review-v2/review-setting.interface.d.ts +0 -23
  401. package/dist/review-v2/review-setting.interface.d.ts.map +0 -1
  402. package/dist/review-v2/review-setting.interface.js +0 -5
  403. package/dist/review-v2/review-setting.interface.js.map +0 -1
  404. package/dist/review-v2/review.interface.d.ts +0 -20
  405. package/dist/review-v2/review.interface.d.ts.map +0 -1
  406. package/dist/review-v2/review.interface.js +0 -5
  407. package/dist/review-v2/review.interface.js.map +0 -1
  408. package/dist/service/api.interface.d.ts +0 -35
  409. package/dist/service/api.interface.d.ts.map +0 -1
  410. package/dist/service/api.interface.js +0 -12
  411. package/dist/service/api.interface.js.map +0 -1
  412. package/dist/service/base.interface.js +0 -7
  413. package/dist/service/base.interface.js.map +0 -1
  414. package/dist/service/service.interface.js +0 -11
  415. package/dist/service/service.interface.js.map +0 -1
  416. package/dist/shared/log/create-api-logger.d.ts +0 -17
  417. package/dist/shared/log/create-api-logger.d.ts.map +0 -1
  418. package/dist/shared/log/create-api-logger.js +0 -15
  419. package/dist/shared/log/create-api-logger.js.map +0 -1
  420. package/dist/shared/log/log-manager.js +0 -218
  421. package/dist/shared/log/log-manager.js.map +0 -1
  422. package/dist/shared/utils/config-path.utils.js +0 -85
  423. package/dist/shared/utils/config-path.utils.js.map +0 -1
  424. package/dist/shared/utils/error.utils.js +0 -15
  425. package/dist/shared/utils/error.utils.js.map +0 -1
  426. package/dist/shared/utils/id.utils.js +0 -5
  427. package/dist/shared/utils/id.utils.js.map +0 -1
  428. package/dist/supabase.js +0 -100
  429. package/dist/supabase.js.map +0 -1
  430. package/dist/task/local-task-registry.js +0 -153
  431. package/dist/task/local-task-registry.js.map +0 -1
  432. package/dist/task/task-manager.js +0 -217
  433. package/dist/task/task-manager.js.map +0 -1
  434. package/dist/task/task-repo-context.js +0 -12
  435. package/dist/task/task-repo-context.js.map +0 -1
  436. package/dist/task/task.api.js +0 -351
  437. package/dist/task/task.api.js.map +0 -1
  438. package/dist/task/task.interface.js +0 -36
  439. package/dist/task/task.interface.js.map +0 -1
  440. package/dist/task/task.utils.js +0 -2
  441. package/dist/task/task.utils.js.map +0 -1
  442. package/dist/word/word.api.js +0 -30
  443. package/dist/word/word.api.js.map +0 -1
  444. package/dist/word/word.interface.js +0 -6
  445. package/dist/word/word.interface.js.map +0 -1
  446. package/src/auth/auth.api.ts +0 -87
  447. package/src/feed/feed.interface.ts +0 -33
  448. package/src/file/file-manager.ts +0 -145
  449. package/src/file/file.api.ts +0 -43
  450. package/src/file/file.interface.ts +0 -30
  451. package/src/file-list/file-list.api.ts +0 -64
  452. package/src/file-list/file-list.interface.ts +0 -24
  453. package/src/node/node-manager.ts +0 -673
  454. package/src/node/node-task.preset.ts +0 -13
  455. package/src/question-list/question-list.api.ts +0 -42
  456. package/src/question-list/question-list.interface.ts +0 -21
  457. package/src/review/review.api.ts +0 -145
  458. package/src/review/review.interface.ts +0 -26
  459. package/src/review-v2/apis/post-review-setting.api.ts +0 -35
  460. package/src/review-v2/apis/post-review.api.ts +0 -59
  461. package/src/review-v2/review-setting.interface.ts +0 -26
  462. package/src/review-v2/review.interface.ts +0 -23
  463. package/src/service/api.interface.ts +0 -47
  464. package/src/shared/log/create-api-logger.ts +0 -25
@@ -0,0 +1,1973 @@
1
+ import { B as BaseValidator, e as createTarget, E as validateWithSchema, d as createLogger, A as updateTargetDetails, g as generateResponse, f as deleteTarget, i as getTarget, y as scanTargetList, h as getPossibleTarget, j as getTargetList, o as isOptimisticLockError, c as OPTIMISTIC_LOCK_FAILED_MESSAGE, O as OPTIMISTIC_LOCK_ERROR_CODE, s as logManager } from './create-logger-DyH3mZ8p.js';
2
+ import { z } from 'zod';
3
+
4
+ var CategoryIdea;
5
+ (function (CategoryIdea) {
6
+ CategoryIdea["OPPORTUNITY"] = "opportunity";
7
+ })(CategoryIdea || (CategoryIdea = {}));
8
+ var Market;
9
+ (function (Market) {
10
+ Market["NA"] = "NA";
11
+ Market["EU"] = "EU";
12
+ Market["JP"] = "JP";
13
+ Market["CN"] = "CN";
14
+ Market["TW"] = "TW";
15
+ })(Market || (Market = {}));
16
+
17
+ class PostLinkValidator extends BaseValidator {
18
+ requiredFields = ["name", "value", "category", "details"];
19
+ optionalFields = [];
20
+ constructor() {
21
+ super();
22
+ // Add custom
23
+ this.addCustomValidator((_val) => {
24
+ return true;
25
+ });
26
+ }
27
+ }
28
+ const postLinkCreate = async (payload) => {
29
+ return createTarget({
30
+ payload: payload,
31
+ validator: PostLinkValidator,
32
+ createFn: (validPayload) => {
33
+ const { name, value, category, details } = validPayload;
34
+ return {
35
+ name,
36
+ category,
37
+ value,
38
+ tagList: [],
39
+ details,
40
+ };
41
+ },
42
+ });
43
+ };
44
+
45
+ var CategoryLink;
46
+ (function (CategoryLink) {
47
+ CategoryLink["LINK"] = "link";
48
+ })(CategoryLink || (CategoryLink = {}));
49
+
50
+ var NodeStatus;
51
+ (function (NodeStatus) {
52
+ /** Registered, not yet in worker loop. */
53
+ NodeStatus["READY"] = "READY";
54
+ /** Worker main loop is running (accepts tasks until shutdown). */
55
+ NodeStatus["BUSY"] = "BUSY";
56
+ /** Heartbeat lost or voluntarily offline; considered unavailable by the scheduler. */
57
+ NodeStatus["LOST"] = "LOST";
58
+ /** TODO Gracefully draining: not accepting new tasks, waiting for in-flight tasks to complete. */
59
+ NodeStatus["DRAINING"] = "DRAINING";
60
+ /** TODO Disabled by an administrator; excluded from scheduling. */
61
+ NodeStatus["DISABLED"] = "DISABLED";
62
+ })(NodeStatus || (NodeStatus = {}));
63
+ var CategoryNode;
64
+ (function (CategoryNode) {
65
+ CategoryNode["NODE"] = "node";
66
+ })(CategoryNode || (CategoryNode = {}));
67
+
68
+ const NODE_STATUS_FIELD = "details->>status";
69
+ const LOG_TOPIC_NODE = "node";
70
+ const nodeIdSchema$1 = z.string().trim().min(1);
71
+ const traceIdSchema$2 = z.string().trim().min(1).optional();
72
+ // ─── Zod schemas ─────────────────────────────────────────────────────────────
73
+ const postRegisterNodeSchema = z.object({
74
+ traceId: traceIdSchema$2,
75
+ });
76
+ const patchNodeHeartBeatSchema = z.object({
77
+ nodeId: nodeIdSchema$1,
78
+ traceId: traceIdSchema$2,
79
+ });
80
+ const patchStopNodeSchema = z.object({
81
+ nodeId: nodeIdSchema$1,
82
+ traceId: traceIdSchema$2,
83
+ });
84
+ const patchChangeNodeStatusSchema = z.object({
85
+ nodeId: nodeIdSchema$1,
86
+ status: z.nativeEnum(NodeStatus),
87
+ /** When set, UPDATE only if current status matches (optimistic lock). */
88
+ fromStatus: z.nativeEnum(NodeStatus).optional(),
89
+ traceId: traceIdSchema$2,
90
+ });
91
+ // ─── Optimistic lock helpers ─────────────────────────────────────────────────
92
+ function lockOnNodeStatus(status) {
93
+ return [{ field: NODE_STATUS_FIELD, operator: "eq", value: status }];
94
+ }
95
+ // ─── postRegisterNode ────────────────────────────────────────────────────────
96
+ const postRegisterNode = validateWithSchema(postRegisterNodeSchema, "postRegisterNodeSchema")(async (payload) => {
97
+ return createTarget({
98
+ payload,
99
+ createFn: () => {
100
+ const details = {
101
+ manifestVersion: 0,
102
+ status: NodeStatus.READY,
103
+ lastHeartBeat: Date.now(),
104
+ };
105
+ return {
106
+ name: "",
107
+ category: CategoryNode.NODE,
108
+ value: "",
109
+ tagList: [],
110
+ details,
111
+ };
112
+ },
113
+ });
114
+ });
115
+ // ─── patchNodeHeartBeat ──────────────────────────────────────────────────────
116
+ const patchNodeHeartBeat = validateWithSchema(patchNodeHeartBeatSchema, "patchNodeHeartBeatSchema")(async ({ nodeId }) => {
117
+ const lastHeartBeat = Date.now();
118
+ await updateTargetDetails({
119
+ id: nodeId,
120
+ updateFn: (details) => ({
121
+ ...details,
122
+ lastHeartBeat,
123
+ }),
124
+ });
125
+ return generateResponse.success(lastHeartBeat);
126
+ });
127
+ // ─── patchStopNode ───────────────────────────────────────────────────────────
128
+ const patchStopNode = validateWithSchema(patchStopNodeSchema, "patchStopNodeSchema")(async ({ nodeId }) => {
129
+ const lastHeartBeat = Date.now();
130
+ // TODO 等待任務全部完成才下綫 應該先使用NodeStatus.DRAINING
131
+ await updateTargetDetails({
132
+ id: nodeId,
133
+ updateFn: (details) => ({
134
+ ...details,
135
+ lastHeartBeat,
136
+ status: NodeStatus.LOST,
137
+ }),
138
+ });
139
+ return generateResponse.success(lastHeartBeat);
140
+ });
141
+ // ─── patchChangeNodeStatus ───────────────────────────────────────────────────
142
+ const patchChangeNodeStatus = validateWithSchema(patchChangeNodeStatusSchema, "patchChangeNodeStatusSchema")(async ({ nodeId, status, fromStatus, traceId }) => {
143
+ const logger = createLogger({ module: "patchChangeNodeStatus", traceId, labels: { nodeId } });
144
+ const data = await updateTargetDetails({
145
+ id: nodeId,
146
+ optimisticLockFilterList: fromStatus != null ? lockOnNodeStatus(fromStatus) : [],
147
+ updateFn: (details) => ({
148
+ ...details,
149
+ status,
150
+ lastHeartBeat: Date.now(),
151
+ }),
152
+ });
153
+ logger.info("节点状态更新成功", {
154
+ topic: LOG_TOPIC_NODE,
155
+ data: {
156
+ nodeId,
157
+ status,
158
+ fromStatus,
159
+ },
160
+ });
161
+ return generateResponse.success(data);
162
+ });
163
+
164
+ function isBusyWithHeartbeat(node) {
165
+ return node.details.status === NodeStatus.BUSY && typeof node.details.lastHeartBeat === "number";
166
+ }
167
+ /** Evaluate TaskNode liveness from a scanned node list (no I/O). */
168
+ function evaluateBusyNodeLiveness(nodes, options) {
169
+ const now = options.now ?? Date.now();
170
+ const { staleMs, excludeNodeId, onlyFreshCandidates = false } = options;
171
+ const candidates = nodes.filter((node) => (excludeNodeId == null || node.id !== excludeNodeId) && isBusyWithHeartbeat(node));
172
+ const busyWorkerCount = candidates.length;
173
+ const freshCandidates = candidates.filter((node) => now - node.details.lastHeartBeat < staleMs);
174
+ const freshWorkerCount = freshCandidates.length;
175
+ const pool = onlyFreshCandidates ? freshCandidates : candidates;
176
+ const freshestNode = pool.reduce((best, node) => {
177
+ if (best == null) {
178
+ return node;
179
+ }
180
+ return node.details.lastHeartBeat > best.details.lastHeartBeat ? node : best;
181
+ }, null);
182
+ const ageMs = freshestNode == null ? Number.POSITIVE_INFINITY : now - freshestNode.details.lastHeartBeat;
183
+ const healthy = onlyFreshCandidates ? freshestNode != null : freshestNode != null && ageMs < staleMs;
184
+ return {
185
+ healthy,
186
+ staleMs,
187
+ busyWorkerCount,
188
+ freshWorkerCount,
189
+ freshest: freshestNode == null
190
+ ? null
191
+ : {
192
+ nodeId: freshestNode.id,
193
+ status: freshestNode.details.status,
194
+ lastHeartBeat: new Date(freshestNode.details.lastHeartBeat).toISOString(),
195
+ ageMs,
196
+ },
197
+ };
198
+ }
199
+
200
+ function resolveFetchUrl(input) {
201
+ if (typeof input === "string") {
202
+ return input;
203
+ }
204
+ if (input instanceof URL) {
205
+ return input.href;
206
+ }
207
+ return input.url;
208
+ }
209
+ function isHttpUrl(url) {
210
+ return url.startsWith("http://") || url.startsWith("https://");
211
+ }
212
+
213
+ function isLocalFilesystemPath(url) {
214
+ if (url.startsWith("file://")) {
215
+ return true;
216
+ }
217
+ return /^[a-zA-Z]:[\\/]/.test(url) || url.startsWith("\\\\") || url.startsWith("/");
218
+ }
219
+ /** Opaque chunk locator - not HTTP and not a local path (e.g. Telegram file_id). */
220
+ function isOpaqueChunkUrl(url) {
221
+ return !isHttpUrl(url) && !isLocalFilesystemPath(url);
222
+ }
223
+ /** `provider:opaque` scheme (e.g. `telegram:BQACAg...`). */
224
+ function parseProviderPrefixedUrl(url) {
225
+ const match = /^([a-z][a-z0-9_-]*):(.+)$/i.exec(url);
226
+ if (match == null) {
227
+ return null;
228
+ }
229
+ const provider = match[1].toLowerCase();
230
+ const locator = match[2].trim();
231
+ if (locator === "") {
232
+ return null;
233
+ }
234
+ if (provider === "http" || provider === "https" || provider === "file") {
235
+ return null;
236
+ }
237
+ return { provider, locator };
238
+ }
239
+
240
+ const resolvers = new Map();
241
+ function registerChunkResolver(resolver) {
242
+ resolvers.set(resolver.provider, resolver);
243
+ }
244
+ /** Register a provider's chunk resolver (call when the provider module loads). */
245
+ function registerProviderChunkResolver(module) {
246
+ if (module.resolveChunk == null) {
247
+ return;
248
+ }
249
+ const resolveChunk = module.resolveChunk;
250
+ registerChunkResolver({
251
+ provider: module.provider,
252
+ matches(url) {
253
+ const prefixed = parseProviderPrefixedUrl(url);
254
+ if (prefixed != null) {
255
+ return prefixed.provider === module.provider;
256
+ }
257
+ return module.matchesOpaqueUrl?.(url) === true;
258
+ },
259
+ resolve(locator) {
260
+ const prefixed = parseProviderPrefixedUrl(locator);
261
+ const opaque = prefixed?.provider === module.provider ? prefixed.locator : locator;
262
+ return resolveChunk(opaque);
263
+ },
264
+ });
265
+ }
266
+ async function resolveOpaqueUrl(url) {
267
+ const prefixed = parseProviderPrefixedUrl(url);
268
+ if (prefixed != null) {
269
+ const resolver = resolvers.get(prefixed.provider);
270
+ if (resolver == null) {
271
+ throw new Error(`No chunk resolver registered for provider: ${prefixed.provider}`);
272
+ }
273
+ return resolver.resolve(prefixed.locator);
274
+ }
275
+ const matches = [...resolvers.values()].filter((entry) => entry.matches(url));
276
+ if (matches.length === 1) {
277
+ return matches[0].resolve(url);
278
+ }
279
+ if (matches.length > 1) {
280
+ throw new Error(`Ambiguous chunk url (${url}); use provider-prefixed form e.g. telegram:${url.slice(0, 12)}…`);
281
+ }
282
+ const registered = [...resolvers.keys()].join(", ") || "(none)";
283
+ throw new Error(`No chunk resolver for opaque url (${url.slice(0, 24)}…). Registered: ${registered}`);
284
+ }
285
+ /**
286
+ * Patch global fetch so ParcelManager.reassemble can resolve opaque chunk locators.
287
+ * HTTP URLs use the original fetch (S3 presigned, etc.).
288
+ */
289
+ function installChunkFetchRegistry() {
290
+ const originalFetch = globalThis.fetch.bind(globalThis);
291
+ globalThis.fetch = (async (input, init) => {
292
+ const url = resolveFetchUrl(input);
293
+ if (isHttpUrl(url)) {
294
+ return originalFetch(input, init);
295
+ }
296
+ if (isLocalFilesystemPath(url)) {
297
+ throw new Error(`Chunk fetch registry: local path not supported (${url}). ` +
298
+ "Use a local provider module or parcel-restore-local.");
299
+ }
300
+ const buffer = await resolveOpaqueUrl(url);
301
+ return new Response(buffer, { headers: { "Content-Type": "application/octet-stream" } });
302
+ });
303
+ return () => {
304
+ globalThis.fetch = originalFetch;
305
+ };
306
+ }
307
+
308
+ var CategoryParcel;
309
+ (function (CategoryParcel) {
310
+ CategoryParcel["PARCEL"] = "parcel";
311
+ })(CategoryParcel || (CategoryParcel = {}));
312
+ var LifecycleStatus;
313
+ (function (LifecycleStatus) {
314
+ LifecycleStatus["STORED"] = "STORED";
315
+ LifecycleStatus["SOFT_DELETED"] = "SOFT_DELETED";
316
+ LifecycleStatus["HARD_DELETED"] = "HARD_DELETED";
317
+ })(LifecycleStatus || (LifecycleStatus = {}));
318
+
319
+ const parcelIdSchema = z.string().trim().min(1);
320
+ const chunkSchema = z.object({
321
+ index: z.number().int().nonnegative(),
322
+ size: z.number().int().nonnegative(),
323
+ checksum: z.string().trim().min(1),
324
+ url: z.string().trim().min(1),
325
+ provider: z.string().optional(),
326
+ });
327
+ const parcelCryptoSchema = z.object({
328
+ enabled: z.boolean(),
329
+ algorithm: z.string().optional(),
330
+ iv: z.string().optional(),
331
+ keyDerivation: z.string().optional(),
332
+ salt: z.string().optional(),
333
+ pbkdf2Iterations: z.number().int().positive().optional(),
334
+ });
335
+ const parcelDetailsSchema = z.object({
336
+ manifestVersion: z.number().int().nonnegative(),
337
+ chunkList: z.array(chunkSchema).min(1),
338
+ checksum: z.string().trim().min(1),
339
+ size: z.number().int().nonnegative(),
340
+ preview: z.string().optional(),
341
+ crypto: parcelCryptoSchema.optional(),
342
+ });
343
+ const postParcelSchema = z.object({
344
+ name: z.string().trim().min(1),
345
+ value: z.string().trim().min(1),
346
+ details: parcelDetailsSchema,
347
+ tagList: z.array(z.string()).optional().default([]),
348
+ extra: z.string().optional(),
349
+ });
350
+ const getParcelSchema = z.object({
351
+ id: parcelIdSchema,
352
+ });
353
+ const deleteParcelSchema = z.object({
354
+ id: parcelIdSchema,
355
+ });
356
+ const parcelCategoryFilter = {
357
+ field: "category",
358
+ operator: "eq",
359
+ value: CategoryParcel.PARCEL,
360
+ };
361
+ /** Persist a Parcel row (`category=parcel`) after chunks are uploaded via {@link ParcelManager.save}. */
362
+ const postParcel = validateWithSchema(postParcelSchema, "postParcelSchema")(async ({ name, value, details, tagList, extra }) => {
363
+ return createTarget({
364
+ payload: { name, value, details, tagList, extra },
365
+ createFn: () => ({
366
+ name,
367
+ value,
368
+ category: CategoryParcel.PARCEL,
369
+ tagList,
370
+ extra,
371
+ details: details,
372
+ }),
373
+ });
374
+ });
375
+ /** Fetch a Parcel by id (`category=parcel`). */
376
+ const getParcel = validateWithSchema(getParcelSchema, "getParcelSchema")(async ({ id }) => {
377
+ const result = await getTarget({
378
+ id,
379
+ filterList: [parcelCategoryFilter],
380
+ });
381
+ return {
382
+ ...result,
383
+ data: result.data,
384
+ };
385
+ });
386
+ /** Delete a Parcel row by id (`category=parcel`). Does not remove chunk blobs from storage providers. */
387
+ const deleteParcel = validateWithSchema(deleteParcelSchema, "deleteParcelSchema")(async ({ id }) => {
388
+ return deleteTarget({
389
+ id,
390
+ filterList: [parcelCategoryFilter],
391
+ });
392
+ });
393
+
394
+ function getCrypto$1() {
395
+ if (typeof globalThis !== "undefined" && globalThis.crypto) {
396
+ return globalThis.crypto;
397
+ }
398
+ throw new Error("sha256Hex: crypto.subtle not available");
399
+ }
400
+ /** SHA-256 digest as lowercase hex (browser + Node Web Crypto). */
401
+ async function sha256Hex(buffer) {
402
+ const crypto = getCrypto$1();
403
+ const hash = await crypto.subtle.digest("SHA-256", buffer);
404
+ return Array.from(new Uint8Array(hash))
405
+ .map((byte) => byte.toString(16).padStart(2, "0"))
406
+ .join("");
407
+ }
408
+
409
+ const MANIFEST_VERSION = 1;
410
+ const DEFAULT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB - fallback for empty input only
411
+ const MB = 1024 * 1024;
412
+ /** Source files at or below this size use at most 2 chunks */
413
+ const SMALL_FILE_MAX_BYTES = 50 * MB;
414
+ /** Target per-chunk size for larger files */
415
+ const PREFERRED_CHUNK_BYTES = 16 * MB;
416
+ /** Cap chunk count for very large files */
417
+ const MAX_CHUNK_COUNT = 64;
418
+ const AES_GCM_ALGORITHM = "AES-GCM-256";
419
+ const KEY_DERIVATION_PBKDF2 = "PBKDF2-SHA256";
420
+ const PBKDF2_ITERATIONS = 100_000;
421
+ const AES_GCM_IV_LENGTH = 12;
422
+ const AES_GCM_TAG_LENGTH = 128;
423
+ /** Auth tag bytes Web Crypto appends to AES-GCM ciphertext */
424
+ const AES_GCM_AUTH_TAG_BYTES = AES_GCM_TAG_LENGTH / 8;
425
+ /** @deprecated Legacy IV in Target.extra - read only for old parcels */
426
+ const LEGACY_EXTRA_IV_KEY = "iv";
427
+ function getCrypto() {
428
+ if (typeof globalThis !== "undefined" && globalThis.crypto)
429
+ return globalThis.crypto;
430
+ throw new Error("ParcelManager: crypto not available");
431
+ }
432
+ function bytesToBase64(bytes) {
433
+ return btoa(String.fromCharCode(...bytes));
434
+ }
435
+ function base64ToBytes(base64) {
436
+ return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
437
+ }
438
+ async function encrypt(data, key, iv) {
439
+ const crypto = getCrypto();
440
+ return crypto.subtle.encrypt({ name: "AES-GCM", iv: new Uint8Array(iv), tagLength: AES_GCM_TAG_LENGTH }, key, data);
441
+ }
442
+ async function decrypt(data, key, iv) {
443
+ const crypto = getCrypto();
444
+ return crypto.subtle.decrypt({ name: "AES-GCM", iv: new Uint8Array(iv), tagLength: AES_GCM_TAG_LENGTH }, key, data);
445
+ }
446
+ function isDecryptAuthFailure(error) {
447
+ if (error instanceof DOMException && error.name === "OperationError") {
448
+ return true;
449
+ }
450
+ if (error instanceof Error) {
451
+ return /operation failed|operation-specific|decrypt|OperationError/i.test(error.message);
452
+ }
453
+ return false;
454
+ }
455
+ async function decryptPayload(data, key, iv, usedPassphrase) {
456
+ try {
457
+ return await decrypt(data, key, iv);
458
+ }
459
+ catch (error) {
460
+ if (isDecryptAuthFailure(error)) {
461
+ throw new Error(usedPassphrase
462
+ ? "ParcelManager.reassemble: 解密失败,口令错误或密文已损坏"
463
+ : "ParcelManager.reassemble: 解密失败,密钥错误或密文已损坏");
464
+ }
465
+ throw error;
466
+ }
467
+ }
468
+ async function generateKey() {
469
+ const crypto = getCrypto();
470
+ return crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]);
471
+ }
472
+ async function deriveKeyFromPassphrase(passphrase, salt, iterations) {
473
+ const crypto = getCrypto();
474
+ const keyMaterial = await crypto.subtle.importKey("raw", new TextEncoder().encode(passphrase), "PBKDF2", false, [
475
+ "deriveKey",
476
+ ]);
477
+ return crypto.subtle.deriveKey({
478
+ name: "PBKDF2",
479
+ salt: new Uint8Array(salt),
480
+ iterations,
481
+ hash: "SHA-256",
482
+ }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
483
+ }
484
+ function usesPassphraseDerivation(crypto) {
485
+ return crypto.keyDerivation === KEY_DERIVATION_PBKDF2;
486
+ }
487
+ async function resolveDecryptionKey(crypto, options) {
488
+ if (usesPassphraseDerivation(crypto)) {
489
+ if (options.passphrase == null || options.passphrase === "") {
490
+ throw new Error("ParcelManager.reassemble: 口令加密 Parcel 需要提供 passphrase");
491
+ }
492
+ if (crypto.salt == null || crypto.salt === "") {
493
+ throw new Error("ParcelManager.reassemble: 缺少 details.crypto.salt");
494
+ }
495
+ const iterations = crypto.pbkdf2Iterations ?? PBKDF2_ITERATIONS;
496
+ const salt = base64ToBytes(crypto.salt);
497
+ return deriveKeyFromPassphrase(options.passphrase, salt, iterations);
498
+ }
499
+ if (options.key != null) {
500
+ return options.key;
501
+ }
502
+ throw new Error("ParcelManager.reassemble: 加密 Parcel 需要提供 key");
503
+ }
504
+ async function buildChunkList(payload, chunkSize) {
505
+ const chunks = [];
506
+ const chunkList = [];
507
+ let offset = 0;
508
+ let index = 0;
509
+ while (offset < payload.byteLength) {
510
+ const end = Math.min(offset + chunkSize, payload.byteLength);
511
+ const chunkBuffer = payload.slice(offset, end);
512
+ const checksum = await sha256Hex(chunkBuffer);
513
+ chunks.push(chunkBuffer);
514
+ chunkList.push({
515
+ index,
516
+ size: chunkBuffer.byteLength,
517
+ checksum,
518
+ url: "",
519
+ });
520
+ offset = end;
521
+ index += 1;
522
+ }
523
+ return { chunks, chunkList };
524
+ }
525
+ /**
526
+ * Derive per-chunk byte size from the buffer that will be split.
527
+ *
528
+ * | Payload size | Policy |
529
+ * |--------------|--------|
530
+ * | ≤50 MB | At most **2** chunks (`ceil(size / 2)` per chunk) |
531
+ * | > 50 MB | Target ~16 MB per chunk; chunk count capped at **64** |
532
+ *
533
+ * For encrypted parcels, pass plaintext size + {@link AES_GCM_AUTH_TAG_BYTES}
534
+ * (GCM auth tag is appended before split).
535
+ *
536
+ * Explicit `chunkSize` in {@link CreateOptions} overrides this table.
537
+ */
538
+ function resolveChunkSize(fileSize, override) {
539
+ if (override != null) {
540
+ if (!Number.isFinite(override) || override <= 0) {
541
+ throw new Error("ParcelManager.create: chunkSize must be a positive number");
542
+ }
543
+ return override;
544
+ }
545
+ if (fileSize <= 0) {
546
+ return DEFAULT_CHUNK_SIZE;
547
+ }
548
+ if (fileSize <= SMALL_FILE_MAX_BYTES) {
549
+ return Math.ceil(fileSize / 2);
550
+ }
551
+ const targetChunks = Math.min(MAX_CHUNK_COUNT, Math.max(2, Math.ceil(fileSize / PREFERRED_CHUNK_BYTES)));
552
+ return Math.ceil(fileSize / targetChunks);
553
+ }
554
+ function concatBuffers(buffers) {
555
+ const total = buffers.reduce((sum, buffer) => sum + buffer.byteLength, 0);
556
+ const merged = new Uint8Array(total);
557
+ let offset = 0;
558
+ for (const buffer of buffers) {
559
+ merged.set(new Uint8Array(buffer), offset);
560
+ offset += buffer.byteLength;
561
+ }
562
+ return merged.buffer;
563
+ }
564
+ function isEncryptionEnabled(details, parcelExtra) {
565
+ if (details.crypto != null) {
566
+ return details.crypto.enabled === true;
567
+ }
568
+ if (parcelExtra == null || parcelExtra.trim() === "") {
569
+ return false;
570
+ }
571
+ try {
572
+ const legacy = JSON.parse(parcelExtra);
573
+ return typeof legacy[LEGACY_EXTRA_IV_KEY] === "string";
574
+ }
575
+ catch {
576
+ return false;
577
+ }
578
+ }
579
+ function resolveCrypto(details, parcelExtra) {
580
+ if (details.crypto?.enabled === true) {
581
+ return details.crypto;
582
+ }
583
+ if (parcelExtra == null || parcelExtra.trim() === "") {
584
+ return null;
585
+ }
586
+ try {
587
+ const legacy = JSON.parse(parcelExtra);
588
+ const iv = legacy[LEGACY_EXTRA_IV_KEY];
589
+ if (typeof iv !== "string" || iv === "") {
590
+ return null;
591
+ }
592
+ return { enabled: true, algorithm: AES_GCM_ALGORITHM, iv };
593
+ }
594
+ catch {
595
+ return null;
596
+ }
597
+ }
598
+ /**
599
+ * Split a file into chunks. Default: plaintext shards; optional whole-file AES-GCM before split.
600
+ */
601
+ async function create(file, options = {}) {
602
+ const encryptEnabled = options.encrypt === true;
603
+ const splitPayloadSize = encryptEnabled ? file.byteLength + AES_GCM_AUTH_TAG_BYTES : file.byteLength;
604
+ const chunkSize = resolveChunkSize(splitPayloadSize, options.chunkSize);
605
+ const plaintextChecksum = await sha256Hex(file);
606
+ if (!encryptEnabled) {
607
+ const { chunks, chunkList } = await buildChunkList(file, chunkSize);
608
+ return {
609
+ details: {
610
+ manifestVersion: MANIFEST_VERSION,
611
+ chunkList,
612
+ checksum: plaintextChecksum,
613
+ size: file.byteLength,
614
+ },
615
+ chunks,
616
+ };
617
+ }
618
+ if (options.passphrase != null && options.key != null) {
619
+ throw new Error("ParcelManager.create: passphrase 与 key 不能同時指定");
620
+ }
621
+ const cryptoApi = getCrypto();
622
+ const iv = cryptoApi.getRandomValues(new Uint8Array(AES_GCM_IV_LENGTH));
623
+ let key;
624
+ let generatedKey = false;
625
+ let cryptoMeta;
626
+ if (options.passphrase != null && options.passphrase !== "") {
627
+ const salt = cryptoApi.getRandomValues(new Uint8Array(16));
628
+ key = await deriveKeyFromPassphrase(options.passphrase, salt, PBKDF2_ITERATIONS);
629
+ cryptoMeta = {
630
+ enabled: true,
631
+ algorithm: AES_GCM_ALGORITHM,
632
+ iv: bytesToBase64(iv),
633
+ keyDerivation: KEY_DERIVATION_PBKDF2,
634
+ salt: bytesToBase64(salt),
635
+ pbkdf2Iterations: PBKDF2_ITERATIONS,
636
+ };
637
+ }
638
+ else if (options.key != null) {
639
+ key = options.key;
640
+ cryptoMeta = {
641
+ enabled: true,
642
+ algorithm: AES_GCM_ALGORITHM,
643
+ iv: bytesToBase64(iv),
644
+ };
645
+ }
646
+ else {
647
+ key = await generateKey();
648
+ generatedKey = true;
649
+ cryptoMeta = {
650
+ enabled: true,
651
+ algorithm: AES_GCM_ALGORITHM,
652
+ iv: bytesToBase64(iv),
653
+ };
654
+ }
655
+ const encrypted = await encrypt(file, key, iv);
656
+ const { chunks, chunkList } = await buildChunkList(encrypted, chunkSize);
657
+ const result = {
658
+ details: {
659
+ manifestVersion: MANIFEST_VERSION,
660
+ chunkList,
661
+ checksum: plaintextChecksum,
662
+ size: file.byteLength,
663
+ crypto: cryptoMeta,
664
+ },
665
+ chunks,
666
+ };
667
+ if (generatedKey) {
668
+ result.key = key;
669
+ }
670
+ return result;
671
+ }
672
+ /** Upload chunks round-robin across storage adapters */
673
+ async function save(createResult, fileSystems, input) {
674
+ if (fileSystems.length === 0) {
675
+ throw new Error("ParcelManager.save: fileSystems 不能为空");
676
+ }
677
+ const { details, chunks } = createResult;
678
+ const chunkListWithUrls = [];
679
+ for (let i = 0; i < chunks.length; i++) {
680
+ const adapter = fileSystems[i % fileSystems.length];
681
+ const pathOrKey = `chunk-${i}-${details.checksum.slice(0, 8)}`;
682
+ const { url } = await adapter.upload(chunks[i], pathOrKey);
683
+ chunkListWithUrls.push({
684
+ ...details.chunkList[i],
685
+ url,
686
+ provider: adapter.provider,
687
+ });
688
+ }
689
+ return {
690
+ name: input.name,
691
+ value: input.value,
692
+ tagList: input.tagList ?? [],
693
+ category: CategoryParcel.PARCEL,
694
+ details: {
695
+ ...details,
696
+ chunkList: chunkListWithUrls,
697
+ },
698
+ };
699
+ }
700
+ async function downloadAndVerifyChunks(chunkList) {
701
+ const sortedChunks = [...chunkList].sort((a, b) => a.index - b.index);
702
+ const buffers = [];
703
+ for (const chunkMeta of sortedChunks) {
704
+ const res = await fetch(chunkMeta.url);
705
+ if (!res.ok) {
706
+ throw new Error(`ParcelManager.reassemble: 下载 chunk ${chunkMeta.index} 失败: ${res.status}`);
707
+ }
708
+ const chunkBuffer = await res.arrayBuffer();
709
+ const chunkChecksum = await sha256Hex(chunkBuffer);
710
+ if (chunkChecksum !== chunkMeta.checksum) {
711
+ throw new Error(`ParcelManager.reassemble: chunk ${chunkMeta.index} 校验失败 (checksum 不一致`);
712
+ }
713
+ buffers.push(chunkBuffer);
714
+ }
715
+ return buffers;
716
+ }
717
+ function verifyPlaintextSize(buffer, details) {
718
+ if (buffer.byteLength !== details.size) {
719
+ throw new Error(`ParcelManager.reassemble: 重组后大小与 details.size 不一致(${buffer.byteLength} !== ${details.size})`);
720
+ }
721
+ }
722
+ /**
723
+ * Fetch chunks from {@link Parcel.details.chunkList}, reassemble, optionally decrypt, verify checksum.
724
+ * Encrypted parcels: pass `{ passphrase }` for PBKDF2 parcels, or `{ key }` for raw-key parcels.
725
+ */
726
+ async function reassemble(parcel, options = {}) {
727
+ const { details } = parcel;
728
+ const encrypted = isEncryptionEnabled(details, parcel.extra);
729
+ const buffers = await downloadAndVerifyChunks(details.chunkList);
730
+ const merged = concatBuffers(buffers);
731
+ if (!encrypted) {
732
+ verifyPlaintextSize(merged, details);
733
+ const fileChecksum = await sha256Hex(merged);
734
+ if (fileChecksum !== details.checksum) {
735
+ throw new Error("ParcelManager.reassemble: 重组后文件校验失败 (sha256 与 details.checksum 不一致)");
736
+ }
737
+ return merged;
738
+ }
739
+ const cryptoMeta = resolveCrypto(details, parcel.extra);
740
+ if (cryptoMeta?.iv == null || cryptoMeta.iv === "") {
741
+ throw new Error("ParcelManager.reassemble: 加密 Parcel 缺少 details.crypto.iv");
742
+ }
743
+ const iv = base64ToBytes(cryptoMeta.iv);
744
+ if (iv.length !== AES_GCM_IV_LENGTH) {
745
+ throw new Error("ParcelManager.reassemble: IV 长度无效");
746
+ }
747
+ const key = await resolveDecryptionKey(cryptoMeta, options);
748
+ const usedPassphrase = usesPassphraseDerivation(cryptoMeta);
749
+ const decrypted = await decryptPayload(merged, key, iv, usedPassphrase);
750
+ verifyPlaintextSize(decrypted, details);
751
+ const fileChecksum = await sha256Hex(decrypted);
752
+ if (fileChecksum !== details.checksum) {
753
+ throw new Error(usedPassphrase
754
+ ? "ParcelManager.reassemble: 解密后校验失败,口令错误或数据已损坏"
755
+ : "ParcelManager.reassemble: 解密后文件校验失败 (sha256 与 details.checksum 不一致)");
756
+ }
757
+ return decrypted;
758
+ }
759
+ const ParcelManager = {
760
+ create,
761
+ save,
762
+ reassemble,
763
+ };
764
+
765
+ function requireResponseData(response, label) {
766
+ if (response.data == null) {
767
+ const suffix = response.message != null ? ` (${response.message})` : "";
768
+ throw new Error(`${label}: no data${suffix}`);
769
+ }
770
+ return response.data;
771
+ }
772
+ /**
773
+ * One-shot publish: split (optional encrypt) → upload chunks → persist Parcel row.
774
+ * Orchestrates {@link ParcelManager} + {@link postParcel}.
775
+ */
776
+ async function publishParcel(input) {
777
+ const { file, adapters, name, value, tagList = [], extra, createOptions } = input;
778
+ const createResult = await ParcelManager.create(file, createOptions ?? {});
779
+ const draft = await ParcelManager.save(createResult, adapters, { name, value, tagList });
780
+ const response = await postParcel({
781
+ name: draft.name,
782
+ value: draft.value,
783
+ details: draft.details,
784
+ tagList: draft.tagList ?? [],
785
+ extra,
786
+ });
787
+ return {
788
+ parcel: requireResponseData(response, "postParcel"),
789
+ key: createResult.key,
790
+ };
791
+ }
792
+ /**
793
+ * Reassemble file bytes from a {@link Parcel} (chunk URLs in details).
794
+ */
795
+ async function restoreParcel(parcel, reassembleOptions) {
796
+ return ParcelManager.reassemble(parcel, reassembleOptions ?? {});
797
+ }
798
+ /**
799
+ * Fetch Parcel by id, then reassemble. Orchestrates {@link getParcel} + {@link restoreParcel}.
800
+ */
801
+ async function restoreParcelById(input) {
802
+ const response = await getParcel({ id: input.id });
803
+ const parcel = requireResponseData(response, "getParcel");
804
+ const file = await restoreParcel(parcel, input.reassembleOptions);
805
+ return { parcel, file };
806
+ }
807
+
808
+ function createUploadTracker() {
809
+ const handles = [];
810
+ return {
811
+ handles,
812
+ push(handle) {
813
+ handles.push(handle);
814
+ },
815
+ };
816
+ }
817
+
818
+ /** In-process registry for {@link StorageProviderModule}; syncs chunk resolvers on register. */
819
+ function createStorageProviderRegistry() {
820
+ const modules = new Map();
821
+ return {
822
+ register(module) {
823
+ modules.set(module.provider, module);
824
+ registerProviderChunkResolver(module);
825
+ },
826
+ get(provider) {
827
+ const found = modules.get(provider);
828
+ if (found == null) {
829
+ const available = [...modules.keys()].join(", ") || "(none)";
830
+ throw new Error(`Unknown storage provider: ${provider}. Registered: ${available}`);
831
+ }
832
+ return found;
833
+ },
834
+ has(provider) {
835
+ return modules.has(provider);
836
+ },
837
+ list() {
838
+ return [...modules.keys()];
839
+ },
840
+ async probeAll() {
841
+ const out = {};
842
+ for (const [name, module] of modules) {
843
+ if (module.probe == null) {
844
+ out[name] = { ok: true, detail: { skipped: true } };
845
+ continue;
846
+ }
847
+ out[name] = await module.probe();
848
+ }
849
+ return out;
850
+ },
851
+ };
852
+ }
853
+
854
+ var CategoryRepo;
855
+ (function (CategoryRepo) {
856
+ /** Project */
857
+ CategoryRepo["REPO"] = "repo";
858
+ })(CategoryRepo || (CategoryRepo = {}));
859
+ /** `Repo.details.usage` for task worker remote discovery ({@link registerTasks}). */
860
+ const TASK_REPO_USAGE = "task";
861
+
862
+ const REPO_USAGE_FIELD = "details->>usage";
863
+ const getScanRemoteRepoValuesSchema = z.object({
864
+ usage: z.string().trim().min(1),
865
+ });
866
+ /**
867
+ * Scan `Repo.value` keys for `category=repo` with matching `details.usage`.
868
+ * Returns `{ data: string[] }` on success; validation and DB failures use `{ error }` (never throws).
869
+ */
870
+ const getScanRemoteRepoValues = async (payload) => {
871
+ try {
872
+ return await getScanRemoteRepoValuesValidated(payload);
873
+ }
874
+ catch (error) {
875
+ const message = error instanceof Error ? error.message : String(error);
876
+ return generateResponse.error(message);
877
+ }
878
+ };
879
+ const getScanRemoteRepoValuesValidated = validateWithSchema(getScanRemoteRepoValuesSchema, "getScanRemoteRepoValuesSchema")(async ({ usage }) => {
880
+ try {
881
+ const { data } = await scanTargetList({
882
+ category: CategoryRepo.REPO,
883
+ selectFields: "value",
884
+ orderBy: { field: "value", ascending: true },
885
+ filterList: [{ field: REPO_USAGE_FIELD, operator: "eq", value: usage }],
886
+ });
887
+ const values = (data ?? [])
888
+ .map((row) => row.value?.trim())
889
+ .filter((value) => value != null && value !== "");
890
+ return generateResponse.success([...new Set(values)]);
891
+ }
892
+ catch (error) {
893
+ const message = error instanceof Error ? error.message : String(error);
894
+ return generateResponse.error(message);
895
+ }
896
+ });
897
+
898
+ var ServiceLifecycleStatus;
899
+ (function (ServiceLifecycleStatus) {
900
+ ServiceLifecycleStatus["ACTIVE"] = "ACTIVE";
901
+ ServiceLifecycleStatus["DEPRECATED"] = "DEPRECATED";
902
+ ServiceLifecycleStatus["SUNSET"] = "SUNSET";
903
+ })(ServiceLifecycleStatus || (ServiceLifecycleStatus = {}));
904
+
905
+ var CategoryService;
906
+ (function (CategoryService) {
907
+ CategoryService["SERVICE"] = "service";
908
+ })(CategoryService || (CategoryService = {}));
909
+ var CategoryApi;
910
+ (function (CategoryApi) {
911
+ CategoryApi["API"] = "api";
912
+ })(CategoryApi || (CategoryApi = {}));
913
+ var ApiMethod;
914
+ (function (ApiMethod) {
915
+ ApiMethod["POST"] = "POST";
916
+ ApiMethod["GET"] = "GET";
917
+ ApiMethod["PUT"] = "PUT";
918
+ ApiMethod["DELETE"] = "DELETE";
919
+ })(ApiMethod || (ApiMethod = {}));
920
+
921
+ const targetIdSchema = z.string().trim().min(1);
922
+ const enumMemberSchema = z.object({
923
+ key: z.string().trim().min(1),
924
+ value: z.string(),
925
+ });
926
+ const fieldPresenceSchema = z.object({
927
+ nullable: z.boolean(),
928
+ optional: z.boolean(),
929
+ });
930
+ const schemaDefinitionSchema = z.lazy(() => z.discriminatedUnion("type", [
931
+ fieldPresenceSchema.extend({
932
+ type: z.literal("string"),
933
+ min: z.number().optional(),
934
+ max: z.number().optional(),
935
+ regex: z.string().optional(),
936
+ default: z.string().optional(),
937
+ }),
938
+ fieldPresenceSchema.extend({
939
+ type: z.literal("number"),
940
+ min: z.number().optional(),
941
+ max: z.number().optional(),
942
+ default: z.number().optional(),
943
+ }),
944
+ fieldPresenceSchema.extend({
945
+ type: z.literal("boolean"),
946
+ default: z.boolean().optional(),
947
+ }),
948
+ fieldPresenceSchema.extend({
949
+ type: z.literal("unknown"),
950
+ default: z.unknown().optional(),
951
+ }),
952
+ fieldPresenceSchema.extend({
953
+ type: z.literal("enum"),
954
+ members: z.array(enumMemberSchema).min(1),
955
+ defaultKey: z.string().trim().min(1).optional(),
956
+ }),
957
+ fieldPresenceSchema.extend({
958
+ type: z.literal("object"),
959
+ fields: z.array(fieldDefinitionSchema),
960
+ default: z.record(z.unknown()).optional(),
961
+ }),
962
+ fieldPresenceSchema.extend({
963
+ type: z.literal("array"),
964
+ items: schemaDefinitionSchema,
965
+ min: z.number().int().nonnegative().optional(),
966
+ max: z.number().int().nonnegative().optional(),
967
+ default: z.unknown().optional(),
968
+ }),
969
+ ]));
970
+ const fieldDefinitionSchema = z.intersection(z.object({ fieldName: z.string().trim().min(1) }), schemaDefinitionSchema);
971
+ const serviceLifecycleSchema = z.object({
972
+ status: z.nativeEnum(ServiceLifecycleStatus),
973
+ activeSince: z.string().trim().min(1),
974
+ deprecatedAt: z.string().nullable(),
975
+ sunsetAt: z.string().nullable(),
976
+ });
977
+ const apiDetailsSchema = z.object({
978
+ method: z.nativeEnum(ApiMethod),
979
+ path: z.string().trim().min(1),
980
+ endpoint: z.string().trim().min(1),
981
+ request: z.object({
982
+ query: z.array(fieldDefinitionSchema),
983
+ }),
984
+ response: z.object({
985
+ "200": z.array(fieldDefinitionSchema),
986
+ }),
987
+ manifestVersion: z.number().int().nonnegative(),
988
+ lifecycle: serviceLifecycleSchema,
989
+ });
990
+ const serviceDetailsSchema = z.object({
991
+ manifestVersion: z.number().int().nonnegative(),
992
+ apiKeys: z.array(z.string().trim().min(1)),
993
+ dependencies: z.array(z.string().trim().min(1)).default([]),
994
+ lifecycle: serviceLifecycleSchema,
995
+ });
996
+ const postApiSchema = z.object({
997
+ name: z.string().trim().min(1),
998
+ value: z.string().trim().min(1),
999
+ details: apiDetailsSchema,
1000
+ tagList: z.array(z.string()).optional().default([]),
1001
+ extra: z.string().optional(),
1002
+ });
1003
+ const getApiSchema = z
1004
+ .object({
1005
+ id: targetIdSchema.optional(),
1006
+ value: z.string().trim().min(1).optional(),
1007
+ })
1008
+ .refine((payload) => {
1009
+ const hasId = payload.id != null && payload.id !== "";
1010
+ const hasValue = payload.value != null && payload.value !== "";
1011
+ return hasId !== hasValue;
1012
+ }, { message: "Provide exactly one of id or value" });
1013
+ const getServiceSchema = z
1014
+ .object({
1015
+ id: targetIdSchema.optional(),
1016
+ value: z.string().trim().min(1).optional(),
1017
+ /** When set, filters `details.lifecycle.status` at query time. */
1018
+ lifecycleStatus: z.nativeEnum(ServiceLifecycleStatus).optional(),
1019
+ })
1020
+ .refine((payload) => {
1021
+ const hasId = payload.id != null && payload.id !== "";
1022
+ const hasValue = payload.value != null && payload.value !== "";
1023
+ return hasId !== hasValue;
1024
+ }, { message: "Provide exactly one of id or value" });
1025
+ const postServiceSchema = z.object({
1026
+ name: z.string().trim().min(1),
1027
+ value: z.string().trim().min(1),
1028
+ details: serviceDetailsSchema,
1029
+ tagList: z.array(z.string()).optional().default([]),
1030
+ extra: z.string().optional(),
1031
+ });
1032
+ const apiCategoryFilter = {
1033
+ field: "category",
1034
+ operator: "eq",
1035
+ value: CategoryApi.API,
1036
+ };
1037
+ const serviceCategoryFilter = {
1038
+ field: "category",
1039
+ operator: "eq",
1040
+ value: CategoryService.SERVICE,
1041
+ };
1042
+ const SERVICE_LIFECYCLE_STATUS_FIELD$1 = "details->lifecycle->>status";
1043
+ function buildServiceLookupFilters(payload) {
1044
+ const filters = [serviceCategoryFilter];
1045
+ if (payload.id != null && payload.id !== "") ;
1046
+ else {
1047
+ filters.push({ field: "value", operator: "eq", value: payload.value });
1048
+ }
1049
+ if (payload.lifecycleStatus != null) {
1050
+ filters.push({
1051
+ field: SERVICE_LIFECYCLE_STATUS_FIELD$1,
1052
+ operator: "eq",
1053
+ value: payload.lifecycleStatus,
1054
+ });
1055
+ }
1056
+ return filters;
1057
+ }
1058
+ /** Register an Api contract row (`category=api`). */
1059
+ const postApi = validateWithSchema(postApiSchema, "postApiSchema")(async ({ name, value, details, tagList, extra }) => {
1060
+ return createTarget({
1061
+ payload: { name, value, details, tagList, extra },
1062
+ createFn: () => ({
1063
+ name,
1064
+ value,
1065
+ category: CategoryApi.API,
1066
+ tagList,
1067
+ extra,
1068
+ details: details,
1069
+ }),
1070
+ });
1071
+ });
1072
+ /** Fetch an Api by id or by {@link Api.value} key (`category=api`). */
1073
+ const getApi = validateWithSchema(getApiSchema, "getApiSchema")(async (payload) => {
1074
+ if (payload.id != null && payload.id !== "") {
1075
+ const result = await getTarget({
1076
+ id: payload.id,
1077
+ filterList: [apiCategoryFilter],
1078
+ });
1079
+ return {
1080
+ ...result,
1081
+ data: result.data,
1082
+ };
1083
+ }
1084
+ const result = await getPossibleTarget({
1085
+ filterList: [apiCategoryFilter, { field: "value", operator: "eq", value: payload.value }],
1086
+ });
1087
+ if (result.data == null) {
1088
+ return {
1089
+ ...result,
1090
+ data: undefined,
1091
+ };
1092
+ }
1093
+ return {
1094
+ ...result,
1095
+ data: result.data,
1096
+ };
1097
+ });
1098
+ /** Fetch a Service by id or by {@link Service.value} key (`category=service`). */
1099
+ const getService = validateWithSchema(getServiceSchema, "getServiceSchema")(async (payload) => {
1100
+ const filterList = buildServiceLookupFilters(payload);
1101
+ if (payload.id != null && payload.id !== "") {
1102
+ const result = await getTarget({
1103
+ id: payload.id,
1104
+ filterList,
1105
+ });
1106
+ return {
1107
+ ...result,
1108
+ data: result.data,
1109
+ };
1110
+ }
1111
+ const result = await getPossibleTarget({
1112
+ filterList,
1113
+ });
1114
+ if (result.data == null) {
1115
+ return {
1116
+ ...result,
1117
+ data: undefined,
1118
+ };
1119
+ }
1120
+ return {
1121
+ ...result,
1122
+ data: result.data,
1123
+ };
1124
+ });
1125
+ /** Register a Service catalog row (`category=service`). */
1126
+ const postService = validateWithSchema(postServiceSchema, "postServiceSchema")(async ({ name, value, details, tagList, extra }) => {
1127
+ return createTarget({
1128
+ payload: { name, value, details, tagList, extra },
1129
+ createFn: () => ({
1130
+ name,
1131
+ value,
1132
+ category: CategoryService.SERVICE,
1133
+ tagList,
1134
+ extra,
1135
+ details: details,
1136
+ }),
1137
+ });
1138
+ });
1139
+
1140
+ const DISCOVER_LIFECYCLE_STATUS = ServiceLifecycleStatus.ACTIVE;
1141
+ const SERVICE_LIFECYCLE_STATUS_FIELD = "details->lifecycle->>status";
1142
+ async function lookupServicePrimary(value) {
1143
+ const response = await getService({ value, lifecycleStatus: DISCOVER_LIFECYCLE_STATUS });
1144
+ return response.data ?? null;
1145
+ }
1146
+ async function lookupServiceByScan(value) {
1147
+ const { data } = await scanTargetList({
1148
+ category: CategoryService.SERVICE,
1149
+ orderBy: { field: "value", ascending: true },
1150
+ maxRows: 1,
1151
+ filterList: [
1152
+ { field: "value", operator: "eq", value },
1153
+ {
1154
+ field: SERVICE_LIFECYCLE_STATUS_FIELD,
1155
+ operator: "eq",
1156
+ value: DISCOVER_LIFECYCLE_STATUS,
1157
+ },
1158
+ ],
1159
+ });
1160
+ return data?.[0] ?? null;
1161
+ }
1162
+ async function resolveDiscoverFailureReason(value) {
1163
+ const response = await getService({ value });
1164
+ if (response.data == null) {
1165
+ return "not-found";
1166
+ }
1167
+ return "not-available";
1168
+ }
1169
+ /**
1170
+ * Discover a single service by {@link Service.value}.
1171
+ * Only returns services with `lifecycle.status === ACTIVE` (filtered at query time).
1172
+ *
1173
+ * Lookup: primary `getService` → fallback `scanTargetList` by value.
1174
+ */
1175
+ async function discoverService(input) {
1176
+ const value = input.value.trim();
1177
+ const logger = createLogger({
1178
+ module: "discoverService",
1179
+ traceId: input.traceId,
1180
+ labels: { serviceValue: value },
1181
+ });
1182
+ if (value === "") {
1183
+ const message = "discoverService: value must not be empty";
1184
+ logger.warn(message, { topic: "service", data: { value: input.value } });
1185
+ return generateResponse.error(message, undefined, "SERVICE_VALUE_REQUIRED");
1186
+ }
1187
+ try {
1188
+ logger.info("开始发现服务", {
1189
+ topic: "service",
1190
+ data: { value, lifecycleStatus: DISCOVER_LIFECYCLE_STATUS },
1191
+ });
1192
+ let service = await lookupServicePrimary(value);
1193
+ let source = "primary";
1194
+ if (service == null) {
1195
+ logger.warn("主路径未命中,尝试 catalog 扫描回退", {
1196
+ topic: "service",
1197
+ data: { value, step: "scan-fallback", lifecycleStatus: DISCOVER_LIFECYCLE_STATUS },
1198
+ });
1199
+ service = await lookupServiceByScan(value);
1200
+ source = "scan";
1201
+ }
1202
+ if (service == null) {
1203
+ const reason = await resolveDiscoverFailureReason(value);
1204
+ if (reason === "not-available") {
1205
+ const message = `Service ${value} is not available (lifecycle is not ACTIVE)`;
1206
+ logger.warn("服务已注册但不可用", {
1207
+ topic: "service",
1208
+ data: { value, step: "not-available", lifecycleStatus: DISCOVER_LIFECYCLE_STATUS },
1209
+ });
1210
+ return generateResponse.error(message, undefined, "SERVICE_NOT_AVAILABLE");
1211
+ }
1212
+ const message = `Service not found: ${value}`;
1213
+ logger.error("服务未发现", {
1214
+ topic: "service",
1215
+ data: { value, step: "not-found", tried: ["primary", "scan"] },
1216
+ });
1217
+ return generateResponse.error(message, undefined, "SERVICE_NOT_FOUND");
1218
+ }
1219
+ logger.info("服务发现成功", {
1220
+ topic: "service",
1221
+ data: {
1222
+ value,
1223
+ source,
1224
+ serviceId: service.id,
1225
+ lifecycleStatus: service.details.lifecycle.status,
1226
+ apiKeyCount: service.details.apiKeys.length,
1227
+ dependencyCount: service.details.dependencies.length,
1228
+ },
1229
+ });
1230
+ return generateResponse.success(service);
1231
+ }
1232
+ catch (error) {
1233
+ const message = error instanceof Error ? error.message : String(error);
1234
+ logger.error("服务发现失败", {
1235
+ topic: "service",
1236
+ data: { value, message },
1237
+ });
1238
+ let service = null;
1239
+ try {
1240
+ service = await lookupServiceByScan(value);
1241
+ }
1242
+ catch (fallbackError) {
1243
+ const fallbackMessage = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
1244
+ logger.error("扫描回退失败", {
1245
+ topic: "service",
1246
+ data: { value, message: fallbackMessage },
1247
+ });
1248
+ return generateResponse.error(message, undefined, "SERVICE_DISCOVER_FAILED");
1249
+ }
1250
+ if (service != null) {
1251
+ logger.warn("主路径异常后扫描回退成功", {
1252
+ topic: "service",
1253
+ data: { value, serviceId: service.id, primaryError: message },
1254
+ });
1255
+ return generateResponse.success(service);
1256
+ }
1257
+ return generateResponse.error(message, undefined, "SERVICE_DISCOVER_FAILED");
1258
+ }
1259
+ }
1260
+
1261
+ const RETRYABLE_CAUSE_CODES = new Set([
1262
+ "UND_ERR_CONNECT_TIMEOUT",
1263
+ "UND_ERR_HEADERS_TIMEOUT",
1264
+ "UND_ERR_BODY_TIMEOUT",
1265
+ "UND_ERR_SOCKET",
1266
+ "ECONNRESET",
1267
+ "ECONNREFUSED",
1268
+ "ENOTFOUND",
1269
+ "ETIMEDOUT",
1270
+ "EPIPE",
1271
+ "EAI_AGAIN",
1272
+ ]);
1273
+ function errorCause(error) {
1274
+ if (error instanceof Error) {
1275
+ return error.cause;
1276
+ }
1277
+ return undefined;
1278
+ }
1279
+ function classifyNetworkError(error) {
1280
+ if (!(error instanceof Error)) {
1281
+ return { kind: "unknown", retryable: false, code: "", detail: String(error) };
1282
+ }
1283
+ const cause = errorCause(error);
1284
+ const code = cause?.code ?? "";
1285
+ const causeMessage = cause?.message ?? "";
1286
+ const message = error.message;
1287
+ const tlsDisconnect = /TLS connection was established/i.test(causeMessage) ||
1288
+ /secure TLS connection/i.test(causeMessage) ||
1289
+ /socket disconnected before secure TLS/i.test(message) ||
1290
+ /socket disconnected before secure TLS/i.test(causeMessage);
1291
+ if (tlsDisconnect) {
1292
+ return {
1293
+ kind: "tls_disconnect",
1294
+ retryable: true,
1295
+ code,
1296
+ detail: causeMessage || message,
1297
+ };
1298
+ }
1299
+ if (code === "UND_ERR_CONNECT_TIMEOUT" || error.name === "TimeoutError" || error.name === "AbortError") {
1300
+ return {
1301
+ kind: error.name === "AbortError" ? "timeout" : "connect_timeout",
1302
+ retryable: true,
1303
+ code,
1304
+ detail: causeMessage || message,
1305
+ };
1306
+ }
1307
+ if (code === "ECONNREFUSED") {
1308
+ return {
1309
+ kind: "connection_refused",
1310
+ retryable: true,
1311
+ code,
1312
+ detail: causeMessage || message,
1313
+ };
1314
+ }
1315
+ if (code === "ENOTFOUND" || code === "EAI_AGAIN") {
1316
+ return {
1317
+ kind: "dns_error",
1318
+ retryable: code === "EAI_AGAIN",
1319
+ code,
1320
+ detail: causeMessage || message,
1321
+ };
1322
+ }
1323
+ if (code === "UND_ERR_SOCKET" ||
1324
+ code === "ECONNRESET" ||
1325
+ code === "EPIPE" ||
1326
+ /socket disconnected/i.test(causeMessage) ||
1327
+ /other side closed/i.test(causeMessage)) {
1328
+ return {
1329
+ kind: "socket_closed",
1330
+ retryable: true,
1331
+ code,
1332
+ detail: causeMessage || message,
1333
+ };
1334
+ }
1335
+ if (RETRYABLE_CAUSE_CODES.has(code)) {
1336
+ return {
1337
+ kind: "proxy_error",
1338
+ retryable: true,
1339
+ code,
1340
+ detail: causeMessage || message,
1341
+ };
1342
+ }
1343
+ return {
1344
+ kind: "unknown",
1345
+ retryable: false,
1346
+ code,
1347
+ detail: causeMessage ? `${message}: ${causeMessage}` : message,
1348
+ };
1349
+ }
1350
+ function formatNetworkError(error, label, options = {}) {
1351
+ const classified = classifyNetworkError(error);
1352
+ const hint = options.hint ?? "";
1353
+ switch (classified.kind) {
1354
+ case "connect_timeout":
1355
+ return `${label}: connect timeout${hint}`;
1356
+ case "tls_disconnect":
1357
+ return `${label}: TLS handshake dropped${hint}. Often transient through proxies — retries may succeed.`;
1358
+ case "connection_refused":
1359
+ return `${label}: connection refused — ${classified.detail}${hint}`;
1360
+ case "dns_error":
1361
+ return `${label}: DNS lookup failed (${classified.code}) — ${classified.detail}`;
1362
+ case "socket_closed":
1363
+ return (`${label}: connection closed mid-request (${classified.code || "socket"}) — ` +
1364
+ `${classified.detail}${hint}`);
1365
+ case "timeout":
1366
+ return `${label}: request timeout — ${classified.detail}${hint}`;
1367
+ case "proxy_error":
1368
+ return `${label}: network/proxy error (${classified.code}) — ${classified.detail}${hint}`;
1369
+ default:
1370
+ return `${label}: ${classified.detail}${hint}`;
1371
+ }
1372
+ }
1373
+
1374
+ function sleep(ms) {
1375
+ return new Promise((resolve) => setTimeout(resolve, ms));
1376
+ }
1377
+ /** Default HTTP statuses that trigger retry (429, 5xx). */
1378
+ function isRetryableHttpStatus(status) {
1379
+ return status === 429 || status >= 500;
1380
+ }
1381
+ function requestHasBody(init) {
1382
+ return init.body != null;
1383
+ }
1384
+ function backoffMs(retryBaseMs, attempt, response, maxBackoffMs) {
1385
+ const retryAfter = response?.headers.get("Retry-After");
1386
+ if (retryAfter != null) {
1387
+ const seconds = Number(retryAfter);
1388
+ if (Number.isFinite(seconds) && seconds > 0) {
1389
+ const delayMs = seconds * 1000;
1390
+ return maxBackoffMs != null ? Math.min(delayMs, maxBackoffMs) : delayMs;
1391
+ }
1392
+ }
1393
+ let delayMs = retryBaseMs * 2 ** (attempt - 1);
1394
+ if (maxBackoffMs != null) {
1395
+ delayMs = Math.min(delayMs, maxBackoffMs);
1396
+ }
1397
+ return delayMs;
1398
+ }
1399
+ async function fetchOnce(url, init, timeoutMs, dispatcher) {
1400
+ const options = {
1401
+ ...init,
1402
+ signal: AbortSignal.timeout(timeoutMs),
1403
+ };
1404
+ if (dispatcher != null) {
1405
+ options.dispatcher = dispatcher;
1406
+ }
1407
+ return fetch(url, options);
1408
+ }
1409
+ async function fetchWithRetry(url, initOrFactory, options) {
1410
+ const maxAttempts = options.maxAttempts ?? 1;
1411
+ const retryBaseMs = options.retryBaseMs ?? 2_000;
1412
+ const isRetryableStatus = options.isRetryableStatus ?? isRetryableHttpStatus;
1413
+ const buildInit = typeof initOrFactory === "function" ? initOrFactory : () => initOrFactory;
1414
+ if (maxAttempts > 1 && typeof initOrFactory !== "function" && requestHasBody(initOrFactory)) {
1415
+ throw new Error(`${options.label}: retry requires an init factory when request body may be consumed`);
1416
+ }
1417
+ let lastError = null;
1418
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1419
+ try {
1420
+ const response = await fetchOnce(url, buildInit(), options.timeoutMs, options.dispatcher);
1421
+ if (!response.ok && isRetryableStatus(response.status) && attempt < maxAttempts) {
1422
+ const delayMs = backoffMs(retryBaseMs, attempt, response, options.maxBackoffMs);
1423
+ if (options.logger != null) {
1424
+ options.logger.warn("retrying after HTTP error", {
1425
+ topic: "fetch",
1426
+ data: {
1427
+ label: options.label,
1428
+ attempt,
1429
+ status: response.status,
1430
+ delayMs,
1431
+ },
1432
+ });
1433
+ }
1434
+ await sleep(delayMs);
1435
+ continue;
1436
+ }
1437
+ if (attempt > 1 && options.logger != null) {
1438
+ options.logger.info("request succeeded after retry", {
1439
+ topic: "fetch",
1440
+ data: { label: options.label, attempt },
1441
+ });
1442
+ }
1443
+ return response;
1444
+ }
1445
+ catch (error) {
1446
+ const classified = classifyNetworkError(error);
1447
+ lastError = new Error(formatNetworkError(error, options.label, { hint: options.hint }));
1448
+ if (classified.retryable && attempt < maxAttempts) {
1449
+ const delayMs = backoffMs(retryBaseMs, attempt, undefined, options.maxBackoffMs);
1450
+ if (options.logger != null) {
1451
+ options.logger.warn("retrying after network error", {
1452
+ topic: "fetch",
1453
+ data: {
1454
+ label: options.label,
1455
+ attempt,
1456
+ maxAttempts,
1457
+ kind: classified.kind,
1458
+ code: classified.code,
1459
+ delayMs,
1460
+ },
1461
+ });
1462
+ }
1463
+ await sleep(delayMs);
1464
+ continue;
1465
+ }
1466
+ throw lastError;
1467
+ }
1468
+ }
1469
+ throw lastError ?? new Error(`${options.label}: request failed`);
1470
+ }
1471
+ async function fetchBinaryWithRetry(url, init, options) {
1472
+ const response = await fetchWithRetry(url, init, options);
1473
+ if (!response.ok) {
1474
+ throw new Error(`${options.label}: HTTP ${response.status}`);
1475
+ }
1476
+ return response.arrayBuffer();
1477
+ }
1478
+
1479
+ function fileBaseName(raw) {
1480
+ const normalized = raw.replace(/\\/g, "/");
1481
+ const parts = normalized.split("/");
1482
+ return parts.at(-1) ?? normalized;
1483
+ }
1484
+ /**
1485
+ * Safe display / storage file name from a browser or filesystem path string.
1486
+ * Strips directory segments and forbidden characters.
1487
+ */
1488
+ function sanitizeFileName(raw, options = {}) {
1489
+ const maxLength = options.maxLength ?? 200;
1490
+ const base = fileBaseName(raw);
1491
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: intentionally strip ASCII control chars (0x00–0x1f)
1492
+ const cleaned = base.replace(/[\x00-\x1f<>:"/\\|?*]+/g, "_").trim();
1493
+ if (cleaned === "" || cleaned === "." || cleaned === "..") {
1494
+ if (options.fallback != null) {
1495
+ return options.fallback.slice(0, maxLength);
1496
+ }
1497
+ throw new Error("Invalid file name");
1498
+ }
1499
+ return cleaned.slice(0, maxLength);
1500
+ }
1501
+ /** Parcel.name / value default — 200 char cap. */
1502
+ function sanitizeParcelFileName(raw) {
1503
+ return sanitizeFileName(raw, { maxLength: 200 });
1504
+ }
1505
+
1506
+ /**
1507
+ * Normalize unknown catch / rejection values to {@link Error}.
1508
+ *
1509
+ * `catch` and Promise rejections are typed `unknown` because `throw` can be
1510
+ * anything (string, number, plain object). Call sites that need `.message`,
1511
+ * re-throw, or `instanceof Error` checks should normalize first.
1512
+ */
1513
+ function toError(value) {
1514
+ return value instanceof Error ? value : new Error(String(value));
1515
+ }
1516
+ /** Error message safe for log `context` fields (JSON-serializable). */
1517
+ function getErrorMessage(value) {
1518
+ return toError(value).message;
1519
+ }
1520
+
1521
+ /** Log topic for task domain (`topic` field on structured logs). */
1522
+ const LOG_TOPIC_TASK = "task";
1523
+ const CRITICAL_UNKNOWN_TASK_TRACE_ID = "CRITICAL_UNKNOWN_TASK_TRACE_ID";
1524
+
1525
+ var CategoryTask;
1526
+ (function (CategoryTask) {
1527
+ CategoryTask["TASK"] = "task";
1528
+ })(CategoryTask || (CategoryTask = {}));
1529
+ var TaskStatus;
1530
+ (function (TaskStatus) {
1531
+ TaskStatus["OPEN"] = "OPEN";
1532
+ TaskStatus["TODO"] = "TODO";
1533
+ TaskStatus["DOING"] = "DOING";
1534
+ TaskStatus["DONE"] = "DONE";
1535
+ TaskStatus["CLOSED"] = "CLOSED";
1536
+ })(TaskStatus || (TaskStatus = {}));
1537
+ /** Named transitions for {@link patchChangeTaskStatus} — verb aligned with state machine edges */
1538
+ var TaskStatusAction;
1539
+ (function (TaskStatusAction) {
1540
+ TaskStatusAction["PUBLISH"] = "publish";
1541
+ TaskStatusAction["CLAIM"] = "claim";
1542
+ TaskStatusAction["RESET"] = "reset";
1543
+ TaskStatusAction["CANCEL"] = "cancel";
1544
+ TaskStatusAction["CLOSE"] = "close";
1545
+ TaskStatusAction["FINISH"] = "finish";
1546
+ })(TaskStatusAction || (TaskStatusAction = {}));
1547
+ var ResultCode;
1548
+ (function (ResultCode) {
1549
+ ResultCode[ResultCode["SUCCESS"] = 1000] = "SUCCESS";
1550
+ /** 3xxx 依赖 / 外部 */
1551
+ ResultCode[ResultCode["PARAMS_NOT_VALID"] = 3001] = "PARAMS_NOT_VALID";
1552
+ ResultCode[ResultCode["REPO_NOT_VALID"] = 3002] = "REPO_NOT_VALID";
1553
+ /** 4xxx — 运行环境 */
1554
+ ResultCode[ResultCode["TIMEOUT"] = 4001] = "TIMEOUT";
1555
+ ResultCode[ResultCode["CANCELLED"] = 4002] = "CANCELLED";
1556
+ ResultCode[ResultCode["NODE_UNAVAILABLE"] = 4003] = "NODE_UNAVAILABLE";
1557
+ ResultCode[ResultCode["UNKNOWN_ERROR"] = 9999] = "UNKNOWN_ERROR";
1558
+ })(ResultCode || (ResultCode = {}));
1559
+
1560
+ const TASK_STATUS_FIELD = "details->>status";
1561
+ const TASK_NODE_ID_FIELD = "details->>nodeId";
1562
+ // ─── State machine ───────────────────────────────────────────────────────────
1563
+ /**
1564
+ * Task state machine (field: `details.status`)
1565
+ *
1566
+ * ```text
1567
+ * publish claim (CLAIM / patchClaimTask) finish
1568
+ * OPEN ──────► TODO ──────────────────► DOING ─────────────► DONE
1569
+ * │ │ reset │ cancel │ close
1570
+ * │ │ └──────► TODO │
1571
+ * └──────── reset ─┴──────────────────────── reset ────────────┘
1572
+ * | │
1573
+ * └──────────────────── close ─────────────────────────────────┘
1574
+ * ▼
1575
+ * CLOSED
1576
+ * ```
1577
+ *
1578
+ * | TaskStatusAction | from | to | lock filters | caller |
1579
+ * |------------------|-------------------|--------|--------------------------------|---------------|
1580
+ * | PUBLISH | OPEN | TODO | status = OPEN | scheduler |
1581
+ * | CLAIM | TODO | DOING | status = TODO | worker |
1582
+ * | RESET | TODO | OPEN | status = TODO (no nodeId) | admin |
1583
+ * | RESET | DOING, DONE | OPEN | status ∈ {DOING,DONE} + nodeId | worker |
1584
+ * | CANCEL | DOING | TODO | DOING + nodeId | worker |
1585
+ * | FINISH | DOING | DONE | DOING + nodeId | worker |
1586
+ * | CLOSE | OPEN, DONE | CLOSED | status ∈ {OPEN, DONE} | scheduler |
1587
+ *
1588
+ * RESET: omit `nodeId` to reset from **TODO**; pass `nodeId` to reset from **DOING** or **DONE**.
1589
+ *
1590
+ * All public APIs validate input with Zod (`validateWithSchema`). Optimistic locks live in
1591
+ * `optimisticLockFilterList` on UPDATE — see `.cursor/skills/optimistic-lock-update/SKILL.md`.
1592
+ */
1593
+ // ─── Zod schemas ─────────────────────────────────────────────────────────────
1594
+ const taskIdSchema = z.string().trim().min(1);
1595
+ const nodeIdSchema = z.string().trim().min(1);
1596
+ /** Optional — orchestrator (e.g. TaskNode loop) passes its trace to correlate logs. */
1597
+ const traceIdSchema$1 = z.string().trim().min(1).optional();
1598
+ z.string().trim().min(1).nullable().optional();
1599
+ const patchChangeTaskStatusBaseSchema = {
1600
+ id: taskIdSchema,
1601
+ extra: z.string().optional(),
1602
+ traceId: traceIdSchema$1,
1603
+ };
1604
+ /** Shared by CLAIM / CANCEL / FINISH — worker-side actions that require nodeId */
1605
+ const patchChangeTaskStatusNodeOwnedSchema = {
1606
+ ...patchChangeTaskStatusBaseSchema,
1607
+ nodeId: nodeIdSchema,
1608
+ };
1609
+ const patchChangeTaskStatusSchema = z.discriminatedUnion("action", [
1610
+ z.object({
1611
+ ...patchChangeTaskStatusBaseSchema,
1612
+ action: z.literal(TaskStatusAction.PUBLISH),
1613
+ }),
1614
+ z.object({
1615
+ ...patchChangeTaskStatusBaseSchema,
1616
+ action: z.literal(TaskStatusAction.CLOSE),
1617
+ }),
1618
+ z.object({
1619
+ ...patchChangeTaskStatusNodeOwnedSchema,
1620
+ action: z.literal(TaskStatusAction.CLAIM),
1621
+ }),
1622
+ z.object({
1623
+ ...patchChangeTaskStatusBaseSchema,
1624
+ action: z.literal(TaskStatusAction.RESET),
1625
+ nodeId: nodeIdSchema.optional(),
1626
+ }),
1627
+ z.object({
1628
+ ...patchChangeTaskStatusNodeOwnedSchema,
1629
+ action: z.literal(TaskStatusAction.CANCEL),
1630
+ }),
1631
+ z.object({
1632
+ ...patchChangeTaskStatusNodeOwnedSchema,
1633
+ action: z.literal(TaskStatusAction.FINISH),
1634
+ cost: z.number().min(0),
1635
+ }),
1636
+ ]);
1637
+ const patchTaskProgressSchema = z.object({
1638
+ id: taskIdSchema,
1639
+ progress: z.number().min(0).max(100),
1640
+ nodeId: nodeIdSchema,
1641
+ traceId: traceIdSchema$1,
1642
+ });
1643
+ const patchClaimTaskSchema = z.object({
1644
+ nodeId: nodeIdSchema,
1645
+ availableTaskList: z.array(z.string()).min(1),
1646
+ traceId: traceIdSchema$1,
1647
+ });
1648
+ // ─── Optimistic lock helpers ─────────────────────────────────────────────────
1649
+ function lockOnStatus(...allowed) {
1650
+ if (allowed.length === 1) {
1651
+ return [{ field: TASK_STATUS_FIELD, operator: "eq", value: allowed[0] }];
1652
+ }
1653
+ return [{ field: TASK_STATUS_FIELD, operator: "in", value: allowed }];
1654
+ }
1655
+ function lockOnOwnerNode(nodeId) {
1656
+ return { field: TASK_NODE_ID_FIELD, operator: "eq", value: nodeId };
1657
+ }
1658
+ /** DOING row owned by `nodeId` — used by FINISH, CANCEL, patchTaskProgress */
1659
+ function lockOnDoingOwner(nodeId) {
1660
+ return [...lockOnStatus(TaskStatus.DOING), lockOnOwnerNode(nodeId)];
1661
+ }
1662
+ /** TODO without nodeId; DOING/DONE with owner when nodeId is provided */
1663
+ function lockOnReset(nodeId) {
1664
+ if (nodeId != null) {
1665
+ return [...lockOnStatus(TaskStatus.DOING, TaskStatus.DONE), lockOnOwnerNode(nodeId)];
1666
+ }
1667
+ return lockOnStatus(TaskStatus.TODO);
1668
+ }
1669
+ function clearExecutionState() {
1670
+ return { progress: 0, nodeId: null, result: undefined };
1671
+ }
1672
+ // ─── Internal transitions ────────────────────────────────────────────────────
1673
+ async function transitionTask({ id, optimisticLockFilterList, updateFn, updateExtraFn, }) {
1674
+ return updateTargetDetails({
1675
+ id,
1676
+ optimisticLockFilterList,
1677
+ updateFn,
1678
+ updateExtraFn,
1679
+ });
1680
+ }
1681
+ function logTaskTransition(logger, action, task, data) {
1682
+ logger.debug("任務狀態遷移成功", {
1683
+ topic: LOG_TOPIC_TASK,
1684
+ data: {
1685
+ action,
1686
+ taskId: task.id,
1687
+ taskValue: task.value,
1688
+ status: task.details.status,
1689
+ nodeId: task.details.nodeId,
1690
+ ...data,
1691
+ },
1692
+ });
1693
+ }
1694
+ /** TODO → DOING — lock status only (no owner yet); used by CLAIM and {@link patchClaimTask} */
1695
+ async function claimTaskById({ taskId, nodeId, updateExtraFn, }) {
1696
+ return transitionTask({
1697
+ id: taskId,
1698
+ optimisticLockFilterList: lockOnStatus(TaskStatus.TODO),
1699
+ updateFn: (details) => ({
1700
+ ...details,
1701
+ status: TaskStatus.DOING,
1702
+ nodeId,
1703
+ }),
1704
+ updateExtraFn,
1705
+ });
1706
+ }
1707
+ // ─── patchChangeTaskStatus ───────────────────────────────────────────────────
1708
+ const patchChangeTaskStatus = validateWithSchema(patchChangeTaskStatusSchema, "patchChangeTaskStatusSchema")(async (params) => {
1709
+ const logger = createLogger({ module: "patchChangeTaskStatus", traceId: params.traceId });
1710
+ const { id, action, extra } = params;
1711
+ const updateExtraFn = extra == null ? undefined : () => extra;
1712
+ switch (action) {
1713
+ case TaskStatusAction.PUBLISH: {
1714
+ const data = await transitionTask({
1715
+ id,
1716
+ optimisticLockFilterList: lockOnStatus(TaskStatus.OPEN),
1717
+ updateFn: (details) => ({
1718
+ ...details,
1719
+ ...clearExecutionState(),
1720
+ status: TaskStatus.TODO,
1721
+ }),
1722
+ updateExtraFn,
1723
+ });
1724
+ logTaskTransition(logger, action, data);
1725
+ return generateResponse.success(data);
1726
+ }
1727
+ case TaskStatusAction.CLAIM: {
1728
+ const { nodeId } = params;
1729
+ const data = await claimTaskById({ taskId: id, nodeId, updateExtraFn });
1730
+ logTaskTransition(logger, action, data);
1731
+ return generateResponse.success(data);
1732
+ }
1733
+ case TaskStatusAction.RESET: {
1734
+ const { nodeId } = params;
1735
+ const data = await transitionTask({
1736
+ id,
1737
+ optimisticLockFilterList: lockOnReset(nodeId),
1738
+ updateFn: (details) => ({
1739
+ ...details,
1740
+ ...clearExecutionState(),
1741
+ status: TaskStatus.OPEN,
1742
+ }),
1743
+ updateExtraFn,
1744
+ });
1745
+ logTaskTransition(logger, action, data, nodeId != null ? undefined : { resetFrom: "TODO" });
1746
+ return generateResponse.success(data);
1747
+ }
1748
+ case TaskStatusAction.CANCEL: {
1749
+ const { nodeId } = params;
1750
+ const data = await transitionTask({
1751
+ id,
1752
+ optimisticLockFilterList: lockOnDoingOwner(nodeId),
1753
+ updateFn: (details) => ({
1754
+ ...details,
1755
+ ...clearExecutionState(),
1756
+ status: TaskStatus.TODO,
1757
+ }),
1758
+ updateExtraFn,
1759
+ });
1760
+ logTaskTransition(logger, action, data);
1761
+ return generateResponse.success(data);
1762
+ }
1763
+ case TaskStatusAction.CLOSE: {
1764
+ const data = await transitionTask({
1765
+ id,
1766
+ optimisticLockFilterList: lockOnStatus(TaskStatus.OPEN, TaskStatus.DONE),
1767
+ updateFn: (details) => ({
1768
+ ...details,
1769
+ status: TaskStatus.CLOSED,
1770
+ }),
1771
+ updateExtraFn,
1772
+ });
1773
+ logTaskTransition(logger, action, data);
1774
+ return generateResponse.success(data);
1775
+ }
1776
+ case TaskStatusAction.FINISH: {
1777
+ const { cost, nodeId } = params;
1778
+ const data = await transitionTask({
1779
+ id,
1780
+ optimisticLockFilterList: lockOnDoingOwner(nodeId),
1781
+ updateFn: (details) => ({
1782
+ ...details,
1783
+ progress: 100,
1784
+ status: TaskStatus.DONE,
1785
+ nodeId,
1786
+ result: {
1787
+ cost,
1788
+ code: ResultCode.SUCCESS,
1789
+ },
1790
+ }),
1791
+ updateExtraFn,
1792
+ });
1793
+ logTaskTransition(logger, action, data, { cost });
1794
+ return generateResponse.success(data);
1795
+ }
1796
+ default: {
1797
+ const _exhaustive = action;
1798
+ const message = `[patchChangeTaskStatus] Unknown action: ${String(_exhaustive)}`;
1799
+ logger.error(message, { topic: "task", data: { action: String(_exhaustive) } });
1800
+ return generateResponse.error(message);
1801
+ }
1802
+ }
1803
+ });
1804
+ // ─── patchTaskProgress ───────────────────────────────────────────────────────
1805
+ /** Update progress on a DOING task; only the owning node may write (see `lockOnDoingOwner`). */
1806
+ const patchTaskProgress = validateWithSchema(patchTaskProgressSchema, "patchTaskProgressSchema")(async ({ id, progress, nodeId, traceId }) => {
1807
+ const logger = createLogger({ module: "patchTaskProgress", traceId, labels: { nodeId } });
1808
+ const data = await transitionTask({
1809
+ id,
1810
+ optimisticLockFilterList: lockOnDoingOwner(nodeId),
1811
+ updateFn: (details) => ({
1812
+ ...details,
1813
+ progress,
1814
+ }),
1815
+ });
1816
+ logTaskTransition(logger, "patchTaskProgress", data, { progress });
1817
+ return generateResponse.success(data);
1818
+ });
1819
+ // ─── patchClaimTask ──────────────────────────────────────────────────────────
1820
+ /**
1821
+ * Discover and claim one TODO task for this node.
1822
+ *
1823
+ * Flow: oldest TODO in `availableTaskList` (FIFO by `created_at`) → {@link claimTaskById}.
1824
+ * Equivalent to `patchChangeTaskStatus({ id, action: CLAIM, nodeId })` when `id` is already known.
1825
+ *
1826
+ * Returns `data: null` when no TODO task matches.
1827
+ * Optimistic lock conflicts return `{ error, code: OPTIMISTIC_LOCK_ERROR_CODE }` (not thrown).
1828
+ */
1829
+ const patchClaimTask = validateWithSchema(patchClaimTaskSchema, "patchClaimTaskSchema")(async ({ nodeId, availableTaskList, traceId }) => {
1830
+ const logger = createLogger({ module: "patchClaimTask", traceId, labels: { nodeId } });
1831
+ let todoTask;
1832
+ try {
1833
+ const { data: taskCandidates } = await getTargetList({
1834
+ category: CategoryTask.TASK,
1835
+ filterList: [
1836
+ { field: TASK_STATUS_FIELD, operator: "eq", value: TaskStatus.TODO },
1837
+ { field: "value", operator: "in", value: availableTaskList },
1838
+ ],
1839
+ limit: 1,
1840
+ orderBy: { field: "created_at", ascending: true },
1841
+ });
1842
+ const possibleTask = taskCandidates?.[0] ?? null;
1843
+ if (possibleTask == null) {
1844
+ return generateResponse.success(null);
1845
+ }
1846
+ todoTask = possibleTask;
1847
+ }
1848
+ catch (error) {
1849
+ const message = getErrorMessage(error);
1850
+ logger.error("獲取 TODO 任務失敗", { topic: LOG_TOPIC_TASK, data: { error: message, availableTaskList } });
1851
+ return generateResponse.error(message);
1852
+ }
1853
+ const taskLogger = createLogger({
1854
+ module: "patchClaimTask",
1855
+ traceId,
1856
+ traceParentId: todoTask.details.traceId,
1857
+ labels: { nodeId },
1858
+ });
1859
+ try {
1860
+ const data = await claimTaskById({ taskId: todoTask.id, nodeId });
1861
+ logTaskTransition(taskLogger, "patchClaimTask", data);
1862
+ return generateResponse.success(data);
1863
+ }
1864
+ catch (error) {
1865
+ if (isOptimisticLockError(error)) {
1866
+ taskLogger.debug("認領競爭失敗,任務已被其他節點認領", {
1867
+ topic: LOG_TOPIC_TASK,
1868
+ data: { taskId: todoTask.id, taskTypeKey: todoTask.value },
1869
+ });
1870
+ return generateResponse.error(OPTIMISTIC_LOCK_FAILED_MESSAGE, undefined, OPTIMISTIC_LOCK_ERROR_CODE);
1871
+ }
1872
+ const message = getErrorMessage(error);
1873
+ taskLogger.error("認領任務失敗", {
1874
+ topic: LOG_TOPIC_TASK,
1875
+ data: { error: message, taskId: todoTask.id, taskTypeKey: todoTask.value },
1876
+ });
1877
+ return generateResponse.error(message);
1878
+ }
1879
+ });
1880
+
1881
+ const traceIdSchema = z.string().trim().min(1).optional();
1882
+ const traceParentIdSchema = z.string().trim().min(1).nullable().optional();
1883
+ /** Initial status for a new task — OPEN (draft) or TODO (claimable by workers). */
1884
+ const postTaskInitialStatusSchema = z
1885
+ .union([z.literal(TaskStatus.OPEN), z.literal(TaskStatus.TODO)])
1886
+ .optional()
1887
+ .default(TaskStatus.TODO);
1888
+ const postTaskSchema = z.object({
1889
+ name: z.string().trim().min(1),
1890
+ /** Task type key — matches `task.value`, {@link patchClaimTask}, {@link Repo.value}, and local Repo registry. */
1891
+ value: z.string().trim().min(1),
1892
+ params: z.unknown(),
1893
+ taskStatus: postTaskInitialStatusSchema,
1894
+ tagList: z.array(z.string()).optional().default([]),
1895
+ extra: z.string().optional(),
1896
+ traceId: traceIdSchema,
1897
+ traceParentId: traceParentIdSchema,
1898
+ });
1899
+ /** Shared DB insert for {@link postTask} and {@link postTaskWithValidation}. */
1900
+ async function createTaskRow({ name, value, params, taskStatus, tagList, extra, taskTraceId, traceParentId }, logger) {
1901
+ const result = await createTarget({
1902
+ payload: {
1903
+ name,
1904
+ value,
1905
+ params,
1906
+ taskStatus,
1907
+ tagList,
1908
+ extra,
1909
+ traceId: taskTraceId,
1910
+ traceParentId,
1911
+ },
1912
+ createFn: () => ({
1913
+ name,
1914
+ value,
1915
+ category: CategoryTask.TASK,
1916
+ tagList,
1917
+ extra,
1918
+ details: {
1919
+ manifestVersion: 0,
1920
+ status: taskStatus,
1921
+ params,
1922
+ progress: 0,
1923
+ nodeId: null,
1924
+ traceId: taskTraceId,
1925
+ },
1926
+ }),
1927
+ });
1928
+ logger.info("任務已創建", {
1929
+ topic: "task",
1930
+ data: {
1931
+ taskId: result.data?.id,
1932
+ taskTypeKey: value,
1933
+ status: taskStatus,
1934
+ traceId: taskTraceId,
1935
+ },
1936
+ });
1937
+ return result;
1938
+ }
1939
+ /**
1940
+ * Create a task row (scheduler / admin). **Browser and Node** — no Repo or params validation.
1941
+ * Execution-time checks live in {@link TaskManager.prepareTask}.
1942
+ */
1943
+ const postTask = validateWithSchema(postTaskSchema, "postTaskSchema")(async ({ name, value, params, taskStatus, tagList, extra, traceId, traceParentId }) => {
1944
+ const taskTraceId = traceId?.trim() || logManager.generateTraceId();
1945
+ const logger = createLogger({
1946
+ module: "postTask",
1947
+ traceId: taskTraceId,
1948
+ traceParentId: traceParentId ?? null,
1949
+ });
1950
+ return createTaskRow({ name, value, params, taskStatus, tagList, extra, traceParentId, taskTraceId }, logger);
1951
+ });
1952
+
1953
+ /** Count tasks of `taskType` grouped by each requested status. */
1954
+ function countTasksByType(tasks, taskType, statuses) {
1955
+ const filtered = tasks.filter((task) => task.value === taskType);
1956
+ const counts = {};
1957
+ for (const status of statuses) {
1958
+ counts[status] = filtered.filter((task) => task.details.status === status).length;
1959
+ }
1960
+ return counts;
1961
+ }
1962
+ /** Total tasks of `taskType` whose status is in `statuses`. */
1963
+ function summarizeTaskQueue(tasks, taskType, statuses) {
1964
+ return tasks.filter((task) => task.value === taskType && statuses.includes(task.details.status)).length;
1965
+ }
1966
+
1967
+ var CategoryWord;
1968
+ (function (CategoryWord) {
1969
+ CategoryWord["WORD"] = "word";
1970
+ })(CategoryWord || (CategoryWord = {}));
1971
+
1972
+ export { patchNodeHeartBeatSchema as $, ApiMethod as A, getParcelSchema as B, CategoryIdea as C, getScanRemoteRepoValues as D, getScanRemoteRepoValuesSchema as E, getService as F, getServiceSchema as G, installChunkFetchRegistry as H, isHttpUrl as I, isLocalFilesystemPath as J, isOpaqueChunkUrl as K, isRetryableHttpStatus as L, Market as M, NodeStatus as N, parcelDetailsSchema as O, ParcelManager as P, parseProviderPrefixedUrl as Q, ResultCode as R, ServiceLifecycleStatus as S, TASK_REPO_USAGE as T, patchChangeNodeStatus as U, patchChangeNodeStatusSchema as V, patchChangeTaskStatus as W, patchChangeTaskStatusSchema as X, patchClaimTask as Y, patchClaimTaskSchema as Z, patchNodeHeartBeat as _, CategoryLink as a, patchStopNode as a0, patchStopNodeSchema as a1, patchTaskProgress as a2, patchTaskProgressSchema as a3, postApi as a4, postApiSchema as a5, postLinkCreate as a6, postParcel as a7, postParcelSchema as a8, postRegisterNode as a9, postRegisterNodeSchema as aa, postService as ab, postServiceSchema as ac, postTask as ad, postTaskSchema as ae, publishParcel as af, registerProviderChunkResolver as ag, requestHasBody as ah, resolveFetchUrl as ai, restoreParcel as aj, restoreParcelById as ak, sanitizeFileName as al, sanitizeParcelFileName as am, schemaDefinitionSchema as an, serviceDetailsSchema as ao, serviceLifecycleSchema as ap, sha256Hex as aq, summarizeTaskQueue as ar, getErrorMessage as as, LOG_TOPIC_TASK as at, CRITICAL_UNKNOWN_TASK_TRACE_ID as au, toError as av, createTaskRow as aw, CategoryNode as b, CategoryParcel as c, CategoryRepo as d, CategoryService as e, CategoryTask as f, CategoryWord as g, PostLinkValidator as h, TaskStatus as i, TaskStatusAction as j, apiDetailsSchema as k, classifyNetworkError as l, countTasksByType as m, createStorageProviderRegistry as n, createUploadTracker as o, deleteParcel as p, deleteParcelSchema as q, discoverService as r, evaluateBusyNodeLiveness as s, fetchBinaryWithRetry as t, fetchWithRetry as u, fieldDefinitionSchema as v, formatNetworkError as w, getApi as x, getApiSchema as y, getParcel as z };
1973
+ //# sourceMappingURL=word.interface-DLgRobKV.js.map