@zlink-systems/framework 0.30.0 → 0.30.1

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 (245) hide show
  1. package/LICENSE +150 -68
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/contracts/Actors/ZLinkActorClient.d.ts +2 -1
  4. package/dist/contracts/Channels/Calls.d.ts +2 -1
  5. package/dist/contracts/Common/ZLinkMessageMetadata.js +11 -5
  6. package/dist/contracts/Handlers/Attributes.d.ts +5 -13
  7. package/dist/contracts/Handlers/Attributes.js +7 -11
  8. package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
  9. package/dist/contracts/Handlers/JsonContract.js +4 -153
  10. package/dist/contracts/Spots/Contracts.d.ts +2 -1
  11. package/dist/nest-integration.d.ts +1 -1
  12. package/dist/nest-integration.js +2 -1
  13. package/dist/runtime/actors/actor-client.d.ts +1 -1
  14. package/dist/runtime/actors/actor-client.js +14 -12
  15. package/dist/runtime/actors/actor-handoff.d.ts +1 -1
  16. package/dist/runtime/actors/actor-handoff.js +7 -4
  17. package/dist/runtime/actors/actor-join-relocation.d.ts +1 -0
  18. package/dist/runtime/actors/actor-local-native-join.js +9 -12
  19. package/dist/runtime/actors/actor-remote-wire.js +15 -0
  20. package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
  21. package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
  22. package/dist/runtime/actors/index.d.ts +2 -1
  23. package/dist/runtime/actors/index.js +18 -6
  24. package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
  25. package/dist/runtime/admission.d.ts +1 -1
  26. package/dist/runtime/admission.js +15 -5
  27. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +6 -8
  28. package/dist/runtime/application-jobs/application-ingress-record-owner.js +39 -22
  29. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +2 -1
  30. package/dist/runtime/application-jobs/application-job-queue-scope.js +37 -22
  31. package/dist/runtime/application-jobs/contracts.d.ts +10 -1
  32. package/dist/runtime/backend/contracts/index.d.ts +18 -9
  33. package/dist/runtime/backend/mesh-completion-table.d.ts +9 -1
  34. package/dist/runtime/backend/mesh-completion-table.js +149 -49
  35. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +3 -0
  36. package/dist/runtime/backend/mesh-dispatch-pump.js +32 -11
  37. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
  38. package/dist/runtime/backend/node/node-backend-adapter-support.js +16 -9
  39. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
  40. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
  41. package/dist/runtime/backend/node/node-raw-binding-port.js +42 -22
  42. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +13 -5
  43. package/dist/runtime/backend/node/node-raw-mesh-backend.js +69 -51
  44. package/dist/runtime/backend/node/node-socket-backend-adapter.js +6 -6
  45. package/dist/runtime/backend/raw-binding-port.d.ts +2 -2
  46. package/dist/runtime/backend/runtime-message.d.ts +1 -0
  47. package/dist/runtime/backend/runtime-message.js +5 -0
  48. package/dist/runtime/backend/runtime-values.d.ts +1 -0
  49. package/dist/runtime/backend/runtime-values.js +2 -1
  50. package/dist/runtime/channels/channel-clients.d.ts +1 -0
  51. package/dist/runtime/channels/channel-clients.js +58 -21
  52. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +3 -2
  53. package/dist/runtime/channels/channel-dispatch-pipeline.js +20 -11
  54. package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
  55. package/dist/runtime/channels/channel-dispatch-services.js +45 -0
  56. package/dist/runtime/channels/channel-dispatchers.d.ts +1 -1
  57. package/dist/runtime/channels/channel-dispatchers.js +27 -26
  58. package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
  59. package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
  60. package/dist/runtime/channels/channel-envelope.d.ts +1 -0
  61. package/dist/runtime/channels/channel-envelope.js +83 -8
  62. package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
  63. package/dist/runtime/channels/channel-outbound-operations.js +8 -8
  64. package/dist/runtime/channels/channel-runtime-manager.d.ts +6 -6
  65. package/dist/runtime/channels/channel-runtime-manager.js +12 -12
  66. package/dist/runtime/channels/channel-transports.d.ts +18 -15
  67. package/dist/runtime/channels/channel-transports.js +48 -31
  68. package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
  69. package/dist/runtime/channels/local-spot-route-transport.js +2 -1
  70. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
  71. package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
  72. package/dist/runtime/channels/source-spot-router.d.ts +2 -2
  73. package/dist/runtime/channels/source-spot-router.js +4 -4
  74. package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
  75. package/dist/runtime/channels/spot-node-route-transport.js +4 -4
  76. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
  77. package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
  78. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
  79. package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
  80. package/dist/runtime/execution/serial-execution-queue.d.ts +1 -0
  81. package/dist/runtime/execution/serial-execution-queue.js +1 -0
  82. package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
  83. package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
  84. package/dist/runtime/foundation/durable-service-request.js +98 -0
  85. package/dist/runtime/foundation/operation-identity.d.ts +1 -0
  86. package/dist/runtime/foundation/operation-identity.js +5 -1
  87. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +22 -5
  88. package/dist/runtime/foundation/raw-service-mesh-runtime.js +356 -232
  89. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +1 -0
  90. package/dist/runtime/foundation/service-relocation-object-owner.js +1 -0
  91. package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
  92. package/dist/runtime/foundation/service-relocation-runtime.js +13 -1
  93. package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -0
  94. package/dist/runtime/foundation/service-stateful-runtime.d.ts +4 -4
  95. package/dist/runtime/foundation/service-stateful-runtime.js +44 -103
  96. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +0 -5
  97. package/dist/runtime/foundation/service-topology-registry.d.ts +12 -2
  98. package/dist/runtime/foundation/service-topology-registry.js +61 -27
  99. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +3 -3
  100. package/dist/runtime/foundation/service-wire-m6a-codec.js +36 -38
  101. package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
  102. package/dist/runtime/handlers/handler-instance-scope.js +54 -11
  103. package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
  104. package/dist/runtime/host/application-job-queue.d.ts +19 -7
  105. package/dist/runtime/host/application-job-queue.js +150 -42
  106. package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
  107. package/dist/runtime/host/entry-actor-runtime.js +3 -0
  108. package/dist/runtime/host/index.d.ts +7 -1
  109. package/dist/runtime/host/index.js +142 -118
  110. package/dist/runtime/host/remote-bound-session-relay.js +2 -18
  111. package/dist/runtime/host/route-mesh-runtime.js +1 -1
  112. package/dist/runtime/host/service-relocation-control.d.ts +1 -0
  113. package/dist/runtime/host/service-relocation-control.js +10 -4
  114. package/dist/runtime/host/service-relocation-host-runtime.d.ts +6 -8
  115. package/dist/runtime/host/service-relocation-host-runtime.js +213 -241
  116. package/dist/runtime/host/spot-address-transport.js +3 -2
  117. package/dist/runtime/host/spot-runtime-options-factory.js +1 -0
  118. package/dist/runtime/locations/actor-location-claims.d.ts +2 -2
  119. package/dist/runtime/locations/actor-location-claims.js +34 -19
  120. package/dist/runtime/locations/lifecycle.d.ts +1 -2
  121. package/dist/runtime/locations/lifecycle.js +2 -5
  122. package/dist/runtime/locations/runtime.d.ts +1 -1
  123. package/dist/runtime/locations/runtime.js +24 -23
  124. package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
  125. package/dist/runtime/messaging/framework-json-v1.js +38 -294
  126. package/dist/runtime/messaging/packet-name.d.ts +1 -1
  127. package/dist/runtime/messaging/packet-name.js +8 -24
  128. package/dist/runtime/messaging/request-result.d.ts +2 -0
  129. package/dist/runtime/messaging/request-result.js +54 -0
  130. package/dist/runtime/messaging/submission-result.d.ts +1 -0
  131. package/dist/runtime/messaging/submission-result.js +5 -2
  132. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +15 -0
  133. package/dist/runtime/protocol/service_wire_codec.generated.js +144 -0
  134. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +9 -0
  135. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +14 -1
  136. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +7 -2
  137. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +33 -19
  138. package/dist/runtime/spots/index.d.ts +3 -0
  139. package/dist/runtime/spots/index.js +9 -2
  140. package/dist/runtime/spots/spot-activation.d.ts +1 -0
  141. package/dist/runtime/spots/spot-activation.js +17 -8
  142. package/dist/runtime/spots/spot-entry-activation.js +6 -2
  143. package/dist/runtime/spots/spot-handler-registry.d.ts +3 -1
  144. package/dist/runtime/spots/spot-handler-registry.js +18 -8
  145. package/dist/runtime/spots/spot-node-autoconnect.js +4 -3
  146. package/dist/runtime/spots/spot-outbound.d.ts +3 -0
  147. package/dist/runtime/spots/spot-outbound.js +24 -15
  148. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
  149. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
  150. package/dist/runtime/spots/spot-runtime-ports.d.ts +1 -0
  151. package/dist/runtime/spots/spot-subscription-dispatch.js +0 -3
  152. package/dist/runtime/spots/spot-timer.js +1 -0
  153. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
  154. package/dist/runtime/streams/stream-session-runtime.js +13 -27
  155. package/package.json +2 -2
  156. package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
  157. package/src/contracts/Channels/Calls.ts +2 -1
  158. package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
  159. package/src/contracts/Handlers/Attributes.ts +14 -21
  160. package/src/contracts/Handlers/JsonContract.ts +8 -216
  161. package/src/contracts/Spots/Contracts.ts +2 -1
  162. package/src/nest-integration.ts +1 -0
  163. package/src/runtime/actors/actor-client.ts +40 -16
  164. package/src/runtime/actors/actor-handoff.ts +9 -4
  165. package/src/runtime/actors/actor-join-relocation.ts +1 -0
  166. package/src/runtime/actors/actor-local-native-join.ts +17 -26
  167. package/src/runtime/actors/actor-remote-wire.ts +17 -0
  168. package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
  169. package/src/runtime/actors/actor-routed-json-request.ts +10 -2
  170. package/src/runtime/actors/index.ts +19 -5
  171. package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
  172. package/src/runtime/admission.ts +18 -5
  173. package/src/runtime/application-jobs/application-ingress-record-owner.ts +41 -25
  174. package/src/runtime/application-jobs/application-job-queue-scope.ts +51 -22
  175. package/src/runtime/application-jobs/contracts.ts +14 -1
  176. package/src/runtime/backend/contracts/index.ts +53 -14
  177. package/src/runtime/backend/mesh-completion-table.ts +156 -57
  178. package/src/runtime/backend/mesh-dispatch-pump.ts +40 -10
  179. package/src/runtime/backend/node/node-backend-adapter-support.ts +17 -8
  180. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
  181. package/src/runtime/backend/node/node-raw-binding-port.ts +57 -30
  182. package/src/runtime/backend/node/node-raw-mesh-backend.ts +128 -65
  183. package/src/runtime/backend/node/node-socket-backend-adapter.ts +21 -6
  184. package/src/runtime/backend/raw-binding-port.ts +7 -2
  185. package/src/runtime/backend/runtime-message.ts +6 -0
  186. package/src/runtime/backend/runtime-values.ts +1 -0
  187. package/src/runtime/channels/channel-clients.ts +90 -41
  188. package/src/runtime/channels/channel-dispatch-pipeline.ts +69 -34
  189. package/src/runtime/channels/channel-dispatch-services.ts +69 -1
  190. package/src/runtime/channels/channel-dispatchers.ts +29 -27
  191. package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
  192. package/src/runtime/channels/channel-envelope.ts +133 -8
  193. package/src/runtime/channels/channel-outbound-operations.ts +22 -8
  194. package/src/runtime/channels/channel-runtime-manager.ts +29 -12
  195. package/src/runtime/channels/channel-transports.ts +128 -60
  196. package/src/runtime/channels/local-spot-route-transport.ts +3 -1
  197. package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
  198. package/src/runtime/channels/source-spot-router.ts +8 -4
  199. package/src/runtime/channels/spot-node-route-transport.ts +8 -4
  200. package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
  201. package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
  202. package/src/runtime/execution/serial-execution-queue.ts +2 -0
  203. package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
  204. package/src/runtime/foundation/durable-service-request.ts +137 -0
  205. package/src/runtime/foundation/operation-identity.ts +5 -1
  206. package/src/runtime/foundation/raw-service-mesh-runtime.ts +484 -293
  207. package/src/runtime/foundation/service-relocation-object-owner.ts +2 -0
  208. package/src/runtime/foundation/service-relocation-runtime.ts +18 -1
  209. package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
  210. package/src/runtime/foundation/service-stateful-runtime.ts +67 -125
  211. package/src/runtime/foundation/service-stateful-wire-codec.ts +0 -5
  212. package/src/runtime/foundation/service-topology-registry.ts +91 -36
  213. package/src/runtime/foundation/service-wire-m6a-codec.ts +57 -38
  214. package/src/runtime/handlers/handler-instance-scope.ts +67 -16
  215. package/src/runtime/host/actor-runtime-options-factory.ts +13 -2
  216. package/src/runtime/host/application-job-queue.ts +175 -41
  217. package/src/runtime/host/entry-actor-runtime.ts +4 -0
  218. package/src/runtime/host/index.ts +201 -156
  219. package/src/runtime/host/remote-bound-session-relay.ts +2 -23
  220. package/src/runtime/host/route-mesh-runtime.ts +1 -1
  221. package/src/runtime/host/service-relocation-control.ts +11 -5
  222. package/src/runtime/host/service-relocation-host-runtime.ts +315 -291
  223. package/src/runtime/host/spot-address-transport.ts +4 -2
  224. package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
  225. package/src/runtime/locations/actor-location-claims.ts +52 -30
  226. package/src/runtime/locations/lifecycle.ts +8 -26
  227. package/src/runtime/locations/runtime.ts +28 -24
  228. package/src/runtime/messaging/framework-json-v1.ts +5 -325
  229. package/src/runtime/messaging/packet-name.ts +5 -25
  230. package/src/runtime/messaging/request-result.ts +58 -0
  231. package/src/runtime/messaging/submission-result.ts +5 -1
  232. package/src/runtime/protocol/service_wire_codec.generated.ts +131 -1
  233. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
  234. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +43 -23
  235. package/src/runtime/spots/index.ts +14 -2
  236. package/src/runtime/spots/spot-activation.ts +28 -10
  237. package/src/runtime/spots/spot-entry-activation.ts +9 -2
  238. package/src/runtime/spots/spot-handler-registry.ts +41 -8
  239. package/src/runtime/spots/spot-node-autoconnect.ts +6 -2
  240. package/src/runtime/spots/spot-outbound.ts +36 -16
  241. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
  242. package/src/runtime/spots/spot-runtime-ports.ts +1 -0
  243. package/src/runtime/spots/spot-subscription-dispatch.ts +0 -3
  244. package/src/runtime/spots/spot-timer.ts +5 -1
  245. package/src/runtime/streams/stream-session-runtime.ts +12 -29
@@ -8,6 +8,7 @@ import {
8
8
  } from './service-topology-registry';
9
9
  import {
10
10
  SERVICE_WIRE_PREFIX_SIZE,
11
+ SERVICE_WIRE_TEXT8_MAX_BYTES,
11
12
  decodeCanonicalServiceWireText,
12
13
  encodeCanonicalServiceWireText
13
14
  } from './service-wire-binary-primitives';
@@ -70,8 +71,7 @@ export function encodeNodeRequestHeader(correlation: bigint): Buffer {
70
71
  return withU64(prefix(M6aServiceWireCommand.nodeRequest), correlation, 'correlation');
71
72
  }
72
73
 
73
- export function decodeNodeRequestHeader(frame: Uint8Array): bigint {
74
- const header = decodeHeader(frame);
74
+ export function decodeNodeRequestHeader(frame: Uint8Array, header = decodeHeader(frame)): bigint {
75
75
  if (
76
76
  header.command !== M6aServiceWireCommand.nodeRequest ||
77
77
  header.flags !== 0 ||
@@ -86,8 +86,7 @@ export function encodeChannelSendHeader(channelName: string): Buffer {
86
86
  return concat(prefix(M6aServiceWireCommand.channelSend), encodeText8(channelName, 'channelName'));
87
87
  }
88
88
 
89
- export function decodeChannelSendHeader(frame: Uint8Array): string {
90
- const header = decodeHeader(frame);
89
+ export function decodeChannelSendHeader(frame: Uint8Array, header = decodeHeader(frame)): string {
91
90
  if (header.command !== M6aServiceWireCommand.channelSend || header.flags !== 0) {
92
91
  fail('Invalid channelSend header.');
93
92
  }
@@ -104,11 +103,13 @@ export function encodeChannelRequestHeader(correlation: bigint, channelName: str
104
103
  );
105
104
  }
106
105
 
107
- export function decodeChannelRequestHeader(frame: Uint8Array): {
106
+ export function decodeChannelRequestHeader(
107
+ frame: Uint8Array,
108
+ header = decodeHeader(frame)
109
+ ): {
108
110
  readonly correlation: bigint;
109
111
  readonly channelName: string;
110
112
  } {
111
- const header = decodeHeader(frame);
112
113
  if (header.command !== M6aServiceWireCommand.channelRequest || header.flags !== 0) {
113
114
  fail('Invalid channelRequest header.');
114
115
  }
@@ -165,24 +166,12 @@ export function decodeReplyHeader(frame: Uint8Array): ServiceReplyHeader {
165
166
  }
166
167
 
167
168
  export function encodeApplicationPayload(payload: ServiceApplicationPayload): Buffer {
168
- const packetName = encodeText8(payload.packetName, 'packetName');
169
- const contentType = encodeText8(payload.contentType, 'contentType');
170
- if (payload.payload.byteLength > MAX_U32) fail('Application payload exceeds u32.');
171
- const bodyLength =
172
- packetName.byteLength + contentType.byteLength + 4 + payload.payload.byteLength;
173
- if (bodyLength > MAX_U32) fail('Application payload body exceeds u32.');
174
- const result = Buffer.alloc(5 + bodyLength);
175
- result[0] = APPLICATION_PAYLOAD_VERSION;
176
- result.writeUInt32BE(bodyLength, 1);
177
- let offset = 5;
178
- offset += packetName.copy(result, offset);
179
- offset += contentType.copy(result, offset);
180
- result.writeUInt32BE(payload.payload.byteLength, offset);
181
- offset += 4;
182
- Buffer.from(payload.payload.buffer, payload.payload.byteOffset, payload.payload.byteLength).copy(
183
- result,
184
- offset
169
+ const result = allocateApplicationPayload(
170
+ payload.packetName,
171
+ payload.contentType,
172
+ payload.payload.byteLength
185
173
  );
174
+ result.set(payload.payload, result.byteLength - payload.payload.byteLength);
186
175
  return result;
187
176
  }
188
177
 
@@ -198,35 +187,65 @@ export function encodeMultipartApplicationPayload(
198
187
  ): Buffer {
199
188
  if (parts.length === 0) fail('Multipart payload must contain at least one part.');
200
189
  if (parts.length > MAX_U32) fail('Multipart part count exceeds u32.');
201
- const packetNameBytes = encodeText8(packetName, 'packetName');
202
- const contentTypeBytes = encodeText8(contentType, 'contentType');
203
190
  let multipartLength = 4;
204
191
  for (const part of parts) {
205
192
  if (part.byteLength > MAX_U32) fail('Multipart part exceeds u32.');
206
193
  multipartLength += 4 + part.byteLength;
207
194
  if (multipartLength > MAX_U32) fail('Multipart payload exceeds u32.');
208
195
  }
209
- const bodyLength = packetNameBytes.byteLength + contentTypeBytes.byteLength + 4 + multipartLength;
210
- if (bodyLength > MAX_U32) fail('Application payload body exceeds u32.');
211
- const result = Buffer.alloc(5 + bodyLength);
212
- result[0] = APPLICATION_PAYLOAD_VERSION;
213
- result.writeUInt32BE(bodyLength, 1);
214
- let offset = 5;
215
- offset += packetNameBytes.copy(result, offset);
216
- offset += contentTypeBytes.copy(result, offset);
217
- result.writeUInt32BE(multipartLength, offset);
218
- offset += 4;
196
+ const result = allocateApplicationPayload(packetName, contentType, multipartLength);
197
+ let offset = result.byteLength - multipartLength;
219
198
  result.writeUInt32BE(parts.length, offset);
220
199
  offset += 4;
221
200
  for (const part of parts) {
222
201
  result.writeUInt32BE(part.byteLength, offset);
223
202
  offset += 4;
224
- Buffer.from(part.buffer, part.byteOffset, part.byteLength).copy(result, offset);
203
+ result.set(part, offset);
225
204
  offset += part.byteLength;
226
205
  }
227
206
  return result;
228
207
  }
229
208
 
209
+ function allocateApplicationPayload(
210
+ packetName: string,
211
+ contentType: string,
212
+ payloadLength: number
213
+ ): Buffer {
214
+ const packetNameBytes = encodeCanonicalServiceWireText(
215
+ packetName,
216
+ 'packetName',
217
+ SERVICE_WIRE_TEXT8_MAX_BYTES,
218
+ fail
219
+ );
220
+ const contentTypeBytes = encodeCanonicalServiceWireText(
221
+ contentType,
222
+ 'contentType',
223
+ SERVICE_WIRE_TEXT8_MAX_BYTES,
224
+ fail
225
+ );
226
+ if (payloadLength > MAX_U32) fail('Application payload exceeds u32.');
227
+ const frameLength =
228
+ APPLICATION_PAYLOAD_MINIMUM_FIELD_BYTES +
229
+ packetNameBytes.byteLength +
230
+ contentTypeBytes.byteLength +
231
+ payloadLength;
232
+ const prefixLength = 1 + APPLICATION_PAYLOAD_LENGTH_FIELD_BYTES;
233
+ const bodyLength = frameLength - prefixLength;
234
+ if (bodyLength > MAX_U32) fail('Application payload body exceeds u32.');
235
+ const result = Buffer.alloc(frameLength);
236
+ result[0] = APPLICATION_PAYLOAD_VERSION;
237
+ result.writeUInt32BE(bodyLength, 1);
238
+ let offset = prefixLength;
239
+ result[offset++] = packetNameBytes.byteLength;
240
+ result.set(packetNameBytes, offset);
241
+ offset += packetNameBytes.byteLength;
242
+ result[offset++] = contentTypeBytes.byteLength;
243
+ result.set(contentTypeBytes, offset);
244
+ offset += contentTypeBytes.byteLength;
245
+ result.writeUInt32BE(payloadLength, offset);
246
+ return result;
247
+ }
248
+
230
249
  export function decodeApplicationPayload(frame: Uint8Array): ServiceApplicationPayload {
231
250
  const decoded = decodeApplicationPayloadView(frame);
232
251
  return {
@@ -487,7 +506,7 @@ function encodeU64(value: bigint): Buffer {
487
506
  }
488
507
 
489
508
  function encodeText8(value: string, field: string): Buffer {
490
- const bytes = encodeCanonicalServiceWireText(value, field, 0xff, fail);
509
+ const bytes = encodeCanonicalServiceWireText(value, field, SERVICE_WIRE_TEXT8_MAX_BYTES, fail);
491
510
  return concat(Buffer.of(bytes.byteLength), bytes);
492
511
  }
493
512
 
@@ -501,7 +520,7 @@ function tlv(id: number, value: Buffer): Buffer {
501
520
  }
502
521
 
503
522
  function concat(...parts: readonly Uint8Array[]): Buffer {
504
- return Buffer.concat(parts.map((part) => Buffer.from(part)));
523
+ return Buffer.concat(parts);
505
524
  }
506
525
 
507
526
  function readNonZeroU64(bytes: Buffer, offset: number, field: string): bigint {
@@ -9,13 +9,10 @@ export interface ZLinkHandlerInstanceScope {
9
9
  }
10
10
 
11
11
  interface ZLinkHandlerInstanceScopeFactory {
12
+ prepare?(type: Type): void | (() => unknown);
12
13
  create(context?: ZLinkMessageContext): ZLinkHandlerInstanceScope;
13
14
  }
14
15
 
15
- interface ActiveHandlerScope {
16
- readonly scope: ZLinkHandlerInstanceScope;
17
- }
18
-
19
16
  interface Deferred<T> {
20
17
  readonly promise: Promise<T>;
21
18
  readonly resolve: (value: T) => void;
@@ -29,12 +26,37 @@ interface LifecycleScopeDisposal {
29
26
  }
30
27
 
31
28
  const HANDLER_SCOPE_FACTORY = Symbol.for('@zlink-systems/framework.handler-instance-scope-factory');
32
- const activeHandlerScope = new AsyncLocalStorage<ActiveHandlerScope>();
29
+ const activeHandlerScope = new AsyncLocalStorage<ZLinkHandlerInstanceScope>();
33
30
  const activeLifecycleScope = new AsyncLocalStorage<LifecycleHandlerInstanceScope>();
34
31
  const detachedLifecycleResource = new AsyncResource('zlink:handler-instance-scope');
35
32
  const dispatchScopes = new WeakMap<object, ZLinkHandlerInstanceScope>();
36
33
  const lifecycleScopes = new WeakMap<object, LifecycleHandlerInstanceScope>();
37
34
 
35
+ export function registerHandlerInstanceScopeFactory(
36
+ providerResolver: ZLinkProviderResolver,
37
+ factory: ZLinkHandlerInstanceScopeFactory
38
+ ): void {
39
+ Object.defineProperty(providerResolver, HANDLER_SCOPE_FACTORY, {
40
+ value: factory,
41
+ enumerable: false
42
+ });
43
+ }
44
+
45
+ export function prepareHandlerInstance<T>(
46
+ providerResolver: ZLinkProviderResolver | undefined,
47
+ type: Type<T>
48
+ ): (() => T) | undefined {
49
+ if (providerResolver === undefined) return () => new type();
50
+ const factory = (providerResolver as unknown as Record<PropertyKey, unknown>)[
51
+ HANDLER_SCOPE_FACTORY
52
+ ];
53
+ if (isHandlerInstanceScopeFactory(factory)) {
54
+ const activate = factory.prepare?.(type);
55
+ if (activate !== undefined) return activate as () => T;
56
+ }
57
+ return undefined;
58
+ }
59
+
38
60
  export async function runInHandlerInstanceScope<T>(
39
61
  providerResolver: ZLinkProviderResolver | undefined,
40
62
  context: ZLinkMessageContext | undefined,
@@ -42,7 +64,7 @@ export async function runInHandlerInstanceScope<T>(
42
64
  ): Promise<T> {
43
65
  const active = activeHandlerScope.getStore();
44
66
  if (active !== undefined) {
45
- return callback(active.scope);
67
+ return callback(active);
46
68
  }
47
69
  if (context !== undefined) {
48
70
  const existing = dispatchScopes.get(context);
@@ -56,7 +78,7 @@ export async function runInHandlerInstanceScope<T>(
56
78
  dispatchScopes.set(context, scope);
57
79
  }
58
80
  try {
59
- return await activeHandlerScope.run({ scope }, () => callback(scope));
81
+ return await activeHandlerScope.run(scope, () => callback(scope));
60
82
  } finally {
61
83
  if (context !== undefined && dispatchScopes.get(context) === scope) {
62
84
  dispatchScopes.delete(context);
@@ -144,14 +166,15 @@ class DefaultHandlerInstanceScope implements ZLinkHandlerInstanceScope {
144
166
  if (existing !== undefined) return existing;
145
167
  const activation = createDeferred<unknown>();
146
168
  this.instances.set(type, activation.promise);
147
- void this.activate(type, activation);
169
+ this.activate(type, activation);
148
170
  return activation.promise as Promise<T>;
149
171
  }
150
172
 
151
173
  async dispose(): Promise<void> {
152
174
  if (this.disposed) return;
153
175
  this.disposed = true;
154
- await Promise.allSettled(this.instances.values());
176
+ if (this.owned.length !== this.instances.size)
177
+ await Promise.allSettled(this.instances.values());
155
178
  try {
156
179
  await disposeOwnedInstances(this.owned);
157
180
  } finally {
@@ -159,21 +182,43 @@ class DefaultHandlerInstanceScope implements ZLinkHandlerInstanceScope {
159
182
  this.instances.clear();
160
183
  }
161
184
  }
162
- private async activate<T>(type: Type<T>, activation: Deferred<unknown>): Promise<void> {
163
- let instance: T;
185
+ private activate<T>(type: Type<T>, activation: Deferred<unknown>): void {
164
186
  try {
165
187
  const created = this.providerResolver?.create?.(type);
166
- instance = created === undefined ? new type() : await created;
188
+ if (created === undefined) {
189
+ this.completeActivation(new type(), activation);
190
+ } else {
191
+ void this.activatePending(created, activation);
192
+ }
167
193
  } catch (error) {
168
194
  activation.reject(error);
169
- return;
170
195
  }
196
+ }
171
197
 
198
+ private async activatePending<T>(
199
+ created: T | Promise<T>,
200
+ activation: Deferred<unknown>
201
+ ): Promise<void> {
202
+ try {
203
+ this.completeActivation(await created, activation);
204
+ } catch (error) {
205
+ activation.reject(error);
206
+ }
207
+ }
208
+
209
+ private completeActivation(instance: unknown, activation: Deferred<unknown>): void {
172
210
  if (!this.disposed) {
173
211
  this.owned.push(instance);
174
212
  activation.resolve(instance);
175
213
  return;
176
214
  }
215
+ void this.disposeLateActivation(instance, activation);
216
+ }
217
+
218
+ private async disposeLateActivation(
219
+ instance: unknown,
220
+ activation: Deferred<unknown>
221
+ ): Promise<void> {
177
222
  try {
178
223
  await disposeOwnedInstance(instance);
179
224
  activation.reject(new Error('Handler instance scope was disposed during activation.'));
@@ -306,6 +351,11 @@ function startOutsideLifecycleInvocation<T>(work: () => T): T {
306
351
  }
307
352
 
308
353
  export async function disposeOwnedInstance(instance: unknown): Promise<void> {
354
+ const cleanup = handlerInstanceCleanup(instance);
355
+ if (cleanup !== undefined) await cleanup.call(instance);
356
+ }
357
+
358
+ export function handlerInstanceCleanup(instance: unknown): (() => unknown) | undefined {
309
359
  if (instance === null || instance === undefined) return;
310
360
  const value = instance as {
311
361
  dispose?: () => unknown;
@@ -313,12 +363,13 @@ export async function disposeOwnedInstance(instance: unknown): Promise<void> {
313
363
  onModuleDestroy?: () => unknown;
314
364
  };
315
365
  if (typeof value.dispose === 'function') {
316
- await value.dispose();
366
+ return value.dispose;
317
367
  } else if (typeof value.close === 'function') {
318
- await value.close();
368
+ return value.close;
319
369
  } else if (typeof value.onModuleDestroy === 'function') {
320
- await value.onModuleDestroy();
370
+ return value.onModuleDestroy;
321
371
  }
372
+ return undefined;
322
373
  }
323
374
 
324
375
  export async function disposeOwnedInstances(instances: readonly unknown[]): Promise<void> {
@@ -276,7 +276,15 @@ export class ZLinkActorRuntimeOptionsFactory {
276
276
  staleActorRefPredicate: (meshName, actor) =>
277
277
  this.actorBelongsToMesh(meshName, actor.actorId) &&
278
278
  this.options.actorHandoff.isKnownStale(actor),
279
- handoffCapture: (meshName, actorId, parts, returnResponse, actor, deadlineUnixMs) =>
279
+ handoffCapture: (
280
+ meshName,
281
+ actorId,
282
+ parts,
283
+ returnResponse,
284
+ actor,
285
+ deadlineUnixMs,
286
+ onAdmitted
287
+ ) =>
280
288
  this.actorBelongsToMesh(meshName, actorId) &&
281
289
  !this.options.actorHandoff.isProvisional(actorId)
282
290
  ? this.options.actorHandoff.capture(
@@ -286,7 +294,10 @@ export class ZLinkActorRuntimeOptionsFactory {
286
294
  returnResponse,
287
295
  undefined,
288
296
  actor,
289
- deadlineUnixMs
297
+ deadlineUnixMs,
298
+ undefined,
299
+ undefined,
300
+ onAdmitted
290
301
  )
291
302
  : undefined,
292
303
  sendErrorReporter: this.options.reportPostCommitError
@@ -15,6 +15,7 @@ import { availableParallelism } from 'node:os';
15
15
  import type {
16
16
  ApplicationJobOrigin,
17
17
  ApplicationJobPermitPort,
18
+ ApplicationJobReceiveRotationPort,
18
19
  ApplicationJobQueuePort
19
20
  } from '../application-jobs/contracts';
20
21
  import {
@@ -122,13 +123,42 @@ export function resolveApplicationJobQueueConfiguration(
122
123
  });
123
124
  }
124
125
 
126
+ const enum QueuePermitCount {
127
+ Reserved,
128
+ Queued,
129
+ Peak,
130
+ Size
131
+ }
132
+
125
133
  export class ApplicationJobQueuePermit implements ApplicationJobPermitPort {
126
- private state: 'reserved' | 'queued' | 'released' = 'reserved';
134
+ detachedForHandlerTurn = false;
135
+ private state: 'idle' | 'reserved' | 'queued' | 'released';
127
136
 
128
137
  constructor(
129
138
  private readonly owner: ApplicationJobQueue,
130
- readonly origin: ApplicationJobOrigin
131
- ) {}
139
+ readonly origin: ApplicationJobOrigin,
140
+ private readonly reusable = false
141
+ ) {
142
+ this.state = reusable ? 'idle' : 'reserved';
143
+ }
144
+
145
+ reserveStorage(): boolean {
146
+ if (this.state !== 'idle') return false;
147
+ this.state = 'reserved';
148
+ this.detachedForHandlerTurn = false;
149
+ return true;
150
+ }
151
+
152
+ releaseStorage(): void {
153
+ if (!this.reusable || this.state === 'idle') return;
154
+ if (this.state !== 'released')
155
+ throw new Error('Reservation storage still owns queue capacity.');
156
+ this.state = 'idle';
157
+ }
158
+
159
+ detachForHandlerTurn(): void {
160
+ this.detachedForHandlerTurn = true;
161
+ }
132
162
 
133
163
  markApplicationQueued(): void {
134
164
  if (this.state !== 'reserved') {
@@ -140,17 +170,73 @@ export class ApplicationJobQueuePermit implements ApplicationJobPermitPort {
140
170
 
141
171
  releaseBeforeHandler(): void {
142
172
  if (this.owner.shouldHoldPermitBeforeHandler()) return;
143
- this.release();
173
+ this.owner.releasePermit(this);
144
174
  }
145
175
 
146
176
  releaseAfterInternalProcessing(): void {
147
- this.release();
177
+ this.owner.releasePermit(this);
148
178
  }
149
179
 
150
- private release(): void {
151
- if (this.state === 'released') return;
152
- this.owner.release(this.state);
180
+ takeReleaseState(): 'reserved' | 'queued' | undefined {
181
+ if (this.state === 'released' || this.state === 'idle') return undefined;
182
+ const state = this.state;
153
183
  this.state = 'released';
184
+ return state;
185
+ }
186
+ }
187
+
188
+ /** Connection-owned storage; queue accounting remains with the host queue. */
189
+ class ApplicationJobReceiveRotation implements ApplicationJobReceiveRotationPort {
190
+ private readonly storage: ApplicationJobQueuePermit[] = [];
191
+ private readonly grants: (ApplicationJobQueuePermit | undefined)[];
192
+ private granted = 0;
193
+ private consumed = 0;
194
+
195
+ constructor(
196
+ private readonly owner: ApplicationJobQueue,
197
+ private readonly capacity: number,
198
+ private readonly origin: ApplicationJobOrigin
199
+ ) {
200
+ this.grants = new Array<ApplicationJobQueuePermit | undefined>(capacity);
201
+ this.prepareStorage();
202
+ }
203
+
204
+ private prepareStorage(): void {
205
+ for (let index = 0; index < this.capacity; index++)
206
+ this.storage.push(new ApplicationJobQueuePermit(this.owner, this.origin, true));
207
+ }
208
+
209
+ reserve(): void {
210
+ this.releaseUnused();
211
+ const count = this.owner.receiveRotationCapacity(this.capacity);
212
+ if (count === 0) return;
213
+ for (let index = 0; index < this.storage.length; index++) {
214
+ const permit = this.storage[index]!;
215
+ if (permit.reserveStorage()) this.grants[this.granted++] = permit;
216
+ if (this.granted === count) break;
217
+ }
218
+ if (this.granted < count) {
219
+ const start = this.storage.length;
220
+ this.prepareStorage();
221
+ for (let index = start; this.granted < count; index++) {
222
+ const permit = this.storage[index]!;
223
+ permit.reserveStorage();
224
+ this.grants[this.granted++] = permit;
225
+ }
226
+ }
227
+ this.owner.reserveReceiveRotation(count);
228
+ }
229
+
230
+ take(): ApplicationJobQueuePermit | undefined {
231
+ if (this.consumed === this.granted) return undefined;
232
+ return this.grants[this.consumed++];
233
+ }
234
+
235
+ releaseUnused(): void {
236
+ this.owner.releaseUnusedReceiveRotation(this.grants, this.consumed, this.granted);
237
+ // Keep the prepared grant slots and reset only the logical count.
238
+ this.granted = 0;
239
+ this.consumed = 0;
154
240
  }
155
241
  }
156
242
 
@@ -173,9 +259,11 @@ interface CapacityWaiter {
173
259
  export class ApplicationJobQueue implements ApplicationJobQueuePort {
174
260
  private localWaiters = 0;
175
261
  private localBacklogLogged = false;
176
- private reservedSupplyPermits = 0n;
177
- private queuedApplicationJobs = 0n;
178
- private peakPermitsInUse = 0n;
262
+ // The contract bounds capacity by INT32_MAX; public snapshots remain bigint.
263
+ private readonly permitCounts = new Uint32Array(QueuePermitCount.Size);
264
+ private readonly limitCount: number;
265
+ private readonly pauseCount: number;
266
+ private readonly resumeCount: number;
179
267
  private capacityWaitCount = 0n;
180
268
  private capacityWaitDurationSeconds = 0;
181
269
  private metricsEpoch = 0n;
@@ -203,6 +291,9 @@ export class ApplicationJobQueue implements ApplicationJobQueuePort {
203
291
  private readonly handlerStartGate?: () => boolean,
204
292
  private readonly loggerFailureReporter?: (error: unknown) => void
205
293
  ) {
294
+ this.limitCount = Number(configuration.effectiveMaxQueuedApplicationJobs);
295
+ this.pauseCount = Number(configuration.pausePermitCount);
296
+ this.resumeCount = Number(configuration.resumePermitCount);
206
297
  this.receiveFlowController = new ApplicationJobReceiveFlowController(this, (state) => state);
207
298
  }
208
299
 
@@ -210,6 +301,24 @@ export class ApplicationJobQueue implements ApplicationJobQueuePort {
210
301
  return this.handlerStartGate?.() === true;
211
302
  }
212
303
 
304
+ createReceiveRotation(
305
+ capacity: number,
306
+ origin: ApplicationJobOrigin
307
+ ): ApplicationJobReceiveRotationPort {
308
+ if (!Number.isSafeInteger(capacity) || capacity < 1)
309
+ throw new RangeError('Receive capacity must be positive.');
310
+ return new ApplicationJobReceiveRotation(this, capacity, origin);
311
+ }
312
+
313
+ receiveRotationCapacity(capacity: number): number {
314
+ if (this.waiters.length !== 0) return 0;
315
+ return Math.min(capacity, this.limitCount - this.permitsInUse());
316
+ }
317
+
318
+ reserveReceiveRotation(count: number): void {
319
+ this.reserveSupply(count);
320
+ }
321
+
213
322
  registerReceiveFlowTarget(
214
323
  identity: object,
215
324
  applyState: (state: ApplicationJobQueuePressureState) => void,
@@ -272,7 +381,7 @@ export class ApplicationJobQueue implements ApplicationJobQueuePort {
272
381
  reject(abortReason(signal));
273
382
  return undefined;
274
383
  }
275
- if (this.waiters.length === 0 && this.permitsInUse() < this.limit()) {
384
+ if (this.waiters.length === 0 && this.permitsInUse() < this.limitCount) {
276
385
  return this.reserve(origin);
277
386
  }
278
387
 
@@ -304,10 +413,10 @@ export class ApplicationJobQueue implements ApplicationJobQueuePort {
304
413
  const now = this.nowMs();
305
414
  return Object.freeze({
306
415
  ...this.configuration,
307
- reservedSupplyPermits: this.reservedSupplyPermits,
308
- queuedApplicationJobs: this.queuedApplicationJobs,
309
- permitsInUse,
310
- peakPermitsInUse: this.peakPermitsInUse,
416
+ reservedSupplyPermits: BigInt(this.permitCounts[QueuePermitCount.Reserved]!),
417
+ queuedApplicationJobs: BigInt(this.permitCounts[QueuePermitCount.Queued]!),
418
+ permitsInUse: BigInt(permitsInUse),
419
+ peakPermitsInUse: BigInt(this.permitCounts[QueuePermitCount.Peak]!),
311
420
  capacityWaiters: BigInt(this.waiters.length),
312
421
  capacityWaitCount: this.capacityWaitCount,
313
422
  capacityWaitDurationSeconds: this.capacityWaitDurationSeconds,
@@ -323,7 +432,7 @@ export class ApplicationJobQueue implements ApplicationJobQueuePort {
323
432
 
324
433
  resetMetrics(): void {
325
434
  this.metricsEpoch += 1n;
326
- this.peakPermitsInUse = this.permitsInUse();
435
+ this.permitCounts[QueuePermitCount.Peak] = this.permitsInUse();
327
436
  this.capacityWaitCount = 0n;
328
437
  this.capacityWaitDurationSeconds = 0;
329
438
  this.runningTransitionCount = 0n;
@@ -357,25 +466,42 @@ export class ApplicationJobQueue implements ApplicationJobQueuePort {
357
466
  }
358
467
 
359
468
  markQueued(): void {
360
- if (this.reservedSupplyPermits === 0n) {
469
+ if (this.permitCounts[QueuePermitCount.Reserved] === 0) {
361
470
  throw new Error('Application job queue has no reserved supply permit.');
362
471
  }
363
- this.reservedSupplyPermits -= 1n;
364
- this.queuedApplicationJobs += 1n;
472
+ this.permitCounts[QueuePermitCount.Reserved] =
473
+ this.permitCounts[QueuePermitCount.Reserved]! - 1;
474
+ this.permitCounts[QueuePermitCount.Queued] = this.permitCounts[QueuePermitCount.Queued]! + 1;
475
+ }
476
+
477
+ releasePermit(permit: ApplicationJobQueuePermit): void {
478
+ const state = permit.takeReleaseState();
479
+ if (state !== undefined) this.release(state);
480
+ }
481
+
482
+ releaseUnusedReceiveRotation(
483
+ grants: readonly (ApplicationJobQueuePermit | undefined)[],
484
+ consumed: number,
485
+ granted: number
486
+ ): void {
487
+ const count = granted - consumed;
488
+ if (count === 0) return;
489
+ // Unconsumed grants still belong to this receive round; no record has acquired them.
490
+ for (let index = consumed; index < granted; index++) {
491
+ const permit = grants[index]!;
492
+ permit.takeReleaseState();
493
+ permit.releaseStorage();
494
+ }
495
+ this.release('reserved', count);
365
496
  }
366
497
 
367
- release(state: 'reserved' | 'queued'): void {
368
- if (state === 'reserved') {
369
- if (this.reservedSupplyPermits === 0n) {
370
- throw new Error('Application job queue reserved permit accounting underflow.');
371
- }
372
- this.reservedSupplyPermits -= 1n;
373
- } else {
374
- if (this.queuedApplicationJobs === 0n) {
375
- throw new Error('Application job queue queued permit accounting underflow.');
376
- }
377
- this.queuedApplicationJobs -= 1n;
498
+ release(state: 'reserved' | 'queued', count = 1): void {
499
+ const index = state === 'reserved' ? QueuePermitCount.Reserved : QueuePermitCount.Queued;
500
+ const available = this.permitCounts[index]!;
501
+ if (available < count) {
502
+ throw new Error(`Application job queue ${state} permit accounting underflow.`);
378
503
  }
504
+ this.permitCounts[index] = available - count;
379
505
  this.drainWaiters();
380
506
  this.evaluatePressure();
381
507
  }
@@ -384,23 +510,32 @@ export class ApplicationJobQueue implements ApplicationJobQueuePort {
384
510
  return this.configuration.effectiveMaxQueuedApplicationJobs;
385
511
  }
386
512
 
387
- private permitsInUse(): bigint {
388
- return this.reservedSupplyPermits + this.queuedApplicationJobs;
513
+ private permitsInUse(): number {
514
+ return (
515
+ this.permitCounts[QueuePermitCount.Reserved]! + this.permitCounts[QueuePermitCount.Queued]!
516
+ );
517
+ }
518
+
519
+ private reserveSupply(count: number, evaluatePressure = true): void {
520
+ this.permitCounts[QueuePermitCount.Reserved] =
521
+ this.permitCounts[QueuePermitCount.Reserved]! + count;
522
+ this.permitCounts[QueuePermitCount.Peak] = Math.max(
523
+ this.permitCounts[QueuePermitCount.Peak]!,
524
+ this.permitsInUse()
525
+ );
526
+ if (evaluatePressure) this.evaluatePressure();
389
527
  }
390
528
 
391
529
  private reserve(
392
530
  origin: ApplicationJobOrigin,
393
531
  evaluatePressure = true
394
532
  ): ApplicationJobQueuePermit {
395
- this.reservedSupplyPermits += 1n;
396
- const current = this.permitsInUse();
397
- if (current > this.peakPermitsInUse) this.peakPermitsInUse = current;
398
- if (evaluatePressure) this.evaluatePressure();
533
+ this.reserveSupply(1, evaluatePressure);
399
534
  return new ApplicationJobQueuePermit(this, origin);
400
535
  }
401
536
 
402
537
  private drainWaiters(): void {
403
- while (this.waiters.length > 0 && this.permitsInUse() < this.limit()) {
538
+ while (this.waiters.length > 0 && this.permitsInUse() < this.limitCount) {
404
539
  const waiter = this.waiters.shift()!;
405
540
  if (!waiter.active) continue;
406
541
  waiter.active = false;
@@ -460,13 +595,12 @@ export class ApplicationJobQueue implements ApplicationJobQueuePort {
460
595
  }
461
596
 
462
597
  private evaluatePressure(): void {
463
- const permitsInUse = this.permitsInUse();
464
598
  const next =
465
599
  this.pressureStateValue === 'running'
466
- ? permitsInUse >= this.configuration.pausePermitCount
600
+ ? this.permitsInUse() >= this.pauseCount
467
601
  ? 'paused'
468
602
  : 'running'
469
- : permitsInUse <= this.configuration.resumePermitCount
603
+ : this.permitsInUse() <= this.resumeCount
470
604
  ? 'running'
471
605
  : 'paused';
472
606
  if (next === this.pressureStateValue) return;