@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,57 @@
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 const PLUGIN_FINDING_REASONS = [
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
+ ];
57
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../src/findings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,6CAA6C;IAC7C,kBAAkB;IAClB,yEAAyE;IACzE,yBAAyB;IACzB,mDAAmD;IACnD,eAAe;IACf,wDAAwD;IACxD,eAAe;IACf,wDAAwD;IACxD,gBAAgB;IAChB,+DAA+D;IAC/D,gBAAgB;IAChB,0DAA0D;IAC1D,eAAe;IACf,wEAAwE;IACxE,iBAAiB;IACjB,8CAA8C;IAC9C,qBAAqB;IACrB,qEAAqE;IACrE,uBAAuB;IACvB,+CAA+C;IAC/C,eAAe;IACf,2CAA2C;IAC3C,UAAU;IACV,mCAAmC;IACnC,aAAa;IACb,6CAA6C;IAC7C,eAAe;IACf,6EAA6E;IAC7E,iBAAiB;IACjB,+DAA+D;IAC/D,gBAAgB;IAChB,6EAA6E;IAC7E,qBAAqB;IACrB;;;;OAIG;IACH,yBAAyB;CACjB,CAAC"}
package/dist/host.d.ts ADDED
@@ -0,0 +1,208 @@
1
+ import type { PluginActions } from "./actions.ts";
2
+ import type { PluginPermission } from "./permissions.ts";
3
+ import type { PluginSettingsValues } from "./settings-schema.ts";
4
+ /**
5
+ * The host services a plugin receives.
6
+ *
7
+ * Every service is present on the object whether or not the plugin declared
8
+ * the permission it needs; the ones it did not declare throw
9
+ * PluginPermissionError on use. Handing out nulls instead would push a
10
+ * null-check into every call site of a plugin that did declare the permission,
11
+ * for the sake of a case the plugin author has already ruled out by writing
12
+ * the manifest. `permissions` is on the object for the plugin that genuinely
13
+ * wants to degrade rather than fail.
14
+ */
15
+ export declare class PluginPermissionError extends Error {
16
+ readonly pluginId: string;
17
+ readonly permission: PluginPermission;
18
+ constructor(pluginId: string, permission: PluginPermission);
19
+ }
20
+ /**
21
+ * Writes to the host's log, tagged with the plugin's id.
22
+ *
23
+ * A plugin must not reach for console: its output would be indistinguishable
24
+ * from the core's, and an operator reading a log needs to know which plugin
25
+ * produced a line before they can decide whether to disable it.
26
+ */
27
+ export interface PluginLogger {
28
+ debug(message: string): void;
29
+ info(message: string): void;
30
+ warn(message: string): void;
31
+ error(message: string, cause?: unknown): void;
32
+ }
33
+ /** The plugin's own settings, validated against its declared settingsSchema. */
34
+ export interface PluginSettings {
35
+ /**
36
+ * The stored values, with declared defaults applied. Reads the current
37
+ * values on each call rather than caching, so a change made in the admin
38
+ * interface reaches a long-running job without a restart.
39
+ */
40
+ read(): Promise<PluginSettingsValues>;
41
+ }
42
+ export interface PluginMailMessage {
43
+ to: string;
44
+ subject: string;
45
+ /**
46
+ * The body, as text.
47
+ *
48
+ * Blank lines separate paragraphs; the host renders them in the house style
49
+ * and escapes them. There is no markup parameter, and that is the point: a
50
+ * message sent here leaves under the cooperative's own address and passes
51
+ * its DKIM signature, so a link, an image or a styled block a plugin put in
52
+ * it would be a link, an image or a styled block the cooperative appears to
53
+ * have written. A plugin that interpolates a resident's own text into a
54
+ * body - the ordinary case, and the one that actually happens - cannot turn
55
+ * it into markup from here.
56
+ */
57
+ text: string;
58
+ }
59
+ /**
60
+ * Sends mail through the instance's configured SMTP server.
61
+ *
62
+ * The from address is the instance's and is not a parameter: mail from a
63
+ * housing cooperative's system has to be attributable to the cooperative.
64
+ * Requires the mail:send permission.
65
+ */
66
+ export interface PluginMail {
67
+ send(message: PluginMailMessage): Promise<void>;
68
+ }
69
+ export interface PluginSmsMessage {
70
+ /** The recipient's number in E.164 form. */
71
+ to: string;
72
+ /**
73
+ * The whole message, as text.
74
+ *
75
+ * SMS carries no markup, no subject and no alternative part, so what is
76
+ * written here is literally what the recipient reads. Its length is the
77
+ * plugin's own decision and is not bounded by the host: a text message is
78
+ * billed by length, and what a message may cost the association is the
79
+ * plugin's business to keep in hand rather than something a silent
80
+ * truncation can settle.
81
+ */
82
+ text: string;
83
+ }
84
+ /**
85
+ * Sends text messages through the instance's configured SMS provider.
86
+ *
87
+ * The sender the message presents is the instance's and is not a parameter,
88
+ * for the reason the mail from address is not one: a text message from a
89
+ * housing cooperative's system has to be attributable to the cooperative.
90
+ *
91
+ * An instance with no provider configured cannot send at all, and the send
92
+ * fails rather than being dropped. Having no provider is the ordinary state of
93
+ * a housing cooperative that only ever mails its members, so a plugin whose
94
+ * work depends on SMS should read `permissions` and degrade, or treat the
95
+ * failure as the answer. Requires the sms:send permission.
96
+ */
97
+ export interface PluginSms {
98
+ send(message: PluginSmsMessage): Promise<void>;
99
+ }
100
+ /**
101
+ * Background work. Queue names are namespaced with the plugin's id by the
102
+ * host, so two plugins cannot collide on a name and no plugin can subscribe to
103
+ * a core queue. A name is 1-64 letters, digits, `_`, `.` or `-`; any other
104
+ * name is refused with a RangeError. Requires the jobs:schedule permission.
105
+ */
106
+ export interface PluginJobs {
107
+ work<Data extends object>(name: string, handler: (data: Data) => Promise<void> | void): Promise<void>;
108
+ send<Data extends object>(name: string, data: Data): Promise<void>;
109
+ sendAt<Data extends object>(name: string, data: Data, runAt: Date): Promise<void>;
110
+ schedule<Data extends object>(name: string, cron: string, data: Data): Promise<void>;
111
+ }
112
+ export interface PluginApartment {
113
+ id: string;
114
+ number: string;
115
+ floor: number | null;
116
+ address: {
117
+ id: string;
118
+ street: string;
119
+ number: string;
120
+ };
121
+ }
122
+ export interface PluginResident {
123
+ personId: string;
124
+ name: string;
125
+ /** MEMBER holds the tenant-ownership; RESIDENT occupies without holding it. */
126
+ role: "MEMBER" | "RESIDENT";
127
+ apartment: PluginApartment | null;
128
+ movedInOn: string | null;
129
+ movedOutOn: string | null;
130
+ /** Present only with the addressBook:readContact permission. */
131
+ email?: string | null;
132
+ /** Present only with the addressBook:readContact permission. */
133
+ phone?: string | null;
134
+ }
135
+ export interface PluginOccupancySummary {
136
+ apartments: number;
137
+ /** Distinct persons with a current residency. */
138
+ residents: number;
139
+ /** Distinct persons holding a current tenant-ownership. */
140
+ members: number;
141
+ }
142
+ /**
143
+ * Reading the register, scoped to what the plugin declared.
144
+ *
145
+ * Three rules hold on every method here regardless of permission, because
146
+ * they are the product's own (plan section 4.4) and a plugin is not a reason
147
+ * to relax them: a person with protected personal data never appears, a
148
+ * personal identity number is never returned, and nothing is writable.
149
+ * Requires addressBook:read; the contact fields additionally require
150
+ * addressBook:readContact.
151
+ */
152
+ export interface PluginAddressBook {
153
+ apartments(): Promise<PluginApartment[]>;
154
+ /** Current residencies only. Moved-out rows are not plugin business. */
155
+ residents(): Promise<PluginResident[]>;
156
+ summary(): Promise<PluginOccupancySummary>;
157
+ }
158
+ /**
159
+ * The host object a plugin's module factory receives.
160
+ *
161
+ * It is late-bound: the services behind it are the application's own, and the
162
+ * application is built after the factory has run. Every member below is
163
+ * therefore usable from a lifecycle hook (`onModuleInit` onwards), a guard or
164
+ * a request handler, and not from a provider's constructor - which is where
165
+ * NestJS asks for work to be done in any case. A call made too early throws
166
+ * rather than reading a half-built application.
167
+ *
168
+ * A plugin the board has switched off keeps its object, and every service on
169
+ * it refuses. Disabling has to bite immediately, and a plugin whose own timer
170
+ * outlived the switch must not still be reading the register through it.
171
+ */
172
+ export interface PluginHost {
173
+ /** The plugin's own id, as declared in its manifest. */
174
+ id: string;
175
+ /** What the manifest declared and the board consented to. */
176
+ permissions: readonly PluginPermission[];
177
+ logger: PluginLogger;
178
+ settings: PluginSettings;
179
+ mail: PluginMail;
180
+ sms: PluginSms;
181
+ jobs: PluginJobs;
182
+ addressBook: PluginAddressBook;
183
+ /**
184
+ * The actions this plugin declared, and dispatch for every action it may
185
+ * reach.
186
+ *
187
+ * Added after this contract version shipped, so a plugin built against a
188
+ * newer host than the one it is installed on must feature-detect before
189
+ * using it - `isSupportedApiVersion` cannot see a member added to an
190
+ * interface, and the failure would otherwise surface as a load-failed
191
+ * finding with the message deliberately withheld.
192
+ */
193
+ actions: PluginActions;
194
+ }
195
+ /**
196
+ * A host service was used before the application finished starting, or after
197
+ * the plugin stopped serving.
198
+ *
199
+ * Both cases are the plugin reaching for the host at a moment the host cannot
200
+ * answer for: the first is work done in a constructor that belongs in
201
+ * `onModuleInit`, the second is a plugin the board switched off.
202
+ */
203
+ export declare class PluginHostUnavailableError extends Error {
204
+ readonly pluginId: string;
205
+ readonly detail: string;
206
+ constructor(pluginId: string, detail: string);
207
+ }
208
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
package/dist/host.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The host services a plugin receives.
3
+ *
4
+ * Every service is present on the object whether or not the plugin declared
5
+ * the permission it needs; the ones it did not declare throw
6
+ * PluginPermissionError on use. Handing out nulls instead would push a
7
+ * null-check into every call site of a plugin that did declare the permission,
8
+ * for the sake of a case the plugin author has already ruled out by writing
9
+ * the manifest. `permissions` is on the object for the plugin that genuinely
10
+ * wants to degrade rather than fail.
11
+ */
12
+ export class PluginPermissionError extends Error {
13
+ pluginId;
14
+ permission;
15
+ constructor(pluginId, permission) {
16
+ super(`Plugin "${pluginId}" used a service requiring the "${permission}" ` +
17
+ `permission, which its manifest does not declare.`);
18
+ this.pluginId = pluginId;
19
+ this.permission = permission;
20
+ this.name = "PluginPermissionError";
21
+ }
22
+ }
23
+ /**
24
+ * A host service was used before the application finished starting, or after
25
+ * the plugin stopped serving.
26
+ *
27
+ * Both cases are the plugin reaching for the host at a moment the host cannot
28
+ * answer for: the first is work done in a constructor that belongs in
29
+ * `onModuleInit`, the second is a plugin the board switched off.
30
+ */
31
+ export class PluginHostUnavailableError extends Error {
32
+ pluginId;
33
+ detail;
34
+ constructor(pluginId, detail) {
35
+ super(`Plugin "${pluginId}" used a host service ${detail}`);
36
+ this.pluginId = pluginId;
37
+ this.detail = detail;
38
+ this.name = "PluginHostUnavailableError";
39
+ }
40
+ }
41
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAEnC,QAAQ;IACR,UAAU;IAFrB,YACW,QAAgB,EAChB,UAA4B;QAErC,KAAK,CACH,WAAW,QAAQ,mCAAmC,UAAU,IAAI;YAClE,kDAAkD,CACrD,CAAC;wBANO,QAAQ;0BACR,UAAU;QAMnB,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAoMD;;;;;;;GAOG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAExC,QAAQ;IACR,MAAM;IAFjB,YACW,QAAgB,EAChB,MAAc;QAEvB,KAAK,CAAC,WAAW,QAAQ,yBAAyB,MAAM,EAAE,CAAC,CAAC;wBAHnD,QAAQ;sBACR,MAAM;QAGf,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @openbrf/plugin-sdk - the public plugin contract for Open BRF.
3
+ *
4
+ * A plugin depends on this package for types and for the manifest schema it
5
+ * validates itself against in its own CI. At runtime the host injects
6
+ * everything a plugin uses (see PluginHost), so nothing exported here needs to
7
+ * be resolvable from inside an installed plugin directory - which is what lets
8
+ * a plugin ship as a self-contained bundle (ADR 0003).
9
+ */
10
+ export { ACTION_CHANNELS, ACTION_EFFECTS, ACTION_NAME_PATTERN, ACTION_PERSONAL_DATA, ACTION_SURFACES, type ActionChannel, type ActionClient, type ActionContext, type ActionDefinition, type ActionEffect, type ActionErrorSpec, type ActionPersonalData, type ActionPrincipal, type ActionRequest, type ActionSummary, type ActionSurface, type PluginActionFilter, type PluginActionRegistration, type PluginActions, } from "./actions.ts";
11
+ export { actionInputJsonSchema, actionOutputJsonSchema, isHostZodSchema, } from "./action-schema.ts";
12
+ export { isSupportedApiVersion, PLUGIN_API_VERSION, SUPPORTED_PLUGIN_API_VERSIONS, } from "./api-version.ts";
13
+ export { type Catalog, type CatalogArtifact, catalogArtifactSchema, type CatalogEntry, catalogEntrySchema, type CatalogParseResult, type CatalogPluginEntry, catalogPluginEntrySchema, catalogSchema, type CatalogThemeEntry, catalogThemeEntrySchema, type LocalizedText, parseCatalogIndex, } from "./catalog.ts";
14
+ export { definePlugin } from "./define-plugin.ts";
15
+ export { formatSha512, IntegrityError, parseSha512 } from "./integrity.ts";
16
+ export { PLUGIN_FINDING_REASONS, type PluginFindingDetail, type PluginFindingReason, } from "./findings.ts";
17
+ export { type PluginAddressBook, type PluginApartment, type PluginHost, PluginHostUnavailableError, type PluginJobs, type PluginLogger, type PluginMail, type PluginMailMessage, type PluginOccupancySummary, PluginPermissionError, type PluginResident, type PluginSettings, type PluginSms, type PluginSmsMessage, } from "./host.ts";
18
+ export type { PluginModuleFactory } from "./module.ts";
19
+ export { assertPluginPackage, composedActionName, CURRENT_PLUGIN_API_VERSION, type ManifestParseResult, type PluginActionDeclaration, pluginActionSchema, pluginActionsSchema, type PluginEntry, pluginEntrySchema, pluginIdSchema, type PluginManifest, pluginManifestSchema, type PluginPackage, pluginPackageSchema, parsePluginPackage, } from "./manifest.ts";
20
+ export { HOST_SHARED_PACKAGES, type PluginPackageContents, pluginPackageProblems, } from "./package-check.ts";
21
+ export type { StandardSchemaIssue, StandardSchemaResult, StandardSchemaV1, } from "./standard-schema.ts";
22
+ export { isPluginPermission, PLUGIN_PERMISSIONS, PLUGIN_PERSONAL_DATA_CATEGORIES, type PluginPermission, type PluginPersonalDataCategory, } from "./permissions.ts";
23
+ export { defaultSettings, type PluginSettingsField, pluginSettingsFieldSchema, type PluginSettingsSchema, pluginSettingsSchema, type PluginSettingsValues, settingsValidator, } from "./settings-schema.ts";
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,YAAY,EACjB,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,wBAAwB,EACxB,aAAa,EACb,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,aAAa,EAClB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EACL,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,0BAA0B,EAC1B,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,gBAAgB,GACtB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,0BAA0B,EAC1B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,WAAW,EAChB,iBAAiB,EACjB,cAAc,EACd,KAAK,cAAc,EACnB,oBAAoB,EACpB,KAAK,aAAa,EAClB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,+BAA+B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,GAChC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,iBAAiB,GAClB,MAAM,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @openbrf/plugin-sdk - the public plugin contract for Open BRF.
3
+ *
4
+ * A plugin depends on this package for types and for the manifest schema it
5
+ * validates itself against in its own CI. At runtime the host injects
6
+ * everything a plugin uses (see PluginHost), so nothing exported here needs to
7
+ * be resolvable from inside an installed plugin directory - which is what lets
8
+ * a plugin ship as a self-contained bundle (ADR 0003).
9
+ */
10
+ export { ACTION_CHANNELS, ACTION_EFFECTS, ACTION_NAME_PATTERN, ACTION_PERSONAL_DATA, ACTION_SURFACES, } from "./actions.js";
11
+ export { actionInputJsonSchema, actionOutputJsonSchema, isHostZodSchema, } from "./action-schema.js";
12
+ export { isSupportedApiVersion, PLUGIN_API_VERSION, SUPPORTED_PLUGIN_API_VERSIONS, } from "./api-version.js";
13
+ export { catalogArtifactSchema, catalogEntrySchema, catalogPluginEntrySchema, catalogSchema, catalogThemeEntrySchema, parseCatalogIndex, } from "./catalog.js";
14
+ export { definePlugin } from "./define-plugin.js";
15
+ export { formatSha512, IntegrityError, parseSha512 } from "./integrity.js";
16
+ export { PLUGIN_FINDING_REASONS, } from "./findings.js";
17
+ export { PluginHostUnavailableError, PluginPermissionError, } from "./host.js";
18
+ export { assertPluginPackage, composedActionName, CURRENT_PLUGIN_API_VERSION, pluginActionSchema, pluginActionsSchema, pluginEntrySchema, pluginIdSchema, pluginManifestSchema, pluginPackageSchema, parsePluginPackage, } from "./manifest.js";
19
+ export { HOST_SHARED_PACKAGES, pluginPackageProblems, } from "./package-check.js";
20
+ export { isPluginPermission, PLUGIN_PERMISSIONS, PLUGIN_PERSONAL_DATA_CATEGORIES, } from "./permissions.js";
21
+ export { defaultSettings, pluginSettingsFieldSchema, pluginSettingsSchema, settingsValidator, } from "./settings-schema.js";
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,GAehB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAGL,qBAAqB,EAErB,kBAAkB,EAGlB,wBAAwB,EACxB,aAAa,EAEb,uBAAuB,EAEvB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EACL,sBAAsB,GAGvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAIL,0BAA0B,EAM1B,qBAAqB,GAKtB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,0BAA0B,EAG1B,kBAAkB,EAClB,mBAAmB,EAEnB,iBAAiB,EACjB,cAAc,EAEd,oBAAoB,EAEpB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EAEpB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,+BAA+B,GAGhC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,eAAe,EAEf,yBAAyB,EAEzB,oBAAoB,EAEpB,iBAAiB,GAClB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * How a catalog entry spells the sha512 digest of its tarball.
3
+ *
4
+ * The instance verifies the digest before it unpacks a download, and the
5
+ * catalog's own check verifies it before a listing is merged. Both must accept
6
+ * exactly the same spellings, or the catalog passes an entry the instance then
7
+ * refuses. So the parsing lives here, in the contract both depend on, and
8
+ * nowhere else.
9
+ *
10
+ * Written without `Buffer` or `node:crypto`: this package is also bundled into
11
+ * apps/web, a browser, where neither exists, and hashing itself stays with the
12
+ * caller. Base64 is decoded by hand rather than with `atob` so that padding and
13
+ * stray trailing bits are read as `Buffer` reads them, whatever the runtime.
14
+ */
15
+ /**
16
+ * Why a digest was refused. `malformed-digest` is a catalog entry that is
17
+ * written wrongly; `digest-mismatch` is bytes that are not the ones the entry
18
+ * names. Installers branch on the difference.
19
+ */
20
+ export declare class IntegrityError extends Error {
21
+ readonly reason: "malformed-digest" | "digest-mismatch";
22
+ constructor(message: string, reason: "malformed-digest" | "digest-mismatch");
23
+ }
24
+ /**
25
+ * Normalizes a declared digest to raw bytes.
26
+ *
27
+ * Both spellings are accepted because both are what a publisher actually has
28
+ * to hand: `npm pack --json` reports the subresource-integrity form
29
+ * (`sha512-<base64>`), while `sha512sum` prints hex. Requiring one would mean
30
+ * every catalog entry is transcribed by hand from the other, which is how a
31
+ * digest ends up wrong in a way nobody notices until an install fails.
32
+ *
33
+ * @throws IntegrityError with reason `malformed-digest`.
34
+ */
35
+ export declare function parseSha512(declared: string): Uint8Array;
36
+ /** The subresource-integrity spelling, which is what a catalog entry carries. */
37
+ export declare function formatSha512(digest: Uint8Array): string;
38
+ //# sourceMappingURL=integrity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.d.ts","sourceRoot":"","sources":["../src/integrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,KAAK;IAGrC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,iBAAiB;IAFzD,YACE,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,kBAAkB,GAAG,iBAAiB,EAIxD;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAuBxD;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * How a catalog entry spells the sha512 digest of its tarball.
3
+ *
4
+ * The instance verifies the digest before it unpacks a download, and the
5
+ * catalog's own check verifies it before a listing is merged. Both must accept
6
+ * exactly the same spellings, or the catalog passes an entry the instance then
7
+ * refuses. So the parsing lives here, in the contract both depend on, and
8
+ * nowhere else.
9
+ *
10
+ * Written without `Buffer` or `node:crypto`: this package is also bundled into
11
+ * apps/web, a browser, where neither exists, and hashing itself stays with the
12
+ * caller. Base64 is decoded by hand rather than with `atob` so that padding and
13
+ * stray trailing bits are read as `Buffer` reads them, whatever the runtime.
14
+ */
15
+ const SRI_PATTERN = /^sha512-([A-Za-z0-9+/]+)={0,2}$/;
16
+ const HEX_PATTERN = /^[0-9a-f]{128}$/i;
17
+ const SHA512_BYTES = 64;
18
+ const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
19
+ /**
20
+ * Why a digest was refused. `malformed-digest` is a catalog entry that is
21
+ * written wrongly; `digest-mismatch` is bytes that are not the ones the entry
22
+ * names. Installers branch on the difference.
23
+ */
24
+ export class IntegrityError extends Error {
25
+ reason;
26
+ constructor(message, reason) {
27
+ super(message);
28
+ this.reason = reason;
29
+ this.name = "IntegrityError";
30
+ }
31
+ }
32
+ /**
33
+ * Normalizes a declared digest to raw bytes.
34
+ *
35
+ * Both spellings are accepted because both are what a publisher actually has
36
+ * to hand: `npm pack --json` reports the subresource-integrity form
37
+ * (`sha512-<base64>`), while `sha512sum` prints hex. Requiring one would mean
38
+ * every catalog entry is transcribed by hand from the other, which is how a
39
+ * digest ends up wrong in a way nobody notices until an install fails.
40
+ *
41
+ * @throws IntegrityError with reason `malformed-digest`.
42
+ */
43
+ export function parseSha512(declared) {
44
+ const trimmed = declared.trim();
45
+ const sri = SRI_PATTERN.exec(trimmed);
46
+ if (sri !== null) {
47
+ const bytes = fromBase64(sri[1] ?? "");
48
+ if (bytes.length !== SHA512_BYTES) {
49
+ throw new IntegrityError("A sha512 digest is 64 bytes; this one is not.", "malformed-digest");
50
+ }
51
+ return bytes;
52
+ }
53
+ if (HEX_PATTERN.test(trimmed)) {
54
+ return fromHex(trimmed);
55
+ }
56
+ throw new IntegrityError('Expected a digest written as "sha512-<base64>" or 128 hex characters.', "malformed-digest");
57
+ }
58
+ /** The subresource-integrity spelling, which is what a catalog entry carries. */
59
+ export function formatSha512(digest) {
60
+ return `sha512-${toBase64(digest)}`;
61
+ }
62
+ function fromHex(hex) {
63
+ const bytes = new Uint8Array(hex.length / 2);
64
+ for (let index = 0; index < bytes.length; index += 1) {
65
+ bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
66
+ }
67
+ return bytes;
68
+ }
69
+ /**
70
+ * Standard base64 without its padding, which the caller has already split off.
71
+ * Stray trailing bits are dropped, as `Buffer.from(_, "base64")` drops them.
72
+ */
73
+ function fromBase64(characters) {
74
+ const bytes = new Uint8Array(Math.floor((characters.length * 6) / 8));
75
+ let accumulator = 0;
76
+ let bits = 0;
77
+ let written = 0;
78
+ for (const character of characters) {
79
+ accumulator = (accumulator << 6) | BASE64_ALPHABET.indexOf(character);
80
+ bits += 6;
81
+ if (bits >= 8) {
82
+ bits -= 8;
83
+ bytes[written] = (accumulator >> bits) & 0xff;
84
+ written += 1;
85
+ accumulator &= (1 << bits) - 1;
86
+ }
87
+ }
88
+ return bytes;
89
+ }
90
+ function toBase64(bytes) {
91
+ let encoded = "";
92
+ for (let index = 0; index < bytes.length; index += 3) {
93
+ const first = bytes[index] ?? 0;
94
+ const second = bytes[index + 1] ?? 0;
95
+ const third = bytes[index + 2] ?? 0;
96
+ const group = (first << 16) | (second << 8) | third;
97
+ const remaining = bytes.length - index;
98
+ encoded += BASE64_ALPHABET.charAt((group >> 18) & 63);
99
+ encoded += BASE64_ALPHABET.charAt((group >> 12) & 63);
100
+ encoded += remaining > 1 ? BASE64_ALPHABET.charAt((group >> 6) & 63) : "=";
101
+ encoded += remaining > 2 ? BASE64_ALPHABET.charAt(group & 63) : "=";
102
+ }
103
+ return encoded;
104
+ }
105
+ //# sourceMappingURL=integrity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.js","sourceRoot":"","sources":["../src/integrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,GAAG,iCAAiC,CAAC;AACtD,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAEvC,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,eAAe,GACnB,kEAAkE,CAAC;AAErE;;;;GAIG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;IAG5B,MAAM;IAFjB,YACE,OAAe,EACN,MAA8C;QAEvD,KAAK,CAAC,OAAO,CAAC,CAAC;sBAFN,MAAM;QAGf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEhC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACvC,IAAI,KAAK,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;YAClC,MAAM,IAAI,cAAc,CACtB,+CAA+C,EAC/C,kBAAkB,CACnB,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,IAAI,cAAc,CACtB,uEAAuE,EACvE,kBAAkB,CACnB,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,YAAY,CAAC,MAAkB;IAC7C,OAAO,UAAU,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,UAAkB;IACpC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtE,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,WAAW,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACtE,IAAI,IAAI,CAAC,CAAC;QACV,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,CAAC;YACV,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC;YAC9C,OAAO,IAAI,CAAC,CAAC;YACb,WAAW,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAiB;IACjC,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;QACpD,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;QAEvC,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QACtD,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QACtD,OAAO,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC3E,OAAO,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACtE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}