@openbrf/plugin-sdk 0.0.0-stage → 1.0.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.
Files changed (79) hide show
  1. package/LICENSE +661 -0
  2. package/LICENSE-EXCEPTION.md +28 -0
  3. package/dist/action-schema.d.ts +42 -0
  4. package/dist/action-schema.d.ts.map +1 -0
  5. package/dist/action-schema.js +64 -0
  6. package/dist/action-schema.js.map +1 -0
  7. package/dist/actions.d.ts +199 -0
  8. package/dist/actions.d.ts.map +1 -0
  9. package/dist/actions.js +68 -0
  10. package/dist/actions.js.map +1 -0
  11. package/dist/api-version.d.ts +23 -0
  12. package/dist/api-version.d.ts.map +1 -0
  13. package/dist/api-version.js +27 -0
  14. package/dist/api-version.js.map +1 -0
  15. package/dist/catalog.d.ts +315 -0
  16. package/dist/catalog.d.ts.map +1 -0
  17. package/dist/catalog.js +203 -0
  18. package/dist/catalog.js.map +1 -0
  19. package/dist/define-plugin.d.ts +14 -0
  20. package/dist/define-plugin.d.ts.map +1 -0
  21. package/dist/define-plugin.js +15 -0
  22. package/dist/define-plugin.js.map +1 -0
  23. package/dist/findings.d.ts +67 -0
  24. package/dist/findings.d.ts.map +1 -0
  25. package/dist/findings.js +57 -0
  26. package/dist/findings.js.map +1 -0
  27. package/dist/host.d.ts +208 -0
  28. package/dist/host.d.ts.map +1 -0
  29. package/dist/host.js +41 -0
  30. package/dist/host.js.map +1 -0
  31. package/dist/index.d.ts +24 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +22 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/integrity.d.ts +38 -0
  36. package/dist/integrity.d.ts.map +1 -0
  37. package/dist/integrity.js +105 -0
  38. package/dist/integrity.js.map +1 -0
  39. package/dist/manifest.d.ts +392 -0
  40. package/dist/manifest.d.ts.map +1 -0
  41. package/dist/manifest.js +324 -0
  42. package/dist/manifest.js.map +1 -0
  43. package/dist/module.d.ts +35 -0
  44. package/dist/module.d.ts.map +1 -0
  45. package/dist/module.js +2 -0
  46. package/dist/module.js.map +1 -0
  47. package/dist/package-check.d.ts +66 -0
  48. package/dist/package-check.d.ts.map +1 -0
  49. package/dist/package-check.js +755 -0
  50. package/dist/package-check.js.map +1 -0
  51. package/dist/permissions.d.ts +65 -0
  52. package/dist/permissions.d.ts.map +1 -0
  53. package/dist/permissions.js +69 -0
  54. package/dist/permissions.js.map +1 -0
  55. package/dist/settings-schema.d.ts +95 -0
  56. package/dist/settings-schema.d.ts.map +1 -0
  57. package/dist/settings-schema.js +219 -0
  58. package/dist/settings-schema.js.map +1 -0
  59. package/dist/standard-schema.d.ts +43 -0
  60. package/dist/standard-schema.d.ts.map +1 -0
  61. package/dist/standard-schema.js +2 -0
  62. package/dist/standard-schema.js.map +1 -0
  63. package/package.json +55 -3
  64. package/src/action-schema.ts +86 -0
  65. package/src/actions.ts +247 -0
  66. package/src/api-version.ts +28 -0
  67. package/src/catalog.ts +236 -0
  68. package/src/define-plugin.ts +18 -0
  69. package/src/findings.ts +71 -0
  70. package/src/host.ts +240 -0
  71. package/src/index.ts +123 -0
  72. package/src/integrity.ts +125 -0
  73. package/src/manifest.ts +385 -0
  74. package/src/module.ts +38 -0
  75. package/src/package-check.ts +894 -0
  76. package/src/permissions.ts +75 -0
  77. package/src/settings-schema.ts +272 -0
  78. package/src/standard-schema.ts +39 -0
  79. package/README.md +0 -3
@@ -0,0 +1,315 @@
1
+ import { z } from "zod";
2
+ /** A tarball and the digest its bytes must hash to. */
3
+ export declare const catalogArtifactSchema: z.ZodObject<{
4
+ url: z.ZodString;
5
+ sha512: z.ZodString;
6
+ bytes: z.ZodOptional<z.ZodInt>;
7
+ }, z.core.$strict>;
8
+ export type CatalogArtifact = z.infer<typeof catalogArtifactSchema>;
9
+ /** Text a curator writes in both languages the interface is offered in. */
10
+ declare const localizedTextSchema: z.ZodObject<{
11
+ sv: z.ZodString;
12
+ en: z.ZodString;
13
+ }, z.core.$strict>;
14
+ export type LocalizedText = z.infer<typeof localizedTextSchema>;
15
+ export declare const catalogPluginEntrySchema: z.ZodObject<{
16
+ id: z.ZodString;
17
+ version: z.ZodString;
18
+ name: z.ZodObject<{
19
+ sv: z.ZodString;
20
+ en: z.ZodString;
21
+ }, z.core.$strict>;
22
+ description: z.ZodObject<{
23
+ sv: z.ZodString;
24
+ en: z.ZodString;
25
+ }, z.core.$strict>;
26
+ artifact: z.ZodObject<{
27
+ url: z.ZodString;
28
+ sha512: z.ZodString;
29
+ bytes: z.ZodOptional<z.ZodInt>;
30
+ }, z.core.$strict>;
31
+ homepage: z.ZodOptional<z.ZodString>;
32
+ deprecated: z.ZodDefault<z.ZodBoolean>;
33
+ type: z.ZodLiteral<"plugin">;
34
+ packageName: z.ZodString;
35
+ apiVersion: z.ZodInt;
36
+ permissions: z.ZodDefault<z.ZodArray<z.ZodEnum<{
37
+ "addressBook:read": "addressBook:read";
38
+ "addressBook:readContact": "addressBook:readContact";
39
+ "jobs:schedule": "jobs:schedule";
40
+ "mail:send": "mail:send";
41
+ "sms:send": "sms:send";
42
+ }>>>;
43
+ personalData: z.ZodDefault<z.ZodArray<z.ZodEnum<{
44
+ apartment: "apartment";
45
+ email: "email";
46
+ name: "name";
47
+ phone: "phone";
48
+ residency: "residency";
49
+ }>>>;
50
+ actions: z.ZodDefault<z.ZodArray<z.ZodObject<{
51
+ id: z.ZodString;
52
+ capability: z.ZodString;
53
+ effect: z.ZodEnum<{
54
+ delete: "delete";
55
+ read: "read";
56
+ write: "write";
57
+ }>;
58
+ personalData: z.ZodDefault<z.ZodArray<z.ZodEnum<{
59
+ account: "account";
60
+ apartment: "apartment";
61
+ auditTrail: "auditTrail";
62
+ email: "email";
63
+ financial: "financial";
64
+ freeText: "freeText";
65
+ health: "health";
66
+ name: "name";
67
+ personalIdentityNumber: "personalIdentityNumber";
68
+ phone: "phone";
69
+ photograph: "photograph";
70
+ postalAddress: "postalAddress";
71
+ protected: "protected";
72
+ residency: "residency";
73
+ }>>>;
74
+ surfaces: z.ZodDefault<z.ZodArray<z.ZodEnum<{
75
+ ai: "ai";
76
+ mcp: "mcp";
77
+ ui: "ui";
78
+ }>>>;
79
+ }, z.core.$strict>>>;
80
+ oauthProtectedResource: z.ZodOptional<z.ZodString>;
81
+ }, z.core.$strict>;
82
+ /**
83
+ * A theme entry. Themes install through the same download-and-verify path and
84
+ * are listed in the same index; what happens after the bytes are verified is
85
+ * the theme installer's business, not this schema's.
86
+ *
87
+ * No package name: a theme is data read out of its archive, never an npm
88
+ * package, and nothing that installs one keys on a package name.
89
+ */
90
+ export declare const catalogThemeEntrySchema: z.ZodObject<{
91
+ id: z.ZodString;
92
+ version: z.ZodString;
93
+ name: z.ZodObject<{
94
+ sv: z.ZodString;
95
+ en: z.ZodString;
96
+ }, z.core.$strict>;
97
+ description: z.ZodObject<{
98
+ sv: z.ZodString;
99
+ en: z.ZodString;
100
+ }, z.core.$strict>;
101
+ artifact: z.ZodObject<{
102
+ url: z.ZodString;
103
+ sha512: z.ZodString;
104
+ bytes: z.ZodOptional<z.ZodInt>;
105
+ }, z.core.$strict>;
106
+ homepage: z.ZodOptional<z.ZodString>;
107
+ deprecated: z.ZodDefault<z.ZodBoolean>;
108
+ type: z.ZodLiteral<"theme">;
109
+ contract: z.ZodOptional<z.ZodString>;
110
+ extends: z.ZodOptional<z.ZodString>;
111
+ }, z.core.$strict>;
112
+ export declare const catalogEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
113
+ id: z.ZodString;
114
+ version: z.ZodString;
115
+ name: z.ZodObject<{
116
+ sv: z.ZodString;
117
+ en: z.ZodString;
118
+ }, z.core.$strict>;
119
+ description: z.ZodObject<{
120
+ sv: z.ZodString;
121
+ en: z.ZodString;
122
+ }, z.core.$strict>;
123
+ artifact: z.ZodObject<{
124
+ url: z.ZodString;
125
+ sha512: z.ZodString;
126
+ bytes: z.ZodOptional<z.ZodInt>;
127
+ }, z.core.$strict>;
128
+ homepage: z.ZodOptional<z.ZodString>;
129
+ deprecated: z.ZodDefault<z.ZodBoolean>;
130
+ type: z.ZodLiteral<"plugin">;
131
+ packageName: z.ZodString;
132
+ apiVersion: z.ZodInt;
133
+ permissions: z.ZodDefault<z.ZodArray<z.ZodEnum<{
134
+ "addressBook:read": "addressBook:read";
135
+ "addressBook:readContact": "addressBook:readContact";
136
+ "jobs:schedule": "jobs:schedule";
137
+ "mail:send": "mail:send";
138
+ "sms:send": "sms:send";
139
+ }>>>;
140
+ personalData: z.ZodDefault<z.ZodArray<z.ZodEnum<{
141
+ apartment: "apartment";
142
+ email: "email";
143
+ name: "name";
144
+ phone: "phone";
145
+ residency: "residency";
146
+ }>>>;
147
+ actions: z.ZodDefault<z.ZodArray<z.ZodObject<{
148
+ id: z.ZodString;
149
+ capability: z.ZodString;
150
+ effect: z.ZodEnum<{
151
+ delete: "delete";
152
+ read: "read";
153
+ write: "write";
154
+ }>;
155
+ personalData: z.ZodDefault<z.ZodArray<z.ZodEnum<{
156
+ account: "account";
157
+ apartment: "apartment";
158
+ auditTrail: "auditTrail";
159
+ email: "email";
160
+ financial: "financial";
161
+ freeText: "freeText";
162
+ health: "health";
163
+ name: "name";
164
+ personalIdentityNumber: "personalIdentityNumber";
165
+ phone: "phone";
166
+ photograph: "photograph";
167
+ postalAddress: "postalAddress";
168
+ protected: "protected";
169
+ residency: "residency";
170
+ }>>>;
171
+ surfaces: z.ZodDefault<z.ZodArray<z.ZodEnum<{
172
+ ai: "ai";
173
+ mcp: "mcp";
174
+ ui: "ui";
175
+ }>>>;
176
+ }, z.core.$strict>>>;
177
+ oauthProtectedResource: z.ZodOptional<z.ZodString>;
178
+ }, z.core.$strict>, z.ZodObject<{
179
+ id: z.ZodString;
180
+ version: z.ZodString;
181
+ name: z.ZodObject<{
182
+ sv: z.ZodString;
183
+ en: z.ZodString;
184
+ }, z.core.$strict>;
185
+ description: z.ZodObject<{
186
+ sv: z.ZodString;
187
+ en: z.ZodString;
188
+ }, z.core.$strict>;
189
+ artifact: z.ZodObject<{
190
+ url: z.ZodString;
191
+ sha512: z.ZodString;
192
+ bytes: z.ZodOptional<z.ZodInt>;
193
+ }, z.core.$strict>;
194
+ homepage: z.ZodOptional<z.ZodString>;
195
+ deprecated: z.ZodDefault<z.ZodBoolean>;
196
+ type: z.ZodLiteral<"theme">;
197
+ contract: z.ZodOptional<z.ZodString>;
198
+ extends: z.ZodOptional<z.ZodString>;
199
+ }, z.core.$strict>], "type">;
200
+ export type CatalogPluginEntry = z.infer<typeof catalogPluginEntrySchema>;
201
+ export type CatalogThemeEntry = z.infer<typeof catalogThemeEntrySchema>;
202
+ export type CatalogEntry = z.infer<typeof catalogEntrySchema>;
203
+ export declare const catalogSchema: z.ZodObject<{
204
+ version: z.ZodLiteral<1>;
205
+ entries: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
206
+ id: z.ZodString;
207
+ version: z.ZodString;
208
+ name: z.ZodObject<{
209
+ sv: z.ZodString;
210
+ en: z.ZodString;
211
+ }, z.core.$strict>;
212
+ description: z.ZodObject<{
213
+ sv: z.ZodString;
214
+ en: z.ZodString;
215
+ }, z.core.$strict>;
216
+ artifact: z.ZodObject<{
217
+ url: z.ZodString;
218
+ sha512: z.ZodString;
219
+ bytes: z.ZodOptional<z.ZodInt>;
220
+ }, z.core.$strict>;
221
+ homepage: z.ZodOptional<z.ZodString>;
222
+ deprecated: z.ZodDefault<z.ZodBoolean>;
223
+ type: z.ZodLiteral<"plugin">;
224
+ packageName: z.ZodString;
225
+ apiVersion: z.ZodInt;
226
+ permissions: z.ZodDefault<z.ZodArray<z.ZodEnum<{
227
+ "addressBook:read": "addressBook:read";
228
+ "addressBook:readContact": "addressBook:readContact";
229
+ "jobs:schedule": "jobs:schedule";
230
+ "mail:send": "mail:send";
231
+ "sms:send": "sms:send";
232
+ }>>>;
233
+ personalData: z.ZodDefault<z.ZodArray<z.ZodEnum<{
234
+ apartment: "apartment";
235
+ email: "email";
236
+ name: "name";
237
+ phone: "phone";
238
+ residency: "residency";
239
+ }>>>;
240
+ actions: z.ZodDefault<z.ZodArray<z.ZodObject<{
241
+ id: z.ZodString;
242
+ capability: z.ZodString;
243
+ effect: z.ZodEnum<{
244
+ delete: "delete";
245
+ read: "read";
246
+ write: "write";
247
+ }>;
248
+ personalData: z.ZodDefault<z.ZodArray<z.ZodEnum<{
249
+ account: "account";
250
+ apartment: "apartment";
251
+ auditTrail: "auditTrail";
252
+ email: "email";
253
+ financial: "financial";
254
+ freeText: "freeText";
255
+ health: "health";
256
+ name: "name";
257
+ personalIdentityNumber: "personalIdentityNumber";
258
+ phone: "phone";
259
+ photograph: "photograph";
260
+ postalAddress: "postalAddress";
261
+ protected: "protected";
262
+ residency: "residency";
263
+ }>>>;
264
+ surfaces: z.ZodDefault<z.ZodArray<z.ZodEnum<{
265
+ ai: "ai";
266
+ mcp: "mcp";
267
+ ui: "ui";
268
+ }>>>;
269
+ }, z.core.$strict>>>;
270
+ oauthProtectedResource: z.ZodOptional<z.ZodString>;
271
+ }, z.core.$strict>, z.ZodObject<{
272
+ id: z.ZodString;
273
+ version: z.ZodString;
274
+ name: z.ZodObject<{
275
+ sv: z.ZodString;
276
+ en: z.ZodString;
277
+ }, z.core.$strict>;
278
+ description: z.ZodObject<{
279
+ sv: z.ZodString;
280
+ en: z.ZodString;
281
+ }, z.core.$strict>;
282
+ artifact: z.ZodObject<{
283
+ url: z.ZodString;
284
+ sha512: z.ZodString;
285
+ bytes: z.ZodOptional<z.ZodInt>;
286
+ }, z.core.$strict>;
287
+ homepage: z.ZodOptional<z.ZodString>;
288
+ deprecated: z.ZodDefault<z.ZodBoolean>;
289
+ type: z.ZodLiteral<"theme">;
290
+ contract: z.ZodOptional<z.ZodString>;
291
+ extends: z.ZodOptional<z.ZodString>;
292
+ }, z.core.$strict>], "type">>;
293
+ }, z.core.$strict>;
294
+ export type Catalog = z.infer<typeof catalogSchema>;
295
+ export type CatalogParseResult = {
296
+ ok: true;
297
+ value: Catalog;
298
+ } | {
299
+ ok: false;
300
+ issues: readonly string[];
301
+ };
302
+ /**
303
+ * Parses a catalog index.
304
+ *
305
+ * A single malformed entry rejects the whole index rather than being dropped
306
+ * quietly. A board that installs from a catalog which silently lost an entry
307
+ * has no way to tell that from an entry that was delisted on purpose, and the
308
+ * two mean opposite things.
309
+ *
310
+ * Returns a result rather than throwing, as `parsePluginPackage` does, so a
311
+ * catalog's own check can list every problem at once.
312
+ */
313
+ export declare function parseCatalogIndex(input: unknown): CatalogParseResult;
314
+ export {};
315
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAqDxB,uDAAuD;AACvD,eAAO,MAAM,qBAAqB;;;;kBAyBhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,2EAA2E;AAC3E,QAAA,MAAM,mBAAmB;;;kBAGvB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAmBhE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6CnC,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;kBAMlC,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAG7B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA0BtB,CAAC;AAEL,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,MAAM,MAAM,kBAAkB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE1E;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAWpE"}
@@ -0,0 +1,203 @@
1
+ import { z } from "zod";
2
+ import { IntegrityError, parseSha512 } from "./integrity.js";
3
+ import { declaredActionsSchema, pluginActionSchema, pluginIdSchema, pluginManifestSchema, } from "./manifest.js";
4
+ import { PLUGIN_PERMISSIONS, PLUGIN_PERSONAL_DATA_CATEGORIES, } from "./permissions.js";
5
+ /**
6
+ * The catalog index.
7
+ *
8
+ * One file listing everything an instance may install: plugins and themes
9
+ * alike, since both are distributed the same way and the board browses one
10
+ * screen per kind rather than one source per kind. Delisting is a commit
11
+ * against the index, which is why an instance re-reads it rather than caching
12
+ * it across installs.
13
+ *
14
+ * Exported so the index is checked by the same schema wherever it is read: by
15
+ * the instance before it offers an entry to a board, and by the catalog's own
16
+ * check before a listing is merged.
17
+ *
18
+ * Entries are parsed strictly. The index arrives over the network, and an
19
+ * entry the instance does not fully understand is an entry it must not offer
20
+ * to a board for consent - the consent screen's whole job is to say precisely
21
+ * what is being agreed to.
22
+ *
23
+ * Every object in it is strict as well: a field this version of the index does
24
+ * not define is refused, never dropped. Dropped, a misspelled field of the
25
+ * declaration would be replaced by its default before the consent screen or
26
+ * any check of the manifest saw it. The index carries its version for exactly
27
+ * this, so a new field is a new index version rather than a key an older
28
+ * instance ignores.
29
+ */
30
+ /** Whether `declared` is a digest `parseSha512` can read. */
31
+ function isReadableSha512(declared) {
32
+ try {
33
+ parseSha512(declared);
34
+ return true;
35
+ }
36
+ catch (error) {
37
+ if (error instanceof IntegrityError) {
38
+ return false;
39
+ }
40
+ throw error;
41
+ }
42
+ }
43
+ /** A tarball and the digest its bytes must hash to. */
44
+ export const catalogArtifactSchema = z.strictObject({
45
+ /**
46
+ * Direct URL.
47
+ *
48
+ * https on a curated instance, and nothing else: the shape is checked here
49
+ * but the destination is decided at fetch time, where http: and file: are
50
+ * refused unless the instance has opted out of curation. That is what keeps
51
+ * an entry - which is data fetched from elsewhere - from naming a `file:`
52
+ * path and having the instance read its own disk, or a plain-http address
53
+ * inside the network the instance sits in.
54
+ */
55
+ url: z.string().min(1).max(2000),
56
+ /**
57
+ * "sha512-<base64>" or 128 hex characters.
58
+ *
59
+ * Read through the same `parseSha512` the instance verifies a download with,
60
+ * so an entry the catalog's check lets through is one the instance can read,
61
+ * and an index with a badly spelled digest is refused by `parseCatalogIndex`
62
+ * alone.
63
+ */
64
+ sha512: z.string().min(1).max(200).refine(isReadableSha512, {
65
+ error: 'Expected a digest written as "sha512-<base64>" or 128 hex characters.',
66
+ }),
67
+ bytes: z.int().min(1).optional(),
68
+ });
69
+ /** Text a curator writes in both languages the interface is offered in. */
70
+ const localizedTextSchema = z.strictObject({
71
+ sv: z.string().min(1).max(500),
72
+ en: z.string().min(1).max(500),
73
+ });
74
+ /** Strict, and `.extend()` keeps it so for both kinds of entry. */
75
+ const baseEntrySchema = z.strictObject({
76
+ /**
77
+ * Unique across the whole index, whatever the entry's type: an install
78
+ * looks an entry up by id alone.
79
+ */
80
+ id: pluginIdSchema,
81
+ version: z.string().min(1).max(64),
82
+ /** The curator's text, in both languages the interface is offered in. */
83
+ name: localizedTextSchema,
84
+ description: localizedTextSchema,
85
+ artifact: catalogArtifactSchema,
86
+ homepage: z.string().max(2000).optional(),
87
+ /** Set on an entry that is still listed but should not be installed anew. */
88
+ deprecated: z.boolean().default(false),
89
+ });
90
+ export const catalogPluginEntrySchema = baseEntrySchema.extend({
91
+ type: z.literal("plugin"),
92
+ /**
93
+ * The npm package name the tarball unpacks as. Needed because the installer
94
+ * writes a dependency set for npm, which keys on the package name and not on
95
+ * the catalog id.
96
+ */
97
+ packageName: z.string().min(1).max(214),
98
+ /** Gated against the host's own contract version before an install starts. */
99
+ apiVersion: z.int().min(1),
100
+ /**
101
+ * Repeated from the plugin's manifest so the consent screen can be shown
102
+ * before anything is downloaded. The installed manifest is authoritative:
103
+ * the loader compares the two and refuses a plugin that asks for more than
104
+ * the board consented to.
105
+ */
106
+ permissions: z.array(z.enum(PLUGIN_PERMISSIONS)).max(16).default([]),
107
+ personalData: z
108
+ .array(z.enum(PLUGIN_PERSONAL_DATA_CATEGORIES))
109
+ .max(16)
110
+ .default([]),
111
+ /**
112
+ * The actions the plugin proposes, on the same terms as the two above.
113
+ *
114
+ * The widest part of the declaration, and so the part the consent screen
115
+ * most needs before anything is downloaded: an action names a capability and
116
+ * offers it to callers the board decides on.
117
+ *
118
+ * The manifest's own action fields and its own uniqueness rule, not a
119
+ * second array of the same thing: the rule on the ids has to hold at
120
+ * whichever boundary is read first, and two copies is two places for it to
121
+ * stop holding. Read strictly here, as everything in the index is.
122
+ */
123
+ actions: declaredActionsSchema(pluginActionSchema.strict()).default([]),
124
+ /**
125
+ * The route that serves MCP, repeated on the same terms as the three above.
126
+ *
127
+ * Both rules about it are decided before anything is downloaded - a second
128
+ * plugin declaring it is refused, and the reserved id `mcp-connector` may be
129
+ * taken only by a plugin that does declare it - so the index has to carry it.
130
+ * The manifest's own field schema rather than a second spelling of it: the
131
+ * value becomes a URL an unauthenticated caller is pointed at, and one
132
+ * definition of what it may contain is the point of that schema.
133
+ */
134
+ oauthProtectedResource: pluginManifestSchema.shape.oauthProtectedResource,
135
+ });
136
+ /**
137
+ * A theme entry. Themes install through the same download-and-verify path and
138
+ * are listed in the same index; what happens after the bytes are verified is
139
+ * the theme installer's business, not this schema's.
140
+ *
141
+ * No package name: a theme is data read out of its archive, never an npm
142
+ * package, and nothing that installs one keys on a package name.
143
+ */
144
+ export const catalogThemeEntrySchema = baseEntrySchema.extend({
145
+ type: z.literal("theme"),
146
+ /** The token contract range the theme was authored against. */
147
+ contract: z.string().min(1).max(64).optional(),
148
+ /** The theme it inherits from, as its manifest names it. */
149
+ extends: z.string().min(1).max(64).optional(),
150
+ });
151
+ export const catalogEntrySchema = z.discriminatedUnion("type", [
152
+ catalogPluginEntrySchema,
153
+ catalogThemeEntrySchema,
154
+ ]);
155
+ export const catalogSchema = z
156
+ .strictObject({
157
+ /** Index format version, so a future shape can be recognised and refused. */
158
+ version: z.literal(1),
159
+ entries: z.array(catalogEntrySchema).max(500),
160
+ })
161
+ .superRefine((catalog, ctx) => {
162
+ /*
163
+ * An id names one entry in the whole index, not one per type. An install
164
+ * finds its entry by id and then refuses one of the wrong type, so a theme
165
+ * sharing a plugin's id would leave that plugin impossible to install, and
166
+ * which of the two a board got would depend on the order of the file.
167
+ */
168
+ const firstIndexById = new Map();
169
+ for (const [index, entry] of catalog.entries.entries()) {
170
+ const first = firstIndexById.get(entry.id);
171
+ if (first === undefined) {
172
+ firstIndexById.set(entry.id, index);
173
+ continue;
174
+ }
175
+ ctx.addIssue({
176
+ code: "custom",
177
+ path: ["entries", index, "id"],
178
+ message: `"${entry.id}" is already the id of entry ${String(first)}; an id appears once in the index`,
179
+ });
180
+ }
181
+ });
182
+ /**
183
+ * Parses a catalog index.
184
+ *
185
+ * A single malformed entry rejects the whole index rather than being dropped
186
+ * quietly. A board that installs from a catalog which silently lost an entry
187
+ * has no way to tell that from an entry that was delisted on purpose, and the
188
+ * two mean opposite things.
189
+ *
190
+ * Returns a result rather than throwing, as `parsePluginPackage` does, so a
191
+ * catalog's own check can list every problem at once.
192
+ */
193
+ export function parseCatalogIndex(input) {
194
+ const result = catalogSchema.safeParse(input);
195
+ if (result.success) {
196
+ return { ok: true, value: result.data };
197
+ }
198
+ return {
199
+ ok: false,
200
+ issues: result.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`),
201
+ };
202
+ }
203
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { PluginModuleFactory } from "./module.ts";
2
+ /**
3
+ * Declares a plugin's server entry point.
4
+ *
5
+ * Deliberately an identity function. ADR 0003 requires a plugin to ship a
6
+ * prebuilt CJS bundle whose only externals are host packages, so anything
7
+ * this helper did at runtime would either have to be bundled into every
8
+ * plugin or would make the SDK a runtime dependency the host has to resolve
9
+ * for it. Being identity means a bundler inlines it to nothing and the value
10
+ * the helper adds - the type of the factory, checked at the author's build
11
+ * time - costs the running instance nothing.
12
+ */
13
+ export declare function definePlugin(factory: PluginModuleFactory): PluginModuleFactory;
14
+ //# sourceMappingURL=define-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-plugin.d.ts","sourceRoot":"","sources":["../src/define-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,CAErB"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Declares a plugin's server entry point.
3
+ *
4
+ * Deliberately an identity function. ADR 0003 requires a plugin to ship a
5
+ * prebuilt CJS bundle whose only externals are host packages, so anything
6
+ * this helper did at runtime would either have to be bundled into every
7
+ * plugin or would make the SDK a runtime dependency the host has to resolve
8
+ * for it. Being identity means a bundler inlines it to nothing and the value
9
+ * the helper adds - the type of the factory, checked at the author's build
10
+ * time - costs the running instance nothing.
11
+ */
12
+ export function definePlugin(factory) {
13
+ return factory;
14
+ }
15
+ //# sourceMappingURL=define-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-plugin.js","sourceRoot":"","sources":["../src/define-plugin.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAC1B,OAA4B;IAE5B,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Why a plugin on the data volume is not running.
3
+ *
4
+ * A finding travels as one of these codes plus the values its sentence needs,
5
+ * never as a sentence composed by the host. The interface is Swedish by
6
+ * default and this package is English, so what a board reads has to be a
7
+ * translation of the code: a sentence written where the finding is produced
8
+ * reaches the board panel in the language the server happens to be written in.
9
+ *
10
+ * Listed as values rather than as a bare union so a caller can walk them and
11
+ * prove it has a sentence for each. Part of the contract rather than an
12
+ * implementation detail - docs/plugin-contract.md lists the same set, and a
13
+ * plugin author reading why their package was skipped is reading one of these.
14
+ */
15
+ export declare const PLUGIN_FINDING_REASONS: readonly [
16
+ /** The `openbrf` field failed validation. */
17
+ "manifest-invalid",
18
+ /** Built against a contract version this instance does not implement. */
19
+ "api-version-unsupported",
20
+ /** A declared entry file is not in the package. */
21
+ "entry-missing",
22
+ /** The server bundle does not export `createPlugin`. */
23
+ "entry-invalid",
24
+ /** `createPlugin` returned no NestJS dynamic module. */
25
+ "module-invalid",
26
+ /** Its module declares behaviour a plugin may not register. */
27
+ "module-refused",
28
+ /** Its module could not be built into the application. */
29
+ "module-failed",
30
+ /** The package carries its own copy of a host package it must share. */
31
+ "module-identity",
32
+ /** It asks for more than was consented to. */
33
+ "permissions-widened",
34
+ /** It handles a personal-data category that was not consented to. */
35
+ "personal-data-widened",
36
+ /** On the volume with no record of consent. */
37
+ "not-consented",
38
+ /** Switched off in the admin interface. */
39
+ "disabled",
40
+ /** It threw while being loaded. */
41
+ "load-failed",
42
+ /** Recorded as installed but not present. */
43
+ "not-on-volume",
44
+ /** The installed version declares an action the board did not consent to. */
45
+ "actions-widened",
46
+ /** An action the manifest declares could not be registered. */
47
+ "action-refused",
48
+ /** One of its providers reaches for a core service a plugin may not hold. */
49
+ "forbidden-injection",
50
+ /**
51
+ * It declares the OAuth protected resource, and another installed plugin
52
+ * already does. The one installed first keeps it: the resource URL is the
53
+ * audience every issued token carries, so moving it would strand them all.
54
+ */
55
+ "oauth-resource-conflict"];
56
+ export type PluginFindingReason = (typeof PLUGIN_FINDING_REASONS)[number];
57
+ /**
58
+ * The values a finding's sentence is completed with.
59
+ *
60
+ * Identifiers, paths, numbers and what a thrown error said - never a sentence,
61
+ * and never personal data. A list stays a list rather than being joined here,
62
+ * because its members can have sentences of their own: a board told that a
63
+ * package handles a category it never agreed to has to read that category in
64
+ * its own language, not as `residency`.
65
+ */
66
+ export type PluginFindingDetail = Readonly<Record<string, string | number | readonly string[]>>;
67
+ //# sourceMappingURL=findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../src/findings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB;AACjC,6CAA6C;AAC7C,kBAAkB;AAClB,yEAAyE;AACzE,yBAAyB;AACzB,mDAAmD;AACnD,eAAe;AACf,wDAAwD;AACxD,eAAe;AACf,wDAAwD;AACxD,gBAAgB;AAChB,+DAA+D;AAC/D,gBAAgB;AAChB,0DAA0D;AAC1D,eAAe;AACf,wEAAwE;AACxE,iBAAiB;AACjB,8CAA8C;AAC9C,qBAAqB;AACrB,qEAAqE;AACrE,uBAAuB;AACvB,+CAA+C;AAC/C,eAAe;AACf,2CAA2C;AAC3C,UAAU;AACV,mCAAmC;AACnC,aAAa;AACb,6CAA6C;AAC7C,eAAe;AACf,6EAA6E;AAC7E,iBAAiB;AACjB,+DAA+D;AAC/D,gBAAgB;AAChB,6EAA6E;AAC7E,qBAAqB;AACrB;;;;GAIG;AACH,yBAAyB,CACjB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CACxC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CACpD,CAAC"}