@zlink-systems/framework 0.30.1 → 0.30.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +6 -0
- package/dist/contracts/Common/ZLinkEncodedPayload.js +18 -3
- package/dist/contracts/Common/encoded-payload-storage.d.ts +1 -1
- package/dist/contracts/Common/encoded-payload-storage.js +5 -2
- package/dist/contracts/Configuration/Builders.d.ts +1 -1
- package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +2 -1
- package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +5 -1
- package/dist/contracts/Configuration/RegistrationBuilders.js +2 -2
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -0
- package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +2 -2
- package/dist/contracts/Locations/Rows.d.ts +2 -0
- package/dist/contracts/Spots/Contracts.d.ts +4 -0
- package/dist/contracts/Spots/ZLinkSpot.d.ts +3 -3
- package/dist/runtime/abort.d.ts +5 -0
- package/dist/runtime/abort.js +10 -0
- package/dist/runtime/actors/actor-authority-publication.js +3 -2
- package/dist/runtime/actors/actor-client.d.ts +0 -1
- package/dist/runtime/actors/actor-client.js +38 -45
- package/dist/runtime/actors/actor-context.d.ts +2 -0
- package/dist/runtime/actors/actor-context.js +46 -9
- package/dist/runtime/actors/actor-handoff.d.ts +7 -3
- package/dist/runtime/actors/actor-handoff.js +212 -88
- package/dist/runtime/actors/actor-join-relocation.d.ts +2 -0
- package/dist/runtime/actors/actor-local-native-join.js +4 -0
- package/dist/runtime/actors/actor-mailbox.js +27 -1
- package/dist/runtime/actors/actor-remote-joiner.js +3 -1
- package/dist/runtime/actors/actor-reply.d.ts +4 -0
- package/dist/runtime/actors/actor-reply.js +29 -0
- package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -0
- package/dist/runtime/actors/actor-runtime-state.js +2 -20
- package/dist/runtime/actors/actor-source-transfer.d.ts +1 -17
- package/dist/runtime/actors/index.d.ts +6 -2
- package/dist/runtime/actors/index.js +37 -21
- package/dist/runtime/actors/session-disconnected-wire.d.ts +8 -0
- package/dist/runtime/actors/session-disconnected-wire.js +48 -0
- package/dist/runtime/admission.d.ts +9 -1
- package/dist/runtime/admission.js +55 -32
- package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +13 -0
- package/dist/runtime/application-jobs/application-job-queue-scope.js +27 -1
- package/dist/runtime/application-jobs/contracts.d.ts +2 -0
- package/dist/runtime/backend/contracts/index.d.ts +19 -3
- package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -2
- package/dist/runtime/backend/mesh-completion-table.js +5 -0
- package/dist/runtime/backend/mesh-dispatch-pump.d.ts +26 -2
- package/dist/runtime/backend/mesh-dispatch-pump.js +193 -107
- package/dist/runtime/backend/node/node-raw-binding-port.js +90 -58
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +33 -8
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +142 -143
- package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +1 -1
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +5 -5
- package/dist/runtime/channels/channel-clients.d.ts +1 -0
- package/dist/runtime/channels/channel-clients.js +20 -5
- package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +22 -3
- package/dist/runtime/channels/channel-dispatch-pipeline.js +103 -57
- package/dist/runtime/channels/channel-dispatchers.d.ts +3 -2
- package/dist/runtime/channels/channel-dispatchers.js +44 -37
- package/dist/runtime/channels/channel-envelope.d.ts +1 -0
- package/dist/runtime/channels/channel-envelope.js +74 -31
- package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +4 -3
- package/dist/runtime/channels/channel-runtime-lifecycle.js +19 -24
- package/dist/runtime/channels/channel-runtime-manager.d.ts +3 -2
- package/dist/runtime/channels/channel-runtime-manager.js +4 -4
- package/dist/runtime/channels/channel-transports.d.ts +0 -1
- package/dist/runtime/channels/channel-transports.js +35 -33
- package/dist/runtime/channels/client-server-location-runtime.js +5 -4
- package/dist/runtime/channels/dispatch-error-reporter.d.ts +2 -1
- package/dist/runtime/channels/dispatch-error-reporter.js +2 -1
- package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
- package/dist/runtime/channels/fanout-location-runtime.js +3 -3
- package/dist/runtime/diagnostics/flow-context.js +19 -7
- package/dist/runtime/diagnostics/index.js +4 -9
- package/dist/runtime/diagnostics/message-flow.d.ts +8 -0
- package/dist/runtime/diagnostics/message-flow.js +35 -5
- package/dist/runtime/diagnostics/runtime-metrics.d.ts +2 -2
- package/dist/runtime/diagnostics/runtime-metrics.js +10 -8
- package/dist/runtime/execution/index.d.ts +4 -2
- package/dist/runtime/execution/index.js +33 -10
- package/dist/runtime/execution/serial-execution-queue.d.ts +4 -0
- package/dist/runtime/execution/serial-execution-queue.js +21 -2
- package/dist/runtime/execution/state-lane.d.ts +2 -0
- package/dist/runtime/execution/state-lane.js +5 -0
- package/dist/runtime/foundation/operation-registry.d.ts +25 -1
- package/dist/runtime/foundation/operation-registry.js +86 -18
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +39 -3
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +151 -55
- package/dist/runtime/foundation/service-liveness-registry.d.ts +12 -1
- package/dist/runtime/foundation/service-liveness-registry.js +38 -0
- package/dist/runtime/foundation/service-mailbox.d.ts +7 -0
- package/dist/runtime/foundation/service-maintenance-runtime.js +1 -6
- package/dist/runtime/foundation/service-relocation-object-owner.d.ts +2 -3
- package/dist/runtime/foundation/service-relocation-object-owner.js +48 -35
- package/dist/runtime/foundation/service-relocation-runtime.js +7 -3
- package/dist/runtime/foundation/service-runtime-contracts.d.ts +8 -1
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +2 -1
- package/dist/runtime/foundation/service-stateful-registry.d.ts +5 -4
- package/dist/runtime/foundation/service-stateful-registry.js +24 -26
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +72 -6
- package/dist/runtime/foundation/service-stateful-runtime.js +444 -117
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +14 -1
- package/dist/runtime/foundation/service-stateful-wire-codec.js +48 -27
- package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +6 -1
- package/dist/runtime/foundation/service-wire-binary-primitives.js +27 -11
- package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
- package/dist/runtime/foundation/service-wire-constants.generated.js +1 -0
- package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +10 -0
- package/dist/runtime/foundation/service-wire-m6a-codec.js +166 -53
- package/dist/runtime/host/actor-packet-relay.d.ts +6 -4
- package/dist/runtime/host/actor-packet-relay.js +59 -72
- package/dist/runtime/host/actor-placement-coordinator.js +25 -8
- package/dist/runtime/host/actor-transfer-runtime.d.ts +7 -31
- package/dist/runtime/host/actor-transfer-runtime.js +85 -331
- package/dist/runtime/host/application-job-queue.d.ts +24 -3
- package/dist/runtime/host/application-job-queue.js +28 -41
- package/dist/runtime/host/index.d.ts +5 -1
- package/dist/runtime/host/index.js +171 -97
- package/dist/runtime/host/location-runtime-owner.js +2 -6
- package/dist/runtime/host/mesh-router-resolver.d.ts +4 -0
- package/dist/runtime/host/mesh-router-resolver.js +14 -6
- package/dist/runtime/host/remote-bound-session-relay.d.ts +2 -4
- package/dist/runtime/host/remote-bound-session-relay.js +71 -190
- package/dist/runtime/host/route-mesh-runtime.d.ts +2 -2
- package/dist/runtime/host/route-mesh-runtime.js +5 -3
- package/dist/runtime/host/runtime-shutdown.d.ts +1 -0
- package/dist/runtime/host/runtime-shutdown.js +3 -2
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +17 -7
- package/dist/runtime/host/service-relocation-host-runtime.js +550 -367
- package/dist/runtime/host/spot-runtime-options-factory.js +15 -7
- package/dist/runtime/host/user-spot-creation-coordinator.js +33 -84
- package/dist/runtime/locations/auto-connect-loop.d.ts +2 -0
- package/dist/runtime/locations/auto-connect-loop.js +22 -14
- package/dist/runtime/locations/auto-connect-reconciler.js +0 -6
- package/dist/runtime/locations/auto-connect-types.d.ts +0 -1
- package/dist/runtime/locations/descriptor-publication.d.ts +4 -0
- package/dist/runtime/locations/descriptor-publication.js +11 -0
- package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
- package/dist/runtime/locations/in-memory-authority-store.d.ts +7 -1
- package/dist/runtime/locations/in-memory-authority-store.js +56 -19
- package/dist/runtime/locations/in-memory-location-store.js +1 -10
- package/dist/runtime/locations/index.d.ts +1 -0
- package/dist/runtime/locations/index.js +1 -0
- package/dist/runtime/locations/lease-tracker.js +1 -6
- package/dist/runtime/locations/location-store-repository.d.ts +51 -1
- package/dist/runtime/locations/location-store-repository.js +363 -139
- package/dist/runtime/locations/relocation-blob.d.ts +18 -1
- package/dist/runtime/locations/relocation-blob.js +52 -1
- package/dist/runtime/locations/request-source-resolver.d.ts +37 -0
- package/dist/runtime/locations/request-source-resolver.js +80 -0
- package/dist/runtime/locations/resolvers.js +1 -1
- package/dist/runtime/locations/runtime.d.ts +6 -2
- package/dist/runtime/locations/runtime.js +37 -30
- package/dist/runtime/messaging/payload-codec.d.ts +7 -1
- package/dist/runtime/messaging/payload-codec.js +7 -6
- package/dist/runtime/messaging/request-result.js +29 -26
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +19 -1
- package/dist/runtime/protocol/service_wire_codec.generated.js +85 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +7 -1
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +23 -7
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +3 -2
- package/dist/runtime/spots/index.d.ts +18 -11
- package/dist/runtime/spots/index.js +234 -176
- package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
- package/dist/runtime/spots/spot-activation-registry.js +21 -11
- package/dist/runtime/spots/spot-activation-state.d.ts +1 -1
- package/dist/runtime/spots/spot-activation-state.js +7 -7
- package/dist/runtime/spots/spot-activation.d.ts +6 -3
- package/dist/runtime/spots/spot-activation.js +123 -44
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -0
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +13 -22
- package/dist/runtime/spots/spot-actor-membership.d.ts +0 -1
- package/dist/runtime/spots/spot-actor-membership.js +0 -8
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +33 -8
- package/dist/runtime/spots/spot-actor-packet-drain.js +5 -33
- package/dist/runtime/spots/spot-entry-activation.d.ts +2 -0
- package/dist/runtime/spots/spot-entry-activation.js +14 -9
- package/dist/runtime/spots/spot-handler-registry.d.ts +4 -3
- package/dist/runtime/spots/spot-handler-registry.js +6 -2
- package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +2 -2
- package/dist/runtime/spots/spot-manager-public.js +2 -2
- package/dist/runtime/spots/spot-node-autoconnect.d.ts +2 -1
- package/dist/runtime/spots/spot-node-autoconnect.js +18 -39
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +19 -2
- package/dist/runtime/spots/spot-node-runtime-manager.js +115 -50
- package/dist/runtime/spots/spot-outbound.js +3 -3
- package/dist/runtime/spots/spot-remote-codec.js +5 -1
- package/dist/runtime/spots/spot-runtime-ports.d.ts +0 -1
- package/dist/runtime/spots/spot-serial-executor.d.ts +10 -0
- package/dist/runtime/spots/spot-serial-executor.js +61 -8
- package/dist/runtime/spots/spot-serial-turn-executor.js +19 -2
- package/dist/runtime/spots/spot-subscription-dispatch.js +1 -1
- package/dist/runtime/spots/spot-timer.d.ts +57 -5
- package/dist/runtime/spots/spot-timer.js +287 -103
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +42 -11
- package/dist/runtime/streams/actor-session-binding-registry.js +165 -48
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +8 -4
- package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -1
- package/dist/runtime/streams/bound-actor-relay-sender.js +15 -8
- package/dist/runtime/streams/bound-session-service.d.ts +1 -1
- package/dist/runtime/streams/bound-session-service.js +6 -11
- package/dist/runtime/streams/index.d.ts +3 -2
- package/dist/runtime/streams/index.js +6 -4
- package/dist/runtime/streams/managed-stream.js +3 -2
- package/dist/runtime/streams/native-fallback-bound-session.js +8 -73
- package/dist/runtime/streams/session-actor-coordinator.d.ts +2 -8
- package/dist/runtime/streams/session-actor-coordinator.js +15 -32
- package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +3 -10
- package/dist/runtime/streams/stream-session-runtime.js +1 -4
- package/dist/runtime/workers/index.js +1 -1
- package/package.json +3 -3
- package/src/contracts/Common/ZLinkEncodedPayload.ts +24 -4
- package/src/contracts/Common/encoded-payload-storage.ts +6 -3
- package/src/contracts/Configuration/Builders.ts +4 -1
- package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +7 -2
- package/src/contracts/Configuration/RegistrationBuilders.ts +6 -2
- package/src/contracts/Configuration/RegistrationTypes.ts +1 -0
- package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -1
- package/src/contracts/Locations/Rows.ts +2 -0
- package/src/contracts/Spots/Contracts.ts +8 -0
- package/src/contracts/Spots/ZLinkSpot.ts +3 -3
- package/src/runtime/abort.ts +12 -0
- package/src/runtime/actors/actor-authority-publication.ts +3 -2
- package/src/runtime/actors/actor-client.ts +61 -70
- package/src/runtime/actors/actor-context.ts +49 -9
- package/src/runtime/actors/actor-handoff.ts +282 -106
- package/src/runtime/actors/actor-join-relocation.ts +2 -0
- package/src/runtime/actors/actor-local-native-join.ts +4 -0
- package/src/runtime/actors/actor-mailbox.ts +40 -2
- package/src/runtime/actors/actor-remote-joiner.ts +6 -1
- package/src/runtime/actors/actor-reply.ts +42 -0
- package/src/runtime/actors/actor-runtime-contracts.ts +2 -0
- package/src/runtime/actors/actor-runtime-state.ts +2 -20
- package/src/runtime/actors/actor-source-transfer.ts +1 -34
- package/src/runtime/actors/index.ts +41 -27
- package/src/runtime/actors/session-disconnected-wire.ts +66 -0
- package/src/runtime/admission.ts +69 -34
- package/src/runtime/application-jobs/application-job-queue-scope.ts +33 -1
- package/src/runtime/application-jobs/contracts.ts +2 -0
- package/src/runtime/backend/contracts/index.ts +39 -4
- package/src/runtime/backend/mesh-actor-session-node-adapter.ts +5 -3
- package/src/runtime/backend/mesh-completion-table.ts +4 -0
- package/src/runtime/backend/mesh-dispatch-pump.ts +223 -124
- package/src/runtime/backend/node/node-raw-binding-port.ts +106 -70
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +221 -170
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +5 -5
- package/src/runtime/channels/channel-clients.ts +49 -24
- package/src/runtime/channels/channel-dispatch-pipeline.ts +173 -124
- package/src/runtime/channels/channel-dispatchers.ts +116 -72
- package/src/runtime/channels/channel-envelope.ts +105 -36
- package/src/runtime/channels/channel-runtime-lifecycle.ts +13 -13
- package/src/runtime/channels/channel-runtime-manager.ts +12 -5
- package/src/runtime/channels/channel-transports.ts +49 -58
- package/src/runtime/channels/client-server-location-runtime.ts +11 -10
- package/src/runtime/channels/dispatch-error-reporter.ts +4 -2
- package/src/runtime/channels/fanout-location-runtime.ts +17 -9
- package/src/runtime/diagnostics/flow-context.ts +20 -7
- package/src/runtime/diagnostics/index.ts +1 -7
- package/src/runtime/diagnostics/message-flow.ts +47 -9
- package/src/runtime/diagnostics/runtime-metrics.ts +12 -10
- package/src/runtime/execution/index.ts +40 -14
- package/src/runtime/execution/serial-execution-queue.ts +31 -4
- package/src/runtime/execution/state-lane.ts +7 -0
- package/src/runtime/foundation/operation-registry.ts +98 -20
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +244 -67
- package/src/runtime/foundation/service-liveness-registry.ts +39 -0
- package/src/runtime/foundation/service-mailbox.ts +8 -0
- package/src/runtime/foundation/service-maintenance-runtime.ts +1 -8
- package/src/runtime/foundation/service-relocation-object-owner.ts +54 -37
- package/src/runtime/foundation/service-relocation-runtime.ts +7 -3
- package/src/runtime/foundation/service-runtime-contracts.ts +12 -1
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -1
- package/src/runtime/foundation/service-stateful-registry.ts +38 -35
- package/src/runtime/foundation/service-stateful-runtime.ts +667 -152
- package/src/runtime/foundation/service-stateful-wire-codec.ts +49 -11
- package/src/runtime/foundation/service-wire-binary-primitives.ts +35 -12
- package/src/runtime/foundation/service-wire-constants.generated.ts +1 -0
- package/src/runtime/foundation/service-wire-m6a-codec.ts +187 -51
- package/src/runtime/host/actor-packet-relay.ts +113 -94
- package/src/runtime/host/actor-placement-coordinator.ts +31 -8
- package/src/runtime/host/actor-transfer-runtime.ts +104 -430
- package/src/runtime/host/application-job-queue.ts +29 -44
- package/src/runtime/host/index.ts +286 -129
- package/src/runtime/host/location-runtime-owner.ts +2 -6
- package/src/runtime/host/mesh-router-resolver.ts +13 -5
- package/src/runtime/host/remote-bound-session-relay.ts +86 -248
- package/src/runtime/host/route-mesh-runtime.ts +11 -5
- package/src/runtime/host/runtime-shutdown.ts +15 -4
- package/src/runtime/host/service-relocation-host-runtime.ts +784 -475
- package/src/runtime/host/spot-runtime-options-factory.ts +18 -7
- package/src/runtime/host/user-spot-creation-coordinator.ts +41 -100
- package/src/runtime/locations/auto-connect-loop.ts +22 -14
- package/src/runtime/locations/auto-connect-reconciler.ts +0 -6
- package/src/runtime/locations/auto-connect-types.ts +0 -1
- package/src/runtime/locations/descriptor-publication.ts +7 -0
- package/src/runtime/locations/domain-store-contract.ts +5 -0
- package/src/runtime/locations/in-memory-authority-store.ts +85 -23
- package/src/runtime/locations/in-memory-location-store.ts +1 -12
- package/src/runtime/locations/index.ts +1 -0
- package/src/runtime/locations/lease-tracker.ts +2 -9
- package/src/runtime/locations/location-store-repository.ts +628 -152
- package/src/runtime/locations/relocation-blob.ts +75 -1
- package/src/runtime/locations/request-source-resolver.ts +138 -0
- package/src/runtime/locations/resolvers.ts +2 -2
- package/src/runtime/locations/runtime.ts +70 -40
- package/src/runtime/messaging/payload-codec.ts +8 -11
- package/src/runtime/messaging/request-result.ts +33 -29
- package/src/runtime/protocol/service_wire_codec.generated.ts +87 -4
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +13 -10
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +3 -2
- package/src/runtime/spots/index.ts +375 -281
- package/src/runtime/spots/spot-activation-registry.ts +25 -13
- package/src/runtime/spots/spot-activation-state.ts +12 -19
- package/src/runtime/spots/spot-activation.ts +170 -86
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +25 -55
- package/src/runtime/spots/spot-actor-membership.ts +0 -15
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +56 -11
- package/src/runtime/spots/spot-actor-packet-drain.ts +9 -52
- package/src/runtime/spots/spot-entry-activation.ts +24 -19
- package/src/runtime/spots/spot-handler-registry.ts +15 -4
- package/src/runtime/spots/spot-manager-internal-contracts.ts +2 -2
- package/src/runtime/spots/spot-manager-public.ts +2 -2
- package/src/runtime/spots/spot-node-autoconnect.ts +22 -45
- package/src/runtime/spots/spot-node-runtime-manager.ts +197 -67
- package/src/runtime/spots/spot-outbound.ts +3 -3
- package/src/runtime/spots/spot-remote-codec.ts +9 -2
- package/src/runtime/spots/spot-runtime-ports.ts +0 -1
- package/src/runtime/spots/spot-serial-executor.ts +97 -25
- package/src/runtime/spots/spot-serial-turn-executor.ts +22 -3
- package/src/runtime/spots/spot-subscription-dispatch.ts +1 -1
- package/src/runtime/spots/spot-timer.ts +413 -157
- package/src/runtime/streams/actor-session-binding-registry.ts +236 -64
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +16 -8
- package/src/runtime/streams/bound-actor-relay-sender.ts +23 -9
- package/src/runtime/streams/bound-session-service.ts +7 -10
- package/src/runtime/streams/index.ts +12 -6
- package/src/runtime/streams/managed-stream.ts +4 -2
- package/src/runtime/streams/native-fallback-bound-session.ts +14 -103
- package/src/runtime/streams/session-actor-coordinator.ts +39 -88
- package/src/runtime/streams/stream-binding-runtime-ports.ts +3 -9
- package/src/runtime/streams/stream-session-runtime.ts +1 -5
- package/src/runtime/workers/index.ts +1 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { decodeRoutingId } from '../routing-id';
|
|
2
|
+
import { decodeBoundSessionCloseCommand } from '../protocol/service_wire_codec.generated';
|
|
1
3
|
import { UINT64_MAX, ZlinkStreamContentType } from '@zlink-systems/stream-wire';
|
|
2
4
|
import { RELOCATION_STATE_CHUNK_DATA_MAX_BYTES } from '../../contracts/Configuration/InternalDefaults';
|
|
3
5
|
import { isCanonicalWireReplyTerminal } from '../framework-errors-internal';
|
|
@@ -177,6 +179,7 @@ interface ServiceWireRelocationBase {
|
|
|
177
179
|
|
|
178
180
|
export interface ServiceMaintenanceRelocationPrepare extends ServiceWireRelocationBase {
|
|
179
181
|
readonly kind: 'prepare';
|
|
182
|
+
readonly deadlineUnixMs: bigint;
|
|
180
183
|
readonly target: ServiceWireRelocationTarget;
|
|
181
184
|
readonly initiatorRole: ServiceWireRelocationRole;
|
|
182
185
|
readonly object: ServiceWireRelocationObject;
|
|
@@ -324,6 +327,8 @@ export interface ServiceSessionRelocationOwnerFence {
|
|
|
324
327
|
}
|
|
325
328
|
|
|
326
329
|
export interface ServiceSessionRelocationSeal {
|
|
330
|
+
readonly targetNodeRid: string;
|
|
331
|
+
readonly targetNodeGeneration: bigint;
|
|
327
332
|
readonly relocation: ServiceWireOperationId;
|
|
328
333
|
readonly coordinator: ServiceWireRelocationCoordinatorFence;
|
|
329
334
|
readonly senderRole: 'source' | 'coordinator';
|
|
@@ -332,6 +337,7 @@ export interface ServiceSessionRelocationSeal {
|
|
|
332
337
|
}
|
|
333
338
|
|
|
334
339
|
export interface ServiceSessionRelocationSealed {
|
|
340
|
+
readonly sealResult: 'sealed' | 'bindingAbsent';
|
|
335
341
|
readonly relocation: ServiceWireOperationId;
|
|
336
342
|
readonly coordinator: ServiceWireRelocationCoordinatorFence;
|
|
337
343
|
readonly actor: ServiceBoundSessionActorAuthority;
|
|
@@ -371,17 +377,13 @@ export function serviceSessionRelocationIdentityKey(
|
|
|
371
377
|
ServiceSessionRelocationSeal | ServiceSessionRelocationSealed | ServiceSessionRelocationRoute
|
|
372
378
|
): string {
|
|
373
379
|
const actor = 'targetNodeGeneration' in value.actor ? value.actor.actor : value.actor;
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
|
|
377
|
-
return [
|
|
380
|
+
// Session–Actor binding §8.3: all original fields are checked against the
|
|
381
|
+
// recorded request; only relocation identity and ActorId select the record.
|
|
382
|
+
return JSON.stringify([
|
|
378
383
|
value.relocation.high.toString(),
|
|
379
384
|
value.relocation.low.toString(),
|
|
380
|
-
actor.actorId
|
|
381
|
-
|
|
382
|
-
value.session.sessionRid,
|
|
383
|
-
value.session.bindingGeneration.toString()
|
|
384
|
-
].join(':');
|
|
385
|
+
actor.actorId
|
|
386
|
+
]);
|
|
385
387
|
}
|
|
386
388
|
|
|
387
389
|
function toGeneratedRoutingId(value: string, field: string): Uint8Array {
|
|
@@ -663,6 +665,8 @@ function toGeneratedSessionRelocationSeal(
|
|
|
663
665
|
value: ServiceSessionRelocationSeal
|
|
664
666
|
): GeneratedSessionRelocationSeal42 {
|
|
665
667
|
return {
|
|
668
|
+
targetNodeRid: toGeneratedRoutingId(value.targetNodeRid, 'targetNodeRid'),
|
|
669
|
+
targetNodeGeneration: value.targetNodeGeneration,
|
|
666
670
|
relocation: value.relocation,
|
|
667
671
|
coordinator: toGeneratedCoordinatorFence(value.coordinator),
|
|
668
672
|
senderRole: value.senderRole,
|
|
@@ -675,6 +679,8 @@ function fromGeneratedSessionRelocationSeal(
|
|
|
675
679
|
value: GeneratedSessionRelocationSeal42
|
|
676
680
|
): ServiceSessionRelocationSeal {
|
|
677
681
|
return {
|
|
682
|
+
targetNodeRid: fromGeneratedRoutingId(value.targetNodeRid, 'targetNodeRid'),
|
|
683
|
+
targetNodeGeneration: value.targetNodeGeneration,
|
|
678
684
|
relocation: value.relocation,
|
|
679
685
|
coordinator: fromGeneratedCoordinatorFence(value.coordinator),
|
|
680
686
|
senderRole: value.senderRole as ServiceSessionRelocationSeal['senderRole'],
|
|
@@ -690,7 +696,8 @@ function toGeneratedSessionRelocationSealed(
|
|
|
690
696
|
relocation: value.relocation,
|
|
691
697
|
coordinator: toGeneratedCoordinatorFence(value.coordinator),
|
|
692
698
|
actor: toGeneratedRouteFence(value.actor),
|
|
693
|
-
...toGeneratedSessionOwnerFence(value.session)
|
|
699
|
+
...toGeneratedSessionOwnerFence(value.session),
|
|
700
|
+
sealResult: value.sealResult
|
|
694
701
|
};
|
|
695
702
|
}
|
|
696
703
|
|
|
@@ -698,6 +705,7 @@ function fromGeneratedSessionRelocationSealed(
|
|
|
698
705
|
value: GeneratedSessionRelocationSealed43
|
|
699
706
|
): ServiceSessionRelocationSealed {
|
|
700
707
|
return {
|
|
708
|
+
sealResult: value.sealResult,
|
|
701
709
|
relocation: value.relocation,
|
|
702
710
|
coordinator: fromGeneratedCoordinatorFence(value.coordinator),
|
|
703
711
|
actor: fromGeneratedRouteFence(value.actor),
|
|
@@ -778,6 +786,7 @@ function fromGeneratedRelocationPrepare(
|
|
|
778
786
|
): ServiceMaintenanceRelocationPrepare {
|
|
779
787
|
return {
|
|
780
788
|
kind: 'prepare',
|
|
789
|
+
deadlineUnixMs: value.deadlineUnixMs,
|
|
781
790
|
...fromGeneratedRelocationBase(value),
|
|
782
791
|
target: fromGeneratedTargetFence(value.target),
|
|
783
792
|
initiatorRole: value.initiatorRole,
|
|
@@ -1083,6 +1092,12 @@ export type ServiceStatefulWireRecord =
|
|
|
1083
1092
|
readonly sessionRid: string;
|
|
1084
1093
|
readonly binding: ServiceBoundSessionTransition;
|
|
1085
1094
|
}
|
|
1095
|
+
| {
|
|
1096
|
+
readonly kind: 'boundSessionClose';
|
|
1097
|
+
readonly correlation: bigint;
|
|
1098
|
+
readonly actor: { readonly actorId: string; readonly generation: bigint };
|
|
1099
|
+
readonly session: ServiceRetiredBoundSessionRouteFence;
|
|
1100
|
+
}
|
|
1086
1101
|
| {
|
|
1087
1102
|
readonly kind: 'boundSessionReplaced';
|
|
1088
1103
|
readonly actorAuthority: ServiceBoundSessionActorAuthority;
|
|
@@ -1714,6 +1729,25 @@ export function decodeStatefulHeader(
|
|
|
1714
1729
|
: { state: 'tombstone', retiredGeneration: generation }
|
|
1715
1730
|
};
|
|
1716
1731
|
}
|
|
1732
|
+
case M6bServiceWireCommand.boundSessionClose: {
|
|
1733
|
+
const decoded = decodeBoundSessionCloseCommand([frame], {});
|
|
1734
|
+
return {
|
|
1735
|
+
kind: 'boundSessionClose',
|
|
1736
|
+
correlation: decoded.correlation,
|
|
1737
|
+
actor: { actorId: decoded.actor.actorId, generation: decoded.actor.objectGeneration },
|
|
1738
|
+
session: {
|
|
1739
|
+
...decoded.session,
|
|
1740
|
+
sessionOwnerNodeRid: decodeRoutingId(
|
|
1741
|
+
Buffer.from(decoded.session.sessionOwnerNodeRid).toString('utf8'),
|
|
1742
|
+
Buffer.from(decoded.session.sessionOwnerNodeRid).toString('hex')
|
|
1743
|
+
),
|
|
1744
|
+
sessionRid: decodeRoutingId(
|
|
1745
|
+
Buffer.from(decoded.session.sessionRid).toString('utf8'),
|
|
1746
|
+
Buffer.from(decoded.session.sessionRid).toString('hex')
|
|
1747
|
+
)
|
|
1748
|
+
}
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1717
1751
|
case M6bServiceWireCommand.boundSessionReplaced: {
|
|
1718
1752
|
requireFlags(command.flags, 0);
|
|
1719
1753
|
const actor = reader.actorRef('actorAuthority.actor');
|
|
@@ -1882,7 +1916,8 @@ export function encodeMaintenanceRelocationControl(
|
|
|
1882
1916
|
payloadTotalLength: value.payloadTotalLength,
|
|
1883
1917
|
payloadChunkCount: value.payloadChunkCount,
|
|
1884
1918
|
payloadChecksumCrc32c: value.payloadChecksumCrc32c,
|
|
1885
|
-
applicationVersion: value.applicationVersion
|
|
1919
|
+
applicationVersion: value.applicationVersion,
|
|
1920
|
+
deadlineUnixMs: value.deadlineUnixMs
|
|
1886
1921
|
})
|
|
1887
1922
|
);
|
|
1888
1923
|
case 'ready':
|
|
@@ -2010,6 +2045,7 @@ export function decodeStatefulReply(
|
|
|
2010
2045
|
| 'actorJoin'
|
|
2011
2046
|
| 'streamBind'
|
|
2012
2047
|
| 'streamUnbind'
|
|
2048
|
+
| 'boundSessionClose'
|
|
2013
2049
|
| 'instanceSpotRequest'
|
|
2014
2050
|
| 'userSpotCreate'
|
|
2015
2051
|
| 'userSpotClose'
|
|
@@ -2024,6 +2060,8 @@ export function decodeStatefulReply(
|
|
|
2024
2060
|
const terminalResult = reader.u32('terminalResult');
|
|
2025
2061
|
const failureCode = reader.u32('failureCode');
|
|
2026
2062
|
validateReplyTerminal(terminalResult, failureCode, hasPayload);
|
|
2063
|
+
if (operationKind === 'boundSessionClose' && hasPayload)
|
|
2064
|
+
fail('A bound Session close reply cannot carry application payload.');
|
|
2027
2065
|
let tail: ServiceStatefulReplyTail | undefined;
|
|
2028
2066
|
if (terminalResult === 0) {
|
|
2029
2067
|
if (operationKind === 'actorLookup') {
|
|
@@ -7,38 +7,61 @@ export const SERVICE_WIRE_PREFIX_SIZE = SERVICE_WIRE_FLAGS_OFFSET + 1;
|
|
|
7
7
|
|
|
8
8
|
export const SERVICE_WIRE_TEXT8_MAX_BYTES = 255;
|
|
9
9
|
|
|
10
|
+
// Fatal decoding accepts exactly the canonical UTF-8 encodings; a leading
|
|
11
|
+
// U+FEFF stays part of the value.
|
|
12
|
+
const CANONICAL_UTF8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
|
|
13
|
+
|
|
10
14
|
export type ServiceWireInvalid = (message: string) => never;
|
|
11
15
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
16
|
+
/** String.prototype.isWellFormed (ES2024) exists on every supported Node (20 and later). */
|
|
17
|
+
type ServiceWireText = string & { isWellFormed(): boolean };
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validates text for the service wire and returns its UTF-8 byte length. An
|
|
21
|
+
* unpaired UTF-16 surrogate is rejected instead of being replaced.
|
|
22
|
+
*/
|
|
23
|
+
export function canonicalServiceWireTextLength(
|
|
14
24
|
value: string,
|
|
15
25
|
field: string,
|
|
16
26
|
maximumBytes: number,
|
|
17
27
|
invalid: ServiceWireInvalid
|
|
18
|
-
):
|
|
19
|
-
const
|
|
28
|
+
): number {
|
|
29
|
+
const length = Buffer.byteLength(value, 'utf8');
|
|
20
30
|
if (
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
length < 1 ||
|
|
32
|
+
length > maximumBytes ||
|
|
23
33
|
value.includes('\0') ||
|
|
24
|
-
|
|
34
|
+
!(value as ServiceWireText).isWellFormed()
|
|
25
35
|
) {
|
|
26
36
|
invalid(`${field} must be 1..${maximumBytes} canonical UTF-8 bytes without NUL.`);
|
|
27
37
|
}
|
|
28
|
-
return
|
|
38
|
+
return length;
|
|
29
39
|
}
|
|
30
40
|
|
|
31
|
-
/**
|
|
41
|
+
/** Encodes text without silently replacing an unpaired UTF-16 surrogate. */
|
|
42
|
+
export function encodeCanonicalServiceWireText(
|
|
43
|
+
value: string,
|
|
44
|
+
field: string,
|
|
45
|
+
maximumBytes: number,
|
|
46
|
+
invalid: ServiceWireInvalid
|
|
47
|
+
): Buffer {
|
|
48
|
+
canonicalServiceWireTextLength(value, field, maximumBytes, invalid);
|
|
49
|
+
return Buffer.from(value, 'utf8');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Decodes schema text in place and rejects non-canonical UTF-8 and NUL. */
|
|
32
53
|
export function decodeCanonicalServiceWireText(
|
|
33
54
|
bytes: Uint8Array,
|
|
34
55
|
field: string,
|
|
35
56
|
invalid: ServiceWireInvalid
|
|
36
57
|
): string {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
58
|
+
let value: string;
|
|
59
|
+
try {
|
|
60
|
+
value = CANONICAL_UTF8.decode(bytes);
|
|
61
|
+
} catch {
|
|
40
62
|
invalid(`${field} is not canonical UTF-8 without NUL.`);
|
|
41
63
|
}
|
|
64
|
+
if (value.includes('\0')) invalid(`${field} is not canonical UTF-8 without NUL.`);
|
|
42
65
|
return value;
|
|
43
66
|
}
|
|
44
67
|
|
|
@@ -9,10 +9,13 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
SERVICE_WIRE_PREFIX_SIZE,
|
|
11
11
|
SERVICE_WIRE_TEXT8_MAX_BYTES,
|
|
12
|
+
canonicalServiceWireTextLength,
|
|
12
13
|
decodeCanonicalServiceWireText,
|
|
13
14
|
encodeCanonicalServiceWireText
|
|
14
15
|
} from './service-wire-binary-primitives';
|
|
15
16
|
import {
|
|
17
|
+
SERVICE_FRAMEWORK_MULTIPART_CONTENT_TYPE,
|
|
18
|
+
SERVICE_FRAMEWORK_MULTIPART_PACKET_NAME,
|
|
16
19
|
SERVICE_WIRE_MAGIC,
|
|
17
20
|
SERVICE_WIRE_MAJOR,
|
|
18
21
|
SERVICE_WIRE_REQUIRED_CAPABILITY,
|
|
@@ -33,6 +36,10 @@ export const APPLICATION_PAYLOAD_MINIMUM_FIELD_BYTES =
|
|
|
33
36
|
APPLICATION_PAYLOAD_LENGTH_FIELD_BYTES;
|
|
34
37
|
const MAX_U32 = UINT32_MAX;
|
|
35
38
|
const MAX_U64 = UINT64_MAX;
|
|
39
|
+
// The framework multipart frame always carries these two schema constants;
|
|
40
|
+
// decoding compares their bytes in place instead of decoding text.
|
|
41
|
+
const MULTIPART_PACKET_NAME_BYTES = Buffer.from(SERVICE_FRAMEWORK_MULTIPART_PACKET_NAME);
|
|
42
|
+
const MULTIPART_CONTENT_TYPE_BYTES = Buffer.from(SERVICE_FRAMEWORK_MULTIPART_CONTENT_TYPE);
|
|
36
43
|
export const M6A_SERVICE_WIRE_MAGIC = SERVICE_WIRE_MAGIC;
|
|
37
44
|
export const M6A_SERVICE_WIRE_MAJOR = SERVICE_WIRE_MAJOR;
|
|
38
45
|
export const M6A_SERVICE_WIRE_REQUIRED_CAPABILITY = SERVICE_WIRE_REQUIRED_CAPABILITY;
|
|
@@ -68,7 +75,7 @@ export function encodeNodeSendHeader(): Buffer {
|
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
export function encodeNodeRequestHeader(correlation: bigint): Buffer {
|
|
71
|
-
return withU64(
|
|
78
|
+
return withU64(M6aServiceWireCommand.nodeRequest, correlation, 0);
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
export function decodeNodeRequestHeader(frame: Uint8Array, header = decodeHeader(frame)): bigint {
|
|
@@ -83,7 +90,10 @@ export function decodeNodeRequestHeader(frame: Uint8Array, header = decodeHeader
|
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
export function encodeChannelSendHeader(channelName: string): Buffer {
|
|
86
|
-
|
|
93
|
+
const length = channelNameLength(channelName);
|
|
94
|
+
const result = frame(M6aServiceWireCommand.channelSend, 1 + length);
|
|
95
|
+
writeText8(result, PREFIX_SIZE, channelName, length);
|
|
96
|
+
return result;
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
export function decodeChannelSendHeader(frame: Uint8Array, header = decodeHeader(frame)): string {
|
|
@@ -97,9 +107,18 @@ export function decodeChannelSendHeader(frame: Uint8Array, header = decodeHeader
|
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
export function encodeChannelRequestHeader(correlation: bigint, channelName: string): Buffer {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
const length = channelNameLength(channelName);
|
|
111
|
+
const result = withU64(M6aServiceWireCommand.channelRequest, correlation, 1 + length);
|
|
112
|
+
writeText8(result, PREFIX_SIZE + 8, channelName, length);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function channelNameLength(channelName: string): number {
|
|
117
|
+
return canonicalServiceWireTextLength(
|
|
118
|
+
channelName,
|
|
119
|
+
'channelName',
|
|
120
|
+
SERVICE_WIRE_TEXT8_MAX_BYTES,
|
|
121
|
+
fail
|
|
103
122
|
);
|
|
104
123
|
}
|
|
105
124
|
|
|
@@ -124,7 +143,7 @@ export function encodeReplyHeader(
|
|
|
124
143
|
correlation: bigint,
|
|
125
144
|
terminalResult = 0,
|
|
126
145
|
failureCode = 0,
|
|
127
|
-
tail
|
|
146
|
+
tail?: Uint8Array
|
|
128
147
|
): Buffer {
|
|
129
148
|
validateReplyFields(correlation, terminalResult, failureCode);
|
|
130
149
|
// service-wire-v1.schema.json: reply(20).tail -> `request-specific-tail`,
|
|
@@ -133,12 +152,11 @@ export function encodeReplyHeader(
|
|
|
133
152
|
// length on the wire; an empty tail yields exactly 21 bytes. (Contrast
|
|
134
153
|
// `actor-join-reply-tail`, which does declare `bodyLengthType: u16` and
|
|
135
154
|
// therefore carries its own inner length prefix.)
|
|
136
|
-
const result =
|
|
137
|
-
prefix(M6aServiceWireCommand.reply).copy(result);
|
|
155
|
+
const result = frame(M6aServiceWireCommand.reply, 16 + (tail?.byteLength ?? 0));
|
|
138
156
|
result.writeBigUInt64BE(correlation, PREFIX_SIZE);
|
|
139
157
|
result.writeUInt32BE(terminalResult, PREFIX_SIZE + 8);
|
|
140
158
|
result.writeUInt32BE(failureCode, PREFIX_SIZE + 12);
|
|
141
|
-
|
|
159
|
+
if (tail !== undefined) result.set(tail, PREFIX_SIZE + 16);
|
|
142
160
|
return result;
|
|
143
161
|
}
|
|
144
162
|
|
|
@@ -159,7 +177,8 @@ export function decodeReplyHeader(frame: Uint8Array): ServiceReplyHeader {
|
|
|
159
177
|
correlation: bytes.readBigUInt64BE(PREFIX_SIZE),
|
|
160
178
|
terminalResult: bytes.readUInt32BE(PREFIX_SIZE + 8),
|
|
161
179
|
failureCode: bytes.readUInt32BE(PREFIX_SIZE + 12),
|
|
162
|
-
|
|
180
|
+
// A view of the frame: the caller validates the tail before the frame is released.
|
|
181
|
+
tail: bytes.subarray(PREFIX_SIZE + 16)
|
|
163
182
|
};
|
|
164
183
|
validateReplyFields(result.correlation, result.terminalResult, result.failureCode);
|
|
165
184
|
return result;
|
|
@@ -211,13 +230,13 @@ function allocateApplicationPayload(
|
|
|
211
230
|
contentType: string,
|
|
212
231
|
payloadLength: number
|
|
213
232
|
): Buffer {
|
|
214
|
-
const
|
|
233
|
+
const packetNameLength = canonicalServiceWireTextLength(
|
|
215
234
|
packetName,
|
|
216
235
|
'packetName',
|
|
217
236
|
SERVICE_WIRE_TEXT8_MAX_BYTES,
|
|
218
237
|
fail
|
|
219
238
|
);
|
|
220
|
-
const
|
|
239
|
+
const contentTypeLength = canonicalServiceWireTextLength(
|
|
221
240
|
contentType,
|
|
222
241
|
'contentType',
|
|
223
242
|
SERVICE_WIRE_TEXT8_MAX_BYTES,
|
|
@@ -225,23 +244,15 @@ function allocateApplicationPayload(
|
|
|
225
244
|
);
|
|
226
245
|
if (payloadLength > MAX_U32) fail('Application payload exceeds u32.');
|
|
227
246
|
const frameLength =
|
|
228
|
-
APPLICATION_PAYLOAD_MINIMUM_FIELD_BYTES +
|
|
229
|
-
packetNameBytes.byteLength +
|
|
230
|
-
contentTypeBytes.byteLength +
|
|
231
|
-
payloadLength;
|
|
247
|
+
APPLICATION_PAYLOAD_MINIMUM_FIELD_BYTES + packetNameLength + contentTypeLength + payloadLength;
|
|
232
248
|
const prefixLength = 1 + APPLICATION_PAYLOAD_LENGTH_FIELD_BYTES;
|
|
233
249
|
const bodyLength = frameLength - prefixLength;
|
|
234
250
|
if (bodyLength > MAX_U32) fail('Application payload body exceeds u32.');
|
|
235
251
|
const result = Buffer.alloc(frameLength);
|
|
236
252
|
result[0] = APPLICATION_PAYLOAD_VERSION;
|
|
237
253
|
result.writeUInt32BE(bodyLength, 1);
|
|
238
|
-
let offset = prefixLength;
|
|
239
|
-
|
|
240
|
-
result.set(packetNameBytes, offset);
|
|
241
|
-
offset += packetNameBytes.byteLength;
|
|
242
|
-
result[offset++] = contentTypeBytes.byteLength;
|
|
243
|
-
result.set(contentTypeBytes, offset);
|
|
244
|
-
offset += contentTypeBytes.byteLength;
|
|
254
|
+
let offset = writeText8(result, prefixLength, packetName, packetNameLength);
|
|
255
|
+
offset = writeText8(result, offset, contentType, contentTypeLength);
|
|
245
256
|
result.writeUInt32BE(payloadLength, offset);
|
|
246
257
|
return result;
|
|
247
258
|
}
|
|
@@ -260,18 +271,127 @@ export function decodeApplicationPayload(frame: Uint8Array): ServiceApplicationP
|
|
|
260
271
|
* they must hand the multipart bytes to another runtime-owned queue.
|
|
261
272
|
*/
|
|
262
273
|
export function decodeApplicationPayloadView(frame: Uint8Array): ServiceApplicationPayload {
|
|
263
|
-
const reader =
|
|
264
|
-
if (reader.u8('version') !== APPLICATION_PAYLOAD_VERSION)
|
|
265
|
-
fail('Invalid application payload version.');
|
|
266
|
-
const bodyLength = reader.u32('bodyLength');
|
|
267
|
-
if (bodyLength !== reader.remaining) fail('Application payload body length mismatch.');
|
|
274
|
+
const reader = applicationPayloadReader(frame);
|
|
268
275
|
const packetName = reader.text8('packetName');
|
|
269
276
|
const contentType = reader.text8('contentType');
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
277
|
+
return { packetName, contentType, payload: applicationPayloadView(reader) };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Decodes the framework multipart application frame, whose packet name and
|
|
282
|
+
* content type are the schema's multipart constants, and returns a view of its
|
|
283
|
+
* multipart payload without decoding either text field.
|
|
284
|
+
*/
|
|
285
|
+
export function decodeMultipartApplicationPayloadView(
|
|
286
|
+
frame: Uint8Array
|
|
287
|
+
): ServiceApplicationPayload {
|
|
288
|
+
const bytes = asBuffer(frame);
|
|
289
|
+
const offset = multipartApplicationPayloadOffset(bytes);
|
|
290
|
+
return {
|
|
291
|
+
packetName: SERVICE_FRAMEWORK_MULTIPART_PACKET_NAME,
|
|
292
|
+
contentType: SERVICE_FRAMEWORK_MULTIPART_CONTENT_TYPE,
|
|
293
|
+
payload: bytes.subarray(offset)
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Materializes final message parts directly over the retained application frame. */
|
|
298
|
+
export function decodeMultipartApplicationParts<T>(
|
|
299
|
+
frame: Uint8Array,
|
|
300
|
+
materialize: (part: Buffer) => T,
|
|
301
|
+
release?: (part: T) => void
|
|
302
|
+
): T[] {
|
|
303
|
+
const bytes = asBuffer(frame);
|
|
304
|
+
return decodeMultipartParts(
|
|
305
|
+
bytes,
|
|
306
|
+
materialize,
|
|
307
|
+
release,
|
|
308
|
+
multipartApplicationPayloadOffset(bytes)
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function multipartApplicationPayloadOffset(bytes: Buffer): number {
|
|
313
|
+
let offset = applicationPayloadBodyOffset(bytes);
|
|
314
|
+
offset = expectText8At(bytes, offset, MULTIPART_PACKET_NAME_BYTES, 'packetName');
|
|
315
|
+
offset = expectText8At(bytes, offset, MULTIPART_CONTENT_TYPE_BYTES, 'contentType');
|
|
316
|
+
return applicationPayloadDataOffset(bytes, offset);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function expectText8At(bytes: Buffer, offset: number, expected: Buffer, field: string): number {
|
|
320
|
+
if (bytes.length <= offset) fail(`Truncated ${field}.length.`);
|
|
321
|
+
const length = bytes[offset++]!;
|
|
322
|
+
if (bytes.length - offset < length) fail(`Truncated ${field}.`);
|
|
323
|
+
if (length !== expected.length || expected.compare(bytes, offset, offset + length) !== 0) {
|
|
324
|
+
fail(`Unexpected ${field}.`);
|
|
325
|
+
}
|
|
326
|
+
return offset + length;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function applicationPayloadBodyOffset(bytes: Buffer): number {
|
|
330
|
+
if (bytes.length === 0) fail('Truncated version.');
|
|
331
|
+
if (bytes[0] !== APPLICATION_PAYLOAD_VERSION) fail('Invalid application payload version.');
|
|
332
|
+
const offset = 1 + APPLICATION_PAYLOAD_LENGTH_FIELD_BYTES;
|
|
333
|
+
if (bytes.length < offset) fail('Truncated bodyLength.');
|
|
334
|
+
if (bytes.readUInt32BE(1) !== bytes.length - offset)
|
|
335
|
+
fail('Application payload body length mismatch.');
|
|
336
|
+
return offset;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function applicationPayloadDataOffset(bytes: Buffer, offset: number): number {
|
|
340
|
+
if (bytes.length - offset < APPLICATION_PAYLOAD_LENGTH_FIELD_BYTES)
|
|
341
|
+
fail('Truncated payloadLength.');
|
|
342
|
+
const length = bytes.readUInt32BE(offset);
|
|
343
|
+
offset += APPLICATION_PAYLOAD_LENGTH_FIELD_BYTES;
|
|
344
|
+
if (length !== bytes.length - offset) fail('Application payload length mismatch.');
|
|
345
|
+
return offset;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function applicationPayloadReader(frame: Uint8Array): Reader {
|
|
349
|
+
const bytes = asBuffer(frame);
|
|
350
|
+
return new Reader(bytes, applicationPayloadBodyOffset(bytes));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function applicationPayloadView(reader: Reader): Buffer {
|
|
354
|
+
return reader.buffer.subarray(applicationPayloadDataOffset(reader.buffer, reader.offset));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export function decodeMultipartParts<T>(
|
|
358
|
+
payload: Uint8Array,
|
|
359
|
+
materialize: (part: Buffer) => T,
|
|
360
|
+
release?: (part: T) => void,
|
|
361
|
+
offset = 0
|
|
362
|
+
): T[] {
|
|
363
|
+
const bytes = asBuffer(payload);
|
|
364
|
+
if (bytes.length - offset < 4) throw new ServiceWireProtocolError('Truncated multipart payload.');
|
|
365
|
+
const count = bytes.readUInt32BE(offset);
|
|
366
|
+
if (count === 0 || count > Math.floor((bytes.length - offset - 4) / 4)) {
|
|
367
|
+
throw new ServiceWireProtocolError('Invalid multipart part count.');
|
|
368
|
+
}
|
|
369
|
+
const result = new Array<T>(count);
|
|
370
|
+
offset += 4;
|
|
371
|
+
let index = 0;
|
|
372
|
+
try {
|
|
373
|
+
for (; index < count; index++) {
|
|
374
|
+
if (bytes.length - offset < 4) {
|
|
375
|
+
throw new ServiceWireProtocolError('Truncated multipart part length.');
|
|
376
|
+
}
|
|
377
|
+
const length = bytes.readUInt32BE(offset);
|
|
378
|
+
offset += 4;
|
|
379
|
+
if (bytes.length - offset < length) {
|
|
380
|
+
throw new ServiceWireProtocolError('Truncated multipart part.');
|
|
381
|
+
}
|
|
382
|
+
result[index] = materialize(bytes.subarray(offset, offset + length));
|
|
383
|
+
offset += length;
|
|
384
|
+
}
|
|
385
|
+
if (offset !== bytes.length) {
|
|
386
|
+
throw new ServiceWireProtocolError('Multipart payload has trailing bytes.');
|
|
387
|
+
}
|
|
388
|
+
return result;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
if (release !== undefined) {
|
|
391
|
+
for (let retained = 0; retained < index; retained++) release(result[retained]!);
|
|
392
|
+
}
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
275
395
|
}
|
|
276
396
|
|
|
277
397
|
/**
|
|
@@ -281,11 +401,7 @@ export function decodeApplicationPayloadView(frame: Uint8Array): ServiceApplicat
|
|
|
281
401
|
* message is admitted to an execution queue.
|
|
282
402
|
*/
|
|
283
403
|
export function validateApplicationPayloadFrame(frame: Uint8Array): void {
|
|
284
|
-
const reader =
|
|
285
|
-
if (reader.u8('version') !== APPLICATION_PAYLOAD_VERSION)
|
|
286
|
-
fail('Invalid application payload version.');
|
|
287
|
-
const bodyLength = reader.u32('bodyLength');
|
|
288
|
-
if (bodyLength !== reader.remaining) fail('Application payload body length mismatch.');
|
|
404
|
+
const reader = applicationPayloadReader(frame);
|
|
289
405
|
reader.text8('packetName');
|
|
290
406
|
reader.text8('contentType');
|
|
291
407
|
const payloadLength = reader.u32('payloadLength');
|
|
@@ -469,19 +585,37 @@ export function decodeHeader(frame: Uint8Array): ServiceWireHeader {
|
|
|
469
585
|
return { command: frame[3]!, flags: frame[4]! };
|
|
470
586
|
}
|
|
471
587
|
|
|
588
|
+
/** Allocates a whole service wire record once and writes its prefix; the caller fills the body. */
|
|
589
|
+
function frame(command: number, bodyLength: number): Buffer {
|
|
590
|
+
const result = Buffer.allocUnsafe(PREFIX_SIZE + bodyLength);
|
|
591
|
+
result[0] = M6A_SERVICE_WIRE_MAGIC[0];
|
|
592
|
+
result[1] = M6A_SERVICE_WIRE_MAGIC[1];
|
|
593
|
+
result[2] = M6A_SERVICE_WIRE_MAJOR;
|
|
594
|
+
result[3] = command;
|
|
595
|
+
result[4] = 0;
|
|
596
|
+
return result;
|
|
597
|
+
}
|
|
598
|
+
|
|
472
599
|
function prefix(command: number): Buffer {
|
|
473
|
-
return
|
|
474
|
-
M6A_SERVICE_WIRE_MAGIC[0],
|
|
475
|
-
M6A_SERVICE_WIRE_MAGIC[1],
|
|
476
|
-
M6A_SERVICE_WIRE_MAJOR,
|
|
477
|
-
command,
|
|
478
|
-
0
|
|
479
|
-
]);
|
|
600
|
+
return frame(command, 0);
|
|
480
601
|
}
|
|
481
602
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
603
|
+
/** A record whose body starts with the non-zero u64 correlation, followed by `restLength` bytes. */
|
|
604
|
+
function withU64(command: number, correlation: bigint, restLength: number): Buffer {
|
|
605
|
+
if (correlation <= 0n || correlation > MAX_U64) fail('correlation must be a non-zero u64.');
|
|
606
|
+
const result = frame(command, 8 + restLength);
|
|
607
|
+
result.writeBigUInt64BE(correlation, PREFIX_SIZE);
|
|
608
|
+
return result;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Writes a validated text8 field — the byte length from
|
|
613
|
+
* canonicalServiceWireTextLength, then the UTF-8 text — and returns the next offset.
|
|
614
|
+
*/
|
|
615
|
+
function writeText8(target: Buffer, offset: number, value: string, length: number): number {
|
|
616
|
+
target[offset] = length;
|
|
617
|
+
target.write(value, offset + 1, length, 'utf8');
|
|
618
|
+
return offset + 1 + length;
|
|
485
619
|
}
|
|
486
620
|
|
|
487
621
|
function encodeU16(value: number): Buffer {
|
|
@@ -530,7 +664,9 @@ function readNonZeroU64(bytes: Buffer, offset: number, field: string): bigint {
|
|
|
530
664
|
}
|
|
531
665
|
|
|
532
666
|
function asBuffer(value: Uint8Array): Buffer {
|
|
533
|
-
return Buffer.
|
|
667
|
+
return Buffer.isBuffer(value)
|
|
668
|
+
? value
|
|
669
|
+
: Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
534
670
|
}
|
|
535
671
|
|
|
536
672
|
function validateAdmissionCommand(command: number): void {
|
|
@@ -652,13 +788,13 @@ class Reader {
|
|
|
652
788
|
text8(field: string): string {
|
|
653
789
|
const length = this.u8(`${field}.length`);
|
|
654
790
|
if (length === 0) fail(`${field} must be non-empty.`);
|
|
655
|
-
return decodeText(this.
|
|
791
|
+
return decodeText(this.view(length, field), field);
|
|
656
792
|
}
|
|
657
793
|
|
|
658
794
|
text16(field: string): string {
|
|
659
795
|
const length = this.u16(`${field}.length`);
|
|
660
796
|
if (length === 0 || length > SERVICE_ROUTE_TEXT_MAX_BYTES) fail(`${field} has invalid length.`);
|
|
661
|
-
return decodeText(this.
|
|
797
|
+
return decodeText(this.view(length, field), field);
|
|
662
798
|
}
|
|
663
799
|
|
|
664
800
|
bytes(length: number, field: string): Buffer {
|