@zlink-systems/framework 0.30.3 → 0.32.0
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/Actors/ZLinkActor.d.ts +2 -0
- package/dist/contracts/Actors/ZLinkSessionBindingIdentity.d.ts +6 -0
- package/dist/contracts/Actors/ZLinkSessionBindingIdentity.js +2 -0
- package/dist/contracts/Actors/index.d.ts +1 -0
- package/dist/contracts/Actors/index.js +1 -0
- package/dist/contracts/Common/CoreTypes.d.ts +1 -0
- package/dist/contracts/Common/HandlerMessageType.d.ts +8 -0
- package/dist/contracts/Common/HandlerMessageType.js +41 -0
- package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +1 -1
- package/dist/contracts/Common/ZLinkEncodedPayload.js +12 -20
- package/dist/contracts/Common/ZLinkMessage.js +11 -7
- package/dist/contracts/Common/encoded-payload-storage.d.ts +0 -2
- package/dist/contracts/Common/encoded-payload-storage.js +4 -16
- package/dist/contracts/Common/index.d.ts +1 -1
- package/dist/contracts/Common/payload-slab.d.ts +4 -0
- package/dist/contracts/Common/payload-slab.js +30 -0
- package/dist/contracts/Configuration/RegistrationBuilders.js +15 -9
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +19 -0
- package/dist/contracts/Handlers/Contexts.d.ts +1 -0
- package/dist/contracts/Locations/Authority.d.ts +2 -0
- package/dist/internal.d.ts +9 -0
- package/dist/internal.js +23 -1
- package/dist/nest-integration.d.ts +1 -0
- package/dist/nest-integration.js +3 -1
- package/dist/runtime/actors/actor-client.d.ts +6 -2
- package/dist/runtime/actors/actor-client.js +120 -82
- package/dist/runtime/actors/actor-context.js +16 -5
- package/dist/runtime/actors/actor-execution-context.js +2 -2
- package/dist/runtime/actors/actor-handoff.d.ts +12 -1
- package/dist/runtime/actors/actor-handoff.js +79 -34
- package/dist/runtime/actors/actor-join-deferred-scope.js +6 -6
- package/dist/runtime/actors/actor-local-native-join.d.ts +2 -2
- package/dist/runtime/actors/actor-local-native-join.js +19 -17
- package/dist/runtime/actors/actor-mailbox.d.ts +1 -1
- package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
- package/dist/runtime/actors/actor-remote-joiner.js +4 -4
- package/dist/runtime/actors/actor-routed-join-transport.d.ts +9 -3
- package/dist/runtime/actors/actor-routed-json-request.d.ts +3 -0
- package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -2
- package/dist/runtime/actors/actor-runtime-state.d.ts +1 -1
- package/dist/runtime/actors/spot-actor-dispatch.d.ts +9 -5
- package/dist/runtime/actors/spot-actor-dispatch.js +60 -38
- package/dist/runtime/admission.d.ts +6 -4
- package/dist/runtime/admission.js +21 -10
- package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +1 -0
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +3 -0
- package/dist/runtime/backend/contracts/index.d.ts +26 -10
- package/dist/runtime/backend/mesh-completion-table.d.ts +7 -1
- package/dist/runtime/backend/mesh-completion-table.js +84 -20
- package/dist/runtime/backend/mesh-dispatch-pump.d.ts +19 -6
- package/dist/runtime/backend/mesh-dispatch-pump.js +246 -147
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -2
- package/dist/runtime/backend/node/node-backend-adapter-support.js +27 -19
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +5 -2
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +70 -13
- package/dist/runtime/backend/node/node-event-loop-poller.d.ts +2 -2
- package/dist/runtime/backend/node/node-event-loop-poller.js +4 -3
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +5 -1
- package/dist/runtime/backend/node/node-raw-binding-port.d.ts +7 -2
- package/dist/runtime/backend/node/node-raw-binding-port.js +99 -63
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +34 -16
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +210 -106
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +20 -6
- package/dist/runtime/backend/raw-binding-port.d.ts +6 -3
- package/dist/runtime/channels/channel-clients.js +3 -3
- package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +11 -7
- package/dist/runtime/channels/channel-dispatch-pipeline.js +40 -22
- package/dist/runtime/channels/channel-dispatch-services.d.ts +3 -1
- package/dist/runtime/channels/channel-dispatch-services.js +7 -6
- package/dist/runtime/channels/channel-dispatchers.d.ts +13 -6
- package/dist/runtime/channels/channel-dispatchers.js +57 -36
- package/dist/runtime/channels/channel-envelope.d.ts +2 -2
- package/dist/runtime/channels/channel-envelope.js +609 -83
- package/dist/runtime/channels/channel-multipart.d.ts +1 -0
- package/dist/runtime/channels/channel-multipart.js +10 -6
- package/dist/runtime/channels/channel-outbound-operations.d.ts +6 -9
- package/dist/runtime/channels/channel-outbound-operations.js +107 -105
- package/dist/runtime/channels/channel-receive-loops.d.ts +9 -7
- package/dist/runtime/channels/channel-receive-loops.js +126 -90
- package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +23 -6
- package/dist/runtime/channels/channel-runtime-lifecycle.js +47 -38
- package/dist/runtime/channels/channel-runtime-manager.d.ts +13 -6
- package/dist/runtime/channels/channel-runtime-manager.js +32 -14
- package/dist/runtime/channels/channel-socket-registry.d.ts +28 -4
- package/dist/runtime/channels/channel-socket-registry.js +9 -1
- package/dist/runtime/channels/channel-transports.d.ts +23 -16
- package/dist/runtime/channels/channel-transports.js +139 -119
- package/dist/runtime/channels/dispatch-error-reporter.d.ts +4 -4
- package/dist/runtime/channels/dispatch-error-reporter.js +5 -5
- package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
- package/dist/runtime/channels/local-spot-route-transport.d.ts +5 -2
- package/dist/runtime/channels/local-spot-route-transport.js +15 -18
- package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +6 -3
- package/dist/runtime/channels/router-socket-spot-route-transport.js +33 -19
- package/dist/runtime/channels/source-spot-router.d.ts +6 -3
- package/dist/runtime/channels/source-spot-router.js +34 -23
- package/dist/runtime/channels/spot-node-route-transport.d.ts +6 -3
- package/dist/runtime/channels/spot-node-route-transport.js +23 -17
- package/dist/runtime/channels/spot-route-bridge-transport.d.ts +6 -3
- package/dist/runtime/channels/spot-route-bridge-transport.js +38 -24
- package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +8 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.js +36 -23
- package/dist/runtime/diagnostics/dispatch-error-details.js +9 -3
- package/dist/runtime/diagnostics/message-flow-bootstrap.d.ts +1 -0
- package/dist/runtime/diagnostics/message-flow-bootstrap.js +8 -0
- package/dist/runtime/diagnostics/message-flow-delivery.d.ts +47 -0
- package/dist/runtime/diagnostics/message-flow-delivery.js +149 -0
- package/dist/runtime/diagnostics/message-flow-record.d.ts +50 -0
- package/dist/runtime/diagnostics/message-flow-record.js +228 -0
- package/dist/runtime/diagnostics/message-flow-worker.d.ts +1 -0
- package/dist/runtime/diagnostics/message-flow-worker.js +118 -0
- package/dist/runtime/diagnostics/message-flow.d.ts +7 -19
- package/dist/runtime/diagnostics/message-flow.js +42 -290
- package/dist/runtime/diagnostics/runtime-metrics.d.ts +4 -3
- package/dist/runtime/diagnostics/runtime-metrics.js +8 -4
- package/dist/runtime/execution/index.d.ts +1 -0
- package/dist/runtime/execution/index.js +6 -3
- package/dist/runtime/execution/serial-execution-queue.d.ts +26 -13
- package/dist/runtime/execution/serial-execution-queue.js +75 -71
- package/dist/runtime/foundation/durable-service-request.d.ts +12 -3
- package/dist/runtime/foundation/durable-service-request.js +158 -73
- package/dist/runtime/foundation/operation-registry.d.ts +33 -3
- package/dist/runtime/foundation/operation-registry.js +272 -33
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +62 -23
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +373 -194
- package/dist/runtime/foundation/request-runtime.d.ts +17 -0
- package/dist/runtime/foundation/request-runtime.js +163 -0
- package/dist/runtime/foundation/service-discovery-registry.d.ts +4 -0
- package/dist/runtime/foundation/service-discovery-registry.js +6 -0
- package/dist/runtime/foundation/service-liveness-registry.d.ts +1 -1
- package/dist/runtime/foundation/service-mailbox.d.ts +4 -2
- package/dist/runtime/foundation/service-mailbox.js +4 -1
- package/dist/runtime/foundation/service-relocation-object-owner.d.ts +2 -2
- package/dist/runtime/foundation/service-relocation-object-owner.js +12 -5
- package/dist/runtime/foundation/service-runtime-contracts.d.ts +7 -2
- package/dist/runtime/foundation/service-stateful-registry.d.ts +6 -2
- package/dist/runtime/foundation/service-stateful-registry.js +38 -17
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +91 -26
- package/dist/runtime/foundation/service-stateful-runtime.js +245 -120
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +3 -0
- package/dist/runtime/foundation/service-stateful-wire-codec.js +15 -0
- package/dist/runtime/foundation/service-topology-registry.d.ts +2 -0
- package/dist/runtime/foundation/service-topology-registry.js +13 -3
- package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
- package/dist/runtime/foundation/service-wire-constants.generated.js +12 -0
- package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +5 -1
- package/dist/runtime/foundation/service-wire-m6a-codec.js +50 -15
- package/dist/runtime/host/actor-packet-relay.d.ts +5 -6
- package/dist/runtime/host/actor-packet-relay.js +58 -57
- package/dist/runtime/host/actor-placement-coordinator.d.ts +1 -1
- package/dist/runtime/host/actor-runtime-options-factory.d.ts +2 -0
- package/dist/runtime/host/actor-runtime-options-factory.js +3 -2
- package/dist/runtime/host/actor-transfer-runtime.d.ts +3 -3
- package/dist/runtime/host/application-job-queue.d.ts +7 -5
- package/dist/runtime/host/application-job-queue.js +33 -21
- package/dist/runtime/host/bound-session-relay.js +0 -1
- package/dist/runtime/host/channel-runtime-options-factory.d.ts +2 -0
- package/dist/runtime/host/channel-runtime-options-factory.js +1 -0
- package/dist/runtime/host/entry-actor-runtime.d.ts +5 -2
- package/dist/runtime/host/entry-actor-runtime.js +2 -2
- package/dist/runtime/host/index.d.ts +106 -37
- package/dist/runtime/host/index.js +303 -151
- package/dist/runtime/host/location-runtime-owner.d.ts +2 -2
- package/dist/runtime/host/location-runtime-owner.js +1 -1
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +195 -45
- package/dist/runtime/host/service-relocation-host-runtime.js +257 -144
- package/dist/runtime/host/spot-address-transport.d.ts +3 -0
- package/dist/runtime/host/spot-address-transport.js +73 -76
- package/dist/runtime/host/spot-runtime-options-factory.js +2 -0
- package/dist/runtime/host/user-spot-creation-coordinator.d.ts +3 -1
- package/dist/runtime/host/user-spot-creation-coordinator.js +49 -21
- package/dist/runtime/internal-observation.d.ts +1 -0
- package/dist/runtime/internal-observation.js +5 -0
- package/dist/runtime/locations/actor-location-claims.d.ts +1 -1
- package/dist/runtime/locations/actor-location-claims.js +15 -6
- package/dist/runtime/locations/auto-connect-loop.d.ts +0 -1
- package/dist/runtime/locations/auto-connect-loop.js +25 -19
- package/dist/runtime/locations/auto-connect-planner.js +2 -5
- package/dist/runtime/locations/auto-connect-reconciler.d.ts +1 -0
- package/dist/runtime/locations/auto-connect-reconciler.js +35 -23
- package/dist/runtime/locations/in-memory-authority-store.d.ts +1 -0
- package/dist/runtime/locations/in-memory-authority-store.js +15 -5
- package/dist/runtime/locations/in-memory-location-store.d.ts +0 -2
- package/dist/runtime/locations/in-memory-location-store.js +1 -38
- package/dist/runtime/locations/lifecycle.d.ts +1 -1
- package/dist/runtime/locations/lifecycle.js +2 -2
- package/dist/runtime/locations/location-store-repository.d.ts +0 -1
- package/dist/runtime/locations/location-store-repository.js +163 -246
- package/dist/runtime/locations/resolvers.d.ts +8 -1
- package/dist/runtime/locations/resolvers.js +16 -2
- package/dist/runtime/locations/runtime.d.ts +3 -3
- package/dist/runtime/locations/runtime.js +12 -16
- package/dist/runtime/messaging/creation-payload-codec.js +8 -7
- package/dist/runtime/messaging/framework-json-v1.d.ts +1 -1
- package/dist/runtime/messaging/framework-json-v1.js +6 -2
- package/dist/runtime/messaging/payload-codec.js +21 -35
- package/dist/runtime/messaging/request-deadline.d.ts +4 -2
- package/dist/runtime/messaging/request-deadline.js +40 -25
- package/dist/runtime/messaging/request-result.d.ts +14 -1
- package/dist/runtime/messaging/request-result.js +74 -13
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +4 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +17 -7
- package/dist/runtime/spots/index.d.ts +28 -7
- package/dist/runtime/spots/index.js +31 -6
- package/dist/runtime/spots/spot-activation-registry.d.ts +3 -2
- package/dist/runtime/spots/spot-activation-registry.js +13 -8
- package/dist/runtime/spots/spot-activation-state.d.ts +2 -0
- package/dist/runtime/spots/spot-activation-state.js +1 -0
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +9 -4
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +33 -12
- package/dist/runtime/spots/spot-actor-ingress-admission.d.ts +40 -0
- package/dist/runtime/spots/spot-actor-ingress-admission.js +78 -0
- package/dist/runtime/spots/spot-actor-membership.js +3 -3
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +16 -43
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +56 -113
- package/dist/runtime/spots/spot-actor-packet-drain.d.ts +1 -0
- package/dist/runtime/spots/spot-actor-packet-drain.js +12 -5
- package/dist/runtime/spots/spot-entry-activation.d.ts +4 -3
- package/dist/runtime/spots/spot-entry-activation.js +7 -12
- package/dist/runtime/spots/spot-handler-registry.d.ts +5 -1
- package/dist/runtime/spots/spot-handler-registry.js +31 -15
- package/dist/runtime/spots/spot-manager-public.js +3 -2
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +11 -6
- package/dist/runtime/spots/spot-node-runtime-manager.js +6 -1
- package/dist/runtime/spots/spot-outbound.d.ts +8 -2
- package/dist/runtime/spots/spot-outbound.js +5 -5
- package/dist/runtime/spots/spot-route-packet-dispatch.js +13 -8
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +3 -3
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +9 -5
- package/dist/runtime/spots/spot-runtime-ports.d.ts +2 -2
- package/dist/runtime/spots/spot-serial-executor.d.ts +2 -1
- package/dist/runtime/spots/spot-serial-turn-executor.js +20 -26
- package/dist/runtime/spots/spot-subscription-dispatch.js +5 -2
- package/dist/runtime/spots/spot-timer.d.ts +1 -1
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +11 -3
- package/dist/runtime/streams/actor-session-binding-registry.js +28 -0
- package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -2
- package/dist/runtime/streams/bound-actor-relay-sender.js +3 -4
- package/dist/runtime/streams/bound-session-service.js +6 -7
- package/dist/runtime/streams/index.d.ts +3 -3
- package/dist/runtime/streams/index.js +22 -2
- package/dist/runtime/streams/managed-stream.js +2 -1
- package/dist/runtime/streams/session-calls.d.ts +1 -1
- package/dist/runtime/streams/session-calls.js +3 -9
- package/dist/runtime/streams/session-context.d.ts +2 -2
- package/dist/runtime/streams/session-context.js +2 -2
- package/dist/runtime/streams/stream-session-runtime.d.ts +1 -0
- package/dist/runtime/streams/stream-session-runtime.js +64 -33
- package/package.json +3 -3
- package/src/contracts/Actors/ZLinkActor.ts +6 -0
- package/src/contracts/Actors/ZLinkSessionBindingIdentity.ts +7 -0
- package/src/contracts/Actors/index.ts +1 -0
- package/src/contracts/Common/CoreTypes.ts +1 -0
- package/src/contracts/Common/HandlerMessageType.ts +50 -0
- package/src/contracts/Common/ZLinkEncodedPayload.ts +13 -25
- package/src/contracts/Common/ZLinkMessage.ts +11 -7
- package/src/contracts/Common/encoded-payload-storage.ts +4 -16
- package/src/contracts/Common/index.ts +1 -1
- package/src/contracts/Common/payload-slab.ts +29 -0
- package/src/contracts/Configuration/RegistrationBuilders.ts +29 -15
- package/src/contracts/Configuration/RegistrationTypes.ts +19 -0
- package/src/contracts/Handlers/Contexts.ts +1 -0
- package/src/contracts/Locations/Authority.ts +7 -1
- package/src/internal.ts +17 -0
- package/src/nest-integration.ts +1 -0
- package/src/runtime/actors/actor-client.ts +257 -163
- package/src/runtime/actors/actor-context.ts +26 -14
- package/src/runtime/actors/actor-execution-context.ts +2 -2
- package/src/runtime/actors/actor-handoff.ts +86 -51
- package/src/runtime/actors/actor-join-deferred-scope.ts +6 -6
- package/src/runtime/actors/actor-local-native-join.ts +38 -17
- package/src/runtime/actors/actor-mailbox.ts +1 -1
- package/src/runtime/actors/actor-remote-joiner.ts +8 -4
- package/src/runtime/actors/actor-routed-join-transport.ts +13 -5
- package/src/runtime/actors/actor-routed-json-request.ts +3 -0
- package/src/runtime/actors/actor-runtime-contracts.ts +4 -2
- package/src/runtime/actors/actor-runtime-state.ts +1 -1
- package/src/runtime/actors/spot-actor-dispatch.ts +70 -68
- package/src/runtime/admission.ts +42 -15
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +4 -0
- package/src/runtime/backend/contracts/index.ts +77 -10
- package/src/runtime/backend/mesh-completion-table.ts +106 -15
- package/src/runtime/backend/mesh-dispatch-pump.ts +294 -146
- package/src/runtime/backend/node/node-backend-adapter-support.ts +42 -32
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +91 -34
- package/src/runtime/backend/node/node-event-loop-poller.ts +14 -5
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +5 -1
- package/src/runtime/backend/node/node-raw-binding-port.ts +180 -69
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +386 -157
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +56 -11
- package/src/runtime/backend/raw-binding-port.ts +13 -5
- package/src/runtime/channels/channel-clients.ts +26 -11
- package/src/runtime/channels/channel-dispatch-pipeline.ts +77 -65
- package/src/runtime/channels/channel-dispatch-services.ts +7 -12
- package/src/runtime/channels/channel-dispatchers.ts +93 -39
- package/src/runtime/channels/channel-envelope.ts +680 -144
- package/src/runtime/channels/channel-multipart.ts +17 -13
- package/src/runtime/channels/channel-outbound-operations.ts +204 -178
- package/src/runtime/channels/channel-receive-loops.ts +160 -107
- package/src/runtime/channels/channel-runtime-lifecycle.ts +64 -59
- package/src/runtime/channels/channel-runtime-manager.ts +74 -27
- package/src/runtime/channels/channel-socket-registry.ts +20 -5
- package/src/runtime/channels/channel-transports.ts +414 -287
- package/src/runtime/channels/dispatch-error-reporter.ts +4 -9
- package/src/runtime/channels/local-spot-route-transport.ts +27 -29
- package/src/runtime/channels/router-socket-spot-route-transport.ts +63 -32
- package/src/runtime/channels/source-spot-router.ts +75 -38
- package/src/runtime/channels/spot-node-route-transport.ts +67 -37
- package/src/runtime/channels/spot-route-bridge-transport.ts +62 -30
- package/src/runtime/channels/spot-route-dispatch-strategy.ts +105 -34
- package/src/runtime/diagnostics/dispatch-error-details.ts +10 -2
- package/src/runtime/diagnostics/message-flow-bootstrap.ts +6 -0
- package/src/runtime/diagnostics/message-flow-delivery.ts +171 -0
- package/src/runtime/diagnostics/message-flow-record.ts +295 -0
- package/src/runtime/diagnostics/message-flow-worker.ts +146 -0
- package/src/runtime/diagnostics/message-flow.ts +49 -362
- package/src/runtime/diagnostics/runtime-metrics.ts +10 -4
- package/src/runtime/execution/index.ts +6 -0
- package/src/runtime/execution/serial-execution-queue.ts +94 -96
- package/src/runtime/foundation/durable-service-request.ts +212 -89
- package/src/runtime/foundation/operation-registry.ts +287 -38
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +617 -292
- package/src/runtime/foundation/request-runtime.ts +227 -0
- package/src/runtime/foundation/service-discovery-registry.ts +7 -0
- package/src/runtime/foundation/service-liveness-registry.ts +1 -1
- package/src/runtime/foundation/service-mailbox.ts +7 -2
- package/src/runtime/foundation/service-relocation-object-owner.ts +21 -6
- package/src/runtime/foundation/service-runtime-contracts.ts +12 -2
- package/src/runtime/foundation/service-stateful-registry.ts +52 -19
- package/src/runtime/foundation/service-stateful-runtime.ts +365 -198
- package/src/runtime/foundation/service-stateful-wire-codec.ts +18 -0
- package/src/runtime/foundation/service-topology-registry.ts +21 -3
- package/src/runtime/foundation/service-wire-constants.generated.ts +10 -0
- package/src/runtime/foundation/service-wire-m6a-codec.ts +69 -17
- package/src/runtime/host/actor-packet-relay.ts +160 -156
- package/src/runtime/host/actor-placement-coordinator.ts +1 -1
- package/src/runtime/host/actor-runtime-options-factory.ts +7 -2
- package/src/runtime/host/actor-transfer-runtime.ts +3 -3
- package/src/runtime/host/application-job-queue.ts +56 -27
- package/src/runtime/host/bound-session-relay.ts +0 -1
- package/src/runtime/host/channel-runtime-options-factory.ts +3 -0
- package/src/runtime/host/entry-actor-runtime.ts +14 -6
- package/src/runtime/host/index.ts +388 -113
- package/src/runtime/host/location-runtime-owner.ts +3 -3
- package/src/runtime/host/service-relocation-host-runtime.ts +380 -252
- package/src/runtime/host/spot-address-transport.ts +110 -95
- package/src/runtime/host/spot-runtime-options-factory.ts +3 -0
- package/src/runtime/host/user-spot-creation-coordinator.ts +69 -22
- package/src/runtime/internal-observation.ts +2 -0
- package/src/runtime/locations/actor-location-claims.ts +42 -16
- package/src/runtime/locations/auto-connect-loop.ts +24 -16
- package/src/runtime/locations/auto-connect-planner.ts +2 -5
- package/src/runtime/locations/auto-connect-reconciler.ts +37 -24
- package/src/runtime/locations/in-memory-authority-store.ts +27 -7
- package/src/runtime/locations/in-memory-location-store.ts +1 -74
- package/src/runtime/locations/lifecycle.ts +4 -2
- package/src/runtime/locations/location-store-repository.ts +228 -308
- package/src/runtime/locations/resolvers.ts +20 -8
- package/src/runtime/locations/runtime.ts +16 -28
- package/src/runtime/messaging/creation-payload-codec.ts +12 -10
- package/src/runtime/messaging/framework-json-v1.ts +10 -1
- package/src/runtime/messaging/payload-codec.ts +50 -75
- package/src/runtime/messaging/request-deadline.ts +47 -39
- package/src/runtime/messaging/request-result.ts +88 -17
- package/src/runtime/protocol/service_wire_codec.generated.ts +18 -8
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
- package/src/runtime/spots/index.ts +57 -10
- package/src/runtime/spots/spot-activation-registry.ts +12 -8
- package/src/runtime/spots/spot-activation-state.ts +2 -0
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +62 -37
- package/src/runtime/spots/spot-actor-ingress-admission.ts +157 -0
- package/src/runtime/spots/spot-actor-membership.ts +8 -5
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +122 -206
- package/src/runtime/spots/spot-actor-packet-drain.ts +21 -6
- package/src/runtime/spots/spot-entry-activation.ts +25 -35
- package/src/runtime/spots/spot-handler-registry.ts +72 -15
- package/src/runtime/spots/spot-manager-public.ts +4 -2
- package/src/runtime/spots/spot-node-runtime-manager.ts +16 -7
- package/src/runtime/spots/spot-outbound.ts +26 -10
- package/src/runtime/spots/spot-route-packet-dispatch.ts +18 -8
- package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +14 -8
- package/src/runtime/spots/spot-runtime-ports.ts +5 -2
- package/src/runtime/spots/spot-serial-executor.ts +1 -1
- package/src/runtime/spots/spot-serial-turn-executor.ts +25 -40
- package/src/runtime/spots/spot-subscription-dispatch.ts +9 -2
- package/src/runtime/spots/spot-timer.ts +1 -1
- package/src/runtime/streams/actor-session-binding-registry.ts +46 -3
- package/src/runtime/streams/bound-actor-relay-sender.ts +16 -5
- package/src/runtime/streams/bound-session-service.ts +10 -7
- package/src/runtime/streams/index.ts +30 -4
- package/src/runtime/streams/managed-stream.ts +2 -1
- package/src/runtime/streams/session-calls.ts +9 -14
- package/src/runtime/streams/session-context.ts +6 -11
- package/src/runtime/streams/stream-session-runtime.ts +79 -40
- package/dist/runtime/spots/spot-lifecycle-metrics.d.ts +0 -8
- package/dist/runtime/spots/spot-lifecycle-metrics.js +0 -17
- package/src/runtime/spots/spot-lifecycle-metrics.ts +0 -16
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import type { Message } from '../../contracts/Common/Message';
|
|
2
|
-
import { ZLinkBufferMessage } from '../backend/runtime-message';
|
|
3
2
|
import type { ZLinkBackendMessageLike as MessageLike } from '../backend/runtime-values';
|
|
4
3
|
import { randomBytes } from 'node:crypto';
|
|
5
4
|
import { isUtf8 } from 'node:buffer';
|
|
6
5
|
import {
|
|
6
|
+
type Type,
|
|
7
7
|
ZLinkFrameworkErrorKind,
|
|
8
8
|
ZLinkFrameworkException,
|
|
9
9
|
type ZLinkMessageSerializer,
|
|
10
10
|
type ZLinkFlowOrigin
|
|
11
11
|
} from '../../contracts';
|
|
12
12
|
import { borrowEncodedPayload } from '../../contracts/Common/encoded-payload-storage';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
isZLinkMessage,
|
|
15
|
+
materializeZLinkMessageValue,
|
|
16
|
+
readZLinkMessageDeclaredType
|
|
17
|
+
} from '../../contracts/Common/ZLinkMessage';
|
|
14
18
|
import { ZLinkConfigurationException } from '../configuration';
|
|
15
19
|
import {
|
|
16
20
|
ZLinkFrameworkInternalErrorKind,
|
|
@@ -98,7 +102,7 @@ const CHANNEL_CORRELATION_TEXT = /^[0-9a-f]{32}$/;
|
|
|
98
102
|
const CHANNEL_FLOW_FIELD = ',"flowId":';
|
|
99
103
|
// A flow id is a lowercase UUIDv7 (spec 27 §3): fixed 36 JSON-safe ASCII bytes.
|
|
100
104
|
const PREPARED_CHANNEL_FLOW = '00000000-0000-7000-8000-000000000000';
|
|
101
|
-
const CHANNEL_FLOW_TEXT = /^[0-9a-f-]{
|
|
105
|
+
const CHANNEL_FLOW_TEXT = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
102
106
|
|
|
103
107
|
// A per-process random 64-bit prefix followed by a per-process counter, both
|
|
104
108
|
// as lowercase hex: unique among the runtime's pending requests (spec 06-obs/04
|
|
@@ -109,9 +113,11 @@ let channelCorrelationCounter = 0;
|
|
|
109
113
|
|
|
110
114
|
export function newChannelCorrelationId(): string {
|
|
111
115
|
channelCorrelationCounter += 1;
|
|
116
|
+
const suffix = channelCorrelationCounter.toString(16);
|
|
112
117
|
return (
|
|
113
118
|
CHANNEL_CORRELATION_PREFIX +
|
|
114
|
-
|
|
119
|
+
PREPARED_CHANNEL_CORRELATION.slice(suffix.length, CHANNEL_CORRELATION_TEXT_LENGTH / 2) +
|
|
120
|
+
suffix
|
|
115
121
|
);
|
|
116
122
|
}
|
|
117
123
|
|
|
@@ -166,33 +172,21 @@ export function encodeChannelEnvelopePartsAtDeadline(
|
|
|
166
172
|
throw new RangeError('deadlineUnixMs must be a positive safe integer.');
|
|
167
173
|
}
|
|
168
174
|
const messageName = resolveFrameworkPacketName(payload, packetName, 'Channel');
|
|
169
|
-
|
|
175
|
+
return encodePayload(
|
|
170
176
|
payload,
|
|
171
177
|
codecsForFrameworkPacket(messageName, codecs),
|
|
172
178
|
messageName,
|
|
173
|
-
'payload'
|
|
179
|
+
'payload',
|
|
180
|
+
kind,
|
|
181
|
+
channelName,
|
|
182
|
+
correlationId,
|
|
183
|
+
deadlineUnixMs,
|
|
184
|
+
topic,
|
|
185
|
+
createFlow,
|
|
186
|
+
metadata,
|
|
187
|
+
undefined,
|
|
188
|
+
codecs
|
|
174
189
|
);
|
|
175
|
-
const flow = createFlow ? currentOrCreateFlow('Application') : undefined;
|
|
176
|
-
const envelopeCorrelationId = correlationIdForOutboundKind(kind, correlationId);
|
|
177
|
-
return [
|
|
178
|
-
encodeChannelHeader(
|
|
179
|
-
kind,
|
|
180
|
-
channelName,
|
|
181
|
-
messageName,
|
|
182
|
-
encoded.contentType,
|
|
183
|
-
envelopeCorrelationId,
|
|
184
|
-
deadlineUnixMs === undefined ? null : new Date(deadlineUnixMs).toISOString(),
|
|
185
|
-
topic ?? null,
|
|
186
|
-
null,
|
|
187
|
-
null,
|
|
188
|
-
undefined,
|
|
189
|
-
applicationMetadataRecord(metadata),
|
|
190
|
-
flow?.flowId,
|
|
191
|
-
flow?.flowOrigin,
|
|
192
|
-
codecs
|
|
193
|
-
),
|
|
194
|
-
encoded.message
|
|
195
|
-
];
|
|
196
190
|
}
|
|
197
191
|
|
|
198
192
|
export function encodeChannelPublishEnvelopeParts(
|
|
@@ -205,31 +199,19 @@ export function encodeChannelPublishEnvelopeParts(
|
|
|
205
199
|
metadata: ReadonlyMap<string, string> = EMPTY_OUTBOUND_METADATA
|
|
206
200
|
): readonly MessageLike[] {
|
|
207
201
|
const messageName = resolveFrameworkPacketName(payload, packetName, 'Channel');
|
|
208
|
-
|
|
202
|
+
return encodePayload(
|
|
209
203
|
payload,
|
|
210
204
|
codecsForFrameworkPacket(messageName, codecs),
|
|
211
205
|
messageName,
|
|
212
|
-
'payload'
|
|
206
|
+
'payload',
|
|
207
|
+
ZLinkChannelMessageKind.Publish,
|
|
208
|
+
channelName,
|
|
209
|
+
undefined,
|
|
210
|
+
undefined,
|
|
211
|
+
topic,
|
|
212
|
+
createFlow,
|
|
213
|
+
metadata
|
|
213
214
|
);
|
|
214
|
-
const flow = createFlow ? currentOrCreateFlow('Application') : undefined;
|
|
215
|
-
return [
|
|
216
|
-
encodeChannelHeader(
|
|
217
|
-
ZLinkChannelMessageKind.Publish,
|
|
218
|
-
channelName,
|
|
219
|
-
messageName,
|
|
220
|
-
encoded.contentType,
|
|
221
|
-
null,
|
|
222
|
-
null,
|
|
223
|
-
topic,
|
|
224
|
-
null,
|
|
225
|
-
null,
|
|
226
|
-
undefined,
|
|
227
|
-
applicationMetadataRecord(metadata),
|
|
228
|
-
flow?.flowId,
|
|
229
|
-
flow?.flowOrigin
|
|
230
|
-
),
|
|
231
|
-
encoded.message
|
|
232
|
-
];
|
|
233
215
|
}
|
|
234
216
|
|
|
235
217
|
export function encodeChannelReplyParts(
|
|
@@ -237,31 +219,21 @@ export function encodeChannelReplyParts(
|
|
|
237
219
|
payload: unknown,
|
|
238
220
|
codecs?: ZLinkChannelEnvelopeCodecRegistry
|
|
239
221
|
): readonly MessageLike[] {
|
|
240
|
-
|
|
222
|
+
return encodePayload(
|
|
241
223
|
payload ?? Buffer.alloc(0),
|
|
242
224
|
codecsForFrameworkPacket(request.messageName, codecs),
|
|
243
225
|
request.messageName,
|
|
244
|
-
'reply'
|
|
226
|
+
'reply',
|
|
227
|
+
ZLinkChannelMessageKind.Response,
|
|
228
|
+
request.channelName,
|
|
229
|
+
request.correlationId ?? undefined,
|
|
230
|
+
undefined,
|
|
231
|
+
undefined,
|
|
232
|
+
false,
|
|
233
|
+
EMPTY_OUTBOUND_METADATA,
|
|
234
|
+
request,
|
|
235
|
+
codecs
|
|
245
236
|
);
|
|
246
|
-
return [
|
|
247
|
-
encodeChannelHeader(
|
|
248
|
-
ZLinkChannelMessageKind.Response,
|
|
249
|
-
request.channelName,
|
|
250
|
-
request.messageName,
|
|
251
|
-
encoded.contentType,
|
|
252
|
-
request.correlationId,
|
|
253
|
-
null,
|
|
254
|
-
null,
|
|
255
|
-
undefined,
|
|
256
|
-
undefined,
|
|
257
|
-
undefined,
|
|
258
|
-
EMPTY_APPLICATION_METADATA,
|
|
259
|
-
request.flowId,
|
|
260
|
-
request.flowOrigin,
|
|
261
|
-
codecs
|
|
262
|
-
),
|
|
263
|
-
encoded.message
|
|
264
|
-
];
|
|
265
237
|
}
|
|
266
238
|
|
|
267
239
|
/**
|
|
@@ -342,7 +314,7 @@ export function encodeChannelErrorReplyParts(
|
|
|
342
314
|
request.flowId,
|
|
343
315
|
request.flowOrigin
|
|
344
316
|
),
|
|
345
|
-
|
|
317
|
+
encodeJsonText(null)
|
|
346
318
|
];
|
|
347
319
|
}
|
|
348
320
|
|
|
@@ -368,20 +340,18 @@ export function decodeChannelReply<TReply>(
|
|
|
368
340
|
) {
|
|
369
341
|
throw unsupportedChannelContentType(header.contentType);
|
|
370
342
|
}
|
|
371
|
-
|
|
343
|
+
const body = parts.length < 2 ? undefined : parts[1].data();
|
|
344
|
+
if (body === undefined || body.length === 0) {
|
|
372
345
|
return undefined as TReply;
|
|
373
346
|
}
|
|
374
347
|
if (header.contentType === BINARY_CONTENT_TYPE) {
|
|
375
|
-
return
|
|
348
|
+
return body as TReply;
|
|
376
349
|
}
|
|
377
350
|
if (serializer !== undefined) {
|
|
378
|
-
return serializer.deserialize<TReply>(
|
|
379
|
-
encodedPayloadFromOwned(parts[1].data()),
|
|
380
|
-
Object as never
|
|
381
|
-
);
|
|
351
|
+
return serializer.deserialize<TReply>(encodedPayloadFromOwned(body), Object as never);
|
|
382
352
|
}
|
|
383
353
|
return parseWireJson(
|
|
384
|
-
|
|
354
|
+
body.toString(),
|
|
385
355
|
readZLinkPacketJsonContract(header.messageName)?.reply
|
|
386
356
|
) as TReply;
|
|
387
357
|
}
|
|
@@ -442,7 +412,8 @@ export function decodeChannelEnvelope(
|
|
|
442
412
|
|
|
443
413
|
export function decodeChannelPayload(
|
|
444
414
|
envelope: ZLinkChannelEnvelope,
|
|
445
|
-
codecs?: ZLinkChannelEnvelopeCodecRegistry
|
|
415
|
+
codecs?: ZLinkChannelEnvelopeCodecRegistry,
|
|
416
|
+
messageType?: Type
|
|
446
417
|
): unknown {
|
|
447
418
|
try {
|
|
448
419
|
if (!isCanonicalCodecContentType(envelope.header.contentType)) {
|
|
@@ -450,7 +421,10 @@ export function decodeChannelPayload(
|
|
|
450
421
|
}
|
|
451
422
|
const serializer = codecs?.serializers.get(envelope.header.contentType);
|
|
452
423
|
if (serializer !== undefined) {
|
|
453
|
-
return serializer.deserialize(
|
|
424
|
+
return serializer.deserialize(
|
|
425
|
+
encodedPayloadFromOwned(envelope.payload),
|
|
426
|
+
(messageType ?? Object) as never
|
|
427
|
+
);
|
|
454
428
|
}
|
|
455
429
|
if (envelope.header.contentType === BINARY_CONTENT_TYPE) {
|
|
456
430
|
// The receive loop owns the Message for the duration of dispatch, so
|
|
@@ -458,9 +432,12 @@ export function decodeChannelPayload(
|
|
|
458
432
|
return envelope.payload;
|
|
459
433
|
}
|
|
460
434
|
if (envelope.header.contentType === JSON_CONTENT_TYPE) {
|
|
461
|
-
return
|
|
462
|
-
|
|
463
|
-
|
|
435
|
+
return materializeZLinkMessageValue(
|
|
436
|
+
parseWireJson(
|
|
437
|
+
envelope.payload.toString(),
|
|
438
|
+
schemaForInboundChannelEnvelope(envelope.header)
|
|
439
|
+
),
|
|
440
|
+
messageType
|
|
464
441
|
);
|
|
465
442
|
}
|
|
466
443
|
throw unsupportedChannelContentType(envelope.header.contentType);
|
|
@@ -495,42 +472,71 @@ function encodePayload(
|
|
|
495
472
|
value: unknown,
|
|
496
473
|
codecs: ZLinkChannelEnvelopeCodecRegistry | undefined,
|
|
497
474
|
packetName: string,
|
|
498
|
-
contractPart: 'payload' | 'reply'
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
475
|
+
contractPart: 'payload' | 'reply',
|
|
476
|
+
kind: ZLinkChannelMessageKind,
|
|
477
|
+
channelName: string,
|
|
478
|
+
correlationId: string | undefined,
|
|
479
|
+
deadlineUnixMs: number | undefined,
|
|
480
|
+
topic: string | undefined,
|
|
481
|
+
createFlow: boolean,
|
|
482
|
+
metadata: ReadonlyMap<string, string>,
|
|
483
|
+
request?: ZLinkChannelEnvelopeHeader,
|
|
484
|
+
headerCodecs?: ZLinkChannelEnvelopeCodecRegistry
|
|
485
|
+
): readonly MessageLike[] {
|
|
486
|
+
let declaredType;
|
|
487
|
+
let contentType: string;
|
|
488
|
+
let message: MessageLike;
|
|
503
489
|
if (isZLinkMessage(value) && value.isEncoded()) {
|
|
504
490
|
const payload = value.toEncodedPayload();
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
491
|
+
contentType = BINARY_CONTENT_TYPE;
|
|
492
|
+
message = borrowEncodedPayload(payload) ?? payload.data();
|
|
493
|
+
} else {
|
|
494
|
+
if (isZLinkMessage(value)) {
|
|
495
|
+
declaredType = readZLinkMessageDeclaredType(value);
|
|
496
|
+
value = value.decode();
|
|
497
|
+
}
|
|
498
|
+
const selected = selectSerializerWithContentType(value, codecs, declaredType);
|
|
499
|
+
if (
|
|
500
|
+
selected !== undefined &&
|
|
501
|
+
!(Buffer.isBuffer(value) || value instanceof Uint8Array || isMessage(value))
|
|
502
|
+
) {
|
|
503
|
+
const payload = selected.serializer.serialize(value);
|
|
504
|
+
contentType = selected.contentType;
|
|
505
|
+
message = borrowEncodedPayload(payload) ?? payload.data();
|
|
506
|
+
} else {
|
|
507
|
+
contentType = contentTypeOf(value);
|
|
508
|
+
message = toMessageLike(value, readZLinkPacketJsonContract(packetName)?.[contractPart]);
|
|
509
|
+
}
|
|
522
510
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
511
|
+
const flow = request ?? (createFlow ? currentOrCreateFlow('Application') : undefined);
|
|
512
|
+
return [
|
|
513
|
+
encodeChannelHeader(
|
|
514
|
+
kind,
|
|
515
|
+
channelName,
|
|
516
|
+
packetName,
|
|
517
|
+
contentType,
|
|
518
|
+
request === undefined
|
|
519
|
+
? correlationIdForOutboundKind(kind, correlationId)
|
|
520
|
+
: request.correlationId,
|
|
521
|
+
deadlineUnixMs === undefined ? null : new Date(deadlineUnixMs).toISOString(),
|
|
522
|
+
topic ?? null,
|
|
523
|
+
contractPart === 'reply' ? undefined : null,
|
|
524
|
+
contractPart === 'reply' ? undefined : null,
|
|
525
|
+
undefined,
|
|
526
|
+
applicationMetadataRecord(metadata),
|
|
527
|
+
flow?.flowId,
|
|
528
|
+
flow?.flowOrigin,
|
|
529
|
+
headerCodecs
|
|
530
|
+
),
|
|
531
|
+
message
|
|
532
|
+
];
|
|
527
533
|
}
|
|
528
534
|
|
|
529
535
|
function toMessageLike(value: unknown, schema?: ZLinkJsonSchema): MessageLike {
|
|
530
536
|
if (Buffer.isBuffer(value) || value instanceof Uint8Array || isMessage(value)) {
|
|
531
537
|
return value;
|
|
532
538
|
}
|
|
533
|
-
return
|
|
539
|
+
return encodeJsonText(value, schema);
|
|
534
540
|
}
|
|
535
541
|
|
|
536
542
|
function contentTypeOf(value: unknown): string {
|
|
@@ -547,8 +553,8 @@ function isMessage(value: unknown): value is Message {
|
|
|
547
553
|
);
|
|
548
554
|
}
|
|
549
555
|
|
|
550
|
-
function
|
|
551
|
-
return
|
|
556
|
+
function encodeJsonText(value: unknown, schema?: ZLinkJsonSchema): string {
|
|
557
|
+
return stringifyFrameworkJsonV1(value, schema);
|
|
552
558
|
}
|
|
553
559
|
|
|
554
560
|
function encodeChannelHeader(
|
|
@@ -887,44 +893,77 @@ export function decodeChannelHeader(
|
|
|
887
893
|
if (parts.length === 0) {
|
|
888
894
|
throw new ZLinkConfigurationException('Channel envelope header part is missing.');
|
|
889
895
|
}
|
|
890
|
-
return validateChannelHeader(parseChannelHeaderBytes(parts[0].data()), flowEnabled);
|
|
896
|
+
return validateChannelHeader(parseChannelHeaderBytes(parts[0].data(), flowEnabled), flowEnabled);
|
|
891
897
|
}
|
|
892
898
|
|
|
899
|
+
const CHANNEL_JSON_PARSE_OPTIONS = Object.freeze({ rejectPropertyName: isPrototypeKey });
|
|
900
|
+
|
|
893
901
|
function parseWireJson(payload: string, schema?: ZLinkJsonSchema): unknown {
|
|
894
|
-
return parseFrameworkJsonV1(
|
|
895
|
-
payload,
|
|
896
|
-
{
|
|
897
|
-
rejectPropertyName: isPrototypeKey
|
|
898
|
-
},
|
|
899
|
-
schema
|
|
900
|
-
);
|
|
902
|
+
return parseFrameworkJsonV1(payload, CHANNEL_JSON_PARSE_OPTIONS, schema);
|
|
901
903
|
}
|
|
902
904
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
905
|
+
const CHANNEL_HEADER_FIELD_NAMES = [
|
|
906
|
+
'',
|
|
907
|
+
'formatMarker',
|
|
908
|
+
'kind',
|
|
909
|
+
'channelName',
|
|
910
|
+
'messageName',
|
|
911
|
+
'contentType',
|
|
912
|
+
'correlationId',
|
|
913
|
+
'deadline',
|
|
914
|
+
'topic',
|
|
915
|
+
'errorCode',
|
|
916
|
+
'errorMessage',
|
|
917
|
+
'source',
|
|
918
|
+
'flowId',
|
|
919
|
+
'flowOrigin',
|
|
920
|
+
'metadata'
|
|
921
|
+
] as const;
|
|
922
|
+
const CHANNEL_HEADER_FIELD_COUNT = CHANNEL_HEADER_FIELD_NAMES.length - 1;
|
|
923
|
+
const CHANNEL_HEADER_INVALID_VALUE = Symbol('invalid channel header value');
|
|
924
|
+
const CANONICAL_CHANNEL_HEADER_PREFIX = '{"formatMarker":242,"kind":';
|
|
925
|
+
|
|
926
|
+
function parseChannelHeaderBytes(payload: Buffer, flowEnabled: boolean): unknown {
|
|
927
|
+
if (startsWithJson(payload, CANONICAL_CHANNEL_HEADER_PREFIX)) {
|
|
928
|
+
const reader = new CanonicalChannelHeaderReader(
|
|
929
|
+
payload,
|
|
930
|
+
CANONICAL_CHANNEL_HEADER_PREFIX.length
|
|
931
|
+
);
|
|
932
|
+
const canonical = tryParseCanonicalChannelHeader(reader, flowEnabled);
|
|
933
|
+
// Canonical ASCII headers need no UTF-8 pass; all other paths are checked
|
|
934
|
+
// before byte slices are decoded.
|
|
935
|
+
if (canonical !== undefined && !reader.sawNonAscii) return canonical;
|
|
936
|
+
if (canonical !== undefined) {
|
|
937
|
+
if (!isUtf8(payload)) {
|
|
938
|
+
throw new ZLinkFrameworkException(
|
|
939
|
+
ZLinkFrameworkErrorKind.ProtocolError,
|
|
940
|
+
'Channel envelope header must contain valid UTF-8.'
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
return canonical;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
909
946
|
if (!isUtf8(payload)) {
|
|
910
947
|
throw new ZLinkFrameworkException(
|
|
911
948
|
ZLinkFrameworkErrorKind.ProtocolError,
|
|
912
949
|
'Channel envelope header must contain valid UTF-8.'
|
|
913
950
|
);
|
|
914
951
|
}
|
|
915
|
-
return
|
|
952
|
+
return new ChannelHeaderJsonReader(payload, flowEnabled).parse();
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
function startsWithJson(bytes: Buffer, value: string): boolean {
|
|
956
|
+
if (bytes.length < value.length) return false;
|
|
957
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
958
|
+
if (bytes[index] !== value.charCodeAt(index)) return false;
|
|
959
|
+
}
|
|
960
|
+
return true;
|
|
916
961
|
}
|
|
917
962
|
|
|
918
|
-
/**
|
|
919
|
-
* Accept the byte layout emitted by writeChannelHeader without materializing
|
|
920
|
-
* the enclosing JSON text. Any variation falls through to the established
|
|
921
|
-
* framework-json-v1 parser, which remains the sole authority for JSON
|
|
922
|
-
* failures and unknown properties. Header metadata accepts every valid string key.
|
|
923
|
-
*/
|
|
924
963
|
function tryParseCanonicalChannelHeader(
|
|
925
|
-
reader: CanonicalChannelHeaderReader
|
|
964
|
+
reader: CanonicalChannelHeaderReader,
|
|
965
|
+
flowEnabled: boolean
|
|
926
966
|
): Record<string, unknown> | undefined {
|
|
927
|
-
if (!reader.consume('{"formatMarker":242,"kind":')) return undefined;
|
|
928
967
|
const kind = reader.readSingleDigit();
|
|
929
968
|
if (kind === undefined || !reader.consume(',"channelName":')) return undefined;
|
|
930
969
|
const channelName = reader.readString();
|
|
@@ -948,16 +987,25 @@ function tryParseCanonicalChannelHeader(
|
|
|
948
987
|
contentType,
|
|
949
988
|
correlationId: correlationId === NULL_JSON_STRING ? null : correlationId,
|
|
950
989
|
deadline: deadline === NULL_JSON_STRING ? null : deadline,
|
|
951
|
-
topic: topic === NULL_JSON_STRING ? null : topic
|
|
990
|
+
topic: topic === NULL_JSON_STRING ? null : topic,
|
|
991
|
+
errorCode: null,
|
|
992
|
+
errorMessage: null,
|
|
993
|
+
source: undefined,
|
|
994
|
+
metadata: undefined,
|
|
995
|
+
flowId: undefined,
|
|
996
|
+
flowOrigin: undefined
|
|
952
997
|
};
|
|
953
998
|
if (!reader.readOptionalNullableString(CANONICAL_ERROR_CODE, 'errorCode', header))
|
|
954
999
|
return undefined;
|
|
955
1000
|
if (!reader.readOptionalNullableString(CANONICAL_ERROR_MESSAGE, 'errorMessage', header))
|
|
956
1001
|
return undefined;
|
|
957
1002
|
if (!reader.readOptionalNullableString(CANONICAL_SOURCE, 'source', header)) return undefined;
|
|
1003
|
+
const metadata = reader.readMetadata();
|
|
1004
|
+
if (metadata === undefined) return undefined;
|
|
958
1005
|
// Empty metadata validates to the shared empty record.
|
|
959
|
-
if (
|
|
960
|
-
if (!reader.readOptionalString(CANONICAL_FLOW_ID, 'flowId', header))
|
|
1006
|
+
if (metadata !== NULL_JSON_STRING) header.metadata = metadata;
|
|
1007
|
+
if (!reader.readOptionalString(CANONICAL_FLOW_ID, 'flowId', header, flowEnabled))
|
|
1008
|
+
return undefined;
|
|
961
1009
|
if (!reader.readOptionalSingleDigit(CANONICAL_FLOW_ORIGIN, 'flowOrigin', header))
|
|
962
1010
|
return undefined;
|
|
963
1011
|
return reader.consume('}') && reader.atEnd() ? header : undefined;
|
|
@@ -976,7 +1024,12 @@ class CanonicalChannelHeaderReader {
|
|
|
976
1024
|
/** A string held a byte outside ASCII, so the caller must still check UTF-8. */
|
|
977
1025
|
sawNonAscii = false;
|
|
978
1026
|
|
|
979
|
-
constructor(
|
|
1027
|
+
constructor(
|
|
1028
|
+
private readonly bytes: Buffer,
|
|
1029
|
+
initialIndex = 0
|
|
1030
|
+
) {
|
|
1031
|
+
this.index = initialIndex;
|
|
1032
|
+
}
|
|
980
1033
|
|
|
981
1034
|
atEnd(): boolean {
|
|
982
1035
|
return this.index === this.bytes.length;
|
|
@@ -1045,6 +1098,37 @@ class CanonicalChannelHeaderReader {
|
|
|
1045
1098
|
return this.readString();
|
|
1046
1099
|
}
|
|
1047
1100
|
|
|
1101
|
+
readMetadata(): Record<string, unknown> | symbol | undefined {
|
|
1102
|
+
if (!this.consume(',"metadata":{')) return undefined;
|
|
1103
|
+
if (this.consume('}')) return NULL_JSON_STRING;
|
|
1104
|
+
const metadata: Record<string, unknown> = {};
|
|
1105
|
+
for (;;) {
|
|
1106
|
+
const key = this.readString();
|
|
1107
|
+
if (key === undefined) return undefined;
|
|
1108
|
+
if (Object.prototype.hasOwnProperty.call(metadata, key)) {
|
|
1109
|
+
throw new ZLinkFrameworkException(
|
|
1110
|
+
ZLinkFrameworkErrorKind.ProtocolError,
|
|
1111
|
+
'duplicate envelope metadata key'
|
|
1112
|
+
);
|
|
1113
|
+
}
|
|
1114
|
+
if (!this.consume(':')) return undefined;
|
|
1115
|
+
const value = this.readString();
|
|
1116
|
+
if (value === undefined) return undefined;
|
|
1117
|
+
if (key === '__proto__') {
|
|
1118
|
+
Object.defineProperty(metadata, key, {
|
|
1119
|
+
configurable: true,
|
|
1120
|
+
enumerable: true,
|
|
1121
|
+
value,
|
|
1122
|
+
writable: true
|
|
1123
|
+
});
|
|
1124
|
+
} else {
|
|
1125
|
+
metadata[key] = value;
|
|
1126
|
+
}
|
|
1127
|
+
if (this.consume('}')) return metadata;
|
|
1128
|
+
if (!this.consume(',')) return undefined;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1048
1132
|
readOptionalNullableString(
|
|
1049
1133
|
token: string,
|
|
1050
1134
|
name: string,
|
|
@@ -1057,14 +1141,53 @@ class CanonicalChannelHeaderReader {
|
|
|
1057
1141
|
return true;
|
|
1058
1142
|
}
|
|
1059
1143
|
|
|
1060
|
-
readOptionalString(
|
|
1144
|
+
readOptionalString(
|
|
1145
|
+
token: string,
|
|
1146
|
+
name: string,
|
|
1147
|
+
target: Record<string, unknown>,
|
|
1148
|
+
decode = true
|
|
1149
|
+
): boolean {
|
|
1061
1150
|
if (!this.consume(token)) return true;
|
|
1151
|
+
if (!decode) return this.skipString();
|
|
1062
1152
|
const value = this.readString();
|
|
1063
1153
|
if (value === undefined) return false;
|
|
1064
1154
|
target[name] = value;
|
|
1065
1155
|
return true;
|
|
1066
1156
|
}
|
|
1067
1157
|
|
|
1158
|
+
private skipString(): boolean {
|
|
1159
|
+
if (this.bytes[this.index] !== 0x22) return false;
|
|
1160
|
+
this.index += 1;
|
|
1161
|
+
while (this.index < this.bytes.length) {
|
|
1162
|
+
const value = this.bytes[this.index++]!;
|
|
1163
|
+
if (value === 0x22) return true;
|
|
1164
|
+
if (value < 0x20) return false;
|
|
1165
|
+
if (value >= 0x80) this.sawNonAscii = true;
|
|
1166
|
+
if (value !== 0x5c) continue;
|
|
1167
|
+
if (this.index === this.bytes.length) return false;
|
|
1168
|
+
const escaped = this.bytes[this.index++]!;
|
|
1169
|
+
if (escaped === 0x75) {
|
|
1170
|
+
for (let count = 0; count < 4; count += 1) {
|
|
1171
|
+
if (this.index === this.bytes.length || !isHexDigit(this.bytes[this.index]!))
|
|
1172
|
+
return false;
|
|
1173
|
+
this.index += 1;
|
|
1174
|
+
}
|
|
1175
|
+
} else if (
|
|
1176
|
+
escaped !== 0x22 &&
|
|
1177
|
+
escaped !== 0x5c &&
|
|
1178
|
+
escaped !== 0x2f &&
|
|
1179
|
+
escaped !== 0x62 &&
|
|
1180
|
+
escaped !== 0x66 &&
|
|
1181
|
+
escaped !== 0x6e &&
|
|
1182
|
+
escaped !== 0x72 &&
|
|
1183
|
+
escaped !== 0x74
|
|
1184
|
+
) {
|
|
1185
|
+
return false;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1068
1191
|
readOptionalSingleDigit(token: string, name: string, target: Record<string, unknown>): boolean {
|
|
1069
1192
|
if (!this.consume(token)) return true;
|
|
1070
1193
|
const value = this.readSingleDigit();
|
|
@@ -1082,6 +1205,418 @@ function isHexDigit(value: number): boolean {
|
|
|
1082
1205
|
);
|
|
1083
1206
|
}
|
|
1084
1207
|
|
|
1208
|
+
/** Reads a noncanonical channel header directly from its UTF-8 bytes. */
|
|
1209
|
+
class ChannelHeaderJsonReader {
|
|
1210
|
+
private index = 0;
|
|
1211
|
+
private propertyName = '';
|
|
1212
|
+
private stringStart = 0;
|
|
1213
|
+
private stringEnd = 0;
|
|
1214
|
+
private stringHasEscapes = false;
|
|
1215
|
+
|
|
1216
|
+
constructor(
|
|
1217
|
+
private readonly bytes: Buffer,
|
|
1218
|
+
private readonly flowEnabled: boolean
|
|
1219
|
+
) {}
|
|
1220
|
+
|
|
1221
|
+
parse(): unknown {
|
|
1222
|
+
if (
|
|
1223
|
+
this.bytes.length >= 3 &&
|
|
1224
|
+
this.bytes[0] === 0xef &&
|
|
1225
|
+
this.bytes[1] === 0xbb &&
|
|
1226
|
+
this.bytes[2] === 0xbf
|
|
1227
|
+
) {
|
|
1228
|
+
throw new SyntaxError('framework-json-v1 does not allow a UTF-8 BOM.');
|
|
1229
|
+
}
|
|
1230
|
+
this.skipWhitespace();
|
|
1231
|
+
if (this.bytes[this.index] !== 0x7b) {
|
|
1232
|
+
this.skipValue();
|
|
1233
|
+
this.skipWhitespace();
|
|
1234
|
+
if (this.index !== this.bytes.length) this.fail('trailing data');
|
|
1235
|
+
return CHANNEL_HEADER_INVALID_VALUE;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
const header: Record<string, unknown> = {};
|
|
1239
|
+
let seenFields = 0;
|
|
1240
|
+
this.index += 1;
|
|
1241
|
+
this.skipWhitespace();
|
|
1242
|
+
if (this.consumeByte(0x7d)) return this.finish(header);
|
|
1243
|
+
|
|
1244
|
+
for (;;) {
|
|
1245
|
+
const field = this.readPropertyName(true);
|
|
1246
|
+
const propertyName = this.propertyName;
|
|
1247
|
+
this.skipWhitespace();
|
|
1248
|
+
this.expectByte(0x3a, "':' after object property");
|
|
1249
|
+
this.skipWhitespace();
|
|
1250
|
+
|
|
1251
|
+
if (field !== 0) {
|
|
1252
|
+
const bit = 1 << field;
|
|
1253
|
+
if ((seenFields & bit) !== 0) {
|
|
1254
|
+
throw new ZLinkFrameworkException(
|
|
1255
|
+
ZLinkFrameworkErrorKind.ProtocolError,
|
|
1256
|
+
'duplicate envelope header field'
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
seenFields |= bit;
|
|
1260
|
+
const name = CHANNEL_HEADER_FIELD_NAMES[field]!;
|
|
1261
|
+
if (!this.flowEnabled && (field === 12 || field === 13)) {
|
|
1262
|
+
this.skipValue();
|
|
1263
|
+
header[name] = undefined;
|
|
1264
|
+
} else if (field === 14) {
|
|
1265
|
+
header[name] = this.readMetadata();
|
|
1266
|
+
} else {
|
|
1267
|
+
header[name] = this.readValue(field === 1 || field === 2 || field === 13);
|
|
1268
|
+
}
|
|
1269
|
+
} else {
|
|
1270
|
+
const value = this.readValue();
|
|
1271
|
+
if (propertyName === '__proto__') {
|
|
1272
|
+
Object.defineProperty(header, propertyName, {
|
|
1273
|
+
configurable: true,
|
|
1274
|
+
enumerable: true,
|
|
1275
|
+
value,
|
|
1276
|
+
writable: true
|
|
1277
|
+
});
|
|
1278
|
+
} else {
|
|
1279
|
+
header[propertyName] = value;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
this.skipWhitespace();
|
|
1284
|
+
if (this.consumeByte(0x7d)) break;
|
|
1285
|
+
this.expectByte(0x2c, "',' or '}' after object property");
|
|
1286
|
+
this.skipWhitespace();
|
|
1287
|
+
}
|
|
1288
|
+
return this.finish(header);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
private finish(header: Record<string, unknown>): Record<string, unknown> {
|
|
1292
|
+
this.skipWhitespace();
|
|
1293
|
+
if (this.index !== this.bytes.length) this.fail('trailing data');
|
|
1294
|
+
return header;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
private readMetadata(): unknown {
|
|
1298
|
+
if (this.bytes[this.index] !== 0x7b) return this.readValue();
|
|
1299
|
+
this.index += 1;
|
|
1300
|
+
this.skipWhitespace();
|
|
1301
|
+
if (this.consumeByte(0x7d)) return undefined;
|
|
1302
|
+
const metadata: Record<string, unknown> = {};
|
|
1303
|
+
|
|
1304
|
+
for (;;) {
|
|
1305
|
+
const key = this.readString();
|
|
1306
|
+
if (Object.prototype.hasOwnProperty.call(metadata, key)) {
|
|
1307
|
+
throw new ZLinkFrameworkException(
|
|
1308
|
+
ZLinkFrameworkErrorKind.ProtocolError,
|
|
1309
|
+
'duplicate envelope metadata key'
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
this.skipWhitespace();
|
|
1313
|
+
this.expectByte(0x3a, "':' after object property");
|
|
1314
|
+
this.skipWhitespace();
|
|
1315
|
+
const value = this.readValue();
|
|
1316
|
+
if (key === '__proto__') {
|
|
1317
|
+
Object.defineProperty(metadata, key, {
|
|
1318
|
+
configurable: true,
|
|
1319
|
+
enumerable: true,
|
|
1320
|
+
value,
|
|
1321
|
+
writable: true
|
|
1322
|
+
});
|
|
1323
|
+
} else {
|
|
1324
|
+
metadata[key] = value;
|
|
1325
|
+
}
|
|
1326
|
+
this.skipWhitespace();
|
|
1327
|
+
if (this.consumeByte(0x7d)) return metadata;
|
|
1328
|
+
this.expectByte(0x2c, "',' or '}' after object property");
|
|
1329
|
+
this.skipWhitespace();
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
private readPropertyName(materializeUnknown = false): number {
|
|
1334
|
+
this.scanString();
|
|
1335
|
+
let field = 0;
|
|
1336
|
+
let decoded: string | undefined;
|
|
1337
|
+
if (this.stringHasEscapes) {
|
|
1338
|
+
decoded = this.decodeString();
|
|
1339
|
+
for (let candidate = 1; candidate <= CHANNEL_HEADER_FIELD_COUNT; candidate += 1) {
|
|
1340
|
+
if (CHANNEL_HEADER_FIELD_NAMES[candidate] === decoded) {
|
|
1341
|
+
field = candidate;
|
|
1342
|
+
break;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
} else {
|
|
1346
|
+
for (let candidate = 1; candidate <= CHANNEL_HEADER_FIELD_COUNT; candidate += 1) {
|
|
1347
|
+
if (
|
|
1348
|
+
this.matchesAscii(
|
|
1349
|
+
this.stringStart + 1,
|
|
1350
|
+
this.stringEnd - 1,
|
|
1351
|
+
CHANNEL_HEADER_FIELD_NAMES[candidate]!
|
|
1352
|
+
)
|
|
1353
|
+
) {
|
|
1354
|
+
field = candidate;
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
this.propertyName =
|
|
1360
|
+
field !== 0
|
|
1361
|
+
? CHANNEL_HEADER_FIELD_NAMES[field]!
|
|
1362
|
+
: (decoded ??
|
|
1363
|
+
(materializeUnknown
|
|
1364
|
+
? this.bytes.toString('utf8', this.stringStart + 1, this.stringEnd - 1)
|
|
1365
|
+
: ''));
|
|
1366
|
+
return field;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
private readValue(integerOnly = false): unknown {
|
|
1370
|
+
const value = this.bytes[this.index];
|
|
1371
|
+
if (value === 0x22) return this.readString();
|
|
1372
|
+
if (value === 0x7b) return this.readObject();
|
|
1373
|
+
if (value === 0x5b) return this.readArray();
|
|
1374
|
+
if (value === 0x74) {
|
|
1375
|
+
this.readLiteral('true');
|
|
1376
|
+
return true;
|
|
1377
|
+
}
|
|
1378
|
+
if (value === 0x66) {
|
|
1379
|
+
this.readLiteral('false');
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
if (value === 0x6e) {
|
|
1383
|
+
this.readLiteral('null');
|
|
1384
|
+
return null;
|
|
1385
|
+
}
|
|
1386
|
+
return this.readNumber(integerOnly);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
private readObject(): Record<string, unknown> {
|
|
1390
|
+
this.index += 1;
|
|
1391
|
+
this.skipWhitespace();
|
|
1392
|
+
const object: Record<string, unknown> = {};
|
|
1393
|
+
if (this.consumeByte(0x7d)) return object;
|
|
1394
|
+
for (;;) {
|
|
1395
|
+
const key = this.readString();
|
|
1396
|
+
this.skipWhitespace();
|
|
1397
|
+
this.expectByte(0x3a, "':' after object property");
|
|
1398
|
+
this.skipWhitespace();
|
|
1399
|
+
const value = this.readValue();
|
|
1400
|
+
if (key === '__proto__') {
|
|
1401
|
+
Object.defineProperty(object, key, {
|
|
1402
|
+
configurable: true,
|
|
1403
|
+
enumerable: true,
|
|
1404
|
+
value,
|
|
1405
|
+
writable: true
|
|
1406
|
+
});
|
|
1407
|
+
} else {
|
|
1408
|
+
object[key] = value;
|
|
1409
|
+
}
|
|
1410
|
+
this.skipWhitespace();
|
|
1411
|
+
if (this.consumeByte(0x7d)) return object;
|
|
1412
|
+
this.expectByte(0x2c, "',' or '}' after object property");
|
|
1413
|
+
this.skipWhitespace();
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
private readArray(): unknown[] {
|
|
1418
|
+
this.index += 1;
|
|
1419
|
+
this.skipWhitespace();
|
|
1420
|
+
const array: unknown[] = [];
|
|
1421
|
+
if (this.consumeByte(0x5d)) return array;
|
|
1422
|
+
for (;;) {
|
|
1423
|
+
array.push(this.readValue());
|
|
1424
|
+
this.skipWhitespace();
|
|
1425
|
+
if (this.consumeByte(0x5d)) return array;
|
|
1426
|
+
this.expectByte(0x2c, "',' or ']' after array item");
|
|
1427
|
+
this.skipWhitespace();
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
private skipValue(): void {
|
|
1432
|
+
const value = this.bytes[this.index];
|
|
1433
|
+
if (value === 0x22) {
|
|
1434
|
+
this.scanString();
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
if (value === 0x7b) return this.skipObject();
|
|
1438
|
+
if (value === 0x5b) return this.skipArray();
|
|
1439
|
+
if (value === 0x74) return this.readLiteral('true');
|
|
1440
|
+
if (value === 0x66) return this.readLiteral('false');
|
|
1441
|
+
if (value === 0x6e) return this.readLiteral('null');
|
|
1442
|
+
this.readNumber();
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
private skipObject(): void {
|
|
1446
|
+
this.index += 1;
|
|
1447
|
+
this.skipWhitespace();
|
|
1448
|
+
if (this.consumeByte(0x7d)) return;
|
|
1449
|
+
for (;;) {
|
|
1450
|
+
this.readPropertyName();
|
|
1451
|
+
this.skipWhitespace();
|
|
1452
|
+
this.expectByte(0x3a, "':' after object property");
|
|
1453
|
+
this.skipWhitespace();
|
|
1454
|
+
this.skipValue();
|
|
1455
|
+
this.skipWhitespace();
|
|
1456
|
+
if (this.consumeByte(0x7d)) return;
|
|
1457
|
+
this.expectByte(0x2c, "',' or '}' after object property");
|
|
1458
|
+
this.skipWhitespace();
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
private skipArray(): void {
|
|
1463
|
+
this.index += 1;
|
|
1464
|
+
this.skipWhitespace();
|
|
1465
|
+
if (this.consumeByte(0x5d)) return;
|
|
1466
|
+
for (;;) {
|
|
1467
|
+
this.skipValue();
|
|
1468
|
+
this.skipWhitespace();
|
|
1469
|
+
if (this.consumeByte(0x5d)) return;
|
|
1470
|
+
this.expectByte(0x2c, "',' or ']' after array item");
|
|
1471
|
+
this.skipWhitespace();
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
private readString(): string {
|
|
1476
|
+
this.scanString();
|
|
1477
|
+
return this.decodeString();
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
private scanString(): void {
|
|
1481
|
+
if (this.bytes[this.index] !== 0x22) this.fail('string');
|
|
1482
|
+
this.stringStart = this.index++;
|
|
1483
|
+
this.stringHasEscapes = false;
|
|
1484
|
+
while (this.index < this.bytes.length) {
|
|
1485
|
+
const value = this.bytes[this.index++]!;
|
|
1486
|
+
if (value === 0x22) {
|
|
1487
|
+
this.stringEnd = this.index;
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
if (value < 0x20) this.fail('valid string character');
|
|
1491
|
+
if (value !== 0x5c) continue;
|
|
1492
|
+
this.stringHasEscapes = true;
|
|
1493
|
+
if (this.index === this.bytes.length) this.fail('valid string escape');
|
|
1494
|
+
const escaped = this.bytes[this.index++]!;
|
|
1495
|
+
if (escaped === 0x75) {
|
|
1496
|
+
for (let count = 0; count < 4; count += 1) {
|
|
1497
|
+
if (this.index === this.bytes.length || !isHexDigit(this.bytes[this.index]!))
|
|
1498
|
+
this.fail('four hexadecimal digits after \\u');
|
|
1499
|
+
this.index += 1;
|
|
1500
|
+
}
|
|
1501
|
+
} else if (
|
|
1502
|
+
escaped !== 0x22 &&
|
|
1503
|
+
escaped !== 0x5c &&
|
|
1504
|
+
escaped !== 0x2f &&
|
|
1505
|
+
escaped !== 0x62 &&
|
|
1506
|
+
escaped !== 0x66 &&
|
|
1507
|
+
escaped !== 0x6e &&
|
|
1508
|
+
escaped !== 0x72 &&
|
|
1509
|
+
escaped !== 0x74
|
|
1510
|
+
) {
|
|
1511
|
+
this.fail('valid string escape');
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
this.fail('terminated string');
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
private decodeString(): string {
|
|
1518
|
+
return this.stringHasEscapes
|
|
1519
|
+
? (JSON.parse(this.bytes.toString('utf8', this.stringStart, this.stringEnd)) as string)
|
|
1520
|
+
: this.bytes.toString('utf8', this.stringStart + 1, this.stringEnd - 1);
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
private readNumber(integerOnly = false): number {
|
|
1524
|
+
const start = this.index;
|
|
1525
|
+
let hasFractionOrExponent = false;
|
|
1526
|
+
if (this.bytes[this.index] === 0x2d) this.index += 1;
|
|
1527
|
+
if (this.bytes[this.index] === 0x30) {
|
|
1528
|
+
this.index += 1;
|
|
1529
|
+
} else if (this.isDigitOneToNine(this.bytes[this.index])) {
|
|
1530
|
+
while (this.isDigit(this.bytes[this.index])) this.index += 1;
|
|
1531
|
+
} else {
|
|
1532
|
+
this.fail('JSON value');
|
|
1533
|
+
}
|
|
1534
|
+
if (this.bytes[this.index] === 0x2e) {
|
|
1535
|
+
hasFractionOrExponent = true;
|
|
1536
|
+
this.index += 1;
|
|
1537
|
+
if (!this.isDigit(this.bytes[this.index])) this.fail('digit after decimal point');
|
|
1538
|
+
while (this.isDigit(this.bytes[this.index])) this.index += 1;
|
|
1539
|
+
}
|
|
1540
|
+
if (this.bytes[this.index] === 0x65 || this.bytes[this.index] === 0x45) {
|
|
1541
|
+
hasFractionOrExponent = true;
|
|
1542
|
+
this.index += 1;
|
|
1543
|
+
if (this.bytes[this.index] === 0x2b || this.bytes[this.index] === 0x2d) this.index += 1;
|
|
1544
|
+
if (!this.isDigit(this.bytes[this.index])) this.fail('digit in exponent');
|
|
1545
|
+
while (this.isDigit(this.bytes[this.index])) this.index += 1;
|
|
1546
|
+
}
|
|
1547
|
+
if (integerOnly && hasFractionOrExponent) {
|
|
1548
|
+
throw new ZLinkFrameworkException(
|
|
1549
|
+
ZLinkFrameworkErrorKind.ProtocolError,
|
|
1550
|
+
'Channel envelope integer fields must use an integer literal.'
|
|
1551
|
+
);
|
|
1552
|
+
}
|
|
1553
|
+
if (integerOnly) {
|
|
1554
|
+
const negative = this.bytes[start] === 0x2d;
|
|
1555
|
+
const digitsStart = start + (negative ? 1 : 0);
|
|
1556
|
+
if (this.index - digitsStart <= 3) {
|
|
1557
|
+
let integer = 0;
|
|
1558
|
+
for (let offset = digitsStart; offset < this.index; offset += 1) {
|
|
1559
|
+
integer = integer * 10 + this.bytes[offset]! - 0x30;
|
|
1560
|
+
}
|
|
1561
|
+
return negative ? -integer : integer;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
const number = Number(this.bytes.toString('ascii', start, this.index));
|
|
1565
|
+
if (!Number.isFinite(number)) {
|
|
1566
|
+
throw new TypeError('framework-json-v1 only accepts finite JSON numbers.');
|
|
1567
|
+
}
|
|
1568
|
+
return number;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
private readLiteral(value: 'true' | 'false' | 'null'): void {
|
|
1572
|
+
for (let offset = 0; offset < value.length; offset += 1) {
|
|
1573
|
+
if (this.bytes[this.index + offset] !== value.charCodeAt(offset)) this.fail(value);
|
|
1574
|
+
}
|
|
1575
|
+
this.index += value.length;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
private matchesAscii(start: number, end: number, value: string): boolean {
|
|
1579
|
+
if (end - start !== value.length) return false;
|
|
1580
|
+
for (let offset = 0; offset < value.length; offset += 1) {
|
|
1581
|
+
if (this.bytes[start + offset] !== value.charCodeAt(offset)) return false;
|
|
1582
|
+
}
|
|
1583
|
+
return true;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
private isDigit(value: number | undefined): boolean {
|
|
1587
|
+
return value !== undefined && value >= 0x30 && value <= 0x39;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
private isDigitOneToNine(value: number | undefined): boolean {
|
|
1591
|
+
return value !== undefined && value >= 0x31 && value <= 0x39;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
private skipWhitespace(): void {
|
|
1595
|
+
while (
|
|
1596
|
+
this.bytes[this.index] === 0x20 ||
|
|
1597
|
+
this.bytes[this.index] === 0x09 ||
|
|
1598
|
+
this.bytes[this.index] === 0x0a ||
|
|
1599
|
+
this.bytes[this.index] === 0x0d
|
|
1600
|
+
) {
|
|
1601
|
+
this.index += 1;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
private consumeByte(value: number): boolean {
|
|
1606
|
+
if (this.bytes[this.index] !== value) return false;
|
|
1607
|
+
this.index += 1;
|
|
1608
|
+
return true;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
private expectByte(value: number, expected: string): void {
|
|
1612
|
+
if (!this.consumeByte(value)) this.fail(expected);
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
private fail(expected: string): never {
|
|
1616
|
+
throw new SyntaxError(`framework-json-v1 expected ${expected} at offset ${this.index}.`);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1085
1620
|
function schemaForInboundChannelEnvelope(
|
|
1086
1621
|
header: ZLinkChannelEnvelopeHeader
|
|
1087
1622
|
): ZLinkJsonSchema | undefined {
|
|
@@ -1183,10 +1718,11 @@ function validateCorrelationForKind(
|
|
|
1183
1718
|
const MAXIMUM_CORRELATION_ID_BYTES = 64;
|
|
1184
1719
|
|
|
1185
1720
|
export function isValidChannelCorrelationId(value: string): boolean {
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1721
|
+
if (value.length < 1 || value.length > MAXIMUM_CORRELATION_ID_BYTES) return false;
|
|
1722
|
+
for (let index = 0; index < value.length; index++) {
|
|
1723
|
+
if (value.charCodeAt(index) > 0x7f) return false;
|
|
1724
|
+
}
|
|
1725
|
+
return true;
|
|
1190
1726
|
}
|
|
1191
1727
|
|
|
1192
1728
|
function validateCorrelationValue(correlationId: string): void {
|
|
@@ -1274,7 +1810,7 @@ function optionalFlowOrigin(value: unknown): ZLinkFlowOrigin | undefined {
|
|
|
1274
1810
|
|
|
1275
1811
|
function requireFlowId(value: unknown): string {
|
|
1276
1812
|
const flowId = requireString(value, 'flowId');
|
|
1277
|
-
if (
|
|
1813
|
+
if (!CHANNEL_FLOW_TEXT.test(flowId)) {
|
|
1278
1814
|
throw new ZLinkConfigurationException('Channel envelope flowId must be a lowercase UUIDv7.');
|
|
1279
1815
|
}
|
|
1280
1816
|
return flowId;
|