@mitway/sdk 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +223 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +136 -23
- package/dist/index.d.ts +136 -23
- package/dist/index.js +222 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -29,6 +29,135 @@ interface User {
|
|
|
29
29
|
updated_at: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Token Manager for the MITWAY-BaaS SDK.
|
|
34
|
+
*
|
|
35
|
+
* In-memory storage for the access token + user. Browser CSRF token lives
|
|
36
|
+
* in a cookie so the cookie-based refresh flow works across page reloads.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
declare class TokenManager {
|
|
40
|
+
private accessToken;
|
|
41
|
+
private user;
|
|
42
|
+
/** Fired when the access token changes (used by long-lived consumers). */
|
|
43
|
+
onTokenChange: (() => void) | null;
|
|
44
|
+
saveSession(session: AuthSession): void;
|
|
45
|
+
getSession(): AuthSession | null;
|
|
46
|
+
getAccessToken(): string | null;
|
|
47
|
+
setAccessToken(token: string): void;
|
|
48
|
+
getUser(): User | null;
|
|
49
|
+
setUser(user: User): void;
|
|
50
|
+
clearSession(): void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Realtime module — Socket.IO client wrapper for MITWAY-BaaS.
|
|
55
|
+
*
|
|
56
|
+
* Provides a thin, typed layer over `socket.io-client` so app code can
|
|
57
|
+
* subscribe / publish / listen without dealing with the underlying
|
|
58
|
+
* transport details. The MITWAY-BaaS backend handles auth (JWT / API
|
|
59
|
+
* key), RLS, rate limiting, and fan-out across replicas — the SDK just
|
|
60
|
+
* opens one socket per `MitwayBaasClient` instance and routes events.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/** Standardized meta envelope emitted by the server on every push. */
|
|
64
|
+
interface RealtimeMessageMeta {
|
|
65
|
+
channel?: string;
|
|
66
|
+
message_id: string;
|
|
67
|
+
sender_type: 'system' | 'user';
|
|
68
|
+
sender_id?: string;
|
|
69
|
+
timestamp: string;
|
|
70
|
+
}
|
|
71
|
+
/** Subscribe ack returned by the server. */
|
|
72
|
+
type SubscribeResult = {
|
|
73
|
+
ok: true;
|
|
74
|
+
channel: string;
|
|
75
|
+
} | {
|
|
76
|
+
ok: false;
|
|
77
|
+
channel: string;
|
|
78
|
+
error: {
|
|
79
|
+
code: string;
|
|
80
|
+
message: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
/** Server-pushed unsolicited error. */
|
|
84
|
+
interface RealtimeErrorPayload {
|
|
85
|
+
channel?: string;
|
|
86
|
+
code: string;
|
|
87
|
+
message: string;
|
|
88
|
+
}
|
|
89
|
+
interface RealtimeListener<T = unknown> {
|
|
90
|
+
(payload: T, meta: RealtimeMessageMeta): void;
|
|
91
|
+
}
|
|
92
|
+
type ConnectionListener = () => void;
|
|
93
|
+
type DisconnectListener = (reason: string) => void;
|
|
94
|
+
type ConnectErrorListener = (error: Error) => void;
|
|
95
|
+
interface RealtimeOptions {
|
|
96
|
+
/** Override the path on the server. Defaults to the Socket.IO default. */
|
|
97
|
+
path?: string;
|
|
98
|
+
/** Transport strategy. Defaults to `['websocket']` — modern browsers
|
|
99
|
+
* and Node always support it, no need for the long-polling fallback. */
|
|
100
|
+
transports?: Array<'websocket' | 'polling'>;
|
|
101
|
+
/** Handshake timeout in ms. */
|
|
102
|
+
timeoutMs?: number;
|
|
103
|
+
/** Extra fields merged into socket.handshake.auth. Advanced usage. */
|
|
104
|
+
extraAuth?: Record<string, string>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* MITWAY-BaaS realtime client.
|
|
108
|
+
*
|
|
109
|
+
* Public API mirrors the InsForge realtime SDK for familiarity, but the
|
|
110
|
+
* wire protocol follows our backend (see
|
|
111
|
+
* `MITWAY-BaaS/backend/src/infra/socket/socket.manager.ts`):
|
|
112
|
+
*
|
|
113
|
+
* - Handshake auth uses `auth.token` containing the JWT (preferred)
|
|
114
|
+
* or an opaque API key string.
|
|
115
|
+
* - `realtime:subscribe` / `realtime:unsubscribe` / `realtime:publish`
|
|
116
|
+
* are the client-to-server events.
|
|
117
|
+
* - Server pushes the user-defined `event` name with `{ ...payload,
|
|
118
|
+
* meta }` shape.
|
|
119
|
+
* - `realtime:error` is the unsolicited error channel for publish
|
|
120
|
+
* failures and similar.
|
|
121
|
+
*/
|
|
122
|
+
declare class Realtime {
|
|
123
|
+
private socket;
|
|
124
|
+
private baseUrl;
|
|
125
|
+
private options;
|
|
126
|
+
private anonKey;
|
|
127
|
+
private tokenManager;
|
|
128
|
+
private listeners;
|
|
129
|
+
private reserved;
|
|
130
|
+
private connecting;
|
|
131
|
+
private subscribedChannels;
|
|
132
|
+
constructor(baseUrl: string, tokenManager: TokenManager, anonKey: string | undefined, options?: RealtimeOptions);
|
|
133
|
+
get isConnected(): boolean;
|
|
134
|
+
get socketId(): string | undefined;
|
|
135
|
+
/** Explicitly open the connection. Safe to call multiple times; only
|
|
136
|
+
* opens one socket per instance. Subsequent calls during connection
|
|
137
|
+
* return the same in-flight promise. */
|
|
138
|
+
connect(): Promise<void>;
|
|
139
|
+
private openSocket;
|
|
140
|
+
/** Close the socket and clear in-memory subscription state. Reserved
|
|
141
|
+
* listeners survive so callers can reconnect later via `connect()`. */
|
|
142
|
+
disconnect(): void;
|
|
143
|
+
subscribe(channel: string): Promise<SubscribeResult>;
|
|
144
|
+
/** Fire-and-forget. No ack from the server. */
|
|
145
|
+
unsubscribe(channel: string): void;
|
|
146
|
+
/** Publish via the Socket.IO transport. Subject to RLS INSERT policy
|
|
147
|
+
* on `realtime.messages` (disabled by default — the developer must
|
|
148
|
+
* add a policy before clients can publish). Returns immediately; any
|
|
149
|
+
* server rejection comes through the `error` reserved event. */
|
|
150
|
+
publish(channel: string, event: string, payload: Record<string, unknown>): void;
|
|
151
|
+
on(event: 'connect', cb: ConnectionListener): void;
|
|
152
|
+
on(event: 'disconnect', cb: DisconnectListener): void;
|
|
153
|
+
on(event: 'connect_error', cb: ConnectErrorListener): void;
|
|
154
|
+
on(event: 'error', cb: RealtimeListener<RealtimeErrorPayload>): void;
|
|
155
|
+
on<T = unknown>(event: string, cb: RealtimeListener<T>): void;
|
|
156
|
+
off(event: string, cb: (...args: any[]) => void): void;
|
|
157
|
+
private dispatch;
|
|
158
|
+
private emitReserved;
|
|
159
|
+
}
|
|
160
|
+
|
|
32
161
|
/**
|
|
33
162
|
* MITWAY-BaaS SDK types — only SDK-specific shapes live here.
|
|
34
163
|
* The `User` shape is inlined in `./lib/user` so this package has zero
|
|
@@ -89,6 +218,10 @@ interface MitwayBaasConfig {
|
|
|
89
218
|
* @default true
|
|
90
219
|
*/
|
|
91
220
|
autoRefreshToken?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* Realtime transport options. See `RealtimeOptions`.
|
|
223
|
+
*/
|
|
224
|
+
realtime?: RealtimeOptions;
|
|
92
225
|
}
|
|
93
226
|
/**
|
|
94
227
|
* Active user session in memory. Mirrors what the auth endpoints return.
|
|
@@ -146,27 +279,6 @@ declare class Logger {
|
|
|
146
279
|
logResponse(method: string, url: string, status: number, durationMs: number, body?: any): void;
|
|
147
280
|
}
|
|
148
281
|
|
|
149
|
-
/**
|
|
150
|
-
* Token Manager for the MITWAY-BaaS SDK.
|
|
151
|
-
*
|
|
152
|
-
* In-memory storage for the access token + user. Browser CSRF token lives
|
|
153
|
-
* in a cookie so the cookie-based refresh flow works across page reloads.
|
|
154
|
-
*/
|
|
155
|
-
|
|
156
|
-
declare class TokenManager {
|
|
157
|
-
private accessToken;
|
|
158
|
-
private user;
|
|
159
|
-
/** Fired when the access token changes (used by long-lived consumers). */
|
|
160
|
-
onTokenChange: (() => void) | null;
|
|
161
|
-
saveSession(session: AuthSession): void;
|
|
162
|
-
getSession(): AuthSession | null;
|
|
163
|
-
getAccessToken(): string | null;
|
|
164
|
-
setAccessToken(token: string): void;
|
|
165
|
-
getUser(): User | null;
|
|
166
|
-
setUser(user: User): void;
|
|
167
|
-
clearSession(): void;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
282
|
/**
|
|
171
283
|
* HttpClient with retry, timeout, abort signal composition, and automatic
|
|
172
284
|
* token refresh on 401 INVALID_TOKEN responses.
|
|
@@ -409,6 +521,7 @@ declare class MitwayBaasClient {
|
|
|
409
521
|
private tokenManager;
|
|
410
522
|
readonly auth: Auth;
|
|
411
523
|
readonly database: Database;
|
|
524
|
+
readonly realtime: Realtime;
|
|
412
525
|
constructor(config?: MitwayBaasConfig);
|
|
413
526
|
/**
|
|
414
527
|
* Escape hatch for callers that need to make custom requests against the
|
|
@@ -423,13 +536,13 @@ declare class MitwayBaasClient {
|
|
|
423
536
|
* Currently ships:
|
|
424
537
|
* - auth (signUp, signInWithPassword, signOut, refreshSession, getSession, getUser)
|
|
425
538
|
* - database (PostgREST-backed query builder via @supabase/postgrest-js)
|
|
539
|
+
* - realtime (Socket.IO transport: subscribe / unsubscribe / publish / on)
|
|
426
540
|
*
|
|
427
541
|
* Not yet included (no backend support):
|
|
428
542
|
* - storage
|
|
429
543
|
* - functions
|
|
430
544
|
* - email
|
|
431
545
|
* - ai
|
|
432
|
-
* - realtime
|
|
433
546
|
*
|
|
434
547
|
* @packageDocumentation
|
|
435
548
|
*/
|
|
@@ -449,4 +562,4 @@ declare class MitwayBaasClient {
|
|
|
449
562
|
*/
|
|
450
563
|
declare function createClient(config: MitwayBaasConfig): MitwayBaasClient;
|
|
451
564
|
|
|
452
|
-
export { type ApiError, Auth, type AuthRefreshResponse, type AuthResponse, type AuthResult, type AuthSession, Database, HttpClient, Logger, MitwayBaasClient, type MitwayBaasConfig, MitwayBaasError, type SignInRequest, type SignUpRequest, TokenManager, type User, createClient, MitwayBaasClient as default };
|
|
565
|
+
export { type ApiError, Auth, type AuthRefreshResponse, type AuthResponse, type AuthResult, type AuthSession, type ConnectErrorListener, type ConnectionListener, Database, type DisconnectListener, HttpClient, Logger, MitwayBaasClient, type MitwayBaasConfig, MitwayBaasError, Realtime, type RealtimeErrorPayload, type RealtimeListener, type RealtimeMessageMeta, type RealtimeOptions, type SignInRequest, type SignUpRequest, type SubscribeResult, TokenManager, type User, createClient, MitwayBaasClient as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,135 @@ interface User {
|
|
|
29
29
|
updated_at: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Token Manager for the MITWAY-BaaS SDK.
|
|
34
|
+
*
|
|
35
|
+
* In-memory storage for the access token + user. Browser CSRF token lives
|
|
36
|
+
* in a cookie so the cookie-based refresh flow works across page reloads.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
declare class TokenManager {
|
|
40
|
+
private accessToken;
|
|
41
|
+
private user;
|
|
42
|
+
/** Fired when the access token changes (used by long-lived consumers). */
|
|
43
|
+
onTokenChange: (() => void) | null;
|
|
44
|
+
saveSession(session: AuthSession): void;
|
|
45
|
+
getSession(): AuthSession | null;
|
|
46
|
+
getAccessToken(): string | null;
|
|
47
|
+
setAccessToken(token: string): void;
|
|
48
|
+
getUser(): User | null;
|
|
49
|
+
setUser(user: User): void;
|
|
50
|
+
clearSession(): void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Realtime module — Socket.IO client wrapper for MITWAY-BaaS.
|
|
55
|
+
*
|
|
56
|
+
* Provides a thin, typed layer over `socket.io-client` so app code can
|
|
57
|
+
* subscribe / publish / listen without dealing with the underlying
|
|
58
|
+
* transport details. The MITWAY-BaaS backend handles auth (JWT / API
|
|
59
|
+
* key), RLS, rate limiting, and fan-out across replicas — the SDK just
|
|
60
|
+
* opens one socket per `MitwayBaasClient` instance and routes events.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/** Standardized meta envelope emitted by the server on every push. */
|
|
64
|
+
interface RealtimeMessageMeta {
|
|
65
|
+
channel?: string;
|
|
66
|
+
message_id: string;
|
|
67
|
+
sender_type: 'system' | 'user';
|
|
68
|
+
sender_id?: string;
|
|
69
|
+
timestamp: string;
|
|
70
|
+
}
|
|
71
|
+
/** Subscribe ack returned by the server. */
|
|
72
|
+
type SubscribeResult = {
|
|
73
|
+
ok: true;
|
|
74
|
+
channel: string;
|
|
75
|
+
} | {
|
|
76
|
+
ok: false;
|
|
77
|
+
channel: string;
|
|
78
|
+
error: {
|
|
79
|
+
code: string;
|
|
80
|
+
message: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
/** Server-pushed unsolicited error. */
|
|
84
|
+
interface RealtimeErrorPayload {
|
|
85
|
+
channel?: string;
|
|
86
|
+
code: string;
|
|
87
|
+
message: string;
|
|
88
|
+
}
|
|
89
|
+
interface RealtimeListener<T = unknown> {
|
|
90
|
+
(payload: T, meta: RealtimeMessageMeta): void;
|
|
91
|
+
}
|
|
92
|
+
type ConnectionListener = () => void;
|
|
93
|
+
type DisconnectListener = (reason: string) => void;
|
|
94
|
+
type ConnectErrorListener = (error: Error) => void;
|
|
95
|
+
interface RealtimeOptions {
|
|
96
|
+
/** Override the path on the server. Defaults to the Socket.IO default. */
|
|
97
|
+
path?: string;
|
|
98
|
+
/** Transport strategy. Defaults to `['websocket']` — modern browsers
|
|
99
|
+
* and Node always support it, no need for the long-polling fallback. */
|
|
100
|
+
transports?: Array<'websocket' | 'polling'>;
|
|
101
|
+
/** Handshake timeout in ms. */
|
|
102
|
+
timeoutMs?: number;
|
|
103
|
+
/** Extra fields merged into socket.handshake.auth. Advanced usage. */
|
|
104
|
+
extraAuth?: Record<string, string>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* MITWAY-BaaS realtime client.
|
|
108
|
+
*
|
|
109
|
+
* Public API mirrors the InsForge realtime SDK for familiarity, but the
|
|
110
|
+
* wire protocol follows our backend (see
|
|
111
|
+
* `MITWAY-BaaS/backend/src/infra/socket/socket.manager.ts`):
|
|
112
|
+
*
|
|
113
|
+
* - Handshake auth uses `auth.token` containing the JWT (preferred)
|
|
114
|
+
* or an opaque API key string.
|
|
115
|
+
* - `realtime:subscribe` / `realtime:unsubscribe` / `realtime:publish`
|
|
116
|
+
* are the client-to-server events.
|
|
117
|
+
* - Server pushes the user-defined `event` name with `{ ...payload,
|
|
118
|
+
* meta }` shape.
|
|
119
|
+
* - `realtime:error` is the unsolicited error channel for publish
|
|
120
|
+
* failures and similar.
|
|
121
|
+
*/
|
|
122
|
+
declare class Realtime {
|
|
123
|
+
private socket;
|
|
124
|
+
private baseUrl;
|
|
125
|
+
private options;
|
|
126
|
+
private anonKey;
|
|
127
|
+
private tokenManager;
|
|
128
|
+
private listeners;
|
|
129
|
+
private reserved;
|
|
130
|
+
private connecting;
|
|
131
|
+
private subscribedChannels;
|
|
132
|
+
constructor(baseUrl: string, tokenManager: TokenManager, anonKey: string | undefined, options?: RealtimeOptions);
|
|
133
|
+
get isConnected(): boolean;
|
|
134
|
+
get socketId(): string | undefined;
|
|
135
|
+
/** Explicitly open the connection. Safe to call multiple times; only
|
|
136
|
+
* opens one socket per instance. Subsequent calls during connection
|
|
137
|
+
* return the same in-flight promise. */
|
|
138
|
+
connect(): Promise<void>;
|
|
139
|
+
private openSocket;
|
|
140
|
+
/** Close the socket and clear in-memory subscription state. Reserved
|
|
141
|
+
* listeners survive so callers can reconnect later via `connect()`. */
|
|
142
|
+
disconnect(): void;
|
|
143
|
+
subscribe(channel: string): Promise<SubscribeResult>;
|
|
144
|
+
/** Fire-and-forget. No ack from the server. */
|
|
145
|
+
unsubscribe(channel: string): void;
|
|
146
|
+
/** Publish via the Socket.IO transport. Subject to RLS INSERT policy
|
|
147
|
+
* on `realtime.messages` (disabled by default — the developer must
|
|
148
|
+
* add a policy before clients can publish). Returns immediately; any
|
|
149
|
+
* server rejection comes through the `error` reserved event. */
|
|
150
|
+
publish(channel: string, event: string, payload: Record<string, unknown>): void;
|
|
151
|
+
on(event: 'connect', cb: ConnectionListener): void;
|
|
152
|
+
on(event: 'disconnect', cb: DisconnectListener): void;
|
|
153
|
+
on(event: 'connect_error', cb: ConnectErrorListener): void;
|
|
154
|
+
on(event: 'error', cb: RealtimeListener<RealtimeErrorPayload>): void;
|
|
155
|
+
on<T = unknown>(event: string, cb: RealtimeListener<T>): void;
|
|
156
|
+
off(event: string, cb: (...args: any[]) => void): void;
|
|
157
|
+
private dispatch;
|
|
158
|
+
private emitReserved;
|
|
159
|
+
}
|
|
160
|
+
|
|
32
161
|
/**
|
|
33
162
|
* MITWAY-BaaS SDK types — only SDK-specific shapes live here.
|
|
34
163
|
* The `User` shape is inlined in `./lib/user` so this package has zero
|
|
@@ -89,6 +218,10 @@ interface MitwayBaasConfig {
|
|
|
89
218
|
* @default true
|
|
90
219
|
*/
|
|
91
220
|
autoRefreshToken?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* Realtime transport options. See `RealtimeOptions`.
|
|
223
|
+
*/
|
|
224
|
+
realtime?: RealtimeOptions;
|
|
92
225
|
}
|
|
93
226
|
/**
|
|
94
227
|
* Active user session in memory. Mirrors what the auth endpoints return.
|
|
@@ -146,27 +279,6 @@ declare class Logger {
|
|
|
146
279
|
logResponse(method: string, url: string, status: number, durationMs: number, body?: any): void;
|
|
147
280
|
}
|
|
148
281
|
|
|
149
|
-
/**
|
|
150
|
-
* Token Manager for the MITWAY-BaaS SDK.
|
|
151
|
-
*
|
|
152
|
-
* In-memory storage for the access token + user. Browser CSRF token lives
|
|
153
|
-
* in a cookie so the cookie-based refresh flow works across page reloads.
|
|
154
|
-
*/
|
|
155
|
-
|
|
156
|
-
declare class TokenManager {
|
|
157
|
-
private accessToken;
|
|
158
|
-
private user;
|
|
159
|
-
/** Fired when the access token changes (used by long-lived consumers). */
|
|
160
|
-
onTokenChange: (() => void) | null;
|
|
161
|
-
saveSession(session: AuthSession): void;
|
|
162
|
-
getSession(): AuthSession | null;
|
|
163
|
-
getAccessToken(): string | null;
|
|
164
|
-
setAccessToken(token: string): void;
|
|
165
|
-
getUser(): User | null;
|
|
166
|
-
setUser(user: User): void;
|
|
167
|
-
clearSession(): void;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
282
|
/**
|
|
171
283
|
* HttpClient with retry, timeout, abort signal composition, and automatic
|
|
172
284
|
* token refresh on 401 INVALID_TOKEN responses.
|
|
@@ -409,6 +521,7 @@ declare class MitwayBaasClient {
|
|
|
409
521
|
private tokenManager;
|
|
410
522
|
readonly auth: Auth;
|
|
411
523
|
readonly database: Database;
|
|
524
|
+
readonly realtime: Realtime;
|
|
412
525
|
constructor(config?: MitwayBaasConfig);
|
|
413
526
|
/**
|
|
414
527
|
* Escape hatch for callers that need to make custom requests against the
|
|
@@ -423,13 +536,13 @@ declare class MitwayBaasClient {
|
|
|
423
536
|
* Currently ships:
|
|
424
537
|
* - auth (signUp, signInWithPassword, signOut, refreshSession, getSession, getUser)
|
|
425
538
|
* - database (PostgREST-backed query builder via @supabase/postgrest-js)
|
|
539
|
+
* - realtime (Socket.IO transport: subscribe / unsubscribe / publish / on)
|
|
426
540
|
*
|
|
427
541
|
* Not yet included (no backend support):
|
|
428
542
|
* - storage
|
|
429
543
|
* - functions
|
|
430
544
|
* - email
|
|
431
545
|
* - ai
|
|
432
|
-
* - realtime
|
|
433
546
|
*
|
|
434
547
|
* @packageDocumentation
|
|
435
548
|
*/
|
|
@@ -449,4 +562,4 @@ declare class MitwayBaasClient {
|
|
|
449
562
|
*/
|
|
450
563
|
declare function createClient(config: MitwayBaasConfig): MitwayBaasClient;
|
|
451
564
|
|
|
452
|
-
export { type ApiError, Auth, type AuthRefreshResponse, type AuthResponse, type AuthResult, type AuthSession, Database, HttpClient, Logger, MitwayBaasClient, type MitwayBaasConfig, MitwayBaasError, type SignInRequest, type SignUpRequest, TokenManager, type User, createClient, MitwayBaasClient as default };
|
|
565
|
+
export { type ApiError, Auth, type AuthRefreshResponse, type AuthResponse, type AuthResult, type AuthSession, type ConnectErrorListener, type ConnectionListener, Database, type DisconnectListener, HttpClient, Logger, MitwayBaasClient, type MitwayBaasConfig, MitwayBaasError, Realtime, type RealtimeErrorPayload, type RealtimeListener, type RealtimeMessageMeta, type RealtimeOptions, type SignInRequest, type SignUpRequest, type SubscribeResult, TokenManager, type User, createClient, MitwayBaasClient as default };
|
package/dist/index.js
CHANGED
|
@@ -854,18 +854,239 @@ var Database = class {
|
|
|
854
854
|
}
|
|
855
855
|
};
|
|
856
856
|
|
|
857
|
+
// src/modules/realtime.ts
|
|
858
|
+
import { io } from "socket.io-client";
|
|
859
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
860
|
+
var Realtime = class {
|
|
861
|
+
socket = null;
|
|
862
|
+
baseUrl;
|
|
863
|
+
options;
|
|
864
|
+
anonKey;
|
|
865
|
+
tokenManager;
|
|
866
|
+
listeners = /* @__PURE__ */ new Map();
|
|
867
|
+
reserved = {
|
|
868
|
+
connect: /* @__PURE__ */ new Set(),
|
|
869
|
+
disconnect: /* @__PURE__ */ new Set(),
|
|
870
|
+
connect_error: /* @__PURE__ */ new Set(),
|
|
871
|
+
error: /* @__PURE__ */ new Set()
|
|
872
|
+
};
|
|
873
|
+
connecting = null;
|
|
874
|
+
subscribedChannels = /* @__PURE__ */ new Set();
|
|
875
|
+
constructor(baseUrl, tokenManager, anonKey, options = {}) {
|
|
876
|
+
this.baseUrl = baseUrl;
|
|
877
|
+
this.tokenManager = tokenManager;
|
|
878
|
+
this.anonKey = anonKey;
|
|
879
|
+
this.options = options;
|
|
880
|
+
}
|
|
881
|
+
// -----------------------------------------------------------------
|
|
882
|
+
// Connection lifecycle
|
|
883
|
+
// -----------------------------------------------------------------
|
|
884
|
+
get isConnected() {
|
|
885
|
+
return this.socket?.connected === true;
|
|
886
|
+
}
|
|
887
|
+
get socketId() {
|
|
888
|
+
return this.socket?.id;
|
|
889
|
+
}
|
|
890
|
+
/** Explicitly open the connection. Safe to call multiple times; only
|
|
891
|
+
* opens one socket per instance. Subsequent calls during connection
|
|
892
|
+
* return the same in-flight promise. */
|
|
893
|
+
connect() {
|
|
894
|
+
if (this.isConnected) {
|
|
895
|
+
return Promise.resolve();
|
|
896
|
+
}
|
|
897
|
+
if (this.connecting) {
|
|
898
|
+
return this.connecting;
|
|
899
|
+
}
|
|
900
|
+
this.connecting = this.openSocket();
|
|
901
|
+
return this.connecting;
|
|
902
|
+
}
|
|
903
|
+
openSocket() {
|
|
904
|
+
const token = this.tokenManager.getAccessToken() ?? this.anonKey;
|
|
905
|
+
if (!token) {
|
|
906
|
+
const err = new MitwayBaasError(
|
|
907
|
+
"Realtime requires an access token or anonKey",
|
|
908
|
+
401,
|
|
909
|
+
"AUTH_INVALID_API_KEY"
|
|
910
|
+
);
|
|
911
|
+
this.connecting = null;
|
|
912
|
+
return Promise.reject(err);
|
|
913
|
+
}
|
|
914
|
+
const timeoutMs = this.options.timeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
915
|
+
const socket = io(this.baseUrl, {
|
|
916
|
+
path: this.options.path,
|
|
917
|
+
transports: this.options.transports ?? ["websocket"],
|
|
918
|
+
auth: { token, ...this.options.extraAuth ?? {} },
|
|
919
|
+
reconnection: true,
|
|
920
|
+
timeout: timeoutMs
|
|
921
|
+
});
|
|
922
|
+
this.socket = socket;
|
|
923
|
+
socket.onAny((event, ...args) => this.dispatch(event, args));
|
|
924
|
+
socket.on("connect", () => this.emitReserved("connect"));
|
|
925
|
+
socket.on("disconnect", (reason) => this.emitReserved("disconnect", reason));
|
|
926
|
+
socket.on("connect_error", (err) => this.emitReserved("connect_error", err));
|
|
927
|
+
return new Promise((resolve, reject) => {
|
|
928
|
+
const timer = setTimeout(() => {
|
|
929
|
+
socket.off("connect", onConnect);
|
|
930
|
+
socket.off("connect_error", onConnectError);
|
|
931
|
+
reject(
|
|
932
|
+
new MitwayBaasError(
|
|
933
|
+
`Realtime connection timeout after ${timeoutMs}ms`,
|
|
934
|
+
408,
|
|
935
|
+
"CONNECTION_TIMEOUT"
|
|
936
|
+
)
|
|
937
|
+
);
|
|
938
|
+
this.connecting = null;
|
|
939
|
+
}, timeoutMs);
|
|
940
|
+
const clear = () => {
|
|
941
|
+
clearTimeout(timer);
|
|
942
|
+
socket.off("connect", onConnect);
|
|
943
|
+
socket.off("connect_error", onConnectError);
|
|
944
|
+
};
|
|
945
|
+
const onConnect = () => {
|
|
946
|
+
clear();
|
|
947
|
+
this.connecting = null;
|
|
948
|
+
resolve();
|
|
949
|
+
};
|
|
950
|
+
const onConnectError = (err) => {
|
|
951
|
+
clear();
|
|
952
|
+
this.connecting = null;
|
|
953
|
+
reject(
|
|
954
|
+
new MitwayBaasError(err.message, 0, "CONNECTION_FAILED")
|
|
955
|
+
);
|
|
956
|
+
};
|
|
957
|
+
socket.once("connect", onConnect);
|
|
958
|
+
socket.once("connect_error", onConnectError);
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
/** Close the socket and clear in-memory subscription state. Reserved
|
|
962
|
+
* listeners survive so callers can reconnect later via `connect()`. */
|
|
963
|
+
disconnect() {
|
|
964
|
+
if (!this.socket) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
this.socket.disconnect();
|
|
968
|
+
this.socket = null;
|
|
969
|
+
this.subscribedChannels.clear();
|
|
970
|
+
}
|
|
971
|
+
// -----------------------------------------------------------------
|
|
972
|
+
// Subscribe / Unsubscribe / Publish
|
|
973
|
+
// -----------------------------------------------------------------
|
|
974
|
+
async subscribe(channel) {
|
|
975
|
+
await this.connect();
|
|
976
|
+
const socket = this.socket;
|
|
977
|
+
if (!socket) {
|
|
978
|
+
return {
|
|
979
|
+
ok: false,
|
|
980
|
+
channel,
|
|
981
|
+
error: { code: "NOT_CONNECTED", message: "Socket is not connected" }
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
const result = await new Promise((resolve) => {
|
|
985
|
+
socket.emit("realtime:subscribe", { channel }, (ack) => {
|
|
986
|
+
resolve(ack);
|
|
987
|
+
});
|
|
988
|
+
});
|
|
989
|
+
if (result.ok) {
|
|
990
|
+
this.subscribedChannels.add(channel);
|
|
991
|
+
}
|
|
992
|
+
return result;
|
|
993
|
+
}
|
|
994
|
+
/** Fire-and-forget. No ack from the server. */
|
|
995
|
+
unsubscribe(channel) {
|
|
996
|
+
this.subscribedChannels.delete(channel);
|
|
997
|
+
this.socket?.emit("realtime:unsubscribe", { channel });
|
|
998
|
+
}
|
|
999
|
+
/** Publish via the Socket.IO transport. Subject to RLS INSERT policy
|
|
1000
|
+
* on `realtime.messages` (disabled by default — the developer must
|
|
1001
|
+
* add a policy before clients can publish). Returns immediately; any
|
|
1002
|
+
* server rejection comes through the `error` reserved event. */
|
|
1003
|
+
publish(channel, event, payload) {
|
|
1004
|
+
this.socket?.emit("realtime:publish", { channel, event, payload });
|
|
1005
|
+
}
|
|
1006
|
+
// TypeScript overload impl signature must be assignable from every
|
|
1007
|
+
// public overload. The public overloads take arg lists of different
|
|
1008
|
+
// shapes (ConnectionListener: 0 args, DisconnectListener: 1 string
|
|
1009
|
+
// arg, RealtimeListener: 2 args), so the implementation uses the
|
|
1010
|
+
// widest possible signature. This matches the pattern in socket.io
|
|
1011
|
+
// itself and is the standard TypeScript overload idiom.
|
|
1012
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1013
|
+
on(event, cb) {
|
|
1014
|
+
if (isReserved(event)) {
|
|
1015
|
+
this.reserved[event].add(cb);
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
if (!this.listeners.has(event)) {
|
|
1019
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
1020
|
+
}
|
|
1021
|
+
this.listeners.get(event).add(cb);
|
|
1022
|
+
}
|
|
1023
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1024
|
+
off(event, cb) {
|
|
1025
|
+
if (isReserved(event)) {
|
|
1026
|
+
this.reserved[event].delete(cb);
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
this.listeners.get(event)?.delete(cb);
|
|
1030
|
+
}
|
|
1031
|
+
// -----------------------------------------------------------------
|
|
1032
|
+
// Internals
|
|
1033
|
+
// -----------------------------------------------------------------
|
|
1034
|
+
dispatch(event, args) {
|
|
1035
|
+
if (isReserved(event)) {
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
if (event === "realtime:error") {
|
|
1039
|
+
const err = args[0] ?? {};
|
|
1040
|
+
this.reserved.error.forEach(
|
|
1041
|
+
(cb) => cb(err, {
|
|
1042
|
+
message_id: "",
|
|
1043
|
+
sender_type: "system",
|
|
1044
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1045
|
+
})
|
|
1046
|
+
);
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
const set = this.listeners.get(event);
|
|
1050
|
+
if (!set || set.size === 0) {
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
const envelope = args[0] ?? {};
|
|
1054
|
+
const { meta, ...payload } = envelope;
|
|
1055
|
+
const metaOrStub = meta ?? {
|
|
1056
|
+
message_id: "",
|
|
1057
|
+
sender_type: "system",
|
|
1058
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1059
|
+
};
|
|
1060
|
+
set.forEach((cb) => cb(payload, metaOrStub));
|
|
1061
|
+
}
|
|
1062
|
+
emitReserved(event, ...args) {
|
|
1063
|
+
const set = this.reserved[event];
|
|
1064
|
+
set.forEach((cb) => cb(...args));
|
|
1065
|
+
}
|
|
1066
|
+
};
|
|
1067
|
+
function isReserved(event) {
|
|
1068
|
+
return event === "connect" || event === "disconnect" || event === "connect_error" || event === "error";
|
|
1069
|
+
}
|
|
1070
|
+
|
|
857
1071
|
// src/client.ts
|
|
858
1072
|
var MitwayBaasClient = class {
|
|
859
1073
|
http;
|
|
860
1074
|
tokenManager;
|
|
861
1075
|
auth;
|
|
862
1076
|
database;
|
|
1077
|
+
realtime;
|
|
863
1078
|
constructor(config = {}) {
|
|
864
1079
|
const logger = new Logger(config.debug);
|
|
865
1080
|
this.tokenManager = new TokenManager();
|
|
866
1081
|
this.http = new HttpClient(config, this.tokenManager, logger);
|
|
867
1082
|
this.auth = new Auth(this.http, this.tokenManager);
|
|
868
1083
|
this.database = new Database(this.http, this.tokenManager, config.anonKey);
|
|
1084
|
+
this.realtime = new Realtime(
|
|
1085
|
+
this.http.baseUrl,
|
|
1086
|
+
this.tokenManager,
|
|
1087
|
+
config.anonKey,
|
|
1088
|
+
config.realtime
|
|
1089
|
+
);
|
|
869
1090
|
}
|
|
870
1091
|
/**
|
|
871
1092
|
* Escape hatch for callers that need to make custom requests against the
|
|
@@ -888,6 +1109,7 @@ export {
|
|
|
888
1109
|
Logger,
|
|
889
1110
|
MitwayBaasClient,
|
|
890
1111
|
MitwayBaasError,
|
|
1112
|
+
Realtime,
|
|
891
1113
|
TokenManager,
|
|
892
1114
|
createClient,
|
|
893
1115
|
index_default as default
|