space-data-module-sdk 0.8.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 (39) hide show
  1. package/package.json +2 -2
  2. package/schemas/spacedatastandards/PLG.fbs +191 -0
  3. package/src/bundle/wasm.js +31 -9
  4. package/src/compliance/index.js +4 -0
  5. package/src/compliance/pluginCompliance.js +158 -2
  6. package/src/embeddedManifest.js +25 -5
  7. package/src/generated/orbpro/invoke/plugin-invoke-request.js +2 -2
  8. package/src/generated/orbpro/invoke/plugin-invoke-response.js +2 -2
  9. package/src/generated/orbpro/stream/flat-buffer-type-ref.js +2 -2
  10. package/src/generated/orbpro/stream/typed-arena-buffer.js +2 -2
  11. package/src/generated/spacedatastandards/plg/entry-function.js +86 -0
  12. package/src/generated/spacedatastandards/plg/entry-function.ts +119 -0
  13. package/src/generated/spacedatastandards/plg/index.js +16 -0
  14. package/src/generated/spacedatastandards/plg/index.ts +11 -0
  15. package/src/generated/spacedatastandards/plg/plg.js +657 -0
  16. package/src/generated/spacedatastandards/plg/plg.ts +924 -0
  17. package/src/generated/spacedatastandards/plg/plugin-capability.js +66 -0
  18. package/src/generated/spacedatastandards/plg/plugin-capability.ts +84 -0
  19. package/src/generated/spacedatastandards/plg/plugin-category.js +15 -0
  20. package/src/generated/spacedatastandards/plg/plugin-category.ts +53 -0
  21. package/src/generated/spacedatastandards/plg/plugin-dependency.js +63 -0
  22. package/src/generated/spacedatastandards/plg/plugin-dependency.ts +86 -0
  23. package/src/generated/spacedatastandards/plg/publication-state.js +9 -0
  24. package/src/generated/spacedatastandards/plg/publication-state.ts +23 -0
  25. package/src/generated/spacedatastandards/plg/purchase-tier.js +9 -0
  26. package/src/generated/spacedatastandards/plg/purchase-tier.ts +23 -0
  27. package/src/invoke/codec.js +1 -1
  28. package/src/manifest/browser.js +7 -0
  29. package/src/manifest/index.js +7 -0
  30. package/src/manifest/legacyToPlg.js +249 -0
  31. package/src/manifest/plgCodec.js +826 -0
  32. package/src/standards/sharedCatalog.js +132 -0
  33. package/src/vendor/flatbuffers/LICENSE +202 -0
  34. package/src/vendor/flatbuffers/builder.js +534 -0
  35. package/src/vendor/flatbuffers/byte-buffer.js +253 -0
  36. package/src/vendor/flatbuffers/constants.js +4 -0
  37. package/src/vendor/flatbuffers/encoding.js +5 -0
  38. package/src/vendor/flatbuffers/flatbuffers.js +5 -0
  39. package/src/vendor/flatbuffers/utils.js +4 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "space-data-module-sdk",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Module SDK for building, validating, signing, and deploying WebAssembly modules on the Space Data Network.",
5
5
  "type": "module",
6
6
  "types": "./src/index.d.ts",
@@ -72,7 +72,7 @@
72
72
  "flatsql": "^0.4.0",
73
73
  "hd-wallet-wasm": "1.6.0",
74
74
  "sdn-emception": "1.0.0",
75
- "spacedatastandards.org": "1.85.0"
75
+ "spacedatastandards.org": "^1.92.0"
76
76
  },
77
77
  "devDependencies": {
78
78
  "express": "^4.21.2"
@@ -0,0 +1,191 @@
1
+ // Canonical plugin manifest schema.
2
+ //
3
+ // Upstream source: https://github.com/DigitalArsenal/spacedatastandards.org
4
+ // Path: schema/PLG/main.fbs
5
+ // Version: 1.0.6
6
+ // Upstream hash: 2c9ca90ec923b2476832517dee715559c45dd198d3bdd4b5b3dfe0a4d05c4882
7
+ //
8
+ // This is the canonical spacedatastandards.org "PLG" manifest.
9
+ // It is vendored here verbatim so the plugin SDK can depend on a stable copy
10
+ // without adding a network or submodule fetch at build time. Keep this file
11
+ // byte-for-byte identical to the upstream version; if a refresh is needed,
12
+ // re-vendor from the upstream path above rather than hand-editing.
13
+
14
+ // Hash: 2c9ca90ec923b2476832517dee715559c45dd198d3bdd4b5b3dfe0a4d05c4882
15
+ // Version: 1.0.6
16
+ // -----------------------------------END_HEADER
17
+ /// Plugin type category
18
+ enum pluginCategory : byte {
19
+ /// Sensor simulation and analysis
20
+ Sensor,
21
+ /// Orbital propagation algorithms
22
+ Propagator,
23
+ /// Custom rendering/visualization
24
+ Renderer,
25
+ /// Data analysis and processing
26
+ Analysis,
27
+ /// External data source integration
28
+ DataSource,
29
+ /// Electronic warfare simulation
30
+ EW,
31
+ /// Communications modeling
32
+ Comms,
33
+ /// Physics simulation
34
+ Physics,
35
+ /// GLSL shader plugins for custom visualization
36
+ Shader
37
+ }
38
+
39
+ /// Storefront payment model for the plugin listing
40
+ enum purchaseTier : byte {
41
+ /// No payment required
42
+ Free,
43
+ /// Single one-time purchase
44
+ OneTime,
45
+ /// Recurring subscription purchase
46
+ Subscription
47
+ }
48
+
49
+ /// Publication visibility for the plugin listing
50
+ enum publicationState : byte {
51
+ /// Discoverable in public storefront listings
52
+ Public,
53
+ /// Addressable directly but hidden from public browse surfaces
54
+ Unlisted,
55
+ /// No longer offered for new installs or purchases
56
+ Retired
57
+ }
58
+
59
+ /// Plugin capability declaration
60
+ table PluginCapability {
61
+ /// Capability name, e.g., "gpu_compute", "wasm_simd"
62
+ NAME: string;
63
+ /// Capability version
64
+ VERSION: string;
65
+ /// Whether this capability is required
66
+ REQUIRED: bool;
67
+ }
68
+
69
+ /// Plugin dependency on another plugin
70
+ table PluginDependency {
71
+ /// Plugin ID of the dependency
72
+ PLUGIN_ID: string;
73
+ /// Minimum version required (semver)
74
+ MIN_VERSION: string;
75
+ /// Maximum version allowed (optional)
76
+ MAX_VERSION: string;
77
+ }
78
+
79
+ /// Plugin entry point function definition
80
+ table EntryFunction {
81
+ /// Function name as exported from WASM
82
+ NAME: string (required);
83
+ /// Human-readable description
84
+ DESCRIPTION: string;
85
+ /// Input parameter types (FlatBuffer schema names)
86
+ INPUT_SCHEMAS: [string];
87
+ /// Output type (FlatBuffer schema name)
88
+ OUTPUT_SCHEMA: string;
89
+ }
90
+
91
+ /// Plugin Manifest - canonical signed storefront and WASM distribution record
92
+ table PLG {
93
+ /// Unique identifier for the plugin
94
+ PLUGIN_ID: string (required);
95
+ /// Human-readable plugin name
96
+ NAME: string (required);
97
+ /// Plugin version (semver format)
98
+ VERSION: string (required);
99
+ /// Detailed description of plugin functionality
100
+ DESCRIPTION: string;
101
+ /// Short marketing summary shown in storefront listings
102
+ TAGLINE: string;
103
+ /// Type/category of the plugin
104
+ PLUGIN_TYPE: pluginCategory;
105
+ /// Human-readable publisher or organization name
106
+ PUBLISHER_NAME: string;
107
+ /// Publisher handle or username
108
+ PUBLISHER_HANDLE: string;
109
+ /// Canonical publisher website
110
+ PUBLISHER_URL: string;
111
+ /// Support or helpdesk URL for this plugin
112
+ SUPPORT_URL: string;
113
+ /// Search and categorization tags for discovery
114
+ TAGS: [string];
115
+ /// Short feature bullets highlighted in storefront listings
116
+ FEATURES: [string];
117
+ /// Screenshot URLs showing the plugin in use
118
+ SCREENSHOT_URLS: [string];
119
+ /// Optional hero/banner image URL for the listing
120
+ BANNER_URL: string;
121
+
122
+ /// ABI version for compatibility checking
123
+ ABI_VERSION: uint32 = 1;
124
+
125
+ /// SHA256 hash of the decrypted WASM binary
126
+ WASM_HASH: [ubyte];
127
+ /// Size of decrypted WASM binary in bytes
128
+ WASM_SIZE: uint64;
129
+ /// IPFS CID of the encrypted WASM binary
130
+ WASM_CID: string;
131
+ /// SHA256 hash of the encrypted delivery artifact bytes
132
+ ENCRYPTED_WASM_HASH: [ubyte];
133
+ /// Size of the encrypted delivery artifact in bytes
134
+ ENCRYPTED_WASM_SIZE: uint64;
135
+
136
+ /// Entry point functions exported by the plugin
137
+ ENTRY_FUNCTIONS: [EntryFunction];
138
+ /// FlatBuffer schemas required by this plugin
139
+ REQUIRED_SCHEMAS: [string];
140
+ /// Other plugins this depends on
141
+ DEPENDENCIES: [PluginDependency];
142
+ /// Capabilities provided by this plugin
143
+ CAPABILITIES: [PluginCapability];
144
+
145
+ /// Peer ID of the plugin provider
146
+ PROVIDER_PEER_ID: string;
147
+ /// IPFS CID of provider's EPM (Entity Profile Message)
148
+ PROVIDER_EPM_CID: string;
149
+
150
+ /// Whether the WASM binary is encrypted
151
+ ENCRYPTED: bool = true;
152
+ /// Canonical required scope for grant issuance
153
+ REQUIRED_SCOPE: string;
154
+ /// Provider-local identifier for the module content key
155
+ KEY_ID: string;
156
+ /// Allowed requester domains for module grants
157
+ ALLOWED_DOMAINS: [string];
158
+ /// Maximum grant timeout allowed for this module publication
159
+ MAX_GRANT_TIMEOUT_MS: uint64;
160
+ /// Minimum permissions required to run
161
+ MIN_PERMISSIONS: [string];
162
+
163
+ /// Unix timestamp when plugin was created
164
+ CREATED_AT: uint64;
165
+ /// Unix timestamp when plugin was last updated
166
+ UPDATED_AT: uint64;
167
+ /// URL to plugin documentation
168
+ DOCUMENTATION_URL: string;
169
+ /// URL to plugin changelog or release notes
170
+ CHANGELOG_URL: string;
171
+ /// URL to plugin icon/logo
172
+ ICON_URL: string;
173
+ /// License identifier (SPDX format)
174
+ LICENSE: string;
175
+ /// Commercial model used for storefront purchase flows
176
+ PAYMENT_MODEL: purchaseTier = Free;
177
+ /// Price in USD cents for one-time purchase or subscription period
178
+ PRICE_USD_CENTS: uint32;
179
+ /// Subscription billing period length in days
180
+ SUBSCRIPTION_PERIOD_DAYS: uint32;
181
+ /// Accepted payment methods, e.g. "stripe", "sol", "usdc"
182
+ ACCEPTED_PAYMENT_METHODS: [string];
183
+ /// Storefront publication state for this manifest version
184
+ LISTING_STATUS: publicationState = Public;
185
+
186
+ /// Ed25519 signature from provider over manifest
187
+ SIGNATURE: [ubyte];
188
+ }
189
+
190
+ root_type PLG;
191
+ file_identifier "$PLG";
@@ -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";
@@ -226,20 +232,36 @@ function normalizeJsonPayload(value) {
226
232
  return new Uint8Array(canonicalBytes(value));
227
233
  }
228
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
+
229
245
  function normalizeManifestEntry(manifest, manifestBytes) {
230
246
  if (!manifest && !manifestBytes) {
231
247
  return null;
232
248
  }
233
- const payload = manifestBytes ?? encodePluginManifest(manifest);
249
+ const payload = manifestBytes ?? encodeBundleManifest(manifest);
250
+ const isPlg = isPlgManifestBuffer(payload);
234
251
  return {
235
252
  entryId: "manifest",
236
253
  role: "manifest",
237
254
  sectionName: "sds.manifest",
238
255
  payloadEncoding: "flatbuffer",
239
- typeRef: {
240
- schemaName: "PluginManifest.fbs",
241
- fileIdentifier: "PMAN",
242
- },
256
+ typeRef: isPlg
257
+ ? {
258
+ schemaName: "PLG.fbs",
259
+ fileIdentifier: "$PLG",
260
+ }
261
+ : {
262
+ schemaName: "PluginManifest.fbs",
263
+ fileIdentifier: "PMAN",
264
+ },
243
265
  payload,
244
266
  description: "Canonical plugin manifest.",
245
267
  };
@@ -330,7 +352,7 @@ function buildParsedEntries(bundle) {
330
352
  parsedEntry.payloadEncodingName === "flatbuffer"
331
353
  ) {
332
354
  try {
333
- parsedEntry.decodedManifest = decodePluginManifest(payloadBytes);
355
+ parsedEntry.decodedManifest = decodeBundleManifest(payloadBytes);
334
356
  } catch {
335
357
  parsedEntry.decodedManifest = null;
336
358
  }
@@ -380,7 +402,7 @@ export async function createSingleFileBundle(options = {}) {
380
402
  options.manifestBytes !== undefined
381
403
  ? normalizeBytes(options.manifestBytes, "manifestBytes")
382
404
  : options.manifest
383
- ? encodePluginManifest(options.manifest)
405
+ ? encodeBundleManifest(options.manifest)
384
406
  : null;
385
407
  const manifestEntry = normalizeManifestEntry(options.manifest, manifestBytes);
386
408
  const rawEntries = [
@@ -463,7 +485,7 @@ export async function parseSingleFileBundle(bytes, options = {}) {
463
485
  let manifest = null;
464
486
  if (manifestEntry) {
465
487
  try {
466
- manifest = decodePluginManifest(new Uint8Array(manifestEntry.payload ?? []));
488
+ manifest = decodeBundleManifest(new Uint8Array(manifestEntry.payload ?? []));
467
489
  } catch {
468
490
  manifest = null;
469
491
  }
@@ -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