@openbrf/plugin-sdk 1.2.0 → 1.4.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.
package/src/catalog.ts CHANGED
@@ -5,6 +5,8 @@ import { IntegrityError, parseSha512 } from "./integrity.ts";
5
5
  import { localizedTextSchema } from "./localized-text.ts";
6
6
  import {
7
7
  declaredActionsSchema,
8
+ missingProcessingProblem,
9
+ undeclaredPersonalDataProblem,
8
10
  declaredExtensionPointsSchema,
9
11
  declaredExtensionsSchema,
10
12
  extensionGroupRefusals,
@@ -21,6 +23,7 @@ import {
21
23
  pluginDeviceRouteSchema,
22
24
  pluginIdSchema,
23
25
  pluginManifestSchema,
26
+ pluginProcessingSchema,
24
27
  proposeImportPersonalDataIssues,
25
28
  } from "./manifest.ts";
26
29
  import {
@@ -57,6 +60,12 @@ import {
57
60
  * any check of the manifest saw it. The index carries its version for exactly
58
61
  * this, so a new field is a new index version rather than a key an older
59
62
  * instance ignores.
63
+ *
64
+ * An instance reads both versions there are. Version 2 adds the device routes
65
+ * of ADR 0031 and the processing declaration of ADR 0035 to a plugin entry, and
66
+ * the other fields of ADR 0030 join them there as they are built; version 1 is
67
+ * the index as it stood before, which a catalog keeps serving to instances that
68
+ * read nothing newer.
60
69
  */
61
70
 
62
71
  /** Whether `declared` is a digest `parseSha512` can read. */
@@ -275,6 +284,20 @@ export const catalogPluginEntrySchema = baseEntrySchema
275
284
  }
276
285
  });
277
286
 
287
+ /**
288
+ * A plugin entry in version 2 of the index: version 1's, and the processing
289
+ * declaration.
290
+ *
291
+ * Repeated from the manifest on the terms the permissions are, because the
292
+ * consent screen shows it before anything is downloaded and the install seeds
293
+ * the record of processing activities from what that screen showed. Whether it
294
+ * is there is decided with the personal data, by the index as a whole below,
295
+ * since a refined object cannot be extended into the next version's entry.
296
+ */
297
+ export const catalogPluginEntryV2Schema = catalogPluginEntrySchema.extend({
298
+ processing: pluginProcessingSchema.optional(),
299
+ });
300
+
278
301
  /**
279
302
  * A theme entry. Themes install through the same download-and-verify path and
280
303
  * are listed in the same index; what happens after the bytes are verified is
@@ -296,27 +319,181 @@ export const catalogEntrySchema = z.discriminatedUnion("type", [
296
319
  catalogThemeEntrySchema,
297
320
  ]);
298
321
 
299
- export type CatalogPluginEntry = z.infer<typeof catalogPluginEntrySchema>;
300
- export type CatalogThemeEntry = z.infer<typeof catalogThemeEntrySchema>;
301
- export type CatalogEntry = z.infer<typeof catalogEntrySchema>;
322
+ export const catalogEntryV2Schema = z.discriminatedUnion("type", [
323
+ catalogPluginEntryV2Schema,
324
+ catalogThemeEntrySchema,
325
+ ]);
302
326
 
303
327
  /**
304
- * The index versions this package reads.
305
- *
306
- * Version 2 adds the fields ADR 0030 lists: `extensionPoints` and `extends`
307
- * (ADR 0030), `recipients` (ADR 0037) and `deviceRoutes` (ADR 0031). An
308
- * instance reads both, and the catalog serves version 1, without the entries
309
- * that need version 2, to instances that have not upgraded.
328
+ * A plugin entry, as whichever version of the index it came from. A version 1
329
+ * entry is one with no processing and no device routes declared.
310
330
  */
311
- export const CATALOG_INDEX_VERSIONS = [1, 2] as const;
331
+ export type CatalogPluginEntry = z.infer<typeof catalogPluginEntryV2Schema>;
332
+ export type CatalogThemeEntry = z.infer<typeof catalogThemeEntrySchema>;
333
+ export type CatalogEntry = CatalogPluginEntry | CatalogThemeEntry;
334
+
335
+ /** The index's rules about its entries taken together, in either version. */
336
+ function checkEntries(
337
+ catalog: { version: 1 | 2; entries: readonly CatalogEntry[] },
338
+ ctx: z.RefinementCtx,
339
+ ): void {
340
+ for (const [index, entry] of catalog.entries.entries()) {
341
+ if (entry.type !== "plugin") {
342
+ continue;
343
+ }
344
+ // The manifest's rule, so an entry the loader would refuse is never
345
+ // offered for consent.
346
+ for (const issue of proposeImportPersonalDataIssues(entry)) {
347
+ ctx.addIssue({
348
+ code: "custom",
349
+ path: ["entries", index, "personalData"],
350
+ message: issue.message,
351
+ });
352
+ }
353
+ }
312
354
 
313
- export const catalogSchema = z
355
+ for (const [index, entry] of catalog.entries.entries()) {
356
+ if (entry.type !== "plugin") {
357
+ continue;
358
+ }
359
+ /*
360
+ * A field version 1 does not define is refused there as any unknown key
361
+ * is, so an older instance and this one read the same index the same
362
+ * way.
363
+ */
364
+ if (catalog.version === 1) {
365
+ for (const field of [
366
+ "extensionPoints",
367
+ "extends",
368
+ "deviceRoutes",
369
+ ] as const) {
370
+ if (entry[field] !== undefined) {
371
+ ctx.addIssue({
372
+ code: "custom",
373
+ path: ["entries", index, field],
374
+ message: `${field} needs version 2 of the index`,
375
+ });
376
+ }
377
+ }
378
+ continue;
379
+ }
380
+ // The manifest's own rules, so an entry whose own declaration breaks
381
+ // one is never offered for consent.
382
+ for (const issue of extensionRuleIssues({
383
+ id: entry.id,
384
+ permissions: entry.permissions,
385
+ personalData: entry.personalData,
386
+ deviceRoutes: entry.deviceRoutes ?? [],
387
+ extensionPoints: entry.extensionPoints ?? [],
388
+ extends: entry.extends ?? [],
389
+ })) {
390
+ ctx.addIssue({
391
+ code: "custom",
392
+ path: ["entries", index, ...issue.path],
393
+ message: issue.message,
394
+ });
395
+ }
396
+ // The manifest's own rules, so an entry that the loader would refuse is
397
+ // never offered for consent.
398
+ for (const issue of deviceRouteRuleIssues({
399
+ deviceRoutes: entry.deviceRoutes ?? [],
400
+ oauthProtectedResource: entry.oauthProtectedResource,
401
+ permissions: entry.permissions,
402
+ })) {
403
+ ctx.addIssue({
404
+ code: "custom",
405
+ path: ["entries", index, ...issue.path],
406
+ message: issue.message,
407
+ });
408
+ }
409
+ }
410
+
411
+ /*
412
+ * A field is in the version that defines it and in no earlier one: an
413
+ * instance that reads only version 1 would refuse the entry, and an index
414
+ * claiming version 1 while carrying it is not one such an instance could
415
+ * read.
416
+ */
417
+ if (catalog.version === 1) {
418
+ for (const [index, entry] of catalog.entries.entries()) {
419
+ if (entry.type === "plugin" && entry.recipients !== undefined) {
420
+ ctx.addIssue({
421
+ code: "custom",
422
+ path: ["entries", index, "recipients"],
423
+ message:
424
+ "recipients is not in version 1 of the index; an entry that declares them is listed in version 2",
425
+ });
426
+ }
427
+ }
428
+ }
429
+
430
+ /*
431
+ * The manifest's rule on what a recipient may receive, so an entry the
432
+ * loader would refuse is not offered for consent with a category the
433
+ * plugin does not declare it handles. The comparison with the installed
434
+ * manifest comes later; this holds the entry to itself.
435
+ */
436
+ for (const [index, entry] of catalog.entries.entries()) {
437
+ if (entry.type !== "plugin" || entry.recipients === undefined) {
438
+ continue;
439
+ }
440
+ for (const issue of recipientCategoryIssues(
441
+ entry.recipients,
442
+ entry.personalData,
443
+ )) {
444
+ ctx.addIssue({
445
+ code: "custom",
446
+ path: ["entries", index, ...issue.path],
447
+ message: issue.message,
448
+ });
449
+ }
450
+ }
451
+
452
+ /*
453
+ * An id names one entry in the whole index, not one per type. An install
454
+ * finds its entry by id and then refuses one of the wrong type, so a theme
455
+ * sharing a plugin's id would leave that plugin impossible to install, and
456
+ * which of the two a board got would depend on the order of the file.
457
+ */
458
+ const firstIndexById = new Map<string, number>();
459
+ for (const [index, entry] of catalog.entries.entries()) {
460
+ const first = firstIndexById.get(entry.id);
461
+ if (first === undefined) {
462
+ firstIndexById.set(entry.id, index);
463
+ continue;
464
+ }
465
+ ctx.addIssue({
466
+ code: "custom",
467
+ path: ["entries", index, "id"],
468
+ message: `"${entry.id}" is already the id of entry ${String(first)}; an id appears once in the index`,
469
+ });
470
+ }
471
+ }
472
+
473
+ const catalogV1Schema = z
314
474
  .strictObject({
315
475
  /** Index format version, so a future shape can be recognised and refused. */
316
- version: z.literal(CATALOG_INDEX_VERSIONS),
476
+ version: z.literal(1),
317
477
  entries: z.array(catalogEntrySchema).max(500),
318
478
  })
319
479
  .superRefine((catalog, ctx) => {
480
+ checkEntries(catalog, ctx);
481
+ });
482
+
483
+ const catalogV2Schema = z
484
+ .strictObject({
485
+ /**
486
+ * Version 2 adds the fields `CATALOG_INDEX_VERSIONS` lists to a plugin
487
+ * entry, `processing` (ADR 0035) among them, and changes nothing else.
488
+ * This package reads both versions; the catalog keeps serving version 1,
489
+ * without the entries that need version 2, to instances that have not
490
+ * upgraded.
491
+ */
492
+ version: z.literal(2),
493
+ entries: z.array(catalogEntryV2Schema).max(500),
494
+ })
495
+ .superRefine((catalog, ctx) => {
496
+ checkEntries(catalog, ctx);
320
497
  const plugins = new Map<string, CatalogPluginEntry>();
321
498
  const pluginIndex = new Map<string, number>();
322
499
  for (const [index, entry] of catalog.entries.entries()) {
@@ -327,64 +504,40 @@ export const catalogSchema = z
327
504
  }
328
505
  /** The addons already refused beside a plugin they extend. */
329
506
  const pairRefused = new Set<string>();
507
+ /*
508
+ * The manifest's own rule, both ways: an entry that declares personal data
509
+ * declares its processing, and one that declares none declares no
510
+ * processing. One that reads the address book declares personal data, so
511
+ * it has a processing a person can object to. Held here rather than only
512
+ * by the catalog's check of the package, so an index written by hand is
513
+ * held to it as well.
514
+ */
330
515
  for (const [index, entry] of catalog.entries.entries()) {
331
516
  if (entry.type !== "plugin") {
332
517
  continue;
333
518
  }
334
- // The manifest's rule, so an entry the loader would refuse is never
335
- // offered for consent.
336
- for (const issue of proposeImportPersonalDataIssues(entry)) {
519
+ const missing = missingProcessingProblem(entry);
520
+ if (missing !== null) {
337
521
  ctx.addIssue({
338
522
  code: "custom",
339
- path: ["entries", index, "personalData"],
340
- message: issue.message,
523
+ path: ["entries", index, "processing"],
524
+ message: missing,
341
525
  });
342
526
  }
343
- /*
344
- * A field version 1 does not define is refused there as any unknown key
345
- * is, so an older instance and this one read the same index the same
346
- * way.
347
- */
348
- if (catalog.version === 1) {
349
- for (const field of [
350
- "extensionPoints",
351
- "extends",
352
- "deviceRoutes",
353
- ] as const) {
354
- if (entry[field] !== undefined) {
355
- ctx.addIssue({
356
- code: "custom",
357
- path: ["entries", index, field],
358
- message: `${field} needs version 2 of the index`,
359
- });
360
- }
361
- }
362
- continue;
363
- }
364
- // The manifest's own rules, so an entry whose own declaration breaks
365
- // one is never offered for consent.
366
- for (const issue of extensionRuleIssues({
367
- id: entry.id,
368
- permissions: entry.permissions,
369
- personalData: entry.personalData,
370
- extensionPoints: entry.extensionPoints ?? [],
371
- extends: entry.extends ?? [],
372
- })) {
527
+ const undeclared = undeclaredPersonalDataProblem(entry);
528
+ if (undeclared !== null) {
373
529
  ctx.addIssue({
374
530
  code: "custom",
375
- path: ["entries", index, ...issue.path],
376
- message: issue.message,
531
+ path: ["entries", index, "personalData"],
532
+ message: undeclared,
377
533
  });
378
534
  }
379
- for (const issue of deviceRouteRuleIssues({
380
- deviceRoutes: entry.deviceRoutes ?? [],
381
- oauthProtectedResource: entry.oauthProtectedResource,
382
- permissions: entry.permissions,
383
- })) {
535
+ if (entry.processing !== undefined && entry.personalData.length === 0) {
384
536
  ctx.addIssue({
385
537
  code: "custom",
386
- path: ["entries", index, ...issue.path],
387
- message: issue.message,
538
+ path: ["entries", index, "processing"],
539
+ message:
540
+ "a plugin that declares no personal data declares no processing",
388
541
  });
389
542
  }
390
543
  /*
@@ -490,70 +643,32 @@ export const catalogSchema = z
490
643
  });
491
644
  }
492
645
  }
646
+ });
493
647
 
494
- /*
495
- * A field is in the version that defines it and in no earlier one: an
496
- * instance that reads only version 1 would refuse the entry, and an index
497
- * claiming version 1 while carrying it is not one such an instance could
498
- * read.
499
- */
500
- if (catalog.version === 1) {
501
- for (const [index, entry] of catalog.entries.entries()) {
502
- if (entry.type === "plugin" && entry.recipients !== undefined) {
503
- ctx.addIssue({
504
- code: "custom",
505
- path: ["entries", index, "recipients"],
506
- message:
507
- "recipients is not in version 1 of the index; an entry that declares them is listed in version 2",
508
- });
509
- }
510
- }
511
- }
648
+ /**
649
+ * The index versions this package reads.
650
+ *
651
+ * Version 2 adds the fields ADR 0030 lists: `extensionPoints` and `extends`
652
+ * (ADR 0030), `recipients` (ADR 0037) and `deviceRoutes` (ADR 0031), and
653
+ * `processing` (ADR 0035). An instance reads both, and the catalog serves
654
+ * version 1, without the entries that need version 2, to instances that have
655
+ * not upgraded.
656
+ */
657
+ export const CATALOG_INDEX_VERSIONS = [1, 2] as const;
512
658
 
513
- /*
514
- * The manifest's rule on what a recipient may receive, so an entry the
515
- * loader would refuse is not offered for consent with a category the
516
- * plugin does not declare it handles. The comparison with the installed
517
- * manifest comes later; this holds the entry to itself.
518
- */
519
- for (const [index, entry] of catalog.entries.entries()) {
520
- if (entry.type !== "plugin" || entry.recipients === undefined) {
521
- continue;
522
- }
523
- for (const issue of recipientCategoryIssues(
524
- entry.recipients,
525
- entry.personalData,
526
- )) {
527
- ctx.addIssue({
528
- code: "custom",
529
- path: ["entries", index, ...issue.path],
530
- message: issue.message,
531
- });
532
- }
533
- }
659
+ /** The version of the index this SDK writes and reads first. */
660
+ export const CATALOG_INDEX_VERSION = 2;
534
661
 
535
- /*
536
- * An id names one entry in the whole index, not one per type. An install
537
- * finds its entry by id and then refuses one of the wrong type, so a theme
538
- * sharing a plugin's id would leave that plugin impossible to install, and
539
- * which of the two a board got would depend on the order of the file.
540
- */
541
- const firstIndexById = new Map<string, number>();
542
- for (const [index, entry] of catalog.entries.entries()) {
543
- const first = firstIndexById.get(entry.id);
544
- if (first === undefined) {
545
- firstIndexById.set(entry.id, index);
546
- continue;
547
- }
548
- ctx.addIssue({
549
- code: "custom",
550
- path: ["entries", index, "id"],
551
- message: `"${entry.id}" is already the id of entry ${String(first)}; an id appears once in the index`,
552
- });
553
- }
554
- });
662
+ export const catalogSchema = z.discriminatedUnion("version", [
663
+ catalogV1Schema,
664
+ catalogV2Schema,
665
+ ]);
555
666
 
556
- export type Catalog = z.infer<typeof catalogSchema>;
667
+ /** An index of either version, read as one shape. */
668
+ export interface Catalog {
669
+ version: z.infer<typeof catalogSchema>["version"];
670
+ entries: CatalogEntry[];
671
+ }
557
672
 
558
673
  /**
559
674
  * The refusals of an index that its reader is told in their own language.
package/src/findings.ts CHANGED
@@ -158,6 +158,8 @@ export const PLUGIN_MANIFEST_RULES = [
158
158
  "device-route-proposes-import",
159
159
  /** A plugin with a website block also proposes imports. */
160
160
  "blocks-propose-import",
161
+ /** A plugin with a device route offers an extension point accepting contact details. */
162
+ "device-route-extension-point-contact",
161
163
  ] as const;
162
164
 
163
165
  export type PluginManifestRule = (typeof PLUGIN_MANIFEST_RULES)[number];
package/src/host.ts CHANGED
@@ -174,6 +174,12 @@ export interface PluginApartment {
174
174
  export interface PluginResident {
175
175
  personId: string;
176
176
  name: string;
177
+ /**
178
+ * The family name alone, for a reader that shows no first names: a household
179
+ * as the name on the door shows it, without the first names that say who
180
+ * lives alone and name the children.
181
+ */
182
+ lastName: string;
177
183
  /** MEMBER holds the tenant-ownership; RESIDENT occupies without holding it. */
178
184
  role: "MEMBER" | "RESIDENT";
179
185
  apartment: PluginApartment | null;
@@ -183,6 +189,22 @@ export interface PluginResident {
183
189
  email?: string | null;
184
190
  /** Present only with the addressBook:readContact permission. */
185
191
  phone?: string | null;
192
+ /**
193
+ * Whether a publication consent to the person's name on screens inside the
194
+ * building stands (the `NAME_IN_BUILDING` scope), recorded by the board on
195
+ * the person's panel like every other scope. A different consent from a name
196
+ * on the website, because the two are different things to agree to.
197
+ */
198
+ nameInBuilding: boolean;
199
+ }
200
+
201
+ /** Narrows a read of the residents. */
202
+ export interface PluginResidentFilter {
203
+ /**
204
+ * Only the residents of this entrance, so a plugin that shows one entrance
205
+ * never loads the others. An id no address has returns nobody.
206
+ */
207
+ addressId?: string;
186
208
  }
187
209
 
188
210
  export interface PluginOccupancySummary {
@@ -202,14 +224,76 @@ export interface PluginOccupancySummary {
202
224
  * personal identity number is never returned, and nothing is writable.
203
225
  * Requires addressBook:read; the contact fields additionally require
204
226
  * addressBook:readContact.
227
+ *
228
+ * A person who has objected to this plugin's processing, and whose objection
229
+ * the board granted, is absent as well (ADR 0035) - absent, not flagged, so a
230
+ * plugin cannot list who objected. Closing the objection brings the person
231
+ * back on the next read.
205
232
  */
206
233
  export interface PluginAddressBook {
207
234
  apartments(): Promise<PluginApartment[]>;
208
- /** Current residencies only. Moved-out rows are not plugin business. */
209
- residents(): Promise<PluginResident[]>;
235
+ /**
236
+ * Current residencies only. Moved-out rows are not plugin business.
237
+ *
238
+ * The filter was added after this contract version shipped; an older host
239
+ * ignores it and returns every entrance, so a plugin that must not load the
240
+ * others filters the result by `apartment.address.id` as well.
241
+ */
242
+ residents(filter?: PluginResidentFilter): Promise<PluginResident[]>;
210
243
  summary(): Promise<PluginOccupancySummary>;
211
244
  }
212
245
 
246
+ /** The bounds `host.audit.record` holds an entry to. */
247
+ export const PLUGIN_AUDIT_LIMITS = {
248
+ /** Characters in `event`, which is also part of a text key. */
249
+ event: 64,
250
+ /** Characters in `targetKind`. */
251
+ targetKind: 64,
252
+ /** Characters in `targetId`. */
253
+ targetId: 200,
254
+ /** Values in `detail`. */
255
+ detailValues: 8,
256
+ /** Characters in a key of `detail`, letters and digits. */
257
+ detailKey: 64,
258
+ /** Characters in a string value of `detail`. */
259
+ detailValue: 200,
260
+ } as const;
261
+
262
+ /** One entry a plugin writes to the instance's audit log. */
263
+ export interface PluginAuditEntry {
264
+ /**
265
+ * What happened, as lowercase letters, digits, dots and hyphens, starting
266
+ * with a letter: `screen.residents-enabled`. The audit log shows it through
267
+ * the plugin's own text key `audit.<event>`.
268
+ */
269
+ event: string;
270
+ /** What the act was done to, in the plugin's own words: `screen`. */
271
+ targetKind?: string;
272
+ /** Which one: the screen's id. */
273
+ targetId?: string;
274
+ /**
275
+ * At most eight values about the act, never a copy of what the plugin read.
276
+ * A key is letters and digits, starting with a letter: `screenCount`. A
277
+ * person is named as the actor, never here, and a key or value holding a
278
+ * personal identity number is refused.
279
+ */
280
+ detail?: Record<string, string | number | boolean>;
281
+ }
282
+
283
+ /**
284
+ * Writing to the instance's audit log (ADR 0035).
285
+ *
286
+ * The entry is written as `PLUGIN_RECORDED`, with the plugin's id and the
287
+ * event, on the plugin channel. With a request, the actor is the person the
288
+ * host marked on it, as for `actions`; with `null`, the entry has no actor - a
289
+ * plugin's own job, say. An entry that breaks a bound is refused with a
290
+ * RangeError and nothing is written. Needs no permission: an entry is about
291
+ * what the plugin did, which the association is entitled to a record of.
292
+ */
293
+ export interface PluginAudit {
294
+ record(request: ActionRequest | null, entry: PluginAuditEntry): Promise<void>;
295
+ }
296
+
213
297
  /** What a theme install is told about the package besides its bytes. */
214
298
  export interface PluginThemeInstallOptions {
215
299
  /**
@@ -306,6 +390,13 @@ export interface PluginNewsItem {
306
390
  readonly audience: PluginContentAudience;
307
391
  /** ISO 8601 instant. */
308
392
  readonly publishedAt: string;
393
+ /**
394
+ * Whether the board marked the item "show on screens": that it may be shown
395
+ * on a screen in the building (ADR 0050). Off until the board sets it. A
396
+ * plugin that puts items where anybody passing can read them shows only the
397
+ * marked ones.
398
+ */
399
+ readonly onScreens: boolean;
309
400
  }
310
401
 
311
402
  /**
@@ -358,6 +449,11 @@ export interface PluginOccurrence {
358
449
  */
359
450
  readonly placesLeft: number | null;
360
451
  readonly audience: PluginContentAudience;
452
+ /**
453
+ * Whether the board marked the event, with all its occurrences, "show on
454
+ * screens" (ADR 0050), as a news item's mark.
455
+ */
456
+ readonly onScreens: boolean;
361
457
  }
362
458
 
363
459
  /**
@@ -508,6 +604,12 @@ export interface PluginMediaFile {
508
604
  * picture's entity tag from, so a plugin may use it as one too.
509
605
  */
510
606
  readonly checksum: string;
607
+ /**
608
+ * Who the picture is for: `anyone`, or the `members`, as the board held it.
609
+ * The host does not filter for you, because it cannot know where you put it;
610
+ * see {@link PluginContentAudience}.
611
+ */
612
+ readonly audience: PluginContentAudience;
511
613
  /**
512
614
  * The picture's bytes. Read it to the end or cancel it: the host holds the
513
615
  * stored file open until one or the other.
@@ -799,6 +901,14 @@ export interface PluginHost {
799
901
  * before using it.
800
902
  */
801
903
  blocks: PluginBlocks;
904
+ /**
905
+ * The instance's audit log, for what this plugin did.
906
+ *
907
+ * Added after this contract version shipped, like `actions`: a plugin built
908
+ * against a newer host than the one it is installed on must feature-detect
909
+ * before using it.
910
+ */
911
+ audit: PluginAudit;
802
912
  /**
803
913
  * The extension points this plugin offers or extends (ADR 0030): a host
804
914
  * plugin defines its points and calls the addons serving there, and an
package/src/index.ts CHANGED
@@ -83,11 +83,14 @@ export {
83
83
  type CatalogDiagnostic,
84
84
  type CatalogEntry,
85
85
  catalogEntrySchema,
86
+ catalogEntryV2Schema,
87
+ CATALOG_INDEX_VERSION,
86
88
  type CatalogExtensionPoint,
87
89
  catalogExtensionPointSchema,
88
90
  type CatalogParseResult,
89
91
  type CatalogPluginEntry,
90
92
  catalogPluginEntrySchema,
93
+ catalogPluginEntryV2Schema,
91
94
  type CatalogRefusal,
92
95
  type CatalogRefusalCode,
93
96
  catalogSchema,
@@ -170,6 +173,9 @@ export {
170
173
  type PluginAddressBook,
171
174
  type PluginAddresses,
172
175
  type PluginApartment,
176
+ type PluginAudit,
177
+ type PluginAuditEntry,
178
+ PLUGIN_AUDIT_LIMITS,
173
179
  type PluginBookableResource,
174
180
  type PluginBookings,
175
181
  type PluginBusyInterval,
@@ -198,6 +204,7 @@ export {
198
204
  type PluginRecipientResponse,
199
205
  type PluginRecipients,
200
206
  type PluginResident,
207
+ type PluginResidentFilter,
201
208
  type PluginSettings,
202
209
  type PluginInstalledTheme,
203
210
  type PluginSms,
@@ -227,6 +234,11 @@ export {
227
234
  licenceKeyIdSchema,
228
235
  licencePublicKeySchema,
229
236
  type ManifestParseResult,
237
+ missingProcessingProblem,
238
+ readsAddressBook,
239
+ undeclaredPersonalDataProblem,
240
+ PLUGIN_DATA_SUBJECTS,
241
+ PLUGIN_LEGAL_BASES,
230
242
  type PluginActionDeclaration,
231
243
  pluginActionSchema,
232
244
  pluginActionsSchema,
@@ -240,12 +252,16 @@ export {
240
252
  pluginExtensionPointSchema,
241
253
  pluginExtensionSchema,
242
254
  pluginIdSchema,
255
+ type PluginDataSubject,
256
+ type PluginLegalBasis,
243
257
  type PluginLicenceDeclaration,
244
258
  pluginLicenceSchema,
245
259
  type PluginManifest,
246
260
  pluginManifestSchema,
247
261
  type PluginPackage,
248
262
  pluginPackageSchema,
263
+ type PluginProcessing,
264
+ pluginProcessingSchema,
249
265
  type PluginView,
250
266
  pluginViewSchema,
251
267
  type PluginViewSection,