@cervio/plugin-core 0.1.0 → 0.1.4

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/dist/index.d.cts CHANGED
@@ -1,92 +1,16 @@
1
- import JSZip from 'jszip';
1
+ import { P as PluginCervioApiRequirement, a as PluginEntityRequirement, b as PluginSettingsFieldRequirement, c as PluginConnectionRequirement, d as PluginActionResult, e as ParseManifestOptions, f as PluginType, g as ParsedPluginManifest } from './browser-CbWn_0Kk.cjs';
2
+ export { A as AllowedApiRule, D as DEFAULT_PLUGIN_DECLARABLE_CAPABILITIES, E as ExternalConnectionHttpMethod, M as MAX_PLUGIN_UNCOMPRESSED_BYTES, h as MAX_PLUGIN_ZIP_BYTES, i as MAX_PLUGIN_ZIP_ENTRIES, j as PLUGIN_ARTIFACT_BUCKET, k as PLUGIN_KEY_RE, l as PLUGIN_VERSION_SELECT, m as PluginEntityAccess, n as PluginSettingsFieldOption, o as PluginSettingsFieldType, p as PluginVersionRow, q as assertZipFile, r as assertZipSafe } from './browser-CbWn_0Kk.cjs';
2
3
  import { z } from 'zod';
3
-
4
- type PluginType = 'task' | 'form' | 'task_form' | 'route';
5
- type PluginActionResult<T> = {
6
- ok: true;
7
- value: T;
8
- } | {
9
- ok: false;
10
- error: string;
11
- };
12
- interface PluginVersionRow {
13
- id: string;
14
- plugin_id: string;
15
- version: string;
16
- changelog: string | null;
17
- artifact_path: string;
18
- artifact_entry_path?: string | null;
19
- artifact_sha256: string;
20
- content_sha256?: string | null;
21
- artifact_size_bytes: number;
22
- created_at: string;
23
- }
24
- interface ParsedPluginManifest {
25
- pluginKey: string;
26
- pluginName: string | null;
27
- pluginType: PluginType | null;
28
- /** Present in ZIP but ignored for assignment; Cervio owns release versions. */
29
- manifestVersion: string | null;
30
- /** Catalog capability ids the plugin needs (e.g. calendar). */
31
- requiredConnectionCapabilities: string[];
32
- /** External Connections requirements (OAuth broker). */
33
- connections: PluginConnectionRequirement[];
34
- /** Declared Cervio entity deps (name-based; for Admin + future export). */
35
- entities: PluginEntityRequirement[];
36
- /** Declared Cervio API path prefixes (documentation / future allowlist). */
37
- cervioApis: PluginCervioApiRequirement[];
38
- artifactEntryPath: string;
39
- rawManifest: Record<string, unknown>;
40
- manifestEntryName: string;
41
- }
42
- type PluginEntityAccess = 'read' | 'write';
43
- type PluginEntityRequirement = {
44
- name: string;
45
- fields: string[];
46
- forms: string[];
47
- access: PluginEntityAccess[];
48
- };
49
- type PluginCervioApiRequirement = {
50
- method: string;
51
- path_prefix: string;
52
- };
53
- type ExternalConnectionHttpMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
54
- type AllowedApiRule = {
55
- host: string;
56
- methods: ExternalConnectionHttpMethod[];
57
- path_prefix: string;
58
- };
59
- type PluginConnectionRequirement = {
60
- id: string;
61
- provider: string;
62
- consent: 'user';
63
- scopes: string[];
64
- allowed_apis: AllowedApiRule[];
65
- };
66
- type ParseManifestOptions = {
67
- /**
68
- * Capability ids a plugin may declare in `required_connection_capabilities`.
69
- * Host passes the live catalog; CLI uses {@link DEFAULT_PLUGIN_DECLARABLE_CAPABILITIES}.
70
- */
71
- allowedCapabilities?: readonly string[];
72
- };
73
- declare const PLUGIN_ARTIFACT_BUCKET = "plugin-artifacts";
74
- declare const MAX_PLUGIN_ZIP_BYTES: number;
75
- declare const MAX_PLUGIN_ZIP_ENTRIES = 5000;
76
- declare const MAX_PLUGIN_UNCOMPRESSED_BYTES: number;
77
- declare const PLUGIN_KEY_RE: RegExp;
78
- declare const PLUGIN_VERSION_SELECT = "id, plugin_id, version, changelog, artifact_path, artifact_entry_path, artifact_sha256, content_sha256, artifact_size_bytes, created_at";
79
- /**
80
- * Static default for CLI validate. Generated from host `CONNECTION_CAPABILITY_CATALOG`
81
- * where `pluginDeclarable === true`. Guarded by drift test against the host catalog.
82
- */
83
- declare const DEFAULT_PLUGIN_DECLARABLE_CAPABILITIES: readonly ["calendar"];
4
+ import JSZip from 'jszip';
84
5
 
85
6
  /** Parse `entities` from manifest.json (invalid entries skipped). */
86
7
  declare function parsePluginEntityRequirements(raw: unknown): PluginEntityRequirement[];
87
8
  /** Parse `cervio_apis` from manifest.json. */
88
9
  declare function parsePluginCervioApiRequirements(raw: unknown): PluginCervioApiRequirement[];
89
10
 
11
+ /** Parse `settings` from manifest.json (invalid entries skipped). */
12
+ declare function parsePluginSettingsRequirements(raw: unknown): PluginSettingsFieldRequirement[];
13
+
90
14
  declare const EXTERNAL_CONNECTION_ALLOWED_HOSTS: Record<string, readonly string[]>;
91
15
  declare const EXTERNAL_CONNECTION_HTTP_METHODS: readonly ["GET", "POST", "PATCH", "PUT", "DELETE"];
92
16
  declare const OAUTH_PROVIDER_KEY_RE: RegExp;
@@ -96,17 +20,6 @@ declare function isExternalConnectionProvider(v: string): boolean;
96
20
  /** Parse manifest `connections` array; drops invalid entries. */
97
21
  declare function parsePluginConnections(raw: unknown): PluginConnectionRequirement[];
98
22
 
99
- /**
100
- * Validates a loaded plugin ZIP before any entry is inflated (CERVIO-SEC-014):
101
- * caps the entry count and total declared uncompressed size to stop zip bombs,
102
- * and rejects path-traversal / absolute entry names as defense-in-depth.
103
- */
104
- declare function assertZipSafe(zip: JSZip): PluginActionResult<true>;
105
- declare function assertZipFile(file: {
106
- name?: string;
107
- size: number;
108
- }): PluginActionResult<true>;
109
-
110
23
  /**
111
24
  * Next patch version assigned by Cervio. Ignores pre-release/build metadata on
112
25
  * the previous label and bumps the patch component only.
@@ -121,9 +34,28 @@ declare const pluginManifestZodSchema: z.ZodObject<{
121
34
  id: z.ZodOptional<z.ZodString>;
122
35
  plugin_name: z.ZodOptional<z.ZodString>;
123
36
  name: z.ZodOptional<z.ZodString>;
124
- plugin_type: z.ZodOptional<z.ZodEnum<["task", "form", "task_form", "route"]>>;
37
+ plugin_type: z.ZodOptional<z.ZodEnum<["task", "form", "task_form", "route", "policy", "server"]>>;
125
38
  kind: z.ZodOptional<z.ZodString>;
126
39
  version: z.ZodOptional<z.ZodString>;
40
+ hooks: z.ZodOptional<z.ZodArray<z.ZodObject<{
41
+ event: z.ZodEnum<["before_create", "before_update"]>;
42
+ entities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
43
+ blocking: z.ZodOptional<z.ZodBoolean>;
44
+ identity: z.ZodOptional<z.ZodEnum<["caller", "plugin_principal"]>>;
45
+ entry: z.ZodOptional<z.ZodString>;
46
+ }, "strip", z.ZodTypeAny, {
47
+ event: "before_create" | "before_update";
48
+ entities?: string[] | undefined;
49
+ blocking?: boolean | undefined;
50
+ identity?: "caller" | "plugin_principal" | undefined;
51
+ entry?: string | undefined;
52
+ }, {
53
+ event: "before_create" | "before_update";
54
+ entities?: string[] | undefined;
55
+ blocking?: boolean | undefined;
56
+ identity?: "caller" | "plugin_principal" | undefined;
57
+ entry?: string | undefined;
58
+ }>, "many">>;
127
59
  required_connection_capabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
128
60
  requiredConnectionCapabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
129
61
  connections: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -200,14 +132,73 @@ declare const pluginManifestZodSchema: z.ZodObject<{
200
132
  pathPrefix?: string | undefined;
201
133
  }>, "many">>;
202
134
  cervioApis: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
135
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
136
+ key: z.ZodString;
137
+ type: z.ZodEnum<["string", "boolean", "select", "multiselect"]>;
138
+ label: z.ZodString;
139
+ hint: z.ZodOptional<z.ZodString>;
140
+ placeholder: z.ZodOptional<z.ZodString>;
141
+ default: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean, z.ZodArray<z.ZodString, "many">]>>;
142
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
143
+ value: z.ZodString;
144
+ label: z.ZodString;
145
+ }, "strip", z.ZodTypeAny, {
146
+ value: string;
147
+ label: string;
148
+ }, {
149
+ value: string;
150
+ label: string;
151
+ }>, "many">>;
152
+ }, "strip", z.ZodTypeAny, {
153
+ label: string;
154
+ key: string;
155
+ type: "string" | "boolean" | "select" | "multiselect";
156
+ options?: {
157
+ value: string;
158
+ label: string;
159
+ }[] | undefined;
160
+ hint?: string | undefined;
161
+ placeholder?: string | undefined;
162
+ default?: string | boolean | string[] | undefined;
163
+ }, {
164
+ label: string;
165
+ key: string;
166
+ type: "string" | "boolean" | "select" | "multiselect";
167
+ options?: {
168
+ value: string;
169
+ label: string;
170
+ }[] | undefined;
171
+ hint?: string | undefined;
172
+ placeholder?: string | undefined;
173
+ default?: string | boolean | string[] | undefined;
174
+ }>, "many">>;
203
175
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
204
176
  plugin_key: z.ZodOptional<z.ZodString>;
205
177
  id: z.ZodOptional<z.ZodString>;
206
178
  plugin_name: z.ZodOptional<z.ZodString>;
207
179
  name: z.ZodOptional<z.ZodString>;
208
- plugin_type: z.ZodOptional<z.ZodEnum<["task", "form", "task_form", "route"]>>;
180
+ plugin_type: z.ZodOptional<z.ZodEnum<["task", "form", "task_form", "route", "policy", "server"]>>;
209
181
  kind: z.ZodOptional<z.ZodString>;
210
182
  version: z.ZodOptional<z.ZodString>;
183
+ hooks: z.ZodOptional<z.ZodArray<z.ZodObject<{
184
+ event: z.ZodEnum<["before_create", "before_update"]>;
185
+ entities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
186
+ blocking: z.ZodOptional<z.ZodBoolean>;
187
+ identity: z.ZodOptional<z.ZodEnum<["caller", "plugin_principal"]>>;
188
+ entry: z.ZodOptional<z.ZodString>;
189
+ }, "strip", z.ZodTypeAny, {
190
+ event: "before_create" | "before_update";
191
+ entities?: string[] | undefined;
192
+ blocking?: boolean | undefined;
193
+ identity?: "caller" | "plugin_principal" | undefined;
194
+ entry?: string | undefined;
195
+ }, {
196
+ event: "before_create" | "before_update";
197
+ entities?: string[] | undefined;
198
+ blocking?: boolean | undefined;
199
+ identity?: "caller" | "plugin_principal" | undefined;
200
+ entry?: string | undefined;
201
+ }>, "many">>;
211
202
  required_connection_capabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
212
203
  requiredConnectionCapabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
213
204
  connections: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -284,14 +275,73 @@ declare const pluginManifestZodSchema: z.ZodObject<{
284
275
  pathPrefix?: string | undefined;
285
276
  }>, "many">>;
286
277
  cervioApis: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
278
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
279
+ key: z.ZodString;
280
+ type: z.ZodEnum<["string", "boolean", "select", "multiselect"]>;
281
+ label: z.ZodString;
282
+ hint: z.ZodOptional<z.ZodString>;
283
+ placeholder: z.ZodOptional<z.ZodString>;
284
+ default: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean, z.ZodArray<z.ZodString, "many">]>>;
285
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
286
+ value: z.ZodString;
287
+ label: z.ZodString;
288
+ }, "strip", z.ZodTypeAny, {
289
+ value: string;
290
+ label: string;
291
+ }, {
292
+ value: string;
293
+ label: string;
294
+ }>, "many">>;
295
+ }, "strip", z.ZodTypeAny, {
296
+ label: string;
297
+ key: string;
298
+ type: "string" | "boolean" | "select" | "multiselect";
299
+ options?: {
300
+ value: string;
301
+ label: string;
302
+ }[] | undefined;
303
+ hint?: string | undefined;
304
+ placeholder?: string | undefined;
305
+ default?: string | boolean | string[] | undefined;
306
+ }, {
307
+ label: string;
308
+ key: string;
309
+ type: "string" | "boolean" | "select" | "multiselect";
310
+ options?: {
311
+ value: string;
312
+ label: string;
313
+ }[] | undefined;
314
+ hint?: string | undefined;
315
+ placeholder?: string | undefined;
316
+ default?: string | boolean | string[] | undefined;
317
+ }>, "many">>;
287
318
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
288
319
  plugin_key: z.ZodOptional<z.ZodString>;
289
320
  id: z.ZodOptional<z.ZodString>;
290
321
  plugin_name: z.ZodOptional<z.ZodString>;
291
322
  name: z.ZodOptional<z.ZodString>;
292
- plugin_type: z.ZodOptional<z.ZodEnum<["task", "form", "task_form", "route"]>>;
323
+ plugin_type: z.ZodOptional<z.ZodEnum<["task", "form", "task_form", "route", "policy", "server"]>>;
293
324
  kind: z.ZodOptional<z.ZodString>;
294
325
  version: z.ZodOptional<z.ZodString>;
326
+ hooks: z.ZodOptional<z.ZodArray<z.ZodObject<{
327
+ event: z.ZodEnum<["before_create", "before_update"]>;
328
+ entities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
329
+ blocking: z.ZodOptional<z.ZodBoolean>;
330
+ identity: z.ZodOptional<z.ZodEnum<["caller", "plugin_principal"]>>;
331
+ entry: z.ZodOptional<z.ZodString>;
332
+ }, "strip", z.ZodTypeAny, {
333
+ event: "before_create" | "before_update";
334
+ entities?: string[] | undefined;
335
+ blocking?: boolean | undefined;
336
+ identity?: "caller" | "plugin_principal" | undefined;
337
+ entry?: string | undefined;
338
+ }, {
339
+ event: "before_create" | "before_update";
340
+ entities?: string[] | undefined;
341
+ blocking?: boolean | undefined;
342
+ identity?: "caller" | "plugin_principal" | undefined;
343
+ entry?: string | undefined;
344
+ }>, "many">>;
295
345
  required_connection_capabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
296
346
  requiredConnectionCapabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
297
347
  connections: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -368,9 +418,115 @@ declare const pluginManifestZodSchema: z.ZodObject<{
368
418
  pathPrefix?: string | undefined;
369
419
  }>, "many">>;
370
420
  cervioApis: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
421
+ settings: z.ZodOptional<z.ZodArray<z.ZodObject<{
422
+ key: z.ZodString;
423
+ type: z.ZodEnum<["string", "boolean", "select", "multiselect"]>;
424
+ label: z.ZodString;
425
+ hint: z.ZodOptional<z.ZodString>;
426
+ placeholder: z.ZodOptional<z.ZodString>;
427
+ default: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean, z.ZodArray<z.ZodString, "many">]>>;
428
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
429
+ value: z.ZodString;
430
+ label: z.ZodString;
431
+ }, "strip", z.ZodTypeAny, {
432
+ value: string;
433
+ label: string;
434
+ }, {
435
+ value: string;
436
+ label: string;
437
+ }>, "many">>;
438
+ }, "strip", z.ZodTypeAny, {
439
+ label: string;
440
+ key: string;
441
+ type: "string" | "boolean" | "select" | "multiselect";
442
+ options?: {
443
+ value: string;
444
+ label: string;
445
+ }[] | undefined;
446
+ hint?: string | undefined;
447
+ placeholder?: string | undefined;
448
+ default?: string | boolean | string[] | undefined;
449
+ }, {
450
+ label: string;
451
+ key: string;
452
+ type: "string" | "boolean" | "select" | "multiselect";
453
+ options?: {
454
+ value: string;
455
+ label: string;
456
+ }[] | undefined;
457
+ hint?: string | undefined;
458
+ placeholder?: string | undefined;
459
+ default?: string | boolean | string[] | undefined;
460
+ }>, "many">>;
371
461
  }, z.ZodTypeAny, "passthrough">>;
372
462
  type PluginManifestZod = z.infer<typeof pluginManifestZodSchema>;
373
463
 
464
+ /**
465
+ * Policy Plugin hook contract (shared by host, SDK, and manifest authors).
466
+ * Wire legacy: `plugin_type: "server"` is an alias for `"policy"`.
467
+ */
468
+ type PolicyHookEvent = 'before_create' | 'before_update';
469
+ type PolicyHookCaller = {
470
+ userId?: string;
471
+ channel?: string;
472
+ organizationId?: string;
473
+ };
474
+ type PolicyHookInput = {
475
+ event: PolicyHookEvent;
476
+ entity: {
477
+ id?: string;
478
+ name?: string;
479
+ };
480
+ record: {
481
+ id?: string | null;
482
+ data: Record<string, unknown>;
483
+ previousData?: Record<string, unknown> | null;
484
+ };
485
+ caller?: PolicyHookCaller;
486
+ settings?: Record<string, unknown>;
487
+ pluginKey?: string;
488
+ allowedEntityReads?: string[];
489
+ deadlineMs?: number;
490
+ };
491
+ type PolicyHookResult = {
492
+ allow: true;
493
+ } | {
494
+ allow: false;
495
+ message: string;
496
+ code?: string;
497
+ };
498
+ /** Host-mediated reads injected by plugin-sandbox-runner (null if no allowlist/caller). */
499
+ type PolicyHost = {
500
+ getRecord(entityName: string, id: string): Promise<{
501
+ id: string;
502
+ data: Record<string, unknown>;
503
+ } | null>;
504
+ listRecords(entityName: string, opts?: {
505
+ filters?: Record<string, unknown>;
506
+ limit?: number;
507
+ offset?: number;
508
+ }): Promise<Array<{
509
+ id: string;
510
+ data: Record<string, unknown>;
511
+ }>>;
512
+ sumField(entityName: string, fieldName: string, opts?: {
513
+ filters?: Record<string, unknown>;
514
+ }): Promise<number>;
515
+ };
516
+ /** True for canonical `policy` and legacy wire `server`. */
517
+ declare function isPolicyPluginType(t: string | null | undefined): boolean;
518
+ /** Canonical type written on upload / preferred in new manifests. */
519
+ declare function normalizeToPolicyPluginType(t: string | null | undefined): 'policy' | null;
520
+
521
+ declare function findBareModuleSpecifiers(source: string): string[];
522
+ declare function assertPolicyEntrySelfContained(source: string): {
523
+ ok: true;
524
+ } | {
525
+ ok: false;
526
+ error: string;
527
+ specifiers: string[];
528
+ };
529
+
374
530
  declare function normalizePluginKey(raw: string): string;
375
531
  declare function parseManifestObject(parsed: Record<string, unknown>, options?: ParseManifestOptions): PluginActionResult<{
376
532
  pluginKey: string;
@@ -381,6 +537,7 @@ declare function parseManifestObject(parsed: Record<string, unknown>, options?:
381
537
  connections: PluginConnectionRequirement[];
382
538
  entities: PluginEntityRequirement[];
383
539
  cervioApis: PluginCervioApiRequirement[];
540
+ settings: PluginSettingsFieldRequirement[];
384
541
  }>;
385
542
  /** Manifest JSON for hashing: drop author `version` so Cervio-owned labels do not affect dedup. */
386
543
  declare function manifestJsonForContentHash(raw: Record<string, unknown>): string;
@@ -421,4 +578,4 @@ declare function validatePluginZipBuffer(buffer: Buffer, options?: ParseManifest
421
578
  contentSha256: string;
422
579
  }>>;
423
580
 
424
- export { type AllowedApiRule, DEFAULT_PLUGIN_DECLARABLE_CAPABILITIES, EXTERNAL_CONNECTION_ALLOWED_HOSTS, EXTERNAL_CONNECTION_HTTP_METHODS, type ExternalConnectionHttpMethod, MAX_PLUGIN_UNCOMPRESSED_BYTES, MAX_PLUGIN_ZIP_BYTES, MAX_PLUGIN_ZIP_ENTRIES, OAUTH_PROVIDER_KEY_RE, PLUGIN_ARTIFACT_BUCKET, PLUGIN_KEY_RE, PLUGIN_VERSION_SELECT, type PackPluginResult, type ParseManifestOptions, type ParsedPluginManifest, type PluginActionResult, type PluginCervioApiRequirement, type PluginConnectionRequirement, type PluginEntityAccess, type PluginEntityRequirement, type PluginManifestZod, type PluginType, type PluginVersionRow, assertZipFile, assertZipSafe, compareSemverDesc, computePluginContentSha256, isExternalConnectionProvider, loadZipFromBuffer, manifestJsonForContentHash, nextPatchVersion, normalizeExactApiHost, normalizePluginKey, packPlugin, parseManifestObject, parsePluginCervioApiRequirements, parsePluginConnections, parsePluginEntityRequirements, parseZipManifest, pluginManifestZodSchema, sha256Hex, validatePluginDir, validatePluginZipBuffer };
581
+ export { EXTERNAL_CONNECTION_ALLOWED_HOSTS, EXTERNAL_CONNECTION_HTTP_METHODS, OAUTH_PROVIDER_KEY_RE, type PackPluginResult, ParseManifestOptions, ParsedPluginManifest, PluginActionResult, PluginCervioApiRequirement, PluginConnectionRequirement, PluginEntityRequirement, type PluginManifestZod, PluginSettingsFieldRequirement, PluginType, type PolicyHookCaller, type PolicyHookEvent, type PolicyHookInput, type PolicyHookResult, type PolicyHost, assertPolicyEntrySelfContained, compareSemverDesc, computePluginContentSha256, findBareModuleSpecifiers, isExternalConnectionProvider, isPolicyPluginType, loadZipFromBuffer, manifestJsonForContentHash, nextPatchVersion, normalizeExactApiHost, normalizePluginKey, normalizeToPolicyPluginType, packPlugin, parseManifestObject, parsePluginCervioApiRequirements, parsePluginConnections, parsePluginEntityRequirements, parsePluginSettingsRequirements, parseZipManifest, pluginManifestZodSchema, sha256Hex, validatePluginDir, validatePluginZipBuffer };