@intentius/chant-lexicon-render 0.53.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/README.md +89 -0
- package/dist/catalog.d.ts +100 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/codegen/docs-cli.d.ts +3 -0
- package/dist/codegen/docs-cli.d.ts.map +1 -0
- package/dist/codegen/docs.d.ts +21 -0
- package/dist/codegen/docs.d.ts.map +1 -0
- package/dist/codegen/generate-cli.d.ts +6 -0
- package/dist/codegen/generate-cli.d.ts.map +1 -0
- package/dist/codegen/generate-lexicon.d.ts +18 -0
- package/dist/codegen/generate-lexicon.d.ts.map +1 -0
- package/dist/codegen/generate-typescript.d.ts +12 -0
- package/dist/codegen/generate-typescript.d.ts.map +1 -0
- package/dist/codegen/generate.d.ts +15 -0
- package/dist/codegen/generate.d.ts.map +1 -0
- package/dist/codegen/naming.d.ts +14 -0
- package/dist/codegen/naming.d.ts.map +1 -0
- package/dist/codegen/package.d.ts +17 -0
- package/dist/codegen/package.d.ts.map +1 -0
- package/dist/composites/render-deploy.d.ts +88 -0
- package/dist/composites/render-deploy.d.ts.map +1 -0
- package/dist/coverage.d.ts +15 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/describe-resources.d.ts +60 -0
- package/dist/describe-resources.d.ts.map +1 -0
- package/dist/detect.d.ts +12 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/generated/index.d.ts +38 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/runtime.d.ts +5 -0
- package/dist/generated/runtime.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/integrity.json +18 -0
- package/dist/lint/audit-catalog.d.ts +13 -0
- package/dist/lint/audit-catalog.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts +3 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -0
- package/dist/lint/post-synth/ren010-native-runtime-requires-commands.d.ts +12 -0
- package/dist/lint/post-synth/ren010-native-runtime-requires-commands.d.ts.map +1 -0
- package/dist/lint/post-synth/ren011-service-requires-source.d.ts +12 -0
- package/dist/lint/post-synth/ren011-service-requires-source.d.ts.map +1 -0
- package/dist/lint/post-synth/ren012-free-plan-cannot-scale.d.ts +11 -0
- package/dist/lint/post-synth/ren012-free-plan-cannot-scale.d.ts.map +1 -0
- package/dist/lint/post-synth/render-helpers.d.ts +19 -0
- package/dist/lint/post-synth/render-helpers.d.ts.map +1 -0
- package/dist/lint/rules/index.d.ts +7 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lint/rules/no-secret-literals.d.ts +13 -0
- package/dist/lint/rules/no-secret-literals.d.ts.map +1 -0
- package/dist/lint/rules/valid-cron-schedule.d.ts +12 -0
- package/dist/lint/rules/valid-cron-schedule.d.ts.map +1 -0
- package/dist/lint/rules/valid-region.d.ts +16 -0
- package/dist/lint/rules/valid-region.d.ts.map +1 -0
- package/dist/lsp/completions.d.ts +8 -0
- package/dist/lsp/completions.d.ts.map +1 -0
- package/dist/lsp/hover.d.ts +6 -0
- package/dist/lsp/hover.d.ts.map +1 -0
- package/dist/manifest.json +6 -0
- package/dist/meta.json +304 -0
- package/dist/okf/index.md +29 -0
- package/dist/okf/rules/REN001.md +11 -0
- package/dist/okf/rules/REN002.md +15 -0
- package/dist/okf/rules/REN003.md +15 -0
- package/dist/okf/rules/REN010.md +11 -0
- package/dist/okf/rules/REN011.md +11 -0
- package/dist/okf/rules/REN012.md +11 -0
- package/dist/okf/types/BackgroundWorker.md +24 -0
- package/dist/okf/types/CronJob.md +28 -0
- package/dist/okf/types/CustomDomain.md +14 -0
- package/dist/okf/types/Disk.md +16 -0
- package/dist/okf/types/EnvGroup.md +22 -0
- package/dist/okf/types/Environment.md +17 -0
- package/dist/okf/types/KeyValue.md +20 -0
- package/dist/okf/types/Postgres.md +29 -0
- package/dist/okf/types/PrivateService.md +24 -0
- package/dist/okf/types/Project.md +15 -0
- package/dist/okf/types/RegistryCredential.md +17 -0
- package/dist/okf/types/StaticSite.md +24 -0
- package/dist/okf/types/WebService.md +24 -0
- package/dist/okf/types/Webhook.md +17 -0
- package/dist/op/activities/fake-render.d.ts +52 -0
- package/dist/op/activities/fake-render.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +10 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/render-apply.d.ts +229 -0
- package/dist/op/activities/render-apply.d.ts.map +1 -0
- package/dist/ownership.d.ts +32 -0
- package/dist/ownership.d.ts.map +1 -0
- package/dist/package-cli.d.ts +3 -0
- package/dist/package-cli.d.ts.map +1 -0
- package/dist/plugin.d.ts +8 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/pseudo.d.ts +21 -0
- package/dist/pseudo.d.ts.map +1 -0
- package/dist/rules/no-secret-literals.ts +73 -0
- package/dist/rules/ren010-native-runtime-requires-commands.ts +47 -0
- package/dist/rules/ren011-service-requires-source.ts +50 -0
- package/dist/rules/ren012-free-plan-cannot-scale.ts +43 -0
- package/dist/rules/render-helpers.ts +38 -0
- package/dist/rules/valid-cron-schedule.ts +51 -0
- package/dist/rules/valid-region.ts +49 -0
- package/dist/serializer.d.ts +99 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/skills/chant-render-patterns.md +126 -0
- package/dist/skills/chant-render.md +112 -0
- package/dist/spec/fetch.d.ts +21 -0
- package/dist/spec/fetch.d.ts.map +1 -0
- package/dist/spec/parse.d.ts +120 -0
- package/dist/spec/parse.d.ts.map +1 -0
- package/dist/types/index.d.ts +573 -0
- package/dist/validate-cli.d.ts +3 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate.d.ts +15 -0
- package/dist/validate.d.ts.map +1 -0
- package/package.json +73 -0
- package/src/catalog.ts +286 -0
- package/src/codegen/docs-cli.ts +7 -0
- package/src/codegen/docs.ts +120 -0
- package/src/codegen/generate-cli.ts +36 -0
- package/src/codegen/generate-lexicon.ts +52 -0
- package/src/codegen/generate-typescript.ts +70 -0
- package/src/codegen/generate.ts +106 -0
- package/src/codegen/naming.ts +55 -0
- package/src/codegen/package.ts +30 -0
- package/src/composites/render-deploy.ts +133 -0
- package/src/coverage.ts +49 -0
- package/src/describe-resources.test.ts +143 -0
- package/src/describe-resources.ts +366 -0
- package/src/detect.ts +29 -0
- package/src/generated/index.d.ts +573 -0
- package/src/generated/index.ts +43 -0
- package/src/generated/lexicon-render.json +304 -0
- package/src/generated/runtime.ts +4 -0
- package/src/index.ts +30 -0
- package/src/lint/audit-catalog.ts +47 -0
- package/src/lint/post-synth/index.ts +11 -0
- package/src/lint/post-synth/post-synth.test.ts +151 -0
- package/src/lint/post-synth/ren010-native-runtime-requires-commands.ts +47 -0
- package/src/lint/post-synth/ren011-service-requires-source.ts +50 -0
- package/src/lint/post-synth/ren012-free-plan-cannot-scale.ts +43 -0
- package/src/lint/post-synth/render-helpers.ts +38 -0
- package/src/lint/rules/index.ts +11 -0
- package/src/lint/rules/no-secret-literals.ts +73 -0
- package/src/lint/rules/rules.test.ts +73 -0
- package/src/lint/rules/valid-cron-schedule.ts +51 -0
- package/src/lint/rules/valid-region.ts +49 -0
- package/src/lsp/completions.test.ts +28 -0
- package/src/lsp/completions.ts +22 -0
- package/src/lsp/hover.test.ts +32 -0
- package/src/lsp/hover.ts +50 -0
- package/src/op/activities/fake-render.ts +275 -0
- package/src/op/activities/index.ts +51 -0
- package/src/op/activities/render-apply.test.ts +403 -0
- package/src/op/activities/render-apply.ts +1042 -0
- package/src/ownership.ts +44 -0
- package/src/package-cli.ts +23 -0
- package/src/plugin.test.ts +54 -0
- package/src/plugin.ts +258 -0
- package/src/pseudo.ts +26 -0
- package/src/serializer.test.ts +221 -0
- package/src/serializer.ts +286 -0
- package/src/skills/chant-render-patterns.md +126 -0
- package/src/skills/chant-render.md +112 -0
- package/src/spec/fetch.ts +33 -0
- package/src/spec/parse.ts +721 -0
- package/src/validate-cli.ts +5 -0
- package/src/validate.ts +47 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Autoscaling": {
|
|
3
|
+
"resourceType": "Render::Services::Autoscaling",
|
|
4
|
+
"kind": "property",
|
|
5
|
+
"lexicon": "render",
|
|
6
|
+
"constraints": {
|
|
7
|
+
"enabled": {
|
|
8
|
+
"default": false
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"AutoscalingCriteria": {
|
|
13
|
+
"resourceType": "Render::Services::AutoscalingCriteria",
|
|
14
|
+
"kind": "property",
|
|
15
|
+
"lexicon": "render"
|
|
16
|
+
},
|
|
17
|
+
"AutoscalingCriterion": {
|
|
18
|
+
"resourceType": "Render::Services::AutoscalingCriterion",
|
|
19
|
+
"kind": "property",
|
|
20
|
+
"lexicon": "render",
|
|
21
|
+
"constraints": {
|
|
22
|
+
"enabled": {
|
|
23
|
+
"default": false
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"BackgroundWorker": {
|
|
28
|
+
"resourceType": "Render::Services::BackgroundWorker",
|
|
29
|
+
"kind": "resource",
|
|
30
|
+
"lexicon": "render"
|
|
31
|
+
},
|
|
32
|
+
"BackgroundWorkerDetails": {
|
|
33
|
+
"resourceType": "Render::Services::BackgroundWorkerDetails",
|
|
34
|
+
"kind": "property",
|
|
35
|
+
"lexicon": "render",
|
|
36
|
+
"constraints": {
|
|
37
|
+
"numInstances": {
|
|
38
|
+
"minimum": 1,
|
|
39
|
+
"default": 1
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"BuildFilter": {
|
|
44
|
+
"resourceType": "Render::Services::BuildFilter",
|
|
45
|
+
"kind": "property",
|
|
46
|
+
"lexicon": "render"
|
|
47
|
+
},
|
|
48
|
+
"CidrBlockAndDescription": {
|
|
49
|
+
"resourceType": "Render::Services::CidrBlockAndDescription",
|
|
50
|
+
"kind": "property",
|
|
51
|
+
"lexicon": "render"
|
|
52
|
+
},
|
|
53
|
+
"CronJob": {
|
|
54
|
+
"resourceType": "Render::Services::CronJob",
|
|
55
|
+
"kind": "resource",
|
|
56
|
+
"lexicon": "render"
|
|
57
|
+
},
|
|
58
|
+
"CronJobDetails": {
|
|
59
|
+
"resourceType": "Render::Services::CronJobDetails",
|
|
60
|
+
"kind": "property",
|
|
61
|
+
"lexicon": "render"
|
|
62
|
+
},
|
|
63
|
+
"CustomDomain": {
|
|
64
|
+
"resourceType": "Render::Services::CustomDomain",
|
|
65
|
+
"kind": "resource",
|
|
66
|
+
"lexicon": "render"
|
|
67
|
+
},
|
|
68
|
+
"Disk": {
|
|
69
|
+
"resourceType": "Render::Services::Disk",
|
|
70
|
+
"kind": "resource",
|
|
71
|
+
"lexicon": "render"
|
|
72
|
+
},
|
|
73
|
+
"DockerDetails": {
|
|
74
|
+
"resourceType": "Render::Services::DockerDetails",
|
|
75
|
+
"kind": "property",
|
|
76
|
+
"lexicon": "render"
|
|
77
|
+
},
|
|
78
|
+
"EnvGroup": {
|
|
79
|
+
"resourceType": "Render::Config::EnvGroup",
|
|
80
|
+
"kind": "resource",
|
|
81
|
+
"lexicon": "render"
|
|
82
|
+
},
|
|
83
|
+
"EnvVar": {
|
|
84
|
+
"resourceType": "Render::Services::EnvVar",
|
|
85
|
+
"kind": "property",
|
|
86
|
+
"lexicon": "render"
|
|
87
|
+
},
|
|
88
|
+
"Environment": {
|
|
89
|
+
"resourceType": "Render::Projects::Environment",
|
|
90
|
+
"kind": "resource",
|
|
91
|
+
"lexicon": "render"
|
|
92
|
+
},
|
|
93
|
+
"GeneratedEnvVar": {
|
|
94
|
+
"resourceType": "Render::Services::GeneratedEnvVar",
|
|
95
|
+
"kind": "property",
|
|
96
|
+
"lexicon": "render"
|
|
97
|
+
},
|
|
98
|
+
"Header": {
|
|
99
|
+
"resourceType": "Render::Services::Header",
|
|
100
|
+
"kind": "property",
|
|
101
|
+
"lexicon": "render"
|
|
102
|
+
},
|
|
103
|
+
"Image": {
|
|
104
|
+
"resourceType": "Render::Services::Image",
|
|
105
|
+
"kind": "property",
|
|
106
|
+
"lexicon": "render"
|
|
107
|
+
},
|
|
108
|
+
"KeyValue": {
|
|
109
|
+
"resourceType": "Render::Datastores::KeyValue",
|
|
110
|
+
"kind": "resource",
|
|
111
|
+
"lexicon": "render"
|
|
112
|
+
},
|
|
113
|
+
"MaintenanceMode": {
|
|
114
|
+
"resourceType": "Render::Services::MaintenanceMode",
|
|
115
|
+
"kind": "property",
|
|
116
|
+
"lexicon": "render"
|
|
117
|
+
},
|
|
118
|
+
"NativeEnvironmentDetails": {
|
|
119
|
+
"resourceType": "Render::Services::NativeEnvironmentDetails",
|
|
120
|
+
"kind": "property",
|
|
121
|
+
"lexicon": "render"
|
|
122
|
+
},
|
|
123
|
+
"Postgres": {
|
|
124
|
+
"resourceType": "Render::Datastores::Postgres",
|
|
125
|
+
"kind": "resource",
|
|
126
|
+
"lexicon": "render",
|
|
127
|
+
"constraints": {
|
|
128
|
+
"databaseName": {
|
|
129
|
+
"default": "randomly generated"
|
|
130
|
+
},
|
|
131
|
+
"databaseUser": {
|
|
132
|
+
"default": "randomly generated"
|
|
133
|
+
},
|
|
134
|
+
"enableHighAvailability": {
|
|
135
|
+
"default": false
|
|
136
|
+
},
|
|
137
|
+
"plan": {
|
|
138
|
+
"enum": [
|
|
139
|
+
"free",
|
|
140
|
+
"starter",
|
|
141
|
+
"standard",
|
|
142
|
+
"pro",
|
|
143
|
+
"pro_plus",
|
|
144
|
+
"custom",
|
|
145
|
+
"basic_256mb",
|
|
146
|
+
"basic_1gb",
|
|
147
|
+
"basic_4gb",
|
|
148
|
+
"pro_4gb",
|
|
149
|
+
"pro_8gb",
|
|
150
|
+
"pro_16gb",
|
|
151
|
+
"pro_32gb",
|
|
152
|
+
"pro_64gb",
|
|
153
|
+
"pro_128gb",
|
|
154
|
+
"pro_192gb",
|
|
155
|
+
"pro_256gb",
|
|
156
|
+
"pro_384gb",
|
|
157
|
+
"pro_512gb",
|
|
158
|
+
"accelerated_16gb",
|
|
159
|
+
"accelerated_32gb",
|
|
160
|
+
"accelerated_64gb",
|
|
161
|
+
"accelerated_128gb",
|
|
162
|
+
"accelerated_256gb",
|
|
163
|
+
"accelerated_384gb",
|
|
164
|
+
"accelerated_512gb",
|
|
165
|
+
"accelerated_768gb",
|
|
166
|
+
"accelerated_1024gb",
|
|
167
|
+
"0.1c-256mb",
|
|
168
|
+
"0.5c-1g",
|
|
169
|
+
"1c-2g",
|
|
170
|
+
"1c-4g",
|
|
171
|
+
"2c-4g",
|
|
172
|
+
"2c-8g",
|
|
173
|
+
"2c-16g",
|
|
174
|
+
"4c-16g",
|
|
175
|
+
"4c-32g",
|
|
176
|
+
"8c-32g",
|
|
177
|
+
"8c-64g",
|
|
178
|
+
"16c-64g",
|
|
179
|
+
"16c-128g",
|
|
180
|
+
"32c-128g",
|
|
181
|
+
"32c-256g",
|
|
182
|
+
"48c-192g",
|
|
183
|
+
"48c-384g",
|
|
184
|
+
"64c-256g",
|
|
185
|
+
"64c-512g",
|
|
186
|
+
"96c-384g",
|
|
187
|
+
"96c-768g",
|
|
188
|
+
"128c-512g",
|
|
189
|
+
"128c-1024g"
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
"enableDiskAutoscaling": {
|
|
193
|
+
"default": false
|
|
194
|
+
},
|
|
195
|
+
"connectionPool": {
|
|
196
|
+
"default": "none"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"Previews": {
|
|
201
|
+
"resourceType": "Render::Services::Previews",
|
|
202
|
+
"kind": "property",
|
|
203
|
+
"lexicon": "render",
|
|
204
|
+
"constraints": {
|
|
205
|
+
"generation": {
|
|
206
|
+
"default": "off",
|
|
207
|
+
"enum": [
|
|
208
|
+
"off",
|
|
209
|
+
"manual",
|
|
210
|
+
"automatic"
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"PrivateService": {
|
|
216
|
+
"resourceType": "Render::Services::PrivateService",
|
|
217
|
+
"kind": "resource",
|
|
218
|
+
"lexicon": "render"
|
|
219
|
+
},
|
|
220
|
+
"PrivateServiceDetails": {
|
|
221
|
+
"resourceType": "Render::Services::PrivateServiceDetails",
|
|
222
|
+
"kind": "property",
|
|
223
|
+
"lexicon": "render",
|
|
224
|
+
"constraints": {
|
|
225
|
+
"numInstances": {
|
|
226
|
+
"minimum": 1,
|
|
227
|
+
"default": 1
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
"Project": {
|
|
232
|
+
"resourceType": "Render::Projects::Project",
|
|
233
|
+
"kind": "resource",
|
|
234
|
+
"lexicon": "render"
|
|
235
|
+
},
|
|
236
|
+
"ProjectEnvironment": {
|
|
237
|
+
"resourceType": "Render::Services::ProjectEnvironment",
|
|
238
|
+
"kind": "property",
|
|
239
|
+
"lexicon": "render"
|
|
240
|
+
},
|
|
241
|
+
"ReadReplica": {
|
|
242
|
+
"resourceType": "Render::Services::ReadReplica",
|
|
243
|
+
"kind": "property",
|
|
244
|
+
"lexicon": "render"
|
|
245
|
+
},
|
|
246
|
+
"RegistryCredential": {
|
|
247
|
+
"resourceType": "Render::Config::RegistryCredential",
|
|
248
|
+
"kind": "resource",
|
|
249
|
+
"lexicon": "render"
|
|
250
|
+
},
|
|
251
|
+
"Route": {
|
|
252
|
+
"resourceType": "Render::Services::Route",
|
|
253
|
+
"kind": "property",
|
|
254
|
+
"lexicon": "render"
|
|
255
|
+
},
|
|
256
|
+
"SecretFile": {
|
|
257
|
+
"resourceType": "Render::Services::SecretFile",
|
|
258
|
+
"kind": "property",
|
|
259
|
+
"lexicon": "render"
|
|
260
|
+
},
|
|
261
|
+
"ServiceDisk": {
|
|
262
|
+
"resourceType": "Render::Services::ServiceDisk",
|
|
263
|
+
"kind": "property",
|
|
264
|
+
"lexicon": "render",
|
|
265
|
+
"constraints": {
|
|
266
|
+
"sizeGB": {
|
|
267
|
+
"minimum": 1
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
"StaticSite": {
|
|
272
|
+
"resourceType": "Render::Services::StaticSite",
|
|
273
|
+
"kind": "resource",
|
|
274
|
+
"lexicon": "render"
|
|
275
|
+
},
|
|
276
|
+
"StaticSiteDetails": {
|
|
277
|
+
"resourceType": "Render::Services::StaticSiteDetails",
|
|
278
|
+
"kind": "property",
|
|
279
|
+
"lexicon": "render"
|
|
280
|
+
},
|
|
281
|
+
"WebService": {
|
|
282
|
+
"resourceType": "Render::Services::WebService",
|
|
283
|
+
"kind": "resource",
|
|
284
|
+
"lexicon": "render"
|
|
285
|
+
},
|
|
286
|
+
"WebServiceDetails": {
|
|
287
|
+
"resourceType": "Render::Services::WebServiceDetails",
|
|
288
|
+
"kind": "property",
|
|
289
|
+
"lexicon": "render",
|
|
290
|
+
"constraints": {
|
|
291
|
+
"numInstances": {
|
|
292
|
+
"minimum": 1
|
|
293
|
+
},
|
|
294
|
+
"plan": {
|
|
295
|
+
"default": "0.5c-512mb"
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
"Webhook": {
|
|
300
|
+
"resourceType": "Render::Config::Webhook",
|
|
301
|
+
"kind": "resource",
|
|
302
|
+
"lexicon": "render"
|
|
303
|
+
}
|
|
304
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Plugin
|
|
2
|
+
export { renderPlugin } from "./plugin";
|
|
3
|
+
|
|
4
|
+
// Serializer (+ the marker shapes the applier resolves)
|
|
5
|
+
export { renderSerializer, isRefMarker, isAttrMarker, isOwnerMarker } from "./serializer";
|
|
6
|
+
export type { RenderPlan, RenderRequest, RefMarker, AttrMarker, OwnerMarker } from "./serializer";
|
|
7
|
+
|
|
8
|
+
// Pseudo-parameters — environment-resolved values (`Render.OwnerId`,
|
|
9
|
+
// `Render.Region`) usable in place of hard-coded strings.
|
|
10
|
+
export { Render, OwnerId, Region, PseudoParameter } from "./pseudo";
|
|
11
|
+
|
|
12
|
+
// Ownership marker convention (env-var keys on services and env groups)
|
|
13
|
+
export { RENDER_ENV_OWNERSHIP_KEYS } from "./ownership";
|
|
14
|
+
|
|
15
|
+
// The resource catalog: entity type → REST collection, identity, ordering.
|
|
16
|
+
export { CATALOG, ENTITY_TYPES, SERVICE_TYPE_OF, catalogEntry, isServiceEntityType } from "./catalog";
|
|
17
|
+
export type { CatalogEntry, EntityType } from "./catalog";
|
|
18
|
+
|
|
19
|
+
// Deploy Op composite + typed step builders. `renderDeploy` returns a
|
|
20
|
+
// `build → renderApply [→ verify] [→ teardown]` Op; the step builders wrap the
|
|
21
|
+
// generic `activity()` so the render activities resolve by name.
|
|
22
|
+
export { renderDeploy, renderApplyStep, renderDeleteStep } from "./composites/render-deploy";
|
|
23
|
+
export type { RenderDeployOpts, RenderApplyStepOpts } from "./composites/render-deploy";
|
|
24
|
+
|
|
25
|
+
// Generated resources — export everything from generated index.
|
|
26
|
+
// Provides `WebService`, `StaticSite`, `PrivateService`, `BackgroundWorker`,
|
|
27
|
+
// `CronJob`, `Postgres`, `KeyValue`, `EnvGroup`, `Project`, `Environment`,
|
|
28
|
+
// `Disk`, `CustomDomain`, `RegistryCredential`, `Webhook`, and the property
|
|
29
|
+
// types (`WebServiceDetails`, `Image`, `ServiceDisk`, ...) for authoring.
|
|
30
|
+
export * from "./generated/index";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The render lexicon's chant audit catalog — metadata for the REN post-synth
|
|
3
|
+
* checks, contributed via `renderPlugin.auditCatalog()`.
|
|
4
|
+
*
|
|
5
|
+
* All entries carry `yamlBased: false`: each check reads the chant model
|
|
6
|
+
* (`ctx.entities`) rather than the emitted plan, because what they need — the
|
|
7
|
+
* runtime, the plan tier, whether a source was named — lives in the typed
|
|
8
|
+
* graph. So they fire on `chant build` and cannot fire on an audit of a
|
|
9
|
+
* standalone Render config.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { RuleMeta } from "@intentius/chant/audit/catalog";
|
|
13
|
+
|
|
14
|
+
/** Entity-based rule: everything render ships. */
|
|
15
|
+
function rule(
|
|
16
|
+
id: string,
|
|
17
|
+
tier: RuleMeta["tier"],
|
|
18
|
+
category: RuleMeta["category"],
|
|
19
|
+
title: string,
|
|
20
|
+
remediation: string,
|
|
21
|
+
): RuleMeta {
|
|
22
|
+
return { id, tier, fixKind: "guidance", category, title, remediation, yamlBased: false };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const renderAuditCatalog: Record<string, RuleMeta> = {
|
|
26
|
+
REN010: rule(
|
|
27
|
+
"REN010",
|
|
28
|
+
"merge-worthy",
|
|
29
|
+
"correctness",
|
|
30
|
+
"Native-runtime service has no build/start command",
|
|
31
|
+
"Set `envSpecificDetails: new NativeEnvironmentDetails({ buildCommand, startCommand })` on the service.",
|
|
32
|
+
),
|
|
33
|
+
REN011: rule(
|
|
34
|
+
"REN011",
|
|
35
|
+
"merge-worthy",
|
|
36
|
+
"correctness",
|
|
37
|
+
"Service has no source (repo or image)",
|
|
38
|
+
"Set `repo` for a git-backed service, or `image: new Image({ imagePath })` for an image-backed one.",
|
|
39
|
+
),
|
|
40
|
+
REN012: rule(
|
|
41
|
+
"REN012",
|
|
42
|
+
"merge-worthy",
|
|
43
|
+
"correctness",
|
|
44
|
+
"Free-plan service configured to scale or mount a disk",
|
|
45
|
+
"Move the service to a paid instance type, or drop numInstances/autoscaling/disk.",
|
|
46
|
+
),
|
|
47
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Code generated by chant generate. DO NOT EDIT.
|
|
2
|
+
import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
|
|
3
|
+
import { ren010 } from "./ren010-native-runtime-requires-commands";
|
|
4
|
+
import { ren011 } from "./ren011-service-requires-source";
|
|
5
|
+
import { ren012 } from "./ren012-free-plan-cannot-scale";
|
|
6
|
+
|
|
7
|
+
export const postSynthChecks: PostSynthCheck[] = [
|
|
8
|
+
ren010,
|
|
9
|
+
ren011,
|
|
10
|
+
ren012,
|
|
11
|
+
];
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import type { Declarable } from "@intentius/chant";
|
|
3
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
4
|
+
import { ren010 } from "./ren010-native-runtime-requires-commands";
|
|
5
|
+
import { ren011 } from "./ren011-service-requires-source";
|
|
6
|
+
import { ren012 } from "./ren012-free-plan-cannot-scale";
|
|
7
|
+
import { postSynthChecks } from "./index";
|
|
8
|
+
import {
|
|
9
|
+
WebService,
|
|
10
|
+
WebServiceDetails,
|
|
11
|
+
NativeEnvironmentDetails,
|
|
12
|
+
DockerDetails,
|
|
13
|
+
StaticSite,
|
|
14
|
+
StaticSiteDetails,
|
|
15
|
+
Image,
|
|
16
|
+
ServiceDisk,
|
|
17
|
+
Postgres,
|
|
18
|
+
} from "../../generated/index";
|
|
19
|
+
|
|
20
|
+
function ctx(...entries: Array<[string, unknown]>): PostSynthContext {
|
|
21
|
+
const entities = new Map(entries as Array<[string, Declarable]>);
|
|
22
|
+
return {
|
|
23
|
+
outputs: new Map(),
|
|
24
|
+
entities,
|
|
25
|
+
buildResult: { outputs: new Map(), entities, warnings: [], errors: [], sourceFileCount: 1 },
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const REPO = "https://github.com/render-examples/express-hello-world";
|
|
30
|
+
|
|
31
|
+
describe("render post-synth checks", () => {
|
|
32
|
+
test("the barrel exports the three checks", () => {
|
|
33
|
+
expect(postSynthChecks.map((c) => c.id)).toEqual(["REN010", "REN011", "REN012"]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("REN010: native runtime requires build/start commands", () => {
|
|
37
|
+
test("flags a node service with no envSpecificDetails", () => {
|
|
38
|
+
const diags = ren010.check(ctx(["web", new WebService({ name: "web", repo: REPO, serviceDetails: new WebServiceDetails({ runtime: "node" }) })]));
|
|
39
|
+
expect(diags).toHaveLength(1);
|
|
40
|
+
expect(diags[0].checkId).toBe("REN010");
|
|
41
|
+
expect(diags[0].severity).toBe("error");
|
|
42
|
+
expect(diags[0].message).toContain("buildCommand or startCommand");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("passes a node service with both commands (instance and inline forms)", () => {
|
|
46
|
+
expect(
|
|
47
|
+
ren010.check(
|
|
48
|
+
ctx([
|
|
49
|
+
"web",
|
|
50
|
+
new WebService({
|
|
51
|
+
name: "web",
|
|
52
|
+
repo: REPO,
|
|
53
|
+
serviceDetails: new WebServiceDetails({
|
|
54
|
+
runtime: "node",
|
|
55
|
+
envSpecificDetails: new NativeEnvironmentDetails({ buildCommand: "npm ci", startCommand: "npm start" }),
|
|
56
|
+
}),
|
|
57
|
+
}),
|
|
58
|
+
]),
|
|
59
|
+
),
|
|
60
|
+
).toHaveLength(0);
|
|
61
|
+
expect(
|
|
62
|
+
ren010.check(
|
|
63
|
+
ctx([
|
|
64
|
+
"web",
|
|
65
|
+
new WebService({
|
|
66
|
+
name: "web",
|
|
67
|
+
repo: REPO,
|
|
68
|
+
serviceDetails: { runtime: "python", envSpecificDetails: { buildCommand: "pip install -r requirements.txt", startCommand: "gunicorn app:app" } } as unknown as InstanceType<typeof WebServiceDetails>,
|
|
69
|
+
}),
|
|
70
|
+
]),
|
|
71
|
+
),
|
|
72
|
+
).toHaveLength(0);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("ignores docker/image runtimes, static sites, and non-services", () => {
|
|
76
|
+
expect(
|
|
77
|
+
ren010.check(
|
|
78
|
+
ctx(
|
|
79
|
+
["d", new WebService({ name: "d", repo: REPO, serviceDetails: new WebServiceDetails({ runtime: "docker", envSpecificDetails: new DockerDetails({}) }) })],
|
|
80
|
+
["i", new WebService({ name: "i", image: new Image({ imagePath: "nginx" }), serviceDetails: new WebServiceDetails({ runtime: "image" }) })],
|
|
81
|
+
["s", new StaticSite({ name: "s", repo: REPO, serviceDetails: new StaticSiteDetails({}) })],
|
|
82
|
+
["db", new Postgres({ name: "db", plan: "free", version: "16" })],
|
|
83
|
+
),
|
|
84
|
+
),
|
|
85
|
+
).toHaveLength(0);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("REN011: service requires a source", () => {
|
|
90
|
+
test("flags a service with neither repo nor image", () => {
|
|
91
|
+
const diags = ren011.check(ctx(["web", new WebService({ name: "web", serviceDetails: new WebServiceDetails({ runtime: "docker" }) })]));
|
|
92
|
+
expect(diags).toHaveLength(1);
|
|
93
|
+
expect(diags[0].checkId).toBe("REN011");
|
|
94
|
+
expect(diags[0].message).toContain("neither a repo nor an image");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("flags runtime image without an image", () => {
|
|
98
|
+
const diags = ren011.check(ctx(["web", new WebService({ name: "web", repo: REPO, serviceDetails: new WebServiceDetails({ runtime: "image" }) })]));
|
|
99
|
+
expect(diags).toHaveLength(1);
|
|
100
|
+
expect(diags[0].message).toContain('runtime "image"');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("passes a repo-backed and an image-backed service", () => {
|
|
104
|
+
expect(
|
|
105
|
+
ren011.check(
|
|
106
|
+
ctx(
|
|
107
|
+
["r", new WebService({ name: "r", repo: REPO, serviceDetails: new WebServiceDetails({ runtime: "docker" }) })],
|
|
108
|
+
["i", new WebService({ name: "i", image: new Image({ imagePath: "docker.io/library/nginx:latest" }), serviceDetails: new WebServiceDetails({ runtime: "image" }) })],
|
|
109
|
+
),
|
|
110
|
+
),
|
|
111
|
+
).toHaveLength(0);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe("REN012: free plan cannot scale", () => {
|
|
116
|
+
test("flags numInstances, autoscaling, and disk on free", () => {
|
|
117
|
+
const diags = ren012.check(
|
|
118
|
+
ctx([
|
|
119
|
+
"web",
|
|
120
|
+
new WebService({
|
|
121
|
+
name: "web",
|
|
122
|
+
repo: REPO,
|
|
123
|
+
serviceDetails: new WebServiceDetails({
|
|
124
|
+
runtime: "docker",
|
|
125
|
+
plan: "free",
|
|
126
|
+
numInstances: 3,
|
|
127
|
+
autoscaling: { enabled: true, min: 1, max: 3, criteria: { cpu: { enabled: true, percentage: 70 }, memory: { enabled: false, percentage: 70 } } },
|
|
128
|
+
disk: new ServiceDisk({ name: "data", mountPath: "/data" }),
|
|
129
|
+
}),
|
|
130
|
+
}),
|
|
131
|
+
]),
|
|
132
|
+
);
|
|
133
|
+
expect(diags).toHaveLength(1);
|
|
134
|
+
expect(diags[0].checkId).toBe("REN012");
|
|
135
|
+
expect(diags[0].message).toContain("numInstances: 3");
|
|
136
|
+
expect(diags[0].message).toContain("autoscaling");
|
|
137
|
+
expect(diags[0].message).toContain("a disk");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("passes a free single-instance service and a scaled paid one", () => {
|
|
141
|
+
expect(
|
|
142
|
+
ren012.check(
|
|
143
|
+
ctx(
|
|
144
|
+
["f", new WebService({ name: "f", repo: REPO, serviceDetails: new WebServiceDetails({ runtime: "docker", plan: "free" }) })],
|
|
145
|
+
["p", new WebService({ name: "p", repo: REPO, serviceDetails: new WebServiceDetails({ runtime: "docker", plan: "standard", numInstances: 3 }) })],
|
|
146
|
+
),
|
|
147
|
+
),
|
|
148
|
+
).toHaveLength(0);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REN010: A native-runtime service must say how to build and start.
|
|
3
|
+
*
|
|
4
|
+
* Render's native runtimes (node, python, ruby, go, rust, elixir) need a
|
|
5
|
+
* `buildCommand` and a `startCommand` in `envSpecificDetails`; without them the
|
|
6
|
+
* API rejects the create (or, on some paths, accepts it and the first deploy
|
|
7
|
+
* fails). `docker` reads a Dockerfile and `image` pulls a prebuilt image, so
|
|
8
|
+
* neither needs commands. Static sites have no runtime.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
12
|
+
import { ENTITY_TYPES } from "../../catalog";
|
|
13
|
+
import { readProps, entityTypeOf, isService, kindOf } from "./render-helpers";
|
|
14
|
+
|
|
15
|
+
const NATIVE_RUNTIMES = new Set(["node", "python", "ruby", "go", "rust", "elixir"]);
|
|
16
|
+
|
|
17
|
+
export const ren010: PostSynthCheck = {
|
|
18
|
+
id: "REN010",
|
|
19
|
+
description: "A native-runtime service must set envSpecificDetails.buildCommand and startCommand",
|
|
20
|
+
|
|
21
|
+
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
22
|
+
const diagnostics: PostSynthDiagnostic[] = [];
|
|
23
|
+
|
|
24
|
+
for (const [name, entity] of ctx.entities) {
|
|
25
|
+
if (!isService(entity) || entityTypeOf(entity) === ENTITY_TYPES.staticSite) continue;
|
|
26
|
+
const details = readProps(readProps(entity).serviceDetails);
|
|
27
|
+
const runtime = details.runtime;
|
|
28
|
+
if (typeof runtime !== "string" || !NATIVE_RUNTIMES.has(runtime)) continue;
|
|
29
|
+
|
|
30
|
+
const env = readProps(details.envSpecificDetails);
|
|
31
|
+
const missing: string[] = [];
|
|
32
|
+
if (typeof env.buildCommand !== "string" || env.buildCommand.length === 0) missing.push("buildCommand");
|
|
33
|
+
if (typeof env.startCommand !== "string" || env.startCommand.length === 0) missing.push("startCommand");
|
|
34
|
+
if (missing.length > 0) {
|
|
35
|
+
diagnostics.push({
|
|
36
|
+
checkId: "REN010",
|
|
37
|
+
severity: "error",
|
|
38
|
+
message: `${kindOf(entity)} "${name}" uses the ${runtime} runtime but sets no ${missing.join(" or ")} — add envSpecificDetails: new NativeEnvironmentDetails({ buildCommand, startCommand })`,
|
|
39
|
+
entity: name,
|
|
40
|
+
lexicon: "render",
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return diagnostics;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REN011: A service needs a source — a repo or an image.
|
|
3
|
+
*
|
|
4
|
+
* Every Render service is either git-backed (`repo`, built on Render) or
|
|
5
|
+
* image-backed (`image.imagePath`, pulled from a registry). One that names
|
|
6
|
+
* neither has nothing to deploy and is rejected at create time; one that uses
|
|
7
|
+
* the `image` runtime without an `image` is the same mistake spelled
|
|
8
|
+
* differently. Static sites are always git-backed.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
12
|
+
import { readProps, isService, kindOf } from "./render-helpers";
|
|
13
|
+
|
|
14
|
+
export const ren011: PostSynthCheck = {
|
|
15
|
+
id: "REN011",
|
|
16
|
+
description: "A service must have a repo (git-backed) or an image (image-backed)",
|
|
17
|
+
|
|
18
|
+
check(ctx: PostSynthContext): PostSynthDiagnostic[] {
|
|
19
|
+
const diagnostics: PostSynthDiagnostic[] = [];
|
|
20
|
+
|
|
21
|
+
for (const [name, entity] of ctx.entities) {
|
|
22
|
+
if (!isService(entity)) continue;
|
|
23
|
+
const props = readProps(entity);
|
|
24
|
+
const repo = typeof props.repo === "string" && props.repo.length > 0;
|
|
25
|
+
const imagePath = readProps(props.image).imagePath;
|
|
26
|
+
const image = typeof imagePath === "string" && imagePath.length > 0;
|
|
27
|
+
const runtime = readProps(props.serviceDetails).runtime;
|
|
28
|
+
|
|
29
|
+
if (!repo && !image) {
|
|
30
|
+
diagnostics.push({
|
|
31
|
+
checkId: "REN011",
|
|
32
|
+
severity: "error",
|
|
33
|
+
message: `${kindOf(entity)} "${name}" has neither a repo nor an image — set repo: "https://github.com/…" or image: new Image({ imagePath: "docker.io/…" })`,
|
|
34
|
+
entity: name,
|
|
35
|
+
lexicon: "render",
|
|
36
|
+
});
|
|
37
|
+
} else if (runtime === "image" && !image) {
|
|
38
|
+
diagnostics.push({
|
|
39
|
+
checkId: "REN011",
|
|
40
|
+
severity: "error",
|
|
41
|
+
message: `${kindOf(entity)} "${name}" uses runtime "image" but sets no image.imagePath`,
|
|
42
|
+
entity: name,
|
|
43
|
+
lexicon: "render",
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return diagnostics;
|
|
49
|
+
},
|
|
50
|
+
};
|