@rayselfs/cf-rule-engine 1.5.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 +276 -0
  2. package/dist/adapters/cf-function.cjs +10 -0
  3. package/dist/adapters/cf-function.d.cts +2 -0
  4. package/dist/adapters/cf-function.d.ts +2 -0
  5. package/dist/adapters/cf-function.js +10 -0
  6. package/dist/adapters/lambda-edge.cjs +10 -0
  7. package/dist/adapters/lambda-edge.d.cts +2 -0
  8. package/dist/adapters/lambda-edge.d.ts +2 -0
  9. package/dist/adapters/lambda-edge.js +10 -0
  10. package/dist/behaviors/construct-response.cjs +7 -0
  11. package/dist/behaviors/construct-response.d.cts +62 -0
  12. package/dist/behaviors/construct-response.d.ts +62 -0
  13. package/dist/behaviors/construct-response.js +7 -0
  14. package/dist/behaviors/copy-header.cjs +7 -0
  15. package/dist/behaviors/copy-header.d.cts +27 -0
  16. package/dist/behaviors/copy-header.d.ts +27 -0
  17. package/dist/behaviors/copy-header.js +7 -0
  18. package/dist/behaviors/directory-index.cjs +7 -0
  19. package/dist/behaviors/directory-index.d.cts +33 -0
  20. package/dist/behaviors/directory-index.d.ts +33 -0
  21. package/dist/behaviors/directory-index.js +7 -0
  22. package/dist/behaviors/image-optimize.cjs +9 -0
  23. package/dist/behaviors/image-optimize.d.cts +103 -0
  24. package/dist/behaviors/image-optimize.d.ts +103 -0
  25. package/dist/behaviors/image-optimize.js +9 -0
  26. package/dist/behaviors/index.cjs +126 -0
  27. package/dist/behaviors/index.d.cts +46 -0
  28. package/dist/behaviors/index.d.ts +46 -0
  29. package/dist/behaviors/index.js +126 -0
  30. package/dist/behaviors/redirect.cjs +7 -0
  31. package/dist/behaviors/redirect.d.cts +44 -0
  32. package/dist/behaviors/redirect.d.ts +44 -0
  33. package/dist/behaviors/redirect.js +7 -0
  34. package/dist/behaviors/remove-response-headers.cjs +7 -0
  35. package/dist/behaviors/remove-response-headers.d.cts +27 -0
  36. package/dist/behaviors/remove-response-headers.d.ts +27 -0
  37. package/dist/behaviors/remove-response-headers.js +7 -0
  38. package/dist/behaviors/rewrite-uri.cjs +7 -0
  39. package/dist/behaviors/rewrite-uri.d.cts +43 -0
  40. package/dist/behaviors/rewrite-uri.d.ts +43 -0
  41. package/dist/behaviors/rewrite-uri.js +7 -0
  42. package/dist/behaviors/set-cache-control.cjs +7 -0
  43. package/dist/behaviors/set-cache-control.d.cts +29 -0
  44. package/dist/behaviors/set-cache-control.d.ts +29 -0
  45. package/dist/behaviors/set-cache-control.js +7 -0
  46. package/dist/behaviors/set-cors-headers.cjs +7 -0
  47. package/dist/behaviors/set-cors-headers.d.cts +76 -0
  48. package/dist/behaviors/set-cors-headers.d.ts +76 -0
  49. package/dist/behaviors/set-cors-headers.js +7 -0
  50. package/dist/behaviors/set-csp.cjs +7 -0
  51. package/dist/behaviors/set-csp.d.cts +48 -0
  52. package/dist/behaviors/set-csp.d.ts +48 -0
  53. package/dist/behaviors/set-csp.js +7 -0
  54. package/dist/behaviors/set-request-header.cjs +7 -0
  55. package/dist/behaviors/set-request-header.d.cts +26 -0
  56. package/dist/behaviors/set-request-header.d.ts +26 -0
  57. package/dist/behaviors/set-request-header.js +7 -0
  58. package/dist/behaviors/set-response-header.cjs +7 -0
  59. package/dist/behaviors/set-response-header.d.cts +28 -0
  60. package/dist/behaviors/set-response-header.d.ts +28 -0
  61. package/dist/behaviors/set-response-header.js +7 -0
  62. package/dist/behaviors/set-security-headers.cjs +7 -0
  63. package/dist/behaviors/set-security-headers.d.cts +55 -0
  64. package/dist/behaviors/set-security-headers.d.ts +55 -0
  65. package/dist/behaviors/set-security-headers.js +7 -0
  66. package/dist/behaviors/strip-query-params.cjs +7 -0
  67. package/dist/behaviors/strip-query-params.d.cts +25 -0
  68. package/dist/behaviors/strip-query-params.d.ts +25 -0
  69. package/dist/behaviors/strip-query-params.js +7 -0
  70. package/dist/cf-function-D27hUVtN.d.cts +70 -0
  71. package/dist/cf-function-u0PvbW_s.d.ts +70 -0
  72. package/dist/chunk-2DE6WPPL.js +21 -0
  73. package/dist/chunk-32SMWYAF.cjs +13 -0
  74. package/dist/chunk-3BBLG4IX.cjs +132 -0
  75. package/dist/chunk-3PVDUC5M.js +12 -0
  76. package/dist/chunk-5CPBXZ4X.js +12 -0
  77. package/dist/chunk-5PT5X62W.js +98 -0
  78. package/dist/chunk-63WIEBQB.cjs +50 -0
  79. package/dist/chunk-6DBZBV2M.js +42 -0
  80. package/dist/chunk-75ZPJI57.cjs +9 -0
  81. package/dist/chunk-B4WEJSEZ.cjs +14 -0
  82. package/dist/chunk-BDNPQ7AU.js +21 -0
  83. package/dist/chunk-BUAIBB3N.js +14 -0
  84. package/dist/chunk-BZQJYOU2.js +12 -0
  85. package/dist/chunk-C32DL3EP.js +13 -0
  86. package/dist/chunk-CF5PWWTF.cjs +15 -0
  87. package/dist/chunk-CV234DQT.cjs +14 -0
  88. package/dist/chunk-D47P7HVZ.cjs +12 -0
  89. package/dist/chunk-DSSFFJWL.js +38 -0
  90. package/dist/chunk-FTP7NLKX.js +29 -0
  91. package/dist/chunk-G7JGTBTT.cjs +8 -0
  92. package/dist/chunk-GK5JX7OM.cjs +39 -0
  93. package/dist/chunk-H2LO6MQG.js +50 -0
  94. package/dist/chunk-IBXAK2A4.cjs +21 -0
  95. package/dist/chunk-JGJW7D2N.cjs +12 -0
  96. package/dist/chunk-JU5WX5RU.cjs +21 -0
  97. package/dist/chunk-KW5YBTSD.js +12 -0
  98. package/dist/chunk-KZ72PI2A.js +0 -0
  99. package/dist/chunk-L7NBJ4JA.cjs +12 -0
  100. package/dist/chunk-LBJUCJF2.js +14 -0
  101. package/dist/chunk-LNQPYKGG.js +20 -0
  102. package/dist/chunk-LO2BO3RU.js +15 -0
  103. package/dist/chunk-LSCC62CZ.cjs +13 -0
  104. package/dist/chunk-LTLBEBKL.cjs +42 -0
  105. package/dist/chunk-M5KUQBDW.js +17 -0
  106. package/dist/chunk-MEHWLQLR.cjs +1 -0
  107. package/dist/chunk-MLKGABMK.js +9 -0
  108. package/dist/chunk-MRPTC74I.cjs +29 -0
  109. package/dist/chunk-MSES76XK.cjs +14 -0
  110. package/dist/chunk-MVGYPBYB.cjs +16 -0
  111. package/dist/chunk-NPMGSPNL.js +88 -0
  112. package/dist/chunk-OSGZTNTS.cjs +42 -0
  113. package/dist/chunk-OSZWDCTS.cjs +12 -0
  114. package/dist/chunk-OTFDML3K.cjs +11 -0
  115. package/dist/chunk-PPUHEL4H.cjs +17 -0
  116. package/dist/chunk-PY3JMRDG.js +11 -0
  117. package/dist/chunk-Q4NP4C3B.js +47 -0
  118. package/dist/chunk-R7WXS7BI.js +42 -0
  119. package/dist/chunk-RBBKFG5J.js +14 -0
  120. package/dist/chunk-S2AAATFN.js +16 -0
  121. package/dist/chunk-SAXDN5NS.cjs +88 -0
  122. package/dist/chunk-SGEBNQR2.cjs +14 -0
  123. package/dist/chunk-SOBTD7AD.js +39 -0
  124. package/dist/chunk-SRQF5UEJ.js +13 -0
  125. package/dist/chunk-TQLJIT4H.cjs +98 -0
  126. package/dist/chunk-U54FZCOH.cjs +14 -0
  127. package/dist/chunk-UD456E4I.js +8 -0
  128. package/dist/chunk-UI6LKDJI.cjs +19 -0
  129. package/dist/chunk-UKB5JAX4.js +32 -0
  130. package/dist/chunk-VEEOQ7TS.cjs +8 -0
  131. package/dist/chunk-VQCRSBWL.js +19 -0
  132. package/dist/chunk-WEBU4R5C.js +132 -0
  133. package/dist/chunk-WKYMSRCD.cjs +47 -0
  134. package/dist/chunk-WW7YVRAI.cjs +32 -0
  135. package/dist/chunk-WWSRNCUP.cjs +38 -0
  136. package/dist/chunk-XLSZ5RB7.js +8 -0
  137. package/dist/chunk-XPQG5IML.js +14 -0
  138. package/dist/chunk-XUI4Y22M.js +20 -0
  139. package/dist/chunk-YVUR35RN.cjs +20 -0
  140. package/dist/chunk-ZTMSH34E.js +14 -0
  141. package/dist/chunk-ZXS23HXA.cjs +20 -0
  142. package/dist/core/rule.cjs +17 -0
  143. package/dist/core/rule.d.cts +101 -0
  144. package/dist/core/rule.d.ts +101 -0
  145. package/dist/core/rule.js +17 -0
  146. package/dist/core/types.cjs +1 -0
  147. package/dist/core/types.d.cts +53 -0
  148. package/dist/core/types.d.ts +53 -0
  149. package/dist/core/types.js +1 -0
  150. package/dist/criteria/country-is.cjs +7 -0
  151. package/dist/criteria/country-is.d.cts +35 -0
  152. package/dist/criteria/country-is.d.ts +35 -0
  153. package/dist/criteria/country-is.js +7 -0
  154. package/dist/criteria/file-extension.cjs +7 -0
  155. package/dist/criteria/file-extension.d.cts +32 -0
  156. package/dist/criteria/file-extension.d.ts +32 -0
  157. package/dist/criteria/file-extension.js +7 -0
  158. package/dist/criteria/header-contains.cjs +7 -0
  159. package/dist/criteria/header-contains.d.cts +33 -0
  160. package/dist/criteria/header-contains.d.ts +33 -0
  161. package/dist/criteria/header-contains.js +7 -0
  162. package/dist/criteria/header-equals.cjs +7 -0
  163. package/dist/criteria/header-equals.d.cts +31 -0
  164. package/dist/criteria/header-equals.d.ts +31 -0
  165. package/dist/criteria/header-equals.js +7 -0
  166. package/dist/criteria/hostname-is.cjs +7 -0
  167. package/dist/criteria/hostname-is.d.cts +22 -0
  168. package/dist/criteria/hostname-is.d.ts +22 -0
  169. package/dist/criteria/hostname-is.js +7 -0
  170. package/dist/criteria/index.cjs +49 -0
  171. package/dist/criteria/index.d.cts +12 -0
  172. package/dist/criteria/index.d.ts +12 -0
  173. package/dist/criteria/index.js +49 -0
  174. package/dist/criteria/ip-cidr.cjs +8 -0
  175. package/dist/criteria/ip-cidr.d.cts +31 -0
  176. package/dist/criteria/ip-cidr.d.ts +31 -0
  177. package/dist/criteria/ip-cidr.js +8 -0
  178. package/dist/criteria/method-is.cjs +7 -0
  179. package/dist/criteria/method-is.d.cts +29 -0
  180. package/dist/criteria/method-is.d.ts +29 -0
  181. package/dist/criteria/method-is.js +7 -0
  182. package/dist/criteria/path-equals.cjs +7 -0
  183. package/dist/criteria/path-equals.d.cts +22 -0
  184. package/dist/criteria/path-equals.d.ts +22 -0
  185. package/dist/criteria/path-equals.js +7 -0
  186. package/dist/criteria/path-matches.cjs +8 -0
  187. package/dist/criteria/path-matches.d.cts +22 -0
  188. package/dist/criteria/path-matches.d.ts +22 -0
  189. package/dist/criteria/path-matches.js +8 -0
  190. package/dist/criteria/path-prefix.cjs +7 -0
  191. package/dist/criteria/path-prefix.d.cts +21 -0
  192. package/dist/criteria/path-prefix.d.ts +21 -0
  193. package/dist/criteria/path-prefix.js +7 -0
  194. package/dist/criteria/user-agent-matches.cjs +8 -0
  195. package/dist/criteria/user-agent-matches.d.cts +32 -0
  196. package/dist/criteria/user-agent-matches.d.ts +32 -0
  197. package/dist/criteria/user-agent-matches.js +8 -0
  198. package/dist/helpers/index.cjs +42 -0
  199. package/dist/helpers/index.d.cts +34 -0
  200. package/dist/helpers/index.d.ts +34 -0
  201. package/dist/helpers/index.js +42 -0
  202. package/dist/helpers/preflight-request.cjs +8 -0
  203. package/dist/helpers/preflight-request.d.cts +38 -0
  204. package/dist/helpers/preflight-request.d.ts +38 -0
  205. package/dist/helpers/preflight-request.js +8 -0
  206. package/dist/helpers/send-country-code.cjs +8 -0
  207. package/dist/helpers/send-country-code.d.cts +35 -0
  208. package/dist/helpers/send-country-code.d.ts +35 -0
  209. package/dist/helpers/send-country-code.js +8 -0
  210. package/dist/helpers/staging-whitelist.cjs +14 -0
  211. package/dist/helpers/staging-whitelist.d.cts +73 -0
  212. package/dist/helpers/staging-whitelist.d.ts +73 -0
  213. package/dist/helpers/staging-whitelist.js +14 -0
  214. package/dist/index.cjs +26 -0
  215. package/dist/index.d.cts +4 -0
  216. package/dist/index.d.ts +4 -0
  217. package/dist/index.js +26 -0
  218. package/dist/lambda-edge-D15Nf__n.d.ts +66 -0
  219. package/dist/lambda-edge-DxTOa2cg.d.cts +66 -0
  220. package/dist/shared/cidr.cjs +11 -0
  221. package/dist/shared/cidr.d.cts +8 -0
  222. package/dist/shared/cidr.d.ts +8 -0
  223. package/dist/shared/cidr.js +11 -0
  224. package/dist/shared/wildcard.cjs +11 -0
  225. package/dist/shared/wildcard.d.cts +8 -0
  226. package/dist/shared/wildcard.d.ts +8 -0
  227. package/dist/shared/wildcard.js +11 -0
  228. package/package.json +65 -0
@@ -0,0 +1,103 @@
1
+ import { BehaviorFn, HttpRequest } from '../core/types.cjs';
2
+
3
+ /**
4
+ * Origin configuration for image-optimize-proxy.
5
+ *
6
+ * Determines which request headers are injected so the proxy knows where to
7
+ * fetch the source image:
8
+ * - gateway: injects X-Img-Source-Type=gateway and X-Img-Upstream-Gateway
9
+ * - s3: injects X-Img-Source-Type=s3 and X-Img-Source-Bucket
10
+ */
11
+ type ImageOriginConfig = {
12
+ type: 'gateway';
13
+ upstreamGateway: string;
14
+ } | {
15
+ type: 's3';
16
+ sourceBucket: string;
17
+ };
18
+ /**
19
+ * Options for imageOptimize querystring normalization behavior.
20
+ *
21
+ * This behavior normalizes Akamai Image Manager-compatible query parameters
22
+ * for use with the `image-optimize-proxy` K8s proxy at origin, which reads
23
+ * the normalized `imwidth`, `f`, and `q` params to drive imgproxy transformation
24
+ * and S3 caching.
25
+ */
26
+ interface ImageOptimizeOptions {
27
+ /** Ordered list of breakpoint widths (px). Request widths snap to the nearest ceiling breakpoint. */
28
+ breakpoints: number[];
29
+ /** Preferred format priority. Defaults to ['avif', 'webp', 'jpeg']. */
30
+ formats?: ('avif' | 'webp' | 'jpeg')[];
31
+ /** Default image quality (1-100). Defaults to 75. */
32
+ quality?: number;
33
+ /** Query string param name for width override (Akamai IM compatible). Default: 'imwidth' */
34
+ imwidthParam?: string;
35
+ /** Query string param name for format override (Akamai IM compatible). Default: 'imformat' */
36
+ imformatParam?: string;
37
+ /**
38
+ * Origin configuration for image-optimize-proxy.
39
+ * When provided, injects the corresponding X-Img-* request headers so the
40
+ * proxy knows how to resolve the source image. This removes the need to
41
+ * configure CloudFront origin custom headers separately in Terraform.
42
+ */
43
+ origin?: ImageOriginConfig;
44
+ /**
45
+ * CloudFront origin verification secret.
46
+ * When provided, injects the value as the X-Origin-Verify request header.
47
+ * The proxy validates this header to ensure requests originate from CloudFront.
48
+ */
49
+ originSecret?: string;
50
+ }
51
+ /** Resolved normalized image parameters. */
52
+ interface ResolvedImageParams {
53
+ /** Width snapped to nearest ceiling breakpoint. */
54
+ breakpoint: number;
55
+ /** Resolved output format. */
56
+ format: 'avif' | 'webp' | 'jpeg';
57
+ /** Quality value (1-100). */
58
+ quality: number;
59
+ }
60
+ /**
61
+ * Resolves normalized image parameters (breakpoint, format, quality) from a request.
62
+ *
63
+ * Shared logic consumed by both the `imageOptimize` CF Function behavior and the
64
+ * `imageOptimizeJS` Lambda handler — keeps param resolution consistent across paths.
65
+ *
66
+ * Width resolution order: `imwidth` query param → `CloudFront-Viewer-Width` header → largest breakpoint.
67
+ * Format resolution order: `imformat` query param (Akamai IM) → `Accept` header → last format in list.
68
+ */
69
+ declare function resolveImageParams(request: Pick<HttpRequest, 'querystring' | 'headers'>, options: {
70
+ breakpoints: number[];
71
+ formats?: ('avif' | 'webp' | 'jpeg')[];
72
+ quality?: number;
73
+ imwidthParam?: string;
74
+ imformatParam?: string;
75
+ }): ResolvedImageParams;
76
+ /**
77
+ * Normalizes image-related query string parameters for use with the
78
+ * `image-optimize-proxy` K8s origin proxy, and optionally injects the
79
+ * origin routing headers so the proxy knows where to fetch source images.
80
+ *
81
+ * What this CF Function behavior does:
82
+ * - Snaps `imwidth` (or `CloudFront-Viewer-Width`) to the nearest ceiling breakpoint
83
+ * - Translates `imformat` (Akamai IM) to `f` param that `image-optimize-proxy` reads
84
+ * - Converts legacy `quality` param to `q` and removes `quality` from querystring
85
+ * - Adds default `q` (quality) param if not already set
86
+ * - Removes the `imformat` param after translation
87
+ * - Leaves `uri` unchanged — imgproxy URL construction is the proxy's responsibility
88
+ * - When `origin` is set, injects X-Img-Source-Type and X-Img-Upstream-Gateway
89
+ * or X-Img-Source-Bucket headers (eliminates need for Terraform origin custom headers)
90
+ * - When `originSecret` is set, injects X-Origin-Verify header
91
+ *
92
+ * Architecture:
93
+ * CF Function (viewer-request): imageOptimize — normalize querystring + inject origin headers
94
+ * image-optimize-proxy (origin): reads imwidth/f/q + X-Img-* headers, calls imgproxy sidecar, caches to S3
95
+ *
96
+ * Akamai `imformat` mapping:
97
+ * chrome / webp → webp
98
+ * avif → avif
99
+ * ie / safari / generic / (other) → jpeg
100
+ */
101
+ declare function imageOptimize(options: ImageOptimizeOptions): BehaviorFn;
102
+
103
+ export { type ImageOptimizeOptions, type ImageOriginConfig, type ResolvedImageParams, imageOptimize, resolveImageParams };
@@ -0,0 +1,103 @@
1
+ import { BehaviorFn, HttpRequest } from '../core/types.js';
2
+
3
+ /**
4
+ * Origin configuration for image-optimize-proxy.
5
+ *
6
+ * Determines which request headers are injected so the proxy knows where to
7
+ * fetch the source image:
8
+ * - gateway: injects X-Img-Source-Type=gateway and X-Img-Upstream-Gateway
9
+ * - s3: injects X-Img-Source-Type=s3 and X-Img-Source-Bucket
10
+ */
11
+ type ImageOriginConfig = {
12
+ type: 'gateway';
13
+ upstreamGateway: string;
14
+ } | {
15
+ type: 's3';
16
+ sourceBucket: string;
17
+ };
18
+ /**
19
+ * Options for imageOptimize querystring normalization behavior.
20
+ *
21
+ * This behavior normalizes Akamai Image Manager-compatible query parameters
22
+ * for use with the `image-optimize-proxy` K8s proxy at origin, which reads
23
+ * the normalized `imwidth`, `f`, and `q` params to drive imgproxy transformation
24
+ * and S3 caching.
25
+ */
26
+ interface ImageOptimizeOptions {
27
+ /** Ordered list of breakpoint widths (px). Request widths snap to the nearest ceiling breakpoint. */
28
+ breakpoints: number[];
29
+ /** Preferred format priority. Defaults to ['avif', 'webp', 'jpeg']. */
30
+ formats?: ('avif' | 'webp' | 'jpeg')[];
31
+ /** Default image quality (1-100). Defaults to 75. */
32
+ quality?: number;
33
+ /** Query string param name for width override (Akamai IM compatible). Default: 'imwidth' */
34
+ imwidthParam?: string;
35
+ /** Query string param name for format override (Akamai IM compatible). Default: 'imformat' */
36
+ imformatParam?: string;
37
+ /**
38
+ * Origin configuration for image-optimize-proxy.
39
+ * When provided, injects the corresponding X-Img-* request headers so the
40
+ * proxy knows how to resolve the source image. This removes the need to
41
+ * configure CloudFront origin custom headers separately in Terraform.
42
+ */
43
+ origin?: ImageOriginConfig;
44
+ /**
45
+ * CloudFront origin verification secret.
46
+ * When provided, injects the value as the X-Origin-Verify request header.
47
+ * The proxy validates this header to ensure requests originate from CloudFront.
48
+ */
49
+ originSecret?: string;
50
+ }
51
+ /** Resolved normalized image parameters. */
52
+ interface ResolvedImageParams {
53
+ /** Width snapped to nearest ceiling breakpoint. */
54
+ breakpoint: number;
55
+ /** Resolved output format. */
56
+ format: 'avif' | 'webp' | 'jpeg';
57
+ /** Quality value (1-100). */
58
+ quality: number;
59
+ }
60
+ /**
61
+ * Resolves normalized image parameters (breakpoint, format, quality) from a request.
62
+ *
63
+ * Shared logic consumed by both the `imageOptimize` CF Function behavior and the
64
+ * `imageOptimizeJS` Lambda handler — keeps param resolution consistent across paths.
65
+ *
66
+ * Width resolution order: `imwidth` query param → `CloudFront-Viewer-Width` header → largest breakpoint.
67
+ * Format resolution order: `imformat` query param (Akamai IM) → `Accept` header → last format in list.
68
+ */
69
+ declare function resolveImageParams(request: Pick<HttpRequest, 'querystring' | 'headers'>, options: {
70
+ breakpoints: number[];
71
+ formats?: ('avif' | 'webp' | 'jpeg')[];
72
+ quality?: number;
73
+ imwidthParam?: string;
74
+ imformatParam?: string;
75
+ }): ResolvedImageParams;
76
+ /**
77
+ * Normalizes image-related query string parameters for use with the
78
+ * `image-optimize-proxy` K8s origin proxy, and optionally injects the
79
+ * origin routing headers so the proxy knows where to fetch source images.
80
+ *
81
+ * What this CF Function behavior does:
82
+ * - Snaps `imwidth` (or `CloudFront-Viewer-Width`) to the nearest ceiling breakpoint
83
+ * - Translates `imformat` (Akamai IM) to `f` param that `image-optimize-proxy` reads
84
+ * - Converts legacy `quality` param to `q` and removes `quality` from querystring
85
+ * - Adds default `q` (quality) param if not already set
86
+ * - Removes the `imformat` param after translation
87
+ * - Leaves `uri` unchanged — imgproxy URL construction is the proxy's responsibility
88
+ * - When `origin` is set, injects X-Img-Source-Type and X-Img-Upstream-Gateway
89
+ * or X-Img-Source-Bucket headers (eliminates need for Terraform origin custom headers)
90
+ * - When `originSecret` is set, injects X-Origin-Verify header
91
+ *
92
+ * Architecture:
93
+ * CF Function (viewer-request): imageOptimize — normalize querystring + inject origin headers
94
+ * image-optimize-proxy (origin): reads imwidth/f/q + X-Img-* headers, calls imgproxy sidecar, caches to S3
95
+ *
96
+ * Akamai `imformat` mapping:
97
+ * chrome / webp → webp
98
+ * avif → avif
99
+ * ie / safari / generic / (other) → jpeg
100
+ */
101
+ declare function imageOptimize(options: ImageOptimizeOptions): BehaviorFn;
102
+
103
+ export { type ImageOptimizeOptions, type ImageOriginConfig, type ResolvedImageParams, imageOptimize, resolveImageParams };
@@ -0,0 +1,9 @@
1
+ import {
2
+ imageOptimize,
3
+ resolveImageParams
4
+ } from "../chunk-5PT5X62W.js";
5
+ import "../chunk-MLKGABMK.js";
6
+ export {
7
+ imageOptimize,
8
+ resolveImageParams
9
+ };
@@ -0,0 +1,126 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+ var _chunkUI6LKDJIcjs = require('../chunk-UI6LKDJI.cjs');
4
+
5
+
6
+ var _chunkMSES76XKcjs = require('../chunk-MSES76XK.cjs');
7
+
8
+
9
+ var _chunkWWSRNCUPcjs = require('../chunk-WWSRNCUP.cjs');
10
+
11
+
12
+ var _chunkSGEBNQR2cjs = require('../chunk-SGEBNQR2.cjs');
13
+
14
+
15
+ var _chunkMRPTC74Icjs = require('../chunk-MRPTC74I.cjs');
16
+
17
+
18
+ var _chunkCV234DQTcjs = require('../chunk-CV234DQT.cjs');
19
+
20
+
21
+ var _chunkGK5JX7OMcjs = require('../chunk-GK5JX7OM.cjs');
22
+
23
+
24
+ var _chunkZXS23HXAcjs = require('../chunk-ZXS23HXA.cjs');
25
+
26
+
27
+ var _chunkPPUHEL4Hcjs = require('../chunk-PPUHEL4H.cjs');
28
+
29
+
30
+ var _chunkB4WEJSEZcjs = require('../chunk-B4WEJSEZ.cjs');
31
+
32
+
33
+ var _chunkOSGZTNTScjs = require('../chunk-OSGZTNTS.cjs');
34
+
35
+
36
+ var _chunkJU5WX5RUcjs = require('../chunk-JU5WX5RU.cjs');
37
+
38
+
39
+ var _chunkLTLBEBKLcjs = require('../chunk-LTLBEBKL.cjs');
40
+
41
+
42
+ var _chunkTQLJIT4Hcjs = require('../chunk-TQLJIT4H.cjs');
43
+ require('../chunk-75ZPJI57.cjs');
44
+
45
+ // src/behaviors/verify-token.ts
46
+ var _crypto = require('crypto');
47
+ function parseToken(raw) {
48
+ const fields = {};
49
+ const parts = raw.split("~");
50
+ for (let i = 0; i < parts.length; i++) {
51
+ const eq = parts[i].indexOf("=");
52
+ if (eq === -1) return null;
53
+ const k = parts[i].slice(0, eq);
54
+ if (!k) return null;
55
+ fields[k] = parts[i].slice(eq + 1);
56
+ }
57
+ return fields;
58
+ }
59
+ function verifyHmac(fields, keyHex) {
60
+ var hmacVal = fields["hmac"];
61
+ if (!hmacVal) return false;
62
+ var restKeys = Object.keys(fields).filter(function(k) {
63
+ return k !== "hmac";
64
+ });
65
+ var message = restKeys.map(function(k) {
66
+ return k + "=" + fields[k];
67
+ }).join("~");
68
+ let keyBytes;
69
+ try {
70
+ keyBytes = Buffer.from(keyHex, "hex");
71
+ } catch (e) {
72
+ return false;
73
+ }
74
+ const expected = _crypto.createHmac.call(void 0, "sha256", keyBytes).update(message).digest();
75
+ let actual;
76
+ try {
77
+ actual = Buffer.from(hmacVal, "hex");
78
+ } catch (e2) {
79
+ return false;
80
+ }
81
+ if (expected.length !== actual.length) return false;
82
+ return _crypto.timingSafeEqual.call(void 0, expected, actual);
83
+ }
84
+ function verifyToken(options) {
85
+ const param = _nullishCoalesce(options.param, () => ( "hdnts"));
86
+ const failureStatus = _nullishCoalesce(options.failureStatus, () => ( 403));
87
+ const statusDescription = failureStatus === 401 ? "Unauthorized" : "Forbidden";
88
+ const deny = () => ({
89
+ action: "respond",
90
+ response: {
91
+ statusCode: failureStatus,
92
+ statusDescription,
93
+ headers: { "cache-control": { value: "no-store" } }
94
+ }
95
+ });
96
+ return (request) => {
97
+ const tokenEntry = request.querystring[param];
98
+ if (!_optionalChain([tokenEntry, 'optionalAccess', _ => _.value])) return deny();
99
+ const fields = parseToken(tokenEntry.value);
100
+ if (!fields) return deny();
101
+ const expStr = fields["exp"];
102
+ if (expStr) {
103
+ const exp = parseInt(expStr, 10);
104
+ if (isNaN(exp) || Math.floor(Date.now() / 1e3) > exp) return deny();
105
+ }
106
+ if (!verifyHmac(fields, options.key)) return deny();
107
+ return { action: "continue", request };
108
+ };
109
+ }
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+ exports.constructResponse = _chunkOSGZTNTScjs.constructResponse; exports.copyHeader = _chunkJU5WX5RUcjs.copyHeader; exports.directoryIndex = _chunkLTLBEBKLcjs.directoryIndex; exports.imageOptimize = _chunkTQLJIT4Hcjs.imageOptimize; exports.redirect = _chunkWWSRNCUPcjs.redirect; exports.removeResponseHeaders = _chunkSGEBNQR2cjs.removeResponseHeaders; exports.rewriteUri = _chunkMRPTC74Icjs.rewriteUri; exports.setCacheControl = _chunkCV234DQTcjs.setCacheControl; exports.setCorsHeaders = _chunkGK5JX7OMcjs.setCorsHeaders; exports.setCsp = _chunkZXS23HXAcjs.setCsp; exports.setRequestHeader = _chunkPPUHEL4Hcjs.setRequestHeader; exports.setResponseHeader = _chunkB4WEJSEZcjs.setResponseHeader; exports.setSecurityHeaders = _chunkUI6LKDJIcjs.setSecurityHeaders; exports.stripQueryParams = _chunkMSES76XKcjs.stripQueryParams; exports.verifyToken = verifyToken;
@@ -0,0 +1,46 @@
1
+ export { RedirectOptions, redirect } from './redirect.cjs';
2
+ export { RewriteMode, rewriteUri } from './rewrite-uri.cjs';
3
+ export { ConstructResponseOptions, constructResponse } from './construct-response.cjs';
4
+ export { directoryIndex } from './directory-index.cjs';
5
+ export { setRequestHeader } from './set-request-header.cjs';
6
+ export { copyHeader } from './copy-header.cjs';
7
+ export { setResponseHeader } from './set-response-header.cjs';
8
+ export { removeResponseHeaders } from './remove-response-headers.cjs';
9
+ export { CorsOptions, setCorsHeaders } from './set-cors-headers.cjs';
10
+ export { stripQueryParams } from './strip-query-params.cjs';
11
+ export { CspOptions, setCsp } from './set-csp.cjs';
12
+ export { setCacheControl } from './set-cache-control.cjs';
13
+ export { SecurityHeadersOptions, setSecurityHeaders } from './set-security-headers.cjs';
14
+ export { ImageOptimizeOptions, imageOptimize } from './image-optimize.cjs';
15
+ import { BehaviorFn } from '../core/types.cjs';
16
+ export { ResponseBehaviorFn, ResponseRule } from '../core/types.cjs';
17
+
18
+ /**
19
+ * ⚠️ Lambda@Edge only — CF Functions do not have the Node.js `crypto` module.
20
+ *
21
+ * Token format: `exp=<unix>~acl=<path>~hmac=<hex>`
22
+ * The `key` is the hex-encoded HMAC-SHA256 secret (Akamai `verifyTokenAuthorization.key`).
23
+ */
24
+ interface VerifyTokenOptions {
25
+ key: string;
26
+ param?: string;
27
+ failureStatus?: 401 | 403;
28
+ }
29
+ /**
30
+ * Validates an Akamai Edge Auth Token 2.0 (HMAC-SHA256) from the request querystring.
31
+ * Returns 403 on missing / expired / invalid token; continues on success.
32
+ * Chain with `stripQueryParams([param])` to strip the token before forwarding to origin.
33
+ *
34
+ * ⚠️ Lambda@Edge only.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * export const handler = defineViewerRequest([
39
+ * rule(verifyToken({ key: process.env.EDGE_AUTH_KEY! })),
40
+ * rule(stripQueryParams(['hdnts'])),
41
+ * ])
42
+ * ```
43
+ */
44
+ declare function verifyToken(options: VerifyTokenOptions): BehaviorFn;
45
+
46
+ export { type VerifyTokenOptions, verifyToken };
@@ -0,0 +1,46 @@
1
+ export { RedirectOptions, redirect } from './redirect.js';
2
+ export { RewriteMode, rewriteUri } from './rewrite-uri.js';
3
+ export { ConstructResponseOptions, constructResponse } from './construct-response.js';
4
+ export { directoryIndex } from './directory-index.js';
5
+ export { setRequestHeader } from './set-request-header.js';
6
+ export { copyHeader } from './copy-header.js';
7
+ export { setResponseHeader } from './set-response-header.js';
8
+ export { removeResponseHeaders } from './remove-response-headers.js';
9
+ export { CorsOptions, setCorsHeaders } from './set-cors-headers.js';
10
+ export { stripQueryParams } from './strip-query-params.js';
11
+ export { CspOptions, setCsp } from './set-csp.js';
12
+ export { setCacheControl } from './set-cache-control.js';
13
+ export { SecurityHeadersOptions, setSecurityHeaders } from './set-security-headers.js';
14
+ export { ImageOptimizeOptions, imageOptimize } from './image-optimize.js';
15
+ import { BehaviorFn } from '../core/types.js';
16
+ export { ResponseBehaviorFn, ResponseRule } from '../core/types.js';
17
+
18
+ /**
19
+ * ⚠️ Lambda@Edge only — CF Functions do not have the Node.js `crypto` module.
20
+ *
21
+ * Token format: `exp=<unix>~acl=<path>~hmac=<hex>`
22
+ * The `key` is the hex-encoded HMAC-SHA256 secret (Akamai `verifyTokenAuthorization.key`).
23
+ */
24
+ interface VerifyTokenOptions {
25
+ key: string;
26
+ param?: string;
27
+ failureStatus?: 401 | 403;
28
+ }
29
+ /**
30
+ * Validates an Akamai Edge Auth Token 2.0 (HMAC-SHA256) from the request querystring.
31
+ * Returns 403 on missing / expired / invalid token; continues on success.
32
+ * Chain with `stripQueryParams([param])` to strip the token before forwarding to origin.
33
+ *
34
+ * ⚠️ Lambda@Edge only.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * export const handler = defineViewerRequest([
39
+ * rule(verifyToken({ key: process.env.EDGE_AUTH_KEY! })),
40
+ * rule(stripQueryParams(['hdnts'])),
41
+ * ])
42
+ * ```
43
+ */
44
+ declare function verifyToken(options: VerifyTokenOptions): BehaviorFn;
45
+
46
+ export { type VerifyTokenOptions, verifyToken };
@@ -0,0 +1,126 @@
1
+ import {
2
+ setSecurityHeaders
3
+ } from "../chunk-VQCRSBWL.js";
4
+ import {
5
+ stripQueryParams
6
+ } from "../chunk-XPQG5IML.js";
7
+ import {
8
+ redirect
9
+ } from "../chunk-DSSFFJWL.js";
10
+ import {
11
+ removeResponseHeaders
12
+ } from "../chunk-BUAIBB3N.js";
13
+ import {
14
+ rewriteUri
15
+ } from "../chunk-FTP7NLKX.js";
16
+ import {
17
+ setCacheControl
18
+ } from "../chunk-ZTMSH34E.js";
19
+ import {
20
+ setCorsHeaders
21
+ } from "../chunk-SOBTD7AD.js";
22
+ import {
23
+ setCsp
24
+ } from "../chunk-XUI4Y22M.js";
25
+ import {
26
+ setRequestHeader
27
+ } from "../chunk-M5KUQBDW.js";
28
+ import {
29
+ setResponseHeader
30
+ } from "../chunk-RBBKFG5J.js";
31
+ import {
32
+ constructResponse
33
+ } from "../chunk-6DBZBV2M.js";
34
+ import {
35
+ copyHeader
36
+ } from "../chunk-BDNPQ7AU.js";
37
+ import {
38
+ directoryIndex
39
+ } from "../chunk-R7WXS7BI.js";
40
+ import {
41
+ imageOptimize
42
+ } from "../chunk-5PT5X62W.js";
43
+ import "../chunk-MLKGABMK.js";
44
+
45
+ // src/behaviors/verify-token.ts
46
+ import { createHmac, timingSafeEqual } from "crypto";
47
+ function parseToken(raw) {
48
+ const fields = {};
49
+ const parts = raw.split("~");
50
+ for (let i = 0; i < parts.length; i++) {
51
+ const eq = parts[i].indexOf("=");
52
+ if (eq === -1) return null;
53
+ const k = parts[i].slice(0, eq);
54
+ if (!k) return null;
55
+ fields[k] = parts[i].slice(eq + 1);
56
+ }
57
+ return fields;
58
+ }
59
+ function verifyHmac(fields, keyHex) {
60
+ var hmacVal = fields["hmac"];
61
+ if (!hmacVal) return false;
62
+ var restKeys = Object.keys(fields).filter(function(k) {
63
+ return k !== "hmac";
64
+ });
65
+ var message = restKeys.map(function(k) {
66
+ return k + "=" + fields[k];
67
+ }).join("~");
68
+ let keyBytes;
69
+ try {
70
+ keyBytes = Buffer.from(keyHex, "hex");
71
+ } catch {
72
+ return false;
73
+ }
74
+ const expected = createHmac("sha256", keyBytes).update(message).digest();
75
+ let actual;
76
+ try {
77
+ actual = Buffer.from(hmacVal, "hex");
78
+ } catch {
79
+ return false;
80
+ }
81
+ if (expected.length !== actual.length) return false;
82
+ return timingSafeEqual(expected, actual);
83
+ }
84
+ function verifyToken(options) {
85
+ const param = options.param ?? "hdnts";
86
+ const failureStatus = options.failureStatus ?? 403;
87
+ const statusDescription = failureStatus === 401 ? "Unauthorized" : "Forbidden";
88
+ const deny = () => ({
89
+ action: "respond",
90
+ response: {
91
+ statusCode: failureStatus,
92
+ statusDescription,
93
+ headers: { "cache-control": { value: "no-store" } }
94
+ }
95
+ });
96
+ return (request) => {
97
+ const tokenEntry = request.querystring[param];
98
+ if (!tokenEntry?.value) return deny();
99
+ const fields = parseToken(tokenEntry.value);
100
+ if (!fields) return deny();
101
+ const expStr = fields["exp"];
102
+ if (expStr) {
103
+ const exp = parseInt(expStr, 10);
104
+ if (isNaN(exp) || Math.floor(Date.now() / 1e3) > exp) return deny();
105
+ }
106
+ if (!verifyHmac(fields, options.key)) return deny();
107
+ return { action: "continue", request };
108
+ };
109
+ }
110
+ export {
111
+ constructResponse,
112
+ copyHeader,
113
+ directoryIndex,
114
+ imageOptimize,
115
+ redirect,
116
+ removeResponseHeaders,
117
+ rewriteUri,
118
+ setCacheControl,
119
+ setCorsHeaders,
120
+ setCsp,
121
+ setRequestHeader,
122
+ setResponseHeader,
123
+ setSecurityHeaders,
124
+ stripQueryParams,
125
+ verifyToken
126
+ };
@@ -0,0 +1,7 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+ var _chunkWWSRNCUPcjs = require('../chunk-WWSRNCUP.cjs');
4
+ require('../chunk-75ZPJI57.cjs');
5
+
6
+
7
+ exports.redirect = _chunkWWSRNCUPcjs.redirect;
@@ -0,0 +1,44 @@
1
+ import { BehaviorFn } from '../core/types.cjs';
2
+
3
+ /**
4
+ * Options for configuring redirect behavior.
5
+ */
6
+ interface RedirectOptions {
7
+ /**
8
+ * When `true`, the original request's query string is appended to the redirect
9
+ * `location` URL. Useful for preserving search params during path migrations.
10
+ * Default: `false`.
11
+ */
12
+ preserveQuerystring?: boolean;
13
+ }
14
+ /**
15
+ * Redirects the request to the specified URL with the given HTTP status code.
16
+ *
17
+ * The response always includes `Cache-Control: no-store` to prevent clients
18
+ * from caching the redirect.
19
+ *
20
+ * Akamai equivalent: `redirect` / `redirectplus` behaviors.
21
+ *
22
+ * @param statusCode - The HTTP redirect status code: `301` (permanent), `302` (temporary),
23
+ * or `307` (temporary, preserves method).
24
+ * @param location - The target URL to redirect to. Can be an absolute URL
25
+ * (e.g. `'https://www.example.com/new-path'`) or an absolute path (e.g. `'/new-path'`).
26
+ * @param options - Optional settings, e.g. to preserve the original query string.
27
+ * @returns A `BehaviorFn` to use as the second argument to `rule()`.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { redirect } from '@viverse/cf-engine/behaviors'
32
+ * import { pathPrefix, pathEquals } from '@viverse/cf-engine/criteria'
33
+ * import { rule } from '@viverse/cf-engine'
34
+ *
35
+ * // Permanent redirect for a renamed section
36
+ * rule(pathPrefix(['/old-blog/']), redirect(301, '/blog/'))
37
+ *
38
+ * // Temporary redirect preserving query string
39
+ * rule(pathEquals(['/search']), redirect(302, '/new-search', { preserveQuerystring: true }))
40
+ * ```
41
+ */
42
+ declare function redirect(statusCode: 301 | 302 | 307, location: string, options?: RedirectOptions): BehaviorFn;
43
+
44
+ export { type RedirectOptions, redirect };
@@ -0,0 +1,44 @@
1
+ import { BehaviorFn } from '../core/types.js';
2
+
3
+ /**
4
+ * Options for configuring redirect behavior.
5
+ */
6
+ interface RedirectOptions {
7
+ /**
8
+ * When `true`, the original request's query string is appended to the redirect
9
+ * `location` URL. Useful for preserving search params during path migrations.
10
+ * Default: `false`.
11
+ */
12
+ preserveQuerystring?: boolean;
13
+ }
14
+ /**
15
+ * Redirects the request to the specified URL with the given HTTP status code.
16
+ *
17
+ * The response always includes `Cache-Control: no-store` to prevent clients
18
+ * from caching the redirect.
19
+ *
20
+ * Akamai equivalent: `redirect` / `redirectplus` behaviors.
21
+ *
22
+ * @param statusCode - The HTTP redirect status code: `301` (permanent), `302` (temporary),
23
+ * or `307` (temporary, preserves method).
24
+ * @param location - The target URL to redirect to. Can be an absolute URL
25
+ * (e.g. `'https://www.example.com/new-path'`) or an absolute path (e.g. `'/new-path'`).
26
+ * @param options - Optional settings, e.g. to preserve the original query string.
27
+ * @returns A `BehaviorFn` to use as the second argument to `rule()`.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { redirect } from '@viverse/cf-engine/behaviors'
32
+ * import { pathPrefix, pathEquals } from '@viverse/cf-engine/criteria'
33
+ * import { rule } from '@viverse/cf-engine'
34
+ *
35
+ * // Permanent redirect for a renamed section
36
+ * rule(pathPrefix(['/old-blog/']), redirect(301, '/blog/'))
37
+ *
38
+ * // Temporary redirect preserving query string
39
+ * rule(pathEquals(['/search']), redirect(302, '/new-search', { preserveQuerystring: true }))
40
+ * ```
41
+ */
42
+ declare function redirect(statusCode: 301 | 302 | 307, location: string, options?: RedirectOptions): BehaviorFn;
43
+
44
+ export { type RedirectOptions, redirect };
@@ -0,0 +1,7 @@
1
+ import {
2
+ redirect
3
+ } from "../chunk-DSSFFJWL.js";
4
+ import "../chunk-MLKGABMK.js";
5
+ export {
6
+ redirect
7
+ };
@@ -0,0 +1,7 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+ var _chunkSGEBNQR2cjs = require('../chunk-SGEBNQR2.cjs');
4
+ require('../chunk-75ZPJI57.cjs');
5
+
6
+
7
+ exports.removeResponseHeaders = _chunkSGEBNQR2cjs.removeResponseHeaders;