space-data-module-sdk 0.7.0 → 0.8.1

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 (67) hide show
  1. package/README.md +16 -23
  2. package/bin/space-data-module.js +5 -3
  3. package/package.json +2 -2
  4. package/schemas/spacedatastandards/PLG.fbs +191 -0
  5. package/src/AGENTS.md +1 -1
  6. package/src/bundle/AGENTS.md +6 -5
  7. package/src/bundle/codec.js +163 -48
  8. package/src/bundle/constants.js +1 -1
  9. package/src/bundle/wasm.js +53 -32
  10. package/src/compiler/compileModule.js +9 -1
  11. package/src/compliance/index.js +4 -0
  12. package/src/compliance/pluginCompliance.js +158 -2
  13. package/src/embeddedManifest.js +25 -5
  14. package/src/generated/orbpro/invoke/plugin-invoke-request.js +2 -2
  15. package/src/generated/orbpro/invoke/plugin-invoke-response.js +2 -2
  16. package/src/generated/orbpro/stream/flat-buffer-type-ref.js +2 -2
  17. package/src/generated/orbpro/stream/typed-arena-buffer.js +2 -2
  18. package/src/generated/spacedatastandards/plg/entry-function.js +86 -0
  19. package/src/generated/spacedatastandards/plg/entry-function.ts +119 -0
  20. package/src/generated/spacedatastandards/plg/index.js +16 -0
  21. package/src/generated/spacedatastandards/plg/index.ts +11 -0
  22. package/src/generated/spacedatastandards/plg/plg.js +657 -0
  23. package/src/generated/spacedatastandards/plg/plg.ts +924 -0
  24. package/src/generated/spacedatastandards/plg/plugin-capability.js +66 -0
  25. package/src/generated/spacedatastandards/plg/plugin-capability.ts +84 -0
  26. package/src/generated/spacedatastandards/plg/plugin-category.js +15 -0
  27. package/src/generated/spacedatastandards/plg/plugin-category.ts +53 -0
  28. package/src/generated/spacedatastandards/plg/plugin-dependency.js +63 -0
  29. package/src/generated/spacedatastandards/plg/plugin-dependency.ts +86 -0
  30. package/src/generated/spacedatastandards/plg/publication-state.js +9 -0
  31. package/src/generated/spacedatastandards/plg/publication-state.ts +23 -0
  32. package/src/generated/spacedatastandards/plg/purchase-tier.js +9 -0
  33. package/src/generated/spacedatastandards/plg/purchase-tier.ts +23 -0
  34. package/src/index.d.ts +1 -1
  35. package/src/invoke/codec.js +1 -1
  36. package/src/manifest/browser.js +7 -0
  37. package/src/manifest/index.js +7 -0
  38. package/src/manifest/legacyToPlg.js +249 -0
  39. package/src/manifest/plgCodec.js +826 -0
  40. package/src/standards/sharedCatalog.js +132 -0
  41. package/src/transport/records.js +34 -3
  42. package/src/vendor/flatbuffers/LICENSE +202 -0
  43. package/src/vendor/flatbuffers/builder.js +534 -0
  44. package/src/vendor/flatbuffers/byte-buffer.js +253 -0
  45. package/src/vendor/flatbuffers/constants.js +4 -0
  46. package/src/vendor/flatbuffers/encoding.js +5 -0
  47. package/src/vendor/flatbuffers/flatbuffers.js +5 -0
  48. package/src/vendor/flatbuffers/utils.js +4 -0
  49. package/schemas/ModuleBundle.fbs +0 -108
  50. package/src/generated/orbpro/module/canonicalization-rule.d.ts +0 -48
  51. package/src/generated/orbpro/module/canonicalization-rule.js +0 -95
  52. package/src/generated/orbpro/module/canonicalization-rule.ts +0 -142
  53. package/src/generated/orbpro/module/module-bundle-entry-role.d.ts +0 -11
  54. package/src/generated/orbpro/module/module-bundle-entry-role.js +0 -14
  55. package/src/generated/orbpro/module/module-bundle-entry-role.ts +0 -15
  56. package/src/generated/orbpro/module/module-bundle-entry.d.ts +0 -97
  57. package/src/generated/orbpro/module/module-bundle-entry.js +0 -219
  58. package/src/generated/orbpro/module/module-bundle-entry.ts +0 -287
  59. package/src/generated/orbpro/module/module-bundle.d.ts +0 -86
  60. package/src/generated/orbpro/module/module-bundle.js +0 -213
  61. package/src/generated/orbpro/module/module-bundle.ts +0 -277
  62. package/src/generated/orbpro/module/module-payload-encoding.d.ts +0 -9
  63. package/src/generated/orbpro/module/module-payload-encoding.js +0 -12
  64. package/src/generated/orbpro/module/module-payload-encoding.ts +0 -13
  65. package/src/generated/orbpro/module.d.ts +0 -5
  66. package/src/generated/orbpro/module.js +0 -7
  67. package/src/generated/orbpro/module.ts +0 -9
@@ -1,5 +1,11 @@
1
1
  import { canonicalBytes } from "../auth/canonicalize.js";
2
- import { decodePluginManifest, encodePluginManifest } from "../manifest/index.js";
2
+ import {
3
+ decodePluginManifest,
4
+ decodePlgManifest,
5
+ encodePlgManifest,
6
+ isPlgManifestBuffer,
7
+ legacyManifestToPlg,
8
+ } from "../manifest/index.js";
3
9
  import { toUint8Array } from "../runtime/bufferLike.js";
4
10
  import { sha256Bytes } from "../utils/crypto.js";
5
11
  import { bytesToHex } from "../utils/encoding.js";
@@ -7,10 +13,10 @@ import { createDeploymentPlanBundleEntry } from "../deployment/index.js";
7
13
  import {
8
14
  DEFAULT_MANIFEST_EXPORT_SYMBOL,
9
15
  DEFAULT_MANIFEST_SIZE_SYMBOL,
10
- SDS_BUNDLE_SECTION_NAME,
11
16
  SDS_CUSTOM_SECTION_PREFIX,
12
17
  SDS_DEPLOYMENT_ENTRY_ID,
13
18
  SDS_DEPLOYMENT_SECTION_NAME,
19
+ SDS_MBL_CONTAINER_NAME,
14
20
  } from "./constants.js";
15
21
  import {
16
22
  decodeModuleBundle,
@@ -20,7 +26,11 @@ import {
20
26
  moduleBundleEncodingToName,
21
27
  moduleBundleRoleToName,
22
28
  } from "./codec.js";
23
- import { extractPublicationRecordCollection } from "../transport/records.js";
29
+ import {
30
+ appendPublicationRecordCollection,
31
+ encodePublicationRecordCollection,
32
+ extractPublicationRecordCollection,
33
+ } from "../transport/records.js";
24
34
 
25
35
  const textDecoder = new TextDecoder();
26
36
  const textEncoder = new TextEncoder();
@@ -222,20 +232,36 @@ function normalizeJsonPayload(value) {
222
232
  return new Uint8Array(canonicalBytes(value));
223
233
  }
224
234
 
235
+ function encodeBundleManifest(manifest) {
236
+ return encodePlgManifest(legacyManifestToPlg(manifest));
237
+ }
238
+
239
+ function decodeBundleManifest(payloadBytes) {
240
+ return isPlgManifestBuffer(payloadBytes)
241
+ ? decodePlgManifest(payloadBytes)
242
+ : decodePluginManifest(payloadBytes);
243
+ }
244
+
225
245
  function normalizeManifestEntry(manifest, manifestBytes) {
226
246
  if (!manifest && !manifestBytes) {
227
247
  return null;
228
248
  }
229
- const payload = manifestBytes ?? encodePluginManifest(manifest);
249
+ const payload = manifestBytes ?? encodeBundleManifest(manifest);
250
+ const isPlg = isPlgManifestBuffer(payload);
230
251
  return {
231
252
  entryId: "manifest",
232
253
  role: "manifest",
233
254
  sectionName: "sds.manifest",
234
255
  payloadEncoding: "flatbuffer",
235
- typeRef: {
236
- schemaName: "PluginManifest.fbs",
237
- fileIdentifier: "PMAN",
238
- },
256
+ typeRef: isPlg
257
+ ? {
258
+ schemaName: "PLG.fbs",
259
+ fileIdentifier: "$PLG",
260
+ }
261
+ : {
262
+ schemaName: "PluginManifest.fbs",
263
+ fileIdentifier: "PMAN",
264
+ },
239
265
  payload,
240
266
  description: "Canonical plugin manifest.",
241
267
  };
@@ -326,7 +352,7 @@ function buildParsedEntries(bundle) {
326
352
  parsedEntry.payloadEncodingName === "flatbuffer"
327
353
  ) {
328
354
  try {
329
- parsedEntry.decodedManifest = decodePluginManifest(payloadBytes);
355
+ parsedEntry.decodedManifest = decodeBundleManifest(payloadBytes);
330
356
  } catch {
331
357
  parsedEntry.decodedManifest = null;
332
358
  }
@@ -376,7 +402,7 @@ export async function createSingleFileBundle(options = {}) {
376
402
  options.manifestBytes !== undefined
377
403
  ? normalizeBytes(options.manifestBytes, "manifestBytes")
378
404
  : options.manifest
379
- ? encodePluginManifest(options.manifest)
405
+ ? encodeBundleManifest(options.manifest)
380
406
  : null;
381
407
  const manifestEntry = normalizeManifestEntry(options.manifest, manifestBytes);
382
408
  const rawEntries = [
@@ -392,7 +418,7 @@ export async function createSingleFileBundle(options = {}) {
392
418
  version: 1,
393
419
  strippedCustomSectionPrefix:
394
420
  options.customSectionPrefix ?? SDS_CUSTOM_SECTION_PREFIX,
395
- bundleSectionName: options.bundleSectionName ?? SDS_BUNDLE_SECTION_NAME,
421
+ bundleSectionName: options.bundleSectionName ?? SDS_MBL_CONTAINER_NAME,
396
422
  hashAlgorithm: "sha256",
397
423
  };
398
424
  const canonical = await computeCanonicalModuleHash(wasmBytes, {
@@ -415,10 +441,14 @@ export async function createSingleFileBundle(options = {}) {
415
441
  const baseWasmBytes = stripWasmCustomSections(wasmBytes, (section) =>
416
442
  section.name.startsWith(canonicalization.strippedCustomSectionPrefix),
417
443
  );
418
- const outputWasmBytes = appendWasmCustomSection(
444
+ const outputWasmBytes = appendPublicationRecordCollection(
419
445
  baseWasmBytes,
420
- canonicalization.bundleSectionName,
421
- bundleBytes,
446
+ encodePublicationRecordCollection({
447
+ version: protectedArtifact?.version,
448
+ mbl: bundle,
449
+ enc: protectedArtifact?.enc,
450
+ pnm: protectedArtifact?.pnm,
451
+ }),
422
452
  );
423
453
  return {
424
454
  bundle,
@@ -434,25 +464,16 @@ export async function createSingleFileBundle(options = {}) {
434
464
 
435
465
  export async function parseSingleFileBundle(bytes, options = {}) {
436
466
  const protectedArtifact = extractPublicationRecordCollection(bytes);
467
+ if (!protectedArtifact?.mbl) {
468
+ throw new Error("Missing required REC trailer containing an MBL record.");
469
+ }
437
470
  const wasmBytes = normalizeBytes(
438
- protectedArtifact?.payloadBytes ?? bytes,
471
+ protectedArtifact.payloadBytes,
439
472
  "wasm bytes",
440
473
  );
441
474
  const customSections = listWasmCustomSections(wasmBytes);
442
- const bundleSectionName = String(
443
- options.bundleSectionName ?? SDS_BUNDLE_SECTION_NAME,
444
- );
445
- const bundleSections = customSections.filter(
446
- (section) => section.name === bundleSectionName,
447
- );
448
- if (bundleSections.length === 0) {
449
- throw new Error(`Missing required custom section "${bundleSectionName}".`);
450
- }
451
- if (bundleSections.length > 1) {
452
- throw new Error(`Expected one "${bundleSectionName}" section, found ${bundleSections.length}.`);
453
- }
454
- const bundleBytes = bundleSections[0].dataBytes;
455
- const bundle = decodeModuleBundle(bundleBytes);
475
+ const bundle = protectedArtifact.mbl;
476
+ const bundleBytes = protectedArtifact.mblBytes ?? encodeModuleBundle(bundle);
456
477
  const prefix =
457
478
  bundle.canonicalization?.strippedCustomSectionPrefix ??
458
479
  SDS_CUSTOM_SECTION_PREFIX;
@@ -464,7 +485,7 @@ export async function parseSingleFileBundle(bytes, options = {}) {
464
485
  let manifest = null;
465
486
  if (manifestEntry) {
466
487
  try {
467
- manifest = decodePluginManifest(new Uint8Array(manifestEntry.payload ?? []));
488
+ manifest = decodeBundleManifest(new Uint8Array(manifestEntry.payload ?? []));
468
489
  } catch {
469
490
  manifest = null;
470
491
  }
@@ -477,8 +498,8 @@ export async function parseSingleFileBundle(bytes, options = {}) {
477
498
  ) ?? null;
478
499
  return {
479
500
  wasmBytes,
480
- protectedArtifactBytes: protectedArtifact?.protectedBytes ?? null,
481
- publicationRecords: protectedArtifact ?? null,
501
+ protectedArtifactBytes: protectedArtifact.protectedBytes,
502
+ publicationRecords: protectedArtifact,
482
503
  bundleBytes,
483
504
  bundle,
484
505
  entries: parsedEntries,
@@ -894,6 +894,7 @@ export async function protectModuleArtifact(options = {}) {
894
894
  };
895
895
 
896
896
  let singleFileBundle = null;
897
+ let singleFileBundleRecords = null;
897
898
  if (options.singleFileBundle === true) {
898
899
  const additionalEntries = [
899
900
  ...(Array.isArray(options.bundleEntries) ? options.bundleEntries : []),
@@ -905,9 +906,13 @@ export async function protectModuleArtifact(options = {}) {
905
906
  authorization: signedAuthorization,
906
907
  entries: additionalEntries,
907
908
  });
909
+ singleFileBundleRecords = extractPublicationRecordCollection(
910
+ singleFileBundle.wasmBytes,
911
+ );
908
912
  }
909
913
 
910
- const bundleBytes = singleFileBundle?.wasmBytes ?? wasmBytes;
914
+ const bundleBytes = singleFileBundleRecords?.payloadBytes ?? wasmBytes;
915
+ const bundleRecord = singleFileBundleRecords?.mbl ?? null;
911
916
  let publicationNotice = null;
912
917
  let publicationRecordsBytes = null;
913
918
  let protectedArtifactBytes = null;
@@ -931,6 +936,7 @@ export async function protectModuleArtifact(options = {}) {
931
936
  signer,
932
937
  });
933
938
  publicationRecordsBytes = encodePublicationRecordCollection({
939
+ mbl: bundleRecord,
934
940
  enc: parsedEncryptedBase.enc,
935
941
  pnm: publicationNotice,
936
942
  });
@@ -943,6 +949,7 @@ export async function protectModuleArtifact(options = {}) {
943
949
  parsedProtectedBlob: {
944
950
  payloadBytes: parsedEncryptedBase.payloadBytes,
945
951
  recordCollectionBytes: publicationRecordsBytes,
952
+ mbl: bundleRecord,
946
953
  enc: parsedEncryptedBase.enc,
947
954
  pnm: publicationNotice,
948
955
  },
@@ -959,6 +966,7 @@ export async function protectModuleArtifact(options = {}) {
959
966
  signer,
960
967
  });
961
968
  publicationRecordsBytes = encodePublicationRecordCollection({
969
+ mbl: bundleRecord,
962
970
  pnm: publicationNotice,
963
971
  });
964
972
  protectedArtifactBytes = appendPublicationRecordCollection(
@@ -2,8 +2,10 @@ import {
2
2
  findManifestFiles,
3
3
  getWasmExportNames,
4
4
  getWasmExportNamesFromFile,
5
+ hasLegacyPmanManifest,
5
6
  loadManifestFromFile,
6
7
  loadComplianceConfig,
8
+ locateEmbeddedPlgManifest,
7
9
  resolveManifestFiles,
8
10
  validatePluginArtifact,
9
11
  validatePluginManifest,
@@ -49,8 +51,10 @@ export {
49
51
  findManifestFiles,
50
52
  getWasmExportNames,
51
53
  getWasmExportNamesFromFile,
54
+ hasLegacyPmanManifest,
52
55
  loadManifestFromFile,
53
56
  loadComplianceConfig,
57
+ locateEmbeddedPlgManifest,
54
58
  RecommendedCapabilityIds,
55
59
  StandaloneWasiCapabilityIds,
56
60
  resolveManifestFiles,
@@ -16,6 +16,11 @@ import {
16
16
  RecommendedCapabilityIds,
17
17
  StandaloneWasiCapabilityIds,
18
18
  } from "../capabilities.js";
19
+ import {
20
+ PLG_FILE_IDENTIFIER,
21
+ decodePlgManifest,
22
+ isPlgManifestBuffer,
23
+ } from "../manifest/plgCodec.js";
19
24
 
20
25
  const RecommendedCapabilitySet = new Set(RecommendedCapabilityIds);
21
26
  const StandaloneWasiCapabilitySet = new Set(StandaloneWasiCapabilityIds);
@@ -1356,11 +1361,143 @@ export async function getWasmExportNamesFromFile(wasmPath) {
1356
1361
  return getWasmExportNames(wasmBytes);
1357
1362
  }
1358
1363
 
1364
+ const PLG_IDENTIFIER_BYTES = Uint8Array.from(
1365
+ Array.from(PLG_FILE_IDENTIFIER, (ch) => ch.charCodeAt(0)),
1366
+ );
1367
+ const LEGACY_PMAN_IDENTIFIER_BYTES = Uint8Array.from([0x50, 0x4d, 0x41, 0x4e]);
1368
+
1369
+ function indexOfBytes(haystack, needle, startIndex = 0) {
1370
+ if (!haystack || needle.length === 0 || haystack.length < needle.length) {
1371
+ return -1;
1372
+ }
1373
+ for (let i = startIndex; i <= haystack.length - needle.length; i += 1) {
1374
+ let matched = true;
1375
+ for (let j = 0; j < needle.length; j += 1) {
1376
+ if (haystack[i + j] !== needle[j]) {
1377
+ matched = false;
1378
+ break;
1379
+ }
1380
+ }
1381
+ if (matched) {
1382
+ return i;
1383
+ }
1384
+ }
1385
+ return -1;
1386
+ }
1387
+
1388
+ /**
1389
+ * Scan wasm bytes for the canonical `$PLG` FlatBuffer identifier and, when
1390
+ * found, return both the raw offset and the smallest aligned candidate buffer
1391
+ * that a downstream decoder can try to parse. The wasm `data` sections embed
1392
+ * the manifest bytes verbatim; FlatBuffer headers are `<root_offset:u32><$PLG>`
1393
+ * so we walk backwards one 4-byte word and hand the caller a slice starting
1394
+ * there.
1395
+ */
1396
+ export function locateEmbeddedPlgManifest(wasmBytes) {
1397
+ const bytes = wasmBytes instanceof Uint8Array
1398
+ ? wasmBytes
1399
+ : new Uint8Array(wasmBytes);
1400
+ const identifierOffset = indexOfBytes(bytes, PLG_IDENTIFIER_BYTES);
1401
+ if (identifierOffset < 4) {
1402
+ return null;
1403
+ }
1404
+ const start = identifierOffset - 4;
1405
+ // Upper bound on the manifest size — grab up to 64KB and let the caller
1406
+ // decide how much to trim. FlatBuffer decoders only read what they need.
1407
+ const end = Math.min(bytes.length, start + 65536);
1408
+ const candidate = bytes.subarray(start, end);
1409
+ if (!isPlgManifestBuffer(candidate)) {
1410
+ return null;
1411
+ }
1412
+ return { start, identifierOffset, bytes: candidate };
1413
+ }
1414
+
1415
+ export function hasLegacyPmanManifest(wasmBytes) {
1416
+ const bytes = wasmBytes instanceof Uint8Array
1417
+ ? wasmBytes
1418
+ : new Uint8Array(wasmBytes);
1419
+ return indexOfBytes(bytes, LEGACY_PMAN_IDENTIFIER_BYTES) !== -1;
1420
+ }
1421
+
1422
+ function validateEmbeddedManifestBytes({
1423
+ wasmBytes,
1424
+ manifest,
1425
+ issues,
1426
+ sourceLabel,
1427
+ }) {
1428
+ if (hasLegacyPmanManifest(wasmBytes)) {
1429
+ pushIssue(
1430
+ issues,
1431
+ "error",
1432
+ "legacy-pman-manifest-embedded",
1433
+ "Plugin artifact embeds legacy PMAN manifest bytes — rebuild with the PLG codec.",
1434
+ sourceLabel,
1435
+ );
1436
+ }
1437
+
1438
+ const located = locateEmbeddedPlgManifest(wasmBytes);
1439
+ if (!located) {
1440
+ pushIssue(
1441
+ issues,
1442
+ "error",
1443
+ "missing-plg-manifest-bytes",
1444
+ `Plugin artifact does not embed a canonical \"${PLG_FILE_IDENTIFIER}\" manifest buffer.`,
1445
+ sourceLabel,
1446
+ );
1447
+ return;
1448
+ }
1449
+
1450
+ let decoded;
1451
+ try {
1452
+ decoded = decodePlgManifest(located.bytes);
1453
+ } catch (error) {
1454
+ pushIssue(
1455
+ issues,
1456
+ "error",
1457
+ "plg-manifest-decode-failed",
1458
+ `Failed to decode embedded PLG manifest: ${error?.message ?? error}`,
1459
+ sourceLabel,
1460
+ );
1461
+ return;
1462
+ }
1463
+
1464
+ const sourcePluginId = manifest?.pluginId ?? manifest?.plugin_id ?? null;
1465
+ if (
1466
+ isNonEmptyString(sourcePluginId) &&
1467
+ isNonEmptyString(decoded?.pluginId) &&
1468
+ sourcePluginId !== decoded.pluginId
1469
+ ) {
1470
+ pushIssue(
1471
+ issues,
1472
+ "error",
1473
+ "plg-manifest-plugin-id-mismatch",
1474
+ `Embedded PLG manifest pluginId \"${decoded.pluginId}\" does not match source manifest pluginId \"${sourcePluginId}\".`,
1475
+ sourceLabel,
1476
+ );
1477
+ }
1478
+
1479
+ const sourceVersion = manifest?.version ?? null;
1480
+ if (
1481
+ isNonEmptyString(sourceVersion) &&
1482
+ isNonEmptyString(decoded?.version) &&
1483
+ sourceVersion !== decoded.version
1484
+ ) {
1485
+ pushIssue(
1486
+ issues,
1487
+ "warning",
1488
+ "plg-manifest-version-mismatch",
1489
+ `Embedded PLG manifest version \"${decoded.version}\" does not match source manifest version \"${sourceVersion}\".`,
1490
+ sourceLabel,
1491
+ );
1492
+ }
1493
+ }
1494
+
1359
1495
  export async function validatePluginArtifact(options) {
1360
1496
  const {
1361
1497
  manifest,
1362
1498
  manifestPath = null,
1363
1499
  wasmPath = null,
1500
+ wasmBytes: inputWasmBytes = null,
1364
1501
  exportNames = null,
1365
1502
  sourceName = manifestPath ?? "manifest",
1366
1503
  } = options;
@@ -1368,15 +1505,26 @@ export async function validatePluginArtifact(options) {
1368
1505
  const issues = [...report.issues];
1369
1506
  let resolvedExportNames = [];
1370
1507
  let checkedArtifact = false;
1508
+ let loadedWasmBytes = null;
1371
1509
  const declaredInvokeSurfaces = Array.isArray(manifest?.invokeSurfaces)
1372
1510
  ? manifest.invokeSurfaces.filter((surface) => InvokeSurfaceSet.has(surface))
1373
1511
  : [];
1374
1512
 
1375
- if (Array.isArray(exportNames)) {
1513
+ if (inputWasmBytes) {
1514
+ loadedWasmBytes =
1515
+ inputWasmBytes instanceof Uint8Array
1516
+ ? inputWasmBytes
1517
+ : new Uint8Array(inputWasmBytes);
1518
+ resolvedExportNames = Array.isArray(exportNames)
1519
+ ? [...exportNames]
1520
+ : getWasmExportNames(loadedWasmBytes);
1521
+ checkedArtifact = true;
1522
+ } else if (Array.isArray(exportNames)) {
1376
1523
  resolvedExportNames = [...exportNames];
1377
1524
  checkedArtifact = true;
1378
1525
  } else if (isNonEmptyString(wasmPath)) {
1379
- resolvedExportNames = await getWasmExportNamesFromFile(wasmPath);
1526
+ loadedWasmBytes = new Uint8Array(await readFile(wasmPath));
1527
+ resolvedExportNames = getWasmExportNames(loadedWasmBytes);
1380
1528
  checkedArtifact = true;
1381
1529
  }
1382
1530
 
@@ -1424,6 +1572,14 @@ export async function validatePluginArtifact(options) {
1424
1572
  wasmPath ?? sourceName,
1425
1573
  );
1426
1574
  }
1575
+ if (loadedWasmBytes) {
1576
+ validateEmbeddedManifestBytes({
1577
+ wasmBytes: loadedWasmBytes,
1578
+ manifest,
1579
+ issues,
1580
+ sourceLabel: wasmPath ?? sourceName,
1581
+ });
1582
+ }
1427
1583
  } else {
1428
1584
  pushIssue(
1429
1585
  issues,
@@ -2,8 +2,19 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
4
  import { encodePluginManifest } from "./manifest/index.js";
5
-
6
- function toManifestBytes(manifest) {
5
+ import { legacyManifestToPlg } from "./manifest/legacyToPlg.js";
6
+ import { encodePlgManifest } from "./manifest/plgCodec.js";
7
+
8
+ /**
9
+ * Convert a manifest input to the raw FlatBuffer bytes that will be
10
+ * embedded in the plugin artifact.
11
+ *
12
+ * The embedded manifest is the canonical spacedatastandards.org PLG
13
+ * schema (`$PLG` file_identifier) by default. Pass `format: "pman"` to
14
+ * emit the internal PluginManifest schema instead (legacy path, retained
15
+ * for tests that still compare against PMAN bytes).
16
+ */
17
+ function toManifestBytes(manifest, format = "plg") {
7
18
  if (manifest instanceof Uint8Array) {
8
19
  return manifest;
9
20
  }
@@ -17,7 +28,13 @@ function toManifestBytes(manifest) {
17
28
  manifest.byteLength,
18
29
  );
19
30
  }
20
- return encodePluginManifest(manifest);
31
+ if (format === "pman") {
32
+ return encodePluginManifest(manifest);
33
+ }
34
+ // Default: PLG. Accept both PLG-shaped and legacy PluginManifest-shaped
35
+ // inputs; the converter is a no-op for PLG-native shapes.
36
+ const plgShape = legacyManifestToPlg(manifest);
37
+ return encodePlgManifest(plgShape);
21
38
  }
22
39
 
23
40
  function renderByteRows(bytes) {
@@ -34,7 +51,10 @@ function renderByteRows(bytes) {
34
51
  }
35
52
 
36
53
  export function generateEmbeddedManifestSource(options = {}) {
37
- const manifestBytes = toManifestBytes(options.manifest);
54
+ const manifestBytes = toManifestBytes(
55
+ options.manifest,
56
+ options.format ?? "plg",
57
+ );
38
58
  if (manifestBytes.length === 0) {
39
59
  throw new Error("generateEmbeddedManifestSource requires manifest bytes.");
40
60
  }
@@ -91,7 +111,7 @@ export function writeEmbeddedManifestArtifacts(options = {}) {
91
111
  throw new Error("writeEmbeddedManifestArtifacts requires outputDir.");
92
112
  }
93
113
 
94
- const manifestBytes = toManifestBytes(manifest);
114
+ const manifestBytes = toManifestBytes(manifest, options.format ?? "plg");
95
115
  fs.mkdirSync(outputDir, { recursive: true });
96
116
 
97
117
  const binaryPath = path.join(outputDir, binaryFileName);
@@ -1,6 +1,6 @@
1
1
  // automatically generated by the FlatBuffers compiler, do not modify
2
2
  /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
3
- import * as flatbuffers from "flatbuffers/mjs/flatbuffers.js";
3
+ import * as flatbuffers from "../../../vendor/flatbuffers/flatbuffers.js";
4
4
  import { TypedArenaBuffer } from '../../orbpro/stream/typed-arena-buffer.js';
5
5
  /**
6
6
  * Canonical invoke envelope consumed by direct ABI and command-mode execution.
@@ -128,4 +128,4 @@ export class PluginInvokeRequestT {
128
128
  return PluginInvokeRequest.createPluginInvokeRequest(builder, methodId, inputFrames, payloadArena);
129
129
  }
130
130
  }
131
- //# sourceMappingURL=plugin-invoke-request.js.map
131
+ //# sourceMappingURL=plugin-invoke-request.js.map
@@ -1,6 +1,6 @@
1
1
  // automatically generated by the FlatBuffers compiler, do not modify
2
2
  /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
3
- import * as flatbuffers from "flatbuffers/mjs/flatbuffers.js";
3
+ import * as flatbuffers from "../../../vendor/flatbuffers/flatbuffers.js";
4
4
  import { TypedArenaBuffer } from '../../orbpro/stream/typed-arena-buffer.js';
5
5
  /**
6
6
  * Canonical invoke result emitted by direct ABI and command-mode execution.
@@ -181,4 +181,4 @@ export class PluginInvokeResponseT {
181
181
  return PluginInvokeResponse.createPluginInvokeResponse(builder, this.statusCode, this.yielded, this.backlogRemaining, outputFrames, payloadArena, errorCode, errorMessage);
182
182
  }
183
183
  }
184
- //# sourceMappingURL=plugin-invoke-response.js.map
184
+ //# sourceMappingURL=plugin-invoke-response.js.map
@@ -1,6 +1,6 @@
1
1
  // automatically generated by the FlatBuffers compiler, do not modify
2
2
  /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
3
- import * as flatbuffers from "flatbuffers/mjs/flatbuffers.js";
3
+ import * as flatbuffers from "../../../vendor/flatbuffers/flatbuffers.js";
4
4
  import { PayloadWireFormat } from "../../orbpro/stream/payload-wire-format.js";
5
5
  function normalizePayloadWireFormat(value) {
6
6
  if (value === PayloadWireFormat.ALIGNED_BINARY) {
@@ -202,4 +202,4 @@ export class FlatBufferTypeRefT {
202
202
  return FlatBufferTypeRef.createFlatBufferTypeRef(builder, schemaName, fileIdentifier, schemaHash, this.acceptsAnyFlatbuffer, normalizePayloadWireFormat(this.wireFormat), rootTypeName, this.fixedStringLength, this.byteLength, this.requiredAlignment);
203
203
  }
204
204
  }
205
- //# sourceMappingURL=flat-buffer-type-ref.js.map
205
+ //# sourceMappingURL=flat-buffer-type-ref.js.map
@@ -1,6 +1,6 @@
1
1
  // automatically generated by the FlatBuffers compiler, do not modify
2
2
  /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
3
- import * as flatbuffers from "flatbuffers/mjs/flatbuffers.js";
3
+ import * as flatbuffers from "../../../vendor/flatbuffers/flatbuffers.js";
4
4
  import { BufferMutability } from "../../orbpro/stream/buffer-mutability.js";
5
5
  import { BufferOwnership } from "../../orbpro/stream/buffer-ownership.js";
6
6
  import { FlatBufferTypeRef, } from "../../orbpro/stream/flat-buffer-type-ref.js";
@@ -230,4 +230,4 @@ export class TypedArenaBufferT {
230
230
  return TypedArenaBuffer.createTypedArenaBuffer(builder, typeRef, portId, this.alignment, this.offset, this.size, this.ownership, this.generation, this.mutability, this.traceId, this.streamId, this.sequence, this.endOfStream);
231
231
  }
232
232
  }
233
- //# sourceMappingURL=typed-arena-buffer.js.map
233
+ //# sourceMappingURL=typed-arena-buffer.js.map
@@ -0,0 +1,86 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import * as flatbuffers from "flatbuffers";
8
+ class EntryFunction {
9
+ constructor() {
10
+ __publicField(this, "bb", null);
11
+ __publicField(this, "bb_pos", 0);
12
+ }
13
+ __init(i, bb) {
14
+ this.bb_pos = i;
15
+ this.bb = bb;
16
+ return this;
17
+ }
18
+ static getRootAsEntryFunction(bb, obj) {
19
+ return (obj || new EntryFunction()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
20
+ }
21
+ static getSizePrefixedRootAsEntryFunction(bb, obj) {
22
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
23
+ return (obj || new EntryFunction()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
24
+ }
25
+ name(optionalEncoding) {
26
+ const offset = this.bb.__offset(this.bb_pos, 4);
27
+ return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
28
+ }
29
+ description(optionalEncoding) {
30
+ const offset = this.bb.__offset(this.bb_pos, 6);
31
+ return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
32
+ }
33
+ inputSchemas(index, optionalEncoding) {
34
+ const offset = this.bb.__offset(this.bb_pos, 8);
35
+ return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
36
+ }
37
+ inputSchemasLength() {
38
+ const offset = this.bb.__offset(this.bb_pos, 8);
39
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
40
+ }
41
+ outputSchema(optionalEncoding) {
42
+ const offset = this.bb.__offset(this.bb_pos, 10);
43
+ return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
44
+ }
45
+ static startEntryFunction(builder) {
46
+ builder.startObject(4);
47
+ }
48
+ static addName(builder, nameOffset) {
49
+ builder.addFieldOffset(0, nameOffset, 0);
50
+ }
51
+ static addDescription(builder, descriptionOffset) {
52
+ builder.addFieldOffset(1, descriptionOffset, 0);
53
+ }
54
+ static addInputSchemas(builder, inputSchemasOffset) {
55
+ builder.addFieldOffset(2, inputSchemasOffset, 0);
56
+ }
57
+ static createInputSchemasVector(builder, data) {
58
+ builder.startVector(4, data.length, 4);
59
+ for (let i = data.length - 1; i >= 0; i--) {
60
+ builder.addOffset(data[i]);
61
+ }
62
+ return builder.endVector();
63
+ }
64
+ static startInputSchemasVector(builder, numElems) {
65
+ builder.startVector(4, numElems, 4);
66
+ }
67
+ static addOutputSchema(builder, outputSchemaOffset) {
68
+ builder.addFieldOffset(3, outputSchemaOffset, 0);
69
+ }
70
+ static endEntryFunction(builder) {
71
+ const offset = builder.endObject();
72
+ builder.requiredField(offset, 4);
73
+ return offset;
74
+ }
75
+ static createEntryFunction(builder, nameOffset, descriptionOffset, inputSchemasOffset, outputSchemaOffset) {
76
+ EntryFunction.startEntryFunction(builder);
77
+ EntryFunction.addName(builder, nameOffset);
78
+ EntryFunction.addDescription(builder, descriptionOffset);
79
+ EntryFunction.addInputSchemas(builder, inputSchemasOffset);
80
+ EntryFunction.addOutputSchema(builder, outputSchemaOffset);
81
+ return EntryFunction.endEntryFunction(builder);
82
+ }
83
+ }
84
+ export {
85
+ EntryFunction
86
+ };