@oomol-lab/open-flow 0.1.0-beta.73 → 0.1.0-beta.75

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 (444) hide show
  1. package/LICENSE +36 -0
  2. package/NOTICE +7 -0
  3. package/README.md +41 -0
  4. package/dist/browser/{ContentIcon-CUQHjQIw.js → ContentIcon-FCpKiwjp.js} +2 -1
  5. package/dist/browser/{FlowCanvas-Dtf8_cQp.js → FlowCanvas-dzRBnlUT.js} +1 -1
  6. package/dist/browser/{createResourceDialog-BWJkjiOO.js → createResourceDialog-BeYDdUl-.js} +2 -2
  7. package/dist/browser/{dialog-CUy_fwx9.js → dialog-ZtpsFbl4.js} +337 -31
  8. package/dist/browser/{exportSvg-BOoy7-Db.js → exportSvg-DqXw1yf-.js} +2 -2
  9. package/dist/browser/{flowChanges-CgSnSqqP.js → flowChanges-b_5UobFj.js} +586 -87
  10. package/dist/browser/{flowWorkspace-Bf7H-r0t.js → flowWorkspace-ItojZbO4.js} +21162 -20242
  11. package/dist/browser/preview.css +254 -179
  12. package/dist/browser/preview.js +22201 -20625
  13. package/dist/browser/{typeScriptSession-B0hC-C8y.js → typeScriptSession-CSRwWmZm.js} +1 -1
  14. package/dist/browser/ui.css +72 -2
  15. package/dist/browser/workbench.css +254 -179
  16. package/dist/browser/workbench.js +22 -78
  17. package/dist/browser/{workbenchSelect-C3e4J93X.js → workbenchSelect-M441Lz0d.js} +1 -1
  18. package/dist/command/index.js +42 -42
  19. package/dist/common/authoring.d.ts +5 -5
  20. package/dist/common/authoringExamples.d.ts +3 -2
  21. package/dist/common/authoringFields.d.ts +1 -1
  22. package/dist/common/authoringSchema.d.ts +95 -8
  23. package/dist/common/connector-proxy.d.ts +1 -1
  24. package/dist/common/control-api-conformance.d.ts +1 -1
  25. package/dist/common/control-api-conformance.js +119 -31
  26. package/dist/common/control-api.d.ts +4 -3
  27. package/dist/common/control-api.js +117 -29
  28. package/dist/common/control-requests.d.ts +5 -4
  29. package/dist/common/control-requests.js +437 -103
  30. package/dist/common/cron-trigger.d.ts +1 -1
  31. package/dist/common/decision.d.ts +1 -1
  32. package/dist/common/draftOperations.d.ts +1 -1
  33. package/dist/common/engine-contract.d.ts +4 -2
  34. package/dist/common/event-source-definition.d.ts +1 -1
  35. package/dist/common/flow-agent.d.ts +1 -1
  36. package/dist/{browser → common}/flow-authoring-node.d.ts +3 -3
  37. package/dist/{browser → common}/flow-authoring.js +131 -30
  38. package/dist/{browser → common}/flow-change-schema.d.ts +177 -6
  39. package/dist/{browser → common}/flow-change.d.ts +35 -15
  40. package/dist/{browser → common}/flow-change.js +133 -32
  41. package/dist/common/flow-connectionUsage.d.ts +1 -1
  42. package/dist/common/flow-encoding.d.ts +1 -1
  43. package/dist/common/flow-encoding.js +89 -23
  44. package/dist/common/flow-errorHandling.d.ts +1 -1
  45. package/dist/common/flow-graph.d.ts +3 -2
  46. package/dist/common/flow-modules.d.ts +1 -1
  47. package/dist/common/flow-promptTemplate.d.ts +1 -1
  48. package/dist/common/flow-retry.d.ts +2 -2
  49. package/dist/common/flow-semantics.d.ts +1 -1
  50. package/dist/common/flow-semantics.js +966 -614
  51. package/dist/common/flow-workflowFile.d.ts +1 -1
  52. package/dist/common/flowInspection.d.ts +3 -3
  53. package/dist/common/http-request.d.ts +156 -0
  54. package/dist/common/http-request.js +5254 -0
  55. package/dist/common/integration-trigger.d.ts +1 -1
  56. package/dist/common/licenses.md +118 -1
  57. package/dist/common/liveDetails.d.ts +1 -1
  58. package/dist/common/mcp.d.ts +5 -4
  59. package/dist/common/mcp.js +117 -29
  60. package/dist/common/openapi.d.ts +1 -1
  61. package/dist/common/poll-trigger.d.ts +1 -1
  62. package/dist/common/run-events.js +11 -9
  63. package/dist/common/run-results.d.ts +8 -1
  64. package/dist/common/runtime-contract.d.ts +8 -2
  65. package/dist/common/runtime-contract.js +25 -5
  66. package/dist/common/scheduler-checkpoint.d.ts +1 -1
  67. package/dist/common/scheduler-dependencies.d.ts +1 -1
  68. package/dist/common/scheduler-node-execution.d.ts +1 -1
  69. package/dist/common/scheduler.d.ts +3 -3
  70. package/dist/common/scheduler.js +101 -33
  71. package/dist/common/trigger-catalog.d.ts +1 -1
  72. package/dist/common/trigger-config-options.d.ts +1 -1
  73. package/dist/common/trigger-config.d.ts +1 -1
  74. package/dist/common/trigger-contract.d.ts +2 -2
  75. package/dist/common/trigger-localization.d.ts +1 -1
  76. package/dist/common/webhook-response.d.ts +1 -3
  77. package/dist/common/webhook-trigger.d.ts +1 -1
  78. package/dist/common/webhook-trigger.js +12 -11
  79. package/dist/common/workflow.d.ts +17 -1
  80. package/dist/common/workflow.js +68 -22
  81. package/dist/index.d.ts +6 -3
  82. package/package.json +11 -6
  83. package/skills/open-flow/references/flow-authoring.md +1 -0
  84. package/skills/open-flow/references/flow-n8n-conversion.md +19 -15
  85. package/src/base/common/json.ts +90 -0
  86. package/src/canvas/common/commands.ts +15 -0
  87. package/src/connector/common/actionSchema.ts +168 -0
  88. package/src/connector/common/proxy.ts +44 -0
  89. package/src/control/common/api.ts +1506 -0
  90. package/src/control/common/authoring.ts +923 -0
  91. package/src/control/common/authoringCondition.ts +110 -0
  92. package/src/control/common/authoringDiagnosticFields.ts +136 -0
  93. package/src/control/common/authoringExamples.ts +200 -0
  94. package/src/control/common/authoringFields.ts +53 -0
  95. package/src/control/common/authoringLlm.ts +70 -0
  96. package/src/control/common/authoringOpenApi.ts +129 -0
  97. package/src/control/common/authoringSchema.ts +410 -0
  98. package/src/control/common/authoringTools.ts +123 -0
  99. package/src/control/common/authoringTriggers.ts +26 -0
  100. package/src/control/common/checkDecoders.ts +65 -0
  101. package/src/control/common/conformance.ts +1989 -0
  102. package/src/control/common/connectorDecoders.ts +370 -0
  103. package/src/control/common/connectorQueries.ts +61 -0
  104. package/src/control/common/decoding.ts +60 -0
  105. package/src/control/common/draftOperations.ts +61 -0
  106. package/src/control/common/errors.ts +114 -0
  107. package/src/control/common/eventSourceSchemas.ts +13 -0
  108. package/src/control/common/eventSources.ts +186 -0
  109. package/src/control/common/flowDecoders.ts +153 -0
  110. package/src/control/common/flowInspection.ts +181 -0
  111. package/src/control/common/flowNotifications.ts +37 -0
  112. package/src/control/common/liveDetails.ts +124 -0
  113. package/src/control/common/mcp.ts +241 -0
  114. package/src/control/common/mcpConformance.ts +142 -0
  115. package/src/control/common/providerAccess.ts +28 -0
  116. package/src/control/common/providerIconSprite.ts +42 -0
  117. package/src/control/common/publicationDecoders.ts +98 -0
  118. package/src/control/common/random.ts +16 -0
  119. package/src/control/common/requests.ts +112 -0
  120. package/src/control/common/resultQuery.ts +8 -0
  121. package/src/control/common/results.ts +176 -0
  122. package/src/control/common/revisionDecoders.ts +52 -0
  123. package/src/control/common/runDecoders.ts +240 -0
  124. package/src/control/common/triggerCatalog.ts +89 -0
  125. package/src/control/common/triggerDecoders.ts +175 -0
  126. package/src/decision/common/decision.ts +168 -0
  127. package/src/event-source/common/catalog.generated.json +65 -0
  128. package/src/event-source/common/definition.ts +66 -0
  129. package/src/event-source/common/index.ts +99 -0
  130. package/src/execution/common/checkpoint.ts +311 -0
  131. package/src/execution/common/dependencies.ts +440 -0
  132. package/src/execution/common/engineContract.ts +84 -0
  133. package/src/execution/common/events.ts +331 -0
  134. package/src/execution/common/node-execution.ts +469 -0
  135. package/src/execution/common/runLifecycle.ts +250 -0
  136. package/src/execution/common/runtime.ts +563 -0
  137. package/src/execution/common/scheduler.ts +697 -0
  138. package/src/execution/common/wait.ts +36 -0
  139. package/src/flow/common/agent.ts +305 -0
  140. package/src/flow/common/authoring.ts +30 -0
  141. package/src/flow/common/change.ts +1037 -0
  142. package/src/flow/common/changeSchema.ts +792 -0
  143. package/src/flow/common/codePermissions.ts +2 -0
  144. package/src/flow/common/condition.ts +265 -0
  145. package/src/flow/common/connectionUsage.ts +131 -0
  146. package/src/flow/common/edgeChanges.ts +35 -0
  147. package/src/flow/common/encoding.ts +437 -0
  148. package/src/flow/common/errorHandling.ts +34 -0
  149. package/src/flow/common/graph.ts +898 -0
  150. package/src/flow/common/inputValue.ts +16 -0
  151. package/src/flow/common/json.ts +8 -0
  152. package/src/flow/common/moduleChanges.ts +31 -0
  153. package/src/flow/common/modules.ts +292 -0
  154. package/src/flow/common/nodeChanges.ts +762 -0
  155. package/src/flow/common/portChanges.ts +36 -0
  156. package/src/flow/common/promptTemplate.ts +15 -0
  157. package/src/flow/common/retry.ts +20 -0
  158. package/src/flow/common/schema.ts +162 -0
  159. package/src/flow/common/schemaCompare.ts +176 -0
  160. package/src/flow/common/schemaComparer.ts +178 -0
  161. package/src/flow/common/schemaKeywords.ts +53 -0
  162. package/src/flow/common/semantics.ts +531 -0
  163. package/src/flow/common/sourceField.ts +35 -0
  164. package/src/flow/common/triggerScheduleSchema.ts +8 -0
  165. package/src/flow/common/wait.ts +30 -0
  166. package/src/flow/common/webhookMethod.ts +7 -0
  167. package/src/flow/common/webhookResponse.ts +71 -0
  168. package/src/flow/common/workflowFile.ts +97 -0
  169. package/src/http/common/authBindings.ts +12 -0
  170. package/src/http/common/headers.ts +5 -0
  171. package/src/http/common/httpRequest.ts +251 -0
  172. package/src/json-schema-subset/checker/array.ts +142 -0
  173. package/src/json-schema-subset/checker/cache.ts +57 -0
  174. package/src/json-schema-subset/checker/checker.ts +230 -0
  175. package/src/json-schema-subset/checker/enumAndConst.ts +113 -0
  176. package/src/json-schema-subset/checker/equals.ts +93 -0
  177. package/src/json-schema-subset/checker/numeric/checker.ts +50 -0
  178. package/src/json-schema-subset/checker/numeric/float.ts +121 -0
  179. package/src/json-schema-subset/checker/numeric/index.ts +1 -0
  180. package/src/json-schema-subset/checker/numeric/integer.ts +119 -0
  181. package/src/json-schema-subset/checker/numeric/integerNormalizer.ts +72 -0
  182. package/src/json-schema-subset/checker/object.ts +354 -0
  183. package/src/json-schema-subset/checker/range.ts +91 -0
  184. package/src/json-schema-subset/checker/string.ts +60 -0
  185. package/src/json-schema-subset/checker/tools/index.ts +3 -0
  186. package/src/json-schema-subset/checker/tools/mark.ts +82 -0
  187. package/src/json-schema-subset/checker/tools/quantum.ts +106 -0
  188. package/src/json-schema-subset/checker/tools/range.ts +210 -0
  189. package/src/json-schema-subset/checker/validator.ts +23 -0
  190. package/src/json-schema-subset/compiler/array.ts +163 -0
  191. package/src/json-schema-subset/compiler/combination.ts +109 -0
  192. package/src/json-schema-subset/compiler/common.ts +99 -0
  193. package/src/json-schema-subset/compiler/compiler.ts +188 -0
  194. package/src/json-schema-subset/compiler/enumAndConst.ts +75 -0
  195. package/src/json-schema-subset/compiler/index.ts +11 -0
  196. package/src/json-schema-subset/compiler/object.ts +411 -0
  197. package/src/json-schema-subset/compiler/primitive.ts +144 -0
  198. package/src/json-schema-subset/compiler/utils.ts +24 -0
  199. package/src/json-schema-subset/compiler/wrapper.ts +192 -0
  200. package/src/json-schema-subset/error.ts +55 -0
  201. package/src/json-schema-subset/expression/calculator.ts +442 -0
  202. package/src/json-schema-subset/expression/combination.ts +49 -0
  203. package/src/json-schema-subset/expression/expression.ts +191 -0
  204. package/src/json-schema-subset/expression/index.ts +25 -0
  205. package/src/json-schema-subset/expression/result.ts +88 -0
  206. package/src/json-schema-subset/expression/types.ts +36 -0
  207. package/src/json-schema-subset/extends/extendsContext.ts +89 -0
  208. package/src/json-schema-subset/extends/index.ts +2 -0
  209. package/src/json-schema-subset/extends/types.ts +12 -0
  210. package/src/json-schema-subset/global.ts +60 -0
  211. package/src/json-schema-subset/index.ts +8 -0
  212. package/src/json-schema-subset/preprocessing.ts +74 -0
  213. package/src/json-schema-subset/types.ts +8 -0
  214. package/src/json-schema-subset/utils.ts +95 -0
  215. package/src/localization/common/languages.ts +118 -0
  216. package/src/localization/common/timeZone.ts +25 -0
  217. package/src/openapi/common/openapi.ts +459 -0
  218. package/src/trigger/common/config.ts +56 -0
  219. package/src/trigger/common/configOptions.ts +15 -0
  220. package/src/trigger/common/configSchema.ts +8 -0
  221. package/src/trigger/common/contract.ts +132 -0
  222. package/src/trigger/common/cron.ts +151 -0
  223. package/src/trigger/common/integration.ts +498 -0
  224. package/src/trigger/common/poll.ts +187 -0
  225. package/src/trigger/common/webhook.ts +413 -0
  226. package/src/trigger/providers/airtable/locales/fr.json +18 -0
  227. package/src/trigger/providers/airtable/locales/ja.json +18 -0
  228. package/src/trigger/providers/airtable/locales/ko.json +18 -0
  229. package/src/trigger/providers/airtable/locales/ru.json +18 -0
  230. package/src/trigger/providers/airtable/locales/zh-CN.json +18 -0
  231. package/src/trigger/providers/airtable/locales/zh-TW.json +18 -0
  232. package/src/trigger/providers/asana/locales/fr.json +15 -0
  233. package/src/trigger/providers/asana/locales/ja.json +15 -0
  234. package/src/trigger/providers/asana/locales/ko.json +15 -0
  235. package/src/trigger/providers/asana/locales/ru.json +15 -0
  236. package/src/trigger/providers/asana/locales/zh-CN.json +15 -0
  237. package/src/trigger/providers/asana/locales/zh-TW.json +15 -0
  238. package/src/trigger/providers/calendly/locales/fr.json +16 -0
  239. package/src/trigger/providers/calendly/locales/ja.json +16 -0
  240. package/src/trigger/providers/calendly/locales/ko.json +16 -0
  241. package/src/trigger/providers/calendly/locales/ru.json +16 -0
  242. package/src/trigger/providers/calendly/locales/zh-CN.json +16 -0
  243. package/src/trigger/providers/calendly/locales/zh-TW.json +16 -0
  244. package/src/trigger/providers/catalog.generated.json +4996 -0
  245. package/src/trigger/providers/clickup/locales/fr.json +16 -0
  246. package/src/trigger/providers/clickup/locales/ja.json +16 -0
  247. package/src/trigger/providers/clickup/locales/ko.json +16 -0
  248. package/src/trigger/providers/clickup/locales/ru.json +16 -0
  249. package/src/trigger/providers/clickup/locales/zh-CN.json +16 -0
  250. package/src/trigger/providers/clickup/locales/zh-TW.json +16 -0
  251. package/src/trigger/providers/definitions.ts +19 -0
  252. package/src/trigger/providers/feishu/locales/fr.json +20 -0
  253. package/src/trigger/providers/feishu/locales/ja.json +20 -0
  254. package/src/trigger/providers/feishu/locales/ko.json +20 -0
  255. package/src/trigger/providers/feishu/locales/ru.json +20 -0
  256. package/src/trigger/providers/feishu/locales/zh-CN.json +20 -0
  257. package/src/trigger/providers/feishu/locales/zh-TW.json +20 -0
  258. package/src/trigger/providers/fieldDescriptions.ts +392 -0
  259. package/src/trigger/providers/fieldLabels.ts +256 -0
  260. package/src/trigger/providers/fireflies/locales/fr.json +17 -0
  261. package/src/trigger/providers/fireflies/locales/ja.json +17 -0
  262. package/src/trigger/providers/fireflies/locales/ko.json +17 -0
  263. package/src/trigger/providers/fireflies/locales/ru.json +17 -0
  264. package/src/trigger/providers/fireflies/locales/zh-CN.json +17 -0
  265. package/src/trigger/providers/fireflies/locales/zh-TW.json +17 -0
  266. package/src/trigger/providers/github/locales/fr.json +30 -0
  267. package/src/trigger/providers/github/locales/ja.json +30 -0
  268. package/src/trigger/providers/github/locales/ko.json +30 -0
  269. package/src/trigger/providers/github/locales/ru.json +30 -0
  270. package/src/trigger/providers/github/locales/zh-CN.json +30 -0
  271. package/src/trigger/providers/github/locales/zh-TW.json +30 -0
  272. package/src/trigger/providers/gitlab/locales/fr.json +18 -0
  273. package/src/trigger/providers/gitlab/locales/ja.json +18 -0
  274. package/src/trigger/providers/gitlab/locales/ko.json +18 -0
  275. package/src/trigger/providers/gitlab/locales/ru.json +18 -0
  276. package/src/trigger/providers/gitlab/locales/zh-CN.json +18 -0
  277. package/src/trigger/providers/gitlab/locales/zh-TW.json +18 -0
  278. package/src/trigger/providers/gmail/locales/fr.json +18 -0
  279. package/src/trigger/providers/gmail/locales/ja.json +18 -0
  280. package/src/trigger/providers/gmail/locales/ko.json +18 -0
  281. package/src/trigger/providers/gmail/locales/ru.json +18 -0
  282. package/src/trigger/providers/gmail/locales/zh-CN.json +18 -0
  283. package/src/trigger/providers/gmail/locales/zh-TW.json +18 -0
  284. package/src/trigger/providers/google-calendar/locales/fr.json +15 -0
  285. package/src/trigger/providers/google-calendar/locales/ja.json +15 -0
  286. package/src/trigger/providers/google-calendar/locales/ko.json +15 -0
  287. package/src/trigger/providers/google-calendar/locales/ru.json +15 -0
  288. package/src/trigger/providers/google-calendar/locales/zh-CN.json +15 -0
  289. package/src/trigger/providers/google-calendar/locales/zh-TW.json +15 -0
  290. package/src/trigger/providers/google-drive/locales/fr.json +48 -0
  291. package/src/trigger/providers/google-drive/locales/ja.json +48 -0
  292. package/src/trigger/providers/google-drive/locales/ko.json +48 -0
  293. package/src/trigger/providers/google-drive/locales/ru.json +48 -0
  294. package/src/trigger/providers/google-drive/locales/zh-CN.json +48 -0
  295. package/src/trigger/providers/google-drive/locales/zh-TW.json +48 -0
  296. package/src/trigger/providers/google-sheets/locales/fr.json +19 -0
  297. package/src/trigger/providers/google-sheets/locales/ja.json +19 -0
  298. package/src/trigger/providers/google-sheets/locales/ko.json +19 -0
  299. package/src/trigger/providers/google-sheets/locales/ru.json +19 -0
  300. package/src/trigger/providers/google-sheets/locales/zh-CN.json +19 -0
  301. package/src/trigger/providers/google-sheets/locales/zh-TW.json +19 -0
  302. package/src/trigger/providers/intercom/locales/fr.json +17 -0
  303. package/src/trigger/providers/intercom/locales/ja.json +17 -0
  304. package/src/trigger/providers/intercom/locales/ko.json +17 -0
  305. package/src/trigger/providers/intercom/locales/ru.json +17 -0
  306. package/src/trigger/providers/intercom/locales/zh-CN.json +17 -0
  307. package/src/trigger/providers/intercom/locales/zh-TW.json +17 -0
  308. package/src/trigger/providers/jira/locales/fr.json +17 -0
  309. package/src/trigger/providers/jira/locales/ja.json +17 -0
  310. package/src/trigger/providers/jira/locales/ko.json +17 -0
  311. package/src/trigger/providers/jira/locales/ru.json +17 -0
  312. package/src/trigger/providers/jira/locales/zh-CN.json +17 -0
  313. package/src/trigger/providers/jira/locales/zh-TW.json +17 -0
  314. package/src/trigger/providers/linear/locales/fr.json +13 -0
  315. package/src/trigger/providers/linear/locales/ja.json +13 -0
  316. package/src/trigger/providers/linear/locales/ko.json +13 -0
  317. package/src/trigger/providers/linear/locales/ru.json +13 -0
  318. package/src/trigger/providers/linear/locales/zh-CN.json +13 -0
  319. package/src/trigger/providers/linear/locales/zh-TW.json +13 -0
  320. package/src/trigger/providers/locales/fr.ts +71 -0
  321. package/src/trigger/providers/locales/ja.ts +71 -0
  322. package/src/trigger/providers/locales/ko.ts +71 -0
  323. package/src/trigger/providers/locales/ru.ts +71 -0
  324. package/src/trigger/providers/locales/zh-CN.ts +71 -0
  325. package/src/trigger/providers/locales/zh-TW.ts +71 -0
  326. package/src/trigger/providers/localization.ts +59 -0
  327. package/src/trigger/providers/notion/locales/fr.json +16 -0
  328. package/src/trigger/providers/notion/locales/ja.json +16 -0
  329. package/src/trigger/providers/notion/locales/ko.json +16 -0
  330. package/src/trigger/providers/notion/locales/ru.json +16 -0
  331. package/src/trigger/providers/notion/locales/zh-CN.json +16 -0
  332. package/src/trigger/providers/notion/locales/zh-TW.json +16 -0
  333. package/src/trigger/providers/one-drive/locales/fr.json +16 -0
  334. package/src/trigger/providers/one-drive/locales/ja.json +16 -0
  335. package/src/trigger/providers/one-drive/locales/ko.json +16 -0
  336. package/src/trigger/providers/one-drive/locales/ru.json +16 -0
  337. package/src/trigger/providers/one-drive/locales/zh-CN.json +16 -0
  338. package/src/trigger/providers/one-drive/locales/zh-TW.json +16 -0
  339. package/src/trigger/providers/outlook/locales/fr.json +18 -0
  340. package/src/trigger/providers/outlook/locales/ja.json +18 -0
  341. package/src/trigger/providers/outlook/locales/ko.json +18 -0
  342. package/src/trigger/providers/outlook/locales/ru.json +18 -0
  343. package/src/trigger/providers/outlook/locales/zh-CN.json +18 -0
  344. package/src/trigger/providers/outlook/locales/zh-TW.json +18 -0
  345. package/src/trigger/providers/pandadoc/locales/fr.json +12 -0
  346. package/src/trigger/providers/pandadoc/locales/ja.json +12 -0
  347. package/src/trigger/providers/pandadoc/locales/ko.json +12 -0
  348. package/src/trigger/providers/pandadoc/locales/ru.json +12 -0
  349. package/src/trigger/providers/pandadoc/locales/zh-CN.json +12 -0
  350. package/src/trigger/providers/pandadoc/locales/zh-TW.json +12 -0
  351. package/src/trigger/providers/pipedrive/locales/fr.json +15 -0
  352. package/src/trigger/providers/pipedrive/locales/ja.json +15 -0
  353. package/src/trigger/providers/pipedrive/locales/ko.json +15 -0
  354. package/src/trigger/providers/pipedrive/locales/ru.json +15 -0
  355. package/src/trigger/providers/pipedrive/locales/zh-CN.json +15 -0
  356. package/src/trigger/providers/pipedrive/locales/zh-TW.json +15 -0
  357. package/src/trigger/providers/remote.ts +163 -0
  358. package/src/trigger/providers/resend/locales/fr.json +16 -0
  359. package/src/trigger/providers/resend/locales/ja.json +16 -0
  360. package/src/trigger/providers/resend/locales/ko.json +16 -0
  361. package/src/trigger/providers/resend/locales/ru.json +16 -0
  362. package/src/trigger/providers/resend/locales/zh-CN.json +16 -0
  363. package/src/trigger/providers/resend/locales/zh-TW.json +16 -0
  364. package/src/trigger/providers/sentry/locales/fr.json +19 -0
  365. package/src/trigger/providers/sentry/locales/ja.json +19 -0
  366. package/src/trigger/providers/sentry/locales/ko.json +19 -0
  367. package/src/trigger/providers/sentry/locales/ru.json +19 -0
  368. package/src/trigger/providers/sentry/locales/zh-CN.json +19 -0
  369. package/src/trigger/providers/sentry/locales/zh-TW.json +19 -0
  370. package/src/trigger/providers/shopify/locales/fr.json +18 -0
  371. package/src/trigger/providers/shopify/locales/ja.json +18 -0
  372. package/src/trigger/providers/shopify/locales/ko.json +18 -0
  373. package/src/trigger/providers/shopify/locales/ru.json +18 -0
  374. package/src/trigger/providers/shopify/locales/zh-CN.json +18 -0
  375. package/src/trigger/providers/shopify/locales/zh-TW.json +18 -0
  376. package/src/trigger/providers/slack/locales/fr.json +18 -0
  377. package/src/trigger/providers/slack/locales/ja.json +18 -0
  378. package/src/trigger/providers/slack/locales/ko.json +18 -0
  379. package/src/trigger/providers/slack/locales/ru.json +18 -0
  380. package/src/trigger/providers/slack/locales/zh-CN.json +18 -0
  381. package/src/trigger/providers/slack/locales/zh-TW.json +18 -0
  382. package/src/trigger/providers/slackbot/locales/fr.json +23 -0
  383. package/src/trigger/providers/slackbot/locales/ja.json +23 -0
  384. package/src/trigger/providers/slackbot/locales/ko.json +23 -0
  385. package/src/trigger/providers/slackbot/locales/ru.json +23 -0
  386. package/src/trigger/providers/slackbot/locales/zh-CN.json +23 -0
  387. package/src/trigger/providers/slackbot/locales/zh-TW.json +23 -0
  388. package/src/trigger/providers/source-events.ts +25 -0
  389. package/src/trigger/providers/stripe/locales/fr.json +17 -0
  390. package/src/trigger/providers/stripe/locales/ja.json +17 -0
  391. package/src/trigger/providers/stripe/locales/ko.json +17 -0
  392. package/src/trigger/providers/stripe/locales/ru.json +17 -0
  393. package/src/trigger/providers/stripe/locales/zh-CN.json +17 -0
  394. package/src/trigger/providers/stripe/locales/zh-TW.json +17 -0
  395. package/src/trigger/providers/tally/locales/fr.json +12 -0
  396. package/src/trigger/providers/tally/locales/ja.json +12 -0
  397. package/src/trigger/providers/tally/locales/ko.json +12 -0
  398. package/src/trigger/providers/tally/locales/ru.json +12 -0
  399. package/src/trigger/providers/tally/locales/zh-CN.json +12 -0
  400. package/src/trigger/providers/tally/locales/zh-TW.json +12 -0
  401. package/src/trigger/providers/telegram/locales/fr.json +17 -0
  402. package/src/trigger/providers/telegram/locales/ja.json +17 -0
  403. package/src/trigger/providers/telegram/locales/ko.json +17 -0
  404. package/src/trigger/providers/telegram/locales/ru.json +17 -0
  405. package/src/trigger/providers/telegram/locales/zh-CN.json +17 -0
  406. package/src/trigger/providers/telegram/locales/zh-TW.json +17 -0
  407. package/src/trigger/providers/typeform/locales/fr.json +12 -0
  408. package/src/trigger/providers/typeform/locales/ja.json +12 -0
  409. package/src/trigger/providers/typeform/locales/ko.json +12 -0
  410. package/src/trigger/providers/typeform/locales/ru.json +12 -0
  411. package/src/trigger/providers/typeform/locales/zh-CN.json +12 -0
  412. package/src/trigger/providers/typeform/locales/zh-TW.json +12 -0
  413. package/src/trigger/providers/vercel/locales/fr.json +18 -0
  414. package/src/trigger/providers/vercel/locales/ja.json +18 -0
  415. package/src/trigger/providers/vercel/locales/ko.json +18 -0
  416. package/src/trigger/providers/vercel/locales/ru.json +18 -0
  417. package/src/trigger/providers/vercel/locales/zh-CN.json +18 -0
  418. package/src/trigger/providers/vercel/locales/zh-TW.json +18 -0
  419. package/src/trigger/providers/woocommerce/locales/fr.json +19 -0
  420. package/src/trigger/providers/woocommerce/locales/ja.json +19 -0
  421. package/src/trigger/providers/woocommerce/locales/ko.json +19 -0
  422. package/src/trigger/providers/woocommerce/locales/ru.json +19 -0
  423. package/src/trigger/providers/woocommerce/locales/zh-CN.json +19 -0
  424. package/src/trigger/providers/woocommerce/locales/zh-TW.json +19 -0
  425. package/src/trigger/providers/zendesk/locales/fr.json +15 -0
  426. package/src/trigger/providers/zendesk/locales/ja.json +15 -0
  427. package/src/trigger/providers/zendesk/locales/ko.json +15 -0
  428. package/src/trigger/providers/zendesk/locales/ru.json +15 -0
  429. package/src/trigger/providers/zendesk/locales/zh-CN.json +15 -0
  430. package/src/trigger/providers/zendesk/locales/zh-TW.json +15 -0
  431. package/src/trigger/providers/zoom/locales/fr.json +17 -0
  432. package/src/trigger/providers/zoom/locales/ja.json +17 -0
  433. package/src/trigger/providers/zoom/locales/ko.json +17 -0
  434. package/src/trigger/providers/zoom/locales/ru.json +17 -0
  435. package/src/trigger/providers/zoom/locales/zh-CN.json +17 -0
  436. package/src/trigger/providers/zoom/locales/zh-TW.json +17 -0
  437. package/src/types/index.ts +112 -0
  438. package/src/workflow/common/workflow.ts +273 -0
  439. package/dist/browser/lib-DrKav3HG.js +0 -11403
  440. /package/dist/{browser → common}/flow-authoring-edge.d.ts +0 -0
  441. /package/dist/{browser → common}/flow-authoring-module.d.ts +0 -0
  442. /package/dist/{browser → common}/flow-authoring.d.ts +0 -0
  443. /package/dist/{browser → common}/flow-input-value.d.ts +0 -0
  444. /package/dist/{browser → common}/webhook-method.d.ts +0 -0
@@ -0,0 +1,71 @@
1
+ import type { InputPort, JsonValue, Port, PortDefinition } from './change.ts'
2
+
3
+ import { httpHeaderNameIssue } from '../../http/common/headers.ts'
4
+
5
+ export const webhookResponseTimeout = {
6
+ defaultMs: 30_000,
7
+ minMs: 1000,
8
+ maxMs: 60_000,
9
+ } as const
10
+
11
+ export const webhookStatusCodePort = { jsonSchema: { type: 'number' }, nullable: true } as const
12
+
13
+ export function webhookResponseAllowsBody(status: number): boolean {
14
+ return status !== 204 && status !== 205 && status !== 304
15
+ }
16
+
17
+ export const webhookHeaderValuePort = { jsonSchema: { type: ['string', 'number', 'boolean'] }, nullable: true } as const
18
+ export const webhookHeadersPort = {
19
+ jsonSchema: { type: 'object', additionalProperties: { type: ['string', 'number', 'boolean'] } },
20
+ nullable: true,
21
+ } as const
22
+
23
+ export function workflowOutputsPort(outputs: readonly Port[]): PortDefinition {
24
+ return {
25
+ jsonSchema: {
26
+ type: 'object',
27
+ properties: Object.fromEntries(outputs.map((port) => [port.handle, port.jsonSchema])),
28
+ additionalProperties: false,
29
+ required: outputs.map((port) => port.handle),
30
+ },
31
+ nullable: false,
32
+ } as const
33
+ }
34
+
35
+ /** Fixed inputs belong to the node, not author-supplied definitions. */
36
+ export const webhookResponseInputs: readonly InputPort[] = [
37
+ { handle: 'body', jsonSchema: {}, nullable: true, value: '' },
38
+ { handle: 'statusCode', jsonSchema: { type: 'number' }, nullable: false, value: 200 },
39
+ { handle: 'headers', jsonSchema: webhookHeadersPort.jsonSchema, nullable: false, value: {} },
40
+ ]
41
+
42
+ export interface WebhookResponseSnapshot {
43
+ readonly body: string
44
+ readonly contentType: string
45
+ readonly status: number
46
+ readonly headers: Readonly<Record<string, string>>
47
+ }
48
+
49
+ export function validWebhookStatus(value: unknown): value is number {
50
+ return typeof value === 'number' && Number.isInteger(value) && value >= 200 && value <= 599 && webhookResponseAllowsBody(value)
51
+ }
52
+
53
+ /** Portable validation also runs in the isolated engine, which has no HTTP globals. */
54
+ export function webhookHeaderValues(source: unknown): Readonly<Record<string, string>> | undefined {
55
+ if (source == null || typeof source !== 'object' || Array.isArray(source)) return
56
+ const headers: Record<string, string> = {}
57
+ const names: string[] = []
58
+ for (const [name, value] of Object.entries(source)) {
59
+ if (httpHeaderNameIssue(name, names) != null) return
60
+ if (typeof value !== 'string' && typeof value !== 'boolean' && !(typeof value === 'number' && Number.isFinite(value))) return
61
+ const text = String(value)
62
+ if ([...text].some((character) => character.charCodeAt(0) > 255 || /[\0\r\n]/.test(character))) return
63
+ names.push(name)
64
+ Object.defineProperty(headers, name, { value: text, enumerable: true, configurable: true })
65
+ }
66
+ return headers
67
+ }
68
+
69
+ export function encodeWebhookBody(value: JsonValue): Pick<WebhookResponseSnapshot, 'body' | 'contentType'> {
70
+ return typeof value === 'string' ? { body: value, contentType: 'text/plain;charset=UTF-8' } : { body: JSON.stringify(value), contentType: 'application/json' }
71
+ }
@@ -0,0 +1,97 @@
1
+ import type { GraphNode, InputMapping, JsonValue, RevisionContent } from './change.ts'
2
+
3
+ import { dequal } from 'dequal/lite'
4
+ import { z } from 'zod'
5
+ import { clearTriggerExternalConfig } from '../../trigger/common/config.ts'
6
+ import { decodeRevisionContent } from './changeSchema.ts'
7
+ import { clearConditionBindings } from './condition.ts'
8
+ import { clearNodeConnections } from './connectionUsage.ts'
9
+ import { checkJsonDepth } from './json.ts'
10
+
11
+ export interface WorkflowFile {
12
+ readonly kind: 'open-flow-workflow'
13
+ readonly version: 1
14
+ readonly name?: string
15
+ readonly content: RevisionContent
16
+ readonly presentation?: Readonly<Record<string, JsonValue>>
17
+ }
18
+
19
+ export interface WorkflowCleanupSummary {
20
+ readonly changedNodeIds: readonly string[]
21
+ readonly removedBindings: number
22
+ }
23
+
24
+ const envelope = z.strictObject({
25
+ kind: z.literal('open-flow-workflow'),
26
+ version: z.literal(1),
27
+ name: z.string().optional(),
28
+ content: z.unknown(),
29
+ presentation: z.record(z.string(), z.json()).optional(),
30
+ })
31
+
32
+ /** Structural decoding only: incomplete drafts are supported, repair is never attempted. */
33
+ export function decodeWorkflowFile(value: unknown): WorkflowFile {
34
+ checkJsonDepth(value, -1)
35
+ const file = envelope.parse(value)
36
+ return { ...file, content: decodeRevisionContent(file.content) }
37
+ }
38
+
39
+ export function parseWorkflowFile(text: string): WorkflowFile {
40
+ return decodeWorkflowFile(JSON.parse(text))
41
+ }
42
+
43
+ function cleanInput(input: InputMapping): InputMapping {
44
+ if (input.kind != 'sources' || !input.sources.some((source) => source.kind == 'binding')) return input
45
+ const sources = input.sources.filter((source) => source.kind != 'binding')
46
+ return sources.length == 0 ? { kind: 'unset' } : { kind: 'sources', sources }
47
+ }
48
+
49
+ /** Clear only owned structured references, never strings in code or business values. */
50
+ export function cleanWorkflowFile(value: unknown): { readonly file: WorkflowFile; readonly summary: WorkflowCleanupSummary } {
51
+ const file = decodeWorkflowFile(value)
52
+ const original = file.content.document.graph
53
+ const graph = clearNodeConnections(original)
54
+ const nodes = Object.fromEntries(
55
+ Object.entries(graph.nodes).map(([id, source]) => {
56
+ let node: GraphNode = source
57
+ if ('inputs' in node) node = { ...node, inputs: Object.fromEntries(Object.entries(node.inputs).map(([key, input]) => [key, cleanInput(input)])) }
58
+ if (node.kind == 'outputs')
59
+ node = { ...node, outputMappings: Object.fromEntries(Object.entries(node.outputMappings).map(([key, input]) => [key, cleanInput(input)])) }
60
+ if (node.kind == 'condition') node = clearConditionBindings(node)
61
+ if (node.kind == 'error' && node.sourceFlowIds != null) node = { ...node, sourceFlowIds: [] }
62
+ if (node.kind == 'poll' || node.kind == 'integration') node = { ...node, config: clearTriggerExternalConfig(node.definition.key, node.config) }
63
+ return [id, node]
64
+ }),
65
+ )
66
+ return {
67
+ file: {
68
+ ...file,
69
+ content: {
70
+ ...file.content,
71
+ document: {
72
+ ...file.content.document,
73
+ bindings: {},
74
+ graph: { ...graph, nodes },
75
+ },
76
+ },
77
+ },
78
+ summary: {
79
+ changedNodeIds: Object.keys(nodes).filter((id) => !dequal(nodes[id], original.nodes[id])),
80
+ removedBindings: Object.keys(file.content.document.bindings).length,
81
+ },
82
+ }
83
+ }
84
+
85
+ export function encodeWorkflowFile(file: WorkflowFile): string {
86
+ return `${JSON.stringify(cleanWorkflowFile(file).file, null, 2)}\n`
87
+ }
88
+
89
+ export function workflowFileName(name: string): string {
90
+ // Control characters are forbidden in download filenames.
91
+ // oxlint-disable-next-line no-control-regex
92
+ return `${name.replace(/[<>:"/\\|?*\u0000-\u001f]/g, '_').replace(/[. ]+$/g, '') || 'workflow'}.openflow.json`
93
+ }
94
+
95
+ export function workflowNameFromFile(name: string): string {
96
+ return name.replace(/(?:\.openflow)?\.json$/i, '')
97
+ }
@@ -0,0 +1,12 @@
1
+ import type { FlowDocument } from '../../flow/common/change.ts'
2
+
3
+ /** Never allow credentials to enter a Revision as literal node inputs. */
4
+ export function assertHttpAuthBindings(document: FlowDocument): void {
5
+ for (const node of Object.values(document.graph.nodes)) {
6
+ if (node.kind != 'task' || !('executor' in node.task) || !['openapi', 'http-request'].includes(node.task.executor.kind)) continue
7
+ for (const [handle, mapping] of Object.entries(node.inputs)) {
8
+ if (handle.startsWith('auth.') && mapping.kind == 'value')
9
+ throw new TypeError('HTTP authentication accepts deployment variables and upstream outputs only.')
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,5 @@
1
+ /** Header names are case-insensitive; never silently combine duplicate business fields. */
2
+ export function httpHeaderNameIssue(name: string, names: readonly string[]): 'invalid' | 'duplicate' | undefined {
3
+ if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) return 'invalid'
4
+ if (names.some((candidate) => candidate.toLowerCase() === name.toLowerCase())) return 'duplicate'
5
+ }
@@ -0,0 +1,251 @@
1
+ import type { InputMapping, InputPort, JsonValue, ManagedTaskDefinition, TaskNode } from '../../flow/common/change.ts'
2
+
3
+ import { dequal } from 'dequal/lite'
4
+ import { z } from 'zod'
5
+ import { remapInputMappings, renamedPort } from '../../flow/common/portChanges.ts'
6
+ import { httpHeaderNameIssue } from './headers.ts'
7
+
8
+ const parameterSchema = z.strictObject({ mode: z.enum(['fields', 'object']).default('fields'), names: z.array(z.string()).default([]) })
9
+ export const httpRequestConfigSchema = z.strictObject({
10
+ method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']).default('GET'),
11
+ query: parameterSchema.default({ mode: 'fields', names: [] }),
12
+ headers: parameterSchema.default({ mode: 'fields', names: [] }),
13
+ bodyFormat: z.enum(['none', 'json', 'text', 'form']).default('none'),
14
+ authentication: z
15
+ .union([
16
+ z.strictObject({ type: z.literal('none') }),
17
+ z.strictObject({ type: z.enum(['bearer', 'basic']) }),
18
+ z.strictObject({ type: z.literal('apiKey'), name: z.string(), in: z.enum(['header', 'query']) }),
19
+ ])
20
+ .default({ type: 'none' }),
21
+ responseFormat: z.enum(['auto', 'json', 'text']).default('auto'),
22
+ statusPolicy: z.enum(['success', 'all']).default('success'),
23
+ })
24
+ export type HttpRequestConfig = z.infer<typeof httpRequestConfigSchema>
25
+ export interface HttpRequestExecutor extends HttpRequestConfig {
26
+ readonly kind: 'http-request'
27
+ }
28
+ export const httpRequestExecutorSchema = httpRequestConfigSchema.extend({ kind: z.literal('http-request') })
29
+ const scalarSchema = { type: ['string', 'number', 'boolean'] }
30
+ const queryValueSchema = { anyOf: [scalarSchema, { type: 'array', items: scalarSchema }] }
31
+ export const httpHeaderSchema = { type: 'object', additionalProperties: { type: 'string' } }
32
+ export const httpQuerySchema = { type: 'object', additionalProperties: queryValueSchema }
33
+
34
+ export function httpAuthHandles(config: HttpRequestConfig): string[] {
35
+ return config.authentication.type == 'none' ? [] : config.authentication.type == 'basic' ? ['auth.username', 'auth.password'] : ['auth.token']
36
+ }
37
+ // Preserve metadata on ports whose contracts did not change.
38
+ function retain(ports: readonly InputPort[], old: ManagedTaskDefinition['inputs']): ManagedTaskDefinition['inputs'] {
39
+ const remaining = new Map(ports.map((port) => [port.handle, port]))
40
+ return [
41
+ ...old.flatMap((item): ManagedTaskDefinition['inputs'] => {
42
+ if ('group' in item) return [item]
43
+ const next = remaining.get(item.handle)
44
+ if (next == null) return []
45
+ remaining.delete(item.handle)
46
+ return [dequal(item.jsonSchema, next.jsonSchema) && item.nullable == next.nullable ? item : next]
47
+ }),
48
+ ...remaining.values(),
49
+ ]
50
+ }
51
+ export function httpRequestTask(
52
+ config: HttpRequestConfig = httpRequestConfigSchema.parse({}),
53
+ name = 'HTTP Request',
54
+ previous?: ManagedTaskDefinition,
55
+ ): ManagedTaskDefinition {
56
+ const inputs: InputPort[] = [{ handle: 'url', jsonSchema: { type: 'string' }, nullable: false }]
57
+ for (const group of ['query', 'headers'] as const) {
58
+ if (config[group].mode == 'object') inputs.push({ handle: group, jsonSchema: group == 'query' ? httpQuerySchema : httpHeaderSchema, nullable: true })
59
+ else
60
+ for (const parameterName of config[group].names.filter((value) => value.trim()))
61
+ inputs.push({
62
+ handle: `${group == 'query' ? 'query' : 'header'}.${parameterName}`,
63
+ jsonSchema: group == 'query' ? queryValueSchema : { type: 'string' },
64
+ nullable: true,
65
+ })
66
+ }
67
+ if (config.bodyFormat != 'none')
68
+ inputs.push({
69
+ handle: 'body',
70
+ jsonSchema: config.bodyFormat == 'json' ? {} : config.bodyFormat == 'text' ? { type: 'string' } : httpQuerySchema,
71
+ nullable: config.bodyFormat == 'json',
72
+ })
73
+ inputs.push(...httpAuthHandles(config).map((handle) => ({ handle, jsonSchema: { type: 'string' }, nullable: false })))
74
+ const outputs: InputPort[] = [
75
+ { handle: 'body', jsonSchema: config.responseFormat == 'text' ? { type: 'string' } : {}, nullable: true },
76
+ { handle: 'statusCode', jsonSchema: { type: 'integer' }, nullable: false },
77
+ { handle: 'headers', jsonSchema: httpHeaderSchema, nullable: false },
78
+ ]
79
+
80
+ return {
81
+ name,
82
+ executor: { ...config, kind: 'http-request' },
83
+ inputs: retain(inputs, previous?.inputs ?? []),
84
+ outputs: retain(outputs, previous?.outputs ?? []),
85
+ }
86
+ }
87
+ export interface HttpRequestIssue {
88
+ field: string
89
+ index?: number
90
+ code: 'bodyUnsupported' | 'parameterNamesInvalid' | 'headerNameInvalid' | 'keyNameRequired' | 'authConflict'
91
+ message: string
92
+ }
93
+ export function httpRequestIssues(config: HttpRequestConfig): HttpRequestIssue[] {
94
+ const issues: HttpRequestIssue[] = []
95
+ if (['GET', 'HEAD'].includes(config.method) && config.bodyFormat != 'none')
96
+ issues.push({ field: 'bodyFormat', code: 'bodyUnsupported', message: 'GET and HEAD do not support a request body.' })
97
+ for (const group of ['query', 'headers'] as const) {
98
+ if (config[group].mode != 'fields') continue
99
+ const seen = new Set<string>()
100
+ for (const [index, name] of config[group].names.entries()) {
101
+ const key = group == 'headers' ? name.toLowerCase() : name
102
+ if (!name.trim() || seen.has(key))
103
+ issues.push({ field: group, index, code: 'parameterNamesInvalid', message: 'Parameter names must be nonempty and unique.' })
104
+ seen.add(key)
105
+ if (group == 'headers' && httpHeaderNameIssue(name, []) === 'invalid')
106
+ issues.push({ field: group, index, code: 'headerNameInvalid', message: 'Invalid HTTP header name.' })
107
+ }
108
+ }
109
+ const auth = config.authentication
110
+ if (auth.type != 'none') {
111
+ const group = auth.type == 'apiKey' && auth.in == 'query' ? 'query' : 'headers'
112
+ const name = auth.type == 'apiKey' ? auth.name : 'authorization'
113
+ if (!name.trim()) issues.push({ field: 'authentication', code: 'keyNameRequired', message: 'API Key requires a name.' })
114
+ if (group == 'headers' && name.trim() && httpHeaderNameIssue(name, []) === 'invalid')
115
+ issues.push({ field: 'authentication', code: 'headerNameInvalid', message: 'Invalid authentication header name.' })
116
+ if (config[group].mode == 'fields' && config[group].names.some((item) => (group == 'headers' ? item.toLowerCase() == name.toLowerCase() : item == name)))
117
+ issues.push({ field: 'authentication', code: 'authConflict', message: 'Authentication conflicts with a request parameter.' })
118
+ }
119
+ return issues
120
+ }
121
+ function entries(value: JsonValue | undefined): [string, JsonValue][] {
122
+ if (value == null) return []
123
+ if (typeof value != 'object' || Array.isArray(value)) throw new Error('Expected a parameter object.')
124
+ return Object.entries(value)
125
+ }
126
+ function scalar(value: JsonValue): string {
127
+ if (typeof value != 'string' && typeof value != 'number' && typeof value != 'boolean') throw new Error('Expected a scalar parameter.')
128
+ return String(value)
129
+ }
130
+ function append(query: URLSearchParams, name: string, value: JsonValue): void {
131
+ for (const item of Array.isArray(value) ? value : [value]) query.append(name, scalar(item))
132
+ }
133
+ export function httpRequestUrl(value: unknown): URL {
134
+ if (typeof value != 'string' || !value.trim()) throw new Error('A URL is required.')
135
+ const url = new URL(value)
136
+ if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password) throw new Error('An HTTP(S) URL without credentials is required.')
137
+ return url
138
+ }
139
+ export function buildHttpRequest(config: HttpRequestConfig, input: Readonly<Record<string, JsonValue>>): { url: string; init: RequestInit } {
140
+ if (httpRequestIssues(config).length) throw new Error('Invalid HTTP request configuration.')
141
+ const url = httpRequestUrl(input.url)
142
+ const parameters = (group: 'query' | 'headers') =>
143
+ config[group].mode == 'object'
144
+ ? entries(input[group])
145
+ : config[group].names.flatMap((name): [string, JsonValue][] => {
146
+ const value = input[`${group == 'query' ? 'query' : 'header'}.${name}`]
147
+ return value == null ? [] : [[name, value]]
148
+ })
149
+ for (const [name, value] of parameters('query')) {
150
+ url.searchParams.delete(name)
151
+ append(url.searchParams, name, value)
152
+ }
153
+ const headers = new Headers()
154
+ for (const [name, value] of parameters('headers')) {
155
+ if (headers.has(name)) throw new Error('Duplicate HTTP header.')
156
+ if (typeof value != 'string') throw new Error('HTTP headers require text values.')
157
+ headers.set(name, value)
158
+ }
159
+ const auth = config.authentication
160
+ const credential = (part: string) => {
161
+ const value = input[`auth.${part}`]
162
+ if (typeof value != 'string' || !value) throw new Error('Authentication source is required.')
163
+ return value
164
+ }
165
+ if (auth.type != 'none') {
166
+ const name = auth.type == 'apiKey' ? auth.name : 'authorization'
167
+ if (auth.type == 'apiKey' && auth.in == 'query') {
168
+ if (url.searchParams.has(name)) throw new Error('Authentication conflicts with a query parameter.')
169
+ url.searchParams.set(name, credential('token'))
170
+ } else {
171
+ if (headers.has(name)) throw new Error('Authentication conflicts with a header.')
172
+ if (auth.type == 'basic') {
173
+ const username = credential('username')
174
+ if (username.includes(':')) throw new Error('Basic username cannot contain a colon.')
175
+ const bytes = new TextEncoder().encode(`${username}:${credential('password')}`)
176
+ headers.set(name, `Basic ${btoa(Array.from(bytes, (byte) => String.fromCharCode(byte)).join(''))}`)
177
+ } else headers.set(name, auth.type == 'bearer' ? `Bearer ${credential('token')}` : credential('token'))
178
+ }
179
+ }
180
+ let body: string | undefined
181
+ if (config.bodyFormat != 'none') {
182
+ if (!Object.hasOwn(input, 'body')) throw new Error('Request body is unset.')
183
+ let contentType: string
184
+ if (config.bodyFormat == 'json') {
185
+ body = JSON.stringify(input.body)
186
+ contentType = 'application/json'
187
+ } else if (config.bodyFormat == 'text') {
188
+ if (typeof input.body != 'string') throw new Error('Text body requires a string.')
189
+ body = input.body
190
+ contentType = 'text/plain'
191
+ } else {
192
+ if (input.body == null) throw new Error('Form body requires an object.')
193
+ const form = new URLSearchParams()
194
+ for (const [name, value] of entries(input.body)) append(form, name, value)
195
+ body = form.toString()
196
+ contentType = 'application/x-www-form-urlencoded'
197
+ }
198
+ const supplied = headers.get('content-type')
199
+ if (config.bodyFormat != 'text' && supplied != null && supplied.split(';')[0]!.trim().toLowerCase() != contentType)
200
+ throw new Error('Content-Type conflicts with body format.')
201
+ if (supplied == null) headers.set('content-type', contentType)
202
+ }
203
+ return { url: url.href, init: { method: config.method, headers, body, redirect: 'manual' } }
204
+ }
205
+ export function parseHttpResponse(config: HttpRequestConfig, status: number, headers: Headers, text: string): Record<string, JsonValue> {
206
+ if (config.statusPolicy == 'success' && (status < 200 || status >= 300)) throw new Error(`HTTP ${status}`)
207
+ let body: JsonValue = null
208
+ if (text && config.method != 'HEAD' && ![204, 205, 304].includes(status)) {
209
+ const media = (headers.get('content-type') ?? '').split(';')[0]!.trim().toLowerCase()
210
+ body =
211
+ config.responseFormat == 'json' || (config.responseFormat == 'auto' && /^application\/(json|.+\+json)$/.test(media))
212
+ ? (JSON.parse(text) as JsonValue)
213
+ : text
214
+ }
215
+ return { body, statusCode: status, headers: Object.fromEntries([...headers].filter(([name]) => name != 'set-cookie')) }
216
+ }
217
+
218
+ /** Only a named parameter rename carries a value; changing source modes is not a rename. */
219
+ export function httpRequestInputs(
220
+ mappings: Readonly<Record<string, InputMapping>>,
221
+ previous: ManagedTaskDefinition,
222
+ next: ManagedTaskDefinition,
223
+ ): Record<string, InputMapping> {
224
+ const candidate = renamedPort(previous.inputs, next.inputs)
225
+ const rename = candidate != null && ['query.', 'header.'].some((prefix) => candidate.every((name) => name.startsWith(prefix))) ? candidate : undefined
226
+ return remapInputMappings(mappings, next.inputs, rename)
227
+ }
228
+
229
+ /** The object editor assembles named inputs without changing unrelated request settings. */
230
+ export function withHttpParameterFields(node: TaskNode, group: 'query' | 'headers', values: Record<string, JsonValue>): TaskNode {
231
+ if (!('executor' in node.task) || node.task.executor.kind !== 'http-request') return node
232
+ const config = node.task.executor
233
+ const task = httpRequestTask({ ...config, [group]: { mode: 'fields', names: Object.keys(values) } }, node.task.name, node.task)
234
+ const inputs = httpRequestInputs(node.inputs, node.task, task)
235
+ const rename = renamedPort(node.task.inputs, task.inputs)
236
+ for (const [name, value] of Object.entries(values)) {
237
+ const handle = `${group === 'query' ? 'query' : 'header'}.${name}`
238
+ const existing = config[group].mode === 'fields' && (config[group].names.includes(name) || rename?.[1] === handle)
239
+ if (inputs[handle] == null && !existing) inputs[handle] = { kind: 'value', value }
240
+ }
241
+ return { ...node, task, inputs }
242
+ }
243
+
244
+ export function withHttpParameterSource(node: TaskNode, group: 'query' | 'headers', mapping?: InputMapping): TaskNode {
245
+ if (!('executor' in node.task) || node.task.executor.kind !== 'http-request') return node
246
+ const task = httpRequestTask({ ...node.task.executor, [group]: { mode: 'object', names: [] } }, node.task.name, node.task)
247
+ const inputs = httpRequestInputs(node.inputs, node.task, task)
248
+ if (mapping == null) delete inputs[group]
249
+ else inputs[group] = mapping
250
+ return { ...node, task, inputs }
251
+ }
@@ -0,0 +1,142 @@
1
+ import type { CompiledSchema } from '../compiler/index.ts'
2
+ import type { ExpressionResult } from '../expression/index.ts'
3
+ import type { Schema } from '../types.ts'
4
+ import type { Context } from './cache.ts'
5
+
6
+ import { ANY } from '../compiler/index.ts'
7
+ import {
8
+ ExpressionNone,
9
+ ExpressionContainedBy,
10
+ ExpressionContaining,
11
+ ExpressionEquals,
12
+ ExpressionIntersection,
13
+ ExpressionRejection,
14
+ ExpressionSingleResult,
15
+ } from '../expression/index.ts'
16
+ import { createRangeSplitter, toExpressionSingleResult } from './range.ts'
17
+ import { makeQuantum } from './tools/index.ts'
18
+
19
+ const splitRange = createRangeSplitter(0)
20
+ const quantum = makeQuantum(['hasCommon', 'hasExtra1', 'hasExtra2', 'hasRejection', 'hasCommonBroken'])
21
+
22
+ export function calculateArray<E>({ calculate }: Context<E>, schema1: CompiledSchema<E>, schema2: CompiledSchema<E>): ExpressionResult {
23
+ const splitResult = splitRange(schema1.minItems, schema1.maxItems, schema2.minItems, schema2.maxItems)
24
+ const splitExpression = toExpressionSingleResult(splitResult)
25
+
26
+ if (splitExpression === ExpressionSingleResult.Rejection) {
27
+ return ExpressionRejection
28
+ }
29
+ const [items1, additionalItems1] = normalizeArray(schema1)
30
+ const [items2, additionalItems2] = normalizeArray(schema2)
31
+
32
+ // The final slot compares additionalItems without a tuple item.
33
+ const itemsLength = Math.max(items1.length, items2.length) + 1
34
+ const length = Math.min(itemsLength, splitResult.intersection!.max)
35
+ const quantumVariable = quantum.variable({})
36
+ const minItems = Math.min(schema1.minItems ?? 0, schema2.minItems ?? 0)
37
+
38
+ for (let i = 0; i < length; i++) {
39
+ const subSchema1 = items1[i] ?? additionalItems1
40
+ const subSchema2 = items2[i] ?? additionalItems2
41
+ const expression = calculate(subSchema1, subSchema2)
42
+
43
+ quantumVariable.push(expression, (singleExpression, variable) => {
44
+ switch (singleExpression) {
45
+ case ExpressionSingleResult.Equals: {
46
+ if (!variable.hasRejection) {
47
+ variable.hasCommon = true
48
+ }
49
+ break
50
+ }
51
+ case ExpressionSingleResult.Containing: {
52
+ if (!variable.hasRejection) {
53
+ variable.hasCommon = true
54
+ }
55
+ variable.hasExtra1 = true
56
+ break
57
+ }
58
+ case ExpressionSingleResult.ContainedBy: {
59
+ if (!variable.hasRejection) {
60
+ variable.hasCommon = true
61
+ }
62
+ variable.hasExtra2 = true
63
+ break
64
+ }
65
+ case ExpressionSingleResult.Intersection: {
66
+ if (!variable.hasRejection) {
67
+ variable.hasCommon = true
68
+ }
69
+ variable.hasExtra1 = true
70
+ variable.hasExtra2 = true
71
+ break
72
+ }
73
+ case ExpressionSingleResult.Rejection: {
74
+ if (i < minItems) {
75
+ variable.hasCommonBroken = true
76
+ }
77
+ variable.hasRejection = true
78
+ variable.hasExtra1 = true
79
+ variable.hasExtra2 = true
80
+ break
81
+ }
82
+ }
83
+ })
84
+ }
85
+ quantumVariable.update((variable) => {
86
+ switch (splitExpression) {
87
+ case ExpressionSingleResult.Containing: {
88
+ variable.hasExtra1 = true
89
+ break
90
+ }
91
+ case ExpressionSingleResult.ContainedBy: {
92
+ variable.hasExtra2 = true
93
+ break
94
+ }
95
+ case ExpressionSingleResult.Intersection: {
96
+ variable.hasExtra1 = true
97
+ variable.hasExtra2 = true
98
+ break
99
+ }
100
+ }
101
+ if (schema1.uniqueItems && !schema2.uniqueItems && (schema2.maxItems ?? Number.POSITIVE_INFINITY) > 1) variable.hasExtra2 = true
102
+ else if (!schema1.uniqueItems && schema2.uniqueItems && (schema1.maxItems ?? Number.POSITIVE_INFINITY) > 1) variable.hasExtra1 = true
103
+ if (schema1.maxItems === 0 || schema2.maxItems === 0) {
104
+ // An unconstrained empty array can match any array schema.
105
+ variable.hasCommon = true
106
+ if (schema1.maxItems !== 0) {
107
+ variable.hasExtra1 = true
108
+ }
109
+ if (schema2.maxItems !== 0) {
110
+ variable.hasExtra2 = true
111
+ }
112
+ }
113
+ })
114
+ let expression = ExpressionNone
115
+
116
+ for (const { hasExtra1, hasExtra2, hasCommon, hasCommonBroken } of quantumVariable) {
117
+ let finalHasCommon = hasCommon
118
+ if (hasCommonBroken) {
119
+ finalHasCommon = false
120
+ }
121
+ if (!finalHasCommon) {
122
+ expression |= ExpressionRejection
123
+ } else if (hasExtra1 && hasExtra2) {
124
+ expression |= ExpressionIntersection
125
+ } else if (hasExtra1) {
126
+ expression |= ExpressionContaining
127
+ } else if (hasExtra2) {
128
+ expression |= ExpressionContainedBy
129
+ } else {
130
+ expression |= ExpressionEquals
131
+ }
132
+ }
133
+ return expression
134
+ }
135
+
136
+ function normalizeArray<E>({ items, additionalItems }: CompiledSchema<E>): [readonly Schema<E>[], Schema<E>] {
137
+ if (Array.isArray(items)) {
138
+ return [items as readonly Schema<E>[], (additionalItems ?? ANY) as Schema<E>]
139
+ } else {
140
+ return [[], (items ?? ANY) as Schema<E>]
141
+ }
142
+ }
@@ -0,0 +1,57 @@
1
+ import type { CompiledObject, CompiledSchema, CompiledValue } from '../compiler/index.ts'
2
+ import type { ExpressionResult } from '../expression/index.ts'
3
+ import type { ExtendsSchema } from '../extends/index.ts'
4
+ import type { Schema } from '../types.ts'
5
+ import type { DeepReadonly } from '../utils.ts'
6
+
7
+ import { getId, isCompiledObject } from '../compiler/index.ts'
8
+
9
+ export type Context<E> = {
10
+ readonly isEquals: EqualsChecker
11
+ readonly calculate: SchemaCalculator<E>
12
+ }
13
+
14
+ export type EqualsChecker = (value1: CompiledValue, value2: CompiledValue) => boolean
15
+ export type SchemaCalculator<E> = (superSchema: Schema<E>, subSchema: Schema<E>) => ExpressionResult
16
+
17
+ export function wrapEqualsCheckerWithCache(check: (object1: CompiledObject, object2: CompiledObject) => boolean): EqualsChecker {
18
+ const map = new Map<string, boolean>()
19
+
20
+ return (value1, value2) => {
21
+ const isObject1 = isCompiledObject(value1)
22
+ const isObject2 = isCompiledObject(value2)
23
+
24
+ if (isObject1 !== isObject2) {
25
+ return false
26
+ }
27
+ if (!isObject1) {
28
+ return value1 === value2
29
+ }
30
+ const object1 = value1 as CompiledObject
31
+ const object2 = value2 as CompiledObject
32
+
33
+ return getWithCache(map, object1, object2, check)
34
+ }
35
+ }
36
+
37
+ export function wrapSchemaCalculatorWithCache<E>(check: SchemaCalculator<E>): SchemaCalculator<E> {
38
+ const map = new Map<string, ExpressionResult>()
39
+ return (schema1, schema2) => getWithCache(map, schema1, schema2, check)
40
+ }
41
+
42
+ function getWithCache<R, E, N extends ExtendsSchema | DeepReadonly<CompiledSchema<E>> | DeepReadonly<CompiledObject>>(
43
+ map: Map<string, R>,
44
+ node1: N,
45
+ node2: N,
46
+ check: (n1: N, n2: N) => R,
47
+ ): R {
48
+ const id1 = getId(node1)
49
+ const id2 = getId(node2)
50
+ const key = `${id1}/${id2}`
51
+
52
+ let result = map.get(key)
53
+ if (result === undefined) {
54
+ map.set(key, (result = check(node1, node2)))
55
+ }
56
+ return result
57
+ }