@tulipes/socket.io 0.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/load-sockets.d.ts +12 -0
- package/dist/load-sockets.js +39 -0
- package/dist/load-sockets.js.map +1 -0
- package/dist/provider.d.ts +12 -0
- package/dist/provider.js +30 -0
- package/dist/provider.js.map +1 -0
- package/dist/socket-manager.d.ts +56 -0
- package/dist/socket-manager.js +92 -0
- package/dist/socket-manager.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TulipesJS contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="https://cdn.jsdelivr.net/npm/@tulipes/core@0.7.1/assets/tulipesjs-logo.png" alt="TulipesJs" width="340">
|
|
4
|
+
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
# @tulipes/socket.io
|
|
8
|
+
|
|
9
|
+
The Socket.IO **sockets provider** for [Tulipes](https://www.npmjs.com/package/@tulipes/core)
|
|
10
|
+
apps. Every module's `sockets/*.sockets.ts` claims its namespace on one
|
|
11
|
+
Socket.IO server that core attaches to the backend's HTTP server just before it
|
|
12
|
+
listens. Core itself no longer installs Socket.IO; an app without realtime
|
|
13
|
+
features declares no provider and never pays for one.
|
|
14
|
+
|
|
15
|
+
Requires Node 24.x and a core that ships the provider contract with
|
|
16
|
+
`situations` and `attach`. `socket.io` is this package's own dependency.
|
|
17
|
+
|
|
18
|
+
## Select it
|
|
19
|
+
|
|
20
|
+
```jsonc
|
|
21
|
+
{ "tulipes": { "providers": { "sockets": "@tulipes/socket.io" } } }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
A `sockets/` directory requires the provider automatically; a module that only
|
|
25
|
+
emits declares `"tulipes": { "requires": ["sockets"] }`. Installing this package
|
|
26
|
+
without the declaration selects nothing.
|
|
27
|
+
|
|
28
|
+
## Use it
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// modules/billing/sockets/billing.sockets.ts
|
|
32
|
+
import type { Ctx } from "@tulipes/core/boot";
|
|
33
|
+
import type { SocketRegistry } from "@tulipes/socket.io";
|
|
34
|
+
|
|
35
|
+
export default function billingSockets(ctx: Ctx, sockets: SocketRegistry): void {
|
|
36
|
+
sockets.namespace("/billing", (nsp) => nsp.on("connection", (socket) => socket.emit("ready")));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// anywhere in the backend after acquisition
|
|
40
|
+
ctx.sockets!.of("/billing").emit("invoice", { id });
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Behavior
|
|
44
|
+
|
|
45
|
+
- Backend only (`situations: ["backend"]`): worker, script and inspection boots
|
|
46
|
+
report the provider as not used and never import a socket file.
|
|
47
|
+
- Namespaces are claimed during acquisition on an unattached server; core
|
|
48
|
+
attaches the HTTP server after routes mount and before `listen()`, so no
|
|
49
|
+
client can reach an unwired namespace. An attach failure is a boot error.
|
|
50
|
+
- Shutdown: the server closes in the drain phase alongside the HTTP drain,
|
|
51
|
+
disconnecting clients and releasing the listener as before.
|
|
52
|
+
- A namespace is claimed by exactly one module; `of()` throws on unclaimed
|
|
53
|
+
names; names are `/` or `/kebab-case`.
|
|
54
|
+
|
|
55
|
+
## Versions
|
|
56
|
+
|
|
57
|
+
`0.1.0-rc.1` requires core `^0.10.0-rc.2`, the candidate that added the
|
|
58
|
+
`situations`/`attach` contract; install both with `@next`. See core's
|
|
59
|
+
[MIGRATING.md](https://github.com/kemora13conf/bp-backend-express/blob/v0.10.0-rc.2/packages/core/MIGRATING.md#0100-rc2--declare-the-sockets-provider).
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Ctx } from "@tulipes/core/boot";
|
|
2
|
+
import type { BootReport } from "@tulipes/core/errors";
|
|
3
|
+
import type { ModuleFiles } from "@tulipes/core/modules";
|
|
4
|
+
import { SocketManager, type SocketRegistry } from "./socket-manager.js";
|
|
5
|
+
/** Default export of `sockets/*.sockets.ts` (backend branch only). */
|
|
6
|
+
export type SocketsFn = (ctx: Ctx, sockets: SocketRegistry) => void | Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Run by the provider in the backend process: create the Socket.IO server
|
|
9
|
+
* and run every `*.sockets.ts` in load order so namespaces are claimed and
|
|
10
|
+
* wired before core attaches the server and listens.
|
|
11
|
+
*/
|
|
12
|
+
export declare function initSockets(explored: readonly ModuleFiles[], ctx: Ctx, report: BootReport, onManager?: (manager: SocketManager) => void): Promise<SocketManager>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { importFile } from "@tulipes/core/boot";
|
|
2
|
+
import { SocketManager } from "./socket-manager.js";
|
|
3
|
+
/**
|
|
4
|
+
* Run by the provider in the backend process: create the Socket.IO server
|
|
5
|
+
* and run every `*.sockets.ts` in load order so namespaces are claimed and
|
|
6
|
+
* wired before core attaches the server and listens.
|
|
7
|
+
*/
|
|
8
|
+
export async function initSockets(explored, ctx, report, onManager) {
|
|
9
|
+
const manager = new SocketManager();
|
|
10
|
+
onManager?.(manager);
|
|
11
|
+
ctx.sockets = manager;
|
|
12
|
+
for (const { module, socketFiles } of explored) {
|
|
13
|
+
for (const file of socketFiles) {
|
|
14
|
+
const exported = await importFile(file, "boot", module.name, report);
|
|
15
|
+
if (!exported)
|
|
16
|
+
continue;
|
|
17
|
+
if (typeof exported.default !== "function") {
|
|
18
|
+
report.add({
|
|
19
|
+
scope: "boot",
|
|
20
|
+
module: module.name,
|
|
21
|
+
message: `${file} must default-export a sockets function (ctx, sockets) => void`,
|
|
22
|
+
});
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
await exported.default(ctx, manager.forModule(module.name, report));
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
report.add({
|
|
30
|
+
scope: "boot",
|
|
31
|
+
module: module.name,
|
|
32
|
+
message: `sockets function threw: ${error.message}`,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return manager;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=load-sockets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-sockets.js","sourceRoot":"","sources":["../src/load-sockets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,MAAM,oBAAoB,CAAC;AAI1D,OAAO,EAAE,aAAa,EAAuB,MAAM,qBAAqB,CAAC;AAKzE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAgC,EAChC,GAAQ,EACR,MAAkB,EAClB,SAA4C;IAE5C,MAAM,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;IACpC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC;IACrB,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IAEtB,KAAK,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC/C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,MAAM,UAAU,CAC/B,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAClC,CAAC;YACF,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAExB,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;gBAC3C,MAAM,CAAC,GAAG,CAAC;oBACT,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,MAAM,CAAC,IAAI;oBACnB,OAAO,EAAE,GAAG,IAAI,gEAAgE;iBACjF,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAO,QAAQ,CAAC,OAAqB,CACnC,GAAG,EACH,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CACvC,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,GAAG,CAAC;oBACT,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,MAAM,CAAC,IAAI;oBACnB,OAAO,EAAE,2BAA4B,KAAe,CAAC,OAAO,EAAE;iBAC/D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Provider } from "@tulipes/core/boot";
|
|
2
|
+
/**
|
|
3
|
+
* The "sockets" provider an app selects with
|
|
4
|
+
* `"tulipes": { "providers": { "sockets": "@tulipes/socket.io" } }`.
|
|
5
|
+
*
|
|
6
|
+
* Backend only: a worker or script has no HTTP server to attach to and
|
|
7
|
+
* inspection must not wire namespaces, so core skips it there. Namespaces are
|
|
8
|
+
* claimed during acquisition (phase 8) on an unattached server; core hands it
|
|
9
|
+
* the HTTP server through attach() before listen(). Closing it in the drain
|
|
10
|
+
* phase disconnects clients alongside the HTTP drain, exactly as before.
|
|
11
|
+
*/
|
|
12
|
+
export declare const provider: Provider<"sockets">;
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { initSockets } from "./load-sockets.js";
|
|
2
|
+
/**
|
|
3
|
+
* The "sockets" provider an app selects with
|
|
4
|
+
* `"tulipes": { "providers": { "sockets": "@tulipes/socket.io" } }`.
|
|
5
|
+
*
|
|
6
|
+
* Backend only: a worker or script has no HTTP server to attach to and
|
|
7
|
+
* inspection must not wire namespaces, so core skips it there. Namespaces are
|
|
8
|
+
* claimed during acquisition (phase 8) on an unattached server; core hands it
|
|
9
|
+
* the HTTP server through attach() before listen(). Closing it in the drain
|
|
10
|
+
* phase disconnects clients alongside the HTTP drain, exactly as before.
|
|
11
|
+
*/
|
|
12
|
+
export const provider = {
|
|
13
|
+
contract: 1,
|
|
14
|
+
capability: "sockets",
|
|
15
|
+
name: "socket.io",
|
|
16
|
+
situations: ["backend"],
|
|
17
|
+
async acquire({ ctx, files }, report, own) {
|
|
18
|
+
const manager = await initSockets(files, ctx, report, (created) => own({
|
|
19
|
+
attach: (server) => created.attach(server),
|
|
20
|
+
drain: () => created.close(),
|
|
21
|
+
dispose: () => undefined,
|
|
22
|
+
status: () => ({
|
|
23
|
+
label: created.namespaces().join(", ") || "no namespaces claimed",
|
|
24
|
+
ready: true,
|
|
25
|
+
}),
|
|
26
|
+
}));
|
|
27
|
+
return manager;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAwB;IAC3C,QAAQ,EAAE,CAAC;IACX,UAAU,EAAE,SAAS;IACrB,IAAI,EAAE,WAAW;IACjB,UAAU,EAAE,CAAC,SAAS,CAAC;IACvB,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG;QACvC,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC;YACrE,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;YAC1C,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;YAC5B,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS;YACxB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;gBACb,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,uBAAuB;gBACjE,KAAK,EAAE,IAAI;aACZ,CAAC;SACH,CAAC,CAAC,CAAC;QACJ,OAAO,OAAO,CAAC;IACjB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Server as HttpServer } from "node:http";
|
|
2
|
+
import { Server, type Namespace, type ServerOptions } from "socket.io";
|
|
3
|
+
import type { SocketsCapability } from "@tulipes/core/boot";
|
|
4
|
+
import type { BootReport } from "@tulipes/core/errors";
|
|
5
|
+
/**
|
|
6
|
+
* What `ctx.sockets` is once this provider is in the compilation. Core's
|
|
7
|
+
* SocketsCapability is empty; an app that imports anything from this package
|
|
8
|
+
* (its socket files do, for SocketRegistry) sees these members typed.
|
|
9
|
+
*/
|
|
10
|
+
declare module "@tulipes/core/boot" {
|
|
11
|
+
interface SocketsCapability {
|
|
12
|
+
readonly io: Server;
|
|
13
|
+
of(name: string): Namespace;
|
|
14
|
+
namespaces(): string[];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Wraps the process-wide Socket.IO server (backend branch only). Created
|
|
19
|
+
* unattached during provider acquisition so modules can claim namespaces;
|
|
20
|
+
* core hands it the HTTP server through attach() just before listen().
|
|
21
|
+
*
|
|
22
|
+
* Namespaces are the socket-side equivalent of route prefixes, and get the
|
|
23
|
+
* same ownership rule as everything else in Tulipes: a module claims its
|
|
24
|
+
* namespace ("/users") exactly once, and emitting into a namespace nobody
|
|
25
|
+
* claimed throws instead of silently broadcasting to nothing.
|
|
26
|
+
*/
|
|
27
|
+
export declare class SocketManager implements SocketsCapability {
|
|
28
|
+
#private;
|
|
29
|
+
constructor(options?: Partial<ServerOptions>);
|
|
30
|
+
/** Bind to the server that will accept the upgrades; once, before it listens. */
|
|
31
|
+
attach(httpServer: HttpServer): void;
|
|
32
|
+
/** Escape hatch for advanced use — prefer `of()` for claimed namespaces. */
|
|
33
|
+
get io(): Server;
|
|
34
|
+
/** Emit-side accessor, fail-closed on unclaimed namespaces. */
|
|
35
|
+
of(name: string): Namespace;
|
|
36
|
+
/** Claimed namespace names — for the startup banner and tooling. */
|
|
37
|
+
namespaces(): string[];
|
|
38
|
+
/** @internal Module-scoped facade for the loader. */
|
|
39
|
+
forModule(moduleName: string, report: BootReport): SocketRegistry;
|
|
40
|
+
/** @internal SocketRegistry only. */
|
|
41
|
+
claim_(name: string, owner: string): string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Close namespace clients and the underlying Engine.IO transports.
|
|
44
|
+
* This also closes HTTP; boot starts and awaits HTTP draining alongside it.
|
|
45
|
+
*/
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
export declare class SocketRegistry {
|
|
49
|
+
#private;
|
|
50
|
+
constructor(manager: SocketManager, moduleName: string, report: BootReport);
|
|
51
|
+
/**
|
|
52
|
+
* Claim a namespace and wire it up. The setup callback receives the live
|
|
53
|
+
* Namespace — attach middleware and connection handlers there.
|
|
54
|
+
*/
|
|
55
|
+
namespace(name: string, setup: (nsp: Namespace) => void): this;
|
|
56
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Server } from "socket.io";
|
|
2
|
+
/**
|
|
3
|
+
* Wraps the process-wide Socket.IO server (backend branch only). Created
|
|
4
|
+
* unattached during provider acquisition so modules can claim namespaces;
|
|
5
|
+
* core hands it the HTTP server through attach() just before listen().
|
|
6
|
+
*
|
|
7
|
+
* Namespaces are the socket-side equivalent of route prefixes, and get the
|
|
8
|
+
* same ownership rule as everything else in Tulipes: a module claims its
|
|
9
|
+
* namespace ("/users") exactly once, and emitting into a namespace nobody
|
|
10
|
+
* claimed throws instead of silently broadcasting to nothing.
|
|
11
|
+
*/
|
|
12
|
+
export class SocketManager {
|
|
13
|
+
#io;
|
|
14
|
+
/** namespace name → owning module */
|
|
15
|
+
#namespaces = new Map();
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.#io = new Server(options);
|
|
18
|
+
}
|
|
19
|
+
/** Bind to the server that will accept the upgrades; once, before it listens. */
|
|
20
|
+
attach(httpServer) {
|
|
21
|
+
this.#io.attach(httpServer);
|
|
22
|
+
}
|
|
23
|
+
/** Escape hatch for advanced use — prefer `of()` for claimed namespaces. */
|
|
24
|
+
get io() {
|
|
25
|
+
return this.#io;
|
|
26
|
+
}
|
|
27
|
+
/** Emit-side accessor, fail-closed on unclaimed namespaces. */
|
|
28
|
+
of(name) {
|
|
29
|
+
if (!this.#namespaces.has(name)) {
|
|
30
|
+
throw new Error(`Socket namespace "${name}" was never claimed by any module (known: ${[...this.#namespaces.keys()].join(", ") || "none"})`);
|
|
31
|
+
}
|
|
32
|
+
return this.#io.of(name);
|
|
33
|
+
}
|
|
34
|
+
/** Claimed namespace names — for the startup banner and tooling. */
|
|
35
|
+
namespaces() {
|
|
36
|
+
return [...this.#namespaces.keys()];
|
|
37
|
+
}
|
|
38
|
+
/** @internal Module-scoped facade for the loader. */
|
|
39
|
+
forModule(moduleName, report) {
|
|
40
|
+
return new SocketRegistry(this, moduleName, report);
|
|
41
|
+
}
|
|
42
|
+
/** @internal SocketRegistry only. */
|
|
43
|
+
claim_(name, owner) {
|
|
44
|
+
const existing = this.#namespaces.get(name);
|
|
45
|
+
if (existing)
|
|
46
|
+
return existing;
|
|
47
|
+
this.#namespaces.set(name, owner);
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Close namespace clients and the underlying Engine.IO transports.
|
|
52
|
+
* This also closes HTTP; boot starts and awaits HTTP draining alongside it.
|
|
53
|
+
*/
|
|
54
|
+
close() {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
this.#io.close(() => resolve());
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** "/", or "/name" — lowercase kebab-case. */
|
|
61
|
+
const NAMESPACE = /^\/([a-z0-9-]+)?$/;
|
|
62
|
+
export class SocketRegistry {
|
|
63
|
+
#manager;
|
|
64
|
+
#module;
|
|
65
|
+
#report;
|
|
66
|
+
constructor(manager, moduleName, report) {
|
|
67
|
+
this.#manager = manager;
|
|
68
|
+
this.#module = moduleName;
|
|
69
|
+
this.#report = report;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Claim a namespace and wire it up. The setup callback receives the live
|
|
73
|
+
* Namespace — attach middleware and connection handlers there.
|
|
74
|
+
*/
|
|
75
|
+
namespace(name, setup) {
|
|
76
|
+
if (!NAMESPACE.test(name)) {
|
|
77
|
+
this.#issue(`namespace "${name}" is invalid — expected "/" or "/kebab-case-name"`);
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
const owner = this.#manager.claim_(name, this.#module);
|
|
81
|
+
if (owner) {
|
|
82
|
+
this.#issue(`namespace "${name}" is already claimed by module "${owner}"`);
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
setup(this.#manager.io.of(name));
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
#issue(message) {
|
|
89
|
+
this.#report.add({ scope: "boot", module: this.#module, message });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=socket-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket-manager.js","sourceRoot":"","sources":["../src/socket-manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tulipes/socket.io",
|
|
3
|
+
"version": "0.1.0-rc.1",
|
|
4
|
+
"description": "Socket.IO sockets provider for Tulipes apps: module-owned namespaces on the backend's HTTP server, behind core's sockets capability",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
|
+
"build": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
|
|
17
|
+
"prepack": "yarn build"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"socket.io": "^4"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@tulipes/core": "^0.10.0-rc.2"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@tulipes/core": "0.10.0-rc.2",
|
|
33
|
+
"@types/node": "^24.2.0",
|
|
34
|
+
"typescript": "^7.0.2"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/kemora13conf/bp-backend-express.git",
|
|
39
|
+
"directory": "packages/socket.io"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"tulipes",
|
|
43
|
+
"socket.io",
|
|
44
|
+
"websocket",
|
|
45
|
+
"express"
|
|
46
|
+
],
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=24.0.0 <25"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/kemora13conf/bp-backend-express/tree/master/packages/socket.io#readme",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/kemora13conf/bp-backend-express/issues"
|
|
54
|
+
}
|
|
55
|
+
}
|