@iadev93/zuno-elysia 0.0.2 → 0.0.3

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,8 +1,10 @@
1
1
  # @iadev93/zuno-elysia
2
2
 
3
- Elysia adapter for [Zuno](https://github.com/iadev93/zuno), providing seamless state synchronization for ElysiaJS applications.
3
+ <p><b>Elysia adapter for Zuno.</b></p>
4
4
 
5
- ## Installation
5
+ Provides seamless state synchronization for ElysiaJS (Bun) applications using native async generators.
6
+
7
+ ---
6
8
 
7
9
  ```bash
8
10
  pnpm add @iadev93/zuno-elysia
@@ -0,0 +1,66 @@
1
+ import * as _iadev93_zuno_server from '@iadev93/zuno/server';
2
+ import { ZunoStateEvent } from '@iadev93/zuno';
3
+
4
+ /**
5
+ * Creates a Zuno Elysia instance.
6
+ * @returns {Object} An object with the following properties:
7
+ * - sse: An async generator function that handles SSE connections for Elysia.
8
+ * @property {Object} set - Elysia response object.
9
+ * @property {Object} headers - Elysia request headers.
10
+ * @property {Object} query - Elysia request query parameters.
11
+ * - sync: A function that handles sync POST requests for Elysia.
12
+ * @property {Object} body - Elysia request body.
13
+ * @property {Object} set - Elysia response object.
14
+ * - snapshot: A function that handles snapshot GET requests for Elysia.
15
+ */
16
+ declare function createZunoElysia(): {
17
+ /**
18
+ * Handles SSE connections for Elysia using an async generator.
19
+ * @param {Object} param - Elysia request object.
20
+ * @param {Object} param.set - Elysia response object.
21
+ * @param {Object} param.headers - Elysia request headers.
22
+ * @param {Object} param.query - Elysia request query parameters.
23
+ */
24
+ sse: ({ set, headers, query }: any) => AsyncGenerator<string | {
25
+ readonly data: string;
26
+ }, never, unknown>;
27
+ /**
28
+ * Handles sync POST requests for Elysia.
29
+ * @param {Object} param - Elysia request object.
30
+ * @param {Object} param.body - Elysia request body.
31
+ * @param {Object} param.set - Elysia response object.
32
+ * @returns {Object} An object with the following properties:
33
+ * - ok: A boolean indicating whether the sync was successful.
34
+ * - event: The event that was applied to the universe.
35
+ */
36
+ sync: ({ body, set }: any) => {
37
+ ok: boolean;
38
+ reason: string;
39
+ current: {
40
+ state: any;
41
+ version: number;
42
+ } | undefined;
43
+ event?: undefined;
44
+ } | {
45
+ ok: boolean;
46
+ event: ZunoStateEvent;
47
+ reason?: undefined;
48
+ current?: undefined;
49
+ };
50
+ /**
51
+ * Handles snapshot GET requests for Elysia.
52
+ * @returns {Object} An object with the following properties:
53
+ * - state: The current state of the universe.
54
+ * - version: The version of the universe.
55
+ * - lastEventId: The ID of the last event in the universe.
56
+ */
57
+ snapshot: () => {
58
+ state: {
59
+ [k: string]: _iadev93_zuno_server.UniverseRecord;
60
+ };
61
+ version: any;
62
+ lastEventId: number;
63
+ };
64
+ };
65
+
66
+ export { createZunoElysia };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- import type { ZunoStateEvent } from "@iadev93/zuno";
1
+ import * as _iadev93_zuno_server from '@iadev93/zuno/server';
2
+ import { ZunoStateEvent } from '@iadev93/zuno';
3
+
2
4
  /**
3
5
  * Creates a Zuno Elysia instance.
4
6
  * @returns {Object} An object with the following properties:
@@ -11,7 +13,7 @@ import type { ZunoStateEvent } from "@iadev93/zuno";
11
13
  * @property {Object} set - Elysia response object.
12
14
  * - snapshot: A function that handles snapshot GET requests for Elysia.
13
15
  */
14
- export declare function createZunoElysia(): {
16
+ declare function createZunoElysia(): {
15
17
  /**
16
18
  * Handles SSE connections for Elysia using an async generator.
17
19
  * @param {Object} param - Elysia request object.
@@ -33,11 +35,11 @@ export declare function createZunoElysia(): {
33
35
  */
34
36
  sync: ({ body, set }: any) => {
35
37
  ok: boolean;
36
- reason: "VERSION_CONFLICT";
38
+ reason: string;
37
39
  current: {
38
40
  state: any;
39
41
  version: number;
40
- };
42
+ } | undefined;
41
43
  event?: undefined;
42
44
  } | {
43
45
  ok: boolean;
@@ -54,13 +56,11 @@ export declare function createZunoElysia(): {
54
56
  */
55
57
  snapshot: () => {
56
58
  state: {
57
- [k: string]: {
58
- state: any;
59
- version: number;
60
- };
59
+ [k: string]: _iadev93_zuno_server.UniverseRecord;
61
60
  };
62
61
  version: any;
63
62
  lastEventId: number;
64
63
  };
65
64
  };
66
- //# sourceMappingURL=index.d.ts.map
65
+
66
+ export { createZunoElysia };
package/dist/index.js CHANGED
@@ -1,116 +1,18 @@
1
- import { applyStateEvent, getEventsAfter, getLastEventId, getUniverseState, subscribeToStateEvents, } from "@iadev93/zuno/server";
2
- import { sse as elysiaSSE } from "elysia";
3
- /**
4
- * Creates a Zuno Elysia instance.
5
- * @returns {Object} An object with the following properties:
6
- * - sse: An async generator function that handles SSE connections for Elysia.
7
- * @property {Object} set - Elysia response object.
8
- * @property {Object} headers - Elysia request headers.
9
- * @property {Object} query - Elysia request query parameters.
10
- * - sync: A function that handles sync POST requests for Elysia.
11
- * @property {Object} body - Elysia request body.
12
- * @property {Object} set - Elysia response object.
13
- * - snapshot: A function that handles snapshot GET requests for Elysia.
14
- */
15
- export function createZunoElysia() {
16
- return {
17
- /**
18
- * Handles SSE connections for Elysia using an async generator.
19
- * @param {Object} param - Elysia request object.
20
- * @param {Object} param.set - Elysia response object.
21
- * @param {Object} param.headers - Elysia request headers.
22
- * @param {Object} param.query - Elysia request query parameters.
23
- */
24
- sse: async function* ({ set, headers, query }) {
25
- set.headers["Content-Type"] = "text/event-stream";
26
- set.headers["Cache-Control"] = "no-cache";
27
- set.headers["Connection"] = "keep-alive";
28
- yield elysiaSSE(": connected\n");
29
- yield elysiaSSE(":" + " ".repeat(2048) + "\n\n"); // Padding to bypass browser buffering
30
- // Get last event id
31
- const rawLastEventId = headers["last-event-id"] || query?.lastEventId;
32
- const lastEventId = Number.parseInt(rawLastEventId || "0", 10) || 0;
33
- if (lastEventId > 0) {
34
- const missed = getEventsAfter(lastEventId);
35
- for (const event of missed) {
36
- yield elysiaSSE(`id: ${event.eventId}\nevent: state\ndata: ${JSON.stringify(event)}\n\n`);
37
- }
38
- }
39
- else {
40
- const snapshot = getUniverseState();
41
- yield elysiaSSE(`event: snapshot\ndata: ${JSON.stringify(snapshot)}\n\n`);
42
- }
43
- // Buffer queue for events
44
- const queue = [];
45
- let resolve = null;
46
- // Subscribe to events
47
- const unsubscribe = subscribeToStateEvents((event) => {
48
- queue.push(`id: ${event.eventId}\nevent: state\ndata: ${JSON.stringify(event)}\n\n`);
49
- if (resolve) {
50
- resolve();
51
- resolve = null;
52
- }
53
- });
54
- // Heartbeat interval
55
- const heartbeat = setInterval(() => {
56
- queue.push(`: ping ${Date.now()}\n\n`);
57
- if (resolve) {
58
- resolve();
59
- resolve = null;
60
- }
61
- }, 15000);
62
- try {
63
- while (true) {
64
- if (queue.length === 0) {
65
- await new Promise((r) => {
66
- resolve = r;
67
- });
68
- }
69
- while (queue.length > 0) {
70
- yield queue.shift();
71
- }
72
- }
73
- }
74
- finally {
75
- clearInterval(heartbeat);
76
- unsubscribe();
77
- }
78
- },
79
- /**
80
- * Handles sync POST requests for Elysia.
81
- * @param {Object} param - Elysia request object.
82
- * @param {Object} param.body - Elysia request body.
83
- * @param {Object} param.set - Elysia response object.
84
- * @returns {Object} An object with the following properties:
85
- * - ok: A boolean indicating whether the sync was successful.
86
- * - event: The event that was applied to the universe.
87
- */
88
- sync: ({ body, set }) => {
89
- const incoming = body;
90
- const result = applyStateEvent(incoming);
91
- if (!result.ok) {
92
- set.status = 409;
93
- return {
94
- ok: false,
95
- reason: result.reason,
96
- current: result.current,
97
- };
98
- }
99
- return { ok: true, event: result.event };
100
- },
101
- /**
102
- * Handles snapshot GET requests for Elysia.
103
- * @returns {Object} An object with the following properties:
104
- * - state: The current state of the universe.
105
- * - version: The version of the universe.
106
- * - lastEventId: The ID of the last event in the universe.
107
- */
108
- snapshot: () => {
109
- return {
110
- state: getUniverseState(),
111
- version: getUniverseState().version ?? 0,
112
- lastEventId: getLastEventId(),
113
- };
114
- },
115
- };
116
- }
1
+ 'use strict';var server=require('@iadev93/zuno/server'),elysia=require('elysia');function g(){return {sse:async function*({set:s,headers:i,query:l}){s.headers["Content-Type"]="text/event-stream",s.headers["Cache-Control"]="no-cache",s.headers.Connection="keep-alive",yield elysia.sse(`: connected
2
+ `),yield elysia.sse(":"+" ".repeat(2048)+`
3
+
4
+ `);let n=i["last-event-id"]||l?.lastEventId,v=Number.parseInt(n||"0",10)||0;if(v>0){let e=server.getEventsAfter(v);for(let u of e)yield elysia.sse(`id: ${u.eventId}
5
+ event: state
6
+ data: ${JSON.stringify(u)}
7
+
8
+ `);}else {let e=server.getUniverseState();yield elysia.sse(`event: snapshot
9
+ data: ${JSON.stringify(e)}
10
+
11
+ `);}let a=[],t=null,c=server.subscribeToStateEvents(e=>{a.push(`id: ${e.eventId}
12
+ event: state
13
+ data: ${JSON.stringify(e)}
14
+
15
+ `),t&&(t(),t=null);}),d=setInterval(()=>{a.push(`: ping ${Date.now()}
16
+
17
+ `),t&&(t(),t=null);},15e3);try{for(;;)for(a.length===0&&await new Promise(e=>{t=e;});a.length>0;)yield a.shift();}finally{clearInterval(d),c();}},sync:({body:s,set:i})=>{let n=server.applyStateEvent(s);return n.ok?{ok:true,event:n.event}:(i.status=409,{ok:false,reason:n.reason,current:n.current})},snapshot:()=>({state:server.getUniverseState(),version:server.getUniverseState().version??0,lastEventId:server.getLastEventId()})}}exports.createZunoElysia=g;//# sourceMappingURL=index.js.map
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["createZunoElysia","set","headers","query","elysiaSSE","rawLastEventId","lastEventId","missed","getEventsAfter","event","snapshot","getUniverseState","queue","resolve","unsubscribe","subscribeToStateEvents","heartbeat","r","body","result","applyStateEvent","getLastEventId"],"mappings":"iFAsBO,SAASA,GAAmB,CACjC,OAAO,CAQL,GAAA,CAAK,gBAAiB,CAAE,IAAAC,CAAAA,CAAK,OAAA,CAAAC,EAAS,KAAA,CAAAC,CAAM,EAAQ,CAClDF,CAAAA,CAAI,QAAQ,cAAc,CAAA,CAAI,oBAC9BA,CAAAA,CAAI,OAAA,CAAQ,eAAe,CAAA,CAAI,UAAA,CAC/BA,EAAI,OAAA,CAAQ,UAAA,CAAgB,YAAA,CAE5B,MAAMG,UAAAA,CAAU,CAAA;AAAA,CAAe,EAC/B,MAAMA,UAAAA,CAAU,IAAM,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,CAAI;;AAAA,CAAM,CAAA,CAG/C,IAAMC,CAAAA,CAAiBH,CAAAA,CAAQ,eAAe,CAAA,EAAKC,CAAAA,EAAO,WAAA,CACpDG,CAAAA,CAAc,MAAA,CAAO,QAAA,CAASD,CAAAA,EAAkB,GAAA,CAAK,EAAE,CAAA,EAAK,CAAA,CAElE,GAAIC,CAAAA,CAAc,CAAA,CAAG,CACnB,IAAMC,CAAAA,CAASC,sBAAeF,CAAW,CAAA,CACzC,IAAA,IAAWG,CAAAA,IAASF,CAAAA,CAClB,MAAMH,UAAAA,CAAU,CAAA,IAAA,EAAOK,EAAM,OAAO;AAAA;AAAA,MAAA,EAAyB,IAAA,CAAK,SAAA,CAAUA,CAAK,CAAC;;AAAA,CAAM,EAE5F,MAAO,CACL,IAAMC,EAAWC,uBAAAA,EAAiB,CAClC,MAAMP,UAAAA,CAAU,CAAA;AAAA,MAAA,EAA0B,IAAA,CAAK,SAAA,CAAUM,CAAQ,CAAC;;AAAA,CAAM,EAC1E,CAGA,IAAME,CAAAA,CAAkB,GACpBC,CAAAA,CAA8D,IAAA,CAG5DC,CAAAA,CAAcC,6BAAAA,CAAwBN,GAA0B,CACpEG,CAAAA,CAAM,IAAA,CAAK,CAAA,IAAA,EAAOH,EAAM,OAAO;AAAA;AAAA,MAAA,EAAyB,IAAA,CAAK,SAAA,CAAUA,CAAK,CAAC;;AAAA,CAAM,EAC/EI,CAAAA,GACFA,CAAAA,EAAQ,CACRA,CAAAA,CAAU,MAEd,CAAC,CAAA,CAGKG,CAAAA,CAAY,WAAA,CAAY,IAAM,CAClCJ,CAAAA,CAAM,KAAK,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK;;AAAA,CAAM,CAAA,CACjCC,IACFA,CAAAA,EAAQ,CACRA,EAAU,IAAA,EAEd,CAAA,CAAG,IAAK,CAAA,CAER,GAAI,CACF,OAOE,IANID,EAAM,MAAA,GAAW,CAAA,EACnB,MAAM,IAAI,OAAA,CAAeK,GAAM,CAC7BJ,CAAAA,CAAUI,EACZ,CAAC,CAAA,CAGIL,EAAM,MAAA,CAAS,CAAA,EACpB,MAAMA,CAAAA,CAAM,KAAA,GAGlB,CAAA,OAAE,CACA,cAAcI,CAAS,CAAA,CACvBF,IACF,CACF,EAWA,IAAA,CAAM,CAAC,CAAE,IAAA,CAAAI,CAAAA,CAAM,GAAA,CAAAjB,CAAI,CAAA,GAAW,CAE5B,IAAMkB,CAAAA,CAASC,sBAAAA,CADEF,CACsB,CAAA,CAEvC,OAAKC,EAAO,EAAA,CASL,CAAE,GAAI,IAAA,CAAM,KAAA,CAAOA,EAAO,KAAM,CAAA,EARrClB,EAAI,MAAA,CAAS,GAAA,CACN,CACL,EAAA,CAAI,KAAA,CACJ,OAAQkB,CAAAA,CAAO,MAAA,CACf,QAASA,CAAAA,CAAO,OAClB,EAIJ,CAAA,CASA,QAAA,CAAU,KACD,CACL,KAAA,CAAOR,yBAAiB,CACxB,OAAA,CAAUA,yBAAiB,CAAU,OAAA,EAAW,EAChD,WAAA,CAAaU,qBAAAA,EACf,CAAA,CAEJ,CACF","file":"index.js","sourcesContent":["import type { ZunoStateEvent } from \"@iadev93/zuno\";\nimport {\n applyStateEvent,\n getEventsAfter,\n getLastEventId,\n getUniverseState,\n subscribeToStateEvents,\n} from \"@iadev93/zuno/server\";\nimport { sse as elysiaSSE } from \"elysia\"\n\n/**\n * Creates a Zuno Elysia instance.\n * @returns {Object} An object with the following properties:\n * - sse: An async generator function that handles SSE connections for Elysia.\n * @property {Object} set - Elysia response object.\n * @property {Object} headers - Elysia request headers.\n * @property {Object} query - Elysia request query parameters.\n * - sync: A function that handles sync POST requests for Elysia.\n * @property {Object} body - Elysia request body.\n * @property {Object} set - Elysia response object.\n * - snapshot: A function that handles snapshot GET requests for Elysia.\n */\nexport function createZunoElysia() {\n return {\n /**\n * Handles SSE connections for Elysia using an async generator.\n * @param {Object} param - Elysia request object.\n * @param {Object} param.set - Elysia response object.\n * @param {Object} param.headers - Elysia request headers.\n * @param {Object} param.query - Elysia request query parameters.\n */\n sse: async function* ({ set, headers, query }: any) {\n set.headers[\"Content-Type\"] = \"text/event-stream\";\n set.headers[\"Cache-Control\"] = \"no-cache\";\n set.headers[\"Connection\"] = \"keep-alive\";\n\n yield elysiaSSE(\": connected\\n\");\n yield elysiaSSE(\":\" + \" \".repeat(2048) + \"\\n\\n\"); // Padding to bypass browser buffering\n\n // Get last event id\n const rawLastEventId = headers[\"last-event-id\"] || query?.lastEventId;\n const lastEventId = Number.parseInt(rawLastEventId || \"0\", 10) || 0;\n\n if (lastEventId > 0) {\n const missed = getEventsAfter(lastEventId);\n for (const event of missed) {\n yield elysiaSSE(`id: ${event.eventId}\\nevent: state\\ndata: ${JSON.stringify(event)}\\n\\n`);\n }\n } else {\n const snapshot = getUniverseState();\n yield elysiaSSE(`event: snapshot\\ndata: ${JSON.stringify(snapshot)}\\n\\n`);\n }\n\n // Buffer queue for events\n const queue: string[] = [];\n let resolve: ((value: void | PromiseLike<void>) => void) | null = null;\n\n // Subscribe to events\n const unsubscribe = subscribeToStateEvents((event: ZunoStateEvent) => {\n queue.push(`id: ${event.eventId}\\nevent: state\\ndata: ${JSON.stringify(event)}\\n\\n`);\n if (resolve) {\n resolve();\n resolve = null;\n }\n });\n\n // Heartbeat interval\n const heartbeat = setInterval(() => {\n queue.push(`: ping ${Date.now()}\\n\\n`);\n if (resolve) {\n resolve();\n resolve = null;\n }\n }, 15000);\n\n try {\n while (true) {\n if (queue.length === 0) {\n await new Promise<void>((r) => {\n resolve = r;\n });\n }\n\n while (queue.length > 0) {\n yield queue.shift()!;\n }\n }\n } finally {\n clearInterval(heartbeat);\n unsubscribe();\n }\n },\n\n /**\n * Handles sync POST requests for Elysia.\n * @param {Object} param - Elysia request object.\n * @param {Object} param.body - Elysia request body.\n * @param {Object} param.set - Elysia response object.\n * @returns {Object} An object with the following properties:\n * - ok: A boolean indicating whether the sync was successful.\n * - event: The event that was applied to the universe.\n */\n sync: ({ body, set }: any) => {\n const incoming = body as ZunoStateEvent;\n const result = applyStateEvent(incoming);\n\n if (!result.ok) {\n set.status = 409;\n return {\n ok: false,\n reason: result.reason,\n current: result.current,\n };\n }\n\n return { ok: true, event: result.event };\n },\n\n /**\n * Handles snapshot GET requests for Elysia.\n * @returns {Object} An object with the following properties:\n * - state: The current state of the universe.\n * - version: The version of the universe.\n * - lastEventId: The ID of the last event in the universe.\n */\n snapshot: () => {\n return {\n state: getUniverseState(),\n version: (getUniverseState() as any).version ?? 0,\n lastEventId: getLastEventId(),\n };\n },\n };\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,18 @@
1
+ import {getLastEventId,getUniverseState,applyStateEvent,getEventsAfter,subscribeToStateEvents}from'@iadev93/zuno/server';import {sse}from'elysia';function g(){return {sse:async function*({set:s,headers:i,query:l}){s.headers["Content-Type"]="text/event-stream",s.headers["Cache-Control"]="no-cache",s.headers.Connection="keep-alive",yield sse(`: connected
2
+ `),yield sse(":"+" ".repeat(2048)+`
3
+
4
+ `);let n=i["last-event-id"]||l?.lastEventId,v=Number.parseInt(n||"0",10)||0;if(v>0){let e=getEventsAfter(v);for(let u of e)yield sse(`id: ${u.eventId}
5
+ event: state
6
+ data: ${JSON.stringify(u)}
7
+
8
+ `);}else {let e=getUniverseState();yield sse(`event: snapshot
9
+ data: ${JSON.stringify(e)}
10
+
11
+ `);}let a=[],t=null,c=subscribeToStateEvents(e=>{a.push(`id: ${e.eventId}
12
+ event: state
13
+ data: ${JSON.stringify(e)}
14
+
15
+ `),t&&(t(),t=null);}),d=setInterval(()=>{a.push(`: ping ${Date.now()}
16
+
17
+ `),t&&(t(),t=null);},15e3);try{for(;;)for(a.length===0&&await new Promise(e=>{t=e;});a.length>0;)yield a.shift();}finally{clearInterval(d),c();}},sync:({body:s,set:i})=>{let n=applyStateEvent(s);return n.ok?{ok:true,event:n.event}:(i.status=409,{ok:false,reason:n.reason,current:n.current})},snapshot:()=>({state:getUniverseState(),version:getUniverseState().version??0,lastEventId:getLastEventId()})}}export{g as createZunoElysia};//# sourceMappingURL=index.mjs.map
18
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["createZunoElysia","set","headers","query","elysiaSSE","rawLastEventId","lastEventId","missed","getEventsAfter","event","snapshot","getUniverseState","queue","resolve","unsubscribe","subscribeToStateEvents","heartbeat","r","body","result","applyStateEvent","getLastEventId"],"mappings":"kJAsBO,SAASA,GAAmB,CACjC,OAAO,CAQL,GAAA,CAAK,gBAAiB,CAAE,IAAAC,CAAAA,CAAK,OAAA,CAAAC,EAAS,KAAA,CAAAC,CAAM,EAAQ,CAClDF,CAAAA,CAAI,QAAQ,cAAc,CAAA,CAAI,oBAC9BA,CAAAA,CAAI,OAAA,CAAQ,eAAe,CAAA,CAAI,UAAA,CAC/BA,EAAI,OAAA,CAAQ,UAAA,CAAgB,YAAA,CAE5B,MAAMG,GAAAA,CAAU,CAAA;AAAA,CAAe,EAC/B,MAAMA,GAAAA,CAAU,IAAM,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,CAAI;;AAAA,CAAM,CAAA,CAG/C,IAAMC,CAAAA,CAAiBH,CAAAA,CAAQ,eAAe,CAAA,EAAKC,CAAAA,EAAO,WAAA,CACpDG,CAAAA,CAAc,MAAA,CAAO,QAAA,CAASD,CAAAA,EAAkB,GAAA,CAAK,EAAE,CAAA,EAAK,CAAA,CAElE,GAAIC,CAAAA,CAAc,CAAA,CAAG,CACnB,IAAMC,CAAAA,CAASC,eAAeF,CAAW,CAAA,CACzC,IAAA,IAAWG,CAAAA,IAASF,CAAAA,CAClB,MAAMH,GAAAA,CAAU,CAAA,IAAA,EAAOK,EAAM,OAAO;AAAA;AAAA,MAAA,EAAyB,IAAA,CAAK,SAAA,CAAUA,CAAK,CAAC;;AAAA,CAAM,EAE5F,MAAO,CACL,IAAMC,EAAWC,gBAAAA,EAAiB,CAClC,MAAMP,GAAAA,CAAU,CAAA;AAAA,MAAA,EAA0B,IAAA,CAAK,SAAA,CAAUM,CAAQ,CAAC;;AAAA,CAAM,EAC1E,CAGA,IAAME,CAAAA,CAAkB,GACpBC,CAAAA,CAA8D,IAAA,CAG5DC,CAAAA,CAAcC,sBAAAA,CAAwBN,GAA0B,CACpEG,CAAAA,CAAM,IAAA,CAAK,CAAA,IAAA,EAAOH,EAAM,OAAO;AAAA;AAAA,MAAA,EAAyB,IAAA,CAAK,SAAA,CAAUA,CAAK,CAAC;;AAAA,CAAM,EAC/EI,CAAAA,GACFA,CAAAA,EAAQ,CACRA,CAAAA,CAAU,MAEd,CAAC,CAAA,CAGKG,CAAAA,CAAY,WAAA,CAAY,IAAM,CAClCJ,CAAAA,CAAM,KAAK,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK;;AAAA,CAAM,CAAA,CACjCC,IACFA,CAAAA,EAAQ,CACRA,EAAU,IAAA,EAEd,CAAA,CAAG,IAAK,CAAA,CAER,GAAI,CACF,OAOE,IANID,EAAM,MAAA,GAAW,CAAA,EACnB,MAAM,IAAI,OAAA,CAAeK,GAAM,CAC7BJ,CAAAA,CAAUI,EACZ,CAAC,CAAA,CAGIL,EAAM,MAAA,CAAS,CAAA,EACpB,MAAMA,CAAAA,CAAM,KAAA,GAGlB,CAAA,OAAE,CACA,cAAcI,CAAS,CAAA,CACvBF,IACF,CACF,EAWA,IAAA,CAAM,CAAC,CAAE,IAAA,CAAAI,CAAAA,CAAM,GAAA,CAAAjB,CAAI,CAAA,GAAW,CAE5B,IAAMkB,CAAAA,CAASC,eAAAA,CADEF,CACsB,CAAA,CAEvC,OAAKC,EAAO,EAAA,CASL,CAAE,GAAI,IAAA,CAAM,KAAA,CAAOA,EAAO,KAAM,CAAA,EARrClB,EAAI,MAAA,CAAS,GAAA,CACN,CACL,EAAA,CAAI,KAAA,CACJ,OAAQkB,CAAAA,CAAO,MAAA,CACf,QAASA,CAAAA,CAAO,OAClB,EAIJ,CAAA,CASA,QAAA,CAAU,KACD,CACL,KAAA,CAAOR,kBAAiB,CACxB,OAAA,CAAUA,kBAAiB,CAAU,OAAA,EAAW,EAChD,WAAA,CAAaU,cAAAA,EACf,CAAA,CAEJ,CACF","file":"index.mjs","sourcesContent":["import type { ZunoStateEvent } from \"@iadev93/zuno\";\nimport {\n applyStateEvent,\n getEventsAfter,\n getLastEventId,\n getUniverseState,\n subscribeToStateEvents,\n} from \"@iadev93/zuno/server\";\nimport { sse as elysiaSSE } from \"elysia\"\n\n/**\n * Creates a Zuno Elysia instance.\n * @returns {Object} An object with the following properties:\n * - sse: An async generator function that handles SSE connections for Elysia.\n * @property {Object} set - Elysia response object.\n * @property {Object} headers - Elysia request headers.\n * @property {Object} query - Elysia request query parameters.\n * - sync: A function that handles sync POST requests for Elysia.\n * @property {Object} body - Elysia request body.\n * @property {Object} set - Elysia response object.\n * - snapshot: A function that handles snapshot GET requests for Elysia.\n */\nexport function createZunoElysia() {\n return {\n /**\n * Handles SSE connections for Elysia using an async generator.\n * @param {Object} param - Elysia request object.\n * @param {Object} param.set - Elysia response object.\n * @param {Object} param.headers - Elysia request headers.\n * @param {Object} param.query - Elysia request query parameters.\n */\n sse: async function* ({ set, headers, query }: any) {\n set.headers[\"Content-Type\"] = \"text/event-stream\";\n set.headers[\"Cache-Control\"] = \"no-cache\";\n set.headers[\"Connection\"] = \"keep-alive\";\n\n yield elysiaSSE(\": connected\\n\");\n yield elysiaSSE(\":\" + \" \".repeat(2048) + \"\\n\\n\"); // Padding to bypass browser buffering\n\n // Get last event id\n const rawLastEventId = headers[\"last-event-id\"] || query?.lastEventId;\n const lastEventId = Number.parseInt(rawLastEventId || \"0\", 10) || 0;\n\n if (lastEventId > 0) {\n const missed = getEventsAfter(lastEventId);\n for (const event of missed) {\n yield elysiaSSE(`id: ${event.eventId}\\nevent: state\\ndata: ${JSON.stringify(event)}\\n\\n`);\n }\n } else {\n const snapshot = getUniverseState();\n yield elysiaSSE(`event: snapshot\\ndata: ${JSON.stringify(snapshot)}\\n\\n`);\n }\n\n // Buffer queue for events\n const queue: string[] = [];\n let resolve: ((value: void | PromiseLike<void>) => void) | null = null;\n\n // Subscribe to events\n const unsubscribe = subscribeToStateEvents((event: ZunoStateEvent) => {\n queue.push(`id: ${event.eventId}\\nevent: state\\ndata: ${JSON.stringify(event)}\\n\\n`);\n if (resolve) {\n resolve();\n resolve = null;\n }\n });\n\n // Heartbeat interval\n const heartbeat = setInterval(() => {\n queue.push(`: ping ${Date.now()}\\n\\n`);\n if (resolve) {\n resolve();\n resolve = null;\n }\n }, 15000);\n\n try {\n while (true) {\n if (queue.length === 0) {\n await new Promise<void>((r) => {\n resolve = r;\n });\n }\n\n while (queue.length > 0) {\n yield queue.shift()!;\n }\n }\n } finally {\n clearInterval(heartbeat);\n unsubscribe();\n }\n },\n\n /**\n * Handles sync POST requests for Elysia.\n * @param {Object} param - Elysia request object.\n * @param {Object} param.body - Elysia request body.\n * @param {Object} param.set - Elysia response object.\n * @returns {Object} An object with the following properties:\n * - ok: A boolean indicating whether the sync was successful.\n * - event: The event that was applied to the universe.\n */\n sync: ({ body, set }: any) => {\n const incoming = body as ZunoStateEvent;\n const result = applyStateEvent(incoming);\n\n if (!result.ok) {\n set.status = 409;\n return {\n ok: false,\n reason: result.reason,\n current: result.current,\n };\n }\n\n return { ok: true, event: result.event };\n },\n\n /**\n * Handles snapshot GET requests for Elysia.\n * @returns {Object} An object with the following properties:\n * - state: The current state of the universe.\n * - version: The version of the universe.\n * - lastEventId: The ID of the last event in the universe.\n */\n snapshot: () => {\n return {\n state: getUniverseState(),\n version: (getUniverseState() as any).version ?? 0,\n lastEventId: getLastEventId(),\n };\n },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iadev93/zuno-elysia",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -20,6 +20,7 @@
20
20
  },
21
21
  "devDependencies": {
22
22
  "elysia": "^1.2.10",
23
+ "tsup": "^8.5.1",
23
24
  "typescript": "^5.9.3",
24
25
  "@iadev93/zuno": "0.0.5"
25
26
  },
@@ -45,6 +46,7 @@
45
46
  "realtime"
46
47
  ],
47
48
  "scripts": {
48
- "build": "tsc -p tsconfig.json"
49
+ "build": "tsup",
50
+ "dev": "tsup --watch"
49
51
  }
50
52
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAUpD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB;IAE5B;;;;;;OAMG;mCAC4C,GAAG;;;IA8DlD;;;;;;;;OAQG;0BACmB,GAAG;;;;;;;;;;;;;;IAgBzB;;;;;;OAMG;;;;;;;;;;;EASN"}