git.iko.soy/rowtype-yoga/purescript-supabase
on main help sign in
19 files changed+858−57
since splitsnapshots
unifiedsplit
.gitignore+1 package-lock.json+543 package.json+5 spago.dhall+5 src/Supabase.purs+13 src/Supabase/AuthHelpers.js+8−5 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+12−8 src/Supabase/Supabase.purs+73−24 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+8−5
@@ -1,8 +1,11 @@
1−export {
2− UserProvider as userProvider,
3− useUser as useUserImpl,
4−} from "@supabase/auth-helpers-react";
5−
1+'use client'
2+import { useUser } from "@supabase/auth-helpers-react";
63import { createBrowserSupabaseClient } from "@supabase/auth-helpers-nextjs";
74
5+export const useUserImpl = useUser;
6+
7+
88export 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+12−8
@@ -1,18 +1,15 @@
1−import { supabaseClient } from "@supabase/auth-helpers-nextjs";
2−
3−
4−// supabaseClient.from("bla")
5−// .select("wurst")
6−// .eq("", 1)
7−// .single()
8−
91export const signInWithOtpImpl = (supabase) => (email) => () =>
102 supabase.auth.signInWithOtp({ email });
113
4+export const signInWithOtpOptionsImpl = (supabase, email, options) =>
5+ supabase.auth.signInWithOtp({ email, options });
6+
127export const getSessionImpl = (supabase) => () => supabase.auth.getSession();
138export const onAuthStateChangeImpl = (supabase) => (handler) => () =>
149 supabase.auth.onAuthStateChange((_event, session) => handler(session));
1510
11+export const getUserImpl = supabase => () => supabase.auth.getUser();
12+
1613export const signOutImpl = (supabase) => () => supabase.auth.signOut();
1714export const fromImpl = (client) => (table) => client.from(table);
1815export const selectQueryImpl = (queryBuilder) => (projection) =>
@@ -32,8 +29,13 @@ export const eqRunImpl = (builder) => (key, value) => () =>
3229
3330export const eqImpl = (builder) => (key, value) => builder.eq(key, value);
3431
32+export const orImpl = conditions => builder => builder.or(...conditions);
33+
3534export const singleImpl = (filterBuilder) => () => filterBuilder.single();
3635
36+export const maybeSingleImpl = (filterBuilder) => () =>
37+ filterBuilder.maybeSingle();
38+
3739export const rangeImpl = (from) => (to) => (filterBuilder) => () =>
3840 filterBuilder.range(from, to);
3941export const upsertImpl = (queryBuilder) => (values) =>
@@ -47,3 +49,5 @@ export const invokeImpl = (client) => (functionName, body, headers) => () =>
4749 body,
4850 headers,
4951 });
52+
53+export const channel = (channelName) => (client) => () => client.channel(channelName);
src/Supabase/Supabase.purs+73−24
@@ -12,48 +12,57 @@ 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
3037 , update
3138 , upsert
32− )
33− where
39+ ) where
3440
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,13 +129,28 @@ 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
123−foreign import singleImpl :: FilterBuilder -> Effect (Promise Foreign)
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
124136
125−--type ResultResponse d = { "data" :: Maybe d, status :: Int, error :: Maybe ResultError }
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+
144+foreign import singleImpl :: FilterBuilder -> Effect (Promise Foreign)
126145
127146single :: forall t. YogaJson.ReadForeign t => FilterBuilder -> Aff (Response t)
128147single = singleImpl >>> Promise.toAffE >=> Util.fromJSON
129148
149+foreign import maybeSingleImpl :: FilterBuilder -> Effect (Promise Foreign)
150+
151+maybeSingle :: forall t. YogaJson.ReadForeign t => FilterBuilder -> Aff (Response t)
152+maybeSingle = maybeSingleImpl >>> Promise.toAffE >=> Util.fromJSON
153+
130154foreign import rangeImpl :: forall i. i -> i -> FilterBuilder -> Effect (Promise Foreign)
131155
132156type CountResponse t = { | DataR t + ErrorR + CountR + StatusR + () }
@@ -136,24 +160,34 @@ range { from: f, to } = rangeImpl f to >>> Promise.toAffE >=> Util.fromJSON
136160
137161type InternalAuthResponse = { error :: Nullable Error }
138162
139−foreign import signInWithOtpImpl :: Client -> String -> Effect (Promise InternalAuthResponse)
140−
141163type AuthResponse = { error :: Maybe Error }
142164
165+foreign import signInWithOtpImpl :: Client -> String -> Effect (Promise InternalAuthResponse)
166+
143167signInWithOtp :: Client -> String -> Aff AuthResponse
144168signInWithOtp client email = signInWithOtpImpl client email # Promise.toAffE <#> \{ error } -> { error: Nullable.toMaybe error }
145169
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+
146180foreign import signOutImpl :: Client -> Effect (Promise Unit)
147181
148182signOut ∷ Client → Aff Unit
149183signOut client = signOutImpl client # Promise.toAffE
150184
151−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 } }
152186
153−onAuthStateChange ∷ Client → (Maybe Session → Effect Unit) → Effect Unit
187+onAuthStateChange ∷ Client → (Maybe Session → Effect Unit) → Effect { data :: { id :: String, unsubscribe :: Effect Unit } }
154188onAuthStateChange client handler = onAuthStateChangeImpl client $ mkEffectFn1 (Nullable.toMaybe >>> handler)
155189
156−type User = { id :: String, email :: String }
190+type User = { id :: String, email :: String, user_metadata :: Foreign }
157191type Session = { user :: User }
158192type SessionData = { session :: Maybe Session }
159193
@@ -162,7 +196,10 @@ type ResultError = { code :: Maybe String, details :: Maybe String, message :: S
162196type DataR d r = (data :: Maybe d | r)
163197type ErrorR r = (error ∷ Maybe ResultError | r)
164198type CountR r = (count :: Int | r)
199+
200+type StatusR :: forall k. k -> Row Type
165201type StatusR r = (status ∷ Maybe Int)
202+
166203type Response d = { data :: Maybe d, error ∷ Maybe ResultError, status ∷ Maybe Int }
167204
168205foreign import getSessionImpl :: Client -> Effect (Promise Foreign)
@@ -170,14 +207,26 @@ foreign import getSessionImpl :: Client -> Effect (Promise Foreign)
170207getSession :: Client -> Aff (Response SessionData)
171208getSession client = getSessionImpl client # Promise.toAffE >>= Util.fromJSON
172209
173−type InternalFunctionResponse d = { "data" :: Nullable d, error :: Nullable { message :: String, context :: YogaJson.Core.Response}}
174−foreign import invokeImpl :: forall body headers t. Client -> Fn3 String body headers (Effect $ Promise $ InternalFunctionResponse t)
210+type InternalFunctionResponse d = { "data" :: Nullable d, error :: Nullable { message :: String, context :: YogaJson.Core.Response } }
175211
176−type FunctionResponse d = { "data" :: Maybe d, error :: Maybe { message :: String, context :: Fetch.Response}}
212+foreign import invokeImpl :: forall body headers t. Client -> Fn3 String body headers (Effect $ Promise $ InternalFunctionResponse t)
177213
214+type FunctionResponse d = { "data" :: Maybe d, error :: Maybe { message :: String, context :: Fetch.Response } }
178215
179216invoke ∷ forall t body headers. ReadForeign t ⇒ Client → String → body → headers → Aff (FunctionResponse t)
180217invoke client fn body headers = runFn3 (invokeImpl client) fn body headers # Promise.toAffE <#> convert
181218 where
182− convertError { message, context } = { message, context: FetchInternalResponse.convert context}
183− convert { "data": d, error } = { "data": Nullable.toMaybe d, error: Nullable.toMaybe error <#> convertError}
219+ convertError { message, context } = { message, context: FetchInternalResponse.convert context }
220+ 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