@friggframework/schemas 2.0.0--canary.702.0a3e1ef.0 → 2.0.0--canary.701.00d6b2c.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 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
  const {
20
16
  toApiModuleDefinitionSchemaView,
21
17
  } = require('./api-module-definition');
@@ -83,13 +79,7 @@ function validate(schemaName, data) {
83
79
  * @returns {object} - Validation result
84
80
  */
85
81
  function validateAppDefinition(appDefinition) {
86
- // Apps list integration classes, which JSON Schema cannot describe:
87
- // validate the serialisable view and return the original definition.
88
- const result = validate(
89
- 'app-definition',
90
- toAppDefinitionSchemaView(appDefinition)
91
- );
92
- return { ...result, data: appDefinition };
82
+ return validate('app-definition', appDefinition);
93
83
  }
94
84
 
95
85
  /**
@@ -104,7 +94,7 @@ function validateIntegrationDefinition(integrationDefinition) {
104
94
  /**
105
95
  * Validate API Module Definition.
106
96
  * Real Definitions carry classes and functions; validate the serialisable
107
- * view and return the original definition (same pattern as validateAppDefinition).
97
+ * view and return the original definition.
108
98
  * @param {object} apiModuleDefinition - API module definition object to validate
109
99
  * @returns {object} - Validation result
110
100
  */
@@ -376,8 +366,6 @@ module.exports = {
376
366
  // Validation functions
377
367
  validate,
378
368
  validateAppDefinition,
379
- applyAppDefinitionDefaults,
380
- toAppDefinitionSchemaView,
381
369
  toApiModuleDefinitionSchemaView,
382
370
  validateIntegrationDefinition,
383
371
  validateApiModuleDefinition,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@friggframework/schemas",
3
- "version": "2.0.0--canary.702.0a3e1ef.0",
3
+ "version": "2.0.0--canary.701.00d6b2c.0",
4
4
  "description": "Canonical JSON Schema definitions for Frigg Framework",
5
5
  "main": "index.js",
6
6
  "author": "",
@@ -39,9 +39,8 @@
39
39
  "validators/",
40
40
  "mocks/",
41
41
  "middleware/",
42
- "app-definition.js",
43
42
  "api-module-definition.js",
44
43
  "index.js"
45
44
  ],
46
- "gitHead": "0a3e1ef0f2cbd8ec5739729f2ba10dbbfd262dd6"
45
+ "gitHead": "00d6b2c41f32118d4dbde57f8dfe3c6416840992"
47
46
  }
@@ -22,35 +22,22 @@
22
22
  },
23
23
  "label": {
24
24
  "type": "string",
25
- "description": "Human-readable display name for the application. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
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. 'managed': Frigg creates and owns the VPC, database and KMS key it needs (with vpcIsolation 'isolated', per stage). 'existing': use existing resources given by id. 'discover' (also the behaviour when omitted): find existing resources and create what is missing. 'custom' is accepted for compatibility and behaves like 'discover'.",
43
- "enum": ["managed", "discover", "existing", "custom"]
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": "With managementMode 'managed': 'isolated' gives each stage its own VPC, database and key; 'shared' reuses them across stages. Set it explicitly: when it is omitted the builders do not agree on a default (see ADR-051).",
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,17 +68,10 @@
81
68
  },
82
69
  "integrations": {
83
70
  "type": "array",
84
- "description": "The IntegrationBase subclasses this application exposes. JSON Schema cannot describe a JavaScript class, so validateAppDefinition checks a serialisable view in which each class is replaced by { Definition: <its static Definition> }; `frigg validate` checks each Definition structurally (name, version, modules and their API module definitions).",
71
+ "description": "Array of integration classes to enable in the application",
85
72
  "items": {
86
73
  "type": "object",
87
- "description": "An integration class, seen as { Definition } (see the integrations 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
  },
@@ -130,56 +110,51 @@
130
110
  },
131
111
  "user": {
132
112
  "type": "object",
133
- "description": "User management and authentication. Read by core when it loads the app definition; an omitted block gets the defaults below (ADR-051).",
113
+ "description": "User management and authentication configuration",
134
114
  "properties": {
135
115
  "usePassword": {
136
116
  "type": "boolean",
137
- "description": "Users log in with username and password (POST /user/login). false: users are identified by appUserId (x-frigg-appuserid) instead.",
138
- "default": false
117
+ "description": "Enable password-based authentication for user login",
118
+ "default": true
139
119
  },
140
120
  "password": {
141
121
  "type": "boolean",
142
- "description": "DEPRECATED alias of usePassword: when usePassword is not set, the loader copies this value into it.",
143
- "deprecated": true
122
+ "description": "DEPRECATED: Use 'usePassword' instead. Enable password-based authentication",
123
+ "default": true
144
124
  },
145
125
  "primary": {
146
126
  "type": "string",
147
- "description": "Primary user type. Any value other than 'organization' is treated as 'individual'.",
127
+ "description": "Primary user type for authentication",
148
128
  "enum": ["individual", "organization"],
149
129
  "default": "individual"
150
130
  },
151
131
  "individualUserRequired": {
152
132
  "type": "boolean",
153
- "description": "Require an individual user. POST /user/login logs in individual users only when this is true.",
133
+ "description": "Require individual user for authentication",
154
134
  "default": true
155
135
  },
156
136
  "organizationUserRequired": {
157
137
  "type": "boolean",
158
- "description": "Require an organization user (looked up by appOrgId).",
159
- "default": false
160
- },
161
- "strictUserValidation": {
162
- "type": "boolean",
163
- "description": "With x-frigg headers, reject a user id that does not exist instead of creating and linking it.",
138
+ "description": "Require organization user for authentication",
164
139
  "default": false
165
140
  },
166
141
  "authModes": {
167
142
  "type": "object",
168
- "description": "Authentication modes. When the block is omitted, Frigg tokens and the shared secret are accepted. x-frigg-appUserId and x-frigg-appOrgId headers identify the user with any mode.",
143
+ "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.",
169
144
  "properties": {
170
145
  "friggToken": {
171
146
  "type": "boolean",
172
- "description": "Accept Frigg bearer tokens from /user/login. Enabled unless false.",
147
+ "description": "Enable Frigg native bearer token authentication (from /user/login)",
173
148
  "default": true
174
149
  },
175
150
  "sharedSecret": {
176
151
  "type": "boolean",
177
- "description": "Accept the x-frigg-api-key header (checked against FRIGG_API_KEY) for backend-to-backend calls. Enabled unless false.",
178
- "default": true
152
+ "description": "Enable shared secret authentication for backend-to-backend communication (requires FRIGG_API_KEY env var and x-frigg-api-key header)",
153
+ "default": false
179
154
  },
180
155
  "adopterJwt": {
181
156
  "type": "boolean",
182
- "description": "Accept JWTs from the adopter's own auth system (requires jwtConfig). Enabled only when true.",
157
+ "description": "Enable custom JWT authentication from adopter's auth system (requires jwtConfig)",
183
158
  "default": false
184
159
  }
185
160
  },
@@ -215,25 +190,22 @@
215
190
  },
216
191
  "fields": {
217
192
  "type": "array",
218
- "description": "Additional user fields. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
219
- "items": {"type": "string"},
220
- "examples": [
221
- ["email", "firstName", "lastName"]
222
- ],
223
- "deprecated": true
193
+ "description": "Additional user fields",
194
+ "items": {
195
+ "type": "string"
196
+ },
197
+ "examples": [["email", "firstName", "lastName"]]
224
198
  },
225
199
  "model": {
226
200
  "type": "object",
227
- "description": "Custom user model class. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
228
- "deprecated": true
201
+ "description": "Custom user model class"
229
202
  }
230
203
  },
231
- "additionalProperties": false,
232
- "default": {}
204
+ "additionalProperties": false
233
205
  },
234
206
  "auth": {
235
207
  "type": "object",
236
- "description": "Authentication configuration. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
208
+ "description": "Authentication configuration for integrations",
237
209
  "properties": {
238
210
  "jwtSecret": {
239
211
  "type": "string",
@@ -242,16 +214,17 @@
242
214
  "tokenExpiry": {
243
215
  "type": "string",
244
216
  "description": "Token expiration time",
245
- "pattern": "^\\d+[smhd]$"
217
+ "pattern": "^\\d+[smhd]$",
218
+ "default": "24h"
246
219
  },
247
220
  "refreshTokenExpiry": {
248
221
  "type": "string",
249
- "description": "Refresh token expiration time",
250
- "pattern": "^\\d+[smhd]$"
222
+ "description": "Refresh token expiration time",
223
+ "pattern": "^\\d+[smhd]$",
224
+ "default": "7d"
251
225
  }
252
226
  },
253
- "additionalProperties": false,
254
- "deprecated": true
227
+ "additionalProperties": false
255
228
  },
256
229
  "database": {
257
230
  "type": "object",
@@ -259,8 +232,8 @@
259
232
  "properties": {
260
233
  "uri": {
261
234
  "type": "string",
262
- "description": "Database connection URI (should be set via environment variable). Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
263
- "deprecated": true
235
+ "description": "Database connection URI (should be set via environment variable)",
236
+ "format": "uri"
264
237
  },
265
238
  "mongoDB": {
266
239
  "type": "object",
@@ -273,8 +246,7 @@
273
246
  },
274
247
  "uri": {
275
248
  "type": "string",
276
- "description": "MongoDB connection URI. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set. The connection string comes from DATABASE_URL.",
277
- "deprecated": true
249
+ "description": "MongoDB connection URI"
278
250
  }
279
251
  },
280
252
  "additionalProperties": true
@@ -302,16 +274,18 @@
302
274
  "properties": {
303
275
  "enable": {
304
276
  "type": "boolean",
305
- "description": "Use PostgreSQL. true provisions or discovers Aurora (unless management says otherwise). When omitted, Aurora is not provisioned, but migrations and the Prisma layer still include PostgreSQL; set false for a MongoDB/DocumentDB app."
277
+ "description": "Enable PostgreSQL database",
278
+ "default": false
306
279
  },
307
280
  "management": {
308
281
  "type": "string",
309
- "description": "How Frigg gets the Aurora cluster (ignored when managementMode is 'managed' or 'existing'). 'discover' (also when omitted): find one, else create one in the stack. 'managed': create it in the stack. 'use-existing': connect to `endpoint` without creating anything.",
310
- "enum": ["discover", "managed", "use-existing"]
282
+ "description": "How to manage the PostgreSQL database",
283
+ "enum": ["discover", "create-new", "existing"],
284
+ "default": "discover"
311
285
  },
312
286
  "endpoint": {
313
287
  "type": "string",
314
- "description": "Existing database endpoint (required when management='use-existing')",
288
+ "description": "Existing database endpoint (when management='existing')",
315
289
  "examples": ["mydb.cluster-abc123.us-east-1.rds.amazonaws.com"]
316
290
  },
317
291
  "port": {
@@ -329,15 +303,10 @@
329
303
  "description": "Database username",
330
304
  "default": "postgres"
331
305
  },
332
- "engineVersion": {
333
- "type": "string",
334
- "description": "Aurora PostgreSQL engine version for a cluster Frigg creates",
335
- "default": "15.13"
336
- },
337
306
  "selfHeal": {
338
307
  "type": "boolean",
339
- "description": "Automatically fix database configuration issues. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
340
- "deprecated": true
308
+ "description": "Automatically fix database configuration issues",
309
+ "default": true
341
310
  },
342
311
  "publiclyAccessible": {
343
312
  "type": "boolean",
@@ -346,7 +315,7 @@
346
315
  },
347
316
  "autoCreateCredentials": {
348
317
  "type": "boolean",
349
- "description": "Create a Secrets Manager secret and rotate the Aurora password when a discovered cluster has none (management='discover' only)",
318
+ "description": "Automatically create Secrets Manager secret and rotate Aurora password when discovering existing cluster (only applies when management='discover')",
350
319
  "default": false
351
320
  },
352
321
  "minCapacity": {
@@ -361,65 +330,7 @@
361
330
  "description": "Maximum Aurora Serverless capacity units (0.5-128)",
362
331
  "minimum": 0.5,
363
332
  "maximum": 128,
364
- "default": 4
365
- },
366
- "clusterId": {
367
- "type": "string",
368
- "description": "Only discover the Aurora cluster with this identifier"
369
- },
370
- "instanceId": {
371
- "type": "string",
372
- "description": "Only discover the Aurora instance with this identifier"
373
- },
374
- "ownership": {
375
- "type": "object",
376
- "description": "Per-resource ownership. When set, `management` is not translated.",
377
- "properties": {
378
- "cluster": {
379
- "type": "string",
380
- "enum": ["stack", "external", "auto"],
381
- "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)"
382
- },
383
- "instance": {
384
- "type": "string",
385
- "enum": ["stack", "external", "auto"],
386
- "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)"
387
- },
388
- "subnetGroup": {
389
- "type": "string",
390
- "enum": ["stack", "external", "auto"],
391
- "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)"
392
- },
393
- "secret": {
394
- "type": "string",
395
- "enum": ["stack", "external", "auto"],
396
- "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)"
397
- }
398
- },
399
- "additionalProperties": false
400
- },
401
- "external": {
402
- "type": "object",
403
- "description": "Ids of externally owned resources (ownership 'external')",
404
- "properties": {
405
- "clusterIdentifier": {"type": "string"},
406
- "instanceIdentifier": {"type": "string"},
407
- "subnetGroupName": {"type": "string"},
408
- "secretArn": {"type": "string"}
409
- },
410
- "additionalProperties": false
411
- }
412
- },
413
- "additionalProperties": false
414
- },
415
- "dynamodb": {
416
- "type": "object",
417
- "description": "DynamoDB access from inside the VPC",
418
- "properties": {
419
- "enable": {
420
- "type": "boolean",
421
- "description": "Add a DynamoDB VPC endpoint",
422
- "default": false
333
+ "default": 1
423
334
  }
424
335
  },
425
336
  "additionalProperties": false
@@ -433,12 +344,14 @@
433
344
  "properties": {
434
345
  "fieldLevelEncryptionMethod": {
435
346
  "type": "string",
436
- "description": "Field-level encryption key. 'kms': Frigg creates or discovers a KMS key and sets KMS_KEY_ARN. 'aes': the app supplies AES_KEY_ID and AES_KEY (list both in `environment`). Omitted: no key is provisioned and deployed stages store sensitive fields unencrypted (core logs a warning). Stages dev, test and local never encrypt.",
437
- "enum": ["kms", "aes"]
347
+ "description": "Method for field-level encryption",
348
+ "enum": ["kms", "aes"],
349
+ "default": "aes"
438
350
  },
439
351
  "createResourceIfNoneFound": {
440
352
  "type": "boolean",
441
- "description": "With 'kms' outside managementMode 'managed': create a KMS key when discovery finds none. When omitted, KMS_KEY_ARN falls back to the AWS_DISCOVERY_KMS_KEY_ID environment variable."
353
+ "description": "Create KMS key if none found during discovery",
354
+ "default": false
442
355
  },
443
356
  "schema": {
444
357
  "type": "object",
@@ -475,48 +388,6 @@
475
388
  }
476
389
  }
477
390
  ]
478
- },
479
- "ownership": {
480
- "type": "object",
481
- "description": "Per-resource ownership. When set, createResourceIfNoneFound is not translated.",
482
- "properties": {
483
- "key": {
484
- "type": "string",
485
- "enum": ["stack", "external", "auto"],
486
- "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)"
487
- }
488
- },
489
- "additionalProperties": false
490
- },
491
- "kmsKeyAlias": {
492
- "type": "boolean",
493
- "description": "Create an alias for a KMS key Frigg creates",
494
- "default": false
495
- },
496
- "keyAlias": {
497
- "type": "string",
498
- "description": "Only discover the KMS key with this alias",
499
- "pattern": "^alias/",
500
- "examples": ["alias/my-app-key"]
501
- },
502
- "disable": {
503
- "type": "object",
504
- "description": "Opt specific core-encrypted fields out of encryption: { Model: ['field.path'] }. Existing encrypted values still decrypt.",
505
- "patternProperties": {
506
- "^[A-Z][a-zA-Z0-9]*$": {
507
- "type": "array",
508
- "items": {
509
- "type": "string",
510
- "minLength": 1
511
- }
512
- }
513
- },
514
- "additionalProperties": false
515
- },
516
- "enable": {
517
- "type": "boolean",
518
- "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.",
519
- "deprecated": true
520
391
  }
521
392
  },
522
393
  "additionalProperties": false
@@ -527,23 +398,24 @@
527
398
  "properties": {
528
399
  "enable": {
529
400
  "type": "boolean",
530
- "description": "Run the Lambda functions in a VPC",
401
+ "description": "Enable VPC for Lambda functions",
531
402
  "default": false
532
403
  },
533
404
  "management": {
534
405
  "type": "string",
535
- "description": "How Frigg gets the VPC. 'discover' (also when omitted): find one (discovery fails if none exists). 'create-new': create VPC, security group and subnets in the stack. 'use-existing': use `vpcId` (and securityGroupIds / subnets.ids when given). Ignored when `ownership` is set.",
536
- "enum": ["discover", "create-new", "use-existing"]
406
+ "description": "How to manage VPC infrastructure",
407
+ "enum": ["discover", "create-new", "existing"],
408
+ "default": "discover"
537
409
  },
538
410
  "vpcId": {
539
411
  "type": "string",
540
- "description": "Existing VPC ID (required when management='use-existing')",
412
+ "description": "Existing VPC ID (when management='existing')",
541
413
  "pattern": "^vpc-[a-z0-9]+$",
542
414
  "examples": ["vpc-abc123"]
543
415
  },
544
416
  "cidrBlock": {
545
417
  "type": "string",
546
- "description": "CIDR block for a VPC Frigg creates",
418
+ "description": "CIDR block for VPC (when management='create-new')",
547
419
  "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$",
548
420
  "default": "10.0.0.0/16"
549
421
  },
@@ -554,9 +426,7 @@
554
426
  "type": "string",
555
427
  "pattern": "^sg-[a-z0-9]+$"
556
428
  },
557
- "examples": [
558
- ["sg-abc123", "sg-def456"]
559
- ]
429
+ "examples": [["sg-abc123", "sg-def456"]]
560
430
  },
561
431
  "subnets": {
562
432
  "type": "object",
@@ -564,20 +434,19 @@
564
434
  "properties": {
565
435
  "management": {
566
436
  "type": "string",
567
- "description": "'create': create the subnets in the stack. 'use-existing': use `ids` (at least 2). 'discover', 'create-new' and 'existing' are accepted for compatibility but have no effect (`frigg validate` warns).",
568
- "enum": ["create", "use-existing", "discover", "create-new", "existing"]
437
+ "description": "How to manage subnets",
438
+ "enum": ["discover", "create-new", "existing"],
439
+ "default": "discover"
569
440
  },
570
441
  "ids": {
571
442
  "type": "array",
572
- "description": "Existing subnet IDs (management='use-existing')",
443
+ "description": "Existing subnet IDs",
573
444
  "items": {
574
445
  "type": "string",
575
446
  "pattern": "^subnet-[a-z0-9]+$"
576
447
  },
577
448
  "minItems": 2,
578
- "examples": [
579
- ["subnet-abc123", "subnet-def456"]
580
- ]
449
+ "examples": [["subnet-abc123", "subnet-def456"]]
581
450
  }
582
451
  },
583
452
  "additionalProperties": false
@@ -588,12 +457,13 @@
588
457
  "properties": {
589
458
  "management": {
590
459
  "type": "string",
591
- "description": "'createAndManage': reuse a well-placed NAT gateway or create one. 'discover', 'create-new' and 'existing' are accepted for compatibility but have no effect (`frigg validate` warns). Set `id` to use an existing NAT gateway.",
592
- "enum": ["createAndManage", "discover", "create-new", "existing"]
460
+ "description": "How to manage NAT Gateway",
461
+ "enum": ["discover", "create-new", "existing"],
462
+ "default": "discover"
593
463
  },
594
464
  "id": {
595
465
  "type": "string",
596
- "description": "Existing NAT Gateway ID (makes the NAT gateway external)",
466
+ "description": "Existing NAT Gateway ID",
597
467
  "pattern": "^nat-[a-z0-9]+$",
598
468
  "examples": ["nat-abc123"]
599
469
  }
@@ -602,112 +472,13 @@
602
472
  },
603
473
  "enableVPCEndpoints": {
604
474
  "type": "boolean",
605
- "description": "Create VPC endpoints for AWS services (S3, DynamoDB, KMS, Secrets Manager). Enabled unless false.",
475
+ "description": "Create VPC endpoints for AWS services (S3, DynamoDB, KMS, Secrets Manager)",
606
476
  "default": true
607
477
  },
608
478
  "selfHeal": {
609
479
  "type": "boolean",
610
- "description": "Repair VPC configuration issues (route table associations) during discovery. When omitted, self-healing of stack-owned subnets is on."
611
- },
612
- "shareAcrossStages": {
613
- "type": "boolean",
614
- "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."
615
- },
616
- "ownership": {
617
- "type": "object",
618
- "description": "Per-resource ownership. When set, management, subnets, natGateway, shareAcrossStages, enableVPCEndpoints and selfHeal are not translated; use `config` instead.",
619
- "properties": {
620
- "vpc": {
621
- "type": "string",
622
- "enum": ["stack", "external", "auto"],
623
- "description": "VPC. Who owns the resource: 'stack' (this stack creates it), 'external' (use the id in `external`), 'auto' (reuse what discovery finds, else create)"
624
- },
625
- "securityGroup": {
626
- "type": "string",
627
- "enum": ["stack", "external", "auto"],
628
- "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)"
629
- },
630
- "subnets": {
631
- "type": "string",
632
- "enum": ["stack", "external", "auto"],
633
- "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)"
634
- },
635
- "natGateway": {
636
- "type": "string",
637
- "enum": ["stack", "external", "auto"],
638
- "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)"
639
- },
640
- "vpcEndpoints": {
641
- "type": "string",
642
- "enum": ["stack", "external", "auto"],
643
- "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)"
644
- }
645
- },
646
- "additionalProperties": false
647
- },
648
- "external": {
649
- "type": "object",
650
- "description": "Ids of externally owned resources (ownership 'external'); discovered ids are used when omitted",
651
- "properties": {
652
- "vpcId": {
653
- "type": "string",
654
- "pattern": "^vpc-[a-z0-9]+$"
655
- },
656
- "securityGroupIds": {
657
- "type": "array",
658
- "items": {
659
- "type": "string",
660
- "pattern": "^sg-[a-z0-9]+$"
661
- }
662
- },
663
- "subnetIds": {
664
- "type": "array",
665
- "items": {
666
- "type": "string",
667
- "pattern": "^subnet-[a-z0-9]+$"
668
- }
669
- },
670
- "natGatewayId": {
671
- "type": "string",
672
- "pattern": "^nat-[a-z0-9]+$"
673
- },
674
- "vpcEndpointIds": {
675
- "type": "object",
676
- "description": "Endpoint ids by type (s3, dynamodb, kms, secretsManager, sqs)",
677
- "additionalProperties": {"type": "string"}
678
- }
679
- },
680
- "additionalProperties": false
681
- },
682
- "config": {
683
- "type": "object",
684
- "description": "Settings for the ownership-based VPC configuration",
685
- "properties": {
686
- "cidrBlock": {
687
- "type": "string",
688
- "description": "CIDR block for a VPC Frigg creates (wins over vpc.cidrBlock)",
689
- "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$"
690
- },
691
- "selfHeal": {
692
- "type": "boolean",
693
- "description": "Recreate missing stack-owned subnets. Enabled unless false."
694
- },
695
- "natGateway": {
696
- "type": "object",
697
- "properties": {
698
- "enable": {
699
- "type": "boolean",
700
- "description": "Resolve a NAT gateway. Enabled unless false."
701
- }
702
- },
703
- "additionalProperties": false
704
- },
705
- "enableVpcEndpoints": {
706
- "type": "boolean",
707
- "description": "Create VPC endpoints. Enabled unless false."
708
- }
709
- },
710
- "additionalProperties": false
480
+ "description": "Automatically fix VPC configuration issues",
481
+ "default": false
711
482
  }
712
483
  },
713
484
  "additionalProperties": false
@@ -752,7 +523,9 @@
752
523
  "enum": ["standard", "advanced"],
753
524
  "default": "standard"
754
525
  },
755
- "description": {"type": "string"}
526
+ "description": {
527
+ "type": "string"
528
+ }
756
529
  }
757
530
  }
758
531
  },
@@ -763,15 +536,15 @@
763
536
  },
764
537
  "secretsManager": {
765
538
  "type": "object",
766
- "description": "AWS Secrets Manager configuration. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
539
+ "description": "AWS Secrets Manager configuration",
767
540
  "properties": {
768
541
  "enable": {
769
542
  "type": "boolean",
770
- "description": "Enable AWS Secrets Manager for secure credential storage"
543
+ "description": "Enable AWS Secrets Manager for secure credential storage",
544
+ "default": false
771
545
  }
772
546
  },
773
- "additionalProperties": false,
774
- "deprecated": true
547
+ "additionalProperties": false
775
548
  },
776
549
  "lambda": {
777
550
  "type": "object",
@@ -781,11 +554,6 @@
781
554
  "type": "boolean",
782
555
  "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",
783
556
  "default": false
784
- },
785
- "keepNestedNodeModules": {
786
- "type": "boolean",
787
- "description": "Keep nested node_modules in function packages (nested Frigg, AWS SDK and Prisma packages are still excluded)",
788
- "default": false
789
557
  }
790
558
  },
791
559
  "additionalProperties": false
@@ -801,15 +569,15 @@
801
569
  },
802
570
  "routeSelectionExpression": {
803
571
  "type": "string",
804
- "description": "Route selection expression for WebSocket. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
805
- "deprecated": true
572
+ "description": "Route selection expression for WebSocket",
573
+ "default": "$request.body.action"
806
574
  }
807
575
  },
808
576
  "additionalProperties": false
809
577
  },
810
578
  "security": {
811
579
  "type": "object",
812
- "description": "Security settings for the application. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
580
+ "description": "Security settings for the application",
813
581
  "properties": {
814
582
  "cors": {
815
583
  "type": "object",
@@ -818,17 +586,16 @@
818
586
  "origin": {
819
587
  "oneOf": [
820
588
  {"type": "string"},
821
- {
822
- "type": "array",
823
- "items": {"type": "string"}
824
- },
589
+ {"type": "array", "items": {"type": "string"}},
825
590
  {"type": "boolean"}
826
591
  ],
827
- "description": "Allowed origins for CORS requests"
592
+ "description": "Allowed origins for CORS requests",
593
+ "default": "http://localhost:3000"
828
594
  },
829
595
  "credentials": {
830
596
  "type": "boolean",
831
- "description": "Allow credentials in CORS requests"
597
+ "description": "Allow credentials in CORS requests",
598
+ "default": true
832
599
  },
833
600
  "methods": {
834
601
  "type": "array",
@@ -853,23 +620,24 @@
853
620
  "windowMs": {
854
621
  "type": "integer",
855
622
  "description": "Time window in milliseconds",
856
- "minimum": 1000
623
+ "minimum": 1000,
624
+ "default": 900000
857
625
  },
858
626
  "max": {
859
- "type": "integer",
627
+ "type": "integer",
860
628
  "description": "Maximum requests per window",
861
- "minimum": 1
629
+ "minimum": 1,
630
+ "default": 100
862
631
  }
863
632
  },
864
633
  "additionalProperties": false
865
634
  }
866
635
  },
867
- "additionalProperties": false,
868
- "deprecated": true
636
+ "additionalProperties": false
869
637
  },
870
638
  "webhooks": {
871
639
  "type": "object",
872
- "description": "Webhook handling configuration. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set. Webhooks are declared per integration (Definition.webhooks).",
640
+ "description": "Webhook handling configuration",
873
641
  "properties": {
874
642
  "secret": {
875
643
  "type": "string",
@@ -878,11 +646,11 @@
878
646
  "prefix": {
879
647
  "type": "string",
880
648
  "description": "Webhook endpoint prefix",
881
- "pattern": "^/[a-zA-Z0-9/_-]*$"
649
+ "pattern": "^/[a-zA-Z0-9/_-]*$",
650
+ "default": "/webhooks"
882
651
  }
883
652
  },
884
- "additionalProperties": false,
885
- "deprecated": true
653
+ "additionalProperties": false
886
654
  },
887
655
  "logging": {
888
656
  "type": "object",
@@ -890,8 +658,9 @@
890
658
  "properties": {
891
659
  "level": {
892
660
  "type": "string",
893
- "description": "Minimum log level, in lower or upper case. Sets FRIGG_LOG_LEVEL (when not info) and the Lambda application log level. When omitted, core logs at info and no Lambda log level is set.",
894
- "enum": ["trace", "debug", "info", "warn", "error", "fatal", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"]
661
+ "description": "Minimum log level, in lower or upper case. Sets FRIGG_LOG_LEVEL (when not info) and the Lambda application log level.",
662
+ "enum": ["trace", "debug", "info", "warn", "error", "fatal", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"],
663
+ "default": "info"
895
664
  },
896
665
  "retentionInDays": {
897
666
  "type": "integer",
@@ -900,225 +669,46 @@
900
669
  },
901
670
  "format": {
902
671
  "type": "string",
903
- "description": "Log format. Records are always JSON lines; this key is informational and has no default.",
904
- "enum": ["json"]
905
- }
906
- },
907
- "additionalProperties": false
908
- },
909
- "scheduler": {
910
- "type": "object",
911
- "description": "EventBridge Scheduler resources for one-time jobs. Also enabled automatically when an integration declares webhooks.",
912
- "properties": {
913
- "enable": {
914
- "type": "boolean",
915
- "description": "Provision the scheduler role and dead-letter queue",
916
- "default": false
917
- }
918
- },
919
- "additionalProperties": false
920
- },
921
- "aws": {
922
- "type": "object",
923
- "description": "AWS options for the build",
924
- "properties": {
925
- "discovery": {
926
- "type": "object",
927
- "description": "AWS resource discovery during build/deploy",
928
- "properties": {
929
- "enabled": {
930
- "type": "boolean",
931
- "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."
932
- },
933
- "failOnError": {
934
- "type": "boolean",
935
- "description": "Fail the build when discovery fails",
936
- "default": false
937
- }
938
- },
939
- "additionalProperties": false
940
- }
941
- },
942
- "additionalProperties": false
943
- },
944
- "migration": {
945
- "type": "object",
946
- "description": "Database migration resources",
947
- "properties": {
948
- "ownership": {
949
- "type": "object",
950
- "properties": {
951
- "bucket": {
952
- "type": "string",
953
- "enum": ["stack", "external", "auto"],
954
- "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)"
955
- },
956
- "queue": {
957
- "type": "string",
958
- "enum": ["stack", "external", "auto"],
959
- "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)"
960
- }
961
- },
962
- "additionalProperties": false
963
- }
964
- },
965
- "additionalProperties": false
966
- },
967
- "telemetry": {
968
- "type": "object",
969
- "description": "Telemetry and usage tracking (ADR-011). An invalid block disables telemetry at runtime instead of failing.",
970
- "properties": {
971
- "exporter": {
972
- "type": "object",
973
- "description": "Where traces and metrics go. When omitted: 'console' for STAGE=local, else 'none'.",
974
- "properties": {
975
- "type": {
976
- "type": "string",
977
- "enum": ["none", "noop", "console", "otlp", "honeycomb", "datadog"]
978
- },
979
- "endpoint": {
980
- "type": "string",
981
- "description": "OTLP endpoint (honeycomb defaults to https://api.honeycomb.io)"
982
- },
983
- "headers": {
984
- "type": "object",
985
- "additionalProperties": {"type": "string"}
986
- },
987
- "apiKey": {
988
- "type": "string",
989
- "description": "Honeycomb API key (sent as x-honeycomb-team)"
990
- },
991
- "traceExporter": {
992
- "description": "A pre-built OTel trace exporter instance (advanced)"
993
- },
994
- "metricExporter": {
995
- "description": "A pre-built OTel metric exporter instance (advanced)"
996
- }
997
- },
998
- "additionalProperties": false
999
- },
1000
- "sampleRatio": {
1001
- "type": "number",
1002
- "description": "Fraction of traces exported",
1003
- "minimum": 0,
1004
- "maximum": 1,
1005
- "default": 1
1006
- },
1007
- "northStar": {
1008
- "type": "object",
1009
- "description": "The usage counter that measures each integration type's value: { default: { name }, byType: { <type>: { name } } }",
1010
- "properties": {
1011
- "default": {
1012
- "type": "object",
1013
- "required": ["name"],
1014
- "properties": {
1015
- "name": {"type": "string"}
1016
- }
1017
- },
1018
- "byType": {
1019
- "type": "object",
1020
- "additionalProperties": {
1021
- "type": "object",
1022
- "required": ["name"],
1023
- "properties": {
1024
- "name": {"type": "string"}
1025
- }
1026
- }
1027
- }
1028
- },
1029
- "additionalProperties": false
1030
- },
1031
- "subscribers": {
1032
- "type": "array",
1033
- "description": "Telemetry event subscribers: functions or { handler } objects",
1034
- "items": {
1035
- "description": "A function or { handler }"
1036
- }
1037
- }
1038
- },
1039
- "additionalProperties": false
1040
- },
1041
- "admin": {
1042
- "type": "object",
1043
- "description": "Admin Script Runner options (ADR-005, ADR-010)",
1044
- "properties": {
1045
- "includeBuiltinReports": {
1046
- "type": "boolean",
1047
- "description": "Register Frigg's built-in reports",
1048
- "default": false
1049
- },
1050
- "enableScheduling": {
1051
- "type": "boolean",
1052
- "description": "Provision scheduling for admin scripts"
1053
- }
1054
- },
1055
- "additionalProperties": false
1056
- },
1057
- "adminScripts": {
1058
- "type": "array",
1059
- "description": "Admin script classes (each with a static Definition). Validators see each class as { Definition }.",
1060
- "items": {
1061
- "type": "object",
1062
- "required": ["Definition"],
1063
- "properties": {
1064
- "Definition": {"type": "object"}
1065
- }
1066
- },
1067
- "default": []
1068
- },
1069
- "reports": {
1070
- "type": "array",
1071
- "description": "Report classes (each with a static Definition). Validators see each class as { Definition }.",
1072
- "items": {
1073
- "type": "object",
1074
- "required": ["Definition"],
1075
- "properties": {
1076
- "Definition": {"type": "object"}
1077
- }
1078
- },
1079
- "default": []
1080
- },
1081
- "deployment": {
1082
- "type": "object",
1083
- "description": "`frigg deploy` options",
1084
- "properties": {
1085
- "skipPostDeploymentHealthCheck": {
1086
- "type": "boolean",
1087
- "description": "Skip `frigg doctor` after a deploy",
1088
- "default": false
672
+ "description": "Log format. Records are always JSON lines.",
673
+ "enum": ["json"],
674
+ "default": "json"
1089
675
  }
1090
676
  },
1091
677
  "additionalProperties": false
1092
678
  },
1093
679
  "custom": {
1094
680
  "type": "object",
1095
- "description": "Custom application-specific configuration. Not read by the Frigg runtime: it has no effect. Kept so existing definitions stay valid; `frigg validate` warns when it is set.",
681
+ "description": "Custom application-specific configuration",
1096
682
  "properties": {
1097
683
  "appName": {
1098
684
  "type": "string",
1099
- "description": "Application display name"
685
+ "description": "Application display name",
686
+ "default": "My Frigg Application"
1100
687
  },
1101
688
  "version": {
1102
689
  "type": "string",
1103
690
  "description": "Application version",
1104
- "pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$"
691
+ "pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$",
692
+ "default": "1.0.0"
1105
693
  },
1106
694
  "environment": {
1107
695
  "type": "string",
1108
696
  "description": "Deployment environment/stage",
1109
- "enum": ["development", "staging", "production", "test"]
697
+ "enum": ["development", "staging", "production", "test"],
698
+ "default": "development"
1110
699
  },
1111
700
  "features": {
1112
701
  "type": "object",
1113
702
  "description": "Feature flags and toggles",
1114
703
  "patternProperties": {
1115
- "^[a-zA-Z][a-zA-Z0-9_]*$": {"type": "boolean"}
704
+ "^[a-zA-Z][a-zA-Z0-9_]*$": {
705
+ "type": "boolean"
706
+ }
1116
707
  },
1117
708
  "additionalProperties": false
1118
709
  }
1119
710
  },
1120
- "additionalProperties": true,
1121
- "deprecated": true
711
+ "additionalProperties": true
1122
712
  }
1123
713
  },
1124
714
  "additionalProperties": false,
@@ -1132,15 +722,12 @@
1132
722
  },
1133
723
  "integrations": [],
1134
724
  "user": {
1135
- "usePassword": true,
1136
- "primary": "individual",
1137
- "individualUserRequired": true,
1138
- "organizationUserRequired": false
725
+ "password": true
1139
726
  },
1140
727
  "database": {
1141
728
  "postgres": {
1142
729
  "enable": true,
1143
- "management": "managed"
730
+ "management": "create-new"
1144
731
  }
1145
732
  },
1146
733
  "encryption": {
@@ -1153,8 +740,18 @@
1153
740
  "cidrBlock": "10.0.0.0/16",
1154
741
  "enableVPCEndpoints": true
1155
742
  },
1156
- "ssm": {"enable": true},
1157
- "websockets": {"enable": true},
743
+ "ssm": {
744
+ "enable": true
745
+ },
746
+ "websockets": {
747
+ "enable": true
748
+ },
749
+ "security": {
750
+ "cors": {
751
+ "origin": "http://localhost:3000",
752
+ "credentials": true
753
+ }
754
+ },
1158
755
  "logging": {
1159
756
  "level": "info",
1160
757
  "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
- };