@pluv/platform-pluv 4.0.1 → 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.
@@ -1,18 +1,18 @@
1
-
2
- > @pluv/platform-pluv@4.0.1 build /home/runner/work/pluv/pluv/packages/platform-pluv
3
- > tsdown
4
-
5
- ℹ tsdown v0.20.0-beta.4 powered by rolldown v1.0.0-beta.60
1
+ $ tsdown
2
+ ℹ tsdown v0.22.2 powered by rolldown v1.1.0
6
3
  ℹ config file: /home/runner/work/pluv/pluv/packages/platform-pluv/tsdown.config.ts
7
4
  ℹ entry: src/index.ts
8
5
  ℹ target: esnext
9
6
  ℹ tsconfig: tsconfig.json
10
7
  ℹ Build start
11
- [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugin `rolldown-plugin-dts:generate`. See https://rolldown.rs/options/checks#plugintimings for more details.
12
- ℹ dist/index.mjs 13.74 kB │ gzip: 3.46 kB
13
- ℹ dist/index.mjs.map 33.93 kB │ gzip: 7.44 kB
14
- ℹ dist/index.d.mts.map  1.86 kB │ gzip: 0.69 kB
8
+ ℹ dist/index.mjs 13.62 kB │ gzip: 3.44 kB
9
+ ℹ dist/index.mjs.map 34.06 kB │ gzip: 7.39 kB
10
+ ℹ dist/index.d.mts.map  1.85 kB │ gzip: 0.69 kB
15
11
  ℹ dist/index.d.mts  4.21 kB │ gzip: 1.29 kB
16
- ℹ 4 files, total: 53.74 kB
12
+ ℹ 4 files, total: 53.75 kB
13
+ [PLUGIN_TIMINGS] Your 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
- ✔ Build complete in 3774ms
18
+ ✔ Build complete in 3902ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
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
+
3
13
  ## 4.0.1
4
14
 
5
15
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/PluvPlatform.ts","../src/platformPluv.ts"],"mappings":";;;;;;UAqBiB,eAAA;EACb,WAAA;AAAA;;;KCDQ,SAAA,mBAA4B,YAAA;AAAA,KAC5B,SAAA,mBAA4B,YAAA;AAAA,KAC5B,aAAA,mBAAgC,YAAA;AAAA,UAE3B,kBAAA,kBAAoC,MAAA;;;;;;EAMjD,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,CAAA;EAIA,UAAA,CAAW,MAAA,EAAQ,sBAAA;EAInB,SAAA,CAAU,IAAA,WAAe,WAAA,GAAc,MAAA;EAIvC,UAAA,CAAA;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"}
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
- const SIGNATURE_HEADER = "x-pluv-signature-256";
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,7 +81,6 @@ 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
86
  const createErrorResponse = (c, error, status, event = "unknown") => {
@@ -96,7 +89,6 @@ const createErrorResponse = (c, error, status, event = "unknown") => {
96
89
  error: { message: error.message }
97
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,7 +115,6 @@ 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) => {
@@ -133,7 +123,6 @@ const createSuccessResponse = (c, data, status = 200) => {
133
123
  data: ZodEventResponse.parse(data)
134
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(SIGNATURE_HEADER)?.split("=") ?? [];
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 !== SIGNATURE_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
  }
@@ -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
@@ -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 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":"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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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/platform-pluv",
3
- "version": "4.0.1",
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.0.9",
23
+ "@types/node": "^25.9.2",
24
24
  "fast-json-stable-stringify": "^2.1.0",
25
- "hono": "^4.11.4",
26
- "zod": "^4.3.5",
27
- "@pluv/crdt": "^4.0.1",
28
- "@pluv/io": "^4.0.1",
29
- "@pluv/types": "^4.0.1"
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": "^9.39.2",
33
- "tsdown": "0.20.0-beta.4",
32
+ "eslint": "^10.4.1",
33
+ "tsdown": "0.22.2",
34
34
  "typescript": "^5.9.3",
35
- "@pluv/tsconfig": "^4.0.1",
36
- "eslint-config-pluv": "^4.0.1"
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/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
- event: IORoomDestroyedEvent<PluvPlatform<TContext>, TContext>,
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>,