alchemy-effect 0.5.0 → 0.6.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 (215) hide show
  1. package/README.md +13 -7
  2. package/bin/alchemy-effect.js +16 -17
  3. package/bin/alchemy-effect.js.map +1 -1
  4. package/lib/apply.d.ts.map +1 -1
  5. package/lib/apply.js +19 -17
  6. package/lib/apply.js.map +1 -1
  7. package/lib/aws/client.d.ts.map +1 -1
  8. package/lib/aws/client.js +15 -2
  9. package/lib/aws/client.js.map +1 -1
  10. package/lib/aws/dynamodb/secondary-index.d.ts.map +1 -1
  11. package/lib/aws/dynamodb/table.d.ts.map +1 -1
  12. package/lib/aws/dynamodb/table.js.map +1 -1
  13. package/lib/aws/ec2/egress-only-igw.d.ts +55 -0
  14. package/lib/aws/ec2/egress-only-igw.d.ts.map +1 -0
  15. package/lib/aws/ec2/egress-only-igw.js +4 -0
  16. package/lib/aws/ec2/egress-only-igw.js.map +1 -0
  17. package/lib/aws/ec2/egress-only-igw.provider.d.ts +6 -0
  18. package/lib/aws/ec2/egress-only-igw.provider.d.ts.map +1 -0
  19. package/lib/aws/ec2/egress-only-igw.provider.js +114 -0
  20. package/lib/aws/ec2/egress-only-igw.provider.js.map +1 -0
  21. package/lib/aws/ec2/eip.d.ts +85 -0
  22. package/lib/aws/ec2/eip.d.ts.map +1 -0
  23. package/lib/aws/ec2/eip.js +4 -0
  24. package/lib/aws/ec2/eip.js.map +1 -0
  25. package/lib/aws/ec2/eip.provider.d.ts +6 -0
  26. package/lib/aws/ec2/eip.provider.d.ts.map +1 -0
  27. package/lib/aws/ec2/eip.provider.js +135 -0
  28. package/lib/aws/ec2/eip.provider.js.map +1 -0
  29. package/lib/aws/ec2/index.d.ts +18 -0
  30. package/lib/aws/ec2/index.d.ts.map +1 -1
  31. package/lib/aws/ec2/index.js +18 -0
  32. package/lib/aws/ec2/index.js.map +1 -1
  33. package/lib/aws/ec2/internet-gateway.d.ts.map +1 -1
  34. package/lib/aws/ec2/internet-gateway.provider.d.ts.map +1 -1
  35. package/lib/aws/ec2/internet-gateway.provider.js +9 -5
  36. package/lib/aws/ec2/internet-gateway.provider.js.map +1 -1
  37. package/lib/aws/ec2/nat-gateway.d.ts +127 -0
  38. package/lib/aws/ec2/nat-gateway.d.ts.map +1 -0
  39. package/lib/aws/ec2/nat-gateway.js +4 -0
  40. package/lib/aws/ec2/nat-gateway.js.map +1 -0
  41. package/lib/aws/ec2/nat-gateway.provider.d.ts +6 -0
  42. package/lib/aws/ec2/nat-gateway.provider.d.ts.map +1 -0
  43. package/lib/aws/ec2/nat-gateway.provider.js +222 -0
  44. package/lib/aws/ec2/nat-gateway.provider.js.map +1 -0
  45. package/lib/aws/ec2/network-acl-association.d.ts +44 -0
  46. package/lib/aws/ec2/network-acl-association.d.ts.map +1 -0
  47. package/lib/aws/ec2/network-acl-association.js +4 -0
  48. package/lib/aws/ec2/network-acl-association.js.map +1 -0
  49. package/lib/aws/ec2/network-acl-association.provider.d.ts +4 -0
  50. package/lib/aws/ec2/network-acl-association.provider.d.ts.map +1 -0
  51. package/lib/aws/ec2/network-acl-association.provider.js +115 -0
  52. package/lib/aws/ec2/network-acl-association.provider.js.map +1 -0
  53. package/lib/aws/ec2/network-acl-entry.d.ts +118 -0
  54. package/lib/aws/ec2/network-acl-entry.d.ts.map +1 -0
  55. package/lib/aws/ec2/network-acl-entry.js +3 -0
  56. package/lib/aws/ec2/network-acl-entry.js.map +1 -0
  57. package/lib/aws/ec2/network-acl-entry.provider.d.ts +4 -0
  58. package/lib/aws/ec2/network-acl-entry.provider.d.ts.map +1 -0
  59. package/lib/aws/ec2/network-acl-entry.provider.js +129 -0
  60. package/lib/aws/ec2/network-acl-entry.provider.js.map +1 -0
  61. package/lib/aws/ec2/network-acl.d.ts +82 -0
  62. package/lib/aws/ec2/network-acl.d.ts.map +1 -0
  63. package/lib/aws/ec2/network-acl.js +4 -0
  64. package/lib/aws/ec2/network-acl.js.map +1 -0
  65. package/lib/aws/ec2/network-acl.provider.d.ts +6 -0
  66. package/lib/aws/ec2/network-acl.provider.d.ts.map +1 -0
  67. package/lib/aws/ec2/network-acl.provider.js +136 -0
  68. package/lib/aws/ec2/network-acl.provider.js.map +1 -0
  69. package/lib/aws/ec2/route-table-association.d.ts.map +1 -1
  70. package/lib/aws/ec2/route-table-association.provider.d.ts.map +1 -1
  71. package/lib/aws/ec2/route-table-association.provider.js.map +1 -1
  72. package/lib/aws/ec2/route-table.d.ts.map +1 -1
  73. package/lib/aws/ec2/route-table.provider.d.ts.map +1 -1
  74. package/lib/aws/ec2/route-table.provider.js.map +1 -1
  75. package/lib/aws/ec2/route.d.ts.map +1 -1
  76. package/lib/aws/ec2/route.provider.d.ts.map +1 -1
  77. package/lib/aws/ec2/route.provider.js.map +1 -1
  78. package/lib/aws/ec2/security-group-rule.d.ts +118 -0
  79. package/lib/aws/ec2/security-group-rule.d.ts.map +1 -0
  80. package/lib/aws/ec2/security-group-rule.js +4 -0
  81. package/lib/aws/ec2/security-group-rule.js.map +1 -0
  82. package/lib/aws/ec2/security-group-rule.provider.d.ts +4 -0
  83. package/lib/aws/ec2/security-group-rule.provider.d.ts.map +1 -0
  84. package/lib/aws/ec2/security-group-rule.provider.js +193 -0
  85. package/lib/aws/ec2/security-group-rule.provider.js.map +1 -0
  86. package/lib/aws/ec2/security-group.d.ts +147 -0
  87. package/lib/aws/ec2/security-group.d.ts.map +1 -0
  88. package/lib/aws/ec2/security-group.js +4 -0
  89. package/lib/aws/ec2/security-group.js.map +1 -0
  90. package/lib/aws/ec2/security-group.provider.d.ts +6 -0
  91. package/lib/aws/ec2/security-group.provider.d.ts.map +1 -0
  92. package/lib/aws/ec2/security-group.provider.js +291 -0
  93. package/lib/aws/ec2/security-group.provider.js.map +1 -0
  94. package/lib/aws/ec2/subnet.d.ts.map +1 -1
  95. package/lib/aws/ec2/subnet.provider.d.ts.map +1 -1
  96. package/lib/aws/ec2/subnet.provider.js +33 -30
  97. package/lib/aws/ec2/subnet.provider.js.map +1 -1
  98. package/lib/aws/ec2/vpc-endpoint.d.ts +176 -0
  99. package/lib/aws/ec2/vpc-endpoint.d.ts.map +1 -0
  100. package/lib/aws/ec2/vpc-endpoint.js +4 -0
  101. package/lib/aws/ec2/vpc-endpoint.js.map +1 -0
  102. package/lib/aws/ec2/vpc-endpoint.provider.d.ts +6 -0
  103. package/lib/aws/ec2/vpc-endpoint.provider.d.ts.map +1 -0
  104. package/lib/aws/ec2/vpc-endpoint.provider.js +315 -0
  105. package/lib/aws/ec2/vpc-endpoint.provider.js.map +1 -0
  106. package/lib/aws/ec2/vpc.d.ts.map +1 -1
  107. package/lib/aws/ec2/vpc.provider.d.ts +2 -2
  108. package/lib/aws/ec2/vpc.provider.d.ts.map +1 -1
  109. package/lib/aws/ec2/vpc.provider.js +38 -31
  110. package/lib/aws/ec2/vpc.provider.js.map +1 -1
  111. package/lib/aws/index.d.ts +2 -2
  112. package/lib/aws/index.d.ts.map +1 -1
  113. package/lib/aws/index.js +1 -1
  114. package/lib/aws/index.js.map +1 -1
  115. package/lib/aws/lambda/function.d.ts.map +1 -1
  116. package/lib/aws/lambda/function.invoke.d.ts.map +1 -1
  117. package/lib/aws/lambda/function.invoke.js.map +1 -1
  118. package/lib/aws/lambda/function.js.map +1 -1
  119. package/lib/aws/sqs/queue.d.ts +1 -2
  120. package/lib/aws/sqs/queue.d.ts.map +1 -1
  121. package/lib/aws/sqs/queue.event-source.d.ts.map +1 -1
  122. package/lib/aws/sqs/queue.event-source.js +2 -2
  123. package/lib/aws/sqs/queue.event-source.js.map +1 -1
  124. package/lib/aws/sqs/queue.js.map +1 -1
  125. package/lib/aws/sqs/queue.provider.d.ts.map +1 -1
  126. package/lib/aws/sqs/queue.provider.js +22 -14
  127. package/lib/aws/sqs/queue.provider.js.map +1 -1
  128. package/lib/aws/sqs/queue.send-message.d.ts.map +1 -1
  129. package/lib/aws/sqs/queue.send-message.js.map +1 -1
  130. package/lib/binding.d.ts.map +1 -1
  131. package/lib/cli/components/PlanProgress.d.ts.map +1 -1
  132. package/lib/cli/components/PlanProgress.js.map +1 -1
  133. package/lib/cli/index.d.ts +1 -1
  134. package/lib/cli/index.d.ts.map +1 -1
  135. package/lib/cli/index.js.map +1 -1
  136. package/lib/cloudflare/kv/namespace.binding.d.ts.map +1 -1
  137. package/lib/cloudflare/kv/namespace.binding.js.map +1 -1
  138. package/lib/cloudflare/kv/namespace.d.ts.map +1 -1
  139. package/lib/cloudflare/kv/namespace.provider.d.ts +1 -2
  140. package/lib/cloudflare/kv/namespace.provider.d.ts.map +1 -1
  141. package/lib/cloudflare/kv/namespace.provider.js +0 -2
  142. package/lib/cloudflare/kv/namespace.provider.js.map +1 -1
  143. package/lib/cloudflare/r2/bucket.binding.d.ts.map +1 -1
  144. package/lib/cloudflare/r2/bucket.binding.js.map +1 -1
  145. package/lib/cloudflare/r2/bucket.d.ts.map +1 -1
  146. package/lib/output.d.ts.map +1 -1
  147. package/lib/output.js.map +1 -1
  148. package/lib/plan.d.ts +2 -2
  149. package/lib/plan.d.ts.map +1 -1
  150. package/lib/plan.js +14 -13
  151. package/lib/plan.js.map +1 -1
  152. package/lib/provider.d.ts +1 -1
  153. package/lib/provider.d.ts.map +1 -1
  154. package/lib/provider.js.map +1 -1
  155. package/lib/runtime.d.ts.map +1 -1
  156. package/lib/tags.d.ts +12 -0
  157. package/lib/tags.d.ts.map +1 -1
  158. package/lib/tags.js +24 -0
  159. package/lib/tags.js.map +1 -1
  160. package/lib/tsconfig.test.tsbuildinfo +1 -1
  161. package/package.json +51 -51
  162. package/src/apply.ts +21 -12
  163. package/src/aws/client.ts +22 -1
  164. package/src/aws/dynamodb/secondary-index.ts +5 -5
  165. package/src/aws/dynamodb/table.ts +8 -11
  166. package/src/aws/ec2/egress-only-igw.provider.ts +181 -0
  167. package/src/aws/ec2/egress-only-igw.ts +77 -0
  168. package/src/aws/ec2/eip.provider.ts +191 -0
  169. package/src/aws/ec2/eip.ts +106 -0
  170. package/src/aws/ec2/index.ts +18 -0
  171. package/src/aws/ec2/internet-gateway.provider.ts +15 -6
  172. package/src/aws/ec2/internet-gateway.ts +6 -6
  173. package/src/aws/ec2/nat-gateway.provider.ts +341 -0
  174. package/src/aws/ec2/nat-gateway.ts +155 -0
  175. package/src/aws/ec2/network-acl-association.provider.ts +181 -0
  176. package/src/aws/ec2/network-acl-association.ts +60 -0
  177. package/src/aws/ec2/network-acl-entry.provider.ts +218 -0
  178. package/src/aws/ec2/network-acl-entry.ts +140 -0
  179. package/src/aws/ec2/network-acl.provider.ts +195 -0
  180. package/src/aws/ec2/network-acl.ts +102 -0
  181. package/src/aws/ec2/route-table-association.provider.ts +1 -2
  182. package/src/aws/ec2/route-table-association.ts +6 -6
  183. package/src/aws/ec2/route-table.provider.ts +1 -2
  184. package/src/aws/ec2/route-table.ts +6 -6
  185. package/src/aws/ec2/route.provider.ts +1 -2
  186. package/src/aws/ec2/route.ts +6 -6
  187. package/src/aws/ec2/security-group-rule.provider.ts +264 -0
  188. package/src/aws/ec2/security-group-rule.ts +151 -0
  189. package/src/aws/ec2/security-group.provider.ts +392 -0
  190. package/src/aws/ec2/security-group.ts +182 -0
  191. package/src/aws/ec2/subnet.provider.ts +57 -56
  192. package/src/aws/ec2/subnet.ts +6 -6
  193. package/src/aws/ec2/vpc-endpoint.provider.ts +466 -0
  194. package/src/aws/ec2/vpc-endpoint.ts +213 -0
  195. package/src/aws/ec2/vpc.provider.ts +58 -51
  196. package/src/aws/ec2/vpc.ts +6 -6
  197. package/src/aws/index.ts +9 -0
  198. package/src/aws/lambda/function.invoke.ts +4 -2
  199. package/src/aws/lambda/function.ts +4 -2
  200. package/src/aws/sqs/queue.event-source.ts +12 -14
  201. package/src/aws/sqs/queue.provider.ts +25 -15
  202. package/src/aws/sqs/queue.send-message.ts +4 -2
  203. package/src/aws/sqs/queue.ts +1 -8
  204. package/src/binding.ts +7 -7
  205. package/src/cli/components/PlanProgress.tsx +3 -2
  206. package/src/cloudflare/kv/namespace.binding.ts +4 -2
  207. package/src/cloudflare/kv/namespace.provider.ts +0 -2
  208. package/src/cloudflare/kv/namespace.ts +6 -6
  209. package/src/cloudflare/r2/bucket.binding.ts +4 -2
  210. package/src/cloudflare/r2/bucket.ts +6 -6
  211. package/src/output.ts +5 -3
  212. package/src/plan.ts +26 -20
  213. package/src/provider.ts +12 -11
  214. package/src/runtime.ts +2 -2
  215. package/src/tags.ts +29 -0
@@ -0,0 +1,60 @@
1
+ import type { Input } from "../../input.ts";
2
+ import { Resource } from "../../resource.ts";
3
+ import type { NetworkAclId } from "./network-acl.ts";
4
+ import type { SubnetId } from "./subnet.ts";
5
+
6
+ export const NetworkAclAssociation = Resource<{
7
+ <const ID extends string, const Props extends NetworkAclAssociationProps>(
8
+ id: ID,
9
+ props: Props,
10
+ ): NetworkAclAssociation<ID, Props>;
11
+ }>("AWS.EC2.NetworkAclAssociation");
12
+
13
+ export interface NetworkAclAssociation<
14
+ ID extends string = string,
15
+ Props extends NetworkAclAssociationProps = NetworkAclAssociationProps,
16
+ > extends Resource<
17
+ "AWS.EC2.NetworkAclAssociation",
18
+ ID,
19
+ Props,
20
+ NetworkAclAssociationAttrs<Input.Resolve<Props>>,
21
+ NetworkAclAssociation
22
+ > {}
23
+
24
+ export type NetworkAclAssociationId<ID extends string = string> =
25
+ `aclassoc-${ID}`;
26
+ export const NetworkAclAssociationId = <ID extends string>(
27
+ id: ID,
28
+ ): ID & NetworkAclAssociationId<ID> =>
29
+ `aclassoc-${id}` as ID & NetworkAclAssociationId<ID>;
30
+
31
+ export interface NetworkAclAssociationProps {
32
+ /**
33
+ * The ID of the new network ACL to associate with the subnet.
34
+ */
35
+ networkAclId: Input<NetworkAclId>;
36
+
37
+ /**
38
+ * The ID of the subnet to associate with the network ACL.
39
+ */
40
+ subnetId: Input<SubnetId>;
41
+ }
42
+
43
+ export interface NetworkAclAssociationAttrs<
44
+ Props extends Input.Resolve<NetworkAclAssociationProps>,
45
+ > {
46
+ /**
47
+ * The ID of the association between the network ACL and subnet.
48
+ */
49
+ associationId: NetworkAclAssociationId;
50
+
51
+ /**
52
+ * The ID of the network ACL.
53
+ */
54
+ networkAclId: Props["networkAclId"];
55
+
56
+ /**
57
+ * The ID of the subnet.
58
+ */
59
+ subnetId: Props["subnetId"];
60
+ }
@@ -0,0 +1,218 @@
1
+ import * as Effect from "effect/Effect";
2
+
3
+ import { EC2Client } from "./client.ts";
4
+ import {
5
+ NetworkAclEntry,
6
+ type NetworkAclEntryAttrs,
7
+ type NetworkAclEntryProps,
8
+ } from "./network-acl-entry.ts";
9
+
10
+ export const networkAclEntryProvider = () =>
11
+ NetworkAclEntry.provider.effect(
12
+ // @ts-expect-error - TODO: fix this
13
+ Effect.gen(function* () {
14
+ const ec2 = yield* EC2Client;
15
+
16
+ const findEntry = (
17
+ networkAclId: string,
18
+ ruleNumber: number,
19
+ egress: boolean,
20
+ ) =>
21
+ ec2
22
+ .describeNetworkAcls({ NetworkAclIds: [networkAclId] })
23
+ .pipe(
24
+ Effect.map((r) =>
25
+ r.NetworkAcls?.[0]?.Entries?.find(
26
+ (e) => e.RuleNumber === ruleNumber && e.Egress === egress,
27
+ ),
28
+ ),
29
+ );
30
+
31
+ const toAttrs = (
32
+ props: NetworkAclEntryProps,
33
+ entry: NonNullable<
34
+ Awaited<
35
+ ReturnType<
36
+ typeof findEntry extends (
37
+ ...args: any
38
+ ) => Effect.Effect<infer R, any, any>
39
+ ? () => Promise<R>
40
+ : never
41
+ >
42
+ >
43
+ >,
44
+ ): NetworkAclEntryAttrs<NetworkAclEntryProps> => ({
45
+ networkAclId:
46
+ props.networkAclId as NetworkAclEntryAttrs<NetworkAclEntryProps>["networkAclId"],
47
+ ruleNumber:
48
+ entry.RuleNumber as NetworkAclEntryAttrs<NetworkAclEntryProps>["ruleNumber"],
49
+ egress: entry.Egress!,
50
+ protocol:
51
+ entry.Protocol as NetworkAclEntryAttrs<NetworkAclEntryProps>["protocol"],
52
+ ruleAction:
53
+ entry.RuleAction as NetworkAclEntryAttrs<NetworkAclEntryProps>["ruleAction"],
54
+ cidrBlock: entry.CidrBlock,
55
+ ipv6CidrBlock: entry.Ipv6CidrBlock,
56
+ icmpTypeCode: entry.IcmpTypeCode
57
+ ? {
58
+ code: entry.IcmpTypeCode.Code,
59
+ type: entry.IcmpTypeCode.Type,
60
+ }
61
+ : undefined,
62
+ portRange: entry.PortRange
63
+ ? {
64
+ from: entry.PortRange.From,
65
+ to: entry.PortRange.To,
66
+ }
67
+ : undefined,
68
+ });
69
+
70
+ return {
71
+ stables: [],
72
+
73
+ read: Effect.fn(function* ({ olds, output }) {
74
+ if (!output) return undefined;
75
+ const entry = yield* findEntry(
76
+ olds.networkAclId as string,
77
+ output.ruleNumber,
78
+ output.egress,
79
+ );
80
+ if (!entry) {
81
+ return yield* Effect.fail(
82
+ new Error(
83
+ `Network ACL Entry not found: ${output.networkAclId} rule ${output.ruleNumber} egress=${output.egress}`,
84
+ ),
85
+ );
86
+ }
87
+ return toAttrs(olds, entry);
88
+ }),
89
+
90
+ diff: Effect.fn(function* ({ news, olds }) {
91
+ // If network ACL, rule number, or egress changes, need to replace
92
+ if (
93
+ news.networkAclId !== olds.networkAclId ||
94
+ news.ruleNumber !== olds.ruleNumber ||
95
+ news.egress !== olds.egress
96
+ ) {
97
+ return { action: "replace" };
98
+ }
99
+ // Other properties can be updated by replacing the entry
100
+ }),
101
+
102
+ create: Effect.fn(function* ({ news, session }) {
103
+ yield* session.note(
104
+ `Creating Network ACL Entry (rule ${news.ruleNumber})...`,
105
+ );
106
+
107
+ yield* ec2.createNetworkAclEntry({
108
+ NetworkAclId: news.networkAclId as string,
109
+ RuleNumber: news.ruleNumber,
110
+ Protocol: news.protocol,
111
+ RuleAction: news.ruleAction,
112
+ Egress: news.egress ?? false,
113
+ CidrBlock: news.cidrBlock,
114
+ Ipv6CidrBlock: news.ipv6CidrBlock,
115
+ IcmpTypeCode: news.icmpTypeCode
116
+ ? {
117
+ Code: news.icmpTypeCode.code,
118
+ Type: news.icmpTypeCode.type,
119
+ }
120
+ : undefined,
121
+ PortRange: news.portRange
122
+ ? {
123
+ From: news.portRange.from,
124
+ To: news.portRange.to,
125
+ }
126
+ : undefined,
127
+ DryRun: false,
128
+ });
129
+
130
+ yield* session.note(
131
+ `Network ACL Entry created: rule ${news.ruleNumber}`,
132
+ );
133
+
134
+ const entry = yield* findEntry(
135
+ news.networkAclId as string,
136
+ news.ruleNumber,
137
+ news.egress ?? false,
138
+ );
139
+ if (!entry) {
140
+ return yield* Effect.fail(
141
+ new Error("Network ACL Entry not found after creation"),
142
+ );
143
+ }
144
+ return toAttrs(news, entry);
145
+ }),
146
+
147
+ update: Effect.fn(function* ({ news, session }) {
148
+ // To update a network ACL entry, we need to replace it
149
+ yield* session.note(
150
+ `Updating Network ACL Entry (rule ${news.ruleNumber})...`,
151
+ );
152
+
153
+ yield* ec2.replaceNetworkAclEntry({
154
+ NetworkAclId: news.networkAclId as string,
155
+ RuleNumber: news.ruleNumber,
156
+ Protocol: news.protocol,
157
+ RuleAction: news.ruleAction,
158
+ Egress: news.egress ?? false,
159
+ CidrBlock: news.cidrBlock,
160
+ Ipv6CidrBlock: news.ipv6CidrBlock,
161
+ IcmpTypeCode: news.icmpTypeCode
162
+ ? {
163
+ Code: news.icmpTypeCode.code,
164
+ Type: news.icmpTypeCode.type,
165
+ }
166
+ : undefined,
167
+ PortRange: news.portRange
168
+ ? {
169
+ From: news.portRange.from,
170
+ To: news.portRange.to,
171
+ }
172
+ : undefined,
173
+ DryRun: false,
174
+ });
175
+
176
+ yield* session.note(
177
+ `Network ACL Entry updated: rule ${news.ruleNumber}`,
178
+ );
179
+
180
+ const entry = yield* findEntry(
181
+ news.networkAclId as string,
182
+ news.ruleNumber,
183
+ news.egress ?? false,
184
+ );
185
+ if (!entry) {
186
+ return yield* Effect.fail(
187
+ new Error("Network ACL Entry not found after update"),
188
+ );
189
+ }
190
+ return toAttrs(news, entry);
191
+ }),
192
+
193
+ delete: Effect.fn(function* ({ olds, output, session }) {
194
+ yield* session.note(
195
+ `Deleting Network ACL Entry (rule ${output.ruleNumber})...`,
196
+ );
197
+
198
+ yield* ec2
199
+ .deleteNetworkAclEntry({
200
+ NetworkAclId: olds.networkAclId as string,
201
+ RuleNumber: output.ruleNumber,
202
+ Egress: output.egress,
203
+ DryRun: false,
204
+ })
205
+ .pipe(
206
+ Effect.catchTag(
207
+ "InvalidNetworkAclEntry.NotFound",
208
+ () => Effect.void,
209
+ ),
210
+ );
211
+
212
+ yield* session.note(
213
+ `Network ACL Entry deleted: rule ${output.ruleNumber}`,
214
+ );
215
+ }),
216
+ };
217
+ }),
218
+ );
@@ -0,0 +1,140 @@
1
+ import type * as EC2 from "itty-aws/ec2";
2
+ import type { Input } from "../../input.ts";
3
+ import { Resource } from "../../resource.ts";
4
+ import type { NetworkAclId } from "./network-acl.ts";
5
+
6
+ export const NetworkAclEntry = Resource<{
7
+ <const ID extends string, const Props extends NetworkAclEntryProps>(
8
+ id: ID,
9
+ props: Props,
10
+ ): NetworkAclEntry<ID, Props>;
11
+ }>("AWS.EC2.NetworkAclEntry");
12
+
13
+ export interface NetworkAclEntry<
14
+ ID extends string = string,
15
+ Props extends NetworkAclEntryProps = NetworkAclEntryProps,
16
+ > extends Resource<
17
+ "AWS.EC2.NetworkAclEntry",
18
+ ID,
19
+ Props,
20
+ NetworkAclEntryAttrs<Input.Resolve<Props>>,
21
+ NetworkAclEntry
22
+ > {}
23
+
24
+ export interface NetworkAclEntryProps {
25
+ /**
26
+ * The ID of the network ACL.
27
+ */
28
+ networkAclId: Input<NetworkAclId>;
29
+
30
+ /**
31
+ * The rule number for the entry (1-32766).
32
+ * Rules are evaluated in order from lowest to highest.
33
+ */
34
+ ruleNumber: number;
35
+
36
+ /**
37
+ * The protocol number.
38
+ * A value of "-1" means all protocols.
39
+ * Common values: 6 (TCP), 17 (UDP), 1 (ICMP)
40
+ */
41
+ protocol: string;
42
+
43
+ /**
44
+ * Whether to allow or deny the traffic that matches the rule.
45
+ */
46
+ ruleAction: EC2.RuleAction;
47
+
48
+ /**
49
+ * Whether this is an egress (outbound) rule.
50
+ * @default false (ingress)
51
+ */
52
+ egress?: boolean;
53
+
54
+ /**
55
+ * The IPv4 CIDR block.
56
+ * Either cidrBlock or ipv6CidrBlock must be specified.
57
+ */
58
+ cidrBlock?: string;
59
+
60
+ /**
61
+ * The IPv6 CIDR block.
62
+ * Either cidrBlock or ipv6CidrBlock must be specified.
63
+ */
64
+ ipv6CidrBlock?: string;
65
+
66
+ /**
67
+ * ICMP type and code. Required if protocol is 1 (ICMP) or 58 (ICMPv6).
68
+ */
69
+ icmpTypeCode?: {
70
+ /**
71
+ * The ICMP code. Use -1 to specify all codes.
72
+ */
73
+ code?: number;
74
+ /**
75
+ * The ICMP type. Use -1 to specify all types.
76
+ */
77
+ type?: number;
78
+ };
79
+
80
+ /**
81
+ * The port range for TCP/UDP protocols.
82
+ */
83
+ portRange?: {
84
+ /**
85
+ * The first port in the range.
86
+ */
87
+ from?: number;
88
+ /**
89
+ * The last port in the range.
90
+ */
91
+ to?: number;
92
+ };
93
+ }
94
+
95
+ export interface NetworkAclEntryAttrs<Props extends NetworkAclEntryProps> {
96
+ /**
97
+ * The ID of the network ACL.
98
+ */
99
+ networkAclId: Props["networkAclId"];
100
+
101
+ /**
102
+ * The rule number.
103
+ */
104
+ ruleNumber: Props["ruleNumber"];
105
+
106
+ /**
107
+ * Whether this is an egress rule.
108
+ */
109
+ egress: boolean;
110
+
111
+ /**
112
+ * The protocol.
113
+ */
114
+ protocol: Props["protocol"];
115
+
116
+ /**
117
+ * The rule action (allow or deny).
118
+ */
119
+ ruleAction: Props["ruleAction"];
120
+
121
+ /**
122
+ * The IPv4 CIDR block.
123
+ */
124
+ cidrBlock?: Props["cidrBlock"];
125
+
126
+ /**
127
+ * The IPv6 CIDR block.
128
+ */
129
+ ipv6CidrBlock?: Props["ipv6CidrBlock"];
130
+
131
+ /**
132
+ * The ICMP type and code.
133
+ */
134
+ icmpTypeCode?: Props["icmpTypeCode"];
135
+
136
+ /**
137
+ * The port range.
138
+ */
139
+ portRange?: Props["portRange"];
140
+ }
@@ -0,0 +1,195 @@
1
+ import type * as EC2 from "itty-aws/ec2";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Schedule from "effect/Schedule";
4
+
5
+ import { createTagger, createTagsList, diffTags } from "../../tags.ts";
6
+ import { Account } from "../account.ts";
7
+ import { Region } from "../region.ts";
8
+ import { EC2Client } from "./client.ts";
9
+ import {
10
+ type NetworkAclArn,
11
+ NetworkAcl,
12
+ type NetworkAclAttrs,
13
+ type NetworkAclId,
14
+ } from "./network-acl.ts";
15
+ import type { VpcId } from "./vpc.ts";
16
+
17
+ export const networkAclProvider = () =>
18
+ NetworkAcl.provider.effect(
19
+ Effect.gen(function* () {
20
+ const ec2 = yield* EC2Client;
21
+ const region = yield* Region;
22
+ const accountId = yield* Account;
23
+ const tagged = yield* createTagger();
24
+
25
+ const createTags = (
26
+ id: string,
27
+ tags?: Record<string, string>,
28
+ ): Record<string, string> => ({
29
+ Name: id,
30
+ ...tagged(id),
31
+ ...tags,
32
+ });
33
+
34
+ const describeNetworkAcl = (networkAclId: string) =>
35
+ ec2.describeNetworkAcls({ NetworkAclIds: [networkAclId] }).pipe(
36
+ Effect.map((r) => r.NetworkAcls?.[0]),
37
+ Effect.flatMap((acl) =>
38
+ acl
39
+ ? Effect.succeed(acl)
40
+ : Effect.fail(new Error(`Network ACL ${networkAclId} not found`)),
41
+ ),
42
+ );
43
+
44
+ const toAttrs = (acl: EC2.NetworkAcl): NetworkAclAttrs => ({
45
+ networkAclId: acl.NetworkAclId as NetworkAclId,
46
+ networkAclArn:
47
+ `arn:aws:ec2:${region}:${accountId}:network-acl/${acl.NetworkAclId}` as NetworkAclArn,
48
+ vpcId: acl.VpcId as VpcId,
49
+ isDefault: acl.IsDefault ?? false,
50
+ ownerId: acl.OwnerId!,
51
+ entries: acl.Entries?.map((e) => ({
52
+ ruleNumber: e.RuleNumber!,
53
+ protocol: e.Protocol!,
54
+ ruleAction: e.RuleAction!,
55
+ egress: e.Egress!,
56
+ cidrBlock: e.CidrBlock,
57
+ ipv6CidrBlock: e.Ipv6CidrBlock,
58
+ icmpTypeCode: e.IcmpTypeCode
59
+ ? {
60
+ code: e.IcmpTypeCode.Code,
61
+ type: e.IcmpTypeCode.Type,
62
+ }
63
+ : undefined,
64
+ portRange: e.PortRange
65
+ ? {
66
+ from: e.PortRange.From,
67
+ to: e.PortRange.To,
68
+ }
69
+ : undefined,
70
+ })),
71
+ associations: acl.Associations?.map((a) => ({
72
+ networkAclAssociationId: a.NetworkAclAssociationId!,
73
+ networkAclId: a.NetworkAclId!,
74
+ subnetId: a.SubnetId!,
75
+ })),
76
+ });
77
+
78
+ return {
79
+ stables: ["networkAclId", "networkAclArn", "ownerId", "isDefault"],
80
+
81
+ read: Effect.fn(function* ({ output }) {
82
+ if (!output) return undefined;
83
+ const acl = yield* describeNetworkAcl(output.networkAclId);
84
+ return toAttrs(acl);
85
+ }),
86
+
87
+ diff: Effect.fn(function* ({ news, olds }) {
88
+ // VPC change requires replacement
89
+ if (news.vpcId !== olds.vpcId) {
90
+ return { action: "replace" };
91
+ }
92
+ // Tags can be updated in-place
93
+ }),
94
+
95
+ create: Effect.fn(function* ({ id, news, session }) {
96
+ yield* session.note("Creating Network ACL...");
97
+
98
+ const result = yield* ec2.createNetworkAcl({
99
+ VpcId: news.vpcId as string,
100
+ TagSpecifications: [
101
+ {
102
+ ResourceType: "network-acl",
103
+ Tags: createTagsList(createTags(id, news.tags)),
104
+ },
105
+ ],
106
+ DryRun: false,
107
+ });
108
+
109
+ const networkAclId = result.NetworkAcl!.NetworkAclId!;
110
+ yield* session.note(`Network ACL created: ${networkAclId}`);
111
+
112
+ const acl = yield* describeNetworkAcl(networkAclId);
113
+ return toAttrs(acl);
114
+ }),
115
+
116
+ update: Effect.fn(function* ({ id, news, output, session }) {
117
+ const networkAclId = output.networkAclId;
118
+
119
+ // Handle tag updates
120
+ const newTags = createTags(id, news.tags);
121
+ const oldTags =
122
+ (yield* ec2
123
+ .describeTags({
124
+ Filters: [
125
+ { Name: "resource-id", Values: [networkAclId] },
126
+ { Name: "resource-type", Values: ["network-acl"] },
127
+ ],
128
+ })
129
+ .pipe(
130
+ Effect.map(
131
+ (r) =>
132
+ Object.fromEntries(
133
+ r.Tags?.map((t) => [t.Key!, t.Value!]) ?? [],
134
+ ) as Record<string, string>,
135
+ ),
136
+ )) ?? {};
137
+
138
+ const { removed, upsert } = diffTags(oldTags, newTags);
139
+
140
+ if (removed.length > 0) {
141
+ yield* ec2.deleteTags({
142
+ Resources: [networkAclId],
143
+ Tags: removed.map((key) => ({ Key: key })),
144
+ DryRun: false,
145
+ });
146
+ }
147
+ if (upsert.length > 0) {
148
+ yield* ec2.createTags({
149
+ Resources: [networkAclId],
150
+ Tags: upsert,
151
+ DryRun: false,
152
+ });
153
+ yield* session.note("Updated tags");
154
+ }
155
+
156
+ const acl = yield* describeNetworkAcl(networkAclId);
157
+ return toAttrs(acl);
158
+ }),
159
+
160
+ delete: Effect.fn(function* ({ output, session }) {
161
+ const networkAclId = output.networkAclId;
162
+
163
+ yield* session.note(`Deleting Network ACL: ${networkAclId}`);
164
+
165
+ yield* ec2
166
+ .deleteNetworkAcl({
167
+ NetworkAclId: networkAclId,
168
+ DryRun: false,
169
+ })
170
+ .pipe(
171
+ Effect.catchTag(
172
+ "InvalidNetworkAclID.NotFound",
173
+ () => Effect.void,
174
+ ),
175
+ // Retry on dependency violations (e.g., associations still being removed)
176
+ Effect.retry({
177
+ while: (e) => {
178
+ return e._tag === "DependencyViolation";
179
+ },
180
+ schedule: Schedule.exponential(1000, 1.5).pipe(
181
+ Schedule.intersect(Schedule.recurs(15)),
182
+ Schedule.tapOutput(([, attempt]) =>
183
+ session.note(
184
+ `Waiting for dependencies to clear... (attempt ${attempt + 1})`,
185
+ ),
186
+ ),
187
+ ),
188
+ }),
189
+ );
190
+
191
+ yield* session.note(`Network ACL ${networkAclId} deleted`);
192
+ }),
193
+ };
194
+ }),
195
+ );
@@ -0,0 +1,102 @@
1
+ import type * as EC2 from "itty-aws/ec2";
2
+ import type { Input } from "../../input.ts";
3
+ import { Resource } from "../../resource.ts";
4
+ import type { AccountID } from "../account.ts";
5
+ import type { RegionID } from "../region.ts";
6
+ import type { VpcId } from "./vpc.ts";
7
+
8
+ export const NetworkAcl = Resource<{
9
+ <const ID extends string, const Props extends NetworkAclProps>(
10
+ id: ID,
11
+ props: Props,
12
+ ): NetworkAcl<ID, Props>;
13
+ }>("AWS.EC2.NetworkAcl");
14
+
15
+ export interface NetworkAcl<
16
+ ID extends string = string,
17
+ Props extends NetworkAclProps = NetworkAclProps,
18
+ > extends Resource<
19
+ "AWS.EC2.NetworkAcl",
20
+ ID,
21
+ Props,
22
+ NetworkAclAttrs<Input.Resolve<Props>>,
23
+ NetworkAcl
24
+ > {}
25
+
26
+ export type NetworkAclId<ID extends string = string> = `acl-${ID}`;
27
+ export const NetworkAclId = <ID extends string>(
28
+ id: ID,
29
+ ): ID & NetworkAclId<ID> => `acl-${id}` as ID & NetworkAclId<ID>;
30
+
31
+ export interface NetworkAclProps {
32
+ /**
33
+ * The VPC to create the network ACL in.
34
+ */
35
+ vpcId: Input<VpcId>;
36
+
37
+ /**
38
+ * Tags to assign to the network ACL.
39
+ */
40
+ tags?: Record<string, Input<string>>;
41
+ }
42
+
43
+ export type NetworkAclArn<ID extends NetworkAclId = NetworkAclId> =
44
+ `arn:aws:ec2:${RegionID}:${AccountID}:network-acl/${ID}`;
45
+
46
+ export interface NetworkAclAttrs<
47
+ Props extends Input.Resolve<NetworkAclProps> = Input.Resolve<NetworkAclProps>,
48
+ > {
49
+ /**
50
+ * The ID of the network ACL.
51
+ */
52
+ networkAclId: NetworkAclId;
53
+
54
+ /**
55
+ * The Amazon Resource Name (ARN) of the network ACL.
56
+ */
57
+ networkAclArn: NetworkAclArn<this["networkAclId"]>;
58
+
59
+ /**
60
+ * The ID of the VPC for the network ACL.
61
+ */
62
+ vpcId: Props["vpcId"];
63
+
64
+ /**
65
+ * Whether this is the default network ACL for the VPC.
66
+ */
67
+ isDefault: boolean;
68
+
69
+ /**
70
+ * The ID of the AWS account that owns the network ACL.
71
+ */
72
+ ownerId: string;
73
+
74
+ /**
75
+ * The entries (rules) in the network ACL.
76
+ */
77
+ entries?: Array<{
78
+ ruleNumber: number;
79
+ protocol: string;
80
+ ruleAction: EC2.RuleAction;
81
+ egress: boolean;
82
+ cidrBlock?: string;
83
+ ipv6CidrBlock?: string;
84
+ icmpTypeCode?: {
85
+ code?: number;
86
+ type?: number;
87
+ };
88
+ portRange?: {
89
+ from?: number;
90
+ to?: number;
91
+ };
92
+ }>;
93
+
94
+ /**
95
+ * The associations between the network ACL and subnets.
96
+ */
97
+ associations?: Array<{
98
+ networkAclAssociationId: string;
99
+ networkAclId: string;
100
+ subnetId: string;
101
+ }>;
102
+ }