sst 2.2.7 → 2.3.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/sst.mjs CHANGED
@@ -177,6 +177,13 @@ var init_module = __esm({
177
177
  });
178
178
 
179
179
  // src/util/fs.ts
180
+ var fs_exports = {};
181
+ __export(fs_exports, {
182
+ existsAsync: () => existsAsync,
183
+ findAbove: () => findAbove,
184
+ findBelow: () => findBelow,
185
+ isChild: () => isChild
186
+ });
180
187
  import fs2 from "fs/promises";
181
188
  import path2 from "path";
182
189
  async function findAbove(dir, target) {
@@ -746,65 +753,6 @@ var init_spinner = __esm({
746
753
  }
747
754
  });
748
755
 
749
- // src/site-env.ts
750
- var site_env_exports = {};
751
- __export(site_env_exports, {
752
- SiteEnv: () => site_env_exports,
753
- append: () => append,
754
- keys: () => keys,
755
- reset: () => reset2,
756
- values: () => values,
757
- valuesFile: () => valuesFile,
758
- writeValues: () => writeValues
759
- });
760
- import fs5 from "fs";
761
- import path5 from "path";
762
- function keysFile() {
763
- return path5.join(useProject().paths.out, "site-environment-keys.jsonl");
764
- }
765
- function valuesFile() {
766
- return path5.join(useProject().paths.out, "site-environment-values.json");
767
- }
768
- async function keys() {
769
- try {
770
- const file = keysFile();
771
- const data2 = await fs5.promises.readFile(file).then((x) => x.toString().split("\n"));
772
- return data2.filter(Boolean).map((x) => JSON.parse(x));
773
- } catch {
774
- return [];
775
- }
776
- }
777
- async function values() {
778
- try {
779
- const file = valuesFile();
780
- const data2 = await fs5.promises.readFile(file).then((x) => JSON.parse(x.toString()));
781
- return data2;
782
- } catch {
783
- return {};
784
- }
785
- }
786
- async function writeValues(input) {
787
- const file = valuesFile();
788
- await fs5.promises.writeFile(file, JSON.stringify(input));
789
- }
790
- function append(input) {
791
- input.path = path5.resolve(useProject().paths.root, input.path);
792
- fs5.appendFileSync(keysFile(), JSON.stringify(input) + "\n");
793
- }
794
- function reset2() {
795
- fs5.rmSync(keysFile(), {
796
- force: true,
797
- recursive: true
798
- });
799
- }
800
- var init_site_env = __esm({
801
- "src/site-env.ts"() {
802
- "use strict";
803
- init_site_env();
804
- init_project();
805
- }
806
- });
807
-
808
756
  // ../../node_modules/.pnpm/tslib@2.5.0/node_modules/tslib/tslib.es6.js
809
757
  var tslib_es6_exports = {};
810
758
  __export(tslib_es6_exports, {
@@ -1742,6 +1690,110 @@ var init_credentials = __esm({
1742
1690
  }
1743
1691
  });
1744
1692
 
1693
+ // src/stacks/app-metadata.ts
1694
+ import {
1695
+ S3Client,
1696
+ GetObjectCommand,
1697
+ PutObjectCommand,
1698
+ DeleteObjectCommand
1699
+ } from "@aws-sdk/client-s3";
1700
+ async function metadata() {
1701
+ Logger.debug("Fetching app metadata");
1702
+ const [project, credentials, bootstrap2] = await Promise.all([
1703
+ useProject(),
1704
+ useAWSCredentials(),
1705
+ useBootstrap()
1706
+ ]);
1707
+ const s3 = new S3Client({
1708
+ region: project.config.region,
1709
+ credentials
1710
+ });
1711
+ try {
1712
+ const result = await s3.send(
1713
+ new GetObjectCommand({
1714
+ Key: useS3Key(),
1715
+ Bucket: bootstrap2.bucket
1716
+ })
1717
+ );
1718
+ const body = await result.Body.transformToString();
1719
+ return JSON.parse(body);
1720
+ } catch (ex) {
1721
+ Logger.debug("Fetching app metadata: not found");
1722
+ }
1723
+ }
1724
+ async function saveAppMetadata(data2) {
1725
+ Logger.debug("Saving app metadata");
1726
+ const [project, credentials, bootstrap2] = await Promise.all([
1727
+ useProject(),
1728
+ useAWSCredentials(),
1729
+ useBootstrap()
1730
+ ]);
1731
+ const s3 = new S3Client({
1732
+ region: project.config.region,
1733
+ credentials
1734
+ });
1735
+ try {
1736
+ await s3.send(
1737
+ new PutObjectCommand({
1738
+ Key: useS3Key(),
1739
+ Bucket: bootstrap2.bucket,
1740
+ Body: JSON.stringify(data2)
1741
+ })
1742
+ );
1743
+ } catch (ex) {
1744
+ Logger.debug("Saving app metadata: not found");
1745
+ }
1746
+ }
1747
+ async function clearAppMetadata() {
1748
+ Logger.debug("Clearing app metadata");
1749
+ const [project, credentials, bootstrap2] = await Promise.all([
1750
+ useProject(),
1751
+ useAWSCredentials(),
1752
+ useBootstrap()
1753
+ ]);
1754
+ const s3 = new S3Client({
1755
+ region: project.config.region,
1756
+ credentials
1757
+ });
1758
+ await s3.send(
1759
+ new DeleteObjectCommand({
1760
+ Key: useS3Key(),
1761
+ Bucket: bootstrap2.bucket
1762
+ })
1763
+ );
1764
+ }
1765
+ function useS3Key() {
1766
+ const project = useProject();
1767
+ return `appMetadata/app.${project.config.name}/stage.${project.config.stage}.json`;
1768
+ }
1769
+ var MetadataContext, useAppMetadata;
1770
+ var init_app_metadata = __esm({
1771
+ "src/stacks/app-metadata.ts"() {
1772
+ "use strict";
1773
+ init_bootstrap();
1774
+ init_credentials();
1775
+ init_context();
1776
+ init_logger();
1777
+ init_project();
1778
+ MetadataContext = Context.create(async () => {
1779
+ const data2 = await metadata();
1780
+ return data2;
1781
+ });
1782
+ useAppMetadata = MetadataContext.use;
1783
+ }
1784
+ });
1785
+
1786
+ // src/stacks/assembly.ts
1787
+ async function loadAssembly(from) {
1788
+ const { CloudAssembly } = await import("aws-cdk-lib/cx-api");
1789
+ return new CloudAssembly(from);
1790
+ }
1791
+ var init_assembly = __esm({
1792
+ "src/stacks/assembly.ts"() {
1793
+ "use strict";
1794
+ }
1795
+ });
1796
+
1745
1797
  // src/bus.ts
1746
1798
  var bus_exports = {};
1747
1799
  __export(bus_exports, {
@@ -1806,1282 +1858,366 @@ var init_bus = __esm({
1806
1858
  }
1807
1859
  });
1808
1860
 
1809
- // src/cli/local/router.ts
1810
- import * as trpc from "@trpc/server";
1811
- var router2;
1812
- var init_router = __esm({
1813
- "src/cli/local/router.ts"() {
1814
- "use strict";
1815
- init_project();
1816
- init_bus();
1817
- init_credentials();
1818
- router2 = trpc.router().query("getCredentials", {
1819
- async resolve({ ctx }) {
1820
- const project = useProject();
1821
- const credentials = await useAWSCredentials();
1822
- return {
1823
- region: project.config.region,
1824
- credentials: {
1825
- accessKeyId: credentials.accessKeyId,
1826
- secretAccessKey: credentials.secretAccessKey,
1827
- sessionToken: credentials.sessionToken
1861
+ // src/stacks/monitor.ts
1862
+ import {
1863
+ CloudFormationClient,
1864
+ DescribeStackResourcesCommand,
1865
+ DescribeStacksCommand,
1866
+ DescribeStackEventsCommand
1867
+ } from "@aws-sdk/client-cloudformation";
1868
+ import { map, omitBy, pipe } from "remeda";
1869
+ function isFinal(input) {
1870
+ return STATUSES_SUCCESS.includes(input) || STATUSES_FAILED.includes(input);
1871
+ }
1872
+ function isFailed(input) {
1873
+ return STATUSES_FAILED.includes(input);
1874
+ }
1875
+ function isSuccess(input) {
1876
+ return STATUSES_SUCCESS.includes(input);
1877
+ }
1878
+ function isPending(input) {
1879
+ return STATUSES_PENDING.includes(input);
1880
+ }
1881
+ async function monitor(stack) {
1882
+ const [cfn, bus] = await Promise.all([
1883
+ useAWSClient(CloudFormationClient),
1884
+ useBus()
1885
+ ]);
1886
+ let lastStatus;
1887
+ const errors = {};
1888
+ let lastEvent;
1889
+ while (true) {
1890
+ try {
1891
+ const [describe, resources, events] = await Promise.all([
1892
+ cfn.send(
1893
+ new DescribeStacksCommand({
1894
+ StackName: stack
1895
+ })
1896
+ ),
1897
+ cfn.send(
1898
+ new DescribeStackResourcesCommand({
1899
+ StackName: stack
1900
+ })
1901
+ ),
1902
+ cfn.send(
1903
+ new DescribeStackEventsCommand({
1904
+ StackName: stack
1905
+ })
1906
+ )
1907
+ ]);
1908
+ Logger.debug("Stack description", describe);
1909
+ if (lastEvent) {
1910
+ const eventsReversed = [...events.StackEvents ?? []].reverse();
1911
+ for (const event of eventsReversed) {
1912
+ if (!event.Timestamp)
1913
+ continue;
1914
+ if (event.Timestamp.getTime() > lastEvent.getTime()) {
1915
+ bus.publish("stack.event", {
1916
+ event,
1917
+ stackID: stack
1918
+ });
1919
+ if (event.ResourceStatusReason) {
1920
+ if (event.ResourceStatusReason.includes(
1921
+ "Resource creation cancelled"
1922
+ ) || event.ResourceStatusReason.includes(
1923
+ "Resource update cancelled"
1924
+ ) || event.ResourceStatusReason.includes(
1925
+ "Resource creation Initiated"
1926
+ ) || event.ResourceStatusReason.startsWith(
1927
+ "The following resource(s) failed to"
1928
+ ))
1929
+ continue;
1930
+ errors[event.LogicalResourceId] = event.ResourceStatusReason;
1931
+ }
1828
1932
  }
1829
- };
1830
- }
1831
- }).query("getState", {
1832
- async resolve({ ctx }) {
1833
- return ctx.state;
1933
+ }
1934
+ Logger.debug("Last event set to", lastEvent);
1834
1935
  }
1835
- }).mutation("deploy", {
1836
- async resolve() {
1837
- return;
1936
+ lastEvent = events.StackEvents?.at(0)?.Timestamp;
1937
+ bus.publish("stack.resources", {
1938
+ stackID: stack,
1939
+ resources: resources.StackResources
1940
+ });
1941
+ for (const resource of resources.StackResources || []) {
1942
+ if (resource.ResourceStatusReason?.includes(
1943
+ "Resource creation cancelled"
1944
+ ) || resource.ResourceStatusReason?.includes(
1945
+ "Resource update cancelled"
1946
+ ) || resource.ResourceStatusReason?.includes(
1947
+ "Resource creation Initiated"
1948
+ ) || resource.ResourceStatusReason?.startsWith(
1949
+ "The following resource(s) failed to"
1950
+ ))
1951
+ continue;
1952
+ if (resource.ResourceStatusReason)
1953
+ errors[resource.LogicalResourceId] = resource.ResourceStatusReason;
1838
1954
  }
1839
- }).subscription("onStateChange", {
1840
- async resolve({ ctx }) {
1841
- const bus = useBus();
1842
- return new trpc.Subscription((emit) => {
1843
- const sub = bus.subscribe("local.patches", (evt) => {
1844
- emit.data(evt.properties);
1955
+ const [first] = describe.Stacks || [];
1956
+ if (first) {
1957
+ if (lastStatus !== first.StackStatus && first.StackStatus) {
1958
+ lastStatus = first.StackStatus;
1959
+ bus.publish("stack.status", {
1960
+ stackID: stack,
1961
+ status: first.StackStatus
1845
1962
  });
1846
- return () => {
1847
- bus.unsubscribe(sub);
1848
- };
1849
- });
1963
+ Logger.debug(first);
1964
+ if (isFinal(first.StackStatus)) {
1965
+ return {
1966
+ status: first.StackStatus,
1967
+ outputs: pipe(
1968
+ first.Outputs || [],
1969
+ map((o) => [o.OutputKey, o.OutputValue]),
1970
+ Object.fromEntries,
1971
+ filterOutputs
1972
+ ),
1973
+ errors: isFailed(first.StackStatus) ? errors : {}
1974
+ };
1975
+ }
1976
+ }
1850
1977
  }
1851
- });
1978
+ } catch (ex) {
1979
+ if (ex.message.includes("does not exist")) {
1980
+ bus.publish("stack.status", {
1981
+ stackID: stack,
1982
+ status: "DELETE_COMPLETE"
1983
+ });
1984
+ return {
1985
+ status: "DELETE_COMPLETE",
1986
+ outputs: {},
1987
+ errors: {}
1988
+ };
1989
+ }
1990
+ }
1991
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
1992
+ }
1993
+ }
1994
+ function filterOutputs(input) {
1995
+ return pipe(
1996
+ input,
1997
+ omitBy((_, key) => {
1998
+ return key.startsWith("Export") || key === "SSTMetadata";
1999
+ })
2000
+ );
2001
+ }
2002
+ var STATUSES_PENDING, STATUSES_SUCCESS, STATUSES_FAILED, STATUSES;
2003
+ var init_monitor = __esm({
2004
+ "src/stacks/monitor.ts"() {
2005
+ "use strict";
2006
+ init_bus();
2007
+ init_credentials();
2008
+ init_logger();
2009
+ STATUSES_PENDING = [
2010
+ "CREATE_IN_PROGRESS",
2011
+ "DELETE_IN_PROGRESS",
2012
+ "REVIEW_IN_PROGRESS",
2013
+ "ROLLBACK_IN_PROGRESS",
2014
+ "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS",
2015
+ "UPDATE_IN_PROGRESS",
2016
+ "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS",
2017
+ "UPDATE_ROLLBACK_IN_PROGRESS"
2018
+ ];
2019
+ STATUSES_SUCCESS = [
2020
+ "CREATE_COMPLETE",
2021
+ "UPDATE_COMPLETE",
2022
+ "DELETE_COMPLETE",
2023
+ "SKIPPED"
2024
+ ];
2025
+ STATUSES_FAILED = [
2026
+ "CREATE_FAILED",
2027
+ "DELETE_FAILED",
2028
+ "ROLLBACK_FAILED",
2029
+ "ROLLBACK_COMPLETE",
2030
+ "UPDATE_FAILED",
2031
+ "UPDATE_ROLLBACK_COMPLETE",
2032
+ "UPDATE_ROLLBACK_FAILED",
2033
+ "DEPENDENCY_FAILED"
2034
+ ];
2035
+ STATUSES = [
2036
+ ...STATUSES_PENDING,
2037
+ ...STATUSES_SUCCESS,
2038
+ ...STATUSES_FAILED
2039
+ ];
1852
2040
  }
1853
2041
  });
1854
2042
 
1855
- // src/cli/local/server.ts
1856
- var server_exports = {};
1857
- __export(server_exports, {
1858
- useLocalServer: () => useLocalServer,
1859
- useLocalServerConfig: () => useLocalServerConfig
2043
+ // src/cdk/util.ts
2044
+ async function callWithRetry(cb) {
2045
+ try {
2046
+ return await cb();
2047
+ } catch (e) {
2048
+ 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") {
2049
+ return await callWithRetry(cb);
2050
+ }
2051
+ throw e;
2052
+ }
2053
+ }
2054
+ var init_util = __esm({
2055
+ "src/cdk/util.ts"() {
2056
+ "use strict";
2057
+ }
1860
2058
  });
1861
- import { produceWithPatches, enablePatches } from "immer";
1862
- import express from "express";
1863
- import fs6 from "fs/promises";
1864
- import { WebSocketServer } from "ws";
1865
- import https2 from "https";
1866
- import http from "http";
1867
- import { applyWSSHandler } from "@trpc/server/adapters/ws/dist/trpc-server-adapters-ws.cjs.js";
1868
- import { optimise } from "dendriform-immer-patch-optimiser";
1869
- import { sync } from "cross-spawn";
1870
- import getPort from "get-port";
1871
- async function useLocalServer(opts) {
1872
- const cfg = await useLocalServerConfig();
1873
- const project = useProject();
1874
- let state2 = {
1875
- app: project.config.name,
1876
- stage: project.config.stage,
1877
- bootstrap: project.config.bootstrap,
1878
- live: opts.live,
1879
- stacks: {
1880
- status: "idle"
1881
- },
1882
- functions: {}
1883
- };
1884
- const rest = express();
1885
- rest.all(`/ping`, (req, res) => {
1886
- res.header("Access-Control-Allow-Origin", "*");
1887
- res.header("Access-Control-Allow-Methods", "GET, PUT, PATCH, POST, DELETE");
1888
- res.header(
1889
- "Access-Control-Allow-Headers",
1890
- req.header("access-control-request-headers")
2059
+
2060
+ // src/cdk/deploy-stack.ts
2061
+ import * as cxapi from "@aws-cdk/cx-api";
2062
+ import fs5 from "fs/promises";
2063
+ import * as uuid from "uuid";
2064
+ import { addMetadataAssetsToManifest } from "sst-aws-cdk/lib/assets.js";
2065
+ import { debug, error, print } from "sst-aws-cdk/lib/logging.js";
2066
+ import { toYAML } from "sst-aws-cdk/lib/serialize.js";
2067
+ import { AssetManifestBuilder } from "sst-aws-cdk/lib/util/asset-manifest-builder.js";
2068
+ import { publishAssets } from "sst-aws-cdk/lib/util/asset-publishing.js";
2069
+ import { contentHash } from "sst-aws-cdk/lib/util/content-hash.js";
2070
+ import { CfnEvaluationException } from "sst-aws-cdk/lib/api/evaluate-cloudformation-template.js";
2071
+ import { tryHotswapDeployment } from "sst-aws-cdk/lib/api/hotswap-deployments.js";
2072
+ import {
2073
+ changeSetHasNoChanges,
2074
+ CloudFormationStack,
2075
+ TemplateParameters,
2076
+ waitForChangeSet,
2077
+ waitForStackDeploy,
2078
+ waitForStackDelete
2079
+ } from "sst-aws-cdk/lib/api/util/cloudformation.js";
2080
+ import { blue as blue2 } from "colorette";
2081
+ async function deployStack(options) {
2082
+ const stackArtifact = options.stack;
2083
+ const stackEnv = options.resolvedEnvironment;
2084
+ options.sdk.appendCustomUserAgent(options.extraUserAgent);
2085
+ const cfn = options.sdk.cloudFormation();
2086
+ const deployName = options.deployName || stackArtifact.stackName;
2087
+ let cloudFormationStack = await callWithRetry(
2088
+ () => CloudFormationStack.lookup(cfn, deployName)
2089
+ );
2090
+ if (cloudFormationStack.stackStatus.isCreationFailure) {
2091
+ debug(
2092
+ `Found existing stack ${deployName} that had previously failed creation. Deleting it before attempting to re-create it.`
1891
2093
  );
1892
- res.sendStatus(200);
1893
- });
1894
- rest.all(
1895
- `/proxy*`,
1896
- express.raw({
1897
- type: "*/*",
1898
- limit: "1024mb"
1899
- }),
1900
- (req, res) => {
1901
- res.header("Access-Control-Allow-Origin", "*");
1902
- res.header(
1903
- "Access-Control-Allow-Methods",
1904
- "GET, PUT, PATCH, POST, DELETE"
1905
- );
1906
- res.header(
1907
- "Access-Control-Allow-Headers",
1908
- req.header("access-control-request-headers")
1909
- );
1910
- if (req.method === "OPTIONS")
1911
- return res.send();
1912
- const u = new URL(req.url.substring(7));
1913
- const forward = https2.request(
1914
- u,
1915
- {
1916
- headers: {
1917
- ...req.headers,
1918
- host: u.hostname
1919
- },
1920
- method: req.method
1921
- },
1922
- (proxied) => {
1923
- res.status(proxied.statusCode);
1924
- for (const [key, value] of Object.entries(proxied.headers)) {
1925
- res.header(key, value);
1926
- }
1927
- proxied.pipe(res);
1928
- }
2094
+ await cfn.deleteStack({ StackName: deployName }).promise();
2095
+ const deletedStack = await waitForStackDelete(cfn, deployName);
2096
+ if (deletedStack && deletedStack.stackStatus.name !== "DELETE_COMPLETE") {
2097
+ throw new Error(
2098
+ `Failed deleting stack ${deployName} that had previously failed creation (current state: ${deletedStack.stackStatus})`
1929
2099
  );
1930
- if (req.method !== "GET" && req.method !== "DELETE" && req.method !== "HEAD" && req.body)
1931
- forward.write(req.body);
1932
- forward.end();
1933
- forward.on("error", (e) => {
1934
- console.log(e.message);
1935
- });
1936
2100
  }
2101
+ cloudFormationStack = CloudFormationStack.doesNotExist(cfn, deployName);
2102
+ }
2103
+ const legacyAssets = new AssetManifestBuilder();
2104
+ const assetParams = await addMetadataAssetsToManifest(
2105
+ stackArtifact,
2106
+ legacyAssets,
2107
+ options.toolkitInfo,
2108
+ options.reuseAssets
1937
2109
  );
1938
- const server = await (async () => {
1939
- const result2 = sync("mkcert", ["--help"]);
1940
- const KEY_PATH = ".sst/localhost-key.pem";
1941
- const CERT_PATH = ".sst/localhost.pem";
1942
- if (result2.status === 0) {
1943
- try {
1944
- await Promise.all([fs6.access(KEY_PATH), fs6.access(CERT_PATH)]);
1945
- } catch (e) {
1946
- sync("mkcert", ["localhost"], {
1947
- cwd: ".sst"
1948
- });
1949
- }
1950
- const [key, cert] = await Promise.all([
1951
- fs6.readFile(KEY_PATH),
1952
- fs6.readFile(CERT_PATH)
1953
- ]);
1954
- return https2.createServer(
1955
- {
1956
- key,
1957
- cert
1958
- },
1959
- rest
1960
- );
2110
+ const finalParameterValues = { ...options.parameters, ...assetParams };
2111
+ const templateParams = TemplateParameters.fromTemplate(
2112
+ stackArtifact.template
2113
+ );
2114
+ const stackParams = options.usePreviousParameters ? templateParams.updateExisting(
2115
+ finalParameterValues,
2116
+ cloudFormationStack.parameters
2117
+ ) : templateParams.supplyAll(finalParameterValues);
2118
+ if (await canSkipDeploy(
2119
+ options,
2120
+ cloudFormationStack,
2121
+ stackParams.hasChanges(cloudFormationStack.parameters)
2122
+ )) {
2123
+ debug(`${deployName}: skipping deployment (use --force to override)`);
2124
+ if (options.hotswap) {
1961
2125
  }
1962
- return http.createServer({}, rest);
1963
- })();
1964
- const wss = new WebSocketServer({ server });
1965
- wss.on("connection", (socket, req) => {
1966
- if (req.headers.origin?.endsWith("localhost:3000"))
1967
- return;
1968
- if (req.headers.origin?.endsWith("localhost:3001"))
1969
- return;
1970
- if (req.headers.origin?.endsWith("console.serverless-stack.com"))
1971
- return;
1972
- if (req.headers.origin?.endsWith("console.sst.dev"))
1973
- return;
1974
- if (req.headers.origin?.endsWith("--sst-console.netlify.app"))
1975
- return;
1976
- console.log("Rejecting unauthorized connection from " + req.headers.origin);
1977
- socket.terminate();
1978
- });
1979
- server.listen(cfg.port);
1980
- const handler = applyWSSHandler({
1981
- wss,
1982
- router: router2,
1983
- createContext() {
1984
- return {
1985
- state: state2
1986
- };
1987
- }
1988
- });
1989
- process.on("SIGTERM", () => {
1990
- handler.broadcastReconnectNotification();
1991
- wss.close();
1992
- });
1993
- const bus = useBus();
1994
- const pending = [];
1995
- function updateState(cb) {
1996
- const [next, patches] = produceWithPatches(state2, cb);
1997
- if (!patches.length)
1998
- return;
1999
- const scheduled = pending.length;
2000
- pending.push(...optimise(state2, patches));
2001
- if (!scheduled)
2002
- setTimeout(() => {
2003
- bus.publish("local.patches", pending);
2004
- pending.splice(0, pending.length);
2005
- }, 0);
2006
- state2 = next;
2007
- }
2008
- function updateFunction(id, cb) {
2009
- return updateState((draft) => {
2010
- let func = draft.functions[id];
2011
- if (!func) {
2012
- func = {
2013
- warm: true,
2014
- state: "idle",
2015
- issues: {},
2016
- invocations: []
2017
- };
2018
- draft.functions[id] = func;
2019
- }
2020
- cb(func);
2021
- });
2126
+ return {
2127
+ noOp: true,
2128
+ outputs: cloudFormationStack.outputs,
2129
+ stackArn: cloudFormationStack.stackId
2130
+ };
2131
+ } else {
2132
+ debug(`${deployName}: deploying...`);
2022
2133
  }
2023
- bus.subscribe("function.invoked", (evt) => {
2024
- updateFunction(evt.properties.functionID, (draft) => {
2025
- if (draft.invocations.length >= 25)
2026
- draft.invocations.pop();
2027
- draft.invocations.unshift({
2028
- id: evt.properties.context.awsRequestId,
2029
- request: evt.properties.event,
2030
- times: {
2031
- start: Date.now()
2032
- },
2033
- logs: []
2034
- });
2035
- });
2036
- });
2037
- bus.subscribe("worker.stdout", (evt) => {
2038
- updateFunction(evt.properties.functionID, (draft) => {
2039
- const entry = draft.invocations.find(
2040
- (i) => i.id === evt.properties.requestID
2134
+ const bodyParameter = await makeBodyParameter(
2135
+ stackArtifact,
2136
+ options.resolvedEnvironment,
2137
+ legacyAssets,
2138
+ options.toolkitInfo,
2139
+ options.sdk,
2140
+ options.overrideTemplate
2141
+ );
2142
+ await publishAssets(
2143
+ legacyAssets.toManifest(stackArtifact.assembly.directory),
2144
+ options.sdkProvider,
2145
+ stackEnv,
2146
+ {
2147
+ parallel: options.assetParallelism
2148
+ }
2149
+ );
2150
+ if (options.hotswap) {
2151
+ try {
2152
+ const hotswapDeploymentResult = await tryHotswapDeployment(
2153
+ options.sdkProvider,
2154
+ assetParams,
2155
+ cloudFormationStack,
2156
+ stackArtifact
2041
2157
  );
2042
- if (!entry)
2043
- return;
2044
- entry.logs.push({
2045
- timestamp: Date.now(),
2046
- message: evt.properties.message
2047
- });
2048
- });
2049
- });
2050
- bus.subscribe("function.success", (evt) => {
2051
- updateFunction(evt.properties.functionID, (draft) => {
2052
- const invocation = draft.invocations.find(
2053
- (x) => x.id === evt.properties.requestID
2158
+ if (hotswapDeploymentResult) {
2159
+ return hotswapDeploymentResult;
2160
+ }
2161
+ print(
2162
+ "Could not perform a hotswap deployment, as the stack %s contains non-Asset changes",
2163
+ stackArtifact.displayName
2054
2164
  );
2055
- if (!invocation)
2056
- return;
2057
- invocation.response = {
2058
- type: "success",
2059
- data: evt.properties.body
2060
- };
2061
- invocation.times.end = Date.now();
2062
- });
2063
- });
2064
- bus.subscribe("function.error", (evt) => {
2065
- updateFunction(evt.properties.functionID, (draft) => {
2066
- const invocation = draft.invocations.find(
2067
- (x) => x.id === evt.properties.requestID
2165
+ } catch (e) {
2166
+ if (!(e instanceof CfnEvaluationException)) {
2167
+ throw e;
2168
+ }
2169
+ print(
2170
+ "Could not perform a hotswap deployment, because the CloudFormation template could not be resolved: %s",
2171
+ e.message
2068
2172
  );
2069
- if (!invocation)
2070
- return;
2071
- invocation.response = {
2072
- type: "failure",
2073
- error: {
2074
- errorMessage: evt.properties.errorMessage,
2075
- stackTrace: evt.properties.trace || []
2076
- }
2077
- };
2078
- invocation.times.end = Date.now();
2079
- });
2080
- });
2081
- const result = {
2082
- updateState,
2083
- updateFunction
2084
- };
2085
- return result;
2173
+ }
2174
+ print("Falling back to doing a full deployment");
2175
+ options.sdk.appendCustomUserAgent("cdk-hotswap/fallback");
2176
+ }
2177
+ const fullDeployment = new FullCloudFormationDeployment(
2178
+ options,
2179
+ cloudFormationStack,
2180
+ stackArtifact,
2181
+ stackParams,
2182
+ bodyParameter
2183
+ );
2184
+ return fullDeployment.performDeployment();
2086
2185
  }
2087
- var useLocalServerConfig;
2088
- var init_server = __esm({
2089
- "src/cli/local/server.ts"() {
2090
- "use strict";
2091
- init_router();
2092
- init_project();
2093
- init_bus();
2094
- init_context();
2095
- enablePatches();
2096
- useLocalServerConfig = Context.memo(async () => {
2097
- const project = useProject();
2098
- const port = await getPort({
2099
- port: 13557
2100
- });
2101
- return {
2102
- port,
2103
- url: `https://console.sst.dev/${project.config.name}/${project.config.stage}${port !== 13557 ? `?_port=${port}` : ""}`
2104
- };
2105
- });
2186
+ async function makeBodyParameter(stack, resolvedEnvironment, assetManifest, toolkitInfo, sdk, overrideTemplate) {
2187
+ if (stack.stackTemplateAssetObjectUrl && !overrideTemplate) {
2188
+ return {
2189
+ TemplateURL: restUrlFromManifest(
2190
+ stack.stackTemplateAssetObjectUrl,
2191
+ resolvedEnvironment,
2192
+ sdk
2193
+ )
2194
+ };
2106
2195
  }
2107
- });
2196
+ const templateJson = toYAML(overrideTemplate ?? stack.template);
2197
+ if (templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024) {
2198
+ return { TemplateBody: templateJson };
2199
+ }
2200
+ if (!toolkitInfo.found) {
2201
+ error(
2202
+ `The template for stack "${stack.displayName}" is ${Math.round(
2203
+ templateJson.length / 1024
2204
+ )}KiB. Templates larger than ${LARGE_TEMPLATE_SIZE_KB}KiB must be uploaded to S3.
2205
+ Run the following command in order to setup an S3 bucket in this environment, and then re-deploy:
2108
2206
 
2109
- // src/cli/ui/header.ts
2110
- var header_exports = {};
2111
- __export(header_exports, {
2112
- printConsole: () => printConsole,
2113
- printHeader: () => printHeader
2114
- });
2115
- async function printHeader(input) {
2116
- const project = useProject();
2117
- Colors.line(
2118
- `${Colors.primary.bold(`SST v${project.version}`)} ${input.hint ? Colors.dim(`ready!`) : ""}`
2119
- );
2120
- Colors.gap();
2121
- Colors.line(
2122
- `${Colors.primary(`\u279C`)} ${Colors.bold("App:")} ${project.config.name}`
2123
- );
2124
- Colors.line(
2125
- `${Colors.primary(` `)} ${Colors.bold("Stage:")} ${project.config.stage}`
2126
- );
2127
- if (input.console) {
2128
- const local = await useLocalServerConfig();
2129
- Colors.line(
2130
- `${Colors.primary(` `)} ${Colors.bold("Console:")} ${Colors.link(
2131
- local.url
2132
- )}`
2207
+ `,
2208
+ blue2(` $ cdk bootstrap ${resolvedEnvironment.name}
2209
+ `)
2210
+ );
2211
+ throw new Error(
2212
+ 'Template too large to deploy ("cdk bootstrap" is required)'
2133
2213
  );
2134
2214
  }
2135
- Colors.gap();
2136
- }
2137
- function printConsole() {
2138
- }
2139
- var init_header = __esm({
2140
- "src/cli/ui/header.ts"() {
2141
- "use strict";
2142
- init_project();
2143
- init_colors();
2144
- init_server();
2145
- }
2146
- });
2147
-
2148
- // src/watcher.ts
2149
- var watcher_exports = {};
2150
- __export(watcher_exports, {
2151
- useWatcher: () => useWatcher
2152
- });
2153
- import chokidar from "chokidar";
2154
- import path6 from "path";
2155
- var useWatcher;
2156
- var init_watcher = __esm({
2157
- "src/watcher.ts"() {
2158
- "use strict";
2159
- init_context();
2160
- init_bus();
2161
- init_project();
2162
- useWatcher = Context.memo(() => {
2163
- const project = useProject();
2164
- const bus = useBus();
2165
- const watcher = chokidar.watch([project.paths.root], {
2166
- persistent: true,
2167
- ignoreInitial: true,
2168
- followSymlinks: false,
2169
- disableGlobbing: false,
2170
- ignored: [
2171
- "**/node_modules/**",
2172
- "**/.build/**",
2173
- "**/.sst/**",
2174
- "**/debug.log"
2175
- ],
2176
- awaitWriteFinish: {
2177
- pollInterval: 100,
2178
- stabilityThreshold: 20
2179
- }
2180
- });
2181
- watcher.on("change", (file) => {
2182
- bus.publish("file.changed", {
2183
- file,
2184
- relative: path6.relative(project.paths.root, file)
2185
- });
2186
- });
2187
- return {
2188
- subscribe: bus.forward("file.changed")
2189
- };
2190
- });
2191
- }
2192
- });
2193
-
2194
- // src/runtime/handlers.ts
2195
- import path7 from "path";
2196
- import fs7 from "fs/promises";
2197
- import { useFunctions } from "../src/constructs/Function.js";
2198
- var useRuntimeHandlers, useFunctionBuilder;
2199
- var init_handlers = __esm({
2200
- "src/runtime/handlers.ts"() {
2201
- "use strict";
2202
- init_context();
2203
- init_logger();
2204
- init_watcher();
2205
- init_bus();
2206
- init_project();
2207
- useRuntimeHandlers = Context.memo(() => {
2208
- const handlers = [];
2209
- const project = useProject();
2210
- const bus = useBus();
2211
- const pendingBuilds = /* @__PURE__ */ new Map();
2212
- const result = {
2213
- subscribe: bus.forward("function.build.success", "function.build.failed"),
2214
- register: (handler) => {
2215
- handlers.push(handler);
2216
- },
2217
- for: (runtime) => {
2218
- const result2 = handlers.find((x) => x.canHandle(runtime));
2219
- if (!result2)
2220
- throw new Error(`${runtime} runtime is unsupported`);
2221
- return result2;
2222
- },
2223
- async build(functionID, mode) {
2224
- async function task() {
2225
- const func = useFunctions().fromID(functionID);
2226
- const handler = result.for(func.runtime);
2227
- const out = path7.join(project.paths.artifacts, functionID);
2228
- await fs7.rm(out, { recursive: true, force: true });
2229
- await fs7.mkdir(out, { recursive: true });
2230
- if (func.hooks?.beforeBuild)
2231
- await func.hooks.beforeBuild(func, out);
2232
- const built = await handler.build({
2233
- functionID,
2234
- out,
2235
- mode,
2236
- props: func
2237
- });
2238
- if (built.type === "error") {
2239
- bus.publish("function.build.failed", {
2240
- functionID,
2241
- errors: built.errors
2242
- });
2243
- return built;
2244
- }
2245
- if (func.copyFiles) {
2246
- await Promise.all(
2247
- func.copyFiles.map(async (entry) => {
2248
- const fromPath = path7.join(project.paths.root, entry.from);
2249
- const to = entry.to || entry.from;
2250
- if (path7.isAbsolute(to))
2251
- throw new Error(
2252
- `Copy destination path "${to}" must be relative`
2253
- );
2254
- const toPath = path7.join(out, to);
2255
- if (mode === "deploy")
2256
- await fs7.cp(fromPath, toPath, {
2257
- recursive: true
2258
- });
2259
- if (mode === "start") {
2260
- const dir = path7.dirname(toPath);
2261
- await fs7.mkdir(dir, { recursive: true });
2262
- await fs7.symlink(fromPath, toPath);
2263
- }
2264
- })
2265
- );
2266
- }
2267
- if (func.hooks?.afterBuild)
2268
- await func.hooks.afterBuild(func, out);
2269
- bus.publish("function.build.success", { functionID });
2270
- return {
2271
- ...built,
2272
- out
2273
- };
2274
- }
2275
- if (pendingBuilds.has(functionID)) {
2276
- Logger.debug("Waiting on pending build", functionID);
2277
- return pendingBuilds.get(functionID);
2278
- }
2279
- const promise = task();
2280
- pendingBuilds.set(functionID, promise);
2281
- Logger.debug("Building function", functionID);
2282
- const r = await promise;
2283
- pendingBuilds.delete(functionID);
2284
- return r;
2285
- }
2286
- };
2287
- return result;
2288
- });
2289
- useFunctionBuilder = Context.memo(() => {
2290
- const artifacts = /* @__PURE__ */ new Map();
2291
- const handlers = useRuntimeHandlers();
2292
- const result = {
2293
- artifact: (functionID) => {
2294
- if (artifacts.has(functionID))
2295
- return artifacts.get(functionID);
2296
- return result.build(functionID);
2297
- },
2298
- build: async (functionID) => {
2299
- const result2 = await handlers.build(functionID, "start");
2300
- if (result2.type === "error")
2301
- return;
2302
- artifacts.set(functionID, result2);
2303
- return artifacts.get(functionID);
2304
- }
2305
- };
2306
- const watcher = useWatcher();
2307
- watcher.subscribe("file.changed", async (evt) => {
2308
- try {
2309
- const functions = useFunctions();
2310
- for (const [functionID, props] of Object.entries(functions.all)) {
2311
- const handler = handlers.for(props.runtime);
2312
- if (!handler?.shouldBuild({
2313
- functionID,
2314
- file: evt.properties.file
2315
- }))
2316
- continue;
2317
- await result.build(functionID);
2318
- Logger.debug("Rebuilt function", functionID);
2319
- }
2320
- } catch {
2321
- }
2322
- });
2323
- return result;
2324
- });
2325
- }
2326
- });
2327
-
2328
- // src/runtime/server.ts
2329
- var server_exports2 = {};
2330
- __export(server_exports2, {
2331
- useRuntimeServer: () => useRuntimeServer,
2332
- useRuntimeServerConfig: () => useRuntimeServerConfig
2333
- });
2334
- import express2 from "express";
2335
- import https3 from "https";
2336
- import getPort2 from "get-port";
2337
- var useRuntimeServerConfig, useRuntimeServer;
2338
- var init_server2 = __esm({
2339
- "src/runtime/server.ts"() {
2340
- "use strict";
2341
- init_context();
2342
- init_bus();
2343
- init_logger();
2344
- init_workers();
2345
- useRuntimeServerConfig = Context.memo(async () => {
2346
- const port = await getPort2({
2347
- port: 12557
2348
- });
2349
- return {
2350
- API_VERSION: "2018-06-01",
2351
- port,
2352
- url: `http://localhost:${port}`
2353
- };
2354
- });
2355
- useRuntimeServer = Context.memo(async () => {
2356
- const bus = useBus();
2357
- const app = express2();
2358
- const workers = await useRuntimeWorkers();
2359
- const cfg = await useRuntimeServerConfig();
2360
- const workersWaiting = /* @__PURE__ */ new Map();
2361
- const invocationsQueued = /* @__PURE__ */ new Map();
2362
- function next(workerID) {
2363
- const queue = invocationsQueued.get(workerID);
2364
- const value = queue?.shift();
2365
- if (value)
2366
- return value;
2367
- return new Promise((resolve, reject) => {
2368
- workersWaiting.set(workerID, resolve);
2369
- });
2370
- }
2371
- workers.subscribe("worker.exited", async (evt) => {
2372
- const waiting = workersWaiting.get(evt.properties.workerID);
2373
- if (!waiting)
2374
- return;
2375
- workersWaiting.delete(evt.properties.workerID);
2376
- });
2377
- bus.subscribe("function.invoked", async (evt) => {
2378
- const worker = workersWaiting.get(evt.properties.workerID);
2379
- if (worker) {
2380
- workersWaiting.delete(evt.properties.workerID);
2381
- worker(evt.properties);
2382
- return;
2383
- }
2384
- let arr = invocationsQueued.get(evt.properties.workerID);
2385
- if (!arr) {
2386
- arr = [];
2387
- invocationsQueued.set(evt.properties.workerID, arr);
2388
- }
2389
- arr.push(evt.properties);
2390
- });
2391
- app.post(
2392
- `/:workerID/${cfg.API_VERSION}/runtime/init/error`,
2393
- express2.json({
2394
- strict: false,
2395
- type: ["application/json", "application/*+json"],
2396
- limit: "10mb"
2397
- }),
2398
- async (req, res) => {
2399
- const worker = workers.fromID(req.params.workerID);
2400
- bus.publish("function.error", {
2401
- requestID: workers.getCurrentRequestID(worker.workerID),
2402
- workerID: worker.workerID,
2403
- functionID: worker.functionID,
2404
- ...req.body
2405
- });
2406
- res.json("ok");
2407
- }
2408
- );
2409
- app.get(
2410
- `/:workerID/${cfg.API_VERSION}/runtime/invocation/next`,
2411
- async (req, res) => {
2412
- Logger.debug(
2413
- "Worker",
2414
- req.params.workerID,
2415
- "is waiting for next invocation"
2416
- );
2417
- const payload = await next(req.params.workerID);
2418
- Logger.debug("Worker", req.params.workerID, "sending next payload");
2419
- res.set({
2420
- "Lambda-Runtime-Aws-Request-Id": payload.context.awsRequestId,
2421
- "Lambda-Runtime-Deadline-Ms": Date.now() + payload.deadline,
2422
- "Lambda-Runtime-Invoked-Function-Arn": payload.context.invokedFunctionArn,
2423
- "Lambda-Runtime-Client-Context": JSON.stringify(
2424
- payload.context.clientContext || null
2425
- ),
2426
- "Lambda-Runtime-Cognito-Identity": JSON.stringify(
2427
- payload.context.identity || null
2428
- ),
2429
- "Lambda-Runtime-Log-Group-Name": payload.context.logGroupName,
2430
- "Lambda-Runtime-Log-Stream-Name": payload.context.logStreamName
2431
- });
2432
- res.json(payload.event);
2433
- }
2434
- );
2435
- app.post(
2436
- `/:workerID/${cfg.API_VERSION}/runtime/invocation/:awsRequestId/response`,
2437
- express2.json({
2438
- strict: false,
2439
- type() {
2440
- return true;
2441
- },
2442
- limit: "10mb"
2443
- }),
2444
- (req, res) => {
2445
- Logger.debug("Worker", req.params.workerID, "got response", req.body);
2446
- const worker = workers.fromID(req.params.workerID);
2447
- bus.publish("function.success", {
2448
- workerID: worker.workerID,
2449
- functionID: worker.functionID,
2450
- requestID: req.params.awsRequestId,
2451
- body: req.body
2452
- });
2453
- res.status(202).send();
2454
- }
2455
- );
2456
- app.all(
2457
- `/proxy*`,
2458
- express2.raw({
2459
- type: "*/*",
2460
- limit: "1024mb"
2461
- }),
2462
- (req, res) => {
2463
- res.header("Access-Control-Allow-Origin", "*");
2464
- res.header(
2465
- "Access-Control-Allow-Methods",
2466
- "GET, PUT, PATCH, POST, DELETE"
2467
- );
2468
- res.header(
2469
- "Access-Control-Allow-Headers",
2470
- req.header("access-control-request-headers")
2471
- );
2472
- if (req.method === "OPTIONS")
2473
- return res.send();
2474
- const u = new URL(req.url.substring(7));
2475
- const forward = https3.request(
2476
- u,
2477
- {
2478
- headers: {
2479
- ...req.headers,
2480
- host: u.hostname
2481
- },
2482
- method: req.method
2483
- },
2484
- (proxied) => {
2485
- res.status(proxied.statusCode);
2486
- for (const [key, value] of Object.entries(proxied.headers)) {
2487
- res.header(key, value);
2488
- }
2489
- proxied.pipe(res);
2490
- }
2491
- );
2492
- if (req.method !== "GET" && req.method !== "DELETE" && req.method !== "HEAD" && req.body)
2493
- forward.write(req.body);
2494
- forward.end();
2495
- forward.on("error", (e) => {
2496
- console.log(e.message);
2497
- });
2498
- }
2499
- );
2500
- app.post(
2501
- `/:workerID/${cfg.API_VERSION}/runtime/invocation/:awsRequestId/error`,
2502
- express2.json({
2503
- strict: false,
2504
- type: ["application/json", "application/*+json"],
2505
- limit: "10mb"
2506
- }),
2507
- (req, res) => {
2508
- const worker = workers.fromID(req.params.workerID);
2509
- bus.publish("function.error", {
2510
- workerID: worker.workerID,
2511
- functionID: worker.functionID,
2512
- errorType: req.body.errorType,
2513
- errorMessage: req.body.errorMessage,
2514
- requestID: req.params.awsRequestId,
2515
- trace: req.body.trace
2516
- });
2517
- res.status(202).send();
2518
- }
2519
- );
2520
- app.listen(cfg.port);
2521
- });
2522
- }
2523
- });
2524
-
2525
- // src/runtime/workers.ts
2526
- var workers_exports = {};
2527
- __export(workers_exports, {
2528
- useRuntimeWorkers: () => useRuntimeWorkers
2529
- });
2530
- import { useFunctions as useFunctions2 } from "../src/constructs/Function.js";
2531
- var useRuntimeWorkers;
2532
- var init_workers = __esm({
2533
- "src/runtime/workers.ts"() {
2534
- "use strict";
2535
- init_context();
2536
- init_bus();
2537
- init_handlers();
2538
- init_server2();
2539
- useRuntimeWorkers = Context.memo(async () => {
2540
- const workers = /* @__PURE__ */ new Map();
2541
- const bus = useBus();
2542
- const handlers = useRuntimeHandlers();
2543
- const builder = useFunctionBuilder();
2544
- const server = await useRuntimeServerConfig();
2545
- handlers.subscribe("function.build.success", async (evt) => {
2546
- for (const [_, worker] of workers) {
2547
- if (worker.functionID === evt.properties.functionID) {
2548
- const props = useFunctions2().fromID(worker.functionID);
2549
- const handler = handlers.for(props.runtime);
2550
- await handler?.stopWorker(worker.workerID);
2551
- bus.publish("worker.stopped", worker);
2552
- }
2553
- }
2554
- });
2555
- const lastRequestId = /* @__PURE__ */ new Map();
2556
- bus.subscribe("function.invoked", async (evt) => {
2557
- bus.publish("function.ack", {
2558
- functionID: evt.properties.functionID,
2559
- workerID: evt.properties.workerID
2560
- });
2561
- lastRequestId.set(evt.properties.workerID, evt.properties.requestID);
2562
- let worker = workers.get(evt.properties.workerID);
2563
- if (worker)
2564
- return;
2565
- const props = useFunctions2().fromID(evt.properties.functionID);
2566
- const handler = handlers.for(props.runtime);
2567
- if (!handler)
2568
- return;
2569
- const build2 = await builder.artifact(evt.properties.functionID);
2570
- if (!build2)
2571
- return;
2572
- await handler.startWorker({
2573
- ...build2,
2574
- workerID: evt.properties.workerID,
2575
- environment: evt.properties.env,
2576
- url: `${server.url}/${evt.properties.workerID}/${server.API_VERSION}`
2577
- });
2578
- workers.set(evt.properties.workerID, {
2579
- workerID: evt.properties.workerID,
2580
- functionID: evt.properties.functionID
2581
- });
2582
- bus.publish("worker.started", {
2583
- workerID: evt.properties.workerID,
2584
- functionID: evt.properties.functionID
2585
- });
2586
- });
2587
- return {
2588
- fromID(workerID) {
2589
- return workers.get(workerID);
2590
- },
2591
- getCurrentRequestID(workerID) {
2592
- return lastRequestId.get(workerID);
2593
- },
2594
- stdout(workerID, message) {
2595
- const worker = workers.get(workerID);
2596
- bus.publish("worker.stdout", {
2597
- ...worker,
2598
- message: message.trim(),
2599
- requestID: lastRequestId.get(workerID)
2600
- });
2601
- },
2602
- exited(workerID) {
2603
- const existing = workers.get(workerID);
2604
- if (!existing)
2605
- return;
2606
- workers.delete(workerID);
2607
- lastRequestId.delete(workerID);
2608
- bus.publish("worker.exited", existing);
2609
- },
2610
- subscribe: bus.forward(
2611
- "worker.started",
2612
- "worker.stopped",
2613
- "worker.exited",
2614
- "worker.stdout"
2615
- )
2616
- };
2617
- });
2618
- }
2619
- });
2620
-
2621
- // src/stacks/app-metadata.ts
2622
- import {
2623
- S3Client,
2624
- GetObjectCommand,
2625
- PutObjectCommand,
2626
- DeleteObjectCommand
2627
- } from "@aws-sdk/client-s3";
2628
- async function metadata() {
2629
- Logger.debug("Fetching app metadata");
2630
- const [project, credentials, bootstrap] = await Promise.all([
2631
- useProject(),
2632
- useAWSCredentials(),
2633
- useBootstrap()
2634
- ]);
2635
- const s3 = new S3Client({
2636
- region: project.config.region,
2637
- credentials
2638
- });
2639
- try {
2640
- const result = await s3.send(
2641
- new GetObjectCommand({
2642
- Key: useS3Key(),
2643
- Bucket: bootstrap.bucket
2644
- })
2645
- );
2646
- const body = await result.Body.transformToString();
2647
- return JSON.parse(body);
2648
- } catch (ex) {
2649
- Logger.debug("Fetching app metadata: not found");
2650
- }
2651
- }
2652
- async function saveAppMetadata(data2) {
2653
- Logger.debug("Saving app metadata");
2654
- const [project, credentials, bootstrap] = await Promise.all([
2655
- useProject(),
2656
- useAWSCredentials(),
2657
- useBootstrap()
2658
- ]);
2659
- const s3 = new S3Client({
2660
- region: project.config.region,
2661
- credentials
2662
- });
2663
- try {
2664
- await s3.send(
2665
- new PutObjectCommand({
2666
- Key: useS3Key(),
2667
- Bucket: bootstrap.bucket,
2668
- Body: JSON.stringify(data2)
2669
- })
2670
- );
2671
- } catch (ex) {
2672
- Logger.debug("Saving app metadata: not found");
2673
- }
2674
- }
2675
- async function clearAppMetadata() {
2676
- Logger.debug("Clearing app metadata");
2677
- const [project, credentials, bootstrap] = await Promise.all([
2678
- useProject(),
2679
- useAWSCredentials(),
2680
- useBootstrap()
2681
- ]);
2682
- const s3 = new S3Client({
2683
- region: project.config.region,
2684
- credentials
2685
- });
2686
- await s3.send(
2687
- new DeleteObjectCommand({
2688
- Key: useS3Key(),
2689
- Bucket: bootstrap.bucket
2690
- })
2691
- );
2692
- }
2693
- function useS3Key() {
2694
- const project = useProject();
2695
- return `appMetadata/app.${project.config.name}/stage.${project.config.stage}.json`;
2696
- }
2697
- var MetadataContext, useAppMetadata;
2698
- var init_app_metadata = __esm({
2699
- "src/stacks/app-metadata.ts"() {
2700
- "use strict";
2701
- init_bootstrap();
2702
- init_credentials();
2703
- init_context();
2704
- init_logger();
2705
- init_project();
2706
- MetadataContext = Context.create(async () => {
2707
- const data2 = await metadata();
2708
- return data2;
2709
- });
2710
- useAppMetadata = MetadataContext.use;
2711
- }
2712
- });
2713
-
2714
- // src/stacks/assembly.ts
2715
- async function loadAssembly(from) {
2716
- const { CloudAssembly } = await import("aws-cdk-lib/cx-api");
2717
- return new CloudAssembly(from);
2718
- }
2719
- var init_assembly = __esm({
2720
- "src/stacks/assembly.ts"() {
2721
- "use strict";
2722
- }
2723
- });
2724
-
2725
- // src/stacks/monitor.ts
2726
- import {
2727
- CloudFormationClient,
2728
- DescribeStackResourcesCommand,
2729
- DescribeStacksCommand,
2730
- DescribeStackEventsCommand
2731
- } from "@aws-sdk/client-cloudformation";
2732
- import { map, omitBy, pipe } from "remeda";
2733
- function isFinal(input) {
2734
- return STATUSES_SUCCESS.includes(input) || STATUSES_FAILED.includes(input);
2735
- }
2736
- function isFailed(input) {
2737
- return STATUSES_FAILED.includes(input);
2738
- }
2739
- function isSuccess(input) {
2740
- return STATUSES_SUCCESS.includes(input);
2741
- }
2742
- function isPending(input) {
2743
- return STATUSES_PENDING.includes(input);
2744
- }
2745
- async function monitor(stack) {
2746
- const [cfn, bus] = await Promise.all([
2747
- useAWSClient(CloudFormationClient),
2748
- useBus()
2749
- ]);
2750
- let lastStatus;
2751
- const errors = {};
2752
- let lastEvent;
2753
- while (true) {
2754
- try {
2755
- const [describe, resources, events] = await Promise.all([
2756
- cfn.send(
2757
- new DescribeStacksCommand({
2758
- StackName: stack
2759
- })
2760
- ),
2761
- cfn.send(
2762
- new DescribeStackResourcesCommand({
2763
- StackName: stack
2764
- })
2765
- ),
2766
- cfn.send(
2767
- new DescribeStackEventsCommand({
2768
- StackName: stack
2769
- })
2770
- )
2771
- ]);
2772
- Logger.debug("Stack description", describe);
2773
- if (lastEvent) {
2774
- const eventsReversed = [...events.StackEvents ?? []].reverse();
2775
- for (const event of eventsReversed) {
2776
- if (!event.Timestamp)
2777
- continue;
2778
- if (event.Timestamp.getTime() > lastEvent.getTime()) {
2779
- bus.publish("stack.event", {
2780
- event,
2781
- stackID: stack
2782
- });
2783
- if (event.ResourceStatusReason) {
2784
- if (event.ResourceStatusReason.includes(
2785
- "Resource creation cancelled"
2786
- ) || event.ResourceStatusReason.includes(
2787
- "Resource update cancelled"
2788
- ) || event.ResourceStatusReason.includes(
2789
- "Resource creation Initiated"
2790
- ) || event.ResourceStatusReason.startsWith(
2791
- "The following resource(s) failed to"
2792
- ))
2793
- continue;
2794
- errors[event.LogicalResourceId] = event.ResourceStatusReason;
2795
- }
2796
- }
2797
- }
2798
- Logger.debug("Last event set to", lastEvent);
2799
- }
2800
- lastEvent = events.StackEvents?.at(0)?.Timestamp;
2801
- bus.publish("stack.resources", {
2802
- stackID: stack,
2803
- resources: resources.StackResources
2804
- });
2805
- for (const resource of resources.StackResources || []) {
2806
- if (resource.ResourceStatusReason?.includes(
2807
- "Resource creation cancelled"
2808
- ) || resource.ResourceStatusReason?.includes(
2809
- "Resource update cancelled"
2810
- ) || resource.ResourceStatusReason?.includes(
2811
- "Resource creation Initiated"
2812
- ) || resource.ResourceStatusReason?.startsWith(
2813
- "The following resource(s) failed to"
2814
- ))
2815
- continue;
2816
- if (resource.ResourceStatusReason)
2817
- errors[resource.LogicalResourceId] = resource.ResourceStatusReason;
2818
- }
2819
- const [first] = describe.Stacks || [];
2820
- if (first) {
2821
- if (lastStatus !== first.StackStatus && first.StackStatus) {
2822
- lastStatus = first.StackStatus;
2823
- bus.publish("stack.status", {
2824
- stackID: stack,
2825
- status: first.StackStatus
2826
- });
2827
- Logger.debug(first);
2828
- if (isFinal(first.StackStatus)) {
2829
- return {
2830
- status: first.StackStatus,
2831
- outputs: pipe(
2832
- first.Outputs || [],
2833
- map((o) => [o.OutputKey, o.OutputValue]),
2834
- Object.fromEntries,
2835
- filterOutputs
2836
- ),
2837
- errors: isFailed(first.StackStatus) ? errors : {}
2838
- };
2839
- }
2840
- }
2841
- }
2842
- } catch (ex) {
2843
- if (ex.message.includes("does not exist")) {
2844
- bus.publish("stack.status", {
2845
- stackID: stack,
2846
- status: "DELETE_COMPLETE"
2847
- });
2848
- return {
2849
- status: "DELETE_COMPLETE",
2850
- outputs: {},
2851
- errors: {}
2852
- };
2853
- }
2854
- }
2855
- await new Promise((resolve) => setTimeout(resolve, 1e3));
2856
- }
2857
- }
2858
- function filterOutputs(input) {
2859
- return pipe(
2860
- input,
2861
- omitBy((_, key) => {
2862
- return key.startsWith("Export") || key === "SSTMetadata";
2863
- })
2864
- );
2865
- }
2866
- var STATUSES_PENDING, STATUSES_SUCCESS, STATUSES_FAILED, STATUSES;
2867
- var init_monitor = __esm({
2868
- "src/stacks/monitor.ts"() {
2869
- "use strict";
2870
- init_bus();
2871
- init_credentials();
2872
- init_logger();
2873
- STATUSES_PENDING = [
2874
- "CREATE_IN_PROGRESS",
2875
- "DELETE_IN_PROGRESS",
2876
- "REVIEW_IN_PROGRESS",
2877
- "ROLLBACK_IN_PROGRESS",
2878
- "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS",
2879
- "UPDATE_IN_PROGRESS",
2880
- "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS",
2881
- "UPDATE_ROLLBACK_IN_PROGRESS"
2882
- ];
2883
- STATUSES_SUCCESS = [
2884
- "CREATE_COMPLETE",
2885
- "UPDATE_COMPLETE",
2886
- "DELETE_COMPLETE",
2887
- "SKIPPED"
2888
- ];
2889
- STATUSES_FAILED = [
2890
- "CREATE_FAILED",
2891
- "DELETE_FAILED",
2892
- "ROLLBACK_FAILED",
2893
- "ROLLBACK_COMPLETE",
2894
- "UPDATE_FAILED",
2895
- "UPDATE_ROLLBACK_COMPLETE",
2896
- "UPDATE_ROLLBACK_FAILED",
2897
- "DEPENDENCY_FAILED"
2898
- ];
2899
- STATUSES = [
2900
- ...STATUSES_PENDING,
2901
- ...STATUSES_SUCCESS,
2902
- ...STATUSES_FAILED
2903
- ];
2904
- }
2905
- });
2906
-
2907
- // src/cdk/util.ts
2908
- async function callWithRetry(cb) {
2909
- try {
2910
- return await cb();
2911
- } catch (e) {
2912
- 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") {
2913
- return await callWithRetry(cb);
2914
- }
2915
- throw e;
2916
- }
2917
- }
2918
- var init_util = __esm({
2919
- "src/cdk/util.ts"() {
2920
- "use strict";
2921
- }
2922
- });
2923
-
2924
- // src/cdk/deploy-stack.ts
2925
- import * as cxapi from "@aws-cdk/cx-api";
2926
- import fs8 from "fs/promises";
2927
- import * as uuid from "uuid";
2928
- import { addMetadataAssetsToManifest } from "sst-aws-cdk/lib/assets.js";
2929
- import { debug, error, print } from "sst-aws-cdk/lib/logging.js";
2930
- import { toYAML } from "sst-aws-cdk/lib/serialize.js";
2931
- import { AssetManifestBuilder } from "sst-aws-cdk/lib/util/asset-manifest-builder.js";
2932
- import { publishAssets } from "sst-aws-cdk/lib/util/asset-publishing.js";
2933
- import { contentHash } from "sst-aws-cdk/lib/util/content-hash.js";
2934
- import { CfnEvaluationException } from "sst-aws-cdk/lib/api/evaluate-cloudformation-template.js";
2935
- import { tryHotswapDeployment } from "sst-aws-cdk/lib/api/hotswap-deployments.js";
2936
- import {
2937
- changeSetHasNoChanges,
2938
- CloudFormationStack,
2939
- TemplateParameters,
2940
- waitForChangeSet,
2941
- waitForStackDeploy,
2942
- waitForStackDelete
2943
- } from "sst-aws-cdk/lib/api/util/cloudformation.js";
2944
- import { blue as blue2 } from "colorette";
2945
- async function deployStack(options) {
2946
- const stackArtifact = options.stack;
2947
- const stackEnv = options.resolvedEnvironment;
2948
- options.sdk.appendCustomUserAgent(options.extraUserAgent);
2949
- const cfn = options.sdk.cloudFormation();
2950
- const deployName = options.deployName || stackArtifact.stackName;
2951
- let cloudFormationStack = await callWithRetry(
2952
- () => CloudFormationStack.lookup(cfn, deployName)
2953
- );
2954
- if (cloudFormationStack.stackStatus.isCreationFailure) {
2955
- debug(
2956
- `Found existing stack ${deployName} that had previously failed creation. Deleting it before attempting to re-create it.`
2957
- );
2958
- await cfn.deleteStack({ StackName: deployName }).promise();
2959
- const deletedStack = await waitForStackDelete(cfn, deployName);
2960
- if (deletedStack && deletedStack.stackStatus.name !== "DELETE_COMPLETE") {
2961
- throw new Error(
2962
- `Failed deleting stack ${deployName} that had previously failed creation (current state: ${deletedStack.stackStatus})`
2963
- );
2964
- }
2965
- cloudFormationStack = CloudFormationStack.doesNotExist(cfn, deployName);
2966
- }
2967
- const legacyAssets = new AssetManifestBuilder();
2968
- const assetParams = await addMetadataAssetsToManifest(
2969
- stackArtifact,
2970
- legacyAssets,
2971
- options.toolkitInfo,
2972
- options.reuseAssets
2973
- );
2974
- const finalParameterValues = { ...options.parameters, ...assetParams };
2975
- const templateParams = TemplateParameters.fromTemplate(
2976
- stackArtifact.template
2977
- );
2978
- const stackParams = options.usePreviousParameters ? templateParams.updateExisting(
2979
- finalParameterValues,
2980
- cloudFormationStack.parameters
2981
- ) : templateParams.supplyAll(finalParameterValues);
2982
- if (await canSkipDeploy(
2983
- options,
2984
- cloudFormationStack,
2985
- stackParams.hasChanges(cloudFormationStack.parameters)
2986
- )) {
2987
- debug(`${deployName}: skipping deployment (use --force to override)`);
2988
- if (options.hotswap) {
2989
- }
2990
- return {
2991
- noOp: true,
2992
- outputs: cloudFormationStack.outputs,
2993
- stackArn: cloudFormationStack.stackId
2994
- };
2995
- } else {
2996
- debug(`${deployName}: deploying...`);
2997
- }
2998
- const bodyParameter = await makeBodyParameter(
2999
- stackArtifact,
3000
- options.resolvedEnvironment,
3001
- legacyAssets,
3002
- options.toolkitInfo,
3003
- options.sdk,
3004
- options.overrideTemplate
3005
- );
3006
- await publishAssets(
3007
- legacyAssets.toManifest(stackArtifact.assembly.directory),
3008
- options.sdkProvider,
3009
- stackEnv,
3010
- {
3011
- parallel: options.assetParallelism
3012
- }
3013
- );
3014
- if (options.hotswap) {
3015
- try {
3016
- const hotswapDeploymentResult = await tryHotswapDeployment(
3017
- options.sdkProvider,
3018
- assetParams,
3019
- cloudFormationStack,
3020
- stackArtifact
3021
- );
3022
- if (hotswapDeploymentResult) {
3023
- return hotswapDeploymentResult;
3024
- }
3025
- print(
3026
- "Could not perform a hotswap deployment, as the stack %s contains non-Asset changes",
3027
- stackArtifact.displayName
3028
- );
3029
- } catch (e) {
3030
- if (!(e instanceof CfnEvaluationException)) {
3031
- throw e;
3032
- }
3033
- print(
3034
- "Could not perform a hotswap deployment, because the CloudFormation template could not be resolved: %s",
3035
- e.message
3036
- );
3037
- }
3038
- print("Falling back to doing a full deployment");
3039
- options.sdk.appendCustomUserAgent("cdk-hotswap/fallback");
3040
- }
3041
- const fullDeployment = new FullCloudFormationDeployment(
3042
- options,
3043
- cloudFormationStack,
3044
- stackArtifact,
3045
- stackParams,
3046
- bodyParameter
3047
- );
3048
- return fullDeployment.performDeployment();
3049
- }
3050
- async function makeBodyParameter(stack, resolvedEnvironment, assetManifest, toolkitInfo, sdk, overrideTemplate) {
3051
- if (stack.stackTemplateAssetObjectUrl && !overrideTemplate) {
3052
- return {
3053
- TemplateURL: restUrlFromManifest(
3054
- stack.stackTemplateAssetObjectUrl,
3055
- resolvedEnvironment,
3056
- sdk
3057
- )
3058
- };
3059
- }
3060
- const templateJson = toYAML(overrideTemplate ?? stack.template);
3061
- if (templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024) {
3062
- return { TemplateBody: templateJson };
3063
- }
3064
- if (!toolkitInfo.found) {
3065
- error(
3066
- `The template for stack "${stack.displayName}" is ${Math.round(
3067
- templateJson.length / 1024
3068
- )}KiB. Templates larger than ${LARGE_TEMPLATE_SIZE_KB}KiB must be uploaded to S3.
3069
- Run the following command in order to setup an S3 bucket in this environment, and then re-deploy:
3070
-
3071
- `,
3072
- blue2(` $ cdk bootstrap ${resolvedEnvironment.name}
3073
- `)
3074
- );
3075
- throw new Error(
3076
- 'Template too large to deploy ("cdk bootstrap" is required)'
3077
- );
3078
- }
3079
- const templateHash = contentHash(templateJson);
3080
- const key = `cdk/${stack.id}/${templateHash}.yml`;
3081
- let templateFile = stack.templateFile;
3082
- if (overrideTemplate) {
3083
- templateFile = `${stack.templateFile}-${templateHash}.yaml`;
3084
- await fs8.writeFile(templateFile, templateJson, { encoding: "utf-8" });
2215
+ const templateHash = contentHash(templateJson);
2216
+ const key = `cdk/${stack.id}/${templateHash}.yml`;
2217
+ let templateFile = stack.templateFile;
2218
+ if (overrideTemplate) {
2219
+ templateFile = `${stack.templateFile}-${templateHash}.yaml`;
2220
+ await fs5.writeFile(templateFile, templateJson, { encoding: "utf-8" });
3085
2221
  }
3086
2222
  assetManifest.addFileAsset(
3087
2223
  templateHash,
@@ -4129,13 +3265,13 @@ async function listImports(exportName) {
4129
3265
  }
4130
3266
  }
4131
3267
  async function getLocalTemplate(stack) {
4132
- const fs19 = await import("fs/promises");
4133
- const fileContent = await fs19.readFile(stack.templateFullPath);
3268
+ const fs18 = await import("fs/promises");
3269
+ const fileContent = await fs18.readFile(stack.templateFullPath);
4134
3270
  return fileContent.toString();
4135
3271
  }
4136
3272
  async function saveLocalTemplate(stack, content) {
4137
- const fs19 = await import("fs/promises");
4138
- await fs19.writeFile(stack.templateFullPath, content);
3273
+ const fs18 = await import("fs/promises");
3274
+ await fs18.writeFile(stack.templateFullPath, content);
4139
3275
  }
4140
3276
  var init_deploy = __esm({
4141
3277
  "src/stacks/deploy.ts"() {
@@ -4194,157 +3330,603 @@ async function buildLogicalToPathMap(stack) {
4194
3330
  )) {
4195
3331
  map3[md.data] = md.path;
4196
3332
  }
4197
- return map3;
4198
- }
4199
- var init_diff = __esm({
4200
- "src/stacks/diff.ts"() {
3333
+ return map3;
3334
+ }
3335
+ var init_diff = __esm({
3336
+ "src/stacks/diff.ts"() {
3337
+ "use strict";
3338
+ }
3339
+ });
3340
+
3341
+ // src/cache.ts
3342
+ import path5 from "path";
3343
+ import fs6 from "fs/promises";
3344
+ var useCache;
3345
+ var init_cache = __esm({
3346
+ "src/cache.ts"() {
3347
+ "use strict";
3348
+ init_project();
3349
+ init_logger();
3350
+ init_context();
3351
+ useCache = Context.memo(async () => {
3352
+ const project = useProject();
3353
+ const cache = path5.join(project.paths.out, "cache");
3354
+ await fs6.mkdir(cache, {
3355
+ recursive: true
3356
+ });
3357
+ async function write(key, data2) {
3358
+ const full = path5.join(cache, key);
3359
+ Logger.debug("Writing cache", full, data2.length, "bytes");
3360
+ await fs6.writeFile(full, data2);
3361
+ }
3362
+ async function read(key) {
3363
+ const full = path5.join(cache, key);
3364
+ try {
3365
+ const data2 = await fs6.readFile(full);
3366
+ return data2.toString();
3367
+ } catch {
3368
+ return null;
3369
+ }
3370
+ }
3371
+ return {
3372
+ write,
3373
+ read
3374
+ };
3375
+ });
3376
+ }
3377
+ });
3378
+
3379
+ // src/stacks/metadata.ts
3380
+ var metadata_exports = {};
3381
+ __export(metadata_exports, {
3382
+ metadata: () => metadata2,
3383
+ useMetadata: () => useMetadata
3384
+ });
3385
+ import {
3386
+ S3Client as S3Client2,
3387
+ GetObjectCommand as GetObjectCommand2,
3388
+ ListObjectsV2Command
3389
+ } from "@aws-sdk/client-s3";
3390
+ async function metadata2() {
3391
+ Logger.debug("Fetching all metadata");
3392
+ const project = useProject();
3393
+ const [credentials, bootstrap2] = await Promise.all([
3394
+ useAWSCredentials(),
3395
+ useBootstrap()
3396
+ ]);
3397
+ const s3 = new S3Client2({
3398
+ region: project.config.region,
3399
+ credentials
3400
+ });
3401
+ const key = `stackMetadata/app.${project.config.name}/stage.${project.config.stage}/`;
3402
+ const list2 = await s3.send(
3403
+ new ListObjectsV2Command({
3404
+ Prefix: key,
3405
+ Bucket: bootstrap2.bucket
3406
+ })
3407
+ );
3408
+ const result = Object.fromEntries(
3409
+ await Promise.all(
3410
+ list2.Contents?.map(async (obj) => {
3411
+ const stackID = obj.Key?.split("/").pop();
3412
+ const result2 = await s3.send(
3413
+ new GetObjectCommand2({
3414
+ Key: obj.Key,
3415
+ Bucket: bootstrap2.bucket
3416
+ })
3417
+ );
3418
+ const body = await result2.Body.transformToString();
3419
+ return [stackID, JSON.parse(body)];
3420
+ }) || []
3421
+ )
3422
+ );
3423
+ Logger.debug("Fetched metadata from", list2.KeyCount, "stacks");
3424
+ return result;
3425
+ }
3426
+ var MetadataContext2, useMetadata;
3427
+ var init_metadata = __esm({
3428
+ "src/stacks/metadata.ts"() {
3429
+ "use strict";
3430
+ init_bootstrap();
3431
+ init_credentials();
3432
+ init_cache();
3433
+ init_context();
3434
+ init_bus();
3435
+ init_logger();
3436
+ init_project();
3437
+ MetadataContext2 = Context.create(async () => {
3438
+ const bus = useBus();
3439
+ const cache = await useCache();
3440
+ const data2 = await metadata2();
3441
+ bus.publish("stacks.metadata", data2);
3442
+ bus.subscribe("stacks.metadata.updated", async () => {
3443
+ const data3 = await metadata2();
3444
+ await cache.write(`metadata.json`, JSON.stringify(data3));
3445
+ bus.publish("stacks.metadata", data3);
3446
+ MetadataContext2.provide(Promise.resolve(data3));
3447
+ });
3448
+ bus.subscribe("stacks.metadata.deleted", async () => {
3449
+ const data3 = await metadata2();
3450
+ await cache.write(`metadata.json`, JSON.stringify(data3));
3451
+ bus.publish("stacks.metadata", data3);
3452
+ MetadataContext2.provide(Promise.resolve(data3));
3453
+ });
3454
+ return data2;
3455
+ });
3456
+ useMetadata = MetadataContext2.use;
3457
+ }
3458
+ });
3459
+
3460
+ // src/watcher.ts
3461
+ var watcher_exports = {};
3462
+ __export(watcher_exports, {
3463
+ useWatcher: () => useWatcher
3464
+ });
3465
+ import chokidar from "chokidar";
3466
+ import path6 from "path";
3467
+ var useWatcher;
3468
+ var init_watcher = __esm({
3469
+ "src/watcher.ts"() {
3470
+ "use strict";
3471
+ init_context();
3472
+ init_bus();
3473
+ init_project();
3474
+ useWatcher = Context.memo(() => {
3475
+ const project = useProject();
3476
+ const bus = useBus();
3477
+ const watcher = chokidar.watch([project.paths.root], {
3478
+ persistent: true,
3479
+ ignoreInitial: true,
3480
+ followSymlinks: false,
3481
+ disableGlobbing: false,
3482
+ ignored: [
3483
+ "**/node_modules/**",
3484
+ "**/.build/**",
3485
+ "**/.sst/**",
3486
+ "**/debug.log"
3487
+ ],
3488
+ awaitWriteFinish: {
3489
+ pollInterval: 100,
3490
+ stabilityThreshold: 20
3491
+ }
3492
+ });
3493
+ watcher.on("change", (file) => {
3494
+ bus.publish("file.changed", {
3495
+ file,
3496
+ relative: path6.relative(project.paths.root, file)
3497
+ });
3498
+ });
3499
+ return {
3500
+ subscribe: bus.forward("file.changed")
3501
+ };
3502
+ });
3503
+ }
3504
+ });
3505
+
3506
+ // src/runtime/handlers.ts
3507
+ import path7 from "path";
3508
+ import fs7 from "fs/promises";
3509
+ import { useFunctions } from "../src/constructs/Function.js";
3510
+ var useRuntimeHandlers, useFunctionBuilder;
3511
+ var init_handlers = __esm({
3512
+ "src/runtime/handlers.ts"() {
4201
3513
  "use strict";
3514
+ init_context();
3515
+ init_logger();
3516
+ init_watcher();
3517
+ init_bus();
3518
+ init_project();
3519
+ useRuntimeHandlers = Context.memo(() => {
3520
+ const handlers = [];
3521
+ const project = useProject();
3522
+ const bus = useBus();
3523
+ const pendingBuilds = /* @__PURE__ */ new Map();
3524
+ const result = {
3525
+ subscribe: bus.forward("function.build.success", "function.build.failed"),
3526
+ register: (handler) => {
3527
+ handlers.push(handler);
3528
+ },
3529
+ for: (runtime) => {
3530
+ const result2 = handlers.find((x) => x.canHandle(runtime));
3531
+ if (!result2)
3532
+ throw new Error(`${runtime} runtime is unsupported`);
3533
+ return result2;
3534
+ },
3535
+ async build(functionID, mode) {
3536
+ async function task() {
3537
+ const func = useFunctions().fromID(functionID);
3538
+ const handler = result.for(func.runtime);
3539
+ const out = path7.join(project.paths.artifacts, functionID);
3540
+ await fs7.rm(out, { recursive: true, force: true });
3541
+ await fs7.mkdir(out, { recursive: true });
3542
+ if (func.hooks?.beforeBuild)
3543
+ await func.hooks.beforeBuild(func, out);
3544
+ const built = await handler.build({
3545
+ functionID,
3546
+ out,
3547
+ mode,
3548
+ props: func
3549
+ });
3550
+ if (built.type === "error") {
3551
+ bus.publish("function.build.failed", {
3552
+ functionID,
3553
+ errors: built.errors
3554
+ });
3555
+ return built;
3556
+ }
3557
+ if (func.copyFiles) {
3558
+ await Promise.all(
3559
+ func.copyFiles.map(async (entry) => {
3560
+ const fromPath = path7.join(project.paths.root, entry.from);
3561
+ const to = entry.to || entry.from;
3562
+ if (path7.isAbsolute(to))
3563
+ throw new Error(
3564
+ `Copy destination path "${to}" must be relative`
3565
+ );
3566
+ const toPath = path7.join(out, to);
3567
+ if (mode === "deploy")
3568
+ await fs7.cp(fromPath, toPath, {
3569
+ recursive: true
3570
+ });
3571
+ if (mode === "start") {
3572
+ const dir = path7.dirname(toPath);
3573
+ await fs7.mkdir(dir, { recursive: true });
3574
+ await fs7.symlink(fromPath, toPath);
3575
+ }
3576
+ })
3577
+ );
3578
+ }
3579
+ if (func.hooks?.afterBuild)
3580
+ await func.hooks.afterBuild(func, out);
3581
+ bus.publish("function.build.success", { functionID });
3582
+ return {
3583
+ ...built,
3584
+ out
3585
+ };
3586
+ }
3587
+ if (pendingBuilds.has(functionID)) {
3588
+ Logger.debug("Waiting on pending build", functionID);
3589
+ return pendingBuilds.get(functionID);
3590
+ }
3591
+ const promise = task();
3592
+ pendingBuilds.set(functionID, promise);
3593
+ Logger.debug("Building function", functionID);
3594
+ const r = await promise;
3595
+ pendingBuilds.delete(functionID);
3596
+ return r;
3597
+ }
3598
+ };
3599
+ return result;
3600
+ });
3601
+ useFunctionBuilder = Context.memo(() => {
3602
+ const artifacts = /* @__PURE__ */ new Map();
3603
+ const handlers = useRuntimeHandlers();
3604
+ const result = {
3605
+ artifact: (functionID) => {
3606
+ if (artifacts.has(functionID))
3607
+ return artifacts.get(functionID);
3608
+ return result.build(functionID);
3609
+ },
3610
+ build: async (functionID) => {
3611
+ const result2 = await handlers.build(functionID, "start");
3612
+ if (result2.type === "error")
3613
+ return;
3614
+ artifacts.set(functionID, result2);
3615
+ return artifacts.get(functionID);
3616
+ }
3617
+ };
3618
+ const watcher = useWatcher();
3619
+ watcher.subscribe("file.changed", async (evt) => {
3620
+ try {
3621
+ const functions = useFunctions();
3622
+ for (const [functionID, props] of Object.entries(functions.all)) {
3623
+ const handler = handlers.for(props.runtime);
3624
+ if (!handler?.shouldBuild({
3625
+ functionID,
3626
+ file: evt.properties.file
3627
+ }))
3628
+ continue;
3629
+ await result.build(functionID);
3630
+ Logger.debug("Rebuilt function", functionID);
3631
+ }
3632
+ } catch {
3633
+ }
3634
+ });
3635
+ return result;
3636
+ });
4202
3637
  }
4203
3638
  });
4204
3639
 
4205
- // src/cache.ts
4206
- import path8 from "path";
4207
- import fs9 from "fs/promises";
4208
- var useCache;
4209
- var init_cache = __esm({
4210
- "src/cache.ts"() {
3640
+ // src/runtime/server.ts
3641
+ var server_exports = {};
3642
+ __export(server_exports, {
3643
+ useRuntimeServer: () => useRuntimeServer,
3644
+ useRuntimeServerConfig: () => useRuntimeServerConfig
3645
+ });
3646
+ import express from "express";
3647
+ import https2 from "https";
3648
+ import getPort from "get-port";
3649
+ var useRuntimeServerConfig, useRuntimeServer;
3650
+ var init_server = __esm({
3651
+ "src/runtime/server.ts"() {
4211
3652
  "use strict";
4212
- init_project();
4213
- init_logger();
4214
3653
  init_context();
4215
- useCache = Context.memo(async () => {
4216
- const project = useProject();
4217
- const cache = path8.join(project.paths.out, "cache");
4218
- await fs9.mkdir(cache, {
4219
- recursive: true
3654
+ init_bus();
3655
+ init_logger();
3656
+ init_workers();
3657
+ useRuntimeServerConfig = Context.memo(async () => {
3658
+ const port = await getPort({
3659
+ port: 12557
4220
3660
  });
4221
- async function write(key, data2) {
4222
- const full = path8.join(cache, key);
4223
- Logger.debug("Writing cache", full, data2.length, "bytes");
4224
- await fs9.writeFile(full, data2);
3661
+ return {
3662
+ API_VERSION: "2018-06-01",
3663
+ port,
3664
+ url: `http://localhost:${port}`
3665
+ };
3666
+ });
3667
+ useRuntimeServer = Context.memo(async () => {
3668
+ const bus = useBus();
3669
+ const app = express();
3670
+ const workers = await useRuntimeWorkers();
3671
+ const cfg = await useRuntimeServerConfig();
3672
+ const workersWaiting = /* @__PURE__ */ new Map();
3673
+ const invocationsQueued = /* @__PURE__ */ new Map();
3674
+ function next(workerID) {
3675
+ const queue = invocationsQueued.get(workerID);
3676
+ const value = queue?.shift();
3677
+ if (value)
3678
+ return value;
3679
+ return new Promise((resolve, reject) => {
3680
+ workersWaiting.set(workerID, resolve);
3681
+ });
4225
3682
  }
4226
- async function read(key) {
4227
- const full = path8.join(cache, key);
4228
- try {
4229
- const data2 = await fs9.readFile(full);
4230
- return data2.toString();
4231
- } catch {
4232
- return null;
3683
+ workers.subscribe("worker.exited", async (evt) => {
3684
+ const waiting = workersWaiting.get(evt.properties.workerID);
3685
+ if (!waiting)
3686
+ return;
3687
+ workersWaiting.delete(evt.properties.workerID);
3688
+ });
3689
+ bus.subscribe("function.invoked", async (evt) => {
3690
+ const worker = workersWaiting.get(evt.properties.workerID);
3691
+ if (worker) {
3692
+ workersWaiting.delete(evt.properties.workerID);
3693
+ worker(evt.properties);
3694
+ return;
3695
+ }
3696
+ let arr = invocationsQueued.get(evt.properties.workerID);
3697
+ if (!arr) {
3698
+ arr = [];
3699
+ invocationsQueued.set(evt.properties.workerID, arr);
3700
+ }
3701
+ arr.push(evt.properties);
3702
+ });
3703
+ app.post(
3704
+ `/:workerID/${cfg.API_VERSION}/runtime/init/error`,
3705
+ express.json({
3706
+ strict: false,
3707
+ type: ["application/json", "application/*+json"],
3708
+ limit: "10mb"
3709
+ }),
3710
+ async (req, res) => {
3711
+ const worker = workers.fromID(req.params.workerID);
3712
+ bus.publish("function.error", {
3713
+ requestID: workers.getCurrentRequestID(worker.workerID),
3714
+ workerID: worker.workerID,
3715
+ functionID: worker.functionID,
3716
+ ...req.body
3717
+ });
3718
+ res.json("ok");
3719
+ }
3720
+ );
3721
+ app.get(
3722
+ `/:workerID/${cfg.API_VERSION}/runtime/invocation/next`,
3723
+ async (req, res) => {
3724
+ Logger.debug(
3725
+ "Worker",
3726
+ req.params.workerID,
3727
+ "is waiting for next invocation"
3728
+ );
3729
+ const payload = await next(req.params.workerID);
3730
+ Logger.debug("Worker", req.params.workerID, "sending next payload");
3731
+ res.set({
3732
+ "Lambda-Runtime-Aws-Request-Id": payload.context.awsRequestId,
3733
+ "Lambda-Runtime-Deadline-Ms": Date.now() + payload.deadline,
3734
+ "Lambda-Runtime-Invoked-Function-Arn": payload.context.invokedFunctionArn,
3735
+ "Lambda-Runtime-Client-Context": JSON.stringify(
3736
+ payload.context.clientContext || null
3737
+ ),
3738
+ "Lambda-Runtime-Cognito-Identity": JSON.stringify(
3739
+ payload.context.identity || null
3740
+ ),
3741
+ "Lambda-Runtime-Log-Group-Name": payload.context.logGroupName,
3742
+ "Lambda-Runtime-Log-Stream-Name": payload.context.logStreamName
3743
+ });
3744
+ res.json(payload.event);
3745
+ }
3746
+ );
3747
+ app.post(
3748
+ `/:workerID/${cfg.API_VERSION}/runtime/invocation/:awsRequestId/response`,
3749
+ express.json({
3750
+ strict: false,
3751
+ type() {
3752
+ return true;
3753
+ },
3754
+ limit: "10mb"
3755
+ }),
3756
+ (req, res) => {
3757
+ Logger.debug("Worker", req.params.workerID, "got response", req.body);
3758
+ const worker = workers.fromID(req.params.workerID);
3759
+ bus.publish("function.success", {
3760
+ workerID: worker.workerID,
3761
+ functionID: worker.functionID,
3762
+ requestID: req.params.awsRequestId,
3763
+ body: req.body
3764
+ });
3765
+ res.status(202).send();
4233
3766
  }
4234
- }
4235
- return {
4236
- write,
4237
- read
4238
- };
3767
+ );
3768
+ app.all(
3769
+ `/proxy*`,
3770
+ express.raw({
3771
+ type: "*/*",
3772
+ limit: "1024mb"
3773
+ }),
3774
+ (req, res) => {
3775
+ res.header("Access-Control-Allow-Origin", "*");
3776
+ res.header(
3777
+ "Access-Control-Allow-Methods",
3778
+ "GET, PUT, PATCH, POST, DELETE"
3779
+ );
3780
+ res.header(
3781
+ "Access-Control-Allow-Headers",
3782
+ req.header("access-control-request-headers")
3783
+ );
3784
+ if (req.method === "OPTIONS")
3785
+ return res.send();
3786
+ const u = new URL(req.url.substring(7));
3787
+ const forward = https2.request(
3788
+ u,
3789
+ {
3790
+ headers: {
3791
+ ...req.headers,
3792
+ host: u.hostname
3793
+ },
3794
+ method: req.method
3795
+ },
3796
+ (proxied) => {
3797
+ res.status(proxied.statusCode);
3798
+ for (const [key, value] of Object.entries(proxied.headers)) {
3799
+ res.header(key, value);
3800
+ }
3801
+ proxied.pipe(res);
3802
+ }
3803
+ );
3804
+ if (req.method !== "GET" && req.method !== "DELETE" && req.method !== "HEAD" && req.body)
3805
+ forward.write(req.body);
3806
+ forward.end();
3807
+ forward.on("error", (e) => {
3808
+ console.log(e.message);
3809
+ });
3810
+ }
3811
+ );
3812
+ app.post(
3813
+ `/:workerID/${cfg.API_VERSION}/runtime/invocation/:awsRequestId/error`,
3814
+ express.json({
3815
+ strict: false,
3816
+ type: ["application/json", "application/*+json"],
3817
+ limit: "10mb"
3818
+ }),
3819
+ (req, res) => {
3820
+ const worker = workers.fromID(req.params.workerID);
3821
+ bus.publish("function.error", {
3822
+ workerID: worker.workerID,
3823
+ functionID: worker.functionID,
3824
+ errorType: req.body.errorType,
3825
+ errorMessage: req.body.errorMessage,
3826
+ requestID: req.params.awsRequestId,
3827
+ trace: req.body.trace
3828
+ });
3829
+ res.status(202).send();
3830
+ }
3831
+ );
3832
+ app.listen(cfg.port);
4239
3833
  });
4240
3834
  }
4241
3835
  });
4242
3836
 
4243
- // src/stacks/metadata.ts
4244
- var metadata_exports = {};
4245
- __export(metadata_exports, {
4246
- metadata: () => metadata2,
4247
- metadataForStack: () => metadataForStack,
4248
- useMetadata: () => useMetadata
3837
+ // src/runtime/workers.ts
3838
+ var workers_exports = {};
3839
+ __export(workers_exports, {
3840
+ useRuntimeWorkers: () => useRuntimeWorkers
4249
3841
  });
4250
- import {
4251
- S3Client as S3Client2,
4252
- GetObjectCommand as GetObjectCommand2,
4253
- ListObjectsV2Command
4254
- } from "@aws-sdk/client-s3";
4255
- async function metadata2() {
4256
- Logger.debug("Fetching all metadata");
4257
- const project = useProject();
4258
- const [credentials, bootstrap] = await Promise.all([
4259
- useAWSCredentials(),
4260
- useBootstrap()
4261
- ]);
4262
- const s3 = new S3Client2({
4263
- region: project.config.region,
4264
- credentials
4265
- });
4266
- const key = `stackMetadata/app.${project.config.name}/stage.${project.config.stage}/`;
4267
- const list2 = await s3.send(
4268
- new ListObjectsV2Command({
4269
- Prefix: key,
4270
- Bucket: bootstrap.bucket
4271
- })
4272
- );
4273
- const result = Object.fromEntries(
4274
- await Promise.all(
4275
- list2.Contents?.map(async (obj) => {
4276
- const stackID = obj.Key?.split("/").pop();
4277
- const result2 = await s3.send(
4278
- new GetObjectCommand2({
4279
- Key: obj.Key,
4280
- Bucket: bootstrap.bucket
4281
- })
4282
- );
4283
- const body = await result2.Body.transformToString();
4284
- return [stackID, JSON.parse(body)];
4285
- }) || []
4286
- )
4287
- );
4288
- Logger.debug("Fetched metadata from", list2.KeyCount, "stacks");
4289
- return result;
4290
- }
4291
- async function metadataForStack(stackID) {
4292
- const [project, credentials, bootstrap] = await Promise.all([
4293
- useProject(),
4294
- useAWSCredentialsProvider(),
4295
- useBootstrap()
4296
- ]);
4297
- const s3 = new S3Client2({
4298
- region: project.config.region,
4299
- credentials
4300
- });
4301
- const key = `stackMetadata/app.${project.config.name}/stage.${project.config.stage}/stack.${stackID}.json`;
4302
- Logger.debug("Getting metadata", key, "from", bootstrap.bucket);
4303
- try {
4304
- const result = await s3.send(
4305
- new GetObjectCommand2({
4306
- Key: key,
4307
- Bucket: bootstrap.bucket
4308
- })
4309
- );
4310
- const body = await result.Body.transformToString();
4311
- return JSON.parse(body);
4312
- } catch (ex) {
4313
- console.error(ex);
4314
- return [];
4315
- }
4316
- }
4317
- var MetadataContext2, useMetadata;
4318
- var init_metadata = __esm({
4319
- "src/stacks/metadata.ts"() {
3842
+ import { useFunctions as useFunctions2 } from "../src/constructs/Function.js";
3843
+ var useRuntimeWorkers;
3844
+ var init_workers = __esm({
3845
+ "src/runtime/workers.ts"() {
4320
3846
  "use strict";
4321
- init_bootstrap();
4322
- init_credentials();
4323
- init_cache();
4324
3847
  init_context();
4325
3848
  init_bus();
4326
- init_logger();
4327
- init_project();
4328
- MetadataContext2 = Context.create(async () => {
3849
+ init_handlers();
3850
+ init_server();
3851
+ useRuntimeWorkers = Context.memo(async () => {
3852
+ const workers = /* @__PURE__ */ new Map();
4329
3853
  const bus = useBus();
4330
- const cache = await useCache();
4331
- const data2 = await metadata2();
4332
- bus.publish("stacks.metadata", data2);
4333
- bus.subscribe("stacks.metadata.updated", async () => {
4334
- const data3 = await metadata2();
4335
- await cache.write(`metadata.json`, JSON.stringify(data3));
4336
- bus.publish("stacks.metadata", data3);
4337
- MetadataContext2.provide(Promise.resolve(data3));
3854
+ const handlers = useRuntimeHandlers();
3855
+ const builder = useFunctionBuilder();
3856
+ const server = await useRuntimeServerConfig();
3857
+ handlers.subscribe("function.build.success", async (evt) => {
3858
+ for (const [_, worker] of workers) {
3859
+ if (worker.functionID === evt.properties.functionID) {
3860
+ const props = useFunctions2().fromID(worker.functionID);
3861
+ const handler = handlers.for(props.runtime);
3862
+ await handler?.stopWorker(worker.workerID);
3863
+ bus.publish("worker.stopped", worker);
3864
+ }
3865
+ }
4338
3866
  });
4339
- bus.subscribe("stacks.metadata.deleted", async () => {
4340
- const data3 = await metadata2();
4341
- await cache.write(`metadata.json`, JSON.stringify(data3));
4342
- bus.publish("stacks.metadata", data3);
4343
- MetadataContext2.provide(Promise.resolve(data3));
3867
+ const lastRequestId = /* @__PURE__ */ new Map();
3868
+ bus.subscribe("function.invoked", async (evt) => {
3869
+ bus.publish("function.ack", {
3870
+ functionID: evt.properties.functionID,
3871
+ workerID: evt.properties.workerID
3872
+ });
3873
+ lastRequestId.set(evt.properties.workerID, evt.properties.requestID);
3874
+ let worker = workers.get(evt.properties.workerID);
3875
+ if (worker)
3876
+ return;
3877
+ const props = useFunctions2().fromID(evt.properties.functionID);
3878
+ const handler = handlers.for(props.runtime);
3879
+ if (!handler)
3880
+ return;
3881
+ const build2 = await builder.artifact(evt.properties.functionID);
3882
+ if (!build2)
3883
+ return;
3884
+ await handler.startWorker({
3885
+ ...build2,
3886
+ workerID: evt.properties.workerID,
3887
+ environment: evt.properties.env,
3888
+ url: `${server.url}/${evt.properties.workerID}/${server.API_VERSION}`
3889
+ });
3890
+ workers.set(evt.properties.workerID, {
3891
+ workerID: evt.properties.workerID,
3892
+ functionID: evt.properties.functionID
3893
+ });
3894
+ bus.publish("worker.started", {
3895
+ workerID: evt.properties.workerID,
3896
+ functionID: evt.properties.functionID
3897
+ });
4344
3898
  });
4345
- return data2;
3899
+ return {
3900
+ fromID(workerID) {
3901
+ return workers.get(workerID);
3902
+ },
3903
+ getCurrentRequestID(workerID) {
3904
+ return lastRequestId.get(workerID);
3905
+ },
3906
+ stdout(workerID, message) {
3907
+ const worker = workers.get(workerID);
3908
+ bus.publish("worker.stdout", {
3909
+ ...worker,
3910
+ message: message.trim(),
3911
+ requestID: lastRequestId.get(workerID)
3912
+ });
3913
+ },
3914
+ exited(workerID) {
3915
+ const existing = workers.get(workerID);
3916
+ if (!existing)
3917
+ return;
3918
+ workers.delete(workerID);
3919
+ lastRequestId.delete(workerID);
3920
+ bus.publish("worker.exited", existing);
3921
+ },
3922
+ subscribe: bus.forward(
3923
+ "worker.started",
3924
+ "worker.stopped",
3925
+ "worker.exited",
3926
+ "worker.stdout"
3927
+ )
3928
+ };
4346
3929
  });
4347
- useMetadata = MetadataContext2.use;
4348
3930
  }
4349
3931
  });
4350
3932
 
@@ -4369,7 +3951,7 @@ var init_dotnet = __esm({
4369
3951
  init_handlers();
4370
3952
  init_workers();
4371
3953
  init_context();
4372
- init_server2();
3954
+ init_server();
4373
3955
  init_fs();
4374
3956
  init_project();
4375
3957
  init_process();
@@ -4493,8 +4075,8 @@ var node_exports = {};
4493
4075
  __export(node_exports, {
4494
4076
  useNodeHandler: () => useNodeHandler
4495
4077
  });
4496
- import path9 from "path";
4497
- import fs10 from "fs/promises";
4078
+ import path8 from "path";
4079
+ import fs8 from "fs/promises";
4498
4080
  import { exec as exec2 } from "child_process";
4499
4081
  import fsSync2 from "fs";
4500
4082
  import esbuild2 from "esbuild";
@@ -4521,7 +4103,7 @@ var init_node = __esm({
4521
4103
  const result = cache[input.functionID];
4522
4104
  if (!result)
4523
4105
  return false;
4524
- const relative = path9.relative(project.paths.root, input.file).split(path9.sep).join(path9.posix.sep);
4106
+ const relative = path8.relative(project.paths.root, input.file).split(path8.sep).join(path8.posix.sep);
4525
4107
  return Boolean(result.metafile?.inputs[relative]);
4526
4108
  },
4527
4109
  canHandle: (input) => input.startsWith("nodejs"),
@@ -4559,7 +4141,7 @@ var init_node = __esm({
4559
4141
  },
4560
4142
  build: async (input) => {
4561
4143
  const exists = cache[input.functionID];
4562
- const parsed = path9.parse(input.props.handler);
4144
+ const parsed = path8.parse(input.props.handler);
4563
4145
  const file = [
4564
4146
  ".ts",
4565
4147
  ".tsx",
@@ -4569,7 +4151,7 @@ var init_node = __esm({
4569
4151
  ".jsx",
4570
4152
  ".mjs",
4571
4153
  ".cjs"
4572
- ].map((ext) => path9.join(parsed.dir, parsed.name + ext)).find((file2) => {
4154
+ ].map((ext) => path8.join(parsed.dir, parsed.name + ext)).find((file2) => {
4573
4155
  return fsSync2.existsSync(file2);
4574
4156
  });
4575
4157
  if (!file)
@@ -4579,17 +4161,17 @@ var init_node = __esm({
4579
4161
  };
4580
4162
  const nodejs = input.props.nodejs || {};
4581
4163
  const isESM = (nodejs.format || "esm") === "esm";
4582
- const relative = path9.relative(
4164
+ const relative = path8.relative(
4583
4165
  project.paths.root,
4584
- path9.resolve(parsed.dir)
4166
+ path8.resolve(parsed.dir)
4585
4167
  );
4586
4168
  const extension = isESM ? ".mjs" : ".cjs";
4587
- const target = path9.join(
4169
+ const target = path8.join(
4588
4170
  input.out,
4589
- !relative.startsWith("..") && !path9.isAbsolute(input.props.handler) ? relative : "",
4171
+ !relative.startsWith("..") && !path8.isAbsolute(input.props.handler) ? relative : "",
4590
4172
  parsed.name + extension
4591
4173
  );
4592
- const handler = path9.relative(input.out, target.replace(extension, parsed.ext)).split(path9.sep).join(path9.posix.sep);
4174
+ const handler = path8.relative(input.out, target.replace(extension, parsed.ext)).split(path8.sep).join(path8.posix.sep);
4593
4175
  if (exists?.rebuild) {
4594
4176
  const result = await exists.rebuild();
4595
4177
  cache[input.functionID] = result;
@@ -4663,17 +4245,17 @@ var init_node = __esm({
4663
4245
  async function find2(dir, target2) {
4664
4246
  if (dir === "/")
4665
4247
  throw new VisibleError("Could not find a package.json file");
4666
- if (await fs10.access(path9.join(dir, target2)).then(() => true).catch(() => false))
4248
+ if (await fs8.access(path8.join(dir, target2)).then(() => true).catch(() => false))
4667
4249
  return dir;
4668
- return find2(path9.join(dir, ".."), target2);
4250
+ return find2(path8.join(dir, ".."), target2);
4669
4251
  }
4670
4252
  if (input.mode === "deploy" && installPackages) {
4671
4253
  const src = await find2(parsed.dir, "package.json");
4672
4254
  const json = JSON.parse(
4673
- await fs10.readFile(path9.join(src, "package.json")).then((x) => x.toString())
4255
+ await fs8.readFile(path8.join(src, "package.json")).then((x) => x.toString())
4674
4256
  );
4675
- fs10.writeFile(
4676
- path9.join(input.out, "package.json"),
4257
+ fs8.writeFile(
4258
+ path8.join(input.out, "package.json"),
4677
4259
  JSON.stringify({
4678
4260
  dependencies: Object.fromEntries(
4679
4261
  installPackages.map((x) => [x, json.dependencies?.[x] || "*"])
@@ -4695,14 +4277,14 @@ var init_node = __esm({
4695
4277
  });
4696
4278
  }
4697
4279
  if (input.mode === "start") {
4698
- const dir = path9.join(
4280
+ const dir = path8.join(
4699
4281
  await find2(parsed.dir, "package.json"),
4700
4282
  "node_modules"
4701
4283
  );
4702
4284
  try {
4703
- await fs10.symlink(
4704
- path9.resolve(dir),
4705
- path9.resolve(path9.join(input.out, "node_modules")),
4285
+ await fs8.symlink(
4286
+ path8.resolve(dir),
4287
+ path8.resolve(path8.join(input.out, "node_modules")),
4706
4288
  "dir"
4707
4289
  );
4708
4290
  } catch {
@@ -4741,15 +4323,15 @@ var go_exports = {};
4741
4323
  __export(go_exports, {
4742
4324
  useGoHandler: () => useGoHandler
4743
4325
  });
4744
- import path10 from "path";
4745
- import fs11 from "fs/promises";
4326
+ import path9 from "path";
4327
+ import fs9 from "fs/promises";
4746
4328
  import { spawn as spawn2 } from "child_process";
4747
4329
  async function find(dir, target) {
4748
4330
  if (dir === "/")
4749
4331
  throw new VisibleError(`Could not find a ${target} file`);
4750
- if (await fs11.access(path10.join(dir, target)).then(() => true).catch(() => false))
4332
+ if (await fs9.access(path9.join(dir, target)).then(() => true).catch(() => false))
4751
4333
  return dir;
4752
- return find(path10.join(dir, ".."), target);
4334
+ return find(path9.join(dir, ".."), target);
4753
4335
  }
4754
4336
  var useGoHandler;
4755
4337
  var init_go = __esm({
@@ -4759,7 +4341,7 @@ var init_go = __esm({
4759
4341
  init_workers();
4760
4342
  init_context();
4761
4343
  init_error();
4762
- init_server2();
4344
+ init_server();
4763
4345
  init_fs();
4764
4346
  init_process();
4765
4347
  useGoHandler = Context.memo(async () => {
@@ -4778,7 +4360,7 @@ var init_go = __esm({
4778
4360
  },
4779
4361
  canHandle: (input) => input.startsWith("go"),
4780
4362
  startWorker: async (input) => {
4781
- const proc = spawn2(path10.join(input.out, handlerName), {
4363
+ const proc = spawn2(path9.join(input.out, handlerName), {
4782
4364
  env: {
4783
4365
  ...process.env,
4784
4366
  ...input.environment,
@@ -4804,13 +4386,13 @@ var init_go = __esm({
4804
4386
  }
4805
4387
  },
4806
4388
  build: async (input) => {
4807
- const parsed = path10.parse(input.props.handler);
4389
+ const parsed = path9.parse(input.props.handler);
4808
4390
  const project = await find(parsed.dir, "go.mod");
4809
4391
  sources.set(input.functionID, project);
4810
- const src = path10.relative(project, input.props.handler);
4392
+ const src = path9.relative(project, input.props.handler);
4811
4393
  if (input.mode === "start") {
4812
4394
  try {
4813
- const target = path10.join(input.out, handlerName);
4395
+ const target = path9.join(input.out, handlerName);
4814
4396
  const result = await execAsync(
4815
4397
  `go build -ldflags '-s -w' -o '${target}' ./${src}`,
4816
4398
  {
@@ -4826,7 +4408,7 @@ var init_go = __esm({
4826
4408
  }
4827
4409
  if (input.mode === "deploy") {
4828
4410
  try {
4829
- const target = path10.join(input.out, "bootstrap");
4411
+ const target = path9.join(input.out, "bootstrap");
4830
4412
  await execAsync(`go build -ldflags '-s -w' -o '${target}' ./${src}`, {
4831
4413
  cwd: project,
4832
4414
  env: {
@@ -4855,8 +4437,8 @@ var rust_exports = {};
4855
4437
  __export(rust_exports, {
4856
4438
  useRustHandler: () => useRustHandler
4857
4439
  });
4858
- import path11 from "path";
4859
- import fs12 from "fs/promises";
4440
+ import path10 from "path";
4441
+ import fs10 from "fs/promises";
4860
4442
  import { exec as exec4, spawn as spawn3 } from "child_process";
4861
4443
  import { promisify as promisify2 } from "util";
4862
4444
  var execAsync2, useRustHandler;
@@ -4867,7 +4449,7 @@ var init_rust = __esm({
4867
4449
  init_workers();
4868
4450
  init_context();
4869
4451
  init_error();
4870
- init_server2();
4452
+ init_server();
4871
4453
  init_fs();
4872
4454
  execAsync2 = promisify2(exec4);
4873
4455
  useRustHandler = Context.memo(async () => {
@@ -4889,7 +4471,7 @@ var init_rust = __esm({
4889
4471
  },
4890
4472
  canHandle: (input) => input.startsWith("rust"),
4891
4473
  startWorker: async (input) => {
4892
- const proc = spawn3(path11.join(input.out, handlerName), {
4474
+ const proc = spawn3(path10.join(input.out, handlerName), {
4893
4475
  env: {
4894
4476
  ...process.env,
4895
4477
  ...input.environment,
@@ -4917,7 +4499,7 @@ var init_rust = __esm({
4917
4499
  }
4918
4500
  },
4919
4501
  build: async (input) => {
4920
- const parsed = path11.parse(input.props.handler);
4502
+ const parsed = path10.parse(input.props.handler);
4921
4503
  const project = await findAbove(parsed.dir, "Cargo.toml");
4922
4504
  if (!project)
4923
4505
  return {
@@ -4933,9 +4515,9 @@ var init_rust = __esm({
4933
4515
  ...process.env
4934
4516
  }
4935
4517
  });
4936
- await fs12.cp(
4937
- path11.join(project, `target/debug`, parsed.name),
4938
- path11.join(input.out, "handler")
4518
+ await fs10.cp(
4519
+ path10.join(project, `target/debug`, parsed.name),
4520
+ path10.join(input.out, "handler")
4939
4521
  );
4940
4522
  } catch (ex) {
4941
4523
  throw new VisibleError("Failed to build");
@@ -4949,9 +4531,9 @@ var init_rust = __esm({
4949
4531
  ...process.env
4950
4532
  }
4951
4533
  });
4952
- await fs12.cp(
4953
- path11.join(project, `target/lambda/`, parsed.name, "bootstrap"),
4954
- path11.join(input.out, "bootstrap")
4534
+ await fs10.cp(
4535
+ path10.join(project, `target/lambda/`, parsed.name, "bootstrap"),
4536
+ path10.join(input.out, "bootstrap")
4955
4537
  );
4956
4538
  } catch (ex) {
4957
4539
  throw new VisibleError("Failed to build");
@@ -4968,9 +4550,9 @@ var init_rust = __esm({
4968
4550
  });
4969
4551
 
4970
4552
  // src/runtime/handlers/pythonBundling.ts
4971
- import fs13 from "fs";
4553
+ import fs11 from "fs";
4972
4554
  import url5 from "url";
4973
- import path12 from "path";
4555
+ import path11 from "path";
4974
4556
  import {
4975
4557
  DockerImage,
4976
4558
  FileSystem
@@ -4984,9 +4566,9 @@ function bundle(options) {
4984
4566
  stagedir
4985
4567
  );
4986
4568
  const dockerfile = hasInstallCommands ? "Dockerfile.custom" : hasDeps ? "Dockerfile.dependencies" : "Dockerfile";
4987
- fs13.copyFileSync(
4988
- path12.join(__dirname, "../../support/python-runtime", dockerfile),
4989
- path12.join(stagedir, dockerfile)
4569
+ fs11.copyFileSync(
4570
+ path11.join(__dirname, "../../support/python-runtime", dockerfile),
4571
+ path11.join(stagedir, dockerfile)
4990
4572
  );
4991
4573
  const image = DockerImage.fromBuild(stagedir, {
4992
4574
  buildArgs: {
@@ -4994,21 +4576,21 @@ function bundle(options) {
4994
4576
  },
4995
4577
  file: dockerfile
4996
4578
  });
4997
- const outputPath = path12.join(options.out, outputPathSuffix);
4579
+ const outputPath = path11.join(options.out, outputPathSuffix);
4998
4580
  if (hasDeps || hasInstallCommands) {
4999
4581
  image.cp(`${BUNDLER_DEPENDENCIES_CACHE}/.`, outputPath);
5000
4582
  }
5001
- fs13.cpSync(entry, outputPath, {
4583
+ fs11.cpSync(entry, outputPath, {
5002
4584
  recursive: true
5003
4585
  });
5004
4586
  }
5005
4587
  function stageDependencies(entry, stagedir) {
5006
4588
  const prefixes = ["Pipfile", "pyproject", "poetry", "requirements.txt"];
5007
4589
  let found = false;
5008
- for (const file of fs13.readdirSync(entry)) {
4590
+ for (const file of fs11.readdirSync(entry)) {
5009
4591
  for (const prefix of prefixes) {
5010
4592
  if (file.startsWith(prefix)) {
5011
- fs13.copyFileSync(path12.join(entry, file), path12.join(stagedir, file));
4593
+ fs11.copyFileSync(path11.join(entry, file), path11.join(stagedir, file));
5012
4594
  found = true;
5013
4595
  }
5014
4596
  }
@@ -5018,9 +4600,9 @@ function stageDependencies(entry, stagedir) {
5018
4600
  function stageInstallCommands(installCommands, stagedir) {
5019
4601
  let found = false;
5020
4602
  if (installCommands.length > 0) {
5021
- const filePath = path12.join(stagedir, "sst-deps-install-command.sh");
5022
- fs13.writeFileSync(filePath, installCommands.join(" && "));
5023
- fs13.chmodSync(filePath, "755");
4603
+ const filePath = path11.join(stagedir, "sst-deps-install-command.sh");
4604
+ fs11.writeFileSync(filePath, installCommands.join(" && "));
4605
+ fs11.chmodSync(filePath, "755");
5024
4606
  found = true;
5025
4607
  }
5026
4608
  return found;
@@ -5029,7 +4611,7 @@ var __dirname, BUNDLER_DEPENDENCIES_CACHE;
5029
4611
  var init_pythonBundling = __esm({
5030
4612
  "src/runtime/handlers/pythonBundling.ts"() {
5031
4613
  "use strict";
5032
- __dirname = path12.dirname(url5.fileURLToPath(import.meta.url));
4614
+ __dirname = path11.dirname(url5.fileURLToPath(import.meta.url));
5033
4615
  BUNDLER_DEPENDENCIES_CACHE = "/var/dependencies";
5034
4616
  }
5035
4617
  });
@@ -5039,7 +4621,7 @@ var python_exports = {};
5039
4621
  __export(python_exports, {
5040
4622
  usePythonHandler: () => usePythonHandler
5041
4623
  });
5042
- import path13 from "path";
4624
+ import path12 from "path";
5043
4625
  import { exec as exec5, spawn as spawn4 } from "child_process";
5044
4626
  import { promisify as promisify3 } from "util";
5045
4627
  import { Runtime } from "aws-cdk-lib/aws-lambda";
@@ -5052,7 +4634,7 @@ var init_python = __esm({
5052
4634
  init_handlers();
5053
4635
  init_workers();
5054
4636
  init_context();
5055
- init_server2();
4637
+ init_server();
5056
4638
  init_fs();
5057
4639
  init_pythonBundling();
5058
4640
  execAsync3 = promisify3(exec5);
@@ -5089,8 +4671,8 @@ var init_python = __esm({
5089
4671
  const src = await findSrc(input.handler);
5090
4672
  if (!src)
5091
4673
  throw new Error(`Could not find src for ${input.handler}`);
5092
- const parsed = path13.parse(path13.relative(src, input.handler));
5093
- const target = [...parsed.dir.split(path13.sep), parsed.name].join(".");
4674
+ const parsed = path12.parse(path12.relative(src, input.handler));
4675
+ const target = [...parsed.dir.split(path12.sep), parsed.name].join(".");
5094
4676
  const proc = spawn4(
5095
4677
  os3.platform() === "win32" ? "python.exe" : "python3",
5096
4678
  [
@@ -5151,7 +4733,7 @@ var init_python = __esm({
5151
4733
  });
5152
4734
  return {
5153
4735
  type: "success",
5154
- handler: path13.relative(src, path13.resolve(input.props.handler)).split(path13.sep).join(path13.posix.sep)
4736
+ handler: path12.relative(src, path12.resolve(input.props.handler)).split(path12.sep).join(path12.posix.sep)
5155
4737
  };
5156
4738
  }
5157
4739
  });
@@ -5164,14 +4746,14 @@ var java_exports = {};
5164
4746
  __export(java_exports, {
5165
4747
  useJavaHandler: () => useJavaHandler
5166
4748
  });
5167
- import path14 from "path";
5168
- import fs14 from "fs/promises";
4749
+ import path13 from "path";
4750
+ import fs12 from "fs/promises";
5169
4751
  import os4 from "os";
5170
4752
  import zipLocal from "zip-local";
5171
4753
  import { spawn as spawn5 } from "child_process";
5172
4754
  import url7 from "url";
5173
4755
  async function getGradleBinary(srcPath) {
5174
- const gradleWrapperPath = path14.resolve(path14.join(srcPath, "gradlew"));
4756
+ const gradleWrapperPath = path13.resolve(path13.join(srcPath, "gradlew"));
5175
4757
  return await existsAsync(gradleWrapperPath) ? gradleWrapperPath : "gradle";
5176
4758
  }
5177
4759
  var useJavaHandler;
@@ -5181,7 +4763,7 @@ var init_java = __esm({
5181
4763
  init_handlers();
5182
4764
  init_workers();
5183
4765
  init_context();
5184
- init_server2();
4766
+ init_server();
5185
4767
  init_fs();
5186
4768
  init_project();
5187
4769
  init_process();
@@ -5255,11 +4837,11 @@ var init_java = __esm({
5255
4837
  cwd: srcPath
5256
4838
  }
5257
4839
  );
5258
- const buildOutput = path14.join(srcPath, "build", outputDir);
5259
- const zip = (await fs14.readdir(buildOutput)).find(
4840
+ const buildOutput = path13.join(srcPath, "build", outputDir);
4841
+ const zip = (await fs12.readdir(buildOutput)).find(
5260
4842
  (f) => f.endsWith(".zip")
5261
4843
  );
5262
- zipLocal.sync.unzip(path14.join(buildOutput, zip)).save(input.out);
4844
+ zipLocal.sync.unzip(path13.join(buildOutput, zip)).save(input.out);
5263
4845
  return {
5264
4846
  type: "success",
5265
4847
  handler: input.props.handler
@@ -5278,7 +4860,7 @@ var init_java = __esm({
5278
4860
 
5279
4861
  // src/stacks/synth.ts
5280
4862
  import * as contextproviders from "sst-aws-cdk/lib/context-providers/index.js";
5281
- import path15 from "path";
4863
+ import path14 from "path";
5282
4864
  async function synth(opts) {
5283
4865
  Logger.debug("Synthesizing stacks...");
5284
4866
  const { App: App2 } = await import("../src/constructs/App.js");
@@ -5298,7 +4880,7 @@ async function synth(opts) {
5298
4880
  const identity = await useSTSIdentity();
5299
4881
  opts = {
5300
4882
  ...opts,
5301
- buildDir: opts.buildDir || path15.join(project.paths.out, "dist")
4883
+ buildDir: opts.buildDir || path14.join(project.paths.out, "dist")
5302
4884
  };
5303
4885
  const cfg = new Configuration();
5304
4886
  await cfg.load();
@@ -5360,420 +4942,763 @@ function formatCustomDomainError(message) {
5360
4942
  `Please double check and make sure the zone exists, or pass in a different zone.`
5361
4943
  ].join(" ");
5362
4944
  }
5363
- var init_synth = __esm({
5364
- "src/stacks/synth.ts"() {
5365
- "use strict";
5366
- init_logger();
5367
- init_project();
5368
- init_credentials();
5369
- init_error();
5370
- init_dotnet();
4945
+ var init_synth = __esm({
4946
+ "src/stacks/synth.ts"() {
4947
+ "use strict";
4948
+ init_logger();
4949
+ init_project();
4950
+ init_credentials();
4951
+ init_error();
4952
+ init_dotnet();
4953
+ }
4954
+ });
4955
+
4956
+ // src/stacks/remove.ts
4957
+ import {
4958
+ CloudFormationClient as CloudFormationClient2,
4959
+ DeleteStackCommand
4960
+ } from "@aws-sdk/client-cloudformation";
4961
+ async function removeMany(stacks) {
4962
+ await useAWSProvider();
4963
+ const bus = useBus();
4964
+ const complete = /* @__PURE__ */ new Set();
4965
+ const todo = new Set(stacks.map((s) => s.id));
4966
+ const results = {};
4967
+ return new Promise((resolve) => {
4968
+ async function trigger() {
4969
+ for (const stack of stacks) {
4970
+ if (!todo.has(stack.id))
4971
+ continue;
4972
+ Logger.debug("Checking if", stack.id, "can be removed");
4973
+ const waiting = stacks.filter((dependant) => {
4974
+ if (dependant.id === stack.id)
4975
+ return false;
4976
+ if (complete.has(dependant.id))
4977
+ return false;
4978
+ return dependant.dependencies?.some((d) => d.id === stack.id);
4979
+ });
4980
+ if (waiting.length) {
4981
+ Logger.debug(
4982
+ "Waiting on",
4983
+ waiting.map((s) => s.id)
4984
+ );
4985
+ continue;
4986
+ }
4987
+ remove(stack).then((result) => {
4988
+ results[stack.id] = result;
4989
+ complete.add(stack.id);
4990
+ if (isFailed(result.status))
4991
+ stacks.forEach((s) => {
4992
+ if (todo.delete(s.stackName)) {
4993
+ complete.add(s.stackName);
4994
+ results[s.id] = {
4995
+ status: "DEPENDENCY_FAILED",
4996
+ outputs: {},
4997
+ errors: {}
4998
+ };
4999
+ bus.publish("stack.status", {
5000
+ stackID: s.id,
5001
+ status: "DEPENDENCY_FAILED"
5002
+ });
5003
+ }
5004
+ });
5005
+ if (complete.size === stacks.length) {
5006
+ resolve(results);
5007
+ }
5008
+ trigger();
5009
+ });
5010
+ todo.delete(stack.id);
5011
+ }
5012
+ }
5013
+ trigger();
5014
+ });
5015
+ }
5016
+ async function remove(stack) {
5017
+ Logger.debug("Removing stack", stack.id);
5018
+ const cfn = useAWSClient(CloudFormationClient2);
5019
+ try {
5020
+ await cfn.send(
5021
+ new DeleteStackCommand({
5022
+ StackName: stack.stackName
5023
+ })
5024
+ );
5025
+ return monitor(stack.stackName);
5026
+ } catch (ex) {
5027
+ return {
5028
+ errors: {
5029
+ stack: ex.message
5030
+ },
5031
+ outputs: {},
5032
+ status: "UPDATE_FAILED"
5033
+ };
5034
+ }
5035
+ }
5036
+ var init_remove = __esm({
5037
+ "src/stacks/remove.ts"() {
5038
+ "use strict";
5039
+ init_bus();
5040
+ init_credentials();
5041
+ init_logger();
5042
+ init_monitor();
5043
+ }
5044
+ });
5045
+
5046
+ // src/stacks/index.ts
5047
+ var stacks_exports = {};
5048
+ __export(stacks_exports, {
5049
+ STATUSES: () => STATUSES,
5050
+ Stacks: () => stacks_exports,
5051
+ clearAppMetadata: () => clearAppMetadata,
5052
+ deploy: () => deploy,
5053
+ deployMany: () => deployMany,
5054
+ diff: () => diff,
5055
+ filterOutputs: () => filterOutputs,
5056
+ isFailed: () => isFailed,
5057
+ isFinal: () => isFinal,
5058
+ isPending: () => isPending,
5059
+ isSuccess: () => isSuccess,
5060
+ load: () => load,
5061
+ loadAssembly: () => loadAssembly,
5062
+ metadata: () => metadata2,
5063
+ monitor: () => monitor,
5064
+ publishAssets: () => publishAssets4,
5065
+ remove: () => remove,
5066
+ removeMany: () => removeMany,
5067
+ saveAppMetadata: () => saveAppMetadata,
5068
+ synth: () => synth,
5069
+ useAppMetadata: () => useAppMetadata,
5070
+ useMetadata: () => useMetadata
5071
+ });
5072
+ var init_stacks = __esm({
5073
+ "src/stacks/index.ts"() {
5074
+ "use strict";
5075
+ init_app_metadata();
5076
+ init_assembly();
5077
+ init_build();
5078
+ init_deploy();
5079
+ init_diff();
5080
+ init_metadata();
5081
+ init_synth();
5082
+ init_monitor();
5083
+ init_remove();
5084
+ init_stacks();
5085
+ }
5086
+ });
5087
+
5088
+ // src/bootstrap.ts
5089
+ var bootstrap_exports = {};
5090
+ __export(bootstrap_exports, {
5091
+ bootstrapSST: () => bootstrapSST,
5092
+ useBootstrap: () => useBootstrap
5093
+ });
5094
+ import url8 from "url";
5095
+ import path15 from "path";
5096
+ import { bold, dim } from "colorette";
5097
+ import { spawn as spawn6 } from "child_process";
5098
+ import {
5099
+ DescribeStacksCommand as DescribeStacksCommand2,
5100
+ CloudFormationClient as CloudFormationClient3
5101
+ } from "@aws-sdk/client-cloudformation";
5102
+ import {
5103
+ App,
5104
+ DefaultStackSynthesizer,
5105
+ CfnOutput,
5106
+ Duration,
5107
+ Tags,
5108
+ Stack,
5109
+ RemovalPolicy
5110
+ } from "aws-cdk-lib";
5111
+ import { Function, Runtime as Runtime2, Code } from "aws-cdk-lib/aws-lambda";
5112
+ import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
5113
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
5114
+ import { Queue } from "aws-cdk-lib/aws-sqs";
5115
+ import { Rule } from "aws-cdk-lib/aws-events";
5116
+ import { SqsQueue } from "aws-cdk-lib/aws-events-targets";
5117
+ import {
5118
+ BlockPublicAccess,
5119
+ Bucket,
5120
+ BucketEncryption
5121
+ } from "aws-cdk-lib/aws-s3";
5122
+ async function loadCDKStatus() {
5123
+ const { cdk } = useProject().config;
5124
+ const client = useAWSClient(CloudFormationClient3);
5125
+ const stackName = cdk?.toolkitStackName || CDK_STACK_NAME;
5126
+ try {
5127
+ const { Stacks: stacks } = await client.send(
5128
+ new DescribeStacksCommand2({ StackName: stackName })
5129
+ );
5130
+ if (!stacks || stacks.length === 0)
5131
+ return false;
5132
+ if (!["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
5133
+ return false;
5134
+ }
5135
+ const output = stacks[0].Outputs?.find(
5136
+ (o) => o.OutputKey === "BootstrapVersion"
5137
+ );
5138
+ if (!output || parseInt(output.OutputValue) < 14)
5139
+ return false;
5140
+ return true;
5141
+ } catch (e) {
5142
+ if (e.name === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
5143
+ return false;
5144
+ } else {
5145
+ throw e;
5146
+ }
5147
+ }
5148
+ }
5149
+ async function loadSSTStatus() {
5150
+ const { bootstrap: bootstrap2 } = useProject().config;
5151
+ const cf = useAWSClient(CloudFormationClient3);
5152
+ const stackName = bootstrap2?.stackName || SST_STACK_NAME;
5153
+ let result;
5154
+ try {
5155
+ result = await cf.send(
5156
+ new DescribeStacksCommand2({
5157
+ StackName: stackName
5158
+ })
5159
+ );
5160
+ } catch (e) {
5161
+ if (e.Code === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
5162
+ return null;
5163
+ }
5164
+ throw e;
5165
+ }
5166
+ let version2, bucket;
5167
+ (result.Stacks[0].Outputs || []).forEach((o) => {
5168
+ if (o.OutputKey === OUTPUT_VERSION) {
5169
+ version2 = o.OutputValue;
5170
+ } else if (o.OutputKey === OUTPUT_BUCKET) {
5171
+ bucket = o.OutputValue;
5172
+ }
5173
+ });
5174
+ if (!version2 || !bucket) {
5175
+ return null;
5176
+ }
5177
+ return { version: version2, bucket };
5178
+ }
5179
+ async function bootstrapSST() {
5180
+ const { region, bootstrap: bootstrap2, cdk } = useProject().config;
5181
+ const app = new App();
5182
+ const stackName = bootstrap2?.stackName || SST_STACK_NAME;
5183
+ const stack = new Stack(app, stackName, {
5184
+ env: {
5185
+ region
5186
+ },
5187
+ synthesizer: new DefaultStackSynthesizer({
5188
+ qualifier: cdk?.qualifier,
5189
+ fileAssetsBucketName: cdk?.fileAssetsBucketName
5190
+ })
5191
+ });
5192
+ for (const [key, value] of Object.entries(bootstrap2?.tags || {})) {
5193
+ Tags.of(app).add(key, value);
5371
5194
  }
5372
- });
5373
-
5374
- // src/stacks/remove.ts
5375
- import {
5376
- CloudFormationClient as CloudFormationClient2,
5377
- DeleteStackCommand
5378
- } from "@aws-sdk/client-cloudformation";
5379
- async function removeMany(stacks) {
5380
- await useAWSProvider();
5381
- const bus = useBus();
5382
- const complete = /* @__PURE__ */ new Set();
5383
- const todo = new Set(stacks.map((s) => s.id));
5384
- const results = {};
5385
- return new Promise((resolve) => {
5386
- async function trigger() {
5387
- for (const stack of stacks) {
5388
- if (!todo.has(stack.id))
5389
- continue;
5390
- Logger.debug("Checking if", stack.id, "can be removed");
5391
- const waiting = stacks.filter((dependant) => {
5392
- if (dependant.id === stack.id)
5393
- return false;
5394
- if (complete.has(dependant.id))
5395
- return false;
5396
- return dependant.dependencies?.some((d) => d.id === stack.id);
5397
- });
5398
- if (waiting.length) {
5399
- Logger.debug(
5400
- "Waiting on",
5401
- waiting.map((s) => s.id)
5402
- );
5403
- continue;
5195
+ const bucket = new Bucket(stack, region, {
5196
+ encryption: BucketEncryption.S3_MANAGED,
5197
+ removalPolicy: RemovalPolicy.DESTROY,
5198
+ autoDeleteObjects: true,
5199
+ blockPublicAccess: cdk?.publicAccessBlockConfiguration !== false ? BlockPublicAccess.BLOCK_ALL : void 0
5200
+ });
5201
+ const fn = new Function(stack, "MetadataHandler", {
5202
+ code: Code.fromAsset(
5203
+ path15.resolve(__dirname2, "support/bootstrap-metadata-function")
5204
+ ),
5205
+ handler: "index.handler",
5206
+ runtime: region?.startsWith("us-gov-") || region?.startsWith("cn-") ? Runtime2.NODEJS_16_X : Runtime2.NODEJS_18_X,
5207
+ environment: {
5208
+ BUCKET_NAME: bucket.bucketName
5209
+ },
5210
+ initialPolicy: [
5211
+ new PolicyStatement({
5212
+ actions: ["cloudformation:DescribeStacks"],
5213
+ resources: ["*"]
5214
+ }),
5215
+ new PolicyStatement({
5216
+ actions: ["s3:PutObject", "s3:DeleteObject"],
5217
+ resources: [bucket.bucketArn + "/*"]
5218
+ }),
5219
+ new PolicyStatement({
5220
+ actions: ["iot:Publish"],
5221
+ resources: [
5222
+ `arn:${stack.partition}:iot:${stack.region}:${stack.account}:topic//sst/*`
5223
+ ]
5224
+ })
5225
+ ]
5226
+ });
5227
+ const queue = new Queue(stack, "MetadataQueue", {
5228
+ visibilityTimeout: Duration.seconds(30),
5229
+ retentionPeriod: Duration.minutes(2)
5230
+ });
5231
+ fn.addEventSource(new SqsEventSource(queue));
5232
+ const rule = new Rule(stack, "MetadataRule", {
5233
+ eventPattern: {
5234
+ source: ["aws.cloudformation"],
5235
+ detailType: ["CloudFormation Stack Status Change"],
5236
+ detail: {
5237
+ "status-details": {
5238
+ status: [
5239
+ "CREATE_COMPLETE",
5240
+ "UPDATE_COMPLETE",
5241
+ "UPDATE_ROLLBACK_COMPLETE",
5242
+ "ROLLBACK_COMPLETE",
5243
+ "DELETE_COMPLETE"
5244
+ ]
5404
5245
  }
5405
- remove(stack).then((result) => {
5406
- results[stack.id] = result;
5407
- complete.add(stack.id);
5408
- if (isFailed(result.status))
5409
- stacks.forEach((s) => {
5410
- if (todo.delete(s.stackName)) {
5411
- complete.add(s.stackName);
5412
- results[s.id] = {
5413
- status: "DEPENDENCY_FAILED",
5414
- outputs: {},
5415
- errors: {}
5416
- };
5417
- bus.publish("stack.status", {
5418
- stackID: s.id,
5419
- status: "DEPENDENCY_FAILED"
5420
- });
5421
- }
5422
- });
5423
- if (complete.size === stacks.length) {
5424
- resolve(results);
5425
- }
5426
- trigger();
5427
- });
5428
- todo.delete(stack.id);
5429
5246
  }
5430
5247
  }
5431
- trigger();
5432
5248
  });
5433
- }
5434
- async function remove(stack) {
5435
- Logger.debug("Removing stack", stack.id);
5436
- const cfn = useAWSClient(CloudFormationClient2);
5437
- try {
5438
- await cfn.send(
5439
- new DeleteStackCommand({
5440
- StackName: stack.stackName
5441
- })
5249
+ rule.addTarget(
5250
+ new SqsQueue(queue, {
5251
+ retryAttempts: 10
5252
+ })
5253
+ );
5254
+ new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
5255
+ new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
5256
+ const asm = app.synth();
5257
+ const result = await stacks_exports.deploy(asm.stacks[0]);
5258
+ if (stacks_exports.isFailed(result.status)) {
5259
+ throw new VisibleError(
5260
+ `Failed to deploy bootstrap stack:
5261
+ ${JSON.stringify(
5262
+ result.errors,
5263
+ null,
5264
+ 4
5265
+ )}`
5442
5266
  );
5443
- return monitor(stack.stackName);
5444
- } catch (ex) {
5445
- return {
5446
- errors: {
5447
- stack: ex.message
5448
- },
5449
- outputs: {},
5450
- status: "UPDATE_FAILED"
5451
- };
5452
5267
  }
5453
5268
  }
5454
- var init_remove = __esm({
5455
- "src/stacks/remove.ts"() {
5269
+ async function bootstrapCDK() {
5270
+ const identity = await useSTSIdentity();
5271
+ const credentials = await useAWSCredentials();
5272
+ const { region, profile, cdk } = useProject().config;
5273
+ cdk || {};
5274
+ await new Promise((resolve, reject) => {
5275
+ const proc = spawn6(
5276
+ [
5277
+ "npx",
5278
+ "cdk",
5279
+ "bootstrap",
5280
+ `aws://${identity.Account}/${region}`,
5281
+ "--no-version-reporting",
5282
+ ...cdk?.publicAccessBlockConfiguration === false ? ["--public-access-block-configuration", "false"] : cdk?.publicAccessBlockConfiguration === true ? ["--public-access-block-configuration", "false"] : [],
5283
+ ...cdk?.toolkitStackName ? ["--toolkit-stack-name", cdk.toolkitStackName] : [],
5284
+ ...cdk?.qualifier ? ["--qualifier", cdk.qualifier] : [],
5285
+ ...cdk?.fileAssetsBucketName ? ["--toolkit-bucket-name", cdk.fileAssetsBucketName] : []
5286
+ ].join(" "),
5287
+ {
5288
+ env: {
5289
+ ...process.env,
5290
+ AWS_ACCESS_KEY_ID: credentials.accessKeyId,
5291
+ AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
5292
+ AWS_SESSION_TOKEN: credentials.sessionToken,
5293
+ AWS_REGION: region,
5294
+ AWS_PROFILE: profile
5295
+ },
5296
+ stdio: "pipe",
5297
+ shell: true
5298
+ }
5299
+ );
5300
+ let stderr = "";
5301
+ proc.stdout.on("data", (data2) => {
5302
+ Logger.debug(data2.toString());
5303
+ });
5304
+ proc.stderr.on("data", (data2) => {
5305
+ Logger.debug(data2.toString());
5306
+ stderr += data2;
5307
+ });
5308
+ proc.on("exit", (code) => {
5309
+ Logger.debug("CDK bootstrap exited with code " + code);
5310
+ if (code === 0) {
5311
+ resolve();
5312
+ } else {
5313
+ console.log(bold(dim(stderr)));
5314
+ reject(new VisibleError(`Failed to bootstrap`));
5315
+ }
5316
+ });
5317
+ });
5318
+ }
5319
+ var CDK_STACK_NAME, SST_STACK_NAME, OUTPUT_VERSION, OUTPUT_BUCKET, LATEST_VERSION, __dirname2, useBootstrap;
5320
+ var init_bootstrap = __esm({
5321
+ "src/bootstrap.ts"() {
5456
5322
  "use strict";
5457
- init_bus();
5323
+ init_project();
5324
+ init_spinner();
5325
+ init_context();
5458
5326
  init_credentials();
5327
+ init_error();
5459
5328
  init_logger();
5460
- init_monitor();
5329
+ init_stacks();
5330
+ CDK_STACK_NAME = "CDKToolkit";
5331
+ SST_STACK_NAME = "SSTBootstrap";
5332
+ OUTPUT_VERSION = "Version";
5333
+ OUTPUT_BUCKET = "BucketName";
5334
+ LATEST_VERSION = "7";
5335
+ __dirname2 = url8.fileURLToPath(new URL(".", import.meta.url));
5336
+ useBootstrap = Context.memo(async () => {
5337
+ Logger.debug("Initializing bootstrap context");
5338
+ let [cdkStatus, sstStatus] = await Promise.all([
5339
+ loadCDKStatus(),
5340
+ loadSSTStatus()
5341
+ ]);
5342
+ Logger.debug("Loaded bootstrap status");
5343
+ const needToBootstrapCDK = !cdkStatus;
5344
+ const needToBootstrapSST = !sstStatus || sstStatus.version !== LATEST_VERSION;
5345
+ if (needToBootstrapCDK || needToBootstrapSST) {
5346
+ const spinner = createSpinner(
5347
+ "Deploying bootstrap stack, this only needs to happen once"
5348
+ ).start();
5349
+ if (needToBootstrapCDK) {
5350
+ await bootstrapCDK();
5351
+ }
5352
+ if (needToBootstrapSST) {
5353
+ await bootstrapSST();
5354
+ sstStatus = await loadSSTStatus();
5355
+ if (!sstStatus)
5356
+ throw new VisibleError("Failed to load bootstrap stack status");
5357
+ }
5358
+ spinner.succeed();
5359
+ }
5360
+ Logger.debug("Bootstrap context initialized", sstStatus);
5361
+ return sstStatus;
5362
+ }, "Bootstrap");
5461
5363
  }
5462
5364
  });
5463
5365
 
5464
- // src/stacks/index.ts
5465
- var stacks_exports = {};
5466
- __export(stacks_exports, {
5467
- STATUSES: () => STATUSES,
5468
- Stacks: () => stacks_exports,
5469
- clearAppMetadata: () => clearAppMetadata,
5470
- deploy: () => deploy,
5471
- deployMany: () => deployMany,
5472
- diff: () => diff,
5473
- filterOutputs: () => filterOutputs,
5474
- isFailed: () => isFailed,
5475
- isFinal: () => isFinal,
5476
- isPending: () => isPending,
5477
- isSuccess: () => isSuccess,
5478
- load: () => load,
5479
- loadAssembly: () => loadAssembly,
5480
- metadata: () => metadata2,
5481
- metadataForStack: () => metadataForStack,
5482
- monitor: () => monitor,
5483
- publishAssets: () => publishAssets4,
5484
- remove: () => remove,
5485
- removeMany: () => removeMany,
5486
- saveAppMetadata: () => saveAppMetadata,
5487
- synth: () => synth,
5488
- useAppMetadata: () => useAppMetadata,
5489
- useMetadata: () => useMetadata
5490
- });
5491
- var init_stacks = __esm({
5492
- "src/stacks/index.ts"() {
5366
+ // src/cli/local/router.ts
5367
+ import * as trpc from "@trpc/server";
5368
+ var router2;
5369
+ var init_router = __esm({
5370
+ "src/cli/local/router.ts"() {
5493
5371
  "use strict";
5494
- init_app_metadata();
5495
- init_assembly();
5496
- init_build();
5497
- init_deploy();
5498
- init_diff();
5499
- init_metadata();
5500
- init_synth();
5501
- init_monitor();
5502
- init_remove();
5503
- init_stacks();
5372
+ init_project();
5373
+ init_bus();
5374
+ init_credentials();
5375
+ router2 = trpc.router().query("getCredentials", {
5376
+ async resolve({ ctx }) {
5377
+ const project = useProject();
5378
+ const credentials = await useAWSCredentials();
5379
+ return {
5380
+ region: project.config.region,
5381
+ credentials: {
5382
+ accessKeyId: credentials.accessKeyId,
5383
+ secretAccessKey: credentials.secretAccessKey,
5384
+ sessionToken: credentials.sessionToken
5385
+ }
5386
+ };
5387
+ }
5388
+ }).query("getState", {
5389
+ async resolve({ ctx }) {
5390
+ return ctx.state;
5391
+ }
5392
+ }).mutation("deploy", {
5393
+ async resolve() {
5394
+ return;
5395
+ }
5396
+ }).subscription("onStateChange", {
5397
+ async resolve({ ctx }) {
5398
+ const bus = useBus();
5399
+ return new trpc.Subscription((emit) => {
5400
+ const sub = bus.subscribe("local.patches", (evt) => {
5401
+ emit.data(evt.properties);
5402
+ });
5403
+ return () => {
5404
+ bus.unsubscribe(sub);
5405
+ };
5406
+ });
5407
+ }
5408
+ });
5504
5409
  }
5505
5410
  });
5506
5411
 
5507
- // src/bootstrap.ts
5508
- import url8 from "url";
5509
- import path16 from "path";
5510
- import { bold, dim } from "colorette";
5511
- import { spawn as spawn6 } from "child_process";
5512
- import {
5513
- DescribeStacksCommand as DescribeStacksCommand2,
5514
- CloudFormationClient as CloudFormationClient3
5515
- } from "@aws-sdk/client-cloudformation";
5516
- import {
5517
- App,
5518
- DefaultStackSynthesizer,
5519
- CfnOutput,
5520
- Duration,
5521
- Tags,
5522
- Stack,
5523
- RemovalPolicy
5524
- } from "aws-cdk-lib";
5525
- import { Function, Runtime as Runtime2, Code } from "aws-cdk-lib/aws-lambda";
5526
- import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
5527
- import { PolicyStatement } from "aws-cdk-lib/aws-iam";
5528
- import { Queue } from "aws-cdk-lib/aws-sqs";
5529
- import { Rule } from "aws-cdk-lib/aws-events";
5530
- import { SqsQueue } from "aws-cdk-lib/aws-events-targets";
5531
- import {
5532
- BlockPublicAccess,
5533
- Bucket,
5534
- BucketEncryption
5535
- } from "aws-cdk-lib/aws-s3";
5536
- async function loadCDKStatus() {
5537
- const { cdk } = useProject().config;
5538
- const client = useAWSClient(CloudFormationClient3);
5539
- const stackName = cdk?.toolkitStackName || CDK_STACK_NAME;
5540
- try {
5541
- const { Stacks: stacks } = await client.send(
5542
- new DescribeStacksCommand2({ StackName: stackName })
5543
- );
5544
- if (!stacks || stacks.length === 0)
5545
- return false;
5546
- if (!["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
5547
- return false;
5548
- }
5549
- const output = stacks[0].Outputs?.find(
5550
- (o) => o.OutputKey === "BootstrapVersion"
5412
+ // src/cli/local/server.ts
5413
+ var server_exports2 = {};
5414
+ __export(server_exports2, {
5415
+ useLocalServer: () => useLocalServer,
5416
+ useLocalServerConfig: () => useLocalServerConfig
5417
+ });
5418
+ import { produceWithPatches, enablePatches } from "immer";
5419
+ import express2 from "express";
5420
+ import fs13 from "fs/promises";
5421
+ import { WebSocketServer } from "ws";
5422
+ import https3 from "https";
5423
+ import http from "http";
5424
+ import { applyWSSHandler } from "@trpc/server/adapters/ws/dist/trpc-server-adapters-ws.cjs.js";
5425
+ import { optimise } from "dendriform-immer-patch-optimiser";
5426
+ import { sync } from "cross-spawn";
5427
+ import getPort2 from "get-port";
5428
+ async function useLocalServer(opts) {
5429
+ const cfg = await useLocalServerConfig();
5430
+ const project = useProject();
5431
+ let state2 = {
5432
+ app: project.config.name,
5433
+ stage: project.config.stage,
5434
+ bootstrap: project.config.bootstrap,
5435
+ live: opts.live,
5436
+ stacks: {
5437
+ status: "idle"
5438
+ },
5439
+ functions: {}
5440
+ };
5441
+ const rest = express2();
5442
+ rest.all(`/ping`, (req, res) => {
5443
+ res.header("Access-Control-Allow-Origin", "*");
5444
+ res.header("Access-Control-Allow-Methods", "GET, PUT, PATCH, POST, DELETE");
5445
+ res.header(
5446
+ "Access-Control-Allow-Headers",
5447
+ req.header("access-control-request-headers")
5551
5448
  );
5552
- if (!output || parseInt(output.OutputValue) < 14)
5553
- return false;
5554
- return true;
5555
- } catch (e) {
5556
- if (e.name === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
5557
- return false;
5558
- } else {
5559
- throw e;
5449
+ res.sendStatus(200);
5450
+ });
5451
+ rest.all(
5452
+ `/proxy*`,
5453
+ express2.raw({
5454
+ type: "*/*",
5455
+ limit: "1024mb"
5456
+ }),
5457
+ (req, res) => {
5458
+ res.header("Access-Control-Allow-Origin", "*");
5459
+ res.header(
5460
+ "Access-Control-Allow-Methods",
5461
+ "GET, PUT, PATCH, POST, DELETE"
5462
+ );
5463
+ res.header(
5464
+ "Access-Control-Allow-Headers",
5465
+ req.header("access-control-request-headers")
5466
+ );
5467
+ if (req.method === "OPTIONS")
5468
+ return res.send();
5469
+ const u = new URL(req.url.substring(7));
5470
+ const forward = https3.request(
5471
+ u,
5472
+ {
5473
+ headers: {
5474
+ ...req.headers,
5475
+ host: u.hostname
5476
+ },
5477
+ method: req.method
5478
+ },
5479
+ (proxied) => {
5480
+ res.status(proxied.statusCode);
5481
+ for (const [key, value] of Object.entries(proxied.headers)) {
5482
+ res.header(key, value);
5483
+ }
5484
+ proxied.pipe(res);
5485
+ }
5486
+ );
5487
+ if (req.method !== "GET" && req.method !== "DELETE" && req.method !== "HEAD" && req.body)
5488
+ forward.write(req.body);
5489
+ forward.end();
5490
+ forward.on("error", (e) => {
5491
+ console.log(e.message);
5492
+ });
5560
5493
  }
5561
- }
5562
- }
5563
- async function loadSSTStatus() {
5564
- const { bootstrap } = useProject().config;
5565
- const cf = useAWSClient(CloudFormationClient3);
5566
- const stackName = bootstrap?.stackName || SST_STACK_NAME;
5567
- let result;
5568
- try {
5569
- result = await cf.send(
5570
- new DescribeStacksCommand2({
5571
- StackName: stackName
5572
- })
5573
- );
5574
- } catch (e) {
5575
- if (e.Code === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
5576
- return null;
5494
+ );
5495
+ const server = await (async () => {
5496
+ const result2 = sync("mkcert", ["--help"]);
5497
+ const KEY_PATH = ".sst/localhost-key.pem";
5498
+ const CERT_PATH = ".sst/localhost.pem";
5499
+ if (result2.status === 0) {
5500
+ try {
5501
+ await Promise.all([fs13.access(KEY_PATH), fs13.access(CERT_PATH)]);
5502
+ } catch (e) {
5503
+ sync("mkcert", ["localhost"], {
5504
+ cwd: ".sst"
5505
+ });
5506
+ }
5507
+ const [key, cert] = await Promise.all([
5508
+ fs13.readFile(KEY_PATH),
5509
+ fs13.readFile(CERT_PATH)
5510
+ ]);
5511
+ return https3.createServer(
5512
+ {
5513
+ key,
5514
+ cert
5515
+ },
5516
+ rest
5517
+ );
5577
5518
  }
5578
- throw e;
5579
- }
5580
- let version2, bucket;
5581
- (result.Stacks[0].Outputs || []).forEach((o) => {
5582
- if (o.OutputKey === OUTPUT_VERSION) {
5583
- version2 = o.OutputValue;
5584
- } else if (o.OutputKey === OUTPUT_BUCKET) {
5585
- bucket = o.OutputValue;
5519
+ return http.createServer({}, rest);
5520
+ })();
5521
+ const wss = new WebSocketServer({ server });
5522
+ wss.on("connection", (socket, req) => {
5523
+ if (req.headers.origin?.endsWith("localhost:3000"))
5524
+ return;
5525
+ if (req.headers.origin?.endsWith("localhost:3001"))
5526
+ return;
5527
+ if (req.headers.origin?.endsWith("console.serverless-stack.com"))
5528
+ return;
5529
+ if (req.headers.origin?.endsWith("console.sst.dev"))
5530
+ return;
5531
+ if (req.headers.origin?.endsWith("--sst-console.netlify.app"))
5532
+ return;
5533
+ console.log("Rejecting unauthorized connection from " + req.headers.origin);
5534
+ socket.terminate();
5535
+ });
5536
+ server.listen(cfg.port);
5537
+ const handler = applyWSSHandler({
5538
+ wss,
5539
+ router: router2,
5540
+ createContext() {
5541
+ return {
5542
+ state: state2
5543
+ };
5586
5544
  }
5587
5545
  });
5588
- if (!version2 || !bucket) {
5589
- return null;
5590
- }
5591
- return { version: version2, bucket };
5592
- }
5593
- async function bootstrapSST() {
5594
- const { region, bootstrap, cdk } = useProject().config;
5595
- const app = new App();
5596
- const stackName = bootstrap?.stackName || SST_STACK_NAME;
5597
- const stack = new Stack(app, stackName, {
5598
- env: {
5599
- region
5600
- },
5601
- synthesizer: new DefaultStackSynthesizer({
5602
- qualifier: cdk?.qualifier,
5603
- fileAssetsBucketName: cdk?.fileAssetsBucketName
5604
- })
5546
+ process.on("SIGTERM", () => {
5547
+ handler.broadcastReconnectNotification();
5548
+ wss.close();
5605
5549
  });
5606
- for (const [key, value] of Object.entries(bootstrap?.tags || {})) {
5607
- Tags.of(app).add(key, value);
5550
+ const bus = useBus();
5551
+ const pending = [];
5552
+ function updateState(cb) {
5553
+ const [next, patches] = produceWithPatches(state2, cb);
5554
+ if (!patches.length)
5555
+ return;
5556
+ const scheduled = pending.length;
5557
+ pending.push(...optimise(state2, patches));
5558
+ if (!scheduled)
5559
+ setTimeout(() => {
5560
+ bus.publish("local.patches", pending);
5561
+ pending.splice(0, pending.length);
5562
+ }, 0);
5563
+ state2 = next;
5608
5564
  }
5609
- const bucket = new Bucket(stack, region, {
5610
- encryption: BucketEncryption.S3_MANAGED,
5611
- removalPolicy: RemovalPolicy.DESTROY,
5612
- autoDeleteObjects: true,
5613
- blockPublicAccess: cdk?.publicAccessBlockConfiguration !== false ? BlockPublicAccess.BLOCK_ALL : void 0
5565
+ function updateFunction(id, cb) {
5566
+ return updateState((draft) => {
5567
+ let func = draft.functions[id];
5568
+ if (!func) {
5569
+ func = {
5570
+ warm: true,
5571
+ state: "idle",
5572
+ issues: {},
5573
+ invocations: []
5574
+ };
5575
+ draft.functions[id] = func;
5576
+ }
5577
+ cb(func);
5578
+ });
5579
+ }
5580
+ bus.subscribe("function.invoked", (evt) => {
5581
+ updateFunction(evt.properties.functionID, (draft) => {
5582
+ if (draft.invocations.length >= 25)
5583
+ draft.invocations.pop();
5584
+ draft.invocations.unshift({
5585
+ id: evt.properties.context.awsRequestId,
5586
+ request: evt.properties.event,
5587
+ times: {
5588
+ start: Date.now()
5589
+ },
5590
+ logs: []
5591
+ });
5592
+ });
5614
5593
  });
5615
- const fn = new Function(stack, "MetadataHandler", {
5616
- code: Code.fromAsset(
5617
- path16.resolve(__dirname2, "support/bootstrap-metadata-function")
5618
- ),
5619
- handler: "index.handler",
5620
- runtime: region?.startsWith("us-gov-") || region?.startsWith("cn-") ? Runtime2.NODEJS_16_X : Runtime2.NODEJS_18_X,
5621
- environment: {
5622
- BUCKET_NAME: bucket.bucketName
5623
- },
5624
- initialPolicy: [
5625
- new PolicyStatement({
5626
- actions: ["cloudformation:DescribeStacks"],
5627
- resources: ["*"]
5628
- }),
5629
- new PolicyStatement({
5630
- actions: ["s3:PutObject", "s3:DeleteObject"],
5631
- resources: [bucket.bucketArn + "/*"]
5632
- }),
5633
- new PolicyStatement({
5634
- actions: ["iot:Publish"],
5635
- resources: [
5636
- `arn:${stack.partition}:iot:${stack.region}:${stack.account}:topic//sst/*`
5637
- ]
5638
- })
5639
- ]
5594
+ bus.subscribe("worker.stdout", (evt) => {
5595
+ updateFunction(evt.properties.functionID, (draft) => {
5596
+ const entry = draft.invocations.find(
5597
+ (i) => i.id === evt.properties.requestID
5598
+ );
5599
+ if (!entry)
5600
+ return;
5601
+ entry.logs.push({
5602
+ timestamp: Date.now(),
5603
+ message: evt.properties.message
5604
+ });
5605
+ });
5640
5606
  });
5641
- const queue = new Queue(stack, "MetadataQueue", {
5642
- visibilityTimeout: Duration.seconds(30),
5643
- retentionPeriod: Duration.minutes(2)
5607
+ bus.subscribe("function.success", (evt) => {
5608
+ updateFunction(evt.properties.functionID, (draft) => {
5609
+ const invocation = draft.invocations.find(
5610
+ (x) => x.id === evt.properties.requestID
5611
+ );
5612
+ if (!invocation)
5613
+ return;
5614
+ invocation.response = {
5615
+ type: "success",
5616
+ data: evt.properties.body
5617
+ };
5618
+ invocation.times.end = Date.now();
5619
+ });
5644
5620
  });
5645
- fn.addEventSource(new SqsEventSource(queue));
5646
- const rule = new Rule(stack, "MetadataRule", {
5647
- eventPattern: {
5648
- source: ["aws.cloudformation"],
5649
- detailType: ["CloudFormation Stack Status Change"],
5650
- detail: {
5651
- "status-details": {
5652
- status: [
5653
- "CREATE_COMPLETE",
5654
- "UPDATE_COMPLETE",
5655
- "UPDATE_ROLLBACK_COMPLETE",
5656
- "ROLLBACK_COMPLETE",
5657
- "DELETE_COMPLETE"
5658
- ]
5621
+ bus.subscribe("function.error", (evt) => {
5622
+ updateFunction(evt.properties.functionID, (draft) => {
5623
+ const invocation = draft.invocations.find(
5624
+ (x) => x.id === evt.properties.requestID
5625
+ );
5626
+ if (!invocation)
5627
+ return;
5628
+ invocation.response = {
5629
+ type: "failure",
5630
+ error: {
5631
+ errorMessage: evt.properties.errorMessage,
5632
+ stackTrace: evt.properties.trace || []
5659
5633
  }
5660
- }
5661
- }
5634
+ };
5635
+ invocation.times.end = Date.now();
5636
+ });
5662
5637
  });
5663
- rule.addTarget(
5664
- new SqsQueue(queue, {
5665
- retryAttempts: 10
5666
- })
5667
- );
5668
- new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
5669
- new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
5670
- const asm = app.synth();
5671
- const result = await stacks_exports.deploy(asm.stacks[0]);
5672
- if (stacks_exports.isFailed(result.status)) {
5673
- throw new VisibleError(
5674
- `Failed to deploy bootstrap stack:
5675
- ${JSON.stringify(
5676
- result.errors,
5677
- null,
5678
- 4
5679
- )}`
5680
- );
5681
- }
5638
+ const result = {
5639
+ updateState,
5640
+ updateFunction
5641
+ };
5642
+ return result;
5682
5643
  }
5683
- async function bootstrapCDK() {
5684
- const identity = await useSTSIdentity();
5685
- const credentials = await useAWSCredentials();
5686
- const { region, profile, cdk } = useProject().config;
5687
- cdk || {};
5688
- await new Promise((resolve, reject) => {
5689
- const proc = spawn6(
5690
- [
5691
- "npx",
5692
- "cdk",
5693
- "bootstrap",
5694
- `aws://${identity.Account}/${region}`,
5695
- "--no-version-reporting",
5696
- ...cdk?.publicAccessBlockConfiguration === false ? ["--public-access-block-configuration", "false"] : cdk?.publicAccessBlockConfiguration === true ? ["--public-access-block-configuration", "false"] : [],
5697
- ...cdk?.toolkitStackName ? ["--toolkit-stack-name", cdk.toolkitStackName] : [],
5698
- ...cdk?.qualifier ? ["--qualifier", cdk.qualifier] : [],
5699
- ...cdk?.fileAssetsBucketName ? ["--toolkit-bucket-name", cdk.fileAssetsBucketName] : []
5700
- ].join(" "),
5701
- {
5702
- env: {
5703
- ...process.env,
5704
- AWS_ACCESS_KEY_ID: credentials.accessKeyId,
5705
- AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
5706
- AWS_SESSION_TOKEN: credentials.sessionToken,
5707
- AWS_REGION: region,
5708
- AWS_PROFILE: profile
5709
- },
5710
- stdio: "pipe",
5711
- shell: true
5712
- }
5713
- );
5714
- let stderr = "";
5715
- proc.stdout.on("data", (data2) => {
5716
- Logger.debug(data2.toString());
5717
- });
5718
- proc.stderr.on("data", (data2) => {
5719
- Logger.debug(data2.toString());
5720
- stderr += data2;
5721
- });
5722
- proc.on("exit", (code) => {
5723
- Logger.debug("CDK bootstrap exited with code " + code);
5724
- if (code === 0) {
5725
- resolve();
5726
- } else {
5727
- console.log(bold(dim(stderr)));
5728
- reject(new VisibleError(`Failed to bootstrap`));
5729
- }
5644
+ var useLocalServerConfig;
5645
+ var init_server2 = __esm({
5646
+ "src/cli/local/server.ts"() {
5647
+ "use strict";
5648
+ init_router();
5649
+ init_project();
5650
+ init_bus();
5651
+ init_context();
5652
+ enablePatches();
5653
+ useLocalServerConfig = Context.memo(async () => {
5654
+ const project = useProject();
5655
+ const port = await getPort2({
5656
+ port: 13557
5657
+ });
5658
+ return {
5659
+ port,
5660
+ url: `https://console.sst.dev/${project.config.name}/${project.config.stage}${port !== 13557 ? `?_port=${port}` : ""}`
5661
+ };
5730
5662
  });
5731
- });
5663
+ }
5664
+ });
5665
+
5666
+ // src/cli/ui/header.ts
5667
+ var header_exports = {};
5668
+ __export(header_exports, {
5669
+ printConsole: () => printConsole,
5670
+ printHeader: () => printHeader
5671
+ });
5672
+ async function printHeader(input) {
5673
+ const project = useProject();
5674
+ Colors.line(
5675
+ `${Colors.primary.bold(`SST v${project.version}`)} ${input.hint ? Colors.dim(`ready!`) : ""}`
5676
+ );
5677
+ Colors.gap();
5678
+ Colors.line(
5679
+ `${Colors.primary(`\u279C`)} ${Colors.bold("App:")} ${project.config.name}`
5680
+ );
5681
+ Colors.line(
5682
+ `${Colors.primary(` `)} ${Colors.bold("Stage:")} ${project.config.stage}`
5683
+ );
5684
+ if (input.console) {
5685
+ const local = await useLocalServerConfig();
5686
+ Colors.line(
5687
+ `${Colors.primary(` `)} ${Colors.bold("Console:")} ${Colors.link(
5688
+ local.url
5689
+ )}`
5690
+ );
5691
+ }
5692
+ Colors.gap();
5732
5693
  }
5733
- var CDK_STACK_NAME, SST_STACK_NAME, OUTPUT_VERSION, OUTPUT_BUCKET, LATEST_VERSION, __dirname2, useBootstrap;
5734
- var init_bootstrap = __esm({
5735
- "src/bootstrap.ts"() {
5694
+ function printConsole() {
5695
+ }
5696
+ var init_header = __esm({
5697
+ "src/cli/ui/header.ts"() {
5736
5698
  "use strict";
5737
5699
  init_project();
5738
- init_spinner();
5739
- init_context();
5740
- init_credentials();
5741
- init_error();
5742
- init_logger();
5743
- init_stacks();
5744
- CDK_STACK_NAME = "CDKToolkit";
5745
- SST_STACK_NAME = "SSTBootstrap";
5746
- OUTPUT_VERSION = "Version";
5747
- OUTPUT_BUCKET = "BucketName";
5748
- LATEST_VERSION = "7";
5749
- __dirname2 = url8.fileURLToPath(new URL(".", import.meta.url));
5750
- useBootstrap = Context.memo(async () => {
5751
- Logger.debug("Initializing bootstrap context");
5752
- let [cdkStatus, sstStatus] = await Promise.all([
5753
- loadCDKStatus(),
5754
- loadSSTStatus()
5755
- ]);
5756
- Logger.debug("Loaded bootstrap status");
5757
- const needToBootstrapCDK = !cdkStatus;
5758
- const needToBootstrapSST = !sstStatus || sstStatus.version !== LATEST_VERSION;
5759
- if (needToBootstrapCDK || needToBootstrapSST) {
5760
- const spinner = createSpinner(
5761
- "Deploying bootstrap stack, this only needs to happen once"
5762
- ).start();
5763
- if (needToBootstrapCDK) {
5764
- await bootstrapCDK();
5765
- }
5766
- if (needToBootstrapSST) {
5767
- await bootstrapSST();
5768
- sstStatus = await loadSSTStatus();
5769
- if (!sstStatus)
5770
- throw new VisibleError("Failed to load bootstrap stack status");
5771
- }
5772
- spinner.succeed();
5773
- }
5774
- Logger.debug("Bootstrap context initialized", sstStatus);
5775
- return sstStatus;
5776
- }, "Bootstrap");
5700
+ init_colors();
5701
+ init_server2();
5777
5702
  }
5778
5703
  });
5779
5704
 
@@ -5815,7 +5740,7 @@ var init_iot = __esm({
5815
5740
  const endpoint = await useIOTEndpoint();
5816
5741
  const creds = await useAWSCredentials();
5817
5742
  const project = useProject();
5818
- const bootstrap = await useBootstrap();
5743
+ const bootstrap2 = await useBootstrap();
5819
5744
  const s3 = useAWSClient(S3Client3);
5820
5745
  async function encode(input) {
5821
5746
  const id = Math.random().toString();
@@ -5824,7 +5749,7 @@ var init_iot = __esm({
5824
5749
  const key = `pointers/${id}`;
5825
5750
  await s3.send(
5826
5751
  new PutObjectCommand2({
5827
- Bucket: bootstrap.bucket,
5752
+ Bucket: bootstrap2.bucket,
5828
5753
  Key: key,
5829
5754
  Body: json
5830
5755
  })
@@ -5838,7 +5763,7 @@ var init_iot = __esm({
5838
5763
  type: "pointer",
5839
5764
  properties: {
5840
5765
  key,
5841
- bucket: bootstrap.bucket
5766
+ bucket: bootstrap2.bucket
5842
5767
  }
5843
5768
  })
5844
5769
  }
@@ -5990,15 +5915,10 @@ function printDeploymentResults(assembly, results, remove4) {
5990
5915
  Colors.bold(remove4 ? ` Removed:` : ` Deployed:`)
5991
5916
  );
5992
5917
  for (const [stack, result] of success) {
5993
- const outputs = Object.entries(result.outputs).filter(
5994
- ([key, _]) => !key.includes("SstSiteEnv")
5995
- );
5996
5918
  Colors.line(` ${Colors.dim(stackNameToId(stack))}`);
5997
- if (outputs.length > 0) {
5998
- for (const key of Object.keys(Object.fromEntries(outputs)).sort()) {
5999
- const value = result.outputs[key];
6000
- Colors.line(` ${Colors.bold.dim(key + ":")} ${value}`);
6001
- }
5919
+ for (const key of Object.keys(result.outputs).sort()) {
5920
+ const value = result.outputs[key];
5921
+ Colors.line(` ${Colors.bold.dim(key + ":")} ${value}`);
6002
5922
  }
6003
5923
  }
6004
5924
  Colors.gap();
@@ -6137,16 +6057,16 @@ __export(pothos_exports, {
6137
6057
  import babel from "@babel/core";
6138
6058
  import generator from "@babel/generator";
6139
6059
  import esbuild3 from "esbuild";
6140
- import fs15 from "fs/promises";
6141
- import path17 from "path";
6060
+ import fs14 from "fs/promises";
6061
+ import path16 from "path";
6142
6062
  import url9 from "url";
6143
6063
  async function generate(opts) {
6144
6064
  const { printSchema, lexicographicSortSchema } = await import("graphql");
6145
6065
  const contents = await extractSchema(opts);
6146
- const out = path17.join(path17.dirname(opts.schema), "out.mjs");
6147
- await fs15.writeFile(out, contents, "utf8");
6066
+ const out = path16.join(path16.dirname(opts.schema), "out.mjs");
6067
+ await fs14.writeFile(out, contents, "utf8");
6148
6068
  const { schema } = await import(url9.pathToFileURL(out).href + "?bust=" + Date.now());
6149
- await fs15.rm(out);
6069
+ await fs14.rm(out);
6150
6070
  const schemaAsString = printSchema(lexicographicSortSchema(schema));
6151
6071
  return schemaAsString;
6152
6072
  }
@@ -6294,10 +6214,10 @@ var pothos_exports2 = {};
6294
6214
  __export(pothos_exports2, {
6295
6215
  usePothosBuilder: () => usePothosBuilder
6296
6216
  });
6297
- import fs16 from "fs/promises";
6217
+ import fs15 from "fs/promises";
6298
6218
  import { exec as exec6 } from "child_process";
6299
6219
  import { promisify as promisify4 } from "util";
6300
- import path18 from "path";
6220
+ import path17 from "path";
6301
6221
  var execAsync4, usePothosBuilder;
6302
6222
  var init_pothos2 = __esm({
6303
6223
  "src/cli/commands/plugins/pothos.ts"() {
@@ -6315,7 +6235,7 @@ var init_pothos2 = __esm({
6315
6235
  const schema = await pothos_exports.generate({
6316
6236
  schema: route.schema
6317
6237
  });
6318
- await fs16.writeFile(route.output, schema);
6238
+ await fs15.writeFile(route.output, schema);
6319
6239
  if (Array.isArray(route.commands) && route.commands.length > 0) {
6320
6240
  await Promise.all(route.commands.map((cmd) => execAsync4(cmd)));
6321
6241
  }
@@ -6331,9 +6251,9 @@ var init_pothos2 = __esm({
6331
6251
  if (evt.properties.file.endsWith("out.mjs"))
6332
6252
  return;
6333
6253
  for (const route of routes) {
6334
- const dir = path18.dirname(route.schema);
6335
- const relative = path18.relative(dir, evt.properties.file);
6336
- if (relative && !relative.startsWith("..") && !path18.isAbsolute(relative))
6254
+ const dir = path17.dirname(route.schema);
6255
+ const relative = path17.relative(dir, evt.properties.file);
6256
+ if (relative && !relative.startsWith("..") && !path17.isAbsolute(relative))
6337
6257
  build2(route);
6338
6258
  }
6339
6259
  });
@@ -6359,7 +6279,7 @@ __export(kysely_exports, {
6359
6279
  import { Kysely } from "kysely";
6360
6280
  import { DataApiDialect } from "kysely-data-api";
6361
6281
  import { RDSData } from "@aws-sdk/client-rds-data";
6362
- import * as fs17 from "fs/promises";
6282
+ import * as fs16 from "fs/promises";
6363
6283
  import {
6364
6284
  DatabaseMetadata,
6365
6285
  EnumCollection,
@@ -6431,7 +6351,7 @@ var init_kysely = __esm({
6431
6351
  };
6432
6352
  const serializer = new Serializer();
6433
6353
  const data2 = serializer.serialize(nodes);
6434
- await fs17.writeFile(db.types.path, data2);
6354
+ await fs16.writeFile(db.types.path, data2);
6435
6355
  }
6436
6356
  bus.subscribe("stacks.metadata", (evt) => {
6437
6357
  const constructs = Object.values(evt.properties).flat();
@@ -6568,12 +6488,39 @@ function parse(ssmName) {
6568
6488
  prop: parts.slice(6).join("/")
6569
6489
  };
6570
6490
  }
6491
+ async function restartFunction(arn) {
6492
+ const lambda = useAWSClient(LambdaClient);
6493
+ try {
6494
+ const config = await lambda.send(
6495
+ new GetFunctionConfigurationCommand({
6496
+ FunctionName: arn
6497
+ })
6498
+ );
6499
+ await lambda.send(
6500
+ new UpdateFunctionConfigurationCommand({
6501
+ FunctionName: arn,
6502
+ Environment: {
6503
+ Variables: {
6504
+ ...config.Environment?.Variables || {},
6505
+ [SECRET_UPDATED_AT_ENV]: Date.now().toString()
6506
+ }
6507
+ }
6508
+ })
6509
+ );
6510
+ return true;
6511
+ } catch (e) {
6512
+ if (e.name === "ResourceNotFoundException" && e.message.startsWith("Function not found")) {
6513
+ return;
6514
+ }
6515
+ }
6516
+ }
6571
6517
  var Config, FALLBACK_STAGE, SECRET_UPDATED_AT_ENV, PREFIX;
6572
6518
  var init_config = __esm({
6573
6519
  "src/config.ts"() {
6574
6520
  "use strict";
6575
6521
  init_project();
6576
6522
  init_credentials();
6523
+ init_iot();
6577
6524
  init_stacks();
6578
6525
  ((Config2) => {
6579
6526
  async function parameters() {
@@ -6628,10 +6575,10 @@ var init_config = __esm({
6628
6575
  return result;
6629
6576
  }
6630
6577
  Config2.secrets = secrets2;
6631
- async function env2() {
6578
+ async function env() {
6632
6579
  const project = useProject();
6633
6580
  const parameters2 = await Config2.parameters();
6634
- const env3 = {
6581
+ const env2 = {
6635
6582
  SST_APP: project.config.name,
6636
6583
  SST_STAGE: project.config.stage,
6637
6584
  ...pipe2(
@@ -6640,12 +6587,12 @@ var init_config = __esm({
6640
6587
  Object.fromEntries
6641
6588
  )
6642
6589
  };
6643
- return env3;
6590
+ return env2;
6644
6591
  }
6645
- Config2.env = env2;
6592
+ Config2.env = env;
6646
6593
  async function setSecret(input) {
6647
6594
  const ssm = useAWSClient(SSMClient);
6648
- const result = await ssm.send(
6595
+ await ssm.send(
6649
6596
  new PutParameterCommand({
6650
6597
  Name: pathFor({
6651
6598
  id: input.key,
@@ -6658,6 +6605,9 @@ var init_config = __esm({
6658
6605
  Overwrite: true
6659
6606
  })
6660
6607
  );
6608
+ const iot2 = await useIOT();
6609
+ const topic = `${iot2.prefix}/events`;
6610
+ await iot2.publish(topic, "config.secret.updated", { name: input.key });
6661
6611
  }
6662
6612
  Config2.setSecret = setSecret;
6663
6613
  async function getSecret(input) {
@@ -6691,37 +6641,35 @@ var init_config = __esm({
6691
6641
  }
6692
6642
  Config2.removeSecret = removeSecret;
6693
6643
  async function restart(key) {
6694
- const lambda = useAWSClient(LambdaClient);
6695
6644
  const metadata3 = await stacks_exports.metadata();
6696
- const filtered = Object.values(metadata3).flat().filter((f) => f.type === "Function").filter((f) => f.data.secrets.includes(key));
6697
- const restarted = await Promise.all(
6698
- filtered.map(async (f) => {
6699
- try {
6700
- const config = await lambda.send(
6701
- new GetFunctionConfigurationCommand({
6702
- FunctionName: f.data.arn
6703
- })
6704
- );
6705
- await lambda.send(
6706
- new UpdateFunctionConfigurationCommand({
6707
- FunctionName: f.data.arn,
6708
- Environment: {
6709
- Variables: {
6710
- ...config.Environment?.Variables || {},
6711
- [SECRET_UPDATED_AT_ENV]: Date.now().toString()
6712
- }
6713
- }
6714
- })
6715
- );
6716
- return true;
6717
- } catch (e) {
6718
- if (e.name === "ResourceNotFoundException" && e.message.startsWith("Function not found")) {
6719
- return;
6720
- }
6721
- }
6722
- })
6645
+ const siteData = Object.values(metadata3).flat().filter(
6646
+ (c) => c.type === "AstroSite" || c.type === "NextjsSite" || c.type === "RemixSite" || c.type === "SolidStartSite"
6647
+ ).filter((c) => c.data.secrets.includes(key));
6648
+ const siteDataPlaceholder = siteData.filter(
6649
+ (c) => c.data.mode === "placeholder"
6723
6650
  );
6724
- return restarted.filter(Boolean).length;
6651
+ const siteDataEdge = siteData.filter((c) => c.data.mode === "deployed").filter((c) => c.data.edge);
6652
+ const siteDataRegional = siteData.filter((c) => c.data.mode === "deployed").filter((c) => !c.data.edge);
6653
+ const regionalSiteArns = siteData.map((s) => s.data.server);
6654
+ const functionData = Object.values(metadata3).flat().filter((c) => c.type === "Function").filter((c) => !regionalSiteArns.includes(c.data.arn)).filter((c) => c.data.secrets.includes(key));
6655
+ const restartedSites = (await Promise.all(
6656
+ siteDataRegional.map(async (s) => {
6657
+ const restarted = await restartFunction(s.data.server);
6658
+ return restarted ? s : restarted;
6659
+ })
6660
+ )).filter((c) => Boolean(c));
6661
+ const restartedFunctions = (await Promise.all(
6662
+ functionData.map(async (f) => {
6663
+ const restarted = await restartFunction(f.data.arn);
6664
+ return restarted ? f : restarted;
6665
+ })
6666
+ )).filter((c) => Boolean(c));
6667
+ return {
6668
+ edgeSites: siteDataEdge,
6669
+ sites: restartedSites,
6670
+ placeholderSites: siteDataPlaceholder,
6671
+ functions: restartedFunctions
6672
+ };
6725
6673
  }
6726
6674
  Config2.restart = restart;
6727
6675
  })(Config || (Config = {}));
@@ -6785,62 +6733,17 @@ init_spinner();
6785
6733
  init_logger();
6786
6734
  import dotenv2 from "dotenv";
6787
6735
 
6788
- // src/cli/commands/env.ts
6789
- init_error();
6790
- var env = (program2) => program2.command(
6791
- "env <command..>",
6792
- "Load environment variables and start your frontend",
6793
- (yargs2) => yargs2.array("command").example(
6794
- `sst env "next dev"`,
6795
- "Start Next.js with your environment variables"
6796
- ).example(
6797
- `sst env "vite dev"`,
6798
- "Start Vite with your environment variables"
6799
- ),
6800
- async (args) => {
6801
- const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_spinner(), spinner_exports));
6802
- const fs19 = await import("fs/promises");
6803
- const { SiteEnv } = await Promise.resolve().then(() => (init_site_env(), site_env_exports));
6804
- const { spawnSync } = await import("child_process");
6805
- const { useAWSCredentials: useAWSCredentials3 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
6806
- const { useProject: useProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
6807
- let spinner;
6808
- while (true) {
6809
- const exists = await fs19.access(SiteEnv.valuesFile()).then(() => true).catch(() => false);
6810
- if (!exists) {
6811
- spinner = createSpinner2(
6812
- "Cannot find SST environment variables. Waiting for SST to start..."
6813
- ).start();
6814
- await new Promise((resolve) => setTimeout(resolve, 1e3));
6815
- continue;
6816
- }
6817
- spinner?.succeed();
6818
- const sites = await SiteEnv.values();
6819
- const env2 = sites[process.cwd()] || {};
6820
- const project = useProject2();
6821
- const credentials = await useAWSCredentials3();
6822
- const joined = args.command?.join(" ");
6823
- if (!joined)
6824
- throw new VisibleError(
6825
- "Command is required, e.g. sst env vite dev"
6826
- );
6827
- const result = spawnSync(joined, {
6828
- env: {
6829
- ...process.env,
6830
- ...env2,
6831
- AWS_ACCESS_KEY_ID: credentials.accessKeyId,
6832
- AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
6833
- AWS_SESSION_TOKEN: credentials.sessionToken,
6834
- AWS_REGION: project.config.region
6835
- },
6836
- stdio: "inherit",
6837
- shell: true
6838
- });
6839
- process.exitCode = result.status || void 0;
6840
- break;
6841
- }
6736
+ // src/cli/commands/bootstrap.ts
6737
+ var bootstrap = (program2) => program2.command(
6738
+ "bootstrap",
6739
+ "Create the SST bootstrap stack",
6740
+ (yargs2) => yargs2,
6741
+ async () => {
6742
+ const { useBootstrap: useBootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), bootstrap_exports));
6743
+ await useBootstrap2();
6744
+ process.exit(0);
6842
6745
  }
6843
- ).strict(false);
6746
+ );
6844
6747
 
6845
6748
  // src/cli/commands/dev.tsx
6846
6749
  var dev = (program2) => program2.command(
@@ -6853,11 +6756,11 @@ var dev = (program2) => program2.command(
6853
6756
  async (args) => {
6854
6757
  const { Colors: Colors2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
6855
6758
  const { printHeader: printHeader2 } = await Promise.resolve().then(() => (init_header(), header_exports));
6856
- const { mapValues, omitBy: omitBy2, pipe: pipe3 } = await import("remeda");
6759
+ const { mapValues } = await import("remeda");
6857
6760
  const path20 = await import("path");
6858
6761
  const { useRuntimeWorkers: useRuntimeWorkers2 } = await Promise.resolve().then(() => (init_workers(), workers_exports));
6859
6762
  const { useIOTBridge: useIOTBridge2 } = await Promise.resolve().then(() => (init_iot2(), iot_exports2));
6860
- const { useRuntimeServer: useRuntimeServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
6763
+ const { useRuntimeServer: useRuntimeServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
6861
6764
  const { useBus: useBus2 } = await Promise.resolve().then(() => (init_bus(), bus_exports));
6862
6765
  const { useWatcher: useWatcher2 } = await Promise.resolve().then(() => (init_watcher(), watcher_exports));
6863
6766
  const { useAppMetadata: useAppMetadata2, saveAppMetadata: saveAppMetadata2, Stacks } = await Promise.resolve().then(() => (init_stacks(), stacks_exports));
@@ -6868,11 +6771,10 @@ var dev = (program2) => program2.command(
6868
6771
  const React2 = await import("react");
6869
6772
  const { Context: Context2 } = await Promise.resolve().then(() => (init_context(), context_exports));
6870
6773
  const { printDeploymentResults: printDeploymentResults2, DeploymentUI: DeploymentUI2 } = await Promise.resolve().then(() => (init_deploy2(), deploy_exports));
6871
- const { useLocalServer: useLocalServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
6872
- const fs19 = await import("fs/promises");
6774
+ const { useLocalServer: useLocalServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
6775
+ const fs18 = await import("fs/promises");
6873
6776
  const crypto2 = await import("crypto");
6874
6777
  const { useFunctions: useFunctions3 } = await import("../src/constructs/Function.js");
6875
- const { SiteEnv } = await Promise.resolve().then(() => (init_site_env(), site_env_exports));
6876
6778
  const { usePothosBuilder: usePothosBuilder2 } = await Promise.resolve().then(() => (init_pothos2(), pothos_exports2));
6877
6779
  const { useKyselyTypeGenerator: useKyselyTypeGenerator2 } = await Promise.resolve().then(() => (init_kysely(), kysely_exports));
6878
6780
  const { useRDSWarmer: useRDSWarmer2 } = await Promise.resolve().then(() => (init_warmer(), warmer_exports));
@@ -7044,27 +6946,10 @@ var dev = (program2) => program2.command(
7044
6946
  await saveAppMetadata2({ mode: "dev" });
7045
6947
  }
7046
6948
  lastDeployed = nextChecksum;
7047
- const keys2 = await SiteEnv.keys();
7048
- const result = {};
7049
- for (const key of keys2) {
7050
- const stack = results[key.stack];
7051
- const value = stack.outputs[key.output];
7052
- let existing = result[key.path];
7053
- if (!existing) {
7054
- result[key.path] = existing;
7055
- existing = result[key.path] = {};
7056
- }
7057
- existing[key.environment] = value;
7058
- }
7059
- await SiteEnv.writeValues(result);
7060
- fs19.writeFile(
6949
+ fs18.writeFile(
7061
6950
  path20.join(project.paths.out, "outputs.json"),
7062
6951
  JSON.stringify(
7063
- pipe3(
7064
- results,
7065
- omitBy2((_, key) => key.includes("SstSiteEnv")),
7066
- mapValues((val) => val.outputs)
7067
- ),
6952
+ mapValues(results, (val) => val.outputs),
7068
6953
  null,
7069
6954
  2
7070
6955
  )
@@ -7076,7 +6961,7 @@ var dev = (program2) => program2.command(
7076
6961
  async function checksum(cdkOutPath) {
7077
6962
  const manifestPath = path20.join(cdkOutPath, "manifest.json");
7078
6963
  const cdkManifest = JSON.parse(
7079
- await fs19.readFile(manifestPath).then((x) => x.toString())
6964
+ await fs18.readFile(manifestPath).then((x) => x.toString())
7080
6965
  );
7081
6966
  const checksumData = await Promise.all(
7082
6967
  Object.keys(cdkManifest.artifacts).filter(
@@ -7084,7 +6969,7 @@ var dev = (program2) => program2.command(
7084
6969
  ).map(async (key) => {
7085
6970
  const { templateFile } = cdkManifest.artifacts[key].properties;
7086
6971
  const templatePath = path20.join(cdkOutPath, templateFile);
7087
- const templateContent = await fs19.readFile(templatePath);
6972
+ const templateContent = await fs18.readFile(templatePath);
7088
6973
  return templateContent;
7089
6974
  })
7090
6975
  ).then((x) => x.join("\n"));
@@ -7175,37 +7060,231 @@ Are you sure you want to run this stage in dev mode? [y/N] `,
7175
7060
 
7176
7061
  // src/cli/commands/bind.ts
7177
7062
  init_error();
7063
+ import path18 from "path";
7064
+ var SITE_CONFIG = {
7065
+ NextjsSite: "next.config",
7066
+ AstroSite: "astro.config",
7067
+ RemixSite: "remix.config",
7068
+ SolidStartSite: "vite.config",
7069
+ StaticSite: "vite.config",
7070
+ SlsNextjsSite: "next.config"
7071
+ };
7178
7072
  var bind = (program2) => program2.command(
7179
- "bind <command..>",
7073
+ ["bind <command..>", "env <command..>"],
7180
7074
  "Bind your app's resources to a command",
7181
7075
  (yargs2) => yargs2.array("command").example(`sst bind "vitest run"`, "Bind your resources to your tests").example(
7182
7076
  `sst bind "tsx scripts/myscript.ts"`,
7183
7077
  "Bind your resources to a script"
7184
7078
  ),
7185
7079
  async (args) => {
7186
- const { Config: Config2 } = await Promise.resolve().then(() => (init_config(), config_exports));
7187
- const { spawnSync } = await import("child_process");
7188
- const { useAWSCredentials: useAWSCredentials3 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7080
+ const { spawn: spawn7 } = await import("child_process");
7189
7081
  const { useProject: useProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
7190
- const env2 = await Config2.env();
7082
+ const { useBus: useBus2 } = await Promise.resolve().then(() => (init_bus(), bus_exports));
7083
+ const { useIOT: useIOT2 } = await Promise.resolve().then(() => (init_iot(), iot_exports));
7084
+ const { Colors: Colors2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
7085
+ if (args._[0] === "env") {
7086
+ Colors2.line(
7087
+ Colors2.warning(
7088
+ `Warning: ${Colors2.bold(
7089
+ `sst env`
7090
+ )} has been renamed to ${Colors2.bold(`sst bind`)}`
7091
+ )
7092
+ );
7093
+ }
7094
+ await useIOT2();
7095
+ const bus = useBus2();
7191
7096
  const project = useProject2();
7192
- const credentials = await useAWSCredentials3();
7193
- const joined = args.command?.join(" ");
7194
- if (!joined)
7195
- throw new VisibleError("Command is required, e.g. sst bind env");
7196
- const result = spawnSync(joined, {
7197
- env: {
7198
- ...process.env,
7199
- ...env2,
7097
+ const command = args.command?.join(" ");
7098
+ const isFrontend = await isRunningInFrontend();
7099
+ let p;
7100
+ let timer;
7101
+ let metadataCache;
7102
+ if (!command) {
7103
+ throw new VisibleError(
7104
+ `Command is required, e.g. sst bind ${isFrontend ? "next dev" : "env"}`
7105
+ );
7106
+ }
7107
+ const initialMetadata = await getSiteMetadata();
7108
+ if (!initialMetadata) {
7109
+ return await bindScript();
7110
+ }
7111
+ await bindSite("init");
7112
+ bus.subscribe(
7113
+ "stacks.metadata.updated",
7114
+ () => bindSite("metadata_updated")
7115
+ );
7116
+ bus.subscribe(
7117
+ "stacks.metadata.deleted",
7118
+ () => bindSite("metadata_updated")
7119
+ );
7120
+ bus.subscribe("config.secret.updated", (payload) => {
7121
+ const secretName = payload.properties.name;
7122
+ if (metadataCache?.secrets === void 0)
7123
+ return;
7124
+ if (!metadataCache.secrets.includes(secretName))
7125
+ return;
7126
+ Colors2.line(
7127
+ `
7128
+ `,
7129
+ `SST secrets have been updated. Restarting \`${command}\`...`
7130
+ );
7131
+ bindSite("secrets_updated");
7132
+ });
7133
+ async function isRunningInFrontend() {
7134
+ const { existsAsync: existsAsync3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
7135
+ const results = await Promise.all(
7136
+ Object.values(SITE_CONFIG).map(
7137
+ (config) => [".js", ".cjs", ".mjs", ".ts"].map(
7138
+ (ext) => existsAsync3(`${config}${ext}`)
7139
+ )
7140
+ ).flat()
7141
+ );
7142
+ return results.some(Boolean);
7143
+ }
7144
+ async function bindSite(reason) {
7145
+ const metadata3 = reason === "init" ? initialMetadata : await getSiteMetadata();
7146
+ if (reason === "metadata_updated") {
7147
+ if (areEnvsSame(metadata3.envs, metadataCache?.envs || {}))
7148
+ return;
7149
+ Colors2.line(
7150
+ `
7151
+ `,
7152
+ `SST resources have been updated. Restarting \`${command}\`...`
7153
+ );
7154
+ }
7155
+ metadataCache = metadata3;
7156
+ if (metadata3.role) {
7157
+ const credentials = await assumeSsrRole(metadata3.role);
7158
+ if (credentials) {
7159
+ const expireAt = credentials.Expiration.getTime() - 6e4;
7160
+ clearTimeout(timer);
7161
+ timer = setTimeout(() => {
7162
+ Colors2.line(
7163
+ `
7164
+ `,
7165
+ `Your AWS session is about to expire. Creating a new session and restarting \`${command}\`...`
7166
+ );
7167
+ bindSite("iam_expired");
7168
+ }, expireAt - Date.now());
7169
+ runCommand({
7170
+ ...metadata3.envs,
7171
+ AWS_ACCESS_KEY_ID: credentials.AccessKeyId,
7172
+ AWS_SECRET_ACCESS_KEY: credentials.SecretAccessKey,
7173
+ AWS_SESSION_TOKEN: credentials.SessionToken
7174
+ });
7175
+ return;
7176
+ }
7177
+ }
7178
+ runCommand({
7179
+ ...metadata3.envs,
7180
+ ...await localIamCredentials()
7181
+ });
7182
+ }
7183
+ async function bindScript() {
7184
+ const { Config: Config2 } = await Promise.resolve().then(() => (init_config(), config_exports));
7185
+ runCommand({
7186
+ ...await Config2.env(),
7187
+ ...await localIamCredentials()
7188
+ });
7189
+ }
7190
+ async function getSiteMetadata() {
7191
+ const { metadata: metadata3 } = await Promise.resolve().then(() => (init_metadata(), metadata_exports));
7192
+ const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_spinner(), spinner_exports));
7193
+ const { LambdaClient: LambdaClient2, GetFunctionCommand } = await import("@aws-sdk/client-lambda");
7194
+ const { useAWSClient: useAWSClient2 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7195
+ const spinner = createSpinner2({});
7196
+ while (true) {
7197
+ const metadataData = await metadata3();
7198
+ const data2 = Object.values(metadataData).flat().filter(
7199
+ (c) => Boolean(c)
7200
+ ).filter((c) => Boolean(SITE_CONFIG[c.type])).find(
7201
+ (c) => path18.resolve(project.paths.root, c.data.path) === process.cwd()
7202
+ );
7203
+ if (!data2 && !isFrontend) {
7204
+ return;
7205
+ }
7206
+ if (!data2) {
7207
+ spinner.start(
7208
+ "Make sure `sst dev` is running..."
7209
+ );
7210
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
7211
+ continue;
7212
+ }
7213
+ const isBindSupported = data2.type !== "StaticSite" && data2.type !== "SlsNextjsSite";
7214
+ if (isBindSupported && !data2.data.server || !isBindSupported && !data2.data.environment) {
7215
+ spinner.start(
7216
+ "This was deployed with an old version of SST. Make sure to restart `sst dev`..."
7217
+ );
7218
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
7219
+ continue;
7220
+ }
7221
+ spinner.isSpinning && spinner.stop().clear();
7222
+ if (!isBindSupported) {
7223
+ return { envs: data2.data.environment };
7224
+ }
7225
+ const lambda = useAWSClient2(LambdaClient2);
7226
+ const { Configuration: functionConfig } = await lambda.send(
7227
+ new GetFunctionCommand({
7228
+ FunctionName: data2.data.server
7229
+ })
7230
+ );
7231
+ return {
7232
+ role: functionConfig?.Role,
7233
+ envs: functionConfig?.Environment?.Variables || {},
7234
+ secrets: data2.data.secrets
7235
+ };
7236
+ }
7237
+ }
7238
+ async function assumeSsrRole(roleArn) {
7239
+ const { STSClient: STSClient2, AssumeRoleCommand } = await import("@aws-sdk/client-sts");
7240
+ const { Logger: Logger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
7241
+ const { useAWSClient: useAWSClient2 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7242
+ const sts = useAWSClient2(STSClient2);
7243
+ try {
7244
+ const { Credentials: credentials } = await sts.send(
7245
+ new AssumeRoleCommand({
7246
+ RoleArn: roleArn,
7247
+ RoleSessionName: "dev-session",
7248
+ DurationSeconds: 43200
7249
+ })
7250
+ );
7251
+ return credentials;
7252
+ } catch (e) {
7253
+ Colors2.line(
7254
+ Colors2.warning(
7255
+ `Failed to assume SSR role ${roleArn}. Falling back to using local IAM credentials.`
7256
+ )
7257
+ );
7258
+ Logger2.debug(`Failed to assume ${roleArn}.`, e);
7259
+ }
7260
+ }
7261
+ async function localIamCredentials() {
7262
+ const { useAWSCredentials: useAWSCredentials3 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7263
+ const credentials = await useAWSCredentials3();
7264
+ return {
7200
7265
  AWS_ACCESS_KEY_ID: credentials.accessKeyId,
7201
7266
  AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
7202
- AWS_SESSION_TOKEN: credentials.sessionToken,
7203
- AWS_REGION: project.config.region
7204
- },
7205
- stdio: "inherit",
7206
- shell: true
7207
- });
7208
- process.exitCode = result.status || void 0;
7267
+ AWS_SESSION_TOKEN: credentials.sessionToken
7268
+ };
7269
+ }
7270
+ function runCommand(envs) {
7271
+ Colors2.gap();
7272
+ if (p) {
7273
+ p.kill();
7274
+ }
7275
+ p = spawn7(command, {
7276
+ env: {
7277
+ ...process.env,
7278
+ ...envs,
7279
+ AWS_REGION: project.config.region
7280
+ },
7281
+ stdio: "inherit",
7282
+ shell: true
7283
+ });
7284
+ }
7285
+ function areEnvsSame(envs1, envs2) {
7286
+ return Object.keys(envs1).length === Object.keys(envs2).length && Object.keys(envs1).every((key) => envs1[key] === envs2[key]);
7287
+ }
7209
7288
  }
7210
7289
  ).strict(false);
7211
7290
 
@@ -7240,7 +7319,7 @@ var build = (program2) => program2.command(
7240
7319
  // src/cli/commands/deploy.tsx
7241
7320
  init_credentials();
7242
7321
  init_colors();
7243
- import fs18 from "fs/promises";
7322
+ import fs17 from "fs/promises";
7244
7323
  import path19 from "path";
7245
7324
  var deploy2 = (program2) => program2.command(
7246
7325
  "deploy [filter]",
@@ -7329,7 +7408,7 @@ Are you sure you want to deploy to this stage? (y/N) `,
7329
7408
  printDeploymentResults2(assembly, results);
7330
7409
  if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
7331
7410
  process.exit(1);
7332
- fs18.writeFile(
7411
+ fs17.writeFile(
7333
7412
  path19.join(project.paths.out, "outputs.json"),
7334
7413
  JSON.stringify(
7335
7414
  mapValues(results, (val) => val.outputs),
@@ -7408,8 +7487,8 @@ var consoleCommand = async (program2) => program2.command(
7408
7487
  (yargs2) => yargs2,
7409
7488
  async () => {
7410
7489
  const { blue: blue4 } = await import("colorette");
7411
- const { useRuntimeServer: useRuntimeServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
7412
- const { useLocalServer: useLocalServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
7490
+ const { useRuntimeServer: useRuntimeServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
7491
+ const { useLocalServer: useLocalServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
7413
7492
  const { printHeader: printHeader2 } = await Promise.resolve().then(() => (init_header(), header_exports));
7414
7493
  const { clear: clear2 } = await Promise.resolve().then(() => (init_terminal(), terminal_exports));
7415
7494
  await Promise.all([
@@ -7477,14 +7556,14 @@ var list = (program2) => program2.command(
7477
7556
  }
7478
7557
  break;
7479
7558
  case "table":
7480
- const keys2 = Object.keys(secrets2);
7559
+ const keys = Object.keys(secrets2);
7481
7560
  const keyLen = Math.max(
7482
7561
  "Secrets".length,
7483
- ...keys2.map((key) => key.length)
7562
+ ...keys.map((key) => key.length)
7484
7563
  );
7485
7564
  const valueLen = Math.max(
7486
7565
  "Values".length,
7487
- ...keys2.map(
7566
+ ...keys.map(
7488
7567
  (key) => secrets2[key].value ? secrets2[key].value.length : `${secrets2[key].fallback} (fallback)`.length
7489
7568
  )
7490
7569
  );
@@ -7497,7 +7576,7 @@ var list = (program2) => program2.command(
7497
7576
  console.log(
7498
7577
  "\u251C".padEnd(keyLen + 3, "\u2500") + "\u253C" + "".padEnd(valueLen + 2, "\u2500") + "\u2524"
7499
7578
  );
7500
- keys2.sort().forEach((key) => {
7579
+ keys.sort().forEach((key) => {
7501
7580
  const value = secrets2[key].value ? secrets2[key].value : `${secrets2[key].fallback} ${gray("(fallback)")}`;
7502
7581
  console.log(
7503
7582
  `\u2502 ${key.padEnd(keyLen)} \u2502 ${value.padEnd(valueLen)} \u2502`
@@ -7556,6 +7635,7 @@ var set = (program2) => program2.command(
7556
7635
  }),
7557
7636
  async (args) => {
7558
7637
  const { Config: Config2 } = await Promise.resolve().then(() => (init_config(), config_exports));
7638
+ const { Colors: Colors2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
7559
7639
  const { blue: blue4 } = await import("colorette");
7560
7640
  const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_spinner(), spinner_exports));
7561
7641
  const setting = createSpinner2(` Setting "${args.name}"`).start();
@@ -7566,12 +7646,31 @@ var set = (program2) => program2.command(
7566
7646
  });
7567
7647
  setting.succeed();
7568
7648
  const restarting = createSpinner2(
7569
- ` Restarting all functions using ${blue4(args.name)}...`
7649
+ ` Reloading all resources using ${blue4(args.name)}...`
7570
7650
  ).start();
7571
- const count = await Config2.restart(args.name);
7572
- restarting.succeed(
7573
- count === 1 ? ` Restarted ${count} function` : ` Restarted ${count} functions`
7574
- );
7651
+ const { edgeSites, sites, placeholderSites, functions } = await Config2.restart(args.name);
7652
+ restarting.stop().clear();
7653
+ const siteCount = sites.length + placeholderSites.length;
7654
+ if (siteCount > 0) {
7655
+ Colors2.line(
7656
+ Colors2.success(`\u2714 `),
7657
+ siteCount === 1 ? `Reloaded ${siteCount} site` : `Reloaded ${siteCount} sites`
7658
+ );
7659
+ }
7660
+ const functionCount = functions.length;
7661
+ if (functionCount > 0) {
7662
+ Colors2.line(
7663
+ Colors2.success(`\u2714 `),
7664
+ functionCount === 1 ? `Reloaded ${functionCount} function` : `Reloaded ${functionCount} functions`
7665
+ );
7666
+ }
7667
+ edgeSites.forEach(({ id, type }) => {
7668
+ Colors2.line(
7669
+ Colors2.danger(`\u279C `),
7670
+ `Redeploy the "${id}" ${type} to use the new secret`
7671
+ );
7672
+ });
7673
+ process.exit(0);
7575
7674
  }
7576
7675
  );
7577
7676
 
@@ -7599,13 +7698,13 @@ var update = (program2) => program2.command(
7599
7698
  }),
7600
7699
  async (args) => {
7601
7700
  const { green, yellow } = await import("colorette");
7602
- const fs19 = await import("fs/promises");
7701
+ const fs18 = await import("fs/promises");
7603
7702
  const path20 = await import("path");
7604
7703
  const { fetch } = await import("undici");
7605
7704
  const { useProject: useProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
7606
7705
  const { Colors: Colors2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
7607
7706
  async function find2(dir) {
7608
- const children = await fs19.readdir(dir);
7707
+ const children = await fs18.readdir(dir);
7609
7708
  const tasks2 = children.map(async (item) => {
7610
7709
  if (item === "node_modules")
7611
7710
  return [];
@@ -7614,7 +7713,7 @@ var update = (program2) => program2.command(
7614
7713
  const full = path20.join(dir, item);
7615
7714
  if (item === "package.json")
7616
7715
  return [full];
7617
- const stat = await fs19.stat(full);
7716
+ const stat = await fs18.stat(full);
7618
7717
  if (stat.isDirectory())
7619
7718
  return find2(full);
7620
7719
  return [];
@@ -7628,7 +7727,7 @@ var update = (program2) => program2.command(
7628
7727
  ).then((resp) => resp.json());
7629
7728
  const results = /* @__PURE__ */ new Map();
7630
7729
  const tasks = files.map(async (file) => {
7631
- const data2 = await fs19.readFile(file).then((x) => x.toString()).then(JSON.parse);
7730
+ const data2 = await fs18.readFile(file).then((x) => x.toString()).then(JSON.parse);
7632
7731
  for (const field of FIELDS) {
7633
7732
  const deps = data2[field];
7634
7733
  if (!deps)
@@ -7657,7 +7756,7 @@ var update = (program2) => program2.command(
7657
7756
  }
7658
7757
  }
7659
7758
  if (results.has(file)) {
7660
- await fs19.writeFile(file, JSON.stringify(data2, null, 2));
7759
+ await fs18.writeFile(file, JSON.stringify(data2, null, 2));
7661
7760
  }
7662
7761
  });
7663
7762
  await Promise.all(tasks);
@@ -7885,11 +7984,11 @@ dotenv2.config({
7885
7984
  path: ".env.local",
7886
7985
  override: true
7887
7986
  });
7987
+ bootstrap(program);
7888
7988
  dev(program);
7889
7989
  deploy2(program);
7890
7990
  build(program);
7891
7991
  bind(program);
7892
- env(program);
7893
7992
  secrets(program);
7894
7993
  remove2(program);
7895
7994
  update(program);