@pluv/platform-pluv 0.33.0 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +67 -0
- package/dist/index.d.mts +60 -213
- package/dist/index.d.ts +60 -213
- package/dist/index.js +101 -84
- package/dist/index.mjs +96 -79
- package/package.json +9 -9
- package/src/PluvPlatform.ts +197 -5
- package/src/index.ts +8 -4
- package/src/platformPluv.ts +6 -0
- package/src/types.ts +29 -0
- package/src/PluvIO.ts +0 -221
- package/src/createIO.ts +0 -7
package/src/PluvIO.ts
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import type { GetInitialStorageFn, JWTEncodeParams } from "@pluv/io";
|
|
2
|
-
import type { BaseUser, IOLike, InputZodLike } from "@pluv/types";
|
|
3
|
-
import { Hono } from "hono";
|
|
4
|
-
import { handle } from "hono/vercel";
|
|
5
|
-
import { SIGNATURE_HEADER } from "./constants";
|
|
6
|
-
import type { PluvPlatform } from "./PluvPlatform";
|
|
7
|
-
import { ZodEvent } from "./schemas";
|
|
8
|
-
import { verifyWebhook } from "./shared";
|
|
9
|
-
|
|
10
|
-
interface PluvAuthorize<TUser extends BaseUser> {
|
|
11
|
-
required: true;
|
|
12
|
-
secret: string;
|
|
13
|
-
user: InputZodLike<TUser>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface PluvIOEndpoints {
|
|
17
|
-
createToken: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type RoomDeletedMessageEventData = {
|
|
21
|
-
encodedState: string | null;
|
|
22
|
-
room: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
type UserConnectedEventData<TUser extends BaseUser> = {
|
|
26
|
-
encodedState: string | null;
|
|
27
|
-
room: string;
|
|
28
|
-
user: TUser;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type UserDisconnectedEventData<TUser extends BaseUser> = {
|
|
32
|
-
encodedState: string | null;
|
|
33
|
-
room: string;
|
|
34
|
-
user: TUser;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
type PluvIOListeners<TUser extends BaseUser> = {
|
|
38
|
-
getInitialStorage?: GetInitialStorageFn<{}>;
|
|
39
|
-
onRoomDeleted: (event: RoomDeletedMessageEventData) => void;
|
|
40
|
-
onUserConnected: (event: UserConnectedEventData<TUser>) => void;
|
|
41
|
-
onUserDisconnected: (event: UserDisconnectedEventData<TUser>) => void;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
type WebhooksConfig<TUser extends BaseUser> =
|
|
45
|
-
| ({ webhookSecret?: undefined } & { [P in keyof PluvIOListeners<TUser>]?: undefined })
|
|
46
|
-
| ({ webhookSecret: string } & Partial<PluvIOListeners<TUser>>);
|
|
47
|
-
|
|
48
|
-
export type PluvIOConfig<TUser extends BaseUser> = WebhooksConfig<TUser> & {
|
|
49
|
-
/**
|
|
50
|
-
* @ignore
|
|
51
|
-
* @readonly
|
|
52
|
-
* @deprecated Internal use only. Changes to this will never be marked as breaking.
|
|
53
|
-
*/
|
|
54
|
-
_defs?: {
|
|
55
|
-
endpoints?: PluvIOEndpoints;
|
|
56
|
-
};
|
|
57
|
-
authorize: {
|
|
58
|
-
user: InputZodLike<TUser>;
|
|
59
|
-
};
|
|
60
|
-
basePath: string;
|
|
61
|
-
publicKey: string;
|
|
62
|
-
secretKey: string;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export class PluvIO<TUser extends BaseUser> implements IOLike<PluvAuthorize<TUser>, {}> {
|
|
66
|
-
private readonly _authorize: PluvAuthorize<TUser>;
|
|
67
|
-
private readonly _basePath: string;
|
|
68
|
-
private readonly _endpoints: PluvIOEndpoints;
|
|
69
|
-
private readonly _getInitialStorage?: GetInitialStorageFn<{}>;
|
|
70
|
-
private readonly _listeners: PluvIOListeners<TUser>;
|
|
71
|
-
private readonly _publicKey: string;
|
|
72
|
-
private readonly _secretKey: string;
|
|
73
|
-
private readonly _webhookSecret?: string;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* @ignore
|
|
77
|
-
* @readonly
|
|
78
|
-
* @deprecated Internal use only. Changes to this will never be marked as breaking.
|
|
79
|
-
*/
|
|
80
|
-
public get _defs() {
|
|
81
|
-
return {
|
|
82
|
-
authorize: this._authorize,
|
|
83
|
-
context: {},
|
|
84
|
-
events: {},
|
|
85
|
-
get platform() {
|
|
86
|
-
throw new Error("Invalid platform reference");
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
public get fetch() {
|
|
92
|
-
const app = new Hono().basePath(this._basePath).route("/", this._webhooks);
|
|
93
|
-
|
|
94
|
-
return app.fetch;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
public get handler() {
|
|
98
|
-
const app = new Hono().basePath(this._basePath).route("/", this._webhooks);
|
|
99
|
-
|
|
100
|
-
return handle(app);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private _webhooks = new Hono().basePath("/").post("/", async (c) => {
|
|
104
|
-
const signature = c.req.header(SIGNATURE_HEADER);
|
|
105
|
-
|
|
106
|
-
if (!this._webhookSecret || !signature) return c.json({ error: "Unauthorized" }, 401);
|
|
107
|
-
|
|
108
|
-
const payload = await c.req.json();
|
|
109
|
-
|
|
110
|
-
const verified = await verifyWebhook({
|
|
111
|
-
payload,
|
|
112
|
-
signature,
|
|
113
|
-
secret: this._webhookSecret,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
if (!verified) return c.json({ error: "Unauthorized" }, 401);
|
|
117
|
-
|
|
118
|
-
const parsed = ZodEvent.safeParse(payload);
|
|
119
|
-
|
|
120
|
-
if (!parsed.success) return c.json({ data: { ok: true } }, 200);
|
|
121
|
-
|
|
122
|
-
const { event, data } = parsed.data;
|
|
123
|
-
|
|
124
|
-
switch (event) {
|
|
125
|
-
case "initial-storage": {
|
|
126
|
-
const room = data.room;
|
|
127
|
-
const storage =
|
|
128
|
-
typeof room === "string"
|
|
129
|
-
? ((await this._getInitialStorage?.({ context: {}, room })) ?? null)
|
|
130
|
-
: null;
|
|
131
|
-
|
|
132
|
-
return c.json({ data: { storage } }, 200);
|
|
133
|
-
}
|
|
134
|
-
case "room-deleted": {
|
|
135
|
-
const room = data.room;
|
|
136
|
-
const encodedState = data.storage;
|
|
137
|
-
|
|
138
|
-
await Promise.resolve(this._listeners.onRoomDeleted({ encodedState, room }));
|
|
139
|
-
|
|
140
|
-
return c.json({ data: { room } }, 200);
|
|
141
|
-
}
|
|
142
|
-
case "user-connected": {
|
|
143
|
-
const room = data.room;
|
|
144
|
-
const encodedState = data.storage;
|
|
145
|
-
const user = data.user as TUser;
|
|
146
|
-
|
|
147
|
-
await Promise.resolve(this._listeners.onUserConnected({ encodedState, room, user }));
|
|
148
|
-
}
|
|
149
|
-
case "user-disconnected": {
|
|
150
|
-
const room = data.room;
|
|
151
|
-
const encodedState = data.storage;
|
|
152
|
-
const user = data.user as TUser;
|
|
153
|
-
|
|
154
|
-
await Promise.resolve(this._listeners.onUserDisconnected({ encodedState, room, user }));
|
|
155
|
-
}
|
|
156
|
-
default:
|
|
157
|
-
return c.json({ data: { ok: true } }, 200);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
constructor(options: PluvIOConfig<TUser>) {
|
|
162
|
-
const {
|
|
163
|
-
_defs,
|
|
164
|
-
authorize,
|
|
165
|
-
basePath,
|
|
166
|
-
getInitialStorage,
|
|
167
|
-
onRoomDeleted,
|
|
168
|
-
onUserConnected,
|
|
169
|
-
onUserDisconnected,
|
|
170
|
-
publicKey,
|
|
171
|
-
secretKey,
|
|
172
|
-
webhookSecret,
|
|
173
|
-
} = options;
|
|
174
|
-
|
|
175
|
-
this._authorize = {
|
|
176
|
-
required: true,
|
|
177
|
-
secret: "",
|
|
178
|
-
user: authorize.user,
|
|
179
|
-
};
|
|
180
|
-
this._basePath = basePath;
|
|
181
|
-
this._endpoints = {
|
|
182
|
-
createToken: "https://pluv.io/api/room/token",
|
|
183
|
-
..._defs?.endpoints,
|
|
184
|
-
};
|
|
185
|
-
this._getInitialStorage = getInitialStorage;
|
|
186
|
-
this._listeners = {
|
|
187
|
-
onRoomDeleted: (event) => onRoomDeleted?.(event),
|
|
188
|
-
onUserConnected: (event) => onUserConnected?.(event),
|
|
189
|
-
onUserDisconnected: (event) => onUserDisconnected?.(event),
|
|
190
|
-
};
|
|
191
|
-
this._publicKey = publicKey;
|
|
192
|
-
this._secretKey = secretKey;
|
|
193
|
-
this._webhookSecret = webhookSecret;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
public async createToken(params: JWTEncodeParams<TUser, PluvPlatform>): Promise<string> {
|
|
197
|
-
const parsed = this._authorize.user.parse(params.user);
|
|
198
|
-
|
|
199
|
-
const res = await fetch(this._endpoints.createToken, {
|
|
200
|
-
headers: { "content-type": "application/json" },
|
|
201
|
-
method: "post",
|
|
202
|
-
body: JSON.stringify({
|
|
203
|
-
maxAge: params.maxAge ?? null,
|
|
204
|
-
publicKey: this._publicKey,
|
|
205
|
-
room: params.room,
|
|
206
|
-
secretKey: this._secretKey,
|
|
207
|
-
user: parsed,
|
|
208
|
-
}),
|
|
209
|
-
}).catch(() => null);
|
|
210
|
-
|
|
211
|
-
if (!res || !res.ok || res.status !== 200) {
|
|
212
|
-
throw new Error("Authorization failed");
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const token = await res.text().catch(() => null);
|
|
216
|
-
|
|
217
|
-
if (typeof token !== "string") throw new Error("Authorization failed");
|
|
218
|
-
|
|
219
|
-
return token;
|
|
220
|
-
}
|
|
221
|
-
}
|
package/src/createIO.ts
DELETED