@distilled.cloud/aws 0.20.1 → 0.21.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.
- package/lib/auth.browser.d.ts +70 -0
- package/lib/auth.browser.d.ts.map +1 -0
- package/lib/auth.browser.js +8 -0
- package/lib/auth.browser.js.map +1 -0
- package/lib/auth.d.ts +9 -70
- package/lib/auth.d.ts.map +1 -1
- package/lib/auth.js +2 -3
- package/lib/auth.js.map +1 -1
- package/lib/client/api.d.ts.map +1 -1
- package/lib/client/api.js +3 -1
- package/lib/client/api.js.map +1 -1
- package/lib/credentials.browser.d.ts +140 -0
- package/lib/credentials.browser.d.ts.map +1 -0
- package/lib/credentials.browser.js +134 -0
- package/lib/credentials.browser.js.map +1 -0
- package/lib/credentials.d.ts +9 -135
- package/lib/credentials.d.ts.map +1 -1
- package/lib/credentials.js +10 -139
- package/lib/credentials.js.map +1 -1
- package/lib/index.browser.d.ts +50 -0
- package/lib/index.browser.d.ts.map +1 -0
- package/lib/index.browser.js +50 -0
- package/lib/index.browser.js.map +1 -0
- package/package.json +10 -7
- package/src/auth.browser.ts +88 -0
- package/src/auth.ts +8 -78
- package/src/client/api.ts +3 -1
- package/src/credentials.browser.ts +267 -0
- package/src/credentials.ts +18 -274
- package/src/index.browser.ts +56 -0
package/src/credentials.ts
CHANGED
|
@@ -1,298 +1,40 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fromContainerMetadata as _fromContainerMetadata,
|
|
3
3
|
fromEnv as _fromEnv,
|
|
4
|
-
fromHttp as _fromHttp,
|
|
5
4
|
fromIni as _fromIni,
|
|
6
5
|
fromNodeProviderChain as _fromNodeProviderChain,
|
|
7
6
|
fromProcess as _fromProcess,
|
|
8
7
|
fromTokenFile as _fromTokenFile,
|
|
9
8
|
} from "@aws-sdk/credential-providers";
|
|
9
|
+
import * as BrowserCredentials from "./credentials.browser.ts";
|
|
10
|
+
export * from "./credentials.browser.ts";
|
|
10
11
|
|
|
11
|
-
import {
|
|
12
|
-
type AwsCredentialIdentity,
|
|
13
|
-
type AwsCredentialIdentityProvider,
|
|
14
|
-
} from "@smithy/types";
|
|
15
|
-
import * as Data from "effect/Data";
|
|
16
12
|
import * as Effect from "effect/Effect";
|
|
17
13
|
import * as Layer from "effect/Layer";
|
|
18
|
-
import type { PlatformError } from "effect/PlatformError";
|
|
19
|
-
import * as Redacted from "effect/Redacted";
|
|
20
|
-
import * as Context from "effect/Context";
|
|
21
|
-
import type { HttpClientError } from "effect/unstable/http/HttpClientError";
|
|
22
14
|
import { Auth } from "./auth.ts";
|
|
23
|
-
export * as AWSTypes from "@aws-sdk/types";
|
|
24
|
-
|
|
25
|
-
export interface AwsCredentials {
|
|
26
|
-
readonly accessKeyId: string;
|
|
27
|
-
readonly secretAccessKey: string;
|
|
28
|
-
readonly sessionToken?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Resolved credential values ready for request signing.
|
|
33
|
-
*/
|
|
34
|
-
export interface ResolvedCredentials {
|
|
35
|
-
readonly accessKeyId: Redacted.Redacted<string>;
|
|
36
|
-
readonly secretAccessKey: Redacted.Redacted<string>;
|
|
37
|
-
readonly sessionToken: Redacted.Redacted<string> | undefined;
|
|
38
|
-
readonly expiration?: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* The requirements for resolving credentials (HttpClient for SSO, FileSystem for cache).
|
|
43
|
-
*/
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Error types that can occur during credential resolution.
|
|
47
|
-
*/
|
|
48
|
-
export type CredentialsError =
|
|
49
|
-
| AwsCredentialProviderError
|
|
50
|
-
| ProfileNotFound
|
|
51
|
-
| InvalidSSOProfile
|
|
52
|
-
| InvalidSSOToken
|
|
53
|
-
| ExpiredSSOToken
|
|
54
|
-
| ConflictingSSORegion
|
|
55
|
-
| ConflictingSSOStartUrl
|
|
56
|
-
| SsoPortalError
|
|
57
|
-
| HttpClientError
|
|
58
|
-
| PlatformError;
|
|
59
|
-
|
|
60
|
-
export class Credentials extends Context.Service<
|
|
61
|
-
Credentials,
|
|
62
|
-
Effect.Effect<ResolvedCredentials, CredentialsError>
|
|
63
|
-
>()("AWS::Credentials") {}
|
|
64
|
-
|
|
65
|
-
export const mock = Layer.succeed(
|
|
66
|
-
Credentials,
|
|
67
|
-
Effect.succeed({
|
|
68
|
-
accessKeyId: Redacted.make("test"),
|
|
69
|
-
secretAccessKey: Redacted.make("test"),
|
|
70
|
-
sessionToken: Redacted.make("test"),
|
|
71
|
-
}),
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Create resolved credentials from an AWS credential identity.
|
|
76
|
-
*/
|
|
77
|
-
export const fromAwsCredentialIdentity = (
|
|
78
|
-
identity: AwsCredentialIdentity,
|
|
79
|
-
): ResolvedCredentials => ({
|
|
80
|
-
accessKeyId: Redacted.make(identity.accessKeyId),
|
|
81
|
-
secretAccessKey: Redacted.make(identity.secretAccessKey),
|
|
82
|
-
sessionToken: identity.sessionToken
|
|
83
|
-
? Redacted.make(identity.sessionToken)
|
|
84
|
-
: undefined,
|
|
85
|
-
expiration: identity.expiration?.getTime(),
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
type ProviderName =
|
|
89
|
-
| "env"
|
|
90
|
-
| "ini"
|
|
91
|
-
| "chain"
|
|
92
|
-
| "container"
|
|
93
|
-
| "http"
|
|
94
|
-
| "process"
|
|
95
|
-
| "token-file";
|
|
96
|
-
|
|
97
|
-
const providerHints = (
|
|
98
|
-
provider: ProviderName,
|
|
99
|
-
): ReadonlyArray<string> | undefined => {
|
|
100
|
-
switch (provider) {
|
|
101
|
-
case "env":
|
|
102
|
-
return [
|
|
103
|
-
"Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (and AWS_SESSION_TOKEN if needed).",
|
|
104
|
-
];
|
|
105
|
-
case "ini":
|
|
106
|
-
return ["Check ~/.aws/credentials and ~/.aws/config for the profile."];
|
|
107
|
-
case "chain":
|
|
108
|
-
return [
|
|
109
|
-
"Configure at least one credential source for the default chain.",
|
|
110
|
-
"If using SSO, run `aws sso login` for the profile.",
|
|
111
|
-
];
|
|
112
|
-
case "container":
|
|
113
|
-
return ["Ensure a container credential endpoint is available."];
|
|
114
|
-
case "http":
|
|
115
|
-
return ["Ensure the configured credential endpoint is reachable."];
|
|
116
|
-
case "process":
|
|
117
|
-
return [
|
|
118
|
-
"Set AWS_CREDENTIAL_PROCESS to a valid command and ensure it exits successfully.",
|
|
119
|
-
];
|
|
120
|
-
case "token-file":
|
|
121
|
-
return [
|
|
122
|
-
"Set AWS_WEB_IDENTITY_TOKEN_FILE and ensure the file is readable.",
|
|
123
|
-
];
|
|
124
|
-
default:
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
export const _providerHints = providerHints;
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Time window (5 mins) to refresh credentials before they actually expire.
|
|
133
|
-
* This prevents using credentials that are about to expire.
|
|
134
|
-
*/
|
|
135
|
-
const CREDENTIAL_REFRESH_WINDOW_MS = 5 * 60 * 1000;
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Create a credentials effect with lazy resolution and expiration-aware caching.
|
|
139
|
-
* Uses Effect.cachedWithTTL where the TTL is computed from the credentials' expiration.
|
|
140
|
-
*/
|
|
141
|
-
const createCachedCredentialsEffect = <E, R>(
|
|
142
|
-
resolve: Effect.Effect<ResolvedCredentials, E, R>,
|
|
143
|
-
): Effect.Effect<ResolvedCredentials, E, R> => {
|
|
144
|
-
let cachedCreds: ResolvedCredentials | undefined;
|
|
145
|
-
let expiresAt: number | undefined;
|
|
146
|
-
|
|
147
|
-
return Effect.suspend(() => {
|
|
148
|
-
const now = Date.now();
|
|
149
|
-
if (cachedCreds && expiresAt && now < expiresAt) {
|
|
150
|
-
return Effect.succeed(cachedCreds);
|
|
151
|
-
}
|
|
152
|
-
return Effect.map(resolve, (creds) => {
|
|
153
|
-
cachedCreds = creds;
|
|
154
|
-
expiresAt = creds.expiration
|
|
155
|
-
? creds.expiration - CREDENTIAL_REFRESH_WINDOW_MS
|
|
156
|
-
: undefined;
|
|
157
|
-
return creds;
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Create a lazy, cached credentials provider from an AWS SDK credential provider.
|
|
164
|
-
* Credentials are resolved on first access and cached based on their expiration time.
|
|
165
|
-
*/
|
|
166
|
-
const createLazyProvider = (
|
|
167
|
-
provider: (config: {}) => AwsCredentialIdentityProvider,
|
|
168
|
-
providerName: ProviderName,
|
|
169
|
-
): Layer.Layer<Credentials> => {
|
|
170
|
-
const resolve = Effect.gen(function* () {
|
|
171
|
-
const hints = providerHints(providerName);
|
|
172
|
-
const identity = yield* Effect.tryPromise({
|
|
173
|
-
try: () => provider({})(),
|
|
174
|
-
catch: (cause) =>
|
|
175
|
-
new AwsCredentialProviderError({
|
|
176
|
-
message: `Failed to resolve credentials from ${providerName}.`,
|
|
177
|
-
provider: providerName,
|
|
178
|
-
cause,
|
|
179
|
-
hints,
|
|
180
|
-
}),
|
|
181
|
-
});
|
|
182
|
-
return fromAwsCredentialIdentity(identity);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
return Layer.succeed(Credentials, createCachedCredentialsEffect(resolve));
|
|
186
|
-
};
|
|
187
15
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
* No lazy loading or caching needed since credentials are already available.
|
|
191
|
-
*/
|
|
192
|
-
export const fromCredentials = (
|
|
193
|
-
credentials: AwsCredentialIdentity,
|
|
194
|
-
): Layer.Layer<Credentials> =>
|
|
195
|
-
Layer.succeed(
|
|
196
|
-
Credentials,
|
|
197
|
-
Effect.succeed(fromAwsCredentialIdentity(credentials)),
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
export const fromEnv = () => createLazyProvider(_fromEnv, "env");
|
|
16
|
+
export const fromEnv = () =>
|
|
17
|
+
BrowserCredentials.createLazyProvider(_fromEnv, "env");
|
|
201
18
|
|
|
202
19
|
export const fromChain = () =>
|
|
203
|
-
createLazyProvider(
|
|
20
|
+
BrowserCredentials.createLazyProvider(
|
|
21
|
+
() => _fromNodeProviderChain(),
|
|
22
|
+
"chain",
|
|
23
|
+
);
|
|
204
24
|
|
|
205
25
|
// export const fromSSO = () => createLazyProvider(_fromSSO);
|
|
206
26
|
|
|
207
|
-
export const fromIni = () =>
|
|
27
|
+
export const fromIni = () =>
|
|
28
|
+
BrowserCredentials.createLazyProvider(_fromIni, "ini");
|
|
208
29
|
|
|
209
30
|
export const fromContainerMetadata = () =>
|
|
210
|
-
createLazyProvider(_fromContainerMetadata, "container");
|
|
211
|
-
|
|
212
|
-
export const fromHttp = () => createLazyProvider(_fromHttp, "http");
|
|
31
|
+
BrowserCredentials.createLazyProvider(_fromContainerMetadata, "container");
|
|
213
32
|
|
|
214
|
-
export const fromProcess = () =>
|
|
33
|
+
export const fromProcess = () =>
|
|
34
|
+
BrowserCredentials.createLazyProvider(_fromProcess, "process");
|
|
215
35
|
|
|
216
36
|
export const fromTokenFile = () =>
|
|
217
|
-
createLazyProvider(_fromTokenFile, "token-file");
|
|
218
|
-
|
|
219
|
-
export const ssoRegion = (region: string) => Layer.succeed(SsoRegion, region);
|
|
220
|
-
|
|
221
|
-
export class SsoRegion extends Context.Service<SsoRegion, string>()(
|
|
222
|
-
"AWS::SsoRegion",
|
|
223
|
-
) {}
|
|
224
|
-
export class SsoStartUrl extends Context.Service<SsoStartUrl, string>()(
|
|
225
|
-
"AWS::SsoStartUrl",
|
|
226
|
-
) {}
|
|
227
|
-
|
|
228
|
-
export class ProfileNotFound extends Data.TaggedError(
|
|
229
|
-
"Alchemy::AWS::ProfileNotFound",
|
|
230
|
-
)<{
|
|
231
|
-
message: string;
|
|
232
|
-
profile: string;
|
|
233
|
-
}> {}
|
|
234
|
-
|
|
235
|
-
export class ConflictingSSORegion extends Data.TaggedError(
|
|
236
|
-
"Alchemy::AWS::ConflictingSSORegion",
|
|
237
|
-
)<{
|
|
238
|
-
message: string;
|
|
239
|
-
ssoRegion: string;
|
|
240
|
-
profile: string;
|
|
241
|
-
}> {}
|
|
242
|
-
|
|
243
|
-
export class ConflictingSSOStartUrl extends Data.TaggedError(
|
|
244
|
-
"Alchemy::AWS::ConflictingSSOStartUrl",
|
|
245
|
-
)<{
|
|
246
|
-
message: string;
|
|
247
|
-
ssoStartUrl: string;
|
|
248
|
-
profile: string;
|
|
249
|
-
}> {}
|
|
250
|
-
|
|
251
|
-
export class InvalidSSOProfile extends Data.TaggedError(
|
|
252
|
-
"Alchemy::AWS::InvalidSSOProfile",
|
|
253
|
-
)<{
|
|
254
|
-
message: string;
|
|
255
|
-
profile: string;
|
|
256
|
-
missingFields: string[];
|
|
257
|
-
}> {}
|
|
258
|
-
|
|
259
|
-
export class InvalidSSOToken extends Data.TaggedError(
|
|
260
|
-
"Alchemy::AWS::InvalidSSOToken",
|
|
261
|
-
)<{
|
|
262
|
-
message: string;
|
|
263
|
-
sso_session: string;
|
|
264
|
-
}> {}
|
|
265
|
-
|
|
266
|
-
export class ExpiredSSOToken extends Data.TaggedError(
|
|
267
|
-
"Alchemy::AWS::ExpiredSSOToken",
|
|
268
|
-
)<{
|
|
269
|
-
message: string;
|
|
270
|
-
profile: string;
|
|
271
|
-
}> {}
|
|
272
|
-
|
|
273
|
-
export class AwsCredentialProviderError extends Data.TaggedError(
|
|
274
|
-
"AWS::CredentialProviderError",
|
|
275
|
-
)<{
|
|
276
|
-
message: string;
|
|
277
|
-
provider: string;
|
|
278
|
-
cause?: unknown;
|
|
279
|
-
hints?: ReadonlyArray<string>;
|
|
280
|
-
}> {}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* The AWS SSO portal returned a response with no `roleCredentials`, e.g. a
|
|
284
|
-
* `ForbiddenException` when an IAM Identity Center role assignment is in a
|
|
285
|
-
* stale state.
|
|
286
|
-
*/
|
|
287
|
-
export class SsoPortalError extends Data.TaggedError(
|
|
288
|
-
"Alchemy::AWS::SsoPortalError",
|
|
289
|
-
)<{
|
|
290
|
-
message: string;
|
|
291
|
-
profile: string;
|
|
292
|
-
account_id?: string;
|
|
293
|
-
role_name?: string;
|
|
294
|
-
status?: number;
|
|
295
|
-
}> {}
|
|
37
|
+
BrowserCredentials.createLazyProvider(_fromTokenFile, "token-file");
|
|
296
38
|
|
|
297
39
|
/**
|
|
298
40
|
* Create a lazy, cached SSO credentials provider.
|
|
@@ -301,10 +43,12 @@ export class SsoPortalError extends Data.TaggedError(
|
|
|
301
43
|
*/
|
|
302
44
|
export const fromSSO = (profileName: string = "default") =>
|
|
303
45
|
Layer.effect(
|
|
304
|
-
Credentials,
|
|
46
|
+
BrowserCredentials.Credentials,
|
|
305
47
|
Auth.use((auth) =>
|
|
306
48
|
Effect.succeed(
|
|
307
|
-
createCachedCredentialsEffect(
|
|
49
|
+
BrowserCredentials.createCachedCredentialsEffect(
|
|
50
|
+
auth.loadProfileCredentials(profileName),
|
|
51
|
+
),
|
|
308
52
|
),
|
|
309
53
|
),
|
|
310
54
|
);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Authentication service for loading AWS profiles and credentials.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
export * as Auth from "./auth.browser.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* AWS Credentials providers for obtaining temporary or long-lived credentials.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.0.0
|
|
12
|
+
*/
|
|
13
|
+
export * as Credentials from "./credentials.browser.ts";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* AWS Endpoint configuration for custom or local endpoints.
|
|
17
|
+
*
|
|
18
|
+
* @since 0.0.0
|
|
19
|
+
*/
|
|
20
|
+
export * as Endpoint from "./endpoint.ts";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Common AWS error types shared across all services.
|
|
24
|
+
*
|
|
25
|
+
* @since 0.0.0
|
|
26
|
+
*/
|
|
27
|
+
export * as Errors from "./errors.ts";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* AWS Region configuration.
|
|
31
|
+
*
|
|
32
|
+
* @since 0.0.0
|
|
33
|
+
*/
|
|
34
|
+
export * as Region from "./region.ts";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Retry policy configuration for AWS API calls.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.0.0
|
|
40
|
+
*/
|
|
41
|
+
export * as Retry from "./retry.ts";
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Sensitive data schemas for the smithy.api#sensitive trait.
|
|
45
|
+
* Wraps values in Effect's Redacted type to prevent accidental logging.
|
|
46
|
+
*
|
|
47
|
+
* @since 0.0.0
|
|
48
|
+
*/
|
|
49
|
+
export * as Sensitive from "./sensitive.ts";
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Smithy trait annotations for AWS service schemas.
|
|
53
|
+
*
|
|
54
|
+
* @since 0.0.0
|
|
55
|
+
*/
|
|
56
|
+
export * as Traits from "./traits.ts";
|