@enfyra/sdk-nuxt 0.7.5 → 0.7.6

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
@@ -7,6 +7,7 @@ Nuxt SDK for Enfyra CMS - A lightweight composable-based API client with full Ty
7
7
  ✅ **Simple & Flexible** - Get base URL and build your own composables
8
8
  ✅ **Authentication Integration** - Built-in auth composables with automatic header forwarding
9
9
  ✅ **Asset Proxy** - Automatic `/assets/**` proxy to backend with no configuration needed
10
+ ✅ **WebSocket Relay** - Relay Socket.IO through Nuxt at `/ws/:path` (keeps backend hidden)
10
11
  ✅ **TypeScript Support** - Full type safety with auto-generated declarations
11
12
  ✅ **SSR Ready** - Works seamlessly with Nuxt's `useFetch` and `$fetch`
12
13
 
@@ -43,10 +44,27 @@ The SDK automatically detects your application URL:
43
44
 
44
45
  ```typescript
45
46
  // Get the base URL for your API requests
46
- const { baseUrl, apiPrefix } = useEnfyra();
47
+ const { baseUrl, apiPrefix, wsBaseUrl, wsPath } = useEnfyra();
47
48
 
48
49
  // baseUrl: "http://localhost:3001/enfyra/api"
49
50
  // apiPrefix: "/enfyra/api"
51
+ // wsBaseUrl: "http://localhost:3001" (for WebSocket relay)
52
+ // wsPath: "/ws/socket.io" (engine path)
53
+ ```
54
+
55
+ ### WebSocket Relay
56
+
57
+ The SDK relays Socket.IO through Nuxt so the backend can stay non-public. Use `socket.io-client` with `wsBaseUrl` and `wsPath`:
58
+
59
+ ```typescript
60
+ import { io } from 'socket.io-client';
61
+
62
+ const { wsBaseUrl, wsPath } = useEnfyra();
63
+
64
+ const socket = io(wsBaseUrl + '/chat', {
65
+ path: wsPath,
66
+ auth: { token }, // if gateway requireAuth
67
+ });
50
68
  ```
51
69
 
52
70
  ### Using with `useFetch` (SSR)
package/dist/module.cjs CHANGED
@@ -106,6 +106,9 @@ declare module '#imports' {
106
106
  route: `${apiPrefix}/**`,
107
107
  handler: resolve("./runtime/server/api/all")
108
108
  });
109
+ nuxt.options.nitro = nuxt.options.nitro || {};
110
+ nuxt.options.nitro.experimental = nuxt.options.nitro.experimental || {};
111
+ nuxt.options.nitro.experimental.websocket = true;
109
112
  }
110
113
  });
111
114
 
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;;AAED,wBA6HG"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;;AAED,wBAiIG"}
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "0.7.5",
7
+ "version": "0.7.6",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -103,6 +103,9 @@ declare module '#imports' {
103
103
  route: `${apiPrefix}/**`,
104
104
  handler: resolve("./runtime/server/api/all")
105
105
  });
106
+ nuxt.options.nitro = nuxt.options.nitro || {};
107
+ nuxt.options.nitro.experimental = nuxt.options.nitro.experimental || {};
108
+ nuxt.options.nitro.experimental.websocket = true;
106
109
  }
107
110
  });
108
111
 
@@ -0,0 +1,3 @@
1
+ declare const _default: import("nitropack").NitroAppPlugin;
2
+ export default _default;
3
+ //# sourceMappingURL=socket-relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket-relay.d.ts","sourceRoot":"","sources":["../../../../src/runtime/server/plugins/socket-relay.ts"],"names":[],"mappings":";AAUA,wBAwEG"}
@@ -0,0 +1,69 @@
1
+ import { defineNitroPlugin } from "nitropack/runtime";
2
+ import { Server as Engine } from "engine.io";
3
+ import { Server } from "socket.io";
4
+ import { io as ioClient } from "socket.io-client";
5
+ import { defineEventHandler } from "h3";
6
+ import { useRuntimeConfig } from "#imports";
7
+ const ENGINE_PATH = "/socket.io";
8
+ const ENGINE_PATH_SLASH = `${ENGINE_PATH}/`;
9
+ export default defineNitroPlugin((nitroApp) => {
10
+ const config = useRuntimeConfig();
11
+ const apiUrl = config.public?.enfyraSDK?.apiUrl;
12
+ if (!apiUrl) return;
13
+ const backendUrl = String(apiUrl).replace(/\/+$/, "");
14
+ const engine = new Engine();
15
+ const io = new Server();
16
+ io.bind(engine);
17
+ io.on("connection", (clientSocket) => {
18
+ const namespace = clientSocket.nsp.name;
19
+ const backendNamespace = namespace === "/" || namespace === "" ? "/" : namespace;
20
+ const backendNsUrl = `${backendUrl}${backendNamespace}`;
21
+ const backendSocket = ioClient(backendNsUrl, {
22
+ path: "/socket.io",
23
+ auth: clientSocket.handshake.auth,
24
+ transports: ["websocket", "polling"]
25
+ });
26
+ clientSocket.onAny((event, ...args) => {
27
+ if (event !== "disconnect") {
28
+ backendSocket.emit(event, ...args);
29
+ }
30
+ });
31
+ backendSocket.onAny((event, ...args) => {
32
+ clientSocket.emit(event, ...args);
33
+ });
34
+ clientSocket.on("disconnect", () => {
35
+ backendSocket.disconnect();
36
+ });
37
+ backendSocket.on("disconnect", () => {
38
+ clientSocket.disconnect();
39
+ });
40
+ backendSocket.on("connect_error", (err) => {
41
+ clientSocket.emit("connect_error", err.message);
42
+ clientSocket.disconnect();
43
+ });
44
+ });
45
+ nitroApp.router.use(
46
+ `${ENGINE_PATH_SLASH}`,
47
+ defineEventHandler({
48
+ handler(event) {
49
+ const req = event.node.req;
50
+ const res = event.node.res;
51
+ engine.handleRequest(req, res);
52
+ event._handled = true;
53
+ },
54
+ websocket: {
55
+ open(peer) {
56
+ const nodeReq = peer._internal?.nodeReq;
57
+ if (nodeReq) {
58
+ engine.prepare(nodeReq);
59
+ engine.onWebSocket(
60
+ nodeReq,
61
+ nodeReq.socket,
62
+ peer.websocket
63
+ );
64
+ }
65
+ }
66
+ }
67
+ })
68
+ );
69
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enfyra/sdk-nuxt",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
4
4
  "type": "module",
5
5
  "description": "Nuxt SDK for Enfyra CMS",
6
6
  "repository": {
@@ -55,13 +55,17 @@
55
55
  },
56
56
  "peerDependencies": {
57
57
  "@nuxt/kit": "^3.18.1",
58
+ "nitropack": ">=2.0.0",
58
59
  "vue": "^3.0.0"
59
60
  },
60
61
  "dependencies": {
61
62
  "defu": "^6.1.4",
63
+ "engine.io": "^6.6.3",
62
64
  "h3": "^1.15.4",
63
65
  "http-proxy": "^1.18.1",
64
- "ofetch": "^1.3.3"
66
+ "ofetch": "^1.3.3",
67
+ "socket.io": "^4.8.3",
68
+ "socket.io-client": "^4.8.3"
65
69
  },
66
70
  "devDependencies": {
67
71
  "@nuxt/module-builder": "^0.8.4",
package/src/module.ts CHANGED
@@ -139,5 +139,9 @@ declare module '#imports' {
139
139
  route: `${apiPrefix}/**`,
140
140
  handler: resolve("./runtime/server/api/all"),
141
141
  });
142
+
143
+ nuxt.options.nitro = nuxt.options.nitro || {};
144
+ nuxt.options.nitro.experimental = nuxt.options.nitro.experimental || {};
145
+ nuxt.options.nitro.experimental.websocket = true;
142
146
  },
143
147
  });
@@ -0,0 +1,83 @@
1
+ // @ts-nocheck - Nitro plugin
2
+ import { defineNitroPlugin } from "nitropack/runtime";
3
+ import { Server as Engine } from "engine.io";
4
+ import { Server } from "socket.io";
5
+ import { io as ioClient } from "socket.io-client";
6
+ import { defineEventHandler } from "h3";
7
+ import { useRuntimeConfig } from "#imports";
8
+ const ENGINE_PATH = "/socket.io";
9
+ const ENGINE_PATH_SLASH = `${ENGINE_PATH}/`;
10
+
11
+ export default defineNitroPlugin((nitroApp) => {
12
+ const config = useRuntimeConfig();
13
+ const apiUrl = config.public?.enfyraSDK?.apiUrl;
14
+ if (!apiUrl) return;
15
+
16
+ const backendUrl = String(apiUrl).replace(/\/+$/, "");
17
+ const engine = new Engine();
18
+ const io = new Server();
19
+ io.bind(engine);
20
+
21
+ io.on("connection", (clientSocket) => {
22
+ const namespace = clientSocket.nsp.name;
23
+ const backendNamespace =
24
+ namespace === "/" || namespace === "" ? "/" : namespace;
25
+ const backendNsUrl = `${backendUrl}${backendNamespace}`;
26
+
27
+ const backendSocket = ioClient(backendNsUrl, {
28
+ path: "/socket.io",
29
+ auth: clientSocket.handshake.auth,
30
+ transports: ["websocket", "polling"],
31
+ });
32
+
33
+ clientSocket.onAny((event: string, ...args: unknown[]) => {
34
+ if (event !== "disconnect") {
35
+ backendSocket.emit(event, ...args);
36
+ }
37
+ });
38
+
39
+ backendSocket.onAny((event: string, ...args: unknown[]) => {
40
+ clientSocket.emit(event, ...args);
41
+ });
42
+
43
+ clientSocket.on("disconnect", () => {
44
+ backendSocket.disconnect();
45
+ });
46
+
47
+ backendSocket.on("disconnect", () => {
48
+ clientSocket.disconnect();
49
+ });
50
+
51
+ backendSocket.on("connect_error", (err: Error) => {
52
+ clientSocket.emit("connect_error", err.message);
53
+ clientSocket.disconnect();
54
+ });
55
+ });
56
+
57
+ nitroApp.router.use(
58
+ `${ENGINE_PATH_SLASH}`,
59
+ defineEventHandler({
60
+ handler(event) {
61
+ const req = event.node.req as Parameters<InstanceType<typeof Engine>["handleRequest"]>[0];
62
+ const res = event.node.res as Parameters<InstanceType<typeof Engine>["handleRequest"]>[1];
63
+ engine.handleRequest(req, res);
64
+ event._handled = true;
65
+ },
66
+ websocket: {
67
+ open(peer) {
68
+ // Nitro/crossws peer with nodeReq for engine.io integration
69
+ const nodeReq = (peer as { _internal?: { nodeReq?: { socket?: unknown } } })._internal?.nodeReq;
70
+ if (nodeReq) {
71
+ (engine as unknown as { prepare(r: unknown): void; onWebSocket(a: unknown, b: unknown, c: WebSocket): void })
72
+ .prepare(nodeReq);
73
+ (engine as unknown as { onWebSocket(a: unknown, b: unknown, c: WebSocket): void }).onWebSocket(
74
+ nodeReq,
75
+ (nodeReq as { socket?: unknown }).socket,
76
+ peer.websocket,
77
+ );
78
+ }
79
+ },
80
+ },
81
+ }),
82
+ );
83
+ });