@lsts_tech/infra 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +58 -70
  2. package/dist/bin/init.d.ts +4 -3
  3. package/dist/bin/init.d.ts.map +1 -1
  4. package/dist/bin/init.js +619 -117
  5. package/dist/bin/init.js.map +1 -1
  6. package/dist/src/auth/index.d.ts +17 -0
  7. package/dist/src/auth/index.d.ts.map +1 -0
  8. package/dist/src/auth/index.js +18 -0
  9. package/dist/src/auth/index.js.map +1 -0
  10. package/dist/stacks/Dns.d.ts +24 -14
  11. package/dist/stacks/Dns.d.ts.map +1 -1
  12. package/dist/stacks/Dns.js +69 -18
  13. package/dist/stacks/Dns.js.map +1 -1
  14. package/dist/stacks/Pipeline.d.ts +7 -0
  15. package/dist/stacks/Pipeline.d.ts.map +1 -1
  16. package/dist/stacks/Pipeline.js +60 -7
  17. package/dist/stacks/Pipeline.js.map +1 -1
  18. package/docs/CLI.md +58 -15
  19. package/docs/CONFIGURATION.md +73 -30
  20. package/docs/EXAMPLES.md +5 -1
  21. package/examples/delegated-subdomain/infra.config.ts +102 -0
  22. package/examples/next-and-expo/infra.config.ts +33 -28
  23. package/examples/next-only/infra.config.ts +35 -22
  24. package/package.json +10 -4
  25. package/scripts/ensure-pipelines.sh +151 -43
  26. package/scripts/postdeploy-update-dns.sh +42 -11
  27. package/scripts/predeploy-checks.sh +38 -5
  28. package/templates/buildspec.yml +23 -0
  29. package/templates/ensure-pipelines.sh +157 -22
  30. package/templates/env.example +15 -0
  31. package/templates/infra.config.expo-web.ts +153 -0
  32. package/templates/infra.config.next-only.ts +159 -0
  33. package/templates/infra.config.ts +21 -4
  34. package/templates/pipelines.example.json +19 -0
  35. package/templates/private.example.json +13 -0
  36. package/templates/scaffold.gitignore +29 -0
  37. package/templates/scaffold.package.json +25 -0
  38. package/templates/scaffold.tsconfig.json +22 -0
  39. package/templates/secrets.schema.expo-web.json +8 -0
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Template: infra.config.ts (profile: expo-web)
3
+ */
4
+
5
+ /// <reference path="./sst-env.d.ts" />
6
+
7
+ import { resolveDomain, createExpoSite, createPipeline } from "@lsts_tech/infra";
8
+
9
+ type PipelineStage = "production" | "dev" | "mobile";
10
+
11
+ const profile = process.env.INFRA_PROFILE ?? "__PROFILE__";
12
+ const rootDomain = process.env.INFRA_ROOT_DOMAIN ?? "__ROOT_DOMAIN__";
13
+ const pipelineRepo = process.env.INFRA_PIPELINE_REPO ?? "__PIPELINE_REPO__";
14
+ const pipelinePrefix = process.env.INFRA_PIPELINE_PREFIX ?? "__PROJECT_PREFIX__";
15
+ const pipelineProjectTag = process.env.INFRA_PROJECT_TAG ?? "__PROJECT_PREFIX__";
16
+ const appName = process.env.INFRA_APP_NAME ?? "__APP_NAME__";
17
+ const selectedPipelinesRaw = process.env.INFRA_PIPELINES ?? "__PIPELINES_DEFAULT__";
18
+ const createPipelines = (process.env.INFRA_CREATE_PIPELINES ?? "__CREATE_PIPELINES_DEFAULT__") === "true";
19
+ const hostedZoneDomain = process.env.INFRA_HOSTED_ZONE_DOMAIN || undefined;
20
+
21
+ const pipelinePermissionsMode =
22
+ (process.env.INFRA_PIPELINE_PERMISSIONS_MODE ?? "__PIPELINE_PERMISSIONS_MODE__") === "least-privilege"
23
+ ? "least-privilege"
24
+ : "admin";
25
+
26
+ const expoStageMap: Record<string, string> = {
27
+ production: process.env.INFRA_EXPO_DOMAIN_PRODUCTION ?? `mobile.${rootDomain}`,
28
+ dev: process.env.INFRA_EXPO_DOMAIN_DEV ?? `dev.mobile.${rootDomain}`,
29
+ mobile: process.env.INFRA_EXPO_DOMAIN_MOBILE ?? `preview.mobile.${rootDomain}`,
30
+ };
31
+
32
+ const expoCerts: Record<string, string | undefined> = {
33
+ production: process.env.INFRA_EXPO_CERT_ARN_PRODUCTION,
34
+ dev: process.env.INFRA_EXPO_CERT_ARN_DEV,
35
+ mobile: process.env.INFRA_EXPO_CERT_ARN_MOBILE,
36
+ };
37
+
38
+ const commonBuildEnv = {
39
+ INFRA_PROFILE: profile,
40
+ INFRA_APP_NAME: appName,
41
+ INFRA_ROOT_DOMAIN: rootDomain,
42
+ INFRA_HOSTED_ZONE_DOMAIN: hostedZoneDomain ?? "",
43
+ INFRA_PIPELINE_REPO: pipelineRepo,
44
+ INFRA_PIPELINE_PREFIX: pipelinePrefix,
45
+ INFRA_PROJECT_TAG: pipelineProjectTag,
46
+ INFRA_PIPELINE_BRANCH_PROD: process.env.INFRA_PIPELINE_BRANCH_PROD ?? "__BRANCH_PROD__",
47
+ INFRA_PIPELINE_BRANCH_DEV: process.env.INFRA_PIPELINE_BRANCH_DEV ?? "__BRANCH_DEV__",
48
+ INFRA_PIPELINE_BRANCH_MOBILE: process.env.INFRA_PIPELINE_BRANCH_MOBILE ?? "__BRANCH_MOBILE__",
49
+ INFRA_PIPELINES_CONFIG_PATH: process.env.INFRA_PIPELINES_CONFIG_PATH ?? "config/pipelines.json",
50
+ INFRA_PIPELINE_PERMISSIONS_MODE: pipelinePermissionsMode,
51
+ INFRA_CREATE_PIPELINES: "false",
52
+ INFRA_ENABLE_EXPO_SITE: "true",
53
+ INFRA_EXPO_DOMAIN_PRODUCTION: expoStageMap.production,
54
+ INFRA_EXPO_DOMAIN_DEV: expoStageMap.dev,
55
+ INFRA_EXPO_DOMAIN_MOBILE: expoStageMap.mobile,
56
+ INFRA_EXPO_CERT_ARN_PRODUCTION: expoCerts.production ?? "",
57
+ INFRA_EXPO_CERT_ARN_DEV: expoCerts.dev ?? "",
58
+ INFRA_EXPO_CERT_ARN_MOBILE: expoCerts.mobile ?? "",
59
+ DOMAIN_ROOT: rootDomain,
60
+ PROJECT_PREFIX: pipelinePrefix,
61
+ PREFIX: pipelinePrefix,
62
+ DOMAIN_PRODUCTION: expoStageMap.production,
63
+ DOMAIN_DEV: expoStageMap.dev,
64
+ DOMAIN_MOBILE: expoStageMap.mobile,
65
+ };
66
+
67
+ function parsePipelineStage(value: string): PipelineStage | undefined {
68
+ const normalized = value.trim().toLowerCase();
69
+ if (normalized === "production" || normalized === "prod") return "production";
70
+ if (normalized === "dev") return "dev";
71
+ if (normalized === "mobile") return "mobile";
72
+ return undefined;
73
+ }
74
+
75
+ const selectedPipelines = new Set<PipelineStage>(
76
+ selectedPipelinesRaw
77
+ .split(",")
78
+ .map((value) => parsePipelineStage(value))
79
+ .filter((value): value is PipelineStage => value !== undefined)
80
+ );
81
+
82
+ const pipelineSpecs: Record<PipelineStage, { suffix: string; branch: string; stage: PipelineStage }> = {
83
+ production: {
84
+ suffix: "prod",
85
+ branch: process.env.INFRA_PIPELINE_BRANCH_PROD ?? "__BRANCH_PROD__",
86
+ stage: "production",
87
+ },
88
+ dev: {
89
+ suffix: "dev",
90
+ branch: process.env.INFRA_PIPELINE_BRANCH_DEV ?? "__BRANCH_DEV__",
91
+ stage: "dev",
92
+ },
93
+ mobile: {
94
+ suffix: "mobile",
95
+ branch: process.env.INFRA_PIPELINE_BRANCH_MOBILE ?? "__BRANCH_MOBILE__",
96
+ stage: "mobile",
97
+ },
98
+ };
99
+
100
+ export function createInfrastructure() {
101
+ const stage = $app.stage;
102
+
103
+ const { domain, domainName } = resolveDomain({
104
+ rootDomain,
105
+ stage,
106
+ stageMap: expoStageMap,
107
+ hostedZoneDomain,
108
+ });
109
+
110
+ const { url } = createExpoSite({
111
+ appPath: "../../apps/mobile",
112
+ id: `mobile-${stage}`,
113
+ domain,
114
+ certificateArn: expoCerts[stage],
115
+ environment: {
116
+ EXPO_PUBLIC_STAGE: stage,
117
+ EXPO_PUBLIC_SITE_URL: `https://${domainName}`,
118
+ },
119
+ invalidation: {
120
+ paths: ["/*"],
121
+ wait: stage === "production" || stage === "mobile",
122
+ },
123
+ });
124
+
125
+ const outputs: Record<string, unknown> = {
126
+ profile,
127
+ mobileUrl: url,
128
+ mobileDomain: domainName,
129
+ };
130
+
131
+ if (stage === "production" && createPipelines && selectedPipelines.size > 0) {
132
+ const pipelineOutputs: Record<string, string> = {};
133
+
134
+ for (const pipelineStage of selectedPipelines) {
135
+ const spec = pipelineSpecs[pipelineStage];
136
+ const pipeline = createPipeline({
137
+ name: `${pipelinePrefix}-${spec.suffix}`,
138
+ repo: pipelineRepo,
139
+ branch: spec.branch,
140
+ stage: spec.stage,
141
+ projectTag: pipelineProjectTag,
142
+ buildEnv: commonBuildEnv,
143
+ permissionsMode: pipelinePermissionsMode,
144
+ });
145
+
146
+ pipelineOutputs[`${pipelineStage}PipelineName`] = pipeline.pipelineName;
147
+ }
148
+
149
+ outputs.pipelines = pipelineOutputs;
150
+ }
151
+
152
+ return outputs;
153
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Template: infra.config.ts (profile: next-only)
3
+ */
4
+
5
+ /// <reference path="./sst-env.d.ts" />
6
+
7
+ import { resolveDomain, createNextSite, createPipeline } from "@lsts_tech/infra";
8
+
9
+ type PipelineStage = "production" | "dev" | "mobile";
10
+
11
+ const secrets = {
12
+ DatabaseUrl: new sst.Secret("DatabaseUrl"),
13
+ AuthSecret: new sst.Secret("AuthSecret"),
14
+ };
15
+
16
+ const profile = process.env.INFRA_PROFILE ?? "__PROFILE__";
17
+ const rootDomain = process.env.INFRA_ROOT_DOMAIN ?? "__ROOT_DOMAIN__";
18
+ const pipelineRepo = process.env.INFRA_PIPELINE_REPO ?? "__PIPELINE_REPO__";
19
+ const pipelinePrefix = process.env.INFRA_PIPELINE_PREFIX ?? "__PROJECT_PREFIX__";
20
+ const pipelineProjectTag = process.env.INFRA_PROJECT_TAG ?? "__PROJECT_PREFIX__";
21
+ const appName = process.env.INFRA_APP_NAME ?? "__APP_NAME__";
22
+ const selectedPipelinesRaw = process.env.INFRA_PIPELINES ?? "__PIPELINES_DEFAULT__";
23
+ const createPipelines = (process.env.INFRA_CREATE_PIPELINES ?? "__CREATE_PIPELINES_DEFAULT__") === "true";
24
+ const hostedZoneDomain = process.env.INFRA_HOSTED_ZONE_DOMAIN || undefined;
25
+
26
+ const pipelinePermissionsMode =
27
+ (process.env.INFRA_PIPELINE_PERMISSIONS_MODE ?? "__PIPELINE_PERMISSIONS_MODE__") === "least-privilege"
28
+ ? "least-privilege"
29
+ : "admin";
30
+
31
+ const webStageMap: Record<string, string> = {
32
+ production: process.env.INFRA_WEB_DOMAIN_PRODUCTION ?? rootDomain,
33
+ dev: process.env.INFRA_WEB_DOMAIN_DEV ?? `dev.${rootDomain}`,
34
+ mobile: process.env.INFRA_WEB_DOMAIN_MOBILE ?? `api.${rootDomain}`,
35
+ };
36
+
37
+ const webCerts: Record<string, string | undefined> = {
38
+ production: process.env.INFRA_WEB_CERT_ARN_PRODUCTION,
39
+ dev: process.env.INFRA_WEB_CERT_ARN_DEV,
40
+ mobile: process.env.INFRA_WEB_CERT_ARN_MOBILE,
41
+ };
42
+
43
+ const commonBuildEnv = {
44
+ INFRA_PROFILE: profile,
45
+ INFRA_APP_NAME: appName,
46
+ INFRA_ROOT_DOMAIN: rootDomain,
47
+ INFRA_HOSTED_ZONE_DOMAIN: hostedZoneDomain ?? "",
48
+ INFRA_PIPELINE_REPO: pipelineRepo,
49
+ INFRA_PIPELINE_PREFIX: pipelinePrefix,
50
+ INFRA_PROJECT_TAG: pipelineProjectTag,
51
+ INFRA_PIPELINE_BRANCH_PROD: process.env.INFRA_PIPELINE_BRANCH_PROD ?? "__BRANCH_PROD__",
52
+ INFRA_PIPELINE_BRANCH_DEV: process.env.INFRA_PIPELINE_BRANCH_DEV ?? "__BRANCH_DEV__",
53
+ INFRA_PIPELINE_BRANCH_MOBILE: process.env.INFRA_PIPELINE_BRANCH_MOBILE ?? "__BRANCH_MOBILE__",
54
+ INFRA_PIPELINES_CONFIG_PATH: process.env.INFRA_PIPELINES_CONFIG_PATH ?? "config/pipelines.json",
55
+ INFRA_PIPELINE_PERMISSIONS_MODE: pipelinePermissionsMode,
56
+ INFRA_CREATE_PIPELINES: "false",
57
+ INFRA_WEB_DOMAIN_PRODUCTION: webStageMap.production,
58
+ INFRA_WEB_DOMAIN_DEV: webStageMap.dev,
59
+ INFRA_WEB_DOMAIN_MOBILE: webStageMap.mobile,
60
+ INFRA_WEB_CERT_ARN_PRODUCTION: webCerts.production ?? "",
61
+ INFRA_WEB_CERT_ARN_DEV: webCerts.dev ?? "",
62
+ INFRA_WEB_CERT_ARN_MOBILE: webCerts.mobile ?? "",
63
+ DOMAIN_ROOT: rootDomain,
64
+ PROJECT_PREFIX: pipelinePrefix,
65
+ PREFIX: pipelinePrefix,
66
+ DOMAIN_PRODUCTION: webStageMap.production,
67
+ DOMAIN_DEV: webStageMap.dev,
68
+ DOMAIN_MOBILE: webStageMap.mobile,
69
+ };
70
+
71
+ function parsePipelineStage(value: string): PipelineStage | undefined {
72
+ const normalized = value.trim().toLowerCase();
73
+ if (normalized === "production" || normalized === "prod") return "production";
74
+ if (normalized === "dev") return "dev";
75
+ if (normalized === "mobile") return "mobile";
76
+ return undefined;
77
+ }
78
+
79
+ const selectedPipelines = new Set<PipelineStage>(
80
+ selectedPipelinesRaw
81
+ .split(",")
82
+ .map((value) => parsePipelineStage(value))
83
+ .filter((value): value is PipelineStage => value !== undefined)
84
+ );
85
+
86
+ const pipelineSpecs: Record<PipelineStage, { suffix: string; branch: string; stage: PipelineStage }> = {
87
+ production: {
88
+ suffix: "prod",
89
+ branch: process.env.INFRA_PIPELINE_BRANCH_PROD ?? "__BRANCH_PROD__",
90
+ stage: "production",
91
+ },
92
+ dev: {
93
+ suffix: "dev",
94
+ branch: process.env.INFRA_PIPELINE_BRANCH_DEV ?? "__BRANCH_DEV__",
95
+ stage: "dev",
96
+ },
97
+ mobile: {
98
+ suffix: "mobile",
99
+ branch: process.env.INFRA_PIPELINE_BRANCH_MOBILE ?? "__BRANCH_MOBILE__",
100
+ stage: "mobile",
101
+ },
102
+ };
103
+
104
+ export function createInfrastructure() {
105
+ const stage = $app.stage;
106
+
107
+ const { domain, domainName } = resolveDomain({
108
+ rootDomain,
109
+ stage,
110
+ stageMap: webStageMap,
111
+ hostedZoneDomain,
112
+ });
113
+
114
+ const { url } = createNextSite({
115
+ appPath: "../../apps/web",
116
+ id: `web-${stage}`,
117
+ domain,
118
+ certificateArn: webCerts[stage],
119
+ environment: {
120
+ NEXT_PUBLIC_APP_URL: `https://${domainName}`,
121
+ DATABASE_URL: secrets.DatabaseUrl.value,
122
+ AUTH_SECRET: secrets.AuthSecret.value,
123
+ },
124
+ warm: stage === "production" ? 1 : 0,
125
+ invalidation: {
126
+ paths: ["/*"],
127
+ wait: stage === "production",
128
+ },
129
+ });
130
+
131
+ const outputs: Record<string, unknown> = {
132
+ profile,
133
+ siteUrl: url,
134
+ domain: domainName,
135
+ };
136
+
137
+ if (stage === "production" && createPipelines && selectedPipelines.size > 0) {
138
+ const pipelineOutputs: Record<string, string> = {};
139
+
140
+ for (const pipelineStage of selectedPipelines) {
141
+ const spec = pipelineSpecs[pipelineStage];
142
+ const pipeline = createPipeline({
143
+ name: `${pipelinePrefix}-${spec.suffix}`,
144
+ repo: pipelineRepo,
145
+ branch: spec.branch,
146
+ stage: spec.stage,
147
+ projectTag: pipelineProjectTag,
148
+ buildEnv: commonBuildEnv,
149
+ permissionsMode: pipelinePermissionsMode,
150
+ });
151
+
152
+ pipelineOutputs[`${pipelineStage}PipelineName`] = pipeline.pipelineName;
153
+ }
154
+
155
+ outputs.pipelines = pipelineOutputs;
156
+ }
157
+
158
+ return outputs;
159
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Template: infra.config.ts
2
+ * Template: infra.config.ts (profile: next-expo)
3
3
  *
4
4
  * Generated by `npx @lsts_tech/infra init`.
5
- * This file is white-label and environment-driven for public repositories.
5
+ * White-label and environment-driven for public repositories.
6
6
  */
7
7
 
8
8
  /// <reference path="./sst-env.d.ts" />
@@ -16,13 +16,21 @@ const secrets = {
16
16
  AuthSecret: new sst.Secret("AuthSecret"),
17
17
  };
18
18
 
19
+ const profile = process.env.INFRA_PROFILE ?? "__PROFILE__";
19
20
  const rootDomain = process.env.INFRA_ROOT_DOMAIN ?? "__ROOT_DOMAIN__";
20
21
  const pipelineRepo = process.env.INFRA_PIPELINE_REPO ?? "__PIPELINE_REPO__";
21
22
  const pipelinePrefix = process.env.INFRA_PIPELINE_PREFIX ?? "__PROJECT_PREFIX__";
22
23
  const pipelineProjectTag = process.env.INFRA_PROJECT_TAG ?? "__PROJECT_PREFIX__";
23
- const appName = process.env.INFRA_APP_NAME ?? "__PROJECT_PREFIX__";
24
+ const appName = process.env.INFRA_APP_NAME ?? "__APP_NAME__";
24
25
  const selectedPipelinesRaw = process.env.INFRA_PIPELINES ?? "__PIPELINES_DEFAULT__";
26
+ const createPipelines = (process.env.INFRA_CREATE_PIPELINES ?? "__CREATE_PIPELINES_DEFAULT__") === "true";
25
27
  const enableExpoSite = (process.env.INFRA_ENABLE_EXPO_SITE ?? "__ENABLE_EXPO_SITE__") === "true";
28
+ const hostedZoneDomain = process.env.INFRA_HOSTED_ZONE_DOMAIN || undefined;
29
+
30
+ const pipelinePermissionsMode =
31
+ (process.env.INFRA_PIPELINE_PERMISSIONS_MODE ?? "__PIPELINE_PERMISSIONS_MODE__") === "least-privilege"
32
+ ? "least-privilege"
33
+ : "admin";
26
34
 
27
35
  const webStageMap: Record<string, string> = {
28
36
  production: process.env.INFRA_WEB_DOMAIN_PRODUCTION ?? rootDomain,
@@ -49,14 +57,19 @@ const expoCerts: Record<string, string | undefined> = {
49
57
  };
50
58
 
51
59
  const commonBuildEnv = {
60
+ INFRA_PROFILE: profile,
52
61
  INFRA_APP_NAME: appName,
53
62
  INFRA_ROOT_DOMAIN: rootDomain,
63
+ INFRA_HOSTED_ZONE_DOMAIN: hostedZoneDomain ?? "",
54
64
  INFRA_PIPELINE_REPO: pipelineRepo,
55
65
  INFRA_PIPELINE_PREFIX: pipelinePrefix,
56
66
  INFRA_PROJECT_TAG: pipelineProjectTag,
57
67
  INFRA_PIPELINE_BRANCH_PROD: process.env.INFRA_PIPELINE_BRANCH_PROD ?? "__BRANCH_PROD__",
58
68
  INFRA_PIPELINE_BRANCH_DEV: process.env.INFRA_PIPELINE_BRANCH_DEV ?? "__BRANCH_DEV__",
59
69
  INFRA_PIPELINE_BRANCH_MOBILE: process.env.INFRA_PIPELINE_BRANCH_MOBILE ?? "__BRANCH_MOBILE__",
70
+ INFRA_PIPELINES_CONFIG_PATH: process.env.INFRA_PIPELINES_CONFIG_PATH ?? "config/pipelines.json",
71
+ INFRA_PIPELINE_PERMISSIONS_MODE: pipelinePermissionsMode,
72
+ INFRA_CREATE_PIPELINES: "false",
60
73
  INFRA_WEB_DOMAIN_PRODUCTION: webStageMap.production,
61
74
  INFRA_WEB_DOMAIN_DEV: webStageMap.dev,
62
75
  INFRA_WEB_DOMAIN_MOBILE: webStageMap.mobile,
@@ -117,6 +130,7 @@ export function createInfrastructure() {
117
130
  rootDomain,
118
131
  stage,
119
132
  stageMap: webStageMap,
133
+ hostedZoneDomain,
120
134
  });
121
135
 
122
136
  const { url } = createNextSite({
@@ -144,6 +158,7 @@ export function createInfrastructure() {
144
158
  rootDomain,
145
159
  stage,
146
160
  stageMap: expoStageMap,
161
+ hostedZoneDomain,
147
162
  });
148
163
 
149
164
  mobileDomainName = expoDomainResult.domainName;
@@ -166,6 +181,7 @@ export function createInfrastructure() {
166
181
  }
167
182
 
168
183
  const outputs: Record<string, unknown> = {
184
+ profile,
169
185
  siteUrl: url,
170
186
  domain: domainName,
171
187
  };
@@ -175,7 +191,7 @@ export function createInfrastructure() {
175
191
  outputs.mobileDomain = mobileDomainName;
176
192
  }
177
193
 
178
- if (stage === "production" && selectedPipelines.size > 0) {
194
+ if (stage === "production" && createPipelines && selectedPipelines.size > 0) {
179
195
  const pipelineOutputs: Record<string, string> = {};
180
196
 
181
197
  for (const pipelineStage of selectedPipelines) {
@@ -187,6 +203,7 @@ export function createInfrastructure() {
187
203
  stage: spec.stage,
188
204
  projectTag: pipelineProjectTag,
189
205
  buildEnv: commonBuildEnv,
206
+ permissionsMode: pipelinePermissionsMode,
190
207
  });
191
208
 
192
209
  pipelineOutputs[`${pipelineStage}PipelineName`] = pipeline.pipelineName;
@@ -0,0 +1,19 @@
1
+ {
2
+ "pipelines": {
3
+ "production": {
4
+ "enabled": true,
5
+ "branch": "__BRANCH_PROD__",
6
+ "repo": "__PIPELINE_REPO__"
7
+ },
8
+ "dev": {
9
+ "enabled": true,
10
+ "branch": "__BRANCH_DEV__",
11
+ "repo": "__PIPELINE_REPO__"
12
+ },
13
+ "mobile": {
14
+ "enabled": false,
15
+ "branch": "__BRANCH_MOBILE__",
16
+ "repo": "__PIPELINE_REPO__"
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "notes": "Copy this file to config/private.json and keep it untracked.",
3
+ "secrets": {
4
+ "DatabaseUrl": "postgresql://username:password@host:5432/database",
5
+ "AuthSecret": "replace-with-secure-random-value"
6
+ },
7
+ "deploy": {
8
+ "region": "us-east-1",
9
+ "tags": {
10
+ "Project": "__PROJECT_PREFIX__"
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,29 @@
1
+ # Build output
2
+ dist/
3
+
4
+ # SST state
5
+ .sst/
6
+ state.json
7
+ Pulumi.*.yaml
8
+
9
+ # Node
10
+ node_modules/
11
+
12
+ # Environment
13
+ .env
14
+ .env.*
15
+ !.env.example
16
+
17
+ # Local private config
18
+ config/*.json
19
+ !config/*.example.json
20
+
21
+ # Editor
22
+ .vscode/
23
+ *.swp
24
+
25
+ # OS
26
+ .DS_Store
27
+
28
+ # Tarball
29
+ *.tgz
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "__PROJECT_PREFIX__-infra",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "sst dev",
7
+ "deploy": "sst deploy",
8
+ "deploy:dev": "sst deploy --stage dev",
9
+ "deploy:prod": "sst deploy --stage production",
10
+ "doctor": "npx @lsts_tech/infra doctor --target .",
11
+ "ensure:pipelines": "APPROVE=true bash scripts/ensure-pipelines.sh",
12
+ "ensure:secrets": "bash scripts/ensure-secrets.sh dev"
13
+ },
14
+ "dependencies": {
15
+ "@lsts_tech/infra": "__INFRA_VERSION__",
16
+ "sst": "^3.7.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^22.13.9",
20
+ "typescript": "^5"
21
+ },
22
+ "engines": {
23
+ "node": ">=20"
24
+ }
25
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "types": ["node"]
11
+ },
12
+ "include": [
13
+ "infra.config.ts",
14
+ "sst.config.ts",
15
+ "sst-env.d.ts"
16
+ ],
17
+ "exclude": [
18
+ "node_modules",
19
+ "dist",
20
+ ".sst"
21
+ ]
22
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "Secrets Schema",
4
+ "description": "Expo web profile does not require app secrets by default.",
5
+ "type": "object",
6
+ "properties": {},
7
+ "required": []
8
+ }