Skip to content

Commit 0445780

Browse files
committed
✨ Implemented
1 parent 8acda73 commit 0445780

File tree

3 files changed

+226
-1
lines changed

3 files changed

+226
-1
lines changed

mod.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/// <reference no-default-lib="true" />
2+
/// <reference lib="esnext" />
3+
/// <reference lib="dom" />
4+
5+
import type { Socket } from "./socket.ts";
6+
import type { DataOf, EventMap, ListenEventMap, ResponseOf } from "./types.ts";
7+
export * from "./types.ts";
8+
export * from "./socket.ts";
9+
10+
export function wrap(
11+
socket: Socket,
12+
timeout = 90000,
13+
) {
14+
function request<EventName extends keyof EventMap>(
15+
event: EventName,
16+
data: DataOf<EventName>,
17+
): Promise<
18+
EventName extends "cursor" ? void
19+
: ResponseOf<"socket.io-request">["data"]
20+
> {
21+
let id: number | undefined;
22+
type ResolveType = EventName extends "cursor" ? void
23+
: ResponseOf<"socket.io-request">["data"];
24+
return new Promise((resolve, reject) => {
25+
const onDisconnect = (message: string) => {
26+
clearTimeout(id);
27+
reject(new Error(message));
28+
};
29+
socket.emit(event, data, (response: ResponseOf<EventName>) => {
30+
clearTimeout(id);
31+
socket.off("disconnect", onDisconnect);
32+
if (response.error) {
33+
reject(
34+
new Error(JSON.stringify(response.error)),
35+
);
36+
}
37+
if ("data" in response) {
38+
resolve(response?.data as ResolveType);
39+
} else {
40+
resolve(undefined as ResolveType);
41+
}
42+
});
43+
id = setTimeout(() => {
44+
socket.off("disconnect", onDisconnect);
45+
reject(new Error(`Timeout: exceeded ${timeout}ms`));
46+
}, timeout);
47+
socket.once("disconnect", onDisconnect);
48+
});
49+
}
50+
51+
async function* response<EventName extends keyof ListenEventMap>(
52+
event: EventName,
53+
) {
54+
type Data = Parameters<ListenEventMap[EventName]>[0];
55+
let _resolve: ((data: Data) => void) | undefined;
56+
const waitForEvent = () => new Promise<Data>((res) => _resolve = res);
57+
const resolve = (data: Data) => {
58+
_resolve?.(data);
59+
};
60+
61+
socket.on(
62+
event,
63+
// @ts-ignore 何故か型推論に失敗する
64+
resolve,
65+
);
66+
try {
67+
yield await waitForEvent();
68+
} finally {
69+
socket.off(event, resolve);
70+
}
71+
}
72+
73+
return { request, response };
74+
}

socket.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
ManagerOptions,
77
Socket,
88
SocketOptions,
9-
} from "https://cdn.esm.sh/v54/socket.io-client@4.2.0/build/index.d.ts";
9+
} from "./types/socketIO/index.ts";
1010
export type { Manager, ManagerOptions, Socket, SocketOptions };
1111

1212
declare function io(

types.ts

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
export type JoinRoomData = {
2+
pageId: string | null;
3+
projectId: string;
4+
projectUpdatesStream: false;
5+
} | {
6+
pageId: null;
7+
projectId: string;
8+
projectUpdatesStream: true;
9+
};
10+
11+
export interface JoinRoomResponse {
12+
data: {
13+
success: true;
14+
pageId: string | null;
15+
projectId: string;
16+
};
17+
}
18+
19+
export interface ProjectUpdatesStreamCommit {
20+
kind: "page";
21+
id: string;
22+
parentId: string;
23+
projectId: string;
24+
pageId: string;
25+
userId: string;
26+
changes: (Change[] | [Delete]);
27+
cursor: null;
28+
freeze: true;
29+
}
30+
export type ProjectUpdatesStreamEvent =
31+
& {
32+
id: string;
33+
pageId: string;
34+
userId: string;
35+
projectId: string;
36+
created: number;
37+
updated: number;
38+
}
39+
& ({
40+
type: "member.join" | "invitation.reset";
41+
} | {
42+
type: "page.delete";
43+
data: {
44+
titleLc: string;
45+
};
46+
} | {
47+
type: "admin.add" | "admin.delete" | "owner.set";
48+
targetUserId: string;
49+
});
50+
51+
export interface CommitNotification {
52+
kind: "page";
53+
id: string;
54+
parentId: string;
55+
projectId: string;
56+
pageId: string;
57+
userId: string;
58+
changes: (Change[] | [Pin] | [Delete]);
59+
cursor: null;
60+
freeze: true;
61+
}
62+
export type CommitData = Omit<CommitNotification, "id">;
63+
export interface CommitResponse {
64+
data: {
65+
commitId: string;
66+
};
67+
}
68+
export interface EventMap {
69+
"socket.io-request": (
70+
data: CommitData | JoinRoomData,
71+
callback: (
72+
response: (CommitResponse | JoinRoomResponse) & { error?: unknown },
73+
) => void,
74+
) => void;
75+
cursor: (
76+
data: Omit<MoveCursorData, "socketId">,
77+
callback: (response: { error?: unknown }) => void,
78+
) => void;
79+
}
80+
export interface ListenEventMap {
81+
"projectUpdatesStream:commit": (
82+
data: ProjectUpdatesStreamCommit,
83+
) => void;
84+
"projectUpdatesStream:event": (
85+
data: ProjectUpdatesStreamEvent,
86+
) => void;
87+
commit: (data: CommitNotification) => void;
88+
cursor: (data: MoveCursorData) => void;
89+
}
90+
export type DataOf<Event extends keyof EventMap> = Parameters<
91+
EventMap[Event]
92+
>[0];
93+
export type ResponseOf<Event extends keyof EventMap> = Parameters<
94+
Parameters<
95+
EventMap[Event]
96+
>[1]
97+
>[0];
98+
99+
export interface MoveCursorData {
100+
user: {
101+
id: string;
102+
displayName: string;
103+
};
104+
pageId: string;
105+
position: {
106+
line: number;
107+
char: number;
108+
};
109+
visible: boolean;
110+
socketId: string;
111+
}
112+
113+
export type Change =
114+
| InsertCommit
115+
| UpdateCommit
116+
| DeleteCommit
117+
| LinksCommit
118+
| DescriptionsCommit
119+
| TitleCommit;
120+
export interface InsertCommit {
121+
_insert: string;
122+
lines: {
123+
id: string;
124+
text: string;
125+
};
126+
}
127+
export interface UpdateCommit {
128+
_update: string;
129+
lines: {
130+
text: string;
131+
};
132+
}
133+
export interface DeleteCommit {
134+
_delete: string;
135+
lines: -1;
136+
}
137+
export interface LinksCommit {
138+
links: string[];
139+
}
140+
export interface DescriptionsCommit {
141+
descriptions: string[];
142+
}
143+
export interface TitleCommit {
144+
title: string;
145+
}
146+
export interface Pin {
147+
pin: number;
148+
}
149+
export interface Delete {
150+
delete: true;
151+
}

0 commit comments

Comments
 (0)