@shware/workflow 2.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/README.md +106 -2
  2. package/dist/apns-relay.cjs +4 -17
  3. package/dist/apns-relay.cjs.map +1 -1
  4. package/dist/apns-relay.mjs +4 -17
  5. package/dist/apns-relay.mjs.map +1 -1
  6. package/dist/aws/engine-step.cjs +104 -0
  7. package/dist/aws/engine-step.cjs.map +1 -0
  8. package/dist/aws/engine-step.d.cts +28 -0
  9. package/dist/aws/engine-step.d.cts.map +1 -0
  10. package/dist/aws/engine-step.d.mts +28 -0
  11. package/dist/aws/engine-step.d.mts.map +1 -0
  12. package/dist/aws/engine-step.mjs +102 -0
  13. package/dist/aws/engine-step.mjs.map +1 -0
  14. package/dist/aws/function-url.cjs +62 -0
  15. package/dist/aws/function-url.cjs.map +1 -0
  16. package/dist/aws/function-url.d.cts +38 -0
  17. package/dist/aws/function-url.d.cts.map +1 -0
  18. package/dist/aws/function-url.d.mts +38 -0
  19. package/dist/aws/function-url.d.mts.map +1 -0
  20. package/dist/aws/function-url.mjs +59 -0
  21. package/dist/aws/function-url.mjs.map +1 -0
  22. package/dist/aws/index.cjs +160 -0
  23. package/dist/aws/index.cjs.map +1 -0
  24. package/dist/aws/index.d.cts +68 -0
  25. package/dist/aws/index.d.cts.map +1 -0
  26. package/dist/aws/index.d.mts +68 -0
  27. package/dist/aws/index.d.mts.map +1 -0
  28. package/dist/aws/index.mjs +148 -0
  29. package/dist/aws/index.mjs.map +1 -0
  30. package/dist/aws/instances.cjs +196 -0
  31. package/dist/aws/instances.cjs.map +1 -0
  32. package/dist/aws/instances.d.cts +94 -0
  33. package/dist/aws/instances.d.cts.map +1 -0
  34. package/dist/aws/instances.d.mts +94 -0
  35. package/dist/aws/instances.d.mts.map +1 -0
  36. package/dist/aws/instances.mjs +192 -0
  37. package/dist/aws/instances.mjs.map +1 -0
  38. package/dist/aws/lambda-api.cjs +89 -0
  39. package/dist/aws/lambda-api.cjs.map +1 -0
  40. package/dist/aws/lambda-api.d.cts +43 -0
  41. package/dist/aws/lambda-api.d.cts.map +1 -0
  42. package/dist/aws/lambda-api.d.mts +43 -0
  43. package/dist/aws/lambda-api.d.mts.map +1 -0
  44. package/dist/aws/lambda-api.mjs +88 -0
  45. package/dist/aws/lambda-api.mjs.map +1 -0
  46. package/dist/client.d.cts +1 -1
  47. package/dist/client.d.mts +1 -1
  48. package/dist/cloudflare/bindings.cjs +19 -0
  49. package/dist/cloudflare/bindings.cjs.map +1 -1
  50. package/dist/cloudflare/bindings.d.cts +39 -0
  51. package/dist/cloudflare/bindings.d.cts.map +1 -1
  52. package/dist/cloudflare/bindings.d.mts +39 -0
  53. package/dist/cloudflare/bindings.d.mts.map +1 -1
  54. package/dist/cloudflare/bindings.mjs +18 -1
  55. package/dist/cloudflare/bindings.mjs.map +1 -1
  56. package/dist/cloudflare/index.cjs +32 -28
  57. package/dist/cloudflare/index.d.cts +8 -6
  58. package/dist/cloudflare/index.d.mts +8 -6
  59. package/dist/cloudflare/index.mjs +12 -10
  60. package/dist/cloudflare/runner.cjs +27 -76
  61. package/dist/cloudflare/runner.cjs.map +1 -1
  62. package/dist/cloudflare/runner.d.cts +7 -2
  63. package/dist/cloudflare/runner.d.cts.map +1 -1
  64. package/dist/cloudflare/runner.d.mts +7 -2
  65. package/dist/cloudflare/runner.d.mts.map +1 -1
  66. package/dist/cloudflare/runner.mjs +26 -75
  67. package/dist/cloudflare/runner.mjs.map +1 -1
  68. package/dist/cloudflare/worker.cjs +22 -203
  69. package/dist/cloudflare/worker.cjs.map +1 -1
  70. package/dist/cloudflare/worker.d.cts +10 -56
  71. package/dist/cloudflare/worker.d.cts.map +1 -1
  72. package/dist/cloudflare/worker.d.mts +10 -56
  73. package/dist/cloudflare/worker.d.mts.map +1 -1
  74. package/dist/cloudflare/worker.mjs +20 -199
  75. package/dist/cloudflare/worker.mjs.map +1 -1
  76. package/dist/email-sender.cjs +62 -0
  77. package/dist/email-sender.cjs.map +1 -0
  78. package/dist/email-sender.d.cts +70 -0
  79. package/dist/email-sender.d.cts.map +1 -0
  80. package/dist/email-sender.d.mts +70 -0
  81. package/dist/email-sender.d.mts.map +1 -0
  82. package/dist/email-sender.mjs +60 -0
  83. package/dist/email-sender.mjs.map +1 -0
  84. package/dist/email.cjs +21 -0
  85. package/dist/email.cjs.map +1 -1
  86. package/dist/email.d.cts +6 -0
  87. package/dist/email.d.cts.map +1 -1
  88. package/dist/email.d.mts +6 -0
  89. package/dist/email.d.mts.map +1 -1
  90. package/dist/email.mjs +21 -1
  91. package/dist/email.mjs.map +1 -1
  92. package/dist/engine/index.cjs +1 -1
  93. package/dist/engine/index.mjs +1 -1
  94. package/dist/engine/interpreter.cjs +1 -1
  95. package/dist/engine/interpreter.cjs.map +1 -1
  96. package/dist/engine/interpreter.mjs +1 -1
  97. package/dist/engine/interpreter.mjs.map +1 -1
  98. package/dist/engine/ports.d.cts +6 -1
  99. package/dist/engine/ports.d.cts.map +1 -1
  100. package/dist/engine/ports.d.mts +6 -1
  101. package/dist/engine/ports.d.mts.map +1 -1
  102. package/dist/{cloudflare → host}/channels.cjs +13 -11
  103. package/dist/host/channels.cjs.map +1 -0
  104. package/dist/{cloudflare → host}/channels.d.cts +8 -3
  105. package/dist/host/channels.d.cts.map +1 -0
  106. package/dist/{cloudflare → host}/channels.d.mts +8 -3
  107. package/dist/host/channels.d.mts.map +1 -0
  108. package/dist/{cloudflare → host}/channels.mjs +9 -7
  109. package/dist/host/channels.mjs.map +1 -0
  110. package/dist/host/execute.cjs +81 -0
  111. package/dist/host/execute.cjs.map +1 -0
  112. package/dist/host/execute.d.cts +37 -0
  113. package/dist/host/execute.d.cts.map +1 -0
  114. package/dist/host/execute.d.mts +37 -0
  115. package/dist/host/execute.d.mts.map +1 -0
  116. package/dist/host/execute.mjs +80 -0
  117. package/dist/host/execute.mjs.map +1 -0
  118. package/dist/host/journey-host.cjs +214 -0
  119. package/dist/host/journey-host.cjs.map +1 -0
  120. package/dist/host/journey-host.d.cts +105 -0
  121. package/dist/host/journey-host.d.cts.map +1 -0
  122. package/dist/host/journey-host.d.mts +105 -0
  123. package/dist/host/journey-host.d.mts.map +1 -0
  124. package/dist/host/journey-host.mjs +210 -0
  125. package/dist/host/journey-host.mjs.map +1 -0
  126. package/dist/{cloudflare → host}/router.cjs +34 -13
  127. package/dist/host/router.cjs.map +1 -0
  128. package/dist/{cloudflare → host}/router.d.cts +2 -2
  129. package/dist/host/router.d.cts.map +1 -0
  130. package/dist/{cloudflare → host}/router.d.mts +2 -2
  131. package/dist/host/router.d.mts.map +1 -0
  132. package/dist/{cloudflare → host}/router.mjs +34 -13
  133. package/dist/host/router.mjs.map +1 -0
  134. package/dist/host/senders.cjs +63 -0
  135. package/dist/host/senders.cjs.map +1 -0
  136. package/dist/host/senders.d.cts +31 -0
  137. package/dist/host/senders.d.cts.map +1 -0
  138. package/dist/host/senders.d.mts +31 -0
  139. package/dist/host/senders.d.mts.map +1 -0
  140. package/dist/host/senders.mjs +59 -0
  141. package/dist/host/senders.mjs.map +1 -0
  142. package/dist/http2-client.cjs +90 -0
  143. package/dist/http2-client.cjs.map +1 -0
  144. package/dist/http2-client.d.cts +47 -0
  145. package/dist/http2-client.d.cts.map +1 -0
  146. package/dist/http2-client.d.mts +47 -0
  147. package/dist/http2-client.d.mts.map +1 -0
  148. package/dist/http2-client.mjs +88 -0
  149. package/dist/http2-client.mjs.map +1 -0
  150. package/dist/index.cjs +1 -0
  151. package/dist/index.d.cts +2 -2
  152. package/dist/index.d.mts +2 -2
  153. package/dist/index.mjs +2 -2
  154. package/dist/react-email.cjs.map +1 -1
  155. package/dist/react-email.d.cts +1 -2
  156. package/dist/react-email.d.cts.map +1 -1
  157. package/dist/react-email.d.mts +1 -2
  158. package/dist/react-email.d.mts.map +1 -1
  159. package/dist/react-email.mjs.map +1 -1
  160. package/dist/store/d1.cjs +1 -0
  161. package/dist/store/d1.cjs.map +1 -1
  162. package/dist/store/d1.d.cts.map +1 -1
  163. package/dist/store/d1.d.mts.map +1 -1
  164. package/dist/store/d1.mjs +1 -0
  165. package/dist/store/d1.mjs.map +1 -1
  166. package/dist/store/index.cjs.map +1 -1
  167. package/dist/store/index.d.cts +74 -0
  168. package/dist/store/index.d.cts.map +1 -1
  169. package/dist/store/index.d.mts +74 -0
  170. package/dist/store/index.d.mts.map +1 -1
  171. package/dist/store/index.mjs.map +1 -1
  172. package/dist/store/postgres.cjs +177 -12
  173. package/dist/store/postgres.cjs.map +1 -1
  174. package/dist/store/postgres.d.cts +10 -1
  175. package/dist/store/postgres.d.cts.map +1 -1
  176. package/dist/store/postgres.d.mts +10 -1
  177. package/dist/store/postgres.d.mts.map +1 -1
  178. package/dist/store/postgres.mjs +177 -12
  179. package/dist/store/postgres.mjs.map +1 -1
  180. package/dist/store/tables.cjs +31 -2
  181. package/dist/store/tables.cjs.map +1 -1
  182. package/dist/store/tables.d.cts +1 -0
  183. package/dist/store/tables.d.cts.map +1 -1
  184. package/dist/store/tables.d.mts +1 -0
  185. package/dist/store/tables.d.mts.map +1 -1
  186. package/dist/store/tables.mjs +31 -2
  187. package/dist/store/tables.mjs.map +1 -1
  188. package/dist/transports/cloudflare-email.cjs +59 -0
  189. package/dist/transports/cloudflare-email.cjs.map +1 -0
  190. package/dist/transports/cloudflare-email.d.cts +38 -0
  191. package/dist/transports/cloudflare-email.d.cts.map +1 -0
  192. package/dist/transports/cloudflare-email.d.mts +38 -0
  193. package/dist/transports/cloudflare-email.d.mts.map +1 -0
  194. package/dist/transports/cloudflare-email.mjs +57 -0
  195. package/dist/transports/cloudflare-email.mjs.map +1 -0
  196. package/dist/transports/ses.cjs +91 -0
  197. package/dist/transports/ses.cjs.map +1 -0
  198. package/dist/transports/ses.d.cts +39 -0
  199. package/dist/transports/ses.d.cts.map +1 -0
  200. package/dist/transports/ses.d.mts +39 -0
  201. package/dist/transports/ses.d.mts.map +1 -0
  202. package/dist/transports/ses.mjs +89 -0
  203. package/dist/transports/ses.mjs.map +1 -0
  204. package/dist/transports/sigv4.cjs +83 -0
  205. package/dist/transports/sigv4.cjs.map +1 -0
  206. package/dist/transports/sigv4.d.cts +27 -0
  207. package/dist/transports/sigv4.d.cts.map +1 -0
  208. package/dist/transports/sigv4.d.mts +27 -0
  209. package/dist/transports/sigv4.d.mts.map +1 -0
  210. package/dist/transports/sigv4.mjs +82 -0
  211. package/dist/transports/sigv4.mjs.map +1 -0
  212. package/package.json +53 -1
  213. package/dist/cloudflare/channels.cjs.map +0 -1
  214. package/dist/cloudflare/channels.d.cts.map +0 -1
  215. package/dist/cloudflare/channels.d.mts.map +0 -1
  216. package/dist/cloudflare/channels.mjs.map +0 -1
  217. package/dist/cloudflare/router.cjs.map +0 -1
  218. package/dist/cloudflare/router.d.cts.map +0 -1
  219. package/dist/cloudflare/router.d.mts.map +0 -1
  220. package/dist/cloudflare/router.mjs.map +0 -1
  221. package/dist/cloudflare/senders.cjs +0 -121
  222. package/dist/cloudflare/senders.cjs.map +0 -1
  223. package/dist/cloudflare/senders.d.cts +0 -72
  224. package/dist/cloudflare/senders.d.cts.map +0 -1
  225. package/dist/cloudflare/senders.d.mts +0 -72
  226. package/dist/cloudflare/senders.d.mts.map +0 -1
  227. package/dist/cloudflare/senders.mjs +0 -115
  228. package/dist/cloudflare/senders.mjs.map +0 -1
@@ -0,0 +1,62 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/aws/function-url.ts
3
+ /**
4
+ * An HTTP request, told apart by the event's own top-level shape — the Function URL wraps
5
+ * every request in `requestContext.http`, so no request body can pass for anything else.
6
+ */
7
+ function isFunctionUrlEvent(event) {
8
+ if (typeof event !== "object" || event === null) return false;
9
+ const { requestContext, rawPath } = event;
10
+ return typeof rawPath === "string" && typeof requestContext === "object" && requestContext !== null && typeof requestContext.http === "object" && requestContext.http !== null && typeof requestContext.http.method === "string";
11
+ }
12
+ function fromBase64(value) {
13
+ const binary = atob(value);
14
+ const bytes = new Uint8Array(binary.length);
15
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
16
+ return bytes;
17
+ }
18
+ function toBase64(bytes) {
19
+ let binary = "";
20
+ for (let i = 0; i < bytes.length; i += 32768) binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
21
+ return btoa(binary);
22
+ }
23
+ function toRequest(event) {
24
+ const method = event.requestContext.http.method.toUpperCase();
25
+ const headers = new Headers();
26
+ for (const [name, value] of Object.entries(event.headers ?? {})) if (value !== void 0) headers.set(name, value);
27
+ if (event.cookies !== void 0 && event.cookies.length > 0) headers.set("cookie", event.cookies.join("; "));
28
+ const host = event.requestContext.domainName ?? headers.get("host") ?? "localhost";
29
+ const query = event.rawQueryString === void 0 || event.rawQueryString === "" ? "" : `?${event.rawQueryString}`;
30
+ const hasBody = method !== "GET" && method !== "HEAD" && event.body !== void 0;
31
+ return new Request(`https://${host}${event.rawPath}${query}`, {
32
+ method,
33
+ headers,
34
+ ...hasBody ? { body: event.isBase64Encoded === true ? fromBase64(event.body ?? "") : event.body } : {}
35
+ });
36
+ }
37
+ /** Content types sent as text; everything else (a tracking pixel) goes back base64. */
38
+ const TEXTUAL = /^(text\/|application\/(json|javascript|xml|x-www-form-urlencoded)|image\/svg\+xml)/i;
39
+ async function fromResponse(response, method) {
40
+ const headers = {};
41
+ const cookies = [];
42
+ response.headers.forEach((value, name) => {
43
+ if (name === "set-cookie") cookies.push(value);
44
+ else headers[name] = value;
45
+ });
46
+ const contentType = response.headers.get("content-type") ?? "";
47
+ const bytes = method.toUpperCase() === "HEAD" ? /* @__PURE__ */ new Uint8Array() : new Uint8Array(await response.arrayBuffer());
48
+ const textual = bytes.length === 0 || TEXTUAL.test(contentType);
49
+ return {
50
+ statusCode: response.status,
51
+ headers,
52
+ ...cookies.length === 0 ? {} : { cookies },
53
+ body: textual ? new TextDecoder().decode(bytes) : toBase64(bytes),
54
+ isBase64Encoded: !textual
55
+ };
56
+ }
57
+ //#endregion
58
+ exports.fromResponse = fromResponse;
59
+ exports.isFunctionUrlEvent = isFunctionUrlEvent;
60
+ exports.toRequest = toRequest;
61
+
62
+ //# sourceMappingURL=function-url.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-url.cjs","names":[],"sources":["../../src/aws/function-url.ts"],"sourcesContent":["/**\n * Lambda Function URL events (payload format 2.0) as fetch `Request`s, and `Response`s back as\n * the result Lambda turns into the HTTP response — so the host's HTTP API runs unchanged.\n */\n\nexport interface FunctionUrlEvent {\n version?: string;\n rawPath: string;\n rawQueryString?: string;\n headers?: Record<string, string | undefined>;\n cookies?: string[];\n body?: string;\n isBase64Encoded?: boolean;\n requestContext: {\n domainName?: string;\n http: { method: string; sourceIp?: string; userAgent?: string };\n };\n}\n\nexport interface FunctionUrlResult {\n statusCode: number;\n headers: Record<string, string>;\n cookies?: string[];\n body: string;\n isBase64Encoded: boolean;\n}\n\n/**\n * An HTTP request, told apart by the event's own top-level shape — the Function URL wraps\n * every request in `requestContext.http`, so no request body can pass for anything else.\n */\nexport function isFunctionUrlEvent(event: unknown): event is FunctionUrlEvent {\n if (typeof event !== 'object' || event === null) return false;\n // Untrusted until checked: every level may be missing\n const { requestContext, rawPath } = event as {\n requestContext?: { http?: { method?: unknown } | null } | null;\n rawPath?: unknown;\n };\n return (\n typeof rawPath === 'string' &&\n typeof requestContext === 'object' &&\n requestContext !== null &&\n typeof requestContext.http === 'object' &&\n requestContext.http !== null &&\n typeof requestContext.http.method === 'string'\n );\n}\n\nfunction fromBase64(value: string): Uint8Array {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.length; i += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n }\n return btoa(binary);\n}\n\nexport function toRequest(event: FunctionUrlEvent): Request {\n const method = event.requestContext.http.method.toUpperCase();\n const headers = new Headers();\n for (const [name, value] of Object.entries(event.headers ?? {})) {\n if (value !== undefined) headers.set(name, value);\n }\n if (event.cookies !== undefined && event.cookies.length > 0) {\n headers.set('cookie', event.cookies.join('; '));\n }\n const host = event.requestContext.domainName ?? headers.get('host') ?? 'localhost';\n const query =\n event.rawQueryString === undefined || event.rawQueryString === ''\n ? ''\n : `?${event.rawQueryString}`;\n const hasBody = method !== 'GET' && method !== 'HEAD' && event.body !== undefined;\n return new Request(`https://${host}${event.rawPath}${query}`, {\n method,\n headers,\n ...(hasBody\n ? { body: event.isBase64Encoded === true ? fromBase64(event.body ?? '') : event.body }\n : {}),\n });\n}\n\n/** Content types sent as text; everything else (a tracking pixel) goes back base64. */\nconst TEXTUAL =\n /^(text\\/|application\\/(json|javascript|xml|x-www-form-urlencoded)|image\\/svg\\+xml)/i;\n\nexport async function fromResponse(response: Response, method: string): Promise<FunctionUrlResult> {\n const headers: Record<string, string> = {};\n const cookies: string[] = [];\n response.headers.forEach((value, name) => {\n if (name === 'set-cookie') cookies.push(value);\n else headers[name] = value;\n });\n const contentType = response.headers.get('content-type') ?? '';\n const head = method.toUpperCase() === 'HEAD';\n const bytes = head ? new Uint8Array() : new Uint8Array(await response.arrayBuffer());\n const textual = bytes.length === 0 || TEXTUAL.test(contentType);\n return {\n statusCode: response.status,\n headers,\n ...(cookies.length === 0 ? {} : { cookies }),\n body: textual ? new TextDecoder().decode(bytes) : toBase64(bytes),\n isBase64Encoded: !textual,\n };\n}\n"],"mappings":";;;;;;AA+BA,SAAgB,mBAAmB,OAA2C;CAC5E,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAExD,MAAM,EAAE,gBAAgB,YAAY;CAIpC,OACE,OAAO,YAAY,YACnB,OAAO,mBAAmB,YAC1B,mBAAmB,QACnB,OAAO,eAAe,SAAS,YAC/B,eAAe,SAAS,QACxB,OAAO,eAAe,KAAK,WAAW;AAE1C;AAEA,SAAS,WAAW,OAA2B;CAC7C,MAAM,SAAS,KAAK,KAAK;CACzB,MAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;CAC1C,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,MAAM,KAAK,OAAO,WAAW,CAAC;CACtE,OAAO;AACT;AAEA,SAAS,SAAS,OAA2B;CAC3C,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,OACrC,UAAU,OAAO,aAAa,GAAG,MAAM,SAAS,GAAG,IAAI,KAAM,CAAC;CAEhE,OAAO,KAAK,MAAM;AACpB;AAEA,SAAgB,UAAU,OAAkC;CAC1D,MAAM,SAAS,MAAM,eAAe,KAAK,OAAO,YAAY;CAC5D,MAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,WAAW,CAAC,CAAC,GAC5D,IAAI,UAAU,KAAA,GAAW,QAAQ,IAAI,MAAM,KAAK;CAElD,IAAI,MAAM,YAAY,KAAA,KAAa,MAAM,QAAQ,SAAS,GACxD,QAAQ,IAAI,UAAU,MAAM,QAAQ,KAAK,IAAI,CAAC;CAEhD,MAAM,OAAO,MAAM,eAAe,cAAc,QAAQ,IAAI,MAAM,KAAK;CACvE,MAAM,QACJ,MAAM,mBAAmB,KAAA,KAAa,MAAM,mBAAmB,KAC3D,KACA,IAAI,MAAM;CAChB,MAAM,UAAU,WAAW,SAAS,WAAW,UAAU,MAAM,SAAS,KAAA;CACxE,OAAO,IAAI,QAAQ,WAAW,OAAO,MAAM,UAAU,SAAS;EAC5D;EACA;EACA,GAAI,UACA,EAAE,MAAM,MAAM,oBAAoB,OAAO,WAAW,MAAM,QAAQ,EAAE,IAAI,MAAM,KAAK,IACnF,CAAC;CACP,CAAC;AACH;;AAGA,MAAM,UACJ;AAEF,eAAsB,aAAa,UAAoB,QAA4C;CACjG,MAAM,UAAkC,CAAC;CACzC,MAAM,UAAoB,CAAC;CAC3B,SAAS,QAAQ,SAAS,OAAO,SAAS;EACxC,IAAI,SAAS,cAAc,QAAQ,KAAK,KAAK;OACxC,QAAQ,QAAQ;CACvB,CAAC;CACD,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;CAE5D,MAAM,QADO,OAAO,YAAY,MAAM,yBACjB,IAAI,WAAW,IAAI,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC;CACnF,MAAM,UAAU,MAAM,WAAW,KAAK,QAAQ,KAAK,WAAW;CAC9D,OAAO;EACL,YAAY,SAAS;EACrB;EACA,GAAI,QAAQ,WAAW,IAAI,CAAC,IAAI,EAAE,QAAQ;EAC1C,MAAM,UAAU,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,IAAI,SAAS,KAAK;EAChE,iBAAiB,CAAC;CACpB;AACF"}
@@ -0,0 +1,38 @@
1
+ //#region src/aws/function-url.d.ts
2
+ /**
3
+ * Lambda Function URL events (payload format 2.0) as fetch `Request`s, and `Response`s back as
4
+ * the result Lambda turns into the HTTP response — so the host's HTTP API runs unchanged.
5
+ */
6
+ export interface FunctionUrlEvent {
7
+ version?: string;
8
+ rawPath: string;
9
+ rawQueryString?: string;
10
+ headers?: Record<string, string | undefined>;
11
+ cookies?: string[];
12
+ body?: string;
13
+ isBase64Encoded?: boolean;
14
+ requestContext: {
15
+ domainName?: string;
16
+ http: {
17
+ method: string;
18
+ sourceIp?: string;
19
+ userAgent?: string;
20
+ };
21
+ };
22
+ }
23
+ export interface FunctionUrlResult {
24
+ statusCode: number;
25
+ headers: Record<string, string>;
26
+ cookies?: string[];
27
+ body: string;
28
+ isBase64Encoded: boolean;
29
+ }
30
+ /**
31
+ * An HTTP request, told apart by the event's own top-level shape — the Function URL wraps
32
+ * every request in `requestContext.http`, so no request body can pass for anything else.
33
+ */
34
+ export declare function isFunctionUrlEvent(event: unknown): event is FunctionUrlEvent;
35
+ export declare function toRequest(event: FunctionUrlEvent): Request;
36
+ export declare function fromResponse(response: Response, method: string): Promise<FunctionUrlResult>;
37
+ //#endregion
38
+ //# sourceMappingURL=function-url.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-url.d.cts","names":[],"sources":["../../src/aws/function-url.ts"],"mappings":";;;;;iBAKiB;EACf;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;EACA;IACE;IACA;MAAQ;MAAgB;MAAmB;;;;iBAI9B;EACf;EACA,SAAS;EACT;EACA;EACA;;;;;;wBAOc,mBAAmB,iBAAiB,SAAS;wBAgC7C,UAAU,OAAO,mBAAmB;wBA4B9B,aAAa,UAAU,UAAU,iBAAiB,QAAQ"}
@@ -0,0 +1,38 @@
1
+ //#region src/aws/function-url.d.ts
2
+ /**
3
+ * Lambda Function URL events (payload format 2.0) as fetch `Request`s, and `Response`s back as
4
+ * the result Lambda turns into the HTTP response — so the host's HTTP API runs unchanged.
5
+ */
6
+ export interface FunctionUrlEvent {
7
+ version?: string;
8
+ rawPath: string;
9
+ rawQueryString?: string;
10
+ headers?: Record<string, string | undefined>;
11
+ cookies?: string[];
12
+ body?: string;
13
+ isBase64Encoded?: boolean;
14
+ requestContext: {
15
+ domainName?: string;
16
+ http: {
17
+ method: string;
18
+ sourceIp?: string;
19
+ userAgent?: string;
20
+ };
21
+ };
22
+ }
23
+ export interface FunctionUrlResult {
24
+ statusCode: number;
25
+ headers: Record<string, string>;
26
+ cookies?: string[];
27
+ body: string;
28
+ isBase64Encoded: boolean;
29
+ }
30
+ /**
31
+ * An HTTP request, told apart by the event's own top-level shape — the Function URL wraps
32
+ * every request in `requestContext.http`, so no request body can pass for anything else.
33
+ */
34
+ export declare function isFunctionUrlEvent(event: unknown): event is FunctionUrlEvent;
35
+ export declare function toRequest(event: FunctionUrlEvent): Request;
36
+ export declare function fromResponse(response: Response, method: string): Promise<FunctionUrlResult>;
37
+ //#endregion
38
+ //# sourceMappingURL=function-url.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-url.d.mts","names":[],"sources":["../../src/aws/function-url.ts"],"mappings":";;;;;iBAKiB;EACf;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;EACA;IACE;IACA;MAAQ;MAAgB;MAAmB;;;;iBAI9B;EACf;EACA,SAAS;EACT;EACA;EACA;;;;;;wBAOc,mBAAmB,iBAAiB,SAAS;wBAgC7C,UAAU,OAAO,mBAAmB;wBA4B9B,aAAa,UAAU,UAAU,iBAAiB,QAAQ"}
@@ -0,0 +1,59 @@
1
+ //#region src/aws/function-url.ts
2
+ /**
3
+ * An HTTP request, told apart by the event's own top-level shape — the Function URL wraps
4
+ * every request in `requestContext.http`, so no request body can pass for anything else.
5
+ */
6
+ function isFunctionUrlEvent(event) {
7
+ if (typeof event !== "object" || event === null) return false;
8
+ const { requestContext, rawPath } = event;
9
+ return typeof rawPath === "string" && typeof requestContext === "object" && requestContext !== null && typeof requestContext.http === "object" && requestContext.http !== null && typeof requestContext.http.method === "string";
10
+ }
11
+ function fromBase64(value) {
12
+ const binary = atob(value);
13
+ const bytes = new Uint8Array(binary.length);
14
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
15
+ return bytes;
16
+ }
17
+ function toBase64(bytes) {
18
+ let binary = "";
19
+ for (let i = 0; i < bytes.length; i += 32768) binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
20
+ return btoa(binary);
21
+ }
22
+ function toRequest(event) {
23
+ const method = event.requestContext.http.method.toUpperCase();
24
+ const headers = new Headers();
25
+ for (const [name, value] of Object.entries(event.headers ?? {})) if (value !== void 0) headers.set(name, value);
26
+ if (event.cookies !== void 0 && event.cookies.length > 0) headers.set("cookie", event.cookies.join("; "));
27
+ const host = event.requestContext.domainName ?? headers.get("host") ?? "localhost";
28
+ const query = event.rawQueryString === void 0 || event.rawQueryString === "" ? "" : `?${event.rawQueryString}`;
29
+ const hasBody = method !== "GET" && method !== "HEAD" && event.body !== void 0;
30
+ return new Request(`https://${host}${event.rawPath}${query}`, {
31
+ method,
32
+ headers,
33
+ ...hasBody ? { body: event.isBase64Encoded === true ? fromBase64(event.body ?? "") : event.body } : {}
34
+ });
35
+ }
36
+ /** Content types sent as text; everything else (a tracking pixel) goes back base64. */
37
+ const TEXTUAL = /^(text\/|application\/(json|javascript|xml|x-www-form-urlencoded)|image\/svg\+xml)/i;
38
+ async function fromResponse(response, method) {
39
+ const headers = {};
40
+ const cookies = [];
41
+ response.headers.forEach((value, name) => {
42
+ if (name === "set-cookie") cookies.push(value);
43
+ else headers[name] = value;
44
+ });
45
+ const contentType = response.headers.get("content-type") ?? "";
46
+ const bytes = method.toUpperCase() === "HEAD" ? /* @__PURE__ */ new Uint8Array() : new Uint8Array(await response.arrayBuffer());
47
+ const textual = bytes.length === 0 || TEXTUAL.test(contentType);
48
+ return {
49
+ statusCode: response.status,
50
+ headers,
51
+ ...cookies.length === 0 ? {} : { cookies },
52
+ body: textual ? new TextDecoder().decode(bytes) : toBase64(bytes),
53
+ isBase64Encoded: !textual
54
+ };
55
+ }
56
+ //#endregion
57
+ export { fromResponse, isFunctionUrlEvent, toRequest };
58
+
59
+ //# sourceMappingURL=function-url.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-url.mjs","names":[],"sources":["../../src/aws/function-url.ts"],"sourcesContent":["/**\n * Lambda Function URL events (payload format 2.0) as fetch `Request`s, and `Response`s back as\n * the result Lambda turns into the HTTP response — so the host's HTTP API runs unchanged.\n */\n\nexport interface FunctionUrlEvent {\n version?: string;\n rawPath: string;\n rawQueryString?: string;\n headers?: Record<string, string | undefined>;\n cookies?: string[];\n body?: string;\n isBase64Encoded?: boolean;\n requestContext: {\n domainName?: string;\n http: { method: string; sourceIp?: string; userAgent?: string };\n };\n}\n\nexport interface FunctionUrlResult {\n statusCode: number;\n headers: Record<string, string>;\n cookies?: string[];\n body: string;\n isBase64Encoded: boolean;\n}\n\n/**\n * An HTTP request, told apart by the event's own top-level shape — the Function URL wraps\n * every request in `requestContext.http`, so no request body can pass for anything else.\n */\nexport function isFunctionUrlEvent(event: unknown): event is FunctionUrlEvent {\n if (typeof event !== 'object' || event === null) return false;\n // Untrusted until checked: every level may be missing\n const { requestContext, rawPath } = event as {\n requestContext?: { http?: { method?: unknown } | null } | null;\n rawPath?: unknown;\n };\n return (\n typeof rawPath === 'string' &&\n typeof requestContext === 'object' &&\n requestContext !== null &&\n typeof requestContext.http === 'object' &&\n requestContext.http !== null &&\n typeof requestContext.http.method === 'string'\n );\n}\n\nfunction fromBase64(value: string): Uint8Array {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.length; i += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n }\n return btoa(binary);\n}\n\nexport function toRequest(event: FunctionUrlEvent): Request {\n const method = event.requestContext.http.method.toUpperCase();\n const headers = new Headers();\n for (const [name, value] of Object.entries(event.headers ?? {})) {\n if (value !== undefined) headers.set(name, value);\n }\n if (event.cookies !== undefined && event.cookies.length > 0) {\n headers.set('cookie', event.cookies.join('; '));\n }\n const host = event.requestContext.domainName ?? headers.get('host') ?? 'localhost';\n const query =\n event.rawQueryString === undefined || event.rawQueryString === ''\n ? ''\n : `?${event.rawQueryString}`;\n const hasBody = method !== 'GET' && method !== 'HEAD' && event.body !== undefined;\n return new Request(`https://${host}${event.rawPath}${query}`, {\n method,\n headers,\n ...(hasBody\n ? { body: event.isBase64Encoded === true ? fromBase64(event.body ?? '') : event.body }\n : {}),\n });\n}\n\n/** Content types sent as text; everything else (a tracking pixel) goes back base64. */\nconst TEXTUAL =\n /^(text\\/|application\\/(json|javascript|xml|x-www-form-urlencoded)|image\\/svg\\+xml)/i;\n\nexport async function fromResponse(response: Response, method: string): Promise<FunctionUrlResult> {\n const headers: Record<string, string> = {};\n const cookies: string[] = [];\n response.headers.forEach((value, name) => {\n if (name === 'set-cookie') cookies.push(value);\n else headers[name] = value;\n });\n const contentType = response.headers.get('content-type') ?? '';\n const head = method.toUpperCase() === 'HEAD';\n const bytes = head ? new Uint8Array() : new Uint8Array(await response.arrayBuffer());\n const textual = bytes.length === 0 || TEXTUAL.test(contentType);\n return {\n statusCode: response.status,\n headers,\n ...(cookies.length === 0 ? {} : { cookies }),\n body: textual ? new TextDecoder().decode(bytes) : toBase64(bytes),\n isBase64Encoded: !textual,\n };\n}\n"],"mappings":";;;;;AA+BA,SAAgB,mBAAmB,OAA2C;CAC5E,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAExD,MAAM,EAAE,gBAAgB,YAAY;CAIpC,OACE,OAAO,YAAY,YACnB,OAAO,mBAAmB,YAC1B,mBAAmB,QACnB,OAAO,eAAe,SAAS,YAC/B,eAAe,SAAS,QACxB,OAAO,eAAe,KAAK,WAAW;AAE1C;AAEA,SAAS,WAAW,OAA2B;CAC7C,MAAM,SAAS,KAAK,KAAK;CACzB,MAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;CAC1C,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,MAAM,KAAK,OAAO,WAAW,CAAC;CACtE,OAAO;AACT;AAEA,SAAS,SAAS,OAA2B;CAC3C,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,OACrC,UAAU,OAAO,aAAa,GAAG,MAAM,SAAS,GAAG,IAAI,KAAM,CAAC;CAEhE,OAAO,KAAK,MAAM;AACpB;AAEA,SAAgB,UAAU,OAAkC;CAC1D,MAAM,SAAS,MAAM,eAAe,KAAK,OAAO,YAAY;CAC5D,MAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,WAAW,CAAC,CAAC,GAC5D,IAAI,UAAU,KAAA,GAAW,QAAQ,IAAI,MAAM,KAAK;CAElD,IAAI,MAAM,YAAY,KAAA,KAAa,MAAM,QAAQ,SAAS,GACxD,QAAQ,IAAI,UAAU,MAAM,QAAQ,KAAK,IAAI,CAAC;CAEhD,MAAM,OAAO,MAAM,eAAe,cAAc,QAAQ,IAAI,MAAM,KAAK;CACvE,MAAM,QACJ,MAAM,mBAAmB,KAAA,KAAa,MAAM,mBAAmB,KAC3D,KACA,IAAI,MAAM;CAChB,MAAM,UAAU,WAAW,SAAS,WAAW,UAAU,MAAM,SAAS,KAAA;CACxE,OAAO,IAAI,QAAQ,WAAW,OAAO,MAAM,UAAU,SAAS;EAC5D;EACA;EACA,GAAI,UACA,EAAE,MAAM,MAAM,oBAAoB,OAAO,WAAW,MAAM,QAAQ,EAAE,IAAI,MAAM,KAAK,IACnF,CAAC;CACP,CAAC;AACH;;AAGA,MAAM,UACJ;AAEF,eAAsB,aAAa,UAAoB,QAA4C;CACjG,MAAM,UAAkC,CAAC;CACzC,MAAM,UAAoB,CAAC;CAC3B,SAAS,QAAQ,SAAS,OAAO,SAAS;EACxC,IAAI,SAAS,cAAc,QAAQ,KAAK,KAAK;OACxC,QAAQ,QAAQ;CACvB,CAAC;CACD,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;CAE5D,MAAM,QADO,OAAO,YAAY,MAAM,yBACjB,IAAI,WAAW,IAAI,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC;CACnF,MAAM,UAAU,MAAM,WAAW,KAAK,QAAQ,KAAK,WAAW;CAC9D,OAAO;EACL,YAAY,SAAS;EACrB;EACA,GAAI,QAAQ,WAAW,IAAI,CAAC,IAAI,EAAE,QAAQ;EAC1C,MAAM,UAAU,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,IAAI,SAAS,KAAK;EAChE,iBAAiB,CAAC;CACpB;AACF"}
@@ -0,0 +1,160 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_http2_client = require("../http2-client.cjs");
3
+ const require_aws_engine_step = require("./engine-step.cjs");
4
+ const require_aws_function_url = require("./function-url.cjs");
5
+ const require_host_router = require("../host/router.cjs");
6
+ const require_host_execute = require("../host/execute.cjs");
7
+ const require_host_journey_host = require("../host/journey-host.cjs");
8
+ const require_aws_instances = require("./instances.cjs");
9
+ const require_aws_lambda_api = require("./lambda-api.cjs");
10
+ let _aws_durable_execution_sdk_js = require("@aws/durable-execution-sdk-js");
11
+ let node_async_hooks = require("node:async_hooks");
12
+ //#region src/aws/index.ts
13
+ /**
14
+ * `@shware/workflow/aws` — the journey host as one Lambda durable function behind a Function
15
+ * URL, on Postgres.
16
+ *
17
+ * The one handler tells three inputs apart by the event's top-level shape: a Function URL
18
+ * request (the HTTP API — ingest, identify, devices, tracking, bundle, preview), an internal run
19
+ * (one journey instance: one durable execution, started by an asynchronous invoke of this
20
+ * function's own numbered version), and a scheduled maintenance tick. An HTTP body can never
21
+ * pass for the other two: the Function URL always wraps it.
22
+ *
23
+ * const journeys = journeyLambda({
24
+ * config,
25
+ * env, // parsed from process.env (zod)
26
+ * store: (env, database) => postgresJsStore(env.DATABASE_URL, database),
27
+ * email: (env) => sesEmailTransport({ region: env.AWS_REGION }),
28
+ * });
29
+ * export const handler = journeys.handler;
30
+ */
31
+ /** The scheduled tick (EventBridge Scheduler's payload): the segment sweep and maintenance. */
32
+ const SWEEP_EVENT_TYPE = "$workflow.sweep";
33
+ /** This function's ARN without its qualifier, from the ARN it was invoked under. */
34
+ function unqualified(invokedFunctionArn) {
35
+ return invokedFunctionArn.split(":").slice(0, 7).join(":");
36
+ }
37
+ const json = (body, status = 200) => new Response(JSON.stringify(body), {
38
+ status,
39
+ headers: { "content-type": "application/json" }
40
+ });
41
+ function journeyLambda(options) {
42
+ const { env: baseEnv, lambda: lambdaOption, startRetryMs, stopDrainMs, ...hostOptions } = options;
43
+ const host = require_host_journey_host.createJourneyHost({
44
+ ...hostOptions,
45
+ store: (env, database) => options.store(env, database)
46
+ }, { apnsFetch: require_http2_client.http2Fetch() });
47
+ const lambda = lambdaOption ?? require_aws_lambda_api.sdkLambdaApi();
48
+ const ownHashes = new Set(host.bundle().workflows.map((workflow) => workflow.contentHash));
49
+ const scope = new node_async_hooks.AsyncLocalStorage();
50
+ /** The version this code was published as: `$LATEST` while developing. */
51
+ const ownVersion = () => process.env.AWS_LAMBDA_FUNCTION_VERSION ?? "$LATEST";
52
+ /** Numbered versions are ordered: the bundle compiled into a later one goes live by itself. */
53
+ const bundleVersion = () => {
54
+ const version = ownVersion();
55
+ return /^\d+$/.test(version) ? {
56
+ id: version,
57
+ createdAt: Number(version)
58
+ } : void 0;
59
+ };
60
+ /** The store and the env (with the instance port) of this invocation, opened on first use. */
61
+ const open = (context) => {
62
+ const invocation = scope.getStore();
63
+ if (invocation === void 0) throw new Error("journeyLambda: outside an invocation");
64
+ const placeholder = { ...baseEnv };
65
+ invocation.lease ??= host.lease(placeholder);
66
+ const { store } = invocation.lease;
67
+ const executions = store.executions;
68
+ if (executions === void 0) throw new Error("journeyLambda needs a store with an execution registry (PostgresJourneyStore)");
69
+ const functionArn = unqualified(context.lambdaContext.invokedFunctionArn);
70
+ const target = async (contentHash, version) => {
71
+ if (version !== void 0 && /^\d+$/.test(version)) return `${functionArn}:${version}`;
72
+ if (ownHashes.has(contentHash)) return `${functionArn}:${ownVersion()}`;
73
+ throw new Error(`no published version is known to carry workflow IR ${contentHash}`);
74
+ };
75
+ const instances = new require_aws_instances.AwsInstances({
76
+ store,
77
+ executions,
78
+ lambda,
79
+ target,
80
+ ...startRetryMs === void 0 ? {} : { startRetryMs },
81
+ ...stopDrainMs === void 0 ? {} : { stopDrainMs }
82
+ });
83
+ return {
84
+ store,
85
+ env: {
86
+ ...baseEnv,
87
+ JOURNEY: instances
88
+ },
89
+ executions
90
+ };
91
+ };
92
+ const run = async (input, context) => {
93
+ const { store, env, executions } = open(context);
94
+ const { instanceId, params } = input;
95
+ await context.step("$workflow:started", async () => {
96
+ await executions.markSubmitted(instanceId, context.executionContext.durableExecutionArn, Date.now());
97
+ });
98
+ return require_host_execute.executeJourney({
99
+ instanceId,
100
+ params,
101
+ enteredAtMs: input.enteredAtMs,
102
+ step: new require_aws_engine_step.AwsEngineStep(context, store, executions, lambda, params.userId, instanceId)
103
+ }, host.runParts(env, store, params));
104
+ };
105
+ const http = (event, context) => {
106
+ const serve = async () => {
107
+ const method = event.requestContext.http.method;
108
+ try {
109
+ const { store, env } = open(context);
110
+ const request = require_aws_function_url.toRequest(event);
111
+ if (new URL(request.url).pathname === "/deploy") return await require_aws_function_url.fromResponse(json({ error: "deploy by publishing a version (POST /bundle/deploy applies its own bundle)" }, 409), method);
112
+ await host.applyOwnBundle(env, bundleVersion());
113
+ return await require_aws_function_url.fromResponse(await host.handle(request, env, store), method);
114
+ } catch (error) {
115
+ console.error("[workflow] request failed", error);
116
+ return require_aws_function_url.fromResponse(json({ error: "internal error" }, 500), method);
117
+ }
118
+ };
119
+ const method = event.requestContext.http.method.toUpperCase();
120
+ if (method === "GET" || method === "HEAD") return serve();
121
+ return context.step("http", serve, { retryStrategy: () => ({ shouldRetry: false }) });
122
+ };
123
+ const sweep = (context) => context.step("sweep", async () => {
124
+ const { store, env } = open(context);
125
+ await host.applyOwnBundle(env, bundleVersion());
126
+ return require_host_router.sweepSegments(env, store);
127
+ }, { retryStrategy: () => ({ shouldRetry: false }) });
128
+ const durable = (0, _aws_durable_execution_sdk_js.withDurableExecution)(async (input, context) => {
129
+ if (require_aws_function_url.isFunctionUrlEvent(input)) return http(input, context);
130
+ if (require_aws_instances.isRunInput(input)) return run(input, context);
131
+ if (typeof input === "object" && input !== null && input.type === "$workflow.sweep") return sweep(context);
132
+ throw new Error("journeyLambda: unrecognized event (not a Function URL request, run or sweep)");
133
+ });
134
+ const handler = async (event, context) => {
135
+ const invocation = {};
136
+ try {
137
+ return await scope.run(invocation, () => durable(event, context));
138
+ } finally {
139
+ await invocation.lease?.close().catch((error) => {
140
+ console.error("[workflow] closing the store failed", error);
141
+ });
142
+ }
143
+ };
144
+ return { handler };
145
+ }
146
+ //#endregion
147
+ exports.AwsEngineStep = require_aws_engine_step.AwsEngineStep;
148
+ exports.AwsInstances = require_aws_instances.AwsInstances;
149
+ exports.RUN_EVENT_TYPE = require_aws_instances.RUN_EVENT_TYPE;
150
+ exports.SWEEP_EVENT_TYPE = SWEEP_EVENT_TYPE;
151
+ exports.executionName = require_aws_instances.executionName;
152
+ exports.fromResponse = require_aws_function_url.fromResponse;
153
+ exports.isFunctionUrlEvent = require_aws_function_url.isFunctionUrlEvent;
154
+ exports.isRunInput = require_aws_instances.isRunInput;
155
+ exports.journeyLambda = journeyLambda;
156
+ exports.sdkLambdaApi = require_aws_lambda_api.sdkLambdaApi;
157
+ exports.stepRetry = require_aws_engine_step.stepRetry;
158
+ exports.toRequest = require_aws_function_url.toRequest;
159
+
160
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["createJourneyHost","http2Fetch","sdkLambdaApi","AsyncLocalStorage","AwsInstances","executeJourney","AwsEngineStep","toRequest","fromResponse","sweepSegments","withDurableExecution","isFunctionUrlEvent","isRunInput"],"sources":["../../src/aws/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n type DurableContext,\n type DurableExecutionInvocationInput,\n type DurableExecutionInvocationOutput,\n withDurableExecution,\n} from '@aws/durable-execution-sdk-js';\nimport type { JourneyEnv } from '../cloudflare/bindings';\nimport type { JourneyOutcome } from '../engine/ports';\nimport { executeJourney } from '../host/execute';\nimport { type JourneyHostOptions, createJourneyHost } from '../host/journey-host';\nimport { type SweepResult, sweepSegments } from '../host/router';\nimport { http2Fetch } from '../http2-client';\nimport type { BundleVersion, ExecutionRegistry, JourneyStore, StoreLease } from '../store/index';\nimport { AwsEngineStep } from './engine-step';\nimport {\n type FunctionUrlEvent,\n type FunctionUrlResult,\n fromResponse,\n isFunctionUrlEvent,\n toRequest,\n} from './function-url';\nimport { AwsInstances, type RunInput, isRunInput } from './instances';\nimport { type LambdaApi, sdkLambdaApi } from './lambda-api';\n\n/**\n * `@shware/workflow/aws` — the journey host as one Lambda durable function behind a Function\n * URL, on Postgres.\n *\n * The one handler tells three inputs apart by the event's top-level shape: a Function URL\n * request (the HTTP API — ingest, identify, devices, tracking, bundle, preview), an internal run\n * (one journey instance: one durable execution, started by an asynchronous invoke of this\n * function's own numbered version), and a scheduled maintenance tick. An HTTP body can never\n * pass for the other two: the Function URL always wraps it.\n *\n * const journeys = journeyLambda({\n * config,\n * env, // parsed from process.env (zod)\n * store: (env, database) => postgresJsStore(env.DATABASE_URL, database),\n * email: (env) => sesEmailTransport({ region: env.AWS_REGION }),\n * });\n * export const handler = journeys.handler;\n */\n\n/** The scheduled tick (EventBridge Scheduler's payload): the segment sweep and maintenance. */\nexport const SWEEP_EVENT_TYPE = '$workflow.sweep';\n\n/** What journeyLambda reads from its env: `JourneyEnv` without the binding it supplies itself. */\nexport type JourneyLambdaEnv = Omit<JourneyEnv, 'JOURNEY' | 'DB' | 'WORKFLOW_KV' | 'EMAIL'>;\n\nexport interface JourneyLambdaOptions<Env extends JourneyLambdaEnv> extends Omit<\n JourneyHostOptions<Env & JourneyEnv>,\n 'env' | 'store'\n> {\n /** The validated environment (parsed from `process.env` with zod by the app). */\n env: Env;\n /** The Postgres store: AWS needs its execution registry (`postgresJsStore`). */\n store: (env: Env, database: { schema: string }) => JourneyStore | StoreLease;\n /** The Lambda control plane; `@aws-sdk/client-lambda` with the execution role by default. */\n lambda?: LambdaApi;\n /** How long an unconfirmed start is retried (default 12 hours; keep it under the retention). */\n startRetryMs?: number;\n /**\n * How long an erasure waits after stopping an execution before it erases: an invocation\n * running at the stop goes on to its next checkpoint. Set it to at least the function's\n * timeout; 15 minutes (Lambda's maximum) by default.\n */\n stopDrainMs?: number;\n}\n\n/**\n * The Lambda invocation context, as far as the handler's signature needs it — declared here so\n * the package's types do not depend on `@types/aws-lambda`. Lambda passes the full object.\n */\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n invokedFunctionArn: string;\n awsRequestId: string;\n getRemainingTimeInMillis(): number;\n}\n\nexport interface JourneyLambda {\n /** Export as the function's handler. */\n handler: (\n event: DurableExecutionInvocationInput,\n context: LambdaContext\n ) => Promise<DurableExecutionInvocationOutput>;\n}\n\ninterface Invocation {\n lease?: Required<StoreLease>;\n}\n\n/** This function's ARN without its qualifier, from the ARN it was invoked under. */\nfunction unqualified(invokedFunctionArn: string): string {\n return invokedFunctionArn.split(':').slice(0, 7).join(':');\n}\n\nconst json = (body: unknown, status = 200) =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });\n\nexport function journeyLambda<Env extends JourneyLambdaEnv>(\n options: JourneyLambdaOptions<Env>\n): JourneyLambda {\n type HostEnv = Env & JourneyEnv;\n const { env: baseEnv, lambda: lambdaOption, startRetryMs, stopDrainMs, ...hostOptions } = options;\n const host = createJourneyHost<HostEnv>(\n { ...hostOptions, store: (env, database) => options.store(env, database) },\n // Node 24's fetch cannot reach APNs (HTTP/2 only): see http2-client.ts for when this can go\n { apnsFetch: http2Fetch() }\n );\n const lambda = lambdaOption ?? sdkLambdaApi();\n const ownHashes = new Set(host.bundle().workflows.map((workflow) => workflow.contentHash));\n const scope = new AsyncLocalStorage<Invocation>();\n\n /** The version this code was published as: `$LATEST` while developing. */\n const ownVersion = () => process.env.AWS_LAMBDA_FUNCTION_VERSION ?? '$LATEST';\n /** Numbered versions are ordered: the bundle compiled into a later one goes live by itself. */\n const bundleVersion = (): BundleVersion | undefined => {\n const version = ownVersion();\n return /^\\d+$/.test(version) ? { id: version, createdAt: Number(version) } : undefined;\n };\n\n /** The store and the env (with the instance port) of this invocation, opened on first use. */\n const open = (\n context: DurableContext\n ): { store: JourneyStore; env: HostEnv; executions: ExecutionRegistry } => {\n const invocation = scope.getStore();\n if (invocation === undefined) throw new Error('journeyLambda: outside an invocation');\n const placeholder = { ...baseEnv } as unknown as HostEnv;\n invocation.lease ??= host.lease(placeholder);\n const { store } = invocation.lease;\n const executions = store.executions;\n if (executions === undefined) {\n throw new Error(\n 'journeyLambda needs a store with an execution registry (PostgresJourneyStore)'\n );\n }\n const functionArn = unqualified(context.lambdaContext.invokedFunctionArn);\n const target = async (contentHash: string, version?: string): Promise<string> => {\n // An execution runs the code its IR was compiled with: the version whose bundle put the\n // route there, read in the same row as the hash — never a separately read \"live\" version,\n // which a release between the two reads would make another bundle's\n if (version !== undefined && /^\\d+$/.test(version)) return `${functionArn}:${version}`;\n // A forced deploy records no version: only this code's own workflows can run here\n if (ownHashes.has(contentHash)) return `${functionArn}:${ownVersion()}`;\n throw new Error(`no published version is known to carry workflow IR ${contentHash}`);\n };\n const instances = new AwsInstances({\n store,\n executions,\n lambda,\n target,\n ...(startRetryMs === undefined ? {} : { startRetryMs }),\n ...(stopDrainMs === undefined ? {} : { stopDrainMs }),\n });\n return { store, env: { ...baseEnv, JOURNEY: instances }, executions };\n };\n\n const run = async (input: RunInput, context: DurableContext): Promise<JourneyOutcome> => {\n const { store, env, executions } = open(context);\n const { instanceId, params } = input;\n // Running is the proof the start got through, whatever became of the invoke's response\n await context.step('$workflow:started', async () => {\n await executions.markSubmitted(\n instanceId,\n context.executionContext.durableExecutionArn,\n Date.now()\n );\n });\n return executeJourney(\n {\n instanceId,\n params,\n enteredAtMs: input.enteredAtMs,\n step: new AwsEngineStep(context, store, executions, lambda, params.userId, instanceId),\n },\n host.runParts(env, store, params)\n );\n };\n\n const http = (event: FunctionUrlEvent, context: DurableContext): Promise<FunctionUrlResult> => {\n const serve = async (): Promise<FunctionUrlResult> => {\n const method = event.requestContext.http.method;\n try {\n const { store, env } = open(context);\n const request = toRequest(event);\n // Only the bundle compiled into a version may route: one is never swapped in by hand\n if (new URL(request.url).pathname === '/deploy') {\n return await fromResponse(\n json(\n {\n error:\n 'deploy by publishing a version (POST /bundle/deploy applies its own bundle)',\n },\n 409\n ),\n method\n );\n }\n await host.applyOwnBundle(env, bundleVersion());\n return await fromResponse(await host.handle(request, env, store), method);\n } catch (error) {\n console.error('[workflow] request failed', error);\n return fromResponse(json({ error: 'internal error' }, 500), method);\n }\n };\n // A read (the bundle, a preview, a tracked link or pixel) answers straight from the handler:\n // its body can be large, and a step would checkpoint all of it. A write runs in one step,\n // never retried — the caller is waiting, and retries the request itself\n const method = event.requestContext.http.method.toUpperCase();\n if (method === 'GET' || method === 'HEAD') return serve();\n return context.step('http', serve, { retryStrategy: () => ({ shouldRetry: false }) });\n };\n\n const sweep = (context: DurableContext): Promise<SweepResult> =>\n context.step(\n 'sweep',\n async () => {\n const { store, env } = open(context);\n await host.applyOwnBundle(env, bundleVersion());\n return sweepSegments(env, store);\n },\n { retryStrategy: () => ({ shouldRetry: false }) }\n );\n\n const durable = withDurableExecution(async (input: unknown, context: DurableContext) => {\n if (isFunctionUrlEvent(input)) return http(input, context);\n if (isRunInput(input)) return run(input, context);\n if (\n typeof input === 'object' &&\n input !== null &&\n (input as { type?: unknown }).type === SWEEP_EVENT_TYPE\n ) {\n return sweep(context);\n }\n throw new Error('journeyLambda: unrecognized event (not a Function URL request, run or sweep)');\n });\n\n const handler = async (\n event: DurableExecutionInvocationInput,\n context: LambdaContext\n ): Promise<DurableExecutionInvocationOutput> => {\n const invocation: Invocation = {};\n try {\n // The durable wrapper reads the whole context Lambda passed, not just the fields above\n return await scope.run(invocation, () =>\n durable(event, context as Parameters<typeof durable>[1])\n );\n } finally {\n // Outside the durable wrapper: a suspended run returns PENDING without unwinding the\n // handler, so a `finally` in there would never release the connection\n await invocation.lease?.close().catch((error: unknown) => {\n console.error('[workflow] closing the store failed', error);\n });\n }\n };\n\n return { handler };\n}\n\nexport { AwsEngineStep, stepRetry } from './engine-step';\nexport { AwsInstances, RUN_EVENT_TYPE, executionName, isRunInput } from './instances';\nexport type { AwsInstancesOptions, RunInput } from './instances';\nexport { sdkLambdaApi } from './lambda-api';\nexport type { ExecutionState, LambdaApi } from './lambda-api';\nexport { fromResponse, isFunctionUrlEvent, toRequest } from './function-url';\nexport type { FunctionUrlEvent, FunctionUrlResult } from './function-url';\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { JourneyEnv } from "../cloudflare/bindings.cjs";
2
+ import { JourneyStore, StoreLease } from "../store/index.cjs";
3
+ import { ExecutionState, LambdaApi, sdkLambdaApi } from "./lambda-api.cjs";
4
+ import { AwsEngineStep, stepRetry } from "./engine-step.cjs";
5
+ import { FunctionUrlEvent, FunctionUrlResult, fromResponse, isFunctionUrlEvent, toRequest } from "./function-url.cjs";
6
+ import { JourneyHostOptions } from "../host/journey-host.cjs";
7
+ import { AwsInstances, AwsInstancesOptions, RUN_EVENT_TYPE, RunInput, executionName, isRunInput } from "./instances.cjs";
8
+ import { DurableExecutionInvocationInput, DurableExecutionInvocationOutput } from "@aws/durable-execution-sdk-js";
9
+ //#region src/aws/index.d.ts
10
+ /**
11
+ * `@shware/workflow/aws` — the journey host as one Lambda durable function behind a Function
12
+ * URL, on Postgres.
13
+ *
14
+ * The one handler tells three inputs apart by the event's top-level shape: a Function URL
15
+ * request (the HTTP API — ingest, identify, devices, tracking, bundle, preview), an internal run
16
+ * (one journey instance: one durable execution, started by an asynchronous invoke of this
17
+ * function's own numbered version), and a scheduled maintenance tick. An HTTP body can never
18
+ * pass for the other two: the Function URL always wraps it.
19
+ *
20
+ * const journeys = journeyLambda({
21
+ * config,
22
+ * env, // parsed from process.env (zod)
23
+ * store: (env, database) => postgresJsStore(env.DATABASE_URL, database),
24
+ * email: (env) => sesEmailTransport({ region: env.AWS_REGION }),
25
+ * });
26
+ * export const handler = journeys.handler;
27
+ */
28
+ /** The scheduled tick (EventBridge Scheduler's payload): the segment sweep and maintenance. */
29
+ export declare const SWEEP_EVENT_TYPE = "$workflow.sweep";
30
+ /** What journeyLambda reads from its env: `JourneyEnv` without the binding it supplies itself. */
31
+ export type JourneyLambdaEnv = Omit<JourneyEnv, 'JOURNEY' | 'DB' | 'WORKFLOW_KV' | 'EMAIL'>;
32
+ export interface JourneyLambdaOptions<Env extends JourneyLambdaEnv> extends Omit<JourneyHostOptions<Env & JourneyEnv>, 'env' | 'store'> {
33
+ /** The validated environment (parsed from `process.env` with zod by the app). */
34
+ env: Env;
35
+ /** The Postgres store: AWS needs its execution registry (`postgresJsStore`). */
36
+ store: (env: Env, database: {
37
+ schema: string;
38
+ }) => JourneyStore | StoreLease;
39
+ /** The Lambda control plane; `@aws-sdk/client-lambda` with the execution role by default. */
40
+ lambda?: LambdaApi;
41
+ /** How long an unconfirmed start is retried (default 12 hours; keep it under the retention). */
42
+ startRetryMs?: number;
43
+ /**
44
+ * How long an erasure waits after stopping an execution before it erases: an invocation
45
+ * running at the stop goes on to its next checkpoint. Set it to at least the function's
46
+ * timeout; 15 minutes (Lambda's maximum) by default.
47
+ */
48
+ stopDrainMs?: number;
49
+ }
50
+ /**
51
+ * The Lambda invocation context, as far as the handler's signature needs it — declared here so
52
+ * the package's types do not depend on `@types/aws-lambda`. Lambda passes the full object.
53
+ */
54
+ export interface LambdaContext {
55
+ functionName: string;
56
+ functionVersion: string;
57
+ invokedFunctionArn: string;
58
+ awsRequestId: string;
59
+ getRemainingTimeInMillis(): number;
60
+ }
61
+ export interface JourneyLambda {
62
+ /** Export as the function's handler. */
63
+ handler: (event: DurableExecutionInvocationInput, context: LambdaContext) => Promise<DurableExecutionInvocationOutput>;
64
+ }
65
+ export declare function journeyLambda<Env extends JourneyLambdaEnv>(options: JourneyLambdaOptions<Env>): JourneyLambda;
66
+ //#endregion
67
+ export { AwsEngineStep, AwsInstances, type AwsInstancesOptions, type ExecutionState, type FunctionUrlEvent, type FunctionUrlResult, type LambdaApi, RUN_EVENT_TYPE, type RunInput, executionName, fromResponse, isFunctionUrlEvent, isRunInput, sdkLambdaApi, stepRetry, toRequest };
68
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/aws/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA6Ca;;YAGD,mBAAmB,KAAK;iBAEnB,qBAAqB,YAAY,0BAA0B,KAC1E,mBAAmB,MAAM;;EAIzB,KAAK;;EAEL,QAAQ,KAAK,KAAK;IAAY;QAAqB,eAAe;;EAElE,SAAS;;EAET;;;;;;EAMA;;;;;;iBAOe;EACf;EACA;EACA;EACA;EACA;;iBAGe;;EAEf,UACE,OAAO,iCACP,SAAS,kBACN,QAAQ;;wBAeC,cAAc,YAAY,kBACxC,SAAS,qBAAqB,OAC7B"}
@@ -0,0 +1,68 @@
1
+ import { JourneyEnv } from "../cloudflare/bindings.mjs";
2
+ import { JourneyStore, StoreLease } from "../store/index.mjs";
3
+ import { ExecutionState, LambdaApi, sdkLambdaApi } from "./lambda-api.mjs";
4
+ import { AwsEngineStep, stepRetry } from "./engine-step.mjs";
5
+ import { FunctionUrlEvent, FunctionUrlResult, fromResponse, isFunctionUrlEvent, toRequest } from "./function-url.mjs";
6
+ import { JourneyHostOptions } from "../host/journey-host.mjs";
7
+ import { AwsInstances, AwsInstancesOptions, RUN_EVENT_TYPE, RunInput, executionName, isRunInput } from "./instances.mjs";
8
+ import { DurableExecutionInvocationInput, DurableExecutionInvocationOutput } from "@aws/durable-execution-sdk-js";
9
+ //#region src/aws/index.d.ts
10
+ /**
11
+ * `@shware/workflow/aws` — the journey host as one Lambda durable function behind a Function
12
+ * URL, on Postgres.
13
+ *
14
+ * The one handler tells three inputs apart by the event's top-level shape: a Function URL
15
+ * request (the HTTP API — ingest, identify, devices, tracking, bundle, preview), an internal run
16
+ * (one journey instance: one durable execution, started by an asynchronous invoke of this
17
+ * function's own numbered version), and a scheduled maintenance tick. An HTTP body can never
18
+ * pass for the other two: the Function URL always wraps it.
19
+ *
20
+ * const journeys = journeyLambda({
21
+ * config,
22
+ * env, // parsed from process.env (zod)
23
+ * store: (env, database) => postgresJsStore(env.DATABASE_URL, database),
24
+ * email: (env) => sesEmailTransport({ region: env.AWS_REGION }),
25
+ * });
26
+ * export const handler = journeys.handler;
27
+ */
28
+ /** The scheduled tick (EventBridge Scheduler's payload): the segment sweep and maintenance. */
29
+ export declare const SWEEP_EVENT_TYPE = "$workflow.sweep";
30
+ /** What journeyLambda reads from its env: `JourneyEnv` without the binding it supplies itself. */
31
+ export type JourneyLambdaEnv = Omit<JourneyEnv, 'JOURNEY' | 'DB' | 'WORKFLOW_KV' | 'EMAIL'>;
32
+ export interface JourneyLambdaOptions<Env extends JourneyLambdaEnv> extends Omit<JourneyHostOptions<Env & JourneyEnv>, 'env' | 'store'> {
33
+ /** The validated environment (parsed from `process.env` with zod by the app). */
34
+ env: Env;
35
+ /** The Postgres store: AWS needs its execution registry (`postgresJsStore`). */
36
+ store: (env: Env, database: {
37
+ schema: string;
38
+ }) => JourneyStore | StoreLease;
39
+ /** The Lambda control plane; `@aws-sdk/client-lambda` with the execution role by default. */
40
+ lambda?: LambdaApi;
41
+ /** How long an unconfirmed start is retried (default 12 hours; keep it under the retention). */
42
+ startRetryMs?: number;
43
+ /**
44
+ * How long an erasure waits after stopping an execution before it erases: an invocation
45
+ * running at the stop goes on to its next checkpoint. Set it to at least the function's
46
+ * timeout; 15 minutes (Lambda's maximum) by default.
47
+ */
48
+ stopDrainMs?: number;
49
+ }
50
+ /**
51
+ * The Lambda invocation context, as far as the handler's signature needs it — declared here so
52
+ * the package's types do not depend on `@types/aws-lambda`. Lambda passes the full object.
53
+ */
54
+ export interface LambdaContext {
55
+ functionName: string;
56
+ functionVersion: string;
57
+ invokedFunctionArn: string;
58
+ awsRequestId: string;
59
+ getRemainingTimeInMillis(): number;
60
+ }
61
+ export interface JourneyLambda {
62
+ /** Export as the function's handler. */
63
+ handler: (event: DurableExecutionInvocationInput, context: LambdaContext) => Promise<DurableExecutionInvocationOutput>;
64
+ }
65
+ export declare function journeyLambda<Env extends JourneyLambdaEnv>(options: JourneyLambdaOptions<Env>): JourneyLambda;
66
+ //#endregion
67
+ export { AwsEngineStep, AwsInstances, type AwsInstancesOptions, type ExecutionState, type FunctionUrlEvent, type FunctionUrlResult, type LambdaApi, RUN_EVENT_TYPE, type RunInput, executionName, fromResponse, isFunctionUrlEvent, isRunInput, sdkLambdaApi, stepRetry, toRequest };
68
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/aws/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA6Ca;;YAGD,mBAAmB,KAAK;iBAEnB,qBAAqB,YAAY,0BAA0B,KAC1E,mBAAmB,MAAM;;EAIzB,KAAK;;EAEL,QAAQ,KAAK,KAAK;IAAY;QAAqB,eAAe;;EAElE,SAAS;;EAET;;;;;;EAMA;;;;;;iBAOe;EACf;EACA;EACA;EACA;EACA;;iBAGe;;EAEf,UACE,OAAO,iCACP,SAAS,kBACN,QAAQ;;wBAeC,cAAc,YAAY,kBACxC,SAAS,qBAAqB,OAC7B"}