space-data-module-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +174 -83
  3. package/bin/space-data-module.js +24 -0
  4. package/package.json +8 -3
  5. package/schemas/ModuleBundle.fbs +108 -0
  6. package/schemas/PluginManifest.fbs +26 -1
  7. package/src/bundle/codec.js +244 -0
  8. package/src/bundle/constants.js +8 -0
  9. package/src/bundle/index.js +3 -0
  10. package/src/bundle/wasm.js +447 -0
  11. package/src/compiler/compileModule.js +189 -41
  12. package/src/compliance/pluginCompliance.js +334 -0
  13. package/src/generated/orbpro/manifest/capability-kind.d.ts +27 -2
  14. package/src/generated/orbpro/manifest/capability-kind.js +26 -1
  15. package/src/generated/orbpro/manifest/capability-kind.ts +25 -0
  16. package/src/generated/orbpro/module/canonicalization-rule.d.ts +48 -0
  17. package/src/generated/orbpro/module/canonicalization-rule.js +95 -0
  18. package/src/generated/orbpro/module/canonicalization-rule.ts +142 -0
  19. package/src/generated/orbpro/module/module-bundle-entry-role.d.ts +11 -0
  20. package/src/generated/orbpro/module/module-bundle-entry-role.js +14 -0
  21. package/src/generated/orbpro/module/module-bundle-entry-role.ts +15 -0
  22. package/src/generated/orbpro/module/module-bundle-entry.d.ts +97 -0
  23. package/src/generated/orbpro/module/module-bundle-entry.js +219 -0
  24. package/src/generated/orbpro/module/module-bundle-entry.ts +287 -0
  25. package/src/generated/orbpro/module/module-bundle.d.ts +86 -0
  26. package/src/generated/orbpro/module/module-bundle.js +213 -0
  27. package/src/generated/orbpro/module/module-bundle.ts +277 -0
  28. package/src/generated/orbpro/module/module-payload-encoding.d.ts +9 -0
  29. package/src/generated/orbpro/module/module-payload-encoding.js +12 -0
  30. package/src/generated/orbpro/module/module-payload-encoding.ts +13 -0
  31. package/src/generated/orbpro/module.d.ts +5 -0
  32. package/src/generated/orbpro/module.js +7 -0
  33. package/src/generated/orbpro/module.ts +9 -0
  34. package/src/host/abi.js +282 -0
  35. package/src/host/cron.js +247 -0
  36. package/src/host/index.js +3 -0
  37. package/src/host/nodeHost.js +2165 -0
  38. package/src/index.d.ts +880 -0
  39. package/src/index.js +9 -2
  40. package/src/manifest/normalize.js +32 -1
  41. package/src/runtime/constants.js +18 -1
  42. package/src/transport/pki.js +0 -5
  43. package/src/utils/encoding.js +9 -1
  44. package/src/utils/wasmCrypto.js +49 -1
@@ -0,0 +1,108 @@
1
+ // Space Data Module SDK - Single-file Module Bundle Schema
2
+ //
3
+ // Draft schema for packaging a loadable WebAssembly module together with
4
+ // SDS-typed metadata inside one `sds.bundle` custom section.
5
+
6
+ include "TypedArenaBuffer.fbs";
7
+
8
+ namespace orbpro.module;
9
+
10
+ /// Logical role for one payload carried in the bundle.
11
+ enum ModuleBundleEntryRole : ubyte {
12
+ MANIFEST = 0,
13
+ AUTHORIZATION = 1,
14
+ SIGNATURE = 2,
15
+ TRANSPORT = 3,
16
+ ATTESTATION = 4,
17
+ AUXILIARY = 5
18
+ }
19
+
20
+ /// Serialization format used by an entry payload.
21
+ enum ModulePayloadEncoding : ubyte {
22
+ RAW_BYTES = 0,
23
+ FLATBUFFER = 1,
24
+ JSON_UTF8 = 2,
25
+ CBOR = 3
26
+ }
27
+
28
+ /// Canonicalization rule applied before hashing or signature verification.
29
+ table CanonicalizationRule {
30
+ /// Schema version for the canonicalization contract.
31
+ version: uint16 = 1;
32
+
33
+ /// Strip any custom section whose name starts with this prefix before
34
+ /// hashing the module for signature verification.
35
+ stripped_custom_section_prefix: string;
36
+
37
+ /// Name of the required root custom section carrying this bundle.
38
+ bundle_section_name: string;
39
+
40
+ /// Hash function identifier, for example `sha256`.
41
+ hash_algorithm: string;
42
+ }
43
+
44
+ /// One payload carried inside the bundle.
45
+ table ModuleBundleEntry {
46
+ /// Stable bundle-local identifier.
47
+ entry_id: string (required, key);
48
+
49
+ /// High-level semantic role of the payload.
50
+ role: ModuleBundleEntryRole = AUXILIARY;
51
+
52
+ /// Optional logical section name within the bundle, for example
53
+ /// `sds.authorization`.
54
+ section_name: string;
55
+
56
+ /// SDS/shared-module schema identity when the payload is itself a
57
+ /// FlatBuffer.
58
+ type_ref: orbpro.stream.FlatBufferTypeRef;
59
+
60
+ /// Encoding used for `payload`.
61
+ payload_encoding: ModulePayloadEncoding = RAW_BYTES;
62
+
63
+ /// Optional media type for transitional payloads such as JSON envelopes.
64
+ media_type: string;
65
+
66
+ /// Implementation-defined bit flags for signed/encrypted/compressed state.
67
+ flags: uint32 = 0;
68
+
69
+ /// SHA-256 of the payload bytes.
70
+ sha256: [ubyte];
71
+
72
+ /// Embedded payload bytes. For single-file deployment this should be
73
+ /// populated for every entry.
74
+ payload: [ubyte];
75
+
76
+ /// Human-readable description for tooling and diagnostics.
77
+ description: string;
78
+ }
79
+
80
+ /// Metadata stored in the required `sds.bundle` custom section.
81
+ table ModuleBundle {
82
+ /// Bundle schema version.
83
+ bundle_version: uint16 = 1;
84
+
85
+ /// Human-readable package format label.
86
+ module_format: string;
87
+
88
+ /// Canonicalization rule used to compute module hashes.
89
+ canonicalization: CanonicalizationRule;
90
+
91
+ /// SHA-256 of the wasm module after stripping `sds.*` custom sections.
92
+ canonical_module_hash: [ubyte];
93
+
94
+ /// SHA-256 of the canonical plugin manifest bytes.
95
+ manifest_hash: [ubyte];
96
+
97
+ /// Legacy ABI export retained for backward compatibility.
98
+ manifest_export_symbol: string;
99
+
100
+ /// Legacy ABI export retained for backward compatibility.
101
+ manifest_size_symbol: string;
102
+
103
+ /// Payloads embedded in the bundle.
104
+ entries: [ModuleBundleEntry];
105
+ }
106
+
107
+ root_type ModuleBundle;
108
+ file_identifier "SMDB";
@@ -33,7 +33,32 @@ enum CapabilityKind : ushort {
33
33
  STORAGE_QUERY = 7,
34
34
  SCENE_ACCESS = 8,
35
35
  ENTITY_ACCESS = 9,
36
- RENDER_HOOKS = 10
36
+ RENDER_HOOKS = 10,
37
+ HTTP = 11,
38
+ FILESYSTEM = 12,
39
+ PIPE = 13,
40
+ NETWORK = 14,
41
+ DATABASE = 15,
42
+ STORAGE_ADAPTER = 16,
43
+ STORAGE_WRITE = 17,
44
+ WALLET_SIGN = 18,
45
+ IPFS = 19,
46
+ TLS = 20,
47
+ MQTT = 21,
48
+ WEBSOCKET = 22,
49
+ TCP = 23,
50
+ UDP = 24,
51
+ PROCESS_EXEC = 25,
52
+ CONTEXT_READ = 26,
53
+ CONTEXT_WRITE = 27,
54
+ CRYPTO_HASH = 28,
55
+ CRYPTO_SIGN = 29,
56
+ CRYPTO_VERIFY = 30,
57
+ CRYPTO_ENCRYPT = 31,
58
+ CRYPTO_DECRYPT = 32,
59
+ CRYPTO_KEY_AGREEMENT = 33,
60
+ CRYPTO_KDF = 34,
61
+ SCHEDULE_CRON = 35
37
62
  }
38
63
 
39
64
  /// Drain policy for methods that operate over queued stream frames.
@@ -0,0 +1,244 @@
1
+ import * as flatbuffers from "flatbuffers";
2
+
3
+ import {
4
+ CanonicalizationRuleT,
5
+ ModuleBundle,
6
+ ModuleBundleEntryRole,
7
+ ModuleBundleEntryT,
8
+ ModuleBundleT,
9
+ ModulePayloadEncoding,
10
+ } from "../generated/orbpro/module.js";
11
+ import { FlatBufferTypeRefT } from "../generated/orbpro/stream/flat-buffer-type-ref.js";
12
+ import { canonicalBytes } from "../auth/canonicalize.js";
13
+ import { toUint8Array as toBufferLikeUint8Array } from "../runtime/bufferLike.js";
14
+ import {
15
+ DEFAULT_HASH_ALGORITHM,
16
+ DEFAULT_MANIFEST_EXPORT_SYMBOL,
17
+ DEFAULT_MANIFEST_SIZE_SYMBOL,
18
+ DEFAULT_MODULE_FORMAT,
19
+ SDS_BUNDLE_SECTION_NAME,
20
+ SDS_CUSTOM_SECTION_PREFIX,
21
+ } from "./constants.js";
22
+
23
+ const textEncoder = new TextEncoder();
24
+
25
+ const ROLE_NAME_TO_ENUM = new Map([
26
+ ["manifest", ModuleBundleEntryRole.MANIFEST],
27
+ ["authorization", ModuleBundleEntryRole.AUTHORIZATION],
28
+ ["signature", ModuleBundleEntryRole.SIGNATURE],
29
+ ["transport", ModuleBundleEntryRole.TRANSPORT],
30
+ ["attestation", ModuleBundleEntryRole.ATTESTATION],
31
+ ["auxiliary", ModuleBundleEntryRole.AUXILIARY],
32
+ ]);
33
+
34
+ const ROLE_ENUM_TO_NAME = new Map(
35
+ Array.from(ROLE_NAME_TO_ENUM, ([name, value]) => [value, name]),
36
+ );
37
+
38
+ const ENCODING_NAME_TO_ENUM = new Map([
39
+ ["raw-bytes", ModulePayloadEncoding.RAW_BYTES],
40
+ ["flatbuffer", ModulePayloadEncoding.FLATBUFFER],
41
+ ["json-utf8", ModulePayloadEncoding.JSON_UTF8],
42
+ ["cbor", ModulePayloadEncoding.CBOR],
43
+ ]);
44
+
45
+ const ENCODING_ENUM_TO_NAME = new Map(
46
+ Array.from(ENCODING_NAME_TO_ENUM, ([name, value]) => [value, name]),
47
+ );
48
+
49
+ function toByteBuffer(data) {
50
+ if (data instanceof flatbuffers.ByteBuffer) {
51
+ return data;
52
+ }
53
+ const bytes = toBufferLikeUint8Array(data);
54
+ if (bytes) {
55
+ return new flatbuffers.ByteBuffer(bytes);
56
+ }
57
+ throw new TypeError(
58
+ "Expected ByteBuffer, Uint8Array, ArrayBufferView, or ArrayBuffer.",
59
+ );
60
+ }
61
+
62
+ function normalizeString(value, fallback = null) {
63
+ if (value === undefined || value === null) {
64
+ return fallback;
65
+ }
66
+ return String(value);
67
+ }
68
+
69
+ function normalizeByteArray(value, { encoding = null } = {}) {
70
+ if (value === undefined || value === null) {
71
+ return [];
72
+ }
73
+ if (Array.isArray(value)) {
74
+ return value.map((byte) => Number(byte) & 0xff);
75
+ }
76
+ const bytes = toBufferLikeUint8Array(value);
77
+ if (bytes) {
78
+ return Array.from(bytes);
79
+ }
80
+ if (typeof value === "string") {
81
+ return Array.from(textEncoder.encode(value));
82
+ }
83
+ if (encoding === ModulePayloadEncoding.JSON_UTF8) {
84
+ return Array.from(canonicalBytes(value));
85
+ }
86
+ throw new TypeError(
87
+ "Expected payload bytes, ArrayBufferView, ArrayBuffer, string, or JSON value.",
88
+ );
89
+ }
90
+
91
+ function normalizeRole(value) {
92
+ if (typeof value === "number") {
93
+ return value;
94
+ }
95
+ const normalized = String(value ?? "auxiliary")
96
+ .trim()
97
+ .toLowerCase()
98
+ .replace(/_/g, "-");
99
+ return ROLE_NAME_TO_ENUM.get(normalized) ?? ModuleBundleEntryRole.AUXILIARY;
100
+ }
101
+
102
+ function normalizePayloadEncoding(value) {
103
+ if (typeof value === "number") {
104
+ return value;
105
+ }
106
+ const normalized = String(value ?? "raw-bytes")
107
+ .trim()
108
+ .toLowerCase()
109
+ .replace(/_/g, "-");
110
+ return (
111
+ ENCODING_NAME_TO_ENUM.get(normalized) ?? ModulePayloadEncoding.RAW_BYTES
112
+ );
113
+ }
114
+
115
+ function normalizeTypeRef(value) {
116
+ if (!value) {
117
+ return null;
118
+ }
119
+ if (value instanceof FlatBufferTypeRefT) {
120
+ return value;
121
+ }
122
+ return new FlatBufferTypeRefT(
123
+ normalizeString(value.schemaName),
124
+ normalizeString(value.fileIdentifier),
125
+ normalizeByteArray(value.schemaHash),
126
+ Boolean(value.acceptsAnyFlatbuffer),
127
+ );
128
+ }
129
+
130
+ function normalizeCanonicalization(value = {}) {
131
+ if (value instanceof CanonicalizationRuleT) {
132
+ return value;
133
+ }
134
+ return new CanonicalizationRuleT(
135
+ Number(value.version ?? 1),
136
+ normalizeString(
137
+ value.strippedCustomSectionPrefix,
138
+ SDS_CUSTOM_SECTION_PREFIX,
139
+ ),
140
+ normalizeString(value.bundleSectionName, SDS_BUNDLE_SECTION_NAME),
141
+ normalizeString(value.hashAlgorithm, DEFAULT_HASH_ALGORITHM),
142
+ );
143
+ }
144
+
145
+ function normalizeEntry(value = {}) {
146
+ if (value instanceof ModuleBundleEntryT) {
147
+ return value;
148
+ }
149
+ const payloadEncoding = normalizePayloadEncoding(value.payloadEncoding);
150
+ return new ModuleBundleEntryT(
151
+ normalizeString(value.entryId),
152
+ normalizeRole(value.role),
153
+ normalizeString(value.sectionName),
154
+ normalizeTypeRef(value.typeRef),
155
+ payloadEncoding,
156
+ normalizeString(value.mediaType),
157
+ Number(value.flags ?? 0),
158
+ normalizeByteArray(value.sha256),
159
+ normalizeByteArray(value.payload, { encoding: payloadEncoding }),
160
+ normalizeString(value.description),
161
+ );
162
+ }
163
+
164
+ export function decodeModuleBundle(data) {
165
+ const bb = toByteBuffer(data);
166
+ if (!ModuleBundle.bufferHasIdentifier(bb)) {
167
+ throw new Error("Module bundle buffer identifier mismatch.");
168
+ }
169
+ return ModuleBundle.getRootAsModuleBundle(bb).unpack();
170
+ }
171
+
172
+ export function encodeModuleBundle(bundle) {
173
+ const value =
174
+ bundle instanceof ModuleBundleT
175
+ ? bundle
176
+ : new ModuleBundleT(
177
+ Number(bundle?.bundleVersion ?? 1),
178
+ normalizeString(bundle?.moduleFormat, DEFAULT_MODULE_FORMAT),
179
+ normalizeCanonicalization(bundle?.canonicalization),
180
+ normalizeByteArray(bundle?.canonicalModuleHash),
181
+ normalizeByteArray(bundle?.manifestHash),
182
+ normalizeString(
183
+ bundle?.manifestExportSymbol,
184
+ DEFAULT_MANIFEST_EXPORT_SYMBOL,
185
+ ),
186
+ normalizeString(
187
+ bundle?.manifestSizeSymbol,
188
+ DEFAULT_MANIFEST_SIZE_SYMBOL,
189
+ ),
190
+ Array.isArray(bundle?.entries)
191
+ ? bundle.entries.map(normalizeEntry)
192
+ : [],
193
+ );
194
+ const builder = new flatbuffers.Builder(1024);
195
+ ModuleBundle.finishModuleBundleBuffer(builder, value.pack(builder));
196
+ return builder.asUint8Array();
197
+ }
198
+
199
+ export function moduleBundleRoleToName(value) {
200
+ return ROLE_ENUM_TO_NAME.get(value) ?? "auxiliary";
201
+ }
202
+
203
+ export function moduleBundleEncodingToName(value) {
204
+ return ENCODING_ENUM_TO_NAME.get(value) ?? "raw-bytes";
205
+ }
206
+
207
+ export function decodeModuleBundleEntryPayload(entry) {
208
+ const payloadEncoding = normalizePayloadEncoding(entry?.payloadEncoding);
209
+ const payloadBytes = new Uint8Array(
210
+ normalizeByteArray(entry?.payload, { encoding: payloadEncoding }),
211
+ );
212
+ if (payloadEncoding === ModulePayloadEncoding.JSON_UTF8) {
213
+ return JSON.parse(new TextDecoder().decode(payloadBytes));
214
+ }
215
+ return payloadBytes;
216
+ }
217
+
218
+ export function findModuleBundleEntry(bundle, match) {
219
+ const entries = Array.isArray(bundle?.entries) ? bundle.entries : [];
220
+ if (typeof match === "number") {
221
+ return entries.find((entry) => entry.role === match) ?? null;
222
+ }
223
+ const normalized = String(match ?? "")
224
+ .trim()
225
+ .toLowerCase()
226
+ .replace(/_/g, "-");
227
+ return (
228
+ entries.find((entry) => entry.entryId === match) ??
229
+ entries.find(
230
+ (entry) => moduleBundleRoleToName(normalizeRole(entry.role)) === normalized,
231
+ ) ??
232
+ null
233
+ );
234
+ }
235
+
236
+ export {
237
+ CanonicalizationRuleT,
238
+ FlatBufferTypeRefT,
239
+ ModuleBundle,
240
+ ModuleBundleEntryRole,
241
+ ModuleBundleEntryT,
242
+ ModuleBundleT,
243
+ ModulePayloadEncoding,
244
+ };
@@ -0,0 +1,8 @@
1
+ export const SDS_CUSTOM_SECTION_PREFIX = "sds.";
2
+ export const SDS_BUNDLE_SECTION_NAME = "sds.bundle";
3
+ export const DEFAULT_MODULE_FORMAT = "space-data-module";
4
+ export const DEFAULT_HASH_ALGORITHM = "sha256";
5
+ export const DEFAULT_MANIFEST_EXPORT_SYMBOL = "plugin_get_manifest_flatbuffer";
6
+ export const DEFAULT_MANIFEST_SIZE_SYMBOL =
7
+ "plugin_get_manifest_flatbuffer_size";
8
+
@@ -0,0 +1,3 @@
1
+ export * from "./constants.js";
2
+ export * from "./codec.js";
3
+ export * from "./wasm.js";