space-data-module-sdk 0.8.0 → 0.8.2

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 (43) hide show
  1. package/README.md +17 -3
  2. package/bin/space-data-module.js +8 -6
  3. package/package.json +2 -2
  4. package/schemas/spacedatastandards/PLG.fbs +191 -0
  5. package/src/bundle/wasm.js +31 -9
  6. package/src/compliance/index.js +4 -0
  7. package/src/compliance/pluginCompliance.js +158 -2
  8. package/src/embeddedManifest.js +25 -5
  9. package/src/generated/orbpro/invoke/plugin-invoke-request.js +2 -2
  10. package/src/generated/orbpro/invoke/plugin-invoke-response.js +2 -2
  11. package/src/generated/orbpro/stream/flat-buffer-type-ref.js +2 -2
  12. package/src/generated/orbpro/stream/typed-arena-buffer.js +2 -2
  13. package/src/generated/spacedatastandards/plg/entry-function.js +86 -0
  14. package/src/generated/spacedatastandards/plg/entry-function.ts +119 -0
  15. package/src/generated/spacedatastandards/plg/index.js +16 -0
  16. package/src/generated/spacedatastandards/plg/index.ts +11 -0
  17. package/src/generated/spacedatastandards/plg/plg.js +657 -0
  18. package/src/generated/spacedatastandards/plg/plg.ts +924 -0
  19. package/src/generated/spacedatastandards/plg/plugin-capability.js +66 -0
  20. package/src/generated/spacedatastandards/plg/plugin-capability.ts +84 -0
  21. package/src/generated/spacedatastandards/plg/plugin-category.js +15 -0
  22. package/src/generated/spacedatastandards/plg/plugin-category.ts +53 -0
  23. package/src/generated/spacedatastandards/plg/plugin-dependency.js +63 -0
  24. package/src/generated/spacedatastandards/plg/plugin-dependency.ts +86 -0
  25. package/src/generated/spacedatastandards/plg/publication-state.js +9 -0
  26. package/src/generated/spacedatastandards/plg/publication-state.ts +23 -0
  27. package/src/generated/spacedatastandards/plg/purchase-tier.js +9 -0
  28. package/src/generated/spacedatastandards/plg/purchase-tier.ts +23 -0
  29. package/src/invoke/codec.js +1 -1
  30. package/src/manifest/browser.js +7 -0
  31. package/src/manifest/codec.js +73 -0
  32. package/src/manifest/index.js +7 -0
  33. package/src/manifest/legacyToPlg.js +249 -0
  34. package/src/manifest/plgCodec.js +826 -0
  35. package/src/standards/sharedCatalog.js +132 -0
  36. package/src/testing/native/wasmedge_emscripten_pthread_runner.c +17 -3
  37. package/src/vendor/flatbuffers/LICENSE +202 -0
  38. package/src/vendor/flatbuffers/builder.js +534 -0
  39. package/src/vendor/flatbuffers/byte-buffer.js +253 -0
  40. package/src/vendor/flatbuffers/constants.js +4 -0
  41. package/src/vendor/flatbuffers/encoding.js +5 -0
  42. package/src/vendor/flatbuffers/flatbuffers.js +5 -0
  43. package/src/vendor/flatbuffers/utils.js +4 -0
@@ -0,0 +1,826 @@
1
+ /**
2
+ * Codec for the canonical spacedatastandards.org `PLG` plugin manifest schema
3
+ * (vendored at `schemas/spacedatastandards/PLG.fbs`, v1.0.5).
4
+ *
5
+ * This codec replaces the older internal `PluginManifest` (`PMAN`) schema as
6
+ * the on-the-wire manifest format embedded in plugin wasm artifacts.
7
+ *
8
+ * Input shape: a plain JSON-ish object with camelCase field names mirroring
9
+ * the PLG schema (plugin_id/pluginId both accepted). Unknown fields are
10
+ * ignored. All fields except PLUGIN_ID/NAME/VERSION are optional.
11
+ */
12
+ import * as flatbuffers from "flatbuffers/mjs/flatbuffers.js";
13
+
14
+ import {
15
+ EntryFunction,
16
+ PLG,
17
+ PluginCapability,
18
+ PluginDependency,
19
+ publicationState,
20
+ purchaseTier,
21
+ pluginCategory,
22
+ } from "../generated/spacedatastandards/plg/index.js";
23
+ import { toUint8Array } from "../runtime/bufferLike.js";
24
+
25
+ export const PLG_FILE_IDENTIFIER = "$PLG";
26
+
27
+ function pick(manifest, ...keys) {
28
+ for (const key of keys) {
29
+ if (manifest && Object.hasOwn(manifest, key) && manifest[key] !== undefined) {
30
+ return manifest[key];
31
+ }
32
+ }
33
+ return undefined;
34
+ }
35
+
36
+ function toBigInt(value) {
37
+ if (value === undefined || value === null) {
38
+ return 0n;
39
+ }
40
+ if (typeof value === "bigint") {
41
+ return value;
42
+ }
43
+ return BigInt(value);
44
+ }
45
+
46
+ function normalizeStringArray(value) {
47
+ if (!Array.isArray(value)) {
48
+ return [];
49
+ }
50
+ return value.filter((entry) => typeof entry === "string" && entry.length > 0);
51
+ }
52
+
53
+ function normalizeByteVector(value) {
54
+ if (!value) {
55
+ return null;
56
+ }
57
+ if (value instanceof Uint8Array) {
58
+ return value;
59
+ }
60
+ if (Array.isArray(value)) {
61
+ return new Uint8Array(value);
62
+ }
63
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
64
+ return toUint8Array(value);
65
+ }
66
+ if (typeof value === "string") {
67
+ // Hex strings are accepted as a convenience for manifest YAML/JSON.
68
+ const hex = value.startsWith("0x") ? value.slice(2) : value;
69
+ if (hex.length === 0 || hex.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex)) {
70
+ return null;
71
+ }
72
+ const bytes = new Uint8Array(hex.length / 2);
73
+ for (let i = 0; i < bytes.length; i++) {
74
+ bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
75
+ }
76
+ return bytes;
77
+ }
78
+ return null;
79
+ }
80
+
81
+ const pluginTypeByName = Object.freeze({
82
+ sensor: pluginCategory.Sensor,
83
+ propagator: pluginCategory.Propagator,
84
+ renderer: pluginCategory.Renderer,
85
+ analysis: pluginCategory.Analysis,
86
+ datasource: pluginCategory.DataSource,
87
+ data_source: pluginCategory.DataSource,
88
+ ew: pluginCategory.EW,
89
+ comms: pluginCategory.Comms,
90
+ physics: pluginCategory.Physics,
91
+ shader: pluginCategory.Shader,
92
+ });
93
+
94
+ function resolvePluginType(value) {
95
+ if (typeof value === "number") {
96
+ return value;
97
+ }
98
+ if (typeof value !== "string") {
99
+ return pluginCategory.Analysis;
100
+ }
101
+ const key = value.trim().toLowerCase().replace(/-/g, "_");
102
+ if (Object.hasOwn(pluginTypeByName, key)) {
103
+ return pluginTypeByName[key];
104
+ }
105
+ return pluginCategory.Analysis;
106
+ }
107
+
108
+ const paymentModelByName = Object.freeze({
109
+ free: purchaseTier.Free,
110
+ onetime: purchaseTier.OneTime,
111
+ one_time: purchaseTier.OneTime,
112
+ "one-time": purchaseTier.OneTime,
113
+ subscription: purchaseTier.Subscription,
114
+ });
115
+
116
+ function resolvePaymentModel(value) {
117
+ if (typeof value === "number") {
118
+ return value;
119
+ }
120
+ if (typeof value !== "string") {
121
+ return purchaseTier.Free;
122
+ }
123
+ const key = value.trim().toLowerCase();
124
+ return paymentModelByName[key] ?? purchaseTier.Free;
125
+ }
126
+
127
+ const listingStatusByName = Object.freeze({
128
+ public: publicationState.Public,
129
+ unlisted: publicationState.Unlisted,
130
+ retired: publicationState.Retired,
131
+ });
132
+
133
+ function resolveListingStatus(value) {
134
+ if (typeof value === "number") {
135
+ return value;
136
+ }
137
+ if (typeof value !== "string") {
138
+ return publicationState.Public;
139
+ }
140
+ const key = value.trim().toLowerCase();
141
+ return listingStatusByName[key] ?? publicationState.Public;
142
+ }
143
+
144
+ function addStringVector(builder, values, addVectorHelper) {
145
+ const strings = normalizeStringArray(values);
146
+ if (strings.length === 0) {
147
+ return 0;
148
+ }
149
+ const offsets = strings.map((str) => builder.createString(str));
150
+ builder.startVector(4, offsets.length, 4);
151
+ for (let index = offsets.length - 1; index >= 0; index--) {
152
+ builder.addOffset(offsets[index]);
153
+ }
154
+ return builder.endVector();
155
+ }
156
+
157
+ function addByteVector(builder, bytes, StartVector) {
158
+ if (!bytes || bytes.length === 0) {
159
+ return 0;
160
+ }
161
+ StartVector(builder, bytes.length);
162
+ for (let index = bytes.length - 1; index >= 0; index--) {
163
+ builder.addInt8(bytes[index]);
164
+ }
165
+ return builder.endVector();
166
+ }
167
+
168
+ function addEntryFunction(builder, entry) {
169
+ const name = typeof entry?.name === "string" ? entry.name : null;
170
+ const description =
171
+ typeof entry?.description === "string" ? entry.description : null;
172
+ const inputSchemas = normalizeStringArray(
173
+ entry?.inputSchemas ?? entry?.input_schemas,
174
+ );
175
+ const outputSchema =
176
+ typeof (entry?.outputSchema ?? entry?.output_schema) === "string"
177
+ ? entry.outputSchema ?? entry.output_schema
178
+ : null;
179
+
180
+ const nameOffset = name ? builder.createString(name) : 0;
181
+ const descriptionOffset = description ? builder.createString(description) : 0;
182
+ const inputsOffsets = inputSchemas.map((s) => builder.createString(s));
183
+ let inputsVector = 0;
184
+ if (inputsOffsets.length > 0) {
185
+ builder.startVector(4, inputsOffsets.length, 4);
186
+ for (let i = inputsOffsets.length - 1; i >= 0; i--) {
187
+ builder.addOffset(inputsOffsets[i]);
188
+ }
189
+ inputsVector = builder.endVector();
190
+ }
191
+ const outputOffset = outputSchema ? builder.createString(outputSchema) : 0;
192
+
193
+ EntryFunction.startEntryFunction(builder);
194
+ if (nameOffset) {
195
+ EntryFunction.addName(builder, nameOffset);
196
+ }
197
+ if (descriptionOffset) {
198
+ EntryFunction.addDescription(builder, descriptionOffset);
199
+ }
200
+ if (inputsVector) {
201
+ EntryFunction.addInputSchemas(builder, inputsVector);
202
+ }
203
+ if (outputOffset) {
204
+ EntryFunction.addOutputSchema(builder, outputOffset);
205
+ }
206
+ return EntryFunction.endEntryFunction(builder);
207
+ }
208
+
209
+ function addPluginCapability(builder, capability) {
210
+ const name = typeof capability?.name === "string" ? capability.name : null;
211
+ const version =
212
+ typeof capability?.version === "string" ? capability.version : null;
213
+ const required = capability?.required !== false;
214
+
215
+ const nameOffset = name ? builder.createString(name) : 0;
216
+ const versionOffset = version ? builder.createString(version) : 0;
217
+
218
+ PluginCapability.startPluginCapability(builder);
219
+ if (nameOffset) {
220
+ PluginCapability.addName(builder, nameOffset);
221
+ }
222
+ if (versionOffset) {
223
+ PluginCapability.addVersion(builder, versionOffset);
224
+ }
225
+ PluginCapability.addRequired(builder, !!required);
226
+ return PluginCapability.endPluginCapability(builder);
227
+ }
228
+
229
+ function addPluginDependency(builder, dependency) {
230
+ const pluginId =
231
+ typeof (dependency?.pluginId ?? dependency?.plugin_id) === "string"
232
+ ? dependency.pluginId ?? dependency.plugin_id
233
+ : null;
234
+ const minVersion =
235
+ typeof (dependency?.minVersion ?? dependency?.min_version) === "string"
236
+ ? dependency.minVersion ?? dependency.min_version
237
+ : null;
238
+ const maxVersion =
239
+ typeof (dependency?.maxVersion ?? dependency?.max_version) === "string"
240
+ ? dependency.maxVersion ?? dependency.max_version
241
+ : null;
242
+
243
+ const pluginIdOffset = pluginId ? builder.createString(pluginId) : 0;
244
+ const minOffset = minVersion ? builder.createString(minVersion) : 0;
245
+ const maxOffset = maxVersion ? builder.createString(maxVersion) : 0;
246
+
247
+ PluginDependency.startPluginDependency(builder);
248
+ if (pluginIdOffset) {
249
+ PluginDependency.addPluginId(builder, pluginIdOffset);
250
+ }
251
+ if (minOffset) {
252
+ PluginDependency.addMinVersion(builder, minOffset);
253
+ }
254
+ if (maxOffset) {
255
+ PluginDependency.addMaxVersion(builder, maxOffset);
256
+ }
257
+ return PluginDependency.endPluginDependency(builder);
258
+ }
259
+
260
+ function addOffsetVector(builder, offsets) {
261
+ if (offsets.length === 0) {
262
+ return 0;
263
+ }
264
+ builder.startVector(4, offsets.length, 4);
265
+ for (let index = offsets.length - 1; index >= 0; index--) {
266
+ builder.addOffset(offsets[index]);
267
+ }
268
+ return builder.endVector();
269
+ }
270
+
271
+ /**
272
+ * Encode a PLG manifest object to a canonical `$PLG`-identified FlatBuffer.
273
+ * Returns a Uint8Array over a fresh buffer.
274
+ */
275
+ export function encodePlgManifest(manifest = {}) {
276
+ const pluginId = pick(manifest, "pluginId", "plugin_id", "PLUGIN_ID");
277
+ const name = pick(manifest, "name", "NAME");
278
+ const version = pick(manifest, "version", "VERSION");
279
+ if (
280
+ typeof pluginId !== "string" ||
281
+ pluginId.length === 0 ||
282
+ typeof name !== "string" ||
283
+ name.length === 0 ||
284
+ typeof version !== "string" ||
285
+ version.length === 0
286
+ ) {
287
+ throw new Error(
288
+ "encodePlgManifest requires string pluginId, name, and version fields.",
289
+ );
290
+ }
291
+
292
+ const builder = new flatbuffers.Builder(1024);
293
+
294
+ const pluginIdOffset = builder.createString(pluginId);
295
+ const nameOffset = builder.createString(name);
296
+ const versionOffset = builder.createString(version);
297
+
298
+ const description = pick(manifest, "description", "DESCRIPTION");
299
+ const descriptionOffset =
300
+ typeof description === "string" && description.length > 0
301
+ ? builder.createString(description)
302
+ : 0;
303
+
304
+ const tagline = pick(manifest, "tagline", "TAGLINE");
305
+ const taglineOffset =
306
+ typeof tagline === "string" && tagline.length > 0
307
+ ? builder.createString(tagline)
308
+ : 0;
309
+
310
+ const pluginTypeValue = resolvePluginType(
311
+ pick(manifest, "pluginType", "plugin_type", "PLUGIN_TYPE", "pluginFamily"),
312
+ );
313
+
314
+ const publisherName = pick(
315
+ manifest,
316
+ "publisherName",
317
+ "publisher_name",
318
+ "PUBLISHER_NAME",
319
+ );
320
+ const publisherNameOffset =
321
+ typeof publisherName === "string" && publisherName.length > 0
322
+ ? builder.createString(publisherName)
323
+ : 0;
324
+
325
+ const publisherHandle = pick(
326
+ manifest,
327
+ "publisherHandle",
328
+ "publisher_handle",
329
+ "PUBLISHER_HANDLE",
330
+ );
331
+ const publisherHandleOffset =
332
+ typeof publisherHandle === "string" && publisherHandle.length > 0
333
+ ? builder.createString(publisherHandle)
334
+ : 0;
335
+
336
+ const publisherUrl = pick(
337
+ manifest,
338
+ "publisherUrl",
339
+ "publisher_url",
340
+ "PUBLISHER_URL",
341
+ );
342
+ const publisherUrlOffset =
343
+ typeof publisherUrl === "string" && publisherUrl.length > 0
344
+ ? builder.createString(publisherUrl)
345
+ : 0;
346
+
347
+ const supportUrl = pick(manifest, "supportUrl", "support_url", "SUPPORT_URL");
348
+ const supportUrlOffset =
349
+ typeof supportUrl === "string" && supportUrl.length > 0
350
+ ? builder.createString(supportUrl)
351
+ : 0;
352
+
353
+ const tagsOffset = addStringVector(
354
+ builder,
355
+ pick(manifest, "tags", "TAGS"),
356
+ );
357
+ const featuresOffset = addStringVector(
358
+ builder,
359
+ pick(manifest, "features", "FEATURES"),
360
+ );
361
+ const screenshotUrlsOffset = addStringVector(
362
+ builder,
363
+ pick(manifest, "screenshotUrls", "screenshot_urls", "SCREENSHOT_URLS"),
364
+ );
365
+
366
+ const bannerUrl = pick(manifest, "bannerUrl", "banner_url", "BANNER_URL");
367
+ const bannerUrlOffset =
368
+ typeof bannerUrl === "string" && bannerUrl.length > 0
369
+ ? builder.createString(bannerUrl)
370
+ : 0;
371
+
372
+ const abiVersion = Number.isFinite(
373
+ pick(manifest, "abiVersion", "abi_version", "ABI_VERSION"),
374
+ )
375
+ ? Number(pick(manifest, "abiVersion", "abi_version", "ABI_VERSION"))
376
+ : 1;
377
+
378
+ const wasmHashBytes = normalizeByteVector(
379
+ pick(manifest, "wasmHash", "wasm_hash", "WASM_HASH"),
380
+ );
381
+ const wasmHashOffset = addByteVector(
382
+ builder,
383
+ wasmHashBytes,
384
+ PLG.startWasmHashVector,
385
+ );
386
+
387
+ const wasmSize = toBigInt(
388
+ pick(manifest, "wasmSize", "wasm_size", "WASM_SIZE"),
389
+ );
390
+
391
+ const wasmCid = pick(manifest, "wasmCid", "wasm_cid", "WASM_CID");
392
+ const wasmCidOffset =
393
+ typeof wasmCid === "string" && wasmCid.length > 0
394
+ ? builder.createString(wasmCid)
395
+ : 0;
396
+
397
+ const encryptedWasmHashBytes = normalizeByteVector(
398
+ pick(
399
+ manifest,
400
+ "encryptedWasmHash",
401
+ "encrypted_wasm_hash",
402
+ "ENCRYPTED_WASM_HASH",
403
+ ),
404
+ );
405
+ const encryptedWasmHashOffset = addByteVector(
406
+ builder,
407
+ encryptedWasmHashBytes,
408
+ PLG.startEncryptedWasmHashVector,
409
+ );
410
+
411
+ const encryptedWasmSize = toBigInt(
412
+ pick(
413
+ manifest,
414
+ "encryptedWasmSize",
415
+ "encrypted_wasm_size",
416
+ "ENCRYPTED_WASM_SIZE",
417
+ ),
418
+ );
419
+
420
+ const entryFunctions = pick(
421
+ manifest,
422
+ "entryFunctions",
423
+ "entry_functions",
424
+ "ENTRY_FUNCTIONS",
425
+ );
426
+ const entryOffsets = Array.isArray(entryFunctions)
427
+ ? entryFunctions.map((entry) => addEntryFunction(builder, entry))
428
+ : [];
429
+ const entryFunctionsOffset = addOffsetVector(builder, entryOffsets);
430
+
431
+ const requiredSchemasOffset = addStringVector(
432
+ builder,
433
+ pick(manifest, "requiredSchemas", "required_schemas", "REQUIRED_SCHEMAS"),
434
+ );
435
+
436
+ const dependencies = pick(manifest, "dependencies", "DEPENDENCIES");
437
+ const dependencyOffsets = Array.isArray(dependencies)
438
+ ? dependencies.map((dep) => addPluginDependency(builder, dep))
439
+ : [];
440
+ const dependenciesOffset = addOffsetVector(builder, dependencyOffsets);
441
+
442
+ const capabilities = pick(manifest, "capabilities", "CAPABILITIES");
443
+ const capabilityOffsets = Array.isArray(capabilities)
444
+ ? capabilities.map((cap) => addPluginCapability(builder, cap))
445
+ : [];
446
+ const capabilitiesOffset = addOffsetVector(builder, capabilityOffsets);
447
+
448
+ const providerPeerId = pick(
449
+ manifest,
450
+ "providerPeerId",
451
+ "provider_peer_id",
452
+ "PROVIDER_PEER_ID",
453
+ );
454
+ const providerPeerIdOffset =
455
+ typeof providerPeerId === "string" && providerPeerId.length > 0
456
+ ? builder.createString(providerPeerId)
457
+ : 0;
458
+
459
+ const providerEpmCid = pick(
460
+ manifest,
461
+ "providerEpmCid",
462
+ "provider_epm_cid",
463
+ "PROVIDER_EPM_CID",
464
+ );
465
+ const providerEpmCidOffset =
466
+ typeof providerEpmCid === "string" && providerEpmCid.length > 0
467
+ ? builder.createString(providerEpmCid)
468
+ : 0;
469
+
470
+ const encrypted = manifest?.encrypted === undefined
471
+ ? false
472
+ : !!manifest.encrypted;
473
+
474
+ const requiredScope = pick(
475
+ manifest,
476
+ "requiredScope",
477
+ "required_scope",
478
+ "REQUIRED_SCOPE",
479
+ );
480
+ const requiredScopeOffset =
481
+ typeof requiredScope === "string" && requiredScope.length > 0
482
+ ? builder.createString(requiredScope)
483
+ : 0;
484
+
485
+ const keyId = pick(manifest, "keyId", "key_id", "KEY_ID");
486
+ const keyIdOffset =
487
+ typeof keyId === "string" && keyId.length > 0
488
+ ? builder.createString(keyId)
489
+ : 0;
490
+
491
+ const allowedDomainsOffset = addStringVector(
492
+ builder,
493
+ pick(manifest, "allowedDomains", "allowed_domains", "ALLOWED_DOMAINS"),
494
+ );
495
+
496
+ const maxGrantTimeoutMs = toBigInt(
497
+ pick(
498
+ manifest,
499
+ "maxGrantTimeoutMs",
500
+ "max_grant_timeout_ms",
501
+ "MAX_GRANT_TIMEOUT_MS",
502
+ ),
503
+ );
504
+
505
+ const minPermissionsOffset = addStringVector(
506
+ builder,
507
+ pick(manifest, "minPermissions", "min_permissions", "MIN_PERMISSIONS"),
508
+ );
509
+
510
+ const createdAt = toBigInt(
511
+ pick(manifest, "createdAt", "created_at", "CREATED_AT"),
512
+ );
513
+ const updatedAt = toBigInt(
514
+ pick(manifest, "updatedAt", "updated_at", "UPDATED_AT"),
515
+ );
516
+
517
+ const documentationUrl = pick(
518
+ manifest,
519
+ "documentationUrl",
520
+ "documentation_url",
521
+ "DOCUMENTATION_URL",
522
+ );
523
+ const documentationUrlOffset =
524
+ typeof documentationUrl === "string" && documentationUrl.length > 0
525
+ ? builder.createString(documentationUrl)
526
+ : 0;
527
+
528
+ const changelogUrl = pick(
529
+ manifest,
530
+ "changelogUrl",
531
+ "changelog_url",
532
+ "CHANGELOG_URL",
533
+ );
534
+ const changelogUrlOffset =
535
+ typeof changelogUrl === "string" && changelogUrl.length > 0
536
+ ? builder.createString(changelogUrl)
537
+ : 0;
538
+
539
+ const iconUrl = pick(manifest, "iconUrl", "icon_url", "ICON_URL");
540
+ const iconUrlOffset =
541
+ typeof iconUrl === "string" && iconUrl.length > 0
542
+ ? builder.createString(iconUrl)
543
+ : 0;
544
+
545
+ const license = pick(manifest, "license", "LICENSE");
546
+ const licenseOffset =
547
+ typeof license === "string" && license.length > 0
548
+ ? builder.createString(license)
549
+ : 0;
550
+
551
+ const paymentModelValue = resolvePaymentModel(
552
+ pick(manifest, "paymentModel", "payment_model", "PAYMENT_MODEL"),
553
+ );
554
+
555
+ const priceUsdCents = Number.isFinite(
556
+ pick(manifest, "priceUsdCents", "price_usd_cents", "PRICE_USD_CENTS"),
557
+ )
558
+ ? Number(pick(manifest, "priceUsdCents", "price_usd_cents", "PRICE_USD_CENTS"))
559
+ : 0;
560
+
561
+ const subscriptionPeriodDays = Number.isFinite(
562
+ pick(
563
+ manifest,
564
+ "subscriptionPeriodDays",
565
+ "subscription_period_days",
566
+ "SUBSCRIPTION_PERIOD_DAYS",
567
+ ),
568
+ )
569
+ ? Number(
570
+ pick(
571
+ manifest,
572
+ "subscriptionPeriodDays",
573
+ "subscription_period_days",
574
+ "SUBSCRIPTION_PERIOD_DAYS",
575
+ ),
576
+ )
577
+ : 0;
578
+
579
+ const acceptedPaymentMethodsOffset = addStringVector(
580
+ builder,
581
+ pick(
582
+ manifest,
583
+ "acceptedPaymentMethods",
584
+ "accepted_payment_methods",
585
+ "ACCEPTED_PAYMENT_METHODS",
586
+ ),
587
+ );
588
+
589
+ const listingStatusValue = resolveListingStatus(
590
+ pick(manifest, "listingStatus", "listing_status", "LISTING_STATUS"),
591
+ );
592
+
593
+ const signatureBytes = normalizeByteVector(
594
+ pick(manifest, "signature", "SIGNATURE"),
595
+ );
596
+ const signatureOffset = addByteVector(
597
+ builder,
598
+ signatureBytes,
599
+ PLG.startSignatureVector,
600
+ );
601
+
602
+ PLG.startPLG(builder);
603
+ PLG.addPluginId(builder, pluginIdOffset);
604
+ PLG.addName(builder, nameOffset);
605
+ PLG.addVersion(builder, versionOffset);
606
+ if (descriptionOffset) PLG.addDescription(builder, descriptionOffset);
607
+ if (taglineOffset) PLG.addTagline(builder, taglineOffset);
608
+ PLG.addPluginType(builder, pluginTypeValue);
609
+ if (publisherNameOffset) PLG.addPublisherName(builder, publisherNameOffset);
610
+ if (publisherHandleOffset)
611
+ PLG.addPublisherHandle(builder, publisherHandleOffset);
612
+ if (publisherUrlOffset) PLG.addPublisherUrl(builder, publisherUrlOffset);
613
+ if (supportUrlOffset) PLG.addSupportUrl(builder, supportUrlOffset);
614
+ if (tagsOffset) PLG.addTags(builder, tagsOffset);
615
+ if (featuresOffset) PLG.addFeatures(builder, featuresOffset);
616
+ if (screenshotUrlsOffset)
617
+ PLG.addScreenshotUrls(builder, screenshotUrlsOffset);
618
+ if (bannerUrlOffset) PLG.addBannerUrl(builder, bannerUrlOffset);
619
+ PLG.addAbiVersion(builder, abiVersion);
620
+ if (wasmHashOffset) PLG.addWasmHash(builder, wasmHashOffset);
621
+ if (wasmSize !== 0n) PLG.addWasmSize(builder, wasmSize);
622
+ if (wasmCidOffset) PLG.addWasmCid(builder, wasmCidOffset);
623
+ if (encryptedWasmHashOffset)
624
+ PLG.addEncryptedWasmHash(builder, encryptedWasmHashOffset);
625
+ if (encryptedWasmSize !== 0n)
626
+ PLG.addEncryptedWasmSize(builder, encryptedWasmSize);
627
+ if (entryFunctionsOffset)
628
+ PLG.addEntryFunctions(builder, entryFunctionsOffset);
629
+ if (requiredSchemasOffset)
630
+ PLG.addRequiredSchemas(builder, requiredSchemasOffset);
631
+ if (dependenciesOffset) PLG.addDependencies(builder, dependenciesOffset);
632
+ if (capabilitiesOffset) PLG.addCapabilities(builder, capabilitiesOffset);
633
+ if (providerPeerIdOffset)
634
+ PLG.addProviderPeerId(builder, providerPeerIdOffset);
635
+ if (providerEpmCidOffset)
636
+ PLG.addProviderEpmCid(builder, providerEpmCidOffset);
637
+ PLG.addEncrypted(builder, encrypted);
638
+ if (requiredScopeOffset) PLG.addRequiredScope(builder, requiredScopeOffset);
639
+ if (keyIdOffset) PLG.addKeyId(builder, keyIdOffset);
640
+ if (allowedDomainsOffset)
641
+ PLG.addAllowedDomains(builder, allowedDomainsOffset);
642
+ if (maxGrantTimeoutMs !== 0n)
643
+ PLG.addMaxGrantTimeoutMs(builder, maxGrantTimeoutMs);
644
+ if (minPermissionsOffset)
645
+ PLG.addMinPermissions(builder, minPermissionsOffset);
646
+ if (createdAt !== 0n) PLG.addCreatedAt(builder, createdAt);
647
+ if (updatedAt !== 0n) PLG.addUpdatedAt(builder, updatedAt);
648
+ if (documentationUrlOffset)
649
+ PLG.addDocumentationUrl(builder, documentationUrlOffset);
650
+ if (changelogUrlOffset) PLG.addChangelogUrl(builder, changelogUrlOffset);
651
+ if (iconUrlOffset) PLG.addIconUrl(builder, iconUrlOffset);
652
+ if (licenseOffset) PLG.addLicense(builder, licenseOffset);
653
+ PLG.addPaymentModel(builder, paymentModelValue);
654
+ PLG.addPriceUsdCents(builder, priceUsdCents);
655
+ PLG.addSubscriptionPeriodDays(builder, subscriptionPeriodDays);
656
+ if (acceptedPaymentMethodsOffset)
657
+ PLG.addAcceptedPaymentMethods(builder, acceptedPaymentMethodsOffset);
658
+ PLG.addListingStatus(builder, listingStatusValue);
659
+ if (signatureOffset) PLG.addSignature(builder, signatureOffset);
660
+ const rootOffset = PLG.endPLG(builder);
661
+ PLG.finishPLGBuffer(builder, rootOffset);
662
+ return builder.asUint8Array();
663
+ }
664
+
665
+ function readStringVector(root, lengthFn, getterFn) {
666
+ const length = typeof root[lengthFn] === "function" ? root[lengthFn]() : 0;
667
+ const out = [];
668
+ for (let index = 0; index < length; index++) {
669
+ const value = root[getterFn](index);
670
+ if (typeof value === "string") {
671
+ out.push(value);
672
+ }
673
+ }
674
+ return out;
675
+ }
676
+
677
+ /**
678
+ * Decode a `$PLG`-identified FlatBuffer back to a JS manifest object.
679
+ * Throws if the identifier does not match.
680
+ */
681
+ export function decodePlgManifest(data) {
682
+ const bytes = toUint8Array(data);
683
+ if (!bytes) {
684
+ throw new TypeError(
685
+ "decodePlgManifest expects Uint8Array, ArrayBuffer, or ByteBuffer.",
686
+ );
687
+ }
688
+ const bb = new flatbuffers.ByteBuffer(bytes);
689
+ if (!PLG.bufferHasIdentifier(bb)) {
690
+ throw new Error(
691
+ `PLG manifest buffer identifier mismatch (expected ${PLG_FILE_IDENTIFIER}).`,
692
+ );
693
+ }
694
+ const root = PLG.getRootAsPLG(bb);
695
+
696
+ const entryFunctions = [];
697
+ const entryLen =
698
+ typeof root.entryFunctionsLength === "function"
699
+ ? root.entryFunctionsLength()
700
+ : 0;
701
+ for (let i = 0; i < entryLen; i++) {
702
+ const entry = root.entryFunctions(i);
703
+ if (!entry) continue;
704
+ entryFunctions.push({
705
+ name: entry.name(),
706
+ description: entry.description() || undefined,
707
+ inputSchemas: readStringVector(
708
+ entry,
709
+ "inputSchemasLength",
710
+ "inputSchemas",
711
+ ),
712
+ outputSchema: entry.outputSchema() || undefined,
713
+ });
714
+ }
715
+
716
+ const capabilities = [];
717
+ const capLen =
718
+ typeof root.capabilitiesLength === "function"
719
+ ? root.capabilitiesLength()
720
+ : 0;
721
+ for (let i = 0; i < capLen; i++) {
722
+ const cap = root.capabilities(i);
723
+ if (!cap) continue;
724
+ capabilities.push({
725
+ name: cap.name() || undefined,
726
+ version: cap.version() || undefined,
727
+ required: !!cap.required(),
728
+ });
729
+ }
730
+
731
+ const dependencies = [];
732
+ const depLen =
733
+ typeof root.dependenciesLength === "function"
734
+ ? root.dependenciesLength()
735
+ : 0;
736
+ for (let i = 0; i < depLen; i++) {
737
+ const dep = root.dependencies(i);
738
+ if (!dep) continue;
739
+ dependencies.push({
740
+ pluginId: dep.pluginId() || undefined,
741
+ minVersion: dep.minVersion() || undefined,
742
+ maxVersion: dep.maxVersion() || undefined,
743
+ });
744
+ }
745
+
746
+ return {
747
+ pluginId: root.pluginId(),
748
+ name: root.name(),
749
+ version: root.version(),
750
+ description: root.description() || undefined,
751
+ tagline: root.tagline() || undefined,
752
+ pluginType: root.pluginType(),
753
+ publisherName: root.publisherName() || undefined,
754
+ publisherHandle: root.publisherHandle() || undefined,
755
+ publisherUrl: root.publisherUrl() || undefined,
756
+ supportUrl: root.supportUrl() || undefined,
757
+ tags: readStringVector(root, "tagsLength", "tags"),
758
+ features: readStringVector(root, "featuresLength", "features"),
759
+ screenshotUrls: readStringVector(
760
+ root,
761
+ "screenshotUrlsLength",
762
+ "screenshotUrls",
763
+ ),
764
+ bannerUrl: root.bannerUrl() || undefined,
765
+ abiVersion: root.abiVersion(),
766
+ wasmHash: root.wasmHashArray() ?? null,
767
+ wasmSize: root.wasmSize(),
768
+ wasmCid: root.wasmCid() || undefined,
769
+ encryptedWasmHash: root.encryptedWasmHashArray() ?? null,
770
+ encryptedWasmSize: root.encryptedWasmSize(),
771
+ entryFunctions,
772
+ requiredSchemas: readStringVector(
773
+ root,
774
+ "requiredSchemasLength",
775
+ "requiredSchemas",
776
+ ),
777
+ dependencies,
778
+ capabilities,
779
+ providerPeerId: root.providerPeerId() || undefined,
780
+ providerEpmCid: root.providerEpmCid() || undefined,
781
+ encrypted: !!root.encrypted(),
782
+ requiredScope: root.requiredScope() || undefined,
783
+ keyId: root.keyId() || undefined,
784
+ allowedDomains: readStringVector(
785
+ root,
786
+ "allowedDomainsLength",
787
+ "allowedDomains",
788
+ ),
789
+ maxGrantTimeoutMs: root.maxGrantTimeoutMs(),
790
+ minPermissions: readStringVector(
791
+ root,
792
+ "minPermissionsLength",
793
+ "minPermissions",
794
+ ),
795
+ createdAt: root.createdAt(),
796
+ updatedAt: root.updatedAt(),
797
+ documentationUrl: root.documentationUrl() || undefined,
798
+ changelogUrl: root.changelogUrl() || undefined,
799
+ iconUrl: root.iconUrl() || undefined,
800
+ license: root.license() || undefined,
801
+ paymentModel: root.paymentModel(),
802
+ priceUsdCents: root.priceUsdCents(),
803
+ subscriptionPeriodDays: root.subscriptionPeriodDays(),
804
+ acceptedPaymentMethods: readStringVector(
805
+ root,
806
+ "acceptedPaymentMethodsLength",
807
+ "acceptedPaymentMethods",
808
+ ),
809
+ listingStatus: root.listingStatus(),
810
+ signature: root.signatureArray() ?? null,
811
+ };
812
+ }
813
+
814
+ /**
815
+ * Verify that a byte buffer carries the canonical PLG file identifier.
816
+ * Returns `true` iff the bytes begin with a FlatBuffer root offset followed
817
+ * by the `$PLG` identifier. Does not throw.
818
+ */
819
+ export function isPlgManifestBuffer(data) {
820
+ const bytes = toUint8Array(data);
821
+ if (!bytes || bytes.length < 8) {
822
+ return false;
823
+ }
824
+ const bb = new flatbuffers.ByteBuffer(bytes);
825
+ return PLG.bufferHasIdentifier(bb);
826
+ }