@brydio/manifest 0.1.0-alpha.45 → 0.1.0-alpha.47
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/schema.d.ts +25 -1
- package/src/schema.js +36 -7
- package/src/secrets.js +12 -1
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.47",
|
|
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": "e8cb7890ccd27170d41d30a1447ea571a255e6ce",
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./src/index.d.ts",
|
package/src/schema.d.ts
CHANGED
|
@@ -93,6 +93,9 @@ declare const secretSchema: z.ZodObject<{
|
|
|
93
93
|
}>>;
|
|
94
94
|
}, z.core.$strip>;
|
|
95
95
|
export type SecretSpec = z.infer<typeof secretSchema>;
|
|
96
|
+
/** The `instances` rules an app may declare (CA10). */
|
|
97
|
+
export declare const INSTANCE_RULES: readonly ["one-per-workspace"];
|
|
98
|
+
export type InstanceRule = (typeof INSTANCE_RULES)[number];
|
|
96
99
|
declare const extensionShape: {
|
|
97
100
|
placements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
98
101
|
key: z.ZodOptional<z.ZodString>;
|
|
@@ -198,6 +201,15 @@ declare const extensionShape: {
|
|
|
198
201
|
install: "install";
|
|
199
202
|
}>>;
|
|
200
203
|
}, z.core.$strip>>>;
|
|
204
|
+
/**
|
|
205
|
+
* How many instances a workspace may keep (CA10). `"one-per-workspace"`:
|
|
206
|
+
* a single workspace instance, shown in the sidebar and on any project as
|
|
207
|
+
* a view of that project's records; never a project's or a person's own.
|
|
208
|
+
* Left out, as many as people make.
|
|
209
|
+
*/
|
|
210
|
+
instances: z.ZodOptional<z.ZodEnum<{
|
|
211
|
+
"one-per-workspace": "one-per-workspace";
|
|
212
|
+
}>>;
|
|
201
213
|
/**
|
|
202
214
|
* How records move when the schema changes between versions (A3-F07).
|
|
203
215
|
* Checked against the previous version when a version is published, and
|
|
@@ -244,7 +256,7 @@ export interface DataProblem {
|
|
|
244
256
|
field?: string;
|
|
245
257
|
message: string;
|
|
246
258
|
}
|
|
247
|
-
export type DataProblemCode = FieldTypeInvalid['code'] | OpenProblemCode | ConfirmProblemCode | AnonymousProblemCode | ReadersProblemCode | EditorsProblemCode | '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_home_sizes' | 'placement_sizes_not_home' | 'placement_widget_sizes' | 'placement_tab_retired' | 'placement_public_shape' | 'placement_public_nothing' | 'placement_chat_card_shape' | 'grant_tool_cross_app_self' | 'placement_children_too_deep' | 'placement_create_tool_unknown' | 'placement_create_not_write' | 'secret_name_taken' | 'grant_secrets_missing';
|
|
259
|
+
export type DataProblemCode = FieldTypeInvalid['code'] | OpenProblemCode | ConfirmProblemCode | AnonymousProblemCode | ReadersProblemCode | EditorsProblemCode | '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_home_sizes' | 'placement_sizes_not_home' | 'placement_widget_sizes' | 'placement_tab_retired' | 'placement_public_shape' | 'placement_public_nothing' | 'placement_chat_card_shape' | 'grant_tool_cross_app_self' | 'placement_children_too_deep' | 'placement_create_tool_unknown' | 'placement_create_not_write' | 'secret_name_taken' | 'grant_secrets_missing' | 'instances_needs_sidebar';
|
|
248
260
|
type Additions = z.infer<z.ZodObject<typeof extensionShape>>;
|
|
249
261
|
/**
|
|
250
262
|
* Everything wrong with an app's additions that a type cannot say.
|
|
@@ -376,6 +388,9 @@ export declare const manifestExtensionsSchema: z.ZodObject<{
|
|
|
376
388
|
install: "install";
|
|
377
389
|
}>>;
|
|
378
390
|
}, z.core.$strip>>>;
|
|
391
|
+
instances: z.ZodOptional<z.ZodEnum<{
|
|
392
|
+
"one-per-workspace": "one-per-workspace";
|
|
393
|
+
}>>;
|
|
379
394
|
migrations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
380
395
|
version: z.ZodString;
|
|
381
396
|
steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -514,6 +529,9 @@ export declare const storedExtensionsSchema: z.ZodObject<{
|
|
|
514
529
|
install: "install";
|
|
515
530
|
}>>;
|
|
516
531
|
}, z.core.$strip>>>;
|
|
532
|
+
instances: z.ZodOptional<z.ZodEnum<{
|
|
533
|
+
"one-per-workspace": "one-per-workspace";
|
|
534
|
+
}>>;
|
|
517
535
|
migrations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
518
536
|
version: z.ZodString;
|
|
519
537
|
steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -687,6 +705,9 @@ export declare const appManifestSchema: z.ZodObject<{
|
|
|
687
705
|
install: "install";
|
|
688
706
|
}>>;
|
|
689
707
|
}, z.core.$strip>>>;
|
|
708
|
+
instances: z.ZodOptional<z.ZodEnum<{
|
|
709
|
+
"one-per-workspace": "one-per-workspace";
|
|
710
|
+
}>>;
|
|
690
711
|
migrations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
691
712
|
version: z.ZodString;
|
|
692
713
|
steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -864,6 +885,9 @@ export declare const newAppManifestSchema: z.ZodObject<{
|
|
|
864
885
|
install: "install";
|
|
865
886
|
}>>;
|
|
866
887
|
}, z.core.$strip>>>;
|
|
888
|
+
instances: z.ZodOptional<z.ZodEnum<{
|
|
889
|
+
"one-per-workspace": "one-per-workspace";
|
|
890
|
+
}>>;
|
|
867
891
|
migrations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
868
892
|
version: z.ZodString;
|
|
869
893
|
steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
package/src/schema.js
CHANGED
|
@@ -237,6 +237,8 @@ const grantsSchema = z.object({
|
|
|
237
237
|
collections: z.array(z.string().max(100)).max(FIELD_LIMITS.collections + 1).optional(),
|
|
238
238
|
host: z.array(z.string().max(60)).max(20).optional(),
|
|
239
239
|
});
|
|
240
|
+
/** The `instances` rules an app may declare (CA10). */
|
|
241
|
+
export const INSTANCE_RULES = ['one-per-workspace'];
|
|
240
242
|
const extensionShape = {
|
|
241
243
|
placements: z.array(placementSchema).max(20).optional(),
|
|
242
244
|
data: z.record(z.string(), collectionSchema).optional(),
|
|
@@ -245,6 +247,13 @@ const extensionShape = {
|
|
|
245
247
|
grants: grantsSchema.optional(),
|
|
246
248
|
/** The secrets its handlers read (ADR-A24): names only, never values. */
|
|
247
249
|
secrets: z.array(secretSchema).max(MAX_APP_SECRETS).optional(),
|
|
250
|
+
/**
|
|
251
|
+
* How many instances a workspace may keep (CA10). `"one-per-workspace"`:
|
|
252
|
+
* a single workspace instance, shown in the sidebar and on any project as
|
|
253
|
+
* a view of that project's records; never a project's or a person's own.
|
|
254
|
+
* Left out, as many as people make.
|
|
255
|
+
*/
|
|
256
|
+
instances: z.enum(INSTANCE_RULES).optional(),
|
|
248
257
|
/**
|
|
249
258
|
* How records move when the schema changes between versions (A3-F07).
|
|
250
259
|
* Checked against the previous version when a version is published, and
|
|
@@ -421,6 +430,7 @@ export function dataProblems(additions, options = {}) {
|
|
|
421
430
|
}
|
|
422
431
|
problems.push(...customToolProblems(additions, options));
|
|
423
432
|
problems.push(...secretProblems(additions, options));
|
|
433
|
+
problems.push(...instanceRuleProblems(additions));
|
|
424
434
|
const screens = new Set(Object.keys(additions.screens ?? {}));
|
|
425
435
|
const placementKeys = new Set();
|
|
426
436
|
for (const placement of additions.placements ?? []) {
|
|
@@ -644,6 +654,23 @@ export const appToolPrefix = (name) => name
|
|
|
644
654
|
* Each secret declared once, and asked for (ADR-A24): an app that declares
|
|
645
655
|
* secrets without the `secrets` host grant could never read one.
|
|
646
656
|
*/
|
|
657
|
+
/**
|
|
658
|
+
* One instance per workspace is added once, from the workspace sidebar
|
|
659
|
+
* (CA10): an app that says so and offers no sidebar item could never be
|
|
660
|
+
* added at all.
|
|
661
|
+
*/
|
|
662
|
+
function instanceRuleProblems(additions) {
|
|
663
|
+
if (additions.instances !== 'one-per-workspace')
|
|
664
|
+
return [];
|
|
665
|
+
if ((additions.placements ?? []).some(one => one.kind === 'workspace-sidebar'))
|
|
666
|
+
return [];
|
|
667
|
+
return [
|
|
668
|
+
{
|
|
669
|
+
code: 'instances_needs_sidebar',
|
|
670
|
+
message: 'An app kept once per workspace is added from the workspace sidebar: add a "workspace-sidebar" placement.',
|
|
671
|
+
},
|
|
672
|
+
];
|
|
673
|
+
}
|
|
647
674
|
function secretProblems(additions, options) {
|
|
648
675
|
const problems = [];
|
|
649
676
|
const secrets = additions.secrets ?? [];
|
|
@@ -678,13 +705,15 @@ const refuse = (additions, ctx, options = {}) => {
|
|
|
678
705
|
? ['grants', 'host']
|
|
679
706
|
: problem.code === 'secret_name_taken'
|
|
680
707
|
? ['secrets']
|
|
681
|
-
: problem.code
|
|
682
|
-
? ['
|
|
683
|
-
: problem.code.startsWith('
|
|
684
|
-
? ['
|
|
685
|
-
: problem.
|
|
686
|
-
? ['
|
|
687
|
-
:
|
|
708
|
+
: problem.code === 'instances_needs_sidebar'
|
|
709
|
+
? ['instances']
|
|
710
|
+
: problem.code.startsWith('grant_')
|
|
711
|
+
? ['grants', 'collections']
|
|
712
|
+
: problem.code.startsWith('custom_')
|
|
713
|
+
? ['tools', 'custom']
|
|
714
|
+
: problem.collection
|
|
715
|
+
? ['data', problem.collection, ...(problem.field ? ['schema', problem.field] : [])]
|
|
716
|
+
: [],
|
|
688
717
|
params: { code: problem.code },
|
|
689
718
|
});
|
|
690
719
|
}
|
package/src/secrets.js
CHANGED
|
@@ -59,9 +59,20 @@ function walk(node, at, found, publicValue = () => false) {
|
|
|
59
59
|
*/
|
|
60
60
|
export function secretsInJson(document, at) {
|
|
61
61
|
const found = [];
|
|
62
|
-
walk(document, at, found, path =>
|
|
62
|
+
walk(document, at, found, path => DECLARATIONS.some(declared => declared.test(path)));
|
|
63
63
|
return found;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Names in an app.json that read like credentials but are declarations: a
|
|
67
|
+
* placement's identity, a collection's field definition (an open-schema
|
|
68
|
+
* companion must declare `key`), and a tool's input field. Their values are
|
|
69
|
+
* types and names, never secrets.
|
|
70
|
+
*/
|
|
71
|
+
const DECLARATIONS = [
|
|
72
|
+
/(?:^|\.)placements\[\d+\]\.key$/,
|
|
73
|
+
/(?:^|\.)data\.[^.[\]]+\.schema\.[^.[\]]+$/,
|
|
74
|
+
/(?:^|\.)tools\.custom\[\d+\]\.input\.[^.[\]]+$/,
|
|
75
|
+
];
|
|
65
76
|
/** Every secret declared in a bundle's files, as the server finds them. */
|
|
66
77
|
export function findSecrets(files, root = '') {
|
|
67
78
|
const found = [];
|