@friggframework/schemas 2.0.0--canary.730.f2ba24a.0 → 2.0.0--canary.656.6eb85ab.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 +0 -26
- package/index.js +1 -13
- package/package.json +2 -3
- package/schemas/app-definition.schema.json +132 -534
- package/app-definition.js +0 -113
package/README.md
CHANGED
|
@@ -41,32 +41,6 @@ if (result.valid) {
|
|
|
41
41
|
}
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
### Integration classes and defaults (ADR-051)
|
|
45
|
-
|
|
46
|
-
Apps list integration classes, which JSON Schema cannot describe.
|
|
47
|
-
`validateAppDefinition` validates a view of the definition in which each
|
|
48
|
-
class in `integrations`, `adminScripts` and `reports` is replaced by
|
|
49
|
-
`{ Definition }`; `frigg validate` checks the classes themselves.
|
|
50
|
-
|
|
51
|
-
```javascript
|
|
52
|
-
const { applyAppDefinitionDefaults } = require('@friggframework/schemas');
|
|
53
|
-
// or, without loading Ajv:
|
|
54
|
-
// require('@friggframework/schemas/app-definition').applyAppDefinitionDefaults
|
|
55
|
-
|
|
56
|
-
const definition = applyAppDefinitionDefaults(require('./index').Definition);
|
|
57
|
-
definition.user.individualUserRequired; // true (schema default)
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
`applyAppDefinitionDefaults` returns a copy with every `default` declared in
|
|
61
|
-
the app-definition schema applied (only inside blocks the app sets, plus
|
|
62
|
-
blocks that have a default themselves, such as `user`). core's
|
|
63
|
-
`loadAppDefinition` and devtools' `createFriggInfrastructure` call it, so a
|
|
64
|
-
schema default is the runtime default. A schema default must equal what the
|
|
65
|
-
code does when the key is absent; the contract test in
|
|
66
|
-
`packages/devtools/infrastructure/app-definition-schema-contract.test.js`
|
|
67
|
-
checks this for the infrastructure builders. Keys nothing reads are marked
|
|
68
|
-
`"deprecated": true`.
|
|
69
|
-
|
|
70
44
|
### Advanced Validation
|
|
71
45
|
|
|
72
46
|
```javascript
|
package/index.js
CHANGED
|
@@ -12,10 +12,6 @@ const path = require('path');
|
|
|
12
12
|
|
|
13
13
|
// Import middleware
|
|
14
14
|
const schemaValidationMiddleware = require('./middleware/schema-validation');
|
|
15
|
-
const {
|
|
16
|
-
applyAppDefinitionDefaults,
|
|
17
|
-
toAppDefinitionSchemaView,
|
|
18
|
-
} = require('./app-definition');
|
|
19
15
|
|
|
20
16
|
// Initialize AJV with formats
|
|
21
17
|
const ajv = new Ajv({
|
|
@@ -80,13 +76,7 @@ function validate(schemaName, data) {
|
|
|
80
76
|
* @returns {object} - Validation result
|
|
81
77
|
*/
|
|
82
78
|
function validateAppDefinition(appDefinition) {
|
|
83
|
-
|
|
84
|
-
// validate the serialisable view and return the original definition.
|
|
85
|
-
const result = validate(
|
|
86
|
-
'app-definition',
|
|
87
|
-
toAppDefinitionSchemaView(appDefinition)
|
|
88
|
-
);
|
|
89
|
-
return { ...result, data: appDefinition };
|
|
79
|
+
return validate('app-definition', appDefinition);
|
|
90
80
|
}
|
|
91
81
|
|
|
92
82
|
/**
|
|
@@ -367,8 +357,6 @@ module.exports = {
|
|
|
367
357
|
// Validation functions
|
|
368
358
|
validate,
|
|
369
359
|
validateAppDefinition,
|
|
370
|
-
applyAppDefinitionDefaults,
|
|
371
|
-
toAppDefinitionSchemaView,
|
|
372
360
|
validateIntegrationDefinition,
|
|
373
361
|
validateApiModuleDefinition,
|
|
374
362
|
validateServerlessConfig,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/schemas",
|
|
3
|
-
"version": "2.0.0--canary.
|
|
3
|
+
"version": "2.0.0--canary.656.6eb85ab.0",
|
|
4
4
|
"description": "Canonical JSON Schema definitions for Frigg Framework",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "",
|
|
@@ -39,8 +39,7 @@
|
|
|
39
39
|
"validators/",
|
|
40
40
|
"mocks/",
|
|
41
41
|
"middleware/",
|
|
42
|
-
"app-definition.js",
|
|
43
42
|
"index.js"
|
|
44
43
|
],
|
|
45
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "6eb85ab403f6a3aa18fc5ad49c63c1799890ec55"
|
|
46
45
|
}
|
|
@@ -22,35 +22,22 @@
|
|
|
22
22
|
},
|
|
23
23
|
"label": {
|
|
24
24
|
"type": "string",
|
|
25
|
-
"description": "Human-readable display name for the application
|
|
25
|
+
"description": "Human-readable display name for the application",
|
|
26
26
|
"minLength": 1,
|
|
27
27
|
"maxLength": 200,
|
|
28
|
-
"examples": ["My Frigg Application", "Customer Portal Integrations"]
|
|
29
|
-
"deprecated": true
|
|
30
|
-
},
|
|
31
|
-
"region": {
|
|
32
|
-
"type": "string",
|
|
33
|
-
"description": "AWS region. The deploy region comes from AWS_REGION (default us-east-1), not from this key. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
|
|
34
|
-
"deprecated": true
|
|
35
|
-
},
|
|
36
|
-
"stage": {
|
|
37
|
-
"type": "string",
|
|
38
|
-
"description": "Stage name used only to infer the KMS key alias. The deployed stage comes from `--stage`."
|
|
28
|
+
"examples": ["My Frigg Application", "Customer Portal Integrations"]
|
|
39
29
|
},
|
|
40
30
|
"managementMode": {
|
|
41
31
|
"type": "string",
|
|
42
|
-
"description": "Infrastructure management mode
|
|
43
|
-
"enum": ["managed", "discover", "
|
|
32
|
+
"description": "Infrastructure management mode: 'managed' lets Frigg manage resources, 'discover' uses existing resources, 'custom' for manual configuration",
|
|
33
|
+
"enum": ["managed", "discover", "custom"],
|
|
34
|
+
"default": "managed"
|
|
44
35
|
},
|
|
45
36
|
"vpcIsolation": {
|
|
46
37
|
"type": "string",
|
|
47
|
-
"description": "
|
|
48
|
-
"enum": ["isolated", "shared"]
|
|
49
|
-
|
|
50
|
-
"usePrismaLambdaLayer": {
|
|
51
|
-
"type": "boolean",
|
|
52
|
-
"description": "Ship Prisma in a shared Lambda layer. false bundles Prisma into each function instead.",
|
|
53
|
-
"default": true
|
|
38
|
+
"description": "VPC isolation strategy: 'isolated' creates separate VPC per stage, 'shared' reuses VPC across stages",
|
|
39
|
+
"enum": ["isolated", "shared"],
|
|
40
|
+
"default": "isolated"
|
|
54
41
|
},
|
|
55
42
|
"environment": {
|
|
56
43
|
"type": "object",
|
|
@@ -81,72 +68,60 @@
|
|
|
81
68
|
},
|
|
82
69
|
"integrations": {
|
|
83
70
|
"type": "array",
|
|
84
|
-
"description": "
|
|
71
|
+
"description": "Array of integration classes to enable in the application",
|
|
85
72
|
"items": {
|
|
86
73
|
"type": "object",
|
|
87
|
-
"description": "
|
|
88
|
-
"required": ["Definition"],
|
|
89
|
-
"properties": {
|
|
90
|
-
"Definition": {
|
|
91
|
-
"type": "object",
|
|
92
|
-
"description": "The integration's static Definition (see integration-definition.schema.json)"
|
|
93
|
-
}
|
|
94
|
-
}
|
|
74
|
+
"description": "Integration class or configuration object"
|
|
95
75
|
},
|
|
96
76
|
"default": []
|
|
97
77
|
},
|
|
98
78
|
"user": {
|
|
99
79
|
"type": "object",
|
|
100
|
-
"description": "User management and authentication
|
|
80
|
+
"description": "User management and authentication configuration",
|
|
101
81
|
"properties": {
|
|
102
82
|
"usePassword": {
|
|
103
83
|
"type": "boolean",
|
|
104
|
-
"description": "
|
|
105
|
-
"default":
|
|
84
|
+
"description": "Enable password-based authentication for user login",
|
|
85
|
+
"default": true
|
|
106
86
|
},
|
|
107
87
|
"password": {
|
|
108
88
|
"type": "boolean",
|
|
109
|
-
"description": "DEPRECATED
|
|
110
|
-
"
|
|
89
|
+
"description": "DEPRECATED: Use 'usePassword' instead. Enable password-based authentication",
|
|
90
|
+
"default": true
|
|
111
91
|
},
|
|
112
92
|
"primary": {
|
|
113
93
|
"type": "string",
|
|
114
|
-
"description": "Primary user type
|
|
94
|
+
"description": "Primary user type for authentication",
|
|
115
95
|
"enum": ["individual", "organization"],
|
|
116
96
|
"default": "individual"
|
|
117
97
|
},
|
|
118
98
|
"individualUserRequired": {
|
|
119
99
|
"type": "boolean",
|
|
120
|
-
"description": "Require
|
|
100
|
+
"description": "Require individual user for authentication",
|
|
121
101
|
"default": true
|
|
122
102
|
},
|
|
123
103
|
"organizationUserRequired": {
|
|
124
104
|
"type": "boolean",
|
|
125
|
-
"description": "Require
|
|
126
|
-
"default": false
|
|
127
|
-
},
|
|
128
|
-
"strictUserValidation": {
|
|
129
|
-
"type": "boolean",
|
|
130
|
-
"description": "With x-frigg headers, reject a user id that does not exist instead of creating and linking it.",
|
|
105
|
+
"description": "Require organization user for authentication",
|
|
131
106
|
"default": false
|
|
132
107
|
},
|
|
133
108
|
"authModes": {
|
|
134
109
|
"type": "object",
|
|
135
|
-
"description": "Authentication
|
|
110
|
+
"description": "Authentication mode configuration - enables multiple authentication strategies. x-frigg-appUserId and x-frigg-appOrgId headers are automatically supported for user identification with any auth mode.",
|
|
136
111
|
"properties": {
|
|
137
112
|
"friggToken": {
|
|
138
113
|
"type": "boolean",
|
|
139
|
-
"description": "
|
|
114
|
+
"description": "Enable Frigg native bearer token authentication (from /user/login)",
|
|
140
115
|
"default": true
|
|
141
116
|
},
|
|
142
117
|
"sharedSecret": {
|
|
143
118
|
"type": "boolean",
|
|
144
|
-
"description": "
|
|
145
|
-
"default":
|
|
119
|
+
"description": "Enable shared secret authentication for backend-to-backend communication (requires FRIGG_API_KEY env var and x-frigg-api-key header)",
|
|
120
|
+
"default": false
|
|
146
121
|
},
|
|
147
122
|
"adopterJwt": {
|
|
148
123
|
"type": "boolean",
|
|
149
|
-
"description": "
|
|
124
|
+
"description": "Enable custom JWT authentication from adopter's auth system (requires jwtConfig)",
|
|
150
125
|
"default": false
|
|
151
126
|
}
|
|
152
127
|
},
|
|
@@ -158,7 +133,7 @@
|
|
|
158
133
|
"properties": {
|
|
159
134
|
"secret": {
|
|
160
135
|
"type": "string",
|
|
161
|
-
"description": "JWT secret key for signature validation
|
|
136
|
+
"description": "JWT secret key for signature validation (should be set via environment variable)"
|
|
162
137
|
},
|
|
163
138
|
"userIdClaim": {
|
|
164
139
|
"type": "string",
|
|
@@ -177,29 +152,27 @@
|
|
|
177
152
|
"default": "HS256"
|
|
178
153
|
}
|
|
179
154
|
},
|
|
155
|
+
"required": ["secret"],
|
|
180
156
|
"additionalProperties": false
|
|
181
157
|
},
|
|
182
158
|
"fields": {
|
|
183
159
|
"type": "array",
|
|
184
|
-
"description": "Additional user fields
|
|
185
|
-
"items": {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
]
|
|
189
|
-
"deprecated": true
|
|
160
|
+
"description": "Additional user fields",
|
|
161
|
+
"items": {
|
|
162
|
+
"type": "string"
|
|
163
|
+
},
|
|
164
|
+
"examples": [["email", "firstName", "lastName"]]
|
|
190
165
|
},
|
|
191
166
|
"model": {
|
|
192
167
|
"type": "object",
|
|
193
|
-
"description": "Custom user model class
|
|
194
|
-
"deprecated": true
|
|
168
|
+
"description": "Custom user model class"
|
|
195
169
|
}
|
|
196
170
|
},
|
|
197
|
-
"additionalProperties": false
|
|
198
|
-
"default": {}
|
|
171
|
+
"additionalProperties": false
|
|
199
172
|
},
|
|
200
173
|
"auth": {
|
|
201
174
|
"type": "object",
|
|
202
|
-
"description": "Authentication configuration
|
|
175
|
+
"description": "Authentication configuration for integrations",
|
|
203
176
|
"properties": {
|
|
204
177
|
"jwtSecret": {
|
|
205
178
|
"type": "string",
|
|
@@ -208,16 +181,17 @@
|
|
|
208
181
|
"tokenExpiry": {
|
|
209
182
|
"type": "string",
|
|
210
183
|
"description": "Token expiration time",
|
|
211
|
-
"pattern": "^\\d+[smhd]$"
|
|
184
|
+
"pattern": "^\\d+[smhd]$",
|
|
185
|
+
"default": "24h"
|
|
212
186
|
},
|
|
213
187
|
"refreshTokenExpiry": {
|
|
214
188
|
"type": "string",
|
|
215
|
-
"description": "Refresh token expiration time",
|
|
216
|
-
"pattern": "^\\d+[smhd]$"
|
|
189
|
+
"description": "Refresh token expiration time",
|
|
190
|
+
"pattern": "^\\d+[smhd]$",
|
|
191
|
+
"default": "7d"
|
|
217
192
|
}
|
|
218
193
|
},
|
|
219
|
-
"additionalProperties": false
|
|
220
|
-
"deprecated": true
|
|
194
|
+
"additionalProperties": false
|
|
221
195
|
},
|
|
222
196
|
"database": {
|
|
223
197
|
"type": "object",
|
|
@@ -225,8 +199,8 @@
|
|
|
225
199
|
"properties": {
|
|
226
200
|
"uri": {
|
|
227
201
|
"type": "string",
|
|
228
|
-
"description": "Database connection URI (should be set via environment variable)
|
|
229
|
-
"
|
|
202
|
+
"description": "Database connection URI (should be set via environment variable)",
|
|
203
|
+
"format": "uri"
|
|
230
204
|
},
|
|
231
205
|
"mongoDB": {
|
|
232
206
|
"type": "object",
|
|
@@ -239,8 +213,7 @@
|
|
|
239
213
|
},
|
|
240
214
|
"uri": {
|
|
241
215
|
"type": "string",
|
|
242
|
-
"description": "MongoDB connection URI
|
|
243
|
-
"deprecated": true
|
|
216
|
+
"description": "MongoDB connection URI"
|
|
244
217
|
}
|
|
245
218
|
},
|
|
246
219
|
"additionalProperties": true
|
|
@@ -268,16 +241,18 @@
|
|
|
268
241
|
"properties": {
|
|
269
242
|
"enable": {
|
|
270
243
|
"type": "boolean",
|
|
271
|
-
"description": "
|
|
244
|
+
"description": "Enable PostgreSQL database",
|
|
245
|
+
"default": false
|
|
272
246
|
},
|
|
273
247
|
"management": {
|
|
274
248
|
"type": "string",
|
|
275
|
-
"description": "How
|
|
276
|
-
"enum": ["discover", "
|
|
249
|
+
"description": "How to manage the PostgreSQL database",
|
|
250
|
+
"enum": ["discover", "create-new", "existing"],
|
|
251
|
+
"default": "discover"
|
|
277
252
|
},
|
|
278
253
|
"endpoint": {
|
|
279
254
|
"type": "string",
|
|
280
|
-
"description": "Existing database endpoint (
|
|
255
|
+
"description": "Existing database endpoint (when management='existing')",
|
|
281
256
|
"examples": ["mydb.cluster-abc123.us-east-1.rds.amazonaws.com"]
|
|
282
257
|
},
|
|
283
258
|
"port": {
|
|
@@ -295,15 +270,10 @@
|
|
|
295
270
|
"description": "Database username",
|
|
296
271
|
"default": "postgres"
|
|
297
272
|
},
|
|
298
|
-
"engineVersion": {
|
|
299
|
-
"type": "string",
|
|
300
|
-
"description": "Aurora PostgreSQL engine version for a cluster Frigg creates",
|
|
301
|
-
"default": "15.13"
|
|
302
|
-
},
|
|
303
273
|
"selfHeal": {
|
|
304
274
|
"type": "boolean",
|
|
305
|
-
"description": "Automatically fix database configuration issues
|
|
306
|
-
"
|
|
275
|
+
"description": "Automatically fix database configuration issues",
|
|
276
|
+
"default": true
|
|
307
277
|
},
|
|
308
278
|
"publiclyAccessible": {
|
|
309
279
|
"type": "boolean",
|
|
@@ -312,7 +282,7 @@
|
|
|
312
282
|
},
|
|
313
283
|
"autoCreateCredentials": {
|
|
314
284
|
"type": "boolean",
|
|
315
|
-
"description": "
|
|
285
|
+
"description": "Automatically create Secrets Manager secret and rotate Aurora password when discovering existing cluster (only applies when management='discover')",
|
|
316
286
|
"default": false
|
|
317
287
|
},
|
|
318
288
|
"minCapacity": {
|
|
@@ -327,65 +297,7 @@
|
|
|
327
297
|
"description": "Maximum Aurora Serverless capacity units (0.5-128)",
|
|
328
298
|
"minimum": 0.5,
|
|
329
299
|
"maximum": 128,
|
|
330
|
-
"default":
|
|
331
|
-
},
|
|
332
|
-
"clusterId": {
|
|
333
|
-
"type": "string",
|
|
334
|
-
"description": "Only discover the Aurora cluster with this identifier"
|
|
335
|
-
},
|
|
336
|
-
"instanceId": {
|
|
337
|
-
"type": "string",
|
|
338
|
-
"description": "Only discover the Aurora instance with this identifier"
|
|
339
|
-
},
|
|
340
|
-
"ownership": {
|
|
341
|
-
"type": "object",
|
|
342
|
-
"description": "Per-resource ownership. When set, `management` is not translated.",
|
|
343
|
-
"properties": {
|
|
344
|
-
"cluster": {
|
|
345
|
-
"type": "string",
|
|
346
|
-
"enum": ["stack", "external", "auto"],
|
|
347
|
-
"description": "Aurora cluster. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
348
|
-
},
|
|
349
|
-
"instance": {
|
|
350
|
-
"type": "string",
|
|
351
|
-
"enum": ["stack", "external", "auto"],
|
|
352
|
-
"description": "Aurora instance. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
353
|
-
},
|
|
354
|
-
"subnetGroup": {
|
|
355
|
-
"type": "string",
|
|
356
|
-
"enum": ["stack", "external", "auto"],
|
|
357
|
-
"description": "DB subnet group. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
358
|
-
},
|
|
359
|
-
"secret": {
|
|
360
|
-
"type": "string",
|
|
361
|
-
"enum": ["stack", "external", "auto"],
|
|
362
|
-
"description": "Secrets Manager credentials secret. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
363
|
-
}
|
|
364
|
-
},
|
|
365
|
-
"additionalProperties": false
|
|
366
|
-
},
|
|
367
|
-
"external": {
|
|
368
|
-
"type": "object",
|
|
369
|
-
"description": "Ids of externally owned resources (ownership 'external')",
|
|
370
|
-
"properties": {
|
|
371
|
-
"clusterIdentifier": {"type": "string"},
|
|
372
|
-
"instanceIdentifier": {"type": "string"},
|
|
373
|
-
"subnetGroupName": {"type": "string"},
|
|
374
|
-
"secretArn": {"type": "string"}
|
|
375
|
-
},
|
|
376
|
-
"additionalProperties": false
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
|
-
"additionalProperties": false
|
|
380
|
-
},
|
|
381
|
-
"dynamodb": {
|
|
382
|
-
"type": "object",
|
|
383
|
-
"description": "DynamoDB access from inside the VPC",
|
|
384
|
-
"properties": {
|
|
385
|
-
"enable": {
|
|
386
|
-
"type": "boolean",
|
|
387
|
-
"description": "Add a DynamoDB VPC endpoint",
|
|
388
|
-
"default": false
|
|
300
|
+
"default": 1
|
|
389
301
|
}
|
|
390
302
|
},
|
|
391
303
|
"additionalProperties": false
|
|
@@ -399,12 +311,14 @@
|
|
|
399
311
|
"properties": {
|
|
400
312
|
"fieldLevelEncryptionMethod": {
|
|
401
313
|
"type": "string",
|
|
402
|
-
"description": "
|
|
403
|
-
"enum": ["kms", "aes",
|
|
314
|
+
"description": "Method for field-level encryption",
|
|
315
|
+
"enum": ["kms", "aes"],
|
|
316
|
+
"default": "aes"
|
|
404
317
|
},
|
|
405
318
|
"createResourceIfNoneFound": {
|
|
406
319
|
"type": "boolean",
|
|
407
|
-
"description": "
|
|
320
|
+
"description": "Create KMS key if none found during discovery",
|
|
321
|
+
"default": false
|
|
408
322
|
},
|
|
409
323
|
"schema": {
|
|
410
324
|
"type": "object",
|
|
@@ -441,48 +355,6 @@
|
|
|
441
355
|
}
|
|
442
356
|
}
|
|
443
357
|
]
|
|
444
|
-
},
|
|
445
|
-
"ownership": {
|
|
446
|
-
"type": "object",
|
|
447
|
-
"description": "Per-resource ownership. When set, createResourceIfNoneFound is not translated.",
|
|
448
|
-
"properties": {
|
|
449
|
-
"key": {
|
|
450
|
-
"type": "string",
|
|
451
|
-
"enum": ["stack", "external", "auto"],
|
|
452
|
-
"description": "KMS key. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
453
|
-
}
|
|
454
|
-
},
|
|
455
|
-
"additionalProperties": false
|
|
456
|
-
},
|
|
457
|
-
"kmsKeyAlias": {
|
|
458
|
-
"type": "boolean",
|
|
459
|
-
"description": "Create an alias for a KMS key Frigg creates",
|
|
460
|
-
"default": false
|
|
461
|
-
},
|
|
462
|
-
"keyAlias": {
|
|
463
|
-
"type": "string",
|
|
464
|
-
"description": "Only discover the KMS key with this alias",
|
|
465
|
-
"pattern": "^alias/",
|
|
466
|
-
"examples": ["alias/my-app-key"]
|
|
467
|
-
},
|
|
468
|
-
"disable": {
|
|
469
|
-
"type": "object",
|
|
470
|
-
"description": "Opt specific core-encrypted fields out of encryption: { Model: ['field.path'] }. Existing encrypted values still decrypt.",
|
|
471
|
-
"patternProperties": {
|
|
472
|
-
"^[A-Z][a-zA-Z0-9]*$": {
|
|
473
|
-
"type": "array",
|
|
474
|
-
"items": {
|
|
475
|
-
"type": "string",
|
|
476
|
-
"minLength": 1
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
},
|
|
480
|
-
"additionalProperties": false
|
|
481
|
-
},
|
|
482
|
-
"enable": {
|
|
483
|
-
"type": "boolean",
|
|
484
|
-
"description": "Encryption is controlled by fieldLevelEncryptionMethod. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
|
|
485
|
-
"deprecated": true
|
|
486
358
|
}
|
|
487
359
|
},
|
|
488
360
|
"additionalProperties": false
|
|
@@ -493,23 +365,24 @@
|
|
|
493
365
|
"properties": {
|
|
494
366
|
"enable": {
|
|
495
367
|
"type": "boolean",
|
|
496
|
-
"description": "
|
|
368
|
+
"description": "Enable VPC for Lambda functions",
|
|
497
369
|
"default": false
|
|
498
370
|
},
|
|
499
371
|
"management": {
|
|
500
372
|
"type": "string",
|
|
501
|
-
"description": "How
|
|
502
|
-
"enum": ["discover", "create-new", "
|
|
373
|
+
"description": "How to manage VPC infrastructure",
|
|
374
|
+
"enum": ["discover", "create-new", "existing"],
|
|
375
|
+
"default": "discover"
|
|
503
376
|
},
|
|
504
377
|
"vpcId": {
|
|
505
378
|
"type": "string",
|
|
506
|
-
"description": "Existing VPC ID (
|
|
379
|
+
"description": "Existing VPC ID (when management='existing')",
|
|
507
380
|
"pattern": "^vpc-[a-z0-9]+$",
|
|
508
381
|
"examples": ["vpc-abc123"]
|
|
509
382
|
},
|
|
510
383
|
"cidrBlock": {
|
|
511
384
|
"type": "string",
|
|
512
|
-
"description": "CIDR block for
|
|
385
|
+
"description": "CIDR block for VPC (when management='create-new')",
|
|
513
386
|
"pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$",
|
|
514
387
|
"default": "10.0.0.0/16"
|
|
515
388
|
},
|
|
@@ -520,9 +393,7 @@
|
|
|
520
393
|
"type": "string",
|
|
521
394
|
"pattern": "^sg-[a-z0-9]+$"
|
|
522
395
|
},
|
|
523
|
-
"examples": [
|
|
524
|
-
["sg-abc123", "sg-def456"]
|
|
525
|
-
]
|
|
396
|
+
"examples": [["sg-abc123", "sg-def456"]]
|
|
526
397
|
},
|
|
527
398
|
"subnets": {
|
|
528
399
|
"type": "object",
|
|
@@ -530,20 +401,19 @@
|
|
|
530
401
|
"properties": {
|
|
531
402
|
"management": {
|
|
532
403
|
"type": "string",
|
|
533
|
-
"description": "
|
|
534
|
-
"enum": ["
|
|
404
|
+
"description": "How to manage subnets",
|
|
405
|
+
"enum": ["discover", "create-new", "existing"],
|
|
406
|
+
"default": "discover"
|
|
535
407
|
},
|
|
536
408
|
"ids": {
|
|
537
409
|
"type": "array",
|
|
538
|
-
"description": "Existing subnet IDs
|
|
410
|
+
"description": "Existing subnet IDs",
|
|
539
411
|
"items": {
|
|
540
412
|
"type": "string",
|
|
541
413
|
"pattern": "^subnet-[a-z0-9]+$"
|
|
542
414
|
},
|
|
543
415
|
"minItems": 2,
|
|
544
|
-
"examples": [
|
|
545
|
-
["subnet-abc123", "subnet-def456"]
|
|
546
|
-
]
|
|
416
|
+
"examples": [["subnet-abc123", "subnet-def456"]]
|
|
547
417
|
}
|
|
548
418
|
},
|
|
549
419
|
"additionalProperties": false
|
|
@@ -554,12 +424,13 @@
|
|
|
554
424
|
"properties": {
|
|
555
425
|
"management": {
|
|
556
426
|
"type": "string",
|
|
557
|
-
"description": "
|
|
558
|
-
"enum": ["
|
|
427
|
+
"description": "How to manage NAT Gateway",
|
|
428
|
+
"enum": ["discover", "create-new", "existing"],
|
|
429
|
+
"default": "discover"
|
|
559
430
|
},
|
|
560
431
|
"id": {
|
|
561
432
|
"type": "string",
|
|
562
|
-
"description": "Existing NAT Gateway ID
|
|
433
|
+
"description": "Existing NAT Gateway ID",
|
|
563
434
|
"pattern": "^nat-[a-z0-9]+$",
|
|
564
435
|
"examples": ["nat-abc123"]
|
|
565
436
|
}
|
|
@@ -568,112 +439,13 @@
|
|
|
568
439
|
},
|
|
569
440
|
"enableVPCEndpoints": {
|
|
570
441
|
"type": "boolean",
|
|
571
|
-
"description": "Create VPC endpoints for AWS services (S3, DynamoDB, KMS, Secrets Manager)
|
|
442
|
+
"description": "Create VPC endpoints for AWS services (S3, DynamoDB, KMS, Secrets Manager)",
|
|
572
443
|
"default": true
|
|
573
444
|
},
|
|
574
445
|
"selfHeal": {
|
|
575
446
|
"type": "boolean",
|
|
576
|
-
"description": "
|
|
577
|
-
|
|
578
|
-
"shareAcrossStages": {
|
|
579
|
-
"type": "boolean",
|
|
580
|
-
"description": "Legacy: true reuses (auto) the VPC and subnets across stages; false creates a VPC, subnets and NAT gateway per stage. Ignored when `ownership` is set."
|
|
581
|
-
},
|
|
582
|
-
"ownership": {
|
|
583
|
-
"type": "object",
|
|
584
|
-
"description": "Per-resource ownership. When set, management, subnets, natGateway, shareAcrossStages, enableVPCEndpoints and selfHeal are not translated; use `config` instead.",
|
|
585
|
-
"properties": {
|
|
586
|
-
"vpc": {
|
|
587
|
-
"type": "string",
|
|
588
|
-
"enum": ["stack", "external", "auto"],
|
|
589
|
-
"description": "VPC. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
590
|
-
},
|
|
591
|
-
"securityGroup": {
|
|
592
|
-
"type": "string",
|
|
593
|
-
"enum": ["stack", "external", "auto"],
|
|
594
|
-
"description": "Lambda security group. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
595
|
-
},
|
|
596
|
-
"subnets": {
|
|
597
|
-
"type": "string",
|
|
598
|
-
"enum": ["stack", "external", "auto"],
|
|
599
|
-
"description": "Private subnets. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
600
|
-
},
|
|
601
|
-
"natGateway": {
|
|
602
|
-
"type": "string",
|
|
603
|
-
"enum": ["stack", "external", "auto"],
|
|
604
|
-
"description": "NAT gateway. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
605
|
-
},
|
|
606
|
-
"vpcEndpoints": {
|
|
607
|
-
"type": "string",
|
|
608
|
-
"enum": ["stack", "external", "auto"],
|
|
609
|
-
"description": "VPC endpoints. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
610
|
-
}
|
|
611
|
-
},
|
|
612
|
-
"additionalProperties": false
|
|
613
|
-
},
|
|
614
|
-
"external": {
|
|
615
|
-
"type": "object",
|
|
616
|
-
"description": "Ids of externally owned resources (ownership 'external'); discovered ids are used when omitted",
|
|
617
|
-
"properties": {
|
|
618
|
-
"vpcId": {
|
|
619
|
-
"type": "string",
|
|
620
|
-
"pattern": "^vpc-[a-z0-9]+$"
|
|
621
|
-
},
|
|
622
|
-
"securityGroupIds": {
|
|
623
|
-
"type": "array",
|
|
624
|
-
"items": {
|
|
625
|
-
"type": "string",
|
|
626
|
-
"pattern": "^sg-[a-z0-9]+$"
|
|
627
|
-
}
|
|
628
|
-
},
|
|
629
|
-
"subnetIds": {
|
|
630
|
-
"type": "array",
|
|
631
|
-
"items": {
|
|
632
|
-
"type": "string",
|
|
633
|
-
"pattern": "^subnet-[a-z0-9]+$"
|
|
634
|
-
}
|
|
635
|
-
},
|
|
636
|
-
"natGatewayId": {
|
|
637
|
-
"type": "string",
|
|
638
|
-
"pattern": "^nat-[a-z0-9]+$"
|
|
639
|
-
},
|
|
640
|
-
"vpcEndpointIds": {
|
|
641
|
-
"type": "object",
|
|
642
|
-
"description": "Endpoint ids by type (s3, dynamodb, kms, secretsManager, sqs)",
|
|
643
|
-
"additionalProperties": {"type": "string"}
|
|
644
|
-
}
|
|
645
|
-
},
|
|
646
|
-
"additionalProperties": false
|
|
647
|
-
},
|
|
648
|
-
"config": {
|
|
649
|
-
"type": "object",
|
|
650
|
-
"description": "Settings for the ownership-based VPC configuration",
|
|
651
|
-
"properties": {
|
|
652
|
-
"cidrBlock": {
|
|
653
|
-
"type": "string",
|
|
654
|
-
"description": "CIDR block for a VPC Frigg creates (wins over vpc.cidrBlock)",
|
|
655
|
-
"pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$"
|
|
656
|
-
},
|
|
657
|
-
"selfHeal": {
|
|
658
|
-
"type": "boolean",
|
|
659
|
-
"description": "Recreate missing stack-owned subnets. Enabled unless false."
|
|
660
|
-
},
|
|
661
|
-
"natGateway": {
|
|
662
|
-
"type": "object",
|
|
663
|
-
"properties": {
|
|
664
|
-
"enable": {
|
|
665
|
-
"type": "boolean",
|
|
666
|
-
"description": "Resolve a NAT gateway. Enabled unless false."
|
|
667
|
-
}
|
|
668
|
-
},
|
|
669
|
-
"additionalProperties": false
|
|
670
|
-
},
|
|
671
|
-
"enableVpcEndpoints": {
|
|
672
|
-
"type": "boolean",
|
|
673
|
-
"description": "Create VPC endpoints. Enabled unless false."
|
|
674
|
-
}
|
|
675
|
-
},
|
|
676
|
-
"additionalProperties": false
|
|
447
|
+
"description": "Automatically fix VPC configuration issues",
|
|
448
|
+
"default": false
|
|
677
449
|
}
|
|
678
450
|
},
|
|
679
451
|
"additionalProperties": false
|
|
@@ -718,7 +490,9 @@
|
|
|
718
490
|
"enum": ["standard", "advanced"],
|
|
719
491
|
"default": "standard"
|
|
720
492
|
},
|
|
721
|
-
"description": {
|
|
493
|
+
"description": {
|
|
494
|
+
"type": "string"
|
|
495
|
+
}
|
|
722
496
|
}
|
|
723
497
|
}
|
|
724
498
|
},
|
|
@@ -729,15 +503,15 @@
|
|
|
729
503
|
},
|
|
730
504
|
"secretsManager": {
|
|
731
505
|
"type": "object",
|
|
732
|
-
"description": "AWS Secrets Manager configuration
|
|
506
|
+
"description": "AWS Secrets Manager configuration",
|
|
733
507
|
"properties": {
|
|
734
508
|
"enable": {
|
|
735
509
|
"type": "boolean",
|
|
736
|
-
"description": "Enable AWS Secrets Manager for secure credential storage"
|
|
510
|
+
"description": "Enable AWS Secrets Manager for secure credential storage",
|
|
511
|
+
"default": false
|
|
737
512
|
}
|
|
738
513
|
},
|
|
739
|
-
"additionalProperties": false
|
|
740
|
-
"deprecated": true
|
|
514
|
+
"additionalProperties": false
|
|
741
515
|
},
|
|
742
516
|
"lambda": {
|
|
743
517
|
"type": "object",
|
|
@@ -747,11 +521,6 @@
|
|
|
747
521
|
"type": "boolean",
|
|
748
522
|
"description": "Scope framework-generated environment variables (queue URLs, migration/scheduler vars) to the functions that consume them instead of broadcasting to every function. Reduces per-function env size against the Lambda 4KB limit",
|
|
749
523
|
"default": false
|
|
750
|
-
},
|
|
751
|
-
"keepNestedNodeModules": {
|
|
752
|
-
"type": "boolean",
|
|
753
|
-
"description": "Keep nested node_modules in function packages (nested Frigg, AWS SDK and Prisma packages are still excluded). Set false to exclude every nested node_modules",
|
|
754
|
-
"default": true
|
|
755
524
|
}
|
|
756
525
|
},
|
|
757
526
|
"additionalProperties": false
|
|
@@ -767,15 +536,15 @@
|
|
|
767
536
|
},
|
|
768
537
|
"routeSelectionExpression": {
|
|
769
538
|
"type": "string",
|
|
770
|
-
"description": "Route selection expression for WebSocket
|
|
771
|
-
"
|
|
539
|
+
"description": "Route selection expression for WebSocket",
|
|
540
|
+
"default": "$request.body.action"
|
|
772
541
|
}
|
|
773
542
|
},
|
|
774
543
|
"additionalProperties": false
|
|
775
544
|
},
|
|
776
545
|
"security": {
|
|
777
546
|
"type": "object",
|
|
778
|
-
"description": "Security settings for the application
|
|
547
|
+
"description": "Security settings for the application",
|
|
779
548
|
"properties": {
|
|
780
549
|
"cors": {
|
|
781
550
|
"type": "object",
|
|
@@ -784,17 +553,16 @@
|
|
|
784
553
|
"origin": {
|
|
785
554
|
"oneOf": [
|
|
786
555
|
{"type": "string"},
|
|
787
|
-
{
|
|
788
|
-
"type": "array",
|
|
789
|
-
"items": {"type": "string"}
|
|
790
|
-
},
|
|
556
|
+
{"type": "array", "items": {"type": "string"}},
|
|
791
557
|
{"type": "boolean"}
|
|
792
558
|
],
|
|
793
|
-
"description": "Allowed origins for CORS requests"
|
|
559
|
+
"description": "Allowed origins for CORS requests",
|
|
560
|
+
"default": "http://localhost:3000"
|
|
794
561
|
},
|
|
795
562
|
"credentials": {
|
|
796
563
|
"type": "boolean",
|
|
797
|
-
"description": "Allow credentials in CORS requests"
|
|
564
|
+
"description": "Allow credentials in CORS requests",
|
|
565
|
+
"default": true
|
|
798
566
|
},
|
|
799
567
|
"methods": {
|
|
800
568
|
"type": "array",
|
|
@@ -819,23 +587,24 @@
|
|
|
819
587
|
"windowMs": {
|
|
820
588
|
"type": "integer",
|
|
821
589
|
"description": "Time window in milliseconds",
|
|
822
|
-
"minimum": 1000
|
|
590
|
+
"minimum": 1000,
|
|
591
|
+
"default": 900000
|
|
823
592
|
},
|
|
824
593
|
"max": {
|
|
825
|
-
"type": "integer",
|
|
594
|
+
"type": "integer",
|
|
826
595
|
"description": "Maximum requests per window",
|
|
827
|
-
"minimum": 1
|
|
596
|
+
"minimum": 1,
|
|
597
|
+
"default": 100
|
|
828
598
|
}
|
|
829
599
|
},
|
|
830
600
|
"additionalProperties": false
|
|
831
601
|
}
|
|
832
602
|
},
|
|
833
|
-
"additionalProperties": false
|
|
834
|
-
"deprecated": true
|
|
603
|
+
"additionalProperties": false
|
|
835
604
|
},
|
|
836
605
|
"webhooks": {
|
|
837
606
|
"type": "object",
|
|
838
|
-
"description": "Webhook handling configuration
|
|
607
|
+
"description": "Webhook handling configuration",
|
|
839
608
|
"properties": {
|
|
840
609
|
"secret": {
|
|
841
610
|
"type": "string",
|
|
@@ -844,11 +613,11 @@
|
|
|
844
613
|
"prefix": {
|
|
845
614
|
"type": "string",
|
|
846
615
|
"description": "Webhook endpoint prefix",
|
|
847
|
-
"pattern": "^/[a-zA-Z0-9/_-]*$"
|
|
616
|
+
"pattern": "^/[a-zA-Z0-9/_-]*$",
|
|
617
|
+
"default": "/webhooks"
|
|
848
618
|
}
|
|
849
619
|
},
|
|
850
|
-
"additionalProperties": false
|
|
851
|
-
"deprecated": true
|
|
620
|
+
"additionalProperties": false
|
|
852
621
|
},
|
|
853
622
|
"logging": {
|
|
854
623
|
"type": "object",
|
|
@@ -856,8 +625,9 @@
|
|
|
856
625
|
"properties": {
|
|
857
626
|
"level": {
|
|
858
627
|
"type": "string",
|
|
859
|
-
"description": "Minimum log level, in lower or upper case. Sets FRIGG_LOG_LEVEL (when not info) and the Lambda application log level.
|
|
860
|
-
"enum": ["trace", "debug", "info", "warn", "error", "fatal", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"]
|
|
628
|
+
"description": "Minimum log level, in lower or upper case. Sets FRIGG_LOG_LEVEL (when not info) and the Lambda application log level.",
|
|
629
|
+
"enum": ["trace", "debug", "info", "warn", "error", "fatal", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"],
|
|
630
|
+
"default": "info"
|
|
861
631
|
},
|
|
862
632
|
"retentionInDays": {
|
|
863
633
|
"type": "integer",
|
|
@@ -866,225 +636,46 @@
|
|
|
866
636
|
},
|
|
867
637
|
"format": {
|
|
868
638
|
"type": "string",
|
|
869
|
-
"description": "Log format. Records are always JSON lines
|
|
870
|
-
"enum": ["json"]
|
|
871
|
-
|
|
872
|
-
},
|
|
873
|
-
"additionalProperties": false
|
|
874
|
-
},
|
|
875
|
-
"scheduler": {
|
|
876
|
-
"type": "object",
|
|
877
|
-
"description": "EventBridge Scheduler resources for one-time jobs. Also enabled automatically when an integration declares webhooks.",
|
|
878
|
-
"properties": {
|
|
879
|
-
"enable": {
|
|
880
|
-
"type": "boolean",
|
|
881
|
-
"description": "Provision the scheduler role and dead-letter queue",
|
|
882
|
-
"default": false
|
|
883
|
-
}
|
|
884
|
-
},
|
|
885
|
-
"additionalProperties": false
|
|
886
|
-
},
|
|
887
|
-
"aws": {
|
|
888
|
-
"type": "object",
|
|
889
|
-
"description": "AWS options for the build",
|
|
890
|
-
"properties": {
|
|
891
|
-
"discovery": {
|
|
892
|
-
"type": "object",
|
|
893
|
-
"description": "AWS resource discovery during build/deploy",
|
|
894
|
-
"properties": {
|
|
895
|
-
"enabled": {
|
|
896
|
-
"type": "boolean",
|
|
897
|
-
"description": "Force discovery on or off. When omitted, discovery runs when a feature needs it (VPC, KMS, SSM, PostgreSQL) and FRIGG_SKIP_AWS_DISCOVERY is not set."
|
|
898
|
-
},
|
|
899
|
-
"failOnError": {
|
|
900
|
-
"type": "boolean",
|
|
901
|
-
"description": "Fail the build when discovery fails",
|
|
902
|
-
"default": false
|
|
903
|
-
}
|
|
904
|
-
},
|
|
905
|
-
"additionalProperties": false
|
|
906
|
-
}
|
|
907
|
-
},
|
|
908
|
-
"additionalProperties": false
|
|
909
|
-
},
|
|
910
|
-
"migration": {
|
|
911
|
-
"type": "object",
|
|
912
|
-
"description": "Database migration resources",
|
|
913
|
-
"properties": {
|
|
914
|
-
"ownership": {
|
|
915
|
-
"type": "object",
|
|
916
|
-
"properties": {
|
|
917
|
-
"bucket": {
|
|
918
|
-
"type": "string",
|
|
919
|
-
"enum": ["stack", "external", "auto"],
|
|
920
|
-
"description": "Migration S3 bucket. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
921
|
-
},
|
|
922
|
-
"queue": {
|
|
923
|
-
"type": "string",
|
|
924
|
-
"enum": ["stack", "external", "auto"],
|
|
925
|
-
"description": "Migration SQS queue. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
|
|
926
|
-
}
|
|
927
|
-
},
|
|
928
|
-
"additionalProperties": false
|
|
929
|
-
}
|
|
930
|
-
},
|
|
931
|
-
"additionalProperties": false
|
|
932
|
-
},
|
|
933
|
-
"telemetry": {
|
|
934
|
-
"type": "object",
|
|
935
|
-
"description": "Telemetry and usage tracking (ADR-011). An invalid block disables telemetry at runtime instead of failing.",
|
|
936
|
-
"properties": {
|
|
937
|
-
"exporter": {
|
|
938
|
-
"type": "object",
|
|
939
|
-
"description": "Where traces and metrics go. When omitted: 'console' for STAGE=local, else 'none'.",
|
|
940
|
-
"properties": {
|
|
941
|
-
"type": {
|
|
942
|
-
"type": "string",
|
|
943
|
-
"enum": ["none", "noop", "console", "otlp", "honeycomb", "datadog"]
|
|
944
|
-
},
|
|
945
|
-
"endpoint": {
|
|
946
|
-
"type": "string",
|
|
947
|
-
"description": "OTLP endpoint (honeycomb defaults to https://api.honeycomb.io)"
|
|
948
|
-
},
|
|
949
|
-
"headers": {
|
|
950
|
-
"type": "object",
|
|
951
|
-
"additionalProperties": {"type": "string"}
|
|
952
|
-
},
|
|
953
|
-
"apiKey": {
|
|
954
|
-
"type": "string",
|
|
955
|
-
"description": "Honeycomb API key (sent as x-honeycomb-team)"
|
|
956
|
-
},
|
|
957
|
-
"traceExporter": {
|
|
958
|
-
"description": "A pre-built OTel trace exporter instance (advanced)"
|
|
959
|
-
},
|
|
960
|
-
"metricExporter": {
|
|
961
|
-
"description": "A pre-built OTel metric exporter instance (advanced)"
|
|
962
|
-
}
|
|
963
|
-
},
|
|
964
|
-
"additionalProperties": false
|
|
965
|
-
},
|
|
966
|
-
"sampleRatio": {
|
|
967
|
-
"type": "number",
|
|
968
|
-
"description": "Fraction of traces exported",
|
|
969
|
-
"minimum": 0,
|
|
970
|
-
"maximum": 1,
|
|
971
|
-
"default": 1
|
|
972
|
-
},
|
|
973
|
-
"northStar": {
|
|
974
|
-
"type": "object",
|
|
975
|
-
"description": "The usage counter that measures each integration type's value: { default: { name }, byType: { <type>: { name } } }",
|
|
976
|
-
"properties": {
|
|
977
|
-
"default": {
|
|
978
|
-
"type": "object",
|
|
979
|
-
"required": ["name"],
|
|
980
|
-
"properties": {
|
|
981
|
-
"name": {"type": "string"}
|
|
982
|
-
}
|
|
983
|
-
},
|
|
984
|
-
"byType": {
|
|
985
|
-
"type": "object",
|
|
986
|
-
"additionalProperties": {
|
|
987
|
-
"type": "object",
|
|
988
|
-
"required": ["name"],
|
|
989
|
-
"properties": {
|
|
990
|
-
"name": {"type": "string"}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
},
|
|
995
|
-
"additionalProperties": false
|
|
996
|
-
},
|
|
997
|
-
"subscribers": {
|
|
998
|
-
"type": "array",
|
|
999
|
-
"description": "Telemetry event subscribers: functions or { handler } objects",
|
|
1000
|
-
"items": {
|
|
1001
|
-
"description": "A function or { handler }"
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
},
|
|
1005
|
-
"additionalProperties": false
|
|
1006
|
-
},
|
|
1007
|
-
"admin": {
|
|
1008
|
-
"type": "object",
|
|
1009
|
-
"description": "Admin Script Runner options (ADR-005, ADR-010)",
|
|
1010
|
-
"properties": {
|
|
1011
|
-
"includeBuiltinReports": {
|
|
1012
|
-
"type": "boolean",
|
|
1013
|
-
"description": "Register Frigg's built-in reports",
|
|
1014
|
-
"default": false
|
|
1015
|
-
},
|
|
1016
|
-
"enableScheduling": {
|
|
1017
|
-
"type": "boolean",
|
|
1018
|
-
"description": "Provision scheduling for admin scripts"
|
|
1019
|
-
}
|
|
1020
|
-
},
|
|
1021
|
-
"additionalProperties": false
|
|
1022
|
-
},
|
|
1023
|
-
"adminScripts": {
|
|
1024
|
-
"type": "array",
|
|
1025
|
-
"description": "Admin script classes (each with a static Definition). Validators see each class as { Definition }.",
|
|
1026
|
-
"items": {
|
|
1027
|
-
"type": "object",
|
|
1028
|
-
"required": ["Definition"],
|
|
1029
|
-
"properties": {
|
|
1030
|
-
"Definition": {"type": "object"}
|
|
1031
|
-
}
|
|
1032
|
-
},
|
|
1033
|
-
"default": []
|
|
1034
|
-
},
|
|
1035
|
-
"reports": {
|
|
1036
|
-
"type": "array",
|
|
1037
|
-
"description": "Report classes (each with a static Definition). Validators see each class as { Definition }.",
|
|
1038
|
-
"items": {
|
|
1039
|
-
"type": "object",
|
|
1040
|
-
"required": ["Definition"],
|
|
1041
|
-
"properties": {
|
|
1042
|
-
"Definition": {"type": "object"}
|
|
1043
|
-
}
|
|
1044
|
-
},
|
|
1045
|
-
"default": []
|
|
1046
|
-
},
|
|
1047
|
-
"deployment": {
|
|
1048
|
-
"type": "object",
|
|
1049
|
-
"description": "`frigg deploy` options",
|
|
1050
|
-
"properties": {
|
|
1051
|
-
"skipPostDeploymentHealthCheck": {
|
|
1052
|
-
"type": "boolean",
|
|
1053
|
-
"description": "Skip `frigg doctor` after a deploy",
|
|
1054
|
-
"default": false
|
|
639
|
+
"description": "Log format. Records are always JSON lines.",
|
|
640
|
+
"enum": ["json"],
|
|
641
|
+
"default": "json"
|
|
1055
642
|
}
|
|
1056
643
|
},
|
|
1057
644
|
"additionalProperties": false
|
|
1058
645
|
},
|
|
1059
646
|
"custom": {
|
|
1060
647
|
"type": "object",
|
|
1061
|
-
"description": "Custom application-specific configuration
|
|
648
|
+
"description": "Custom application-specific configuration",
|
|
1062
649
|
"properties": {
|
|
1063
650
|
"appName": {
|
|
1064
651
|
"type": "string",
|
|
1065
|
-
"description": "Application display name"
|
|
652
|
+
"description": "Application display name",
|
|
653
|
+
"default": "My Frigg Application"
|
|
1066
654
|
},
|
|
1067
655
|
"version": {
|
|
1068
656
|
"type": "string",
|
|
1069
657
|
"description": "Application version",
|
|
1070
|
-
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$"
|
|
658
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$",
|
|
659
|
+
"default": "1.0.0"
|
|
1071
660
|
},
|
|
1072
661
|
"environment": {
|
|
1073
662
|
"type": "string",
|
|
1074
663
|
"description": "Deployment environment/stage",
|
|
1075
|
-
"enum": ["development", "staging", "production", "test"]
|
|
664
|
+
"enum": ["development", "staging", "production", "test"],
|
|
665
|
+
"default": "development"
|
|
1076
666
|
},
|
|
1077
667
|
"features": {
|
|
1078
668
|
"type": "object",
|
|
1079
669
|
"description": "Feature flags and toggles",
|
|
1080
670
|
"patternProperties": {
|
|
1081
|
-
"^[a-zA-Z][a-zA-Z0-9_]*$": {
|
|
671
|
+
"^[a-zA-Z][a-zA-Z0-9_]*$": {
|
|
672
|
+
"type": "boolean"
|
|
673
|
+
}
|
|
1082
674
|
},
|
|
1083
675
|
"additionalProperties": false
|
|
1084
676
|
}
|
|
1085
677
|
},
|
|
1086
|
-
"additionalProperties": true
|
|
1087
|
-
"deprecated": true
|
|
678
|
+
"additionalProperties": true
|
|
1088
679
|
}
|
|
1089
680
|
},
|
|
1090
681
|
"additionalProperties": false,
|
|
@@ -1098,15 +689,12 @@
|
|
|
1098
689
|
},
|
|
1099
690
|
"integrations": [],
|
|
1100
691
|
"user": {
|
|
1101
|
-
"
|
|
1102
|
-
"primary": "individual",
|
|
1103
|
-
"individualUserRequired": true,
|
|
1104
|
-
"organizationUserRequired": false
|
|
692
|
+
"password": true
|
|
1105
693
|
},
|
|
1106
694
|
"database": {
|
|
1107
695
|
"postgres": {
|
|
1108
696
|
"enable": true,
|
|
1109
|
-
"management": "
|
|
697
|
+
"management": "create-new"
|
|
1110
698
|
}
|
|
1111
699
|
},
|
|
1112
700
|
"encryption": {
|
|
@@ -1119,8 +707,18 @@
|
|
|
1119
707
|
"cidrBlock": "10.0.0.0/16",
|
|
1120
708
|
"enableVPCEndpoints": true
|
|
1121
709
|
},
|
|
1122
|
-
"ssm": {
|
|
1123
|
-
|
|
710
|
+
"ssm": {
|
|
711
|
+
"enable": true
|
|
712
|
+
},
|
|
713
|
+
"websockets": {
|
|
714
|
+
"enable": true
|
|
715
|
+
},
|
|
716
|
+
"security": {
|
|
717
|
+
"cors": {
|
|
718
|
+
"origin": "http://localhost:3000",
|
|
719
|
+
"credentials": true
|
|
720
|
+
}
|
|
721
|
+
},
|
|
1124
722
|
"logging": {
|
|
1125
723
|
"level": "info",
|
|
1126
724
|
"retentionInDays": 30
|
package/app-definition.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* App definition helpers shared by the runtime (core) and the tooling
|
|
3
|
-
* (devtools, frigg CLI). See ADR-051.
|
|
4
|
-
*
|
|
5
|
-
* This file loads only the JSON schema, not Ajv, so the runtime can apply
|
|
6
|
-
* the schema defaults at cold start without compiling a validator.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const appDefinitionSchema = require('./schemas/app-definition.schema.json');
|
|
10
|
-
|
|
11
|
-
function isPlainObject(value) {
|
|
12
|
-
if (value === null || typeof value !== 'object') return false;
|
|
13
|
-
const proto = Object.getPrototypeOf(value);
|
|
14
|
-
return proto === Object.prototype || proto === null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function cloneDefault(value) {
|
|
18
|
-
// Schema defaults are JSON values: a JSON round trip copies them fully.
|
|
19
|
-
return value === undefined ? value : JSON.parse(JSON.stringify(value));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Copy plain objects and arrays, keep everything else (classes, functions,
|
|
24
|
-
* instances) by reference.
|
|
25
|
-
*/
|
|
26
|
-
function clonePlain(value) {
|
|
27
|
-
if (Array.isArray(value)) return value.map(clonePlain);
|
|
28
|
-
if (isPlainObject(value)) {
|
|
29
|
-
const copy = {};
|
|
30
|
-
for (const [key, inner] of Object.entries(value)) {
|
|
31
|
-
copy[key] = clonePlain(inner);
|
|
32
|
-
}
|
|
33
|
-
return copy;
|
|
34
|
-
}
|
|
35
|
-
return value;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function applyDefaultsInPlace(schema, data) {
|
|
39
|
-
if (!schema || !isPlainObject(data)) return;
|
|
40
|
-
const properties = schema.properties || {};
|
|
41
|
-
for (const [key, propertySchema] of Object.entries(properties)) {
|
|
42
|
-
if (data[key] === undefined && propertySchema.default !== undefined) {
|
|
43
|
-
data[key] = cloneDefault(propertySchema.default);
|
|
44
|
-
}
|
|
45
|
-
if (isPlainObject(data[key]) && propertySchema.properties) {
|
|
46
|
-
applyDefaultsInPlace(propertySchema, data[key]);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Return a copy of the app definition with every `default` that the
|
|
53
|
-
* app-definition schema declares applied, the way Ajv `useDefaults` does:
|
|
54
|
-
* only for properties of objects that exist (a block the app leaves out is
|
|
55
|
-
* not created unless the block itself has a default, as `user` does). It
|
|
56
|
-
* also copies the deprecated `user.password` into `user.usePassword` when
|
|
57
|
-
* only the old spelling is set. Classes and other non-plain values are kept by reference.
|
|
58
|
-
* The input is not mutated, and the function is idempotent.
|
|
59
|
-
*
|
|
60
|
-
* This is the only place schema defaults are applied. core's
|
|
61
|
-
* loadAppDefinition and devtools' createFriggInfrastructure both call it,
|
|
62
|
-
* so a default in the schema is a default at runtime.
|
|
63
|
-
*
|
|
64
|
-
* @param {object} definition the `Definition` exported by the backend
|
|
65
|
-
* @returns {object} the definition with defaults applied
|
|
66
|
-
*/
|
|
67
|
-
function applyAppDefinitionDefaults(definition) {
|
|
68
|
-
if (!isPlainObject(definition)) return definition;
|
|
69
|
-
const copy = clonePlain(definition);
|
|
70
|
-
// user.password is the deprecated spelling of user.usePassword.
|
|
71
|
-
if (
|
|
72
|
-
isPlainObject(copy.user) &&
|
|
73
|
-
copy.user.usePassword === undefined &&
|
|
74
|
-
typeof copy.user.password === 'boolean'
|
|
75
|
-
) {
|
|
76
|
-
copy.user.usePassword = copy.user.password;
|
|
77
|
-
}
|
|
78
|
-
applyDefaultsInPlace(appDefinitionSchema, copy);
|
|
79
|
-
return copy;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Keys whose entries are classes with a static Definition.
|
|
83
|
-
const CLASS_LIST_KEYS = ['integrations', 'adminScripts', 'reports'];
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* JSON Schema cannot describe a JavaScript class, and apps list integration
|
|
87
|
-
* (and admin script, and report) classes. Validators therefore check this serialisable view, in which each
|
|
88
|
-
* class is replaced by `{ Definition }` (its static Definition). The schema
|
|
89
|
-
* describes that view; `frigg validate` checks the Definition itself.
|
|
90
|
-
*
|
|
91
|
-
* @param {object} definition the `Definition` exported by the backend
|
|
92
|
-
* @returns {object} a shallow copy with the class lists mapped to views
|
|
93
|
-
*/
|
|
94
|
-
function toAppDefinitionSchemaView(definition) {
|
|
95
|
-
if (!isPlainObject(definition)) return definition;
|
|
96
|
-
const view = { ...definition };
|
|
97
|
-
for (const key of CLASS_LIST_KEYS) {
|
|
98
|
-
if (Array.isArray(definition[key])) {
|
|
99
|
-
view[key] = definition[key].map((entry) =>
|
|
100
|
-
typeof entry === 'function'
|
|
101
|
-
? { Definition: entry.Definition }
|
|
102
|
-
: entry
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return view;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
module.exports = {
|
|
110
|
-
applyAppDefinitionDefaults,
|
|
111
|
-
toAppDefinitionSchemaView,
|
|
112
|
-
appDefinitionSchema,
|
|
113
|
-
};
|