space-data-module-sdk 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/package.json +5 -1
- package/schemas/PluginManifest.fbs +9 -0
- package/src/bundle/constants.js +4 -1
- package/src/bundle/wasm.js +30 -2
- package/src/compliance/pluginCompliance.js +306 -1
- package/src/deployment/index.d.ts +224 -0
- package/src/deployment/index.js +1552 -0
- package/src/generated/orbpro/manifest/protocol-spec.d.ts +35 -3
- package/src/generated/orbpro/manifest/protocol-spec.js +120 -6
- package/src/generated/orbpro/manifest/protocol-spec.ts +191 -1
- package/src/index.d.ts +136 -3
- package/src/index.js +4 -0
- package/src/manifest/index.js +7 -0
- package/src/manifest/normalize.js +75 -5
- package/src/manifest/typeRefs.js +143 -0
- package/src/runtime/constants.js +13 -0
- package/src/runtime/index.d.ts +2 -0
- package/src/testing/index.d.ts +84 -0
- package/src/testing/index.js +414 -0
package/src/manifest/index.js
CHANGED
|
@@ -6,6 +6,13 @@ export {
|
|
|
6
6
|
} from "../generated/orbpro/stream/flat-buffer-type-ref.js";
|
|
7
7
|
export { decodePluginManifest, encodePluginManifest } from "./codec.js";
|
|
8
8
|
export { toEmbeddedPluginManifest } from "./normalize.js";
|
|
9
|
+
export {
|
|
10
|
+
clonePayloadTypeRef,
|
|
11
|
+
getPayloadTypeWireFormat,
|
|
12
|
+
normalizePayloadWireFormatName,
|
|
13
|
+
payloadTypeRefsMatch,
|
|
14
|
+
selectPreferredPayloadTypeRef,
|
|
15
|
+
} from "./typeRefs.js";
|
|
9
16
|
export {
|
|
10
17
|
generateEmbeddedManifestSource,
|
|
11
18
|
writeEmbeddedManifestArtifacts,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
TimerSpecT,
|
|
14
14
|
} from "../generated/orbpro/manifest.js";
|
|
15
15
|
import { FlatBufferTypeRefT } from "../generated/orbpro/stream/flat-buffer-type-ref.js";
|
|
16
|
+
import { ProtocolRole, ProtocolTransportKind } from "../runtime/constants.js";
|
|
16
17
|
|
|
17
18
|
const pluginFamilyByName = Object.freeze({
|
|
18
19
|
sensor: PluginFamily.SENSOR,
|
|
@@ -81,6 +82,31 @@ const invokeSurfaceByName = Object.freeze({
|
|
|
81
82
|
command: InvokeSurface.COMMAND,
|
|
82
83
|
});
|
|
83
84
|
|
|
85
|
+
const protocolTransportKindByName = Object.freeze({
|
|
86
|
+
libp2p: ProtocolTransportKind.LIBP2P,
|
|
87
|
+
http: ProtocolTransportKind.HTTP,
|
|
88
|
+
ws: ProtocolTransportKind.WS,
|
|
89
|
+
websocket: ProtocolTransportKind.WS,
|
|
90
|
+
"wasi-pipe": ProtocolTransportKind.WASI_PIPE,
|
|
91
|
+
wasi_pipe: ProtocolTransportKind.WASI_PIPE,
|
|
92
|
+
pipe: ProtocolTransportKind.WASI_PIPE,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const protocolRoleByName = Object.freeze({
|
|
96
|
+
handle: ProtocolRole.HANDLE,
|
|
97
|
+
handler: ProtocolRole.HANDLE,
|
|
98
|
+
dial: ProtocolRole.DIAL,
|
|
99
|
+
both: ProtocolRole.BOTH,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
function normalizeOptionalString(value) {
|
|
103
|
+
if (value === undefined || value === null) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const normalized = String(value).trim();
|
|
107
|
+
return normalized.length > 0 ? normalized : null;
|
|
108
|
+
}
|
|
109
|
+
|
|
84
110
|
function normalizeSchemaHash(value) {
|
|
85
111
|
if (!value) {
|
|
86
112
|
return [];
|
|
@@ -177,6 +203,41 @@ function normalizeInvokeSurfaces(value) {
|
|
|
177
203
|
return normalized;
|
|
178
204
|
}
|
|
179
205
|
|
|
206
|
+
function normalizeBoolean(value, fallback = false) {
|
|
207
|
+
if (value === undefined || value === null) {
|
|
208
|
+
return fallback;
|
|
209
|
+
}
|
|
210
|
+
return value === true;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function normalizeProtocolTransportKind(value) {
|
|
214
|
+
if (value === undefined || value === null) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
const normalized = String(value)
|
|
218
|
+
.trim()
|
|
219
|
+
.toLowerCase()
|
|
220
|
+
.replace(/_/g, "-");
|
|
221
|
+
if (normalized.length === 0) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
return protocolTransportKindByName[normalized] ?? normalized;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function normalizeProtocolRole(value) {
|
|
228
|
+
if (value === undefined || value === null) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const normalized = String(value)
|
|
232
|
+
.trim()
|
|
233
|
+
.toLowerCase()
|
|
234
|
+
.replace(/_/g, "-");
|
|
235
|
+
if (normalized.length === 0) {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
return protocolRoleByName[normalized] ?? normalized;
|
|
239
|
+
}
|
|
240
|
+
|
|
180
241
|
function toFlatBufferTypeRefT(value = {}) {
|
|
181
242
|
if (value instanceof FlatBufferTypeRefT) {
|
|
182
243
|
return value;
|
|
@@ -274,11 +335,20 @@ function toProtocolSpecT(value = {}) {
|
|
|
274
335
|
return value;
|
|
275
336
|
}
|
|
276
337
|
return new ProtocolSpecT(
|
|
277
|
-
value.protocolId
|
|
278
|
-
value.methodId
|
|
279
|
-
value.inputPortId
|
|
280
|
-
value.outputPortId
|
|
281
|
-
value.description
|
|
338
|
+
normalizeOptionalString(value.protocolId),
|
|
339
|
+
normalizeOptionalString(value.methodId),
|
|
340
|
+
normalizeOptionalString(value.inputPortId),
|
|
341
|
+
normalizeOptionalString(value.outputPortId),
|
|
342
|
+
normalizeOptionalString(value.description),
|
|
343
|
+
normalizeOptionalString(value.wireId),
|
|
344
|
+
normalizeProtocolTransportKind(value.transportKind),
|
|
345
|
+
normalizeProtocolRole(value.role),
|
|
346
|
+
normalizeOptionalString(value.specUri),
|
|
347
|
+
normalizeBoolean(value.autoInstall, true),
|
|
348
|
+
normalizeBoolean(value.advertise, false),
|
|
349
|
+
normalizeOptionalString(value.discoveryKey),
|
|
350
|
+
normalizeUnsignedInteger(value.defaultPort),
|
|
351
|
+
normalizeBoolean(value.requireSecureTransport, false),
|
|
282
352
|
);
|
|
283
353
|
}
|
|
284
354
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
function cloneSchemaHash(value) {
|
|
2
|
+
if (value instanceof Uint8Array) {
|
|
3
|
+
return new Uint8Array(value);
|
|
4
|
+
}
|
|
5
|
+
if (Array.isArray(value)) {
|
|
6
|
+
return [...value];
|
|
7
|
+
}
|
|
8
|
+
return value ?? undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function clonePayloadTypeRef(value = null) {
|
|
12
|
+
if (!value || typeof value !== "object") {
|
|
13
|
+
return { acceptsAnyFlatbuffer: true };
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
schemaName: value.schemaName ?? value.schema_name ?? undefined,
|
|
17
|
+
fileIdentifier: value.fileIdentifier ?? value.file_identifier ?? undefined,
|
|
18
|
+
schemaHash: cloneSchemaHash(value.schemaHash ?? value.schema_hash),
|
|
19
|
+
acceptsAnyFlatbuffer: Boolean(
|
|
20
|
+
value.acceptsAnyFlatbuffer ?? value.accepts_any_flatbuffer ?? false,
|
|
21
|
+
),
|
|
22
|
+
wireFormat: value.wireFormat ?? value.wire_format ?? undefined,
|
|
23
|
+
rootTypeName: value.rootTypeName ?? value.root_type_name ?? undefined,
|
|
24
|
+
fixedStringLength:
|
|
25
|
+
value.fixedStringLength ?? value.fixed_string_length ?? undefined,
|
|
26
|
+
byteLength: value.byteLength ?? value.byte_length ?? undefined,
|
|
27
|
+
requiredAlignment:
|
|
28
|
+
value.requiredAlignment ?? value.required_alignment ?? undefined,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function normalizePayloadWireFormatName(value) {
|
|
33
|
+
if (value === undefined || value === null || value === "") {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const normalized = String(value).trim().toLowerCase().replace(/_/g, "-");
|
|
37
|
+
if (normalized === "aligned-binary") {
|
|
38
|
+
return "aligned-binary";
|
|
39
|
+
}
|
|
40
|
+
if (normalized === "flatbuffer") {
|
|
41
|
+
return "flatbuffer";
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getPayloadTypeWireFormat(typeRef = {}) {
|
|
47
|
+
return normalizePayloadWireFormatName(typeRef.wireFormat) ?? "flatbuffer";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function schemaHashMatches(expected, actual) {
|
|
51
|
+
if (!Array.isArray(expected) && !(expected instanceof Uint8Array)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
const expectedArray = Array.from(expected);
|
|
55
|
+
if (expectedArray.length === 0) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
const actualArray =
|
|
59
|
+
Array.isArray(actual) || actual instanceof Uint8Array
|
|
60
|
+
? Array.from(actual)
|
|
61
|
+
: null;
|
|
62
|
+
if (!actualArray || actualArray.length !== expectedArray.length) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
for (let index = 0; index < expectedArray.length; index += 1) {
|
|
66
|
+
if (expectedArray[index] !== actualArray[index]) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function optionalScalarMatches(expected, actual) {
|
|
74
|
+
return expected === undefined || expected === null || expected === actual;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function payloadTypeRefsMatch(expectedTypeRef = {}, actualTypeRef = {}) {
|
|
78
|
+
const expected = clonePayloadTypeRef(expectedTypeRef);
|
|
79
|
+
const actual = clonePayloadTypeRef(actualTypeRef);
|
|
80
|
+
const expectedWireFormat = getPayloadTypeWireFormat(expected);
|
|
81
|
+
const actualWireFormat = getPayloadTypeWireFormat(actual);
|
|
82
|
+
|
|
83
|
+
if (expected.acceptsAnyFlatbuffer === true) {
|
|
84
|
+
return actualWireFormat === "flatbuffer";
|
|
85
|
+
}
|
|
86
|
+
if (expectedWireFormat !== actualWireFormat) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
if (expected.schemaName && expected.schemaName !== actual.schemaName) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
expected.fileIdentifier &&
|
|
94
|
+
expected.fileIdentifier !== actual.fileIdentifier
|
|
95
|
+
) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
if (!schemaHashMatches(expected.schemaHash, actual.schemaHash)) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (expectedWireFormat === "aligned-binary") {
|
|
102
|
+
if (!optionalScalarMatches(expected.rootTypeName, actual.rootTypeName)) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if (!optionalScalarMatches(expected.fixedStringLength, actual.fixedStringLength)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
if (!optionalScalarMatches(expected.byteLength, actual.byteLength)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if (
|
|
112
|
+
!optionalScalarMatches(expected.requiredAlignment, actual.requiredAlignment)
|
|
113
|
+
) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function selectPreferredPayloadTypeRef(port = {}, options = {}) {
|
|
121
|
+
const preferredWireFormat = normalizePayloadWireFormatName(
|
|
122
|
+
options.preferredWireFormat,
|
|
123
|
+
);
|
|
124
|
+
let fallback = null;
|
|
125
|
+
for (const typeSet of Array.isArray(port.acceptedTypeSets) ? port.acceptedTypeSets : []) {
|
|
126
|
+
const allowedTypes = Array.isArray(typeSet.allowedTypes)
|
|
127
|
+
? typeSet.allowedTypes
|
|
128
|
+
: [];
|
|
129
|
+
for (const allowedType of allowedTypes) {
|
|
130
|
+
const candidate = clonePayloadTypeRef(allowedType);
|
|
131
|
+
if (fallback === null) {
|
|
132
|
+
fallback = candidate;
|
|
133
|
+
}
|
|
134
|
+
if (
|
|
135
|
+
preferredWireFormat !== null &&
|
|
136
|
+
getPayloadTypeWireFormat(candidate) === preferredWireFormat
|
|
137
|
+
) {
|
|
138
|
+
return candidate;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return fallback ?? clonePayloadTypeRef(null);
|
|
143
|
+
}
|
package/src/runtime/constants.js
CHANGED
|
@@ -48,6 +48,19 @@ export const InvokeSurface = Object.freeze({
|
|
|
48
48
|
COMMAND: "command",
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
export const ProtocolTransportKind = Object.freeze({
|
|
52
|
+
LIBP2P: "libp2p",
|
|
53
|
+
HTTP: "http",
|
|
54
|
+
WS: "ws",
|
|
55
|
+
WASI_PIPE: "wasi-pipe",
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export const ProtocolRole = Object.freeze({
|
|
59
|
+
HANDLE: "handle",
|
|
60
|
+
DIAL: "dial",
|
|
61
|
+
BOTH: "both",
|
|
62
|
+
});
|
|
63
|
+
|
|
51
64
|
export const DefaultManifestExports = Object.freeze({
|
|
52
65
|
pluginBytesSymbol: "plugin_get_manifest_flatbuffer",
|
|
53
66
|
pluginSizeSymbol: "plugin_get_manifest_flatbuffer_size",
|
package/src/runtime/index.d.ts
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
InvokeSurface,
|
|
3
|
+
PayloadTypeRef,
|
|
4
|
+
PayloadWireFormat,
|
|
5
|
+
PluginManifest,
|
|
6
|
+
} from "../index.js";
|
|
7
|
+
|
|
8
|
+
export interface HarnessInputFrame {
|
|
9
|
+
portId?: string | null;
|
|
10
|
+
typeRef?: PayloadTypeRef | null;
|
|
11
|
+
payload?: Uint8Array | ArrayBuffer | ArrayBufferView | string | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface HarnessInvokeScenario {
|
|
15
|
+
id: string;
|
|
16
|
+
kind: "invoke";
|
|
17
|
+
surface: InvokeSurface;
|
|
18
|
+
methodId: string;
|
|
19
|
+
displayName?: string | null;
|
|
20
|
+
inputs?: HarnessInputFrame[];
|
|
21
|
+
requiredPortIds?: string[];
|
|
22
|
+
expectedStatusCode?: number;
|
|
23
|
+
notes?: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface HarnessRawScenario {
|
|
27
|
+
id: string;
|
|
28
|
+
kind: string;
|
|
29
|
+
stdinBytes?: Uint8Array | ArrayBuffer | ArrayBufferView | string | null;
|
|
30
|
+
notes?: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface CapabilityRuntimeSurface {
|
|
34
|
+
capability: string;
|
|
35
|
+
wasi: boolean;
|
|
36
|
+
syncHostcall: boolean;
|
|
37
|
+
nodeHostApi: boolean;
|
|
38
|
+
notes: string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ManifestHarnessPlan {
|
|
42
|
+
moduleKind: "module" | "flow";
|
|
43
|
+
pluginId: string | null;
|
|
44
|
+
name: string | null;
|
|
45
|
+
version: string | null;
|
|
46
|
+
invokeSurfaces: InvokeSurface[];
|
|
47
|
+
methods: Array<{
|
|
48
|
+
methodId: string | null;
|
|
49
|
+
displayName: string | null;
|
|
50
|
+
inputPorts: number;
|
|
51
|
+
outputPorts: number;
|
|
52
|
+
}>;
|
|
53
|
+
capabilities: CapabilityRuntimeSurface[];
|
|
54
|
+
generatedCases: HarnessInvokeScenario[];
|
|
55
|
+
scenarios: Array<HarnessInvokeScenario | HarnessRawScenario>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function describeCapabilityRuntimeSurface(
|
|
59
|
+
capability: string,
|
|
60
|
+
): CapabilityRuntimeSurface;
|
|
61
|
+
|
|
62
|
+
export function generateManifestHarnessPlan(options: {
|
|
63
|
+
manifest: PluginManifest;
|
|
64
|
+
includeOptionalInputs?: boolean;
|
|
65
|
+
expectedStatusCode?: number;
|
|
66
|
+
preferredWireFormat?: PayloadWireFormat;
|
|
67
|
+
payloadForPort?: (context: {
|
|
68
|
+
methodId: string | null;
|
|
69
|
+
portId: string | null;
|
|
70
|
+
port: unknown;
|
|
71
|
+
required: boolean;
|
|
72
|
+
typeRef: PayloadTypeRef;
|
|
73
|
+
}) => Uint8Array | ArrayBuffer | ArrayBufferView | string | null | undefined;
|
|
74
|
+
scenarios?: Array<HarnessInvokeScenario | HarnessRawScenario>;
|
|
75
|
+
}): ManifestHarnessPlan;
|
|
76
|
+
|
|
77
|
+
export function materializeHarnessScenario(
|
|
78
|
+
scenario: HarnessInvokeScenario | HarnessRawScenario,
|
|
79
|
+
): (HarnessInvokeScenario | HarnessRawScenario) & {
|
|
80
|
+
stdinBytes?: Uint8Array;
|
|
81
|
+
requestBytes?: Uint8Array;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export function serializeHarnessPlan(plan: ManifestHarnessPlan): unknown;
|