@motherbase/client 2.2.1 → 2.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPATIBILITY.md +157 -0
- package/LICENSE +21 -21
- package/README.md +52 -4
- package/dist/admin/auth-admin-client.d.ts +43 -0
- package/dist/admin/auth-admin-client.d.ts.map +1 -0
- package/dist/admin/auth-admin-client.js +62 -0
- package/dist/admin/auth-admin-client.js.map +1 -0
- package/dist/admin/auth-admin-mfa-client.d.ts +22 -0
- package/dist/admin/auth-admin-mfa-client.d.ts.map +1 -0
- package/dist/admin/auth-admin-mfa-client.js +17 -0
- package/dist/admin/auth-admin-mfa-client.js.map +1 -0
- package/dist/admin/types.d.ts +85 -0
- package/dist/admin/types.d.ts.map +1 -0
- package/dist/admin/types.js +3 -0
- package/dist/admin/types.js.map +1 -0
- package/dist/auth/constants.d.ts +21 -0
- package/dist/auth/constants.d.ts.map +1 -0
- package/dist/auth/constants.js +34 -0
- package/dist/auth/constants.js.map +1 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +34 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/motherbase-plugin.d.ts +6 -0
- package/dist/auth/motherbase-plugin.d.ts.map +1 -0
- package/dist/auth/motherbase-plugin.js +80 -0
- package/dist/auth/motherbase-plugin.js.map +1 -0
- package/dist/auth/pkce.d.ts +19 -0
- package/dist/auth/pkce.d.ts.map +1 -0
- package/dist/auth/pkce.js +89 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/auth/session-utils.d.ts +29 -0
- package/dist/auth/session-utils.d.ts.map +1 -0
- package/dist/auth/session-utils.js +123 -0
- package/dist/auth/session-utils.js.map +1 -0
- package/dist/auth/session.d.ts +51 -0
- package/dist/auth/session.d.ts.map +1 -0
- package/dist/auth/session.js +161 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/auth/types.d.ts +341 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/auth/utils.d.ts +28 -0
- package/dist/auth/utils.d.ts.map +1 -0
- package/dist/auth/utils.js +70 -0
- package/dist/auth/utils.js.map +1 -0
- package/dist/auth.d.ts +3 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +27 -11
- package/dist/auth.js.map +1 -1
- package/dist/channel.d.ts +11 -0
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js +26 -2
- package/dist/channel.js.map +1 -1
- package/dist/cookies/cookie-storage.d.ts +12 -0
- package/dist/cookies/cookie-storage.d.ts.map +1 -0
- package/dist/cookies/cookie-storage.js +35 -0
- package/dist/cookies/cookie-storage.js.map +1 -0
- package/dist/cookies/index.d.ts +5 -0
- package/dist/cookies/index.d.ts.map +1 -0
- package/dist/cookies/index.js +5 -0
- package/dist/cookies/index.js.map +1 -0
- package/dist/cookies/server-cookie-storage.d.ts +20 -0
- package/dist/cookies/server-cookie-storage.d.ts.map +1 -0
- package/dist/cookies/server-cookie-storage.js +60 -0
- package/dist/cookies/server-cookie-storage.js.map +1 -0
- package/dist/cookies/types.d.ts +33 -0
- package/dist/cookies/types.d.ts.map +1 -0
- package/dist/cookies/types.js +8 -0
- package/dist/cookies/types.js.map +1 -0
- package/dist/cookies/utils.d.ts +23 -0
- package/dist/cookies/utils.d.ts.map +1 -0
- package/dist/cookies/utils.js +67 -0
- package/dist/cookies/utils.js.map +1 -0
- package/dist/database/database.d.ts +197 -0
- package/dist/database/database.d.ts.map +1 -0
- package/dist/database/database.js +2 -0
- package/dist/database/database.js.map +1 -0
- package/dist/database/facade.d.ts +144 -0
- package/dist/database/facade.d.ts.map +1 -0
- package/dist/database/facade.js +147 -0
- package/dist/database/facade.js.map +1 -0
- package/dist/database/query.d.ts +97 -0
- package/dist/database/query.d.ts.map +1 -0
- package/dist/database/query.js +94 -0
- package/dist/database/query.js.map +1 -0
- package/dist/database/types.d.ts +314 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +2 -0
- package/dist/database/types.js.map +1 -0
- package/dist/functions/errors.d.ts +28 -0
- package/dist/functions/errors.d.ts.map +1 -0
- package/dist/functions/errors.js +37 -0
- package/dist/functions/errors.js.map +1 -0
- package/dist/functions/index.d.ts +9 -0
- package/dist/functions/index.d.ts.map +1 -0
- package/dist/functions/index.js +40 -0
- package/dist/functions/index.js.map +1 -0
- package/dist/functions/types.d.ts +25 -0
- package/dist/functions/types.d.ts.map +1 -0
- package/dist/functions/types.js +2 -0
- package/dist/functions/types.js.map +1 -0
- package/dist/http/backend-error.d.ts +17 -0
- package/dist/http/backend-error.d.ts.map +1 -0
- package/dist/http/backend-error.js +11 -0
- package/dist/http/backend-error.js.map +1 -0
- package/dist/http/index.d.ts +59 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +175 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/types.d.ts +45 -0
- package/dist/http/types.d.ts.map +1 -0
- package/dist/http/types.js +2 -0
- package/dist/http/types.js.map +1 -0
- package/dist/http/utils.d.ts +14 -0
- package/dist/http/utils.d.ts.map +1 -0
- package/dist/http/utils.js +37 -0
- package/dist/http/utils.js.map +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +2 -1
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +47 -77
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +58 -73
- package/dist/index.js.map +1 -1
- package/dist/pkce.js +4 -4
- package/dist/postgrest/index.d.ts +4 -0
- package/dist/postgrest/index.d.ts.map +1 -0
- package/dist/postgrest/index.js +4 -0
- package/dist/postgrest/index.js.map +1 -0
- package/dist/postgrest/query-builder.d.ts +224 -0
- package/dist/postgrest/query-builder.d.ts.map +1 -0
- package/dist/postgrest/query-builder.js +544 -0
- package/dist/postgrest/query-builder.js.map +1 -0
- package/dist/postgrest/rpc.d.ts +12 -0
- package/dist/postgrest/rpc.d.ts.map +1 -0
- package/dist/postgrest/rpc.js +42 -0
- package/dist/postgrest/rpc.js.map +1 -0
- package/dist/postgrest/types.d.ts +88 -0
- package/dist/postgrest/types.d.ts.map +1 -0
- package/dist/postgrest/types.js +2 -0
- package/dist/postgrest/types.js.map +1 -0
- package/dist/postgrest/utils.d.ts +23 -0
- package/dist/postgrest/utils.d.ts.map +1 -0
- package/dist/postgrest/utils.js +87 -0
- package/dist/postgrest/utils.js.map +1 -0
- package/dist/postgrest.d.ts +5 -1
- package/dist/postgrest.d.ts.map +1 -1
- package/dist/postgrest.js +17 -10
- package/dist/postgrest.js.map +1 -1
- package/dist/realtime/channel.d.ts +83 -0
- package/dist/realtime/channel.d.ts.map +1 -0
- package/dist/realtime/channel.js +240 -0
- package/dist/realtime/channel.js.map +1 -0
- package/dist/realtime/index.d.ts +94 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +455 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/types.d.ts +120 -0
- package/dist/realtime/types.d.ts.map +1 -0
- package/dist/realtime/types.js +2 -0
- package/dist/realtime/types.js.map +1 -0
- package/dist/realtime.d.ts +1 -0
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +26 -1
- package/dist/realtime.js.map +1 -1
- package/dist/runtime.d.ts +13 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +15 -0
- package/dist/runtime.js.map +1 -0
- package/dist/session.d.ts +2 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +11 -2
- package/dist/session.js.map +1 -1
- package/dist/storage/bucket.d.ts +166 -0
- package/dist/storage/bucket.d.ts.map +1 -0
- package/dist/storage/bucket.js +294 -0
- package/dist/storage/bucket.js.map +1 -0
- package/dist/storage/index.d.ts +45 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +55 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/types.d.ts +131 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/storage/utils.d.ts +27 -0
- package/dist/storage/utils.d.ts.map +1 -0
- package/dist/storage/utils.js +43 -0
- package/dist/storage/utils.js.map +1 -0
- package/dist/test.d.ts +2 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +3 -0
- package/dist/test.js.map +1 -0
- package/dist/types.d.ts +14 -249
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/compat.d.ts +40 -0
- package/dist/utils/compat.d.ts.map +1 -0
- package/dist/utils/compat.js +100 -0
- package/dist/utils/compat.js.map +1 -0
- package/dist/utils/runtime.d.ts +13 -0
- package/dist/utils/runtime.d.ts.map +1 -0
- package/dist/utils/runtime.js +15 -0
- package/dist/utils/runtime.js.map +1 -0
- package/dist/utils/testing.d.ts +38 -0
- package/dist/utils/testing.d.ts.map +1 -0
- package/dist/utils/testing.js +50 -0
- package/dist/utils/testing.js.map +1 -0
- package/dist/utils/warn.d.ts +2 -0
- package/dist/utils/warn.d.ts.map +1 -0
- package/dist/utils/warn.js +23 -0
- package/dist/utils/warn.js.map +1 -0
- package/package.json +13 -11
- package/dist/devices.d.ts +0 -13
- package/dist/devices.d.ts.map +0 -1
- package/dist/devices.js +0 -13
- package/dist/devices.js.map +0 -1
- package/dist/profile.d.ts +0 -16
- package/dist/profile.d.ts.map +0 -1
- package/dist/profile.js +0 -26
- package/dist/profile.js.map +0 -1
package/COMPATIBILITY.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
GENERATED FILE. Do not edit by hand.
|
|
3
|
+
Written by apps/server/tests/sdk-contract.integration.test.ts.
|
|
4
|
+
Regenerate with: npm run test -w apps/server -- sdk-contract
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
# @motherbase/client vs supabase-js
|
|
8
|
+
|
|
9
|
+
Every row is produced by a contract test that runs the real `@motherbase/client` against a real Motherbase server backed by a real Postgres. Rows marked `Not supported` assert the current failure behaviour, so implementing the feature breaks the test and forces this table to be regenerated. The table cannot claim more or less than the code does.
|
|
10
|
+
|
|
11
|
+
Legend:
|
|
12
|
+
|
|
13
|
+
- `Supported`: behaves as supabase-js does.
|
|
14
|
+
- `Partial`: works, with the difference stated in the note.
|
|
15
|
+
- `Not supported`: not implemented today. The note says what happens if you call it.
|
|
16
|
+
|
|
17
|
+
Totals: 67 supported, 14 partial, 14 not supported (95 rows).
|
|
18
|
+
|
|
19
|
+
## Client
|
|
20
|
+
|
|
21
|
+
| Test id | Surface | Status | Notes |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `client.createClient` | `createClient(url, key, options)` | Supported | The key is sent as an apikey header. Options cover session storage, a fetch override and extra headers. |
|
|
24
|
+
| `client.getChannels` | `client.getChannels()` | Supported | Returns the channels this client has created, as supabase-js does. |
|
|
25
|
+
| `client.options-shape` | `createClient(url, key, { auth, db, global })` | Supported | supabase-js nests its options under auth, db, global and realtime, and ported code passes them that way. Both spellings are read, the flat one winning where they collide, so { auth: { persistSession } } and { global: { headers, fetch } } take effect instead of being silently dropped. auth.storage accepts either adapter shape, including a React Native AsyncStorage. |
|
|
26
|
+
| `client.rpc` | `client.rpc(fn, args)` | Supported | POST and GET /rest/v1/rpc/:fn resolve a public function from the catalog and call it with named arguments inside the caller RLS transaction. SECURITY DEFINER functions are refused unless an operator allowlists them, and an unknown function is a 404. |
|
|
27
|
+
| `client.schema` | `client.schema('other') / createClient(url, key, { db: { schema } })` | Partial | schema('public') is the client. schema(name).rpc() calls functions in another schema through the Content-Profile/Accept-Profile headers, for the schemas a feature exposes (Queues' pgmq_public); any other is refused with PGRST106. Tables are served from public only, so schema(name).from() and the db.schema constructor option throw with the reason rather than reading public under another name. |
|
|
28
|
+
| `client.typed-database` | `createClient<Database>(url, key)` | Supported | motherbase gen types typescript emits the supabase-js Database shape (Row, Insert, Update, Relationships, Enums, Functions) from the Postgres catalog, and createClient<Database> types from() and rpc() from it. Unknown columns are still rejected at runtime as well. |
|
|
29
|
+
|
|
30
|
+
## Data · verbs
|
|
31
|
+
|
|
32
|
+
| Test id | Surface | Status | Notes |
|
|
33
|
+
| --- | --- | --- | --- |
|
|
34
|
+
| `data.verb.delete` | `from(t).delete().eq(col, v)` | Supported | Deleted rows are returned when .select() is requested. The delete is bound to the row versions whose realtime audience was captured. |
|
|
35
|
+
| `data.verb.delete.unfiltered` | `from(t).delete()` | Partial | An unfiltered delete is refused with 400 for non-admin callers, on purpose. supabase-js would delete every visible row. |
|
|
36
|
+
| `data.verb.insert.bulk` | `from(t).insert([rowA, rowB])` | Supported | An array body is compiled into one multi-row INSERT. Rows may declare different key subsets; a key a row omits is written as DEFAULT so the column default applies. |
|
|
37
|
+
| `data.verb.insert.single` | `from(t).insert(row)` | Supported | One row per call; .select() returns it with server defaults applied. Without .select(), data is null. |
|
|
38
|
+
| `data.verb.select` | `from(t).select('*')` | Supported | Awaitable, resolves to { data, error } and never throws for an API error. |
|
|
39
|
+
| `data.verb.update` | `from(t).update(values).eq(col, v)` | Supported | Returns the updated rows when .select() is requested. A filter that matches nothing is a 404 rather than an empty array. |
|
|
40
|
+
| `data.verb.upsert` | `from(t).upsert(rows, { onConflict })` | Supported | A real INSERT ... ON CONFLICT DO UPDATE. The conflict target is ?on_conflict= or the catalog primary key, and a row that actually conflicted emits an updated realtime event rather than a created one. |
|
|
41
|
+
| `data.verb.write-returning` | `from(t).insert(row).select()` | Supported | Writes return no rows by default. Add .select() to opt into a representation, subject to the caller’s SELECT policy. |
|
|
42
|
+
|
|
43
|
+
## Data · filters
|
|
44
|
+
|
|
45
|
+
| Test id | Surface | Status | Notes |
|
|
46
|
+
| --- | --- | --- | --- |
|
|
47
|
+
| `data.filter.containedBy-overlaps` | `from(t).containedBy(col, v) / .overlaps(col, v)` | Supported | Compiled to the contained-by and overlap operators, on array and range columns. |
|
|
48
|
+
| `data.filter.contains` | `from(t).contains(col, value)` | Supported | Compiled to the containment operator. It applies to array, range and jsonb columns; used on a scalar column it is a 400 rather than a silently empty result. |
|
|
49
|
+
| `data.filter.eq` | `from(t).eq(col, v)` | Supported | Compiled to a parameterised equality. |
|
|
50
|
+
| `data.filter.filter` | `from(t).filter(col, op, value)` | Supported | The escape hatch reaches any operator in the dialect, including ones with no dedicated builder method. |
|
|
51
|
+
| `data.filter.gt-gte-lt-lte` | `from(t).gt/gte/lt/lte(col, v)` | Supported | All four compile to the matching SQL comparison. |
|
|
52
|
+
| `data.filter.ilike` | `from(t).ilike(col, pattern)` | Supported | Case-insensitive ILIKE with PostgREST anchoring, so %ETA means "ends with eta" rather than a substring match. |
|
|
53
|
+
| `data.filter.in` | `from(t).in(col, [..])` | Supported | Compiled to an IN list. The client quotes any value that needs it, so a value containing a comma stays one value instead of splitting into two. |
|
|
54
|
+
| `data.filter.is` | `from(t).is(col, null \| true \| false)` | Supported | is null becomes IS NULL. Boolean forms become an equality. |
|
|
55
|
+
| `data.filter.json-path` | `from(t).eq('col->>key', v)` | Supported | A jsonb path operand is parsed and compiled. The text arrow compares as text, the object arrow compares as jsonb, and every path segment is bound as a parameter rather than interpolated. |
|
|
56
|
+
| `data.filter.like` | `from(t).like(col, pattern)` | Supported | Case-sensitive LIKE with PostgREST anchoring. * is translated to %, and an unanchored pattern is an exact match. |
|
|
57
|
+
| `data.filter.match` | `from(t).match({ col: v })` | Supported | Expanded into one equality filter per key, all ANDed together. |
|
|
58
|
+
| `data.filter.neq` | `from(t).neq(col, v)` | Supported | Compiled to !=, so NULL values are excluded exactly as in PostgREST. |
|
|
59
|
+
| `data.filter.not` | `from(t).not(col, op, value)` | Supported | Emitted as a not. prefix and honoured on every operator, including not.is.null. |
|
|
60
|
+
| `data.filter.or` | `from(t).or('a.eq.1,b.eq.2')` | Supported | Emitted as an or group and compiled recursively, so a nested and() inside it works too. |
|
|
61
|
+
| `data.filter.range-operators` | `from(t).rangeGt/rangeGte/rangeLt/rangeLte/rangeAdjacent` | Supported | Emitted as the strictly-left, strictly-right, not-extending and adjacent operators. The compat fixture has no range column, so this pins the emitted encoding rather than a result set. |
|
|
62
|
+
| `data.filter.textSearch` | `from(t).textSearch(col, query)` | Supported | Maps to the four text-search operators, with an optional configuration rendered in parentheses. |
|
|
63
|
+
|
|
64
|
+
## Data · modifiers
|
|
65
|
+
|
|
66
|
+
| Test id | Surface | Status | Notes |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| `data.modifier.abortSignal` | `from(t).select().abortSignal(signal)` | Supported | The signal is handed to fetch, so an aborted query settles as an error instead of resolving rows. |
|
|
69
|
+
| `data.modifier.csv-explain` | `from(t).select().csv() / .explain()` | Partial | csv() returns RFC 4180 text. explain() is admin-only: the server answers 403 for a normal caller, so an application cannot rely on it. |
|
|
70
|
+
| `data.modifier.limit` | `from(t).limit(n)` | Supported | Sent as ?limit=n. The server caps it at the console-tunable api.rest.maxRows (1000 by default). |
|
|
71
|
+
| `data.modifier.limit.foreignTable` | `from(t).limit(n, { foreignTable })` | Supported | Emitted as <relation>.limit and applied to the embedded subquery, so a parent keeps all its rows while its children are capped. |
|
|
72
|
+
| `data.modifier.maxAffected-rollback` | `from(t).update(v).maxAffected(n) / .rollback()` | Supported | maxAffected rejects and rolls back writes above the limit; rollback performs a dry run. Both preserve transaction atomicity even when no rows are requested. |
|
|
73
|
+
| `data.modifier.maybeSingle` | `from(t).select().maybeSingle()` | Supported | Resolves the first row or null. Applied client side. |
|
|
74
|
+
| `data.modifier.order` | `from(t).order(col, { ascending })` | Supported | Multiple order() calls are concatenated into one ?order= list, as PostgREST does. |
|
|
75
|
+
| `data.modifier.order.options` | `from(t).order(col, { nullsFirst, referencedTable })` | Supported | nullsFirst emits the nullsfirst and nullslast qualifiers, and referencedTable scopes the ordering to an embedded relation. |
|
|
76
|
+
| `data.modifier.range` | `from(t).range(from, to)` | Supported | Translated to limit and offset. The server also reads a Range request header and always answers with Content-Range and Range-Unit. |
|
|
77
|
+
| `data.modifier.returns` | `from(t).select().returns<T>()` | Supported | A compile-time cast helper. It changes no request, matching supabase-js. |
|
|
78
|
+
| `data.modifier.setHeader` | `from(t).select().setHeader(name, value)` | Supported | Sends the header with that request only. It is how a CAPTCHA token reaches a table guarded under Attack Protection. |
|
|
79
|
+
| `data.modifier.single` | `from(t).select().single()` | Supported | Resolves one row, or a PGRST116 error when the result is not exactly one row. Applied client side. |
|
|
80
|
+
| `data.modifier.throwOnError` | `from(t).select().throwOnError()` | Supported | Rejects instead of resolving { data: null, error }, so ported code using try/catch works. Without it the envelope is still the default, in both SDKs. |
|
|
81
|
+
|
|
82
|
+
## Data · response
|
|
83
|
+
|
|
84
|
+
| Test id | Surface | Status | Notes |
|
|
85
|
+
| --- | --- | --- | --- |
|
|
86
|
+
| `data.response.count` | `from(t).select('*', { count: 'exact' })` | Supported | Prefer count=exact, planned or estimated is honoured, and the total comes back with a Content-Range header computed in the same transaction as the rows. |
|
|
87
|
+
| `data.response.default-limit` | `from(t).select() with no limit` | Supported | An unbounded select returns up to api.rest.maxRows (1000 by default), which is what PostgREST does with db-max-rows and what a Supabase app was built against. One number governs both the default and the ceiling, so lowering it is how you cap an unbounded read. |
|
|
88
|
+
| `data.response.embedding` | `from(t).select('*, author(*)')` | Supported | Embedded resources compile to correlated LATERAL subqueries inside the same RLS transaction, so embedded rows are policy-filtered too. Aliases, !inner, FK hints, nested filter/order/limit and the count aggregate all work. |
|
|
89
|
+
| `data.response.error-shape` | `{ data, error } result envelope` | Supported | Expected API failures resolve rather than throw. error is { message, status, code }. |
|
|
90
|
+
| `data.response.select-alias-cast` | `from(t).select('alias:col, col::text')` | Supported | Renamed columns and casts both compile. A cast target must be a bare lowercase type name with an optional array marker, so it cannot smuggle SQL. |
|
|
91
|
+
| `data.response.select-projection` | `from(t).select('id,label')` | Supported | Column lists are validated against the table and compiled into the SELECT list. |
|
|
92
|
+
|
|
93
|
+
## Auth
|
|
94
|
+
|
|
95
|
+
| Test id | Surface | Status | Notes |
|
|
96
|
+
| --- | --- | --- | --- |
|
|
97
|
+
| `auth.admin` | `auth.admin.*` | Partial | User administration, MFA factor administration (admin.mfa.listFactors / deleteFactor) and generateLink, only with a secret project API key. This is Motherbase's API, shaped like supabase-js, not Better Auth's admin plugin. Narrower than the supabase service role, which also opens SQL and DDL. generateLink covers signup, invite, magiclink and recovery; recovery is code-based here, so it returns email_otp and no action_link, and email_change_* is refused. |
|
|
98
|
+
| `auth.better-auth` | `auth.<any Better Auth client method>` | Supported | client.auth is Better Auth's client, typed with every plugin the server mounts (anonymous, email OTP, magic link, phone number, two-factor, organization, generic OAuth, JWT, passkey, SSO, API keys). Method names, parameters and the { data, error } results are Better Auth's, so its documentation applies as written; the SDK stores the session it returns, which is what from(), storage and realtime then send. |
|
|
99
|
+
| `auth.deleteUser` | `auth.deleteUser()` | Partial | Better Auth's deleteUser: self-service, which supabase-js only offers to an admin. It takes the password (or a fresh session), and clears the local session once the account is gone. |
|
|
100
|
+
| `auth.exchangeCodeForSession` | `auth.exchangeCodeForSession(code) / getSessionFromUrl(href?)` | Supported | With flowType 'pkce' the S256 challenge rides on the callback URL and the redirect returns ?code=, exchanged once against the verifier this browser kept (automatically on load, as detectSessionInUrl does). The implicit flow remains the default: the token comes back in the fragment and getSessionFromUrl reads it and strips it from the URL. |
|
|
101
|
+
| `auth.getClaims` | `auth.getClaims()` | Not supported | Use auth.token(): a Better Auth session token is an opaque bearer, so the jwt plugin mints a JWT for the session. Verify it server side against /api/auth/jwks. |
|
|
102
|
+
| `auth.getSession` | `auth.getSession()` | Partial | Better Auth's getSession: it asks the server, so it is the verified read, and returns { session, user } with Better Auth's session row rather than a token pair. A session the server no longer knows is cleared locally. The stored session without a network call is client.hydrate(). |
|
|
103
|
+
| `auth.getUser` | `auth.getUser()` | Not supported | Use auth.getSession(), which asks the server and returns the user with the session. |
|
|
104
|
+
| `auth.identities` | `auth.getUserIdentities() / linkIdentity() / unlinkIdentity()` | Not supported | Use auth.listAccounts(), auth.linkSocial({ provider, callbackURL }) and auth.unlinkAccount({ providerId }). A password account lists its credential account. |
|
|
105
|
+
| `auth.mfa` | `auth.mfa.*` | Not supported | Use auth.twoFactor: enable({ password }) returns the TOTP URI and backup codes, verifyTotp / verifyOtp / verifyBackupCode finish a sign-in that answered twoFactorRedirect, disable({ password }) turns it off. The aal the server stamps on a session is on auth.getSession(). |
|
|
106
|
+
| `auth.onAuthStateChange` | `auth.onAuthStateChange(cb)` | Supported | Fires INITIAL_SESSION once on subscribe, as supabase-js does, so an app that clears its loading flag on that event also clears it for a signed-out visitor. Then SIGNED_IN, USER_UPDATED, MFA_CHALLENGE_VERIFIED and SIGNED_OUT as the Better Auth calls change the session. There is no TOKEN_REFRESHED: Better Auth sessions are not rotated. Returns { data: { subscription } }. |
|
|
107
|
+
| `auth.refreshSession` | `auth.refreshSession() / startAutoRefresh()` | Not supported | Better Auth sessions have no refresh token to rotate. auth.getSession() revalidates, and the client already does so on a 401. |
|
|
108
|
+
| `auth.resetPassword` | `auth.resetPasswordForEmail(email)` | Not supported | Use auth.emailOtp.requestPasswordReset({ email }), then auth.emailOtp.resetPassword({ email, otp, password }): the reset is completed with a one time code rather than a redirect link. |
|
|
109
|
+
| `auth.session-shape` | `session.access_token / user.user_metadata` | Partial | The session the SDK stores (client.hydrate(), onAuthStateChange) carries the supabase-js spellings alongside the native ones: access_token, refresh_token (always null), token_type, and on the user aud, role, created_at, email_confirmed_at, phone, identities and user_metadata holding the profile fields. app_metadata is {} rather than a guessed provider, and expires_at is absent. Better Auth's own responses keep its native shape. |
|
|
110
|
+
| `auth.setSession` | `auth.setSession({ access_token, refresh_token })` | Not supported | A session token from elsewhere is adopted through the storage adapter the client is created with, or through auth.getSessionFromUrl() on an OAuth return. |
|
|
111
|
+
| `auth.signInWithIdToken` | `auth.signInWithIdToken({ provider, token })` | Not supported | Use auth.signIn.social({ provider, idToken: { token } }), for Sign in with Apple and Google One Tap from a native app. The provider must be configured on the backend. |
|
|
112
|
+
| `auth.signInWithOAuth` | `auth.signInWithOAuth({ provider, options })` | Not supported | Use auth.signIn.social({ provider, callbackURL }). In a browser it navigates to the server's start route, which keeps the OAuth state cookie first-party; disableRedirect: true returns the URL instead. The redirect back is completed by getSessionFromUrl(), on load by default. |
|
|
113
|
+
| `auth.signInWithOtp` | `auth.signInWithOtp({ email \| phone }) then auth.verifyOtp({ token })` | Not supported | Use auth.emailOtp.sendVerificationOtp({ email, type: 'sign-in' }) then auth.signIn.emailOtp({ email, otp }); by SMS, auth.phoneNumber.sendOtp and auth.phoneNumber.verify, when the phone-number plugin is on with a sender configured. Magic links are auth.signIn.magicLink. |
|
|
114
|
+
| `auth.signInWithPassword` | `auth.signInWithPassword({ email, password })` | Not supported | Use auth.signIn.email({ email, password }). The session is stored through the configured storage adapter and SIGNED_IN fires; with two-factor on, the answer is { twoFactorRedirect: true } and no session until auth.twoFactor verifies a code. |
|
|
115
|
+
| `auth.signInWithSSO` | `auth.signInWithSSO({ domain })` | Not supported | Use auth.signIn.sso({ email, callbackURL }), or name the provider by domain, providerId or organizationSlug instead of email. The project needs the SSO plugin on and a provider registered; providers are managed with auth.sso.*. |
|
|
116
|
+
| `auth.signOut` | `auth.signOut()` | Supported | Better Auth's signOut: revokes the server session and clears the local one. Other devices are auth.revokeOtherSessions(), every device auth.revokeSessions(). |
|
|
117
|
+
| `auth.signUp` | `auth.signUp({ email, password })` | Not supported | Use auth.signUp.email({ email, password, name }). It answers { token, user }, with a null token while the project requires email verification first. |
|
|
118
|
+
| `auth.updateUser` | `auth.updateUser({ data, email, password })` | Partial | Better Auth's updateUser takes the profile fields flat ({ name, image, ...additional fields }), not under data. A password is auth.changePassword({ currentPassword, newPassword }); an anonymous user's first email, a first password, or a password replaced with the nonce from auth.reauthenticate() is auth.updateUserCredentials(). |
|
|
119
|
+
|
|
120
|
+
## Storage
|
|
121
|
+
|
|
122
|
+
| Test id | Surface | Status | Notes |
|
|
123
|
+
| --- | --- | --- | --- |
|
|
124
|
+
| `storage.bucket-admin` | `storage.createBucket/getBucket/listBuckets/updateBucket/emptyBucket/deleteBucket` | Partial | All six are on the client and every one needs a secret project API key, which is the same rule Supabase applies to bucket administration. With a publishable key they resolve with a 401 rather than a partial answer. deleteBucket refuses a bucket that still holds objects unless force is passed, so one unqualified call cannot destroy the files in it. |
|
|
125
|
+
| `storage.createSignedUrl` | `storage.from(b).createSignedUrl(path, expiresIn)` | Partial | expiresIn is read, in seconds, and validated from 1 second to 7 days (the AWS SigV4 ceiling); a longer lifetime is refused rather than quietly clamped. It resolves to { signedUrl, expiresAt }, and expiresAt is null when nothing actually expires: a public object URL is permanent, and a private object on the local driver resolves to the authenticated streaming endpoint, which is bound to the session rather than to a clock. |
|
|
126
|
+
| `storage.createSignedUrls` | `storage.from(b).createSignedUrls(paths, expiresIn)` | Supported | Signs each key and reports per entry, so a missing object yields one entry carrying an error instead of failing the batch. There is no batch endpoint behind it: it is one request per key. |
|
|
127
|
+
| `storage.download` | `storage.from(b).download(path)` | Supported | Resolves a Blob, addressed by the key the object was uploaded under. A file id is still accepted. |
|
|
128
|
+
| `storage.getPublicUrl` | `storage.from(b).getPublicUrl(path)` | Supported | Synchronous, returns { data: { publicUrl } } built from the client base URL. |
|
|
129
|
+
| `storage.info-exists` | `storage.from(b).info(path) / .exists(path)` | Supported | info returns the object's metadata without its body, in the supabase-js shape. exists reports false only for a 404: an authorization failure is reported as an error, because treating one as absence is how a UI offers to create something that is already there. |
|
|
130
|
+
| `storage.list` | `storage.from(b).list(prefix, options)` | Supported | Lists objects under a prefix in the Supabase response shape (name, id, created_at, updated_at, metadata), with limit, offset, search and sortBy. Keys come back relative to the bucket. |
|
|
131
|
+
| `storage.move-copy` | `storage.from(b).move(from, to) / .copy(from, to)` | Supported | Both work within one bucket. The bytes stream through the upload path, so bucket quota, the size guard and the mime allowlist apply to a copy exactly as to a fresh upload. move deletes the source only once the copy has landed. |
|
|
132
|
+
| `storage.remove` | `storage.from(b).remove([path])` | Supported | Addressed by the key the object was uploaded under, as in supabase-js, and reported per entry. A bare file id still resolves, exactly as it does for download. |
|
|
133
|
+
| `storage.signed-upload` | `storage.from(b).createSignedUploadUrl(path) / .uploadToSignedUrl(path, token, file)` | Partial | Both exist and land the object at the key you asked for, but createSignedUploadUrl needs the byte size and content type up front: the upload is reserved against the bucket quota and the signature is bound to that exact length, which is what stops a signed URL becoming an unbounded write. Requires the S3 driver; the local driver has no presigned uploads. |
|
|
134
|
+
| `storage.transform` | `storage.from(b).download(path, { transform })` | Supported | Also getPublicUrl and createSignedUrl with { transform }, served by /storage/v1/render/image with Supabase limits. Without format, WebP is negotiated from Accept. |
|
|
135
|
+
| `storage.update` | `storage.from(b).update(path, file)` | Supported | upload with upsert forced on, exactly as in supabase-js. |
|
|
136
|
+
| `storage.upload` | `storage.from(b).upload(path, file, options)` | Supported | The key is the one you passed. avatars/{uid}/pic.png style paths round trip through upload, download, remove and the signed URL. The file id keeps working everywhere a path does. |
|
|
137
|
+
| `storage.upload.options` | `storage.from(b).upload(path, file, { upsert, contentType })` | Partial | upsert works: without it a second write to the same key is a 409, with it the object is replaced. contentType overrides what the file itself declares. supabase-js' cacheControl is not part of UploadOptions, so a ported call naming it is a type error rather than a silently dropped option: cache headers are decided by the driver and, for a transform, by the render endpoint. |
|
|
138
|
+
|
|
139
|
+
## Realtime
|
|
140
|
+
|
|
141
|
+
| Test id | Surface | Status | Notes |
|
|
142
|
+
| --- | --- | --- | --- |
|
|
143
|
+
| `realtime.broadcast` | `channel(n).on('broadcast', { event }, cb) and channel.send(...)` | Supported | Routed by topic. config.broadcast.self and config.broadcast.ack are both honoured. |
|
|
144
|
+
| `realtime.channel.private` | `channel(n, { config: { private: true } })` | Supported | The flag is sent in the join payload; the server then checks the RLS policies on realtime.messages (SELECT to receive, INSERT to send or track). |
|
|
145
|
+
| `realtime.channel.unknown-event` | `channel(n).on('system', ...)` | Not supported | Only broadcast, presence and postgres_changes are accepted. Anything else throws immediately. |
|
|
146
|
+
| `realtime.postgres_changes` | `channel(n).on('postgres_changes', { event, schema, table, filter }, cb).subscribe()` | Supported | INSERT, UPDATE, DELETE and * are delivered with the supabase payload shape. Server side the stream is RLS filtered. |
|
|
147
|
+
| `realtime.presence` | `channel(n).on('presence', ...) with track/untrack/presenceState` | Supported | The server sends full state and the client diffs it into sync, join and leave, keyed by config.presence.key. |
|
|
148
|
+
| `realtime.removeChannel` | `client.removeChannel(channel) / client.removeAllChannels()` | Supported | Unsubscribes and drops the channel, resolving to "ok". |
|
|
149
|
+
| `realtime.subscribe.status` | `channel.subscribe(status => {})` | Supported | Reports SUBSCRIBED, TIMED_OUT, CLOSED and CHANNEL_ERROR, as supabase-js does. |
|
|
150
|
+
|
|
151
|
+
## Edge functions
|
|
152
|
+
|
|
153
|
+
| Test id | Surface | Status | Notes |
|
|
154
|
+
| --- | --- | --- | --- |
|
|
155
|
+
| `functions.invoke` | `functions.invoke(name, { body })` | Supported | POSTs the JSON body to /api/edge/:name with the current session bearer attached. |
|
|
156
|
+
| `functions.invoke.error` | `functions.invoke error handling` | Partial | invoke resolves { data: null, error } rather than throwing, but error is a real FunctionsHttpError (or FunctionsFetchError when the request never reached the server), so an instanceof check ported from supabase-js still works. |
|
|
157
|
+
| `functions.invoke.options` | `functions.invoke(name, { headers, method, region })` | Partial | method and headers are honoured: the invoke route answers every verb and forwards the request headers to the function, so a function reading req.method sees the one you asked for. region is accepted and ignored, because a self-hosted Motherbase runs its functions in one place. |
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Motherbase contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Motherbase contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ traversal-checked. `copy`, `move`, `info`, `exists`, batch signed URLs and
|
|
|
31
31
|
direct-to-storage signed uploads are supported; image transforms are not.
|
|
32
32
|
Authorization is ownership plus bucket tokens by default, and real RLS policies on
|
|
33
33
|
`storage.files` when the `storage.policies` setting is on. See
|
|
34
|
-
[`docs/migrating-from-supabase.md`](
|
|
34
|
+
[`docs/migrating-from-supabase.md`](https://github.com/JulienGuinot/Boilerplate-backend/blob/master/docs/migrating-from-supabase.md).
|
|
35
35
|
|
|
36
36
|
On the server, `createClient(url, secretKey)` also authorizes storage objects as
|
|
37
37
|
`service_role`, including objects uploaded by another user. Secret-key
|
|
@@ -75,6 +75,18 @@ requiring client read access. It does not enable event delivery for arbitrary
|
|
|
75
75
|
SQL-editor or RPC writes. Motherbase's `transaction()` extension retains its
|
|
76
76
|
existing batch response contract.
|
|
77
77
|
|
|
78
|
+
Transaction callbacks describe writes without awaiting the individual builders.
|
|
79
|
+
Awaiting a transaction builder is rejected before any request is sent. The batch
|
|
80
|
+
endpoint does not support per-operation preferences or headers: `rollback()`,
|
|
81
|
+
`maxAffected()`, upsert conflict preferences, count options and custom headers
|
|
82
|
+
are rejected locally instead of being silently ignored. Use a standalone query
|
|
83
|
+
for those options.
|
|
84
|
+
|
|
85
|
+
Multiple `postgres_changes` bindings on one realtime channel require a server
|
|
86
|
+
that advertises binding-id support in its join acknowledgement. Older servers
|
|
87
|
+
remain usable with one binding per channel; a multi-binding subscription reports
|
|
88
|
+
`CHANNEL_ERROR` with upgrade instructions.
|
|
89
|
+
|
|
78
90
|
**Invalid keys are refused.** A project key that is unknown or revoked now
|
|
79
91
|
answers `401 UNAUTHORIZED` even when the project does not require an API key.
|
|
80
92
|
Before, it was ignored and the request ran as anonymous. Remove stale keys from
|
|
@@ -85,6 +97,30 @@ on global `fetch`. Its runtime dependencies are Better Auth's client and its
|
|
|
85
97
|
plugins; `socket.io-client` is an optional peer dependency, used only for
|
|
86
98
|
realtime.
|
|
87
99
|
|
|
100
|
+
## Upgrading from 1.x
|
|
101
|
+
|
|
102
|
+
Only the auth renames fail to compile. Go through the rest by hand:
|
|
103
|
+
|
|
104
|
+
1. **Upgrade the server first**, with its migrations applied
|
|
105
|
+
(`20260924120000_rest_write_capture` among them). A 2.x client does not check
|
|
106
|
+
the server version.
|
|
107
|
+
2. **Auth calls are Better Auth's.** `signInWithPassword` is `signIn.email`,
|
|
108
|
+
`signUp` is `signUp.email` (which requires `name`), `getUser` is gone.
|
|
109
|
+
[`COMPATIBILITY.md`](./COMPATIBILITY.md) has every rename;
|
|
110
|
+
`motherbase migrate codemod` lists the ones in your code.
|
|
111
|
+
3. **Authorize on `auth.getSession()`**: it asks the server. `client.hydrate()`
|
|
112
|
+
returns what storage holds, unverified.
|
|
113
|
+
4. **Writes resolve `data: null` without `.select()`**, now in the types too: a
|
|
114
|
+
1.x call that read `data` from a bare `insert()` stops compiling.
|
|
115
|
+
5. **A stale project key is a 401** (see *Invalid keys are refused* above).
|
|
116
|
+
|
|
117
|
+
Signed-in users stay signed in: 1.x already stored the server's Better Auth
|
|
118
|
+
session token, in the same shape.
|
|
119
|
+
|
|
120
|
+
On npm 10, `npm install` crashes resolving Better Auth 1.6's optional peers
|
|
121
|
+
(`Cannot read properties of null (reading 'edgesOut')`), with or without this
|
|
122
|
+
package. Use npm 11+, or `legacy-peer-deps=true` in `.npmrc`.
|
|
123
|
+
|
|
88
124
|
## Install
|
|
89
125
|
|
|
90
126
|
```bash
|
|
@@ -192,6 +228,17 @@ client.from('posts').select('id, comments(count)') // aggregate
|
|
|
192
228
|
// unless an operator allowlists them.
|
|
193
229
|
client.rpc(fn, args, { get, head, count })
|
|
194
230
|
|
|
231
|
+
// The same tables, Prisma-style. Sends the same requests as from(), but throws
|
|
232
|
+
// on failure instead of resolving { data, error }. Operators: equals not in gt
|
|
233
|
+
// gte lt lte contains startsWith endsWith. Embedded relations and or() stay on from().
|
|
234
|
+
client.db.posts.findMany({ where: { published: true, views: { gt: 100 } }, select: { id: true, title: true },
|
|
235
|
+
orderBy: { created_at: 'desc' }, take: 20, skip: 40 })
|
|
236
|
+
client.db.posts.findFirst({ where: { id } }) // row | null
|
|
237
|
+
client.db.posts.create({ data: { title } }) // the inserted row
|
|
238
|
+
client.db.posts.updateMany({ where: { id }, data: { title } }) | .deleteMany({ where: { id } })
|
|
239
|
+
// Both resolve the affected rows, and refuse a where that matches no column:
|
|
240
|
+
// { id: undefined } would otherwise write every row.
|
|
241
|
+
|
|
195
242
|
// Auth → Better Auth's client: https://www.better-auth.com/docs. A sample of
|
|
196
243
|
// what is there; each plugin needs to be on in the project's Auth settings.
|
|
197
244
|
client.auth.signUp.email({ email, password, name })
|
|
@@ -394,6 +441,7 @@ Regenerate it locally with:
|
|
|
394
441
|
npm run test -w apps/server -- sdk-contract
|
|
395
442
|
```
|
|
396
443
|
|
|
397
|
-
More examples live in
|
|
398
|
-
|
|
399
|
-
project
|
|
444
|
+
More examples live in
|
|
445
|
+
[`docs/sdk.md`](https://github.com/JulienGuinot/Boilerplate-backend/blob/master/docs/sdk.md).
|
|
446
|
+
Project Studio also exposes a project-specific Connect page with the exact API
|
|
447
|
+
URL, WebSocket URL and project ID to paste into `.env`.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { HttpClient } from "../http/index.js";
|
|
2
|
+
import { MotherbaseResponse } from "../types.js";
|
|
3
|
+
import { User } from "../auth/types.js";
|
|
4
|
+
import { AuthAdminMfaClient } from "./auth-admin-mfa-client.js";
|
|
5
|
+
import { AdminCreatedUser, AdminCreateUserParams, AdminGeneratedLink, AdminGenerateLinkParams, AdminListUsersParams, AdminUpdateUserParams, AdminUserList } from "./types.js";
|
|
6
|
+
/** User administration, `client.auth.admin`. Secret key only: never ship it to a browser. */
|
|
7
|
+
export declare class AuthAdminClient {
|
|
8
|
+
private readonly http;
|
|
9
|
+
/** Users' second factors. */
|
|
10
|
+
readonly mfa: AuthAdminMfaClient;
|
|
11
|
+
constructor(http: HttpClient);
|
|
12
|
+
/** The link (or code) an auth email would carry, returned instead of sent. */
|
|
13
|
+
generateLink(params: AdminGenerateLinkParams): Promise<MotherbaseResponse<AdminGeneratedLink>>;
|
|
14
|
+
/** Every user, a page at a time (`page`, `perPage`). */
|
|
15
|
+
listUsers(params?: AdminListUsersParams): Promise<MotherbaseResponse<AdminUserList>>;
|
|
16
|
+
/** One user, or `{ user: null }` when the id matches none. */
|
|
17
|
+
getUserById(id: string): Promise<MotherbaseResponse<{
|
|
18
|
+
user: User | null;
|
|
19
|
+
}>>;
|
|
20
|
+
/** Create a user directly, without the sign-up flow or its emails. */
|
|
21
|
+
createUser(params: AdminCreateUserParams): Promise<MotherbaseResponse<AdminCreatedUser>>;
|
|
22
|
+
/** Change a user's email, password, role or profile. */
|
|
23
|
+
updateUserById(id: string, params: AdminUpdateUserParams): Promise<MotherbaseResponse<{
|
|
24
|
+
user: User | null;
|
|
25
|
+
}>>;
|
|
26
|
+
/** Delete a user. */
|
|
27
|
+
deleteUser(id: string): Promise<MotherbaseResponse<{
|
|
28
|
+
id: string;
|
|
29
|
+
}>>;
|
|
30
|
+
/** End every session this user holds, everywhere. */
|
|
31
|
+
signOut(userId: string): Promise<MotherbaseResponse<{
|
|
32
|
+
id: string;
|
|
33
|
+
}>>;
|
|
34
|
+
/** Create the account and email the temporary password to it. */
|
|
35
|
+
inviteUserByEmail(email: string, options?: {
|
|
36
|
+
username?: string;
|
|
37
|
+
role?: 'ADMIN' | 'USER';
|
|
38
|
+
}): Promise<MotherbaseResponse<{
|
|
39
|
+
user: User;
|
|
40
|
+
invited: boolean;
|
|
41
|
+
}>>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=auth-admin-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-admin-client.d.ts","sourceRoot":"","sources":["../../src/admin/auth-admin-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAQ,MAAM,YAAY,CAAC;AAIpL,6FAA6F;AAC7F,qBAAa,eAAe;IAIZ,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,6BAA6B;IAC7B,QAAQ,CAAC,GAAG,EAAE,kBAAkB,CAAC;gBAEJ,IAAI,EAAE,UAAU;IAI7C,8EAA8E;IAC9E,YAAY,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;IAI9F,wDAAwD;IACxD,SAAS,CAAC,MAAM,GAAE,oBAAyB,GAAG,OAAO,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAQxF,8DAA8D;IACxD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;QAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAMjF,sEAAsE;IACtE,UAAU,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;IAIxF,wDAAwD;IAClD,cAAc,CAChB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,qBAAqB,GAC9B,OAAO,CAAC,kBAAkB,CAAC;QAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAKrD,qBAAqB;IACrB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAOnE,qDAAqD;IACrD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAOpE,iEAAiE;IACjE,iBAAiB,CACb,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;KAAO,GAC7D,OAAO,CAAC,kBAAkB,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAMnE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { settle } from "../http/utils.js";
|
|
2
|
+
import { AuthAdminMfaClient } from "./auth-admin-mfa-client.js";
|
|
3
|
+
import { BASE } from "./types.js";
|
|
4
|
+
const userPath = (id) => `${BASE}/users/${encodeURIComponent(id)}`;
|
|
5
|
+
/** User administration, `client.auth.admin`. Secret key only: never ship it to a browser. */
|
|
6
|
+
export class AuthAdminClient {
|
|
7
|
+
constructor(http) {
|
|
8
|
+
this.http = http;
|
|
9
|
+
this.mfa = new AuthAdminMfaClient(http);
|
|
10
|
+
}
|
|
11
|
+
/** The link (or code) an auth email would carry, returned instead of sent. */
|
|
12
|
+
generateLink(params) {
|
|
13
|
+
return settle(() => this.http.request(`${BASE}/generate-link`, { method: 'POST', body: params }));
|
|
14
|
+
}
|
|
15
|
+
/** Every user, a page at a time (`page`, `perPage`). */
|
|
16
|
+
listUsers(params = {}) {
|
|
17
|
+
const query = new URLSearchParams();
|
|
18
|
+
if (params.page !== undefined)
|
|
19
|
+
query.set('page', String(params.page));
|
|
20
|
+
if (params.perPage !== undefined)
|
|
21
|
+
query.set('per_page', String(params.perPage));
|
|
22
|
+
const suffix = query.toString();
|
|
23
|
+
return settle(() => this.http.request(`${BASE}/users${suffix ? `?${suffix}` : ''}`));
|
|
24
|
+
}
|
|
25
|
+
/** One user, or `{ user: null }` when the id matches none. */
|
|
26
|
+
async getUserById(id) {
|
|
27
|
+
const { data, error } = await settle(() => this.http.request(userPath(id)));
|
|
28
|
+
// supabase-js answers a failed lookup with `{ user: null }`, not `null`.
|
|
29
|
+
return { data: data ?? { user: null }, error };
|
|
30
|
+
}
|
|
31
|
+
/** Create a user directly, without the sign-up flow or its emails. */
|
|
32
|
+
createUser(params) {
|
|
33
|
+
return settle(() => this.http.request(`${BASE}/users`, { method: 'POST', body: params }));
|
|
34
|
+
}
|
|
35
|
+
/** Change a user's email, password, role or profile. */
|
|
36
|
+
async updateUserById(id, params) {
|
|
37
|
+
const { data, error } = await settle(() => this.http.request(userPath(id), { method: 'PATCH', body: params }));
|
|
38
|
+
return { data: data ?? { user: null }, error };
|
|
39
|
+
}
|
|
40
|
+
/** Delete a user. */
|
|
41
|
+
deleteUser(id) {
|
|
42
|
+
return settle(async () => {
|
|
43
|
+
await this.http.request(userPath(id), { method: 'DELETE' });
|
|
44
|
+
return { id };
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** End every session this user holds, everywhere. */
|
|
48
|
+
signOut(userId) {
|
|
49
|
+
return settle(async () => {
|
|
50
|
+
await this.http.request(`${userPath(userId)}/sign-out`, { method: 'POST' });
|
|
51
|
+
return { id: userId };
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** Create the account and email the temporary password to it. */
|
|
55
|
+
inviteUserByEmail(email, options = {}) {
|
|
56
|
+
return settle(() => this.http.request(`${BASE}/invite`, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
body: { email, ...options },
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=auth-admin-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-admin-client.js","sourceRoot":"","sources":["../../src/admin/auth-admin-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAoJ,IAAI,EAAE,MAAM,YAAY,CAAC;AAEpL,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,GAAG,IAAI,UAAU,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC;AAE3E,6FAA6F;AAC7F,MAAM,OAAO,eAAe;IAIxB,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;QACzC,IAAI,CAAC,GAAG,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,8EAA8E;IAC9E,YAAY,CAAC,MAA+B;QACxC,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAqB,GAAG,IAAI,gBAAgB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1H,CAAC;IAED,wDAAwD;IACxD,SAAS,CAAC,SAA+B,EAAE;QACvC,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;QACpC,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;YAAE,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACtE,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAgB,GAAG,IAAI,SAAS,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACxG,CAAC;IAED,8DAA8D;IAC9D,KAAK,CAAC,WAAW,CAAC,EAAU;QACxB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAiB,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5F,yEAAyE;QACzE,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC;IAED,sEAAsE;IACtE,UAAU,CAAC,MAA6B;QACpC,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAmB,GAAG,IAAI,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAChH,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,cAAc,CAChB,EAAU,EACV,MAA6B;QAE7B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAiB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/H,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC;IAED,qBAAqB;IACrB,UAAU,CAAC,EAAU;QACjB,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE;YACrB,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC5D,OAAO,EAAE,EAAE,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,qDAAqD;IACrD,OAAO,CAAC,MAAc;QAClB,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE;YACrB,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YAC5E,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;QAC1B,CAAC,CAAC,CAAC;IACP,CAAC;IAED,iEAAiE;IACjE,iBAAiB,CACb,KAAa,EACb,UAA0D,EAAE;QAE5D,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAmC,GAAG,IAAI,SAAS,EAAE;YACtF,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE;SAC9B,CAAC,CAAC,CAAC;IACR,CAAC;CACJ"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { HttpClient } from "../http/index.js";
|
|
2
|
+
import { MotherbaseResponse } from "../types.js";
|
|
3
|
+
import { AdminMfaFactor } from "./types.js";
|
|
4
|
+
/** A user's second factors (TOTP, passkeys), `client.auth.admin.mfa`. Secret key only. */
|
|
5
|
+
export declare class AuthAdminMfaClient {
|
|
6
|
+
private readonly http;
|
|
7
|
+
constructor(http: HttpClient);
|
|
8
|
+
/** The second factors a user has enrolled. */
|
|
9
|
+
listFactors(params: {
|
|
10
|
+
userId: string;
|
|
11
|
+
}): Promise<MotherbaseResponse<{
|
|
12
|
+
factors: AdminMfaFactor[];
|
|
13
|
+
}>>;
|
|
14
|
+
/** Remove one of a user's second factors, e.g. to recover a lost device. */
|
|
15
|
+
deleteFactor(params: {
|
|
16
|
+
userId: string;
|
|
17
|
+
id: string;
|
|
18
|
+
}): Promise<MotherbaseResponse<{
|
|
19
|
+
id: string;
|
|
20
|
+
}>>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=auth-admin-mfa-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-admin-mfa-client.d.ts","sourceRoot":"","sources":["../../src/admin/auth-admin-mfa-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAQ,MAAM,YAAY,CAAC;AAElD,0FAA0F;AAC1F,qBAAa,kBAAkB;IACf,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,8CAA8C;IAC9C,WAAW,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;QAAE,OAAO,EAAE,cAAc,EAAE,CAAA;KAAE,CAAC,CAAC;IAMnG,4EAA4E;IAC5E,YAAY,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAMpG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { settle } from "../http/utils.js";
|
|
2
|
+
import { BASE } from "./types.js";
|
|
3
|
+
/** A user's second factors (TOTP, passkeys), `client.auth.admin.mfa`. Secret key only. */
|
|
4
|
+
export class AuthAdminMfaClient {
|
|
5
|
+
constructor(http) {
|
|
6
|
+
this.http = http;
|
|
7
|
+
}
|
|
8
|
+
/** The second factors a user has enrolled. */
|
|
9
|
+
listFactors(params) {
|
|
10
|
+
return settle(() => this.http.request(`${BASE}/users/${encodeURIComponent(params.userId)}/factors`));
|
|
11
|
+
}
|
|
12
|
+
/** Remove one of a user's second factors, e.g. to recover a lost device. */
|
|
13
|
+
deleteFactor(params) {
|
|
14
|
+
return settle(() => this.http.request(`${BASE}/users/${encodeURIComponent(params.userId)}/factors/${encodeURIComponent(params.id)}`, { method: 'DELETE' }));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=auth-admin-mfa-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-admin-mfa-client.js","sourceRoot":"","sources":["../../src/admin/auth-admin-mfa-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAkB,IAAI,EAAE,MAAM,YAAY,CAAC;AAElD,0FAA0F;AAC1F,MAAM,OAAO,kBAAkB;IAC3B,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAI,CAAC;IAElD,8CAA8C;IAC9C,WAAW,CAAC,MAA0B;QAClC,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CACjC,GAAG,IAAI,UAAU,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAC/D,CAAC,CAAC;IACP,CAAC;IAED,4EAA4E;IAC5E,YAAY,CAAC,MAAsC;QAC/C,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CACjC,GAAG,IAAI,UAAU,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAC7F,EAAE,MAAM,EAAE,QAAQ,EAAE,CACvB,CAAC,CAAC;IACP,CAAC;CACJ"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { User } from '../auth/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* `client.auth.admin`, shaped like `supabase.auth.admin`.
|
|
4
|
+
*
|
|
5
|
+
* Every method here needs a **secret** project API key, so the client it hangs
|
|
6
|
+
* off must have been built with one. A publishable key gets a 401 from the
|
|
7
|
+
* server, which is the correct outcome: these calls create and delete users
|
|
8
|
+
* without being any user.
|
|
9
|
+
*
|
|
10
|
+
* Two differences from supabase-js worth knowing before you port code:
|
|
11
|
+
*
|
|
12
|
+
* * Scope. This is user administration only. Supabase's service key also opens
|
|
13
|
+
* SQL and DDL; here those stay behind operator authentication, so a leaked
|
|
14
|
+
* application key cannot drop a table.
|
|
15
|
+
* * `generateLink` covers signup, invite, magiclink and recovery. Recovery is
|
|
16
|
+
* code-based here, so it returns `email_otp` and no `action_link`, and the
|
|
17
|
+
* `email_change_*` types are refused.
|
|
18
|
+
*/
|
|
19
|
+
export interface AdminListUsersParams {
|
|
20
|
+
page?: number;
|
|
21
|
+
perPage?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface AdminUserList {
|
|
24
|
+
users: User[];
|
|
25
|
+
page: number;
|
|
26
|
+
perPage: number;
|
|
27
|
+
total: number;
|
|
28
|
+
}
|
|
29
|
+
export interface AdminCreateUserParams {
|
|
30
|
+
email: string;
|
|
31
|
+
password?: string;
|
|
32
|
+
username?: string;
|
|
33
|
+
role?: 'ADMIN' | 'USER';
|
|
34
|
+
/** Mark the address verified without sending a confirmation. */
|
|
35
|
+
email_confirm?: boolean;
|
|
36
|
+
/** Also email the temporary password. `invite()` is the same thing, named. */
|
|
37
|
+
sendInvite?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface AdminCreatedUser {
|
|
40
|
+
user: User;
|
|
41
|
+
/** Generated when no password was supplied. Never logged by the SDK. */
|
|
42
|
+
temporaryPassword: string;
|
|
43
|
+
invited: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface AdminUpdateUserParams {
|
|
46
|
+
password?: string;
|
|
47
|
+
role?: 'ADMIN' | 'USER';
|
|
48
|
+
username?: string;
|
|
49
|
+
firstName?: string;
|
|
50
|
+
lastName?: string;
|
|
51
|
+
status?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface AdminGenerateLinkParams {
|
|
54
|
+
type: 'signup' | 'invite' | 'magiclink' | 'recovery' | 'email_change_current' | 'email_change_new';
|
|
55
|
+
email: string;
|
|
56
|
+
/** Required for `signup`. */
|
|
57
|
+
password?: string;
|
|
58
|
+
newEmail?: string;
|
|
59
|
+
options?: {
|
|
60
|
+
redirectTo?: string;
|
|
61
|
+
data?: Record<string, unknown>;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export interface AdminGeneratedLink {
|
|
65
|
+
properties: {
|
|
66
|
+
/** The link the email would carry. Null for `recovery`, which is code-based here. */
|
|
67
|
+
action_link: string | null;
|
|
68
|
+
email_otp: string | null;
|
|
69
|
+
hashed_token: string | null;
|
|
70
|
+
redirect_to: string | null;
|
|
71
|
+
verification_type: string;
|
|
72
|
+
};
|
|
73
|
+
user: User | null;
|
|
74
|
+
}
|
|
75
|
+
/** A supabase-js `Factor`: TOTP from two-factor, and each passkey as `webauthn`. */
|
|
76
|
+
export interface AdminMfaFactor {
|
|
77
|
+
id: string;
|
|
78
|
+
factor_type: 'totp' | 'webauthn';
|
|
79
|
+
status: 'verified' | 'unverified';
|
|
80
|
+
friendly_name: string;
|
|
81
|
+
created_at: string | null;
|
|
82
|
+
updated_at: string | null;
|
|
83
|
+
}
|
|
84
|
+
export declare const BASE: "/api/auth/admin";
|
|
85
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/admin/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,oBAAoB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,IAAI,CAAC;IACX,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,sBAAsB,GAAG,kBAAkB,CAAC;IACnG,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;CACrE;AAED,MAAM,WAAW,kBAAkB;IAC/B,UAAU,EAAE;QACR,qFAAqF;QACrF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,iBAAiB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CACrB;AAED,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC;IACjC,MAAM,EAAE,UAAU,GAAG,YAAY,CAAC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,eAAO,MAAM,IAAI,mBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/admin/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AA2FpD,MAAM,CAAC,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AuthChangeEvent, AuthEvent } from "./types.js";
|
|
2
|
+
export declare const EVENT_MAP: Record<AuthEvent, AuthChangeEvent>;
|
|
3
|
+
/**
|
|
4
|
+
* Endpoints whose next step needs a cookie set on the response: the OAuth
|
|
5
|
+
* state, the WebAuthn challenge, or the pending second factor a password
|
|
6
|
+
* sign-in leaves for `twoFactor.verify*`. Cross-origin, fetch only keeps and
|
|
7
|
+
* resends a cookie with `credentials: 'include'`. Everything else stays
|
|
8
|
+
* `same-origin`, so a backend that does not allow credentialed CORS still
|
|
9
|
+
* serves it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const COOKIE_PATHS: string[];
|
|
12
|
+
/** Sign-ins that come back through the server's OAuth callback, where the PKCE challenge rides. */
|
|
13
|
+
export declare const REDIRECT_SIGN_IN_PATHS: string[];
|
|
14
|
+
/** Calls after which the session this client holds no longer exists. */
|
|
15
|
+
export declare const SIGN_OUT_PATHS: Set<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Calls that change the user but answer without it (`{ status: true }`): the
|
|
18
|
+
* session is read again after them, so the stored user and USER_UPDATED follow.
|
|
19
|
+
*/
|
|
20
|
+
export declare const USER_CHANGE_PATHS: Set<string>;
|
|
21
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/auth/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,eAAe,CAMxD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,UAQxB,CAAC;AAEF,mGAAmG;AACnG,eAAO,MAAM,sBAAsB,UAAsC,CAAC;AAE1E,wEAAwE;AACxE,eAAO,MAAM,cAAc,aAA6C,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,aAAgG,CAAC"}
|