@supabase/realtime-js 2.108.3-canary.1 → 2.109.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/README.md +114 -0
- package/dist/main/RealtimeChannel.d.ts +89 -3
- package/dist/main/RealtimeChannel.d.ts.map +1 -1
- package/dist/main/RealtimeChannel.js +16 -1
- package/dist/main/RealtimeChannel.js.map +1 -1
- package/dist/main/RealtimePostgresFilterBuilder.d.ts +132 -0
- package/dist/main/RealtimePostgresFilterBuilder.d.ts.map +1 -0
- package/dist/main/RealtimePostgresFilterBuilder.js +165 -0
- package/dist/main/RealtimePostgresFilterBuilder.js.map +1 -0
- package/dist/main/index.d.ts +2 -2
- package/dist/main/index.d.ts.map +1 -1
- package/dist/main/index.js +3 -1
- package/dist/main/index.js.map +1 -1
- package/dist/main/lib/constants.d.ts +2 -2
- package/dist/main/lib/constants.d.ts.map +1 -1
- package/dist/main/lib/version.d.ts +1 -1
- package/dist/main/lib/version.d.ts.map +1 -1
- package/dist/main/lib/version.js +1 -1
- package/dist/main/lib/version.js.map +1 -1
- package/dist/module/RealtimeChannel.d.ts +89 -3
- package/dist/module/RealtimeChannel.d.ts.map +1 -1
- package/dist/module/RealtimeChannel.js +13 -0
- package/dist/module/RealtimeChannel.js.map +1 -1
- package/dist/module/RealtimePostgresFilterBuilder.d.ts +132 -0
- package/dist/module/RealtimePostgresFilterBuilder.d.ts.map +1 -0
- package/dist/module/RealtimePostgresFilterBuilder.js +160 -0
- package/dist/module/RealtimePostgresFilterBuilder.js.map +1 -0
- package/dist/module/index.d.ts +2 -2
- package/dist/module/index.d.ts.map +1 -1
- package/dist/module/index.js +2 -2
- package/dist/module/index.js.map +1 -1
- package/dist/module/lib/constants.d.ts +2 -2
- package/dist/module/lib/constants.d.ts.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.d.ts.map +1 -1
- package/dist/module/lib/version.js +1 -1
- package/dist/module/lib/version.js.map +1 -1
- package/dist/tsconfig.module.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/RealtimeChannel.ts +116 -4
- package/src/RealtimePostgresFilterBuilder.ts +253 -0
- package/src/index.ts +8 -0
- package/src/lib/version.ts +1 -1
package/src/RealtimeChannel.ts
CHANGED
|
@@ -13,6 +13,14 @@ import { normalizeChannelError } from './lib/normalizeChannelError'
|
|
|
13
13
|
import ChannelAdapter from './phoenix/channelAdapter'
|
|
14
14
|
import { ChannelBindingCallback, ChannelOnErrorCallback } from './phoenix/types'
|
|
15
15
|
import type { Timer } from './phoenix/types'
|
|
16
|
+
import { RealtimePostgresFilterBuilder } from './RealtimePostgresFilterBuilder'
|
|
17
|
+
import type { RealtimePostgresChangesFilterOperator } from './RealtimePostgresFilterBuilder'
|
|
18
|
+
|
|
19
|
+
export type { RealtimePostgresChangesFilterOperator } from './RealtimePostgresFilterBuilder'
|
|
20
|
+
export {
|
|
21
|
+
RealtimePostgresFilterBuilder,
|
|
22
|
+
postgresChangesFilter,
|
|
23
|
+
} from './RealtimePostgresFilterBuilder'
|
|
16
24
|
|
|
17
25
|
type ReplayOption = {
|
|
18
26
|
since: number
|
|
@@ -25,8 +33,18 @@ export type RealtimeChannelOptions = {
|
|
|
25
33
|
* self option enables client to receive message it broadcast
|
|
26
34
|
* ack option instructs server to acknowledge that broadcast message was received
|
|
27
35
|
* replay option instructs server to replay broadcast messages
|
|
36
|
+
* replication_ready option instructs the server to emit a `system` event once the
|
|
37
|
+
* Postgres replication connection backing this channel is established and ready to
|
|
38
|
+
* stream changes. Listen for it with `channel.on('system', {}, (payload) => ...)`;
|
|
39
|
+
* the payload's `status` is `'ok'` (`message: 'Replication connection established'`)
|
|
40
|
+
* on success or `'error'` if the connection is not ready in time.
|
|
28
41
|
*/
|
|
29
|
-
broadcast?: {
|
|
42
|
+
broadcast?: {
|
|
43
|
+
self?: boolean
|
|
44
|
+
ack?: boolean
|
|
45
|
+
replay?: ReplayOption
|
|
46
|
+
replication_ready?: boolean
|
|
47
|
+
}
|
|
30
48
|
/**
|
|
31
49
|
* key option is used to track presence payload across clients
|
|
32
50
|
*/
|
|
@@ -120,13 +138,67 @@ export type RealtimePostgresChangesFilter<T extends `${REALTIME_POSTGRES_CHANGES
|
|
|
120
138
|
*/
|
|
121
139
|
table?: string
|
|
122
140
|
/**
|
|
123
|
-
* Receive database changes when filter is matched.
|
|
141
|
+
* Receive database changes only when the filter is matched.
|
|
142
|
+
*
|
|
143
|
+
* A filter is a `column=operator.value` expression, e.g. `id=eq.1` or
|
|
144
|
+
* `title=like.%foo%`. See {@link RealtimePostgresChangesFilterOperator} for
|
|
145
|
+
* the available operators.
|
|
146
|
+
*
|
|
147
|
+
* Multiple filters can be combined with commas; they are applied as an `AND`
|
|
148
|
+
* condition: `filter: 'id=gt.0,id=lt.100'`.
|
|
149
|
+
*
|
|
150
|
+
* Any operator can be negated with the `not.` prefix: `filter: 'status=not.in.(draft,archived)'`.
|
|
151
|
+
*
|
|
152
|
+
* The server splits conditions on commas outside quotes/parentheses. To
|
|
153
|
+
* include a reserved character (`,`, `(`, `)`) in a value, wrap it in double
|
|
154
|
+
* quotes PostgREST-style: `name=eq."a,b"`. The {@link RealtimePostgresFilterBuilder}
|
|
155
|
+
* does this quoting for you.
|
|
156
|
+
*
|
|
157
|
+
* Instead of a raw string you can pass a {@link RealtimePostgresFilterBuilder}
|
|
158
|
+
* (via `postgresChangesFilter()`) for a type-checked, ergonomic way to compose filters; the
|
|
159
|
+
* SDK serializes it to a string automatically.
|
|
160
|
+
*/
|
|
161
|
+
filter?: string | RealtimePostgresFilterBuilder
|
|
162
|
+
/**
|
|
163
|
+
* Restrict the change payload to a subset of columns instead of receiving the
|
|
164
|
+
* full row. Reduces payload size (helpful for large `bytea`/`jsonb` columns)
|
|
165
|
+
* and the data transferred per event.
|
|
166
|
+
*
|
|
167
|
+
* The listed columns must be selectable by the subscribing role.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* channel.on('postgres_changes', {
|
|
171
|
+
* event: '*',
|
|
172
|
+
* schema: 'public',
|
|
173
|
+
* table: 'users',
|
|
174
|
+
* select: ['id', 'first_name'],
|
|
175
|
+
* }, (payload) => {
|
|
176
|
+
* // payload.new only contains { id, first_name }
|
|
177
|
+
* })
|
|
124
178
|
*/
|
|
125
|
-
|
|
179
|
+
select?: string[]
|
|
126
180
|
}
|
|
127
181
|
|
|
128
182
|
export type RealtimeChannelSendResponse = 'ok' | 'timed out' | 'error' | (string & {})
|
|
129
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Payload of a `system` event emitted by the server.
|
|
186
|
+
*
|
|
187
|
+
* Most notably, when a channel is created with `config.broadcast.replication_ready: true`,
|
|
188
|
+
* the server sends one of these once the Postgres replication connection is ready
|
|
189
|
+
* (`status: 'ok'`) or fails to become ready in time (`status: 'error'`).
|
|
190
|
+
*/
|
|
191
|
+
export type RealtimeSystemPayload = {
|
|
192
|
+
/** The extension that produced the message, e.g. `'system'` or `'postgres_changes'`. */
|
|
193
|
+
extension: 'system' | 'postgres_changes' | (string & {})
|
|
194
|
+
/** `'ok'` on success, `'error'` on failure. */
|
|
195
|
+
status: 'ok' | 'error' | (string & {})
|
|
196
|
+
/** Human-readable description, e.g. `'Replication connection established'`. */
|
|
197
|
+
message: string
|
|
198
|
+
/** The channel (sub)topic the message refers to. */
|
|
199
|
+
channel: string
|
|
200
|
+
}
|
|
201
|
+
|
|
130
202
|
export enum REALTIME_POSTGRES_CHANGES_LISTEN_EVENT {
|
|
131
203
|
ALL = '*',
|
|
132
204
|
INSERT = 'INSERT',
|
|
@@ -157,6 +229,7 @@ type PostgresChangesFilters = {
|
|
|
157
229
|
schema?: string
|
|
158
230
|
table?: string
|
|
159
231
|
filter?: string
|
|
232
|
+
select?: string[]
|
|
160
233
|
}[]
|
|
161
234
|
}
|
|
162
235
|
|
|
@@ -569,6 +642,31 @@ export default class RealtimeChannel {
|
|
|
569
642
|
payload: RealtimeBroadcastDeletePayload<T>
|
|
570
643
|
}) => void
|
|
571
644
|
): RealtimeChannel
|
|
645
|
+
/**
|
|
646
|
+
* Listen for `system` events on this channel.
|
|
647
|
+
*
|
|
648
|
+
* The payload follows the {@link RealtimeSystemPayload} shape. Opt in to the replication-ready
|
|
649
|
+
* notification with `config.broadcast.replication_ready: true` when creating the channel, then
|
|
650
|
+
* watch for `payload.status === 'ok'` to know the Postgres replication connection is ready.
|
|
651
|
+
*
|
|
652
|
+
* @example Know when the replication connection is ready
|
|
653
|
+
* ```js
|
|
654
|
+
* const channel = supabase.channel('room1', {
|
|
655
|
+
* config: { broadcast: { replication_ready: true } },
|
|
656
|
+
* })
|
|
657
|
+
*
|
|
658
|
+
* channel
|
|
659
|
+
* .on('postgres_changes', { event: '*', schema: 'public', table: 'messages' }, (payload) => {
|
|
660
|
+
* console.log('Change received!', payload)
|
|
661
|
+
* })
|
|
662
|
+
* .on('system', {}, (payload) => {
|
|
663
|
+
* if (payload.extension === 'system' && payload.status === 'ok') {
|
|
664
|
+
* console.log('Replication connection is ready:', payload.message)
|
|
665
|
+
* }
|
|
666
|
+
* })
|
|
667
|
+
* .subscribe()
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
572
670
|
on<T extends { [key: string]: any }>(
|
|
573
671
|
type: `${REALTIME_LISTEN_TYPES.SYSTEM}`,
|
|
574
672
|
filter: {},
|
|
@@ -735,7 +833,7 @@ export default class RealtimeChannel {
|
|
|
735
833
|
*/
|
|
736
834
|
on(
|
|
737
835
|
type: `${REALTIME_LISTEN_TYPES}`,
|
|
738
|
-
filter: { event: string; [key: string]:
|
|
836
|
+
filter: { event: string; [key: string]: any },
|
|
739
837
|
callback: (payload: any) => void
|
|
740
838
|
): RealtimeChannel {
|
|
741
839
|
const stateCheck = this.channelAdapter.isJoined() || this.channelAdapter.isJoining()
|
|
@@ -1007,6 +1105,20 @@ export default class RealtimeChannel {
|
|
|
1007
1105
|
_on(type: string, filter: { [key: string]: any }, callback: ChannelBindingCallback) {
|
|
1008
1106
|
const typeLower = type.toLocaleLowerCase()
|
|
1009
1107
|
|
|
1108
|
+
// Serialize a postgres_changes filter builder into its string form so the
|
|
1109
|
+
// rest of the pipeline (join payload, server binding match) sees a string.
|
|
1110
|
+
// Duck-type `build()` in addition to `instanceof` so a builder constructed
|
|
1111
|
+
// against a duplicate copy of the package (separate module realm) still works.
|
|
1112
|
+
const filterValue = filter?.filter
|
|
1113
|
+
if (
|
|
1114
|
+
filterValue instanceof RealtimePostgresFilterBuilder ||
|
|
1115
|
+
(typeof filterValue === 'object' &&
|
|
1116
|
+
filterValue !== null &&
|
|
1117
|
+
typeof (filterValue as { build?: unknown }).build === 'function')
|
|
1118
|
+
) {
|
|
1119
|
+
filter = { ...filter, filter: (filterValue as RealtimePostgresFilterBuilder).build() }
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1010
1122
|
const ref = this.channelAdapter.on(type, callback)
|
|
1011
1123
|
|
|
1012
1124
|
const binding: Binding = {
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comparison operators accepted in a Postgres Changes `filter` string.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the PostgREST operator surface and are evaluated server-side.
|
|
5
|
+
* Any operator can be negated via {@link RealtimePostgresFilterBuilder.not}
|
|
6
|
+
* (the `not.` prefix).
|
|
7
|
+
*
|
|
8
|
+
* This is the subset of PostgREST's `FilterOperator` (see `postgrest-js`) that
|
|
9
|
+
* Realtime Postgres Changes supports. Containment, range and full-text search
|
|
10
|
+
* operators (`cs`, `cd`, `ov`, range ops, `fts`, …) are intentionally not
|
|
11
|
+
* included because the Realtime server does not evaluate them.
|
|
12
|
+
*
|
|
13
|
+
* - `eq`, `neq`, `lt`, `lte`, `gt`, `gte` — comparison
|
|
14
|
+
* - `in` — membership: `status=in.(active,pending)`
|
|
15
|
+
* - `like`, `ilike` — pattern match (case-sensitive / insensitive): `title=like.%foo%`
|
|
16
|
+
* - `is` — `IS` check against `null` / `true` / `false` / `unknown`: `deleted_at=is.null`
|
|
17
|
+
* - `match`, `imatch` — POSIX regex match (`~` / `~*`)
|
|
18
|
+
* - `isdistinct` — NULL-safe inequality (`IS DISTINCT FROM`)
|
|
19
|
+
*/
|
|
20
|
+
export type RealtimePostgresChangesFilterOperator =
|
|
21
|
+
| 'eq'
|
|
22
|
+
| 'neq'
|
|
23
|
+
| 'lt'
|
|
24
|
+
| 'lte'
|
|
25
|
+
| 'gt'
|
|
26
|
+
| 'gte'
|
|
27
|
+
| 'in'
|
|
28
|
+
| 'like'
|
|
29
|
+
| 'ilike'
|
|
30
|
+
| 'is'
|
|
31
|
+
| 'match'
|
|
32
|
+
| 'imatch'
|
|
33
|
+
| 'isdistinct'
|
|
34
|
+
|
|
35
|
+
/** Scalar value accepted by a single filter operator. */
|
|
36
|
+
export type RealtimeFilterValue = string | number | boolean | null
|
|
37
|
+
|
|
38
|
+
/** Value accepted by the `is` operator. */
|
|
39
|
+
export type RealtimeIsFilterValue = null | boolean | 'null' | 'true' | 'false' | 'unknown'
|
|
40
|
+
|
|
41
|
+
// Reserved characters that force PostgREST-style quoting: `[,()]` (which the
|
|
42
|
+
// server reads as condition/list delimiters) plus `"`/`\` (escaped inside quotes).
|
|
43
|
+
const PostgrestReservedCharsRegexp = /[,()"\\]/
|
|
44
|
+
|
|
45
|
+
const needsQuoting = (value: string): boolean =>
|
|
46
|
+
PostgrestReservedCharsRegexp.test(value) || value !== value.trim()
|
|
47
|
+
|
|
48
|
+
const quote = (value: string): string => `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`
|
|
49
|
+
|
|
50
|
+
const serializeScalar = (value: RealtimeFilterValue): string => {
|
|
51
|
+
const serialized = value === null ? 'null' : String(value)
|
|
52
|
+
return needsQuoting(serialized) ? quote(serialized) : serialized
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const serializeIsValue = (value: RealtimeIsFilterValue): string =>
|
|
56
|
+
value === null ? 'null' : String(value)
|
|
57
|
+
|
|
58
|
+
// Builds the `operator.value` portion of a filter (everything after `column=`).
|
|
59
|
+
const serialize = (operator: RealtimePostgresChangesFilterOperator, value: unknown): string => {
|
|
60
|
+
if (operator === 'in') {
|
|
61
|
+
const values = Array.isArray(value) ? value : [value]
|
|
62
|
+
if (values.length === 0) {
|
|
63
|
+
throw new Error('Realtime `in` filter requires at least one value.')
|
|
64
|
+
}
|
|
65
|
+
const items = Array.from(new Set(values))
|
|
66
|
+
.map((v) => serializeScalar(v as RealtimeFilterValue))
|
|
67
|
+
.join(',')
|
|
68
|
+
return `in.(${items})`
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (operator === 'is') {
|
|
72
|
+
return `is.${serializeIsValue(value as RealtimeIsFilterValue)}`
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return `${operator}.${serializeScalar(value as RealtimeFilterValue)}`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Fluent builder for Postgres Changes `filter` strings.
|
|
80
|
+
*
|
|
81
|
+
* Each method appends a single `column=operator.value` condition. Multiple
|
|
82
|
+
* conditions are combined with commas, which the Realtime server applies as an
|
|
83
|
+
* `AND`. Pass an instance straight to `channel.on('postgres_changes', …)` — the
|
|
84
|
+
* SDK serializes it to a string automatically — or call {@link build} to obtain
|
|
85
|
+
* the string yourself.
|
|
86
|
+
*
|
|
87
|
+
* The builder mirrors the `postgrest-js` filter API (`eq`, `neq`, `in`, `like`,
|
|
88
|
+
* `not`, …) for the operators that Realtime supports. Values containing reserved
|
|
89
|
+
* characters (`,`, `(`, `)`, `"`, `\`) — or surrounding whitespace — are
|
|
90
|
+
* automatically double-quoted and escaped the same way PostgREST does, so they
|
|
91
|
+
* survive the server's filter parser; all other values are sent verbatim.
|
|
92
|
+
*
|
|
93
|
+
* The filter is snapshotted when passed to `channel.on(...)`; mutating the
|
|
94
|
+
* builder afterwards does not affect an existing subscription. An empty builder
|
|
95
|
+
* serializes to `''`, which the server treats as "no filter".
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* channel.on('postgres_changes', {
|
|
99
|
+
* event: '*',
|
|
100
|
+
* schema: 'public',
|
|
101
|
+
* table: 'users',
|
|
102
|
+
* filter: postgresChangesFilter().eq('id', 1).lt('age', 30), // → 'id=eq.1,age=lt.30'
|
|
103
|
+
* }, (payload) => { ... })
|
|
104
|
+
*/
|
|
105
|
+
export class RealtimePostgresFilterBuilder {
|
|
106
|
+
private readonly filters: string[] = []
|
|
107
|
+
|
|
108
|
+
private add(
|
|
109
|
+
column: string,
|
|
110
|
+
operator: RealtimePostgresChangesFilterOperator,
|
|
111
|
+
value: unknown,
|
|
112
|
+
negate = false
|
|
113
|
+
): this {
|
|
114
|
+
const prefix = negate ? 'not.' : ''
|
|
115
|
+
this.filters.push(`${column}=${prefix}${serialize(operator, value)}`)
|
|
116
|
+
return this
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Match rows where `column` equals `value` (`column=eq.value`). */
|
|
120
|
+
eq(column: string, value: RealtimeFilterValue): this {
|
|
121
|
+
return this.add(column, 'eq', value)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Match rows where `column` does not equal `value` (`column=neq.value`). */
|
|
125
|
+
neq(column: string, value: RealtimeFilterValue): this {
|
|
126
|
+
return this.add(column, 'neq', value)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Match rows where `column` is greater than `value` (`column=gt.value`). */
|
|
130
|
+
gt(column: string, value: RealtimeFilterValue): this {
|
|
131
|
+
return this.add(column, 'gt', value)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Match rows where `column` is greater than or equal to `value` (`column=gte.value`). */
|
|
135
|
+
gte(column: string, value: RealtimeFilterValue): this {
|
|
136
|
+
return this.add(column, 'gte', value)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Match rows where `column` is less than `value` (`column=lt.value`). */
|
|
140
|
+
lt(column: string, value: RealtimeFilterValue): this {
|
|
141
|
+
return this.add(column, 'lt', value)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Match rows where `column` is less than or equal to `value` (`column=lte.value`). */
|
|
145
|
+
lte(column: string, value: RealtimeFilterValue): this {
|
|
146
|
+
return this.add(column, 'lte', value)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Match rows where `column` is one of `values` (`column=in.(a,b,c)`).
|
|
151
|
+
* Requires at least one value; duplicates are removed. An element containing a
|
|
152
|
+
* reserved character is double-quoted (`in.("a,b",c)`), so commas inside an
|
|
153
|
+
* element are preserved. `null` is intentionally not accepted (`IN (null)`
|
|
154
|
+
* never matches in SQL) — use `is`/`not('col','is',null)` for null checks.
|
|
155
|
+
*/
|
|
156
|
+
in(column: string, values: ReadonlyArray<string | number | boolean>): this {
|
|
157
|
+
return this.add(column, 'in', values)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Match rows where `column` matches the case-sensitive `pattern` (`column=like.pattern`). */
|
|
161
|
+
like(column: string, pattern: string): this {
|
|
162
|
+
return this.add(column, 'like', pattern)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Match rows where `column` matches the case-insensitive `pattern` (`column=ilike.pattern`). */
|
|
166
|
+
ilike(column: string, pattern: string): this {
|
|
167
|
+
return this.add(column, 'ilike', pattern)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Match rows where `column` matches the POSIX regex `pattern` (`column=match.pattern`). */
|
|
171
|
+
match(column: string, pattern: string): this {
|
|
172
|
+
return this.add(column, 'match', pattern)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Match rows where `column` matches the case-insensitive POSIX regex `pattern` (`column=imatch.pattern`). */
|
|
176
|
+
imatch(column: string, pattern: string): this {
|
|
177
|
+
return this.add(column, 'imatch', pattern)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Match rows where `column` `IS` the given value (`column=is.null`).
|
|
182
|
+
* Accepts `null`, a boolean, or the keywords `'null' | 'true' | 'false' | 'unknown'`.
|
|
183
|
+
*/
|
|
184
|
+
is(column: string, value: RealtimeIsFilterValue): this {
|
|
185
|
+
return this.add(column, 'is', value)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Match rows where `column` is distinct from `value` (`column=isdistinct.value`). NULL-safe inequality. */
|
|
189
|
+
isDistinct(column: string, value: RealtimeFilterValue): this {
|
|
190
|
+
return this.add(column, 'isdistinct', value)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Negate any operator with the `not.` prefix (`column=not.operator.value`).
|
|
195
|
+
* `in` takes an array, `is` takes an `IS` keyword/boolean/null, and every
|
|
196
|
+
* other operator takes a scalar value.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* postgresChangesFilter().not('status', 'in', ['draft', 'archived'])
|
|
200
|
+
* // → status=not.in.(draft,archived)
|
|
201
|
+
* postgresChangesFilter().not('deleted_at', 'is', null)
|
|
202
|
+
* // → deleted_at=not.is.null
|
|
203
|
+
*/
|
|
204
|
+
not(column: string, operator: 'in', value: ReadonlyArray<string | number | boolean>): this
|
|
205
|
+
not(column: string, operator: 'is', value: RealtimeIsFilterValue): this
|
|
206
|
+
not(
|
|
207
|
+
column: string,
|
|
208
|
+
operator: Exclude<RealtimePostgresChangesFilterOperator, 'in' | 'is'>,
|
|
209
|
+
value: RealtimeFilterValue
|
|
210
|
+
): this
|
|
211
|
+
not(
|
|
212
|
+
column: string,
|
|
213
|
+
operator: RealtimePostgresChangesFilterOperator,
|
|
214
|
+
value: RealtimeFilterValue | ReadonlyArray<string | number | boolean>
|
|
215
|
+
): this {
|
|
216
|
+
return this.add(column, operator, value, true)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Serialize all conditions into the comma-separated (AND) filter string.
|
|
221
|
+
*
|
|
222
|
+
* Conditions are joined by commas, which the server applies as `AND`. A scalar
|
|
223
|
+
* value (or single `in` element) that contains a reserved character — `,`,
|
|
224
|
+
* `(`, `)`, `"`, `\` — or surrounding whitespace is double-quoted and escaped
|
|
225
|
+
* the way PostgREST does, so commas inside a value are preserved rather than
|
|
226
|
+
* read as a condition boundary.
|
|
227
|
+
*/
|
|
228
|
+
build(): string {
|
|
229
|
+
return this.filters.join(',')
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Alias for {@link build}; lets the builder be used wherever a string is expected. */
|
|
233
|
+
toString(): string {
|
|
234
|
+
return this.build()
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Create a {@link RealtimePostgresFilterBuilder} for composing a Postgres
|
|
240
|
+
* Changes `filter`. Conditions are combined with `AND`.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* import { postgresChangesFilter } from '@supabase/realtime-js'
|
|
244
|
+
*
|
|
245
|
+
* channel.on('postgres_changes', {
|
|
246
|
+
* event: 'UPDATE',
|
|
247
|
+
* schema: 'public',
|
|
248
|
+
* table: 'orders',
|
|
249
|
+
* filter: postgresChangesFilter().gt('amount', 100).eq('status', 'open'),
|
|
250
|
+
* }, (payload) => { ... })
|
|
251
|
+
*/
|
|
252
|
+
export const postgresChangesFilter = (): RealtimePostgresFilterBuilder =>
|
|
253
|
+
new RealtimePostgresFilterBuilder()
|
package/src/index.ts
CHANGED
|
@@ -8,10 +8,14 @@ import RealtimeChannel, {
|
|
|
8
8
|
RealtimeChannelOptions,
|
|
9
9
|
RealtimeChannelSendResponse,
|
|
10
10
|
RealtimePostgresChangesFilter,
|
|
11
|
+
RealtimePostgresChangesFilterOperator,
|
|
12
|
+
RealtimePostgresFilterBuilder,
|
|
13
|
+
postgresChangesFilter,
|
|
11
14
|
RealtimePostgresChangesPayload,
|
|
12
15
|
RealtimePostgresInsertPayload,
|
|
13
16
|
RealtimePostgresUpdatePayload,
|
|
14
17
|
RealtimePostgresDeletePayload,
|
|
18
|
+
RealtimeSystemPayload,
|
|
15
19
|
REALTIME_LISTEN_TYPES,
|
|
16
20
|
REALTIME_POSTGRES_CHANGES_LISTEN_EVENT,
|
|
17
21
|
REALTIME_SUBSCRIBE_STATES,
|
|
@@ -34,10 +38,14 @@ export {
|
|
|
34
38
|
RealtimeClientOptions,
|
|
35
39
|
RealtimeMessage,
|
|
36
40
|
RealtimePostgresChangesFilter,
|
|
41
|
+
RealtimePostgresChangesFilterOperator,
|
|
42
|
+
RealtimePostgresFilterBuilder,
|
|
43
|
+
postgresChangesFilter,
|
|
37
44
|
RealtimePostgresChangesPayload,
|
|
38
45
|
RealtimePostgresInsertPayload,
|
|
39
46
|
RealtimePostgresUpdatePayload,
|
|
40
47
|
RealtimePostgresDeletePayload,
|
|
48
|
+
RealtimeSystemPayload,
|
|
41
49
|
RealtimePresenceJoinPayload,
|
|
42
50
|
RealtimePresenceLeavePayload,
|
|
43
51
|
RealtimePresenceState,
|
package/src/lib/version.ts
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
// - Debugging and support (identifying which version is running)
|
|
5
5
|
// - Telemetry and logging (version reporting in errors/analytics)
|
|
6
6
|
// - Ensuring build artifacts match the published package version
|
|
7
|
-
export const version = '2.
|
|
7
|
+
export const version = '2.109.0'
|