@mitway/sdk 0.2.4 → 0.3.0
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 +44 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -22
- package/dist/index.d.ts +84 -22
- package/dist/index.js +44 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -70,6 +70,7 @@ declare class TokenManager {
|
|
|
70
70
|
*/
|
|
71
71
|
|
|
72
72
|
type PostgresChangesEventSelector = 'INSERT' | 'UPDATE' | 'DELETE' | '*';
|
|
73
|
+
/** Filter for any event (including the `*` catch-all). */
|
|
73
74
|
interface PostgresChangesFilter {
|
|
74
75
|
event: PostgresChangesEventSelector;
|
|
75
76
|
schema?: string;
|
|
@@ -77,8 +78,8 @@ interface PostgresChangesFilter {
|
|
|
77
78
|
/** PostgREST-style filter: `column=op.value` or `column=in.(a,b,c)`. */
|
|
78
79
|
filter?: string;
|
|
79
80
|
}
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
/** Common shape shared by every postgres_changes payload variant. */
|
|
82
|
+
interface PostgresChangesPayloadBase {
|
|
82
83
|
schema: string;
|
|
83
84
|
table: string;
|
|
84
85
|
commit_timestamp: string;
|
|
@@ -86,10 +87,33 @@ interface PostgresChangesPayload<T = Record<string, unknown>> {
|
|
|
86
87
|
name: string;
|
|
87
88
|
type: string;
|
|
88
89
|
}>;
|
|
89
|
-
record?: T;
|
|
90
|
-
old_record?: T;
|
|
91
90
|
errors?: string[];
|
|
92
91
|
}
|
|
92
|
+
/** INSERT: the new row is in `new`. `old` is kept as an empty object so
|
|
93
|
+
* code that accesses both fields never needs optional chaining. */
|
|
94
|
+
interface PostgresChangesInsertPayload<T = Record<string, unknown>> extends PostgresChangesPayloadBase {
|
|
95
|
+
eventType: 'INSERT';
|
|
96
|
+
new: T;
|
|
97
|
+
old: Record<string, never>;
|
|
98
|
+
}
|
|
99
|
+
/** UPDATE: both `new` and `old` are populated. `old` is `Partial<T>`
|
|
100
|
+
* because RLS / REPLICA IDENTITY may strip columns the subscriber can't
|
|
101
|
+
* see. */
|
|
102
|
+
interface PostgresChangesUpdatePayload<T = Record<string, unknown>> extends PostgresChangesPayloadBase {
|
|
103
|
+
eventType: 'UPDATE';
|
|
104
|
+
new: T;
|
|
105
|
+
old: Partial<T>;
|
|
106
|
+
}
|
|
107
|
+
/** DELETE: the deleted row is in `old`. On RLS-enabled tables only
|
|
108
|
+
* primary-key columns are populated. `new` is always an empty object. */
|
|
109
|
+
interface PostgresChangesDeletePayload<T = Record<string, unknown>> extends PostgresChangesPayloadBase {
|
|
110
|
+
eventType: 'DELETE';
|
|
111
|
+
new: Record<string, never>;
|
|
112
|
+
old: Partial<T>;
|
|
113
|
+
}
|
|
114
|
+
/** Discriminated union — what the `'*'` overload of `on('postgres_changes',
|
|
115
|
+
* ...)` passes to the callback. */
|
|
116
|
+
type PostgresChangesPayload<T = Record<string, unknown>> = PostgresChangesInsertPayload<T> | PostgresChangesUpdatePayload<T> | PostgresChangesDeletePayload<T>;
|
|
93
117
|
interface BroadcastFilter {
|
|
94
118
|
event: string;
|
|
95
119
|
}
|
|
@@ -140,11 +164,6 @@ interface ChannelOptions {
|
|
|
140
164
|
* requested on a private channel. Default: `false` (open topic). */
|
|
141
165
|
private?: boolean;
|
|
142
166
|
broadcast?: {
|
|
143
|
-
/** When true, `channel.send(...)` resolves only after the server
|
|
144
|
-
* ack'd the publish — useful if the app wants to know the
|
|
145
|
-
* message_id assigned by the server. Default: `false`
|
|
146
|
-
* (fire-and-forget). */
|
|
147
|
-
ack?: boolean;
|
|
148
167
|
/** When `false`, the sending socket is excluded from the fan-out.
|
|
149
168
|
* Default: `true` (sender also receives its own broadcasts). */
|
|
150
169
|
self?: boolean;
|
|
@@ -158,9 +177,13 @@ interface ChannelOptions {
|
|
|
158
177
|
};
|
|
159
178
|
}
|
|
160
179
|
type ChannelStatus = 'SUBSCRIBED' | 'CHANNEL_ERROR' | 'TIMED_OUT' | 'CLOSED';
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
180
|
+
/** Callback invoked for every channel status transition. The second
|
|
181
|
+
* argument is a standard `Error` (so consumers can annotate it as
|
|
182
|
+
* `err: Error` out of the box) with a non-standard `.code` string
|
|
183
|
+
* attached for programmatic discrimination (`SUBSCRIBE_FAILED`,
|
|
184
|
+
* `CONNECT_FAILED`, `REJOIN_FAILED`, …). */
|
|
185
|
+
type ChannelStatusCallback = (status: ChannelStatus, error?: Error & {
|
|
186
|
+
code?: string;
|
|
164
187
|
}) => void;
|
|
165
188
|
interface RealtimeOptions {
|
|
166
189
|
path?: string;
|
|
@@ -168,9 +191,10 @@ interface RealtimeOptions {
|
|
|
168
191
|
timeoutMs?: number;
|
|
169
192
|
extraAuth?: Record<string, string>;
|
|
170
193
|
}
|
|
171
|
-
type PostgresChangesCallback<T = Record<string, unknown>> = (payload: PostgresChangesPayload<T>) => void;
|
|
172
194
|
type BroadcastCallback<T = Record<string, unknown>> = (payload: BroadcastPayload<T>) => void;
|
|
173
|
-
type
|
|
195
|
+
type PresenceSyncCallback = () => void;
|
|
196
|
+
type PresenceJoinCallback<T = Record<string, unknown>> = (payload: PresenceJoinPayload<T>) => void;
|
|
197
|
+
type PresenceLeaveCallback<T = Record<string, unknown>> = (payload: PresenceLeavePayload<T>) => void;
|
|
174
198
|
declare class RealtimeChannel {
|
|
175
199
|
readonly topic: string;
|
|
176
200
|
private readonly realtime;
|
|
@@ -204,9 +228,40 @@ declare class RealtimeChannel {
|
|
|
204
228
|
* statusCallback (from the original subscribe()) fires again with
|
|
205
229
|
* 'SUBSCRIBED' or 'CHANNEL_ERROR' so the app can reflect state. */
|
|
206
230
|
_rejoinAfterReconnect(): Promise<void>;
|
|
207
|
-
on<T = Record<string, unknown>>(type: 'postgres_changes', filter:
|
|
231
|
+
on<T = Record<string, unknown>>(type: 'postgres_changes', filter: {
|
|
232
|
+
event: 'INSERT';
|
|
233
|
+
schema?: string;
|
|
234
|
+
table: string;
|
|
235
|
+
filter?: string;
|
|
236
|
+
}, callback: (payload: PostgresChangesInsertPayload<T>) => void): this;
|
|
237
|
+
on<T = Record<string, unknown>>(type: 'postgres_changes', filter: {
|
|
238
|
+
event: 'UPDATE';
|
|
239
|
+
schema?: string;
|
|
240
|
+
table: string;
|
|
241
|
+
filter?: string;
|
|
242
|
+
}, callback: (payload: PostgresChangesUpdatePayload<T>) => void): this;
|
|
243
|
+
on<T = Record<string, unknown>>(type: 'postgres_changes', filter: {
|
|
244
|
+
event: 'DELETE';
|
|
245
|
+
schema?: string;
|
|
246
|
+
table: string;
|
|
247
|
+
filter?: string;
|
|
248
|
+
}, callback: (payload: PostgresChangesDeletePayload<T>) => void): this;
|
|
249
|
+
on<T = Record<string, unknown>>(type: 'postgres_changes', filter: {
|
|
250
|
+
event: '*';
|
|
251
|
+
schema?: string;
|
|
252
|
+
table: string;
|
|
253
|
+
filter?: string;
|
|
254
|
+
}, callback: (payload: PostgresChangesPayload<T>) => void): this;
|
|
208
255
|
on<T = Record<string, unknown>>(type: 'broadcast', filter: BroadcastFilter, callback: BroadcastCallback<T>): this;
|
|
209
|
-
on
|
|
256
|
+
on(type: 'presence', filter: {
|
|
257
|
+
event: 'sync';
|
|
258
|
+
}, callback: PresenceSyncCallback): this;
|
|
259
|
+
on<T = Record<string, unknown>>(type: 'presence', filter: {
|
|
260
|
+
event: 'join';
|
|
261
|
+
}, callback: PresenceJoinCallback<T>): this;
|
|
262
|
+
on<T = Record<string, unknown>>(type: 'presence', filter: {
|
|
263
|
+
event: 'leave';
|
|
264
|
+
}, callback: PresenceLeaveCallback<T>): this;
|
|
210
265
|
/**
|
|
211
266
|
* Register or refresh this client's presence entry on the channel. Safe
|
|
212
267
|
* to call many times — state replaces (not merges). Starts a heartbeat
|
|
@@ -248,21 +303,27 @@ declare class RealtimeChannel {
|
|
|
248
303
|
* events, write to your own application table and enable
|
|
249
304
|
* `postgres_changes` on it; the SDK will surface the INSERT as a
|
|
250
305
|
* `postgres_changes` event without a separate channel.send call.
|
|
306
|
+
*
|
|
307
|
+
* The returned promise always resolves with the server ack, so callers
|
|
308
|
+
* can `await channel.send(...)` to confirm delivery + get the server-
|
|
309
|
+
* assigned `message_id`. There's no performance cost — Socket.IO piggy-
|
|
310
|
+
* backs the ack on the same frame. Callers that don't need it just
|
|
311
|
+
* don't await.
|
|
251
312
|
*/
|
|
252
313
|
send<T extends Record<string, unknown>>(args: {
|
|
253
314
|
type: 'broadcast';
|
|
254
315
|
event: string;
|
|
255
316
|
payload: T;
|
|
256
317
|
}): Promise<{
|
|
257
|
-
|
|
318
|
+
status: 'ok';
|
|
258
319
|
message_id: string;
|
|
259
320
|
} | {
|
|
260
|
-
|
|
321
|
+
status: 'error';
|
|
261
322
|
error: {
|
|
262
323
|
code: string;
|
|
263
324
|
message: string;
|
|
264
325
|
};
|
|
265
|
-
}
|
|
326
|
+
}>;
|
|
266
327
|
/**
|
|
267
328
|
* Replay SQL-originated broadcasts on this topic since the given
|
|
268
329
|
* timestamp. Delivered only to this socket (same envelope format as
|
|
@@ -301,13 +362,14 @@ declare class Realtime {
|
|
|
301
362
|
* The optional `opts` argument lets the caller configure the channel:
|
|
302
363
|
* * `config.private` — enable subscribe-side authorization against
|
|
303
364
|
* `realtime.authorize_subscribe(...)` on the tenant DB.
|
|
304
|
-
* * `config.broadcast.ack` — `channel.send()` resolves with the
|
|
305
|
-
* server's ack (message_id) instead of fire-and-forget.
|
|
306
365
|
* * `config.broadcast.self` — `false` excludes the sender from the
|
|
307
366
|
* fan-out (defaults to `true`).
|
|
308
367
|
* * `config.presence.key` — stable presence key to group multiple
|
|
309
368
|
* tabs of the same user under one entry.
|
|
310
369
|
*
|
|
370
|
+
* `channel.send()` always resolves with the server ack (see its own
|
|
371
|
+
* docstring); there is no separate opt-in needed.
|
|
372
|
+
*
|
|
311
373
|
* Options are locked in when the channel is first created; subsequent
|
|
312
374
|
* `.channel('same')` calls with different opts are ignored. Pass a
|
|
313
375
|
* different topic to get a different-configured channel.
|
|
@@ -729,4 +791,4 @@ declare class MitwayBaasClient {
|
|
|
729
791
|
*/
|
|
730
792
|
declare function createClient(config: MitwayBaasConfig): MitwayBaasClient;
|
|
731
793
|
|
|
732
|
-
export { type ApiError, Auth, type AuthRefreshResponse, type AuthResponse, type AuthResult, type AuthSession, type BroadcastFilter, type BroadcastPayload, type ChannelOptions, type ChannelStatus, type ChannelStatusCallback, Database, HttpClient, Logger, MitwayBaasClient, type MitwayBaasConfig, MitwayBaasError, type PostgresChangesEventSelector, type PostgresChangesFilter, type PostgresChangesPayload, type PresenceEventSelector, type PresenceFilter, type PresenceJoinPayload, type PresenceLeavePayload, type PresencePayload, type PresenceState, type PresenceSyncPayload, Realtime, RealtimeChannel, type RealtimeMessageMeta, type RealtimeOptions, type SignInRequest, type SignUpRequest, TokenManager, type User, createClient, MitwayBaasClient as default };
|
|
794
|
+
export { type ApiError, Auth, type AuthRefreshResponse, type AuthResponse, type AuthResult, type AuthSession, type BroadcastFilter, type BroadcastPayload, type ChannelOptions, type ChannelStatus, type ChannelStatusCallback, Database, HttpClient, Logger, MitwayBaasClient, type MitwayBaasConfig, MitwayBaasError, type PostgresChangesDeletePayload, type PostgresChangesEventSelector, type PostgresChangesFilter, type PostgresChangesInsertPayload, type PostgresChangesPayload, type PostgresChangesUpdatePayload, type PresenceEventSelector, type PresenceFilter, type PresenceJoinPayload, type PresenceLeavePayload, type PresencePayload, type PresenceState, type PresenceSyncPayload, Realtime, RealtimeChannel, type RealtimeMessageMeta, type RealtimeOptions, type SignInRequest, type SignUpRequest, TokenManager, type User, createClient, MitwayBaasClient as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,7 @@ declare class TokenManager {
|
|
|
70
70
|
*/
|
|
71
71
|
|
|
72
72
|
type PostgresChangesEventSelector = 'INSERT' | 'UPDATE' | 'DELETE' | '*';
|
|
73
|
+
/** Filter for any event (including the `*` catch-all). */
|
|
73
74
|
interface PostgresChangesFilter {
|
|
74
75
|
event: PostgresChangesEventSelector;
|
|
75
76
|
schema?: string;
|
|
@@ -77,8 +78,8 @@ interface PostgresChangesFilter {
|
|
|
77
78
|
/** PostgREST-style filter: `column=op.value` or `column=in.(a,b,c)`. */
|
|
78
79
|
filter?: string;
|
|
79
80
|
}
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
/** Common shape shared by every postgres_changes payload variant. */
|
|
82
|
+
interface PostgresChangesPayloadBase {
|
|
82
83
|
schema: string;
|
|
83
84
|
table: string;
|
|
84
85
|
commit_timestamp: string;
|
|
@@ -86,10 +87,33 @@ interface PostgresChangesPayload<T = Record<string, unknown>> {
|
|
|
86
87
|
name: string;
|
|
87
88
|
type: string;
|
|
88
89
|
}>;
|
|
89
|
-
record?: T;
|
|
90
|
-
old_record?: T;
|
|
91
90
|
errors?: string[];
|
|
92
91
|
}
|
|
92
|
+
/** INSERT: the new row is in `new`. `old` is kept as an empty object so
|
|
93
|
+
* code that accesses both fields never needs optional chaining. */
|
|
94
|
+
interface PostgresChangesInsertPayload<T = Record<string, unknown>> extends PostgresChangesPayloadBase {
|
|
95
|
+
eventType: 'INSERT';
|
|
96
|
+
new: T;
|
|
97
|
+
old: Record<string, never>;
|
|
98
|
+
}
|
|
99
|
+
/** UPDATE: both `new` and `old` are populated. `old` is `Partial<T>`
|
|
100
|
+
* because RLS / REPLICA IDENTITY may strip columns the subscriber can't
|
|
101
|
+
* see. */
|
|
102
|
+
interface PostgresChangesUpdatePayload<T = Record<string, unknown>> extends PostgresChangesPayloadBase {
|
|
103
|
+
eventType: 'UPDATE';
|
|
104
|
+
new: T;
|
|
105
|
+
old: Partial<T>;
|
|
106
|
+
}
|
|
107
|
+
/** DELETE: the deleted row is in `old`. On RLS-enabled tables only
|
|
108
|
+
* primary-key columns are populated. `new` is always an empty object. */
|
|
109
|
+
interface PostgresChangesDeletePayload<T = Record<string, unknown>> extends PostgresChangesPayloadBase {
|
|
110
|
+
eventType: 'DELETE';
|
|
111
|
+
new: Record<string, never>;
|
|
112
|
+
old: Partial<T>;
|
|
113
|
+
}
|
|
114
|
+
/** Discriminated union — what the `'*'` overload of `on('postgres_changes',
|
|
115
|
+
* ...)` passes to the callback. */
|
|
116
|
+
type PostgresChangesPayload<T = Record<string, unknown>> = PostgresChangesInsertPayload<T> | PostgresChangesUpdatePayload<T> | PostgresChangesDeletePayload<T>;
|
|
93
117
|
interface BroadcastFilter {
|
|
94
118
|
event: string;
|
|
95
119
|
}
|
|
@@ -140,11 +164,6 @@ interface ChannelOptions {
|
|
|
140
164
|
* requested on a private channel. Default: `false` (open topic). */
|
|
141
165
|
private?: boolean;
|
|
142
166
|
broadcast?: {
|
|
143
|
-
/** When true, `channel.send(...)` resolves only after the server
|
|
144
|
-
* ack'd the publish — useful if the app wants to know the
|
|
145
|
-
* message_id assigned by the server. Default: `false`
|
|
146
|
-
* (fire-and-forget). */
|
|
147
|
-
ack?: boolean;
|
|
148
167
|
/** When `false`, the sending socket is excluded from the fan-out.
|
|
149
168
|
* Default: `true` (sender also receives its own broadcasts). */
|
|
150
169
|
self?: boolean;
|
|
@@ -158,9 +177,13 @@ interface ChannelOptions {
|
|
|
158
177
|
};
|
|
159
178
|
}
|
|
160
179
|
type ChannelStatus = 'SUBSCRIBED' | 'CHANNEL_ERROR' | 'TIMED_OUT' | 'CLOSED';
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
180
|
+
/** Callback invoked for every channel status transition. The second
|
|
181
|
+
* argument is a standard `Error` (so consumers can annotate it as
|
|
182
|
+
* `err: Error` out of the box) with a non-standard `.code` string
|
|
183
|
+
* attached for programmatic discrimination (`SUBSCRIBE_FAILED`,
|
|
184
|
+
* `CONNECT_FAILED`, `REJOIN_FAILED`, …). */
|
|
185
|
+
type ChannelStatusCallback = (status: ChannelStatus, error?: Error & {
|
|
186
|
+
code?: string;
|
|
164
187
|
}) => void;
|
|
165
188
|
interface RealtimeOptions {
|
|
166
189
|
path?: string;
|
|
@@ -168,9 +191,10 @@ interface RealtimeOptions {
|
|
|
168
191
|
timeoutMs?: number;
|
|
169
192
|
extraAuth?: Record<string, string>;
|
|
170
193
|
}
|
|
171
|
-
type PostgresChangesCallback<T = Record<string, unknown>> = (payload: PostgresChangesPayload<T>) => void;
|
|
172
194
|
type BroadcastCallback<T = Record<string, unknown>> = (payload: BroadcastPayload<T>) => void;
|
|
173
|
-
type
|
|
195
|
+
type PresenceSyncCallback = () => void;
|
|
196
|
+
type PresenceJoinCallback<T = Record<string, unknown>> = (payload: PresenceJoinPayload<T>) => void;
|
|
197
|
+
type PresenceLeaveCallback<T = Record<string, unknown>> = (payload: PresenceLeavePayload<T>) => void;
|
|
174
198
|
declare class RealtimeChannel {
|
|
175
199
|
readonly topic: string;
|
|
176
200
|
private readonly realtime;
|
|
@@ -204,9 +228,40 @@ declare class RealtimeChannel {
|
|
|
204
228
|
* statusCallback (from the original subscribe()) fires again with
|
|
205
229
|
* 'SUBSCRIBED' or 'CHANNEL_ERROR' so the app can reflect state. */
|
|
206
230
|
_rejoinAfterReconnect(): Promise<void>;
|
|
207
|
-
on<T = Record<string, unknown>>(type: 'postgres_changes', filter:
|
|
231
|
+
on<T = Record<string, unknown>>(type: 'postgres_changes', filter: {
|
|
232
|
+
event: 'INSERT';
|
|
233
|
+
schema?: string;
|
|
234
|
+
table: string;
|
|
235
|
+
filter?: string;
|
|
236
|
+
}, callback: (payload: PostgresChangesInsertPayload<T>) => void): this;
|
|
237
|
+
on<T = Record<string, unknown>>(type: 'postgres_changes', filter: {
|
|
238
|
+
event: 'UPDATE';
|
|
239
|
+
schema?: string;
|
|
240
|
+
table: string;
|
|
241
|
+
filter?: string;
|
|
242
|
+
}, callback: (payload: PostgresChangesUpdatePayload<T>) => void): this;
|
|
243
|
+
on<T = Record<string, unknown>>(type: 'postgres_changes', filter: {
|
|
244
|
+
event: 'DELETE';
|
|
245
|
+
schema?: string;
|
|
246
|
+
table: string;
|
|
247
|
+
filter?: string;
|
|
248
|
+
}, callback: (payload: PostgresChangesDeletePayload<T>) => void): this;
|
|
249
|
+
on<T = Record<string, unknown>>(type: 'postgres_changes', filter: {
|
|
250
|
+
event: '*';
|
|
251
|
+
schema?: string;
|
|
252
|
+
table: string;
|
|
253
|
+
filter?: string;
|
|
254
|
+
}, callback: (payload: PostgresChangesPayload<T>) => void): this;
|
|
208
255
|
on<T = Record<string, unknown>>(type: 'broadcast', filter: BroadcastFilter, callback: BroadcastCallback<T>): this;
|
|
209
|
-
on
|
|
256
|
+
on(type: 'presence', filter: {
|
|
257
|
+
event: 'sync';
|
|
258
|
+
}, callback: PresenceSyncCallback): this;
|
|
259
|
+
on<T = Record<string, unknown>>(type: 'presence', filter: {
|
|
260
|
+
event: 'join';
|
|
261
|
+
}, callback: PresenceJoinCallback<T>): this;
|
|
262
|
+
on<T = Record<string, unknown>>(type: 'presence', filter: {
|
|
263
|
+
event: 'leave';
|
|
264
|
+
}, callback: PresenceLeaveCallback<T>): this;
|
|
210
265
|
/**
|
|
211
266
|
* Register or refresh this client's presence entry on the channel. Safe
|
|
212
267
|
* to call many times — state replaces (not merges). Starts a heartbeat
|
|
@@ -248,21 +303,27 @@ declare class RealtimeChannel {
|
|
|
248
303
|
* events, write to your own application table and enable
|
|
249
304
|
* `postgres_changes` on it; the SDK will surface the INSERT as a
|
|
250
305
|
* `postgres_changes` event without a separate channel.send call.
|
|
306
|
+
*
|
|
307
|
+
* The returned promise always resolves with the server ack, so callers
|
|
308
|
+
* can `await channel.send(...)` to confirm delivery + get the server-
|
|
309
|
+
* assigned `message_id`. There's no performance cost — Socket.IO piggy-
|
|
310
|
+
* backs the ack on the same frame. Callers that don't need it just
|
|
311
|
+
* don't await.
|
|
251
312
|
*/
|
|
252
313
|
send<T extends Record<string, unknown>>(args: {
|
|
253
314
|
type: 'broadcast';
|
|
254
315
|
event: string;
|
|
255
316
|
payload: T;
|
|
256
317
|
}): Promise<{
|
|
257
|
-
|
|
318
|
+
status: 'ok';
|
|
258
319
|
message_id: string;
|
|
259
320
|
} | {
|
|
260
|
-
|
|
321
|
+
status: 'error';
|
|
261
322
|
error: {
|
|
262
323
|
code: string;
|
|
263
324
|
message: string;
|
|
264
325
|
};
|
|
265
|
-
}
|
|
326
|
+
}>;
|
|
266
327
|
/**
|
|
267
328
|
* Replay SQL-originated broadcasts on this topic since the given
|
|
268
329
|
* timestamp. Delivered only to this socket (same envelope format as
|
|
@@ -301,13 +362,14 @@ declare class Realtime {
|
|
|
301
362
|
* The optional `opts` argument lets the caller configure the channel:
|
|
302
363
|
* * `config.private` — enable subscribe-side authorization against
|
|
303
364
|
* `realtime.authorize_subscribe(...)` on the tenant DB.
|
|
304
|
-
* * `config.broadcast.ack` — `channel.send()` resolves with the
|
|
305
|
-
* server's ack (message_id) instead of fire-and-forget.
|
|
306
365
|
* * `config.broadcast.self` — `false` excludes the sender from the
|
|
307
366
|
* fan-out (defaults to `true`).
|
|
308
367
|
* * `config.presence.key` — stable presence key to group multiple
|
|
309
368
|
* tabs of the same user under one entry.
|
|
310
369
|
*
|
|
370
|
+
* `channel.send()` always resolves with the server ack (see its own
|
|
371
|
+
* docstring); there is no separate opt-in needed.
|
|
372
|
+
*
|
|
311
373
|
* Options are locked in when the channel is first created; subsequent
|
|
312
374
|
* `.channel('same')` calls with different opts are ignored. Pass a
|
|
313
375
|
* different topic to get a different-configured channel.
|
|
@@ -729,4 +791,4 @@ declare class MitwayBaasClient {
|
|
|
729
791
|
*/
|
|
730
792
|
declare function createClient(config: MitwayBaasConfig): MitwayBaasClient;
|
|
731
793
|
|
|
732
|
-
export { type ApiError, Auth, type AuthRefreshResponse, type AuthResponse, type AuthResult, type AuthSession, type BroadcastFilter, type BroadcastPayload, type ChannelOptions, type ChannelStatus, type ChannelStatusCallback, Database, HttpClient, Logger, MitwayBaasClient, type MitwayBaasConfig, MitwayBaasError, type PostgresChangesEventSelector, type PostgresChangesFilter, type PostgresChangesPayload, type PresenceEventSelector, type PresenceFilter, type PresenceJoinPayload, type PresenceLeavePayload, type PresencePayload, type PresenceState, type PresenceSyncPayload, Realtime, RealtimeChannel, type RealtimeMessageMeta, type RealtimeOptions, type SignInRequest, type SignUpRequest, TokenManager, type User, createClient, MitwayBaasClient as default };
|
|
794
|
+
export { type ApiError, Auth, type AuthRefreshResponse, type AuthResponse, type AuthResult, type AuthSession, type BroadcastFilter, type BroadcastPayload, type ChannelOptions, type ChannelStatus, type ChannelStatusCallback, Database, HttpClient, Logger, MitwayBaasClient, type MitwayBaasConfig, MitwayBaasError, type PostgresChangesDeletePayload, type PostgresChangesEventSelector, type PostgresChangesFilter, type PostgresChangesInsertPayload, type PostgresChangesPayload, type PostgresChangesUpdatePayload, type PresenceEventSelector, type PresenceFilter, type PresenceJoinPayload, type PresenceLeavePayload, type PresencePayload, type PresenceState, type PresenceSyncPayload, Realtime, RealtimeChannel, type RealtimeMessageMeta, type RealtimeOptions, type SignInRequest, type SignUpRequest, TokenManager, type User, createClient, MitwayBaasClient as default };
|
package/dist/index.js
CHANGED
|
@@ -857,6 +857,11 @@ var Database = class {
|
|
|
857
857
|
// src/modules/realtime.ts
|
|
858
858
|
import { io } from "socket.io-client";
|
|
859
859
|
var PRESENCE_HEARTBEAT_MS = 2e4;
|
|
860
|
+
function makeChannelError(code, message) {
|
|
861
|
+
const err = new Error(message);
|
|
862
|
+
err.code = code;
|
|
863
|
+
return err;
|
|
864
|
+
}
|
|
860
865
|
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
861
866
|
var RealtimeChannel = class {
|
|
862
867
|
constructor(topic, realtime, options = {}) {
|
|
@@ -927,12 +932,19 @@ var RealtimeChannel = class {
|
|
|
927
932
|
this.statusCallback?.("SUBSCRIBED");
|
|
928
933
|
} catch (err) {
|
|
929
934
|
this.state = "errored";
|
|
930
|
-
this.statusCallback?.(
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
935
|
+
this.statusCallback?.(
|
|
936
|
+
"CHANNEL_ERROR",
|
|
937
|
+
makeChannelError("REJOIN_FAILED", err instanceof Error ? err.message : String(err))
|
|
938
|
+
);
|
|
934
939
|
}
|
|
935
940
|
}
|
|
941
|
+
// ── implementation signature (not in public type surface).
|
|
942
|
+
// The callback type is intentionally broad: each overload above pins a
|
|
943
|
+
// specific payload shape, but TypeScript overload resolution needs the
|
|
944
|
+
// implementation to accept the union of every narrow callback without
|
|
945
|
+
// the contravariance conflict (TS2394). `any` is the standard escape
|
|
946
|
+
// hatch for this exact pattern and is confined to this one line — the
|
|
947
|
+
// public surface users see is strictly typed via the overloads.
|
|
936
948
|
on(type, filter, callback) {
|
|
937
949
|
if (type === "postgres_changes") {
|
|
938
950
|
this.bindings.push({
|
|
@@ -1034,18 +1046,18 @@ var RealtimeChannel = class {
|
|
|
1034
1046
|
} catch (err) {
|
|
1035
1047
|
this.state = "errored";
|
|
1036
1048
|
const message = err instanceof Error ? err.message : String(err);
|
|
1037
|
-
this.statusCallback?.(
|
|
1038
|
-
|
|
1039
|
-
message
|
|
1040
|
-
|
|
1049
|
+
this.statusCallback?.(
|
|
1050
|
+
"CHANNEL_ERROR",
|
|
1051
|
+
makeChannelError("SUBSCRIBE_FAILED", message)
|
|
1052
|
+
);
|
|
1041
1053
|
}
|
|
1042
1054
|
},
|
|
1043
1055
|
(err) => {
|
|
1044
1056
|
this.state = "errored";
|
|
1045
|
-
this.statusCallback?.(
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1057
|
+
this.statusCallback?.(
|
|
1058
|
+
"CHANNEL_ERROR",
|
|
1059
|
+
makeChannelError("CONNECT_FAILED", err.message)
|
|
1060
|
+
);
|
|
1049
1061
|
}
|
|
1050
1062
|
);
|
|
1051
1063
|
return this;
|
|
@@ -1098,6 +1110,12 @@ var RealtimeChannel = class {
|
|
|
1098
1110
|
* events, write to your own application table and enable
|
|
1099
1111
|
* `postgres_changes` on it; the SDK will surface the INSERT as a
|
|
1100
1112
|
* `postgres_changes` event without a separate channel.send call.
|
|
1113
|
+
*
|
|
1114
|
+
* The returned promise always resolves with the server ack, so callers
|
|
1115
|
+
* can `await channel.send(...)` to confirm delivery + get the server-
|
|
1116
|
+
* assigned `message_id`. There's no performance cost — Socket.IO piggy-
|
|
1117
|
+
* backs the ack on the same frame. Callers that don't need it just
|
|
1118
|
+
* don't await.
|
|
1101
1119
|
*/
|
|
1102
1120
|
async send(args) {
|
|
1103
1121
|
if (args.type !== "broadcast") {
|
|
@@ -1124,9 +1142,7 @@ var RealtimeChannel = class {
|
|
|
1124
1142
|
if (!socket) {
|
|
1125
1143
|
throw new MitwayBaasError("Socket not connected", 503, "NOT_CONNECTED");
|
|
1126
1144
|
}
|
|
1127
|
-
const
|
|
1128
|
-
const wantAck = broadcastCfg?.ack === true;
|
|
1129
|
-
const self = broadcastCfg?.self;
|
|
1145
|
+
const self = this.options.config?.broadcast?.self;
|
|
1130
1146
|
const wirePayload = {
|
|
1131
1147
|
channel: this.topic,
|
|
1132
1148
|
event: args.event,
|
|
@@ -1135,10 +1151,6 @@ var RealtimeChannel = class {
|
|
|
1135
1151
|
if (self === false) {
|
|
1136
1152
|
wirePayload.self = false;
|
|
1137
1153
|
}
|
|
1138
|
-
if (!wantAck) {
|
|
1139
|
-
socket.emit("realtime:publish", wirePayload);
|
|
1140
|
-
return;
|
|
1141
|
-
}
|
|
1142
1154
|
return await new Promise((resolve) => {
|
|
1143
1155
|
socket.emit(
|
|
1144
1156
|
"realtime:publish",
|
|
@@ -1179,7 +1191,7 @@ var RealtimeChannel = class {
|
|
|
1179
1191
|
if (!b.subscriptionId || !pcEvent.ids.includes(b.subscriptionId)) {
|
|
1180
1192
|
continue;
|
|
1181
1193
|
}
|
|
1182
|
-
const matchesEvent = b.filter.event === "*" || b.filter.event === pcEvent.data.
|
|
1194
|
+
const matchesEvent = b.filter.event === "*" || b.filter.event === pcEvent.data.eventType;
|
|
1183
1195
|
if (!matchesEvent) {
|
|
1184
1196
|
continue;
|
|
1185
1197
|
}
|
|
@@ -1238,7 +1250,13 @@ var RealtimeChannel = class {
|
|
|
1238
1250
|
continue;
|
|
1239
1251
|
}
|
|
1240
1252
|
try {
|
|
1241
|
-
|
|
1253
|
+
if (payload.event === "sync") {
|
|
1254
|
+
b.callback();
|
|
1255
|
+
} else if (payload.event === "join") {
|
|
1256
|
+
b.callback(payload);
|
|
1257
|
+
} else {
|
|
1258
|
+
b.callback(payload);
|
|
1259
|
+
}
|
|
1242
1260
|
} catch {
|
|
1243
1261
|
}
|
|
1244
1262
|
}
|
|
@@ -1257,7 +1275,7 @@ var RealtimeChannel = class {
|
|
|
1257
1275
|
"realtime:subscribe",
|
|
1258
1276
|
{ channel: this.topic, private: this.isPrivate },
|
|
1259
1277
|
(ack) => {
|
|
1260
|
-
if (ack.ok) {
|
|
1278
|
+
if (ack.status === "ok") {
|
|
1261
1279
|
resolve();
|
|
1262
1280
|
} else {
|
|
1263
1281
|
reject(new Error(ack.error?.message ?? "subscribe failed"));
|
|
@@ -1281,7 +1299,7 @@ var RealtimeChannel = class {
|
|
|
1281
1299
|
filter: b.filter.filter
|
|
1282
1300
|
},
|
|
1283
1301
|
(ack) => {
|
|
1284
|
-
if (ack.ok && ack.subscription_id) {
|
|
1302
|
+
if (ack.status === "ok" && ack.subscription_id) {
|
|
1285
1303
|
b.subscriptionId = ack.subscription_id;
|
|
1286
1304
|
resolve();
|
|
1287
1305
|
} else {
|
|
@@ -1327,13 +1345,14 @@ var Realtime = class {
|
|
|
1327
1345
|
* The optional `opts` argument lets the caller configure the channel:
|
|
1328
1346
|
* * `config.private` — enable subscribe-side authorization against
|
|
1329
1347
|
* `realtime.authorize_subscribe(...)` on the tenant DB.
|
|
1330
|
-
* * `config.broadcast.ack` — `channel.send()` resolves with the
|
|
1331
|
-
* server's ack (message_id) instead of fire-and-forget.
|
|
1332
1348
|
* * `config.broadcast.self` — `false` excludes the sender from the
|
|
1333
1349
|
* fan-out (defaults to `true`).
|
|
1334
1350
|
* * `config.presence.key` — stable presence key to group multiple
|
|
1335
1351
|
* tabs of the same user under one entry.
|
|
1336
1352
|
*
|
|
1353
|
+
* `channel.send()` always resolves with the server ack (see its own
|
|
1354
|
+
* docstring); there is no separate opt-in needed.
|
|
1355
|
+
*
|
|
1337
1356
|
* Options are locked in when the channel is first created; subsequent
|
|
1338
1357
|
* `.channel('same')` calls with different opts are ignored. Pass a
|
|
1339
1358
|
* different topic to get a different-configured channel.
|