git.iko.soy/rowtype-yoga/purescript-supabase
on main help sign in
19 files changed+842−49
since splitsnapshots
unifiedsplit
.gitignore+1 package-lock.json+543 package.json+5 spago.dhall+5 src/Supabase.purs+13 src/Supabase/AuthHelpers.js+6−6 src/Supabase/AuthHelpers.purs+36−7 src/Supabase/AuthHelpers/React.js+3 src/Supabase/AuthHelpers/React.purs+22 src/Supabase/Realtime.js+5 src/Supabase/Realtime.purs+59 src/Supabase/Realtime/ListenType.purs+18 src/Supabase/Realtime/SubscribeStates.purs+25 src/Supabase/Storage.js+6−5 src/Supabase/Storage.purs+16−5 src/Supabase/Supabase.js+9−7 src/Supabase/Supabase.purs+62−16 src/Supabase/Types.purs+5−3 test/Main.purs+3
.gitignore+1
@@ -8,3 +8,4 @@
88/.purs*
99/.psa*
1010/.spago
11+/.idea
package-lock.jsonnew file+543
@@ -0,0 +1,543 @@
1+{
2+ "name": "purescript-supabase",
3+ "version": "1.0.0",
4+ "lockfileVersion": 2,
5+ "requires": true,
6+ "packages": {
7+ "": {
8+ "name": "purescript-supabase",
9+ "version": "1.0.0",
10+ "license": "MIT-0",
11+ "dependencies": {
12+ "@supabase/auth-helpers-nextjs": "^0.5.4",
13+ "@supabase/auth-helpers-react": "^0.3.1",
14+ "@supabase/supabase-js": "^2.7.1"
15+ }
16+ },
17+ "node_modules/@supabase/auth-helpers-nextjs": {
18+ "version": "0.5.4",
19+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-nextjs/-/auth-helpers-nextjs-0.5.4.tgz",
20+ "integrity": "sha512-Xm3BMDOYPbNyuh8UXDRgBDc3JkeM5S2PfuC1jFJ73CCay4YiH1YxTz06Cvtp+vLH432qdjnqH+49ehVvUehPnQ==",
21+ "dependencies": {
22+ "@supabase/auth-helpers-shared": "0.2.4"
23+ },
24+ "peerDependencies": {
25+ "@supabase/supabase-js": "^2.0.4"
26+ }
27+ },
28+ "node_modules/@supabase/auth-helpers-react": {
29+ "version": "0.3.1",
30+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-react/-/auth-helpers-react-0.3.1.tgz",
31+ "integrity": "sha512-g3SFv08Dz9FapNif/ZY1b7qKGlMJDyTLSayHBz3kb3FuYxg7aLWgQtydDhm5AGbc0XtvpIBuhGTIOVevwpdosA==",
32+ "peerDependencies": {
33+ "@supabase/supabase-js": "^2.0.4"
34+ }
35+ },
36+ "node_modules/@supabase/auth-helpers-shared": {
37+ "version": "0.2.4",
38+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-shared/-/auth-helpers-shared-0.2.4.tgz",
39+ "integrity": "sha512-c+hi3N6DhjPTzjXGOokre4gmMZOqt0f1ORrwZwi2s07pk3cbkmn77DwwVtlYMNi3oZNYRQqAfxJu83UzpJrrmg==",
40+ "peerDependencies": {
41+ "@supabase/supabase-js": "^2.0.4"
42+ }
43+ },
44+ "node_modules/@supabase/functions-js": {
45+ "version": "2.0.0",
46+ "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.0.0.tgz",
47+ "integrity": "sha512-ozb7bds2yvf5k7NM2ZzUkxvsx4S4i2eRKFSJetdTADV91T65g4gCzEs9L3LUXSrghcGIkUaon03VPzOrFredqg==",
48+ "dependencies": {
49+ "cross-fetch": "^3.1.5"
50+ }
51+ },
52+ "node_modules/@supabase/gotrue-js": {
53+ "version": "2.11.0",
54+ "resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-2.11.0.tgz",
55+ "integrity": "sha512-yo3yExoTqpJH4YpdI5PDjZ1YLOj3wURppimfsV0ep5uxDY/lE1uOhiMCPnhy59DbFAKG7bjnhJ1L7sk+B2os3w==",
56+ "dependencies": {
57+ "cross-fetch": "^3.1.5"
58+ }
59+ },
60+ "node_modules/@supabase/postgrest-js": {
61+ "version": "1.4.0",
62+ "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.4.0.tgz",
63+ "integrity": "sha512-Qwk7T/thG4gtVjxxVGlnhH9tPWXyBGIpQMxNUtAIyASgJoEEuUFS/Wx/GqGDIfwRtrn1qqZjE6sZon5ULAdRLQ==",
64+ "dependencies": {
65+ "cross-fetch": "^3.1.5"
66+ }
67+ },
68+ "node_modules/@supabase/realtime-js": {
69+ "version": "2.6.0",
70+ "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.6.0.tgz",
71+ "integrity": "sha512-tOVulMobhpxyDuu8VIImpL8FXmZOKsGNOSyS5ihJdj2xYmPPvYG+D2J51Ewfl+MFF65tweiB6p9N9bNIW1cDNA==",
72+ "dependencies": {
73+ "@types/phoenix": "^1.5.4",
74+ "websocket": "^1.0.34"
75+ }
76+ },
77+ "node_modules/@supabase/storage-js": {
78+ "version": "2.3.0",
79+ "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.3.0.tgz",
80+ "integrity": "sha512-YGWVCEYYYF3+UiyL8O4xC78N9n9paLbT0hHl8dmYAtd3DqyWtu5Eph9JTu0PWm+/29Zhns5TbhUZW4xpWjJfPQ==",
81+ "dependencies": {
82+ "cross-fetch": "^3.1.5"
83+ }
84+ },
85+ "node_modules/@supabase/supabase-js": {
86+ "version": "2.7.1",
87+ "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.7.1.tgz",
88+ "integrity": "sha512-Q/e+JAluZEvy7D4ul3aAs3aOiKkGvHlZULy6wjchWQyU9YlJKZLr6VPYcwUeitcnRKZi4al5iTS55LgdJFfqIA==",
89+ "dependencies": {
90+ "@supabase/functions-js": "^2.0.0",
91+ "@supabase/gotrue-js": "^2.10.2",
92+ "@supabase/postgrest-js": "^1.1.1",
93+ "@supabase/realtime-js": "^2.4.0",
94+ "@supabase/storage-js": "^2.1.0",
95+ "cross-fetch": "^3.1.5"
96+ }
97+ },
98+ "node_modules/@types/phoenix": {
99+ "version": "1.5.4",
100+ "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.5.4.tgz",
101+ "integrity": "sha512-L5eZmzw89eXBKkiqVBcJfU1QGx9y+wurRIEgt0cuLH0hwNtVUxtx+6cu0R2STwWj468sjXyBYPYDtGclUd1kjQ=="
102+ },
103+ "node_modules/bufferutil": {
104+ "version": "4.0.7",
105+ "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz",
106+ "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==",
107+ "hasInstallScript": true,
108+ "dependencies": {
109+ "node-gyp-build": "^4.3.0"
110+ },
111+ "engines": {
112+ "node": ">=6.14.2"
113+ }
114+ },
115+ "node_modules/cross-fetch": {
116+ "version": "3.1.5",
117+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
118+ "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
119+ "dependencies": {
120+ "node-fetch": "2.6.7"
121+ }
122+ },
123+ "node_modules/d": {
124+ "version": "1.0.1",
125+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
126+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
127+ "dependencies": {
128+ "es5-ext": "^0.10.50",
129+ "type": "^1.0.1"
130+ }
131+ },
132+ "node_modules/debug": {
133+ "version": "2.6.9",
134+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
135+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
136+ "dependencies": {
137+ "ms": "2.0.0"
138+ }
139+ },
140+ "node_modules/es5-ext": {
141+ "version": "0.10.62",
142+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
143+ "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
144+ "hasInstallScript": true,
145+ "dependencies": {
146+ "es6-iterator": "^2.0.3",
147+ "es6-symbol": "^3.1.3",
148+ "next-tick": "^1.1.0"
149+ },
150+ "engines": {
151+ "node": ">=0.10"
152+ }
153+ },
154+ "node_modules/es6-iterator": {
155+ "version": "2.0.3",
156+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
157+ "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
158+ "dependencies": {
159+ "d": "1",
160+ "es5-ext": "^0.10.35",
161+ "es6-symbol": "^3.1.1"
162+ }
163+ },
164+ "node_modules/es6-symbol": {
165+ "version": "3.1.3",
166+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
167+ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
168+ "dependencies": {
169+ "d": "^1.0.1",
170+ "ext": "^1.1.2"
171+ }
172+ },
173+ "node_modules/ext": {
174+ "version": "1.7.0",
175+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
176+ "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
177+ "dependencies": {
178+ "type": "^2.7.2"
179+ }
180+ },
181+ "node_modules/ext/node_modules/type": {
182+ "version": "2.7.2",
183+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
184+ "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
185+ },
186+ "node_modules/is-typedarray": {
187+ "version": "1.0.0",
188+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
189+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
190+ },
191+ "node_modules/ms": {
192+ "version": "2.0.0",
193+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
194+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
195+ },
196+ "node_modules/next-tick": {
197+ "version": "1.1.0",
198+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
199+ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
200+ },
201+ "node_modules/node-fetch": {
202+ "version": "2.6.7",
203+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
204+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
205+ "dependencies": {
206+ "whatwg-url": "^5.0.0"
207+ },
208+ "engines": {
209+ "node": "4.x || >=6.0.0"
210+ },
211+ "peerDependencies": {
212+ "encoding": "^0.1.0"
213+ },
214+ "peerDependenciesMeta": {
215+ "encoding": {
216+ "optional": true
217+ }
218+ }
219+ },
220+ "node_modules/node-gyp-build": {
221+ "version": "4.6.0",
222+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz",
223+ "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==",
224+ "bin": {
225+ "node-gyp-build": "bin.js",
226+ "node-gyp-build-optional": "optional.js",
227+ "node-gyp-build-test": "build-test.js"
228+ }
229+ },
230+ "node_modules/tr46": {
231+ "version": "0.0.3",
232+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
233+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
234+ },
235+ "node_modules/type": {
236+ "version": "1.2.0",
237+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
238+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
239+ },
240+ "node_modules/typedarray-to-buffer": {
241+ "version": "3.1.5",
242+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
243+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
244+ "dependencies": {
245+ "is-typedarray": "^1.0.0"
246+ }
247+ },
248+ "node_modules/utf-8-validate": {
249+ "version": "5.0.10",
250+ "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
251+ "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
252+ "hasInstallScript": true,
253+ "dependencies": {
254+ "node-gyp-build": "^4.3.0"
255+ },
256+ "engines": {
257+ "node": ">=6.14.2"
258+ }
259+ },
260+ "node_modules/webidl-conversions": {
261+ "version": "3.0.1",
262+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
263+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
264+ },
265+ "node_modules/websocket": {
266+ "version": "1.0.34",
267+ "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
268+ "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
269+ "dependencies": {
270+ "bufferutil": "^4.0.1",
271+ "debug": "^2.2.0",
272+ "es5-ext": "^0.10.50",
273+ "typedarray-to-buffer": "^3.1.5",
274+ "utf-8-validate": "^5.0.2",
275+ "yaeti": "^0.0.6"
276+ },
277+ "engines": {
278+ "node": ">=4.0.0"
279+ }
280+ },
281+ "node_modules/whatwg-url": {
282+ "version": "5.0.0",
283+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
284+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
285+ "dependencies": {
286+ "tr46": "~0.0.3",
287+ "webidl-conversions": "^3.0.0"
288+ }
289+ },
290+ "node_modules/yaeti": {
291+ "version": "0.0.6",
292+ "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
293+ "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==",
294+ "engines": {
295+ "node": ">=0.10.32"
296+ }
297+ }
298+ },
299+ "dependencies": {
300+ "@supabase/auth-helpers-nextjs": {
301+ "version": "0.5.4",
302+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-nextjs/-/auth-helpers-nextjs-0.5.4.tgz",
303+ "integrity": "sha512-Xm3BMDOYPbNyuh8UXDRgBDc3JkeM5S2PfuC1jFJ73CCay4YiH1YxTz06Cvtp+vLH432qdjnqH+49ehVvUehPnQ==",
304+ "requires": {
305+ "@supabase/auth-helpers-shared": "0.2.4"
306+ }
307+ },
308+ "@supabase/auth-helpers-react": {
309+ "version": "0.3.1",
310+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-react/-/auth-helpers-react-0.3.1.tgz",
311+ "integrity": "sha512-g3SFv08Dz9FapNif/ZY1b7qKGlMJDyTLSayHBz3kb3FuYxg7aLWgQtydDhm5AGbc0XtvpIBuhGTIOVevwpdosA==",
312+ "requires": {}
313+ },
314+ "@supabase/auth-helpers-shared": {
315+ "version": "0.2.4",
316+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-shared/-/auth-helpers-shared-0.2.4.tgz",
317+ "integrity": "sha512-c+hi3N6DhjPTzjXGOokre4gmMZOqt0f1ORrwZwi2s07pk3cbkmn77DwwVtlYMNi3oZNYRQqAfxJu83UzpJrrmg==",
318+ "requires": {}
319+ },
320+ "@supabase/functions-js": {
321+ "version": "2.0.0",
322+ "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.0.0.tgz",
323+ "integrity": "sha512-ozb7bds2yvf5k7NM2ZzUkxvsx4S4i2eRKFSJetdTADV91T65g4gCzEs9L3LUXSrghcGIkUaon03VPzOrFredqg==",
324+ "requires": {
325+ "cross-fetch": "^3.1.5"
326+ }
327+ },
328+ "@supabase/gotrue-js": {
329+ "version": "2.11.0",
330+ "resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-2.11.0.tgz",
331+ "integrity": "sha512-yo3yExoTqpJH4YpdI5PDjZ1YLOj3wURppimfsV0ep5uxDY/lE1uOhiMCPnhy59DbFAKG7bjnhJ1L7sk+B2os3w==",
332+ "requires": {
333+ "cross-fetch": "^3.1.5"
334+ }
335+ },
336+ "@supabase/postgrest-js": {
337+ "version": "1.4.0",
338+ "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.4.0.tgz",
339+ "integrity": "sha512-Qwk7T/thG4gtVjxxVGlnhH9tPWXyBGIpQMxNUtAIyASgJoEEuUFS/Wx/GqGDIfwRtrn1qqZjE6sZon5ULAdRLQ==",
340+ "requires": {
341+ "cross-fetch": "^3.1.5"
342+ }
343+ },
344+ "@supabase/realtime-js": {
345+ "version": "2.6.0",
346+ "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.6.0.tgz",
347+ "integrity": "sha512-tOVulMobhpxyDuu8VIImpL8FXmZOKsGNOSyS5ihJdj2xYmPPvYG+D2J51Ewfl+MFF65tweiB6p9N9bNIW1cDNA==",
348+ "requires": {
349+ "@types/phoenix": "^1.5.4",
350+ "websocket": "^1.0.34"
351+ }
352+ },
353+ "@supabase/storage-js": {
354+ "version": "2.3.0",
355+ "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.3.0.tgz",
356+ "integrity": "sha512-YGWVCEYYYF3+UiyL8O4xC78N9n9paLbT0hHl8dmYAtd3DqyWtu5Eph9JTu0PWm+/29Zhns5TbhUZW4xpWjJfPQ==",
357+ "requires": {
358+ "cross-fetch": "^3.1.5"
359+ }
360+ },
361+ "@supabase/supabase-js": {
362+ "version": "2.7.1",
363+ "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.7.1.tgz",
364+ "integrity": "sha512-Q/e+JAluZEvy7D4ul3aAs3aOiKkGvHlZULy6wjchWQyU9YlJKZLr6VPYcwUeitcnRKZi4al5iTS55LgdJFfqIA==",
365+ "requires": {
366+ "@supabase/functions-js": "^2.0.0",
367+ "@supabase/gotrue-js": "^2.10.2",
368+ "@supabase/postgrest-js": "^1.1.1",
369+ "@supabase/realtime-js": "^2.4.0",
370+ "@supabase/storage-js": "^2.1.0",
371+ "cross-fetch": "^3.1.5"
372+ }
373+ },
374+ "@types/phoenix": {
375+ "version": "1.5.4",
376+ "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.5.4.tgz",
377+ "integrity": "sha512-L5eZmzw89eXBKkiqVBcJfU1QGx9y+wurRIEgt0cuLH0hwNtVUxtx+6cu0R2STwWj468sjXyBYPYDtGclUd1kjQ=="
378+ },
379+ "bufferutil": {
380+ "version": "4.0.7",
381+ "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz",
382+ "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==",
383+ "requires": {
384+ "node-gyp-build": "^4.3.0"
385+ }
386+ },
387+ "cross-fetch": {
388+ "version": "3.1.5",
389+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
390+ "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
391+ "requires": {
392+ "node-fetch": "2.6.7"
393+ }
394+ },
395+ "d": {
396+ "version": "1.0.1",
397+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
398+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
399+ "requires": {
400+ "es5-ext": "^0.10.50",
401+ "type": "^1.0.1"
402+ }
403+ },
404+ "debug": {
405+ "version": "2.6.9",
406+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
407+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
408+ "requires": {
409+ "ms": "2.0.0"
410+ }
411+ },
412+ "es5-ext": {
413+ "version": "0.10.62",
414+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
415+ "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
416+ "requires": {
417+ "es6-iterator": "^2.0.3",
418+ "es6-symbol": "^3.1.3",
419+ "next-tick": "^1.1.0"
420+ }
421+ },
422+ "es6-iterator": {
423+ "version": "2.0.3",
424+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
425+ "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
426+ "requires": {
427+ "d": "1",
428+ "es5-ext": "^0.10.35",
429+ "es6-symbol": "^3.1.1"
430+ }
431+ },
432+ "es6-symbol": {
433+ "version": "3.1.3",
434+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
435+ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
436+ "requires": {
437+ "d": "^1.0.1",
438+ "ext": "^1.1.2"
439+ }
440+ },
441+ "ext": {
442+ "version": "1.7.0",
443+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
444+ "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
445+ "requires": {
446+ "type": "^2.7.2"
447+ },
448+ "dependencies": {
449+ "type": {
450+ "version": "2.7.2",
451+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
452+ "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
453+ }
454+ }
455+ },
456+ "is-typedarray": {
457+ "version": "1.0.0",
458+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
459+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
460+ },
461+ "ms": {
462+ "version": "2.0.0",
463+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
464+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
465+ },
466+ "next-tick": {
467+ "version": "1.1.0",
468+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
469+ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
470+ },
471+ "node-fetch": {
472+ "version": "2.6.7",
473+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
474+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
475+ "requires": {
476+ "whatwg-url": "^5.0.0"
477+ }
478+ },
479+ "node-gyp-build": {
480+ "version": "4.6.0",
481+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz",
482+ "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ=="
483+ },
484+ "tr46": {
485+ "version": "0.0.3",
486+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
487+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
488+ },
489+ "type": {
490+ "version": "1.2.0",
491+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
492+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
493+ },
494+ "typedarray-to-buffer": {
495+ "version": "3.1.5",
496+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
497+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
498+ "requires": {
499+ "is-typedarray": "^1.0.0"
500+ }
501+ },
502+ "utf-8-validate": {
503+ "version": "5.0.10",
504+ "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
505+ "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
506+ "requires": {
507+ "node-gyp-build": "^4.3.0"
508+ }
509+ },
510+ "webidl-conversions": {
511+ "version": "3.0.1",
512+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
513+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
514+ },
515+ "websocket": {
516+ "version": "1.0.34",
517+ "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
518+ "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
519+ "requires": {
520+ "bufferutil": "^4.0.1",
521+ "debug": "^2.2.0",
522+ "es5-ext": "^0.10.50",
523+ "typedarray-to-buffer": "^3.1.5",
524+ "utf-8-validate": "^5.0.2",
525+ "yaeti": "^0.0.6"
526+ }
527+ },
528+ "whatwg-url": {
529+ "version": "5.0.0",
530+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
531+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
532+ "requires": {
533+ "tr46": "~0.0.3",
534+ "webidl-conversions": "^3.0.0"
535+ }
536+ },
537+ "yaeti": {
538+ "version": "0.0.6",
539+ "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
540+ "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug=="
541+ }
542+ }
543+}
package.json+5
@@ -6,6 +6,11 @@
66 "scripts": {
77 "test": "echo \"Error: no test specified\" && exit 1"
88 },
9+ "dependencies": {
10+ "@supabase/auth-helpers-nextjs": "^0.5.4",
11+ "@supabase/auth-helpers-react": "^0.3.1",
12+ "@supabase/supabase-js": "^2.7.1"
13+ },
914 "keywords": [],
1015 "author": "",
1116 "license": "MIT-0"
spago.dhall+5
@@ -3,8 +3,10 @@
33 [ "aff"
44 , "aff-promise"
55 , "console"
6+ , "datetime"
67 , "effect"
78 , "either"
9+ , "exceptions"
810 , "fetch"
911 , "fetch-core"
1012 , "foldable-traversable"
@@ -20,6 +22,9 @@
2022 , "transformers"
2123 , "tuples"
2224 , "typelevel-prelude"
25+ , "unsafe-coerce"
26+ , "unsafe-reference"
27+ , "untagged-union"
2328 , "web-file"
2429 , "yoga-json"
2530 ]
src/Supabase.pursnew file+13
@@ -0,0 +1,13 @@
1+module Supabase
2+ ( module Supabase.Supabase
3+ , module Supabase.Storage
4+ , module Supabase.AuthHelpers
5+ , module Supabase.Types
6+ , module Supabase.Util
7+ ) where
8+
9+import Supabase.Supabase (class Equals, class Select, AuthResponse, Count(..), CountR, CountResponse, DataR, ErrorR, FilterBuilder, FunctionResponse, QueryBuilder, Response, ResultError, Session, SessionData, StatusR, User, delete, equals, from, getSession, invoke, maybeSingle, onAuthStateChange, range, select, signInWithOtp, signOut, single, update, upsert)
10+import Supabase.Storage (FileOptions, Storage, createSignedUrl, download, fromStorage, remove, storage, upload)
11+import Supabase.AuthHelpers (ClientOptions, CookieOptions, Options, UseUser, createBrowserClient, createBrowserClientWithOptions, useUser)
12+import Supabase.Types (Client)
13+import Supabase.Util (fromEither, fromJSON, toError)
src/Supabase/AuthHelpers.js+6−6
@@ -1,11 +1,11 @@
1−import {
2− UserProvider,
3− useUser,
4−} from "@supabase/auth-helpers-react";
1+'use client'
2+import { useUser } from "@supabase/auth-helpers-react";
3+import { createBrowserSupabaseClient } from "@supabase/auth-helpers-nextjs";
54
6−export const userProvider = UserProvider;
75export const useUserImpl = useUser;
86
9−import { createBrowserSupabaseClient } from "@supabase/auth-helpers-nextjs";
107
118export const createBrowserClient = () => createBrowserSupabaseClient();
9+
10+export const createBrowserClientWithOptionsInternal = (options) => () =>
11+ createBrowserSupabaseClient(options);
src/Supabase/AuthHelpers.purs+36−7
@@ -1,10 +1,12 @@
11module Supabase.AuthHelpers
2− ( UseUser
2+ ( ClientOptions
3+ , CookieOptions
4+ , Options
5+ , UseUser
36 , createBrowserClient
7+ , createBrowserClientWithOptions
48 , useUser
5− , userProvider
6− )
7− where
9+ ) where
810
911import Prelude
1012
@@ -12,12 +14,13 @@ import Data.Maybe (Maybe)
1214import Data.Nullable (Nullable)
1315import Data.Nullable as Nullable
1416import Effect (Effect)
15−import React.Basic.Hooks (Hook, ReactComponent, unsafeHook)
17+import Foreign (Foreign)
18+import React.Basic.Hooks (Hook, unsafeHook)
1619import Record.Studio (mapRecordKind)
1720import Supabase.Supabase as Supabase
1821import Supabase.Types (Client)
19−
20−foreign import userProvider :: forall props. ReactComponent { supabaseClient :: Client | props }
22+import Yoga.JSON as YogaJSON
23+import Yoga.JSON (class WriteForeign)
2124
2225foreign import useUserImpl :: Effect { user :: Nullable Supabase.User }
2326
@@ -27,3 +30,29 @@ useUser = unsafeHook useUserImpl <#> mapRecordKind Nullable.toMaybe
2730foreign import data UseUser :: Type -> Type
2831
2932foreign import createBrowserClient :: Effect Client
33+
34+type CookieOptions =
35+ { domain :: Maybe String
36+ , maxAge :: Maybe Int
37+ , name :: Maybe Int
38+ , path :: Maybe String
39+ , sameSite :: Maybe String
40+ , secure :: Maybe Boolean
41+ }
42+
43+type Options =
44+ { db :: Maybe String
45+ }
46+
47+type ClientOptions r =
48+ { cookieOptions :: Maybe CookieOptions
49+ , options :: Maybe Options
50+ , supabaseKey :: Maybe String
51+ , supabaseUrl :: Maybe String
52+ | r
53+ }
54+
55+foreign import createBrowserClientWithOptionsInternal :: Foreign -> Effect Client
56+
57+createBrowserClientWithOptions ∷ forall r. WriteForeign (ClientOptions r) => ClientOptions r → Effect Client
58+createBrowserClientWithOptions = YogaJSON.write >>> createBrowserClientWithOptionsInternal
src/Supabase/AuthHelpers/React.jsnew file+3
@@ -0,0 +1,3 @@
1+import { useUser } from "@supabase/auth-helpers-react";
2+
3+export const useUserImpl = useUser;
src/Supabase/AuthHelpers/React.pursnew file+22
@@ -0,0 +1,22 @@
1+module Supabase.AuthHelpers.React where
2+
3+import Prelude
4+
5+import Data.Maybe (Maybe)
6+import Data.Nullable (Nullable)
7+import Data.Nullable as Nullable
8+import Effect (Effect)
9+import Foreign (Foreign)
10+import React.Basic.Hooks (Hook, unsafeHook)
11+import Record.Studio (mapRecordKind)
12+import Supabase.Supabase as Supabase
13+import Supabase.Types (Client)
14+import Yoga.JSON as YogaJSON
15+import Yoga.JSON (class WriteForeign)
16+
17+foreign import useUserImpl :: Effect { user :: Nullable Supabase.User }
18+
19+useUser :: Hook (UseUser) { user :: Maybe Supabase.User }
20+useUser = unsafeHook useUserImpl <#> mapRecordKind Nullable.toMaybe
21+
22+foreign import data UseUser :: Type -> Type
src/Supabase/Realtime.jsnew file+5
@@ -0,0 +1,5 @@
1+export const sendImpl = (what, channel) => channel.send(what)
2+
3+export const onImpl = (listenType, filter, callback, channel) => channel.on(listenType, filter, callback)
4+
5+export const subscribeImpl = (callback,timeout, channel) => channel.subscribe(callback,timeout)
src/Supabase/Realtime.pursnew file+59
@@ -0,0 +1,59 @@
1+module Supabase.Realtime where
2+
3+import Prelude
4+import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, mkEffectFn1, mkEffectFn2, runEffectFn2, runEffectFn3, runEffectFn4)
5+import Supabase.Types (Channel)
6+import Control.Promise (Promise, toAffE)
7+import Effect.Aff (Aff)
8+import Effect (Effect)
9+import Unsafe.Coerce (unsafeCoerce)
10+import Supabase.Realtime.ListenType (RealtimeListenType)
11+import Supabase.Realtime.SubscribeStates (RealtimeSubscribeState, RealtimeSubscribeState(ChannelError))
12+import Effect.Exception (Error, error)
13+import Untagged.Union (UndefinedOr, uorToMaybe)
14+import Data.Time.Duration (Milliseconds)
15+import Data.Maybe (Maybe, Maybe(Nothing), Maybe(Just))
16+import Supabase.Realtime.SubscribeStates (fromString) as SubscribeState
17+import Control.Monad.Error.Class (throwError)
18+
19+data RealtimeResponse = SendingOK | SendingTimedOut | SendingRateLimited
20+
21+foreign import sendImpl :: forall i. EffectFn2 { | i } Channel (Promise String)
22+
23+send :: forall i. { | i } -> Channel -> Aff RealtimeResponse
24+send input channel = do
25+ res <- runEffectFn2 sendImpl input channel # toAffE
26+ case res of
27+ "ok" -> pure SendingOK
28+ "timed out" -> pure SendingTimedOut
29+ "rate limited" -> pure SendingRateLimited
30+ _ -> throwError $ error $ "Supabase.Realtime.send: invalid response: " <> res
31+
32+foreign import onImpl :: forall f cbi. EffectFn4 RealtimeListenType f (EffectFn1 cbi Unit) Channel Unit
33+
34+on :: forall f cbi. RealtimeListenType -> f -> (cbi -> Effect Unit) -> Channel -> Effect Unit
35+on lt filter callback channel = runEffectFn4 onImpl lt filter (mkEffectFn1 callback) channel
36+
37+foreign import subscribeImpl
38+ :: EffectFn3
39+ (EffectFn2 String (UndefinedOr Error) Unit)
40+ Milliseconds
41+ Channel
42+ Unit
43+
44+subscribe
45+ :: Milliseconds
46+ -> (RealtimeSubscribeState -> Maybe Error -> Effect Unit)
47+ -> Channel
48+ -> Effect Unit
49+subscribe timeout cb channel =
50+ runEffectFn3 subscribeImpl
51+ ( mkEffectFn2 \st err ->
52+ case SubscribeState.fromString st of
53+ Nothing ->
54+ cb ChannelError (Just (error $ "Supabase.Realtime.subscribe: invalid subscribe state: " <> st))
55+ Just ok ->
56+ cb ok (uorToMaybe err)
57+ )
58+ timeout
59+ channel
src/Supabase/Realtime/ListenType.pursnew file+18
@@ -0,0 +1,18 @@
1+module Supabase.Realtime.ListenType where
2+
3+import Prelude
4+import Unsafe.Coerce (unsafeCoerce)
5+import Unsafe.Reference (unsafeRefEq)
6+
7+foreign import data RealtimeListenType :: Type
8+instance Eq RealtimeListenType where
9+ eq = unsafeRefEq
10+
11+broadcast :: RealtimeListenType
12+broadcast = unsafeCoerce "broadcast"
13+
14+presence :: RealtimeListenType
15+presence = unsafeCoerce "presence"
16+
17+postgresChanges :: RealtimeListenType
18+postgresChanges = unsafeCoerce "postgres_changes"
src/Supabase/Realtime/SubscribeStates.pursnew file+25
@@ -0,0 +1,25 @@
1+module Supabase.Realtime.SubscribeStates where
2+
3+import Prelude
4+import Unsafe.Coerce (unsafeCoerce)
5+import Unsafe.Reference (unsafeRefEq)
6+import Data.Maybe (Maybe(Nothing), Maybe, Maybe(Just))
7+
8+data RealtimeSubscribeState = Subscribed | TimedOut | Closed | ChannelError
9+derive instance Eq RealtimeSubscribeState
10+
11+toString :: RealtimeSubscribeState -> String
12+toString = case _ of
13+ Subscribed -> "SUBSCRIBED"
14+ TimedOut -> "TIMED_OUT"
15+ Closed -> "CLOSED"
16+ ChannelError -> "CHANNEL_ERROR"
17+
18+fromString :: String -> Maybe RealtimeSubscribeState
19+fromString = case _ of
20+ "SUBSCRIBED" -> Just Subscribed
21+ "TIMED_OUT" -> Just TimedOut
22+ "CLOSED" -> Just Closed
23+ "CHANNEL_ERROR" -> Just ChannelError
24+ _ -> Nothing
25+
src/Supabase/Storage.js+6−5
@@ -1,15 +1,16 @@
1−import { supabaseClient } from "@supabase/auth-helpers-nextjs";
2−
31export const storage = (client) => client.storage;
42
53export const fromImpl = (storage) => (table) => storage.from(table);
64
7−export const uploadImpl = (queryBuilder) => (filePath, file, fileOptions) => () =>
8− queryBuilder.upload(filePath, file, fileOptions);
5+export const uploadImpl =
6+ (queryBuilder) => (filePath, file, fileOptions) => () =>
7+ queryBuilder.upload(filePath, file, fileOptions);
98
109export const downloadImpl = (queryBuilder) => (filePath) => () =>
1110 queryBuilder.download(filePath);
1211
13−
1412export const removeImpl = (queryBuilder) => (filePaths) => () =>
1513 queryBuilder.remove(filePaths);
14+
15+export const createSignedUrlImpl = (queryBuilder) => filePath => options => () =>
16+ queryBuilder.createSignedUrl(filePath, options);
src/Supabase/Storage.purs+16−5
@@ -3,9 +3,11 @@ module Supabase.Storage
33 , Storage
44 , download
55 , from
6+ , fromStorage
67 , remove
78 , storage
89 , upload
10+ , createSignedUrl
911 ) where
1012
1113import Prelude
@@ -26,6 +28,7 @@ import Type.Function (type ($))
2628import Supabase.Util as Util
2729import Web.File.Blob (Blob)
2830import Web.File.File as File
31+import Data.Time.Duration (Seconds)
2932
3033foreign import data Storage :: Type
3134
@@ -35,6 +38,9 @@ foreign import fromImpl :: Storage -> String -> QueryBuilder
3538from :: String -> Storage -> QueryBuilder
3639from = flip fromImpl
3740
41+fromStorage :: String -> Client -> QueryBuilder
42+fromStorage s = from s <<< storage
43+
3844type FileOptions = { upsert :: Boolean }
3945
4046foreign import uploadImpl :: QueryBuilder -> Fn3 String File.File FileOptions $ Effect (Promise Foreign)
@@ -47,13 +53,18 @@ foreign import downloadImpl :: QueryBuilder -> String -> Effect (Promise { "data
4753download :: String -> QueryBuilder -> Aff (SBTypes.Response Blob) -- [TODO] Make this a proper response
4854download file qb = downloadImpl qb file # Promise.toAffE <#> convert
4955 where
50− convert { "data": d, error: error } =
51− let
52− blob = Nullable.toMaybe d
53− in
54− { "data": blob, error: Nullable.toMaybe error, status: Nothing }
56+ convert { "data": d, error: error } = do
57+ { "data": Nullable.toMaybe d, error: Nullable.toMaybe error, status: Nothing }
5558
5659foreign import removeImpl :: QueryBuilder -> Array String -> Effect (Promise Foreign)
5760
5861remove ∷ Array String → QueryBuilder → Aff { error ∷ Maybe ResultError }
5962remove file qb = removeImpl qb file # Promise.toAffE >>= Util.fromJSON
63+
64+foreign import createSignedUrlImpl :: QueryBuilder -> String -> Seconds -> Effect (Promise { "data" :: Nullable { signedUrl :: String }, error :: Nullable ResultError })
65+
66+createSignedUrl :: String -> Seconds -> QueryBuilder -> Aff (SBTypes.Response { signedUrl :: String })
67+createSignedUrl file expiry qb = createSignedUrlImpl qb file expiry # Promise.toAffE <#> convert
68+ where
69+ convert { "data": d, error: error } = do
70+ { "data": Nullable.toMaybe d, error: Nullable.toMaybe error, status: Nothing }
src/Supabase/Supabase.js+9−7
@@ -1,17 +1,15 @@
1−import { supabaseClient } from "@supabase/auth-helpers-nextjs";
2−
3−// supabaseClient.from("bla")
4−// .select("wurst")
5−// .eq("", 1)
6−// .single()
7−
81export const signInWithOtpImpl = (supabase) => (email) => () =>
92 supabase.auth.signInWithOtp({ email });
103
4+export const signInWithOtpOptionsImpl = (supabase, email, options) =>
5+ supabase.auth.signInWithOtp({ email, options });
6+
117export const getSessionImpl = (supabase) => () => supabase.auth.getSession();
128export const onAuthStateChangeImpl = (supabase) => (handler) => () =>
139 supabase.auth.onAuthStateChange((_event, session) => handler(session));
1410
11+export const getUserImpl = supabase => () => supabase.auth.getUser();
12+
1513export const signOutImpl = (supabase) => () => supabase.auth.signOut();
1614export const fromImpl = (client) => (table) => client.from(table);
1715export const selectQueryImpl = (queryBuilder) => (projection) =>
@@ -31,6 +29,8 @@ export const eqRunImpl = (builder) => (key, value) => () =>
3129
3230export const eqImpl = (builder) => (key, value) => builder.eq(key, value);
3331
32+export const orImpl = conditions => builder => builder.or(...conditions);
33+
3434export const singleImpl = (filterBuilder) => () => filterBuilder.single();
3535
3636export const maybeSingleImpl = (filterBuilder) => () =>
@@ -49,3 +49,5 @@ export const invokeImpl = (client) => (functionName, body, headers) => () =>
4949 body,
5050 headers,
5151 });
52+
53+export const channel = (channelName) => (client) => () => client.channel(channelName);
src/Supabase/Supabase.purs+62−16
@@ -12,22 +12,28 @@ module Supabase.Supabase
1212 , ResultError
1313 , Session
1414 , SessionData
15+ , SignInOptions
1516 , StatusR
17+ , class Or
1618 , User
1719 , class Equals
1820 , class Select
1921 , delete
2022 , equals
23+ , channel
2124 , from
2225 , getSession
2326 , invoke
27+ , maybeSingle
2428 , onAuthStateChange
29+ , or
2530 , range
2631 , select
32+ , getUser
2733 , signInWithOtp
34+ , signInWithOtpOptions
2835 , signOut
2936 , single
30− , maybeSingle
3137 , update
3238 , upsert
3339 ) where
@@ -35,25 +41,28 @@ module Supabase.Supabase
3541import Prelude
3642
3743import Control.Promise (Promise)
38−import Control.Promise as Promise
44+import Data.Either (Either(..))
3945import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3)
40−import Data.Maybe (Maybe)
46+import Data.Maybe (Maybe(..))
4147import Data.Nullable (Nullable)
42−import Data.Nullable as Nullable
4348import Data.Tuple (Tuple(..))
4449import Effect (Effect)
4550import Effect.Aff (Aff, Error)
46−import Effect.Uncurried (EffectFn1, mkEffectFn1)
47−import Fetch as Fetch
48−import Fetch.Core.Response as YogaJson.Core
49−import Fetch.Internal.Response as FetchInternalResponse
51+import Effect.Exception (error)
52+import Effect.Uncurried (EffectFn1, EffectFn3, mkEffectFn1, runEffectFn3)
5053import Foreign (Foreign)
51−import Supabase.Types (Client)
54+import Prim.Row (class Union)
55+import Supabase.Types (Channel, ChannelName, Client)
5256import Type.Function (type ($))
5357import Type.Row (type (+))
58+import Yoga.JSON (class ReadForeign, class WriteForeign, writeImpl)
59+import Fetch as Fetch
60+import Fetch.Internal.Response as FetchInternalResponse
61+import Data.Nullable as Nullable
62+import Control.Promise as Promise
5463import Supabase.Util as Util
5564import Yoga.JSON (class ReadForeign, class WriteForeign, write) as YogaJson
56−import Yoga.JSON (class ReadForeign, class WriteForeign, writeImpl)
65+import Fetch.Core.Response as YogaJson.Core
5766
5867foreign import data QueryBuilder :: Type
5968foreign import data FilterBuilder :: Type
@@ -91,7 +100,7 @@ foreign import selectQueryImpl :: QueryBuilder -> String -> FilterBuilder
91100
92101foreign import selectQueryWithCountImpl :: QueryBuilder -> String -> String -> FilterBuilder
93102
94−class Select input builder output where
103+class Select input builder output | output -> builder where
95104 select :: input -> builder -> output
96105
97106instance (YogaJson.ReadForeign output) => Select Unit FilterBuilder (Aff output) where
@@ -120,6 +129,18 @@ else instance (YogaJson.ReadForeign output) => Equals FilterBuilder (Aff output)
120129 equals :: String -> String -> FilterBuilder -> Aff output
121130 equals l r builder = runFn2 (eqRunImpl builder) l r # Promise.toAffE >>= Util.fromJSON
122131
132+foreign import orImpl :: forall builderIn builderOut. Array String -> builderIn -> builderOut
133+
134+class Or builder output | output -> builder where
135+ or :: Array String -> builder -> output
136+
137+instance Or FilterBuilder FilterBuilder where
138+ or :: Array String -> FilterBuilder -> FilterBuilder
139+ or keys fb = orImpl keys fb
140+else instance Or QueryBuilder FilterBuilder where
141+ or :: Array String -> QueryBuilder -> FilterBuilder
142+ or keys fb = orImpl keys fb
143+
123144foreign import singleImpl :: FilterBuilder -> Effect (Promise Foreign)
124145
125146single :: forall t. YogaJson.ReadForeign t => FilterBuilder -> Aff (Response t)
@@ -139,24 +160,34 @@ range { from: f, to } = rangeImpl f to >>> Promise.toAffE >=> Util.fromJSON
139160
140161type InternalAuthResponse = { error :: Nullable Error }
141162
142−foreign import signInWithOtpImpl :: Client -> String -> Effect (Promise InternalAuthResponse)
143−
144163type AuthResponse = { error :: Maybe Error }
145164
165+foreign import signInWithOtpImpl :: Client -> String -> Effect (Promise InternalAuthResponse)
166+
146167signInWithOtp :: Client -> String -> Aff AuthResponse
147168signInWithOtp client email = signInWithOtpImpl client email # Promise.toAffE <#> \{ error } -> { error: Nullable.toMaybe error }
148169
170+type SignInOptions =
171+ ( shouldCreateUser :: Boolean
172+ , captchaToken :: String
173+ )
174+
175+foreign import signInWithOtpOptionsImpl :: forall options. EffectFn3 Client String options (Promise InternalAuthResponse)
176+
177+signInWithOtpOptions :: forall options thru. Union options thru SignInOptions => Client -> String -> { | options } -> Aff AuthResponse
178+signInWithOtpOptions client email options = runEffectFn3 signInWithOtpOptionsImpl client email options # Promise.toAffE <#> \{ error } -> { error: Nullable.toMaybe error }
179+
149180foreign import signOutImpl :: Client -> Effect (Promise Unit)
150181
151182signOut ∷ Client → Aff Unit
152183signOut client = signOutImpl client # Promise.toAffE
153184
154−foreign import onAuthStateChangeImpl :: Client -> (EffectFn1 (Nullable Session) Unit) -> Effect Unit
185+foreign import onAuthStateChangeImpl :: Client -> (EffectFn1 (Nullable Session) Unit) -> Effect { data :: { id :: String, unsubscribe :: Effect Unit } }
155186
156−onAuthStateChange ∷ Client → (Maybe Session → Effect Unit) → Effect Unit
187+onAuthStateChange ∷ Client → (Maybe Session → Effect Unit) → Effect { data :: { id :: String, unsubscribe :: Effect Unit } }
157188onAuthStateChange client handler = onAuthStateChangeImpl client $ mkEffectFn1 (Nullable.toMaybe >>> handler)
158189
159−type User = { id :: String, email :: String }
190+type User = { id :: String, email :: String, user_metadata :: Foreign }
160191type Session = { user :: User }
161192type SessionData = { session :: Maybe Session }
162193
@@ -165,7 +196,10 @@ type ResultError = { code :: Maybe String, details :: Maybe String, message :: S
165196type DataR d r = (data :: Maybe d | r)
166197type ErrorR r = (error ∷ Maybe ResultError | r)
167198type CountR r = (count :: Int | r)
199+
200+type StatusR :: forall k. k -> Row Type
168201type StatusR r = (status ∷ Maybe Int)
202+
169203type Response d = { data :: Maybe d, error ∷ Maybe ResultError, status ∷ Maybe Int }
170204
171205foreign import getSessionImpl :: Client -> Effect (Promise Foreign)
@@ -184,3 +218,15 @@ invoke client fn body headers = runFn3 (invokeImpl client) fn body headers # Pro
184218 where
185219 convertError { message, context } = { message, context: FetchInternalResponse.convert context }
186220 convert { "data": d, error } = { "data": Nullable.toMaybe d, error: Nullable.toMaybe error <#> convertError }
221+
222+foreign import channel :: ChannelName -> Client -> Effect Channel
223+
224+foreign import getUserImpl :: Client -> Effect (Promise { data :: Nullable User, error :: Nullable Error })
225+
226+getUser :: Client -> Aff (Either Error User)
227+getUser client = do
228+ res <- getUserImpl client # Promise.toAffE
229+ case Nullable.toMaybe res.data, Nullable.toMaybe res.error of
230+ Just user, _ -> pure $ Right user
231+ _, Just error -> pure $ Left error
232+ _, _ -> pure $ Left (error "Unexpected response error")
src/Supabase/Types.purs+5−3
@@ -1,7 +1,9 @@
1−module Supabase.Types
2− ( Client
3− ) where
1+module Supabase.Types where
42
53import Prelude
64
75foreign import data Client :: Type
6+
7+foreign import data Channel :: Type
8+
9+newtype ChannelName = ChannelName String
test/Main.purs+3
@@ -4,6 +4,9 @@ import Prelude
44
55import Effect (Effect)
66import Effect.Class.Console (log)
7+import Supabase (Client)
8+import Supabase.Supabase as SB
9+import Unsafe.Coerce (unsafeCoerce)
710
811main :: Effect Unit
912main = do