@nyirusu/nact-websocket-nuxtjs-server 0.0.0-stage → 1.0.4

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/README.md CHANGED
@@ -1,3 +1,9 @@
1
- # Temporary Holding Version
1
+ # nact-websocket-nuxtjs-server
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Nuxt / Nitro 原生 WebSocket 路由的 NACT Server Provider。
4
+
5
+ 在 Nitro 插件内注册 Provider,配置 `type: 'websocket-nuxtjs', provider: {}` 并启动 NApp;路由通过 `defineWebSocketHandler(provider.hooks)` 接入。启用 `nitro.experimental.websocket`,由 Nitro/CrossWS 完成升级,不自行监听端口,不操作 Node Req/Res。
6
+
7
+ `provider.authorize(request)` 可在升级前鉴权。关闭 Provider 释放自己的连接,不关闭 Nitro 服务。客户端使用现有 `nact-websocket-client`,客户端传输类型为 `websocket`。
8
+
9
+ 完整示例见 [运行时接入文档](../../docs/transport/nact/runtime-build.md#nuxt)。
@@ -0,0 +1,24 @@
1
+ import type { Channel, ServerHandle, ServerProvider } from '@nyirusu/nasdk/NACT';
2
+ import type { Hooks } from 'crossws';
3
+ export interface NuxtWebSocketServerOptions {
4
+ authorize?: (request: Parameters<Hooks['upgrade']>[0]) => boolean | Promise<boolean>;
5
+ }
6
+ export interface NuxtWebSocketServerTransportSpec {
7
+ type: 'websocket-nuxtjs';
8
+ provider?: NuxtWebSocketServerOptions;
9
+ nact?: {
10
+ chunkSize?: number;
11
+ };
12
+ }
13
+ export default class NuxtWebSocketServerProvider implements ServerProvider<'websocket-nuxtjs', NuxtWebSocketServerOptions> {
14
+ readonly type = "websocket-nuxtjs";
15
+ readonly role = "server";
16
+ readonly defaultChunkSize: number;
17
+ private accept?;
18
+ private options?;
19
+ private channels;
20
+ private admissions;
21
+ listen(options: NuxtWebSocketServerOptions, accept: (channel: Channel) => void): Promise<ServerHandle>;
22
+ readonly hooks: Hooks;
23
+ }
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAChF,OAAO,KAAK,EAAE,KAAK,EAAQ,MAAM,SAAS,CAAA;AAE1C,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACrF;AAED,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,kBAAkB,CAAA;IACxB,QAAQ,CAAC,EAAE,0BAA0B,CAAA;IACrC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9B;AAoDD,MAAM,CAAC,OAAO,OAAO,2BACnB,YAAW,cAAc,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACzE,QAAQ,CAAC,IAAI,sBAAqB;IAClC,QAAQ,CAAC,IAAI,YAAW;IACxB,QAAQ,CAAC,gBAAgB,SAAY;IACrC,OAAO,CAAC,MAAM,CAAC,CAA4B;IAC3C,OAAO,CAAC,OAAO,CAAC,CAA4B;IAC5C,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,UAAU,CAAoD;IAEhE,MAAM,CAAC,OAAO,EAAE,0BAA0B,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;IAkB5G,QAAQ,CAAC,KAAK,EAAE,KAAK,CAyBpB;CACF"}
package/dist/index.js ADDED
@@ -0,0 +1,136 @@
1
+ const transportError = (code) => Object.assign(new Error(code), { code });
2
+ class NuxtWebSocketChannel {
3
+ peer;
4
+ receivers = new Set();
5
+ closers = new Set();
6
+ errors = new Set();
7
+ ended = false;
8
+ constructor(peer) {
9
+ this.peer = peer;
10
+ }
11
+ send(frame) {
12
+ if (this.ended)
13
+ throw transportError('transport-closed');
14
+ const bytes = new Uint8Array(frame.reduce((size, part) => size + part.byteLength, 0));
15
+ let offset = 0;
16
+ for (const part of frame) {
17
+ bytes.set(part, offset);
18
+ offset += part.byteLength;
19
+ }
20
+ this.peer.send(bytes, { compress: false });
21
+ }
22
+ close() { this.end(); this.peer.close(1000, 'NACT closed'); }
23
+ terminate() { this.end(); this.peer.terminate(); }
24
+ onReceive(handler) {
25
+ this.receivers.add(handler);
26
+ return () => this.receivers.delete(handler);
27
+ }
28
+ onClose(handler) {
29
+ if (this.ended)
30
+ queueMicrotask(handler);
31
+ else
32
+ this.closers.add(handler);
33
+ return () => this.closers.delete(handler);
34
+ }
35
+ onError(handler) {
36
+ this.errors.add(handler);
37
+ return () => this.errors.delete(handler);
38
+ }
39
+ receive(bytes) {
40
+ if (!this.ended)
41
+ for (const handler of this.receivers)
42
+ handler([bytes]);
43
+ }
44
+ fail(reason) {
45
+ if (this.ended)
46
+ return;
47
+ try {
48
+ for (const handler of this.errors)
49
+ handler(reason);
50
+ }
51
+ finally {
52
+ this.terminate();
53
+ }
54
+ }
55
+ end() {
56
+ if (this.ended)
57
+ return;
58
+ this.ended = true;
59
+ for (const handler of this.closers)
60
+ handler();
61
+ this.receivers.clear();
62
+ this.closers.clear();
63
+ this.errors.clear();
64
+ }
65
+ }
66
+ // Nitro/CrossWS owns routing and upgrade; this Provider only handles accepted peers.
67
+ export default class NuxtWebSocketServerProvider {
68
+ type = 'websocket-nuxtjs';
69
+ role = 'server';
70
+ defaultChunkSize = 64 * 1024;
71
+ accept;
72
+ options;
73
+ channels = new Map();
74
+ admissions = new WeakMap();
75
+ async listen(options, accept) {
76
+ if (this.accept)
77
+ throw transportError('provider-already-listening');
78
+ this.accept = accept;
79
+ this.options = options;
80
+ let closed = false;
81
+ return {
82
+ close: async () => {
83
+ if (closed)
84
+ return;
85
+ closed = true;
86
+ this.accept = undefined;
87
+ this.options = undefined;
88
+ this.admissions = new WeakMap();
89
+ for (const channel of this.channels.values())
90
+ channel.terminate();
91
+ this.channels.clear();
92
+ },
93
+ };
94
+ }
95
+ hooks = {
96
+ upgrade: async (request) => {
97
+ const accept = this.accept;
98
+ const options = this.options;
99
+ if (!accept || !options)
100
+ return new Response(null, { status: 503 });
101
+ if (options.authorize && !await options.authorize(request))
102
+ return new Response(null, { status: 403 });
103
+ if (this.accept !== accept)
104
+ return new Response(null, { status: 503 });
105
+ this.admissions.set(request.context, accept);
106
+ },
107
+ open: peer => {
108
+ const accept = this.accept;
109
+ if (!accept || this.admissions.get(peer.context) !== accept) {
110
+ peer.terminate();
111
+ return;
112
+ }
113
+ this.admissions.delete(peer.context);
114
+ const channel = new NuxtWebSocketChannel(peer);
115
+ this.channels.set(peer, channel);
116
+ channel.onClose(() => this.channels.delete(peer));
117
+ try {
118
+ accept(channel);
119
+ }
120
+ catch (reason) {
121
+ channel.fail(reason);
122
+ throw reason;
123
+ }
124
+ },
125
+ message: (peer, message) => {
126
+ const channel = this.channels.get(peer);
127
+ if (typeof message.rawData === 'string')
128
+ channel?.fail(transportError('non-binary-frame'));
129
+ else
130
+ channel?.receive(message.uint8Array());
131
+ },
132
+ close: peer => { this.channels.get(peer)?.end(); },
133
+ error: (peer, reason) => { this.channels.get(peer)?.fail(reason); },
134
+ };
135
+ }
136
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,20 @@
1
1
  {
2
2
  "name": "@nyirusu/nact-websocket-nuxtjs-server",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.4",
4
+ "type": "module",
5
+ "files": ["dist"],
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
9
+ "scripts": {
10
+ "build": "tsc -p tsconfig.build.json",
11
+ "typecheck": "tsc -p tsconfig.json --noEmit",
12
+ "test": "npm run test:simple",
13
+ "test:simple": "node --import tsx --test test/simple.test.mjs",
14
+ "test:full": "node --import tsx --test test/full.test.mjs",
15
+ "test:edge": "node --import tsx --test test/edge.test.mjs"
16
+ },
17
+ "devDependencies": { "crossws": "^0.3.5" },
18
+ "peerDependencies": { "@nyirusu/nasdk": ">=1.0.4", "crossws": "^0.3.5" },
19
+ "peerDependenciesMeta": { "@nyirusu/nasdk": { "optional": true } }
20
+ }