alchemy 0.22.4 → 0.24.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/aws/bucket.d.ts.map +1 -1
- package/lib/aws/bucket.js +13 -12
- package/lib/aws/bucket.js.map +1 -1
- package/lib/aws/control/client.d.ts.map +1 -1
- package/lib/aws/control/client.js +5 -3
- package/lib/aws/control/client.js.map +1 -1
- package/lib/aws/control/properties.d.ts +11 -2
- package/lib/aws/control/properties.d.ts.map +1 -1
- package/lib/aws/control/properties.js +96 -19
- package/lib/aws/control/properties.js.map +1 -1
- package/lib/aws/control/resource.d.ts.map +1 -1
- package/lib/aws/control/resource.js +13 -4
- package/lib/aws/control/resource.js.map +1 -1
- package/lib/aws/control/types.d.ts +81069 -0
- package/lib/aws/control/types.d.ts.map +1 -0
- package/lib/aws/control/types.js +4 -0
- package/lib/aws/control/types.js.map +1 -0
- package/lib/aws/function.d.ts.map +1 -1
- package/lib/aws/function.js +51 -42
- package/lib/aws/function.js.map +1 -1
- package/lib/aws/index.d.ts +1 -0
- package/lib/aws/index.d.ts.map +1 -1
- package/lib/aws/index.js +1 -0
- package/lib/aws/index.js.map +1 -1
- package/lib/aws/policy-attachment.d.ts.map +1 -1
- package/lib/aws/policy-attachment.js +5 -4
- package/lib/aws/policy-attachment.js.map +1 -1
- package/lib/aws/policy.d.ts.map +1 -1
- package/lib/aws/policy.js +21 -20
- package/lib/aws/policy.js.map +1 -1
- package/lib/aws/queue.d.ts.map +1 -1
- package/lib/aws/queue.js +19 -15
- package/lib/aws/queue.js.map +1 -1
- package/lib/aws/retry.d.ts +5 -0
- package/lib/aws/retry.d.ts.map +1 -0
- package/lib/aws/retry.js +27 -0
- package/lib/aws/retry.js.map +1 -0
- package/lib/aws/role.d.ts.map +1 -1
- package/lib/aws/role.js +31 -30
- package/lib/aws/role.js.map +1 -1
- package/lib/aws/ses.d.ts.map +1 -1
- package/lib/aws/ses.js +27 -26
- package/lib/aws/ses.js.map +1 -1
- package/lib/aws/ssm-parameter.d.ts +150 -0
- package/lib/aws/ssm-parameter.d.ts.map +1 -0
- package/lib/aws/ssm-parameter.js +184 -0
- package/lib/aws/ssm-parameter.js.map +1 -0
- package/lib/aws/table.d.ts.map +1 -1
- package/lib/aws/table.js +9 -27
- package/lib/aws/table.js.map +1 -1
- package/lib/cloudflare/account-id.d.ts +1 -0
- package/lib/cloudflare/account-id.d.ts.map +1 -1
- package/lib/cloudflare/account-id.js.map +1 -1
- package/lib/cloudflare/api.d.ts.map +1 -1
- package/lib/cloudflare/api.js +22 -2
- package/lib/cloudflare/api.js.map +1 -1
- package/lib/cloudflare/bound.d.ts +1 -1
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/index.d.ts +2 -1
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +2 -1
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/queue-consumer.d.ts +7 -1
- package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
- package/lib/cloudflare/queue-consumer.js +14 -0
- package/lib/cloudflare/queue-consumer.js.map +1 -1
- package/lib/cloudflare/queue.d.ts +27 -0
- package/lib/cloudflare/queue.d.ts.map +1 -1
- package/lib/cloudflare/queue.js +23 -0
- package/lib/cloudflare/queue.js.map +1 -1
- package/lib/cloudflare/route.d.ts +7 -0
- package/lib/cloudflare/route.d.ts.map +1 -1
- package/lib/cloudflare/route.js +44 -2
- package/lib/cloudflare/route.js.map +1 -1
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +1 -2
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +2 -1
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +20 -9
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/workflow.d.ts +7 -0
- package/lib/cloudflare/workflow.d.ts.map +1 -1
- package/lib/cloudflare/workflow.js +2 -0
- package/lib/cloudflare/workflow.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +1 -0
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +1 -0
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/destroy.js +1 -1
- package/lib/destroy.js.map +1 -1
- package/lib/dns/godaddy.d.ts.map +1 -1
- package/lib/dns/godaddy.js +2 -1
- package/lib/dns/godaddy.js.map +1 -1
- package/lib/fs/file-system-state-store.d.ts.map +1 -1
- package/lib/fs/file-system-state-store.js +14 -2
- package/lib/fs/file-system-state-store.js.map +1 -1
- package/lib/github/secret.d.ts.map +1 -1
- package/lib/github/secret.js +1 -0
- package/lib/github/secret.js.map +1 -1
- package/lib/neon/api.d.ts.map +1 -1
- package/lib/neon/api.js +2 -1
- package/lib/neon/api.js.map +1 -1
- package/lib/runtime/shims.d.ts +6 -0
- package/lib/runtime/shims.d.ts.map +1 -0
- package/lib/runtime/shims.js +27 -0
- package/lib/runtime/shims.js.map +1 -0
- package/lib/sentry/api.d.ts.map +1 -1
- package/lib/sentry/api.js +2 -1
- package/lib/sentry/api.js.map +1 -1
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js +1 -7
- package/lib/test/bun.js.map +1 -1
- package/lib/test/prune.d.ts +2 -1
- package/lib/test/prune.d.ts.map +1 -1
- package/lib/test/prune.js +29 -5
- package/lib/test/prune.js.map +1 -1
- package/lib/test/vitest.d.ts +92 -0
- package/lib/test/vitest.d.ts.map +1 -0
- package/lib/test/vitest.js +94 -0
- package/lib/test/vitest.js.map +1 -0
- package/lib/upstash/api.d.ts.map +1 -1
- package/lib/upstash/api.js +2 -1
- package/lib/upstash/api.js.map +1 -1
- package/lib/util/retry.js +2 -2
- package/lib/util/retry.js.map +1 -1
- package/lib/util/safe-fetch.d.ts +2 -0
- package/lib/util/safe-fetch.d.ts.map +1 -0
- package/lib/util/safe-fetch.js +49 -0
- package/lib/util/safe-fetch.js.map +1 -0
- package/lib/vercel/api.d.ts.map +1 -1
- package/lib/vercel/api.js +2 -1
- package/lib/vercel/api.js.map +1 -1
- package/lib/web/vitepress/process-front-matter-files.d.ts.map +1 -1
- package/lib/web/vitepress/process-front-matter-files.js +11 -7
- package/lib/web/vitepress/process-front-matter-files.js.map +1 -1
- package/package.json +10 -6
- package/src/alchemy.ts +2 -2
- package/src/aws/bucket.ts +55 -36
- package/src/aws/control/client.ts +13 -13
- package/src/aws/control/properties.ts +96 -19
- package/src/aws/control/resource.ts +19 -3
- package/src/aws/control/types.ts +87235 -0
- package/src/aws/function.ts +233 -178
- package/src/aws/index.ts +1 -0
- package/src/aws/policy-attachment.ts +15 -10
- package/src/aws/policy.ts +75 -54
- package/src/aws/queue.ts +53 -36
- package/src/aws/retry.ts +38 -0
- package/src/aws/role.ts +121 -90
- package/src/aws/ses.ts +101 -73
- package/src/aws/ssm-parameter.ts +315 -0
- package/src/aws/table.ts +61 -90
- package/src/cloudflare/account-id.ts +2 -0
- package/src/cloudflare/api.ts +26 -3
- package/src/cloudflare/bound.ts +1 -1
- package/src/cloudflare/index.ts +2 -1
- package/src/cloudflare/queue-consumer.ts +27 -1
- package/src/cloudflare/queue.ts +29 -0
- package/src/cloudflare/route.ts +86 -2
- package/src/cloudflare/worker-metadata.ts +1 -2
- package/src/cloudflare/worker.ts +24 -10
- package/src/cloudflare/workflow.ts +8 -0
- package/src/cloudflare/wrangler.json.ts +8 -1
- package/src/destroy.ts +1 -1
- package/src/dns/godaddy.ts +3 -1
- package/src/fs/file-system-state-store.ts +16 -2
- package/src/github/secret.ts +2 -0
- package/src/neon/api.ts +2 -1
- package/src/sentry/api.ts +2 -1
- package/src/test/bun.ts +1 -7
- package/src/test/prune.ts +31 -4
- package/src/test/vitest.ts +209 -0
- package/src/upstash/api.ts +2 -1
- package/src/util/retry.ts +3 -3
- package/src/util/safe-fetch.ts +62 -0
- package/src/vercel/api.ts +2 -1
- package/src/web/vitepress/process-front-matter-files.ts +15 -7
- package/src/aws/control/types.d.ts +0 -85129
package/src/aws/function.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type { Context } from "../context.ts";
|
|
|
19
19
|
import type { Bundle } from "../esbuild/bundle.ts";
|
|
20
20
|
import { Resource } from "../resource.ts";
|
|
21
21
|
import { ignore } from "../util/ignore.ts";
|
|
22
|
+
import { retry } from "./retry.ts";
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Properties for creating or updating a Lambda function
|
|
@@ -317,10 +318,12 @@ export const Function = Resource(
|
|
|
317
318
|
// Delete function URL if it exists
|
|
318
319
|
if (this.output?.url) {
|
|
319
320
|
try {
|
|
320
|
-
await
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
321
|
+
await retry(() =>
|
|
322
|
+
client.send(
|
|
323
|
+
new DeleteFunctionUrlConfigCommand({
|
|
324
|
+
FunctionName: props.functionName,
|
|
325
|
+
}),
|
|
326
|
+
),
|
|
324
327
|
);
|
|
325
328
|
} catch (error: any) {
|
|
326
329
|
if (error.name !== "ResourceNotFoundException") {
|
|
@@ -330,10 +333,12 @@ export const Function = Resource(
|
|
|
330
333
|
}
|
|
331
334
|
|
|
332
335
|
await ignore(ResourceNotFoundException.name, () =>
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
336
|
+
retry(() =>
|
|
337
|
+
client.send(
|
|
338
|
+
new DeleteFunctionCommand({
|
|
339
|
+
FunctionName: props.functionName,
|
|
340
|
+
}),
|
|
341
|
+
),
|
|
337
342
|
),
|
|
338
343
|
);
|
|
339
344
|
|
|
@@ -342,10 +347,12 @@ export const Function = Resource(
|
|
|
342
347
|
let functionUrl: string | undefined;
|
|
343
348
|
try {
|
|
344
349
|
// Check if function exists
|
|
345
|
-
await
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
350
|
+
await retry(() =>
|
|
351
|
+
client.send(
|
|
352
|
+
new GetFunctionCommand({
|
|
353
|
+
FunctionName: props.functionName,
|
|
354
|
+
}),
|
|
355
|
+
),
|
|
349
356
|
);
|
|
350
357
|
|
|
351
358
|
if (this.phase === "update") {
|
|
@@ -353,31 +360,35 @@ export const Function = Resource(
|
|
|
353
360
|
await waitForFunctionStabilization(client, props.functionName);
|
|
354
361
|
|
|
355
362
|
// Update function code
|
|
356
|
-
await
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
363
|
+
await retry(() =>
|
|
364
|
+
client.send(
|
|
365
|
+
new UpdateFunctionCodeCommand({
|
|
366
|
+
FunctionName: props.functionName,
|
|
367
|
+
ZipFile: code,
|
|
368
|
+
}),
|
|
369
|
+
),
|
|
361
370
|
);
|
|
362
371
|
|
|
363
372
|
// Wait for code update to stabilize
|
|
364
373
|
await waitForFunctionStabilization(client, props.functionName);
|
|
365
374
|
|
|
366
375
|
// Update function configuration
|
|
367
|
-
await
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
376
|
+
await retry(() =>
|
|
377
|
+
client.send(
|
|
378
|
+
new UpdateFunctionConfigurationCommand({
|
|
379
|
+
FunctionName: props.functionName,
|
|
380
|
+
Handler: props.handler,
|
|
381
|
+
Runtime: props.runtime,
|
|
382
|
+
Role: props.roleArn,
|
|
383
|
+
Description: props.description,
|
|
384
|
+
Timeout: props.timeout,
|
|
385
|
+
MemorySize: props.memorySize,
|
|
386
|
+
Environment: props.environment
|
|
387
|
+
? { Variables: props.environment }
|
|
388
|
+
: undefined,
|
|
389
|
+
Layers: props.layers,
|
|
390
|
+
}),
|
|
391
|
+
),
|
|
381
392
|
);
|
|
382
393
|
|
|
383
394
|
// Wait for configuration update to stabilize
|
|
@@ -387,44 +398,50 @@ export const Function = Resource(
|
|
|
387
398
|
if (props.url) {
|
|
388
399
|
try {
|
|
389
400
|
// Check if URL config exists already
|
|
390
|
-
const urlConfig = await
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
401
|
+
const urlConfig = await retry(() =>
|
|
402
|
+
client.send(
|
|
403
|
+
new GetFunctionUrlConfigCommand({
|
|
404
|
+
FunctionName: props.functionName,
|
|
405
|
+
}),
|
|
406
|
+
),
|
|
394
407
|
);
|
|
395
408
|
|
|
396
409
|
// Update URL configuration if it exists
|
|
397
410
|
if (urlConfig) {
|
|
398
|
-
const updateResult = await
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
411
|
+
const updateResult = await retry(() =>
|
|
412
|
+
client.send(
|
|
413
|
+
new UpdateFunctionUrlConfigCommand({
|
|
414
|
+
FunctionName: props.functionName,
|
|
415
|
+
AuthType: props.url!.authType || "NONE",
|
|
416
|
+
InvokeMode: props.url!.invokeMode || "BUFFERED",
|
|
417
|
+
Cors: props.url!.cors
|
|
418
|
+
? {
|
|
419
|
+
AllowCredentials: props.url!.cors.allowCredentials,
|
|
420
|
+
AllowHeaders: props.url!.cors.allowHeaders,
|
|
421
|
+
AllowMethods: props.url!.cors.allowMethods,
|
|
422
|
+
AllowOrigins: props.url!.cors.allowOrigins,
|
|
423
|
+
ExposeHeaders: props.url!.cors.exposeHeaders,
|
|
424
|
+
MaxAge: props.url!.cors.maxAge,
|
|
425
|
+
}
|
|
426
|
+
: undefined,
|
|
427
|
+
}),
|
|
428
|
+
),
|
|
414
429
|
);
|
|
415
430
|
functionUrl = updateResult.FunctionUrl;
|
|
416
431
|
|
|
417
432
|
// Add public access permission for function URL
|
|
418
|
-
if (props.url
|
|
433
|
+
if (props.url!.authType === "NONE") {
|
|
419
434
|
try {
|
|
420
|
-
await
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
435
|
+
await retry(() =>
|
|
436
|
+
client.send(
|
|
437
|
+
new AddPermissionCommand({
|
|
438
|
+
FunctionName: props.functionName,
|
|
439
|
+
StatementId: "FunctionURLAllowPublicAccess",
|
|
440
|
+
Action: "lambda:InvokeFunctionUrl",
|
|
441
|
+
Principal: "*",
|
|
442
|
+
FunctionUrlAuthType: "NONE",
|
|
443
|
+
}),
|
|
444
|
+
),
|
|
428
445
|
);
|
|
429
446
|
} catch (permError: any) {
|
|
430
447
|
if (!permError.message?.includes("already exists")) {
|
|
@@ -434,36 +451,40 @@ export const Function = Resource(
|
|
|
434
451
|
}
|
|
435
452
|
} else {
|
|
436
453
|
// Create URL configuration if it doesn't exist
|
|
437
|
-
const createResult = await
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
454
|
+
const createResult = await retry(() =>
|
|
455
|
+
client.send(
|
|
456
|
+
new CreateFunctionUrlConfigCommand({
|
|
457
|
+
FunctionName: props.functionName,
|
|
458
|
+
AuthType: props.url!.authType || "NONE",
|
|
459
|
+
InvokeMode: props.url!.invokeMode || "BUFFERED",
|
|
460
|
+
Cors: props.url!.cors
|
|
461
|
+
? {
|
|
462
|
+
AllowCredentials: props.url!.cors.allowCredentials,
|
|
463
|
+
AllowHeaders: props.url!.cors.allowHeaders,
|
|
464
|
+
AllowMethods: props.url!.cors.allowMethods,
|
|
465
|
+
AllowOrigins: props.url!.cors.allowOrigins,
|
|
466
|
+
ExposeHeaders: props.url!.cors.exposeHeaders,
|
|
467
|
+
MaxAge: props.url!.cors.maxAge,
|
|
468
|
+
}
|
|
469
|
+
: undefined,
|
|
470
|
+
}),
|
|
471
|
+
),
|
|
453
472
|
);
|
|
454
473
|
functionUrl = createResult.FunctionUrl;
|
|
455
474
|
|
|
456
475
|
// Add public access permission for function URL
|
|
457
|
-
if (props.url
|
|
476
|
+
if (props.url!.authType === "NONE") {
|
|
458
477
|
try {
|
|
459
|
-
await
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
478
|
+
await retry(() =>
|
|
479
|
+
client.send(
|
|
480
|
+
new AddPermissionCommand({
|
|
481
|
+
FunctionName: props.functionName,
|
|
482
|
+
StatementId: "FunctionURLAllowPublicAccess",
|
|
483
|
+
Action: "lambda:InvokeFunctionUrl",
|
|
484
|
+
Principal: "*",
|
|
485
|
+
FunctionUrlAuthType: "NONE",
|
|
486
|
+
}),
|
|
487
|
+
),
|
|
467
488
|
);
|
|
468
489
|
} catch (permError: any) {
|
|
469
490
|
if (!permError.message?.includes("already exists")) {
|
|
@@ -475,36 +496,40 @@ export const Function = Resource(
|
|
|
475
496
|
} catch (error: any) {
|
|
476
497
|
if (error.name === "ResourceNotFoundException") {
|
|
477
498
|
// Create URL configuration if it doesn't exist
|
|
478
|
-
const createResult = await
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
499
|
+
const createResult = await retry(() =>
|
|
500
|
+
client.send(
|
|
501
|
+
new CreateFunctionUrlConfigCommand({
|
|
502
|
+
FunctionName: props.functionName,
|
|
503
|
+
AuthType: props.url!.authType || "NONE",
|
|
504
|
+
InvokeMode: props.url!.invokeMode || "BUFFERED",
|
|
505
|
+
Cors: props.url!.cors
|
|
506
|
+
? {
|
|
507
|
+
AllowCredentials: props.url!.cors.allowCredentials,
|
|
508
|
+
AllowHeaders: props.url!.cors.allowHeaders,
|
|
509
|
+
AllowMethods: props.url!.cors.allowMethods,
|
|
510
|
+
AllowOrigins: props.url!.cors.allowOrigins,
|
|
511
|
+
ExposeHeaders: props.url!.cors.exposeHeaders,
|
|
512
|
+
MaxAge: props.url!.cors.maxAge,
|
|
513
|
+
}
|
|
514
|
+
: undefined,
|
|
515
|
+
}),
|
|
516
|
+
),
|
|
494
517
|
);
|
|
495
518
|
functionUrl = createResult.FunctionUrl;
|
|
496
519
|
|
|
497
520
|
// Add public access permission for function URL
|
|
498
|
-
if (props.url
|
|
521
|
+
if (props.url!.authType === "NONE") {
|
|
499
522
|
try {
|
|
500
|
-
await
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
523
|
+
await retry(() =>
|
|
524
|
+
client.send(
|
|
525
|
+
new AddPermissionCommand({
|
|
526
|
+
FunctionName: props.functionName,
|
|
527
|
+
StatementId: "FunctionURLAllowPublicAccess",
|
|
528
|
+
Action: "lambda:InvokeFunctionUrl",
|
|
529
|
+
Principal: "*",
|
|
530
|
+
FunctionUrlAuthType: "NONE",
|
|
531
|
+
}),
|
|
532
|
+
),
|
|
508
533
|
);
|
|
509
534
|
} catch (permError: any) {
|
|
510
535
|
if (!permError.message?.includes("already exists")) {
|
|
@@ -519,10 +544,12 @@ export const Function = Resource(
|
|
|
519
544
|
} else if (this.output?.url) {
|
|
520
545
|
// Remove URL config if it was previously set but not in current props
|
|
521
546
|
try {
|
|
522
|
-
await
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
547
|
+
await retry(() =>
|
|
548
|
+
client.send(
|
|
549
|
+
new DeleteFunctionUrlConfigCommand({
|
|
550
|
+
FunctionName: props.functionName,
|
|
551
|
+
}),
|
|
552
|
+
),
|
|
526
553
|
);
|
|
527
554
|
functionUrl = undefined;
|
|
528
555
|
} catch (error: any) {
|
|
@@ -540,25 +567,27 @@ export const Function = Resource(
|
|
|
540
567
|
|
|
541
568
|
while (true) {
|
|
542
569
|
try {
|
|
543
|
-
await
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
570
|
+
await retry(() =>
|
|
571
|
+
client.send(
|
|
572
|
+
new CreateFunctionCommand({
|
|
573
|
+
FunctionName: props.functionName,
|
|
574
|
+
Code: { ZipFile: code },
|
|
575
|
+
Handler: props.handler || "index.handler",
|
|
576
|
+
Runtime: props.runtime || Runtime.nodejs20x,
|
|
577
|
+
Role: props.roleArn,
|
|
578
|
+
Description: props.description,
|
|
579
|
+
Timeout: props.timeout || 3,
|
|
580
|
+
MemorySize: props.memorySize || 128,
|
|
581
|
+
Environment: props.environment
|
|
582
|
+
? { Variables: props.environment }
|
|
583
|
+
: undefined,
|
|
584
|
+
Architectures: props.architecture
|
|
585
|
+
? [props.architecture]
|
|
586
|
+
: [Architecture.x86_64],
|
|
587
|
+
Tags: props.tags,
|
|
588
|
+
Layers: props.layers,
|
|
589
|
+
}),
|
|
590
|
+
),
|
|
562
591
|
);
|
|
563
592
|
break; // Success - exit retry loop
|
|
564
593
|
} catch (createError: any) {
|
|
@@ -583,10 +612,12 @@ export const Function = Resource(
|
|
|
583
612
|
// Wait for function to be active
|
|
584
613
|
let isCreating = true;
|
|
585
614
|
while (isCreating) {
|
|
586
|
-
const config = await
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
615
|
+
const config = await retry(() =>
|
|
616
|
+
client.send(
|
|
617
|
+
new GetFunctionConfigurationCommand({
|
|
618
|
+
FunctionName: props.functionName,
|
|
619
|
+
}),
|
|
620
|
+
),
|
|
590
621
|
);
|
|
591
622
|
isCreating = config.State === "Pending";
|
|
592
623
|
if (isCreating) {
|
|
@@ -594,39 +625,50 @@ export const Function = Resource(
|
|
|
594
625
|
}
|
|
595
626
|
}
|
|
596
627
|
|
|
628
|
+
// Additional stabilization check - ensure role can be used
|
|
629
|
+
// by waiting a bit more after function becomes Active
|
|
630
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
631
|
+
|
|
632
|
+
// Verify function is fully stable and role is usable
|
|
633
|
+
await waitForFunctionStabilization(client, props.functionName);
|
|
634
|
+
|
|
597
635
|
// Create URL configuration if needed
|
|
598
636
|
if (props.url) {
|
|
599
637
|
try {
|
|
600
|
-
const createResult = await
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
638
|
+
const createResult = await retry(() =>
|
|
639
|
+
client.send(
|
|
640
|
+
new CreateFunctionUrlConfigCommand({
|
|
641
|
+
FunctionName: props.functionName,
|
|
642
|
+
AuthType: props.url!.authType || "NONE",
|
|
643
|
+
InvokeMode: props.url!.invokeMode || "BUFFERED",
|
|
644
|
+
Cors: props.url!.cors
|
|
645
|
+
? {
|
|
646
|
+
AllowCredentials: props.url!.cors.allowCredentials,
|
|
647
|
+
AllowHeaders: props.url!.cors.allowHeaders,
|
|
648
|
+
AllowMethods: props.url!.cors.allowMethods,
|
|
649
|
+
AllowOrigins: props.url!.cors.allowOrigins,
|
|
650
|
+
ExposeHeaders: props.url!.cors.exposeHeaders,
|
|
651
|
+
MaxAge: props.url!.cors.maxAge,
|
|
652
|
+
}
|
|
653
|
+
: undefined,
|
|
654
|
+
}),
|
|
655
|
+
),
|
|
616
656
|
);
|
|
617
657
|
functionUrl = createResult.FunctionUrl;
|
|
618
658
|
|
|
619
659
|
// Add public access permission for function URL
|
|
620
|
-
if (props.url
|
|
660
|
+
if (props.url!.authType === "NONE") {
|
|
621
661
|
try {
|
|
622
|
-
await
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
662
|
+
await retry(() =>
|
|
663
|
+
client.send(
|
|
664
|
+
new AddPermissionCommand({
|
|
665
|
+
FunctionName: props.functionName,
|
|
666
|
+
StatementId: "FunctionURLAllowPublicAccess",
|
|
667
|
+
Action: "lambda:InvokeFunctionUrl",
|
|
668
|
+
Principal: "*",
|
|
669
|
+
FunctionUrlAuthType: "NONE",
|
|
670
|
+
}),
|
|
671
|
+
),
|
|
630
672
|
);
|
|
631
673
|
} catch (permError: any) {
|
|
632
674
|
if (!permError.message?.includes("already exists")) {
|
|
@@ -645,25 +687,31 @@ export const Function = Resource(
|
|
|
645
687
|
|
|
646
688
|
// Get complete function details
|
|
647
689
|
const [_func, config] = await Promise.all([
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
690
|
+
retry(() =>
|
|
691
|
+
client.send(
|
|
692
|
+
new GetFunctionCommand({
|
|
693
|
+
FunctionName: props.functionName,
|
|
694
|
+
}),
|
|
695
|
+
),
|
|
652
696
|
),
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
697
|
+
retry(() =>
|
|
698
|
+
client.send(
|
|
699
|
+
new GetFunctionConfigurationCommand({
|
|
700
|
+
FunctionName: props.functionName,
|
|
701
|
+
}),
|
|
702
|
+
),
|
|
657
703
|
),
|
|
658
704
|
]);
|
|
659
705
|
|
|
660
706
|
// Try to get function URL if it wasn't already retrieved and URL is configured
|
|
661
707
|
if (!functionUrl && (props.url || this.output?.url)) {
|
|
662
708
|
try {
|
|
663
|
-
const urlConfig = await
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
709
|
+
const urlConfig = await retry(() =>
|
|
710
|
+
client.send(
|
|
711
|
+
new GetFunctionUrlConfigCommand({
|
|
712
|
+
FunctionName: props.functionName,
|
|
713
|
+
}),
|
|
714
|
+
),
|
|
667
715
|
);
|
|
668
716
|
functionUrl = urlConfig.FunctionUrl;
|
|
669
717
|
} catch (error: any) {
|
|
@@ -706,10 +754,12 @@ async function waitForFunctionStabilization(
|
|
|
706
754
|
functionName: string,
|
|
707
755
|
) {
|
|
708
756
|
while (true) {
|
|
709
|
-
const config = await
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
757
|
+
const config = await retry(() =>
|
|
758
|
+
client.send(
|
|
759
|
+
new GetFunctionConfigurationCommand({
|
|
760
|
+
FunctionName: functionName,
|
|
761
|
+
}),
|
|
762
|
+
),
|
|
713
763
|
);
|
|
714
764
|
|
|
715
765
|
// Check if function is in a stable state
|
|
@@ -745,9 +795,14 @@ async function zipCode(props: FunctionProps): Promise<Buffer> {
|
|
|
745
795
|
parseFile(props.handler) +
|
|
746
796
|
(props.bundle.format === "cjs" ? ".cjs" : ".mjs");
|
|
747
797
|
|
|
798
|
+
if (!fileContent || fileContent.length === 0) {
|
|
799
|
+
throw new Error("Bundle content is empty");
|
|
800
|
+
}
|
|
801
|
+
|
|
748
802
|
// Create a zip buffer in memory
|
|
749
803
|
const zip = new (await import("jszip")).default();
|
|
750
804
|
zip.file(fileName, fileContent);
|
|
805
|
+
|
|
751
806
|
return zip.generateAsync({
|
|
752
807
|
type: "nodebuffer",
|
|
753
808
|
compression: "DEFLATE",
|
package/src/aws/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import type { Context } from "../context.ts";
|
|
8
8
|
import { Resource } from "../resource.ts";
|
|
9
9
|
import { ignore } from "../util/ignore.ts";
|
|
10
|
+
import { retry } from "./retry.ts";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Properties for creating or updating a policy attachment
|
|
@@ -72,20 +73,24 @@ export const PolicyAttachment = Resource(
|
|
|
72
73
|
|
|
73
74
|
if (this.phase === "delete") {
|
|
74
75
|
await ignore(NoSuchEntityException.name, () =>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
retry(() =>
|
|
77
|
+
client.send(
|
|
78
|
+
new DetachRolePolicyCommand({
|
|
79
|
+
PolicyArn: props.policyArn,
|
|
80
|
+
RoleName: props.roleName,
|
|
81
|
+
}),
|
|
82
|
+
),
|
|
80
83
|
),
|
|
81
84
|
);
|
|
82
85
|
return this.destroy();
|
|
83
86
|
}
|
|
84
|
-
await
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
await retry(() =>
|
|
88
|
+
client.send(
|
|
89
|
+
new AttachRolePolicyCommand({
|
|
90
|
+
PolicyArn: props.policyArn,
|
|
91
|
+
RoleName: props.roleName,
|
|
92
|
+
}),
|
|
93
|
+
),
|
|
89
94
|
);
|
|
90
95
|
|
|
91
96
|
return this(props);
|