@rc312/effect-aws-imds 0.0.0-stage → 0.2.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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +158 -2
  3. package/dist/aws-imds.d.ts +58 -0
  4. package/dist/aws-imds.d.ts.map +1 -0
  5. package/dist/aws-imds.js +65 -0
  6. package/dist/aws-imds.js.map +1 -0
  7. package/dist/config.d.ts +64 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +37 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/identity-document.d.ts +33 -0
  12. package/dist/identity-document.d.ts.map +1 -0
  13. package/dist/identity-document.js +58 -0
  14. package/dist/identity-document.js.map +1 -0
  15. package/dist/index.d.ts +48 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +48 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/instance-identity.d.ts +43 -0
  20. package/dist/instance-identity.d.ts.map +1 -0
  21. package/dist/instance-identity.js +38 -0
  22. package/dist/instance-identity.js.map +1 -0
  23. package/dist/internal.d.ts +11 -0
  24. package/dist/internal.d.ts.map +1 -0
  25. package/dist/internal.js +15 -0
  26. package/dist/internal.js.map +1 -0
  27. package/dist/layer.d.ts +25 -0
  28. package/dist/layer.d.ts.map +1 -0
  29. package/dist/layer.js +26 -0
  30. package/dist/layer.js.map +1 -0
  31. package/dist/metadata-error.d.ts +22 -0
  32. package/dist/metadata-error.d.ts.map +1 -0
  33. package/dist/metadata-error.js +19 -0
  34. package/dist/metadata-error.js.map +1 -0
  35. package/dist/token-error.d.ts +19 -0
  36. package/dist/token-error.d.ts.map +1 -0
  37. package/dist/token-error.js +16 -0
  38. package/dist/token-error.js.map +1 -0
  39. package/dist/token.d.ts +27 -0
  40. package/dist/token.d.ts.map +1 -0
  41. package/dist/token.js +53 -0
  42. package/dist/token.js.map +1 -0
  43. package/dist/transport.d.ts +26 -0
  44. package/dist/transport.d.ts.map +1 -0
  45. package/dist/transport.js +46 -0
  46. package/dist/transport.js.map +1 -0
  47. package/package.json +42 -4
  48. package/src/aws-imds.ts +118 -0
  49. package/src/config.ts +96 -0
  50. package/src/identity-document.ts +86 -0
  51. package/src/index.ts +66 -0
  52. package/src/instance-identity.ts +63 -0
  53. package/src/internal.ts +21 -0
  54. package/src/layer.ts +36 -0
  55. package/src/metadata-error.ts +21 -0
  56. package/src/token-error.ts +18 -0
  57. package/src/token.ts +114 -0
  58. package/src/transport.ts +101 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ryan Callahan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,159 @@
1
- # Temporary Holding Version
1
+ # @rc312/effect-aws-imds
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ An **Effect-native client for the AWS EC2 Instance Metadata Service** (IMDSv2). It has no runtime dependencies besides its `effect` peer.
4
+
5
+ ```sh
6
+ bun add @rc312/effect-aws-imds 'effect@^4.1.2'
7
+ ```
8
+
9
+ ## Usage
10
+
11
+ ```ts
12
+ import * as AwsImds from "@rc312/effect-aws-imds";
13
+ import { Effect } from "effect";
14
+
15
+ const program = Effect.gen(function* () {
16
+ // Yield the Effect to obtain the decoded, memoized document.
17
+ const document = yield* AwsImds.identityDocument;
18
+ // document.instanceType is already available without another request.
19
+ // This extra request demonstrates uncached reads with get(path).
20
+ const instanceType = yield* AwsImds.get("/latest/meta-data/instance-type");
21
+
22
+ return {
23
+ accountId: document.accountId,
24
+ region: document.region,
25
+ instanceType,
26
+ };
27
+ });
28
+
29
+ Effect.runPromise(program.pipe(Effect.provide(AwsImds.layerFetch)));
30
+ ```
31
+
32
+ `layerFetch` uses the platform `fetch`. Use `AwsImds.layer` instead to supply your own `HttpClient`, such as a Node or Bun platform client or a test double. Both are plain `Layer` values. Build one into your runtime (for example a single `ManagedRuntime` or one composed application layer) so the whole program shares one token cache and one identity document cache; each separate `Effect.provide` builds its own.
33
+
34
+ ## Composition
35
+
36
+ The package is a small graph of services, each with its own layer:
37
+
38
+ | Service | Provides | `layer` requires |
39
+ | --- | --- | --- |
40
+ | `AwsImdsConfig` | Settings (a `Context.Reference` with defaults) | — |
41
+ | `AwsImdsToken` | `get`, `invalidate(token)`, and `clear` for IMDSv2 session tokens | `HttpClient` |
42
+ | `AwsImds` | `get(path)`: uncached metadata reads with session auth | `HttpClient`, `AwsImdsToken` |
43
+ | `InstanceIdentity` | `document` (memoized) and `invalidate` | `AwsImds` |
44
+
45
+ The top-level `layer` (`AwsImds.layer` with a namespace import) composes the `AwsImdsToken`, `AwsImds`, and `InstanceIdentity` layers with `Layer.provideMerge`, so all three stay available to your program. Those layers read `AwsImdsConfig` while they are built. Each service also has its own `layer` static, such as `AwsImds.AwsImds.layer`, for building a different graph. Replace any one of them to change one concern:
46
+
47
+ ```ts
48
+ import * as AwsImds from "@rc312/effect-aws-imds";
49
+ import { Effect, Layer, Redacted } from "effect";
50
+
51
+ // A fixed session token, for example one issued elsewhere.
52
+ const StaticToken = Layer.succeed(
53
+ AwsImds.AwsImdsToken,
54
+ AwsImds.AwsImdsToken.of({
55
+ clear: Effect.void,
56
+ get: Effect.succeed(Redacted.make("token-issued-elsewhere")),
57
+ invalidate: () => Effect.void,
58
+ })
59
+ );
60
+
61
+ const Reads = AwsImds.AwsImds.layer.pipe(Layer.provide(StaticToken));
62
+ ```
63
+
64
+ ### Client combinators
65
+
66
+ The HTTP policy is exposed as two `HttpClient` combinators, so you can build your own client around them:
67
+
68
+ - `imdsTransport(settings)` applies the endpoint, buffers successful text bodies within the per-attempt timeout, treats non-2xx statuses as errors, and applies `retrySchedule`, including retries for interrupted body downloads.
69
+ - `withSessionToken(token)` resolves a session token from an `AwsImdsToken` before each request, outside that request's timeout and retries, and refreshes it once after a `401`. Apply it after `imdsTransport`.
70
+
71
+ ```ts
72
+ import * as AwsImds from "@rc312/effect-aws-imds";
73
+ import { Effect } from "effect";
74
+ import { HttpClient, HttpClientRequest } from "effect/http";
75
+
76
+ // An IMDS client that also tags every request with a trace id.
77
+ const tracedImdsClient = (traceId: string) =>
78
+ Effect.gen(function* () {
79
+ const settings = yield* AwsImds.AwsImdsConfig;
80
+ const token = yield* AwsImds.AwsImdsToken;
81
+
82
+ return (yield* HttpClient.HttpClient).pipe(
83
+ AwsImds.imdsTransport(settings),
84
+ HttpClient.mapRequest(HttpClientRequest.setHeader("x-trace", traceId)),
85
+ AwsImds.withSessionToken(token)
86
+ );
87
+ });
88
+ ```
89
+
90
+ Code that needs only the identity document can depend on `InstanceIdentity` and receive a fixed document from `Layer.succeed` in tests, with no HTTP at all.
91
+
92
+ ### Settings
93
+
94
+ Provide settings with `Layer.provide`. A settings layer merged beside the IMDS layers is not used to build them, so they silently keep the defaults.
95
+
96
+ ```ts
97
+ import * as AwsImds from "@rc312/effect-aws-imds";
98
+ import { Config, Layer } from "effect";
99
+
100
+ const ImdsLive = AwsImds.layerFetch.pipe(
101
+ Layer.provide(
102
+ AwsImds.AwsImdsConfig.layerConfig({
103
+ endpoint: Config.String("AWS_EC2_METADATA_SERVICE_ENDPOINT").pipe(
104
+ Config.withDefault("http://169.254.169.254")
105
+ ),
106
+ retrySchedule: Config.Int("IMDS_RETRIES").pipe(
107
+ Config.withDefault(2),
108
+ Config.map(AwsImds.retryPolicy)
109
+ ),
110
+ })
111
+ )
112
+ );
113
+ ```
114
+
115
+ | Setting | Default | Notes |
116
+ | --- | --- | --- |
117
+ | `endpoint` | `http://169.254.169.254` | Use `http://[fd00:ec2::254]` on IPv6-only instances. |
118
+ | `tokenTtl` | `6 hours` | Clamped to 1 second through 6 hours. |
119
+ | `attemptTimeout` | `1 second` | Applies to each HTTP attempt, including reading its response body. Token requests run before a read, outside its timeout. |
120
+ | `retrySchedule` | `retryPolicy(2)` | A bounded `Schedule` (for example with `Schedule.upTo`), applied to timeouts, transport errors, and transient statuses (408, 429, 500, 502, 503, 504). It is the only bound on retries: an unbounded schedule retries forever when IMDS is unreachable. |
121
+
122
+ `AwsImdsConfig.layer(options)` takes the same fields as plain values.
123
+
124
+ ## Reading metadata
125
+
126
+ | Export | Description |
127
+ | --- | --- |
128
+ | `get(path)` | The raw text at a path such as `/latest/meta-data/instance-id`. |
129
+ | `getSchema(path, codec)` | Reads `path` and decodes the text with `codec`, for example `Schema.fromJsonString(MySchema)`. Decode failures are `AwsImdsMetadataError`s for `path`. |
130
+ | `optional` | A combinator that maps a `404` to `Option.none()` and a success to `Option.some`, keeping every other failure: `get(path).pipe(AwsImds.optional)`. |
131
+ | `identityDocument` | The decoded instance identity document from `InstanceIdentity`. |
132
+ | `clearCache` | Discards the cached session token and identity document. |
133
+ | `retryPolicy(times)` | Jittered exponential backoff from 50 ms, bounded to `times` retries. Compose your own `Schedule` instead if you need a different policy. |
134
+ | `IdentityDocument` | Schema for the identity document. Unknown keys are ignored. |
135
+ | `AwsImdsTokenError` | Failure to obtain a session token, with a `message` and, for non-2xx responses, `status`. |
136
+ | `AwsImdsMetadataError` | Failure to read or decode a path, with `path`, a sanitized `message` and, for non-2xx responses, `status`. |
137
+
138
+ ## Behavior
139
+
140
+ - **IMDSv2 only.** Session tokens come from `PUT /latest/api/token`, are cached until 30 seconds before they expire (or half their TTL, if that is later), and are refreshed once when a read returns `401`. When several concurrent reads are rejected with the same token, only one replacement is requested.
141
+ - **Retries.** Retries use jittered exponential backoff starting at 50 ms and honor `Retry-After`.
142
+ - **Caching.** Only successful results are cached. A failed lookup is retried the next time it is requested.
143
+ - **Outside EC2.** Operations fail with `AwsImdsTokenError` or `AwsImdsMetadataError` instead of returning `undefined`; use `Effect.option` if the value is optional. With the defaults, an endpoint that accepts connections but never answers fails after about 3.2 seconds (three 1-second attempts plus backoff); a refused connection fails within a fraction of a second. Lower `attemptTimeout` or use `retryPolicy(0)` to fail faster.
144
+
145
+ - **Token handling.** The session token is held as a `Redacted` value. `x-aws-ec2-metadata-token` is added to `Headers.CurrentRedactedNames` for metadata requests, so client spans that capture request headers record it as `<redacted>`. Neither error type keeps the underlying HTTP request or its headers.
146
+
147
+ ## Example and end-to-end tests
148
+
149
+ [`examples/instance-info`](examples/instance-info) is a CLI that uses the built package against a strict mock IMDS. Its end-to-end tests run the CLI as a real process for the healthy, throttled, token-expiry, malformed-document, unresponsive, and unreachable cases. See its [README](examples/instance-info/README.md) to run it by hand.
150
+
151
+ ## Development
152
+
153
+ ```sh
154
+ bun run --cwd packages/effect-aws-imds build
155
+ bun run --cwd packages/effect-aws-imds typecheck
156
+ bun run --cwd packages/effect-aws-imds test
157
+ ```
158
+
159
+ Unit tests use an in-memory `HttpClient`, `TestClock`, and a loopback server; they never contact a real metadata endpoint. The example's end-to-end tests run with `bun run --cwd packages/effect-aws-imds/examples/instance-info test`, and both suites run in `bun run check`.
@@ -0,0 +1,58 @@
1
+ import { Context, Effect, Layer, Schema } from "effect";
2
+ import { HttpClient } from "effect/http";
3
+ import { AwsImdsMetadataError } from "./metadata-error.ts";
4
+ import { AwsImdsTokenError } from "./token-error.ts";
5
+ import { AwsImdsToken } from "./token.ts";
6
+ /**
7
+ * Any failure produced by the IMDS services.
8
+ *
9
+ * @since 0.1.0
10
+ */
11
+ type AwsImdsError = AwsImdsMetadataError | AwsImdsTokenError;
12
+ declare const AwsImds_base: Context.ServiceClass<AwsImds, "@rc312/effect-aws-imds/AwsImds", {
13
+ readonly get: (path: string) => Effect.Effect<string, AwsImdsError>;
14
+ }>;
15
+ /**
16
+ * Reads instance metadata through IMDSv2. Reads are not cached.
17
+ *
18
+ * `get(path)` returns the raw text at a path such as
19
+ * `/latest/meta-data/instance-id`.
20
+ *
21
+ * @since 0.1.0
22
+ */
23
+ declare class AwsImds extends AwsImds_base {
24
+ /** Reads through the `HttpClient` with tokens from `AwsImdsToken`. */
25
+ static readonly layer: Layer.Layer<AwsImds, never, AwsImdsToken | HttpClient.HttpClient>;
26
+ }
27
+ /** Decodes metadata text with `codec`, attributing failures to `path`. */
28
+ declare const decodeAt: <A, RD>(path: string, codec: Schema.Codec<A, string, RD>) => (text: string) => Effect.Effect<A, AwsImdsMetadataError, RD>;
29
+ /**
30
+ * Reads the raw text at a metadata path.
31
+ *
32
+ * @since 0.1.0
33
+ */
34
+ declare const get: (path: string) => Effect.Effect<string, AwsImdsError, AwsImds>;
35
+ /**
36
+ * Reads a metadata path and decodes its text with `codec`, for example
37
+ * `Schema.fromJsonString(MySchema)` for a JSON document.
38
+ *
39
+ * @since 0.1.0
40
+ */
41
+ declare const getSchema: <A, RD>(path: string, codec: Schema.Codec<A, string, RD>) => Effect.Effect<A, AwsImdsError, RD | AwsImds>;
42
+ /**
43
+ * Turns a `404` from IMDS into `Option.none()` and a success into
44
+ * `Option.some`. Every other failure is kept.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const action = AwsImds.get("/latest/meta-data/spot/instance-action").pipe(
49
+ * AwsImds.optional
50
+ * )
51
+ * ```
52
+ *
53
+ * @since 0.1.0
54
+ */
55
+ declare const optional: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<import("effect/Option").Option<never> | import("effect/Option").Option<A>, E, R>;
56
+ export { AwsImds, decodeAt, get, getSchema, optional };
57
+ export type { AwsImdsError };
58
+ //# sourceMappingURL=aws-imds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aws-imds.d.ts","sourceRoot":"","sources":["../src/aws-imds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAQ,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK1C;;;;GAIG;AACH,KAAK,YAAY,GAAG,oBAAoB,GAAG,iBAAiB,CAAC;;kBAoB3C,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;;AAXvE;;;;;;;GAOG;AACH,cAAM,OAAQ,SAAQ,YAKe;IACnC,sEAAsE;IACtE,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAChC,OAAO,EACP,KAAK,EACL,YAAY,GAAG,UAAU,CAAC,UAAU,CACrC,CAsBC;CACH;AAED,0EAA0E;AAC1E,QAAA,MAAM,QAAQ,GAAI,CAAC,EAAE,EAAE,QAAQ,MAAM,SAAS,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,iEAItE,CAAC;AAEJ;;;;GAIG;AACH,QAAA,MAAM,GAAG,SAAU,MAAM,iDAA0C,CAAC;AAEpE;;;;;GAKG;AACH,QAAA,MAAM,SAAS,GAAI,CAAC,EAAE,EAAE,QAAQ,MAAM,SAAS,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,iDACnB,CAAC;AAKxD;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,QAAQ,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,mGAIpD,CAAC;AAEJ,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AAEvD,YAAY,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { Context, Effect, flow, Layer, Schema } from "effect";
2
+ import { HttpClient } from "effect/http";
3
+ import { AwsImdsConfig } from "./config.js";
4
+ import { failureDetails } from "./internal.js";
5
+ import { AwsImdsMetadataError } from "./metadata-error.js";
6
+ import { AwsImdsTokenError } from "./token-error.js";
7
+ import { AwsImdsToken } from "./token.js";
8
+ import { imdsTransport, withSessionToken } from "./transport.js";
9
+ const NOT_FOUND = 404;
10
+ const metadataError = (path) => (cause) => new AwsImdsMetadataError({ ...failureDetails(cause), path });
11
+ // Token failures surface as themselves; everything else is about `path`.
12
+ const toImdsError = (path) => (cause) => cause instanceof AwsImdsTokenError ? cause : metadataError(path)(cause);
13
+ /**
14
+ * Reads instance metadata through IMDSv2. Reads are not cached.
15
+ *
16
+ * `get(path)` returns the raw text at a path such as
17
+ * `/latest/meta-data/instance-id`.
18
+ *
19
+ * @since 0.1.0
20
+ */
21
+ class AwsImds extends Context.Service()("@rc312/effect-aws-imds/AwsImds") {
22
+ /** Reads through the `HttpClient` with tokens from `AwsImdsToken`. */
23
+ static layer = Layer.effect(AwsImds, Effect.gen(function* make() {
24
+ const settings = yield* AwsImdsConfig;
25
+ const token = yield* AwsImdsToken;
26
+ const client = (yield* HttpClient.HttpClient).pipe(imdsTransport(settings), withSessionToken(token));
27
+ return AwsImds.of({
28
+ get: (path) => client.get(path).pipe(Effect.flatMap((response) => response.text), Effect.mapError(toImdsError(path)), Effect.withSpan("AwsImds.get", {
29
+ attributes: { "aws.imds.path": path },
30
+ })),
31
+ });
32
+ }));
33
+ }
34
+ /** Decodes metadata text with `codec`, attributing failures to `path`. */
35
+ const decodeAt = (path, codec) => flow((text) => Schema.decodeEffect(codec)(text), Effect.mapError(metadataError(path)));
36
+ /**
37
+ * Reads the raw text at a metadata path.
38
+ *
39
+ * @since 0.1.0
40
+ */
41
+ const get = (path) => AwsImds.use((imds) => imds.get(path));
42
+ /**
43
+ * Reads a metadata path and decodes its text with `codec`, for example
44
+ * `Schema.fromJsonString(MySchema)` for a JSON document.
45
+ *
46
+ * @since 0.1.0
47
+ */
48
+ const getSchema = (path, codec) => get(path).pipe(Effect.flatMap(decodeAt(path, codec)));
49
+ const isNotFound = (error) => error instanceof AwsImdsMetadataError && error.status === NOT_FOUND;
50
+ /**
51
+ * Turns a `404` from IMDS into `Option.none()` and a success into
52
+ * `Option.some`. Every other failure is kept.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const action = AwsImds.get("/latest/meta-data/spot/instance-action").pipe(
57
+ * AwsImds.optional
58
+ * )
59
+ * ```
60
+ *
61
+ * @since 0.1.0
62
+ */
63
+ const optional = (self) => self.pipe(Effect.asSome, Effect.catchIf(isNotFound, () => Effect.succeedNone));
64
+ export { AwsImds, decodeAt, get, getSchema, optional };
65
+ //# sourceMappingURL=aws-imds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aws-imds.js","sourceRoot":"","sources":["../src/aws-imds.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import { Config, Context, Duration, Layer, Schedule } from "effect";
2
+ /**
3
+ * The default retry policy: jittered exponential backoff from 50 ms, bounded
4
+ * to `times` retries after the first attempt.
5
+ *
6
+ * @since 0.1.0
7
+ */
8
+ declare const retryPolicy: (times: number) => Schedule.Schedule<Duration.Duration, unknown, never, never>;
9
+ /**
10
+ * Resolved settings read by every IMDS layer.
11
+ *
12
+ * @since 0.1.0
13
+ */
14
+ interface AwsImdsSettings {
15
+ /** Base URL of the metadata service. */
16
+ readonly endpoint: string;
17
+ /**
18
+ * Requested session token lifetime. The value sent to IMDS is rounded down
19
+ * to whole seconds and clamped to 1 second through 6 hours.
20
+ */
21
+ readonly tokenTtl: Duration.Duration;
22
+ /** Timeout for each individual HTTP attempt. */
23
+ readonly attemptTimeout: Duration.Duration;
24
+ /**
25
+ * Policy for retrying timeouts, transport errors, and transient statuses.
26
+ * It is the only bound on retries, so it must stop on its own, for example
27
+ * with `Schedule.upTo`.
28
+ */
29
+ readonly retrySchedule: Schedule.Schedule<unknown>;
30
+ }
31
+ /**
32
+ * Partial settings for `AwsImdsConfig.layer` and `AwsImdsConfig.layerConfig`.
33
+ * Omitted fields keep their defaults.
34
+ *
35
+ * @since 0.1.0
36
+ */
37
+ interface AwsImdsOptions {
38
+ /** Defaults to `http://169.254.169.254`; use `http://[fd00:ec2::254]` on IPv6-only instances. */
39
+ readonly endpoint?: string | undefined;
40
+ /** Defaults to 6 hours. */
41
+ readonly tokenTtl?: Duration.Input | undefined;
42
+ /** Defaults to 1 second. */
43
+ readonly attemptTimeout?: Duration.Input | undefined;
44
+ /** Defaults to `retryPolicy(2)`. Must be bounded, for example with `Schedule.upTo`. */
45
+ readonly retrySchedule?: Schedule.Schedule<unknown> | undefined;
46
+ }
47
+ declare const AwsImdsConfig_base: Context.Reference<AwsImdsSettings>;
48
+ /**
49
+ * Settings for the IMDS layers, with defaults when nothing provides them.
50
+ *
51
+ * Provide an override to the layers with `Layer.provide`; merging it beside
52
+ * them has no effect on how they are built.
53
+ *
54
+ * @since 0.1.0
55
+ */
56
+ declare class AwsImdsConfig extends AwsImdsConfig_base {
57
+ /** Overrides the given settings and keeps defaults for the rest. */
58
+ static readonly layer: (options: AwsImdsOptions) => Layer.Layer<never, never, never>;
59
+ /** Reads settings from `Config`, field by field or as one `Config`. */
60
+ static readonly layerConfig: (config: Config.Wrap<AwsImdsOptions>) => Layer.Layer<never, Config.ConfigError, never>;
61
+ }
62
+ export { AwsImdsConfig, retryPolicy };
63
+ export type { AwsImdsOptions, AwsImdsSettings };
64
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAU,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAI5E;;;;;GAKG;AACH,QAAA,MAAM,WAAW,UAAW,MAAM,gEAI/B,CAAC;AAEJ;;;;GAIG;AACH,UAAU,eAAe;IACvB,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACrC,gDAAgD;IAChD,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAAC;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;CACpD;AAED;;;;;GAKG;AACH,UAAU,cAAc;IACtB,iGAAiG;IACjG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC;IAC/C,4BAA4B;IAC5B,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC;IACrD,uFAAuF;IACvF,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;CACjE;;AAkBD;;;;;;;GAOG;AACH,cAAM,aAAc,SAAQ,kBAG3B;IACC,oEAAoE;IACpE,MAAM,CAAC,QAAQ,CAAC,KAAK,YAAa,cAAc,sCACI;IAEpD,uEAAuE;IACvE,MAAM,CAAC,QAAQ,CAAC,WAAW,WAAY,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,mDACQ;CAC3E;AAED,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC;AAEtC,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,37 @@
1
+ import { Config, Context, Duration, Effect, Layer, Schedule } from "effect";
2
+ const RETRY_BASE_DELAY = Duration.millis(50);
3
+ /**
4
+ * The default retry policy: jittered exponential backoff from 50 ms, bounded
5
+ * to `times` retries after the first attempt.
6
+ *
7
+ * @since 0.1.0
8
+ */
9
+ const retryPolicy = (times) => Schedule.exponential(RETRY_BASE_DELAY).pipe(Schedule.jittered, Schedule.upTo({ times }));
10
+ const defaults = {
11
+ attemptTimeout: Duration.seconds(1),
12
+ endpoint: "http://169.254.169.254",
13
+ retrySchedule: retryPolicy(2),
14
+ tokenTtl: Duration.hours(6),
15
+ };
16
+ const resolve = (options) => ({
17
+ attemptTimeout: Duration.fromInputUnsafe(options.attemptTimeout ?? defaults.attemptTimeout),
18
+ endpoint: options.endpoint ?? defaults.endpoint,
19
+ retrySchedule: options.retrySchedule ?? defaults.retrySchedule,
20
+ tokenTtl: Duration.fromInputUnsafe(options.tokenTtl ?? defaults.tokenTtl),
21
+ });
22
+ /**
23
+ * Settings for the IMDS layers, with defaults when nothing provides them.
24
+ *
25
+ * Provide an override to the layers with `Layer.provide`; merging it beside
26
+ * them has no effect on how they are built.
27
+ *
28
+ * @since 0.1.0
29
+ */
30
+ class AwsImdsConfig extends Context.Reference("@rc312/effect-aws-imds/AwsImdsConfig", { defaultValue: () => defaults }) {
31
+ /** Overrides the given settings and keeps defaults for the rest. */
32
+ static layer = (options) => Layer.sync(AwsImdsConfig, () => resolve(options));
33
+ /** Reads settings from `Config`, field by field or as one `Config`. */
34
+ static layerConfig = (config) => Layer.effect(AwsImdsConfig, Effect.map(Config.unwrap(config), resolve));
35
+ }
36
+ export { AwsImdsConfig, retryPolicy };
37
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE5E,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAE,CACpC,QAAQ,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC,IAAI,CACzC,QAAQ,CAAC,QAAQ,EACjB,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CACzB,CAAC;AA0CJ,MAAM,QAAQ,GAAoB;IAChC,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACnC,QAAQ,EAAE,wBAAwB;IAClC,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC;IAC7B,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;CAC5B,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,OAAuB,EAAmB,EAAE,CAAC,CAAC;IAC7D,cAAc,EAAE,QAAQ,CAAC,eAAe,CACtC,OAAO,CAAC,cAAc,IAAI,QAAQ,CAAC,cAAc,CAClD;IACD,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;IAC/C,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,QAAQ,CAAC,aAAa;IAC9D,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC;CAC1E,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,aAAc,SAAQ,OAAO,CAAC,SAAS,CAC3C,sCAAsC,EACtC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,CACjC;IACC,oEAAoE;IACpE,MAAM,CAAU,KAAK,GAAG,CAAC,OAAuB,EAAE,EAAE,CAClD,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpD,uEAAuE;IACvE,MAAM,CAAU,WAAW,GAAG,CAAC,MAAmC,EAAE,EAAE,CACpE,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;CAC3E;AAED,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { Schema } from "effect";
2
+ /**
3
+ * Schema for the EC2 instance identity document served at
4
+ * `/latest/dynamic/instance-identity/document`.
5
+ *
6
+ * Unknown keys are ignored so that fields AWS adds later do not break decoding.
7
+ *
8
+ * @since 0.1.0
9
+ */
10
+ export declare const IdentityDocument: Schema.Struct<{
11
+ readonly accountId: Schema.String;
12
+ readonly architecture: Schema.Literals<readonly ["i386", "x86_64", "arm64"]>;
13
+ readonly availabilityZone: Schema.NonEmptyString;
14
+ readonly billingProducts: Schema.withDecodingDefault<Schema.optional<Schema.NullOr<Schema.$Array<Schema.String>>>, never>;
15
+ readonly devpayProductCodes: Schema.withDecodingDefault<Schema.optional<Schema.NullOr<Schema.$Array<Schema.String>>>, never>;
16
+ readonly imageId: Schema.String;
17
+ readonly instanceId: Schema.String;
18
+ readonly instanceType: Schema.NonEmptyString;
19
+ readonly kernelId: Schema.withDecodingDefault<Schema.optional<Schema.NullOr<Schema.String>>, never>;
20
+ readonly marketplaceProductCodes: Schema.withDecodingDefault<Schema.optional<Schema.NullOr<Schema.$Array<Schema.String>>>, never>;
21
+ readonly pendingTime: Schema.DateFromString;
22
+ readonly privateIp: Schema.String;
23
+ readonly ramdiskId: Schema.withDecodingDefault<Schema.optional<Schema.NullOr<Schema.String>>, never>;
24
+ readonly region: Schema.String;
25
+ readonly version: Schema.String;
26
+ }>;
27
+ /**
28
+ * A decoded EC2 instance identity document.
29
+ *
30
+ * @since 0.1.0
31
+ */
32
+ export type IdentityDocument = typeof IdentityDocument.Type;
33
+ //# sourceMappingURL=identity-document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-document.d.ts","sourceRoot":"","sources":["../src/identity-document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAQxC;;;;;;;GAOG;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;EA6D3B,CAAC;AAEH;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAC,IAAI,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { Effect, Schema } from "effect";
2
+ const optionalNullable = (schema) => Schema.NullOr(schema).pipe(Schema.optional, Schema.withDecodingDefault(Effect.succeed(null)));
3
+ /**
4
+ * Schema for the EC2 instance identity document served at
5
+ * `/latest/dynamic/instance-identity/document`.
6
+ *
7
+ * Unknown keys are ignored so that fields AWS adds later do not break decoding.
8
+ *
9
+ * @since 0.1.0
10
+ */
11
+ // oxlint-disable-next-line no-redeclare -- The decoded type below intentionally shares the schema's name.
12
+ export const IdentityDocument = Schema.Struct({
13
+ accountId: Schema.String.check(Schema.isPattern(/^\d{12}$/u)).annotateKey({
14
+ description: "The ID of the AWS account that launched the instance.",
15
+ }),
16
+ architecture: Schema.Literals(["i386", "x86_64", "arm64"]).annotateKey({
17
+ description: "The architecture of the AMI used to launch the instance.",
18
+ }),
19
+ availabilityZone: Schema.NonEmptyString.annotateKey({
20
+ description: "The Availability Zone in which the instance is running.",
21
+ }),
22
+ billingProducts: optionalNullable(Schema.Array(Schema.String)).annotateKey({
23
+ description: "The billing products of the instance.",
24
+ }),
25
+ devpayProductCodes: optionalNullable(Schema.Array(Schema.String)).annotateKey({ description: "Deprecated AWS DevPay product codes of the AMI." }),
26
+ imageId: Schema.String.check(Schema.isPattern(/^ami-[0-9a-f]+$/iu)).annotateKey({
27
+ description: "The ID of the AMI used to launch the instance.",
28
+ }),
29
+ instanceId: Schema.String.check(Schema.isPattern(/^i-[0-9a-f]+$/iu)).annotateKey({ description: "The ID of the instance." }),
30
+ instanceType: Schema.NonEmptyString.annotateKey({
31
+ description: "The instance type of the instance.",
32
+ }),
33
+ kernelId: optionalNullable(Schema.String).annotateKey({
34
+ description: "The ID of the kernel associated with the instance.",
35
+ }),
36
+ marketplaceProductCodes: optionalNullable(Schema.Array(Schema.String)).annotateKey({
37
+ description: "The AWS Marketplace product codes of the AMI.",
38
+ }),
39
+ pendingTime: Schema.DateFromString.annotateKey({
40
+ description: "The date and time that the instance was launched.",
41
+ }),
42
+ privateIp: Schema.String.check(Schema.isNonEmpty(), Schema.isTrimmed()).annotateKey({
43
+ description: "The private IPv4 address, or IPv6 address on IPv6-only instances.",
44
+ }),
45
+ ramdiskId: optionalNullable(Schema.String).annotateKey({
46
+ description: "The ID of the RAM disk associated with the instance.",
47
+ }),
48
+ region: Schema.String.check(Schema.isPattern(/^[a-z]{2,}(?:-[a-z]+)+-\d+$/u)).annotateKey({
49
+ description: "The Region in which the instance is running.",
50
+ }),
51
+ version: Schema.String.check(Schema.isPattern(/^\d{4}-\d{2}-\d{2}$/u)).annotateKey({
52
+ description: "The version of the identity document format.",
53
+ }),
54
+ }).annotate({
55
+ identifier: "IdentityDocument",
56
+ title: "EC2 Instance Identity Document",
57
+ });
58
+ //# sourceMappingURL=identity-document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-document.js","sourceRoot":"","sources":["../src/identity-document.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Effect-native client for the AWS EC2 Instance Metadata Service (IMDS).
3
+ *
4
+ * The client speaks IMDSv2 only. Session tokens are fetched with `PUT
5
+ * /latest/api/token`, cached for slightly less than their TTL, and refreshed
6
+ * once when IMDS answers `401`. Every attempt has its own timeout, and transient
7
+ * failures are retried with jittered exponential backoff.
8
+ *
9
+ * The instance identity document is decoded against `IdentityDocument` and
10
+ * memoized after the first success. Failures are never cached, so a caller can
11
+ * try again later.
12
+ *
13
+ * Outside EC2 (local development, or a container beyond the IMDS hop limit)
14
+ * operations fail with a typed `AwsImdsError` rather than returning `undefined`.
15
+ * Apply `Effect.option` at the call site when the value is genuinely optional.
16
+ * With the defaults, an endpoint that never answers fails after about 3.2
17
+ * seconds (three 1 second attempts plus backoff); a refused connection fails
18
+ * within a fraction of a second.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { Effect } from "effect"
23
+ * import * as AwsImds from "@rc312/effect-aws-imds"
24
+ *
25
+ * const program = Effect.gen(function* () {
26
+ * // Yield the Effect to obtain the decoded, memoized document.
27
+ * const document = yield* AwsImds.identityDocument
28
+ * // document.instanceType is already available without another request.
29
+ * // This extra request demonstrates uncached reads with get(path).
30
+ * const instanceType = yield* AwsImds.get("/latest/meta-data/instance-type")
31
+ * return { region: document.region, instanceType }
32
+ * })
33
+ *
34
+ * const runnable = program.pipe(Effect.provide(AwsImds.layerFetch))
35
+ * ```
36
+ *
37
+ * @since 0.1.0
38
+ */
39
+ export { AwsImds, type AwsImdsError, get, getSchema, optional, } from "./aws-imds.ts";
40
+ export { AwsImdsConfig, type AwsImdsOptions, type AwsImdsSettings, retryPolicy, } from "./config.ts";
41
+ export { IdentityDocument } from "./identity-document.ts";
42
+ export { identityDocument, InstanceIdentity } from "./instance-identity.ts";
43
+ export { clearCache, layer, layerFetch } from "./layer.ts";
44
+ export { AwsImdsToken } from "./token.ts";
45
+ export { imdsTransport, withSessionToken } from "./transport.ts";
46
+ export { AwsImdsMetadataError } from "./metadata-error.ts";
47
+ export { AwsImdsTokenError } from "./token-error.ts";
48
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EACL,OAAO,EACP,KAAK,YAAY,EACjB,GAAG,EACH,SAAS,EACT,QAAQ,GACT,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Effect-native client for the AWS EC2 Instance Metadata Service (IMDS).
3
+ *
4
+ * The client speaks IMDSv2 only. Session tokens are fetched with `PUT
5
+ * /latest/api/token`, cached for slightly less than their TTL, and refreshed
6
+ * once when IMDS answers `401`. Every attempt has its own timeout, and transient
7
+ * failures are retried with jittered exponential backoff.
8
+ *
9
+ * The instance identity document is decoded against `IdentityDocument` and
10
+ * memoized after the first success. Failures are never cached, so a caller can
11
+ * try again later.
12
+ *
13
+ * Outside EC2 (local development, or a container beyond the IMDS hop limit)
14
+ * operations fail with a typed `AwsImdsError` rather than returning `undefined`.
15
+ * Apply `Effect.option` at the call site when the value is genuinely optional.
16
+ * With the defaults, an endpoint that never answers fails after about 3.2
17
+ * seconds (three 1 second attempts plus backoff); a refused connection fails
18
+ * within a fraction of a second.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { Effect } from "effect"
23
+ * import * as AwsImds from "@rc312/effect-aws-imds"
24
+ *
25
+ * const program = Effect.gen(function* () {
26
+ * // Yield the Effect to obtain the decoded, memoized document.
27
+ * const document = yield* AwsImds.identityDocument
28
+ * // document.instanceType is already available without another request.
29
+ * // This extra request demonstrates uncached reads with get(path).
30
+ * const instanceType = yield* AwsImds.get("/latest/meta-data/instance-type")
31
+ * return { region: document.region, instanceType }
32
+ * })
33
+ *
34
+ * const runnable = program.pipe(Effect.provide(AwsImds.layerFetch))
35
+ * ```
36
+ *
37
+ * @since 0.1.0
38
+ */
39
+ export { AwsImds, get, getSchema, optional, } from "./aws-imds.js";
40
+ export { AwsImdsConfig, retryPolicy, } from "./config.js";
41
+ export { IdentityDocument } from "./identity-document.js";
42
+ export { identityDocument, InstanceIdentity } from "./instance-identity.js";
43
+ export { clearCache, layer, layerFetch } from "./layer.js";
44
+ export { AwsImdsToken } from "./token.js";
45
+ export { imdsTransport, withSessionToken } from "./transport.js";
46
+ export { AwsImdsMetadataError } from "./metadata-error.js";
47
+ export { AwsImdsTokenError } from "./token-error.js";
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EACL,OAAO,EAEP,GAAG,EACH,SAAS,EACT,QAAQ,GACT,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,aAAa,EAGb,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}