naro-js 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # naro-js
2
2
 
3
- Auth and data for your [Naro](https://naro.sh) project, from the browser or
3
+ Auth, data and files for your [Naro](https://naro.sh) project, from the browser or
4
4
  the server. A project's backend brings its own database; this client signs
5
5
  users in and reads and writes it through the project's policies. No SQL, no
6
6
  database credentials, no dependencies.
@@ -71,12 +71,133 @@ await naro.from("posts").delete().eq("id", 10);
71
71
  `auth: { storage }` with your own `getItem` / `setItem` / `removeItem`.
72
72
  - Types: `createClient<Database>()` with the `Database` that
73
73
  `naro gen types` writes — see [Types](#types).
74
+ - Sign-in is naro Auth, the project's own (like Supabase Auth). Email and
75
+ password sign-up and sign-in need no setup: they work as soon as the
76
+ backend is on. Resend is needed only to send confirmation and password
77
+ reset emails.
78
+ - Admin accounts, closed sign-ups, sign-in by username and the password
79
+ length — see [Admin accounts and closed sign-ups](#admin-accounts-and-closed-sign-ups).
74
80
  - Email and social sign-in — see [Sign-in flows](#sign-in-flows).
81
+ - Files — see [Storage](#storage).
82
+
83
+ ## Policies
84
+
85
+ What a request may do is decided by the table's policies — Postgres's
86
+ row-level security, as in Supabase. A table without a policy refuses every
87
+ anon and signed-in request (only the service key gets through), so write a
88
+ table's policies in the migration that creates it: `create policy` after the
89
+ `create table`, in the same file. `naro db push` applies them with the table,
90
+ all or nothing.
91
+
92
+ ```sql
93
+ -- migrations/0002_todos.sql: each signed-in user reads and changes their own rows.
94
+ create table todos (
95
+ id integer primary key,
96
+ user_id uuid not null,
97
+ title text not null
98
+ );
99
+ create policy "own rows" on todos for all to authenticated
100
+ using ((select auth.uid()) = user_id)
101
+ with check ((select auth.uid()) = user_id);
102
+
103
+ -- migrations/0003_posts.sql: anyone reads, signed in or not.
104
+ create table posts (id integer primary key, title text not null);
105
+ create policy "read" on posts for select to anon, authenticated using (true);
106
+
107
+ -- migrations/0004_reports.sql: an app only its admins sign in to. First run
108
+ -- naro backend auth signups off and create the admin accounts: authenticated
109
+ -- then means exactly those accounts.
110
+ create table reports (id integer primary key, body text not null);
111
+ create policy "admins" on reports for all to authenticated using (true) with check (true);
112
+ ```
113
+
114
+ A request no policy lets through, and a written row that fails a check,
115
+ answer `403 PERMISSION_DENIED`; rows a policy's `using` does not pass are left
116
+ out without an error. The `naro-cli` README lists what a
117
+ migration accepts and refuses (`DISABLE ROW LEVEL SECURITY`, `GRANT`,
118
+ `REVOKE` and `ALTER POLICY` are refused), the warnings it answers with, and
119
+ `naro policy set`, a shorthand for the common rules.
120
+
121
+ ## Admin accounts and closed sign-ups
122
+
123
+ An app that only its admins sign in to: close sign-ups, then create the
124
+ accounts yourself. With sign-ups closed, `authenticated` in a policy means
125
+ exactly the users you created.
126
+
127
+ ```bash
128
+ naro backend auth signups off
129
+ echo "$ADMIN_PASSWORD" | naro backend users create --username admin --password-stdin
130
+ ```
131
+
132
+ ```ts
133
+ // In the app: sign in by username, or by email.
134
+ await naro.auth.signIn({ username: "admin", password });
135
+ await naro.auth.signIn({ email, password });
136
+ ```
137
+
138
+ The same from your own server, with supabase-js's `auth.admin` names:
139
+
140
+ ```ts
141
+ // Server only: the service key skips every policy.
142
+ const admin = createClient({
143
+ url: "https://my-app.naro.sh",
144
+ serviceKey: process.env.NARO_SERVICE_KEY,
145
+ });
146
+
147
+ const { data, error } = await admin.auth.admin.createUser({
148
+ username: "admin", // and/or email
149
+ password,
150
+ // emailConfirm: false — only with an email; users are confirmed otherwise
151
+ });
152
+ const {
153
+ data: { users, total },
154
+ } = await admin.auth.admin.listUsers({ page: 1, perPage: 50 });
155
+ await admin.auth.admin.deleteUser(data.user.id);
156
+ ```
157
+
158
+ - `createUser` takes an email, a username or both. The user is confirmed
159
+ and signs in at once — while sign-ups are closed, and while sign-in waits
160
+ for a confirmed email — unless `emailConfirm: false` (which needs an
161
+ email). A user with only a username answers `email: null`, here, in
162
+ `signIn` and in `getUser()`, and signs in with its username. Answers
163
+ carry `id`, `email`, `username`, `emailVerified` and `createdAt`, never a
164
+ password.
165
+ - `listUsers` is newest first, 50 a page unless `perPage` says (at most
166
+ 1000), with the `total`. `deleteUser(id)` removes the user and its
167
+ sign-in methods and ends its sessions; an unknown id is
168
+ `404 USER_NOT_FOUND` ("No user has this id.").
169
+ - `auth.admin` works only on a client made with `serviceKey`. On an anon
170
+ client each call answers `403 PERMISSION_DENIED` ("Only the service key
171
+ can manage users.") without a request.
172
+ - A username is 3–30 letters, digits, `_` and `.`, and is matched in any
173
+ case (stored lowercased). `signUp({ email, password, username })` sets one
174
+ at sign-up.
175
+ - Closed sign-ups: every `signUp` answers `403 SIGNUPS_DISABLED` ("Sign-ups
176
+ are closed for this project."), and so does a first Google or GitHub
177
+ sign-in, in `getSessionFromUrl()`. Users that exist keep signing in, with
178
+ a password or a provider. `naro backend auth signups on` opens them again.
179
+ - While sign-ups are open, a sign-up with a username someone has answers
180
+ `409 USERNAME_TAKEN` ("That username is already taken.") — so anyone can
181
+ learn which usernames exist, as fast as sign-up's per-address rate limit
182
+ lets them. With sign-ups closed, every sign-up answers
183
+ `403 SIGNUPS_DISABLED` first. `createUser` answers `USERNAME_TAKEN` too,
184
+ and `422 USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL` for an email in use.
185
+ - Passwords take at least 6 characters unless
186
+ `naro backend auth password --min-length <n>` (6–128) says more. A
187
+ shorter one, on sign-up, `createUser` or a reset, answers
188
+ `400 PASSWORD_TOO_SHORT` naming it: "Use at least 10 characters." Sign-in
189
+ never checks the length, so raising it locks nobody out.
190
+ - Creating and deleting users are writes: past the project's daily write
191
+ limit they answer `429 WRITE_QUOTA_EXCEEDED`, like sign-up.
192
+ - A backend turned on before these existed gets them with its next upload:
193
+ run `naro backend enable` once. Until then `auth.admin` and
194
+ `signIn({ username })` answer `404 NOT_FOUND`.
75
195
 
76
196
  ## Sign-in flows
77
197
 
78
198
  Google and GitHub sign-in, email confirmation and password reset, once the
79
- project has set them up (`naro backend auth`). The names follow supabase-js.
199
+ project has set them up (`naro backend auth`). Email and password sign-up
200
+ and sign-in need none of it. The names follow supabase-js.
80
201
 
81
202
  ```ts
82
203
  // Sends the browser to the project's /_naro/v1/auth/authorize/github, then
@@ -331,4 +452,67 @@ await naro.from("posts").select().contains("tags", ["a", "b"]);
331
452
  - Limits: groups nest 4 deep (`not` counts); one request holds at most 100
332
453
  conditions, 4 of them `contains` / `containedBy` / `overlaps`; one
333
454
  statement binds at most 100 values (a select's limit and offset are two of
334
- them) and compiles to at most 100,000 bytes of SQL.
455
+ them) and compiles to at most 100,000 bytes of SQL. A `like` or `ilike`
456
+ pattern is at most 50 bytes of UTF-8, which is D1's limit; in `like`, a
457
+ literal `?` or `[` counts as 3. A longer one is `400 INVALID_QUERY` before
458
+ the database is asked.
459
+
460
+ ## Storage
461
+
462
+ Files your users upload — avatars, attachments, documents — go in the
463
+ project's Storage: Cloudflare R2 behind the same URL, under policies on
464
+ `storage.objects` written as in Supabase. Turn it on with
465
+ `naro storage enable` (the backend must be on), make buckets with
466
+ `naro storage bucket create avatars --public`, and write the policies in a
467
+ migration that `naro db push` applies:
468
+
469
+ ```sql
470
+ create policy "avatars are readable" on storage.objects
471
+ for select to public using (bucket_id = 'avatars');
472
+ create policy "upload into own folder" on storage.objects
473
+ for insert to authenticated
474
+ with check (bucket_id = 'avatars' and (storage.foldername(name))[1] = auth.uid()::text);
475
+ ```
476
+
477
+ ```ts
478
+ const avatars = naro.storage.from("avatars");
479
+ await avatars.upload(`${user.id}/me.png`, file, { upsert: true });
480
+ const { data: image } = avatars.getPublicUrl(`${user.id}/me.png`); // no request
481
+ const { data: files } = await avatars.list(user.id, { limit: 20 });
482
+ await avatars.remove([`${user.id}/old.png`]);
483
+ const { data: link } = await naro.storage
484
+ .from("docs")
485
+ .createSignedUrl("team-1/plan.pdf", 600);
486
+ ```
487
+
488
+ - `upload`, `update`, `download`, `info`, `exists`, `list`, `remove`,
489
+ `createSignedUrl` and `getPublicUrl` take supabase-js's arguments and
490
+ answer its shapes (`FileObject` in snake_case), as `{ data, error }`.
491
+ One exception: supabase-js's `info` answers a camelCase object
492
+ (`bucketId`, `createdAt`, `size`, `contentType`, …); naro-js's `info`
493
+ answers the same snake_case `FileObject` as `list`, with the size and type
494
+ in `metadata.size` and `metadata.mimetype`.
495
+ - An upload sends the file's own bytes, 50 MiB at most, typed as the file
496
+ is (`Blob.type`, or `application/octet-stream`; a string is
497
+ `text/plain;charset=utf-8`). The body is a `Blob`, `File`, `ArrayBuffer`,
498
+ typed array or string — not a stream or `FormData`, and not a buffer
499
+ transferred away (detached), which has no bytes left: `INVALID_BODY`.
500
+ - A `contentType` or `cacheControl` no header can carry (a CR, LF or NUL
501
+ inside, or a character past U+00FF) is answered before a request, as the
502
+ backend answers one it cannot read: `INVALID_CONTENT_TYPE`, and
503
+ `INVALID_REQUEST` with `details.path` `cache-control`.
504
+ - supabase-js's `upload(path, file)` sends `multipart/form-data`, which Naro
505
+ refuses with `400 INVALID_REQUEST`. Without naro-js, send the file's bytes
506
+ as the body of `POST /_naro/v1/storage/object/<bucket>/<path>`.
507
+ - Refused before a request, with the backend's own words (`INVALID_PATH`):
508
+ an empty path, a `/` at either end, `//`, a `.` or `..` segment, a lone
509
+ surrogate (`is not valid UTF-8`: no URL can carry it), and a bucket named
510
+ `""`, `.`, `..`, with a lone surrogate or a word the storage routes use
511
+ (`The bucket name is not valid.`). Everything else is the backend's to
512
+ check.
513
+ - `exists` answers `false` for `OBJECT_NOT_FOUND` and passes every other
514
+ error on. `getPublicUrl` makes no request and answers `{ data, error }`.
515
+ - `OBJECT_RATE_LIMITED` and `STORAGE_OPS_QUOTA_EXCEEDED` carry
516
+ `details.retryAfter`, in seconds.
517
+ - Not yet: `move`, `copy`, `createSignedUrls`, `list`'s `search`, files over
518
+ 50 MiB, and bucket methods (buckets are made with `naro storage bucket`).
@@ -0,0 +1,23 @@
1
+ import { type HttpConfig } from "../http.js";
2
+ import type { AdminUserAttributes, AdminUserListResponse, AdminUserResponse, PageParams } from "../types.js";
3
+ export declare class AuthAdminApi {
4
+ #private;
5
+ constructor(http: HttpConfig, serviceKey: boolean);
6
+ /**
7
+ * Creates a user with a password: an email, a username or both. It is
8
+ * made while sign-ups are closed too, and is confirmed unless
9
+ * `emailConfirm: false`. A username-only user answers `email: null` and
10
+ * signs in with `signIn({ username, password })`. Refusals come as the
11
+ * worker says them: USERNAME_TAKEN (409),
12
+ * USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL (422), PASSWORD_TOO_SHORT ("Use at
13
+ * least {n} characters."), VALIDATION_ERROR, WRITE_QUOTA_EXCEEDED (429).
14
+ */
15
+ createUser(attributes: AdminUserAttributes): Promise<AdminUserResponse>;
16
+ /** The project's users, newest first: page 1 and 50 a page unless given. */
17
+ listUsers(params?: PageParams): Promise<AdminUserListResponse>;
18
+ /**
19
+ * Deletes a user and its sign-in methods, and ends its sessions. Answers
20
+ * the user it was; USER_NOT_FOUND (404) for an id that is no user.
21
+ */
22
+ deleteUser(id: string): Promise<AdminUserResponse>;
23
+ }
@@ -1,9 +1,10 @@
1
1
  import { type NaroError } from "../errors.js";
2
2
  import { type HttpConfig } from "../http.js";
3
3
  import type { AuthActionResponse, EmailRedirectOptions, OAuthResponse, SessionResponse, SignInCredentials, SignInWithOAuthOptions, SignOutResponse, SignUpCredentials, UrlSessionResponse, UserAttributes, UserResponse } from "../types.js";
4
+ import { AuthAdminApi } from "./admin.js";
4
5
  import type { FlowVerifiers } from "./flows.js";
5
6
  import type { RecoveryToken } from "./recovery.js";
6
- /** Better Auth requires `name` on sign-up; the email's local part stands in. */
7
+ /** Sign-up needs a `name`; the email's local part stands in. */
7
8
  export declare function defaultName(email: string): string;
8
9
  export type AuthFlowStores = {
9
10
  /** The PKCE verifiers of the provider sign-ins this browser began. */
@@ -24,24 +25,42 @@ export type AuthFlowStores = {
24
25
  storage: object;
25
26
  key: string;
26
27
  };
28
+ /** Made with the service key: `admin` sends its requests. */
29
+ serviceKey: boolean;
27
30
  };
28
31
  /** How long the code exchange a sign-in redirect starts may take. */
29
32
  export declare const EXCHANGE_TIMEOUT_MS = 15000;
30
33
  /**
31
- * `naro.auth` — email and password, email confirmation, password reset and
32
- * provider sign-in through the worker's Better Auth routes
33
- * (`/_naro/v1/auth/*`, spec §8.1, §13; P2-6 §13.3). Every method resolves;
34
- * none throws.
34
+ * `naro.auth` — naro Auth, the project's own sign-in (like Supabase Auth):
35
+ * email or username and password, email confirmation, password reset and
36
+ * provider sign-in through the worker's `/_naro/v1/auth/*` routes (spec
37
+ * §8.1, §13; P2-6 §13.3; 2026-09-26 §2.3). Email and password work with no
38
+ * setup; email is needed only to send confirmation and reset links. Every
39
+ * method resolves; none throws.
35
40
  */
36
41
  export declare class AuthClient {
37
42
  #private;
43
+ /**
44
+ * The service key's user management — createUser, listUsers, deleteUser,
45
+ * as in supabase-js (spec 2026-09-26 §2.2). Only on a client made with
46
+ * `serviceKey`, on a server.
47
+ */
48
+ readonly admin: AuthAdminApi;
38
49
  constructor(http: HttpConfig, flow: AuthFlowStores);
39
50
  /**
40
51
  * Creates the account and signs in; the token is stored for later calls.
41
52
  * When the project requires a confirmed email there is no session yet —
42
53
  * `user` comes back, and after the confirmation link the user signs in.
54
+ * While the project's sign-ups are closed every sign-up answers 403
55
+ * SIGNUPS_DISABLED; while they are open, a taken `username` answers 409
56
+ * USERNAME_TAKEN.
43
57
  */
44
58
  signUp(credentials: SignUpCredentials): Promise<UserResponse>;
59
+ /**
60
+ * Signs in with an email and password, or a username and password (spec
61
+ * 2026-09-26 §2.3); the token is stored for later calls. A wrong password
62
+ * answers 401 INVALID_EMAIL_OR_PASSWORD, or INVALID_USERNAME_OR_PASSWORD.
63
+ */
45
64
  signIn(credentials: SignInCredentials): Promise<UserResponse>;
46
65
  /**
47
66
  * Starts a Google or GitHub sign-in: sends the browser, with a top-level
@@ -1,5 +1,5 @@
1
1
  import type { TokenStore } from "./storage.js";
2
- /** A flow's life: the worker's flow row and Better Auth's state. */
2
+ /** A flow's life: the worker's flow row and its sign-in state. */
3
3
  export declare const FLOW_TTL_MS: number;
4
4
  /** More in flight than anyone clicks; the oldest go first. */
5
5
  export declare const MAX_FLOWS = 10;
package/dist/client.d.ts CHANGED
@@ -2,6 +2,7 @@ import { AuthClient } from "./auth/client.js";
2
2
  import { type AuthStorage } from "./auth/storage.js";
3
3
  import { type FetchLike } from "./http.js";
4
4
  import { TableBuilder } from "./query/builder.js";
5
+ import { StorageClient } from "./storage/client.js";
5
6
  import type { DatabaseShape, InsertOf, RowOf, TableName, TablesOf, UntypedDatabase, UpdateOf } from "./types.js";
6
7
  type CommonOptions = {
7
8
  /**
@@ -46,8 +47,17 @@ export declare const CONFIG_MESSAGES: {
46
47
  };
47
48
  export declare class NaroClient<Database extends DatabaseShape<Database>> {
48
49
  #private;
49
- /** Sign-up, sign-in, sign-out and the current user (spec §13). */
50
+ /**
51
+ * Sign-up, sign-in, sign-out and the current user (spec §13); with the
52
+ * service key, `auth.admin` manages users.
53
+ */
50
54
  readonly auth: AuthClient;
55
+ /**
56
+ * Files in the project's Naro Storage (first-release design 2026-10-06
57
+ * §8.1): `storage.from(bucket)` uploads, downloads, lists and removes
58
+ * them, as supabase-js does.
59
+ */
60
+ readonly storage: StorageClient;
51
61
  constructor(options: ClientOptions);
52
62
  /** Start a query on `table`: `.select()`, `.insert()`, `.update()` or `.delete()`. */
53
63
  from<Table extends TableName<Database>>(table: Table): TableBuilder<RowOf<TablesOf<Database>[Table]>, InsertOf<TablesOf<Database>[Table]>, UpdateOf<TablesOf<Database>[Table]>>;
package/dist/errors.d.ts CHANGED
@@ -1,12 +1,16 @@
1
+ import type { AuthErrorCode } from "./types.js";
1
2
  /**
2
3
  * Every failure the SDK hands back (spec §15). The Naro worker's errors
3
4
  * (spec §14) arrive as they are; the SDK makes its own only for what never
4
5
  * got a readable answer from the worker, and for queries it can tell are
5
6
  * malformed before sending them. The messages are a contract — spec §15's
6
7
  * "(P1-4 구현 결정)" block quotes them.
8
+ *
9
+ * `code` can be any string. The sign-in and user codes an app branches on
10
+ * (`AuthErrorCode`) are spelled out, so an editor completes them.
7
11
  */
8
12
  export type NaroError = {
9
- code: string;
13
+ code: AuthErrorCode | (string & {});
10
14
  message: string;
11
15
  details?: unknown;
12
16
  };
@@ -37,15 +41,21 @@ export declare function codeVerifierMissing(): NaroError;
37
41
  export declare function passwordRecoveryRequired(): NaroError;
38
42
  /** `signInWithOAuth` with a provider the worker does not know. */
39
43
  export declare function invalidProvider(): NaroError;
44
+ /**
45
+ * `naro.auth.admin` on a client made with the anon key (spec 2026-09-26
46
+ * admin users §2.2): the worker's own refusal, word for word, without the
47
+ * request — the answer would be the same.
48
+ */
49
+ export declare function serviceKeyRequired(): NaroError;
40
50
  /** No `crypto.subtle`: an http page that is not localhost. */
41
51
  export declare function cryptoUnavailable(): NaroError;
42
52
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
43
53
  /**
44
54
  * The error a response carries, or null when it carries none. Every error
45
55
  * under `/_naro/v1` comes as `{ data: null, error: { code, message,
46
- * details? } }` — the worker wraps Better Auth's too (spec §14, P1-2 리뷰
47
- * 반영). Better Auth's success bodies are not wrapped, so a 2xx without an
48
- * `error` is not an error; a failing status without the envelope is not a
49
- * Naro answer at all (a proxy's HTML page, the app's own 404).
56
+ * details? } }` — the sign-in routes' too (spec §14, P1-2 리뷰 반영). Their
57
+ * success bodies are not wrapped, so a 2xx without an `error` is not an
58
+ * error; a failing status without the envelope is not a Naro answer at all
59
+ * (a proxy's HTML page, the app's own 404).
50
60
  */
51
61
  export declare function errorFromBody(status: number, body: unknown): NaroError | null;
package/dist/http.d.ts CHANGED
@@ -15,7 +15,7 @@ export type HttpConfig = {
15
15
  tokens: TokenStore;
16
16
  };
17
17
  export type CallOptions = {
18
- method: "GET" | "POST";
18
+ method: "GET" | "POST" | "DELETE";
19
19
  /** Below `/_naro/v1`, e.g. `/data/query`. */
20
20
  path: string;
21
21
  /** Sent as JSON. */
@@ -53,9 +53,32 @@ export type CallResult = {
53
53
  * §11.1), but only if it is still the token this request carried.
54
54
  */
55
55
  export declare function call(config: HttpConfig, options: CallOptions): Promise<CallResult>;
56
+ export type SendOptions = {
57
+ method: "GET" | "POST" | "PUT";
58
+ /** Below `/_naro/v1`, e.g. `/storage/object/avatars/me.png`. */
59
+ path: string;
60
+ headers?: Record<string, string>;
61
+ body?: BodyInit;
62
+ withToken: boolean;
63
+ };
64
+ export type SendResult = {
65
+ error: NaroError;
66
+ } | {
67
+ error: null;
68
+ response: Response;
69
+ };
70
+ /**
71
+ * A request whose body or answer is not JSON (Storage, first-release design
72
+ * 2026-10-06 §8.1): an upload's bytes go as they are, a download's come
73
+ * back unread. The same `apikey`, bearer token and no cookies as `call`;
74
+ * a failing answer is read the way `call` reads one — the worker's error
75
+ * envelope, or INVALID_RESPONSE — and every case resolves.
76
+ */
77
+ export declare function send(config: HttpConfig, options: SendOptions): Promise<SendResult>;
56
78
  /**
57
- * The worker's two 429s. `RATE_LIMITED` is Better Auth's limiter;
58
- * `WRITE_QUOTA_EXCEEDED` (PR C) is the project over its daily database write
59
- * limit — Data API writes and sign-up wait for 00:00 UTC, reads still work.
79
+ * The worker's 429s that say how long to wait. `RATE_LIMITED` is the
80
+ * sign-in routes' per-address limiter; `WRITE_QUOTA_EXCEEDED` (PR C) is the
81
+ * project over its daily database write limit — Data API writes, sign-up
82
+ * and creating or deleting users wait for 00:00 UTC, reads still work.
60
83
  */
61
84
  export declare const RETRY_AFTER_CODES: ReadonlySet<string>;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  export { createClient, NaroClient, type ClientOptions } from "./client.js";
2
+ export type { AuthAdminApi } from "./auth/admin.js";
2
3
  export type { AuthClient } from "./auth/client.js";
3
4
  export type { AuthStorage } from "./auth/storage.js";
4
5
  export type { NaroError } from "./errors.js";
5
6
  export type { FetchLike } from "./http.js";
7
+ export type { StorageClient, StorageFileApi } from "./storage/client.js";
8
+ export type { DownloadOption, FileObject, FolderEntry, ListOptions, UpdateOptions, UploadBody, UploadOptions, UploadResult, } from "./storage/types.js";
6
9
  export type { ArrayValues, FilterGroup, FilterGroupCallback, InsertBuilder, MatchQuery, MutationBuilder, RawFilterValue, SelectBuilder, TableBuilder, } from "./query/builder.js";
7
10
  export { quoteFilterValue, type FilterOperatorName } from "./query/filters.js";
8
- export type { AuthActionResponse, AuthFlowType, AuthResponse, DatabaseShape, EmailRedirectOptions, OAuthProvider, OAuthResponse, SignInWithOAuthOptions, UrlSessionResponse, UserAttributes, GenericTable, GenericView, NaroResponse, OrderOptions, Session, SessionResponse, SignInCredentials, SignOutResponse, SignUpCredentials, UntypedDatabase, User, UserResponse, } from "./types.js";
11
+ export type { AdminUser, AdminUserAttributes, AdminUserListResponse, AdminUserResponse, AuthActionResponse, AuthErrorCode, AuthFlowType, AuthResponse, DatabaseShape, EmailRedirectOptions, OAuthProvider, OAuthResponse, SignInWithOAuthOptions, UrlSessionResponse, UserAttributes, GenericTable, GenericView, NaroResponse, OrderOptions, PageParams, Session, SessionResponse, SignInCredentials, SignOutResponse, SignUpCredentials, UntypedDatabase, User, UserResponse, } from "./types.js";
9
12
  export type { Filter, FilterNode, FilterOperator, Order, Query, Row, Value, } from "./wire.js";