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