space-data-module-sdk 0.2.8 → 0.3.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.
- package/README.md +5 -1
- package/package.json +1 -1
- package/src/deployment/index.d.ts +4 -7
- package/src/deployment/index.js +124 -89
package/README.md
CHANGED
|
@@ -223,11 +223,15 @@ Concrete multiaddrs, peer IDs, and producer routing do not belong in the
|
|
|
223
223
|
canonical manifest. They belong in deployment metadata attached to the final
|
|
224
224
|
package or bundle.
|
|
225
225
|
|
|
226
|
+
Deployment plans should key resolved protocol installations by `protocolId`.
|
|
227
|
+
They may include `wireId` as optional legacy metadata when a concrete transport
|
|
228
|
+
still needs it.
|
|
229
|
+
|
|
226
230
|
This repo exposes that deployment surface from
|
|
227
231
|
`space-data-module-sdk/deployment`. Use it to:
|
|
228
232
|
|
|
229
233
|
- validate resolved protocol installations
|
|
230
|
-
- describe input
|
|
234
|
+
- describe input and publication bindings by declared `interfaceId`
|
|
231
235
|
- attach a deployment plan to `sds.bundle`
|
|
232
236
|
|
|
233
237
|
The full contract split is documented in
|
package/package.json
CHANGED
|
@@ -14,7 +14,7 @@ export type ScheduleBindingKindName = "interval" | "cron" | "once";
|
|
|
14
14
|
|
|
15
15
|
export interface ResolvedProtocolInstallation {
|
|
16
16
|
protocolId: string;
|
|
17
|
-
wireId
|
|
17
|
+
wireId?: string | null;
|
|
18
18
|
transportKind: ProtocolTransportKindName | string;
|
|
19
19
|
role: ProtocolRoleName | string;
|
|
20
20
|
peerId?: string | null;
|
|
@@ -29,13 +29,11 @@ export interface ResolvedProtocolInstallation {
|
|
|
29
29
|
|
|
30
30
|
export interface InputBinding {
|
|
31
31
|
bindingId: string;
|
|
32
|
+
interfaceId: string;
|
|
32
33
|
targetPluginId?: string | null;
|
|
33
34
|
targetMethodId: string;
|
|
34
35
|
targetInputPortId: string;
|
|
35
36
|
sourceKind: InputBindingSourceKindName | string;
|
|
36
|
-
topic?: string | null;
|
|
37
|
-
wireId?: string | null;
|
|
38
|
-
nodeInfoUrl?: string | null;
|
|
39
37
|
multiaddrs?: string[];
|
|
40
38
|
allowPeerIds?: string[];
|
|
41
39
|
allowServerKeys?: string[];
|
|
@@ -96,18 +94,17 @@ export interface AuthPolicy {
|
|
|
96
94
|
|
|
97
95
|
export interface PublicationBinding {
|
|
98
96
|
publicationId: string;
|
|
97
|
+
interfaceId: string;
|
|
99
98
|
bindingMode: DeploymentBindingModeName | string;
|
|
100
99
|
sourceKind: string;
|
|
101
100
|
sourceMethodId?: string | null;
|
|
102
101
|
sourceOutputPortId?: string | null;
|
|
103
102
|
sourceNodeId?: string | null;
|
|
104
103
|
sourceTriggerId?: string | null;
|
|
105
|
-
topic?: string | null;
|
|
106
|
-
wireId?: string | null;
|
|
107
104
|
schemaName?: string | null;
|
|
108
105
|
mediaType?: string | null;
|
|
109
106
|
archivePath?: string | null;
|
|
110
|
-
|
|
107
|
+
queryInterfaceId?: string | null;
|
|
111
108
|
emitPnm?: boolean;
|
|
112
109
|
emitFlatbufferArchive?: boolean;
|
|
113
110
|
pinPolicy?: string | null;
|
package/src/deployment/index.js
CHANGED
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
SDS_DEPLOYMENT_MEDIA_TYPE,
|
|
8
8
|
SDS_DEPLOYMENT_SECTION_NAME,
|
|
9
9
|
} from "../bundle/constants.js";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
ExternalInterfaceDirection,
|
|
12
|
+
ProtocolRole,
|
|
13
|
+
ProtocolTransportKind,
|
|
14
|
+
} from "../runtime/constants.js";
|
|
11
15
|
|
|
12
16
|
export const DEPLOYMENT_PLAN_FORMAT_VERSION = 1;
|
|
13
17
|
|
|
@@ -33,6 +37,14 @@ const DeploymentBindingModeSet = new Set(Object.values(DeploymentBindingMode));
|
|
|
33
37
|
const ProtocolRoleSet = new Set(Object.values(ProtocolRole));
|
|
34
38
|
const ProtocolTransportKindSet = new Set(Object.values(ProtocolTransportKind));
|
|
35
39
|
const ScheduleBindingKindSet = new Set(Object.values(ScheduleBindingKind));
|
|
40
|
+
const InputBindingInterfaceDirectionSet = new Set([
|
|
41
|
+
ExternalInterfaceDirection.INPUT,
|
|
42
|
+
ExternalInterfaceDirection.BIDIRECTIONAL,
|
|
43
|
+
]);
|
|
44
|
+
const PublicationBindingInterfaceDirectionSet = new Set([
|
|
45
|
+
ExternalInterfaceDirection.OUTPUT,
|
|
46
|
+
ExternalInterfaceDirection.BIDIRECTIONAL,
|
|
47
|
+
]);
|
|
36
48
|
|
|
37
49
|
function normalizeString(value) {
|
|
38
50
|
if (value === undefined || value === null) {
|
|
@@ -163,13 +175,11 @@ function normalizeProtocolInstallation(value = {}) {
|
|
|
163
175
|
function normalizeInputBinding(value = {}) {
|
|
164
176
|
return {
|
|
165
177
|
bindingId: normalizeString(value.bindingId),
|
|
178
|
+
interfaceId: normalizeString(value.interfaceId),
|
|
166
179
|
targetPluginId: normalizeString(value.targetPluginId),
|
|
167
180
|
targetMethodId: normalizeString(value.targetMethodId),
|
|
168
181
|
targetInputPortId: normalizeString(value.targetInputPortId),
|
|
169
182
|
sourceKind: normalizeInputBindingSourceKindName(value.sourceKind),
|
|
170
|
-
topic: normalizeString(value.topic),
|
|
171
|
-
wireId: normalizeString(value.wireId),
|
|
172
|
-
nodeInfoUrl: normalizeString(value.nodeInfoUrl),
|
|
173
183
|
multiaddrs: normalizeStringArray(value.multiaddrs),
|
|
174
184
|
allowPeerIds: normalizeStringArray(value.allowPeerIds),
|
|
175
185
|
allowServerKeys: normalizeStringArray(value.allowServerKeys),
|
|
@@ -238,18 +248,17 @@ function normalizeAuthPolicy(value = {}) {
|
|
|
238
248
|
function normalizePublicationBinding(value = {}) {
|
|
239
249
|
return {
|
|
240
250
|
publicationId: normalizeString(value.publicationId),
|
|
251
|
+
interfaceId: normalizeString(value.interfaceId),
|
|
241
252
|
bindingMode: normalizeDeploymentBindingModeName(value.bindingMode),
|
|
242
253
|
sourceKind: normalizeString(value.sourceKind),
|
|
243
254
|
sourceMethodId: normalizeString(value.sourceMethodId),
|
|
244
255
|
sourceOutputPortId: normalizeString(value.sourceOutputPortId),
|
|
245
256
|
sourceNodeId: normalizeString(value.sourceNodeId),
|
|
246
257
|
sourceTriggerId: normalizeString(value.sourceTriggerId),
|
|
247
|
-
topic: normalizeString(value.topic),
|
|
248
|
-
wireId: normalizeString(value.wireId),
|
|
249
258
|
schemaName: normalizeString(value.schemaName),
|
|
250
259
|
mediaType: normalizeString(value.mediaType),
|
|
251
260
|
archivePath: normalizeString(value.archivePath),
|
|
252
|
-
|
|
261
|
+
queryInterfaceId: normalizeString(value.queryInterfaceId),
|
|
253
262
|
emitPnm: normalizeBoolean(value.emitPnm),
|
|
254
263
|
emitFlatbufferArchive: normalizeBoolean(value.emitFlatbufferArchive),
|
|
255
264
|
pinPolicy: normalizeString(value.pinPolicy),
|
|
@@ -392,6 +401,62 @@ function buildMethodLookup(manifest) {
|
|
|
392
401
|
return lookup;
|
|
393
402
|
}
|
|
394
403
|
|
|
404
|
+
function buildExternalInterfaceLookup(manifest) {
|
|
405
|
+
const lookup = new Map();
|
|
406
|
+
if (!Array.isArray(manifest?.externalInterfaces)) {
|
|
407
|
+
return lookup;
|
|
408
|
+
}
|
|
409
|
+
for (const externalInterface of manifest.externalInterfaces) {
|
|
410
|
+
if (
|
|
411
|
+
typeof externalInterface?.interfaceId === "string" &&
|
|
412
|
+
externalInterface.interfaceId.trim().length > 0
|
|
413
|
+
) {
|
|
414
|
+
lookup.set(externalInterface.interfaceId, externalInterface);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return lookup;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function validateDeclaredInterface(
|
|
421
|
+
issues,
|
|
422
|
+
interfaceId,
|
|
423
|
+
location,
|
|
424
|
+
bindingLabel,
|
|
425
|
+
missingCode,
|
|
426
|
+
directionCode,
|
|
427
|
+
externalInterfaceLookup,
|
|
428
|
+
allowedDirections,
|
|
429
|
+
) {
|
|
430
|
+
const normalizedInterfaceId = normalizeString(interfaceId);
|
|
431
|
+
if (!normalizedInterfaceId) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const externalInterface = externalInterfaceLookup.get(normalizedInterfaceId);
|
|
435
|
+
if (!externalInterface) {
|
|
436
|
+
pushIssue(
|
|
437
|
+
issues,
|
|
438
|
+
"error",
|
|
439
|
+
missingCode,
|
|
440
|
+
`${bindingLabel} references unknown interface "${normalizedInterfaceId}".`,
|
|
441
|
+
location,
|
|
442
|
+
);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (
|
|
446
|
+
allowedDirections &&
|
|
447
|
+
typeof externalInterface.direction === "string" &&
|
|
448
|
+
!allowedDirections.has(externalInterface.direction)
|
|
449
|
+
) {
|
|
450
|
+
pushIssue(
|
|
451
|
+
issues,
|
|
452
|
+
"error",
|
|
453
|
+
directionCode,
|
|
454
|
+
`${bindingLabel} references interface "${normalizedInterfaceId}" with direction "${externalInterface.direction}", which is incompatible with this binding.`,
|
|
455
|
+
location,
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
395
460
|
function validateProtocolInstallation(
|
|
396
461
|
installation,
|
|
397
462
|
issues,
|
|
@@ -414,7 +479,7 @@ function validateProtocolInstallation(
|
|
|
414
479
|
`${location}.protocolId`,
|
|
415
480
|
"Protocol installation protocolId",
|
|
416
481
|
);
|
|
417
|
-
|
|
482
|
+
validateOptionalStringField(
|
|
418
483
|
issues,
|
|
419
484
|
installation.wireId,
|
|
420
485
|
`${location}.wireId`,
|
|
@@ -583,6 +648,7 @@ function validateInputBinding(
|
|
|
583
648
|
location,
|
|
584
649
|
manifest,
|
|
585
650
|
manifestMethodLookup,
|
|
651
|
+
externalInterfaceLookup,
|
|
586
652
|
) {
|
|
587
653
|
if (!binding || typeof binding !== "object" || Array.isArray(binding)) {
|
|
588
654
|
pushIssue(
|
|
@@ -600,6 +666,12 @@ function validateInputBinding(
|
|
|
600
666
|
`${location}.bindingId`,
|
|
601
667
|
"Input binding bindingId",
|
|
602
668
|
);
|
|
669
|
+
const interfaceIdValid = validateStringField(
|
|
670
|
+
issues,
|
|
671
|
+
binding.interfaceId,
|
|
672
|
+
`${location}.interfaceId`,
|
|
673
|
+
"Input binding interfaceId",
|
|
674
|
+
);
|
|
603
675
|
const targetPluginId = normalizeString(binding.targetPluginId);
|
|
604
676
|
const targetMethodIdValid = validateStringField(
|
|
605
677
|
issues,
|
|
@@ -639,24 +711,6 @@ function validateInputBinding(
|
|
|
639
711
|
`${location}.targetPluginId`,
|
|
640
712
|
"Input binding targetPluginId",
|
|
641
713
|
);
|
|
642
|
-
validateOptionalStringField(
|
|
643
|
-
issues,
|
|
644
|
-
binding.topic,
|
|
645
|
-
`${location}.topic`,
|
|
646
|
-
"Input binding topic",
|
|
647
|
-
);
|
|
648
|
-
validateOptionalStringField(
|
|
649
|
-
issues,
|
|
650
|
-
binding.wireId,
|
|
651
|
-
`${location}.wireId`,
|
|
652
|
-
"Input binding wireId",
|
|
653
|
-
);
|
|
654
|
-
validateOptionalStringField(
|
|
655
|
-
issues,
|
|
656
|
-
binding.nodeInfoUrl,
|
|
657
|
-
`${location}.nodeInfoUrl`,
|
|
658
|
-
"Input binding nodeInfoUrl",
|
|
659
|
-
);
|
|
660
714
|
validateStringArrayField(
|
|
661
715
|
issues,
|
|
662
716
|
binding.multiaddrs,
|
|
@@ -687,27 +741,17 @@ function validateInputBinding(
|
|
|
687
741
|
`${location}.description`,
|
|
688
742
|
"Input binding description",
|
|
689
743
|
);
|
|
690
|
-
if (
|
|
691
|
-
|
|
692
|
-
!validateStringField(
|
|
744
|
+
if (interfaceIdValid) {
|
|
745
|
+
validateDeclaredInterface(
|
|
693
746
|
issues,
|
|
694
|
-
binding.
|
|
695
|
-
`${location}.
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
sourceKind === InputBindingSourceKind.PROTOCOL_STREAM &&
|
|
703
|
-
!validateStringField(
|
|
704
|
-
issues,
|
|
705
|
-
binding.wireId,
|
|
706
|
-
`${location}.wireId`,
|
|
707
|
-
"Protocol-stream input binding wireId",
|
|
708
|
-
)
|
|
709
|
-
) {
|
|
710
|
-
// error already recorded
|
|
747
|
+
binding.interfaceId,
|
|
748
|
+
`${location}.interfaceId`,
|
|
749
|
+
`Input binding "${binding.bindingId ?? "binding"}"`,
|
|
750
|
+
"unknown-input-binding-interface",
|
|
751
|
+
"input-binding-interface-direction-mismatch",
|
|
752
|
+
externalInterfaceLookup,
|
|
753
|
+
InputBindingInterfaceDirectionSet,
|
|
754
|
+
);
|
|
711
755
|
}
|
|
712
756
|
const targetsCurrentManifest =
|
|
713
757
|
!targetPluginId ||
|
|
@@ -1161,6 +1205,7 @@ function validatePublicationBinding(
|
|
|
1161
1205
|
location,
|
|
1162
1206
|
manifest,
|
|
1163
1207
|
manifestMethodLookup,
|
|
1208
|
+
externalInterfaceLookup,
|
|
1164
1209
|
) {
|
|
1165
1210
|
if (!binding || typeof binding !== "object" || Array.isArray(binding)) {
|
|
1166
1211
|
pushIssue(
|
|
@@ -1178,6 +1223,12 @@ function validatePublicationBinding(
|
|
|
1178
1223
|
`${location}.publicationId`,
|
|
1179
1224
|
"Publication binding publicationId",
|
|
1180
1225
|
);
|
|
1226
|
+
const interfaceIdValid = validateStringField(
|
|
1227
|
+
issues,
|
|
1228
|
+
binding.interfaceId,
|
|
1229
|
+
`${location}.interfaceId`,
|
|
1230
|
+
"Publication binding interfaceId",
|
|
1231
|
+
);
|
|
1181
1232
|
validateBindingModeField(
|
|
1182
1233
|
issues,
|
|
1183
1234
|
binding.bindingMode,
|
|
@@ -1214,18 +1265,6 @@ function validatePublicationBinding(
|
|
|
1214
1265
|
`${location}.sourceTriggerId`,
|
|
1215
1266
|
"Publication binding sourceTriggerId",
|
|
1216
1267
|
);
|
|
1217
|
-
validateOptionalStringField(
|
|
1218
|
-
issues,
|
|
1219
|
-
binding.topic,
|
|
1220
|
-
`${location}.topic`,
|
|
1221
|
-
"Publication binding topic",
|
|
1222
|
-
);
|
|
1223
|
-
validateOptionalStringField(
|
|
1224
|
-
issues,
|
|
1225
|
-
binding.wireId,
|
|
1226
|
-
`${location}.wireId`,
|
|
1227
|
-
"Publication binding wireId",
|
|
1228
|
-
);
|
|
1229
1268
|
validateOptionalStringField(
|
|
1230
1269
|
issues,
|
|
1231
1270
|
binding.schemaName,
|
|
@@ -1246,9 +1285,9 @@ function validatePublicationBinding(
|
|
|
1246
1285
|
);
|
|
1247
1286
|
validateOptionalStringField(
|
|
1248
1287
|
issues,
|
|
1249
|
-
binding.
|
|
1250
|
-
`${location}.
|
|
1251
|
-
"Publication binding
|
|
1288
|
+
binding.queryInterfaceId,
|
|
1289
|
+
`${location}.queryInterfaceId`,
|
|
1290
|
+
"Publication binding queryInterfaceId",
|
|
1252
1291
|
);
|
|
1253
1292
|
validateOptionalStringField(
|
|
1254
1293
|
issues,
|
|
@@ -1287,18 +1326,28 @@ function validatePublicationBinding(
|
|
|
1287
1326
|
location,
|
|
1288
1327
|
);
|
|
1289
1328
|
}
|
|
1290
|
-
if (
|
|
1291
|
-
|
|
1292
|
-
!binding.topic &&
|
|
1293
|
-
!binding.wireId &&
|
|
1294
|
-
!binding.schemaName
|
|
1295
|
-
) {
|
|
1296
|
-
pushIssue(
|
|
1329
|
+
if (interfaceIdValid) {
|
|
1330
|
+
validateDeclaredInterface(
|
|
1297
1331
|
issues,
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1332
|
+
binding.interfaceId,
|
|
1333
|
+
`${location}.interfaceId`,
|
|
1334
|
+
`Publication binding "${binding.publicationId ?? "publication"}"`,
|
|
1335
|
+
"unknown-publication-binding-interface",
|
|
1336
|
+
"publication-binding-interface-direction-mismatch",
|
|
1337
|
+
externalInterfaceLookup,
|
|
1338
|
+
PublicationBindingInterfaceDirectionSet,
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
if (binding.queryInterfaceId) {
|
|
1342
|
+
validateDeclaredInterface(
|
|
1343
|
+
issues,
|
|
1344
|
+
binding.queryInterfaceId,
|
|
1345
|
+
`${location}.queryInterfaceId`,
|
|
1346
|
+
`Publication binding "${binding.publicationId ?? "publication"}" query interface`,
|
|
1347
|
+
"unknown-publication-query-interface",
|
|
1348
|
+
"publication-query-interface-direction-mismatch",
|
|
1349
|
+
externalInterfaceLookup,
|
|
1350
|
+
null,
|
|
1302
1351
|
);
|
|
1303
1352
|
}
|
|
1304
1353
|
if (binding.sourceMethodId && manifest) {
|
|
@@ -1344,6 +1393,7 @@ export function validateDeploymentPlan(plan, options = {}) {
|
|
|
1344
1393
|
const issues = [];
|
|
1345
1394
|
const manifest = options.manifest ?? null;
|
|
1346
1395
|
const methodLookup = buildMethodLookup(manifest);
|
|
1396
|
+
const externalInterfaceLookup = buildExternalInterfaceLookup(manifest);
|
|
1347
1397
|
const protocolLookup = new Map(
|
|
1348
1398
|
Array.isArray(manifest?.protocols)
|
|
1349
1399
|
? manifest.protocols
|
|
@@ -1403,6 +1453,7 @@ export function validateDeploymentPlan(plan, options = {}) {
|
|
|
1403
1453
|
`deploymentPlan.inputBindings[${index}]`,
|
|
1404
1454
|
manifest,
|
|
1405
1455
|
methodLookup,
|
|
1456
|
+
externalInterfaceLookup,
|
|
1406
1457
|
);
|
|
1407
1458
|
});
|
|
1408
1459
|
normalizedPlan.scheduleBindings.forEach((binding, index) => {
|
|
@@ -1435,6 +1486,7 @@ export function validateDeploymentPlan(plan, options = {}) {
|
|
|
1435
1486
|
`deploymentPlan.publicationBindings[${index}]`,
|
|
1436
1487
|
manifest,
|
|
1437
1488
|
methodLookup,
|
|
1489
|
+
externalInterfaceLookup,
|
|
1438
1490
|
);
|
|
1439
1491
|
});
|
|
1440
1492
|
|
|
@@ -1454,23 +1506,6 @@ export function validateDeploymentPlan(plan, options = {}) {
|
|
|
1454
1506
|
);
|
|
1455
1507
|
}
|
|
1456
1508
|
});
|
|
1457
|
-
const serviceIds = new Set(
|
|
1458
|
-
normalizedPlan.serviceBindings
|
|
1459
|
-
.map((entry) => entry.serviceId)
|
|
1460
|
-
.filter((entry) => typeof entry === "string" && entry.length > 0),
|
|
1461
|
-
);
|
|
1462
|
-
normalizedPlan.publicationBindings.forEach((binding, index) => {
|
|
1463
|
-
if (binding.queryServiceId && !serviceIds.has(binding.queryServiceId)) {
|
|
1464
|
-
pushIssue(
|
|
1465
|
-
issues,
|
|
1466
|
-
"error",
|
|
1467
|
-
"unknown-publication-query-service",
|
|
1468
|
-
`Publication binding "${binding.publicationId ?? "publication"}" references unknown query service "${binding.queryServiceId}".`,
|
|
1469
|
-
`deploymentPlan.publicationBindings[${index}].queryServiceId`,
|
|
1470
|
-
);
|
|
1471
|
-
}
|
|
1472
|
-
});
|
|
1473
|
-
|
|
1474
1509
|
const errors = issues.filter((issue) => issue.severity === "error");
|
|
1475
1510
|
const warnings = issues.filter((issue) => issue.severity === "warning");
|
|
1476
1511
|
return {
|