@zlink-systems/zlink 0.17.3

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 (199) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +198 -0
  3. package/README.typedoc.md +56 -0
  4. package/THIRD_PARTY_NOTICES.md +84 -0
  5. package/binding.gyp +27 -0
  6. package/dist/index.d.mts +3 -0
  7. package/dist/index.d.ts +24 -0
  8. package/dist/index.js +117 -0
  9. package/dist/index.mjs +4 -0
  10. package/dist/zlink/contracts/core/buffer_like.d.ts +2 -0
  11. package/dist/zlink/contracts/core/buffer_like.js +3 -0
  12. package/dist/zlink/contracts/core/context.d.ts +103 -0
  13. package/dist/zlink/contracts/core/context.js +11 -0
  14. package/dist/zlink/contracts/core/index.d.ts +3 -0
  15. package/dist/zlink/contracts/core/index.js +20 -0
  16. package/dist/zlink/contracts/core/routing_id.d.ts +28 -0
  17. package/dist/zlink/contracts/core/routing_id.js +120 -0
  18. package/dist/zlink/contracts/errors/errors.d.ts +44 -0
  19. package/dist/zlink/contracts/errors/errors.js +89 -0
  20. package/dist/zlink/contracts/errors/index.d.ts +2 -0
  21. package/dist/zlink/contracts/errors/index.js +29 -0
  22. package/dist/zlink/contracts/errors/results.d.ts +106 -0
  23. package/dist/zlink/contracts/errors/results.js +102 -0
  24. package/dist/zlink/contracts/eventing/index.d.ts +3 -0
  25. package/dist/zlink/contracts/eventing/index.js +20 -0
  26. package/dist/zlink/contracts/eventing/monitor.d.ts +157 -0
  27. package/dist/zlink/contracts/eventing/monitor.js +82 -0
  28. package/dist/zlink/contracts/eventing/poller.d.ts +76 -0
  29. package/dist/zlink/contracts/eventing/poller.js +3 -0
  30. package/dist/zlink/contracts/eventing/timer.d.ts +38 -0
  31. package/dist/zlink/contracts/eventing/timer.js +3 -0
  32. package/dist/zlink/contracts/index.d.ts +5 -0
  33. package/dist/zlink/contracts/index.js +22 -0
  34. package/dist/zlink/contracts/messaging/handlers.d.ts +5 -0
  35. package/dist/zlink/contracts/messaging/handlers.js +3 -0
  36. package/dist/zlink/contracts/messaging/index.d.ts +8 -0
  37. package/dist/zlink/contracts/messaging/index.js +15 -0
  38. package/dist/zlink/contracts/messaging/message.d.ts +68 -0
  39. package/dist/zlink/contracts/messaging/message.js +280 -0
  40. package/dist/zlink/contracts/messaging/message_parts_envelope.d.ts +14 -0
  41. package/dist/zlink/contracts/messaging/message_parts_envelope.js +56 -0
  42. package/dist/zlink/contracts/messaging/operations.d.ts +54 -0
  43. package/dist/zlink/contracts/messaging/operations.js +3 -0
  44. package/dist/zlink/contracts/messaging/received.d.ts +41 -0
  45. package/dist/zlink/contracts/messaging/received.js +130 -0
  46. package/dist/zlink/contracts/messaging/stream_packet.d.ts +14 -0
  47. package/dist/zlink/contracts/messaging/stream_packet.js +33 -0
  48. package/dist/zlink/contracts/messaging/subscription_event.d.ts +12 -0
  49. package/dist/zlink/contracts/messaging/subscription_event.js +20 -0
  50. package/dist/zlink/contracts/messaging/topic_message.d.ts +14 -0
  51. package/dist/zlink/contracts/messaging/topic_message.js +36 -0
  52. package/dist/zlink/contracts/sockets/dealer_socket.d.ts +29 -0
  53. package/dist/zlink/contracts/sockets/dealer_socket.js +3 -0
  54. package/dist/zlink/contracts/sockets/index.d.ts +10 -0
  55. package/dist/zlink/contracts/sockets/index.js +15 -0
  56. package/dist/zlink/contracts/sockets/pair_socket.d.ts +20 -0
  57. package/dist/zlink/contracts/sockets/pair_socket.js +3 -0
  58. package/dist/zlink/contracts/sockets/pubsub_sockets.d.ts +40 -0
  59. package/dist/zlink/contracts/sockets/pubsub_sockets.js +3 -0
  60. package/dist/zlink/contracts/sockets/router_socket.d.ts +32 -0
  61. package/dist/zlink/contracts/sockets/router_socket.js +3 -0
  62. package/dist/zlink/contracts/sockets/socket.d.ts +58 -0
  63. package/dist/zlink/contracts/sockets/socket.js +3 -0
  64. package/dist/zlink/contracts/sockets/socket_constants.d.ts +88 -0
  65. package/dist/zlink/contracts/sockets/socket_constants.js +67 -0
  66. package/dist/zlink/contracts/sockets/socket_options.d.ts +105 -0
  67. package/dist/zlink/contracts/sockets/socket_options.js +3 -0
  68. package/dist/zlink/contracts/sockets/stream_socket.d.ts +31 -0
  69. package/dist/zlink/contracts/sockets/stream_socket.js +3 -0
  70. package/dist/zlink/runtime/buffers/message_conversion.d.ts +6 -0
  71. package/dist/zlink/runtime/buffers/message_conversion.js +49 -0
  72. package/dist/zlink/runtime/core/context.d.ts +43 -0
  73. package/dist/zlink/runtime/core/context.js +150 -0
  74. package/dist/zlink/runtime/core/context_options.d.ts +19 -0
  75. package/dist/zlink/runtime/core/context_options.js +23 -0
  76. package/dist/zlink/runtime/core/routing_id.d.ts +3 -0
  77. package/dist/zlink/runtime/core/routing_id.js +30 -0
  78. package/dist/zlink/runtime/core/routing_id_conversion.d.ts +2 -0
  79. package/dist/zlink/runtime/core/routing_id_conversion.js +11 -0
  80. package/dist/zlink/runtime/core/runtime_info.d.ts +8 -0
  81. package/dist/zlink/runtime/core/runtime_info.js +39 -0
  82. package/dist/zlink/runtime/errors/error_mapping.d.ts +4 -0
  83. package/dist/zlink/runtime/errors/error_mapping.js +132 -0
  84. package/dist/zlink/runtime/errors/error_state.d.ts +1 -0
  85. package/dist/zlink/runtime/errors/error_state.js +15 -0
  86. package/dist/zlink/runtime/errors/native_errors.d.ts +16 -0
  87. package/dist/zlink/runtime/errors/native_errors.js +86 -0
  88. package/dist/zlink/runtime/eventing/counters.d.ts +16 -0
  89. package/dist/zlink/runtime/eventing/counters.js +33 -0
  90. package/dist/zlink/runtime/eventing/index.d.ts +6 -0
  91. package/dist/zlink/runtime/eventing/index.js +22 -0
  92. package/dist/zlink/runtime/eventing/monitor_event_state.d.ts +3 -0
  93. package/dist/zlink/runtime/eventing/monitor_event_state.js +19 -0
  94. package/dist/zlink/runtime/eventing/monitor_raw.d.ts +50 -0
  95. package/dist/zlink/runtime/eventing/monitor_raw.js +3 -0
  96. package/dist/zlink/runtime/eventing/monitor_socket.d.ts +9 -0
  97. package/dist/zlink/runtime/eventing/monitor_socket.js +39 -0
  98. package/dist/zlink/runtime/eventing/monitor_status.d.ts +3 -0
  99. package/dist/zlink/runtime/eventing/monitor_status.js +52 -0
  100. package/dist/zlink/runtime/eventing/poll_events.d.ts +20 -0
  101. package/dist/zlink/runtime/eventing/poll_events.js +92 -0
  102. package/dist/zlink/runtime/eventing/poller.d.ts +34 -0
  103. package/dist/zlink/runtime/eventing/poller.js +275 -0
  104. package/dist/zlink/runtime/eventing/thread.d.ts +6 -0
  105. package/dist/zlink/runtime/eventing/thread.js +52 -0
  106. package/dist/zlink/runtime/eventing/timer.d.ts +8 -0
  107. package/dist/zlink/runtime/eventing/timer.js +45 -0
  108. package/dist/zlink/runtime/handles/native_handle.d.ts +7 -0
  109. package/dist/zlink/runtime/handles/native_handle.js +24 -0
  110. package/dist/zlink/runtime/messaging/completion_owner.d.ts +86 -0
  111. package/dist/zlink/runtime/messaging/completion_owner.js +570 -0
  112. package/dist/zlink/runtime/messaging/message_materializer.d.ts +36 -0
  113. package/dist/zlink/runtime/messaging/message_materializer.js +199 -0
  114. package/dist/zlink/runtime/messaging/message_parts_state.d.ts +4 -0
  115. package/dist/zlink/runtime/messaging/message_parts_state.js +20 -0
  116. package/dist/zlink/runtime/messaging/message_snapshot.d.ts +13 -0
  117. package/dist/zlink/runtime/messaging/message_snapshot.js +42 -0
  118. package/dist/zlink/runtime/messaging/received_operations.d.ts +5 -0
  119. package/dist/zlink/runtime/messaging/received_operations.js +46 -0
  120. package/dist/zlink/runtime/messaging/received_state.d.ts +13 -0
  121. package/dist/zlink/runtime/messaging/received_state.js +29 -0
  122. package/dist/zlink/runtime/messaging/request_executor.d.ts +2 -0
  123. package/dist/zlink/runtime/messaging/request_executor.js +8 -0
  124. package/dist/zlink/runtime/messaging/send_operation_base.d.ts +13 -0
  125. package/dist/zlink/runtime/messaging/send_operation_base.js +52 -0
  126. package/dist/zlink/runtime/messaging/subscription_event_state.d.ts +4 -0
  127. package/dist/zlink/runtime/messaging/subscription_event_state.js +17 -0
  128. package/dist/zlink/runtime/messaging/topic_message_state.d.ts +11 -0
  129. package/dist/zlink/runtime/messaging/topic_message_state.js +75 -0
  130. package/dist/zlink/runtime/native/binding.d.ts +6 -0
  131. package/dist/zlink/runtime/native/binding.js +3 -0
  132. package/dist/zlink/runtime/native/binding_context.d.ts +14 -0
  133. package/dist/zlink/runtime/native/binding_context.js +3 -0
  134. package/dist/zlink/runtime/native/binding_core.d.ts +21 -0
  135. package/dist/zlink/runtime/native/binding_core.js +3 -0
  136. package/dist/zlink/runtime/native/binding_eventing.d.ts +40 -0
  137. package/dist/zlink/runtime/native/binding_eventing.js +3 -0
  138. package/dist/zlink/runtime/native/binding_socket.d.ts +52 -0
  139. package/dist/zlink/runtime/native/binding_socket.js +3 -0
  140. package/dist/zlink/runtime/native/binding_types.d.ts +8 -0
  141. package/dist/zlink/runtime/native/binding_types.js +3 -0
  142. package/dist/zlink/runtime/native/native.d.ts +2 -0
  143. package/dist/zlink/runtime/native/native.js +40 -0
  144. package/dist/zlink/runtime/native/native_load_paths.d.ts +16 -0
  145. package/dist/zlink/runtime/native/native_load_paths.js +165 -0
  146. package/dist/zlink/runtime/options/byte_values.d.ts +3 -0
  147. package/dist/zlink/runtime/options/byte_values.js +27 -0
  148. package/dist/zlink/runtime/options/option_mapping.d.ts +72 -0
  149. package/dist/zlink/runtime/options/option_mapping.js +41 -0
  150. package/dist/zlink/runtime/options/validation.d.ts +1 -0
  151. package/dist/zlink/runtime/options/validation.js +17 -0
  152. package/dist/zlink/runtime/public_bridge.d.ts +6 -0
  153. package/dist/zlink/runtime/public_bridge.js +23 -0
  154. package/dist/zlink/runtime/sockets/dealer_socket.d.ts +16 -0
  155. package/dist/zlink/runtime/sockets/dealer_socket.js +56 -0
  156. package/dist/zlink/runtime/sockets/index.d.ts +19 -0
  157. package/dist/zlink/runtime/sockets/index.js +27 -0
  158. package/dist/zlink/runtime/sockets/pair_socket.d.ts +7 -0
  159. package/dist/zlink/runtime/sockets/pair_socket.js +12 -0
  160. package/dist/zlink/runtime/sockets/pub_socket.d.ts +7 -0
  161. package/dist/zlink/runtime/sockets/pub_socket.js +12 -0
  162. package/dist/zlink/runtime/sockets/router_socket.d.ts +19 -0
  163. package/dist/zlink/runtime/sockets/router_socket.js +70 -0
  164. package/dist/zlink/runtime/sockets/socket_base.d.ts +21 -0
  165. package/dist/zlink/runtime/sockets/socket_base.js +102 -0
  166. package/dist/zlink/runtime/sockets/socket_operation_builders.d.ts +38 -0
  167. package/dist/zlink/runtime/sockets/socket_operation_builders.js +93 -0
  168. package/dist/zlink/runtime/sockets/socket_operations.d.ts +40 -0
  169. package/dist/zlink/runtime/sockets/socket_operations.js +177 -0
  170. package/dist/zlink/runtime/sockets/socket_options.d.ts +104 -0
  171. package/dist/zlink/runtime/sockets/socket_options.js +259 -0
  172. package/dist/zlink/runtime/sockets/socket_submit_errors.d.ts +3 -0
  173. package/dist/zlink/runtime/sockets/socket_submit_errors.js +13 -0
  174. package/dist/zlink/runtime/sockets/stream_socket.d.ts +15 -0
  175. package/dist/zlink/runtime/sockets/stream_socket.js +93 -0
  176. package/dist/zlink/runtime/sockets/sub_socket.d.ts +7 -0
  177. package/dist/zlink/runtime/sockets/sub_socket.js +12 -0
  178. package/dist/zlink/runtime/sockets/xpub_socket.d.ts +10 -0
  179. package/dist/zlink/runtime/sockets/xpub_socket.js +39 -0
  180. package/dist/zlink/runtime/sockets/xsub_socket.d.ts +7 -0
  181. package/dist/zlink/runtime/sockets/xsub_socket.js +12 -0
  182. package/native/src/addon.cc +11 -0
  183. package/native/src/addon_common_api.h +57 -0
  184. package/native/src/addon_core.cc +3974 -0
  185. package/native/src/addon_core_api.h +110 -0
  186. package/native/src/addon_core_options.cc +119 -0
  187. package/native/src/addon_core_options.h +9 -0
  188. package/native/src/addon_exports.cc +151 -0
  189. package/native/src/addon_exports.h +7 -0
  190. package/native/src/addon_message_parts.h +67 -0
  191. package/native/src/addon_message_values.h +345 -0
  192. package/native/src/addon_monitor_status_values.h +71 -0
  193. package/native/src/addon_submit_results.h +30 -0
  194. package/package.json +74 -0
  195. package/prebuilds/linux-x64/libzlink.so.0.17.3 +0 -0
  196. package/prebuilds/linux-x64/zlink.node +0 -0
  197. package/provenance/core-package-provenance.json +73 -0
  198. package/scripts/install.js +37 -0
  199. package/scripts/resolve_core.js +86 -0
@@ -0,0 +1,570 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: MPL-2.0
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.CompletionOwner = exports.CompletionEntry = void 0;
5
+ exports.consumeSubmittedMessages = consumeSubmittedMessages;
6
+ exports.installCompletionOwner = installCompletionOwner;
7
+ exports.completionOwnerOf = completionOwnerOf;
8
+ exports.releaseCompletionOwner = releaseCompletionOwner;
9
+ const contracts_1 = require("../../contracts");
10
+ const errors_1 = require("../../contracts/errors/errors");
11
+ const message_1 = require("../../contracts/messaging/message");
12
+ const message_conversion_1 = require("../buffers/message_conversion");
13
+ const error_mapping_1 = require("../errors/error_mapping");
14
+ const error_state_1 = require("../errors/error_state");
15
+ const native_errors_1 = require("../errors/native_errors");
16
+ const native_1 = require("../native/native");
17
+ const request_executor_1 = require("./request_executor");
18
+ const COMPLETION_REQUEST = 2;
19
+ const COMPLETION_WRITABLE = 3;
20
+ const SEND_ADMITTED = 0;
21
+ const SEND_TERMINAL = 202;
22
+ const DONTWAIT = 1;
23
+ const RESOLVED_SEND = Promise.resolve();
24
+ function snapshotRetryPart(part) {
25
+ return part instanceof contracts_1.Message ? part.toBytes() : Buffer.from(part);
26
+ }
27
+ function snapshotRetryPayload(payload) {
28
+ if (!Array.isArray(payload))
29
+ return snapshotRetryPart(payload);
30
+ if (payload.length === 1)
31
+ return snapshotRetryPart(payload[0]);
32
+ return payload.map(snapshotRetryPart);
33
+ }
34
+ function submitError(result, nativeErrno, message) {
35
+ return (0, error_state_1.withRuntimeErrorMessage)(new errors_1.SubmitError(result, nativeErrno), message);
36
+ }
37
+ function requestError(result, message) {
38
+ return (0, error_state_1.withRuntimeErrorMessage)(new errors_1.RequestError(result), message);
39
+ }
40
+ function consumeSubmittedMessages(payload) {
41
+ if (payload instanceof contracts_1.Message) {
42
+ (0, message_1.consumeSubmittedMessage)(payload);
43
+ }
44
+ else if (Array.isArray(payload)) {
45
+ for (const part of payload) {
46
+ if (part instanceof contracts_1.Message)
47
+ (0, message_1.consumeSubmittedMessage)(part);
48
+ }
49
+ }
50
+ }
51
+ /** Two-phase correlation entry: publish and capture may arrive in either order. */
52
+ class CompletionEntry {
53
+ token;
54
+ kind;
55
+ expectsUserContext;
56
+ promise;
57
+ completionId = 0n;
58
+ published = false;
59
+ captured = false;
60
+ settled = false;
61
+ value;
62
+ error;
63
+ capturedCompletionId = 0n;
64
+ resolvePromise;
65
+ rejectPromise;
66
+ constructor(token, kind, expectsUserContext = true) {
67
+ this.token = token;
68
+ this.kind = kind;
69
+ this.expectsUserContext = expectsUserContext;
70
+ this.promise = new Promise((resolve, reject) => {
71
+ this.resolvePromise = resolve;
72
+ this.rejectPromise = reject;
73
+ });
74
+ }
75
+ publish(completionId) {
76
+ this.completionId = completionId;
77
+ this.published = true;
78
+ this.validateRequestCorrelation();
79
+ this.settleIfJoined();
80
+ }
81
+ awaitWritable(completionId) {
82
+ this.completionId = completionId;
83
+ this.published = true;
84
+ this.captured = false;
85
+ }
86
+ succeed(value) {
87
+ if (this.settled)
88
+ return;
89
+ this.published = true;
90
+ this.captured = true;
91
+ this.value = value;
92
+ this.settleIfJoined();
93
+ }
94
+ capture(completion) {
95
+ if (this.captured)
96
+ return;
97
+ this.capturedCompletionId = completion.completionId;
98
+ try {
99
+ if (this.kind !== 'request' || completion.kind !== COMPLETION_REQUEST) {
100
+ throw requestError(errors_1.RequestResult.InternalError, 'request completion kind mismatch');
101
+ }
102
+ const expectedContext = this.expectsUserContext ? this.token : 0n;
103
+ if (completion.userContext !== expectedContext) {
104
+ throw requestError(errors_1.RequestResult.InternalError, 'request completion context mismatch');
105
+ }
106
+ if (completion.requestResult !== errors_1.RequestResult.Ok) {
107
+ throw requestError(completion.requestResult, 'request failed');
108
+ }
109
+ this.value = (0, request_executor_1.messagesFromNativeBuffers)(completion.parts);
110
+ }
111
+ catch (error) {
112
+ this.error = error;
113
+ }
114
+ this.captured = true;
115
+ this.validateRequestCorrelation();
116
+ this.settleIfJoined();
117
+ }
118
+ fail(error) {
119
+ if (this.settled)
120
+ return;
121
+ this.published = true;
122
+ this.captured = true;
123
+ this.error = error;
124
+ this.settleIfJoined();
125
+ }
126
+ settleIfJoined() {
127
+ if (!this.published || !this.captured || this.settled)
128
+ return;
129
+ this.settled = true;
130
+ if (this.error !== undefined)
131
+ this.rejectPromise(this.error);
132
+ else
133
+ this.resolvePromise(this.value);
134
+ }
135
+ validateRequestCorrelation() {
136
+ if (this.kind !== 'request' || !this.published || !this.captured)
137
+ return;
138
+ if (this.capturedCompletionId !== this.completionId) {
139
+ this.error = requestError(errors_1.RequestResult.InternalError, 'request completion id mismatch');
140
+ }
141
+ }
142
+ }
143
+ exports.CompletionEntry = CompletionEntry;
144
+ const owners = new WeakMap();
145
+ class CompletionOwner {
146
+ handle;
147
+ native = (0, native_1.requireNative)();
148
+ byToken = new Map();
149
+ byId = new Map();
150
+ retries = new Map();
151
+ writableRetries = [];
152
+ nextToken = 1n;
153
+ publicOwner = null;
154
+ runtimeWatch = null;
155
+ managedWritableWaitCount = 0;
156
+ closed = false;
157
+ constructor(handle) {
158
+ this.handle = handle;
159
+ }
160
+ submitSend(payload, routingId) {
161
+ if (this.closed)
162
+ throw submitError(errors_1.SubmitResult.InvalidState, 0, 'socket is closed');
163
+ const token = this.nextToken++;
164
+ let nativePayload;
165
+ try {
166
+ nativePayload = (0, message_conversion_1.normalizeOperationPayload)(payload);
167
+ }
168
+ catch (error) {
169
+ return Promise.reject((0, native_errors_1.submitNativeError)(error, DONTWAIT, 'send submit failed'));
170
+ }
171
+ let result;
172
+ try {
173
+ result = this.native.socketSubmitSend(this.handle, nativePayload, routingId, DONTWAIT, token);
174
+ }
175
+ catch (error) {
176
+ return Promise.reject((0, native_errors_1.submitNativeError)(error, DONTWAIT, 'send submit failed'));
177
+ }
178
+ if (result.result === errors_1.SubmitResult.Ok) {
179
+ try {
180
+ consumeSubmittedMessages(payload);
181
+ }
182
+ catch (error) {
183
+ return Promise.reject(error);
184
+ }
185
+ if (result.completionId !== 0n) {
186
+ return Promise.reject(submitError(errors_1.SubmitResult.InternalError, result.nativeErrno, 'successful send returned a completion token'));
187
+ }
188
+ return RESOLVED_SEND;
189
+ }
190
+ if (result.result !== errors_1.SubmitResult.Backpressured) {
191
+ return Promise.reject(submitError(result.result, result.nativeErrno, 'send submit failed'));
192
+ }
193
+ if (!(0, native_errors_1.isWouldBlock)(result.nativeErrno) || result.completionId === 0n) {
194
+ return Promise.reject(submitError(errors_1.SubmitResult.Backpressured, result.nativeErrno, 'backpressured send did not return an EAGAIN wait token'));
195
+ }
196
+ let retryPayload;
197
+ try {
198
+ // Core retains no SEND payload. Copy only after actual rejection, before
199
+ // returning control to user code, so later caller mutation is invisible.
200
+ retryPayload = snapshotRetryPayload(payload);
201
+ consumeSubmittedMessages(payload);
202
+ }
203
+ catch (error) {
204
+ return Promise.reject(error);
205
+ }
206
+ const entry = new CompletionEntry(token, 'send', false);
207
+ entry.awaitWritable(result.completionId);
208
+ this.byToken.set(token, entry);
209
+ this.byId.set(result.completionId, entry);
210
+ this.retries.set(token, {
211
+ kind: 'send',
212
+ nativePayload: retryPayload,
213
+ routingId: routingId === null ? null : Buffer.from(routingId),
214
+ timeoutMs: 0,
215
+ });
216
+ this.managedWritableWaitCount += 1;
217
+ this.ensureRuntimeWatch();
218
+ return entry.promise;
219
+ }
220
+ submitRequest(payload, target, timeoutMs) {
221
+ if (this.closed)
222
+ throw submitError(errors_1.SubmitResult.InvalidState, 0, 'socket is closed');
223
+ const token = this.nextToken++;
224
+ let nativePayload;
225
+ try {
226
+ nativePayload = (0, message_conversion_1.normalizeOperationPayload)(payload);
227
+ }
228
+ catch (error) {
229
+ return Promise.reject((0, native_errors_1.submitNativeError)(error, DONTWAIT, 'request submit failed'));
230
+ }
231
+ let result;
232
+ try {
233
+ result = this.native.socketSubmitRequest(this.handle, target, nativePayload, timeoutMs, DONTWAIT, token);
234
+ }
235
+ catch (error) {
236
+ return Promise.reject((0, native_errors_1.submitNativeError)(error, DONTWAIT, 'request submit failed'));
237
+ }
238
+ if (result.result === errors_1.SubmitResult.Ok) {
239
+ if (result.completionId === 0n) {
240
+ return Promise.reject(submitError(errors_1.SubmitResult.InternalError, result.nativeErrno, 'successful request returned no completion id'));
241
+ }
242
+ try {
243
+ consumeSubmittedMessages(payload);
244
+ }
245
+ catch (error) {
246
+ return Promise.reject(error);
247
+ }
248
+ const entry = this.createEntry('request', token);
249
+ this.publish(entry, result.completionId);
250
+ this.ensureRuntimeWatch();
251
+ return entry.promise;
252
+ }
253
+ if (result.result !== errors_1.SubmitResult.Backpressured) {
254
+ return Promise.reject(submitError(result.result, result.nativeErrno, 'request submit failed'));
255
+ }
256
+ if (!(0, native_errors_1.isWouldBlock)(result.nativeErrno) || result.completionId === 0n) {
257
+ return Promise.reject(submitError(errors_1.SubmitResult.Backpressured, result.nativeErrno, 'backpressured request did not return an EAGAIN wait token'));
258
+ }
259
+ let retryPayload;
260
+ try {
261
+ // Core retains no REQUEST payload before admission. Snapshot only after
262
+ // refusal, then release the caller-visible Message wrappers immediately.
263
+ retryPayload = snapshotRetryPayload(payload);
264
+ consumeSubmittedMessages(payload);
265
+ }
266
+ catch (error) {
267
+ return Promise.reject(error);
268
+ }
269
+ const entry = this.createEntry('request', token);
270
+ entry.awaitWritable(result.completionId);
271
+ this.byId.set(result.completionId, entry);
272
+ this.retries.set(token, {
273
+ kind: 'request',
274
+ nativePayload: retryPayload,
275
+ routingId: target === null ? null : Buffer.from(target),
276
+ timeoutMs,
277
+ });
278
+ this.managedWritableWaitCount += 1;
279
+ this.ensureRuntimeWatch();
280
+ return entry.promise;
281
+ }
282
+ requestSync(payload, target, timeoutMs) {
283
+ const entry = this.register('request', false, false);
284
+ void entry.promise.catch(() => { });
285
+ let result;
286
+ try {
287
+ result = this.native.socketRequestSync(this.handle, target, (0, message_conversion_1.normalizeOperationPayload)(payload), timeoutMs);
288
+ }
289
+ catch (error) {
290
+ this.failEntry(entry, (0, native_errors_1.submitNativeError)(error, 0, 'request submit failed'));
291
+ throw entry.error;
292
+ }
293
+ if (result.result !== errors_1.SubmitResult.Ok) {
294
+ this.failEntry(entry, submitError(result.result, result.nativeErrno, 'request submit failed'));
295
+ throw entry.error;
296
+ }
297
+ consumeSubmittedMessages(payload);
298
+ this.publish(entry, result.completionId);
299
+ for (const completion of result.completions)
300
+ this.capture(completion);
301
+ this.drain();
302
+ if (!entry.settled) {
303
+ this.failEntry(entry, requestError(errors_1.RequestResult.InternalError, 'request completion missing'));
304
+ }
305
+ if (entry.error !== undefined)
306
+ throw entry.error;
307
+ return entry.value ?? [];
308
+ }
309
+ sendSync(payload, routingId) {
310
+ let result;
311
+ try {
312
+ result = this.native.socketSubmitSend(this.handle, (0, message_conversion_1.normalizeOperationPayload)(payload), routingId, 0, 0n);
313
+ }
314
+ catch (error) {
315
+ throw (0, native_errors_1.submitNativeError)(error, 0, 'send failed');
316
+ }
317
+ if (result.result !== errors_1.SubmitResult.Ok) {
318
+ throw submitError(result.result, result.nativeErrno, 'send failed');
319
+ }
320
+ consumeSubmittedMessages(payload);
321
+ if (result.completionId !== 0n) {
322
+ throw submitError(errors_1.SubmitResult.InternalError, result.nativeErrno, 'successful synchronous send returned a completion token');
323
+ }
324
+ }
325
+ transferToPublic(owner) {
326
+ if (this.closed)
327
+ throw submitError(errors_1.SubmitResult.InvalidState, 0, 'socket is closed');
328
+ if (this.publicOwner && this.publicOwner !== owner) {
329
+ throw submitError(errors_1.SubmitResult.InvalidState, 0, 'completion owner already transferred');
330
+ }
331
+ if (this.publicOwner === owner)
332
+ return false;
333
+ // Stop the event-loop fd watcher before the public Core poller starts
334
+ // observing the same socket notification source.
335
+ this.closeRuntimeWatch();
336
+ this.publicOwner = owner;
337
+ return true;
338
+ }
339
+ transferToRuntime(owner) {
340
+ if (this.publicOwner !== owner)
341
+ return;
342
+ this.publicOwner = null;
343
+ this.ensureRuntimeWatch();
344
+ }
345
+ drain(caller) {
346
+ if (this.publicOwner !== null && this.publicOwner !== caller)
347
+ return 0;
348
+ let processed = 0;
349
+ for (;;) {
350
+ const completion = this.native.socketCompletionRecv(this.handle, 1);
351
+ if (!completion)
352
+ break;
353
+ this.capture(completion);
354
+ processed += 1;
355
+ }
356
+ // Resubmission can enqueue another WRITABLE immediately. It belongs to
357
+ // the next drain, after this queue has reached NO_DATA.
358
+ try {
359
+ for (const entry of this.writableRetries)
360
+ this.attemptRetry(entry);
361
+ }
362
+ finally {
363
+ this.writableRetries.length = 0;
364
+ }
365
+ return processed;
366
+ }
367
+ hasManagedWritableWait() {
368
+ return this.managedWritableWaitCount !== 0;
369
+ }
370
+ close() {
371
+ if (this.closed)
372
+ return;
373
+ this.closed = true;
374
+ this.publicOwner = null;
375
+ for (const entry of this.byToken.values()) {
376
+ entry.fail(entry.kind === 'request'
377
+ ? requestError(errors_1.RequestResult.Terminated, 'socket closed')
378
+ : submitError(errors_1.SubmitResult.Terminated, 0, 'socket closed'));
379
+ }
380
+ this.byToken.clear();
381
+ this.byId.clear();
382
+ this.retries.clear();
383
+ this.writableRetries.length = 0;
384
+ this.managedWritableWaitCount = 0;
385
+ this.closeRuntimeWatch();
386
+ }
387
+ register(kind, schedule = true, expectsUserContext = true) {
388
+ if (this.closed)
389
+ throw submitError(errors_1.SubmitResult.InvalidState, 0, 'socket is closed');
390
+ const entry = this.createEntry(kind, this.nextToken++, expectsUserContext);
391
+ if (schedule)
392
+ this.ensureRuntimeWatch();
393
+ return entry;
394
+ }
395
+ createEntry(kind, token, expectsUserContext = true) {
396
+ const entry = new CompletionEntry(token, kind, expectsUserContext);
397
+ this.byToken.set(entry.token, entry);
398
+ return entry;
399
+ }
400
+ publish(entry, completionId) {
401
+ entry.publish(completionId);
402
+ if (completionId !== 0n)
403
+ this.byId.set(completionId, entry);
404
+ this.removeIfSettled(entry);
405
+ }
406
+ capture(completion) {
407
+ const entry = completion.userContext !== 0n
408
+ ? this.byToken.get(completion.userContext)
409
+ : this.byId.get(completion.completionId);
410
+ if (!entry)
411
+ return; // Native already closed the unclaimed completion.
412
+ if (this.retries.has(entry.token)) {
413
+ this.captureWritable(entry, completion);
414
+ return;
415
+ }
416
+ entry.capture(completion);
417
+ this.removeIfSettled(entry);
418
+ }
419
+ captureWritable(entry, completion) {
420
+ if (completion.kind !== COMPLETION_WRITABLE
421
+ || completion.completionId !== entry.completionId
422
+ || completion.userContext !== entry.token) {
423
+ this.failEntry(entry, submitError(errors_1.SubmitResult.InternalError, completion.terminalErrno, 'writable completion did not match the pending operation'));
424
+ return;
425
+ }
426
+ this.byId.delete(entry.completionId);
427
+ if (completion.sendResult !== SEND_ADMITTED) {
428
+ const error = completion.sendResult === SEND_TERMINAL
429
+ ? (0, error_mapping_1.createError)('submit', completion.terminalErrno, 'submit target became unavailable')
430
+ : submitError(errors_1.SubmitResult.InternalError, completion.terminalErrno, 'writable completion result mismatch');
431
+ this.failEntry(entry, error);
432
+ return;
433
+ }
434
+ this.writableRetries.push(entry);
435
+ }
436
+ attemptRetry(entry) {
437
+ const retry = this.retries.get(entry.token);
438
+ if (!retry) {
439
+ this.failEntry(entry, submitError(errors_1.SubmitResult.InternalError, 0, 'pending operation payload is missing'));
440
+ return;
441
+ }
442
+ let result;
443
+ try {
444
+ result = retry.kind === 'send'
445
+ ? this.native.socketSubmitSend(this.handle, retry.nativePayload, retry.routingId, DONTWAIT, entry.token)
446
+ : this.native.socketSubmitRequest(this.handle, retry.routingId, retry.nativePayload, retry.timeoutMs, DONTWAIT, entry.token);
447
+ }
448
+ catch (error) {
449
+ this.failEntry(entry, (0, native_errors_1.submitNativeError)(error, DONTWAIT, `${retry.kind} submit failed`));
450
+ return;
451
+ }
452
+ if (result.result === errors_1.SubmitResult.Ok) {
453
+ const validCompletionId = retry.kind === 'send'
454
+ ? result.completionId === 0n
455
+ : result.completionId !== 0n;
456
+ if (!validCompletionId) {
457
+ this.failEntry(entry, submitError(errors_1.SubmitResult.InternalError, result.nativeErrno, `successful ${retry.kind} returned an invalid completion id`));
458
+ return;
459
+ }
460
+ this.removeRetry(entry);
461
+ if (retry.kind === 'send') {
462
+ entry.succeed(undefined);
463
+ this.removeIfSettled(entry);
464
+ }
465
+ else {
466
+ entry.publish(result.completionId);
467
+ this.byId.set(result.completionId, entry);
468
+ this.ensureRuntimeWatch();
469
+ }
470
+ return;
471
+ }
472
+ if (result.result === errors_1.SubmitResult.Backpressured) {
473
+ if (!(0, native_errors_1.isWouldBlock)(result.nativeErrno) || result.completionId === 0n) {
474
+ this.failEntry(entry, submitError(errors_1.SubmitResult.Backpressured, result.nativeErrno, `backpressured ${retry.kind} did not return an EAGAIN wait token`));
475
+ return;
476
+ }
477
+ if (entry.completionId !== 0n)
478
+ this.byId.delete(entry.completionId);
479
+ entry.awaitWritable(result.completionId);
480
+ this.byId.set(result.completionId, entry);
481
+ this.ensureRuntimeWatch();
482
+ return;
483
+ }
484
+ this.failEntry(entry, submitError(result.result, result.nativeErrno, `${retry.kind} submit failed`));
485
+ }
486
+ failEntry(entry, error) {
487
+ entry.fail(error);
488
+ this.removeIfSettled(entry);
489
+ }
490
+ removeIfSettled(entry) {
491
+ if (!entry.settled)
492
+ return;
493
+ this.byToken.delete(entry.token);
494
+ if (entry.completionId !== 0n)
495
+ this.byId.delete(entry.completionId);
496
+ this.removeRetry(entry);
497
+ }
498
+ removeRetry(entry) {
499
+ if (this.retries.delete(entry.token))
500
+ this.managedWritableWaitCount -= 1;
501
+ }
502
+ ensureRuntimeWatch() {
503
+ if (this.closed || this.publicOwner || this.byToken.size === 0
504
+ || this.runtimeWatch !== null)
505
+ return;
506
+ this.runtimeWatch = this.native.socketReadableWatchStart(this.handle, (status) => this.runtimeWake(status));
507
+ }
508
+ runtimeWake(status) {
509
+ if (this.closed || this.publicOwner)
510
+ return;
511
+ try {
512
+ if (status < 0)
513
+ throw new Error(`socket readable watch failed (${status})`);
514
+ this.drain();
515
+ }
516
+ catch (error) {
517
+ const nativeErrno = (0, native_errors_1.readErrno)();
518
+ const message = (0, native_errors_1.nativeErrorMessage)(error, 'completion drain failed');
519
+ for (const entry of this.byToken.values()) {
520
+ entry.fail(this.retries.has(entry.token)
521
+ ? (nativeErrno === 0
522
+ ? submitError(errors_1.SubmitResult.InternalError, 0, message)
523
+ : (0, error_mapping_1.createError)('submit', nativeErrno, message))
524
+ : entry.kind === 'request'
525
+ ? (nativeErrno === 0
526
+ ? requestError(errors_1.RequestResult.InternalError, message)
527
+ : (0, error_mapping_1.createError)('request', nativeErrno, message))
528
+ : (nativeErrno === 0
529
+ ? submitError(errors_1.SubmitResult.InternalError, 0, message)
530
+ : (0, error_mapping_1.createError)('submit', nativeErrno, message)));
531
+ }
532
+ this.byToken.clear();
533
+ this.byId.clear();
534
+ this.retries.clear();
535
+ this.writableRetries.length = 0;
536
+ this.managedWritableWaitCount = 0;
537
+ }
538
+ if (this.byToken.size === 0)
539
+ this.closeRuntimeWatch();
540
+ }
541
+ closeRuntimeWatch() {
542
+ const watch = this.runtimeWatch;
543
+ this.runtimeWatch = null;
544
+ if (watch === null)
545
+ return;
546
+ try {
547
+ this.native.socketReadableWatchStop(watch);
548
+ }
549
+ catch { /* best-effort cleanup */ }
550
+ }
551
+ }
552
+ exports.CompletionOwner = CompletionOwner;
553
+ function installCompletionOwner(socket, handle) {
554
+ const owner = new CompletionOwner(handle);
555
+ owners.set(socket, owner);
556
+ return owner;
557
+ }
558
+ function completionOwnerOf(socket) {
559
+ const owner = owners.get(socket);
560
+ if (!owner)
561
+ throw new TypeError('socket has no completion owner');
562
+ return owner;
563
+ }
564
+ function releaseCompletionOwner(socket) {
565
+ const owner = owners.get(socket);
566
+ if (!owner)
567
+ return;
568
+ owner.close();
569
+ owners.delete(socket);
570
+ }
@@ -0,0 +1,36 @@
1
+ import { Message, Received, ReplyToken, TopicMessage, type MessageLike } from '../../contracts';
2
+ import { type MessageSnapshot } from './message_snapshot';
3
+ export interface NativeReceivedEnvelope {
4
+ parts?: MessageSnapshot[];
5
+ data?: Buffer;
6
+ nativeMessage?: unknown;
7
+ routingId?: Buffer | null;
8
+ replyToken?: bigint | null;
9
+ }
10
+ type NativeReceivedBufferParts = readonly Buffer[];
11
+ /** Internal receive transfer: either an envelope or an unrouted native frame. */
12
+ export type NativeReceivedRaw = NativeReceivedEnvelope | NativeReceivedBufferParts | object;
13
+ export interface NativeTopicMessageRaw {
14
+ topic: string;
15
+ parts?: MessageSnapshot[];
16
+ data?: Buffer;
17
+ nativeMessage?: unknown;
18
+ routingId?: Buffer | null;
19
+ }
20
+ type NativeTopicMessageSinglePart = readonly [Buffer, string];
21
+ type NativeTopicMessageEnvelope = NativeTopicMessageRaw | NativeTopicMessageSinglePart;
22
+ export interface RoutedReceiveOperations {
23
+ readonly replyOwner: object;
24
+ send(routingId: Buffer, parts: readonly Message[]): void;
25
+ sendManaged(routingId: Buffer, parts: readonly Message[]): Promise<void>;
26
+ reply(routingId: Buffer, token: ReplyToken, parts: readonly MessageLike[]): void;
27
+ }
28
+ export declare function routedReceivedPrefersManagedBuffer(target: Received): boolean;
29
+ export declare function routedReceivedRoutingBytes(target: Received): Buffer | null;
30
+ export declare function nativeReceivedRoutingId(raw: NativeReceivedRaw): Buffer | null;
31
+ export declare function materializeReceived(raw: NativeReceivedRaw, send?: (parts: readonly Message[]) => void, sendManaged?: (parts: readonly Message[]) => Promise<void>): Received;
32
+ export declare function materializeReceivedInto(target: Received, raw: NativeReceivedRaw, send?: (parts: readonly Message[]) => void, sendManaged?: (parts: readonly Message[]) => Promise<void>): void;
33
+ export declare function materializeRoutedReceivedInto(target: Received, raw: NativeReceivedRaw, operations: RoutedReceiveOperations): void;
34
+ export declare function materializeTopicMessage(raw: NativeTopicMessageEnvelope): TopicMessage;
35
+ export declare function adoptTopicMessage(result: TopicMessage, raw: NativeTopicMessageEnvelope): void;
36
+ export {};