@depup/supabase__realtime-js 2.99.3-depup.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.
Files changed (104) hide show
  1. package/README.md +32 -0
  2. package/changes.json +14 -0
  3. package/dist/main/RealtimeChannel.d.ts +370 -0
  4. package/dist/main/RealtimeChannel.d.ts.map +1 -0
  5. package/dist/main/RealtimeChannel.js +644 -0
  6. package/dist/main/RealtimeChannel.js.map +1 -0
  7. package/dist/main/RealtimeClient.d.ts +238 -0
  8. package/dist/main/RealtimeClient.d.ts.map +1 -0
  9. package/dist/main/RealtimeClient.js +870 -0
  10. package/dist/main/RealtimeClient.js.map +1 -0
  11. package/dist/main/RealtimePresence.d.ts +76 -0
  12. package/dist/main/RealtimePresence.d.ts.map +1 -0
  13. package/dist/main/RealtimePresence.js +237 -0
  14. package/dist/main/RealtimePresence.js.map +1 -0
  15. package/dist/main/index.d.ts +6 -0
  16. package/dist/main/index.d.ts.map +1 -0
  17. package/dist/main/index.js +18 -0
  18. package/dist/main/index.js.map +1 -0
  19. package/dist/main/lib/constants.d.ts +39 -0
  20. package/dist/main/lib/constants.d.ts.map +1 -0
  21. package/dist/main/lib/constants.js +48 -0
  22. package/dist/main/lib/constants.js.map +1 -0
  23. package/dist/main/lib/push.d.ts +48 -0
  24. package/dist/main/lib/push.d.ts.map +1 -0
  25. package/dist/main/lib/push.js +102 -0
  26. package/dist/main/lib/push.js.map +1 -0
  27. package/dist/main/lib/serializer.d.ts +33 -0
  28. package/dist/main/lib/serializer.d.ts.map +1 -0
  29. package/dist/main/lib/serializer.js +155 -0
  30. package/dist/main/lib/serializer.js.map +1 -0
  31. package/dist/main/lib/timer.d.ts +22 -0
  32. package/dist/main/lib/timer.d.ts.map +1 -0
  33. package/dist/main/lib/timer.js +39 -0
  34. package/dist/main/lib/timer.js.map +1 -0
  35. package/dist/main/lib/transformers.d.ts +109 -0
  36. package/dist/main/lib/transformers.d.ts.map +1 -0
  37. package/dist/main/lib/transformers.js +241 -0
  38. package/dist/main/lib/transformers.js.map +1 -0
  39. package/dist/main/lib/version.d.ts +2 -0
  40. package/dist/main/lib/version.d.ts.map +1 -0
  41. package/dist/main/lib/version.js +11 -0
  42. package/dist/main/lib/version.js.map +1 -0
  43. package/dist/main/lib/websocket-factory.d.ts +81 -0
  44. package/dist/main/lib/websocket-factory.d.ts.map +1 -0
  45. package/dist/main/lib/websocket-factory.js +131 -0
  46. package/dist/main/lib/websocket-factory.js.map +1 -0
  47. package/dist/module/RealtimeChannel.d.ts +370 -0
  48. package/dist/module/RealtimeChannel.d.ts.map +1 -0
  49. package/dist/module/RealtimeChannel.js +639 -0
  50. package/dist/module/RealtimeChannel.js.map +1 -0
  51. package/dist/module/RealtimeClient.d.ts +238 -0
  52. package/dist/module/RealtimeClient.d.ts.map +1 -0
  53. package/dist/module/RealtimeClient.js +866 -0
  54. package/dist/module/RealtimeClient.js.map +1 -0
  55. package/dist/module/RealtimePresence.d.ts +76 -0
  56. package/dist/module/RealtimePresence.d.ts.map +1 -0
  57. package/dist/module/RealtimePresence.js +233 -0
  58. package/dist/module/RealtimePresence.js.map +1 -0
  59. package/dist/module/index.d.ts +6 -0
  60. package/dist/module/index.d.ts.map +1 -0
  61. package/dist/module/index.js +6 -0
  62. package/dist/module/index.js.map +1 -0
  63. package/dist/module/lib/constants.d.ts +39 -0
  64. package/dist/module/lib/constants.d.ts.map +1 -0
  65. package/dist/module/lib/constants.js +45 -0
  66. package/dist/module/lib/constants.js.map +1 -0
  67. package/dist/module/lib/push.d.ts +48 -0
  68. package/dist/module/lib/push.d.ts.map +1 -0
  69. package/dist/module/lib/push.js +99 -0
  70. package/dist/module/lib/push.js.map +1 -0
  71. package/dist/module/lib/serializer.d.ts +33 -0
  72. package/dist/module/lib/serializer.d.ts.map +1 -0
  73. package/dist/module/lib/serializer.js +152 -0
  74. package/dist/module/lib/serializer.js.map +1 -0
  75. package/dist/module/lib/timer.d.ts +22 -0
  76. package/dist/module/lib/timer.d.ts.map +1 -0
  77. package/dist/module/lib/timer.js +36 -0
  78. package/dist/module/lib/timer.js.map +1 -0
  79. package/dist/module/lib/transformers.d.ts +109 -0
  80. package/dist/module/lib/transformers.d.ts.map +1 -0
  81. package/dist/module/lib/transformers.js +229 -0
  82. package/dist/module/lib/transformers.js.map +1 -0
  83. package/dist/module/lib/version.d.ts +2 -0
  84. package/dist/module/lib/version.d.ts.map +1 -0
  85. package/dist/module/lib/version.js +8 -0
  86. package/dist/module/lib/version.js.map +1 -0
  87. package/dist/module/lib/websocket-factory.d.ts +81 -0
  88. package/dist/module/lib/websocket-factory.d.ts.map +1 -0
  89. package/dist/module/lib/websocket-factory.js +127 -0
  90. package/dist/module/lib/websocket-factory.js.map +1 -0
  91. package/dist/tsconfig.module.tsbuildinfo +1 -0
  92. package/dist/tsconfig.tsbuildinfo +1 -0
  93. package/package.json +85 -0
  94. package/src/RealtimeChannel.ts +1039 -0
  95. package/src/RealtimeClient.ts +1023 -0
  96. package/src/RealtimePresence.ts +346 -0
  97. package/src/index.ts +53 -0
  98. package/src/lib/constants.ts +49 -0
  99. package/src/lib/push.ts +121 -0
  100. package/src/lib/serializer.ts +203 -0
  101. package/src/lib/timer.ts +43 -0
  102. package/src/lib/transformers.ts +270 -0
  103. package/src/lib/version.ts +7 -0
  104. package/src/lib/websocket-factory.ts +192 -0
@@ -0,0 +1,203 @@
1
+ // This file draws heavily from https://github.com/phoenixframework/phoenix/commit/cf098e9cf7a44ee6479d31d911a97d3c7430c6fe
2
+ // License: https://github.com/phoenixframework/phoenix/blob/master/LICENSE.md
3
+ export type Msg<T> = {
4
+ join_ref?: string | null
5
+ ref?: string | null
6
+ topic: string
7
+ event: string
8
+ payload: T
9
+ }
10
+
11
+ export default class Serializer {
12
+ HEADER_LENGTH = 1
13
+ USER_BROADCAST_PUSH_META_LENGTH = 6
14
+ KINDS = { userBroadcastPush: 3, userBroadcast: 4 }
15
+ BINARY_ENCODING = 0
16
+ JSON_ENCODING = 1
17
+ BROADCAST_EVENT = 'broadcast'
18
+
19
+ allowedMetadataKeys: string[] = []
20
+
21
+ constructor(allowedMetadataKeys?: string[] | null) {
22
+ this.allowedMetadataKeys = allowedMetadataKeys ?? []
23
+ }
24
+
25
+ encode(msg: Msg<{ [key: string]: any }>, callback: (result: ArrayBuffer | string) => any) {
26
+ if (
27
+ msg.event === this.BROADCAST_EVENT &&
28
+ !(msg.payload instanceof ArrayBuffer) &&
29
+ typeof msg.payload.event === 'string'
30
+ ) {
31
+ return callback(
32
+ this._binaryEncodeUserBroadcastPush(msg as Msg<{ event: string } & { [key: string]: any }>)
33
+ )
34
+ }
35
+
36
+ let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload]
37
+ return callback(JSON.stringify(payload))
38
+ }
39
+
40
+ private _binaryEncodeUserBroadcastPush(message: Msg<{ event: string } & { [key: string]: any }>) {
41
+ if (this._isArrayBuffer(message.payload?.payload)) {
42
+ return this._encodeBinaryUserBroadcastPush(message)
43
+ } else {
44
+ return this._encodeJsonUserBroadcastPush(message)
45
+ }
46
+ }
47
+
48
+ private _encodeBinaryUserBroadcastPush(message: Msg<{ event: string } & { [key: string]: any }>) {
49
+ const userPayload = message.payload?.payload ?? new ArrayBuffer(0)
50
+ return this._encodeUserBroadcastPush(message, this.BINARY_ENCODING, userPayload)
51
+ }
52
+
53
+ private _encodeJsonUserBroadcastPush(message: Msg<{ event: string } & { [key: string]: any }>) {
54
+ const userPayload = message.payload?.payload ?? {}
55
+ const encoder = new TextEncoder()
56
+ const encodedUserPayload = encoder.encode(JSON.stringify(userPayload)).buffer
57
+ return this._encodeUserBroadcastPush(message, this.JSON_ENCODING, encodedUserPayload)
58
+ }
59
+
60
+ private _encodeUserBroadcastPush(
61
+ message: Msg<{ event: string } & { [key: string]: any }>,
62
+ encodingType: number,
63
+ encodedPayload: ArrayBuffer
64
+ ) {
65
+ const topic = message.topic
66
+ const ref = message.ref ?? ''
67
+ const joinRef = message.join_ref ?? ''
68
+ const userEvent = message.payload.event
69
+
70
+ // Filter metadata based on allowed keys
71
+ const rest = this.allowedMetadataKeys
72
+ ? this._pick(message.payload, this.allowedMetadataKeys)
73
+ : {}
74
+
75
+ const metadata = Object.keys(rest).length === 0 ? '' : JSON.stringify(rest)
76
+
77
+ // Validate lengths don't exceed uint8 max value (255)
78
+ if (joinRef.length > 255) {
79
+ throw new Error(`joinRef length ${joinRef.length} exceeds maximum of 255`)
80
+ }
81
+ if (ref.length > 255) {
82
+ throw new Error(`ref length ${ref.length} exceeds maximum of 255`)
83
+ }
84
+ if (topic.length > 255) {
85
+ throw new Error(`topic length ${topic.length} exceeds maximum of 255`)
86
+ }
87
+ if (userEvent.length > 255) {
88
+ throw new Error(`userEvent length ${userEvent.length} exceeds maximum of 255`)
89
+ }
90
+ if (metadata.length > 255) {
91
+ throw new Error(`metadata length ${metadata.length} exceeds maximum of 255`)
92
+ }
93
+
94
+ const metaLength =
95
+ this.USER_BROADCAST_PUSH_META_LENGTH +
96
+ joinRef.length +
97
+ ref.length +
98
+ topic.length +
99
+ userEvent.length +
100
+ metadata.length
101
+
102
+ const header = new ArrayBuffer(this.HEADER_LENGTH + metaLength)
103
+ let view = new DataView(header)
104
+ let offset = 0
105
+
106
+ view.setUint8(offset++, this.KINDS.userBroadcastPush) // kind
107
+ view.setUint8(offset++, joinRef.length)
108
+ view.setUint8(offset++, ref.length)
109
+ view.setUint8(offset++, topic.length)
110
+ view.setUint8(offset++, userEvent.length)
111
+ view.setUint8(offset++, metadata.length)
112
+ view.setUint8(offset++, encodingType)
113
+ Array.from(joinRef, (char) => view.setUint8(offset++, char.charCodeAt(0)))
114
+ Array.from(ref, (char) => view.setUint8(offset++, char.charCodeAt(0)))
115
+ Array.from(topic, (char) => view.setUint8(offset++, char.charCodeAt(0)))
116
+ Array.from(userEvent, (char) => view.setUint8(offset++, char.charCodeAt(0)))
117
+ Array.from(metadata, (char) => view.setUint8(offset++, char.charCodeAt(0)))
118
+
119
+ var combined = new Uint8Array(header.byteLength + encodedPayload.byteLength)
120
+ combined.set(new Uint8Array(header), 0)
121
+ combined.set(new Uint8Array(encodedPayload), header.byteLength)
122
+
123
+ return combined.buffer
124
+ }
125
+
126
+ decode(rawPayload: ArrayBuffer | string, callback: Function) {
127
+ if (this._isArrayBuffer(rawPayload)) {
128
+ let result = this._binaryDecode(rawPayload as ArrayBuffer)
129
+ return callback(result)
130
+ }
131
+
132
+ if (typeof rawPayload === 'string') {
133
+ const jsonPayload = JSON.parse(rawPayload)
134
+ const [join_ref, ref, topic, event, payload] = jsonPayload
135
+ return callback({ join_ref, ref, topic, event, payload })
136
+ }
137
+
138
+ return callback({})
139
+ }
140
+
141
+ private _binaryDecode(buffer: ArrayBuffer) {
142
+ const view = new DataView(buffer)
143
+ const kind = view.getUint8(0)
144
+ const decoder = new TextDecoder()
145
+ switch (kind) {
146
+ case this.KINDS.userBroadcast:
147
+ return this._decodeUserBroadcast(buffer, view, decoder)
148
+ }
149
+ }
150
+
151
+ private _decodeUserBroadcast(
152
+ buffer: ArrayBuffer,
153
+ view: DataView,
154
+ decoder: TextDecoder
155
+ ): {
156
+ join_ref: null
157
+ ref: null
158
+ topic: string
159
+ event: string
160
+ payload: { [key: string]: any }
161
+ } {
162
+ const topicSize = view.getUint8(1)
163
+ const userEventSize = view.getUint8(2)
164
+ const metadataSize = view.getUint8(3)
165
+ const payloadEncoding = view.getUint8(4)
166
+
167
+ let offset = this.HEADER_LENGTH + 4
168
+ const topic = decoder.decode(buffer.slice(offset, offset + topicSize))
169
+ offset = offset + topicSize
170
+ const userEvent = decoder.decode(buffer.slice(offset, offset + userEventSize))
171
+ offset = offset + userEventSize
172
+ const metadata = decoder.decode(buffer.slice(offset, offset + metadataSize))
173
+ offset = offset + metadataSize
174
+
175
+ const payload = buffer.slice(offset, buffer.byteLength)
176
+ const parsedPayload =
177
+ payloadEncoding === this.JSON_ENCODING ? JSON.parse(decoder.decode(payload)) : payload
178
+
179
+ const data: { [key: string]: any } = {
180
+ type: this.BROADCAST_EVENT,
181
+ event: userEvent,
182
+ payload: parsedPayload,
183
+ }
184
+
185
+ // Metadata is optional and always JSON encoded
186
+ if (metadataSize > 0) {
187
+ data['meta'] = JSON.parse(metadata)
188
+ }
189
+
190
+ return { join_ref: null, ref: null, topic: topic, event: this.BROADCAST_EVENT, payload: data }
191
+ }
192
+
193
+ private _isArrayBuffer(buffer: any): boolean {
194
+ return buffer instanceof ArrayBuffer || buffer?.constructor?.name === 'ArrayBuffer'
195
+ }
196
+
197
+ private _pick(obj: Record<string, any> | null | undefined, keys: string[]): Record<string, any> {
198
+ if (!obj || typeof obj !== 'object') {
199
+ return {}
200
+ }
201
+ return Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key)))
202
+ }
203
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Creates a timer that accepts a `timerCalc` function to perform calculated timeout retries, such as exponential backoff.
3
+ *
4
+ * @example
5
+ * let reconnectTimer = new Timer(() => this.connect(), function(tries){
6
+ * return [1000, 5000, 10000][tries - 1] || 10000
7
+ * })
8
+ * reconnectTimer.scheduleTimeout() // fires after 1000
9
+ * reconnectTimer.scheduleTimeout() // fires after 5000
10
+ * reconnectTimer.reset()
11
+ * reconnectTimer.scheduleTimeout() // fires after 1000
12
+ */
13
+ export default class Timer {
14
+ timer: number | undefined = undefined
15
+ tries: number = 0
16
+
17
+ constructor(
18
+ public callback: Function,
19
+ public timerCalc: Function
20
+ ) {
21
+ this.callback = callback
22
+ this.timerCalc = timerCalc
23
+ }
24
+
25
+ reset() {
26
+ this.tries = 0
27
+ clearTimeout(this.timer)
28
+ this.timer = undefined
29
+ }
30
+
31
+ // Cancels any previous scheduleTimeout and schedules callback
32
+ scheduleTimeout() {
33
+ clearTimeout(this.timer)
34
+
35
+ this.timer = <any>setTimeout(
36
+ () => {
37
+ this.tries = this.tries + 1
38
+ this.callback()
39
+ },
40
+ this.timerCalc(this.tries + 1)
41
+ )
42
+ }
43
+ }
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Helpers to convert the change Payload into native JS types.
3
+ */
4
+
5
+ // Adapted from epgsql (src/epgsql_binary.erl), this module licensed under
6
+ // 3-clause BSD found here: https://raw.githubusercontent.com/epgsql/epgsql/devel/LICENSE
7
+
8
+ export enum PostgresTypes {
9
+ abstime = 'abstime',
10
+ bool = 'bool',
11
+ date = 'date',
12
+ daterange = 'daterange',
13
+ float4 = 'float4',
14
+ float8 = 'float8',
15
+ int2 = 'int2',
16
+ int4 = 'int4',
17
+ int4range = 'int4range',
18
+ int8 = 'int8',
19
+ int8range = 'int8range',
20
+ json = 'json',
21
+ jsonb = 'jsonb',
22
+ money = 'money',
23
+ numeric = 'numeric',
24
+ oid = 'oid',
25
+ reltime = 'reltime',
26
+ text = 'text',
27
+ time = 'time',
28
+ timestamp = 'timestamp',
29
+ timestamptz = 'timestamptz',
30
+ timetz = 'timetz',
31
+ tsrange = 'tsrange',
32
+ tstzrange = 'tstzrange',
33
+ }
34
+
35
+ type Columns = {
36
+ name: string // the column name. eg: "user_id"
37
+ type: string // the column type. eg: "uuid"
38
+ flags?: string[] // any special flags for the column. eg: ["key"]
39
+ type_modifier?: number // the type modifier. eg: 4294967295
40
+ }[]
41
+
42
+ type BaseValue = null | string | number | boolean
43
+ type RecordValue = BaseValue | BaseValue[]
44
+
45
+ type Record = {
46
+ [key: string]: RecordValue
47
+ }
48
+
49
+ /**
50
+ * Takes an array of columns and an object of string values then converts each string value
51
+ * to its mapped type.
52
+ *
53
+ * @param {{name: String, type: String}[]} columns
54
+ * @param {Object} record
55
+ * @param {Object} options The map of various options that can be applied to the mapper
56
+ * @param {Array} options.skipTypes The array of types that should not be converted
57
+ *
58
+ * @example convertChangeData([{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age:'33'}, {})
59
+ * //=>{ first_name: 'Paul', age: 33 }
60
+ */
61
+ export const convertChangeData = (
62
+ columns: Columns,
63
+ record: Record | null,
64
+ options: { skipTypes?: string[] } = {}
65
+ ): Record => {
66
+ const skipTypes = options.skipTypes ?? []
67
+
68
+ if (!record) {
69
+ return {}
70
+ }
71
+
72
+ return Object.keys(record).reduce((acc, rec_key) => {
73
+ acc[rec_key] = convertColumn(rec_key, columns, record, skipTypes)
74
+ return acc
75
+ }, {} as Record)
76
+ }
77
+
78
+ /**
79
+ * Converts the value of an individual column.
80
+ *
81
+ * @param {String} columnName The column that you want to convert
82
+ * @param {{name: String, type: String}[]} columns All of the columns
83
+ * @param {Object} record The map of string values
84
+ * @param {Array} skipTypes An array of types that should not be converted
85
+ * @return {object} Useless information
86
+ *
87
+ * @example convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age: '33'}, [])
88
+ * //=> 33
89
+ * @example convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age: '33'}, ['int4'])
90
+ * //=> "33"
91
+ */
92
+ export const convertColumn = (
93
+ columnName: string,
94
+ columns: Columns,
95
+ record: Record,
96
+ skipTypes: string[]
97
+ ): RecordValue => {
98
+ const column = columns.find((x) => x.name === columnName)
99
+ const colType = column?.type
100
+ const value = record[columnName]
101
+
102
+ if (colType && !skipTypes.includes(colType)) {
103
+ return convertCell(colType, value)
104
+ }
105
+
106
+ return noop(value)
107
+ }
108
+
109
+ /**
110
+ * If the value of the cell is `null`, returns null.
111
+ * Otherwise converts the string value to the correct type.
112
+ * @param {String} type A postgres column type
113
+ * @param {String} value The cell value
114
+ *
115
+ * @example convertCell('bool', 't')
116
+ * //=> true
117
+ * @example convertCell('int8', '10')
118
+ * //=> 10
119
+ * @example convertCell('_int4', '{1,2,3,4}')
120
+ * //=> [1,2,3,4]
121
+ */
122
+ export const convertCell = (type: string, value: RecordValue): RecordValue => {
123
+ // if data type is an array
124
+ if (type.charAt(0) === '_') {
125
+ const dataType = type.slice(1, type.length)
126
+ return toArray(value, dataType)
127
+ }
128
+
129
+ // If not null, convert to correct type.
130
+ switch (type) {
131
+ case PostgresTypes.bool:
132
+ return toBoolean(value)
133
+ case PostgresTypes.float4:
134
+ case PostgresTypes.float8:
135
+ case PostgresTypes.int2:
136
+ case PostgresTypes.int4:
137
+ case PostgresTypes.int8:
138
+ case PostgresTypes.numeric:
139
+ case PostgresTypes.oid:
140
+ return toNumber(value)
141
+ case PostgresTypes.json:
142
+ case PostgresTypes.jsonb:
143
+ return toJson(value)
144
+ case PostgresTypes.timestamp:
145
+ return toTimestampString(value) // Format to be consistent with PostgREST
146
+ case PostgresTypes.abstime: // To allow users to cast it based on Timezone
147
+ case PostgresTypes.date: // To allow users to cast it based on Timezone
148
+ case PostgresTypes.daterange:
149
+ case PostgresTypes.int4range:
150
+ case PostgresTypes.int8range:
151
+ case PostgresTypes.money:
152
+ case PostgresTypes.reltime: // To allow users to cast it based on Timezone
153
+ case PostgresTypes.text:
154
+ case PostgresTypes.time: // To allow users to cast it based on Timezone
155
+ case PostgresTypes.timestamptz: // To allow users to cast it based on Timezone
156
+ case PostgresTypes.timetz: // To allow users to cast it based on Timezone
157
+ case PostgresTypes.tsrange:
158
+ case PostgresTypes.tstzrange:
159
+ return noop(value)
160
+ default:
161
+ // Return the value for remaining types
162
+ return noop(value)
163
+ }
164
+ }
165
+
166
+ const noop = (value: RecordValue): RecordValue => {
167
+ return value
168
+ }
169
+ export const toBoolean = (value: RecordValue): RecordValue => {
170
+ switch (value) {
171
+ case 't':
172
+ return true
173
+ case 'f':
174
+ return false
175
+ default:
176
+ return value
177
+ }
178
+ }
179
+ export const toNumber = (value: RecordValue): RecordValue => {
180
+ if (typeof value === 'string') {
181
+ const parsedValue = parseFloat(value)
182
+ if (!Number.isNaN(parsedValue)) {
183
+ return parsedValue
184
+ }
185
+ }
186
+ return value
187
+ }
188
+ export const toJson = (value: RecordValue): RecordValue => {
189
+ if (typeof value === 'string') {
190
+ try {
191
+ return JSON.parse(value)
192
+ } catch {
193
+ return value
194
+ }
195
+ }
196
+ return value
197
+ }
198
+
199
+ /**
200
+ * Converts a Postgres Array into a native JS array
201
+ *
202
+ * @example toArray('{}', 'int4')
203
+ * //=> []
204
+ * @example toArray('{"[2021-01-01,2021-12-31)","(2021-01-01,2021-12-32]"}', 'daterange')
205
+ * //=> ['[2021-01-01,2021-12-31)', '(2021-01-01,2021-12-32]']
206
+ * @example toArray([1,2,3,4], 'int4')
207
+ * //=> [1,2,3,4]
208
+ */
209
+ export const toArray = (value: RecordValue, type: string): RecordValue => {
210
+ if (typeof value !== 'string') {
211
+ return value
212
+ }
213
+
214
+ const lastIdx = value.length - 1
215
+ const closeBrace = value[lastIdx]
216
+ const openBrace = value[0]
217
+
218
+ // Confirm value is a Postgres array by checking curly brackets
219
+ if (openBrace === '{' && closeBrace === '}') {
220
+ let arr
221
+ const valTrim = value.slice(1, lastIdx)
222
+
223
+ // TODO: find a better solution to separate Postgres array data
224
+ try {
225
+ arr = JSON.parse('[' + valTrim + ']')
226
+ } catch (_) {
227
+ // WARNING: splitting on comma does not cover all edge cases
228
+ arr = valTrim ? valTrim.split(',') : []
229
+ }
230
+
231
+ return arr.map((val: BaseValue) => convertCell(type, val))
232
+ }
233
+
234
+ return value
235
+ }
236
+
237
+ /**
238
+ * Fixes timestamp to be ISO-8601. Swaps the space between the date and time for a 'T'
239
+ * See https://github.com/supabase/supabase/issues/18
240
+ *
241
+ * @example toTimestampString('2019-09-10 00:00:00')
242
+ * //=> '2019-09-10T00:00:00'
243
+ */
244
+ export const toTimestampString = (value: RecordValue): RecordValue => {
245
+ if (typeof value === 'string') {
246
+ return value.replace(' ', 'T')
247
+ }
248
+
249
+ return value
250
+ }
251
+
252
+ export const httpEndpointURL = (socketUrl: string): string => {
253
+ const wsUrl = new URL(socketUrl)
254
+
255
+ wsUrl.protocol = wsUrl.protocol.replace(/^ws/i, 'http')
256
+
257
+ wsUrl.pathname = wsUrl.pathname
258
+ .replace(/\/+$/, '') // remove all trailing slashes
259
+ .replace(/\/socket\/websocket$/i, '') // remove the socket/websocket path
260
+ .replace(/\/socket$/i, '') // remove the socket path
261
+ .replace(/\/websocket$/i, '') // remove the websocket path
262
+
263
+ if (wsUrl.pathname === '' || wsUrl.pathname === '/') {
264
+ wsUrl.pathname = '/api/broadcast'
265
+ } else {
266
+ wsUrl.pathname = wsUrl.pathname + '/api/broadcast'
267
+ }
268
+
269
+ return wsUrl.href
270
+ }
@@ -0,0 +1,7 @@
1
+ // Generated automatically during releases by scripts/update-version-files.ts
2
+ // This file provides runtime access to the package version for:
3
+ // - HTTP request headers (e.g., X-Client-Info header for API requests)
4
+ // - Debugging and support (identifying which version is running)
5
+ // - Telemetry and logging (version reporting in errors/analytics)
6
+ // - Ensuring build artifacts match the published package version
7
+ export const version = '2.99.3'