sst 2.1.31 → 2.1.33

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/sst.mjs CHANGED
@@ -1620,8 +1620,6 @@ function useAWSClient(client, force = false) {
1620
1620
  credentials,
1621
1621
  retryStrategy: new StandardRetryStrategy(async () => 1e4, {
1622
1622
  retryDecider: (err) => {
1623
- if (err.$fault === "client")
1624
- return false;
1625
1623
  if (err.name === "CredentialsProviderError")
1626
1624
  return false;
1627
1625
  if (err.message === "Could not load credentials from any providers")
@@ -2605,743 +2603,306 @@ var init_workers = __esm({
2605
2603
  }
2606
2604
  });
2607
2605
 
2608
- // src/iot.ts
2609
- var iot_exports = {};
2610
- __export(iot_exports, {
2611
- useIOT: () => useIOT,
2612
- useIOTEndpoint: () => useIOTEndpoint
2613
- });
2614
- import { IoTClient, DescribeEndpointCommand } from "@aws-sdk/client-iot";
2615
- import iot from "aws-iot-device-sdk";
2616
- function encode(input) {
2617
- const json = JSON.stringify(input);
2618
- const parts = json.match(/.{1,100000}/g);
2619
- if (!parts)
2620
- return [];
2621
- const id = Math.random().toString();
2622
- return parts.map((part, index) => ({
2623
- id,
2624
- index,
2625
- count: parts?.length,
2626
- data: part
2627
- }));
2606
+ // src/stacks/app-metadata.ts
2607
+ import {
2608
+ S3Client,
2609
+ GetObjectCommand,
2610
+ PutObjectCommand,
2611
+ DeleteObjectCommand
2612
+ } from "@aws-sdk/client-s3";
2613
+ async function metadata() {
2614
+ Logger.debug("Fetching app metadata");
2615
+ const [project, credentials, bootstrap] = await Promise.all([
2616
+ useProject(),
2617
+ useAWSCredentials(),
2618
+ useBootstrap()
2619
+ ]);
2620
+ const s3 = new S3Client({
2621
+ region: project.config.region,
2622
+ credentials
2623
+ });
2624
+ try {
2625
+ const result = await s3.send(
2626
+ new GetObjectCommand({
2627
+ Key: useS3Key(),
2628
+ Bucket: bootstrap.bucket
2629
+ })
2630
+ );
2631
+ const body = await result.Body.transformToString();
2632
+ return JSON.parse(body);
2633
+ } catch (ex) {
2634
+ Logger.debug("Fetching app metadata: not found");
2635
+ }
2628
2636
  }
2629
- var useIOTEndpoint, useIOT;
2630
- var init_iot = __esm({
2631
- "src/iot.ts"() {
2637
+ async function saveAppMetadata(data2) {
2638
+ Logger.debug("Saving app metadata");
2639
+ const [project, credentials, bootstrap] = await Promise.all([
2640
+ useProject(),
2641
+ useAWSCredentials(),
2642
+ useBootstrap()
2643
+ ]);
2644
+ const s3 = new S3Client({
2645
+ region: project.config.region,
2646
+ credentials
2647
+ });
2648
+ try {
2649
+ await s3.send(
2650
+ new PutObjectCommand({
2651
+ Key: useS3Key(),
2652
+ Bucket: bootstrap.bucket,
2653
+ Body: JSON.stringify(data2)
2654
+ })
2655
+ );
2656
+ } catch (ex) {
2657
+ Logger.debug("Saving app metadata: not found");
2658
+ }
2659
+ }
2660
+ async function clearAppMetadata() {
2661
+ Logger.debug("Clearing app metadata");
2662
+ const [project, credentials, bootstrap] = await Promise.all([
2663
+ useProject(),
2664
+ useAWSCredentials(),
2665
+ useBootstrap()
2666
+ ]);
2667
+ const s3 = new S3Client({
2668
+ region: project.config.region,
2669
+ credentials
2670
+ });
2671
+ await s3.send(
2672
+ new DeleteObjectCommand({
2673
+ Key: useS3Key(),
2674
+ Bucket: bootstrap.bucket
2675
+ })
2676
+ );
2677
+ }
2678
+ function useS3Key() {
2679
+ const project = useProject();
2680
+ return `appMetadata/app.${project.config.name}/stage.${project.config.stage}.json`;
2681
+ }
2682
+ var MetadataContext, useAppMetadata;
2683
+ var init_app_metadata = __esm({
2684
+ "src/stacks/app-metadata.ts"() {
2632
2685
  "use strict";
2633
- init_context();
2686
+ init_bootstrap();
2634
2687
  init_credentials();
2635
- init_error();
2636
- init_bus();
2637
- init_project();
2688
+ init_context();
2638
2689
  init_logger();
2639
- useIOTEndpoint = Context.memo(async () => {
2640
- const iot2 = useAWSClient(IoTClient);
2641
- Logger.debug("Getting IoT endpoint");
2642
- const response = await iot2.send(
2643
- new DescribeEndpointCommand({
2644
- endpointType: "iot:Data-ATS"
2645
- })
2646
- );
2647
- Logger.debug("Using IoT endpoint:", response.endpointAddress);
2648
- if (!response.endpointAddress)
2649
- throw new VisibleError("IoT Endpoint address not found");
2650
- return response.endpointAddress;
2651
- });
2652
- useIOT = Context.memo(async () => {
2653
- const bus = useBus();
2654
- const endpoint = await useIOTEndpoint();
2655
- const creds = await useAWSCredentials();
2656
- const project = useProject();
2657
- const device = new iot.device({
2658
- protocol: "wss",
2659
- host: endpoint,
2660
- region: project.config.region,
2661
- accessKeyId: creds.accessKeyId,
2662
- secretKey: creds.secretAccessKey,
2663
- sessionToken: creds.sessionToken,
2664
- reconnectPeriod: 1
2665
- });
2666
- const PREFIX2 = `/sst/${project.config.name}/${project.config.stage}`;
2667
- device.subscribe(`${PREFIX2}/events`, { qos: 1 });
2668
- const fragments = /* @__PURE__ */ new Map();
2669
- device.on("connect", () => {
2670
- Logger.debug("IoT connected");
2671
- });
2672
- device.on("error", (err) => {
2673
- Logger.debug("IoT error", err);
2674
- });
2675
- device.on("close", () => {
2676
- Logger.debug("IoT closed");
2677
- });
2678
- device.on("reconnect", () => {
2679
- Logger.debug("IoT reconnected");
2680
- });
2681
- device.on("message", (_topic, buffer) => {
2682
- const fragment = JSON.parse(buffer.toString());
2683
- if (!fragment.id) {
2684
- bus.publish(fragment.type, fragment.properties);
2685
- return;
2686
- }
2687
- let pending = fragments.get(fragment.id);
2688
- if (!pending) {
2689
- pending = /* @__PURE__ */ new Map();
2690
- fragments.set(fragment.id, pending);
2691
- }
2692
- pending.set(fragment.index, fragment);
2693
- if (pending.size === fragment.count) {
2694
- const data2 = [...pending.values()].sort((a, b) => a.index - b.index).map((item) => item.data).join("");
2695
- fragments.delete(fragment.id);
2696
- const evt = JSON.parse(data2);
2697
- if (evt.sourceID === bus.sourceID)
2698
- return;
2699
- bus.publish(evt.type, evt.properties);
2700
- }
2701
- });
2702
- return {
2703
- prefix: PREFIX2,
2704
- async publish(topic, type, properties) {
2705
- const payload = {
2706
- type,
2707
- properties,
2708
- sourceID: bus.sourceID
2709
- };
2710
- for (const fragment of encode(payload)) {
2711
- await new Promise((r) => {
2712
- device.publish(
2713
- topic,
2714
- JSON.stringify(fragment),
2715
- {
2716
- qos: 1
2717
- },
2718
- () => {
2719
- r();
2720
- }
2721
- );
2722
- });
2723
- }
2724
- Logger.debug("IOT Published", topic, type);
2725
- }
2726
- };
2690
+ init_project();
2691
+ MetadataContext = Context.create(async () => {
2692
+ const data2 = await metadata();
2693
+ return data2;
2727
2694
  });
2695
+ useAppMetadata = MetadataContext.use;
2728
2696
  }
2729
2697
  });
2730
2698
 
2731
- // src/runtime/iot.ts
2732
- var iot_exports2 = {};
2733
- __export(iot_exports2, {
2734
- useIOTBridge: () => useIOTBridge
2735
- });
2736
- var useIOTBridge;
2737
- var init_iot2 = __esm({
2738
- "src/runtime/iot.ts"() {
2699
+ // src/stacks/assembly.ts
2700
+ async function loadAssembly(from) {
2701
+ const { CloudAssembly } = await import("aws-cdk-lib/cx-api");
2702
+ return new CloudAssembly(from);
2703
+ }
2704
+ var init_assembly = __esm({
2705
+ "src/stacks/assembly.ts"() {
2739
2706
  "use strict";
2740
- init_context();
2741
- init_bus();
2742
- init_iot();
2743
- useIOTBridge = Context.memo(async () => {
2744
- const bus = useBus();
2745
- const iot2 = await useIOT();
2746
- const topic = `${iot2.prefix}/events`;
2747
- bus.subscribe("function.success", async (evt) => {
2748
- iot2.publish(
2749
- topic + "/" + evt.properties.workerID,
2750
- "function.success",
2751
- evt.properties
2752
- );
2753
- });
2754
- bus.subscribe("function.error", async (evt) => {
2755
- iot2.publish(
2756
- topic + "/" + evt.properties.workerID,
2757
- "function.error",
2758
- evt.properties
2759
- );
2760
- });
2761
- bus.subscribe("function.ack", async (evt) => {
2762
- iot2.publish(
2763
- topic + "/" + evt.properties.workerID,
2764
- "function.ack",
2765
- evt.properties
2766
- );
2767
- });
2768
- });
2769
2707
  }
2770
2708
  });
2771
2709
 
2772
- // src/bootstrap.ts
2773
- import url3 from "url";
2774
- import path8 from "path";
2775
- import { bold, dim } from "colorette";
2776
- import { spawn } from "child_process";
2710
+ // src/stacks/monitor.ts
2777
2711
  import {
2712
+ CloudFormationClient,
2713
+ DescribeStackResourcesCommand,
2778
2714
  DescribeStacksCommand,
2779
- CloudFormationClient
2715
+ DescribeStackEventsCommand
2780
2716
  } from "@aws-sdk/client-cloudformation";
2781
- import {
2782
- App,
2783
- DefaultStackSynthesizer,
2784
- CfnOutput,
2785
- Duration,
2786
- Tags,
2787
- Stack,
2788
- RemovalPolicy
2789
- } from "aws-cdk-lib";
2790
- import { Function, Runtime, Code } from "aws-cdk-lib/aws-lambda";
2791
- import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
2792
- import { PolicyStatement } from "aws-cdk-lib/aws-iam";
2793
- import { Queue } from "aws-cdk-lib/aws-sqs";
2794
- import { Rule } from "aws-cdk-lib/aws-events";
2795
- import { SqsQueue } from "aws-cdk-lib/aws-events-targets";
2796
- import {
2797
- BlockPublicAccess,
2798
- Bucket,
2799
- BucketEncryption
2800
- } from "aws-cdk-lib/aws-s3";
2801
- async function loadCDKStatus() {
2802
- const { cdk } = useProject().config;
2803
- const client = useAWSClient(CloudFormationClient);
2804
- const stackName = cdk?.toolkitStackName || CDK_STACK_NAME;
2805
- try {
2806
- const { Stacks: stacks } = await client.send(
2807
- new DescribeStacksCommand({ StackName: stackName })
2808
- );
2809
- if (!stacks || stacks.length === 0)
2810
- return false;
2811
- if (!["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
2812
- return false;
2813
- }
2814
- const output = stacks[0].Outputs?.find(
2815
- (o) => o.OutputKey === "BootstrapVersion"
2816
- );
2817
- if (!output || parseInt(output.OutputValue) < 14)
2818
- return false;
2819
- return true;
2820
- } catch (e) {
2821
- if (e.name === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
2822
- return false;
2823
- } else {
2824
- throw e;
2717
+ import { map, omitBy, pipe } from "remeda";
2718
+ function isFinal(input) {
2719
+ return STATUSES_SUCCESS.includes(input) || STATUSES_FAILED.includes(input);
2720
+ }
2721
+ function isFailed(input) {
2722
+ return STATUSES_FAILED.includes(input);
2723
+ }
2724
+ function isSuccess(input) {
2725
+ return STATUSES_SUCCESS.includes(input);
2726
+ }
2727
+ function isPending(input) {
2728
+ return STATUSES_PENDING.includes(input);
2729
+ }
2730
+ async function monitor(stack) {
2731
+ const [cfn, bus] = await Promise.all([
2732
+ useAWSClient(CloudFormationClient),
2733
+ useBus()
2734
+ ]);
2735
+ let lastStatus;
2736
+ const errors = {};
2737
+ let lastEvent;
2738
+ while (true) {
2739
+ try {
2740
+ const [describe, resources, events] = await Promise.all([
2741
+ cfn.send(
2742
+ new DescribeStacksCommand({
2743
+ StackName: stack
2744
+ })
2745
+ ),
2746
+ cfn.send(
2747
+ new DescribeStackResourcesCommand({
2748
+ StackName: stack
2749
+ })
2750
+ ),
2751
+ cfn.send(
2752
+ new DescribeStackEventsCommand({
2753
+ StackName: stack
2754
+ })
2755
+ )
2756
+ ]);
2757
+ Logger.debug("Stack description", describe);
2758
+ if (lastEvent) {
2759
+ const eventsReversed = [...events.StackEvents ?? []].reverse();
2760
+ for (const event of eventsReversed) {
2761
+ if (!event.Timestamp)
2762
+ continue;
2763
+ if (event.Timestamp.getTime() > lastEvent.getTime()) {
2764
+ bus.publish("stack.event", {
2765
+ event,
2766
+ stackID: stack
2767
+ });
2768
+ if (event.ResourceStatusReason) {
2769
+ if (event.ResourceStatusReason.includes(
2770
+ "Resource creation cancelled"
2771
+ ) || event.ResourceStatusReason.includes(
2772
+ "Resource update cancelled"
2773
+ ) || event.ResourceStatusReason.includes(
2774
+ "Resource creation Initiated"
2775
+ ) || event.ResourceStatusReason.startsWith(
2776
+ "The following resource(s) failed to"
2777
+ ))
2778
+ continue;
2779
+ errors[event.LogicalResourceId] = event.ResourceStatusReason;
2780
+ }
2781
+ }
2782
+ }
2783
+ Logger.debug("Last event set to", lastEvent);
2784
+ }
2785
+ lastEvent = events.StackEvents?.at(0)?.Timestamp;
2786
+ bus.publish("stack.resources", {
2787
+ stackID: stack,
2788
+ resources: resources.StackResources
2789
+ });
2790
+ for (const resource of resources.StackResources || []) {
2791
+ if (resource.ResourceStatusReason?.includes(
2792
+ "Resource creation cancelled"
2793
+ ) || resource.ResourceStatusReason?.includes(
2794
+ "Resource update cancelled"
2795
+ ) || resource.ResourceStatusReason?.includes(
2796
+ "Resource creation Initiated"
2797
+ ) || resource.ResourceStatusReason?.startsWith(
2798
+ "The following resource(s) failed to"
2799
+ ))
2800
+ continue;
2801
+ if (resource.ResourceStatusReason)
2802
+ errors[resource.LogicalResourceId] = resource.ResourceStatusReason;
2803
+ }
2804
+ const [first] = describe.Stacks || [];
2805
+ if (first) {
2806
+ if (lastStatus !== first.StackStatus && first.StackStatus) {
2807
+ lastStatus = first.StackStatus;
2808
+ bus.publish("stack.status", {
2809
+ stackID: stack,
2810
+ status: first.StackStatus
2811
+ });
2812
+ Logger.debug(first);
2813
+ if (isFinal(first.StackStatus)) {
2814
+ return {
2815
+ status: first.StackStatus,
2816
+ outputs: pipe(
2817
+ first.Outputs || [],
2818
+ map((o) => [o.OutputKey, o.OutputValue]),
2819
+ Object.fromEntries,
2820
+ filterOutputs
2821
+ ),
2822
+ errors: isFailed(first.StackStatus) ? errors : {}
2823
+ };
2824
+ }
2825
+ }
2826
+ }
2827
+ } catch (ex) {
2828
+ if (ex.message.includes("does not exist")) {
2829
+ bus.publish("stack.status", {
2830
+ stackID: stack,
2831
+ status: "DELETE_COMPLETE"
2832
+ });
2833
+ return {
2834
+ status: "DELETE_COMPLETE",
2835
+ outputs: {},
2836
+ errors: {}
2837
+ };
2838
+ }
2825
2839
  }
2840
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
2826
2841
  }
2827
2842
  }
2828
- async function loadSSTStatus() {
2829
- const { bootstrap } = useProject().config;
2830
- const cf = useAWSClient(CloudFormationClient);
2831
- const stackName = bootstrap?.stackName || SST_STACK_NAME;
2832
- let result;
2843
+ function filterOutputs(input) {
2844
+ return pipe(
2845
+ input,
2846
+ omitBy((_, key) => {
2847
+ return key.startsWith("Export") || key === "SSTMetadata";
2848
+ })
2849
+ );
2850
+ }
2851
+ var STATUSES_PENDING, STATUSES_SUCCESS, STATUSES_FAILED, STATUSES;
2852
+ var init_monitor = __esm({
2853
+ "src/stacks/monitor.ts"() {
2854
+ "use strict";
2855
+ init_bus();
2856
+ init_credentials();
2857
+ init_logger();
2858
+ STATUSES_PENDING = [
2859
+ "CREATE_IN_PROGRESS",
2860
+ "DELETE_IN_PROGRESS",
2861
+ "REVIEW_IN_PROGRESS",
2862
+ "ROLLBACK_IN_PROGRESS",
2863
+ "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS",
2864
+ "UPDATE_IN_PROGRESS",
2865
+ "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS",
2866
+ "UPDATE_ROLLBACK_IN_PROGRESS"
2867
+ ];
2868
+ STATUSES_SUCCESS = [
2869
+ "CREATE_COMPLETE",
2870
+ "UPDATE_COMPLETE",
2871
+ "DELETE_COMPLETE",
2872
+ "SKIPPED"
2873
+ ];
2874
+ STATUSES_FAILED = [
2875
+ "CREATE_FAILED",
2876
+ "DELETE_FAILED",
2877
+ "ROLLBACK_FAILED",
2878
+ "ROLLBACK_COMPLETE",
2879
+ "UPDATE_FAILED",
2880
+ "UPDATE_ROLLBACK_COMPLETE",
2881
+ "UPDATE_ROLLBACK_FAILED",
2882
+ "DEPENDENCY_FAILED"
2883
+ ];
2884
+ STATUSES = [
2885
+ ...STATUSES_PENDING,
2886
+ ...STATUSES_SUCCESS,
2887
+ ...STATUSES_FAILED
2888
+ ];
2889
+ }
2890
+ });
2891
+
2892
+ // src/cdk/util.ts
2893
+ async function callWithRetry(cb) {
2833
2894
  try {
2834
- result = await cf.send(
2835
- new DescribeStacksCommand({
2836
- StackName: stackName
2837
- })
2838
- );
2895
+ return await cb();
2839
2896
  } catch (e) {
2840
- if (e.Code === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
2841
- return null;
2897
+ if (e.code === "ThrottlingException" && e.message === "Rate exceeded" || e.code === "Throttling" && e.message === "Rate exceeded" || e.code === "TooManyRequestsException" && e.message === "Too Many Requests" || e.code === "OperationAbortedException" || e.code === "TimeoutError" || e.code === "NetworkingError") {
2898
+ return await callWithRetry(cb);
2842
2899
  }
2843
2900
  throw e;
2844
2901
  }
2845
- let version2, bucket;
2846
- (result.Stacks[0].Outputs || []).forEach((o) => {
2847
- if (o.OutputKey === OUTPUT_VERSION) {
2848
- version2 = o.OutputValue;
2849
- } else if (o.OutputKey === OUTPUT_BUCKET) {
2850
- bucket = o.OutputValue;
2851
- }
2852
- });
2853
- if (!version2 || !bucket) {
2854
- return null;
2855
- }
2856
- return { version: version2, bucket };
2857
2902
  }
2858
- async function bootstrapSST() {
2859
- const { region, bootstrap, cdk } = useProject().config;
2860
- const app = new App();
2861
- const stackName = bootstrap?.stackName || SST_STACK_NAME;
2862
- const stack = new Stack(app, stackName, {
2863
- env: {
2864
- region
2865
- },
2866
- synthesizer: new DefaultStackSynthesizer({
2867
- qualifier: cdk?.qualifier,
2868
- fileAssetsBucketName: cdk?.fileAssetsBucketName
2869
- })
2870
- });
2871
- for (const [key, value] of Object.entries(bootstrap?.tags || {})) {
2872
- Tags.of(app).add(key, value);
2873
- }
2874
- const bucket = new Bucket(stack, region, {
2875
- encryption: BucketEncryption.S3_MANAGED,
2876
- removalPolicy: RemovalPolicy.DESTROY,
2877
- autoDeleteObjects: true,
2878
- blockPublicAccess: cdk?.publicAccessBlockConfiguration !== false ? BlockPublicAccess.BLOCK_ALL : void 0
2879
- });
2880
- const fn = new Function(stack, "MetadataHandler", {
2881
- code: Code.fromAsset(
2882
- path8.resolve(__dirname, "support/bootstrap-metadata-function")
2883
- ),
2884
- handler: "index.handler",
2885
- runtime: region?.startsWith("us-gov-") ? Runtime.NODEJS_16_X : Runtime.NODEJS_18_X,
2886
- environment: {
2887
- BUCKET_NAME: bucket.bucketName
2888
- },
2889
- initialPolicy: [
2890
- new PolicyStatement({
2891
- actions: ["cloudformation:DescribeStacks"],
2892
- resources: ["*"]
2893
- }),
2894
- new PolicyStatement({
2895
- actions: ["s3:PutObject", "s3:DeleteObject"],
2896
- resources: [bucket.bucketArn + "/*"]
2897
- }),
2898
- new PolicyStatement({
2899
- actions: ["iot:Publish"],
2900
- resources: [
2901
- `arn:${stack.partition}:iot:${stack.region}:${stack.account}:topic//sst/*`
2902
- ]
2903
- })
2904
- ]
2905
- });
2906
- const queue = new Queue(stack, "MetadataQueue", {
2907
- visibilityTimeout: Duration.seconds(30),
2908
- retentionPeriod: Duration.minutes(2)
2909
- });
2910
- fn.addEventSource(new SqsEventSource(queue));
2911
- const rule = new Rule(stack, "MetadataRule", {
2912
- eventPattern: {
2913
- source: ["aws.cloudformation"],
2914
- detailType: ["CloudFormation Stack Status Change"],
2915
- detail: {
2916
- "status-details": {
2917
- status: [
2918
- "CREATE_COMPLETE",
2919
- "UPDATE_COMPLETE",
2920
- "UPDATE_ROLLBACK_COMPLETE",
2921
- "ROLLBACK_COMPLETE",
2922
- "DELETE_COMPLETE"
2923
- ]
2924
- }
2925
- }
2926
- }
2927
- });
2928
- rule.addTarget(
2929
- new SqsQueue(queue, {
2930
- retryAttempts: 10
2931
- })
2932
- );
2933
- new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
2934
- new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
2935
- const asm = app.synth();
2936
- const result = await stacks_exports.deploy(asm.stacks[0]);
2937
- if (stacks_exports.isFailed(result.status)) {
2938
- throw new VisibleError(
2939
- `Failed to deploy bootstrap stack:
2940
- ${JSON.stringify(
2941
- result.errors,
2942
- null,
2943
- 4
2944
- )}`
2945
- );
2946
- }
2947
- }
2948
- async function bootstrapCDK() {
2949
- const identity = await useSTSIdentity();
2950
- const credentials = await useAWSCredentials();
2951
- const { region, profile, cdk } = useProject().config;
2952
- cdk || {};
2953
- await new Promise((resolve, reject) => {
2954
- const proc = spawn(
2955
- [
2956
- "npx",
2957
- "cdk",
2958
- "bootstrap",
2959
- `aws://${identity.Account}/${region}`,
2960
- "--no-version-reporting",
2961
- ...cdk?.publicAccessBlockConfiguration === false ? ["--public-access-block-configuration", "false"] : cdk?.publicAccessBlockConfiguration === true ? ["--public-access-block-configuration", "false"] : [],
2962
- ...cdk?.toolkitStackName ? ["--toolkit-stack-name", cdk.toolkitStackName] : [],
2963
- ...cdk?.qualifier ? ["--qualifier", cdk.qualifier] : [],
2964
- ...cdk?.fileAssetsBucketName ? ["--toolkit-bucket-name", cdk.fileAssetsBucketName] : []
2965
- ].join(" "),
2966
- {
2967
- env: {
2968
- ...process.env,
2969
- AWS_ACCESS_KEY_ID: credentials.accessKeyId,
2970
- AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
2971
- AWS_SESSION_TOKEN: credentials.sessionToken,
2972
- AWS_REGION: region,
2973
- AWS_PROFILE: profile
2974
- },
2975
- stdio: "pipe",
2976
- shell: true
2977
- }
2978
- );
2979
- let stderr = "";
2980
- proc.stdout.on("data", (data2) => {
2981
- Logger.debug(data2.toString());
2982
- });
2983
- proc.stderr.on("data", (data2) => {
2984
- Logger.debug(data2.toString());
2985
- stderr += data2;
2986
- });
2987
- proc.on("exit", (code) => {
2988
- Logger.debug("CDK bootstrap exited with code " + code);
2989
- if (code === 0) {
2990
- resolve();
2991
- } else {
2992
- console.log(bold(dim(stderr)));
2993
- reject(new VisibleError(`Failed to bootstrap`));
2994
- }
2995
- });
2996
- });
2997
- }
2998
- var CDK_STACK_NAME, SST_STACK_NAME, OUTPUT_VERSION, OUTPUT_BUCKET, LATEST_VERSION, __dirname, useBootstrap;
2999
- var init_bootstrap = __esm({
3000
- "src/bootstrap.ts"() {
3001
- "use strict";
3002
- init_project();
3003
- init_spinner();
3004
- init_context();
3005
- init_credentials();
3006
- init_error();
3007
- init_logger();
3008
- init_stacks();
3009
- CDK_STACK_NAME = "CDKToolkit";
3010
- SST_STACK_NAME = "SSTBootstrap";
3011
- OUTPUT_VERSION = "Version";
3012
- OUTPUT_BUCKET = "BucketName";
3013
- LATEST_VERSION = "7";
3014
- __dirname = url3.fileURLToPath(new URL(".", import.meta.url));
3015
- useBootstrap = Context.memo(async () => {
3016
- Logger.debug("Initializing bootstrap context");
3017
- let [cdkStatus, sstStatus] = await Promise.all([
3018
- loadCDKStatus(),
3019
- loadSSTStatus()
3020
- ]);
3021
- Logger.debug("Loaded bootstrap status");
3022
- const needToBootstrapCDK = !cdkStatus;
3023
- const needToBootstrapSST = !sstStatus || sstStatus.version !== LATEST_VERSION;
3024
- if (needToBootstrapCDK || needToBootstrapSST) {
3025
- const spinner = createSpinner(
3026
- "Deploying bootstrap stack, this only needs to happen once"
3027
- ).start();
3028
- if (needToBootstrapCDK) {
3029
- await bootstrapCDK();
3030
- }
3031
- if (needToBootstrapSST) {
3032
- await bootstrapSST();
3033
- sstStatus = await loadSSTStatus();
3034
- if (!sstStatus)
3035
- throw new VisibleError("Failed to load bootstrap stack status");
3036
- }
3037
- spinner.succeed();
3038
- }
3039
- Logger.debug("Bootstrap context initialized", sstStatus);
3040
- return sstStatus;
3041
- }, "Bootstrap");
3042
- }
3043
- });
3044
-
3045
- // src/stacks/app-metadata.ts
3046
- import {
3047
- S3Client,
3048
- GetObjectCommand,
3049
- PutObjectCommand,
3050
- DeleteObjectCommand
3051
- } from "@aws-sdk/client-s3";
3052
- async function metadata() {
3053
- Logger.debug("Fetching app metadata");
3054
- const [project, credentials, bootstrap] = await Promise.all([
3055
- useProject(),
3056
- useAWSCredentials(),
3057
- useBootstrap()
3058
- ]);
3059
- const s3 = new S3Client({
3060
- region: project.config.region,
3061
- credentials
3062
- });
3063
- try {
3064
- const result = await s3.send(
3065
- new GetObjectCommand({
3066
- Key: useS3Key(),
3067
- Bucket: bootstrap.bucket
3068
- })
3069
- );
3070
- const body = await result.Body.transformToString();
3071
- return JSON.parse(body);
3072
- } catch (ex) {
3073
- Logger.debug("Fetching app metadata: not found");
3074
- }
3075
- }
3076
- async function saveAppMetadata(data2) {
3077
- Logger.debug("Saving app metadata");
3078
- const [project, credentials, bootstrap] = await Promise.all([
3079
- useProject(),
3080
- useAWSCredentials(),
3081
- useBootstrap()
3082
- ]);
3083
- const s3 = new S3Client({
3084
- region: project.config.region,
3085
- credentials
3086
- });
3087
- try {
3088
- await s3.send(
3089
- new PutObjectCommand({
3090
- Key: useS3Key(),
3091
- Bucket: bootstrap.bucket,
3092
- Body: JSON.stringify(data2)
3093
- })
3094
- );
3095
- } catch (ex) {
3096
- Logger.debug("Saving app metadata: not found");
3097
- }
3098
- }
3099
- async function clearAppMetadata() {
3100
- Logger.debug("Clearing app metadata");
3101
- const [project, credentials, bootstrap] = await Promise.all([
3102
- useProject(),
3103
- useAWSCredentials(),
3104
- useBootstrap()
3105
- ]);
3106
- const s3 = new S3Client({
3107
- region: project.config.region,
3108
- credentials
3109
- });
3110
- await s3.send(
3111
- new DeleteObjectCommand({
3112
- Key: useS3Key(),
3113
- Bucket: bootstrap.bucket
3114
- })
3115
- );
3116
- }
3117
- function useS3Key() {
3118
- const project = useProject();
3119
- return `appMetadata/app.${project.config.name}/stage.${project.config.stage}.json`;
3120
- }
3121
- var MetadataContext, useAppMetadata;
3122
- var init_app_metadata = __esm({
3123
- "src/stacks/app-metadata.ts"() {
3124
- "use strict";
3125
- init_bootstrap();
3126
- init_credentials();
3127
- init_context();
3128
- init_logger();
3129
- init_project();
3130
- MetadataContext = Context.create(async () => {
3131
- const data2 = await metadata();
3132
- return data2;
3133
- });
3134
- useAppMetadata = MetadataContext.use;
3135
- }
3136
- });
3137
-
3138
- // src/stacks/assembly.ts
3139
- async function loadAssembly(from) {
3140
- const { CloudAssembly } = await import("aws-cdk-lib/cx-api");
3141
- return new CloudAssembly(from);
3142
- }
3143
- var init_assembly = __esm({
3144
- "src/stacks/assembly.ts"() {
3145
- "use strict";
3146
- }
3147
- });
3148
-
3149
- // src/stacks/monitor.ts
3150
- import {
3151
- CloudFormationClient as CloudFormationClient2,
3152
- DescribeStackResourcesCommand,
3153
- DescribeStacksCommand as DescribeStacksCommand2,
3154
- DescribeStackEventsCommand
3155
- } from "@aws-sdk/client-cloudformation";
3156
- import { map, omitBy, pipe } from "remeda";
3157
- function isFinal(input) {
3158
- return STATUSES_SUCCESS.includes(input) || STATUSES_FAILED.includes(input);
3159
- }
3160
- function isFailed(input) {
3161
- return STATUSES_FAILED.includes(input);
3162
- }
3163
- function isSuccess(input) {
3164
- return STATUSES_SUCCESS.includes(input);
3165
- }
3166
- function isPending(input) {
3167
- return STATUSES_PENDING.includes(input);
3168
- }
3169
- async function monitor(stack) {
3170
- const [cfn, bus] = await Promise.all([
3171
- useAWSClient(CloudFormationClient2),
3172
- useBus()
3173
- ]);
3174
- let lastStatus;
3175
- const errors = {};
3176
- let lastEvent;
3177
- while (true) {
3178
- try {
3179
- const [describe, resources, events] = await Promise.all([
3180
- cfn.send(
3181
- new DescribeStacksCommand2({
3182
- StackName: stack
3183
- })
3184
- ),
3185
- cfn.send(
3186
- new DescribeStackResourcesCommand({
3187
- StackName: stack
3188
- })
3189
- ),
3190
- cfn.send(
3191
- new DescribeStackEventsCommand({
3192
- StackName: stack
3193
- })
3194
- )
3195
- ]);
3196
- Logger.debug("Stack description", describe);
3197
- if (lastEvent) {
3198
- const eventsReversed = [...events.StackEvents ?? []].reverse();
3199
- for (const event of eventsReversed) {
3200
- if (!event.Timestamp)
3201
- continue;
3202
- if (event.Timestamp.getTime() > lastEvent.getTime()) {
3203
- bus.publish("stack.event", {
3204
- event,
3205
- stackID: stack
3206
- });
3207
- if (event.ResourceStatusReason) {
3208
- if (event.ResourceStatusReason.includes(
3209
- "Resource creation cancelled"
3210
- ) || event.ResourceStatusReason.includes(
3211
- "Resource update cancelled"
3212
- ) || event.ResourceStatusReason.includes(
3213
- "Resource creation Initiated"
3214
- ) || event.ResourceStatusReason.startsWith(
3215
- "The following resource(s) failed to"
3216
- ))
3217
- continue;
3218
- errors[event.LogicalResourceId] = event.ResourceStatusReason;
3219
- }
3220
- }
3221
- }
3222
- Logger.debug("Last event set to", lastEvent);
3223
- }
3224
- lastEvent = events.StackEvents?.at(0)?.Timestamp;
3225
- bus.publish("stack.resources", {
3226
- stackID: stack,
3227
- resources: resources.StackResources
3228
- });
3229
- for (const resource of resources.StackResources || []) {
3230
- if (resource.ResourceStatusReason?.includes(
3231
- "Resource creation cancelled"
3232
- ) || resource.ResourceStatusReason?.includes(
3233
- "Resource update cancelled"
3234
- ) || resource.ResourceStatusReason?.includes(
3235
- "Resource creation Initiated"
3236
- ) || resource.ResourceStatusReason?.startsWith(
3237
- "The following resource(s) failed to"
3238
- ))
3239
- continue;
3240
- if (resource.ResourceStatusReason)
3241
- errors[resource.LogicalResourceId] = resource.ResourceStatusReason;
3242
- }
3243
- const [first] = describe.Stacks || [];
3244
- if (first) {
3245
- if (lastStatus !== first.StackStatus && first.StackStatus) {
3246
- lastStatus = first.StackStatus;
3247
- bus.publish("stack.status", {
3248
- stackID: stack,
3249
- status: first.StackStatus
3250
- });
3251
- Logger.debug(first);
3252
- if (isFinal(first.StackStatus)) {
3253
- return {
3254
- status: first.StackStatus,
3255
- outputs: pipe(
3256
- first.Outputs || [],
3257
- map((o) => [o.OutputKey, o.OutputValue]),
3258
- Object.fromEntries,
3259
- filterOutputs
3260
- ),
3261
- errors: isFailed(first.StackStatus) ? errors : {}
3262
- };
3263
- }
3264
- }
3265
- }
3266
- } catch (ex) {
3267
- if (ex.message.includes("does not exist")) {
3268
- bus.publish("stack.status", {
3269
- stackID: stack,
3270
- status: "DELETE_COMPLETE"
3271
- });
3272
- return {
3273
- status: "DELETE_COMPLETE",
3274
- outputs: {},
3275
- errors: {}
3276
- };
3277
- }
3278
- }
3279
- await new Promise((resolve) => setTimeout(resolve, 1e3));
3280
- }
3281
- }
3282
- function filterOutputs(input) {
3283
- return pipe(
3284
- input,
3285
- omitBy((_, key) => {
3286
- return key.startsWith("Export") || key === "SSTMetadata";
3287
- })
3288
- );
3289
- }
3290
- var STATUSES_PENDING, STATUSES_SUCCESS, STATUSES_FAILED, STATUSES;
3291
- var init_monitor = __esm({
3292
- "src/stacks/monitor.ts"() {
3293
- "use strict";
3294
- init_bus();
3295
- init_credentials();
3296
- init_logger();
3297
- STATUSES_PENDING = [
3298
- "CREATE_IN_PROGRESS",
3299
- "DELETE_IN_PROGRESS",
3300
- "REVIEW_IN_PROGRESS",
3301
- "ROLLBACK_IN_PROGRESS",
3302
- "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS",
3303
- "UPDATE_IN_PROGRESS",
3304
- "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS",
3305
- "UPDATE_ROLLBACK_IN_PROGRESS"
3306
- ];
3307
- STATUSES_SUCCESS = [
3308
- "CREATE_COMPLETE",
3309
- "UPDATE_COMPLETE",
3310
- "DELETE_COMPLETE",
3311
- "SKIPPED"
3312
- ];
3313
- STATUSES_FAILED = [
3314
- "CREATE_FAILED",
3315
- "DELETE_FAILED",
3316
- "ROLLBACK_FAILED",
3317
- "ROLLBACK_COMPLETE",
3318
- "UPDATE_FAILED",
3319
- "UPDATE_ROLLBACK_COMPLETE",
3320
- "UPDATE_ROLLBACK_FAILED",
3321
- "DEPENDENCY_FAILED"
3322
- ];
3323
- STATUSES = [
3324
- ...STATUSES_PENDING,
3325
- ...STATUSES_SUCCESS,
3326
- ...STATUSES_FAILED
3327
- ];
3328
- }
3329
- });
3330
-
3331
- // src/cdk/util.ts
3332
- async function callWithRetry(cb) {
3333
- try {
3334
- return await cb();
3335
- } catch (e) {
3336
- if (e.code === "ThrottlingException" && e.message === "Rate exceeded" || e.code === "Throttling" && e.message === "Rate exceeded" || e.code === "TooManyRequestsException" && e.message === "Too Many Requests" || e.code === "OperationAbortedException" || e.code === "TimeoutError" || e.code === "NetworkingError") {
3337
- return await callWithRetry(cb);
3338
- }
3339
- throw e;
3340
- }
3341
- }
3342
- var init_util = __esm({
3343
- "src/cdk/util.ts"() {
3344
- "use strict";
2903
+ var init_util = __esm({
2904
+ "src/cdk/util.ts"() {
2905
+ "use strict";
3345
2906
  }
3346
2907
  });
3347
2908
 
@@ -4627,7 +4188,7 @@ var init_diff = __esm({
4627
4188
  });
4628
4189
 
4629
4190
  // src/cache.ts
4630
- import path9 from "path";
4191
+ import path8 from "path";
4631
4192
  import fs9 from "fs/promises";
4632
4193
  var useCache;
4633
4194
  var init_cache = __esm({
@@ -4638,17 +4199,17 @@ var init_cache = __esm({
4638
4199
  init_context();
4639
4200
  useCache = Context.memo(async () => {
4640
4201
  const project = useProject();
4641
- const cache = path9.join(project.paths.out, "cache");
4202
+ const cache = path8.join(project.paths.out, "cache");
4642
4203
  await fs9.mkdir(cache, {
4643
4204
  recursive: true
4644
4205
  });
4645
4206
  async function write(key, data2) {
4646
- const full = path9.join(cache, key);
4207
+ const full = path8.join(cache, key);
4647
4208
  Logger.debug("Writing cache", full, data2.length, "bytes");
4648
4209
  await fs9.writeFile(full, data2);
4649
4210
  }
4650
4211
  async function read(key) {
4651
- const full = path9.join(cache, key);
4212
+ const full = path8.join(cache, key);
4652
4213
  try {
4653
4214
  const data2 = await fs9.readFile(full);
4654
4215
  return data2.toString();
@@ -4784,8 +4345,8 @@ var init_process = __esm({
4784
4345
  });
4785
4346
 
4786
4347
  // src/runtime/handlers/dotnet.ts
4787
- import { spawn as spawn2 } from "child_process";
4788
- import url4 from "url";
4348
+ import { spawn } from "child_process";
4349
+ import url3 from "url";
4789
4350
  var FRAMEWORK_MAP, BOOTSTRAP_MAP, useDotnetHandler;
4790
4351
  var init_dotnet = __esm({
4791
4352
  "src/runtime/handlers/dotnet.ts"() {
@@ -4830,11 +4391,11 @@ var init_dotnet = __esm({
4830
4391
  canHandle: (input) => input.startsWith("dotnet"),
4831
4392
  startWorker: async (input) => {
4832
4393
  const name = input.handler.split(":")[0];
4833
- const proc = spawn2(
4394
+ const proc = spawn(
4834
4395
  `dotnet`,
4835
4396
  [
4836
4397
  `exec`,
4837
- url4.fileURLToPath(
4398
+ url3.fileURLToPath(
4838
4399
  new URL(
4839
4400
  `../../support/${BOOTSTRAP_MAP["dotnetcore3.1"]}/release/dotnet-bootstrap.dll`,
4840
4401
  import.meta.url
@@ -4917,12 +4478,12 @@ var node_exports = {};
4917
4478
  __export(node_exports, {
4918
4479
  useNodeHandler: () => useNodeHandler
4919
4480
  });
4920
- import path10 from "path";
4481
+ import path9 from "path";
4921
4482
  import fs10 from "fs/promises";
4922
4483
  import { exec as exec2 } from "child_process";
4923
4484
  import fsSync2 from "fs";
4924
4485
  import esbuild2 from "esbuild";
4925
- import url5 from "url";
4486
+ import url4 from "url";
4926
4487
  import { Worker } from "worker_threads";
4927
4488
  var useNodeHandler;
4928
4489
  var init_node = __esm({
@@ -4945,14 +4506,14 @@ var init_node = __esm({
4945
4506
  const result = cache[input.functionID];
4946
4507
  if (!result)
4947
4508
  return false;
4948
- const relative = path10.relative(project.paths.root, input.file).split(path10.sep).join(path10.posix.sep);
4509
+ const relative = path9.relative(project.paths.root, input.file).split(path9.sep).join(path9.posix.sep);
4949
4510
  return Boolean(result.metafile?.inputs[relative]);
4950
4511
  },
4951
4512
  canHandle: (input) => input.startsWith("nodejs"),
4952
4513
  startWorker: async (input) => {
4953
4514
  new Promise(async () => {
4954
4515
  const worker = new Worker(
4955
- url5.fileURLToPath(
4516
+ url4.fileURLToPath(
4956
4517
  new URL("../../support/nodejs-runtime/index.mjs", import.meta.url)
4957
4518
  ),
4958
4519
  {
@@ -4984,7 +4545,7 @@ var init_node = __esm({
4984
4545
  },
4985
4546
  build: async (input) => {
4986
4547
  const exists = cache[input.functionID];
4987
- const parsed = path10.parse(input.props.handler);
4548
+ const parsed = path9.parse(input.props.handler);
4988
4549
  const file = [
4989
4550
  ".ts",
4990
4551
  ".tsx",
@@ -4994,7 +4555,7 @@ var init_node = __esm({
4994
4555
  ".jsx",
4995
4556
  ".mjs",
4996
4557
  ".cjs"
4997
- ].map((ext) => path10.join(parsed.dir, parsed.name + ext)).find((file2) => {
4558
+ ].map((ext) => path9.join(parsed.dir, parsed.name + ext)).find((file2) => {
4998
4559
  return fsSync2.existsSync(file2);
4999
4560
  });
5000
4561
  if (!file)
@@ -5004,17 +4565,17 @@ var init_node = __esm({
5004
4565
  };
5005
4566
  const nodejs = input.props.nodejs || {};
5006
4567
  const isESM = (nodejs.format || "esm") === "esm";
5007
- const relative = path10.relative(
4568
+ const relative = path9.relative(
5008
4569
  project.paths.root,
5009
- path10.resolve(parsed.dir)
4570
+ path9.resolve(parsed.dir)
5010
4571
  );
5011
4572
  const extension = isESM ? ".mjs" : ".cjs";
5012
- const target = path10.join(
4573
+ const target = path9.join(
5013
4574
  input.out,
5014
- !relative.startsWith("..") && !path10.isAbsolute(input.props.handler) ? relative : "",
4575
+ !relative.startsWith("..") && !path9.isAbsolute(input.props.handler) ? relative : "",
5015
4576
  parsed.name + extension
5016
4577
  );
5017
- const handler = path10.relative(input.out, target.replace(extension, parsed.ext)).split(path10.sep).join(path10.posix.sep);
4578
+ const handler = path9.relative(input.out, target.replace(extension, parsed.ext)).split(path9.sep).join(path9.posix.sep);
5018
4579
  if (exists?.rebuild) {
5019
4580
  const result = await exists.rebuild();
5020
4581
  cache[input.functionID] = result;
@@ -5088,17 +4649,17 @@ var init_node = __esm({
5088
4649
  async function find2(dir, target2) {
5089
4650
  if (dir === "/")
5090
4651
  throw new VisibleError("Could not find a package.json file");
5091
- if (await fs10.access(path10.join(dir, target2)).then(() => true).catch(() => false))
4652
+ if (await fs10.access(path9.join(dir, target2)).then(() => true).catch(() => false))
5092
4653
  return dir;
5093
- return find2(path10.join(dir, ".."), target2);
4654
+ return find2(path9.join(dir, ".."), target2);
5094
4655
  }
5095
4656
  if (input.mode === "deploy" && installPackages) {
5096
4657
  const src = await find2(parsed.dir, "package.json");
5097
4658
  const json = JSON.parse(
5098
- await fs10.readFile(path10.join(src, "package.json")).then((x) => x.toString())
4659
+ await fs10.readFile(path9.join(src, "package.json")).then((x) => x.toString())
5099
4660
  );
5100
4661
  fs10.writeFile(
5101
- path10.join(input.out, "package.json"),
4662
+ path9.join(input.out, "package.json"),
5102
4663
  JSON.stringify({
5103
4664
  dependencies: Object.fromEntries(
5104
4665
  installPackages.map((x) => [x, json.dependencies?.[x] || "*"])
@@ -5120,14 +4681,14 @@ var init_node = __esm({
5120
4681
  });
5121
4682
  }
5122
4683
  if (input.mode === "start") {
5123
- const dir = path10.join(
4684
+ const dir = path9.join(
5124
4685
  await find2(parsed.dir, "package.json"),
5125
4686
  "node_modules"
5126
4687
  );
5127
4688
  try {
5128
4689
  await fs10.symlink(
5129
- path10.resolve(dir),
5130
- path10.resolve(path10.join(input.out, "node_modules")),
4690
+ path9.resolve(dir),
4691
+ path9.resolve(path9.join(input.out, "node_modules")),
5131
4692
  "dir"
5132
4693
  );
5133
4694
  } catch {
@@ -5166,16 +4727,16 @@ var go_exports = {};
5166
4727
  __export(go_exports, {
5167
4728
  useGoHandler: () => useGoHandler
5168
4729
  });
5169
- import path11 from "path";
4730
+ import path10 from "path";
5170
4731
  import fs11 from "fs/promises";
5171
- import { exec as exec3, spawn as spawn3 } from "child_process";
4732
+ import { exec as exec3, spawn as spawn2 } from "child_process";
5172
4733
  import { promisify as promisify2 } from "util";
5173
4734
  async function find(dir, target) {
5174
4735
  if (dir === "/")
5175
4736
  throw new VisibleError(`Could not find a ${target} file`);
5176
- if (await fs11.access(path11.join(dir, target)).then(() => true).catch(() => false))
4737
+ if (await fs11.access(path10.join(dir, target)).then(() => true).catch(() => false))
5177
4738
  return dir;
5178
- return find(path11.join(dir, ".."), target);
4739
+ return find(path10.join(dir, ".."), target);
5179
4740
  }
5180
4741
  var execAsync2, useGoHandler;
5181
4742
  var init_go = __esm({
@@ -5204,7 +4765,7 @@ var init_go = __esm({
5204
4765
  },
5205
4766
  canHandle: (input) => input.startsWith("go"),
5206
4767
  startWorker: async (input) => {
5207
- const proc = spawn3(path11.join(input.out, handlerName), {
4768
+ const proc = spawn2(path10.join(input.out, handlerName), {
5208
4769
  env: {
5209
4770
  ...process.env,
5210
4771
  ...input.environment,
@@ -5230,13 +4791,13 @@ var init_go = __esm({
5230
4791
  }
5231
4792
  },
5232
4793
  build: async (input) => {
5233
- const parsed = path11.parse(input.props.handler);
4794
+ const parsed = path10.parse(input.props.handler);
5234
4795
  const project = await find(parsed.dir, "go.mod");
5235
4796
  sources.set(input.functionID, project);
5236
- const src = path11.relative(project, input.props.handler);
4797
+ const src = path10.relative(project, input.props.handler);
5237
4798
  if (input.mode === "start") {
5238
4799
  try {
5239
- const target = path11.join(input.out, handlerName);
4800
+ const target = path10.join(input.out, handlerName);
5240
4801
  const result = await execAsync2(
5241
4802
  `go build -ldflags '-s -w' -o ${target} ./${src}`,
5242
4803
  {
@@ -5252,7 +4813,7 @@ var init_go = __esm({
5252
4813
  }
5253
4814
  if (input.mode === "deploy") {
5254
4815
  try {
5255
- const target = path11.join(input.out, "bootstrap");
4816
+ const target = path10.join(input.out, "bootstrap");
5256
4817
  await execAsync2(`go build -ldflags '-s -w' -o ${target} ./${src}`, {
5257
4818
  cwd: project,
5258
4819
  env: {
@@ -5281,9 +4842,9 @@ var rust_exports = {};
5281
4842
  __export(rust_exports, {
5282
4843
  useRustHandler: () => useRustHandler
5283
4844
  });
5284
- import path12 from "path";
4845
+ import path11 from "path";
5285
4846
  import fs12 from "fs/promises";
5286
- import { exec as exec4, spawn as spawn4 } from "child_process";
4847
+ import { exec as exec4, spawn as spawn3 } from "child_process";
5287
4848
  import { promisify as promisify3 } from "util";
5288
4849
  var execAsync3, useRustHandler;
5289
4850
  var init_rust = __esm({
@@ -5315,7 +4876,7 @@ var init_rust = __esm({
5315
4876
  },
5316
4877
  canHandle: (input) => input.startsWith("rust"),
5317
4878
  startWorker: async (input) => {
5318
- const proc = spawn4(path12.join(input.out, handlerName), {
4879
+ const proc = spawn3(path11.join(input.out, handlerName), {
5319
4880
  env: {
5320
4881
  ...process.env,
5321
4882
  ...input.environment,
@@ -5343,7 +4904,7 @@ var init_rust = __esm({
5343
4904
  }
5344
4905
  },
5345
4906
  build: async (input) => {
5346
- const parsed = path12.parse(input.props.handler);
4907
+ const parsed = path11.parse(input.props.handler);
5347
4908
  const project = await findAbove(parsed.dir, "Cargo.toml");
5348
4909
  if (!project)
5349
4910
  return {
@@ -5360,8 +4921,8 @@ var init_rust = __esm({
5360
4921
  }
5361
4922
  });
5362
4923
  await fs12.cp(
5363
- path12.join(project, `target/debug`, parsed.name),
5364
- path12.join(input.out, "handler")
4924
+ path11.join(project, `target/debug`, parsed.name),
4925
+ path11.join(input.out, "handler")
5365
4926
  );
5366
4927
  } catch (ex) {
5367
4928
  throw new VisibleError("Failed to build");
@@ -5376,8 +4937,8 @@ var init_rust = __esm({
5376
4937
  }
5377
4938
  });
5378
4939
  await fs12.cp(
5379
- path12.join(project, `target/lambda/`, parsed.name, "bootstrap"),
5380
- path12.join(input.out, "bootstrap")
4940
+ path11.join(project, `target/lambda/`, parsed.name, "bootstrap"),
4941
+ path11.join(input.out, "bootstrap")
5381
4942
  );
5382
4943
  } catch (ex) {
5383
4944
  throw new VisibleError("Failed to build");
@@ -5395,8 +4956,8 @@ var init_rust = __esm({
5395
4956
 
5396
4957
  // src/runtime/handlers/pythonBundling.ts
5397
4958
  import fs13 from "fs";
5398
- import url6 from "url";
5399
- import path13 from "path";
4959
+ import url5 from "url";
4960
+ import path12 from "path";
5400
4961
  import {
5401
4962
  DockerImage,
5402
4963
  FileSystem
@@ -5411,8 +4972,8 @@ function bundle(options) {
5411
4972
  );
5412
4973
  const dockerfile = hasInstallCommands ? "Dockerfile.custom" : hasDeps ? "Dockerfile.dependencies" : "Dockerfile";
5413
4974
  fs13.copyFileSync(
5414
- path13.join(__dirname2, "../../support/python-runtime", dockerfile),
5415
- path13.join(stagedir, dockerfile)
4975
+ path12.join(__dirname, "../../support/python-runtime", dockerfile),
4976
+ path12.join(stagedir, dockerfile)
5416
4977
  );
5417
4978
  const image = DockerImage.fromBuild(stagedir, {
5418
4979
  buildArgs: {
@@ -5420,7 +4981,7 @@ function bundle(options) {
5420
4981
  },
5421
4982
  file: dockerfile
5422
4983
  });
5423
- const outputPath = path13.join(options.out, outputPathSuffix);
4984
+ const outputPath = path12.join(options.out, outputPathSuffix);
5424
4985
  if (hasDeps || hasInstallCommands) {
5425
4986
  image.cp(`${BUNDLER_DEPENDENCIES_CACHE}/.`, outputPath);
5426
4987
  }
@@ -5434,7 +4995,7 @@ function stageDependencies(entry, stagedir) {
5434
4995
  for (const file of fs13.readdirSync(entry)) {
5435
4996
  for (const prefix of prefixes) {
5436
4997
  if (file.startsWith(prefix)) {
5437
- fs13.copyFileSync(path13.join(entry, file), path13.join(stagedir, file));
4998
+ fs13.copyFileSync(path12.join(entry, file), path12.join(stagedir, file));
5438
4999
  found = true;
5439
5000
  }
5440
5001
  }
@@ -5444,18 +5005,18 @@ function stageDependencies(entry, stagedir) {
5444
5005
  function stageInstallCommands(installCommands, stagedir) {
5445
5006
  let found = false;
5446
5007
  if (installCommands.length > 0) {
5447
- const filePath = path13.join(stagedir, "sst-deps-install-command.sh");
5008
+ const filePath = path12.join(stagedir, "sst-deps-install-command.sh");
5448
5009
  fs13.writeFileSync(filePath, installCommands.join(" && "));
5449
5010
  fs13.chmodSync(filePath, "755");
5450
5011
  found = true;
5451
5012
  }
5452
5013
  return found;
5453
5014
  }
5454
- var __dirname2, BUNDLER_DEPENDENCIES_CACHE;
5015
+ var __dirname, BUNDLER_DEPENDENCIES_CACHE;
5455
5016
  var init_pythonBundling = __esm({
5456
5017
  "src/runtime/handlers/pythonBundling.ts"() {
5457
5018
  "use strict";
5458
- __dirname2 = path13.dirname(url6.fileURLToPath(import.meta.url));
5019
+ __dirname = path12.dirname(url5.fileURLToPath(import.meta.url));
5459
5020
  BUNDLER_DEPENDENCIES_CACHE = "/var/dependencies";
5460
5021
  }
5461
5022
  });
@@ -5465,12 +5026,12 @@ var python_exports = {};
5465
5026
  __export(python_exports, {
5466
5027
  usePythonHandler: () => usePythonHandler
5467
5028
  });
5468
- import path14 from "path";
5469
- import { exec as exec5, spawn as spawn5 } from "child_process";
5029
+ import path13 from "path";
5030
+ import { exec as exec5, spawn as spawn4 } from "child_process";
5470
5031
  import { promisify as promisify4 } from "util";
5471
- import { Runtime as Runtime2 } from "aws-cdk-lib/aws-lambda";
5032
+ import { Runtime } from "aws-cdk-lib/aws-lambda";
5472
5033
  import os3 from "os";
5473
- import url7 from "url";
5034
+ import url6 from "url";
5474
5035
  var execAsync4, RUNTIME_MAP, usePythonHandler;
5475
5036
  var init_python = __esm({
5476
5037
  "src/runtime/handlers/python.ts"() {
@@ -5483,11 +5044,11 @@ var init_python = __esm({
5483
5044
  init_pythonBundling();
5484
5045
  execAsync4 = promisify4(exec5);
5485
5046
  RUNTIME_MAP = {
5486
- "python2.7": Runtime2.PYTHON_2_7,
5487
- "python3.6": Runtime2.PYTHON_3_6,
5488
- "python3.7": Runtime2.PYTHON_3_7,
5489
- "python3.8": Runtime2.PYTHON_3_8,
5490
- "python3.9": Runtime2.PYTHON_3_9
5047
+ "python2.7": Runtime.PYTHON_2_7,
5048
+ "python3.6": Runtime.PYTHON_3_6,
5049
+ "python3.7": Runtime.PYTHON_3_7,
5050
+ "python3.8": Runtime.PYTHON_3_8,
5051
+ "python3.9": Runtime.PYTHON_3_9
5491
5052
  };
5492
5053
  usePythonHandler = Context.memo(async () => {
5493
5054
  const workers = await useRuntimeWorkers();
@@ -5515,13 +5076,13 @@ var init_python = __esm({
5515
5076
  const src = await findSrc(input.handler);
5516
5077
  if (!src)
5517
5078
  throw new Error(`Could not find src for ${input.handler}`);
5518
- const parsed = path14.parse(path14.relative(src, input.handler));
5519
- const target = [...parsed.dir.split(path14.sep), parsed.name].join(".");
5520
- const proc = spawn5(
5079
+ const parsed = path13.parse(path13.relative(src, input.handler));
5080
+ const target = [...parsed.dir.split(path13.sep), parsed.name].join(".");
5081
+ const proc = spawn4(
5521
5082
  os3.platform() === "win32" ? "python.exe" : "python3",
5522
5083
  [
5523
5084
  "-u",
5524
- url7.fileURLToPath(
5085
+ url6.fileURLToPath(
5525
5086
  new URL("../../support/python-runtime/runtime.py", import.meta.url)
5526
5087
  ),
5527
5088
  target,
@@ -5577,7 +5138,7 @@ var init_python = __esm({
5577
5138
  });
5578
5139
  return {
5579
5140
  type: "success",
5580
- handler: path14.relative(src, path14.resolve(input.props.handler)).split(path14.sep).join(path14.posix.sep)
5141
+ handler: path13.relative(src, path13.resolve(input.props.handler)).split(path13.sep).join(path13.posix.sep)
5581
5142
  };
5582
5143
  }
5583
5144
  });
@@ -5590,14 +5151,14 @@ var java_exports = {};
5590
5151
  __export(java_exports, {
5591
5152
  useJavaHandler: () => useJavaHandler
5592
5153
  });
5593
- import path15 from "path";
5154
+ import path14 from "path";
5594
5155
  import fs14 from "fs/promises";
5595
5156
  import os4 from "os";
5596
5157
  import zipLocal from "zip-local";
5597
- import { spawn as spawn6 } from "child_process";
5598
- import url8 from "url";
5158
+ import { spawn as spawn5 } from "child_process";
5159
+ import url7 from "url";
5599
5160
  async function getGradleBinary(srcPath) {
5600
- const gradleWrapperPath = path15.resolve(path15.join(srcPath, "gradlew"));
5161
+ const gradleWrapperPath = path14.resolve(path14.join(srcPath, "gradlew"));
5601
5162
  return await existsAsync(gradleWrapperPath) ? gradleWrapperPath : "gradle";
5602
5163
  }
5603
5164
  var useJavaHandler;
@@ -5629,12 +5190,12 @@ var init_java = __esm({
5629
5190
  },
5630
5191
  canHandle: (input) => input.startsWith("java"),
5631
5192
  startWorker: async (input) => {
5632
- const proc = spawn6(
5193
+ const proc = spawn5(
5633
5194
  `java`,
5634
5195
  [
5635
5196
  `-cp`,
5636
5197
  [
5637
- url8.fileURLToPath(
5198
+ url7.fileURLToPath(
5638
5199
  new URL("../../support/java-runtime/release/*", import.meta.url)
5639
5200
  )
5640
5201
  ].join(os4.platform() === "win32" ? ";" : ":"),
@@ -5681,11 +5242,11 @@ var init_java = __esm({
5681
5242
  cwd: srcPath
5682
5243
  }
5683
5244
  );
5684
- const buildOutput = path15.join(srcPath, "build", outputDir);
5245
+ const buildOutput = path14.join(srcPath, "build", outputDir);
5685
5246
  const zip = (await fs14.readdir(buildOutput)).find(
5686
5247
  (f) => f.endsWith(".zip")
5687
5248
  );
5688
- zipLocal.sync.unzip(path15.join(buildOutput, zip)).save(input.out);
5249
+ zipLocal.sync.unzip(path14.join(buildOutput, zip)).save(input.out);
5689
5250
  return {
5690
5251
  type: "success",
5691
5252
  handler: input.props.handler
@@ -5704,7 +5265,7 @@ var init_java = __esm({
5704
5265
 
5705
5266
  // src/stacks/synth.ts
5706
5267
  import * as contextproviders from "aws-cdk/lib/context-providers/index.js";
5707
- import path16 from "path";
5268
+ import path15 from "path";
5708
5269
  async function synth(opts) {
5709
5270
  Logger.debug("Synthesizing stacks...");
5710
5271
  const { App: App2 } = await import("../src/constructs/App.js");
@@ -5724,7 +5285,7 @@ async function synth(opts) {
5724
5285
  const identity = await useSTSIdentity();
5725
5286
  opts = {
5726
5287
  ...opts,
5727
- buildDir: opts.buildDir || path16.join(project.paths.out, "dist")
5288
+ buildDir: opts.buildDir || path15.join(project.paths.out, "dist")
5728
5289
  };
5729
5290
  const cfg = new Configuration();
5730
5291
  await cfg.load();
@@ -5767,166 +5328,632 @@ async function synth(opts) {
5767
5328
  }
5768
5329
  continue;
5769
5330
  }
5770
- Logger.debug("Finished synthesizing");
5771
- return assembly;
5331
+ Logger.debug("Finished synthesizing");
5332
+ return assembly;
5333
+ }
5334
+ }
5335
+ function formatErrorMessage(message) {
5336
+ return formatCustomDomainError(message) || `Could not resolve context values for ${message}`;
5337
+ }
5338
+ function formatCustomDomainError(message) {
5339
+ const ret = message.match(/hosted-zone:account=\d+:domainName=(\S+):/);
5340
+ if (!ret) {
5341
+ return;
5342
+ }
5343
+ const hostedZone = ret && ret[1];
5344
+ return [
5345
+ `It seems you are configuring custom domains for you URL.`,
5346
+ hostedZone ? `And SST is not able to find the hosted zone "${hostedZone}" in your AWS Route 53 account.` : `And SST is not able to find the hosted zone in your AWS Route 53 account.`,
5347
+ `Please double check and make sure the zone exists, or pass in a different zone.`
5348
+ ].join(" ");
5349
+ }
5350
+ var init_synth = __esm({
5351
+ "src/stacks/synth.ts"() {
5352
+ "use strict";
5353
+ init_logger();
5354
+ init_project();
5355
+ init_credentials();
5356
+ init_error();
5357
+ init_dotnet();
5358
+ }
5359
+ });
5360
+
5361
+ // src/stacks/remove.ts
5362
+ import {
5363
+ CloudFormationClient as CloudFormationClient2,
5364
+ DeleteStackCommand
5365
+ } from "@aws-sdk/client-cloudformation";
5366
+ async function removeMany(stacks) {
5367
+ await useAWSProvider();
5368
+ const bus = useBus();
5369
+ const complete = /* @__PURE__ */ new Set();
5370
+ const todo = new Set(stacks.map((s) => s.id));
5371
+ const results = {};
5372
+ return new Promise((resolve) => {
5373
+ async function trigger() {
5374
+ for (const stack of stacks) {
5375
+ if (!todo.has(stack.id))
5376
+ continue;
5377
+ Logger.debug("Checking if", stack.id, "can be removed");
5378
+ const waiting = stacks.filter((dependant) => {
5379
+ if (dependant.id === stack.id)
5380
+ return false;
5381
+ if (complete.has(dependant.id))
5382
+ return false;
5383
+ return dependant.dependencies?.some((d) => d.id === stack.id);
5384
+ });
5385
+ if (waiting.length) {
5386
+ Logger.debug(
5387
+ "Waiting on",
5388
+ waiting.map((s) => s.id)
5389
+ );
5390
+ continue;
5391
+ }
5392
+ remove(stack).then((result) => {
5393
+ results[stack.id] = result;
5394
+ complete.add(stack.id);
5395
+ if (isFailed(result.status))
5396
+ stacks.forEach((s) => {
5397
+ if (todo.delete(s.stackName)) {
5398
+ complete.add(s.stackName);
5399
+ results[s.id] = {
5400
+ status: "DEPENDENCY_FAILED",
5401
+ outputs: {},
5402
+ errors: {}
5403
+ };
5404
+ bus.publish("stack.status", {
5405
+ stackID: s.id,
5406
+ status: "DEPENDENCY_FAILED"
5407
+ });
5408
+ }
5409
+ });
5410
+ if (complete.size === stacks.length) {
5411
+ resolve(results);
5412
+ }
5413
+ trigger();
5414
+ });
5415
+ todo.delete(stack.id);
5416
+ }
5417
+ }
5418
+ trigger();
5419
+ });
5420
+ }
5421
+ async function remove(stack) {
5422
+ Logger.debug("Removing stack", stack.id);
5423
+ const cfn = useAWSClient(CloudFormationClient2);
5424
+ try {
5425
+ await cfn.send(
5426
+ new DeleteStackCommand({
5427
+ StackName: stack.stackName
5428
+ })
5429
+ );
5430
+ return monitor(stack.stackName);
5431
+ } catch (ex) {
5432
+ return {
5433
+ errors: {
5434
+ stack: ex.message
5435
+ },
5436
+ outputs: {},
5437
+ status: "UPDATE_FAILED"
5438
+ };
5439
+ }
5440
+ }
5441
+ var init_remove = __esm({
5442
+ "src/stacks/remove.ts"() {
5443
+ "use strict";
5444
+ init_bus();
5445
+ init_credentials();
5446
+ init_logger();
5447
+ init_monitor();
5448
+ }
5449
+ });
5450
+
5451
+ // src/stacks/index.ts
5452
+ var stacks_exports = {};
5453
+ __export(stacks_exports, {
5454
+ STATUSES: () => STATUSES,
5455
+ Stacks: () => stacks_exports,
5456
+ clearAppMetadata: () => clearAppMetadata,
5457
+ deploy: () => deploy,
5458
+ deployMany: () => deployMany,
5459
+ diff: () => diff,
5460
+ filterOutputs: () => filterOutputs,
5461
+ isFailed: () => isFailed,
5462
+ isFinal: () => isFinal,
5463
+ isPending: () => isPending,
5464
+ isSuccess: () => isSuccess,
5465
+ load: () => load,
5466
+ loadAssembly: () => loadAssembly,
5467
+ metadata: () => metadata2,
5468
+ metadataForStack: () => metadataForStack,
5469
+ monitor: () => monitor,
5470
+ publishAssets: () => publishAssets4,
5471
+ remove: () => remove,
5472
+ removeMany: () => removeMany,
5473
+ saveAppMetadata: () => saveAppMetadata,
5474
+ synth: () => synth,
5475
+ useAppMetadata: () => useAppMetadata,
5476
+ useMetadata: () => useMetadata
5477
+ });
5478
+ var init_stacks = __esm({
5479
+ "src/stacks/index.ts"() {
5480
+ "use strict";
5481
+ init_app_metadata();
5482
+ init_assembly();
5483
+ init_build();
5484
+ init_deploy();
5485
+ init_diff();
5486
+ init_metadata();
5487
+ init_synth();
5488
+ init_monitor();
5489
+ init_remove();
5490
+ init_stacks();
5491
+ }
5492
+ });
5493
+
5494
+ // src/bootstrap.ts
5495
+ import url8 from "url";
5496
+ import path16 from "path";
5497
+ import { bold, dim } from "colorette";
5498
+ import { spawn as spawn6 } from "child_process";
5499
+ import {
5500
+ DescribeStacksCommand as DescribeStacksCommand2,
5501
+ CloudFormationClient as CloudFormationClient3
5502
+ } from "@aws-sdk/client-cloudformation";
5503
+ import {
5504
+ App,
5505
+ DefaultStackSynthesizer,
5506
+ CfnOutput,
5507
+ Duration,
5508
+ Tags,
5509
+ Stack,
5510
+ RemovalPolicy
5511
+ } from "aws-cdk-lib";
5512
+ import { Function, Runtime as Runtime2, Code } from "aws-cdk-lib/aws-lambda";
5513
+ import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
5514
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
5515
+ import { Queue } from "aws-cdk-lib/aws-sqs";
5516
+ import { Rule } from "aws-cdk-lib/aws-events";
5517
+ import { SqsQueue } from "aws-cdk-lib/aws-events-targets";
5518
+ import {
5519
+ BlockPublicAccess,
5520
+ Bucket,
5521
+ BucketEncryption
5522
+ } from "aws-cdk-lib/aws-s3";
5523
+ async function loadCDKStatus() {
5524
+ const { cdk } = useProject().config;
5525
+ const client = useAWSClient(CloudFormationClient3);
5526
+ const stackName = cdk?.toolkitStackName || CDK_STACK_NAME;
5527
+ try {
5528
+ const { Stacks: stacks } = await client.send(
5529
+ new DescribeStacksCommand2({ StackName: stackName })
5530
+ );
5531
+ if (!stacks || stacks.length === 0)
5532
+ return false;
5533
+ if (!["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
5534
+ return false;
5535
+ }
5536
+ const output = stacks[0].Outputs?.find(
5537
+ (o) => o.OutputKey === "BootstrapVersion"
5538
+ );
5539
+ if (!output || parseInt(output.OutputValue) < 14)
5540
+ return false;
5541
+ return true;
5542
+ } catch (e) {
5543
+ if (e.name === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
5544
+ return false;
5545
+ } else {
5546
+ throw e;
5547
+ }
5772
5548
  }
5773
5549
  }
5774
- function formatErrorMessage(message) {
5775
- return formatCustomDomainError(message) || `Could not resolve context values for ${message}`;
5776
- }
5777
- function formatCustomDomainError(message) {
5778
- const ret = message.match(/hosted-zone:account=\d+:domainName=(\S+):/);
5779
- if (!ret) {
5780
- return;
5550
+ async function loadSSTStatus() {
5551
+ const { bootstrap } = useProject().config;
5552
+ const cf = useAWSClient(CloudFormationClient3);
5553
+ const stackName = bootstrap?.stackName || SST_STACK_NAME;
5554
+ let result;
5555
+ try {
5556
+ result = await cf.send(
5557
+ new DescribeStacksCommand2({
5558
+ StackName: stackName
5559
+ })
5560
+ );
5561
+ } catch (e) {
5562
+ if (e.Code === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
5563
+ return null;
5564
+ }
5565
+ throw e;
5781
5566
  }
5782
- const hostedZone = ret && ret[1];
5783
- return [
5784
- `It seems you are configuring custom domains for you URL.`,
5785
- hostedZone ? `And SST is not able to find the hosted zone "${hostedZone}" in your AWS Route 53 account.` : `And SST is not able to find the hosted zone in your AWS Route 53 account.`,
5786
- `Please double check and make sure the zone exists, or pass in a different zone.`
5787
- ].join(" ");
5567
+ let version2, bucket;
5568
+ (result.Stacks[0].Outputs || []).forEach((o) => {
5569
+ if (o.OutputKey === OUTPUT_VERSION) {
5570
+ version2 = o.OutputValue;
5571
+ } else if (o.OutputKey === OUTPUT_BUCKET) {
5572
+ bucket = o.OutputValue;
5573
+ }
5574
+ });
5575
+ if (!version2 || !bucket) {
5576
+ return null;
5577
+ }
5578
+ return { version: version2, bucket };
5788
5579
  }
5789
- var init_synth = __esm({
5790
- "src/stacks/synth.ts"() {
5791
- "use strict";
5792
- init_logger();
5793
- init_project();
5794
- init_credentials();
5795
- init_error();
5796
- init_dotnet();
5580
+ async function bootstrapSST() {
5581
+ const { region, bootstrap, cdk } = useProject().config;
5582
+ const app = new App();
5583
+ const stackName = bootstrap?.stackName || SST_STACK_NAME;
5584
+ const stack = new Stack(app, stackName, {
5585
+ env: {
5586
+ region
5587
+ },
5588
+ synthesizer: new DefaultStackSynthesizer({
5589
+ qualifier: cdk?.qualifier,
5590
+ fileAssetsBucketName: cdk?.fileAssetsBucketName
5591
+ })
5592
+ });
5593
+ for (const [key, value] of Object.entries(bootstrap?.tags || {})) {
5594
+ Tags.of(app).add(key, value);
5797
5595
  }
5798
- });
5799
-
5800
- // src/stacks/remove.ts
5801
- import {
5802
- CloudFormationClient as CloudFormationClient3,
5803
- DeleteStackCommand
5804
- } from "@aws-sdk/client-cloudformation";
5805
- async function removeMany(stacks) {
5806
- await useAWSProvider();
5807
- const bus = useBus();
5808
- const complete = /* @__PURE__ */ new Set();
5809
- const todo = new Set(stacks.map((s) => s.id));
5810
- const results = {};
5811
- return new Promise((resolve) => {
5812
- async function trigger() {
5813
- for (const stack of stacks) {
5814
- if (!todo.has(stack.id))
5815
- continue;
5816
- Logger.debug("Checking if", stack.id, "can be removed");
5817
- const waiting = stacks.filter((dependant) => {
5818
- if (dependant.id === stack.id)
5819
- return false;
5820
- if (complete.has(dependant.id))
5821
- return false;
5822
- return dependant.dependencies?.some((d) => d.id === stack.id);
5823
- });
5824
- if (waiting.length) {
5825
- Logger.debug(
5826
- "Waiting on",
5827
- waiting.map((s) => s.id)
5828
- );
5829
- continue;
5596
+ const bucket = new Bucket(stack, region, {
5597
+ encryption: BucketEncryption.S3_MANAGED,
5598
+ removalPolicy: RemovalPolicy.DESTROY,
5599
+ autoDeleteObjects: true,
5600
+ blockPublicAccess: cdk?.publicAccessBlockConfiguration !== false ? BlockPublicAccess.BLOCK_ALL : void 0
5601
+ });
5602
+ const fn = new Function(stack, "MetadataHandler", {
5603
+ code: Code.fromAsset(
5604
+ path16.resolve(__dirname2, "support/bootstrap-metadata-function")
5605
+ ),
5606
+ handler: "index.handler",
5607
+ runtime: region?.startsWith("us-gov-") ? Runtime2.NODEJS_16_X : Runtime2.NODEJS_18_X,
5608
+ environment: {
5609
+ BUCKET_NAME: bucket.bucketName
5610
+ },
5611
+ initialPolicy: [
5612
+ new PolicyStatement({
5613
+ actions: ["cloudformation:DescribeStacks"],
5614
+ resources: ["*"]
5615
+ }),
5616
+ new PolicyStatement({
5617
+ actions: ["s3:PutObject", "s3:DeleteObject"],
5618
+ resources: [bucket.bucketArn + "/*"]
5619
+ }),
5620
+ new PolicyStatement({
5621
+ actions: ["iot:Publish"],
5622
+ resources: [
5623
+ `arn:${stack.partition}:iot:${stack.region}:${stack.account}:topic//sst/*`
5624
+ ]
5625
+ })
5626
+ ]
5627
+ });
5628
+ const queue = new Queue(stack, "MetadataQueue", {
5629
+ visibilityTimeout: Duration.seconds(30),
5630
+ retentionPeriod: Duration.minutes(2)
5631
+ });
5632
+ fn.addEventSource(new SqsEventSource(queue));
5633
+ const rule = new Rule(stack, "MetadataRule", {
5634
+ eventPattern: {
5635
+ source: ["aws.cloudformation"],
5636
+ detailType: ["CloudFormation Stack Status Change"],
5637
+ detail: {
5638
+ "status-details": {
5639
+ status: [
5640
+ "CREATE_COMPLETE",
5641
+ "UPDATE_COMPLETE",
5642
+ "UPDATE_ROLLBACK_COMPLETE",
5643
+ "ROLLBACK_COMPLETE",
5644
+ "DELETE_COMPLETE"
5645
+ ]
5830
5646
  }
5831
- remove(stack).then((result) => {
5832
- results[stack.id] = result;
5833
- complete.add(stack.id);
5834
- if (isFailed(result.status))
5835
- stacks.forEach((s) => {
5836
- if (todo.delete(s.stackName)) {
5837
- complete.add(s.stackName);
5838
- results[s.id] = {
5839
- status: "DEPENDENCY_FAILED",
5840
- outputs: {},
5841
- errors: {}
5842
- };
5843
- bus.publish("stack.status", {
5844
- stackID: s.id,
5845
- status: "DEPENDENCY_FAILED"
5846
- });
5847
- }
5848
- });
5849
- if (complete.size === stacks.length) {
5850
- resolve(results);
5851
- }
5852
- trigger();
5853
- });
5854
- todo.delete(stack.id);
5855
5647
  }
5856
5648
  }
5857
- trigger();
5649
+ });
5650
+ rule.addTarget(
5651
+ new SqsQueue(queue, {
5652
+ retryAttempts: 10
5653
+ })
5654
+ );
5655
+ new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
5656
+ new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
5657
+ const asm = app.synth();
5658
+ const result = await stacks_exports.deploy(asm.stacks[0]);
5659
+ if (stacks_exports.isFailed(result.status)) {
5660
+ throw new VisibleError(
5661
+ `Failed to deploy bootstrap stack:
5662
+ ${JSON.stringify(
5663
+ result.errors,
5664
+ null,
5665
+ 4
5666
+ )}`
5667
+ );
5668
+ }
5669
+ }
5670
+ async function bootstrapCDK() {
5671
+ const identity = await useSTSIdentity();
5672
+ const credentials = await useAWSCredentials();
5673
+ const { region, profile, cdk } = useProject().config;
5674
+ cdk || {};
5675
+ await new Promise((resolve, reject) => {
5676
+ const proc = spawn6(
5677
+ [
5678
+ "npx",
5679
+ "cdk",
5680
+ "bootstrap",
5681
+ `aws://${identity.Account}/${region}`,
5682
+ "--no-version-reporting",
5683
+ ...cdk?.publicAccessBlockConfiguration === false ? ["--public-access-block-configuration", "false"] : cdk?.publicAccessBlockConfiguration === true ? ["--public-access-block-configuration", "false"] : [],
5684
+ ...cdk?.toolkitStackName ? ["--toolkit-stack-name", cdk.toolkitStackName] : [],
5685
+ ...cdk?.qualifier ? ["--qualifier", cdk.qualifier] : [],
5686
+ ...cdk?.fileAssetsBucketName ? ["--toolkit-bucket-name", cdk.fileAssetsBucketName] : []
5687
+ ].join(" "),
5688
+ {
5689
+ env: {
5690
+ ...process.env,
5691
+ AWS_ACCESS_KEY_ID: credentials.accessKeyId,
5692
+ AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
5693
+ AWS_SESSION_TOKEN: credentials.sessionToken,
5694
+ AWS_REGION: region,
5695
+ AWS_PROFILE: profile
5696
+ },
5697
+ stdio: "pipe",
5698
+ shell: true
5699
+ }
5700
+ );
5701
+ let stderr = "";
5702
+ proc.stdout.on("data", (data2) => {
5703
+ Logger.debug(data2.toString());
5704
+ });
5705
+ proc.stderr.on("data", (data2) => {
5706
+ Logger.debug(data2.toString());
5707
+ stderr += data2;
5708
+ });
5709
+ proc.on("exit", (code) => {
5710
+ Logger.debug("CDK bootstrap exited with code " + code);
5711
+ if (code === 0) {
5712
+ resolve();
5713
+ } else {
5714
+ console.log(bold(dim(stderr)));
5715
+ reject(new VisibleError(`Failed to bootstrap`));
5716
+ }
5717
+ });
5858
5718
  });
5859
5719
  }
5860
- async function remove(stack) {
5861
- Logger.debug("Removing stack", stack.id);
5862
- const cfn = useAWSClient(CloudFormationClient3);
5863
- try {
5864
- await cfn.send(
5865
- new DeleteStackCommand({
5866
- StackName: stack.stackName
5867
- })
5868
- );
5869
- return monitor(stack.stackName);
5870
- } catch (ex) {
5871
- return {
5872
- errors: {
5873
- stack: ex.message
5874
- },
5875
- outputs: {},
5876
- status: "UPDATE_FAILED"
5877
- };
5720
+ var CDK_STACK_NAME, SST_STACK_NAME, OUTPUT_VERSION, OUTPUT_BUCKET, LATEST_VERSION, __dirname2, useBootstrap;
5721
+ var init_bootstrap = __esm({
5722
+ "src/bootstrap.ts"() {
5723
+ "use strict";
5724
+ init_project();
5725
+ init_spinner();
5726
+ init_context();
5727
+ init_credentials();
5728
+ init_error();
5729
+ init_logger();
5730
+ init_stacks();
5731
+ CDK_STACK_NAME = "CDKToolkit";
5732
+ SST_STACK_NAME = "SSTBootstrap";
5733
+ OUTPUT_VERSION = "Version";
5734
+ OUTPUT_BUCKET = "BucketName";
5735
+ LATEST_VERSION = "7";
5736
+ __dirname2 = url8.fileURLToPath(new URL(".", import.meta.url));
5737
+ useBootstrap = Context.memo(async () => {
5738
+ Logger.debug("Initializing bootstrap context");
5739
+ let [cdkStatus, sstStatus] = await Promise.all([
5740
+ loadCDKStatus(),
5741
+ loadSSTStatus()
5742
+ ]);
5743
+ Logger.debug("Loaded bootstrap status");
5744
+ const needToBootstrapCDK = !cdkStatus;
5745
+ const needToBootstrapSST = !sstStatus || sstStatus.version !== LATEST_VERSION;
5746
+ if (needToBootstrapCDK || needToBootstrapSST) {
5747
+ const spinner = createSpinner(
5748
+ "Deploying bootstrap stack, this only needs to happen once"
5749
+ ).start();
5750
+ if (needToBootstrapCDK) {
5751
+ await bootstrapCDK();
5752
+ }
5753
+ if (needToBootstrapSST) {
5754
+ await bootstrapSST();
5755
+ sstStatus = await loadSSTStatus();
5756
+ if (!sstStatus)
5757
+ throw new VisibleError("Failed to load bootstrap stack status");
5758
+ }
5759
+ spinner.succeed();
5760
+ }
5761
+ Logger.debug("Bootstrap context initialized", sstStatus);
5762
+ return sstStatus;
5763
+ }, "Bootstrap");
5878
5764
  }
5879
- }
5880
- var init_remove = __esm({
5881
- "src/stacks/remove.ts"() {
5765
+ });
5766
+
5767
+ // src/iot.ts
5768
+ var iot_exports = {};
5769
+ __export(iot_exports, {
5770
+ useIOT: () => useIOT,
5771
+ useIOTEndpoint: () => useIOTEndpoint
5772
+ });
5773
+ import { IoTClient, DescribeEndpointCommand } from "@aws-sdk/client-iot";
5774
+ import iot from "aws-iot-device-sdk";
5775
+ import { PutObjectCommand as PutObjectCommand2, S3Client as S3Client3 } from "@aws-sdk/client-s3";
5776
+ var useIOTEndpoint, useIOT;
5777
+ var init_iot = __esm({
5778
+ "src/iot.ts"() {
5882
5779
  "use strict";
5883
- init_bus();
5780
+ init_context();
5884
5781
  init_credentials();
5782
+ init_error();
5783
+ init_bus();
5784
+ init_project();
5885
5785
  init_logger();
5886
- init_monitor();
5786
+ init_bootstrap();
5787
+ useIOTEndpoint = Context.memo(async () => {
5788
+ const iot2 = useAWSClient(IoTClient);
5789
+ Logger.debug("Getting IoT endpoint");
5790
+ const response = await iot2.send(
5791
+ new DescribeEndpointCommand({
5792
+ endpointType: "iot:Data-ATS"
5793
+ })
5794
+ );
5795
+ Logger.debug("Using IoT endpoint:", response.endpointAddress);
5796
+ if (!response.endpointAddress)
5797
+ throw new VisibleError("IoT Endpoint address not found");
5798
+ return response.endpointAddress;
5799
+ });
5800
+ useIOT = Context.memo(async () => {
5801
+ const bus = useBus();
5802
+ const endpoint = await useIOTEndpoint();
5803
+ const creds = await useAWSCredentials();
5804
+ const project = useProject();
5805
+ const bootstrap = await useBootstrap();
5806
+ const s3 = useAWSClient(S3Client3);
5807
+ async function encode(input) {
5808
+ const id = Math.random().toString();
5809
+ const json = JSON.stringify(input);
5810
+ if (json.length > 1024 * 1024 * 3) {
5811
+ const key = `pointers/${id}`;
5812
+ await s3.send(
5813
+ new PutObjectCommand2({
5814
+ Bucket: bootstrap.bucket,
5815
+ Key: key,
5816
+ Body: json
5817
+ })
5818
+ );
5819
+ return [
5820
+ {
5821
+ id,
5822
+ index: 0,
5823
+ count: 1,
5824
+ data: JSON.stringify({
5825
+ type: "pointer",
5826
+ properties: {
5827
+ key,
5828
+ bucket: bootstrap.bucket
5829
+ }
5830
+ })
5831
+ }
5832
+ ];
5833
+ }
5834
+ const parts = json.match(/.{1,100000}/g);
5835
+ if (!parts)
5836
+ return [];
5837
+ Logger.debug("Encoded iot message into", parts?.length, "parts");
5838
+ return parts.map((part, index) => ({
5839
+ id,
5840
+ index,
5841
+ count: parts?.length,
5842
+ data: part
5843
+ }));
5844
+ }
5845
+ const device = new iot.device({
5846
+ protocol: "wss",
5847
+ host: endpoint,
5848
+ region: project.config.region,
5849
+ accessKeyId: creds.accessKeyId,
5850
+ secretKey: creds.secretAccessKey,
5851
+ sessionToken: creds.sessionToken,
5852
+ reconnectPeriod: 1
5853
+ });
5854
+ const PREFIX2 = `/sst/${project.config.name}/${project.config.stage}`;
5855
+ device.subscribe(`${PREFIX2}/events`, { qos: 1 });
5856
+ const fragments = /* @__PURE__ */ new Map();
5857
+ device.on("connect", () => {
5858
+ Logger.debug("IoT connected");
5859
+ });
5860
+ device.on("error", (err) => {
5861
+ Logger.debug("IoT error", err);
5862
+ });
5863
+ device.on("close", () => {
5864
+ Logger.debug("IoT closed");
5865
+ });
5866
+ device.on("reconnect", () => {
5867
+ Logger.debug("IoT reconnected");
5868
+ });
5869
+ device.on("message", (_topic, buffer) => {
5870
+ const fragment = JSON.parse(buffer.toString());
5871
+ if (!fragment.id) {
5872
+ bus.publish(fragment.type, fragment.properties);
5873
+ return;
5874
+ }
5875
+ let pending = fragments.get(fragment.id);
5876
+ if (!pending) {
5877
+ pending = /* @__PURE__ */ new Map();
5878
+ fragments.set(fragment.id, pending);
5879
+ }
5880
+ pending.set(fragment.index, fragment);
5881
+ if (pending.size === fragment.count) {
5882
+ const data2 = [...pending.values()].sort((a, b) => a.index - b.index).map((item) => item.data).join("");
5883
+ fragments.delete(fragment.id);
5884
+ const evt = JSON.parse(data2);
5885
+ if (evt.sourceID === bus.sourceID)
5886
+ return;
5887
+ bus.publish(evt.type, evt.properties);
5888
+ }
5889
+ });
5890
+ return {
5891
+ prefix: PREFIX2,
5892
+ async publish(topic, type, properties) {
5893
+ const payload = {
5894
+ type,
5895
+ properties,
5896
+ sourceID: bus.sourceID
5897
+ };
5898
+ for (const fragment of await encode(payload)) {
5899
+ await new Promise((r) => {
5900
+ device.publish(
5901
+ topic,
5902
+ JSON.stringify(fragment),
5903
+ {
5904
+ qos: 1
5905
+ },
5906
+ () => {
5907
+ r();
5908
+ }
5909
+ );
5910
+ });
5911
+ }
5912
+ Logger.debug("IOT Published", topic, type);
5913
+ }
5914
+ };
5915
+ });
5887
5916
  }
5888
5917
  });
5889
5918
 
5890
- // src/stacks/index.ts
5891
- var stacks_exports = {};
5892
- __export(stacks_exports, {
5893
- STATUSES: () => STATUSES,
5894
- Stacks: () => stacks_exports,
5895
- clearAppMetadata: () => clearAppMetadata,
5896
- deploy: () => deploy,
5897
- deployMany: () => deployMany,
5898
- diff: () => diff,
5899
- filterOutputs: () => filterOutputs,
5900
- isFailed: () => isFailed,
5901
- isFinal: () => isFinal,
5902
- isPending: () => isPending,
5903
- isSuccess: () => isSuccess,
5904
- load: () => load,
5905
- loadAssembly: () => loadAssembly,
5906
- metadata: () => metadata2,
5907
- metadataForStack: () => metadataForStack,
5908
- monitor: () => monitor,
5909
- publishAssets: () => publishAssets4,
5910
- remove: () => remove,
5911
- removeMany: () => removeMany,
5912
- saveAppMetadata: () => saveAppMetadata,
5913
- synth: () => synth,
5914
- useAppMetadata: () => useAppMetadata,
5915
- useMetadata: () => useMetadata
5919
+ // src/runtime/iot.ts
5920
+ var iot_exports2 = {};
5921
+ __export(iot_exports2, {
5922
+ useIOTBridge: () => useIOTBridge
5916
5923
  });
5917
- var init_stacks = __esm({
5918
- "src/stacks/index.ts"() {
5924
+ var useIOTBridge;
5925
+ var init_iot2 = __esm({
5926
+ "src/runtime/iot.ts"() {
5919
5927
  "use strict";
5920
- init_app_metadata();
5921
- init_assembly();
5922
- init_build();
5923
- init_deploy();
5924
- init_diff();
5925
- init_metadata();
5926
- init_synth();
5927
- init_monitor();
5928
- init_remove();
5929
- init_stacks();
5928
+ init_context();
5929
+ init_bus();
5930
+ init_iot();
5931
+ useIOTBridge = Context.memo(async () => {
5932
+ const bus = useBus();
5933
+ const iot2 = await useIOT();
5934
+ const topic = `${iot2.prefix}/events`;
5935
+ bus.subscribe("function.success", async (evt) => {
5936
+ iot2.publish(
5937
+ topic + "/" + evt.properties.workerID,
5938
+ "function.success",
5939
+ evt.properties
5940
+ );
5941
+ });
5942
+ bus.subscribe("function.error", async (evt) => {
5943
+ iot2.publish(
5944
+ topic + "/" + evt.properties.workerID,
5945
+ "function.error",
5946
+ evt.properties
5947
+ );
5948
+ });
5949
+ bus.subscribe("function.ack", async (evt) => {
5950
+ iot2.publish(
5951
+ topic + "/" + evt.properties.workerID,
5952
+ "function.ack",
5953
+ evt.properties
5954
+ );
5955
+ });
5956
+ });
5930
5957
  }
5931
5958
  });
5932
5959