@hydranium/protocol 1.0.0-next.12 → 1.0.0-next.123

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +35 -1
  2. package/lib/client/data-connection.d.ts +114 -0
  3. package/lib/client/data-connection.d.ts.map +1 -0
  4. package/lib/client/data-connection.js +143 -0
  5. package/lib/client/data-connection.js.map +1 -0
  6. package/lib/client/data-events.d.ts +9 -1
  7. package/lib/client/data-events.d.ts.map +1 -1
  8. package/lib/client/data-events.js +14 -0
  9. package/lib/client/data-events.js.map +1 -1
  10. package/lib/client/data-port.d.ts +17 -22
  11. package/lib/client/data-port.d.ts.map +1 -1
  12. package/lib/client/data-session.d.ts +235 -82
  13. package/lib/client/data-session.d.ts.map +1 -1
  14. package/lib/client/data-session.js +337 -108
  15. package/lib/client/data-session.js.map +1 -1
  16. package/lib/client/index.d.ts +10 -7
  17. package/lib/client/index.d.ts.map +1 -1
  18. package/lib/client/index.js +10 -7
  19. package/lib/client/index.js.map +1 -1
  20. package/lib/client/message-relay.d.ts +8 -2
  21. package/lib/client/message-relay.d.ts.map +1 -1
  22. package/lib/client/message-relay.js +10 -4
  23. package/lib/client/message-relay.js.map +1 -1
  24. package/lib/client/rpc-connection.d.ts +143 -0
  25. package/lib/client/rpc-connection.d.ts.map +1 -0
  26. package/lib/client/rpc-connection.js +171 -0
  27. package/lib/client/rpc-connection.js.map +1 -0
  28. package/lib/client-ids.d.ts +41 -0
  29. package/lib/client-ids.d.ts.map +1 -0
  30. package/lib/client-ids.js +44 -0
  31. package/lib/client-ids.js.map +1 -0
  32. package/lib/data/data-protocol-methods.d.ts +4 -4
  33. package/lib/data/data-protocol-methods.d.ts.map +1 -1
  34. package/lib/data/data-protocol-methods.js +10 -1
  35. package/lib/data/data-protocol-methods.js.map +1 -1
  36. package/lib/data/data-server-protocol.d.ts +100 -31
  37. package/lib/data/data-server-protocol.d.ts.map +1 -1
  38. package/lib/data/events.d.ts +70 -3
  39. package/lib/data/events.d.ts.map +1 -1
  40. package/lib/data/requests.d.ts +67 -11
  41. package/lib/data/requests.d.ts.map +1 -1
  42. package/lib/errors.d.ts +91 -12
  43. package/lib/errors.d.ts.map +1 -1
  44. package/lib/errors.js +127 -18
  45. package/lib/errors.js.map +1 -1
  46. package/lib/index.d.ts +2 -0
  47. package/lib/index.d.ts.map +1 -1
  48. package/lib/index.js +5 -0
  49. package/lib/index.js.map +1 -1
  50. package/lib/latency-collector.d.ts +8 -4
  51. package/lib/latency-collector.d.ts.map +1 -1
  52. package/lib/latency-collector.js.map +1 -1
  53. package/lib/messages/index.d.ts +29 -0
  54. package/lib/messages/index.d.ts.map +1 -0
  55. package/lib/messages/index.js +55 -0
  56. package/lib/messages/index.js.map +1 -0
  57. package/lib/messages/primitives.d.ts +188 -0
  58. package/lib/messages/primitives.d.ts.map +1 -0
  59. package/lib/messages/primitives.js +161 -0
  60. package/lib/messages/primitives.js.map +1 -0
  61. package/lib/model-server.d.ts +44 -13
  62. package/lib/model-server.d.ts.map +1 -1
  63. package/lib/model-server.js +4 -2
  64. package/lib/model-server.js.map +1 -1
  65. package/lib/model-service/based-on.d.ts +57 -0
  66. package/lib/model-service/based-on.d.ts.map +1 -0
  67. package/lib/model-service/based-on.js +37 -0
  68. package/lib/model-service/based-on.js.map +1 -0
  69. package/lib/model-service/index.d.ts +1 -1
  70. package/lib/model-service/index.d.ts.map +1 -1
  71. package/lib/model-service/index.js +4 -5
  72. package/lib/model-service/index.js.map +1 -1
  73. package/lib/patch-merge.d.ts +28 -27
  74. package/lib/patch-merge.d.ts.map +1 -1
  75. package/lib/patch-merge.js +66 -22
  76. package/lib/patch-merge.js.map +1 -1
  77. package/lib/profile-session.d.ts +8 -4
  78. package/lib/profile-session.d.ts.map +1 -1
  79. package/lib/profile-session.js.map +1 -1
  80. package/lib/rpc/bind-rpc-methods.d.ts +29 -3
  81. package/lib/rpc/bind-rpc-methods.d.ts.map +1 -1
  82. package/lib/rpc/bind-rpc-methods.js +22 -3
  83. package/lib/rpc/bind-rpc-methods.js.map +1 -1
  84. package/lib/rpc/create-rpc-proxy.d.ts +7 -0
  85. package/lib/rpc/create-rpc-proxy.d.ts.map +1 -1
  86. package/lib/rpc/create-rpc-proxy.js +6 -1
  87. package/lib/rpc/create-rpc-proxy.js.map +1 -1
  88. package/lib/testing/catalogue-audit.d.ts +80 -0
  89. package/lib/testing/catalogue-audit.d.ts.map +1 -0
  90. package/lib/testing/catalogue-audit.js +94 -0
  91. package/lib/testing/catalogue-audit.js.map +1 -0
  92. package/lib/testing/data-doubles.d.ts +11 -12
  93. package/lib/testing/data-doubles.d.ts.map +1 -1
  94. package/lib/testing/data-doubles.js +14 -5
  95. package/lib/testing/data-doubles.js.map +1 -1
  96. package/lib/testing/index.d.ts +1 -0
  97. package/lib/testing/index.d.ts.map +1 -1
  98. package/lib/testing/index.js +4 -1
  99. package/lib/testing/index.js.map +1 -1
  100. package/lib/transfer-diagnostic.d.ts +33 -0
  101. package/lib/transfer-diagnostic.d.ts.map +1 -1
  102. package/lib/transfer-diagnostic.js +23 -0
  103. package/lib/transfer-diagnostic.js.map +1 -1
  104. package/lib/transfer-document.d.ts +14 -5
  105. package/lib/transfer-document.d.ts.map +1 -1
  106. package/lib/transfer-document.js +14 -1
  107. package/lib/transfer-document.js.map +1 -1
  108. package/package.json +11 -2
  109. package/src/client/data-connection.ts +216 -0
  110. package/src/client/data-events.ts +24 -1
  111. package/src/client/data-port.ts +17 -23
  112. package/src/client/data-session.ts +447 -128
  113. package/src/client/index.ts +10 -7
  114. package/src/client/message-relay.ts +28 -6
  115. package/src/client/rpc-connection.ts +235 -0
  116. package/src/client-ids.ts +45 -0
  117. package/src/data/data-protocol-methods.ts +10 -3
  118. package/src/data/data-server-protocol.ts +119 -31
  119. package/src/data/events.ts +74 -3
  120. package/src/data/requests.ts +71 -11
  121. package/src/errors.ts +139 -20
  122. package/src/index.ts +5 -0
  123. package/src/latency-collector.ts +8 -3
  124. package/src/messages/index.ts +36 -0
  125. package/src/messages/primitives.ts +271 -0
  126. package/src/model-server.ts +47 -18
  127. package/src/model-service/based-on.ts +63 -0
  128. package/src/model-service/index.ts +4 -5
  129. package/src/patch-merge.ts +90 -37
  130. package/src/profile-session.ts +9 -4
  131. package/src/rpc/bind-rpc-methods.ts +49 -4
  132. package/src/rpc/create-rpc-proxy.ts +14 -1
  133. package/src/testing/catalogue-audit.ts +111 -0
  134. package/src/testing/data-doubles.ts +33 -17
  135. package/src/testing/index.ts +4 -1
  136. package/src/transfer-diagnostic.ts +40 -0
  137. package/src/transfer-document.ts +21 -6
  138. package/lib/model-service/args.d.ts +0 -64
  139. package/lib/model-service/args.d.ts.map +0 -1
  140. package/lib/model-service/args.js +0 -11
  141. package/lib/model-service/args.js.map +0 -1
  142. package/src/model-service/args.ts +0 -67
@@ -32,7 +32,8 @@
32
32
  import { type MessageConnection } from 'vscode-jsonrpc';
33
33
  import type { DataPort } from '../client/data-port';
34
34
  import type { DataClientProtocol } from '../data/data-server-protocol';
35
- import type { ProjectsChangedEvent, TransferDocumentSavedEvent, TransferDocumentUpdatedEvent } from '../data/events';
35
+ import type { ProjectsChangedEvent, TransferDocumentDeletedEvent, TransferDocumentSavedEvent, TransferDocumentsBuiltEvent, TransferDocumentUpdatedEvent } from '../data/events';
36
+ import type { ResolvedMessage } from '../messages/primitives';
36
37
  import type { Project } from '../project';
37
38
  import type { TransferDiagnostic } from '../transfer-diagnostic';
38
39
  import type { TransferElement } from '../transfer-element';
@@ -48,13 +49,6 @@ export interface FakeDataPortOptions {
48
49
  * which the consumer surfaces through {@link FakeDataPort.reported}.
49
50
  */
50
51
  connect(): MessageConnection | Promise<MessageConnection>;
51
- /**
52
- * Stable client identity. Defaults to `'fake-data-port'`, which avoids the
53
- * three sentinels the framework reserves (`'language-client'`, `'unknown'`,
54
- * `'revert-on-close'`); override it when a test needs two distinguishable
55
- * clients on one server.
56
- */
57
- clientId?: string;
58
52
  }
59
53
  /** A {@link DataPort} that records what passed through it. */
60
54
  export interface FakeDataPort extends DataPort {
@@ -69,12 +63,13 @@ export interface FakeDataPort extends DataPort {
69
63
  /**
70
64
  * Every {@link DataPort.reportError} call, in order. Read from outside: this
71
65
  * is the only place a transport failure surfaces, so a test for the failure
72
- * path asserts on the `context` string here rather than on a rejection that
73
- * the consumer may legitimately swallow.
66
+ * path asserts here rather than on a rejection the consumer may legitimately
67
+ * swallow. Prefer asserting on `message.code`, which is stable, over
68
+ * `message.text`, which is the English default and may be reworded.
74
69
  */
75
70
  readonly reported: readonly {
76
71
  readonly error: unknown;
77
- readonly context: string;
72
+ readonly message: ResolvedMessage;
78
73
  }[];
79
74
  /**
80
75
  * Fire {@link DataPort.onDispose} — the host tearing the transport down, a
@@ -101,13 +96,17 @@ export interface CapturingDataClient<TTransfer extends TransferElement, TDiagnos
101
96
  readonly updates: TransferDocumentUpdatedEvent<TTransfer, TDiagnostic>[];
102
97
  /** Every `onDocumentSaved` event, in arrival order. */
103
98
  readonly saves: TransferDocumentSavedEvent<TTransfer, TDiagnostic>[];
99
+ /** Every `onDocumentDeleted` event, in arrival order. */
100
+ readonly deletions: TransferDocumentDeletedEvent[];
101
+ /** Every `onDocumentsBuilt` event, in arrival order. */
102
+ readonly builds: TransferDocumentsBuiltEvent[];
104
103
  /** Every `onProjectsChanged` event, in arrival order. */
105
104
  readonly projectsChanges: ProjectsChangedEvent<TProject>[];
106
105
  }
107
106
  /**
108
107
  * A {@link DataClientProtocol} that records every notification it receives.
109
108
  *
110
- * Recording ALL THREE channels even when a suite reads one is deliberate: an
109
+ * Recording EVERY channel even when a suite reads one is deliberate: an
111
110
  * event delivered on the wrong channel is a real defect of the data head, and a
112
111
  * double that drops the other two turns it into silence on the one being
113
112
  * watched.
@@ -1 +1 @@
1
- {"version":3,"file":"data-doubles.d.ts","sourceRoot":"","sources":["../../src/testing/data-doubles.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAW,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AACrH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,0CAA0C;AAC1C,MAAM,WAAW,mBAAmB;IACjC;;;;;;;;OAQG;IACH,OAAO,IAAI,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC1D;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACnD;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpF;;;;OAIG;IACH,WAAW,IAAI,IAAI,CAAC;IACpB,4FAA4F;IAC5F,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAwB3E;AAED,oEAAoE;AACpE,MAAM,WAAW,mBAAmB,CACjC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,QAAQ,SAAS,OAAO,GAAG,OAAO;IAElC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACtE,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,4BAA4B,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;IACzE,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;IACrE,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;CAC7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACpC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,QAAQ,SAAS,OAAO,GAAG,OAAO,EACnC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAM,GAAG,mBAAmB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAsBtI"}
1
+ {"version":3,"file":"data-doubles.d.ts","sourceRoot":"","sources":["../../src/testing/data-doubles.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAW,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EACT,oBAAoB,EACpB,4BAA4B,EAC5B,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC9B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,0CAA0C;AAC1C,MAAM,WAAW,mBAAmB;IACjC;;;;;;;;OAQG;IACH,OAAO,IAAI,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC5D;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACnD;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;KAAE,EAAE,CAAC;IAC7F;;;;OAIG;IACH,WAAW,IAAI,IAAI,CAAC;IACpB,4FAA4F;IAC5F,OAAO,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAuB3E;AAED,oEAAoE;AACpE,MAAM,WAAW,mBAAmB,CACjC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,QAAQ,SAAS,OAAO,GAAG,OAAO;IAElC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACtE,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,4BAA4B,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;IACzE,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;IACrE,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,4BAA4B,EAAE,CAAC;IACnD,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC;IAC/C,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;CAC7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACpC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,QAAQ,SAAS,OAAO,GAAG,OAAO,EACnC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAM,GAAG,mBAAmB,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAkCtI"}
@@ -46,7 +46,6 @@ function makeFakeDataPort(options) {
46
46
  const reported = [];
47
47
  const disposeEmitter = new vscode_jsonrpc_1.Emitter();
48
48
  return {
49
- clientId: options.clientId ?? 'fake-data-port',
50
49
  connections,
51
50
  reported,
52
51
  onDispose: disposeEmitter.event,
@@ -55,8 +54,8 @@ function makeFakeDataPort(options) {
55
54
  connections.push(connection);
56
55
  return connection;
57
56
  },
58
- reportError(error, context) {
59
- reported.push({ error, context });
57
+ reportError(error, message) {
58
+ reported.push({ error, message });
60
59
  },
61
60
  fireDispose() {
62
61
  disposeEmitter.fire(undefined);
@@ -69,7 +68,7 @@ function makeFakeDataPort(options) {
69
68
  /**
70
69
  * A {@link DataClientProtocol} that records every notification it receives.
71
70
  *
72
- * Recording ALL THREE channels even when a suite reads one is deliberate: an
71
+ * Recording EVERY channel even when a suite reads one is deliberate: an
73
72
  * event delivered on the wrong channel is a real defect of the data head, and a
74
73
  * double that drops the other two turns it into silence on the one being
75
74
  * watched.
@@ -82,6 +81,8 @@ function makeFakeDataPort(options) {
82
81
  function makeCapturingDataClient(overrides = {}) {
83
82
  const updates = [];
84
83
  const saves = [];
84
+ const deletions = [];
85
+ const builds = [];
85
86
  const projectsChanges = [];
86
87
  const client = {
87
88
  onDocumentUpdated: overrides.onDocumentUpdated ??
@@ -92,11 +93,19 @@ function makeCapturingDataClient(overrides = {}) {
92
93
  (event => {
93
94
  saves.push(event);
94
95
  }),
96
+ onDocumentDeleted: overrides.onDocumentDeleted ??
97
+ (event => {
98
+ deletions.push(event);
99
+ }),
100
+ onDocumentsBuilt: overrides.onDocumentsBuilt ??
101
+ (event => {
102
+ builds.push(event);
103
+ }),
95
104
  onProjectsChanged: overrides.onProjectsChanged ??
96
105
  (event => {
97
106
  projectsChanges.push(event);
98
107
  })
99
108
  };
100
- return { client, updates, saves, projectsChanges };
109
+ return { client, updates, saves, deletions, builds, projectsChanges };
101
110
  }
102
111
  //# sourceMappingURL=data-doubles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-doubles.js","sourceRoot":"","sources":["../../src/testing/data-doubles.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;AAyFlF,4CAwBC;AA+BD,0DA0BC;AAxKD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,mDAAiE;AAwDjE;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAAC,OAA4B;IAC1D,MAAM,WAAW,GAAwB,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAA0C,EAAE,CAAC;IAC3D,MAAM,cAAc,GAAG,IAAI,wBAAO,EAAQ,CAAC;IAC3C,OAAO;QACJ,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,gBAAgB;QAC9C,WAAW;QACX,QAAQ;QACR,SAAS,EAAE,cAAc,CAAC,KAAK;QAC/B,KAAK,CAAC,OAAO;YACV,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3C,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7B,OAAO,UAAU,CAAC;QACrB,CAAC;QACD,WAAW,CAAC,KAAc,EAAE,OAAe;YACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,WAAW;YACR,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QACD,OAAO;YACJ,cAAc,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC;KACH,CAAC;AACL,CAAC;AAkBD;;;;;;;;;;;;GAYG;AACH,SAAgB,uBAAuB,CAIrC,YAA2E,EAAE;IAC5E,MAAM,OAAO,GAA2D,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAyD,EAAE,CAAC;IACvE,MAAM,eAAe,GAAqC,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAyD;QAClE,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC,CAAC;QACL,eAAe,EACZ,SAAS,CAAC,eAAe;YACzB,CAAC,KAAK,CAAC,EAAE;gBACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC,CAAC;QACL,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC,CAAC;KACP,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;AACtD,CAAC"}
1
+ {"version":3,"file":"data-doubles.js","sourceRoot":"","sources":["../../src/testing/data-doubles.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;AA0FlF,4CAuBC;AAmCD,0DAsCC;AAxLD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,mDAAiE;AAyDjE;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAAC,OAA4B;IAC1D,MAAM,WAAW,GAAwB,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAmD,EAAE,CAAC;IACpE,MAAM,cAAc,GAAG,IAAI,wBAAO,EAAQ,CAAC;IAC3C,OAAO;QACJ,WAAW;QACX,QAAQ;QACR,SAAS,EAAE,cAAc,CAAC,KAAK;QAC/B,KAAK,CAAC,OAAO;YACV,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3C,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7B,OAAO,UAAU,CAAC;QACrB,CAAC;QACD,WAAW,CAAC,KAAc,EAAE,OAAwB;YACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,WAAW;YACR,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QACD,OAAO;YACJ,cAAc,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC;KACH,CAAC;AACL,CAAC;AAsBD;;;;;;;;;;;;GAYG;AACH,SAAgB,uBAAuB,CAIrC,YAA2E,EAAE;IAC5E,MAAM,OAAO,GAA2D,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAyD,EAAE,CAAC;IACvE,MAAM,SAAS,GAAmC,EAAE,CAAC;IACrD,MAAM,MAAM,GAAkC,EAAE,CAAC;IACjD,MAAM,eAAe,GAAqC,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAyD;QAClE,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC,CAAC;QACL,eAAe,EACZ,SAAS,CAAC,eAAe;YACzB,CAAC,KAAK,CAAC,EAAE;gBACN,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC,CAAC;QACL,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC,CAAC;QACL,gBAAgB,EACb,SAAS,CAAC,gBAAgB;YAC1B,CAAC,KAAK,CAAC,EAAE;gBACN,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC,CAAC;QACL,iBAAiB,EACd,SAAS,CAAC,iBAAiB;YAC3B,CAAC,KAAK,CAAC,EAAE;gBACN,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC,CAAC;KACP,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;AACzE,CAAC"}
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
+ export * from './catalogue-audit';
9
10
  export * from './data-doubles';
10
11
  export * from './fake-clock';
11
12
  export * from './harness';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAelF,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAiBlF,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
@@ -25,7 +25,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
25
25
  // Subpath barrel for `@hydranium/protocol/testing` — the BROWSER-NEUTRAL shared
26
26
  // primitives: `makeFakeClock` (deterministic `Clock` double on one virtual time
27
27
  // axis), `waitFor` / `tick`, the client-side data-head doubles
28
- // (`makeFakeDataPort` / `makeCapturingDataClient`), and the `Harness` marker
28
+ // (`makeFakeDataPort` / `makeCapturingDataClient`), the translation-catalogue
29
+ // audit (`flattenCatalogue` / `findUndeclaredCodes` / `findSharedCodes`), and
30
+ // the `Harness` marker
29
31
  // interface every framework harness extends. Kept out of the main barrel so production bundles don't pull
30
32
  // the test scaffolding in by default; adopters opt in by importing from
31
33
  // `@hydranium/protocol/testing`.
@@ -34,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
34
36
  // duplex transports are NOT here: a `PassThrough` pair is in their exported
35
37
  // type, so they cannot be made portable and live at `./testing/node` instead.
36
38
  // The same rule the package surface uses — the portable name is the short one.
39
+ __exportStar(require("./catalogue-audit"), exports);
37
40
  __exportStar(require("./data-doubles"), exports);
38
41
  __exportStar(require("./fake-clock"), exports);
39
42
  __exportStar(require("./harness"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,gFAAgF;AAChF,gFAAgF;AAChF,+DAA+D;AAC/D,6EAA6E;AAC7E,0GAA0G;AAC1G,wEAAwE;AACxE,iCAAiC;AACjC,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAE/E,iDAA+B;AAC/B,+CAA6B;AAC7B,4CAA0B;AAC1B,6CAA2B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,gFAAgF;AAChF,gFAAgF;AAChF,+DAA+D;AAC/D,8EAA8E;AAC9E,8EAA8E;AAC9E,uBAAuB;AACvB,0GAA0G;AAC1G,wEAAwE;AACxE,iCAAiC;AACjC,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAE/E,oDAAkC;AAClC,iDAA+B;AAC/B,+CAA6B;AAC7B,4CAA0B;AAC1B,6CAA2B"}
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
+ import { type MessageParams, type ResolvedMessage } from './messages/primitives';
9
10
  /**
10
11
  * Generic, transport-friendly diagnostic shape used by the model-server protocol.
11
12
  *
@@ -55,6 +56,21 @@ export interface TransferDiagnostic {
55
56
  * is not usable as a rule identity on its own.
56
57
  */
57
58
  code?: number | string;
59
+ /**
60
+ * Substitutions for the placeholders in the message this {@link code} names,
61
+ * present only for a diagnostic raised from a framework message declaration.
62
+ *
63
+ * Without them a translated template renders with its `{name}` tokens left
64
+ * standing, because substitution leaves an unmatched token in place rather
65
+ * than raising — so a surface that translates from {@link code} alone is
66
+ * correct for a parameterless sentence and visibly wrong for a parameterised
67
+ * one. This is the field that makes the second case work; the LSP carrier has
68
+ * always moved the params, and no carrier below it did.
69
+ *
70
+ * Prefer {@link TransferDiagnostic.resolved} over reading this: it decides
71
+ * whether an identity is present at all, which a lone `params` cannot.
72
+ */
73
+ params?: MessageParams;
58
74
  }
59
75
  export declare namespace TransferDiagnostic {
60
76
  /** Path separator between AST nodes within an element location. */
@@ -65,6 +81,23 @@ export declare namespace TransferDiagnostic {
65
81
  const ELEMENT_PROPERTY_SEPARATOR = "^";
66
82
  function isError(diagnostic: TransferDiagnostic): boolean;
67
83
  function isParseError(diagnostic: TransferDiagnostic): boolean;
84
+ /**
85
+ * The diagnostic as a renderable message, for a surface that translates.
86
+ * `undefined` when it carries no framework identity — a syntactic error, an
87
+ * adopter's own check, a linker failure — which is the case a caller must
88
+ * distinguish rather than render.
89
+ *
90
+ * Hand the result to `renderFrameworkMessage` with whatever catalogue the
91
+ * host has loaded. The `text` is the server's English, so a code the
92
+ * catalogue does not carry still yields a complete sentence.
93
+ *
94
+ * `code` alone does not establish an identity: it also holds Langium's
95
+ * internal code and an adopter's own, and either would be looked up against a
96
+ * catalogue that cannot have it. Requiring `params` is what discriminates,
97
+ * and it is why a parameterless framework message still populates the field
98
+ * with an empty object rather than omitting it.
99
+ */
100
+ function resolved(diagnostic: TransferDiagnostic): ResolvedMessage | undefined;
68
101
  function getPath(diagnostic: TransferDiagnostic): string;
69
102
  function errors(diagnostics: TransferDiagnostic[]): TransferDiagnostic[];
70
103
  function hasErrors(diagnostics: TransferDiagnostic[]): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-diagnostic.d.ts","sourceRoot":"","sources":["../src/transfer-diagnostic.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAChC;;;;;OAKG;IACH,IAAI,EAAE,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;IAC5D;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,yBAAiB,kBAAkB,CAAC;IACjC,mEAAmE;IAC5D,MAAM,yBAAyB,MAAM,CAAC;IAC7C,wDAAwD;IACjD,MAAM,uBAAuB,MAAM,CAAC;IAC3C,sFAAsF;IAC/E,MAAM,0BAA0B,MAAM,CAAC;IAE9C,SAAgB,OAAO,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAE/D;IAED,SAAgB,YAAY,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAEpE;IAED,SAAgB,OAAO,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAE9D;IAED,SAAgB,MAAM,CAAC,WAAW,EAAE,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAE9E;IAED,SAAgB,SAAS,CAAC,WAAW,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAEpE;IAED,SAAgB,cAAc,CAAC,WAAW,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAEzE;CACH"}
1
+ {"version":3,"file":"transfer-diagnostic.d.ts","sourceRoot":"","sources":["../src/transfer-diagnostic.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEjF;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAChC;;;;;OAKG;IACH,IAAI,EAAE,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;IAC5D;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,yBAAiB,kBAAkB,CAAC;IACjC,mEAAmE;IAC5D,MAAM,yBAAyB,MAAM,CAAC;IAC7C,wDAAwD;IACjD,MAAM,uBAAuB,MAAM,CAAC;IAC3C,sFAAsF;IAC/E,MAAM,0BAA0B,MAAM,CAAC;IAE9C,SAAgB,OAAO,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAE/D;IAED,SAAgB,YAAY,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAEpE;IAED;;;;;;;;;;;;;;;OAeG;IACH,SAAgB,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,eAAe,GAAG,SAAS,CAKpF;IAED,SAAgB,OAAO,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAE9D;IAED,SAAgB,MAAM,CAAC,WAAW,EAAE,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAE9E;IAED,SAAgB,SAAS,CAAC,WAAW,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAEpE;IAED,SAAgB,cAAc,CAAC,WAAW,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAEzE;CACH"}
@@ -25,6 +25,29 @@ var TransferDiagnostic;
25
25
  return diagnostic.type === 'parsing-error';
26
26
  }
27
27
  TransferDiagnostic.isParseError = isParseError;
28
+ /**
29
+ * The diagnostic as a renderable message, for a surface that translates.
30
+ * `undefined` when it carries no framework identity — a syntactic error, an
31
+ * adopter's own check, a linker failure — which is the case a caller must
32
+ * distinguish rather than render.
33
+ *
34
+ * Hand the result to `renderFrameworkMessage` with whatever catalogue the
35
+ * host has loaded. The `text` is the server's English, so a code the
36
+ * catalogue does not carry still yields a complete sentence.
37
+ *
38
+ * `code` alone does not establish an identity: it also holds Langium's
39
+ * internal code and an adopter's own, and either would be looked up against a
40
+ * catalogue that cannot have it. Requiring `params` is what discriminates,
41
+ * and it is why a parameterless framework message still populates the field
42
+ * with an empty object rather than omitting it.
43
+ */
44
+ function resolved(diagnostic) {
45
+ if (typeof diagnostic.code !== 'string' || diagnostic.params === undefined) {
46
+ return undefined;
47
+ }
48
+ return { code: diagnostic.code, params: diagnostic.params, text: diagnostic.message };
49
+ }
50
+ TransferDiagnostic.resolved = resolved;
28
51
  function getPath(diagnostic) {
29
52
  return diagnostic.property ? `${diagnostic.element}${TransferDiagnostic.ELEMENT_PROPERTY_SEPARATOR}${diagnostic.property}` : diagnostic.element;
30
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-diagnostic.js","sourceRoot":"","sources":["../src/transfer-diagnostic.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAqDlF,IAAiB,kBAAkB,CA+BlC;AA/BD,WAAiB,kBAAkB;IAChC,mEAAmE;IACtD,4CAAyB,GAAG,GAAG,CAAC;IAC7C,wDAAwD;IAC3C,0CAAuB,GAAG,GAAG,CAAC;IAC3C,sFAAsF;IACzE,6CAA0B,GAAG,GAAG,CAAC;IAE9C,SAAgB,OAAO,CAAC,UAA8B;QACnD,OAAO,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC1C,CAAC;IAFe,0BAAO,UAEtB,CAAA;IAED,SAAgB,YAAY,CAAC,UAA8B;QACxD,OAAO,UAAU,CAAC,IAAI,KAAK,eAAe,CAAC;IAC9C,CAAC;IAFe,+BAAY,eAE3B,CAAA;IAED,SAAgB,OAAO,CAAC,UAA8B;QACnD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,OAAO,GAAG,mBAAA,0BAA0B,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;IAChI,CAAC;IAFe,0BAAO,UAEtB,CAAA;IAED,SAAgB,MAAM,CAAC,WAAiC;QACrD,OAAO,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAFe,yBAAM,SAErB,CAAA;IAED,SAAgB,SAAS,CAAC,WAAiC;QACxD,OAAO,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAFe,4BAAS,YAExB,CAAA;IAED,SAAgB,cAAc,CAAC,WAAiC;QAC7D,OAAO,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC;IAFe,iCAAc,iBAE7B,CAAA;AACJ,CAAC,EA/BgB,kBAAkB,kCAAlB,kBAAkB,QA+BlC"}
1
+ {"version":3,"file":"transfer-diagnostic.js","sourceRoot":"","sources":["../src/transfer-diagnostic.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAsElF,IAAiB,kBAAkB,CAsDlC;AAtDD,WAAiB,kBAAkB;IAChC,mEAAmE;IACtD,4CAAyB,GAAG,GAAG,CAAC;IAC7C,wDAAwD;IAC3C,0CAAuB,GAAG,GAAG,CAAC;IAC3C,sFAAsF;IACzE,6CAA0B,GAAG,GAAG,CAAC;IAE9C,SAAgB,OAAO,CAAC,UAA8B;QACnD,OAAO,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC1C,CAAC;IAFe,0BAAO,UAEtB,CAAA;IAED,SAAgB,YAAY,CAAC,UAA8B;QACxD,OAAO,UAAU,CAAC,IAAI,KAAK,eAAe,CAAC;IAC9C,CAAC;IAFe,+BAAY,eAE3B,CAAA;IAED;;;;;;;;;;;;;;;OAeG;IACH,SAAgB,QAAQ,CAAC,UAA8B;QACpD,IAAI,OAAO,UAAU,CAAC,IAAI,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1E,OAAO,SAAS,CAAC;QACpB,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC;IACzF,CAAC;IALe,2BAAQ,WAKvB,CAAA;IAED,SAAgB,OAAO,CAAC,UAA8B;QACnD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,OAAO,GAAG,mBAAA,0BAA0B,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;IAChI,CAAC;IAFe,0BAAO,UAEtB,CAAA;IAED,SAAgB,MAAM,CAAC,WAAiC;QACrD,OAAO,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAFe,yBAAM,SAErB,CAAA;IAED,SAAgB,SAAS,CAAC,WAAiC;QACxD,OAAO,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAFe,4BAAS,YAExB,CAAA;IAED,SAAgB,cAAc,CAAC,WAAiC;QAC7D,OAAO,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC;IAFe,iCAAc,iBAE7B,CAAA;AACJ,CAAC,EAtDgB,kBAAkB,kCAAlB,kBAAkB,QAsDlC"}
@@ -8,6 +8,7 @@
8
8
  ********************************************************************************/
9
9
  import type { TransferDiagnostic } from './transfer-diagnostic';
10
10
  import type { TransferElement } from './transfer-element';
11
+ import { type SnapshotVersion } from './model-service/based-on';
11
12
  /**
12
13
  * Wire envelope exchanged between the model-server's data-server head and
13
14
  * its clients. Carries a transfer-shaped root — never an AST root — plus
@@ -25,14 +26,13 @@ export interface TransferDocument<TTransfer extends TransferElement, TDiagnostic
25
26
  uri: string;
26
27
  /**
27
28
  * The document version this snapshot was taken at — sourced from the
28
- * server's text-document version counter. Callers that mutate the
29
- * document subsequently pass this value back as `TransferUpdateArgs.baseVersion`
30
- * (or `TransferSaveArgs.baseVersion`) so the server can detect stale-based
31
- * updates and reject them with `ConflictError`.
29
+ * server's text-document version counter. A caller that mutates the document
30
+ * subsequently sends this straight back as `TransferUpdateDocumentArgs.basedOn`, and
31
+ * the server rejects a stale-based update with `ConflictError`.
32
32
  *
33
33
  * See `@hydranium/protocol#errors` for the conflict-detection contract.
34
34
  */
35
- version: number;
35
+ version: SnapshotVersion;
36
36
  /**
37
37
  * Absent when the document does not exist — the server answers an unknown URI
38
38
  * with a shaped envelope rather than an error, so absence is an ordinary
@@ -62,6 +62,15 @@ export declare namespace TransferDocument {
62
62
  * with it.
63
63
  */
64
64
  function assertLoaded<TTransfer extends TransferElement, TDiagnostic = TransferDiagnostic>(document: TransferDocument<TTransfer, TDiagnostic>): LoadedTransferDocument<TTransfer, TDiagnostic>;
65
+ /**
66
+ * The envelope for a document the server does not have — `root` absent, and
67
+ * the version a read of a URI the store never saw reports.
68
+ *
69
+ * Exists so the absent branch is built the same way the present one is: both
70
+ * doors mark the version as coming from a read, and neither asks a caller to
71
+ * do it.
72
+ */
73
+ function absent<TTransfer extends TransferElement, TDiagnostic = TransferDiagnostic>(uri: string, diagnostics?: TDiagnostic[]): TransferDocument<TTransfer, TDiagnostic>;
65
74
  /**
66
75
  * Construct a {@link TransferDocument} envelope. `diagnostics` defaults
67
76
  * to `[]` so test fixtures, fake protocol implementations, and the
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-document.d.ts","sourceRoot":"","sources":["../src/transfer-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB;IAClG,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,IAAI,gBAAgB,CACvH,SAAS,EACT,WAAW,CACb,GAAG;IACD,IAAI,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,yBAAiB,gBAAgB,CAAC;IAC/B;;;OAGG;IACH,SAAgB,QAAQ,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACzF,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,GAClD,QAAQ,IAAI,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE5D;IAED;;;;;OAKG;IACH,SAAgB,YAAY,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EAC7F,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,GAClD,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,CAKhD;IAED;;;;;OAKG;IACH,SAAgB,MAAM,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACvF,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,WAAW,GAAE,WAAW,EAAO,GAC/B,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE1C;CACH"}
1
+ {"version":3,"file":"transfer-document.d.ts","sourceRoot":"","sources":["../src/transfer-document.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEnF;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB;IAClG,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,IAAI,gBAAgB,CACvH,SAAS,EACT,WAAW,CACb,GAAG;IACD,IAAI,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,yBAAiB,gBAAgB,CAAC;IAC/B;;;OAGG;IACH,SAAgB,QAAQ,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACzF,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,GAClD,QAAQ,IAAI,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE5D;IAED;;;;;OAKG;IACH,SAAgB,YAAY,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EAC7F,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,GAClD,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,CAKhD;IAED;;;;;;;OAOG;IACH,SAAgB,MAAM,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACvF,GAAG,EAAE,MAAM,EACX,WAAW,GAAE,WAAW,EAAO,GAC/B,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE1C;IAED;;;;;OAKG;IACH,SAAgB,MAAM,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,GAAG,kBAAkB,EACvF,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,WAAW,GAAE,WAAW,EAAO,GAC/B,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAE1C;CACH"}
@@ -9,6 +9,7 @@
9
9
  ********************************************************************************/
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.TransferDocument = void 0;
12
+ const based_on_1 = require("./model-service/based-on");
12
13
  var TransferDocument;
13
14
  (function (TransferDocument) {
14
15
  /**
@@ -32,6 +33,18 @@ var TransferDocument;
32
33
  return document;
33
34
  }
34
35
  TransferDocument.assertLoaded = assertLoaded;
36
+ /**
37
+ * The envelope for a document the server does not have — `root` absent, and
38
+ * the version a read of a URI the store never saw reports.
39
+ *
40
+ * Exists so the absent branch is built the same way the present one is: both
41
+ * doors mark the version as coming from a read, and neither asks a caller to
42
+ * do it.
43
+ */
44
+ function absent(uri, diagnostics = []) {
45
+ return { uri, version: (0, based_on_1.asSnapshotVersion)(0), root: undefined, diagnostics };
46
+ }
47
+ TransferDocument.absent = absent;
35
48
  /**
36
49
  * Construct a {@link TransferDocument} envelope. `diagnostics` defaults
37
50
  * to `[]` so test fixtures, fake protocol implementations, and the
@@ -39,7 +52,7 @@ var TransferDocument;
39
52
  * at every call site.
40
53
  */
41
54
  function create(uri, version, root, diagnostics = []) {
42
- return { uri, version, root, diagnostics };
55
+ return { uri, version: (0, based_on_1.asSnapshotVersion)(version), root, diagnostics };
43
56
  }
44
57
  TransferDocument.create = create;
45
58
  })(TransferDocument || (exports.TransferDocument = TransferDocument = {}));
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-document.js","sourceRoot":"","sources":["../src/transfer-document.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAmDlF,IAAiB,gBAAgB,CAwChC;AAxCD,WAAiB,gBAAgB;IAC9B;;;OAGG;IACH,SAAgB,QAAQ,CACrB,QAAkD;QAElD,OAAO,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC;IACtC,CAAC;IAJe,yBAAQ,WAIvB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,YAAY,CACzB,QAAkD;QAElD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,QAAQ,CAAC;IACnB,CAAC;IAPe,6BAAY,eAO3B,CAAA;IAED;;;;;OAKG;IACH,SAAgB,MAAM,CACnB,GAAW,EACX,OAAe,EACf,IAAe,EACf,cAA6B,EAAE;QAE/B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC9C,CAAC;IAPe,uBAAM,SAOrB,CAAA;AACJ,CAAC,EAxCgB,gBAAgB,gCAAhB,gBAAgB,QAwChC"}
1
+ {"version":3,"file":"transfer-document.js","sourceRoot":"","sources":["../src/transfer-document.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAIlF,uDAAmF;AA+CnF,IAAiB,gBAAgB,CAuDhC;AAvDD,WAAiB,gBAAgB;IAC9B;;;OAGG;IACH,SAAgB,QAAQ,CACrB,QAAkD;QAElD,OAAO,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC;IACtC,CAAC;IAJe,yBAAQ,WAIvB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,YAAY,CACzB,QAAkD;QAElD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,QAAQ,CAAC;IACnB,CAAC;IAPe,6BAAY,eAO3B,CAAA;IAED;;;;;;;OAOG;IACH,SAAgB,MAAM,CACnB,GAAW,EACX,cAA6B,EAAE;QAE/B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAA,4BAAiB,EAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAC/E,CAAC;IALe,uBAAM,SAKrB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,MAAM,CACnB,GAAW,EACX,OAAe,EACf,IAAe,EACf,cAA6B,EAAE;QAE/B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAA,4BAAiB,EAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC1E,CAAC;IAPe,uBAAM,SAOrB,CAAA;AACJ,CAAC,EAvDgB,gBAAgB,gCAAhB,gBAAgB,QAuDhC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydranium/protocol",
3
- "version": "1.0.0-next.12",
3
+ "version": "1.0.0-next.123",
4
4
  "description": "Generic, language-agnostic types, constants, and pure utilities for the hydranium framework.",
5
5
  "keywords": [
6
6
  "hydranium",
@@ -41,6 +41,14 @@
41
41
  "types": "./lib/data/index.d.ts",
42
42
  "default": "./lib/data/index.js"
43
43
  },
44
+ "./messages": {
45
+ "types": "./lib/messages/index.d.ts",
46
+ "default": "./lib/messages/index.js"
47
+ },
48
+ "./lib/messages": {
49
+ "types": "./lib/messages/index.d.ts",
50
+ "default": "./lib/messages/index.js"
51
+ },
44
52
  "./testing": {
45
53
  "types": "./lib/testing/index.d.ts",
46
54
  "default": "./lib/testing/index.js"
@@ -88,7 +96,7 @@
88
96
  "vscode-jsonrpc": "9.0.1"
89
97
  },
90
98
  "peerDependencies": {
91
- "vscode-jsonrpc": "^8.0.0 || ^9.0.0"
99
+ "vscode-jsonrpc": "9.0.1"
92
100
  },
93
101
  "engines": {
94
102
  "node": ">=22.13"
@@ -96,5 +104,6 @@
96
104
  "publishConfig": {
97
105
  "access": "public"
98
106
  },
107
+ "//peerDependencies": "`vscode-jsonrpc` is EXACT rather than a range, because it is one link of an atomic chain with no independently movable link: `vscode-languageserver-protocol` depends on it at exactly 9.0.1, so any other value an adopter supplies is a SECOND physical copy rather than an upgrade. This wire stack breaks on copy identity rather than on structure — `ParameterStructures.auto` is a singleton compared by `===` in connection.js, so a request type built by one copy and sent over a connection owned by the other throws `Unknown parameter structure auto`. A caret or union range was rejected because npm then resolves a `vscode-jsonrpc@8.2.0` tree SILENTLY, with no diagnostic at all, and the failure surfaces only later at server init. Exact does not fail the install either — npm downgrades an unsatisfiable peer to a warning — but it is a NAMED ERESOLVE warning printing the required version beside the found one, and a hard error for anyone installing with `--strict-peer-deps`. It does NOT prevent a NESTED copy — `@eclipse-glsp/*` carries its own exact `vscode-jsonrpc@8.2.0` dependency and root `overrides` do not ship — so a consumer of the GLSP head must pin the chain in its own manifest, and docs/adopting/requirements.md carries the block to paste.",
99
108
  "//prepack": "The publish guard, and it deliberately is NOT a `prepare`: npm runs a workspace `prepare` BEFORE the root `postinstall` that applies patches/vscode-jsonrpc+9.0.1.patch, so building there fails on a cold clone and npm rolls the entire install back. `prepack` runs only when a tarball is made (`npm pack`, `npm publish`) and never on install, so it cannot break the install it has no business touching. It FAILS rather than rebuilds, because the rebuild is exactly the part that ordering defeats. What it defends against: `files` lists `lib`, `lib` is gitignored, and a `files` entry matching nothing is skipped SILENTLY — so `npm publish` from an unbuilt tree emits a tarball of `src` and nothing else, with no error."
100
109
  }
@@ -0,0 +1,216 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+
10
+ import { FRAMEWORK_CLIENT_IDS } from '../client-ids';
11
+ import {
12
+ DATA_CLIENT_PROTOCOL_METHODS,
13
+ DATA_SERVER_WIRE_PREFIX,
14
+ type DataClientProtocol,
15
+ type DataServerProtocol,
16
+ type DiagnosticOf,
17
+ type ProjectOf
18
+ } from '../data';
19
+ import type { TransferElement } from '../transfer-element';
20
+ import { DataEvents } from './data-events';
21
+ import type { DataPort } from './data-port';
22
+ import { DataSession, type DataSessionFactory } from './data-session';
23
+ import { RpcConnection, type RpcConnectionLifecycle } from './rpc-connection';
24
+
25
+ /** Options for {@link DataConnection}. */
26
+ export interface DataConnectionOptions<
27
+ TTransfer extends TransferElement = TransferElement,
28
+ TServer extends DataServerProtocol<TTransfer, DiagnosticOf<TServer>> = DataServerProtocol<TTransfer>
29
+ > extends RpcConnectionLifecycle {
30
+ /**
31
+ * Wire namespace the server is addressed under. Defaults to the
32
+ * framework's {@link DATA_SERVER_WIRE_PREFIX}, which is what an unmodified
33
+ * `DataServer` binds. Override only alongside the server's own
34
+ * `methodNamespace` option — a mismatch turns every request into
35
+ * "Unhandled method" rather than failing at wire-up.
36
+ */
37
+ readonly methodNamespace?: string;
38
+ /** Builds the sessions `createSession` hands out. Defaults to a plain {@link DataSession}. */
39
+ readonly sessionFactory?: DataSessionFactory<TTransfer, TServer>;
40
+ }
41
+
42
+ /** {@link DataConnectionOptions} for a client that does not speak {@link DataClientProtocol}. */
43
+ export interface DataConnectionOptionsWithMethods<
44
+ TClient extends object,
45
+ TTransfer extends TransferElement = TransferElement,
46
+ TServer extends DataServerProtocol<TTransfer, DiagnosticOf<TServer>> = DataServerProtocol<TTransfer>
47
+ > extends DataConnectionOptions<TTransfer, TServer> {
48
+ /**
49
+ * Method names of the client to bind as inbound handlers. Declare it
50
+ * `as const satisfies ReadonlyArray<keyof YourClient & string>` so the list
51
+ * cannot drift from the interface.
52
+ */
53
+ readonly clientMethods: readonly (keyof TClient & string)[];
54
+ }
55
+
56
+ /**
57
+ * Trailing constructor arguments, required only when the client cannot take
58
+ * the framework's default method list.
59
+ *
60
+ * `bindRpcMethods` throws for a name the target does not implement, so a
61
+ * request/response-only client binding the default list fails at wire-up. The
62
+ * conditional turns that into a compile error.
63
+ */
64
+ export type DataConnectionArgs<
65
+ TTransfer extends TransferElement,
66
+ TClient extends object,
67
+ TServer extends DataServerProtocol<TTransfer, DiagnosticOf<TServer>> = DataServerProtocol<TTransfer>
68
+ > =
69
+ TClient extends DataClientProtocol<TTransfer>
70
+ ? [options?: DataConnectionOptions<TTransfer, TServer> & Partial<DataConnectionOptionsWithMethods<TClient, TTransfer, TServer>>]
71
+ : [options: DataConnectionOptionsWithMethods<TClient, TTransfer, TServer>];
72
+
73
+ /**
74
+ * A {@link RpcConnection} to the data head, carrying as many participants as
75
+ * the host has interested parties.
76
+ *
77
+ * Document operations live on the participants rather than here: they carry a
78
+ * `clientId`, which identifies a participant rather than a wire, and the server
79
+ * keys its opens and watches per `(uri, clientId)`. Two parties sharing one
80
+ * identity cannot tell each other's writes from their own echoes.
81
+ *
82
+ * Generic over the transfer root so this file names no grammar. An adopter
83
+ * binds the concrete root (or the union of them, for a multi-grammar head) at
84
+ * its own edge.
85
+ */
86
+ export class DataConnection<
87
+ TTransfer extends TransferElement,
88
+ TServer extends DataServerProtocol<TTransfer, DiagnosticOf<TServer>> = DataServerProtocol<TTransfer>,
89
+ TClient extends object = DataClientProtocol<TTransfer>
90
+ > extends RpcConnection<TServer, TClient> {
91
+ protected readonly sessions = new Set<DataSession<TTransfer, TServer>>();
92
+ protected readonly sessionFactory: DataSessionFactory<TTransfer, TServer>;
93
+
94
+ constructor(port: DataPort, client: TClient, ...rest: DataConnectionArgs<TTransfer, TClient, TServer>) {
95
+ const [options = {}] = rest as [
96
+ (DataConnectionOptions<TTransfer, TServer> & Partial<DataConnectionOptionsWithMethods<TClient, TTransfer, TServer>>)?
97
+ ];
98
+ super(port, client, {
99
+ methodNamespace: options.methodNamespace ?? DATA_SERVER_WIRE_PREFIX,
100
+ // The default is reachable only where `TClient` satisfies
101
+ // `DataClientProtocol`, which the constructor's conditional enforces;
102
+ // the compiler cannot carry that through to the generic parameter.
103
+ clientMethods: options.clientMethods ?? (DATA_CLIENT_PROTOCOL_METHODS as unknown as readonly (keyof TClient & string)[]),
104
+ lifecycle: options
105
+ });
106
+ this.sessionFactory =
107
+ options.sessionFactory ?? ((clientId, host, label) => new DataSession<TTransfer, TServer>(clientId, host, label));
108
+ }
109
+
110
+ /**
111
+ * Start a participant on this connection, registered with the server under a
112
+ * fresh id, `label` plus `#` plus a random UUID, or under `clientId` when
113
+ * given. Synchronous: the registration is sent at once, and the session's
114
+ * calls wait for it. The server refuses an id live anywhere in its process,
115
+ * and every call of that session then rejects with a
116
+ * `DuplicateClientIdError` code.
117
+ *
118
+ * Throws for an id in {@link FRAMEWORK_CLIENT_IDS} — those are authors the
119
+ * SERVER emits rather than participants, so a session holding one would read
120
+ * the framework's own broadcasts as its own echoes and drop them — and for
121
+ * an id a live session on this connection already holds.
122
+ */
123
+ createSession(label = 'session', clientId?: string): DataSession<TTransfer, TServer> {
124
+ this.assertLive();
125
+ const id = clientId ?? `${label}#${globalThis.crypto.randomUUID()}`;
126
+ if (FRAMEWORK_CLIENT_IDS.includes(id)) {
127
+ throw new Error(`clientId '${id}' is reserved by the framework and cannot identify a participant`);
128
+ }
129
+ if ([...this.sessions].some(session => session.clientId === id)) {
130
+ throw new Error(`clientId '${id}' already identifies a live participant on this connection`);
131
+ }
132
+ const session = this.sessionFactory(
133
+ id,
134
+ {
135
+ connected: () => this.connected(),
136
+ releaseSession: released => this.sessions.delete(released),
137
+ reportError: (error, reported) => this.reportError(error, reported)
138
+ },
139
+ label
140
+ );
141
+ this.sessions.add(session);
142
+ // A failure reaches the session's own calls, which wait for the same
143
+ // registration; caught here only so it is not also reported unhandled.
144
+ session.connected().catch(() => undefined);
145
+ return session;
146
+ }
147
+
148
+ /**
149
+ * After the transport dropped, reconnect on the next macrotask for the
150
+ * sessions with documents open, so they re-watch and follow their documents
151
+ * again without waiting for a call of their own; a session with nothing
152
+ * open restores on its next call. Nothing is scheduled once this connection
153
+ * is disposed, which drops its generation too.
154
+ */
155
+ protected override dropGeneration(): void {
156
+ const dropped = this.generation !== undefined;
157
+ super.dropGeneration();
158
+ if (dropped && !this.disposed) {
159
+ setTimeout(() => {
160
+ if (!this.disposed) {
161
+ this.sessions.forEach(session => session.reconnect());
162
+ }
163
+ }, 0);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Sessions are detached rather than disposed: the server ends every session
169
+ * on a connection it sees close, so ending each one first sends requests
170
+ * over a connection this call is about to dispose.
171
+ */
172
+ override dispose(): void {
173
+ for (const session of [...this.sessions]) {
174
+ session.detach();
175
+ }
176
+ this.sessions.clear();
177
+ super.dispose();
178
+ }
179
+ }
180
+
181
+ /**
182
+ * A {@link DataConnection} that brings its own {@link DataEvents}, so a host
183
+ * with several interested parties does not have to supply one.
184
+ *
185
+ * **The client slot holds exactly one object, and that is why this exists.**
186
+ * `createRpcProxy` binds a single `localTarget`, and underneath a method name
187
+ * maps to one handler — a second registration replaces the first silently. So a
188
+ * properties panel and a tree cannot both be the client; one fan-out sits in the
189
+ * slot and both subscribe to it.
190
+ *
191
+ * Use {@link DataConnection} directly instead when the client is yours: an
192
+ * adopter service that implements the protocol plus its own methods, a single
193
+ * consumer that IS the client, or a request/response-only client that binds
194
+ * nothing.
195
+ */
196
+ export class DataConnectionWithEvents<
197
+ TTransfer extends TransferElement,
198
+ TServer extends DataServerProtocol<TTransfer, DiagnosticOf<TServer>> = DataServerProtocol<TTransfer>
199
+ > extends DataConnection<TTransfer, TServer, DataEvents<TTransfer, DiagnosticOf<TServer>, ProjectOf<TServer>>> {
200
+ /** Server pushes, fanned out to as many local listeners as the host has. */
201
+ readonly events: DataEvents<TTransfer, DiagnosticOf<TServer>, ProjectOf<TServer>>;
202
+
203
+ constructor(port: DataPort, options?: DataConnectionOptions<TTransfer, TServer>) {
204
+ // Built as a local because `this` is unavailable before `super`, then
205
+ // read back onto the field.
206
+ const events = new DataEvents<TTransfer, DiagnosticOf<TServer>, ProjectOf<TServer>>();
207
+ super(port, events, options);
208
+ this.events = events;
209
+ }
210
+
211
+ /** Disposes the fan-out it created, which no caller else holds. */
212
+ override dispose(): void {
213
+ super.dispose();
214
+ this.events.dispose();
215
+ }
216
+ }