@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brydio/manifest",
3
- "version": "0.1.0-alpha.7",
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": "0df91ca1c2a40d63ffcb0cad08f5f4b3278064f3",
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
- kind: z.enum(['project-tab', 'project-sidebar', 'workspace-sidebar']),
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. */