@znight/core 0.5.0 → 0.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@znight/core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Znight core runtime: compile-time DI container, lifecycle, plugins and marker decorators",
5
5
  "license": "MIT",
6
6
  "author": "Ugho STEPHAN",
package/src/errors.ts CHANGED
@@ -6,8 +6,8 @@
6
6
  * - `ZNIGHT001`–`ZNIGHT029`: the core, the compiler and the features shipped in 0.1 (http,
7
7
  * messaging, config, observability).
8
8
  * - From `ZNIGHT030`, each first-party package reserves a block of ten: `ZNIGHT030`–`039`
9
- * `@znight/openapi`, `ZNIGHT040`–`049` `@znight/schedule`, `ZNIGHT050`–`059` `@znight/websocket`
10
- * (reserved), `ZNIGHT060`–`069` `@znight/graphql`, `ZNIGHT070`–`079` `@znight/events`.
9
+ * `@znight/openapi`, `ZNIGHT040`–`049` `@znight/schedule`, `ZNIGHT050`–`059` `@znight/websocket`,
10
+ * `ZNIGHT060`–`069` `@znight/graphql`, `ZNIGHT070`–`079` `@znight/events`.
11
11
  *
12
12
  * Within a range, codes are allocated in order without gaps. A package uses its block for its own
13
13
  * failure modes, with one catch-all code for invalid usage and options, and reuses a lower code
@@ -101,6 +101,18 @@ export const ErrorCode = {
101
101
  /** A scheduled run was aborted (`ctx.signal.reason`, `JobAbortedError`); never thrown by the framework. */
102
102
  JobAborted: 'ZNIGHT044',
103
103
 
104
+ // ZNIGHT050–059: @znight/websocket (RFC 0003)
105
+ /**
106
+ * Invalid gateway: `@Gateway` options, lifecycle methods, events handled twice, reserved event
107
+ * names, parameters; at boot, invalid `WebSocketPlugin` options or `metadata.extensions.websocket`.
108
+ */
109
+ InvalidGateway: 'ZNIGHT050',
110
+ /**
111
+ * Gateways cannot be served: no `HttpPlugin`, an adapter without upgrade support, `ws` missing on
112
+ * Node.js, a transport that does not match the server.
113
+ */
114
+ WebSocketTransportUnavailable: 'ZNIGHT051',
115
+
104
116
  // ZNIGHT060–069: @znight/graphql (RFC 0005, RFC 0007)
105
117
  /** A TypeScript type cannot be mapped to a GraphQL type, or a resolver lacks the annotation it needs. */
106
118
  InvalidGraphQLType: 'ZNIGHT060',
@@ -188,6 +200,8 @@ export const ERROR_DESCRIPTIONS: Readonly<Record<ErrorCode, string>> = {
188
200
  ZNIGHT042: 'Unknown job: no job has this name',
189
201
  ZNIGHT043: 'Missing lock store: a job requires a lock but SchedulePlugin has no store',
190
202
  ZNIGHT044: 'Job aborted: a scheduled run was aborted (timeout, lost lock, removal or shutdown)',
203
+ ZNIGHT050: 'Invalid gateway: a WebSocket gateway, its handlers or the WebSocketPlugin options are invalid',
204
+ ZNIGHT051: 'WebSocket transport unavailable: gateways cannot be served by the HTTP server',
191
205
  ZNIGHT060: 'Invalid GraphQL type: a TypeScript type cannot be mapped to a GraphQL type',
192
206
  ZNIGHT061: 'GraphQL name conflict: two types or root fields share a name, or a name is invalid or reserved',
193
207
  ZNIGHT062: 'Invalid resolver: the structure of a GraphQL resolver is invalid',
package/src/hooks.ts CHANGED
@@ -33,6 +33,13 @@ export interface ZnightHooks {
33
33
  * emitted when listeners exist.
34
34
  */
35
35
  'graphql:operation': GraphQLOperationEvent
36
+ /**
37
+ * One inbound WebSocket message handled by `@znight/websocket` (RFC 0003): wrapped with
38
+ * `hooks.run` when wrappers exist, then emitted when listeners exist. `$ping` frames do not run it.
39
+ */
40
+ 'websocket:message': WebSocketMessageEvent
41
+ /** A WebSocket connection of `@znight/websocket` opened or closed (emitted only). */
42
+ 'websocket:connection': WebSocketConnectionEvent
36
43
  /**
37
44
  * One publication of `@znight/events` (`EventPublisher.publish()` or `emit()`) that matched at least
38
45
  * one listener (RFC 0011): wraps the inline phase with `hooks.run` when wrappers exist, then is
@@ -108,6 +115,61 @@ export interface MessageDeliveryEvent {
108
115
  error?: unknown
109
116
  }
110
117
 
118
+ /** Outcome of an inbound WebSocket message (`WebSocketMessageEvent.outcome`). */
119
+ export type WebSocketMessageOutcome = 'ok' | 'error' | 'rejected' | 'unhandled' | 'timeout'
120
+
121
+ /** Who closed a WebSocket connection (`WsCloseInfo.initiator` of `@znight/websocket`). */
122
+ export type WebSocketCloseInitiator = 'client' | 'server' | 'shutdown' | 'heartbeat' | 'backpressure' | 'error'
123
+
124
+ /**
125
+ * Instrumentation event of the `websocket:message` hook (RFC 0003 §8.10), one per inbound message
126
+ * of a gateway. `outcome` and `error` are set before `hooks.run` resolves.
127
+ */
128
+ export interface WebSocketMessageEvent {
129
+ /** Display name of the gateway class. */
130
+ readonly gateway: string
131
+ /** Gateway path pattern, HTTP prefix included (`/api/chat`). */
132
+ readonly path: string
133
+ /** Event name (`events` gateways); `undefined` on `raw` gateways or for an undecodable frame. */
134
+ readonly event: string | undefined
135
+ /** Handler method; `undefined` when no handler matched. */
136
+ readonly handler: string | undefined
137
+ readonly connectionId: string
138
+ /** The request id of the handshake. */
139
+ readonly requestId: string
140
+ /** Size of the frame, in bytes (characters for a text frame). */
141
+ readonly bytes: number
142
+ /** `WsMessageContext` from `@znight/websocket`. */
143
+ readonly context: unknown
144
+ /** `performance.now()` when the message was dispatched. */
145
+ readonly startTime: number
146
+ outcome?: WebSocketMessageOutcome
147
+ error?: unknown
148
+ }
149
+
150
+ /** Instrumentation event of the `websocket:connection` hook (RFC 0003 §8.10). */
151
+ export interface WebSocketConnectionEvent {
152
+ readonly type: 'open' | 'close'
153
+ /** Display name of the gateway class. */
154
+ readonly gateway: string
155
+ /** Gateway path pattern, HTTP prefix included. */
156
+ readonly path: string
157
+ readonly connectionId: string
158
+ /** The request id of the handshake. */
159
+ readonly requestId: string
160
+ /** `WsConnection` from `@znight/websocket`. */
161
+ readonly connection: unknown
162
+ /** `performance.now()` when the connection opened. */
163
+ readonly openedAt: number
164
+ /** Close code (`close` events). */
165
+ readonly code?: number
166
+ readonly reason?: string
167
+ readonly initiator?: WebSocketCloseInitiator
168
+ /** Messages received and sent by the connection (`close` events). */
169
+ readonly messagesIn?: number
170
+ readonly messagesOut?: number
171
+ }
172
+
111
173
  /** How a scheduled run was triggered (`ScheduledRunEvent.trigger`). */
112
174
  export type ScheduledRunTrigger = 'schedule' | 'start' | 'manual' | 'queued'
113
175
 
package/src/index.ts CHANGED
@@ -59,6 +59,10 @@ export {
59
59
  type ScheduledRunEvent,
60
60
  type ScheduledRunOutcome,
61
61
  type ScheduledRunTrigger,
62
+ type WebSocketCloseInitiator,
63
+ type WebSocketConnectionEvent,
64
+ type WebSocketMessageEvent,
65
+ type WebSocketMessageOutcome,
62
66
  type ZnightHooks,
63
67
  } from './hooks.ts'
64
68
  export {