@pluv/platform-pluv 4.0.0 → 4.0.2
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/.turbo/turbo-build.log +11 -11
- package/CHANGELOG.md +19 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +9 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
- package/src/PluvPlatform.ts +1 -1
- package/src/shared/createErrorResponse.ts +9 -1
- package/src/shared/createSuccessResponse.ts +1 -0
- package/src/types.ts +2 -6
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
> tsdown
|
|
4
|
-
|
|
5
|
-
[34mℹ[39m tsdown [2mv0.20.0-beta.4[22m powered by rolldown [2mv1.0.0-beta.60[22m
|
|
1
|
+
$ tsdown
|
|
2
|
+
[34mℹ[39m [34mtsdown v0.22.2[39m powered by [38;2;255;126;23mrolldown v1.1.0[39m
|
|
6
3
|
[34mℹ[39m config file: [4m/home/runner/work/pluv/pluv/packages/platform-pluv/tsdown.config.ts[24m
|
|
7
4
|
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
8
5
|
[34mℹ[39m target: [34mesnext[39m
|
|
9
6
|
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
10
7
|
[34mℹ[39m Build start
|
|
11
|
-
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m13.
|
|
12
|
-
[34mℹ[39m [2mdist/[22mindex.mjs.map [
|
|
13
|
-
[34mℹ[39m [2mdist/[22mindex.d.mts.map [2m 1.
|
|
8
|
+
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m13.62 kB[22m [2m│ gzip: 3.44 kB[22m
|
|
9
|
+
[34mℹ[39m [2mdist/[22mindex.mjs.map [2m34.06 kB[22m [2m│ gzip: 7.39 kB[22m
|
|
10
|
+
[34mℹ[39m [2mdist/[22mindex.d.mts.map [2m 1.85 kB[22m [2m│ gzip: 0.69 kB[22m
|
|
14
11
|
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 4.21 kB[22m [2m│ gzip: 1.29 kB[22m
|
|
15
|
-
[34mℹ[39m 4 files, total: 53.
|
|
16
|
-
[33m[PLUGIN_TIMINGS]
|
|
12
|
+
[34mℹ[39m 4 files, total: 53.75 kB
|
|
13
|
+
[33m[PLUGIN_TIMINGS] [0mYour build spent significant time in plugins. Here is a breakdown:
|
|
14
|
+
- rolldown-plugin-dts:generate (72%)
|
|
15
|
+
- tsdown:deps (23%)
|
|
16
|
+
See https://rolldown.rs/options/checks#plugintimings for more details.
|
|
17
17
|
|
|
18
|
-
[32m✔[39m Build complete in [
|
|
18
|
+
[32m✔[39m Build complete in [32m3902ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @pluv/platform-pluv
|
|
2
2
|
|
|
3
|
+
## 4.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e1913b3: Upgraded internal dependencies
|
|
8
|
+
- Updated dependencies [e1913b3]
|
|
9
|
+
- @pluv/types@4.0.2
|
|
10
|
+
- @pluv/crdt@4.0.2
|
|
11
|
+
- @pluv/io@4.0.2
|
|
12
|
+
|
|
13
|
+
## 4.0.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 982e068: Added http header for webhook events (`x-pluv-event`).
|
|
18
|
+
- @pluv/crdt@4.0.1
|
|
19
|
+
- @pluv/io@4.0.1
|
|
20
|
+
- @pluv/types@4.0.1
|
|
21
|
+
|
|
3
22
|
## 4.0.0
|
|
4
23
|
|
|
5
24
|
### Major Changes
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/PluvPlatform.ts","../src/platformPluv.ts"],"mappings":";;;;;;UAqBiB,eAAA;EACb,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/PluvPlatform.ts","../src/platformPluv.ts"],"mappings":";;;;;;UAqBiB,eAAA;EACb,WAAW;AAAA;;;KCDH,SAAA,mBAA4B,YAAY;AAAA,KACxC,SAAA,mBAA4B,YAAY;AAAA,KACxC,aAAA,mBAAgC,YAAY;AAAA,UAEvC,kBAAA,kBAAoC,MAAA;;;ADHtC;;;ECSX,KAAA;IACI,KAAA;IACA,SAAA,GAAY,eAAA,UAAyB,YAAA,CAAa,eAAA;EAAA;EAEtD,QAAA;EACA,OAAA,GAAU,WAAA,MAAiB,QAAA;EAC3B,SAAA,EAAW,SAAA;EACX,SAAA,EAAW,SAAA;EACX,aAAA,GAAgB,aAAA;AAAA;AAAA,cAGP,YAAA,kBACQ,MAAA,kCACH,QAAA,GAAW,QAAA,UACnB,gBAAA;EAKF,SAAA;IACI,MAAA;EAAA;EAEJ,UAAA;EACA,gBAAA;EACA,WAAA;EACA,SAAA;IACI,eAAA;IACA,aAAA;IACA,kBAAA;IACA,gBAAA;IACA,eAAA;IACA,kBAAA;EAAA;EAEJ,MAAA;AAAA;EAAA,SAGY,EAAA;EAAA,SACA,OAAA;;;;;;;;;;;;;;;;;WAiBA,KAAA;EAAA,iBAEC,IAAA;EAAA,iBACA,SAAA;EAAA,iBACA,QAAA;EAAA,iBACA,MAAA;EAAA,iBACA,UAAA;EAAA,QACT,kBAAA;EAAA,QACA,UAAA;EAAA,iBACS,UAAA;EAAA,iBACA,UAAA;EAAA,iBACA,cAAA;EAEV,YAAA,GAAsB,MAAA,EAAQ,eAAA,eAA4B,OAAA;cA0CrD,MAAA,EAAQ,kBAAA;EAmBb,eAAA,CAAgB,SAAA,EAAW,iBAAA,GAAoB,OAAA;EAI/C,gBAAA,CAAiB,SAAA,OAAgB,MAAA,EAAQ,sBAAA,GAAyB,iBAAA;EAIlE,WAAA,CAAY,SAAA,EAAW,iBAAA;EAIvB,kBAAA,CAAmB,SAAA,QAAiB,wBAAA;EAIpC,YAAA,CAAa,SAAA;EAIb,aAAA;EAIA,UAAA,CAAW,MAAA,EAAQ,sBAAA;EAInB,SAAA,CAAU,IAAA,WAAe,WAAA,GAAc,MAAA;EAIvC,UAAA;EAIA,kBAAA,CACH,SAAA,EAAW,iBAAA,EACX,KAAA,EAAO,wBAAA,GACR,wBAAA;EAII,cAAA,CAAe,MAAA;EAAA,QAyBd,eAAA;EAAA,QAiLM,WAAA;EAAA,QAMN,SAAA;AAAA;;;KCpZA,0BAAA,kBACS,MAAA,kCACH,UAAA,GAAW,UAAA,gBACX,eAAA,QAAuB,eAAA,CAAgB,kBAAA,KACrD,EAAA,CACA,kBAAA,GACI,IAAA,CACI,cAAA,CAAe,YAAA,EAAc,QAAA,EAAU,KAAA,EAAO,KAAA;EAG9C,SAAA,EAAW,eAAA,CAAgB,YAAA,EAAc,KAAA,EAAO,oBAAA,CAAqB,YAAA;EACrE,OAAA,GAAU,WAAA,CAAY,YAAA,EAAc,QAAA;AAAA;AAAA,cAInC,YAAA,oBACQ,MAAA,kCACH,UAAA,GAAW,UAAA,gBACX,eAAA,QAAuB,eAAA,CAAgB,kBAAA,GAErD,MAAA,EAAQ,0BAAA,CAA2B,QAAA,EAAU,KAAA,EAAO,KAAA,MACrD,cAAA,CAAe,YAAA,CAAa,QAAA,EAAU,KAAA,GAAQ,QAAA,EAAU,KAAA,EAAO,KAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -3,18 +3,12 @@ import { AbstractPlatform } from "@pluv/io";
|
|
|
3
3
|
import stringify from "fast-json-stable-stringify";
|
|
4
4
|
import { Hono } from "hono";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
|
|
7
|
-
//#region rolldown:runtime
|
|
6
|
+
//#region \0rolldown/runtime.js
|
|
8
7
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
9
|
-
|
|
10
8
|
//#endregion
|
|
11
9
|
//#region src/constants.ts
|
|
12
10
|
const SIGNATURE_ALGORITHM = "sha256";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//#endregion
|
|
16
|
-
//#region src/schemas.ts
|
|
17
|
-
const ZodEventKind = z.union([
|
|
11
|
+
z.union([
|
|
18
12
|
z.literal("initial-storage"),
|
|
19
13
|
z.literal("room-destroyed"),
|
|
20
14
|
z.literal("storage-destroyed"),
|
|
@@ -87,16 +81,14 @@ const ZodEventResponse = z.discriminatedUnion("event", [
|
|
|
87
81
|
ZodUserConnectedResponse,
|
|
88
82
|
ZodUserDisconnectedResponse
|
|
89
83
|
]);
|
|
90
|
-
|
|
91
84
|
//#endregion
|
|
92
85
|
//#region src/shared/createErrorResponse.ts
|
|
93
|
-
const createErrorResponse = (c, error, status) => {
|
|
86
|
+
const createErrorResponse = (c, error, status, event = "unknown") => {
|
|
94
87
|
return c.json({
|
|
95
88
|
ok: false,
|
|
96
89
|
error: { message: error.message }
|
|
97
|
-
}, status);
|
|
90
|
+
}, status, { "x-pluv-event": event });
|
|
98
91
|
};
|
|
99
|
-
|
|
100
92
|
//#endregion
|
|
101
93
|
//#region src/shared/getCrypto.ts
|
|
102
94
|
const getCrypto = () => {
|
|
@@ -104,7 +96,6 @@ const getCrypto = () => {
|
|
|
104
96
|
if (typeof __require === "function") return __require("node:crypto").webcrypto;
|
|
105
97
|
throw new Error("Missing crypto module");
|
|
106
98
|
};
|
|
107
|
-
|
|
108
99
|
//#endregion
|
|
109
100
|
//#region src/shared/createHmac.ts
|
|
110
101
|
const createHmac = async (params) => {
|
|
@@ -124,16 +115,14 @@ const createHmac = async (params) => {
|
|
|
124
115
|
hmac: Array.from(new Uint8Array(signature)).map((b) => ("0" + b.toString(16)).slice(-2)).join("")
|
|
125
116
|
};
|
|
126
117
|
};
|
|
127
|
-
|
|
128
118
|
//#endregion
|
|
129
119
|
//#region src/shared/createSuccessResponse.ts
|
|
130
120
|
const createSuccessResponse = (c, data, status = 200) => {
|
|
131
121
|
return c.json({
|
|
132
122
|
ok: true,
|
|
133
123
|
data: ZodEventResponse.parse(data)
|
|
134
|
-
}, status);
|
|
124
|
+
}, status, { "x-pluv-event": data.event });
|
|
135
125
|
};
|
|
136
|
-
|
|
137
126
|
//#endregion
|
|
138
127
|
//#region src/shared/HttpError.ts
|
|
139
128
|
var HttpError = class extends Error {
|
|
@@ -143,7 +132,6 @@ var HttpError = class extends Error {
|
|
|
143
132
|
this.status = status;
|
|
144
133
|
}
|
|
145
134
|
};
|
|
146
|
-
|
|
147
135
|
//#endregion
|
|
148
136
|
//#region src/shared/timingSafeEqual.ts
|
|
149
137
|
const timingSafeEqual = (a, b) => {
|
|
@@ -152,7 +140,6 @@ const timingSafeEqual = (a, b) => {
|
|
|
152
140
|
for (let i = 0; i < a.length; i++) result |= a[i] ^ b[i];
|
|
153
141
|
return result === 0;
|
|
154
142
|
};
|
|
155
|
-
|
|
156
143
|
//#endregion
|
|
157
144
|
//#region src/shared/verifyWebhook.ts
|
|
158
145
|
const verifyWebhook = async (params) => {
|
|
@@ -169,7 +156,6 @@ const verifyWebhook = async (params) => {
|
|
|
169
156
|
if (verificationBytes.length !== signatureBytes.length) return false;
|
|
170
157
|
return timingSafeEqual(verificationBytes, signatureBytes);
|
|
171
158
|
};
|
|
172
|
-
|
|
173
159
|
//#endregion
|
|
174
160
|
//#region src/PluvPlatform.ts
|
|
175
161
|
var PluvPlatform = class extends AbstractPlatform {
|
|
@@ -299,13 +285,13 @@ var PluvPlatform = class extends AbstractPlatform {
|
|
|
299
285
|
};
|
|
300
286
|
}
|
|
301
287
|
_webhooksRouter = new Hono().basePath("/").post("/", async (c) => {
|
|
302
|
-
const [algorithm, signature] = c.req.header(
|
|
288
|
+
const [algorithm, signature] = c.req.header("x-pluv-signature-256")?.split("=") ?? [];
|
|
303
289
|
try {
|
|
304
290
|
if (!this._webhookSecret) {
|
|
305
291
|
this._logDebug("Missing webhook secret");
|
|
306
292
|
throw new HttpError("Unauthorized", 401);
|
|
307
293
|
}
|
|
308
|
-
if (algorithm !==
|
|
294
|
+
if (algorithm !== "sha256") {
|
|
309
295
|
this._logDebug(`Verification algorithm is not ${SIGNATURE_ALGORITHM}. Found: `, algorithm);
|
|
310
296
|
throw new HttpError("Unauthorized", 401);
|
|
311
297
|
}
|
|
@@ -431,7 +417,7 @@ var PluvPlatform = class extends AbstractPlatform {
|
|
|
431
417
|
throw error;
|
|
432
418
|
}
|
|
433
419
|
}
|
|
434
|
-
default:
|
|
420
|
+
default: return createErrorResponse(c, { message: "Unknown event" }, 400, event);
|
|
435
421
|
}
|
|
436
422
|
} catch (error) {
|
|
437
423
|
const message = error instanceof Error ? error.message : "Unexpected error";
|
|
@@ -448,7 +434,6 @@ var PluvPlatform = class extends AbstractPlatform {
|
|
|
448
434
|
console.log("[PLATFORM PLUV]", ...args);
|
|
449
435
|
}
|
|
450
436
|
};
|
|
451
|
-
|
|
452
437
|
//#endregion
|
|
453
438
|
//#region src/platformPluv.ts
|
|
454
439
|
const platformPluv = (config) => {
|
|
@@ -461,7 +446,7 @@ const platformPluv = (config) => {
|
|
|
461
446
|
platform: () => new PluvPlatform(config)
|
|
462
447
|
};
|
|
463
448
|
};
|
|
464
|
-
|
|
465
449
|
//#endregion
|
|
466
450
|
export { PluvPlatform, platformPluv };
|
|
451
|
+
|
|
467
452
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/constants.ts","../src/schemas.ts","../src/shared/createErrorResponse.ts","../src/shared/getCrypto.ts","../src/shared/createHmac.ts","../src/shared/createSuccessResponse.ts","../src/shared/HttpError.ts","../src/shared/timingSafeEqual.ts","../src/shared/verifyWebhook.ts","../src/PluvPlatform.ts","../src/platformPluv.ts"],"sourcesContent":["export const SIGNATURE_ALGORITHM = \"sha256\";\nexport const SIGNATURE_HEADER = \"x-pluv-signature-256\";\n","import { z } from \"zod\";\n\nexport const ZodEventKind = z.union([\n z.literal(\"initial-storage\"),\n z.literal(\"room-destroyed\"),\n z.literal(\"storage-destroyed\"),\n z.literal(\"user-connected\"),\n z.literal(\"user-disconnected\"),\n]);\n\nexport const ZodEventInitialStorage = z.object({\n event: z.literal(\"initial-storage\"),\n data: z.object({\n room: z.string(),\n }),\n});\n\nexport const ZodEventRoomDestroyed = z.object({\n event: z.literal(\"room-destroyed\"),\n data: z.object({\n room: z.string(),\n }),\n});\n\nexport const ZodEventStorageDestroyed = z.object({\n event: z.literal(\"storage-destroyed\"),\n data: z.object({\n room: z.string(),\n storage: z.string().nullable(),\n }),\n});\n\nexport const ZodEventUserConnected = z.object({\n event: z.literal(\"user-connected\"),\n data: z.object({\n room: z.string(),\n storage: z.string().nullable(),\n user: z\n .object({\n id: z.string(),\n })\n .passthrough(),\n }),\n});\n\nexport const ZodEventUserDisconnected = z.object({\n event: z.literal(\"user-disconnected\"),\n data: z.object({\n room: z.string(),\n storage: z.string().nullable(),\n user: z\n .object({\n id: z.string(),\n })\n .passthrough(),\n }),\n});\n\nexport const ZodEvent = z.discriminatedUnion(\"event\", [\n ZodEventInitialStorage,\n ZodEventRoomDestroyed,\n ZodEventStorageDestroyed,\n ZodEventUserConnected,\n ZodEventUserDisconnected,\n]);\n\nexport const ZodInitialStorageResponse = z.object({\n event: z.literal(\"initial-storage\"),\n room: z.string(),\n storage: z.string().nullable(),\n});\n\nexport const ZodRoomDestroyedResponse = z.object({\n event: z.literal(\"room-destroyed\"),\n room: z.string(),\n});\n\nexport const ZodStorageDestroyedResponse = z.object({\n event: z.literal(\"storage-destroyed\"),\n room: z.string(),\n});\n\nexport const ZodUserConnectedResponse = z.object({\n event: z.literal(\"user-connected\"),\n room: z.string(),\n});\n\nexport const ZodUserDisconnectedResponse = z.object({\n event: z.literal(\"user-disconnected\"),\n room: z.string(),\n});\n\nexport const ZodEventResponse = z.discriminatedUnion(\"event\", [\n ZodInitialStorageResponse,\n ZodRoomDestroyedResponse,\n ZodStorageDestroyedResponse,\n ZodUserConnectedResponse,\n ZodUserDisconnectedResponse,\n]);\n","import type { Context } from \"hono\";\nimport type { BlankEnv, BlankInput } from \"hono/types\";\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\";\n\nexport const createErrorResponse = <TStatus extends ContentfulStatusCode>(\n c: Context<BlankEnv, \"/\", BlankInput>,\n error: { message: string },\n status: TStatus,\n) => {\n return c.json({ ok: false, error: { message: error.message } }, status);\n};\n","import type { webcrypto } from \"crypto\";\n\nexport const getCrypto = (): webcrypto.Crypto => {\n if (typeof crypto !== \"undefined\") {\n // In a browser or Web Worker (including Cloudflare Workers)\n return crypto;\n }\n\n if (typeof require === \"function\") {\n // In Node.js\n // Node 15+ supports `crypto.webcrypto`\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(\"node:crypto\").webcrypto as webcrypto.Crypto;\n }\n\n throw new Error(\"Missing crypto module\");\n};\n","import type { webcrypto } from \"crypto\";\nimport { getCrypto } from \"./getCrypto\";\n\nexport interface CreateHmacParams {\n payload: string;\n secret: string;\n}\n\nexport type CreateHmacResult = {\n algorithm: \"sha256\";\n hmac: string;\n};\n\nexport const createHmac = async (params: CreateHmacParams): Promise<CreateHmacResult> => {\n const { payload, secret } = params;\n\n if (!payload || !secret) throw new Error(\"Secret and payload are required to sign payload\");\n\n const encoder = new TextEncoder();\n const keyBytes = encoder.encode(secret);\n\n const crypto = getCrypto();\n\n const algorithm: webcrypto.HmacImportParams = { name: \"HMAC\", hash: { name: \"SHA-256\" } };\n const extractable = false;\n\n const key = await crypto.subtle.importKey(\"raw\", keyBytes, algorithm, extractable, [\n \"sign\",\n \"verify\",\n ]);\n const payloadBytes = encoder.encode(payload);\n\n const signature = await crypto.subtle.sign(\"HMAC\", key, payloadBytes);\n\n // Convert the signature to a hex string\n const hmac = Array.from(new Uint8Array(signature))\n .map((b) => (\"0\" + b.toString(16)).slice(-2))\n .join(\"\");\n\n return { algorithm: \"sha256\", hmac };\n};\n","import type { Context } from \"hono\";\nimport type { BlankEnv, BlankInput } from \"hono/types\";\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\";\nimport { ZodEventResponse } from \"../schemas\";\nimport type { EventResponse } from \"../types\";\n\nexport interface CreateSuccessResponseParams<TStatus extends ContentfulStatusCode> {\n data: EventResponse;\n status?: TStatus;\n}\n\nexport const createSuccessResponse = <TStatus extends ContentfulStatusCode = 200>(\n c: Context<BlankEnv, \"/\", BlankInput>,\n data: EventResponse,\n status: TStatus = 200 as TStatus,\n) => {\n return c.json(\n {\n ok: true,\n data: ZodEventResponse.parse(data),\n },\n status,\n );\n};\n","import type { ContentfulStatusCode } from \"hono/utils/http-status\";\n\nexport class HttpError extends Error {\n readonly status: ContentfulStatusCode;\n\n constructor(message: string, status: ContentfulStatusCode) {\n super(message);\n\n this.status = status;\n }\n}\n","export const timingSafeEqual = (a: Uint8Array, b: Uint8Array): boolean => {\n if (a.length !== b.length) return false; // Lengths are different\n\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a[i] ^ b[i]; // XOR each byte\n }\n\n return result === 0; // If all bytes are equal, result will be 0\n};\n","import { createHmac } from \"./createHmac\";\nimport { timingSafeEqual } from \"./timingSafeEqual\";\n\nexport interface VerifyWebhookParams {\n payload: string;\n secret: string;\n signature: string;\n}\n\nexport const verifyWebhook = async (params: VerifyWebhookParams): Promise<boolean> => {\n const { payload, secret, signature } = params;\n\n if (!secret || !payload || !signature) {\n throw new Error(\"Secret, payload and signature are required to verify payload\");\n }\n\n const { hmac } = await createHmac({ payload, secret });\n\n if (hmac.length !== signature.length) return false;\n\n const encoder = new TextEncoder();\n const verificationBytes = encoder.encode(hmac);\n const signatureBytes = encoder.encode(signature);\n\n if (verificationBytes.length !== signatureBytes.length) return false;\n\n return timingSafeEqual(verificationBytes, signatureBytes);\n};\n","import type {\n AbstractPlatformConfig,\n AbstractWebSocket,\n BaseUser,\n ConvertWebSocketConfig,\n GetInitialStorageFn,\n JWTEncodeParams,\n PluvContext,\n WebSocketSerializedState,\n} from \"@pluv/io\";\nimport { AbstractPlatform } from \"@pluv/io\";\nimport type { MaybePromise } from \"@pluv/types\";\nimport stringify from \"fast-json-stable-stringify\";\nimport type { Context } from \"hono\";\nimport { Hono } from \"hono\";\nimport type { BlankEnv, BlankInput } from \"hono/types\";\nimport { SIGNATURE_ALGORITHM, SIGNATURE_HEADER } from \"./constants\";\nimport { ZodEvent } from \"./schemas\";\nimport { createErrorResponse, createSuccessResponse, HttpError, verifyWebhook } from \"./shared\";\nimport type { PluvIOEndpoints, PluvIOListeners } from \"./types\";\n\nexport type PublicKey = string | (() => MaybePromise<string>);\nexport type SecretKey = string | (() => MaybePromise<string>);\nexport type WebhookSecret = string | (() => MaybePromise<string>);\n\nexport interface PluvPlatformConfig<TContext extends Record<string, any> = {}> {\n /**\n * @ignore\n * @readonly\n * @deprecated Internal use only. Changes to this will never be marked as breaking.\n */\n _defs?: {\n debug?: boolean;\n endpoints?: PluvIOEndpoints | (() => MaybePromise<PluvIOEndpoints>);\n };\n basePath: string;\n context?: PluvContext<any, TContext>;\n publicKey: PublicKey;\n secretKey: SecretKey;\n webhookSecret?: WebhookSecret;\n}\n\nexport class PluvPlatform<\n TContext extends Record<string, any> = {},\n TUser extends BaseUser = BaseUser,\n> extends AbstractPlatform<\n any,\n {},\n {},\n {\n authorize: {\n secret: false;\n };\n handleMode: \"fetch\";\n registrationMode: \"attached\";\n requireAuth: true;\n listeners: {\n onRoomDestroyed: true;\n onRoomMessage: false;\n onStorageDestroyed: true;\n onStorageUpdated: false;\n onUserConnected: true;\n onUserDisconnected: true;\n };\n router: false;\n }\n> {\n public readonly id = Math.random().toString();\n public readonly _config = {\n authorize: {\n secret: false as const,\n },\n handleMode: \"fetch\" as const,\n registrationMode: \"attached\" as const,\n requireAuth: true as const,\n listeners: {\n onRoomDestroyed: true as const,\n onRoomMessage: false as const,\n onStorageDestroyed: true as const,\n onStorageUpdated: false as const,\n onUserConnected: true as const,\n onUserDisconnected: true as const,\n },\n router: false as const,\n };\n public readonly _name = \"platformPluv\";\n\n private readonly _app: Hono;\n private readonly _basePath: string;\n private readonly _context: PluvContext<this, TContext>;\n private readonly _debug: boolean;\n private readonly _endpoints: PluvIOEndpoints | (() => MaybePromise<PluvIOEndpoints>);\n private _getInitialStorage?: GetInitialStorageFn<{}>;\n private _listeners?: PluvIOListeners;\n private readonly _publicKey: PublicKey;\n private readonly _secretKey: SecretKey;\n private readonly _webhookSecret?: WebhookSecret;\n\n public _createToken = async (params: JWTEncodeParams<any, any>): Promise<string> => {\n const parsed = params.authorize.user.parse(params.user);\n\n const [endpoints, publicKey, secretKey] = await Promise.all([\n typeof this._endpoints === \"object\" ? this._endpoints : this._endpoints(),\n typeof this._publicKey === \"string\" ? this._publicKey : this._publicKey(),\n typeof this._secretKey === \"string\" ? this._secretKey : this._secretKey(),\n ]);\n\n this._logDebug({ endpoints, publicKey, secretKey });\n\n const res = await fetch(endpoints.createToken, {\n headers: { \"content-type\": \"application/json\" },\n method: \"post\",\n body: JSON.stringify({\n maxAge: params.maxAge ?? null,\n publicKey,\n room: params.room,\n secretKey,\n user: parsed,\n }),\n }).catch((error) => {\n this._logDebug(error);\n\n return null;\n });\n\n this._logDebug({ response: { status: res?.status ?? null } });\n\n if (!res || !res.ok || res.status !== 200) {\n throw new Error(\"Authorization failed\");\n }\n\n const token = await res.text().catch(() => null);\n\n this._logDebug({ token });\n\n if (typeof token !== \"string\") throw new Error(\"Authorization failed\");\n\n return token;\n };\n\n constructor(params: PluvPlatformConfig) {\n super();\n\n const { _defs, basePath, context, publicKey, secretKey, webhookSecret } = params;\n\n this._basePath = basePath;\n this._context = (context ?? {}) as TContext;\n this._debug = _defs?.debug ?? false;\n this._endpoints = _defs?.endpoints ?? {\n createToken: \"https://rooms.pluv.io/api/room/token\",\n };\n this._publicKey = publicKey;\n this._secretKey = secretKey;\n this._webhookSecret = webhookSecret;\n\n this._app = new Hono().basePath(this._basePath).route(\"/\", this._webhooksRouter);\n this._fetch = this._app.fetch as (req: any) => Promise<any>;\n }\n\n public acceptWebSocket(webSocket: AbstractWebSocket): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n\n public convertWebSocket(webSocket: any, config: ConvertWebSocketConfig): AbstractWebSocket {\n throw new Error(\"Not implemented\");\n }\n\n public getLastPing(webSocket: AbstractWebSocket): number | null {\n throw new Error(\"Not implemented\");\n }\n\n public getSerializedState(webSocket: any): WebSocketSerializedState | null {\n throw new Error(\"Not implemented\");\n }\n\n public getSessionId(webSocket: any): string | null {\n throw new Error(\"Not implemented\");\n }\n\n public getWebSockets(): readonly any[] {\n throw new Error(\"Not implemented\");\n }\n\n public initialize(config: AbstractPlatformConfig<{}>): this {\n throw new Error(\"Not implemented\");\n }\n\n public parseData(data: string | ArrayBuffer): Record<string, any> {\n throw new Error(\"Not implemented\");\n }\n\n public randomUUID(): string {\n throw new Error(\"Not implemented\");\n }\n\n public setSerializedState(\n webSocket: AbstractWebSocket,\n state: WebSocketSerializedState,\n ): WebSocketSerializedState {\n throw new Error(\"Not implemented\");\n }\n\n public validateConfig(config: any): void {\n this._logDebug(\"validating config with properties:\", Object.keys(config ?? {}));\n\n if (!config.authorize) {\n this._logDebug(\"Config `authorize` must be provided to `platformPluv`\");\n throw new Error(\"Config `authorize` must be provided to `platformPluv`\");\n }\n if (!!config.onRoomMessage) {\n this._logDebug(\"Config `onRoomMessage` is not supported on `platformPluv`\");\n throw new Error(\"Config `onRoomMessage` is not supported on `platformPluv`\");\n }\n if (!!config.onStorageUpdated) {\n this._logDebug(\"Config `onStorageUpdated` is not supported on `platformPluv`\");\n throw new Error(\"Config `onStorageUpdated` is not supported on `platformPluv`\");\n }\n\n this._getInitialStorage = config.getInitialStorage;\n this._listeners = {\n onRoomDestroyed: (event) => config.onRoomDestroyed?.(event),\n onStorageDestroyed: (event) => config.onStorageDestroyed?.(event),\n onUserConnected: (event) => config.onUserConnected?.(event),\n onUserDisconnected: (event) => config.onUserDisconnected?.(event),\n };\n }\n\n private _webhooksRouter = new Hono()\n .basePath(\"/\")\n .post(\"/\", async (c: Context<BlankEnv, \"/\", BlankInput>) => {\n const [algorithm, signature] = c.req.header(SIGNATURE_HEADER)?.split(\"=\") ?? [];\n\n try {\n if (!this._webhookSecret) {\n this._logDebug(\"Missing webhook secret\");\n throw new HttpError(\"Unauthorized\", 401);\n }\n if (algorithm !== SIGNATURE_ALGORITHM) {\n this._logDebug(\n `Verification algorithm is not ${SIGNATURE_ALGORITHM}. Found: `,\n algorithm,\n );\n throw new HttpError(\"Unauthorized\", 401);\n }\n if (!signature) {\n this._logDebug(\"Missing webhook signature\");\n throw new HttpError(\"Unauthorized\", 401);\n }\n\n const [payload, webhookSecret] = await Promise.all([\n c.req.json(),\n typeof this._webhookSecret === \"string\"\n ? this._webhookSecret\n : await this._webhookSecret(),\n ]).catch((error) => {\n this._logDebug(\n \"Could not derive webhook secret: \",\n error instanceof Error ? error.message : \"Unexpected error\",\n );\n throw error;\n });\n\n const verified = await verifyWebhook({\n payload: stringify(payload),\n signature,\n secret: webhookSecret,\n }).catch((error) => {\n this._logDebug(\n \"Error while verifying webhook: \",\n error instanceof Error ? error.message : \"Unexpected error\",\n );\n\n return false;\n });\n\n if (!verified) {\n this._logDebug(\"Failed to verify webhook\");\n throw new HttpError(\"Unauthorized\", 401);\n }\n\n const parsed = ZodEvent.safeParse(payload);\n\n if (!parsed.success) {\n this._logDebug(\n \"Failed to validate event payload:\",\n JSON.stringify(parsed.data ?? {}, null, 4),\n );\n throw new HttpError(\"Invalid request\", 400);\n }\n\n const { event, data } = parsed.data;\n const context = await this._getContext();\n\n switch (event) {\n case \"initial-storage\": {\n const room = data.room;\n const storage =\n typeof room === \"string\"\n ? ((await this._getInitialStorage?.({ context, room })) ?? null)\n : null;\n\n try {\n return createSuccessResponse(c, { event, room, storage });\n } catch (error) {\n this._logDebug(\"Could not create getInitialStorage response\");\n throw error;\n }\n }\n case \"room-destroyed\": {\n const room = data.room;\n\n await Promise.resolve(\n this._listeners?.onRoomDestroyed({\n context,\n platform: this,\n room,\n }),\n );\n\n try {\n return createSuccessResponse(c, { event, room });\n } catch (error) {\n this._logDebug(\"Could not create onRoomDestroyed response\");\n throw error;\n }\n }\n case \"storage-destroyed\": {\n const room = data.room;\n const encodedState = data.storage;\n\n await Promise.resolve(\n this._listeners?.onStorageDestroyed({\n context,\n encodedState,\n platform: this,\n room,\n }),\n );\n\n try {\n return createSuccessResponse(c, { event, room });\n } catch (error) {\n this._logDebug(\"Could not create onStorageDestroyed response\");\n throw error;\n }\n }\n case \"user-connected\": {\n const room = data.room;\n const encodedState = data.storage;\n const user = data.user as any;\n\n await Promise.resolve(\n this._listeners?.onUserConnected({\n context,\n encodedState,\n platform: this,\n room,\n user,\n }),\n );\n\n try {\n return createSuccessResponse(c, { event, room });\n } catch (error) {\n this._logDebug(\"Could not create onUserConnected response\");\n throw error;\n }\n }\n case \"user-disconnected\": {\n const room = data.room;\n const encodedState = data.storage;\n const user = data.user as any;\n\n await Promise.resolve(\n this._listeners?.onUserDisconnected({\n context,\n encodedState,\n platform: this,\n room,\n user,\n }),\n );\n\n try {\n return createSuccessResponse(c, { event, room });\n } catch (error) {\n this._logDebug(\"Could not create onUserDisconnected response\");\n throw error;\n }\n }\n default: {\n throw new HttpError(\"Unknown event\", 400);\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unexpected error\";\n const status = error instanceof HttpError ? error.status : 500;\n\n this._logDebug(\"Uncaught error: \", message);\n\n return createErrorResponse(c, { message }, status);\n }\n });\n\n private async _getContext(): Promise<TContext> {\n return typeof this._context === \"function\"\n ? await Promise.resolve(this._context(this._roomContext as any))\n : await Promise.resolve(this._context);\n }\n\n private _logDebug(...args: any[]): void {\n if (!this._debug) return;\n\n console.log(\"[PLATFORM PLUV]\", ...args);\n }\n}\n","import type { CrdtLibraryType, NoopCrdtDocFactory } from \"@pluv/crdt\";\nimport type { CreateIOParams, InferInitContextType, PluvContext, PluvIOAuthorize } from \"@pluv/io\";\nimport type { BaseUser, Id } from \"@pluv/types\";\nimport type { PluvPlatformConfig } from \"./PluvPlatform\";\nimport { PluvPlatform } from \"./PluvPlatform\";\n\nexport type PlatformPluvCreateIOParams<\n TContext extends Record<string, any> = {},\n TUser extends BaseUser = BaseUser,\n TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>,\n> = Id<\n PluvPlatformConfig &\n Omit<\n CreateIOParams<PluvPlatform, TContext, TUser, TCrdt>,\n \"authorize\" | \"context\" | \"limits\" | \"platform\"\n > & {\n authorize: PluvIOAuthorize<PluvPlatform, TUser, InferInitContextType<PluvPlatform>>;\n context?: PluvContext<PluvPlatform, TContext>;\n }\n>;\n\nexport const platformPluv = <\n TContext extends Record<string, any> = {},\n TUser extends BaseUser = BaseUser,\n TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>,\n>(\n config: PlatformPluvCreateIOParams<TContext, TUser, TCrdt>,\n): CreateIOParams<PluvPlatform<TContext, TUser>, TContext, TUser, TCrdt> => {\n const { authorize, context, crdt, debug } = config;\n\n return {\n authorize,\n context,\n crdt,\n debug,\n platform: () => new PluvPlatform<TContext, TUser>(config),\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/constants.ts","../src/schemas.ts","../src/shared/createErrorResponse.ts","../src/shared/getCrypto.ts","../src/shared/createHmac.ts","../src/shared/createSuccessResponse.ts","../src/shared/HttpError.ts","../src/shared/timingSafeEqual.ts","../src/shared/verifyWebhook.ts","../src/PluvPlatform.ts","../src/platformPluv.ts"],"sourcesContent":["export const SIGNATURE_ALGORITHM = \"sha256\";\nexport const SIGNATURE_HEADER = \"x-pluv-signature-256\";\n","import { z } from \"zod\";\n\nexport const ZodEventKind = z.union([\n z.literal(\"initial-storage\"),\n z.literal(\"room-destroyed\"),\n z.literal(\"storage-destroyed\"),\n z.literal(\"user-connected\"),\n z.literal(\"user-disconnected\"),\n]);\n\nexport const ZodEventInitialStorage = z.object({\n event: z.literal(\"initial-storage\"),\n data: z.object({\n room: z.string(),\n }),\n});\n\nexport const ZodEventRoomDestroyed = z.object({\n event: z.literal(\"room-destroyed\"),\n data: z.object({\n room: z.string(),\n }),\n});\n\nexport const ZodEventStorageDestroyed = z.object({\n event: z.literal(\"storage-destroyed\"),\n data: z.object({\n room: z.string(),\n storage: z.string().nullable(),\n }),\n});\n\nexport const ZodEventUserConnected = z.object({\n event: z.literal(\"user-connected\"),\n data: z.object({\n room: z.string(),\n storage: z.string().nullable(),\n user: z\n .object({\n id: z.string(),\n })\n .passthrough(),\n }),\n});\n\nexport const ZodEventUserDisconnected = z.object({\n event: z.literal(\"user-disconnected\"),\n data: z.object({\n room: z.string(),\n storage: z.string().nullable(),\n user: z\n .object({\n id: z.string(),\n })\n .passthrough(),\n }),\n});\n\nexport const ZodEvent = z.discriminatedUnion(\"event\", [\n ZodEventInitialStorage,\n ZodEventRoomDestroyed,\n ZodEventStorageDestroyed,\n ZodEventUserConnected,\n ZodEventUserDisconnected,\n]);\n\nexport const ZodInitialStorageResponse = z.object({\n event: z.literal(\"initial-storage\"),\n room: z.string(),\n storage: z.string().nullable(),\n});\n\nexport const ZodRoomDestroyedResponse = z.object({\n event: z.literal(\"room-destroyed\"),\n room: z.string(),\n});\n\nexport const ZodStorageDestroyedResponse = z.object({\n event: z.literal(\"storage-destroyed\"),\n room: z.string(),\n});\n\nexport const ZodUserConnectedResponse = z.object({\n event: z.literal(\"user-connected\"),\n room: z.string(),\n});\n\nexport const ZodUserDisconnectedResponse = z.object({\n event: z.literal(\"user-disconnected\"),\n room: z.string(),\n});\n\nexport const ZodEventResponse = z.discriminatedUnion(\"event\", [\n ZodInitialStorageResponse,\n ZodRoomDestroyedResponse,\n ZodStorageDestroyedResponse,\n ZodUserConnectedResponse,\n ZodUserDisconnectedResponse,\n]);\n","import type { Context } from \"hono\";\nimport type { BlankEnv, BlankInput } from \"hono/types\";\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\";\n\nexport const createErrorResponse = <TStatus extends ContentfulStatusCode>(\n c: Context<BlankEnv, \"/\", BlankInput>,\n error: { message: string },\n status: TStatus,\n event: string = \"unknown\",\n) => {\n return c.json(\n {\n ok: false,\n error: { message: error.message },\n },\n status,\n { \"x-pluv-event\": event },\n );\n};\n","import type { webcrypto } from \"crypto\";\n\nexport const getCrypto = (): webcrypto.Crypto => {\n if (typeof crypto !== \"undefined\") {\n // In a browser or Web Worker (including Cloudflare Workers)\n return crypto;\n }\n\n if (typeof require === \"function\") {\n // In Node.js\n // Node 15+ supports `crypto.webcrypto`\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(\"node:crypto\").webcrypto as webcrypto.Crypto;\n }\n\n throw new Error(\"Missing crypto module\");\n};\n","import type { webcrypto } from \"crypto\";\nimport { getCrypto } from \"./getCrypto\";\n\nexport interface CreateHmacParams {\n payload: string;\n secret: string;\n}\n\nexport type CreateHmacResult = {\n algorithm: \"sha256\";\n hmac: string;\n};\n\nexport const createHmac = async (params: CreateHmacParams): Promise<CreateHmacResult> => {\n const { payload, secret } = params;\n\n if (!payload || !secret) throw new Error(\"Secret and payload are required to sign payload\");\n\n const encoder = new TextEncoder();\n const keyBytes = encoder.encode(secret);\n\n const crypto = getCrypto();\n\n const algorithm: webcrypto.HmacImportParams = { name: \"HMAC\", hash: { name: \"SHA-256\" } };\n const extractable = false;\n\n const key = await crypto.subtle.importKey(\"raw\", keyBytes, algorithm, extractable, [\n \"sign\",\n \"verify\",\n ]);\n const payloadBytes = encoder.encode(payload);\n\n const signature = await crypto.subtle.sign(\"HMAC\", key, payloadBytes);\n\n // Convert the signature to a hex string\n const hmac = Array.from(new Uint8Array(signature))\n .map((b) => (\"0\" + b.toString(16)).slice(-2))\n .join(\"\");\n\n return { algorithm: \"sha256\", hmac };\n};\n","import type { Context } from \"hono\";\nimport type { BlankEnv, BlankInput } from \"hono/types\";\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\";\nimport { ZodEventResponse } from \"../schemas\";\nimport type { EventResponse } from \"../types\";\n\nexport interface CreateSuccessResponseParams<TStatus extends ContentfulStatusCode> {\n data: EventResponse;\n status?: TStatus;\n}\n\nexport const createSuccessResponse = <TStatus extends ContentfulStatusCode = 200>(\n c: Context<BlankEnv, \"/\", BlankInput>,\n data: EventResponse,\n status: TStatus = 200 as TStatus,\n) => {\n return c.json(\n {\n ok: true,\n data: ZodEventResponse.parse(data),\n },\n status,\n { \"x-pluv-event\": data.event },\n );\n};\n","import type { ContentfulStatusCode } from \"hono/utils/http-status\";\n\nexport class HttpError extends Error {\n readonly status: ContentfulStatusCode;\n\n constructor(message: string, status: ContentfulStatusCode) {\n super(message);\n\n this.status = status;\n }\n}\n","export const timingSafeEqual = (a: Uint8Array, b: Uint8Array): boolean => {\n if (a.length !== b.length) return false; // Lengths are different\n\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a[i] ^ b[i]; // XOR each byte\n }\n\n return result === 0; // If all bytes are equal, result will be 0\n};\n","import { createHmac } from \"./createHmac\";\nimport { timingSafeEqual } from \"./timingSafeEqual\";\n\nexport interface VerifyWebhookParams {\n payload: string;\n secret: string;\n signature: string;\n}\n\nexport const verifyWebhook = async (params: VerifyWebhookParams): Promise<boolean> => {\n const { payload, secret, signature } = params;\n\n if (!secret || !payload || !signature) {\n throw new Error(\"Secret, payload and signature are required to verify payload\");\n }\n\n const { hmac } = await createHmac({ payload, secret });\n\n if (hmac.length !== signature.length) return false;\n\n const encoder = new TextEncoder();\n const verificationBytes = encoder.encode(hmac);\n const signatureBytes = encoder.encode(signature);\n\n if (verificationBytes.length !== signatureBytes.length) return false;\n\n return timingSafeEqual(verificationBytes, signatureBytes);\n};\n","import type {\n AbstractPlatformConfig,\n AbstractWebSocket,\n BaseUser,\n ConvertWebSocketConfig,\n GetInitialStorageFn,\n JWTEncodeParams,\n PluvContext,\n WebSocketSerializedState,\n} from \"@pluv/io\";\nimport { AbstractPlatform } from \"@pluv/io\";\nimport type { MaybePromise } from \"@pluv/types\";\nimport stringify from \"fast-json-stable-stringify\";\nimport type { Context } from \"hono\";\nimport { Hono } from \"hono\";\nimport type { BlankEnv, BlankInput } from \"hono/types\";\nimport { SIGNATURE_ALGORITHM, SIGNATURE_HEADER } from \"./constants\";\nimport { ZodEvent } from \"./schemas\";\nimport { createErrorResponse, createSuccessResponse, HttpError, verifyWebhook } from \"./shared\";\nimport type { PluvIOEndpoints, PluvIOListeners } from \"./types\";\n\nexport type PublicKey = string | (() => MaybePromise<string>);\nexport type SecretKey = string | (() => MaybePromise<string>);\nexport type WebhookSecret = string | (() => MaybePromise<string>);\n\nexport interface PluvPlatformConfig<TContext extends Record<string, any> = {}> {\n /**\n * @ignore\n * @readonly\n * @deprecated Internal use only. Changes to this will never be marked as breaking.\n */\n _defs?: {\n debug?: boolean;\n endpoints?: PluvIOEndpoints | (() => MaybePromise<PluvIOEndpoints>);\n };\n basePath: string;\n context?: PluvContext<any, TContext>;\n publicKey: PublicKey;\n secretKey: SecretKey;\n webhookSecret?: WebhookSecret;\n}\n\nexport class PluvPlatform<\n TContext extends Record<string, any> = {},\n TUser extends BaseUser = BaseUser,\n> extends AbstractPlatform<\n any,\n {},\n {},\n {\n authorize: {\n secret: false;\n };\n handleMode: \"fetch\";\n registrationMode: \"attached\";\n requireAuth: true;\n listeners: {\n onRoomDestroyed: true;\n onRoomMessage: false;\n onStorageDestroyed: true;\n onStorageUpdated: false;\n onUserConnected: true;\n onUserDisconnected: true;\n };\n router: false;\n }\n> {\n public readonly id = Math.random().toString();\n public readonly _config = {\n authorize: {\n secret: false as const,\n },\n handleMode: \"fetch\" as const,\n registrationMode: \"attached\" as const,\n requireAuth: true as const,\n listeners: {\n onRoomDestroyed: true as const,\n onRoomMessage: false as const,\n onStorageDestroyed: true as const,\n onStorageUpdated: false as const,\n onUserConnected: true as const,\n onUserDisconnected: true as const,\n },\n router: false as const,\n };\n public readonly _name = \"platformPluv\";\n\n private readonly _app: Hono;\n private readonly _basePath: string;\n private readonly _context: PluvContext<this, TContext>;\n private readonly _debug: boolean;\n private readonly _endpoints: PluvIOEndpoints | (() => MaybePromise<PluvIOEndpoints>);\n private _getInitialStorage?: GetInitialStorageFn<{}>;\n private _listeners?: PluvIOListeners;\n private readonly _publicKey: PublicKey;\n private readonly _secretKey: SecretKey;\n private readonly _webhookSecret?: WebhookSecret;\n\n public _createToken = async (params: JWTEncodeParams<any, any>): Promise<string> => {\n const parsed = params.authorize.user.parse(params.user);\n\n const [endpoints, publicKey, secretKey] = await Promise.all([\n typeof this._endpoints === \"object\" ? this._endpoints : this._endpoints(),\n typeof this._publicKey === \"string\" ? this._publicKey : this._publicKey(),\n typeof this._secretKey === \"string\" ? this._secretKey : this._secretKey(),\n ]);\n\n this._logDebug({ endpoints, publicKey, secretKey });\n\n const res = await fetch(endpoints.createToken, {\n headers: { \"content-type\": \"application/json\" },\n method: \"post\",\n body: JSON.stringify({\n maxAge: params.maxAge ?? null,\n publicKey,\n room: params.room,\n secretKey,\n user: parsed,\n }),\n }).catch((error) => {\n this._logDebug(error);\n\n return null;\n });\n\n this._logDebug({ response: { status: res?.status ?? null } });\n\n if (!res || !res.ok || res.status !== 200) {\n throw new Error(\"Authorization failed\");\n }\n\n const token = await res.text().catch(() => null);\n\n this._logDebug({ token });\n\n if (typeof token !== \"string\") throw new Error(\"Authorization failed\");\n\n return token;\n };\n\n constructor(params: PluvPlatformConfig) {\n super();\n\n const { _defs, basePath, context, publicKey, secretKey, webhookSecret } = params;\n\n this._basePath = basePath;\n this._context = (context ?? {}) as TContext;\n this._debug = _defs?.debug ?? false;\n this._endpoints = _defs?.endpoints ?? {\n createToken: \"https://rooms.pluv.io/api/room/token\",\n };\n this._publicKey = publicKey;\n this._secretKey = secretKey;\n this._webhookSecret = webhookSecret;\n\n this._app = new Hono().basePath(this._basePath).route(\"/\", this._webhooksRouter);\n this._fetch = this._app.fetch as (req: any) => Promise<any>;\n }\n\n public acceptWebSocket(webSocket: AbstractWebSocket): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n\n public convertWebSocket(webSocket: any, config: ConvertWebSocketConfig): AbstractWebSocket {\n throw new Error(\"Not implemented\");\n }\n\n public getLastPing(webSocket: AbstractWebSocket): number | null {\n throw new Error(\"Not implemented\");\n }\n\n public getSerializedState(webSocket: any): WebSocketSerializedState | null {\n throw new Error(\"Not implemented\");\n }\n\n public getSessionId(webSocket: any): string | null {\n throw new Error(\"Not implemented\");\n }\n\n public getWebSockets(): readonly any[] {\n throw new Error(\"Not implemented\");\n }\n\n public initialize(config: AbstractPlatformConfig<{}>): this {\n throw new Error(\"Not implemented\");\n }\n\n public parseData(data: string | ArrayBuffer): Record<string, any> {\n throw new Error(\"Not implemented\");\n }\n\n public randomUUID(): string {\n throw new Error(\"Not implemented\");\n }\n\n public setSerializedState(\n webSocket: AbstractWebSocket,\n state: WebSocketSerializedState,\n ): WebSocketSerializedState {\n throw new Error(\"Not implemented\");\n }\n\n public validateConfig(config: any): void {\n this._logDebug(\"validating config with properties:\", Object.keys(config ?? {}));\n\n if (!config.authorize) {\n this._logDebug(\"Config `authorize` must be provided to `platformPluv`\");\n throw new Error(\"Config `authorize` must be provided to `platformPluv`\");\n }\n if (!!config.onRoomMessage) {\n this._logDebug(\"Config `onRoomMessage` is not supported on `platformPluv`\");\n throw new Error(\"Config `onRoomMessage` is not supported on `platformPluv`\");\n }\n if (!!config.onStorageUpdated) {\n this._logDebug(\"Config `onStorageUpdated` is not supported on `platformPluv`\");\n throw new Error(\"Config `onStorageUpdated` is not supported on `platformPluv`\");\n }\n\n this._getInitialStorage = config.getInitialStorage;\n this._listeners = {\n onRoomDestroyed: (event) => config.onRoomDestroyed?.(event),\n onStorageDestroyed: (event) => config.onStorageDestroyed?.(event),\n onUserConnected: (event) => config.onUserConnected?.(event),\n onUserDisconnected: (event) => config.onUserDisconnected?.(event),\n };\n }\n\n private _webhooksRouter = new Hono()\n .basePath(\"/\")\n .post(\"/\", async (c: Context<BlankEnv, \"/\", BlankInput>) => {\n const [algorithm, signature] = c.req.header(SIGNATURE_HEADER)?.split(\"=\") ?? [];\n\n try {\n if (!this._webhookSecret) {\n this._logDebug(\"Missing webhook secret\");\n throw new HttpError(\"Unauthorized\", 401);\n }\n if (algorithm !== SIGNATURE_ALGORITHM) {\n this._logDebug(\n `Verification algorithm is not ${SIGNATURE_ALGORITHM}. Found: `,\n algorithm,\n );\n throw new HttpError(\"Unauthorized\", 401);\n }\n if (!signature) {\n this._logDebug(\"Missing webhook signature\");\n throw new HttpError(\"Unauthorized\", 401);\n }\n\n const [payload, webhookSecret] = await Promise.all([\n c.req.json(),\n typeof this._webhookSecret === \"string\"\n ? this._webhookSecret\n : await this._webhookSecret(),\n ]).catch((error) => {\n this._logDebug(\n \"Could not derive webhook secret: \",\n error instanceof Error ? error.message : \"Unexpected error\",\n );\n throw error;\n });\n\n const verified = await verifyWebhook({\n payload: stringify(payload),\n signature,\n secret: webhookSecret,\n }).catch((error) => {\n this._logDebug(\n \"Error while verifying webhook: \",\n error instanceof Error ? error.message : \"Unexpected error\",\n );\n\n return false;\n });\n\n if (!verified) {\n this._logDebug(\"Failed to verify webhook\");\n throw new HttpError(\"Unauthorized\", 401);\n }\n\n const parsed = ZodEvent.safeParse(payload);\n\n if (!parsed.success) {\n this._logDebug(\n \"Failed to validate event payload:\",\n JSON.stringify(parsed.data ?? {}, null, 4),\n );\n throw new HttpError(\"Invalid request\", 400);\n }\n\n const { event, data } = parsed.data;\n const context = await this._getContext();\n\n switch (event) {\n case \"initial-storage\": {\n const room = data.room;\n const storage =\n typeof room === \"string\"\n ? ((await this._getInitialStorage?.({ context, room })) ?? null)\n : null;\n\n try {\n return createSuccessResponse(c, { event, room, storage });\n } catch (error) {\n this._logDebug(\"Could not create getInitialStorage response\");\n throw error;\n }\n }\n case \"room-destroyed\": {\n const room = data.room;\n\n await Promise.resolve(\n this._listeners?.onRoomDestroyed({\n context,\n platform: this,\n room,\n }),\n );\n\n try {\n return createSuccessResponse(c, { event, room });\n } catch (error) {\n this._logDebug(\"Could not create onRoomDestroyed response\");\n throw error;\n }\n }\n case \"storage-destroyed\": {\n const room = data.room;\n const encodedState = data.storage;\n\n await Promise.resolve(\n this._listeners?.onStorageDestroyed({\n context,\n encodedState,\n platform: this,\n room,\n }),\n );\n\n try {\n return createSuccessResponse(c, { event, room });\n } catch (error) {\n this._logDebug(\"Could not create onStorageDestroyed response\");\n throw error;\n }\n }\n case \"user-connected\": {\n const room = data.room;\n const encodedState = data.storage;\n const user = data.user as any;\n\n await Promise.resolve(\n this._listeners?.onUserConnected({\n context,\n encodedState,\n platform: this,\n room,\n user,\n }),\n );\n\n try {\n return createSuccessResponse(c, { event, room });\n } catch (error) {\n this._logDebug(\"Could not create onUserConnected response\");\n throw error;\n }\n }\n case \"user-disconnected\": {\n const room = data.room;\n const encodedState = data.storage;\n const user = data.user as any;\n\n await Promise.resolve(\n this._listeners?.onUserDisconnected({\n context,\n encodedState,\n platform: this,\n room,\n user,\n }),\n );\n\n try {\n return createSuccessResponse(c, { event, room });\n } catch (error) {\n this._logDebug(\"Could not create onUserDisconnected response\");\n throw error;\n }\n }\n default: {\n return createErrorResponse(c, { message: \"Unknown event\" }, 400, event);\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unexpected error\";\n const status = error instanceof HttpError ? error.status : 500;\n\n this._logDebug(\"Uncaught error: \", message);\n\n return createErrorResponse(c, { message }, status);\n }\n });\n\n private async _getContext(): Promise<TContext> {\n return typeof this._context === \"function\"\n ? await Promise.resolve(this._context(this._roomContext as any))\n : await Promise.resolve(this._context);\n }\n\n private _logDebug(...args: any[]): void {\n if (!this._debug) return;\n\n console.log(\"[PLATFORM PLUV]\", ...args);\n }\n}\n","import type { CrdtLibraryType, NoopCrdtDocFactory } from \"@pluv/crdt\";\nimport type { CreateIOParams, InferInitContextType, PluvContext, PluvIOAuthorize } from \"@pluv/io\";\nimport type { BaseUser, Id } from \"@pluv/types\";\nimport type { PluvPlatformConfig } from \"./PluvPlatform\";\nimport { PluvPlatform } from \"./PluvPlatform\";\n\nexport type PlatformPluvCreateIOParams<\n TContext extends Record<string, any> = {},\n TUser extends BaseUser = BaseUser,\n TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>,\n> = Id<\n PluvPlatformConfig &\n Omit<\n CreateIOParams<PluvPlatform, TContext, TUser, TCrdt>,\n \"authorize\" | \"context\" | \"limits\" | \"platform\"\n > & {\n authorize: PluvIOAuthorize<PluvPlatform, TUser, InferInitContextType<PluvPlatform>>;\n context?: PluvContext<PluvPlatform, TContext>;\n }\n>;\n\nexport const platformPluv = <\n TContext extends Record<string, any> = {},\n TUser extends BaseUser = BaseUser,\n TCrdt extends CrdtLibraryType<any> = CrdtLibraryType<NoopCrdtDocFactory>,\n>(\n config: PlatformPluvCreateIOParams<TContext, TUser, TCrdt>,\n): CreateIOParams<PluvPlatform<TContext, TUser>, TContext, TUser, TCrdt> => {\n const { authorize, context, crdt, debug } = config;\n\n return {\n authorize,\n context,\n crdt,\n debug,\n platform: () => new PluvPlatform<TContext, TUser>(config),\n };\n};\n"],"mappings":";;;;;;;;;AAAA,MAAa,sBAAsB;ACEP,EAAE,MAAM;CAChC,EAAE,QAAQ,iBAAiB;CAC3B,EAAE,QAAQ,gBAAgB;CAC1B,EAAE,QAAQ,mBAAmB;CAC7B,EAAE,QAAQ,gBAAgB;CAC1B,EAAE,QAAQ,mBAAmB;AACjC,CAAC;AAED,MAAa,yBAAyB,EAAE,OAAO;CAC3C,OAAO,EAAE,QAAQ,iBAAiB;CAClC,MAAM,EAAE,OAAO,EACX,MAAM,EAAE,OAAO,EACnB,CAAC;AACL,CAAC;AAED,MAAa,wBAAwB,EAAE,OAAO;CAC1C,OAAO,EAAE,QAAQ,gBAAgB;CACjC,MAAM,EAAE,OAAO,EACX,MAAM,EAAE,OAAO,EACnB,CAAC;AACL,CAAC;AAED,MAAa,2BAA2B,EAAE,OAAO;CAC7C,OAAO,EAAE,QAAQ,mBAAmB;CACpC,MAAM,EAAE,OAAO;EACX,MAAM,EAAE,OAAO;EACf,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;CACjC,CAAC;AACL,CAAC;AAED,MAAa,wBAAwB,EAAE,OAAO;CAC1C,OAAO,EAAE,QAAQ,gBAAgB;CACjC,MAAM,EAAE,OAAO;EACX,MAAM,EAAE,OAAO;EACf,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;EAC7B,MAAM,EACD,OAAO,EACJ,IAAI,EAAE,OAAO,EACjB,CAAC,CAAC,CACD,YAAY;CACrB,CAAC;AACL,CAAC;AAED,MAAa,2BAA2B,EAAE,OAAO;CAC7C,OAAO,EAAE,QAAQ,mBAAmB;CACpC,MAAM,EAAE,OAAO;EACX,MAAM,EAAE,OAAO;EACf,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;EAC7B,MAAM,EACD,OAAO,EACJ,IAAI,EAAE,OAAO,EACjB,CAAC,CAAC,CACD,YAAY;CACrB,CAAC;AACL,CAAC;AAED,MAAa,WAAW,EAAE,mBAAmB,SAAS;CAClD;CACA;CACA;CACA;CACA;AACJ,CAAC;AAED,MAAa,4BAA4B,EAAE,OAAO;CAC9C,OAAO,EAAE,QAAQ,iBAAiB;CAClC,MAAM,EAAE,OAAO;CACf,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;AACjC,CAAC;AAED,MAAa,2BAA2B,EAAE,OAAO;CAC7C,OAAO,EAAE,QAAQ,gBAAgB;CACjC,MAAM,EAAE,OAAO;AACnB,CAAC;AAED,MAAa,8BAA8B,EAAE,OAAO;CAChD,OAAO,EAAE,QAAQ,mBAAmB;CACpC,MAAM,EAAE,OAAO;AACnB,CAAC;AAED,MAAa,2BAA2B,EAAE,OAAO;CAC7C,OAAO,EAAE,QAAQ,gBAAgB;CACjC,MAAM,EAAE,OAAO;AACnB,CAAC;AAED,MAAa,8BAA8B,EAAE,OAAO;CAChD,OAAO,EAAE,QAAQ,mBAAmB;CACpC,MAAM,EAAE,OAAO;AACnB,CAAC;AAED,MAAa,mBAAmB,EAAE,mBAAmB,SAAS;CAC1D;CACA;CACA;CACA;CACA;AACJ,CAAC;;;AC9FD,MAAa,uBACT,GACA,OACA,QACA,QAAgB,cACf;CACD,OAAO,EAAE,KACL;EACI,IAAI;EACJ,OAAO,EAAE,SAAS,MAAM,QAAQ;CACpC,GACA,QACA,EAAE,gBAAgB,MAAM,CAC5B;AACJ;;;AChBA,MAAa,kBAAoC;CAC7C,IAAI,OAAO,WAAW,aAElB,OAAO;CAGX,IAAI,OAAA,cAAmB,YAInB,OAAA,UAAe,aAAa,CAAC,CAAC;CAGlC,MAAM,IAAI,MAAM,uBAAuB;AAC3C;;;ACHA,MAAa,aAAa,OAAO,WAAwD;CACrF,MAAM,EAAE,SAAS,WAAW;CAE5B,IAAI,CAAC,WAAW,CAAC,QAAQ,MAAM,IAAI,MAAM,iDAAiD;CAE1F,MAAM,UAAU,IAAI,YAAY;CAChC,MAAM,WAAW,QAAQ,OAAO,MAAM;CAEtC,MAAM,SAAS,UAAU;CAKzB,MAAM,MAAM,MAAM,OAAO,OAAO,UAAU,OAAO,UAAU;EAHX,MAAM;EAAQ,MAAM,EAAE,MAAM,UAAU;CAGnB,GAAG,OAAa,CAC/E,QACA,QACJ,CAAC;CACD,MAAM,eAAe,QAAQ,OAAO,OAAO;CAE3C,MAAM,YAAY,MAAM,OAAO,OAAO,KAAK,QAAQ,KAAK,YAAY;CAOpE,OAAO;EAAE,WAAW;EAAU,MAJjB,MAAM,KAAK,IAAI,WAAW,SAAS,CAAC,CAAC,CAC7C,KAAK,OAAO,MAAM,EAAE,SAAS,EAAE,EAAA,CAAG,MAAM,EAAE,CAAC,CAAC,CAC5C,KAAK,EAEuB;CAAE;AACvC;;;AC7BA,MAAa,yBACT,GACA,MACA,SAAkB,QACjB;CACD,OAAO,EAAE,KACL;EACI,IAAI;EACJ,MAAM,iBAAiB,MAAM,IAAI;CACrC,GACA,QACA,EAAE,gBAAgB,KAAK,MAAM,CACjC;AACJ;;;ACtBA,IAAa,YAAb,cAA+B,MAAM;CACjC;CAEA,YAAY,SAAiB,QAA8B;EACvD,MAAM,OAAO;EAEb,KAAK,SAAS;CAClB;AACJ;;;ACVA,MAAa,mBAAmB,GAAe,MAA2B;CACtE,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAElC,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAC1B,UAAU,EAAE,KAAK,EAAE;CAGvB,OAAO,WAAW;AACtB;;;ACAA,MAAa,gBAAgB,OAAO,WAAkD;CAClF,MAAM,EAAE,SAAS,QAAQ,cAAc;CAEvC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,WACxB,MAAM,IAAI,MAAM,8DAA8D;CAGlF,MAAM,EAAE,SAAS,MAAM,WAAW;EAAE;EAAS;CAAO,CAAC;CAErD,IAAI,KAAK,WAAW,UAAU,QAAQ,OAAO;CAE7C,MAAM,UAAU,IAAI,YAAY;CAChC,MAAM,oBAAoB,QAAQ,OAAO,IAAI;CAC7C,MAAM,iBAAiB,QAAQ,OAAO,SAAS;CAE/C,IAAI,kBAAkB,WAAW,eAAe,QAAQ,OAAO;CAE/D,OAAO,gBAAgB,mBAAmB,cAAc;AAC5D;;;ACeA,IAAa,eAAb,cAGU,iBAqBR;CACE,KAAqB,KAAK,OAAO,CAAC,CAAC,SAAS;CAC5C,UAA0B;EACtB,WAAW,EACP,QAAQ,MACZ;EACA,YAAY;EACZ,kBAAkB;EAClB,aAAa;EACb,WAAW;GACP,iBAAiB;GACjB,eAAe;GACf,oBAAoB;GACpB,kBAAkB;GAClB,iBAAiB;GACjB,oBAAoB;EACxB;EACA,QAAQ;CACZ;CACA,QAAwB;CAExB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,eAAsB,OAAO,WAAuD;EAChF,MAAM,SAAS,OAAO,UAAU,KAAK,MAAM,OAAO,IAAI;EAEtD,MAAM,CAAC,WAAW,WAAW,aAAa,MAAM,QAAQ,IAAI;GACxD,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa,KAAK,WAAW;GACxE,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa,KAAK,WAAW;GACxE,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa,KAAK,WAAW;EAC5E,CAAC;EAED,KAAK,UAAU;GAAE;GAAW;GAAW;EAAU,CAAC;EAElD,MAAM,MAAM,MAAM,MAAM,UAAU,aAAa;GAC3C,SAAS,EAAE,gBAAgB,mBAAmB;GAC9C,QAAQ;GACR,MAAM,KAAK,UAAU;IACjB,QAAQ,OAAO,UAAU;IACzB;IACA,MAAM,OAAO;IACb;IACA,MAAM;GACV,CAAC;EACL,CAAC,CAAC,CAAC,OAAO,UAAU;GAChB,KAAK,UAAU,KAAK;GAEpB,OAAO;EACX,CAAC;EAED,KAAK,UAAU,EAAE,UAAU,EAAE,QAAQ,KAAK,UAAU,KAAK,EAAE,CAAC;EAE5D,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,IAAI,WAAW,KAClC,MAAM,IAAI,MAAM,sBAAsB;EAG1C,MAAM,QAAQ,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI;EAE/C,KAAK,UAAU,EAAE,MAAM,CAAC;EAExB,IAAI,OAAO,UAAU,UAAU,MAAM,IAAI,MAAM,sBAAsB;EAErE,OAAO;CACX;CAEA,YAAY,QAA4B;EACpC,MAAM;EAEN,MAAM,EAAE,OAAO,UAAU,SAAS,WAAW,WAAW,kBAAkB;EAE1E,KAAK,YAAY;EACjB,KAAK,WAAY,WAAW,CAAC;EAC7B,KAAK,SAAS,OAAO,SAAS;EAC9B,KAAK,aAAa,OAAO,aAAa,EAClC,aAAa,uCACjB;EACA,KAAK,aAAa;EAClB,KAAK,aAAa;EAClB,KAAK,iBAAiB;EAEtB,KAAK,OAAO,IAAI,KAAK,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,MAAM,KAAK,KAAK,eAAe;EAC/E,KAAK,SAAS,KAAK,KAAK;CAC5B;CAEA,gBAAuB,WAA6C;EAChE,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,iBAAwB,WAAgB,QAAmD;EACvF,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,YAAmB,WAA6C;EAC5D,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,mBAA0B,WAAiD;EACvE,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,aAAoB,WAA+B;EAC/C,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,gBAAuC;EACnC,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,WAAkB,QAA0C;EACxD,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,UAAiB,MAAiD;EAC9D,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,aAA4B;EACxB,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,mBACI,WACA,OACwB;EACxB,MAAM,IAAI,MAAM,iBAAiB;CACrC;CAEA,eAAsB,QAAmB;EACrC,KAAK,UAAU,sCAAsC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC;EAE9E,IAAI,CAAC,OAAO,WAAW;GACnB,KAAK,UAAU,uDAAuD;GACtE,MAAM,IAAI,MAAM,uDAAuD;EAC3E;EACA,IAAI,CAAC,CAAC,OAAO,eAAe;GACxB,KAAK,UAAU,2DAA2D;GAC1E,MAAM,IAAI,MAAM,2DAA2D;EAC/E;EACA,IAAI,CAAC,CAAC,OAAO,kBAAkB;GAC3B,KAAK,UAAU,8DAA8D;GAC7E,MAAM,IAAI,MAAM,8DAA8D;EAClF;EAEA,KAAK,qBAAqB,OAAO;EACjC,KAAK,aAAa;GACd,kBAAkB,UAAU,OAAO,kBAAkB,KAAK;GAC1D,qBAAqB,UAAU,OAAO,qBAAqB,KAAK;GAChE,kBAAkB,UAAU,OAAO,kBAAkB,KAAK;GAC1D,qBAAqB,UAAU,OAAO,qBAAqB,KAAK;EACpE;CACJ;CAEA,kBAA0B,IAAI,KAAK,CAAC,CAC/B,SAAS,GAAG,CAAC,CACb,KAAK,KAAK,OAAO,MAA0C;EACxD,MAAM,CAAC,WAAW,aAAa,EAAE,IAAI,OAAA,sBAAuB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;EAE9E,IAAI;GACA,IAAI,CAAC,KAAK,gBAAgB;IACtB,KAAK,UAAU,wBAAwB;IACvC,MAAM,IAAI,UAAU,gBAAgB,GAAG;GAC3C;GACA,IAAI,cAAA,UAAmC;IACnC,KAAK,UACD,iCAAiC,oBAAoB,YACrD,SACJ;IACA,MAAM,IAAI,UAAU,gBAAgB,GAAG;GAC3C;GACA,IAAI,CAAC,WAAW;IACZ,KAAK,UAAU,2BAA2B;IAC1C,MAAM,IAAI,UAAU,gBAAgB,GAAG;GAC3C;GAEA,MAAM,CAAC,SAAS,iBAAiB,MAAM,QAAQ,IAAI,CAC/C,EAAE,IAAI,KAAK,GACX,OAAO,KAAK,mBAAmB,WACzB,KAAK,iBACL,MAAM,KAAK,eAAe,CACpC,CAAC,CAAC,CAAC,OAAO,UAAU;IAChB,KAAK,UACD,qCACA,iBAAiB,QAAQ,MAAM,UAAU,kBAC7C;IACA,MAAM;GACV,CAAC;GAeD,IAAI,CAAC,MAbkB,cAAc;IACjC,SAAS,UAAU,OAAO;IAC1B;IACA,QAAQ;GACZ,CAAC,CAAC,CAAC,OAAO,UAAU;IAChB,KAAK,UACD,mCACA,iBAAiB,QAAQ,MAAM,UAAU,kBAC7C;IAEA,OAAO;GACX,CAAC,GAEc;IACX,KAAK,UAAU,0BAA0B;IACzC,MAAM,IAAI,UAAU,gBAAgB,GAAG;GAC3C;GAEA,MAAM,SAAS,SAAS,UAAU,OAAO;GAEzC,IAAI,CAAC,OAAO,SAAS;IACjB,KAAK,UACD,qCACA,KAAK,UAAU,OAAO,QAAQ,CAAC,GAAG,MAAM,CAAC,CAC7C;IACA,MAAM,IAAI,UAAU,mBAAmB,GAAG;GAC9C;GAEA,MAAM,EAAE,OAAO,SAAS,OAAO;GAC/B,MAAM,UAAU,MAAM,KAAK,YAAY;GAEvC,QAAQ,OAAR;IACI,KAAK,mBAAmB;KACpB,MAAM,OAAO,KAAK;KAClB,MAAM,UACF,OAAO,SAAS,WACR,MAAM,KAAK,qBAAqB;MAAE;MAAS;KAAK,CAAC,KAAM,OACzD;KAEV,IAAI;MACA,OAAO,sBAAsB,GAAG;OAAE;OAAO;OAAM;MAAQ,CAAC;KAC5D,SAAS,OAAO;MACZ,KAAK,UAAU,6CAA6C;MAC5D,MAAM;KACV;IACJ;IACA,KAAK,kBAAkB;KACnB,MAAM,OAAO,KAAK;KAElB,MAAM,QAAQ,QACV,KAAK,YAAY,gBAAgB;MAC7B;MACA,UAAU;MACV;KACJ,CAAC,CACL;KAEA,IAAI;MACA,OAAO,sBAAsB,GAAG;OAAE;OAAO;MAAK,CAAC;KACnD,SAAS,OAAO;MACZ,KAAK,UAAU,2CAA2C;MAC1D,MAAM;KACV;IACJ;IACA,KAAK,qBAAqB;KACtB,MAAM,OAAO,KAAK;KAClB,MAAM,eAAe,KAAK;KAE1B,MAAM,QAAQ,QACV,KAAK,YAAY,mBAAmB;MAChC;MACA;MACA,UAAU;MACV;KACJ,CAAC,CACL;KAEA,IAAI;MACA,OAAO,sBAAsB,GAAG;OAAE;OAAO;MAAK,CAAC;KACnD,SAAS,OAAO;MACZ,KAAK,UAAU,8CAA8C;MAC7D,MAAM;KACV;IACJ;IACA,KAAK,kBAAkB;KACnB,MAAM,OAAO,KAAK;KAClB,MAAM,eAAe,KAAK;KAC1B,MAAM,OAAO,KAAK;KAElB,MAAM,QAAQ,QACV,KAAK,YAAY,gBAAgB;MAC7B;MACA;MACA,UAAU;MACV;MACA;KACJ,CAAC,CACL;KAEA,IAAI;MACA,OAAO,sBAAsB,GAAG;OAAE;OAAO;MAAK,CAAC;KACnD,SAAS,OAAO;MACZ,KAAK,UAAU,2CAA2C;MAC1D,MAAM;KACV;IACJ;IACA,KAAK,qBAAqB;KACtB,MAAM,OAAO,KAAK;KAClB,MAAM,eAAe,KAAK;KAC1B,MAAM,OAAO,KAAK;KAElB,MAAM,QAAQ,QACV,KAAK,YAAY,mBAAmB;MAChC;MACA;MACA,UAAU;MACV;MACA;KACJ,CAAC,CACL;KAEA,IAAI;MACA,OAAO,sBAAsB,GAAG;OAAE;OAAO;MAAK,CAAC;KACnD,SAAS,OAAO;MACZ,KAAK,UAAU,8CAA8C;MAC7D,MAAM;KACV;IACJ;IACA,SACI,OAAO,oBAAoB,GAAG,EAAE,SAAS,gBAAgB,GAAG,KAAK,KAAK;GAE9E;EACJ,SAAS,OAAO;GACZ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;GACzD,MAAM,SAAS,iBAAiB,YAAY,MAAM,SAAS;GAE3D,KAAK,UAAU,oBAAoB,OAAO;GAE1C,OAAO,oBAAoB,GAAG,EAAE,QAAQ,GAAG,MAAM;EACrD;CACJ,CAAC;CAEL,MAAc,cAAiC;EAC3C,OAAO,OAAO,KAAK,aAAa,aAC1B,MAAM,QAAQ,QAAQ,KAAK,SAAS,KAAK,YAAmB,CAAC,IAC7D,MAAM,QAAQ,QAAQ,KAAK,QAAQ;CAC7C;CAEA,UAAkB,GAAG,MAAmB;EACpC,IAAI,CAAC,KAAK,QAAQ;EAElB,QAAQ,IAAI,mBAAmB,GAAG,IAAI;CAC1C;AACJ;;;AC1YA,MAAa,gBAKT,WACwE;CACxE,MAAM,EAAE,WAAW,SAAS,MAAM,UAAU;CAE5C,OAAO;EACH;EACA;EACA;EACA;EACA,gBAAgB,IAAI,aAA8B,MAAM;CAC5D;AACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/platform-pluv",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "@pluv/io adapter for pluv.io",
|
|
5
5
|
"author": {
|
|
6
6
|
"email": "david@pluv.io",
|
|
@@ -20,20 +20,20 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@types/node": "^25.
|
|
23
|
+
"@types/node": "^25.9.2",
|
|
24
24
|
"fast-json-stable-stringify": "^2.1.0",
|
|
25
|
-
"hono": "^4.
|
|
26
|
-
"zod": "^4.3
|
|
27
|
-
"@pluv/crdt": "^4.0.
|
|
28
|
-
"@pluv/io": "^4.0.
|
|
29
|
-
"@pluv/types": "^4.0.
|
|
25
|
+
"hono": "^4.12.25",
|
|
26
|
+
"zod": "^4.4.3",
|
|
27
|
+
"@pluv/crdt": "^4.0.2",
|
|
28
|
+
"@pluv/io": "^4.0.2",
|
|
29
|
+
"@pluv/types": "^4.0.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"eslint": "^
|
|
33
|
-
"tsdown": "0.
|
|
32
|
+
"eslint": "^10.4.1",
|
|
33
|
+
"tsdown": "0.22.2",
|
|
34
34
|
"typescript": "^5.9.3",
|
|
35
|
-
"@pluv/tsconfig": "^4.0.
|
|
36
|
-
"eslint-config-pluv": "^4.0.
|
|
35
|
+
"@pluv/tsconfig": "^4.0.2",
|
|
36
|
+
"eslint-config-pluv": "^4.0.2"
|
|
37
37
|
},
|
|
38
38
|
"exports": {
|
|
39
39
|
".": "./dist/index.mjs",
|
package/src/PluvPlatform.ts
CHANGED
|
@@ -6,6 +6,14 @@ export const createErrorResponse = <TStatus extends ContentfulStatusCode>(
|
|
|
6
6
|
c: Context<BlankEnv, "/", BlankInput>,
|
|
7
7
|
error: { message: string },
|
|
8
8
|
status: TStatus,
|
|
9
|
+
event: string = "unknown",
|
|
9
10
|
) => {
|
|
10
|
-
return c.json(
|
|
11
|
+
return c.json(
|
|
12
|
+
{
|
|
13
|
+
ok: false,
|
|
14
|
+
error: { message: error.message },
|
|
15
|
+
},
|
|
16
|
+
status,
|
|
17
|
+
{ "x-pluv-event": event },
|
|
18
|
+
);
|
|
11
19
|
};
|
package/src/types.ts
CHANGED
|
@@ -28,12 +28,8 @@ export type PluvIOListeners<
|
|
|
28
28
|
TUser extends BaseUser = BaseUser,
|
|
29
29
|
> = {
|
|
30
30
|
getInitialStorage?: GetInitialStorageFn<TContext>;
|
|
31
|
-
onRoomDestroyed: (
|
|
32
|
-
|
|
33
|
-
) => void;
|
|
34
|
-
onStorageDestroyed: (
|
|
35
|
-
event: IORoomListenerEvent<PluvPlatform<TContext>, TContext>,
|
|
36
|
-
) => void;
|
|
31
|
+
onRoomDestroyed: (event: IORoomDestroyedEvent<PluvPlatform<TContext>, TContext>) => void;
|
|
32
|
+
onStorageDestroyed: (event: IORoomListenerEvent<PluvPlatform<TContext>, TContext>) => void;
|
|
37
33
|
onUserConnected: (
|
|
38
34
|
event: IOUserConnectedEvent<
|
|
39
35
|
PluvPlatform<TContext>,
|