@appsemble/lang-sdk 0.40.7-node-brotli.0 → 0.40.8
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/BasicValidator.js +2 -0
- package/blockUtils.js +3 -0
- package/iterApp.js +14 -1
- package/jsonschema.d.ts +1 -0
- package/jsonschemaBaseResolution.d.ts +13 -0
- package/jsonschemaBaseResolution.js +30 -0
- package/package.json +1 -1
- package/validation.js +7 -12
package/BasicValidator.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Validator, } from 'jsonschema';
|
|
2
2
|
import { isValidIconReference } from './icons.js';
|
|
3
3
|
import { schemas as allSchemas } from './index.js';
|
|
4
|
+
import { skipBaseResolutionForSchemasWithoutId } from './jsonschemaBaseResolution.js';
|
|
4
5
|
import { escapeJsonPointer } from './jsonPointer.js';
|
|
5
6
|
import { has } from './miscellaneous.js';
|
|
6
7
|
export class BaseValidatorFactory {
|
|
@@ -9,6 +10,7 @@ export class BaseValidatorFactory {
|
|
|
9
10
|
this.schemas = schemas;
|
|
10
11
|
}
|
|
11
12
|
build() {
|
|
13
|
+
skipBaseResolutionForSchemasWithoutId();
|
|
12
14
|
const validator = new Validator();
|
|
13
15
|
for (const [key, format] of Object.entries({
|
|
14
16
|
...BaseValidatorFactory.defaultCustomFormats,
|
package/blockUtils.js
CHANGED
|
@@ -49,6 +49,9 @@ export function getAppBlocks(definition) {
|
|
|
49
49
|
const result = [];
|
|
50
50
|
iterApp(definition, {
|
|
51
51
|
onBlock({ type, version }) {
|
|
52
|
+
if (typeof type !== 'string' || typeof version !== 'string') {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
52
55
|
const name = normalizeBlockName(type);
|
|
53
56
|
const asString = `${name}@${version}`;
|
|
54
57
|
if (!visited.has(asString)) {
|
package/iterApp.js
CHANGED
|
@@ -25,6 +25,9 @@ export function iterAction(action, callbacks, prefix = []) {
|
|
|
25
25
|
if (action.type === 'each') {
|
|
26
26
|
return iterAction(action.do, callbacks, [...prefix, 'do']);
|
|
27
27
|
}
|
|
28
|
+
if (action.type === 'match') {
|
|
29
|
+
return action.match.some((matchCase, index) => iterAction(matchCase.action, callbacks, [...prefix, 'match', index, 'action']));
|
|
30
|
+
}
|
|
28
31
|
if ('blocks' in action) {
|
|
29
32
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
30
33
|
return iterBlockList(action.blocks, callbacks, [...prefix, 'blocks']);
|
|
@@ -137,7 +140,10 @@ export function iterPage(page, callbacks, prefix = []) {
|
|
|
137
140
|
}
|
|
138
141
|
return result;
|
|
139
142
|
}
|
|
140
|
-
const { blocks = [] } = page;
|
|
143
|
+
const { actions, blocks = [] } = page;
|
|
144
|
+
if (Object.entries(actions ?? {}).some(([key, action]) => iterAction(action, callbacks, [...prefix, 'actions', key]))) {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
141
147
|
return iterBlockList(blocks, callbacks, [...prefix, 'blocks']);
|
|
142
148
|
}
|
|
143
149
|
/**
|
|
@@ -162,6 +168,13 @@ export function iterApp(app, callbacks) {
|
|
|
162
168
|
}
|
|
163
169
|
}
|
|
164
170
|
}
|
|
171
|
+
if (app.webhooks) {
|
|
172
|
+
for (const [name, webhook] of Object.entries(app.webhooks)) {
|
|
173
|
+
if (webhook?.action && iterAction(webhook.action, callbacks, ['webhooks', name, 'action'])) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
165
178
|
return false;
|
|
166
179
|
}
|
|
167
180
|
//# sourceMappingURL=iterApp.js.map
|
package/jsonschema.d.ts
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a child schema's base URI only when that schema declares an id.
|
|
3
|
+
*
|
|
4
|
+
* `jsonschema` resolves a base URI for every schema node it visits, and that URL resolution is the
|
|
5
|
+
* single most expensive part of validating a large app definition. A schema without an `$id` or
|
|
6
|
+
* `id` always resolves to its parent's base, so the resolution only carries information when an id
|
|
7
|
+
* is present. Appsemble's schemas declare no ids, which makes the resolution pure overhead for
|
|
8
|
+
* every node in the document.
|
|
9
|
+
*
|
|
10
|
+
* Calling this more than once is harmless: it installs the same implementation each time rather
|
|
11
|
+
* than wrapping whatever is already there.
|
|
12
|
+
*/
|
|
13
|
+
export declare function skipBaseResolutionForSchemasWithoutId(): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// `jsonschema` ships no types for its internal helpers module, which is where the schema context
|
|
2
|
+
// it builds while validating lives.
|
|
3
|
+
// @ts-expect-error 7016 -- untyped module
|
|
4
|
+
import { SchemaContext as UntypedSchemaContext } from 'jsonschema/lib/helpers.js';
|
|
5
|
+
const SchemaContextConstructor = UntypedSchemaContext;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a child schema's base URI only when that schema declares an id.
|
|
8
|
+
*
|
|
9
|
+
* `jsonschema` resolves a base URI for every schema node it visits, and that URL resolution is the
|
|
10
|
+
* single most expensive part of validating a large app definition. A schema without an `$id` or
|
|
11
|
+
* `id` always resolves to its parent's base, so the resolution only carries information when an id
|
|
12
|
+
* is present. Appsemble's schemas declare no ids, which makes the resolution pure overhead for
|
|
13
|
+
* every node in the document.
|
|
14
|
+
*
|
|
15
|
+
* Calling this more than once is harmless: it installs the same implementation each time rather
|
|
16
|
+
* than wrapping whatever is already there.
|
|
17
|
+
*/
|
|
18
|
+
export function skipBaseResolutionForSchemasWithoutId() {
|
|
19
|
+
SchemaContextConstructor.prototype.makeChild = function makeChild(schema, propertyName) {
|
|
20
|
+
const path = propertyName === undefined ? this.path : [...this.path, propertyName];
|
|
21
|
+
const id = schema.$id ?? schema.id;
|
|
22
|
+
const base = id ? this.resolve(id) : this.base;
|
|
23
|
+
const ctx = new SchemaContextConstructor(schema, this.options, path, base, Object.create(this.schemas));
|
|
24
|
+
if (id && !ctx.schemas[base]) {
|
|
25
|
+
ctx.schemas[base] = schema;
|
|
26
|
+
}
|
|
27
|
+
return ctx;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=jsonschemaBaseResolution.js.map
|
package/package.json
CHANGED
package/validation.js
CHANGED
|
@@ -9,7 +9,7 @@ import { findPageByName } from './findPageByName.js';
|
|
|
9
9
|
import { isAppLink } from './pageUtils.js';
|
|
10
10
|
import { bottomNavigationGridArea, breadcrumbsGridArea, builtinPagesGridAreaOrder, getBuiltinPagesDefaultGridLayout, getCascadedGridTemplateAreas, getGridTemplateAreas, gridDeviceOrder, resendBannerGridArea, } from './gridUtils.js';
|
|
11
11
|
import { isValidIconName, parseIconReference } from './icons.js';
|
|
12
|
-
import {
|
|
12
|
+
import { iterApp } from './iterApp.js';
|
|
13
13
|
import { has } from './miscellaneous.js';
|
|
14
14
|
import { normalize } from './normalize.js';
|
|
15
15
|
import { serverActions } from './serverActions.js';
|
|
@@ -1467,6 +1467,10 @@ function validateActions(definition, report) {
|
|
|
1467
1467
|
report(action.type, 'action type is not supported for cron jobs', [...path, 'type']);
|
|
1468
1468
|
return;
|
|
1469
1469
|
}
|
|
1470
|
+
if (path[0] === 'webhooks' && !serverActions.has(action.type)) {
|
|
1471
|
+
report(action.type, 'action type is not supported for webhooks', [...path, 'type']);
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1470
1474
|
if (validateUnsupportedServerOptimisticResourceWrite(action, path)) {
|
|
1471
1475
|
return;
|
|
1472
1476
|
}
|
|
@@ -1502,7 +1506,8 @@ function validateActions(definition, report) {
|
|
|
1502
1506
|
report(action.type, 'refers to a resource that doesn’t exist', [...path, 'resource']);
|
|
1503
1507
|
return;
|
|
1504
1508
|
}
|
|
1505
|
-
|
|
1509
|
+
// Webhook actions run on the server without checking resource permissions.
|
|
1510
|
+
if (!action.type.startsWith('resource.subscription.') && path[0] !== 'webhooks') {
|
|
1506
1511
|
if (!definition.security) {
|
|
1507
1512
|
report(action.type, 'missing security definition', [...path, 'resource']);
|
|
1508
1513
|
return;
|
|
@@ -1637,16 +1642,6 @@ function validateActions(definition, report) {
|
|
|
1637
1642
|
}
|
|
1638
1643
|
},
|
|
1639
1644
|
});
|
|
1640
|
-
for (const [name, webhook] of Object.entries(definition.webhooks ?? {})) {
|
|
1641
|
-
if (webhook.action &&
|
|
1642
|
-
iterAction(webhook.action, {
|
|
1643
|
-
onAction(action, path) {
|
|
1644
|
-
return validateUnsupportedServerOptimisticResourceWrite(action, path);
|
|
1645
|
-
},
|
|
1646
|
-
}, ['webhooks', name, 'action'])) {
|
|
1647
|
-
return;
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
1645
|
}
|
|
1651
1646
|
function validateEvents(definition, blockVersions, report) {
|
|
1652
1647
|
const indexMap = new Map();
|