@vertile-ai/iac 0.0.1 → 0.1.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.
Files changed (68) hide show
  1. package/README.md +73 -37
  2. package/docs/README.md +3 -2
  3. package/docs/index.html +2 -2
  4. package/docs/manifest.md +38 -5
  5. package/examples/bun-hono-api/README.md +9 -0
  6. package/examples/bun-hono-api/infrastructure/iac/iac.do.json +87 -0
  7. package/examples/bun-hono-api/infrastructure/iac/iac.json +107 -0
  8. package/examples/bun-hono-api/package.json +15 -0
  9. package/examples/bun-hono-api/src/index.ts +7 -0
  10. package/examples/go-api/README.md +8 -0
  11. package/examples/go-api/cmd/server/main.go +16 -0
  12. package/examples/go-api/go.mod +3 -0
  13. package/examples/go-api/infrastructure/iac/iac.do.json +90 -0
  14. package/examples/go-api/infrastructure/iac/iac.json +106 -0
  15. package/examples/next-monorepo/README.md +22 -0
  16. package/examples/next-monorepo/apps/admin/package.json +7 -0
  17. package/examples/next-monorepo/apps/web/package.json +7 -0
  18. package/examples/next-monorepo/infrastructure/iac/iac.aws.json +172 -0
  19. package/examples/next-monorepo/infrastructure/iac/iac.do.json +129 -0
  20. package/examples/{dynomic → next-monorepo}/infrastructure/iac/iac.json +102 -23
  21. package/examples/next-monorepo/infrastructure/iac/iac.vercel.json +109 -0
  22. package/examples/{dynomic → next-monorepo}/package.json +2 -2
  23. package/examples/node-api/README.md +8 -0
  24. package/examples/node-api/infrastructure/iac/iac.aws.json +132 -0
  25. package/examples/node-api/infrastructure/iac/iac.json +111 -0
  26. package/examples/node-api/package.json +12 -0
  27. package/examples/node-api/src/server.js +8 -0
  28. package/examples/python-fastapi-api/README.md +8 -0
  29. package/examples/python-fastapi-api/app/main.py +8 -0
  30. package/examples/python-fastapi-api/infrastructure/iac/iac.aws.json +129 -0
  31. package/examples/python-fastapi-api/infrastructure/iac/iac.json +113 -0
  32. package/examples/python-fastapi-api/pyproject.toml +10 -0
  33. package/examples/react-spa/README.md +8 -0
  34. package/examples/react-spa/index.html +2 -0
  35. package/examples/react-spa/infrastructure/iac/iac.aws.json +115 -0
  36. package/examples/react-spa/infrastructure/iac/iac.json +111 -0
  37. package/examples/react-spa/infrastructure/iac/iac.vercel.json +76 -0
  38. package/examples/react-spa/package.json +19 -0
  39. package/examples/react-spa/src/main.jsx +8 -0
  40. package/examples/sveltekit-web/README.md +9 -0
  41. package/examples/sveltekit-web/infrastructure/iac/iac.json +76 -0
  42. package/examples/sveltekit-web/infrastructure/iac/iac.vercel.json +74 -0
  43. package/examples/sveltekit-web/package.json +19 -0
  44. package/examples/sveltekit-web/src/routes/+page.svelte +3 -0
  45. package/examples/sveltekit-web/svelte.config.js +7 -0
  46. package/package.json +1 -1
  47. package/schema/iac.schema.json +83 -2
  48. package/src/apply.mjs +3 -4
  49. package/src/cli.mjs +1 -0
  50. package/src/core/context.mjs +4 -2
  51. package/src/core/deployments.mjs +39 -0
  52. package/src/core/env-files.mjs +38 -0
  53. package/src/core/env-source.mjs +5 -0
  54. package/src/core/hcl.mjs +2 -1
  55. package/src/core/manifest.mjs +15 -1
  56. package/src/core/render.mjs +19 -8
  57. package/src/core/vercel-manifests.mjs +5 -11
  58. package/src/plan.mjs +3 -4
  59. package/src/providers/aws/index.mjs +43 -24
  60. package/src/provision-env.mjs +72 -24
  61. package/src/render.mjs +3 -4
  62. package/src/shared.mjs +0 -4
  63. package/src/sync-env.mjs +33 -38
  64. package/examples/dynomic/README.md +0 -22
  65. package/examples/dynomic/apps/admin/package.json +0 -7
  66. package/examples/dynomic/apps/web/package.json +0 -7
  67. /package/examples/{dynomic → next-monorepo}/apps/admin/vercel.json +0 -0
  68. /package/examples/{dynomic → next-monorepo}/apps/web/vercel.json +0 -0
@@ -0,0 +1,115 @@
1
+ {
2
+ "$schema": "../../../../schema/iac.schema.json",
3
+ "version": 1,
4
+ "project": {
5
+ "key": "react-spa",
6
+ "name": "react-spa"
7
+ },
8
+ "environments": [
9
+ "development",
10
+ "test",
11
+ "uat",
12
+ "nightly",
13
+ "staging",
14
+ "preview",
15
+ "production"
16
+ ],
17
+ "providers": {
18
+ "aws": {
19
+ "region": "us-east-1",
20
+ "defaultTags": {
21
+ "Example": "react-spa",
22
+ "Runtime": "react"
23
+ },
24
+ "deployments": {
25
+ "dev": {
26
+ "environment": "development",
27
+ "region": "us-east-1",
28
+ "profile": "react-spa-dev",
29
+ "tags": {
30
+ "Stage": "dev"
31
+ }
32
+ },
33
+ "uat": {
34
+ "environment": "uat",
35
+ "region": "us-east-1",
36
+ "profile": "react-spa-uat",
37
+ "tags": {
38
+ "Stage": "uat"
39
+ }
40
+ },
41
+ "nightly": {
42
+ "environment": "nightly",
43
+ "region": "us-east-1",
44
+ "profile": "react-spa-nightly",
45
+ "tags": {
46
+ "Stage": "nightly"
47
+ }
48
+ },
49
+ "prod": {
50
+ "environment": "production",
51
+ "region": "us-east-1",
52
+ "profile": "react-spa-prod",
53
+ "tags": {
54
+ "Stage": "prod"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ },
60
+ "apps": [
61
+ {
62
+ "key": "web",
63
+ "name": "react-spa",
64
+ "framework": "vite",
65
+ "rootDirectory": ".",
66
+ "outputDir": "dist"
67
+ }
68
+ ],
69
+ "objectStorage": [
70
+ {
71
+ "key": "assets",
72
+ "visibility": "public",
73
+ "providers": {
74
+ "aws": {
75
+ "bucket": "react-spa-assets",
76
+ "forceDestroy": true
77
+ }
78
+ }
79
+ }
80
+ ],
81
+ "env": {
82
+ "environments": {
83
+ "development": {
84
+ "files": [
85
+ ".env.development"
86
+ ]
87
+ },
88
+ "test": {
89
+ "files": [
90
+ ".env.test"
91
+ ]
92
+ },
93
+ "uat": {
94
+ "files": [
95
+ ".env.uat"
96
+ ]
97
+ },
98
+ "nightly": {
99
+ "files": [
100
+ ".env.nightly"
101
+ ]
102
+ },
103
+ "staging": {
104
+ "files": [
105
+ ".env.staging"
106
+ ]
107
+ },
108
+ "production": {
109
+ "files": [
110
+ ".env.production"
111
+ ]
112
+ }
113
+ }
114
+ }
115
+ }
@@ -0,0 +1,111 @@
1
+ {
2
+ "$schema": "../../../../schema/iac.schema.json",
3
+ "version": 1,
4
+ "project": {
5
+ "key": "react-spa",
6
+ "name": "react-spa"
7
+ },
8
+ "environments": [
9
+ "development",
10
+ "test",
11
+ "uat",
12
+ "nightly",
13
+ "staging",
14
+ "preview",
15
+ "production"
16
+ ],
17
+ "providers": {
18
+ "vercel": {
19
+ "teamSlug": "example-team"
20
+ },
21
+ "aws": {
22
+ "region": "us-east-1",
23
+ "deployments": {
24
+ "dev": {
25
+ "environment": "development",
26
+ "region": "us-east-1",
27
+ "profile": "react-spa-dev",
28
+ "tags": {
29
+ "Stage": "dev"
30
+ }
31
+ },
32
+ "uat": {
33
+ "environment": "uat",
34
+ "region": "us-east-1",
35
+ "profile": "react-spa-uat",
36
+ "tags": {
37
+ "Stage": "uat"
38
+ }
39
+ },
40
+ "nightly": {
41
+ "environment": "nightly",
42
+ "region": "us-east-1",
43
+ "profile": "react-spa-nightly",
44
+ "tags": {
45
+ "Stage": "nightly"
46
+ }
47
+ },
48
+ "prod": {
49
+ "environment": "production",
50
+ "region": "us-east-1",
51
+ "profile": "react-spa-prod",
52
+ "tags": {
53
+ "Stage": "prod"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ },
59
+ "apps": [
60
+ {
61
+ "key": "web",
62
+ "name": "react-spa",
63
+ "framework": "vite",
64
+ "rootDirectory": ".",
65
+ "outputDir": "dist",
66
+ "domains": [
67
+ "react-spa.example.com"
68
+ ]
69
+ }
70
+ ],
71
+ "objectStorage": [
72
+ {
73
+ "key": "assets",
74
+ "visibility": "public"
75
+ }
76
+ ],
77
+ "env": {
78
+ "environments": {
79
+ "development": {
80
+ "files": [
81
+ ".env.development"
82
+ ]
83
+ },
84
+ "test": {
85
+ "files": [
86
+ ".env.test"
87
+ ]
88
+ },
89
+ "uat": {
90
+ "files": [
91
+ ".env.uat"
92
+ ]
93
+ },
94
+ "nightly": {
95
+ "files": [
96
+ ".env.nightly"
97
+ ]
98
+ },
99
+ "staging": {
100
+ "files": [
101
+ ".env.staging"
102
+ ]
103
+ },
104
+ "production": {
105
+ "files": [
106
+ ".env.production"
107
+ ]
108
+ }
109
+ }
110
+ }
111
+ }
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "../../../../schema/iac.schema.json",
3
+ "version": 1,
4
+ "project": {
5
+ "key": "react-spa",
6
+ "name": "react-spa"
7
+ },
8
+ "environments": [
9
+ "development",
10
+ "test",
11
+ "uat",
12
+ "nightly",
13
+ "staging",
14
+ "preview",
15
+ "production"
16
+ ],
17
+ "providers": {
18
+ "vercel": {
19
+ "teamSlug": "example-team",
20
+ "projectDefaults": {
21
+ "nodeVersion": "22.x"
22
+ }
23
+ }
24
+ },
25
+ "apps": [
26
+ {
27
+ "key": "web",
28
+ "name": "react-spa",
29
+ "framework": "vite",
30
+ "rootDirectory": ".",
31
+ "outputDir": "dist",
32
+ "domains": [
33
+ "react-spa.example.com"
34
+ ],
35
+ "providers": {
36
+ "vercel": {
37
+ "enableAffectedProjectsDeployments": false
38
+ }
39
+ }
40
+ }
41
+ ],
42
+ "env": {
43
+ "environments": {
44
+ "development": {
45
+ "files": [
46
+ ".env.development"
47
+ ]
48
+ },
49
+ "test": {
50
+ "files": [
51
+ ".env.test"
52
+ ]
53
+ },
54
+ "uat": {
55
+ "files": [
56
+ ".env.uat"
57
+ ]
58
+ },
59
+ "nightly": {
60
+ "files": [
61
+ ".env.nightly"
62
+ ]
63
+ },
64
+ "staging": {
65
+ "files": [
66
+ ".env.staging"
67
+ ]
68
+ },
69
+ "production": {
70
+ "files": [
71
+ ".env.production"
72
+ ]
73
+ }
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "react-spa",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "iac:render": "vertile-iac render --repo-root . --target=all --deployment=prod"
9
+ },
10
+ "dependencies": {
11
+ "@vitejs/plugin-react": "^5.0.0",
12
+ "vite": "^7.0.0",
13
+ "react": "^19.0.0",
14
+ "react-dom": "^19.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "@vertile-ai/iac": "0.1.0"
18
+ }
19
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+
4
+ createRoot(document.getElementById('root')).render(
5
+ <main>
6
+ <h1>React SPA</h1>
7
+ </main>,
8
+ )
@@ -0,0 +1,9 @@
1
+ # SvelteKit Web
2
+
3
+ SvelteKit app example with Vercel as the primary web provider and a
4
+ DigitalOcean variant for infrastructure resources.
5
+
6
+ ```bash
7
+ vertile-iac render --repo-root examples/sveltekit-web --target=all --deployment=prod
8
+ vertile-iac render --repo-root examples/sveltekit-web --iac-manifest infrastructure/iac/iac.vercel.json --target=vercel --env=production
9
+ ```
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "../../../../schema/iac.schema.json",
3
+ "version": 1,
4
+ "project": {
5
+ "key": "sveltekit-web",
6
+ "name": "sveltekit-web"
7
+ },
8
+ "environments": [
9
+ "development",
10
+ "test",
11
+ "uat",
12
+ "nightly",
13
+ "staging",
14
+ "preview",
15
+ "production"
16
+ ],
17
+ "providers": {
18
+ "vercel": {
19
+ "teamSlug": "example-team"
20
+ },
21
+ "digitalocean": {
22
+ "region": "nyc3"
23
+ }
24
+ },
25
+ "apps": [
26
+ {
27
+ "key": "web",
28
+ "name": "sveltekit-web",
29
+ "framework": "sveltekit",
30
+ "rootDirectory": ".",
31
+ "domains": [
32
+ "sveltekit.example.com"
33
+ ]
34
+ }
35
+ ],
36
+ "databases": [
37
+ {
38
+ "key": "content",
39
+ "engine": "postgres"
40
+ }
41
+ ],
42
+ "env": {
43
+ "environments": {
44
+ "development": {
45
+ "files": [
46
+ ".env.development"
47
+ ]
48
+ },
49
+ "test": {
50
+ "files": [
51
+ ".env.test"
52
+ ]
53
+ },
54
+ "uat": {
55
+ "files": [
56
+ ".env.uat"
57
+ ]
58
+ },
59
+ "nightly": {
60
+ "files": [
61
+ ".env.nightly"
62
+ ]
63
+ },
64
+ "staging": {
65
+ "files": [
66
+ ".env.staging"
67
+ ]
68
+ },
69
+ "production": {
70
+ "files": [
71
+ ".env.production"
72
+ ]
73
+ }
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "../../../../schema/iac.schema.json",
3
+ "version": 1,
4
+ "project": {
5
+ "key": "sveltekit-web",
6
+ "name": "sveltekit-web"
7
+ },
8
+ "environments": [
9
+ "development",
10
+ "test",
11
+ "uat",
12
+ "nightly",
13
+ "staging",
14
+ "preview",
15
+ "production"
16
+ ],
17
+ "providers": {
18
+ "vercel": {
19
+ "teamSlug": "example-team",
20
+ "projectDefaults": {
21
+ "nodeVersion": "22.x"
22
+ }
23
+ }
24
+ },
25
+ "apps": [
26
+ {
27
+ "key": "web",
28
+ "name": "sveltekit-web",
29
+ "framework": "sveltekit",
30
+ "rootDirectory": ".",
31
+ "domains": [
32
+ "sveltekit.example.com",
33
+ {
34
+ "name": "preview.sveltekit.example.com",
35
+ "gitBranch": "preview"
36
+ }
37
+ ]
38
+ }
39
+ ],
40
+ "env": {
41
+ "environments": {
42
+ "development": {
43
+ "files": [
44
+ ".env.development"
45
+ ]
46
+ },
47
+ "test": {
48
+ "files": [
49
+ ".env.test"
50
+ ]
51
+ },
52
+ "uat": {
53
+ "files": [
54
+ ".env.uat"
55
+ ]
56
+ },
57
+ "nightly": {
58
+ "files": [
59
+ ".env.nightly"
60
+ ]
61
+ },
62
+ "staging": {
63
+ "files": [
64
+ ".env.staging"
65
+ ]
66
+ },
67
+ "production": {
68
+ "files": [
69
+ ".env.production"
70
+ ]
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "sveltekit-web",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite dev",
7
+ "build": "vite build",
8
+ "iac:render": "vertile-iac render --repo-root . --target=all --deployment=prod"
9
+ },
10
+ "dependencies": {
11
+ "@sveltejs/adapter-auto": "^6.0.0",
12
+ "@sveltejs/kit": "^2.0.0",
13
+ "svelte": "^5.0.0",
14
+ "vite": "^7.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "@vertile-ai/iac": "0.1.0"
18
+ }
19
+ }
@@ -0,0 +1,3 @@
1
+ <main>
2
+ <h1>SvelteKit Web</h1>
3
+ </main>
@@ -0,0 +1,7 @@
1
+ import adapter from '@sveltejs/adapter-auto'
2
+
3
+ export default {
4
+ kit: {
5
+ adapter: adapter(),
6
+ },
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertile-ai/iac",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "App-first portable infrastructure intent for Vercel, AWS, and DigitalOcean.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -46,6 +46,27 @@
46
46
  "team": { "type": "string" },
47
47
  "teamId": { "type": "string" },
48
48
  "teamSlug": { "type": "string" },
49
+ "env": {
50
+ "type": "object",
51
+ "additionalProperties": true,
52
+ "properties": {
53
+ "targets": {
54
+ "type": "object",
55
+ "additionalProperties": {
56
+ "oneOf": [
57
+ { "type": "string", "minLength": 1 },
58
+ {
59
+ "type": "object",
60
+ "additionalProperties": true,
61
+ "properties": {
62
+ "environment": { "type": "string", "minLength": 1 }
63
+ }
64
+ }
65
+ ]
66
+ }
67
+ }
68
+ }
69
+ },
49
70
  "projectDefaults": { "$ref": "#/$defs/vercelProjectSettings" },
50
71
  "projectSettingsDefaults": { "$ref": "#/$defs/vercelProjectSettings" }
51
72
  }
@@ -59,6 +80,11 @@
59
80
  "type": "object",
60
81
  "properties": {
61
82
  "region": { "type": "string" },
83
+ "profile": { "type": "string" },
84
+ "deployments": {
85
+ "type": "object",
86
+ "additionalProperties": { "$ref": "#/$defs/providerDeployment" }
87
+ },
62
88
  "defaultTags": {
63
89
  "type": "object",
64
90
  "additionalProperties": { "type": ["string", "number", "boolean"] }
@@ -86,9 +112,11 @@
86
112
  "additionalProperties": true,
87
113
  "properties": {
88
114
  "sourceDir": { "type": "string" },
89
- "dir": { "type": "string" },
90
- "infraDir": { "type": "string" },
91
115
  "sharedKey": { "type": "string" },
116
+ "environments": {
117
+ "type": "object",
118
+ "additionalProperties": { "$ref": "#/$defs/envEnvironment" }
119
+ },
92
120
  "sync": {
93
121
  "type": "object",
94
122
  "additionalProperties": true,
@@ -169,12 +197,65 @@
169
197
  "type": "object",
170
198
  "additionalProperties": true,
171
199
  "properties": {
200
+ "deployments": {
201
+ "type": "object",
202
+ "additionalProperties": { "$ref": "#/$defs/providerDeployment" }
203
+ },
172
204
  "resources": {
173
205
  "type": "array",
174
206
  "items": { "$ref": "#/$defs/providerResource" }
175
207
  }
176
208
  }
177
209
  },
210
+ "providerDeployment": {
211
+ "type": "object",
212
+ "additionalProperties": true,
213
+ "properties": {
214
+ "environment": { "type": "string", "minLength": 1 },
215
+ "region": { "type": "string" },
216
+ "profile": { "type": "string" },
217
+ "stateKey": { "type": "string" },
218
+ "tags": {
219
+ "type": "object",
220
+ "additionalProperties": { "type": ["string", "number", "boolean"] }
221
+ },
222
+ "env": {
223
+ "type": "object",
224
+ "additionalProperties": true,
225
+ "properties": {
226
+ "destination": { "type": "string" },
227
+ "path": { "type": "string" }
228
+ }
229
+ }
230
+ }
231
+ },
232
+ "envEnvironment": {
233
+ "oneOf": [
234
+ { "type": "string", "minLength": 1 },
235
+ {
236
+ "type": "array",
237
+ "items": { "type": "string", "minLength": 1 }
238
+ },
239
+ {
240
+ "type": "object",
241
+ "additionalProperties": true,
242
+ "properties": {
243
+ "file": { "type": "string" },
244
+ "files": {
245
+ "type": "array",
246
+ "items": { "type": "string", "minLength": 1 }
247
+ },
248
+ "sources": {
249
+ "type": "array",
250
+ "items": { "type": "string", "minLength": 1 }
251
+ },
252
+ "output": { "type": "string" },
253
+ "outputFile": { "type": "string" },
254
+ "strict": { "type": "boolean" }
255
+ }
256
+ }
257
+ ]
258
+ },
178
259
  "providerResource": {
179
260
  "type": "object",
180
261
  "required": ["type", "name"],
package/src/apply.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  import process from 'node:process'
4
4
  import { hasFlag, parseTargetOption, readOption } from './core/args.mjs'
5
5
  import { resolvePlatformContext } from './core/context.mjs'
6
- import { assertEnvironment, readManifest } from './core/manifest.mjs'
6
+ import { readManifest } from './core/manifest.mjs'
7
7
  import { writeTargets } from './core/render.mjs'
8
8
  import { terraformApply } from './core/terraform.mjs'
9
9
 
@@ -12,16 +12,15 @@ async function main() {
12
12
  const context = resolvePlatformContext(argv)
13
13
  const manifest = readManifest(context.manifestPath)
14
14
  const environment = readOption(argv, '--env') || 'production'
15
+ const deploymentName = readOption(argv, '--deployment') || ''
15
16
  const targets = parseTargetOption(argv)
16
17
  const autoApprove = hasFlag(argv, '--yes') || hasFlag(argv, '--auto-approve')
17
18
 
18
- assertEnvironment(manifest, environment)
19
-
20
19
  if (!autoApprove && !process.stdin.isTTY) {
21
20
  throw new Error('Refusing non-interactive apply without --yes.')
22
21
  }
23
22
 
24
- const rendered = await writeTargets({ context, manifest, environment, targets })
23
+ const rendered = await writeTargets({ context, manifest, environment, targets, deploymentName })
25
24
  for (const item of rendered) {
26
25
  console.log(`Applying ${item.workspace}`)
27
26
  terraformApply({
package/src/cli.mjs CHANGED
@@ -45,6 +45,7 @@ ${sharedOptionsHelp()}
45
45
  --out <path> Generated Terraform root. Defaults to .vertile/terraform.
46
46
  --target <name|all> Target provider: vercel, aws, digitalocean, or all.
47
47
  --env <name> Environment to render, plan, or apply. Defaults to production.
48
+ --deployment <name> Provider deployment/stage name, such as uat or prod.
48
49
  --terraform-bin <path> Terraform executable. Defaults to terraform.
49
50
  --yes Allow non-interactive apply with Terraform auto-approve.
50
51
  `)