@redbase/sdk 0.1.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.js ADDED
@@ -0,0 +1,1669 @@
1
+ import { createClient as createClient$1 } from '@supabase/supabase-js';
2
+ export { FunctionRegion, FunctionsError, FunctionsFetchError, FunctionsHttpError, FunctionsRelayError, PostgrestError, StorageApiError, SupabaseClient, createClient as createSupabaseClient } from '@supabase/supabase-js';
3
+
4
+ // src/client.ts
5
+
6
+ // src/email.ts
7
+ function createEmailClient(redbaseUrl, apiKey) {
8
+ const baseUrl = redbaseUrl.replace(/\/$/, "");
9
+ return {
10
+ async send(options) {
11
+ const url = `${baseUrl}/email/v1/send`;
12
+ try {
13
+ const response = await fetch(url, {
14
+ method: "POST",
15
+ headers: {
16
+ Authorization: `Bearer ${apiKey}`,
17
+ apikey: apiKey,
18
+ "Content-Type": "application/json"
19
+ },
20
+ body: JSON.stringify({
21
+ to: Array.isArray(options.to) ? options.to : [options.to],
22
+ subject: options.subject,
23
+ html: options.html,
24
+ text: options.text,
25
+ reply_to: options.replyTo,
26
+ cc: options.cc ? Array.isArray(options.cc) ? options.cc : [options.cc] : void 0,
27
+ bcc: options.bcc ? Array.isArray(options.bcc) ? options.bcc : [options.bcc] : void 0
28
+ })
29
+ });
30
+ if (!response.ok) {
31
+ const errorBody = await response.text();
32
+ let errorMessage;
33
+ try {
34
+ const parsed = JSON.parse(errorBody);
35
+ errorMessage = parsed.error || parsed.message || errorBody;
36
+ } catch {
37
+ errorMessage = errorBody || `HTTP ${response.status}`;
38
+ }
39
+ return {
40
+ success: false,
41
+ error: errorMessage
42
+ };
43
+ }
44
+ const data = await response.json();
45
+ return {
46
+ success: true,
47
+ messageId: data.message_id || data.messageId
48
+ };
49
+ } catch (error) {
50
+ return {
51
+ success: false,
52
+ error: error instanceof Error ? error.message : "Unknown error sending email"
53
+ };
54
+ }
55
+ }
56
+ };
57
+ }
58
+
59
+ // src/client.ts
60
+ function createClient(redbaseUrl, redbaseKey, options) {
61
+ const supabase = createClient$1(
62
+ redbaseUrl,
63
+ redbaseKey,
64
+ options
65
+ );
66
+ const email = createEmailClient(redbaseUrl, redbaseKey);
67
+ return Object.assign(supabase, { email });
68
+ }
69
+
70
+ // node_modules/@supabase/auth-js/dist/module/lib/errors.js
71
+ var AuthError = class extends Error {
72
+ constructor(message, status, code) {
73
+ super(message);
74
+ this.__isAuthError = true;
75
+ this.name = "AuthError";
76
+ this.status = status;
77
+ this.code = code;
78
+ }
79
+ toJSON() {
80
+ return {
81
+ name: this.name,
82
+ message: this.message,
83
+ status: this.status,
84
+ code: this.code
85
+ };
86
+ }
87
+ };
88
+ var AuthApiError = class extends AuthError {
89
+ constructor(message, status, code) {
90
+ super(message, status, code);
91
+ this.name = "AuthApiError";
92
+ this.status = status;
93
+ this.code = code;
94
+ }
95
+ };
96
+
97
+ // node_modules/@supabase/auth-js/dist/module/lib/base64url.js
98
+ var TO_BASE64URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".split("");
99
+ var IGNORE_BASE64URL = " \n\r=".split("");
100
+ (() => {
101
+ const charMap = new Array(128);
102
+ for (let i = 0; i < charMap.length; i += 1) {
103
+ charMap[i] = -1;
104
+ }
105
+ for (let i = 0; i < IGNORE_BASE64URL.length; i += 1) {
106
+ charMap[IGNORE_BASE64URL[i].charCodeAt(0)] = -2;
107
+ }
108
+ for (let i = 0; i < TO_BASE64URL.length; i += 1) {
109
+ charMap[TO_BASE64URL[i].charCodeAt(0)] = i;
110
+ }
111
+ return charMap;
112
+ })();
113
+ var isBrowser = () => typeof window !== "undefined" && typeof document !== "undefined";
114
+ var localStorageWriteTests = {
115
+ tested: false,
116
+ writable: false
117
+ };
118
+ var supportsLocalStorage = () => {
119
+ if (!isBrowser()) {
120
+ return false;
121
+ }
122
+ try {
123
+ if (typeof globalThis.localStorage !== "object") {
124
+ return false;
125
+ }
126
+ } catch (e) {
127
+ return false;
128
+ }
129
+ if (localStorageWriteTests.tested) {
130
+ return localStorageWriteTests.writable;
131
+ }
132
+ const randomKey = `lswt-${Math.random()}${Math.random()}`;
133
+ try {
134
+ globalThis.localStorage.setItem(randomKey, randomKey);
135
+ globalThis.localStorage.removeItem(randomKey);
136
+ localStorageWriteTests.tested = true;
137
+ localStorageWriteTests.writable = true;
138
+ } catch (e) {
139
+ localStorageWriteTests.tested = true;
140
+ localStorageWriteTests.writable = false;
141
+ }
142
+ return localStorageWriteTests.writable;
143
+ };
144
+
145
+ // node_modules/@supabase/auth-js/dist/module/lib/locks.js
146
+ ({
147
+ /**
148
+ * @experimental
149
+ */
150
+ debug: !!(globalThis && supportsLocalStorage() && globalThis.localStorage && globalThis.localStorage.getItem("supabase.gotrue-js.locks.debug") === "true")
151
+ });
152
+
153
+ // node_modules/@supabase/auth-js/dist/module/lib/polyfills.js
154
+ function polyfillGlobalThis() {
155
+ if (typeof globalThis === "object")
156
+ return;
157
+ try {
158
+ Object.defineProperty(Object.prototype, "__magic__", {
159
+ get: function() {
160
+ return this;
161
+ },
162
+ configurable: true
163
+ });
164
+ __magic__.globalThis = __magic__;
165
+ delete Object.prototype.__magic__;
166
+ } catch (e) {
167
+ if (typeof self !== "undefined") {
168
+ self.globalThis = self;
169
+ }
170
+ }
171
+ }
172
+
173
+ // node_modules/@supabase/auth-js/dist/module/GoTrueClient.js
174
+ polyfillGlobalThis();
175
+ var DEFAULT_POSTGRES_CHANGES_WAIT_TIMEOUT = 15e3;
176
+ var POSTGRES_CHANGES_WAIT_ERROR_GRACE = 1e4;
177
+ var MAX_PUSH_BUFFER_SIZE = 100;
178
+ var CHANNEL_STATES = {
179
+ closed: "closed",
180
+ errored: "errored",
181
+ joined: "joined",
182
+ joining: "joining",
183
+ leaving: "leaving"
184
+ };
185
+ var CHANNEL_EVENTS = {
186
+ close: "phx_close",
187
+ error: "phx_error",
188
+ join: "phx_join",
189
+ leave: "phx_leave"};
190
+
191
+ // node_modules/@supabase/realtime-js/dist/module/lib/transformers.js
192
+ var PostgresTypes;
193
+ (function(PostgresTypes2) {
194
+ PostgresTypes2["abstime"] = "abstime";
195
+ PostgresTypes2["bool"] = "bool";
196
+ PostgresTypes2["date"] = "date";
197
+ PostgresTypes2["daterange"] = "daterange";
198
+ PostgresTypes2["float4"] = "float4";
199
+ PostgresTypes2["float8"] = "float8";
200
+ PostgresTypes2["int2"] = "int2";
201
+ PostgresTypes2["int4"] = "int4";
202
+ PostgresTypes2["int4range"] = "int4range";
203
+ PostgresTypes2["int8"] = "int8";
204
+ PostgresTypes2["int8range"] = "int8range";
205
+ PostgresTypes2["json"] = "json";
206
+ PostgresTypes2["jsonb"] = "jsonb";
207
+ PostgresTypes2["money"] = "money";
208
+ PostgresTypes2["numeric"] = "numeric";
209
+ PostgresTypes2["oid"] = "oid";
210
+ PostgresTypes2["reltime"] = "reltime";
211
+ PostgresTypes2["text"] = "text";
212
+ PostgresTypes2["time"] = "time";
213
+ PostgresTypes2["timestamp"] = "timestamp";
214
+ PostgresTypes2["timestamptz"] = "timestamptz";
215
+ PostgresTypes2["timetz"] = "timetz";
216
+ PostgresTypes2["tsrange"] = "tsrange";
217
+ PostgresTypes2["tstzrange"] = "tstzrange";
218
+ })(PostgresTypes || (PostgresTypes = {}));
219
+ var convertChangeData = (columns, record, options = {}) => {
220
+ var _a;
221
+ const skipTypes = (_a = options.skipTypes) !== null && _a !== void 0 ? _a : [];
222
+ if (!record) {
223
+ return {};
224
+ }
225
+ return Object.keys(record).reduce((acc, rec_key) => {
226
+ acc[rec_key] = convertColumn(rec_key, columns, record, skipTypes);
227
+ return acc;
228
+ }, {});
229
+ };
230
+ var convertColumn = (columnName, columns, record, skipTypes) => {
231
+ const column = columns.find((x) => x.name === columnName);
232
+ const colType = column === null || column === void 0 ? void 0 : column.type;
233
+ const value = record[columnName];
234
+ if (colType && !skipTypes.includes(colType)) {
235
+ return convertCell(colType, value);
236
+ }
237
+ return noop(value);
238
+ };
239
+ var convertCell = (type, value) => {
240
+ if (type.charAt(0) === "_") {
241
+ const dataType = type.slice(1, type.length);
242
+ return toArray(value, dataType);
243
+ }
244
+ switch (type) {
245
+ case PostgresTypes.bool:
246
+ return toBoolean(value);
247
+ case PostgresTypes.float4:
248
+ case PostgresTypes.float8:
249
+ case PostgresTypes.int2:
250
+ case PostgresTypes.int4:
251
+ case PostgresTypes.int8:
252
+ case PostgresTypes.numeric:
253
+ case PostgresTypes.oid:
254
+ return toNumber(value);
255
+ case PostgresTypes.json:
256
+ case PostgresTypes.jsonb:
257
+ return toJson(value);
258
+ case PostgresTypes.timestamp:
259
+ return toTimestampString(value);
260
+ // Format to be consistent with PostgREST
261
+ case PostgresTypes.abstime:
262
+ // To allow users to cast it based on Timezone
263
+ case PostgresTypes.date:
264
+ // To allow users to cast it based on Timezone
265
+ case PostgresTypes.daterange:
266
+ case PostgresTypes.int4range:
267
+ case PostgresTypes.int8range:
268
+ case PostgresTypes.money:
269
+ case PostgresTypes.reltime:
270
+ // To allow users to cast it based on Timezone
271
+ case PostgresTypes.text:
272
+ case PostgresTypes.time:
273
+ // To allow users to cast it based on Timezone
274
+ case PostgresTypes.timestamptz:
275
+ // To allow users to cast it based on Timezone
276
+ case PostgresTypes.timetz:
277
+ // To allow users to cast it based on Timezone
278
+ case PostgresTypes.tsrange:
279
+ case PostgresTypes.tstzrange:
280
+ return noop(value);
281
+ default:
282
+ return noop(value);
283
+ }
284
+ };
285
+ var noop = (value) => {
286
+ return value;
287
+ };
288
+ var toBoolean = (value) => {
289
+ switch (value) {
290
+ case "t":
291
+ return true;
292
+ case "f":
293
+ return false;
294
+ default:
295
+ return value;
296
+ }
297
+ };
298
+ var toNumber = (value) => {
299
+ if (typeof value === "string") {
300
+ const parsedValue = parseFloat(value);
301
+ if (!Number.isNaN(parsedValue)) {
302
+ return parsedValue;
303
+ }
304
+ }
305
+ return value;
306
+ };
307
+ var toJson = (value) => {
308
+ if (typeof value === "string") {
309
+ try {
310
+ return JSON.parse(value);
311
+ } catch (_a) {
312
+ return value;
313
+ }
314
+ }
315
+ return value;
316
+ };
317
+ var toArray = (value, type) => {
318
+ if (typeof value !== "string") {
319
+ return value;
320
+ }
321
+ const lastIdx = value.length - 1;
322
+ const closeBrace = value[lastIdx];
323
+ const openBrace = value[0];
324
+ if (openBrace === "{" && closeBrace === "}") {
325
+ let arr;
326
+ const valTrim = value.slice(1, lastIdx);
327
+ try {
328
+ arr = JSON.parse("[" + valTrim + "]");
329
+ } catch (_) {
330
+ arr = valTrim ? valTrim.split(",") : [];
331
+ }
332
+ return arr.map((val) => convertCell(type, val));
333
+ }
334
+ return value;
335
+ };
336
+ var toTimestampString = (value) => {
337
+ if (typeof value === "string") {
338
+ return value.replace(" ", "T");
339
+ }
340
+ return value;
341
+ };
342
+ var httpEndpointURL = (socketUrl) => {
343
+ const wsUrl = new URL(socketUrl);
344
+ wsUrl.protocol = wsUrl.protocol.replace(/^ws/i, "http");
345
+ wsUrl.pathname = wsUrl.pathname.replace(/\/+$/, "").replace(/\/socket\/websocket$/i, "").replace(/\/socket$/i, "").replace(/\/websocket$/i, "");
346
+ if (wsUrl.pathname === "" || wsUrl.pathname === "/") {
347
+ wsUrl.pathname = "/api/broadcast";
348
+ } else {
349
+ wsUrl.pathname = wsUrl.pathname + "/api/broadcast";
350
+ }
351
+ return wsUrl.href;
352
+ };
353
+
354
+ // node_modules/@supabase/phoenix/priv/static/phoenix.mjs
355
+ var Presence = class _Presence {
356
+ /**
357
+ * Initializes the Presence
358
+ * @param {Channel} channel - The Channel
359
+ * @param {PresenceOptions} [opts] - The options, for example `{events: {state: "state", diff: "diff"}}`
360
+ */
361
+ constructor(channel, opts = {}) {
362
+ let events = opts.events || /** @type {PresenceEvents} */
363
+ { state: "presence_state", diff: "presence_diff" };
364
+ this.state = /* @__PURE__ */ Object.create(null);
365
+ this.pendingDiffs = [];
366
+ this.channel = channel;
367
+ this.joinRef = null;
368
+ this.caller = {
369
+ onJoin: function() {
370
+ },
371
+ onLeave: function() {
372
+ },
373
+ onSync: function() {
374
+ }
375
+ };
376
+ this.channel.on(events.state, (newState) => {
377
+ let { onJoin, onLeave, onSync } = this.caller;
378
+ this.joinRef = this.channel.joinRef();
379
+ this.state = _Presence.syncState(this.state, newState, onJoin, onLeave);
380
+ this.pendingDiffs.forEach((diff) => {
381
+ this.state = _Presence.syncDiff(this.state, diff, onJoin, onLeave);
382
+ });
383
+ this.pendingDiffs = [];
384
+ onSync();
385
+ });
386
+ this.channel.on(events.diff, (diff) => {
387
+ let { onJoin, onLeave, onSync } = this.caller;
388
+ if (this.inPendingSyncState()) {
389
+ this.pendingDiffs.push(diff);
390
+ } else {
391
+ this.state = _Presence.syncDiff(this.state, diff, onJoin, onLeave);
392
+ onSync();
393
+ }
394
+ });
395
+ }
396
+ /**
397
+ * @param {PresenceOnJoin} callback
398
+ */
399
+ onJoin(callback) {
400
+ this.caller.onJoin = callback;
401
+ }
402
+ /**
403
+ * @param {PresenceOnLeave} callback
404
+ */
405
+ onLeave(callback) {
406
+ this.caller.onLeave = callback;
407
+ }
408
+ /**
409
+ * @param {PresenceOnSync} callback
410
+ */
411
+ onSync(callback) {
412
+ this.caller.onSync = callback;
413
+ }
414
+ /**
415
+ * Returns the array of presences, with selected metadata.
416
+ *
417
+ * @template [T=PresenceState]
418
+ * @param {((key: string, obj: PresenceState) => T)} [by]
419
+ *
420
+ * @returns {T[]}
421
+ */
422
+ list(by) {
423
+ return _Presence.list(this.state, by);
424
+ }
425
+ inPendingSyncState() {
426
+ return !this.joinRef || this.joinRef !== this.channel.joinRef();
427
+ }
428
+ // lower-level public static API
429
+ /**
430
+ * Used to sync the list of presences on the server
431
+ * with the client's state. An optional `onJoin` and `onLeave` callback can
432
+ * be provided to react to changes in the client's local presences across
433
+ * disconnects and reconnects with the server.
434
+ *
435
+ * @param {Record<string, PresenceState>} currentState
436
+ * @param {Record<string, PresenceState>} newState
437
+ * @param {PresenceOnJoin} onJoin
438
+ * @param {PresenceOnLeave} onLeave
439
+ *
440
+ * @returns {Record<string, PresenceState>}
441
+ */
442
+ static syncState(currentState, newState, onJoin, onLeave) {
443
+ let state = this.toNullProtoObj(this.clone(currentState));
444
+ newState = this.toNullProtoObj(newState);
445
+ let joins = /* @__PURE__ */ Object.create(null);
446
+ let leaves = /* @__PURE__ */ Object.create(null);
447
+ this.map(state, (key, presence) => {
448
+ if (!newState[key]) {
449
+ leaves[key] = presence;
450
+ }
451
+ });
452
+ this.map(newState, (key, newPresence) => {
453
+ let currentPresence = state[key];
454
+ if (currentPresence) {
455
+ let newRefs = newPresence.metas.map((m) => m.phx_ref);
456
+ let curRefs = currentPresence.metas.map((m) => m.phx_ref);
457
+ let joinedMetas = newPresence.metas.filter((m) => curRefs.indexOf(m.phx_ref) < 0);
458
+ let leftMetas = currentPresence.metas.filter((m) => newRefs.indexOf(m.phx_ref) < 0);
459
+ if (joinedMetas.length > 0) {
460
+ joins[key] = newPresence;
461
+ joins[key].metas = joinedMetas;
462
+ }
463
+ if (leftMetas.length > 0) {
464
+ leaves[key] = this.clone(currentPresence);
465
+ leaves[key].metas = leftMetas;
466
+ }
467
+ } else {
468
+ joins[key] = newPresence;
469
+ }
470
+ });
471
+ return this.syncDiff(state, { joins, leaves }, onJoin, onLeave);
472
+ }
473
+ /**
474
+ *
475
+ * Used to sync a diff of presence join and leave
476
+ * events from the server, as they happen. Like `syncState`, `syncDiff`
477
+ * accepts optional `onJoin` and `onLeave` callbacks to react to a user
478
+ * joining or leaving from a device.
479
+ *
480
+ * @param {Record<string, PresenceState>} state
481
+ * @param {PresenceDiff} diff
482
+ * @param {PresenceOnJoin} onJoin
483
+ * @param {PresenceOnLeave} onLeave
484
+ *
485
+ * @returns {Record<string, PresenceState>}
486
+ */
487
+ static syncDiff(state, diff, onJoin, onLeave) {
488
+ state = this.toNullProtoObj(state);
489
+ let { joins, leaves } = this.clone(diff);
490
+ if (!onJoin) {
491
+ onJoin = function() {
492
+ };
493
+ }
494
+ if (!onLeave) {
495
+ onLeave = function() {
496
+ };
497
+ }
498
+ this.map(joins, (key, newPresence) => {
499
+ let currentPresence = state[key];
500
+ state[key] = this.clone(newPresence);
501
+ if (currentPresence) {
502
+ let joinedRefs = state[key].metas.map((m) => m.phx_ref);
503
+ let curMetas = currentPresence.metas.filter((m) => joinedRefs.indexOf(m.phx_ref) < 0);
504
+ state[key].metas.unshift(...curMetas);
505
+ }
506
+ onJoin(key, currentPresence, newPresence);
507
+ });
508
+ this.map(leaves, (key, leftPresence) => {
509
+ let currentPresence = state[key];
510
+ if (!currentPresence) {
511
+ return;
512
+ }
513
+ let refsToRemove = leftPresence.metas.map((m) => m.phx_ref);
514
+ currentPresence.metas = currentPresence.metas.filter((p) => {
515
+ return refsToRemove.indexOf(p.phx_ref) < 0;
516
+ });
517
+ onLeave(key, currentPresence, leftPresence);
518
+ if (currentPresence.metas.length === 0) {
519
+ delete state[key];
520
+ }
521
+ });
522
+ return state;
523
+ }
524
+ /**
525
+ * Returns the array of presences, with selected metadata.
526
+ *
527
+ * @template [T=PresenceState]
528
+ * @param {Record<string, PresenceState>} presences
529
+ * @param {((key: string, obj: PresenceState) => T)} [chooser]
530
+ *
531
+ * @returns {T[]}
532
+ */
533
+ static list(presences, chooser) {
534
+ if (!chooser) {
535
+ chooser = function(key, pres) {
536
+ return pres;
537
+ };
538
+ }
539
+ return this.map(presences, (key, presence) => {
540
+ return chooser(key, presence);
541
+ });
542
+ }
543
+ // private
544
+ /**
545
+ * @template T
546
+ * @param {Record<string, PresenceState>} obj
547
+ * @param {(key: string, obj: PresenceState) => T} func
548
+ */
549
+ static map(obj, func) {
550
+ return Object.getOwnPropertyNames(obj).map((key) => func(key, obj[key]));
551
+ }
552
+ // Presence keys are chosen on the server and may collide with
553
+ // Object.prototype properties ("__proto__", "constructor", ...), so any
554
+ // object indexed by presence key must not have a prototype chain
555
+ //
556
+ // TODO: replace the null-prototype objects with Maps in Phoenix 2.0
557
+ // (breaking change for the lower-level static API)
558
+ static toNullProtoObj(obj) {
559
+ if (Object.getPrototypeOf(obj) === null) {
560
+ return obj;
561
+ }
562
+ let cleaned = /* @__PURE__ */ Object.create(null);
563
+ Object.getOwnPropertyNames(obj).forEach((key) => {
564
+ cleaned[key] = obj[key];
565
+ });
566
+ return cleaned;
567
+ }
568
+ /**
569
+ * @template T
570
+ * @param {T} obj
571
+ * @returns {T}
572
+ */
573
+ static clone(obj) {
574
+ return JSON.parse(JSON.stringify(obj));
575
+ }
576
+ };
577
+
578
+ // node_modules/@supabase/realtime-js/dist/module/phoenix/presenceAdapter.js
579
+ var PresenceAdapter = class _PresenceAdapter {
580
+ constructor(channel, opts) {
581
+ const phoenixOptions = phoenixPresenceOptions(opts);
582
+ this.presence = new Presence(channel.getChannel(), phoenixOptions);
583
+ this.presence.onJoin((key, currentPresence, newPresence) => {
584
+ const onJoinPayload = _PresenceAdapter.onJoinPayload(key, currentPresence, newPresence);
585
+ channel.getChannel().trigger("presence", onJoinPayload);
586
+ });
587
+ this.presence.onLeave((key, currentPresence, leftPresence) => {
588
+ const onLeavePayload = _PresenceAdapter.onLeavePayload(key, currentPresence, leftPresence);
589
+ channel.getChannel().trigger("presence", onLeavePayload);
590
+ });
591
+ this.presence.onSync(() => {
592
+ channel.getChannel().trigger("presence", { event: "sync" });
593
+ });
594
+ }
595
+ get state() {
596
+ return _PresenceAdapter.transformState(this.presence.state);
597
+ }
598
+ /**
599
+ * @private
600
+ * Remove 'metas' key
601
+ * Change 'phx_ref' to 'presence_ref'
602
+ * Remove 'phx_ref' and 'phx_ref_prev'
603
+ *
604
+ * @example Transform state
605
+ * // returns {
606
+ * abc123: [
607
+ * { presence_ref: '2', user_id: 1 },
608
+ * { presence_ref: '3', user_id: 2 }
609
+ * ]
610
+ * }
611
+ * RealtimePresence.transformState({
612
+ * abc123: {
613
+ * metas: [
614
+ * { phx_ref: '2', phx_ref_prev: '1' user_id: 1 },
615
+ * { phx_ref: '3', user_id: 2 }
616
+ * ]
617
+ * }
618
+ * })
619
+ *
620
+ */
621
+ static transformState(state) {
622
+ state = cloneState(state);
623
+ return Object.getOwnPropertyNames(state).reduce((newState, key) => {
624
+ const presences = state[key];
625
+ newState[key] = transformState(presences);
626
+ return newState;
627
+ }, {});
628
+ }
629
+ static onJoinPayload(key, currentPresence, newPresence) {
630
+ const currentPresences = parseCurrentPresences(currentPresence);
631
+ const newPresences = transformState(newPresence);
632
+ return {
633
+ event: "join",
634
+ key,
635
+ currentPresences,
636
+ newPresences
637
+ };
638
+ }
639
+ static onLeavePayload(key, currentPresence, leftPresence) {
640
+ const currentPresences = parseCurrentPresences(currentPresence);
641
+ const leftPresences = transformState(leftPresence);
642
+ return {
643
+ event: "leave",
644
+ key,
645
+ currentPresences,
646
+ leftPresences
647
+ };
648
+ }
649
+ };
650
+ function transformState(presences) {
651
+ return presences.metas.map((presence) => {
652
+ const descriptors = Object.getOwnPropertyDescriptors(presence);
653
+ const transformedPresence = Object.defineProperties({}, descriptors);
654
+ transformedPresence["presence_ref"] = transformedPresence["phx_ref"];
655
+ delete transformedPresence["phx_ref"];
656
+ delete transformedPresence["phx_ref_prev"];
657
+ return transformedPresence;
658
+ });
659
+ }
660
+ function cloneState(state) {
661
+ return JSON.parse(JSON.stringify(state));
662
+ }
663
+ function phoenixPresenceOptions(opts) {
664
+ return (opts === null || opts === void 0 ? void 0 : opts.events) && { events: opts.events };
665
+ }
666
+ function parseCurrentPresences(currentPresences) {
667
+ return (currentPresences === null || currentPresences === void 0 ? void 0 : currentPresences.metas) ? transformState(currentPresences) : [];
668
+ }
669
+
670
+ // node_modules/@supabase/realtime-js/dist/module/RealtimePresence.js
671
+ var REALTIME_PRESENCE_LISTEN_EVENTS;
672
+ (function(REALTIME_PRESENCE_LISTEN_EVENTS2) {
673
+ REALTIME_PRESENCE_LISTEN_EVENTS2["SYNC"] = "sync";
674
+ REALTIME_PRESENCE_LISTEN_EVENTS2["JOIN"] = "join";
675
+ REALTIME_PRESENCE_LISTEN_EVENTS2["LEAVE"] = "leave";
676
+ })(REALTIME_PRESENCE_LISTEN_EVENTS || (REALTIME_PRESENCE_LISTEN_EVENTS = {}));
677
+ var RealtimePresence = class {
678
+ get state() {
679
+ return this.presenceAdapter.state;
680
+ }
681
+ /**
682
+ * Creates a Presence helper that keeps the local presence state in sync with the server.
683
+ *
684
+ * @param channel - The realtime channel to bind to.
685
+ * @param opts - Optional custom event names, e.g. `{ events: { state: 'state', diff: 'diff' } }`.
686
+ *
687
+ * @category Realtime
688
+ *
689
+ * @example Example for a presence channel
690
+ * ```ts
691
+ * const presence = new RealtimePresence(channel)
692
+ *
693
+ * channel.on('presence', ({ event, key }) => {
694
+ * console.log(`Presence ${event} on ${key}`)
695
+ * })
696
+ * ```
697
+ */
698
+ constructor(channel, opts) {
699
+ this.channel = channel;
700
+ this.presenceAdapter = new PresenceAdapter(this.channel.channelAdapter, opts);
701
+ }
702
+ };
703
+
704
+ // node_modules/@supabase/realtime-js/dist/module/lib/normalizeChannelError.js
705
+ function normalizeChannelError(reason) {
706
+ if (reason instanceof Error) {
707
+ return reason;
708
+ }
709
+ if (typeof reason === "string") {
710
+ return new Error(reason);
711
+ }
712
+ if (reason && typeof reason === "object") {
713
+ const obj = reason;
714
+ if (typeof obj.code === "number") {
715
+ const detail = typeof obj.reason === "string" && obj.reason ? ` (${obj.reason})` : "";
716
+ return new Error(`socket closed: ${obj.code}${detail}`, { cause: reason });
717
+ }
718
+ return new Error("channel error: transport failure", { cause: reason });
719
+ }
720
+ return new Error("channel error: connection lost");
721
+ }
722
+
723
+ // node_modules/@supabase/realtime-js/dist/module/phoenix/channelAdapter.js
724
+ var ChannelAdapter = class {
725
+ constructor(socket, topic, params) {
726
+ const phoenixParams = phoenixChannelParams(params);
727
+ this.channel = socket.getSocket().channel(topic, phoenixParams);
728
+ this.socket = socket;
729
+ }
730
+ get state() {
731
+ return this.channel.state;
732
+ }
733
+ set state(state) {
734
+ this.channel.state = state;
735
+ }
736
+ get joinedOnce() {
737
+ return this.channel.joinedOnce;
738
+ }
739
+ get joinPush() {
740
+ return this.channel.joinPush;
741
+ }
742
+ get rejoinTimer() {
743
+ return this.channel.rejoinTimer;
744
+ }
745
+ on(event, callback) {
746
+ return this.channel.on(event, callback);
747
+ }
748
+ off(event, refNumber) {
749
+ this.channel.off(event, refNumber);
750
+ }
751
+ subscribe(timeout) {
752
+ return this.channel.join(timeout);
753
+ }
754
+ unsubscribe(timeout) {
755
+ return this.channel.leave(timeout);
756
+ }
757
+ teardown() {
758
+ this.channel.teardown();
759
+ }
760
+ onClose(callback) {
761
+ this.channel.onClose(callback);
762
+ }
763
+ onError(callback) {
764
+ return this.channel.onError(callback);
765
+ }
766
+ push(event, payload, timeout) {
767
+ let push;
768
+ try {
769
+ push = this.channel.push(event, payload, timeout);
770
+ } catch (error) {
771
+ throw new Error(`tried to push '${event}' to '${this.channel.topic}' before joining. Use channel.subscribe() before pushing events`);
772
+ }
773
+ if (this.channel.pushBuffer.length > MAX_PUSH_BUFFER_SIZE) {
774
+ const removedPush = this.channel.pushBuffer.shift();
775
+ removedPush.cancelTimeout();
776
+ this.socket.log("channel", `discarded push due to buffer overflow: ${removedPush.event}`, removedPush.payload());
777
+ }
778
+ return push;
779
+ }
780
+ updateJoinPayload(payload) {
781
+ const oldPayload = this.channel.joinPush.payload();
782
+ this.channel.joinPush.payload = () => Object.assign(Object.assign({}, oldPayload), payload);
783
+ }
784
+ canPush() {
785
+ return this.socket.isConnected() && this.state === CHANNEL_STATES.joined;
786
+ }
787
+ isJoined() {
788
+ return this.state === CHANNEL_STATES.joined;
789
+ }
790
+ isJoining() {
791
+ return this.state === CHANNEL_STATES.joining;
792
+ }
793
+ isClosed() {
794
+ return this.state === CHANNEL_STATES.closed;
795
+ }
796
+ isLeaving() {
797
+ return this.state === CHANNEL_STATES.leaving;
798
+ }
799
+ updateFilterBindings(filterBindings) {
800
+ this.channel.filterBindings = filterBindings;
801
+ }
802
+ updatePayloadTransform(callback) {
803
+ this.channel.onMessage = callback;
804
+ }
805
+ /**
806
+ * @internal
807
+ */
808
+ getChannel() {
809
+ return this.channel;
810
+ }
811
+ };
812
+ function phoenixChannelParams(options) {
813
+ return {
814
+ config: Object.assign({
815
+ broadcast: { ack: false, self: false },
816
+ presence: { key: "", enabled: false },
817
+ private: false
818
+ }, options.config)
819
+ };
820
+ }
821
+
822
+ // node_modules/@supabase/realtime-js/dist/module/RealtimePostgresFilterBuilder.js
823
+ var PostgrestReservedCharsRegexp = /[,()"\\]/;
824
+ var needsQuoting = (value) => PostgrestReservedCharsRegexp.test(value) || value !== value.trim();
825
+ var quote = (value) => `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
826
+ var serializeScalar = (value) => {
827
+ const serialized = value === null ? "null" : String(value);
828
+ return needsQuoting(serialized) ? quote(serialized) : serialized;
829
+ };
830
+ var serializeIsValue = (value) => value === null ? "null" : String(value);
831
+ var serialize = (operator, value) => {
832
+ if (operator === "in") {
833
+ const values = Array.isArray(value) ? value : [value];
834
+ if (values.length === 0) {
835
+ throw new Error("Realtime `in` filter requires at least one value.");
836
+ }
837
+ const items = Array.from(new Set(values)).map((v) => serializeScalar(v)).join(",");
838
+ return `in.(${items})`;
839
+ }
840
+ if (operator === "is") {
841
+ return `is.${serializeIsValue(value)}`;
842
+ }
843
+ return `${operator}.${serializeScalar(value)}`;
844
+ };
845
+ var RealtimePostgresFilterBuilder = class {
846
+ constructor() {
847
+ this.filters = [];
848
+ }
849
+ add(column, operator, value, negate = false) {
850
+ const prefix = negate ? "not." : "";
851
+ this.filters.push(`${column}=${prefix}${serialize(operator, value)}`);
852
+ return this;
853
+ }
854
+ /** Match rows where `column` equals `value` (`column=eq.value`). */
855
+ eq(column, value) {
856
+ return this.add(column, "eq", value);
857
+ }
858
+ /** Match rows where `column` does not equal `value` (`column=neq.value`). */
859
+ neq(column, value) {
860
+ return this.add(column, "neq", value);
861
+ }
862
+ /** Match rows where `column` is greater than `value` (`column=gt.value`). */
863
+ gt(column, value) {
864
+ return this.add(column, "gt", value);
865
+ }
866
+ /** Match rows where `column` is greater than or equal to `value` (`column=gte.value`). */
867
+ gte(column, value) {
868
+ return this.add(column, "gte", value);
869
+ }
870
+ /** Match rows where `column` is less than `value` (`column=lt.value`). */
871
+ lt(column, value) {
872
+ return this.add(column, "lt", value);
873
+ }
874
+ /** Match rows where `column` is less than or equal to `value` (`column=lte.value`). */
875
+ lte(column, value) {
876
+ return this.add(column, "lte", value);
877
+ }
878
+ /**
879
+ * Match rows where `column` is one of `values` (`column=in.(a,b,c)`).
880
+ * Requires at least one value; duplicates are removed. An element containing a
881
+ * reserved character is double-quoted (`in.("a,b",c)`), so commas inside an
882
+ * element are preserved. `null` is intentionally not accepted (`IN (null)`
883
+ * never matches in SQL) — use `is`/`not('col','is',null)` for null checks.
884
+ */
885
+ in(column, values) {
886
+ return this.add(column, "in", values);
887
+ }
888
+ /** Match rows where `column` matches the case-sensitive `pattern` (`column=like.pattern`). */
889
+ like(column, pattern) {
890
+ return this.add(column, "like", pattern);
891
+ }
892
+ /** Match rows where `column` matches the case-insensitive `pattern` (`column=ilike.pattern`). */
893
+ ilike(column, pattern) {
894
+ return this.add(column, "ilike", pattern);
895
+ }
896
+ /** Match rows where `column` matches the POSIX regex `pattern` (`column=match.pattern`). */
897
+ match(column, pattern) {
898
+ return this.add(column, "match", pattern);
899
+ }
900
+ /** Match rows where `column` matches the case-insensitive POSIX regex `pattern` (`column=imatch.pattern`). */
901
+ imatch(column, pattern) {
902
+ return this.add(column, "imatch", pattern);
903
+ }
904
+ /**
905
+ * Match rows where `column` `IS` the given value (`column=is.null`).
906
+ * Accepts `null`, a boolean, or the keywords `'null' | 'true' | 'false' | 'unknown'`.
907
+ */
908
+ is(column, value) {
909
+ return this.add(column, "is", value);
910
+ }
911
+ /** Match rows where `column` is distinct from `value` (`column=isdistinct.value`). NULL-safe inequality. */
912
+ isDistinct(column, value) {
913
+ return this.add(column, "isdistinct", value);
914
+ }
915
+ not(column, operator, value) {
916
+ return this.add(column, operator, value, true);
917
+ }
918
+ /**
919
+ * Serialize all conditions into the comma-separated (AND) filter string.
920
+ *
921
+ * Conditions are joined by commas, which the server applies as `AND`. A scalar
922
+ * value (or single `in` element) that contains a reserved character — `,`,
923
+ * `(`, `)`, `"`, `\` — or surrounding whitespace is double-quoted and escaped
924
+ * the way PostgREST does, so commas inside a value are preserved rather than
925
+ * read as a condition boundary.
926
+ */
927
+ build() {
928
+ return this.filters.join(",");
929
+ }
930
+ /** Alias for {@link build}; lets the builder be used wherever a string is expected. */
931
+ toString() {
932
+ return this.build();
933
+ }
934
+ };
935
+
936
+ // node_modules/@supabase/realtime-js/dist/module/RealtimeChannel.js
937
+ var REALTIME_POSTGRES_CHANGES_LISTEN_EVENT;
938
+ (function(REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2) {
939
+ REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2["ALL"] = "*";
940
+ REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2["INSERT"] = "INSERT";
941
+ REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2["UPDATE"] = "UPDATE";
942
+ REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2["DELETE"] = "DELETE";
943
+ })(REALTIME_POSTGRES_CHANGES_LISTEN_EVENT || (REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = {}));
944
+ var REALTIME_LISTEN_TYPES;
945
+ (function(REALTIME_LISTEN_TYPES2) {
946
+ REALTIME_LISTEN_TYPES2["BROADCAST"] = "broadcast";
947
+ REALTIME_LISTEN_TYPES2["PRESENCE"] = "presence";
948
+ REALTIME_LISTEN_TYPES2["POSTGRES_CHANGES"] = "postgres_changes";
949
+ REALTIME_LISTEN_TYPES2["SYSTEM"] = "system";
950
+ })(REALTIME_LISTEN_TYPES || (REALTIME_LISTEN_TYPES = {}));
951
+ var REALTIME_SUBSCRIBE_STATES;
952
+ (function(REALTIME_SUBSCRIBE_STATES2) {
953
+ REALTIME_SUBSCRIBE_STATES2["SUBSCRIBED"] = "SUBSCRIBED";
954
+ REALTIME_SUBSCRIBE_STATES2["TIMED_OUT"] = "TIMED_OUT";
955
+ REALTIME_SUBSCRIBE_STATES2["CLOSED"] = "CLOSED";
956
+ REALTIME_SUBSCRIBE_STATES2["CHANNEL_ERROR"] = "CHANNEL_ERROR";
957
+ })(REALTIME_SUBSCRIBE_STATES || (REALTIME_SUBSCRIBE_STATES = {}));
958
+ var RealtimeChannel = class _RealtimeChannel {
959
+ get state() {
960
+ return this.channelAdapter.state;
961
+ }
962
+ set state(state) {
963
+ this.channelAdapter.state = state;
964
+ }
965
+ get joinedOnce() {
966
+ return this.channelAdapter.joinedOnce;
967
+ }
968
+ get timeout() {
969
+ return this.socket.timeout;
970
+ }
971
+ get joinPush() {
972
+ return this.channelAdapter.joinPush;
973
+ }
974
+ get rejoinTimer() {
975
+ return this.channelAdapter.rejoinTimer;
976
+ }
977
+ /**
978
+ * Creates a channel that can broadcast messages, sync presence, and listen to Postgres changes.
979
+ *
980
+ * The topic determines which realtime stream you are subscribing to. Config options let you
981
+ * enable acknowledgement for broadcasts, presence tracking, or private channels.
982
+ *
983
+ * @category Realtime
984
+ *
985
+ * @example Using supabase-js (recommended)
986
+ * ```ts
987
+ * import { createClient } from '@supabase/supabase-js'
988
+ *
989
+ * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')
990
+ * const channel = supabase.channel('room1')
991
+ * channel
992
+ * .on('broadcast', { event: 'cursor-pos' }, (payload) => console.log(payload))
993
+ * .subscribe()
994
+ * ```
995
+ *
996
+ * @example Standalone import for bundle-sensitive environments
997
+ * ```ts
998
+ * import RealtimeClient from '@supabase/realtime-js'
999
+ *
1000
+ * const client = new RealtimeClient('https://xyzcompany.supabase.co/realtime/v1', {
1001
+ * params: { apikey: 'your-publishable-key' },
1002
+ * })
1003
+ * const channel = new RealtimeChannel('realtime:public:messages', { config: {} }, client)
1004
+ * ```
1005
+ */
1006
+ constructor(topic, params = { config: {} }, socket) {
1007
+ var _a, _b;
1008
+ this.topic = topic;
1009
+ this.params = params;
1010
+ this.socket = socket;
1011
+ this.bindings = {};
1012
+ this.subTopic = topic.replace(/^realtime:/i, "");
1013
+ this.params.config = Object.assign({
1014
+ broadcast: { ack: false, self: false },
1015
+ presence: { key: "", enabled: false },
1016
+ private: false
1017
+ }, params.config);
1018
+ this.channelAdapter = new ChannelAdapter(this.socket.socketAdapter, topic, this.params);
1019
+ this.presence = new RealtimePresence(this);
1020
+ this._onClose(() => {
1021
+ this.socket._remove(this);
1022
+ });
1023
+ this._updateFilterTransform();
1024
+ this.broadcastEndpointURL = httpEndpointURL(this.socket.socketAdapter.endPointURL());
1025
+ this.private = this.params.config.private || false;
1026
+ if (!this.private && ((_b = (_a = this.params.config) === null || _a === void 0 ? void 0 : _a.broadcast) === null || _b === void 0 ? void 0 : _b.replay)) {
1027
+ throw new Error(`tried to use replay on public channel '${this.topic}'. It must be a private channel.`);
1028
+ }
1029
+ }
1030
+ /**
1031
+ * Subscribe registers your client with the server.
1032
+ *
1033
+ * The optional `callback` receives a `status` and, on failure, an `err` argument.
1034
+ * Log the full `err` so its `cause`, `name`, and any structured fields aren't hidden
1035
+ * behind `err.message`.
1036
+ *
1037
+ * @category Realtime
1038
+ *
1039
+ * @example Handling errors
1040
+ * ```js
1041
+ * supabase.channel('room1').subscribe((status, err) => {
1042
+ * if (status === 'CHANNEL_ERROR' || status === 'TIMED_OUT') {
1043
+ * // Log the full error: its `cause` often holds the underlying reason.
1044
+ * console.error(status, err)
1045
+ * }
1046
+ * })
1047
+ * ```
1048
+ */
1049
+ subscribe(callback, timeout = this.timeout) {
1050
+ var _a, _b, _c, _d;
1051
+ if (!this.socket.isConnected()) {
1052
+ this.socket.connect();
1053
+ }
1054
+ if (this.channelAdapter.isClosed()) {
1055
+ const { config: { broadcast, presence, private: isPrivate, postgres_changes_options } } = this.params;
1056
+ const postgres_changes = (_b = (_a = this.bindings.postgres_changes) === null || _a === void 0 ? void 0 : _a.map((r) => r.filter)) !== null && _b !== void 0 ? _b : [];
1057
+ const presence_enabled = !!this.bindings[REALTIME_LISTEN_TYPES.PRESENCE] && this.bindings[REALTIME_LISTEN_TYPES.PRESENCE].length > 0 || ((_c = this.params.config.presence) === null || _c === void 0 ? void 0 : _c.enabled) === true;
1058
+ const accessTokenPayload = {};
1059
+ const config = Object.assign({ broadcast, presence: Object.assign(Object.assign({}, presence), { enabled: presence_enabled }), postgres_changes, private: isPrivate }, postgres_changes_options ? { postgres_changes_options } : {});
1060
+ if (this.socket.accessTokenValue) {
1061
+ accessTokenPayload.access_token = this.socket.accessTokenValue;
1062
+ }
1063
+ this._onError((reason) => {
1064
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, normalizeChannelError(reason));
1065
+ });
1066
+ this._onClose(() => callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CLOSED));
1067
+ this.updateJoinPayload(Object.assign({ config }, accessTokenPayload));
1068
+ this._updateFilterMessage();
1069
+ const joinTimeout = (postgres_changes_options === null || postgres_changes_options === void 0 ? void 0 : postgres_changes_options.wait) && postgres_changes.length > 0 ? Math.max(timeout, ((_d = postgres_changes_options.timeout) !== null && _d !== void 0 ? _d : DEFAULT_POSTGRES_CHANGES_WAIT_TIMEOUT) + POSTGRES_CHANGES_WAIT_ERROR_GRACE) : timeout;
1070
+ this.channelAdapter.subscribe(joinTimeout).receive("ok", async ({ postgres_changes: postgres_changes2 }) => {
1071
+ if (!this.socket._isManualToken()) {
1072
+ this.socket.setAuth();
1073
+ }
1074
+ if (postgres_changes2 === void 0) {
1075
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.SUBSCRIBED);
1076
+ return;
1077
+ }
1078
+ this._updatePostgresBindings(postgres_changes2, callback);
1079
+ }).receive("error", (error) => {
1080
+ this.state = CHANNEL_STATES.errored;
1081
+ const message = Object.values(error).join(", ") || "error";
1082
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, new Error(message, { cause: error }));
1083
+ }).receive("timeout", () => {
1084
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.TIMED_OUT);
1085
+ });
1086
+ }
1087
+ return this;
1088
+ }
1089
+ _updatePostgresBindings(postgres_changes, callback) {
1090
+ var _a;
1091
+ const clientPostgresBindings = this.bindings.postgres_changes;
1092
+ const bindingsLen = (_a = clientPostgresBindings === null || clientPostgresBindings === void 0 ? void 0 : clientPostgresBindings.length) !== null && _a !== void 0 ? _a : 0;
1093
+ const newPostgresBindings = [];
1094
+ for (let i = 0; i < bindingsLen; i++) {
1095
+ const clientPostgresBinding = clientPostgresBindings[i];
1096
+ const { filter: { event, schema, table, filter } } = clientPostgresBinding;
1097
+ const serverPostgresFilter = postgres_changes && postgres_changes[i];
1098
+ if (serverPostgresFilter && serverPostgresFilter.event === event && _RealtimeChannel.isFilterValueEqual(serverPostgresFilter.schema, schema) && _RealtimeChannel.isFilterValueEqual(serverPostgresFilter.table, table) && _RealtimeChannel.isFilterValueEqual(serverPostgresFilter.filter, filter)) {
1099
+ newPostgresBindings.push(Object.assign(Object.assign({}, clientPostgresBinding), { id: serverPostgresFilter.id }));
1100
+ } else {
1101
+ this.unsubscribe();
1102
+ this.state = CHANNEL_STATES.errored;
1103
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, new Error("mismatch between server and client bindings for postgres changes"));
1104
+ return;
1105
+ }
1106
+ }
1107
+ this.bindings.postgres_changes = newPostgresBindings;
1108
+ if (this.state != CHANNEL_STATES.errored && callback) {
1109
+ callback(REALTIME_SUBSCRIBE_STATES.SUBSCRIBED);
1110
+ }
1111
+ }
1112
+ /**
1113
+ * Returns the current presence state for this channel.
1114
+ *
1115
+ * The shape is a map keyed by presence key (for example a user id) where each entry contains the
1116
+ * tracked metadata for that user.
1117
+ *
1118
+ * @category Realtime
1119
+ */
1120
+ presenceState() {
1121
+ return this.presence.state;
1122
+ }
1123
+ /**
1124
+ * Sends the supplied payload to the presence tracker so other subscribers can see that this
1125
+ * client is online. Use `untrack` to stop broadcasting presence for the same key.
1126
+ *
1127
+ * Tracking makes this client visible to other subscribers immediately, regardless of this
1128
+ * channel's `config.presence.enabled` setting or whether it has a `presence` listener — that
1129
+ * flag only affects whether *this* client receives presence updates from others (and, on
1130
+ * RLS-protected channels, whether it's authorized to do so).
1131
+ *
1132
+ * @category Realtime
1133
+ */
1134
+ async track(payload, opts = {}) {
1135
+ return await this.send({
1136
+ type: "presence",
1137
+ event: "track",
1138
+ payload
1139
+ }, opts);
1140
+ }
1141
+ /**
1142
+ * Removes the current presence state for this client.
1143
+ *
1144
+ * @category Realtime
1145
+ */
1146
+ async untrack(opts = {}) {
1147
+ return await this.send({
1148
+ type: "presence",
1149
+ event: "untrack"
1150
+ }, opts);
1151
+ }
1152
+ /**
1153
+ * Listen to realtime events on this channel.
1154
+ * @category Realtime
1155
+ *
1156
+ * @remarks
1157
+ * - By default, Broadcast and Presence are enabled for all projects.
1158
+ * - By default, listening to database changes is disabled for new projects due to database performance and security concerns. You can turn it on by managing Realtime's [replication](/docs/guides/api#realtime-api-overview).
1159
+ * - You can receive the "previous" data for updates and deletes by setting the table's `REPLICA IDENTITY` to `FULL` (e.g., `ALTER TABLE your_table REPLICA IDENTITY FULL;`).
1160
+ * - Row level security is not applied to delete statements. When RLS is enabled and replica identity is set to full, only the primary key is sent to clients.
1161
+ *
1162
+ * @example Listen to broadcast messages
1163
+ * ```js
1164
+ * const channel = supabase.channel("room1")
1165
+ *
1166
+ * channel.on("broadcast", { event: "cursor-pos" }, (payload) => {
1167
+ * console.log("Cursor position received!", payload);
1168
+ * }).subscribe((status) => {
1169
+ * if (status === "SUBSCRIBED") {
1170
+ * channel.send({
1171
+ * type: "broadcast",
1172
+ * event: "cursor-pos",
1173
+ * payload: { x: Math.random(), y: Math.random() },
1174
+ * });
1175
+ * }
1176
+ * });
1177
+ * ```
1178
+ *
1179
+ * @example Listen to presence sync
1180
+ * ```js
1181
+ * const channel = supabase.channel('room1')
1182
+ * channel
1183
+ * .on('presence', { event: 'sync' }, () => {
1184
+ * console.log('Synced presence state: ', channel.presenceState())
1185
+ * })
1186
+ * .subscribe(async (status) => {
1187
+ * if (status === 'SUBSCRIBED') {
1188
+ * await channel.track({ online_at: new Date().toISOString() })
1189
+ * }
1190
+ * })
1191
+ * ```
1192
+ *
1193
+ * @example Listen to presence join
1194
+ * ```js
1195
+ * const channel = supabase.channel('room1')
1196
+ * channel
1197
+ * .on('presence', { event: 'join' }, ({ newPresences }) => {
1198
+ * console.log('Newly joined presences: ', newPresences)
1199
+ * })
1200
+ * .subscribe(async (status) => {
1201
+ * if (status === 'SUBSCRIBED') {
1202
+ * await channel.track({ online_at: new Date().toISOString() })
1203
+ * }
1204
+ * })
1205
+ * ```
1206
+ *
1207
+ * @example Listen to presence leave
1208
+ * ```js
1209
+ * const channel = supabase.channel('room1')
1210
+ * channel
1211
+ * .on('presence', { event: 'leave' }, ({ leftPresences }) => {
1212
+ * console.log('Newly left presences: ', leftPresences)
1213
+ * })
1214
+ * .subscribe(async (status) => {
1215
+ * if (status === 'SUBSCRIBED') {
1216
+ * await channel.track({ online_at: new Date().toISOString() })
1217
+ * await channel.untrack()
1218
+ * }
1219
+ * })
1220
+ * ```
1221
+ *
1222
+ * Registering the same `postgres_changes` filter more than once on a channel is a no-op: the
1223
+ * duplicate is ignored and an error is logged, since the server only ever creates one
1224
+ * subscription per distinct filter.
1225
+ *
1226
+ * @example Listen to all database changes
1227
+ * ```js
1228
+ * supabase
1229
+ * .channel('room1')
1230
+ * .on('postgres_changes', { event: '*', schema: '*' }, payload => {
1231
+ * console.log('Change received!', payload)
1232
+ * })
1233
+ * .subscribe()
1234
+ * ```
1235
+ *
1236
+ * @example Listen to a specific table
1237
+ * ```js
1238
+ * supabase
1239
+ * .channel('room1')
1240
+ * .on('postgres_changes', { event: '*', schema: 'public', table: 'countries' }, payload => {
1241
+ * console.log('Change received!', payload)
1242
+ * })
1243
+ * .subscribe()
1244
+ * ```
1245
+ *
1246
+ * @example Listen to inserts
1247
+ * ```js
1248
+ * supabase
1249
+ * .channel('room1')
1250
+ * .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'countries' }, payload => {
1251
+ * console.log('Change received!', payload)
1252
+ * })
1253
+ * .subscribe()
1254
+ * ```
1255
+ *
1256
+ * @exampleDescription Listen to updates
1257
+ * By default, Supabase will send only the updated record. If you want to receive the previous values as well you can
1258
+ * enable full replication for the table you are listening to:
1259
+ *
1260
+ * ```sql
1261
+ * alter table "your_table" replica identity full;
1262
+ * ```
1263
+ *
1264
+ * @example Listen to updates
1265
+ * ```js
1266
+ * supabase
1267
+ * .channel('room1')
1268
+ * .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'countries' }, payload => {
1269
+ * console.log('Change received!', payload)
1270
+ * })
1271
+ * .subscribe()
1272
+ * ```
1273
+ *
1274
+ * @exampleDescription Listen to deletes
1275
+ * By default, Supabase does not send deleted records. If you want to receive the deleted record you can
1276
+ * enable full replication for the table you are listening to:
1277
+ *
1278
+ * ```sql
1279
+ * alter table "your_table" replica identity full;
1280
+ * ```
1281
+ *
1282
+ * @example Listen to deletes
1283
+ * ```js
1284
+ * supabase
1285
+ * .channel('room1')
1286
+ * .on('postgres_changes', { event: 'DELETE', schema: 'public', table: 'countries' }, payload => {
1287
+ * console.log('Change received!', payload)
1288
+ * })
1289
+ * .subscribe()
1290
+ * ```
1291
+ *
1292
+ * @exampleDescription Listen to multiple events
1293
+ * You can chain listeners if you want to listen to multiple events for each table.
1294
+ *
1295
+ * @example Listen to multiple events
1296
+ * ```js
1297
+ * supabase
1298
+ * .channel('room1')
1299
+ * .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'countries' }, handleRecordInserted)
1300
+ * .on('postgres_changes', { event: 'DELETE', schema: 'public', table: 'countries' }, handleRecordDeleted)
1301
+ * .subscribe()
1302
+ * ```
1303
+ *
1304
+ * @exampleDescription Listen to row level changes
1305
+ * You can listen to individual rows using the format `{table}:{col}=eq.{val}` - where `{col}` is the column name, and `{val}` is the value which you want to match.
1306
+ *
1307
+ * @example Listen to row level changes
1308
+ * ```js
1309
+ * supabase
1310
+ * .channel('room1')
1311
+ * .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'countries', filter: 'id=eq.200' }, handleRecordUpdated)
1312
+ * .subscribe()
1313
+ * ```
1314
+ */
1315
+ on(type, filter, callback) {
1316
+ const stateCheck = this.channelAdapter.isJoined() || this.channelAdapter.isJoining();
1317
+ const typeCheck = type === REALTIME_LISTEN_TYPES.PRESENCE || type === REALTIME_LISTEN_TYPES.POSTGRES_CHANGES;
1318
+ if (stateCheck && typeCheck) {
1319
+ this.socket.log("channel", `cannot add \`${type}\` callbacks for ${this.topic} after \`subscribe()\`.`);
1320
+ throw new Error(`cannot add \`${type}\` callbacks for ${this.topic} after \`subscribe()\`.`);
1321
+ }
1322
+ return this._on(type, filter, callback);
1323
+ }
1324
+ /**
1325
+ * Sends a broadcast message explicitly via REST API.
1326
+ *
1327
+ * This method always uses the REST API endpoint regardless of WebSocket connection state.
1328
+ * Useful when you want to guarantee REST delivery or when gradually migrating from implicit REST fallback.
1329
+ *
1330
+ * Payloads that are `ArrayBuffer` or `ArrayBufferView` (e.g. `Uint8Array`) are sent as
1331
+ * `application/octet-stream`; all other payloads are JSON-encoded.
1332
+ *
1333
+ * @param event The name of the broadcast event
1334
+ * @param payload Payload to be sent (required)
1335
+ * @param opts Options including timeout
1336
+ * @returns Promise resolving to object with success status, and error details if failed
1337
+ *
1338
+ * @category Realtime
1339
+ */
1340
+ async httpSend(event, payload, opts = {}) {
1341
+ var _a;
1342
+ if (payload === void 0 || payload === null) {
1343
+ return Promise.reject(new Error("Payload is required for httpSend()"));
1344
+ }
1345
+ const isBinary = payload instanceof ArrayBuffer || ArrayBuffer.isView(payload);
1346
+ const headers = {
1347
+ apikey: this.socket.apiKey ? this.socket.apiKey : "",
1348
+ "Content-Type": isBinary ? "application/octet-stream" : "application/json"
1349
+ };
1350
+ if (this.socket.accessTokenValue) {
1351
+ headers["Authorization"] = `Bearer ${this.socket.accessTokenValue}`;
1352
+ }
1353
+ const url = new URL(this.broadcastEndpointURL);
1354
+ url.pathname += `/${encodeURIComponent(this.subTopic)}/events/${encodeURIComponent(event)}`;
1355
+ if (this.private) {
1356
+ url.searchParams.set("private", "true");
1357
+ }
1358
+ const options = {
1359
+ method: "POST",
1360
+ headers,
1361
+ body: isBinary ? payload : JSON.stringify(payload)
1362
+ };
1363
+ const response = await this._fetchWithTimeout(url.toString(), options, (_a = opts.timeout) !== null && _a !== void 0 ? _a : this.timeout);
1364
+ if (response.status === 202) {
1365
+ return { success: true };
1366
+ }
1367
+ if (response.status === 404) {
1368
+ return Promise.reject(new Error("httpSend() requires Realtime server v2.97.0 or newer; the endpoint returned 404. Update your Supabase CLI to a recent version, or upgrade the Realtime server in your self-hosted setup. See https://github.com/supabase/supabase-js/blob/master/packages/core/realtime-js/migrations/httpsend-server-version.md"));
1369
+ }
1370
+ let errorMessage = response.statusText;
1371
+ try {
1372
+ const errorBody = await response.json();
1373
+ errorMessage = errorBody.error || errorBody.message || errorMessage;
1374
+ } catch (_b) {
1375
+ }
1376
+ return Promise.reject(new Error(errorMessage));
1377
+ }
1378
+ /**
1379
+ * Sends a message into the channel.
1380
+ *
1381
+ * @param args Arguments to send to channel
1382
+ * @param args.type The type of event to send
1383
+ * @param args.event The name of the event being sent
1384
+ * @param args.payload Payload to be sent
1385
+ * @param opts Options to be used during the send process
1386
+ *
1387
+ * @category Realtime
1388
+ *
1389
+ * @remarks
1390
+ * - When using REST you don't need to subscribe to the channel
1391
+ * - REST calls are only available from 2.37.0 onwards
1392
+ * - If you create a channel only to send a REST broadcast, remove it from
1393
+ * the client when the send completes
1394
+ *
1395
+ * @example Send a message via websocket
1396
+ * ```js
1397
+ * const channel = supabase.channel('room1')
1398
+ *
1399
+ * channel.subscribe((status) => {
1400
+ * if (status === 'SUBSCRIBED') {
1401
+ * channel.send({
1402
+ * type: 'broadcast',
1403
+ * event: 'cursor-pos',
1404
+ * payload: { x: Math.random(), y: Math.random() },
1405
+ * })
1406
+ * }
1407
+ * })
1408
+ * ```
1409
+ *
1410
+ * @exampleResponse Send a message via websocket
1411
+ * ```js
1412
+ * ok | timed out | error
1413
+ * ```
1414
+ *
1415
+ * @example Send a message via REST
1416
+ * ```js
1417
+ * const channel = supabase.channel('room1')
1418
+ *
1419
+ * try {
1420
+ * await channel.httpSend('cursor-pos', { x: Math.random(), y: Math.random() })
1421
+ * } finally {
1422
+ * await supabase.removeChannel(channel)
1423
+ * }
1424
+ * ```
1425
+ */
1426
+ async send(args, opts = {}) {
1427
+ var _a, _b;
1428
+ if (!this.channelAdapter.canPush() && args.type === "broadcast") {
1429
+ const fallbackWarning = "Realtime send() is automatically falling back to REST API. This behavior will be deprecated in the future. Please use httpSend() explicitly for REST delivery.";
1430
+ if (this.socket.hasLogger()) {
1431
+ this.socket.log("channel", fallbackWarning);
1432
+ } else {
1433
+ console.warn(fallbackWarning);
1434
+ }
1435
+ const { event, payload: endpoint_payload } = args;
1436
+ const headers = {
1437
+ apikey: this.socket.apiKey ? this.socket.apiKey : "",
1438
+ "Content-Type": "application/json"
1439
+ };
1440
+ if (this.socket.accessTokenValue) {
1441
+ headers["Authorization"] = `Bearer ${this.socket.accessTokenValue}`;
1442
+ }
1443
+ const options = {
1444
+ method: "POST",
1445
+ headers,
1446
+ body: JSON.stringify({
1447
+ messages: [
1448
+ {
1449
+ topic: this.subTopic,
1450
+ event,
1451
+ payload: endpoint_payload,
1452
+ private: this.private
1453
+ }
1454
+ ]
1455
+ })
1456
+ };
1457
+ try {
1458
+ const response = await this._fetchWithTimeout(this.broadcastEndpointURL, options, (_a = opts.timeout) !== null && _a !== void 0 ? _a : this.timeout);
1459
+ await ((_b = response.body) === null || _b === void 0 ? void 0 : _b.cancel());
1460
+ return response.ok ? "ok" : "error";
1461
+ } catch (error) {
1462
+ if (error instanceof Error && error.name === "AbortError") {
1463
+ return "timed out";
1464
+ } else {
1465
+ return "error";
1466
+ }
1467
+ }
1468
+ } else {
1469
+ return new Promise((resolve) => {
1470
+ var _a2, _b2, _c;
1471
+ const push = this.channelAdapter.push(args.type, args, opts.timeout || this.timeout);
1472
+ if (args.type === "broadcast" && !((_c = (_b2 = (_a2 = this.params) === null || _a2 === void 0 ? void 0 : _a2.config) === null || _b2 === void 0 ? void 0 : _b2.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
1473
+ resolve("ok");
1474
+ }
1475
+ push.receive("ok", () => resolve("ok"));
1476
+ push.receive("error", () => resolve("error"));
1477
+ push.receive("timeout", () => resolve("timed out"));
1478
+ });
1479
+ }
1480
+ }
1481
+ /**
1482
+ * Updates the payload that will be sent the next time the channel joins (reconnects).
1483
+ * Useful for rotating access tokens or updating config without re-creating the channel.
1484
+ *
1485
+ * @category Realtime
1486
+ */
1487
+ updateJoinPayload(payload) {
1488
+ this.channelAdapter.updateJoinPayload(payload);
1489
+ }
1490
+ /**
1491
+ * Leaves the channel.
1492
+ *
1493
+ * Unsubscribes from server events, and instructs channel to terminate on server.
1494
+ * Triggers onClose() hooks.
1495
+ *
1496
+ * To receive leave acknowledgements, use the a `receive` hook to bind to the server ack, ie:
1497
+ * channel.unsubscribe().receive("ok", () => alert("left!") )
1498
+ *
1499
+ * @category Realtime
1500
+ */
1501
+ async unsubscribe(timeout = this.timeout) {
1502
+ return new Promise((resolve) => {
1503
+ this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve("ok")).receive("timeout", () => resolve("timed out")).receive("error", () => resolve("error"));
1504
+ });
1505
+ }
1506
+ /**
1507
+ * Destroys and stops related timers.
1508
+ *
1509
+ * @category Realtime
1510
+ */
1511
+ teardown() {
1512
+ this.channelAdapter.teardown();
1513
+ }
1514
+ /** @internal */
1515
+ async _fetchWithTimeout(url, options, timeout) {
1516
+ const controller = new AbortController();
1517
+ const id = setTimeout(() => controller.abort(), timeout);
1518
+ const response = await this.socket.fetch(url, Object.assign(Object.assign({}, options), { signal: controller.signal }));
1519
+ clearTimeout(id);
1520
+ return response;
1521
+ }
1522
+ /** @internal */
1523
+ _on(type, filter, callback) {
1524
+ var _a;
1525
+ const typeLower = type.toLocaleLowerCase();
1526
+ const filterValue = filter === null || filter === void 0 ? void 0 : filter.filter;
1527
+ if (filterValue instanceof RealtimePostgresFilterBuilder || typeof filterValue === "object" && filterValue !== null && typeof filterValue.build === "function") {
1528
+ filter = Object.assign(Object.assign({}, filter), { filter: filterValue.build() });
1529
+ }
1530
+ if (typeLower === REALTIME_LISTEN_TYPES.POSTGRES_CHANGES) {
1531
+ const duplicate = (_a = this.bindings[typeLower]) === null || _a === void 0 ? void 0 : _a.find((bind) => _RealtimeChannel.isSamePostgresFilter(bind.filter, filter));
1532
+ if (duplicate) {
1533
+ this.socket.log("error", `duplicate \`postgres_changes\` binding for ${this.topic} ignored`, filter);
1534
+ return this;
1535
+ }
1536
+ }
1537
+ const ref = this.channelAdapter.on(type, callback);
1538
+ const binding = {
1539
+ type: typeLower,
1540
+ filter,
1541
+ callback,
1542
+ ref
1543
+ };
1544
+ if (this.bindings[typeLower]) {
1545
+ this.bindings[typeLower].push(binding);
1546
+ } else {
1547
+ this.bindings[typeLower] = [binding];
1548
+ }
1549
+ this._updateFilterMessage();
1550
+ return this;
1551
+ }
1552
+ /**
1553
+ * Registers a callback that will be executed when the channel closes.
1554
+ *
1555
+ * @internal
1556
+ */
1557
+ _onClose(callback) {
1558
+ this.channelAdapter.onClose(callback);
1559
+ }
1560
+ /**
1561
+ * Registers a callback that will be executed when the channel encounteres an error.
1562
+ *
1563
+ * @internal
1564
+ */
1565
+ _onError(callback) {
1566
+ this.channelAdapter.onError(callback);
1567
+ }
1568
+ /** @internal */
1569
+ _updateFilterMessage() {
1570
+ this.channelAdapter.updateFilterBindings((binding, payload, ref) => {
1571
+ var _a, _b, _c, _d, _e, _f, _g;
1572
+ const typeLower = binding.event.toLocaleLowerCase();
1573
+ if (this._notThisChannelEvent(typeLower, ref)) {
1574
+ return false;
1575
+ }
1576
+ const bind = (_a = this.bindings[typeLower]) === null || _a === void 0 ? void 0 : _a.find((bind2) => bind2.ref === binding.ref);
1577
+ if (!bind) {
1578
+ return true;
1579
+ }
1580
+ if (["broadcast", "presence", "postgres_changes"].includes(typeLower)) {
1581
+ if ("id" in bind) {
1582
+ const bindId = bind.id;
1583
+ const bindEvent = (_b = bind.filter) === null || _b === void 0 ? void 0 : _b.event;
1584
+ return bindId && ((_c = payload.ids) === null || _c === void 0 ? void 0 : _c.includes(bindId)) && (bindEvent === "*" || (bindEvent === null || bindEvent === void 0 ? void 0 : bindEvent.toLocaleLowerCase()) === ((_d = payload.data) === null || _d === void 0 ? void 0 : _d.type.toLocaleLowerCase()));
1585
+ } else {
1586
+ const bindEvent = (_f = (_e = bind === null || bind === void 0 ? void 0 : bind.filter) === null || _e === void 0 ? void 0 : _e.event) === null || _f === void 0 ? void 0 : _f.toLocaleLowerCase();
1587
+ return bindEvent === "*" || bindEvent === ((_g = payload === null || payload === void 0 ? void 0 : payload.event) === null || _g === void 0 ? void 0 : _g.toLocaleLowerCase());
1588
+ }
1589
+ } else {
1590
+ return bind.type.toLocaleLowerCase() === typeLower;
1591
+ }
1592
+ });
1593
+ }
1594
+ /** @internal */
1595
+ _notThisChannelEvent(event, ref) {
1596
+ const { close, error, leave, join } = CHANNEL_EVENTS;
1597
+ const events = [close, error, leave, join];
1598
+ return ref && events.includes(event) && ref !== this.joinPush.ref;
1599
+ }
1600
+ /** @internal */
1601
+ _updateFilterTransform() {
1602
+ this.channelAdapter.updatePayloadTransform((event, payload, ref) => {
1603
+ if (typeof payload === "object" && "ids" in payload) {
1604
+ const postgresChanges = payload.data;
1605
+ const { schema, table, commit_timestamp, type, errors } = postgresChanges;
1606
+ const enrichedPayload = {
1607
+ schema,
1608
+ table,
1609
+ commit_timestamp,
1610
+ eventType: type,
1611
+ new: {},
1612
+ old: {},
1613
+ errors
1614
+ };
1615
+ return Object.assign(Object.assign({}, enrichedPayload), this._getPayloadRecords(postgresChanges));
1616
+ }
1617
+ return payload;
1618
+ });
1619
+ }
1620
+ copyBindings(other) {
1621
+ if (this.joinedOnce) {
1622
+ throw new Error("cannot copy bindings into joined channel");
1623
+ }
1624
+ for (const kind in other.bindings) {
1625
+ for (const binding of other.bindings[kind]) {
1626
+ this._on(binding.type, binding.filter, binding.callback);
1627
+ }
1628
+ }
1629
+ }
1630
+ /**
1631
+ * Compares two optional filter values for equality.
1632
+ * Treats undefined, null, and empty string as equivalent empty values.
1633
+ * @internal
1634
+ */
1635
+ static isFilterValueEqual(serverValue, clientValue) {
1636
+ const normalizedServer = serverValue !== null && serverValue !== void 0 ? serverValue : void 0;
1637
+ const normalizedClient = clientValue !== null && clientValue !== void 0 ? clientValue : void 0;
1638
+ return normalizedServer === normalizedClient;
1639
+ }
1640
+ /**
1641
+ * Two `postgres_changes` filters are the same when the server would collapse them into a single
1642
+ * subscription.
1643
+ * @internal
1644
+ */
1645
+ static isSamePostgresFilter(a, b) {
1646
+ var _a, _b, _c, _d;
1647
+ const selectA = (_b = (_a = a === null || a === void 0 ? void 0 : a.select) === null || _a === void 0 ? void 0 : _a.join()) !== null && _b !== void 0 ? _b : void 0;
1648
+ const selectB = (_d = (_c = b === null || b === void 0 ? void 0 : b.select) === null || _c === void 0 ? void 0 : _c.join()) !== null && _d !== void 0 ? _d : void 0;
1649
+ return (a === null || a === void 0 ? void 0 : a.event) === (b === null || b === void 0 ? void 0 : b.event) && _RealtimeChannel.isFilterValueEqual(a === null || a === void 0 ? void 0 : a.schema, b === null || b === void 0 ? void 0 : b.schema) && _RealtimeChannel.isFilterValueEqual(a === null || a === void 0 ? void 0 : a.table, b === null || b === void 0 ? void 0 : b.table) && _RealtimeChannel.isFilterValueEqual(a === null || a === void 0 ? void 0 : a.filter, b === null || b === void 0 ? void 0 : b.filter) && selectA === selectB;
1650
+ }
1651
+ /** @internal */
1652
+ _getPayloadRecords(payload) {
1653
+ const records = {
1654
+ new: {},
1655
+ old: {}
1656
+ };
1657
+ if (payload.type === "INSERT" || payload.type === "UPDATE") {
1658
+ records.new = convertChangeData(payload.columns, payload.record);
1659
+ }
1660
+ if (payload.type === "UPDATE" || payload.type === "DELETE") {
1661
+ records.old = convertChangeData(payload.columns, payload.old_record);
1662
+ }
1663
+ return records;
1664
+ }
1665
+ };
1666
+
1667
+ export { AuthApiError, AuthError, REALTIME_LISTEN_TYPES, REALTIME_POSTGRES_CHANGES_LISTEN_EVENT, REALTIME_PRESENCE_LISTEN_EVENTS, REALTIME_SUBSCRIBE_STATES, RealtimeChannel, createClient };
1668
+ //# sourceMappingURL=index.js.map
1669
+ //# sourceMappingURL=index.js.map