@naeemo/capnp 0.4.0 → 0.5.2

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.
@@ -0,0 +1,2296 @@
1
+
2
+ //#region src/rpc/four-tables.ts
3
+ /** Manages the question table for outbound calls */
4
+ var QuestionTable = class {
5
+ questions = /* @__PURE__ */ new Map();
6
+ nextId = 1;
7
+ /** Create a new question entry */
8
+ create() {
9
+ const id = this.allocateId();
10
+ let resolveCompletion;
11
+ let rejectCompletion;
12
+ const question = {
13
+ id,
14
+ isComplete: false,
15
+ finishSent: false,
16
+ completionPromise: new Promise((resolve, reject) => {
17
+ resolveCompletion = resolve;
18
+ rejectCompletion = reject;
19
+ }),
20
+ resolveCompletion,
21
+ rejectCompletion
22
+ };
23
+ this.questions.set(id, question);
24
+ return question;
25
+ }
26
+ /** Get a question by ID */
27
+ get(id) {
28
+ return this.questions.get(id);
29
+ }
30
+ /** Mark a question as complete */
31
+ complete(id, result) {
32
+ const question = this.questions.get(id);
33
+ if (question && !question.isComplete) {
34
+ question.isComplete = true;
35
+ question.resolveCompletion(result);
36
+ }
37
+ }
38
+ /** Mark a question as canceled */
39
+ cancel(id, error) {
40
+ const question = this.questions.get(id);
41
+ if (question && !question.isComplete) {
42
+ question.isComplete = true;
43
+ question.rejectCompletion(error);
44
+ }
45
+ }
46
+ /** Mark that Finish has been sent for a question */
47
+ markFinishSent(id) {
48
+ const question = this.questions.get(id);
49
+ if (question) question.finishSent = true;
50
+ }
51
+ /** Remove a question from the table (when both sides are done) */
52
+ remove(id) {
53
+ const question = this.questions.get(id);
54
+ if (question?.isComplete && question.finishSent) this.questions.delete(id);
55
+ }
56
+ /** Clean up all questions (e.g., on disconnect) */
57
+ clear() {
58
+ for (const question of this.questions.values()) if (!question.isComplete) question.rejectCompletion(/* @__PURE__ */ new Error("Connection closed"));
59
+ this.questions.clear();
60
+ this.nextId = 1;
61
+ }
62
+ allocateId() {
63
+ return this.nextId++;
64
+ }
65
+ };
66
+ /** Manages the answer table for inbound calls */
67
+ var AnswerTable = class {
68
+ answers = /* @__PURE__ */ new Map();
69
+ /** Create a new answer entry */
70
+ create(id) {
71
+ const answer = {
72
+ id,
73
+ isComplete: false,
74
+ returnSent: false,
75
+ finishReceived: false
76
+ };
77
+ this.answers.set(id, answer);
78
+ return answer;
79
+ }
80
+ /** Get an answer by ID */
81
+ get(id) {
82
+ return this.answers.get(id);
83
+ }
84
+ /** Mark that Return has been sent */
85
+ markReturnSent(id) {
86
+ const answer = this.answers.get(id);
87
+ if (answer) answer.returnSent = true;
88
+ }
89
+ /** Mark that Finish has been received */
90
+ markFinishReceived(id) {
91
+ const answer = this.answers.get(id);
92
+ if (answer) answer.finishReceived = true;
93
+ }
94
+ /** Remove an answer from the table (when both sides are done) */
95
+ remove(id) {
96
+ const answer = this.answers.get(id);
97
+ if (answer?.returnSent && answer.finishReceived) this.answers.delete(id);
98
+ }
99
+ /** Clean up all answers (e.g., on disconnect) */
100
+ clear() {
101
+ this.answers.clear();
102
+ }
103
+ };
104
+ /** Manages the import table for capabilities received from remote */
105
+ var ImportTable = class {
106
+ imports = /* @__PURE__ */ new Map();
107
+ /** Add a new import */
108
+ add(id, isPromise) {
109
+ const importEntry = {
110
+ id,
111
+ refCount: 1,
112
+ isPromise
113
+ };
114
+ this.imports.set(id, importEntry);
115
+ return importEntry;
116
+ }
117
+ /** Get an import by ID */
118
+ get(id) {
119
+ return this.imports.get(id);
120
+ }
121
+ /** Increment reference count */
122
+ addRef(id) {
123
+ const importEntry = this.imports.get(id);
124
+ if (importEntry) importEntry.refCount++;
125
+ }
126
+ /** Decrement reference count, returns true if refCount reached 0 */
127
+ release(id, count) {
128
+ const importEntry = this.imports.get(id);
129
+ if (importEntry) {
130
+ importEntry.refCount -= count;
131
+ if (importEntry.refCount <= 0) {
132
+ this.imports.delete(id);
133
+ return true;
134
+ }
135
+ }
136
+ return false;
137
+ }
138
+ /** Mark a promise as resolved */
139
+ markResolved(id) {
140
+ const importEntry = this.imports.get(id);
141
+ if (importEntry) importEntry.isPromise = false;
142
+ }
143
+ /** Clean up all imports (e.g., on disconnect) */
144
+ clear() {
145
+ this.imports.clear();
146
+ }
147
+ };
148
+ /** Manages the export table for capabilities sent to remote */
149
+ var ExportTable = class {
150
+ exports = /* @__PURE__ */ new Map();
151
+ nextId = 1;
152
+ /** Add a new export */
153
+ add(capability, isPromise) {
154
+ const id = this.allocateId();
155
+ const exportEntry = {
156
+ id,
157
+ refCount: 1,
158
+ isPromise,
159
+ capability
160
+ };
161
+ this.exports.set(id, exportEntry);
162
+ return exportEntry;
163
+ }
164
+ /** Get an export by ID */
165
+ get(id) {
166
+ return this.exports.get(id);
167
+ }
168
+ /** Increment reference count */
169
+ addRef(id) {
170
+ const exportEntry = this.exports.get(id);
171
+ if (exportEntry) exportEntry.refCount++;
172
+ }
173
+ /** Decrement reference count, returns true if refCount reached 0 */
174
+ release(id, count) {
175
+ const exportEntry = this.exports.get(id);
176
+ if (exportEntry) {
177
+ exportEntry.refCount -= count;
178
+ if (exportEntry.refCount <= 0) {
179
+ this.exports.delete(id);
180
+ return true;
181
+ }
182
+ }
183
+ return false;
184
+ }
185
+ /** Mark a promise as resolved */
186
+ markResolved(id) {
187
+ const exportEntry = this.exports.get(id);
188
+ if (exportEntry) exportEntry.isPromise = false;
189
+ }
190
+ /** Clean up all exports (e.g., on disconnect) */
191
+ clear() {
192
+ this.exports.clear();
193
+ this.nextId = 1;
194
+ }
195
+ allocateId() {
196
+ return this.nextId++;
197
+ }
198
+ };
199
+
200
+ //#endregion
201
+ //#region src/rpc/pipeline.ts
202
+ /**
203
+ * Tracks a chain of operations to apply to a promised answer.
204
+ * This forms the "transform" field in PromisedAnswer.
205
+ */
206
+ var PipelineOpTracker = class PipelineOpTracker {
207
+ ops = [];
208
+ /**
209
+ * Add a no-op (use the result as-is)
210
+ */
211
+ addNoop() {
212
+ this.ops.push({ type: "noop" });
213
+ }
214
+ /**
215
+ * Add a pointer field access operation
216
+ */
217
+ addGetPointerField(fieldIndex) {
218
+ this.ops.push({
219
+ type: "getPointerField",
220
+ fieldIndex
221
+ });
222
+ }
223
+ /**
224
+ * Get the current transform chain
225
+ */
226
+ getTransform() {
227
+ return [...this.ops];
228
+ }
229
+ /**
230
+ * Clone this tracker (for creating derived pipelines)
231
+ */
232
+ clone() {
233
+ const cloned = new PipelineOpTracker();
234
+ cloned.ops = [...this.ops];
235
+ return cloned;
236
+ }
237
+ };
238
+ /**
239
+ * Symbol used to identify pipeline clients internally
240
+ */
241
+ const PIPELINE_CLIENT_SYMBOL = Symbol("PipelineClient");
242
+ /**
243
+ * Creates a PipelineClient using JavaScript Proxy.
244
+ * The proxy intercepts property accesses to build up the transform chain.
245
+ */
246
+ function createPipelineClient(options) {
247
+ const { connection, questionId, opTracker = new PipelineOpTracker() } = options;
248
+ return {
249
+ [PIPELINE_CLIENT_SYMBOL]: true,
250
+ connection,
251
+ questionId,
252
+ opTracker,
253
+ call(interfaceId, methodId, params) {
254
+ return makePipelinedCall(connection, questionId, opTracker.getTransform(), interfaceId, methodId, params);
255
+ },
256
+ getPointerField(fieldIndex) {
257
+ const newTracker = opTracker.clone();
258
+ newTracker.addGetPointerField(fieldIndex);
259
+ return createPipelineClient({
260
+ connection,
261
+ questionId,
262
+ opTracker: newTracker
263
+ });
264
+ }
265
+ };
266
+ }
267
+ /**
268
+ * Check if a value is a PipelineClient
269
+ */
270
+ function isPipelineClient(value) {
271
+ return typeof value === "object" && value !== null && PIPELINE_CLIENT_SYMBOL in value;
272
+ }
273
+ /**
274
+ * Makes a call on a promised answer (pipeline call).
275
+ * This sends a Call message with target.type = 'promisedAnswer'.
276
+ */
277
+ async function makePipelinedCall(connection, questionId, transform, interfaceId, methodId, params) {
278
+ const newQuestionId = connection.createQuestion();
279
+ const call = {
280
+ questionId: newQuestionId,
281
+ target: {
282
+ type: "promisedAnswer",
283
+ promisedAnswer: {
284
+ questionId,
285
+ transform
286
+ }
287
+ },
288
+ interfaceId,
289
+ methodId,
290
+ allowThirdPartyTailCall: false,
291
+ noPromisePipelining: false,
292
+ onlyPromisePipeline: false,
293
+ params,
294
+ sendResultsTo: { type: "caller" }
295
+ };
296
+ await connection.sendCall(call);
297
+ return connection.waitForAnswer(newQuestionId);
298
+ }
299
+ /**
300
+ * Manages calls that were made on a pipeline client before the answer arrived.
301
+ * When the answer arrives, these calls are dispatched to the actual capability.
302
+ */
303
+ var QueuedCallManager = class {
304
+ queuedCalls = /* @__PURE__ */ new Map();
305
+ /**
306
+ * Queue a call for when the promise resolves
307
+ */
308
+ queueCall(questionId, call) {
309
+ const calls = this.queuedCalls.get(questionId) ?? [];
310
+ calls.push(call);
311
+ this.queuedCalls.set(questionId, calls);
312
+ }
313
+ /**
314
+ * Get and clear all queued calls for a question
315
+ */
316
+ dequeueCalls(questionId) {
317
+ const calls = this.queuedCalls.get(questionId) ?? [];
318
+ this.queuedCalls.delete(questionId);
319
+ return calls;
320
+ }
321
+ /**
322
+ * Check if there are queued calls for a question
323
+ */
324
+ hasQueuedCalls(questionId) {
325
+ return (this.queuedCalls.get(questionId)?.length ?? 0) > 0;
326
+ }
327
+ /**
328
+ * Clear all queued calls (e.g., on disconnect)
329
+ */
330
+ clear() {
331
+ for (const calls of this.queuedCalls.values()) for (const call of calls) call.reject(/* @__PURE__ */ new Error("Connection closed"));
332
+ this.queuedCalls.clear();
333
+ }
334
+ };
335
+ /**
336
+ * Tracks pending pipeline resolutions
337
+ */
338
+ var PipelineResolutionTracker = class {
339
+ pendingResolutions = /* @__PURE__ */ new Map();
340
+ /**
341
+ * Mark a question as resolved to a capability
342
+ */
343
+ resolveToCapability(questionId, importId) {
344
+ this.pendingResolutions.set(questionId, {
345
+ type: "capability",
346
+ importId
347
+ });
348
+ }
349
+ /**
350
+ * Mark a question as resolved to an exception
351
+ */
352
+ resolveToException(questionId, reason) {
353
+ this.pendingResolutions.set(questionId, {
354
+ type: "exception",
355
+ reason
356
+ });
357
+ }
358
+ /**
359
+ * Get the resolution for a question (if available)
360
+ */
361
+ getResolution(questionId) {
362
+ return this.pendingResolutions.get(questionId);
363
+ }
364
+ /**
365
+ * Check if a question has been resolved
366
+ */
367
+ isResolved(questionId) {
368
+ return this.pendingResolutions.has(questionId);
369
+ }
370
+ /**
371
+ * Remove a resolution entry
372
+ */
373
+ remove(questionId) {
374
+ this.pendingResolutions.delete(questionId);
375
+ }
376
+ /**
377
+ * Clear all resolutions
378
+ */
379
+ clear() {
380
+ this.pendingResolutions.clear();
381
+ }
382
+ };
383
+
384
+ //#endregion
385
+ //#region src/rpc/schema-types.ts
386
+ /**
387
+ * Supported schema serialization formats
388
+ */
389
+ let SchemaFormat = /* @__PURE__ */ function(SchemaFormat) {
390
+ /** Standard Cap'n Proto binary format (schema.capnp structs) */
391
+ SchemaFormat[SchemaFormat["BINARY"] = 0] = "BINARY";
392
+ /** JSON representation of the schema */
393
+ SchemaFormat[SchemaFormat["JSON"] = 1] = "JSON";
394
+ /** Cap'n Proto schema language text format */
395
+ SchemaFormat[SchemaFormat["CAPNP"] = 2] = "CAPNP";
396
+ return SchemaFormat;
397
+ }({});
398
+ /**
399
+ * Schema node types (mirroring schema.capnp Node union)
400
+ */
401
+ let SchemaNodeType = /* @__PURE__ */ function(SchemaNodeType) {
402
+ SchemaNodeType[SchemaNodeType["FILE"] = 0] = "FILE";
403
+ SchemaNodeType[SchemaNodeType["STRUCT"] = 1] = "STRUCT";
404
+ SchemaNodeType[SchemaNodeType["ENUM"] = 2] = "ENUM";
405
+ SchemaNodeType[SchemaNodeType["INTERFACE"] = 3] = "INTERFACE";
406
+ SchemaNodeType[SchemaNodeType["CONST"] = 4] = "CONST";
407
+ SchemaNodeType[SchemaNodeType["ANNOTATION"] = 5] = "ANNOTATION";
408
+ return SchemaNodeType;
409
+ }({});
410
+
411
+ //#endregion
412
+ //#region src/rpc/schema-parser.ts
413
+ /**
414
+ * Parse schema binary data into SchemaNode objects
415
+ *
416
+ * This parses the CodeGeneratorRequest format from schema.capnp
417
+ */
418
+ function parseSchemaNodes(data) {
419
+ return new SchemaParser(data).parse();
420
+ }
421
+ /**
422
+ * Schema parser class
423
+ */
424
+ var SchemaParser = class {
425
+ data;
426
+ view;
427
+ textDecoder = new TextDecoder();
428
+ constructor(data) {
429
+ this.data = data;
430
+ this.view = new DataView(data.buffer, data.byteOffset, data.byteLength);
431
+ }
432
+ /**
433
+ * Parse the schema data and return all nodes
434
+ */
435
+ parse() {
436
+ const nodes = [];
437
+ if (this.data.length < 8) return nodes;
438
+ const nodesPtr = this.readPointer(8);
439
+ if (nodesPtr.offset > 0 && nodesPtr.size > 0) {
440
+ const nodeList = this.readStructList(nodesPtr.offset, nodesPtr.size, (offset) => this.parseNode(offset));
441
+ nodes.push(...nodeList);
442
+ }
443
+ return nodes;
444
+ }
445
+ /**
446
+ * Parse a single Node structure
447
+ */
448
+ parseNode(offset) {
449
+ const id = this.view.getBigUint64(offset, true);
450
+ const displayNamePtr = this.readPointer(offset + 8);
451
+ const displayName = this.readText(displayNamePtr.offset, displayNamePtr.size);
452
+ const displayNamePrefixLength = this.view.getUint32(offset + 16, true);
453
+ const scopeId = this.view.getBigUint64(offset + 24, true);
454
+ const nestedNodesPtr = this.readPointer(offset + 32);
455
+ const nestedNodes = nestedNodesPtr.offset > 0 && nestedNodesPtr.size > 0 ? this.readStructList(nestedNodesPtr.offset, nestedNodesPtr.size, (noffset) => this.parseNestedNode(noffset)) : [];
456
+ const annotationsPtr = this.readPointer(offset + 40);
457
+ const annotations = annotationsPtr.offset > 0 && annotationsPtr.size > 0 ? this.readStructList(annotationsPtr.offset, annotationsPtr.size, (aoffset) => this.parseAnnotation(aoffset)) : [];
458
+ const discriminant = this.view.getUint16(offset + 48, true);
459
+ const type = this.mapNodeType(discriminant);
460
+ const node = {
461
+ id,
462
+ displayName,
463
+ displayNamePrefixLength,
464
+ scopeId,
465
+ nestedNodes,
466
+ annotations,
467
+ type
468
+ };
469
+ const unionOffset = offset + 56;
470
+ switch (type) {
471
+ case SchemaNodeType.STRUCT:
472
+ node.structInfo = this.parseStructInfo(unionOffset);
473
+ break;
474
+ case SchemaNodeType.ENUM:
475
+ node.enumInfo = this.parseEnumInfo(unionOffset);
476
+ break;
477
+ case SchemaNodeType.INTERFACE:
478
+ node.interfaceInfo = this.parseInterfaceInfo(unionOffset);
479
+ break;
480
+ case SchemaNodeType.CONST:
481
+ node.constInfo = this.parseConstInfo(unionOffset);
482
+ break;
483
+ case SchemaNodeType.ANNOTATION:
484
+ node.annotationInfo = this.parseAnnotationInfo(unionOffset);
485
+ break;
486
+ }
487
+ return node;
488
+ }
489
+ /**
490
+ * Parse nested node reference
491
+ */
492
+ parseNestedNode(offset) {
493
+ const namePtr = this.readPointer(offset);
494
+ return {
495
+ name: this.readText(namePtr.offset, namePtr.size),
496
+ id: this.view.getBigUint64(offset + 8, true)
497
+ };
498
+ }
499
+ /**
500
+ * Parse annotation
501
+ */
502
+ parseAnnotation(offset) {
503
+ const id = this.view.getBigUint64(offset, true);
504
+ const valuePtr = this.readPointer(offset + 8);
505
+ const value = this.parseValue(valuePtr.offset);
506
+ const brandPtr = this.readPointer(offset + 16);
507
+ return {
508
+ id,
509
+ value,
510
+ brand: brandPtr.offset > 0 ? this.parseBrand(brandPtr.offset) : { scopes: [] }
511
+ };
512
+ }
513
+ /**
514
+ * Parse struct-specific info
515
+ */
516
+ parseStructInfo(offset) {
517
+ const dataWordCount = this.view.getUint16(offset, true);
518
+ const pointerCount = this.view.getUint16(offset + 2, true);
519
+ const preferredListEncoding = this.view.getUint16(offset + 4, true);
520
+ const isGroup = this.view.getUint8(offset + 6) !== 0;
521
+ const discriminantCount = this.view.getUint16(offset + 8, true);
522
+ const discriminantOffset = this.view.getUint32(offset + 12, true);
523
+ const fieldsPtr = this.readPointer(offset + 16);
524
+ return {
525
+ dataWordCount,
526
+ pointerCount,
527
+ preferredListEncoding,
528
+ isGroup,
529
+ discriminantCount,
530
+ discriminantOffset,
531
+ fields: fieldsPtr.offset > 0 && fieldsPtr.size > 0 ? this.readStructList(fieldsPtr.offset, fieldsPtr.size, (foffset) => this.parseField(foffset)) : []
532
+ };
533
+ }
534
+ /**
535
+ * Parse field definition
536
+ */
537
+ parseField(offset) {
538
+ const namePtr = this.readPointer(offset);
539
+ const name = this.readText(namePtr.offset, namePtr.size);
540
+ const codeOrder = this.view.getUint16(offset + 8, true);
541
+ const discriminantValue = this.view.getUint16(offset + 12, true);
542
+ const slotOffset = this.view.getUint32(offset + 24, true);
543
+ const typePtr = this.readPointer(offset + 32);
544
+ const type = this.parseType(typePtr.offset);
545
+ const defaultValuePtr = this.readPointer(offset + 40);
546
+ return {
547
+ name,
548
+ codeOrder,
549
+ discriminantValue,
550
+ offset: slotOffset,
551
+ type,
552
+ defaultValue: defaultValuePtr.offset > 0 ? this.parseValue(defaultValuePtr.offset) : void 0,
553
+ hadExplicitDefault: this.view.getUint8(offset + 48) !== 0
554
+ };
555
+ }
556
+ /**
557
+ * Parse type definition
558
+ */
559
+ parseType(offset) {
560
+ const discriminant = this.view.getUint16(offset, true);
561
+ return { kind: this.parseTypeKind(discriminant, offset + 8) };
562
+ }
563
+ /**
564
+ * Parse type kind based on discriminant
565
+ */
566
+ parseTypeKind(discriminant, offset) {
567
+ switch (discriminant) {
568
+ case 0: return { type: "void" };
569
+ case 1: return { type: "bool" };
570
+ case 2: return { type: "int8" };
571
+ case 3: return { type: "int16" };
572
+ case 4: return { type: "int32" };
573
+ case 5: return { type: "int64" };
574
+ case 6: return { type: "uint8" };
575
+ case 7: return { type: "uint16" };
576
+ case 8: return { type: "uint32" };
577
+ case 9: return { type: "uint64" };
578
+ case 10: return { type: "float32" };
579
+ case 11: return { type: "float64" };
580
+ case 12: return { type: "text" };
581
+ case 13: return { type: "data" };
582
+ case 14: {
583
+ const elementTypePtr = this.readPointer(offset);
584
+ return {
585
+ type: "list",
586
+ elementType: this.parseType(elementTypePtr.offset)
587
+ };
588
+ }
589
+ case 15: {
590
+ const typeId = this.view.getBigUint64(offset, true);
591
+ const brandPtr = this.readPointer(offset + 8);
592
+ return {
593
+ type: "enum",
594
+ typeId,
595
+ brand: brandPtr.offset > 0 ? this.parseBrand(brandPtr.offset) : void 0
596
+ };
597
+ }
598
+ case 16: {
599
+ const typeId = this.view.getBigUint64(offset, true);
600
+ const brandPtr = this.readPointer(offset + 8);
601
+ return {
602
+ type: "struct",
603
+ typeId,
604
+ brand: brandPtr.offset > 0 ? this.parseBrand(brandPtr.offset) : void 0
605
+ };
606
+ }
607
+ case 17: {
608
+ const typeId = this.view.getBigUint64(offset, true);
609
+ const brandPtr = this.readPointer(offset + 8);
610
+ return {
611
+ type: "interface",
612
+ typeId,
613
+ brand: brandPtr.offset > 0 ? this.parseBrand(brandPtr.offset) : void 0
614
+ };
615
+ }
616
+ case 18: {
617
+ const anyPtrDisc = this.view.getUint16(offset, true);
618
+ return this.parseAnyPointerKind(anyPtrDisc, offset + 8);
619
+ }
620
+ default: return { type: "void" };
621
+ }
622
+ }
623
+ /**
624
+ * Parse anyPointer constraint
625
+ */
626
+ parseAnyPointerKind(discriminant, offset) {
627
+ switch (discriminant) {
628
+ case 0: return {
629
+ type: "anyPointer",
630
+ constraint: {
631
+ type: "unconstrained",
632
+ kind: [
633
+ "anyKind",
634
+ "struct",
635
+ "list",
636
+ "capability"
637
+ ][this.view.getUint16(offset, true)] ?? "anyKind"
638
+ }
639
+ };
640
+ case 1: return {
641
+ type: "anyPointer",
642
+ constraint: {
643
+ type: "parameter",
644
+ scopeId: this.view.getBigUint64(offset, true),
645
+ parameterIndex: this.view.getUint16(offset + 8, true)
646
+ }
647
+ };
648
+ case 2: return {
649
+ type: "anyPointer",
650
+ constraint: {
651
+ type: "implicitMethodParameter",
652
+ parameterIndex: this.view.getUint16(offset, true)
653
+ }
654
+ };
655
+ default: return {
656
+ type: "anyPointer",
657
+ constraint: {
658
+ type: "unconstrained",
659
+ kind: "anyKind"
660
+ }
661
+ };
662
+ }
663
+ }
664
+ /**
665
+ * Parse brand (generic type bindings)
666
+ */
667
+ parseBrand(offset) {
668
+ const scopesPtr = this.readPointer(offset);
669
+ return { scopes: scopesPtr.offset > 0 && scopesPtr.size > 0 ? this.readStructList(scopesPtr.offset, scopesPtr.size, (soffset) => this.parseBrandScope(soffset)) : [] };
670
+ }
671
+ /**
672
+ * Parse brand scope
673
+ */
674
+ parseBrandScope(offset) {
675
+ const scopeId = this.view.getBigUint64(offset, true);
676
+ const discriminant = this.view.getUint16(offset + 8, true);
677
+ let bindings = [];
678
+ if (discriminant === 0) {
679
+ const bindingsPtr = this.readPointer(offset + 16);
680
+ bindings = bindingsPtr.offset > 0 && bindingsPtr.size > 0 ? this.readStructList(bindingsPtr.offset, bindingsPtr.size, (boffset) => this.parseBrandBinding(boffset)) : [];
681
+ }
682
+ return {
683
+ scopeId,
684
+ bindings
685
+ };
686
+ }
687
+ /**
688
+ * Parse brand binding
689
+ */
690
+ parseBrandBinding(offset) {
691
+ if (this.view.getUint16(offset, true) === 0) return { type: "unbound" };
692
+ const typePtr = this.readPointer(offset + 8);
693
+ return {
694
+ type: "type",
695
+ value: this.parseType(typePtr.offset)
696
+ };
697
+ }
698
+ /**
699
+ * Parse value
700
+ */
701
+ parseValue(offset) {
702
+ const discriminant = this.view.getUint16(offset, true);
703
+ const dataOffset = offset + 8;
704
+ switch (discriminant) {
705
+ case 0: return { type: "void" };
706
+ case 1: return {
707
+ type: "bool",
708
+ value: this.view.getUint8(dataOffset) !== 0
709
+ };
710
+ case 2: return {
711
+ type: "int8",
712
+ value: this.view.getInt8(dataOffset)
713
+ };
714
+ case 3: return {
715
+ type: "int16",
716
+ value: this.view.getInt16(dataOffset, true)
717
+ };
718
+ case 4: return {
719
+ type: "int32",
720
+ value: this.view.getInt32(dataOffset, true)
721
+ };
722
+ case 5: return {
723
+ type: "int64",
724
+ value: this.view.getBigInt64(dataOffset, true)
725
+ };
726
+ case 6: return {
727
+ type: "uint8",
728
+ value: this.view.getUint8(dataOffset)
729
+ };
730
+ case 7: return {
731
+ type: "uint16",
732
+ value: this.view.getUint16(dataOffset, true)
733
+ };
734
+ case 8: return {
735
+ type: "uint32",
736
+ value: this.view.getUint32(dataOffset, true)
737
+ };
738
+ case 9: return {
739
+ type: "uint64",
740
+ value: this.view.getBigUint64(dataOffset, true)
741
+ };
742
+ case 10: return {
743
+ type: "float32",
744
+ value: this.view.getFloat32(dataOffset, true)
745
+ };
746
+ case 11: return {
747
+ type: "float64",
748
+ value: this.view.getFloat64(dataOffset, true)
749
+ };
750
+ case 12: {
751
+ const ptr = this.readPointer(dataOffset);
752
+ return {
753
+ type: "text",
754
+ value: this.readText(ptr.offset, ptr.size)
755
+ };
756
+ }
757
+ case 13: {
758
+ const ptr = this.readPointer(dataOffset);
759
+ return {
760
+ type: "data",
761
+ value: this.data.slice(ptr.offset, ptr.offset + ptr.size)
762
+ };
763
+ }
764
+ case 14: return {
765
+ type: "list",
766
+ value: null
767
+ };
768
+ case 15: return {
769
+ type: "enum",
770
+ value: this.view.getUint16(dataOffset, true)
771
+ };
772
+ case 16: return {
773
+ type: "struct",
774
+ value: null
775
+ };
776
+ case 17: return { type: "interface" };
777
+ case 18: return {
778
+ type: "anyPointer",
779
+ value: null
780
+ };
781
+ default: return { type: "void" };
782
+ }
783
+ }
784
+ /**
785
+ * Parse enum-specific info
786
+ */
787
+ parseEnumInfo(offset) {
788
+ const enumerantsPtr = this.readPointer(offset);
789
+ return { enumerants: enumerantsPtr.offset > 0 && enumerantsPtr.size > 0 ? this.readStructList(enumerantsPtr.offset, enumerantsPtr.size, (eoffset) => this.parseEnumerant(eoffset)) : [] };
790
+ }
791
+ /**
792
+ * Parse enumerant
793
+ */
794
+ parseEnumerant(offset) {
795
+ const namePtr = this.readPointer(offset);
796
+ const name = this.readText(namePtr.offset, namePtr.size);
797
+ const codeOrder = this.view.getUint16(offset + 8, true);
798
+ const annotationsPtr = this.readPointer(offset + 16);
799
+ return {
800
+ name,
801
+ codeOrder,
802
+ annotations: annotationsPtr.offset > 0 && annotationsPtr.size > 0 ? this.readStructList(annotationsPtr.offset, annotationsPtr.size, (aoffset) => this.parseAnnotation(aoffset)) : []
803
+ };
804
+ }
805
+ /**
806
+ * Parse interface-specific info
807
+ */
808
+ parseInterfaceInfo(offset) {
809
+ const methodsPtr = this.readPointer(offset);
810
+ const methods = methodsPtr.offset > 0 && methodsPtr.size > 0 ? this.readStructList(methodsPtr.offset, methodsPtr.size, (moffset) => this.parseMethod(moffset)) : [];
811
+ const superclassesPtr = this.readPointer(offset + 8);
812
+ return {
813
+ methods,
814
+ superclasses: superclassesPtr.offset > 0 && superclassesPtr.size > 0 ? this.readStructList(superclassesPtr.offset, superclassesPtr.size, (soffset) => this.parseSuperclass(soffset)) : []
815
+ };
816
+ }
817
+ /**
818
+ * Parse method
819
+ */
820
+ parseMethod(offset) {
821
+ const namePtr = this.readPointer(offset);
822
+ const name = this.readText(namePtr.offset, namePtr.size);
823
+ const codeOrder = this.view.getUint16(offset + 8, true);
824
+ const paramStructType = this.view.getBigUint64(offset + 16, true);
825
+ const resultStructType = this.view.getBigUint64(offset + 24, true);
826
+ const annotationsPtr = this.readPointer(offset + 32);
827
+ return {
828
+ name,
829
+ codeOrder,
830
+ paramStructType,
831
+ resultStructType,
832
+ annotations: annotationsPtr.offset > 0 && annotationsPtr.size > 0 ? this.readStructList(annotationsPtr.offset, annotationsPtr.size, (aoffset) => this.parseAnnotation(aoffset)) : []
833
+ };
834
+ }
835
+ /**
836
+ * Parse superclass
837
+ */
838
+ parseSuperclass(offset) {
839
+ const id = this.view.getBigUint64(offset, true);
840
+ const brandPtr = this.readPointer(offset + 8);
841
+ return {
842
+ id,
843
+ brand: brandPtr.offset > 0 ? this.parseBrand(brandPtr.offset) : { scopes: [] }
844
+ };
845
+ }
846
+ /**
847
+ * Parse const-specific info
848
+ */
849
+ parseConstInfo(offset) {
850
+ const typePtr = this.readPointer(offset);
851
+ const type = this.parseType(typePtr.offset);
852
+ const valuePtr = this.readPointer(offset + 8);
853
+ return {
854
+ type,
855
+ value: this.parseValue(valuePtr.offset)
856
+ };
857
+ }
858
+ /**
859
+ * Parse annotation-specific info
860
+ */
861
+ parseAnnotationInfo(offset) {
862
+ const typePtr = this.readPointer(offset);
863
+ const type = this.parseType(typePtr.offset);
864
+ const flags = this.view.getUint16(offset + 8, true);
865
+ return {
866
+ type,
867
+ targetsFile: (flags & 1) !== 0,
868
+ targetsConst: (flags & 2) !== 0,
869
+ targetsEnum: (flags & 4) !== 0,
870
+ targetsEnumerant: (flags & 8) !== 0,
871
+ targetsStruct: (flags & 16) !== 0,
872
+ targetsField: (flags & 32) !== 0,
873
+ targetsUnion: (flags & 64) !== 0,
874
+ targetsGroup: (flags & 128) !== 0,
875
+ targetsInterface: (flags & 256) !== 0,
876
+ targetsMethod: (flags & 512) !== 0,
877
+ targetsParam: (flags & 1024) !== 0,
878
+ targetsAnnotation: (flags & 2048) !== 0
879
+ };
880
+ }
881
+ /**
882
+ * Map node type discriminant to SchemaNodeType
883
+ */
884
+ mapNodeType(discriminant) {
885
+ return [
886
+ SchemaNodeType.FILE,
887
+ SchemaNodeType.FILE,
888
+ SchemaNodeType.FILE,
889
+ SchemaNodeType.FILE,
890
+ SchemaNodeType.FILE,
891
+ SchemaNodeType.FILE,
892
+ SchemaNodeType.FILE,
893
+ SchemaNodeType.STRUCT,
894
+ SchemaNodeType.ENUM,
895
+ SchemaNodeType.INTERFACE,
896
+ SchemaNodeType.CONST,
897
+ SchemaNodeType.ANNOTATION
898
+ ][discriminant] ?? SchemaNodeType.FILE;
899
+ }
900
+ /**
901
+ * Read a pointer value
902
+ */
903
+ readPointer(offset) {
904
+ const wordOffset = this.view.getInt32(offset, true);
905
+ const sizeAndType = this.view.getUint32(offset + 4, true);
906
+ const size = sizeAndType & 16777215;
907
+ sizeAndType >> 24 & 7;
908
+ if (wordOffset === 0 && size === 0) return {
909
+ offset: 0,
910
+ size: 0
911
+ };
912
+ return {
913
+ offset: offset + 8 + wordOffset * 8,
914
+ size
915
+ };
916
+ }
917
+ /**
918
+ * Read text from offset
919
+ */
920
+ readText(offset, size) {
921
+ if (size === 0) return "";
922
+ const actualSize = size > 0 ? size - 1 : 0;
923
+ const bytes = this.data.slice(offset, offset + actualSize);
924
+ return this.textDecoder.decode(bytes);
925
+ }
926
+ /**
927
+ * Read a list of structs
928
+ */
929
+ readStructList(offset, count, parser) {
930
+ const result = [];
931
+ let currentOffset = offset;
932
+ const structSize = 64;
933
+ for (let i = 0; i < count; i++) {
934
+ result.push(parser(currentOffset));
935
+ currentOffset += structSize;
936
+ }
937
+ return result;
938
+ }
939
+ };
940
+ /**
941
+ * Create a schema registry for managing parsed schemas
942
+ */
943
+ function createSchemaRegistry() {
944
+ const nodesById = /* @__PURE__ */ new Map();
945
+ const nodesByName = /* @__PURE__ */ new Map();
946
+ const nodesByFile = /* @__PURE__ */ new Map();
947
+ return {
948
+ registerNode(node) {
949
+ nodesById.set(node.id, node);
950
+ nodesByName.set(node.displayName, node);
951
+ const fileNodes = nodesByFile.get(node.scopeId) ?? [];
952
+ fileNodes.push(node);
953
+ nodesByFile.set(node.scopeId, fileNodes);
954
+ },
955
+ getNode(id) {
956
+ return nodesById.get(id);
957
+ },
958
+ getNodeByName(name) {
959
+ return nodesByName.get(name);
960
+ },
961
+ getNodesByFile(fileId) {
962
+ return nodesByFile.get(fileId) ?? [];
963
+ },
964
+ hasNode(id) {
965
+ return nodesById.has(id);
966
+ },
967
+ clear() {
968
+ nodesById.clear();
969
+ nodesByName.clear();
970
+ nodesByFile.clear();
971
+ }
972
+ };
973
+ }
974
+
975
+ //#endregion
976
+ //#region src/rpc/schema-serializer.ts
977
+ const SCHEMA_MESSAGE_TYPES = {
978
+ SCHEMA_REQUEST: 14,
979
+ SCHEMA_RESPONSE: 15
980
+ };
981
+ /**
982
+ * Serialize a SchemaRequest to binary format
983
+ */
984
+ function serializeSchemaRequest(request) {
985
+ const totalSize = 8 + getSchemaTargetSize(request.targetSchema);
986
+ const buffer = new ArrayBuffer(totalSize);
987
+ const view = new DataView(buffer);
988
+ const bytes = new Uint8Array(buffer);
989
+ view.setUint32(0, request.questionId, true);
990
+ let offset = 8;
991
+ offset = writeSchemaTarget(bytes, offset, request.targetSchema);
992
+ return bytes;
993
+ }
994
+ /**
995
+ * Deserialize a SchemaRequest from binary format
996
+ */
997
+ function deserializeSchemaRequest(data) {
998
+ return {
999
+ questionId: new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0, true),
1000
+ targetSchema: readSchemaTarget(data, 8).value
1001
+ };
1002
+ }
1003
+ /**
1004
+ * Get the serialized size of a SchemaTarget
1005
+ */
1006
+ function getSchemaTargetSize(target) {
1007
+ switch (target.type) {
1008
+ case "allSchemas":
1009
+ case "bootstrapInterface": return 8;
1010
+ case "byTypeId":
1011
+ case "byFileId": return 16;
1012
+ case "byTypeName":
1013
+ case "byFileName": return 16 + align8(target.type === "byTypeName" ? target.typeName.length : target.fileName.length);
1014
+ default: return 8;
1015
+ }
1016
+ }
1017
+ /**
1018
+ * Write a SchemaTarget to binary format
1019
+ */
1020
+ function writeSchemaTarget(bytes, offset, target) {
1021
+ const view = new DataView(bytes.buffer, bytes.byteOffset);
1022
+ switch (target.type) {
1023
+ case "allSchemas":
1024
+ view.setUint16(offset, 0, true);
1025
+ break;
1026
+ case "byTypeId":
1027
+ view.setUint16(offset, 1, true);
1028
+ view.setBigUint64(offset + 8, target.typeId, true);
1029
+ break;
1030
+ case "byTypeName": {
1031
+ view.setUint16(offset, 2, true);
1032
+ const strBytes = new TextEncoder().encode(target.typeName);
1033
+ writePointer(bytes, offset + 8, strBytes.length);
1034
+ bytes.set(strBytes, offset + 16);
1035
+ return offset + 16 + align8(strBytes.length);
1036
+ }
1037
+ case "byFileId":
1038
+ view.setUint16(offset, 3, true);
1039
+ view.setBigUint64(offset + 8, target.fileId, true);
1040
+ break;
1041
+ case "byFileName": {
1042
+ view.setUint16(offset, 4, true);
1043
+ const strBytes = new TextEncoder().encode(target.fileName);
1044
+ writePointer(bytes, offset + 8, strBytes.length);
1045
+ bytes.set(strBytes, offset + 16);
1046
+ return offset + 16 + align8(strBytes.length);
1047
+ }
1048
+ case "bootstrapInterface":
1049
+ view.setUint16(offset, 5, true);
1050
+ break;
1051
+ }
1052
+ return offset + 8;
1053
+ }
1054
+ /**
1055
+ * Read a SchemaTarget from binary format
1056
+ */
1057
+ function readSchemaTarget(data, offset) {
1058
+ const view = new DataView(data.buffer, data.byteOffset);
1059
+ switch (view.getUint16(offset, true)) {
1060
+ case 0: return {
1061
+ value: { type: "allSchemas" },
1062
+ nextOffset: offset + 8
1063
+ };
1064
+ case 1: return {
1065
+ value: {
1066
+ type: "byTypeId",
1067
+ typeId: view.getBigUint64(offset + 8, true)
1068
+ },
1069
+ nextOffset: offset + 16
1070
+ };
1071
+ case 2: {
1072
+ const strLen = readPointer(data, offset + 8);
1073
+ const strBytes = data.slice(offset + 16, offset + 16 + strLen);
1074
+ return {
1075
+ value: {
1076
+ type: "byTypeName",
1077
+ typeName: new TextDecoder().decode(strBytes)
1078
+ },
1079
+ nextOffset: offset + 16 + align8(strLen)
1080
+ };
1081
+ }
1082
+ case 3: return {
1083
+ value: {
1084
+ type: "byFileId",
1085
+ fileId: view.getBigUint64(offset + 8, true)
1086
+ },
1087
+ nextOffset: offset + 16
1088
+ };
1089
+ case 4: {
1090
+ const strLen = readPointer(data, offset + 8);
1091
+ const strBytes = data.slice(offset + 16, offset + 16 + strLen);
1092
+ return {
1093
+ value: {
1094
+ type: "byFileName",
1095
+ fileName: new TextDecoder().decode(strBytes)
1096
+ },
1097
+ nextOffset: offset + 16 + align8(strLen)
1098
+ };
1099
+ }
1100
+ case 5: return {
1101
+ value: { type: "bootstrapInterface" },
1102
+ nextOffset: offset + 8
1103
+ };
1104
+ default: return {
1105
+ value: { type: "allSchemas" },
1106
+ nextOffset: offset + 8
1107
+ };
1108
+ }
1109
+ }
1110
+ /**
1111
+ * Serialize a SchemaResponse to binary format
1112
+ */
1113
+ function serializeSchemaResponse(response) {
1114
+ const totalSize = 8 + getSchemaResponseResultSize(response.result);
1115
+ const buffer = new ArrayBuffer(totalSize);
1116
+ const view = new DataView(buffer);
1117
+ const bytes = new Uint8Array(buffer);
1118
+ view.setUint32(0, response.answerId, true);
1119
+ writeSchemaResponseResult(bytes, 8, response.result);
1120
+ return bytes;
1121
+ }
1122
+ /**
1123
+ * Deserialize a SchemaResponse from binary format
1124
+ */
1125
+ function deserializeSchemaResponse(data) {
1126
+ return {
1127
+ answerId: new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0, true),
1128
+ result: readSchemaResponseResult(data, 8).value
1129
+ };
1130
+ }
1131
+ /**
1132
+ * Get the serialized size of a SchemaResponseResult
1133
+ */
1134
+ function getSchemaResponseResultSize(result) {
1135
+ switch (result.type) {
1136
+ case "success": return 8 + getSchemaPayloadSize(result.payload);
1137
+ case "exception": return 8 + getExceptionSize(result.exception);
1138
+ default: return 8;
1139
+ }
1140
+ }
1141
+ /**
1142
+ * Write a SchemaResponseResult to binary format
1143
+ */
1144
+ function writeSchemaResponseResult(bytes, offset, result) {
1145
+ const view = new DataView(bytes.buffer, bytes.byteOffset);
1146
+ switch (result.type) {
1147
+ case "success":
1148
+ view.setUint16(offset, 0, true);
1149
+ return writeSchemaPayload(bytes, offset + 8, result.payload);
1150
+ case "exception":
1151
+ view.setUint16(offset, 1, true);
1152
+ return writeException(bytes, offset + 8, result.exception);
1153
+ default:
1154
+ view.setUint16(offset, 0, true);
1155
+ return offset + 8;
1156
+ }
1157
+ }
1158
+ /**
1159
+ * Read a SchemaResponseResult from binary format
1160
+ */
1161
+ function readSchemaResponseResult(data, offset) {
1162
+ switch (new DataView(data.buffer, data.byteOffset).getUint16(offset, true)) {
1163
+ case 0: {
1164
+ const payload = readSchemaPayload(data, offset + 8);
1165
+ return {
1166
+ value: {
1167
+ type: "success",
1168
+ payload: payload.value
1169
+ },
1170
+ nextOffset: payload.nextOffset
1171
+ };
1172
+ }
1173
+ case 1: {
1174
+ const exception = readException(data, offset + 8);
1175
+ return {
1176
+ value: {
1177
+ type: "exception",
1178
+ exception: exception.value
1179
+ },
1180
+ nextOffset: exception.nextOffset
1181
+ };
1182
+ }
1183
+ default: return {
1184
+ value: {
1185
+ type: "success",
1186
+ payload: {
1187
+ schemaData: new Uint8Array(),
1188
+ format: SchemaFormat.BINARY,
1189
+ dependencies: []
1190
+ }
1191
+ },
1192
+ nextOffset: offset + 8
1193
+ };
1194
+ }
1195
+ }
1196
+ /**
1197
+ * Get the serialized size of a SchemaPayload
1198
+ */
1199
+ function getSchemaPayloadSize(payload) {
1200
+ let size = 32;
1201
+ size += align8(payload.schemaData.length);
1202
+ if (payload.sourceInfo) size += align8(payload.sourceInfo.length);
1203
+ size += getSchemaDependenciesSize(payload.dependencies);
1204
+ return size;
1205
+ }
1206
+ /**
1207
+ * Write a SchemaPayload to binary format
1208
+ */
1209
+ function writeSchemaPayload(bytes, offset, payload) {
1210
+ new DataView(bytes.buffer, bytes.byteOffset).setUint32(offset, payload.format, true);
1211
+ let currentOffset = offset + 8;
1212
+ writePointer(bytes, currentOffset, payload.schemaData.length);
1213
+ currentOffset += 8;
1214
+ bytes.set(payload.schemaData, currentOffset);
1215
+ currentOffset += align8(payload.schemaData.length);
1216
+ if (payload.sourceInfo) {
1217
+ writePointer(bytes, currentOffset, payload.sourceInfo.length);
1218
+ currentOffset += 8;
1219
+ bytes.set(payload.sourceInfo, currentOffset);
1220
+ currentOffset += align8(payload.sourceInfo.length);
1221
+ } else {
1222
+ writePointer(bytes, currentOffset, 0);
1223
+ currentOffset += 8;
1224
+ }
1225
+ currentOffset = writeSchemaDependencies(bytes, currentOffset, payload.dependencies);
1226
+ return currentOffset;
1227
+ }
1228
+ /**
1229
+ * Read a SchemaPayload from binary format
1230
+ */
1231
+ function readSchemaPayload(data, offset) {
1232
+ const format = new DataView(data.buffer, data.byteOffset).getUint32(offset, true);
1233
+ let currentOffset = offset + 8;
1234
+ const schemaDataLen = readPointer(data, currentOffset);
1235
+ currentOffset += 8;
1236
+ const schemaData = data.slice(currentOffset, currentOffset + schemaDataLen);
1237
+ currentOffset += align8(schemaDataLen);
1238
+ const sourceInfoLen = readPointer(data, currentOffset);
1239
+ currentOffset += 8;
1240
+ let sourceInfo;
1241
+ if (sourceInfoLen > 0) {
1242
+ sourceInfo = data.slice(currentOffset, currentOffset + sourceInfoLen);
1243
+ currentOffset += align8(sourceInfoLen);
1244
+ }
1245
+ const deps = readSchemaDependencies(data, currentOffset);
1246
+ return {
1247
+ value: {
1248
+ schemaData,
1249
+ format,
1250
+ sourceInfo,
1251
+ dependencies: deps.value
1252
+ },
1253
+ nextOffset: deps.nextOffset
1254
+ };
1255
+ }
1256
+ /**
1257
+ * Get the serialized size of SchemaDependency array
1258
+ */
1259
+ function getSchemaDependenciesSize(deps) {
1260
+ let size = 8;
1261
+ for (const dep of deps) {
1262
+ size += 32;
1263
+ size += align8(dep.fileName.length + 1);
1264
+ if (dep.schemaHash) size += align8(dep.schemaHash.length);
1265
+ }
1266
+ return size;
1267
+ }
1268
+ /**
1269
+ * Write SchemaDependency array to binary format
1270
+ */
1271
+ function writeSchemaDependencies(bytes, offset, deps) {
1272
+ const view = new DataView(bytes.buffer, bytes.byteOffset);
1273
+ writePointer(bytes, offset, deps.length);
1274
+ let currentOffset = offset + 8;
1275
+ for (const dep of deps) {
1276
+ view.setBigUint64(currentOffset, dep.fileId, true);
1277
+ currentOffset += 8;
1278
+ const fileNameBytes = new TextEncoder().encode(`${dep.fileName}\0`);
1279
+ writePointer(bytes, currentOffset, fileNameBytes.length);
1280
+ currentOffset += 8;
1281
+ bytes.set(fileNameBytes, currentOffset);
1282
+ currentOffset += align8(fileNameBytes.length);
1283
+ if (dep.schemaHash && dep.schemaHash.length > 0) {
1284
+ writePointer(bytes, currentOffset, dep.schemaHash.length);
1285
+ currentOffset += 8;
1286
+ bytes.set(dep.schemaHash, currentOffset);
1287
+ currentOffset += align8(dep.schemaHash.length);
1288
+ } else {
1289
+ writePointer(bytes, currentOffset, 0);
1290
+ currentOffset += 8;
1291
+ }
1292
+ }
1293
+ return currentOffset;
1294
+ }
1295
+ /**
1296
+ * Read SchemaDependency array from binary format
1297
+ */
1298
+ function readSchemaDependencies(data, offset) {
1299
+ const view = new DataView(data.buffer, data.byteOffset);
1300
+ const count = readPointer(data, offset);
1301
+ let currentOffset = offset + 8;
1302
+ const deps = [];
1303
+ for (let i = 0; i < count; i++) {
1304
+ const fileId = view.getBigUint64(currentOffset, true);
1305
+ currentOffset += 8;
1306
+ const fileNameLen = readPointer(data, currentOffset);
1307
+ currentOffset += 8;
1308
+ const fileNameBytes = data.slice(currentOffset, currentOffset + fileNameLen);
1309
+ const fileName = new TextDecoder().decode(fileNameBytes).replace(/\0$/, "");
1310
+ currentOffset += align8(fileNameLen);
1311
+ const schemaHashLen = readPointer(data, currentOffset);
1312
+ currentOffset += 8;
1313
+ let schemaHash;
1314
+ if (schemaHashLen > 0) {
1315
+ schemaHash = data.slice(currentOffset, currentOffset + schemaHashLen);
1316
+ currentOffset += align8(schemaHashLen);
1317
+ }
1318
+ deps.push({
1319
+ fileId,
1320
+ fileName,
1321
+ schemaHash
1322
+ });
1323
+ }
1324
+ return {
1325
+ value: deps,
1326
+ nextOffset: currentOffset
1327
+ };
1328
+ }
1329
+ /**
1330
+ * Get the serialized size of an Exception
1331
+ */
1332
+ function getExceptionSize(exception) {
1333
+ let size = 24;
1334
+ size += align8(exception.reason.length);
1335
+ return size;
1336
+ }
1337
+ /**
1338
+ * Write an Exception to binary format
1339
+ */
1340
+ function writeException(bytes, offset, exception) {
1341
+ const view = new DataView(bytes.buffer, bytes.byteOffset);
1342
+ const reasonBytes = new TextEncoder().encode(exception.reason);
1343
+ writePointer(bytes, offset, reasonBytes.length);
1344
+ bytes.set(reasonBytes, offset + 8);
1345
+ let currentOffset = offset + 8 + align8(reasonBytes.length);
1346
+ view.setUint16(currentOffset, exception.type, true);
1347
+ currentOffset += 8;
1348
+ view.setUint8(currentOffset, exception.obsoleteIsCallersFault ? 1 : 0);
1349
+ view.setUint16(currentOffset + 1, exception.obsoleteDurability ?? 0, true);
1350
+ currentOffset += 8;
1351
+ return currentOffset;
1352
+ }
1353
+ /**
1354
+ * Read an Exception from binary format
1355
+ */
1356
+ function readException(data, offset) {
1357
+ const view = new DataView(data.buffer, data.byteOffset);
1358
+ const reasonLen = readPointer(data, offset);
1359
+ const reasonBytes = data.slice(offset + 8, offset + 8 + reasonLen);
1360
+ const reason = new TextDecoder().decode(reasonBytes);
1361
+ let currentOffset = offset + 8 + align8(reasonLen);
1362
+ const type = view.getUint16(currentOffset, true);
1363
+ currentOffset += 8;
1364
+ const obsoleteIsCallersFault = view.getUint8(currentOffset) !== 0;
1365
+ const obsoleteDurability = view.getUint16(currentOffset + 1, true);
1366
+ currentOffset += 8;
1367
+ return {
1368
+ value: {
1369
+ reason,
1370
+ type,
1371
+ obsoleteIsCallersFault,
1372
+ obsoleteDurability
1373
+ },
1374
+ nextOffset: currentOffset
1375
+ };
1376
+ }
1377
+ /**
1378
+ * Helper: Align size to 8-byte boundary
1379
+ */
1380
+ function align8(size) {
1381
+ return size + 7 & -8;
1382
+ }
1383
+ /**
1384
+ * Helper: Write a pointer (list/struct offset and size)
1385
+ */
1386
+ function writePointer(bytes, offset, size) {
1387
+ const view = new DataView(bytes.buffer, bytes.byteOffset);
1388
+ view.setUint32(offset, size, true);
1389
+ view.setUint32(offset + 4, 0, true);
1390
+ }
1391
+ /**
1392
+ * Helper: Read a pointer
1393
+ */
1394
+ function readPointer(data, offset) {
1395
+ return new DataView(data.buffer, data.byteOffset).getUint32(offset, true);
1396
+ }
1397
+ /**
1398
+ * Serialize GetSchemaParams
1399
+ */
1400
+ function serializeGetSchemaParams(params) {
1401
+ const totalSize = 12 + getSchemaTargetSize(params.target);
1402
+ const buffer = new ArrayBuffer(totalSize);
1403
+ const view = new DataView(buffer);
1404
+ const bytes = new Uint8Array(buffer);
1405
+ view.setUint32(0, params.format ?? SchemaFormat.BINARY, true);
1406
+ writeSchemaTarget(bytes, 8, params.target);
1407
+ return bytes;
1408
+ }
1409
+ /**
1410
+ * Serialize GetSchemaResults
1411
+ */
1412
+ function serializeGetSchemaResults(results) {
1413
+ const totalSize = 8 + getSchemaPayloadSize(results.payload);
1414
+ const buffer = new ArrayBuffer(totalSize);
1415
+ const bytes = new Uint8Array(buffer);
1416
+ writeSchemaPayload(bytes, 8, results.payload);
1417
+ return bytes;
1418
+ }
1419
+ /**
1420
+ * Serialize ListSchemasResults
1421
+ */
1422
+ function serializeListSchemasResults(results) {
1423
+ let totalSize = 16;
1424
+ for (const schema of results.schemas) {
1425
+ totalSize += 32;
1426
+ totalSize += align8(schema.displayName.length);
1427
+ totalSize += align8(schema.fileName.length);
1428
+ }
1429
+ const buffer = new ArrayBuffer(totalSize);
1430
+ const view = new DataView(buffer);
1431
+ const bytes = new Uint8Array(buffer);
1432
+ writePointer(bytes, 8, results.schemas.length);
1433
+ let offset = 16;
1434
+ for (const schema of results.schemas) {
1435
+ view.setBigUint64(offset, schema.typeId, true);
1436
+ offset += 8;
1437
+ const displayNameBytes = new TextEncoder().encode(schema.displayName);
1438
+ writePointer(bytes, offset, displayNameBytes.length);
1439
+ offset += 8;
1440
+ bytes.set(displayNameBytes, offset);
1441
+ offset += align8(displayNameBytes.length);
1442
+ view.setBigUint64(offset, schema.fileId, true);
1443
+ offset += 8;
1444
+ const fileNameBytes = new TextEncoder().encode(schema.fileName);
1445
+ writePointer(bytes, offset, fileNameBytes.length);
1446
+ offset += 8;
1447
+ bytes.set(fileNameBytes, offset);
1448
+ offset += align8(fileNameBytes.length);
1449
+ let flags = 0;
1450
+ if (schema.isInterface) flags |= 1;
1451
+ if (schema.isStruct) flags |= 2;
1452
+ if (schema.isEnum) flags |= 4;
1453
+ view.setUint8(offset, flags);
1454
+ offset += 8;
1455
+ }
1456
+ return bytes;
1457
+ }
1458
+
1459
+ //#endregion
1460
+ //#region src/rpc/rpc-connection.ts
1461
+ var RpcConnection = class {
1462
+ transport;
1463
+ options;
1464
+ questions = new QuestionTable();
1465
+ answers = new AnswerTable();
1466
+ imports = new ImportTable();
1467
+ exports = new ExportTable();
1468
+ queuedCalls = new QueuedCallManager();
1469
+ pipelineResolutions = new PipelineResolutionTracker();
1470
+ running = false;
1471
+ messageHandler;
1472
+ level3Handlers;
1473
+ level4Handlers;
1474
+ schemaCache = /* @__PURE__ */ new Map();
1475
+ schemaRegistry = createSchemaRegistry();
1476
+ schemaQuestionIdCounter = 1e6;
1477
+ schemaProvider;
1478
+ constructor(transport, options = {}) {
1479
+ this.transport = transport;
1480
+ this.options = options;
1481
+ this.level3Handlers = options.level3Handlers;
1482
+ this.transport.onClose = (reason) => {
1483
+ this.handleDisconnect(reason);
1484
+ };
1485
+ this.transport.onError = (error) => {
1486
+ this.handleError(error);
1487
+ };
1488
+ this.level3Handlers = options.level3Handlers;
1489
+ this.level4Handlers = options.level4Handlers;
1490
+ }
1491
+ /** Start processing messages */
1492
+ async start() {
1493
+ if (this.running) return;
1494
+ this.running = true;
1495
+ this.messageHandler = this.messageLoop();
1496
+ }
1497
+ /** Stop the connection */
1498
+ async stop() {
1499
+ this.running = false;
1500
+ this.transport.close();
1501
+ if (this.messageHandler) try {
1502
+ await this.messageHandler;
1503
+ } catch {}
1504
+ }
1505
+ /** Send a bootstrap request and return the bootstrap capability */
1506
+ async bootstrap() {
1507
+ const question = this.questions.create();
1508
+ const bootstrapMsg = {
1509
+ type: "bootstrap",
1510
+ bootstrap: { questionId: question.id }
1511
+ };
1512
+ await this.transport.send(bootstrapMsg);
1513
+ await question.completionPromise;
1514
+ return {};
1515
+ }
1516
+ /** Make a call to a remote capability */
1517
+ async call(target, interfaceId, methodId, params) {
1518
+ if (isPipelineClient(target)) return target.call(interfaceId, methodId, params);
1519
+ const question = this.questions.create();
1520
+ const callMsg = {
1521
+ type: "call",
1522
+ call: {
1523
+ questionId: question.id,
1524
+ target: {
1525
+ type: "importedCap",
1526
+ importId: target
1527
+ },
1528
+ interfaceId,
1529
+ methodId,
1530
+ allowThirdPartyTailCall: false,
1531
+ noPromisePipelining: false,
1532
+ onlyPromisePipeline: false,
1533
+ params,
1534
+ sendResultsTo: { type: "caller" }
1535
+ }
1536
+ };
1537
+ await this.transport.send(callMsg);
1538
+ return question.completionPromise;
1539
+ }
1540
+ /**
1541
+ * Make a call that returns a PipelineClient for promise pipelining.
1542
+ * This allows making calls on the result before it arrives.
1543
+ */
1544
+ async callPipelined(target, interfaceId, methodId, params) {
1545
+ const question = this.questions.create();
1546
+ const callMsg = {
1547
+ type: "call",
1548
+ call: {
1549
+ questionId: question.id,
1550
+ target: {
1551
+ type: "importedCap",
1552
+ importId: target
1553
+ },
1554
+ interfaceId,
1555
+ methodId,
1556
+ allowThirdPartyTailCall: false,
1557
+ noPromisePipelining: false,
1558
+ onlyPromisePipeline: false,
1559
+ params,
1560
+ sendResultsTo: { type: "caller" }
1561
+ }
1562
+ };
1563
+ await this.transport.send(callMsg);
1564
+ return createPipelineClient({
1565
+ connection: this,
1566
+ questionId: question.id
1567
+ });
1568
+ }
1569
+ /** Send a finish message to release a question */
1570
+ async finish(questionId, releaseResultCaps = true) {
1571
+ if (!this.questions.get(questionId)) return;
1572
+ const finishMsg = {
1573
+ type: "finish",
1574
+ finish: {
1575
+ questionId,
1576
+ releaseResultCaps,
1577
+ requireEarlyCancellationWorkaround: false
1578
+ }
1579
+ };
1580
+ await this.transport.send(finishMsg);
1581
+ this.questions.markFinishSent(questionId);
1582
+ this.questions.remove(questionId);
1583
+ }
1584
+ /** Send a release message for an imported capability */
1585
+ async release(importId, referenceCount = 1) {
1586
+ const releaseMsg = {
1587
+ type: "release",
1588
+ release: {
1589
+ id: importId,
1590
+ referenceCount
1591
+ }
1592
+ };
1593
+ await this.transport.send(releaseMsg);
1594
+ }
1595
+ /** Send a resolve message to indicate a promise has resolved */
1596
+ async resolve(promiseId, cap) {
1597
+ const resolveMsg = {
1598
+ type: "resolve",
1599
+ resolve: {
1600
+ promiseId,
1601
+ resolution: {
1602
+ type: "cap",
1603
+ cap
1604
+ }
1605
+ }
1606
+ };
1607
+ await this.transport.send(resolveMsg);
1608
+ }
1609
+ /** Send a resolve message indicating a promise was broken */
1610
+ async resolveException(promiseId, reason) {
1611
+ const resolveMsg = {
1612
+ type: "resolve",
1613
+ resolve: {
1614
+ promiseId,
1615
+ resolution: {
1616
+ type: "exception",
1617
+ exception: {
1618
+ reason,
1619
+ type: "failed"
1620
+ }
1621
+ }
1622
+ }
1623
+ };
1624
+ await this.transport.send(resolveMsg);
1625
+ }
1626
+ /** Send a return message (internal use) */
1627
+ async sendReturn(ret) {
1628
+ const returnMsg = {
1629
+ type: "return",
1630
+ return: ret
1631
+ };
1632
+ await this.transport.send(returnMsg);
1633
+ }
1634
+ /** Send a disembargo message (internal use) */
1635
+ async sendDisembargo(disembargo) {
1636
+ const disembargoMsg = {
1637
+ type: "disembargo",
1638
+ disembargo
1639
+ };
1640
+ await this.transport.send(disembargoMsg);
1641
+ }
1642
+ /** Internal method: Create a new question (used by pipeline) */
1643
+ createQuestion() {
1644
+ return this.questions.create().id;
1645
+ }
1646
+ /** Internal method: Send a call message (used by pipeline) */
1647
+ async sendCall(call) {
1648
+ const callMsg = {
1649
+ type: "call",
1650
+ call
1651
+ };
1652
+ await this.transport.send(callMsg);
1653
+ }
1654
+ /** Internal method: Wait for an answer (used by pipeline) */
1655
+ async waitForAnswer(questionId) {
1656
+ const question = this.questions.get(questionId);
1657
+ if (!question) throw new Error(`Question ${questionId} not found`);
1658
+ return question.completionPromise;
1659
+ }
1660
+ /** Main message processing loop */
1661
+ async messageLoop() {
1662
+ while (this.running) try {
1663
+ const message = await this.transport.receive();
1664
+ if (message === null) break;
1665
+ await this.handleMessage(message);
1666
+ } catch (error) {
1667
+ if (this.running) this.handleError(error);
1668
+ }
1669
+ }
1670
+ /** Handle incoming messages */
1671
+ async handleMessage(message) {
1672
+ switch (message.type) {
1673
+ case "bootstrap":
1674
+ await this.handleBootstrap(message.bootstrap);
1675
+ break;
1676
+ case "call":
1677
+ await this.handleCall(message.call);
1678
+ break;
1679
+ case "return":
1680
+ await this.handleReturn(message.return);
1681
+ break;
1682
+ case "finish":
1683
+ await this.handleFinish(message.finish);
1684
+ break;
1685
+ case "resolve":
1686
+ await this.handleResolve(message.resolve);
1687
+ break;
1688
+ case "release":
1689
+ await this.handleRelease(message.release);
1690
+ break;
1691
+ case "disembargo":
1692
+ await this.handleDisembargo(message.disembargo);
1693
+ break;
1694
+ case "provide":
1695
+ await this.handleProvide(message.provide);
1696
+ break;
1697
+ case "accept":
1698
+ await this.handleAccept(message.accept);
1699
+ break;
1700
+ case "join":
1701
+ await this.handleJoin(message.join);
1702
+ break;
1703
+ case "abort":
1704
+ this.handleAbort(message.exception.reason);
1705
+ break;
1706
+ case "unimplemented": break;
1707
+ default: await this.sendUnimplemented(message);
1708
+ }
1709
+ }
1710
+ /** Handle bootstrap request */
1711
+ async handleBootstrap(bootstrap) {
1712
+ this.answers.create(bootstrap.questionId);
1713
+ const returnMsg = {
1714
+ type: "return",
1715
+ return: {
1716
+ answerId: bootstrap.questionId,
1717
+ releaseParamCaps: true,
1718
+ noFinishNeeded: false,
1719
+ result: {
1720
+ type: "results",
1721
+ payload: {
1722
+ content: new Uint8Array(0),
1723
+ capTable: []
1724
+ }
1725
+ }
1726
+ }
1727
+ };
1728
+ await this.transport.send(returnMsg);
1729
+ this.answers.markReturnSent(bootstrap.questionId);
1730
+ }
1731
+ /** Handle incoming call */
1732
+ async handleCall(call) {
1733
+ this.answers.create(call.questionId);
1734
+ const returnMsg = {
1735
+ type: "return",
1736
+ return: {
1737
+ answerId: call.questionId,
1738
+ releaseParamCaps: true,
1739
+ noFinishNeeded: false,
1740
+ result: {
1741
+ type: "exception",
1742
+ exception: {
1743
+ reason: "Method not implemented",
1744
+ type: "unimplemented"
1745
+ }
1746
+ }
1747
+ }
1748
+ };
1749
+ await this.transport.send(returnMsg);
1750
+ this.answers.markReturnSent(call.questionId);
1751
+ }
1752
+ /** Handle return message */
1753
+ async handleReturn(ret) {
1754
+ if (!this.questions.get(ret.answerId)) return;
1755
+ if (ret.result.type === "results") {
1756
+ const capTable = ret.result.payload.capTable;
1757
+ if (capTable.length > 0) {
1758
+ const cap = capTable[0];
1759
+ if (cap.type === "receiverHosted") this.pipelineResolutions.resolveToCapability(ret.answerId, cap.importId);
1760
+ else if (cap.type === "thirdPartyHosted") await this.handleThirdPartyCapability(ret.answerId, cap.thirdPartyCapId);
1761
+ }
1762
+ } else if (ret.result.type === "exception") this.pipelineResolutions.resolveToException(ret.answerId, ret.result.exception.reason);
1763
+ switch (ret.result.type) {
1764
+ case "results":
1765
+ this.questions.complete(ret.answerId, ret.result.payload);
1766
+ break;
1767
+ case "exception":
1768
+ this.questions.cancel(ret.answerId, new Error(ret.result.exception.reason));
1769
+ break;
1770
+ case "canceled":
1771
+ this.questions.cancel(ret.answerId, /* @__PURE__ */ new Error("Call canceled"));
1772
+ break;
1773
+ case "acceptFromThirdParty":
1774
+ await this.handleAcceptFromThirdParty(ret.answerId, ret.result.thirdPartyCapId);
1775
+ break;
1776
+ default: this.questions.cancel(ret.answerId, /* @__PURE__ */ new Error("Unknown return type"));
1777
+ }
1778
+ }
1779
+ /** Handle finish message */
1780
+ async handleFinish(finish) {
1781
+ this.answers.markFinishReceived(finish.questionId);
1782
+ this.answers.remove(finish.questionId);
1783
+ }
1784
+ /** Handle resolve message (Level 1) */
1785
+ async handleResolve(resolve) {
1786
+ const { promiseId, resolution } = resolve;
1787
+ switch (resolution.type) {
1788
+ case "cap":
1789
+ this.imports.markResolved(promiseId);
1790
+ break;
1791
+ case "exception":
1792
+ console.warn(`Promise ${promiseId} broken: ${resolution.exception.reason}`);
1793
+ break;
1794
+ }
1795
+ }
1796
+ /** Handle release message (Level 1) */
1797
+ async handleRelease(release) {
1798
+ const { id, referenceCount } = release;
1799
+ if (this.exports.release(id, referenceCount)) console.log(`Export ${id} fully released`);
1800
+ }
1801
+ /** Handle disembargo message (Level 1) */
1802
+ async handleDisembargo(disembargo) {
1803
+ const { target, context } = disembargo;
1804
+ if (this.level3Handlers) {
1805
+ await this.level3Handlers.handleDisembargo(disembargo);
1806
+ return;
1807
+ }
1808
+ if (context.type === "senderLoopback") {
1809
+ const echoMsg = {
1810
+ type: "disembargo",
1811
+ disembargo: {
1812
+ target,
1813
+ context: {
1814
+ type: "receiverLoopback",
1815
+ embargoId: context.embargoId
1816
+ }
1817
+ }
1818
+ };
1819
+ await this.transport.send(echoMsg);
1820
+ }
1821
+ }
1822
+ /** Handle provide message (Level 3) */
1823
+ async handleProvide(provide) {
1824
+ if (this.level3Handlers) await this.level3Handlers.handleProvide(provide);
1825
+ else await this.sendReturnException(provide.questionId, "Level 3 RPC (Provide) not implemented");
1826
+ }
1827
+ /** Handle accept message (Level 3) */
1828
+ async handleAccept(accept) {
1829
+ if (this.level3Handlers) await this.level3Handlers.handleAccept(accept);
1830
+ else await this.sendReturnException(accept.questionId, "Level 3 RPC (Accept) not implemented");
1831
+ }
1832
+ /** Handle third-party capability in return results (Level 3) */
1833
+ async handleThirdPartyCapability(_questionId, thirdPartyCapId) {
1834
+ if (this.level3Handlers) {
1835
+ if (await this.level3Handlers.handleThirdPartyCapability(thirdPartyCapId) !== void 0) {}
1836
+ }
1837
+ }
1838
+ /** Handle acceptFromThirdParty return type (Level 3) */
1839
+ async handleAcceptFromThirdParty(questionId, thirdPartyCapId) {
1840
+ if (this.level3Handlers) {
1841
+ const importId = await this.level3Handlers.handleThirdPartyCapability(thirdPartyCapId);
1842
+ if (importId !== void 0) this.questions.complete(questionId, { importId });
1843
+ else this.questions.cancel(questionId, /* @__PURE__ */ new Error("Failed to resolve third-party capability"));
1844
+ } else this.questions.cancel(questionId, /* @__PURE__ */ new Error("Level 3 RPC not enabled"));
1845
+ }
1846
+ /** Handle abort message */
1847
+ handleAbort(_reason) {
1848
+ this.running = false;
1849
+ this.questions.clear();
1850
+ this.answers.clear();
1851
+ this.imports.clear();
1852
+ this.exports.clear();
1853
+ this.queuedCalls.clear();
1854
+ this.pipelineResolutions.clear();
1855
+ }
1856
+ /** Handle disconnect */
1857
+ handleDisconnect(_reason) {
1858
+ this.running = false;
1859
+ this.questions.clear();
1860
+ this.answers.clear();
1861
+ this.imports.clear();
1862
+ this.exports.clear();
1863
+ this.queuedCalls.clear();
1864
+ this.pipelineResolutions.clear();
1865
+ }
1866
+ /** Handle error */
1867
+ handleError(error) {
1868
+ console.error("RPC error:", error);
1869
+ }
1870
+ /** Send unimplemented response */
1871
+ async sendUnimplemented(originalMessage) {
1872
+ const msg = {
1873
+ type: "unimplemented",
1874
+ message: originalMessage
1875
+ };
1876
+ await this.transport.send(msg);
1877
+ }
1878
+ /** Send return exception (helper) */
1879
+ async sendReturnException(questionId, reason) {
1880
+ const returnMsg = {
1881
+ type: "return",
1882
+ return: {
1883
+ answerId: questionId,
1884
+ releaseParamCaps: true,
1885
+ noFinishNeeded: false,
1886
+ result: {
1887
+ type: "exception",
1888
+ exception: {
1889
+ reason,
1890
+ type: "unimplemented"
1891
+ }
1892
+ }
1893
+ }
1894
+ };
1895
+ await this.transport.send(returnMsg);
1896
+ }
1897
+ /**
1898
+ * Set the Level 4 handlers for this connection.
1899
+ * This enables reference equality verification support.
1900
+ */
1901
+ setLevel4Handlers(handlers) {
1902
+ this.level4Handlers = handlers;
1903
+ }
1904
+ /**
1905
+ * Send a Join message to verify that two capabilities point to the same object.
1906
+ * Requires Level 4 handlers to be set.
1907
+ */
1908
+ async join(_target1, _target2) {
1909
+ if (!this.level4Handlers) throw new Error("Level 4 handlers not set");
1910
+ }
1911
+ /** Handle join message (Level 4) */
1912
+ async handleJoin(join) {
1913
+ if (this.level4Handlers) await this.level4Handlers.handleJoin(join);
1914
+ else await this.sendReturnException(join.questionId, "Level 4 RPC (Join) not implemented");
1915
+ }
1916
+ /** Import a capability from the remote peer */
1917
+ importCapability(importId, isPromise = false) {
1918
+ this.imports.add(importId, isPromise);
1919
+ }
1920
+ /** Export a capability to the remote peer */
1921
+ exportCapability(capability, isPromise = false) {
1922
+ return this.exports.add(capability, isPromise).id;
1923
+ }
1924
+ /** Get an imported capability */
1925
+ getImport(importId) {
1926
+ return this.imports.get(importId);
1927
+ }
1928
+ /** Get an exported capability */
1929
+ getExport(exportId) {
1930
+ return this.exports.get(exportId);
1931
+ }
1932
+ /**
1933
+ * Set the Level 3 handlers for this connection.
1934
+ * This enables three-way introduction support.
1935
+ */
1936
+ setLevel3Handlers(handlers) {
1937
+ this.level3Handlers = handlers;
1938
+ }
1939
+ /**
1940
+ * Send a Provide message to offer a capability to a third party.
1941
+ * Requires Level 3 handlers to be set.
1942
+ */
1943
+ async provideToThirdParty(_target, _recipient) {
1944
+ if (!this.level3Handlers) throw new Error("Level 3 handlers not set");
1945
+ }
1946
+ /**
1947
+ * Get dynamic schema information for a type from the remote server.
1948
+ * This allows runtime discovery of schema information for types not known at compile time.
1949
+ *
1950
+ * Results are cached to avoid repeated network requests for the same type.
1951
+ *
1952
+ * @param typeId - The unique type ID of the schema to fetch
1953
+ * @returns The schema node for the requested type
1954
+ * @throws Error if the schema cannot be fetched or parsed
1955
+ *
1956
+ * @example
1957
+ * ```typescript
1958
+ * const schema = await connection.getDynamicSchema(0x1234567890abcdefn);
1959
+ * console.log('Struct fields:', schema.structInfo?.fields);
1960
+ * ```
1961
+ */
1962
+ async getDynamicSchema(typeId) {
1963
+ const cached = this.schemaCache.get(typeId);
1964
+ if (cached) return cached;
1965
+ const registered = this.schemaRegistry.getNode(typeId);
1966
+ if (registered) {
1967
+ this.schemaCache.set(typeId, registered);
1968
+ return registered;
1969
+ }
1970
+ const nodes = parseSchemaNodes((await this.fetchSchemaFromRemote({
1971
+ type: "byTypeId",
1972
+ typeId
1973
+ })).schemaData);
1974
+ for (const node of nodes) {
1975
+ this.schemaRegistry.registerNode(node);
1976
+ this.schemaCache.set(node.id, node);
1977
+ }
1978
+ const result = this.schemaRegistry.getNode(typeId);
1979
+ if (!result) throw new Error(`Schema for type ${typeId.toString(16)} not found in response`);
1980
+ return result;
1981
+ }
1982
+ /**
1983
+ * Get dynamic schema by type name.
1984
+ *
1985
+ * @param typeName - The fully qualified type name (e.g., "foo.bar.MyStruct")
1986
+ * @returns The schema node for the requested type
1987
+ * @throws Error if the schema cannot be fetched or parsed
1988
+ */
1989
+ async getDynamicSchemaByName(typeName) {
1990
+ const registered = this.schemaRegistry.getNodeByName(typeName);
1991
+ if (registered) {
1992
+ this.schemaCache.set(registered.id, registered);
1993
+ return registered;
1994
+ }
1995
+ const nodes = parseSchemaNodes((await this.fetchSchemaFromRemote({
1996
+ type: "byTypeName",
1997
+ typeName
1998
+ })).schemaData);
1999
+ for (const node of nodes) {
2000
+ this.schemaRegistry.registerNode(node);
2001
+ this.schemaCache.set(node.id, node);
2002
+ }
2003
+ const result = this.schemaRegistry.getNodeByName(typeName);
2004
+ if (!result) throw new Error(`Schema for type "${typeName}" not found in response`);
2005
+ return result;
2006
+ }
2007
+ /**
2008
+ * Fetch schema information from the remote vat.
2009
+ * This is an internal method used by getDynamicSchema.
2010
+ *
2011
+ * @param target - The schema target specification
2012
+ * @returns The schema payload containing binary schema data
2013
+ * @throws Error if the request fails
2014
+ */
2015
+ async fetchSchemaFromRemote(target) {
2016
+ if (!this.running) throw new Error("Connection is not running");
2017
+ const questionId = this.schemaQuestionIdCounter++;
2018
+ const requestData = serializeSchemaRequest({
2019
+ questionId,
2020
+ targetSchema: target
2021
+ });
2022
+ const schemaRequestMsg = {
2023
+ type: "call",
2024
+ call: {
2025
+ questionId,
2026
+ target: {
2027
+ type: "importedCap",
2028
+ importId: 0
2029
+ },
2030
+ interfaceId: BigInt("0x1234567890abcdef"),
2031
+ methodId: 0,
2032
+ allowThirdPartyTailCall: false,
2033
+ noPromisePipelining: false,
2034
+ onlyPromisePipeline: false,
2035
+ params: {
2036
+ content: requestData,
2037
+ capTable: []
2038
+ },
2039
+ sendResultsTo: { type: "caller" }
2040
+ }
2041
+ };
2042
+ await this.transport.send(schemaRequestMsg);
2043
+ const question = this.questions.create();
2044
+ question.id = questionId;
2045
+ try {
2046
+ const result = await question.completionPromise;
2047
+ if (result && typeof result === "object" && "content" in result) {
2048
+ const response = deserializeSchemaResponse(result.content);
2049
+ if (response.result.type === "success") return response.result.payload;
2050
+ throw new Error(`Schema request failed: ${response.result.exception.reason}`);
2051
+ }
2052
+ throw new Error("Invalid schema response format");
2053
+ } catch (error) {
2054
+ this.questions.remove(questionId);
2055
+ throw error;
2056
+ }
2057
+ }
2058
+ /**
2059
+ * Get the schema registry for this connection.
2060
+ * The registry contains all schemas that have been fetched or registered.
2061
+ *
2062
+ * @returns The schema registry
2063
+ */
2064
+ getSchemaRegistry() {
2065
+ return this.schemaRegistry;
2066
+ }
2067
+ /**
2068
+ * Register a schema node locally.
2069
+ * This can be used to pre-populate the schema cache or add custom schemas.
2070
+ *
2071
+ * @param node - The schema node to register
2072
+ */
2073
+ registerSchema(node) {
2074
+ this.schemaRegistry.registerNode(node);
2075
+ this.schemaCache.set(node.id, node);
2076
+ }
2077
+ /**
2078
+ * Clear the schema cache.
2079
+ * This forces subsequent getDynamicSchema calls to fetch from the remote server.
2080
+ */
2081
+ clearSchemaCache() {
2082
+ this.schemaCache.clear();
2083
+ }
2084
+ /**
2085
+ * Check if a schema is cached locally.
2086
+ *
2087
+ * @param typeId - The type ID to check
2088
+ * @returns True if the schema is in the cache
2089
+ */
2090
+ hasCachedSchema(typeId) {
2091
+ return this.schemaCache.has(typeId) || this.schemaRegistry.hasNode(typeId);
2092
+ }
2093
+ /**
2094
+ * Register a schema provider for serving schema requests.
2095
+ * This allows the connection to respond to schema requests from remote peers.
2096
+ *
2097
+ * @param provider - The schema capability server to register
2098
+ */
2099
+ registerSchemaProvider(provider) {
2100
+ this.schemaProvider = provider;
2101
+ }
2102
+ /**
2103
+ * List all available schemas from the remote vat.
2104
+ * This requires the remote to support the schema listing capability.
2105
+ *
2106
+ * @returns Array of available schema information
2107
+ * @throws Error if the request fails or is not supported
2108
+ */
2109
+ async listAvailableSchemas() {
2110
+ if (!this.running) throw new Error("Connection is not running");
2111
+ const questionId = this.schemaQuestionIdCounter++;
2112
+ const requestData = serializeSchemaRequest({
2113
+ questionId,
2114
+ targetSchema: { type: "allSchemas" }
2115
+ });
2116
+ const listRequestMsg = {
2117
+ type: "call",
2118
+ call: {
2119
+ questionId,
2120
+ target: {
2121
+ type: "importedCap",
2122
+ importId: 0
2123
+ },
2124
+ interfaceId: BigInt("0x1234567890abcdef"),
2125
+ methodId: 1,
2126
+ allowThirdPartyTailCall: false,
2127
+ noPromisePipelining: false,
2128
+ onlyPromisePipeline: false,
2129
+ params: {
2130
+ content: requestData,
2131
+ capTable: []
2132
+ },
2133
+ sendResultsTo: { type: "caller" }
2134
+ }
2135
+ };
2136
+ await this.transport.send(listRequestMsg);
2137
+ const question = this.questions.create();
2138
+ question.id = questionId;
2139
+ try {
2140
+ const result = await question.completionPromise;
2141
+ if (result && typeof result === "object" && "content" in result) {
2142
+ const response = deserializeSchemaResponse(result.content);
2143
+ if (response.result.type === "success") return parseSchemaNodes(response.result.payload.schemaData).map((node) => ({
2144
+ typeId: node.id,
2145
+ displayName: node.displayName
2146
+ }));
2147
+ throw new Error(`List schemas failed: ${response.result.exception.reason}`);
2148
+ }
2149
+ throw new Error("Invalid list schemas response format");
2150
+ } catch (error) {
2151
+ this.questions.remove(questionId);
2152
+ throw error;
2153
+ }
2154
+ }
2155
+ };
2156
+
2157
+ //#endregion
2158
+ Object.defineProperty(exports, 'AnswerTable', {
2159
+ enumerable: true,
2160
+ get: function () {
2161
+ return AnswerTable;
2162
+ }
2163
+ });
2164
+ Object.defineProperty(exports, 'ExportTable', {
2165
+ enumerable: true,
2166
+ get: function () {
2167
+ return ExportTable;
2168
+ }
2169
+ });
2170
+ Object.defineProperty(exports, 'ImportTable', {
2171
+ enumerable: true,
2172
+ get: function () {
2173
+ return ImportTable;
2174
+ }
2175
+ });
2176
+ Object.defineProperty(exports, 'PIPELINE_CLIENT_SYMBOL', {
2177
+ enumerable: true,
2178
+ get: function () {
2179
+ return PIPELINE_CLIENT_SYMBOL;
2180
+ }
2181
+ });
2182
+ Object.defineProperty(exports, 'PipelineOpTracker', {
2183
+ enumerable: true,
2184
+ get: function () {
2185
+ return PipelineOpTracker;
2186
+ }
2187
+ });
2188
+ Object.defineProperty(exports, 'PipelineResolutionTracker', {
2189
+ enumerable: true,
2190
+ get: function () {
2191
+ return PipelineResolutionTracker;
2192
+ }
2193
+ });
2194
+ Object.defineProperty(exports, 'QuestionTable', {
2195
+ enumerable: true,
2196
+ get: function () {
2197
+ return QuestionTable;
2198
+ }
2199
+ });
2200
+ Object.defineProperty(exports, 'QueuedCallManager', {
2201
+ enumerable: true,
2202
+ get: function () {
2203
+ return QueuedCallManager;
2204
+ }
2205
+ });
2206
+ Object.defineProperty(exports, 'RpcConnection', {
2207
+ enumerable: true,
2208
+ get: function () {
2209
+ return RpcConnection;
2210
+ }
2211
+ });
2212
+ Object.defineProperty(exports, 'SCHEMA_MESSAGE_TYPES', {
2213
+ enumerable: true,
2214
+ get: function () {
2215
+ return SCHEMA_MESSAGE_TYPES;
2216
+ }
2217
+ });
2218
+ Object.defineProperty(exports, 'SchemaFormat', {
2219
+ enumerable: true,
2220
+ get: function () {
2221
+ return SchemaFormat;
2222
+ }
2223
+ });
2224
+ Object.defineProperty(exports, 'SchemaNodeType', {
2225
+ enumerable: true,
2226
+ get: function () {
2227
+ return SchemaNodeType;
2228
+ }
2229
+ });
2230
+ Object.defineProperty(exports, 'createPipelineClient', {
2231
+ enumerable: true,
2232
+ get: function () {
2233
+ return createPipelineClient;
2234
+ }
2235
+ });
2236
+ Object.defineProperty(exports, 'createSchemaRegistry', {
2237
+ enumerable: true,
2238
+ get: function () {
2239
+ return createSchemaRegistry;
2240
+ }
2241
+ });
2242
+ Object.defineProperty(exports, 'deserializeSchemaRequest', {
2243
+ enumerable: true,
2244
+ get: function () {
2245
+ return deserializeSchemaRequest;
2246
+ }
2247
+ });
2248
+ Object.defineProperty(exports, 'deserializeSchemaResponse', {
2249
+ enumerable: true,
2250
+ get: function () {
2251
+ return deserializeSchemaResponse;
2252
+ }
2253
+ });
2254
+ Object.defineProperty(exports, 'isPipelineClient', {
2255
+ enumerable: true,
2256
+ get: function () {
2257
+ return isPipelineClient;
2258
+ }
2259
+ });
2260
+ Object.defineProperty(exports, 'parseSchemaNodes', {
2261
+ enumerable: true,
2262
+ get: function () {
2263
+ return parseSchemaNodes;
2264
+ }
2265
+ });
2266
+ Object.defineProperty(exports, 'serializeGetSchemaParams', {
2267
+ enumerable: true,
2268
+ get: function () {
2269
+ return serializeGetSchemaParams;
2270
+ }
2271
+ });
2272
+ Object.defineProperty(exports, 'serializeGetSchemaResults', {
2273
+ enumerable: true,
2274
+ get: function () {
2275
+ return serializeGetSchemaResults;
2276
+ }
2277
+ });
2278
+ Object.defineProperty(exports, 'serializeListSchemasResults', {
2279
+ enumerable: true,
2280
+ get: function () {
2281
+ return serializeListSchemasResults;
2282
+ }
2283
+ });
2284
+ Object.defineProperty(exports, 'serializeSchemaRequest', {
2285
+ enumerable: true,
2286
+ get: function () {
2287
+ return serializeSchemaRequest;
2288
+ }
2289
+ });
2290
+ Object.defineProperty(exports, 'serializeSchemaResponse', {
2291
+ enumerable: true,
2292
+ get: function () {
2293
+ return serializeSchemaResponse;
2294
+ }
2295
+ });
2296
+ //# sourceMappingURL=rpc-connection-_eHtWsk2.js.map