@brydio/manifest 0.1.0-alpha.7 → 0.1.0-alpha.9
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/package.json +2 -2
- package/src/index.d.ts +1 -1
- package/src/index.js +1 -1
- package/src/schema.d.ts +16 -1
- package/src/schema.js +18 -1
- package/src/secrets.js +5 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brydio/manifest",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.9",
|
|
4
4
|
"description": "The shape of a Brydio app's manifest, its collections' schemas, and the checks that say what is wrong with one.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"url": "https://github.com/nakel-ola/brydio-sdk",
|
|
11
11
|
"directory": "packages/manifest"
|
|
12
12
|
},
|
|
13
|
-
"gitHead": "
|
|
13
|
+
"gitHead": "9d77a54e497543ae7b921cf86551c171cbeb0352",
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./src/index.d.ts",
|
package/src/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { APP_NAME_FORMAT, MANIFEST_LIMITS, SEMVER_FORMAT, baseManifestSchema, br
|
|
|
7
7
|
export { BRAND_FIELDS, BRAND_LIMITS, brandFilePath, brandPathsOf, brandProblems, brandShapeOf, isBrandPath, pngVerdict, svgColours, toolsProblem, type BrandField, type RequirementCode, type RequirementFiles, type RequirementProblem, } from './requirements.js';
|
|
8
8
|
export { BUNDLE_MANIFEST, BUNDLE_MAX_BYTES, BUNDLE_PATH_MAX_CHARS, bundleBytes, bundleHash, brandOf, bundleProblem, codeOf, isBundlePath, isScriptPath, sizeOf, type BundleFiles, type BundleProblem, type BundleProblemCode, } from './bundle.js';
|
|
9
9
|
export { COLOUR_TOKENS, FIELD_LIMITS, RESERVED_FIELDS, describeType, isSearchable, isSortable, isStructured, parseFieldType, structuredFields, valueProblem, valueSchema, FieldTypeInvalid, type DocumentOf, type FieldKind, type FieldType, type FieldValue, type FieldsOf, } from './field-types.js';
|
|
10
|
-
export { appManifestSchema, collectionOf, collectionsOf, dataProblems, labelOf, manifestExtensionsSchema, MAX_APP_SECRETS, MAX_SECRET_CHARS, SECRET_NAME, storedExtensionsSchema, type AppManifestWithData, type CollectionSpec, type DataProblem, type DataProblemCode, type ManifestExtensions, type SecretSpec, } from './schema.js';
|
|
10
|
+
export { appManifestSchema, collectionOf, collectionsOf, dataProblems, effectivePlacementKey, labelOf, manifestExtensionsSchema, MAX_APP_SECRETS, MAX_SECRET_CHARS, PLACEMENT_KEY, SECRET_NAME, storedExtensionsSchema, type AppManifestWithData, type CollectionSpec, type DataProblem, type DataProblemCode, type ManifestExtensions, type SecretSpec, } from './schema.js';
|
|
11
11
|
export { DOCUMENT_LIMITS } from './document-limits.js';
|
|
12
12
|
export { HOST_CAPABILITIES, KNOWN_HOST_GRANTS, isHostCapability, unknownHostGrant } from './grants.js';
|
|
13
13
|
export { diffSchemas, migrationProblems, migrationSchema, migrationStepSchema, migrationsSchema, publishedMigrationProblems, schemaOf, type Migration, type MigrationCode, type MigrationProblem, type MigrationStep, type SchemaChange, } from './migrations.js';
|
package/src/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export { APP_NAME_FORMAT, MANIFEST_LIMITS, SEMVER_FORMAT, baseManifestSchema, br
|
|
|
7
7
|
export { BRAND_FIELDS, BRAND_LIMITS, brandFilePath, brandPathsOf, brandProblems, brandShapeOf, isBrandPath, pngVerdict, svgColours, toolsProblem, } from "./requirements.js";
|
|
8
8
|
export { BUNDLE_MANIFEST, BUNDLE_MAX_BYTES, BUNDLE_PATH_MAX_CHARS, bundleBytes, bundleHash, brandOf, bundleProblem, codeOf, isBundlePath, isScriptPath, sizeOf, } from "./bundle.js";
|
|
9
9
|
export { COLOUR_TOKENS, FIELD_LIMITS, RESERVED_FIELDS, describeType, isSearchable, isSortable, isStructured, parseFieldType, structuredFields, valueProblem, valueSchema, FieldTypeInvalid, } from "./field-types.js";
|
|
10
|
-
export { appManifestSchema, collectionOf, collectionsOf, dataProblems, labelOf, manifestExtensionsSchema, MAX_APP_SECRETS, MAX_SECRET_CHARS, SECRET_NAME, storedExtensionsSchema, } from "./schema.js";
|
|
10
|
+
export { appManifestSchema, collectionOf, collectionsOf, dataProblems, effectivePlacementKey, labelOf, manifestExtensionsSchema, MAX_APP_SECRETS, MAX_SECRET_CHARS, PLACEMENT_KEY, SECRET_NAME, storedExtensionsSchema, } from "./schema.js";
|
|
11
11
|
export { DOCUMENT_LIMITS } from "./document-limits.js";
|
|
12
12
|
export { HOST_CAPABILITIES, KNOWN_HOST_GRANTS, isHostCapability, unknownHostGrant } from "./grants.js";
|
|
13
13
|
export { diffSchemas, migrationProblems, migrationSchema, migrationStepSchema, migrationsSchema, publishedMigrationProblems, schemaOf, } from "./migrations.js";
|
package/src/schema.d.ts
CHANGED
|
@@ -33,6 +33,13 @@ export type PlacementSettingSpec = z.infer<typeof placementSettingSchema>;
|
|
|
33
33
|
* the limit is for the sidebar's width and a person's patience.
|
|
34
34
|
*/
|
|
35
35
|
export declare const MAX_FOLDER_DEPTH = 4;
|
|
36
|
+
/** A stable identity for one independently addable placement offering. */
|
|
37
|
+
export declare const PLACEMENT_KEY: RegExp;
|
|
38
|
+
export declare function effectivePlacementKey(one: {
|
|
39
|
+
key?: string;
|
|
40
|
+
kind: string;
|
|
41
|
+
screen: string;
|
|
42
|
+
}): string;
|
|
36
43
|
/** Most custom tools one app may declare (A3-F08). */
|
|
37
44
|
export declare const MAX_CUSTOM_TOOLS = 20;
|
|
38
45
|
/** A tool name the model and a policy row can both use as it is. */
|
|
@@ -78,10 +85,12 @@ declare const secretSchema: z.ZodObject<{
|
|
|
78
85
|
export type SecretSpec = z.infer<typeof secretSchema>;
|
|
79
86
|
declare const extensionShape: {
|
|
80
87
|
placements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
88
|
+
key: z.ZodOptional<z.ZodString>;
|
|
81
89
|
kind: z.ZodEnum<{
|
|
82
90
|
"project-tab": "project-tab";
|
|
83
91
|
"project-sidebar": "project-sidebar";
|
|
84
92
|
"workspace-sidebar": "workspace-sidebar";
|
|
93
|
+
home: "home";
|
|
85
94
|
}>;
|
|
86
95
|
screen: z.ZodString;
|
|
87
96
|
label: z.ZodOptional<z.ZodString>;
|
|
@@ -198,7 +207,7 @@ export interface DataProblem {
|
|
|
198
207
|
field?: string;
|
|
199
208
|
message: string;
|
|
200
209
|
}
|
|
201
|
-
export type DataProblemCode = FieldTypeInvalid['code'] | 'data_too_many_collections' | 'data_too_many_fields' | 'data_collection_name_format' | 'data_field_name_format' | 'data_field_reserved' | 'data_label_format' | 'data_label_taken' | 'data_project_field_twice' | 'data_search_unknown_field' | 'data_search_not_text' | 'grant_collection_missing' | 'grant_tool_missing' | 'custom_name_taken' | 'custom_collection_unknown' | 'custom_input_invalid' | 'placement_screen_unknown' | 'placement_children_too_deep' | 'placement_create_tool_unknown' | 'placement_create_not_write' | 'secret_name_taken' | 'grant_secrets_missing';
|
|
210
|
+
export type DataProblemCode = FieldTypeInvalid['code'] | 'data_too_many_collections' | 'data_too_many_fields' | 'data_collection_name_format' | 'data_field_name_format' | 'data_field_reserved' | 'data_label_format' | 'data_label_taken' | 'data_project_field_twice' | 'data_search_unknown_field' | 'data_search_not_text' | 'grant_collection_missing' | 'grant_tool_missing' | 'custom_name_taken' | 'custom_collection_unknown' | 'custom_input_invalid' | 'placement_key_taken' | 'placement_screen_unknown' | 'placement_children_too_deep' | 'placement_create_tool_unknown' | 'placement_create_not_write' | 'secret_name_taken' | 'grant_secrets_missing';
|
|
202
211
|
type Additions = z.infer<z.ZodObject<typeof extensionShape>>;
|
|
203
212
|
/**
|
|
204
213
|
* Everything wrong with an app's additions that a type cannot say.
|
|
@@ -213,10 +222,12 @@ export declare function dataProblems(additions: Additions, options?: {
|
|
|
213
222
|
/** The additions alone, for code that has the rest of the manifest already. */
|
|
214
223
|
export declare const manifestExtensionsSchema: z.ZodObject<{
|
|
215
224
|
placements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
225
|
+
key: z.ZodOptional<z.ZodString>;
|
|
216
226
|
kind: z.ZodEnum<{
|
|
217
227
|
"project-tab": "project-tab";
|
|
218
228
|
"project-sidebar": "project-sidebar";
|
|
219
229
|
"workspace-sidebar": "workspace-sidebar";
|
|
230
|
+
home: "home";
|
|
220
231
|
}>;
|
|
221
232
|
screen: z.ZodString;
|
|
222
233
|
label: z.ZodOptional<z.ZodString>;
|
|
@@ -322,10 +333,12 @@ export declare const manifestExtensionsSchema: z.ZodObject<{
|
|
|
322
333
|
*/
|
|
323
334
|
export declare const storedExtensionsSchema: z.ZodObject<{
|
|
324
335
|
placements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
336
|
+
key: z.ZodOptional<z.ZodString>;
|
|
325
337
|
kind: z.ZodEnum<{
|
|
326
338
|
"project-tab": "project-tab";
|
|
327
339
|
"project-sidebar": "project-sidebar";
|
|
328
340
|
"workspace-sidebar": "workspace-sidebar";
|
|
341
|
+
home: "home";
|
|
329
342
|
}>;
|
|
330
343
|
screen: z.ZodString;
|
|
331
344
|
label: z.ZodOptional<z.ZodString>;
|
|
@@ -466,10 +479,12 @@ export declare const appManifestSchema: z.ZodObject<{
|
|
|
466
479
|
}, z.core.$strip>>;
|
|
467
480
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
468
481
|
placements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
482
|
+
key: z.ZodOptional<z.ZodString>;
|
|
469
483
|
kind: z.ZodEnum<{
|
|
470
484
|
"project-tab": "project-tab";
|
|
471
485
|
"project-sidebar": "project-sidebar";
|
|
472
486
|
"workspace-sidebar": "workspace-sidebar";
|
|
487
|
+
home: "home";
|
|
473
488
|
}>;
|
|
474
489
|
screen: z.ZodString;
|
|
475
490
|
label: z.ZodOptional<z.ZodString>;
|
package/src/schema.js
CHANGED
|
@@ -48,8 +48,14 @@ const folderLevelSchema = z.object({
|
|
|
48
48
|
noun: z.string().min(1).max(60).optional(),
|
|
49
49
|
create: folderCreateSchema.optional(),
|
|
50
50
|
});
|
|
51
|
+
/** A stable identity for one independently addable placement offering. */
|
|
52
|
+
export const PLACEMENT_KEY = /^[a-z][a-z0-9-]{0,39}$/;
|
|
53
|
+
export function effectivePlacementKey(one) {
|
|
54
|
+
return one.key ?? `${one.kind}:${one.screen}`;
|
|
55
|
+
}
|
|
51
56
|
const placementSchema = z.object({
|
|
52
|
-
|
|
57
|
+
key: z.string().regex(PLACEMENT_KEY).optional(),
|
|
58
|
+
kind: z.enum(['project-tab', 'project-sidebar', 'workspace-sidebar', 'home']),
|
|
53
59
|
screen: z.string().min(1).max(FIELD_LIMITS.nameChars),
|
|
54
60
|
label: z.string().min(1).max(60).optional(),
|
|
55
61
|
icon: z.string().max(60).optional(),
|
|
@@ -312,7 +318,18 @@ export function dataProblems(additions, options = {}) {
|
|
|
312
318
|
problems.push(...customToolProblems(additions, options));
|
|
313
319
|
problems.push(...secretProblems(additions, options));
|
|
314
320
|
const screens = new Set(Object.keys(additions.screens ?? {}));
|
|
321
|
+
const placementKeys = new Set();
|
|
315
322
|
for (const placement of additions.placements ?? []) {
|
|
323
|
+
const key = effectivePlacementKey(placement);
|
|
324
|
+
if (placementKeys.has(key)) {
|
|
325
|
+
problems.push({
|
|
326
|
+
code: 'placement_key_taken',
|
|
327
|
+
message: `Two placements use the key "${key}"; each independently addable placement needs its own key.`,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
placementKeys.add(key);
|
|
332
|
+
}
|
|
316
333
|
if (!screens.has(placement.screen)) {
|
|
317
334
|
problems.push({
|
|
318
335
|
code: 'placement_screen_unknown',
|
package/src/secrets.js
CHANGED
|
@@ -35,21 +35,21 @@ const isRealValue = (value) => {
|
|
|
35
35
|
return false;
|
|
36
36
|
return true;
|
|
37
37
|
};
|
|
38
|
-
function walk(node, at, found) {
|
|
38
|
+
function walk(node, at, found, publicValue = () => false) {
|
|
39
39
|
if (Array.isArray(node)) {
|
|
40
|
-
node.forEach((one, index) => walk(one, `${at}[${index}]`, found));
|
|
40
|
+
node.forEach((one, index) => walk(one, `${at}[${index}]`, found, publicValue));
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
if (!node || typeof node !== 'object')
|
|
44
44
|
return;
|
|
45
45
|
for (const [key, value] of Object.entries(node)) {
|
|
46
46
|
const path = at ? `${at}.${key}` : key;
|
|
47
|
-
if (VALUE_KEYS.has(key) && isRealValue(value)) {
|
|
47
|
+
if (VALUE_KEYS.has(key) && isRealValue(value) && !publicValue(path)) {
|
|
48
48
|
// Never quoted back: a report that repeated the secret would copy it somewhere else.
|
|
49
49
|
found.push({ code: 'secret_in_bundle', message: SECRET_MESSAGE, path });
|
|
50
50
|
continue;
|
|
51
51
|
}
|
|
52
|
-
walk(value, path, found);
|
|
52
|
+
walk(value, path, found, publicValue);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
@@ -59,7 +59,7 @@ function walk(node, at, found) {
|
|
|
59
59
|
*/
|
|
60
60
|
export function secretsInJson(document, at) {
|
|
61
61
|
const found = [];
|
|
62
|
-
walk(document, at, found);
|
|
62
|
+
walk(document, at, found, path => /(?:^|\.)placements\[\d+\]\.key$/.test(path));
|
|
63
63
|
return found;
|
|
64
64
|
}
|
|
65
65
|
/** Every secret declared in a bundle's files, as the server finds them. */
|