@supabase/phoenix 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.
Files changed (49) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +122 -0
  3. package/assets/js/phoenix/ajax.js +116 -0
  4. package/assets/js/phoenix/channel.js +331 -0
  5. package/assets/js/phoenix/constants.js +35 -0
  6. package/assets/js/phoenix/index.js +212 -0
  7. package/assets/js/phoenix/longpoll.js +192 -0
  8. package/assets/js/phoenix/presence.js +208 -0
  9. package/assets/js/phoenix/push.js +134 -0
  10. package/assets/js/phoenix/serializer.js +133 -0
  11. package/assets/js/phoenix/socket.js +747 -0
  12. package/assets/js/phoenix/timer.js +48 -0
  13. package/assets/js/phoenix/types.js +184 -0
  14. package/assets/js/phoenix/utils.js +16 -0
  15. package/package.json +58 -0
  16. package/priv/static/favicon.ico +0 -0
  17. package/priv/static/phoenix-orange.png +0 -0
  18. package/priv/static/phoenix.cjs.js +1812 -0
  19. package/priv/static/phoenix.cjs.js.map +7 -0
  20. package/priv/static/phoenix.js +1834 -0
  21. package/priv/static/phoenix.min.js +2 -0
  22. package/priv/static/phoenix.mjs +1789 -0
  23. package/priv/static/phoenix.mjs.map +7 -0
  24. package/priv/static/phoenix.png +0 -0
  25. package/priv/static/types/ajax.d.ts +10 -0
  26. package/priv/static/types/ajax.d.ts.map +1 -0
  27. package/priv/static/types/channel.d.ts +167 -0
  28. package/priv/static/types/channel.d.ts.map +1 -0
  29. package/priv/static/types/constants.d.ts +36 -0
  30. package/priv/static/types/constants.d.ts.map +1 -0
  31. package/priv/static/types/index.d.ts +10 -0
  32. package/priv/static/types/index.d.ts.map +1 -0
  33. package/priv/static/types/longpoll.d.ts +29 -0
  34. package/priv/static/types/longpoll.d.ts.map +1 -0
  35. package/priv/static/types/presence.d.ts +107 -0
  36. package/priv/static/types/presence.d.ts.map +1 -0
  37. package/priv/static/types/push.d.ts +70 -0
  38. package/priv/static/types/push.d.ts.map +1 -0
  39. package/priv/static/types/serializer.d.ts +74 -0
  40. package/priv/static/types/serializer.d.ts.map +1 -0
  41. package/priv/static/types/socket.d.ts +284 -0
  42. package/priv/static/types/socket.d.ts.map +1 -0
  43. package/priv/static/types/timer.d.ts +36 -0
  44. package/priv/static/types/timer.d.ts.map +1 -0
  45. package/priv/static/types/types.d.ts +280 -0
  46. package/priv/static/types/types.d.ts.map +1 -0
  47. package/priv/static/types/utils.d.ts +2 -0
  48. package/priv/static/types/utils.d.ts.map +1 -0
  49. package/tsconfig.json +20 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * @import Channel from "./channel"
3
+ * @import { ChannelEvent } from "./types"
4
+ */
5
+ export default class Push {
6
+ /**
7
+ * Initializes the Push
8
+ * @param {Channel} channel - The Channel
9
+ * @param {ChannelEvent} event - The event, for example `"phx_join"`
10
+ * @param {() => Record<string, unknown>} payload - The payload, for example `{user_id: 123}`
11
+ * @param {number} timeout - The push timeout in milliseconds
12
+ */
13
+ constructor(channel, event, payload, timeout){
14
+ /** @type{Channel} */
15
+ this.channel = channel
16
+ /** @type{ChannelEvent} */
17
+ this.event = event
18
+ /** @type{() => Record<string, unknown>} */
19
+ this.payload = payload || function (){ return {} }
20
+ this.receivedResp = null
21
+ /** @type{number} */
22
+ this.timeout = timeout
23
+ /** @type{(ReturnType<typeof setTimeout>) | null} */
24
+ this.timeoutTimer = null
25
+ /** @type{{status: string; callback: (response: any) => void}[]} */
26
+ this.recHooks = []
27
+ /** @type{boolean} */
28
+ this.sent = false
29
+ /** @type{string | null | undefined} */
30
+ this.ref = undefined
31
+ }
32
+
33
+ /**
34
+ *
35
+ * @param {number} timeout
36
+ */
37
+ resend(timeout){
38
+ this.timeout = timeout
39
+ this.reset()
40
+ this.send()
41
+ }
42
+
43
+ /**
44
+ *
45
+ */
46
+ send(){
47
+ if(this.hasReceived("timeout")){ return }
48
+ this.startTimeout()
49
+ this.sent = true
50
+ this.channel.socket.push({
51
+ topic: this.channel.topic,
52
+ event: this.event,
53
+ payload: this.payload(),
54
+ ref: this.ref,
55
+ join_ref: this.channel.joinRef()
56
+ })
57
+ }
58
+
59
+ /**
60
+ *
61
+ * @param {string} status
62
+ * @param {(response: any) => void} callback
63
+ */
64
+ receive(status, callback){
65
+ if(this.hasReceived(status)){
66
+ callback(this.receivedResp.response)
67
+ }
68
+
69
+ this.recHooks.push({status, callback})
70
+ return this
71
+ }
72
+
73
+ reset(){
74
+ this.cancelRefEvent()
75
+ this.ref = null
76
+ this.refEvent = null
77
+ this.receivedResp = null
78
+ this.sent = false
79
+ }
80
+
81
+ destroy(){
82
+ this.cancelRefEvent()
83
+ this.cancelTimeout()
84
+ }
85
+
86
+ /**
87
+ * @private
88
+ */
89
+ matchReceive({status, response, _ref}){
90
+ this.recHooks.filter(h => h.status === status)
91
+ .forEach(h => h.callback(response))
92
+ }
93
+
94
+ /**
95
+ * @private
96
+ */
97
+ cancelRefEvent(){
98
+ if(!this.refEvent){ return }
99
+ this.channel.off(this.refEvent)
100
+ }
101
+
102
+ cancelTimeout(){
103
+ clearTimeout(this.timeoutTimer)
104
+ this.timeoutTimer = null
105
+ }
106
+
107
+ startTimeout(){
108
+ if(this.timeoutTimer){ this.cancelTimeout() }
109
+ this.ref = this.channel.socket.makeRef()
110
+ this.refEvent = this.channel.replyEventName(this.ref)
111
+
112
+ this.channel.on(this.refEvent, payload => {
113
+ this.cancelRefEvent()
114
+ this.cancelTimeout()
115
+ this.receivedResp = payload
116
+ this.matchReceive(payload)
117
+ })
118
+
119
+ this.timeoutTimer = setTimeout(() => {
120
+ this.trigger("timeout", {})
121
+ }, this.timeout)
122
+ }
123
+
124
+ /**
125
+ * @private
126
+ */
127
+ hasReceived(status){
128
+ return this.receivedResp && this.receivedResp.status === status
129
+ }
130
+
131
+ trigger(status, response){
132
+ this.channel.trigger(this.refEvent, {status, response})
133
+ }
134
+ }
@@ -0,0 +1,133 @@
1
+ /* The default serializer for encoding and decoding messages */
2
+ import {
3
+ CHANNEL_EVENTS
4
+ } from "./constants"
5
+
6
+ /**
7
+ * @import { Message } from "./types"
8
+ */
9
+
10
+ export default {
11
+ HEADER_LENGTH: 1,
12
+ META_LENGTH: 4,
13
+ KINDS: {push: 0, reply: 1, broadcast: 2},
14
+
15
+ /**
16
+ * @template T
17
+ * @param {Message<Record<string, any>>} msg
18
+ * @param {(msg: ArrayBuffer | string) => T} callback
19
+ * @returns {T}
20
+ */
21
+ encode(msg, callback){
22
+ if(msg.payload.constructor === ArrayBuffer){
23
+ return callback(this.binaryEncode(msg))
24
+ } else {
25
+ let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload]
26
+ return callback(JSON.stringify(payload))
27
+ }
28
+ },
29
+
30
+ /**
31
+ * @template T
32
+ * @param {ArrayBuffer | string} rawPayload
33
+ * @param {(msg: Message<unknown>) => T} callback
34
+ * @returns {T}
35
+ */
36
+ decode(rawPayload, callback){
37
+ if(rawPayload.constructor === ArrayBuffer){
38
+ return callback(this.binaryDecode(rawPayload))
39
+ } else {
40
+ let [join_ref, ref, topic, event, payload] = JSON.parse(rawPayload)
41
+ return callback({join_ref, ref, topic, event, payload})
42
+ }
43
+ },
44
+
45
+ /** @private */
46
+ binaryEncode(message){
47
+ let {join_ref, ref, event, topic, payload} = message
48
+ let metaLength = this.META_LENGTH + join_ref.length + ref.length + topic.length + event.length
49
+ let header = new ArrayBuffer(this.HEADER_LENGTH + metaLength)
50
+ let view = new DataView(header)
51
+ let offset = 0
52
+
53
+ view.setUint8(offset++, this.KINDS.push) // kind
54
+ view.setUint8(offset++, join_ref.length)
55
+ view.setUint8(offset++, ref.length)
56
+ view.setUint8(offset++, topic.length)
57
+ view.setUint8(offset++, event.length)
58
+ Array.from(join_ref, char => view.setUint8(offset++, char.charCodeAt(0)))
59
+ Array.from(ref, char => view.setUint8(offset++, char.charCodeAt(0)))
60
+ Array.from(topic, char => view.setUint8(offset++, char.charCodeAt(0)))
61
+ Array.from(event, char => view.setUint8(offset++, char.charCodeAt(0)))
62
+
63
+ var combined = new Uint8Array(header.byteLength + payload.byteLength)
64
+ combined.set(new Uint8Array(header), 0)
65
+ combined.set(new Uint8Array(payload), header.byteLength)
66
+
67
+ return combined.buffer
68
+ },
69
+
70
+ /**
71
+ * @private
72
+ */
73
+ binaryDecode(buffer){
74
+ let view = new DataView(buffer)
75
+ let kind = view.getUint8(0)
76
+ let decoder = new TextDecoder()
77
+ switch(kind){
78
+ case this.KINDS.push: return this.decodePush(buffer, view, decoder)
79
+ case this.KINDS.reply: return this.decodeReply(buffer, view, decoder)
80
+ case this.KINDS.broadcast: return this.decodeBroadcast(buffer, view, decoder)
81
+ }
82
+ },
83
+
84
+ /** @private */
85
+ decodePush(buffer, view, decoder){
86
+ let joinRefSize = view.getUint8(1)
87
+ let topicSize = view.getUint8(2)
88
+ let eventSize = view.getUint8(3)
89
+ let offset = this.HEADER_LENGTH + this.META_LENGTH - 1 // pushes have no ref
90
+ let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize))
91
+ offset = offset + joinRefSize
92
+ let topic = decoder.decode(buffer.slice(offset, offset + topicSize))
93
+ offset = offset + topicSize
94
+ let event = decoder.decode(buffer.slice(offset, offset + eventSize))
95
+ offset = offset + eventSize
96
+ let data = buffer.slice(offset, buffer.byteLength)
97
+ return {join_ref: joinRef, ref: null, topic: topic, event: event, payload: data}
98
+ },
99
+
100
+ /** @private */
101
+ decodeReply(buffer, view, decoder){
102
+ let joinRefSize = view.getUint8(1)
103
+ let refSize = view.getUint8(2)
104
+ let topicSize = view.getUint8(3)
105
+ let eventSize = view.getUint8(4)
106
+ let offset = this.HEADER_LENGTH + this.META_LENGTH
107
+ let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize))
108
+ offset = offset + joinRefSize
109
+ let ref = decoder.decode(buffer.slice(offset, offset + refSize))
110
+ offset = offset + refSize
111
+ let topic = decoder.decode(buffer.slice(offset, offset + topicSize))
112
+ offset = offset + topicSize
113
+ let event = decoder.decode(buffer.slice(offset, offset + eventSize))
114
+ offset = offset + eventSize
115
+ let data = buffer.slice(offset, buffer.byteLength)
116
+ let payload = {status: event, response: data}
117
+ return {join_ref: joinRef, ref: ref, topic: topic, event: CHANNEL_EVENTS.reply, payload: payload}
118
+ },
119
+
120
+ /** @private */
121
+ decodeBroadcast(buffer, view, decoder){
122
+ let topicSize = view.getUint8(1)
123
+ let eventSize = view.getUint8(2)
124
+ let offset = this.HEADER_LENGTH + 2
125
+ let topic = decoder.decode(buffer.slice(offset, offset + topicSize))
126
+ offset = offset + topicSize
127
+ let event = decoder.decode(buffer.slice(offset, offset + eventSize))
128
+ offset = offset + eventSize
129
+ let data = buffer.slice(offset, buffer.byteLength)
130
+
131
+ return {join_ref: null, ref: null, topic: topic, event: event, payload: data}
132
+ }
133
+ }