@flarelink/client 0.2.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.
@@ -0,0 +1,276 @@
1
+ type FlarelinkConfig = {
2
+ /**
3
+ * URL of the Flarelink auth Worker provisioned for your project. Looks like
4
+ * `https://myapp-auth.your-subdomain.workers.dev`. Find it in the Flarelink
5
+ * dashboard under your project's Authentication page.
6
+ */
7
+ url: string;
8
+ /**
9
+ * Per-project service key. Required to use `flarelink.storage.*` or
10
+ * `flarelink.from(...)`. NEVER include this in client-side bundles — it grants
11
+ * full DB + R2 access for the project. Read from server env (process.env,
12
+ * Cloudflare env binding, etc.).
13
+ *
14
+ * Mint a service key from the project's Flarelink dashboard.
15
+ */
16
+ serviceKey?: string;
17
+ /**
18
+ * Replace the global `fetch`. Useful for SSR runtimes that need to pass
19
+ * cookies through manually, or for tests. Defaults to the global `fetch`.
20
+ */
21
+ fetch?: typeof fetch;
22
+ };
23
+ type User = {
24
+ id: string;
25
+ email: string;
26
+ name: string;
27
+ emailVerified: boolean;
28
+ image: string | null;
29
+ createdAt: string;
30
+ updatedAt: string;
31
+ };
32
+ type Session = {
33
+ id: string;
34
+ userId: string;
35
+ expiresAt: string;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ ipAddress?: string | null;
39
+ userAgent?: string | null;
40
+ };
41
+ type SocialProvider = 'google' | 'github';
42
+ type SignUpInput = {
43
+ email: string;
44
+ password: string;
45
+ name: string;
46
+ /**
47
+ * URL the user lands on after clicking the verification email link
48
+ * (only relevant when email verification is enabled on this deployment).
49
+ * Defaults to the current page URL when called from a browser.
50
+ */
51
+ callbackURL?: string;
52
+ };
53
+ type SignInInput = {
54
+ email: string;
55
+ password: string;
56
+ };
57
+ type SignInWithSocialOptions = {
58
+ /** Where to send the user after the OAuth dance finishes. Default: current URL. */
59
+ callbackURL?: string;
60
+ /** If true, return the provider URL instead of navigating. Useful for SSR. */
61
+ noRedirect?: boolean;
62
+ };
63
+ type SignInWithMagicLinkOptions = {
64
+ /** URL the user lands on after the magic-link sign-in succeeds. Default: current URL. */
65
+ callbackURL?: string;
66
+ };
67
+ type RequestPasswordResetInput = {
68
+ email: string;
69
+ /**
70
+ * Page on your app the user lands on after clicking the link in the email.
71
+ * BetterAuth appends `?token=...` to it; your page reads the token and
72
+ * calls `resetPassword({ newPassword, token })`.
73
+ */
74
+ redirectTo: string;
75
+ };
76
+ type ResetPasswordInput = {
77
+ newPassword: string;
78
+ token: string;
79
+ };
80
+ type SendVerificationEmailInput = {
81
+ email: string;
82
+ /** URL the user lands on after the email is verified. Default: current URL. */
83
+ callbackURL?: string;
84
+ };
85
+
86
+ type Auth = {
87
+ signUp(input: SignUpInput): Promise<{
88
+ user: User;
89
+ }>;
90
+ signIn(input: SignInInput): Promise<{
91
+ user: User;
92
+ }>;
93
+ signInWithSocial(provider: SocialProvider, opts?: SignInWithSocialOptions): Promise<{
94
+ url: string;
95
+ }>;
96
+ signInWithMagicLink(email: string, opts?: SignInWithMagicLinkOptions): Promise<{
97
+ status: boolean;
98
+ }>;
99
+ signOut(): Promise<void>;
100
+ /**
101
+ * Triggers a password-reset email. Always resolves with `{ status: true }`
102
+ * even when the email is unknown — that's deliberate, BetterAuth doesn't
103
+ * leak account existence on this endpoint.
104
+ */
105
+ requestPasswordReset(input: RequestPasswordResetInput): Promise<{
106
+ status: boolean;
107
+ }>;
108
+ /**
109
+ * Completes the reset using the token from the email link. Your reset
110
+ * page reads `?token=` from the URL and passes it here alongside the
111
+ * new password.
112
+ */
113
+ resetPassword(input: ResetPasswordInput): Promise<{
114
+ status: boolean;
115
+ }>;
116
+ /**
117
+ * Sends a verification email to the address. The link in the email lands
118
+ * the user on `callbackURL` after the email is marked verified.
119
+ */
120
+ sendVerificationEmail(input: SendVerificationEmailInput): Promise<{
121
+ status: boolean;
122
+ }>;
123
+ /** Current user, or null when not signed in. */
124
+ getMe(): Promise<User | null>;
125
+ /** Active session, or null when not signed in. */
126
+ getSession(): Promise<Session | null>;
127
+ };
128
+
129
+ type Equality = string | number | boolean | null;
130
+
131
+ type QueryResult<T = Record<string, unknown>> = {
132
+ rows: T[];
133
+ meta: {
134
+ duration: number;
135
+ rows_read?: number;
136
+ rows_written?: number;
137
+ last_row_id?: number;
138
+ changes?: number;
139
+ };
140
+ };
141
+
142
+ type QueryBuilder<T = Record<string, unknown>> = PromiseLike<QueryResult<T>> & {
143
+ /** `*` is the default — call this only when you want to narrow. */
144
+ select(columns: '*' | (keyof T & string)[] | string[]): QueryBuilder<T>;
145
+ /** Equality filter, AND-chained. NULL becomes `IS NULL`. */
146
+ where(filter: Partial<Record<keyof T & string, Equality>>): QueryBuilder<T>;
147
+ orderBy(column: keyof T & string, direction?: 'asc' | 'desc'): QueryBuilder<T>;
148
+ limit(n: number): QueryBuilder<T>;
149
+ offset(n: number): QueryBuilder<T>;
150
+ };
151
+ type InsertBuilder<T = Record<string, unknown>> = PromiseLike<QueryResult<T>> & {
152
+ /** Return the inserted row(s). Without this, the promise resolves with `rows: []`. */
153
+ returning(columns?: '*' | (keyof T & string)[] | string[]): InsertBuilder<T>;
154
+ };
155
+ type UpdateBuilder<T = Record<string, unknown>> = PromiseLike<QueryResult<T>> & {
156
+ where(filter: Partial<Record<keyof T & string, Equality>>): UpdateBuilder<T>;
157
+ returning(columns?: '*' | (keyof T & string)[] | string[]): UpdateBuilder<T>;
158
+ };
159
+ type DeleteBuilder<T = Record<string, unknown>> = PromiseLike<QueryResult<T>> & {
160
+ where(filter: Partial<Record<keyof T & string, Equality>>): DeleteBuilder<T>;
161
+ };
162
+ type TableQuery<T = Record<string, unknown>> = QueryBuilder<T> & {
163
+ insert(row: Partial<T> | Partial<T>[]): InsertBuilder<T>;
164
+ update(patch: Partial<T>): UpdateBuilder<T>;
165
+ delete(): DeleteBuilder<T>;
166
+ };
167
+ type Database = {
168
+ from<T extends Record<string, unknown> = Record<string, unknown>>(table: string): TableQuery<T>;
169
+ /**
170
+ * Raw SQL escape hatch. Tagged-template syntax interpolates values as
171
+ * bind params — there's no way for an interpolated value to inject SQL:
172
+ * await flarelink.sql`SELECT * FROM users WHERE id = ${userId}`
173
+ */
174
+ sql<T extends Record<string, unknown> = Record<string, unknown>>(strings: TemplateStringsArray, ...values: unknown[]): Promise<QueryResult<T>>;
175
+ };
176
+
177
+ type StorageBucket = {
178
+ name: string;
179
+ createdAt: string;
180
+ };
181
+ type StorageObject = {
182
+ key: string;
183
+ size: number;
184
+ lastModified: string;
185
+ etag: string;
186
+ };
187
+ type StorageListResponse = {
188
+ objects: StorageObject[];
189
+ prefixes: string[];
190
+ nextCursor?: string;
191
+ };
192
+ type PresignOptions = {
193
+ /** Default 300s (5 min). Server clamps to [60s, 3600s]. */
194
+ expiresIn?: number;
195
+ contentType?: string;
196
+ };
197
+ type StorageBucketAPI = {
198
+ /**
199
+ * Mint a presigned PUT URL. Use it with a plain `fetch` (or XHR for
200
+ * progress) — bytes go direct to R2, the Worker never sees them.
201
+ *
202
+ * @returns `url` to PUT to, and `signedHeaders` you must send on the PUT
203
+ * request (currently `content-type` when supplied). Don't add extra
204
+ * headers — they'll break the signature.
205
+ */
206
+ createSignedUploadUrl(key: string, opts?: PresignOptions): Promise<{
207
+ url: string;
208
+ signedHeaders: Record<string, string>;
209
+ }>;
210
+ /**
211
+ * Mint a presigned GET URL. Open it in the browser, embed it as an
212
+ * `<img src>`, or fetch it server-side — same URL works anywhere until
213
+ * it expires.
214
+ */
215
+ createSignedDownloadUrl(key: string, opts?: PresignOptions): Promise<{
216
+ url: string;
217
+ }>;
218
+ /** Delete an object. */
219
+ remove(keys: string[]): Promise<void>;
220
+ /**
221
+ * List objects under an optional prefix. Returns up to 1000 per call;
222
+ * pass `cursor` from the previous response to page further.
223
+ */
224
+ list(opts?: {
225
+ prefix?: string;
226
+ cursor?: string;
227
+ }): Promise<StorageListResponse>;
228
+ };
229
+ type Storage = {
230
+ /** List buckets attached to the project's R2 account. */
231
+ listBuckets(): Promise<StorageBucket[]>;
232
+ /** Scope all operations to a single bucket. */
233
+ from(bucket: string): StorageBucketAPI;
234
+ };
235
+
236
+ declare class FlarelinkError extends Error {
237
+ readonly status: number;
238
+ readonly code: string | undefined;
239
+ constructor(message: string, status: number, code?: string);
240
+ }
241
+ declare class AuthError extends FlarelinkError {
242
+ constructor(message: string, status: number, code?: string);
243
+ }
244
+ declare class StorageError extends FlarelinkError {
245
+ constructor(message: string, status: number, code?: string);
246
+ }
247
+ declare class DatabaseError extends FlarelinkError {
248
+ constructor(message: string, status: number, code?: string);
249
+ }
250
+ /** Thrown when a server-only API is called without a service key. */
251
+ declare class MissingServiceKeyError extends FlarelinkError {
252
+ constructor(api: 'storage' | 'database');
253
+ }
254
+
255
+ type Flarelink = {
256
+ /** Auth surface — browser + server safe. */
257
+ readonly auth: Auth;
258
+ /** File storage (R2). Server-only — requires `serviceKey`. */
259
+ readonly storage: Storage;
260
+ /**
261
+ * Build a query against a D1 table.
262
+ * Server-only — requires `serviceKey`.
263
+ */
264
+ from<T extends Record<string, unknown> = Record<string, unknown>>(table: string): TableQuery<T>;
265
+ /**
266
+ * Raw SQL escape hatch. Tagged-template syntax interpolates values as
267
+ * bind params:
268
+ * await flarelink.sql`SELECT * FROM users WHERE id = ${userId}`
269
+ *
270
+ * Server-only — requires `serviceKey`.
271
+ */
272
+ sql<T extends Record<string, unknown> = Record<string, unknown>>(strings: TemplateStringsArray, ...values: unknown[]): Promise<QueryResult<T>>;
273
+ };
274
+ declare function createFlarelink(config: FlarelinkConfig): Flarelink;
275
+
276
+ export { type Auth, AuthError, type Database, DatabaseError, type DeleteBuilder, type Equality, type Flarelink, type FlarelinkConfig, FlarelinkError, type InsertBuilder, MissingServiceKeyError, type PresignOptions, type QueryBuilder, type QueryResult, type RequestPasswordResetInput, type ResetPasswordInput, type SendVerificationEmailInput, type Session, type SignInInput, type SignInWithMagicLinkOptions, type SignInWithSocialOptions, type SignUpInput, type SocialProvider, type Storage, type StorageBucket, type StorageBucketAPI, StorageError, type StorageListResponse, type StorageObject, type TableQuery, type UpdateBuilder, type User, createFlarelink };
@@ -0,0 +1,276 @@
1
+ type FlarelinkConfig = {
2
+ /**
3
+ * URL of the Flarelink auth Worker provisioned for your project. Looks like
4
+ * `https://myapp-auth.your-subdomain.workers.dev`. Find it in the Flarelink
5
+ * dashboard under your project's Authentication page.
6
+ */
7
+ url: string;
8
+ /**
9
+ * Per-project service key. Required to use `flarelink.storage.*` or
10
+ * `flarelink.from(...)`. NEVER include this in client-side bundles — it grants
11
+ * full DB + R2 access for the project. Read from server env (process.env,
12
+ * Cloudflare env binding, etc.).
13
+ *
14
+ * Mint a service key from the project's Flarelink dashboard.
15
+ */
16
+ serviceKey?: string;
17
+ /**
18
+ * Replace the global `fetch`. Useful for SSR runtimes that need to pass
19
+ * cookies through manually, or for tests. Defaults to the global `fetch`.
20
+ */
21
+ fetch?: typeof fetch;
22
+ };
23
+ type User = {
24
+ id: string;
25
+ email: string;
26
+ name: string;
27
+ emailVerified: boolean;
28
+ image: string | null;
29
+ createdAt: string;
30
+ updatedAt: string;
31
+ };
32
+ type Session = {
33
+ id: string;
34
+ userId: string;
35
+ expiresAt: string;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ ipAddress?: string | null;
39
+ userAgent?: string | null;
40
+ };
41
+ type SocialProvider = 'google' | 'github';
42
+ type SignUpInput = {
43
+ email: string;
44
+ password: string;
45
+ name: string;
46
+ /**
47
+ * URL the user lands on after clicking the verification email link
48
+ * (only relevant when email verification is enabled on this deployment).
49
+ * Defaults to the current page URL when called from a browser.
50
+ */
51
+ callbackURL?: string;
52
+ };
53
+ type SignInInput = {
54
+ email: string;
55
+ password: string;
56
+ };
57
+ type SignInWithSocialOptions = {
58
+ /** Where to send the user after the OAuth dance finishes. Default: current URL. */
59
+ callbackURL?: string;
60
+ /** If true, return the provider URL instead of navigating. Useful for SSR. */
61
+ noRedirect?: boolean;
62
+ };
63
+ type SignInWithMagicLinkOptions = {
64
+ /** URL the user lands on after the magic-link sign-in succeeds. Default: current URL. */
65
+ callbackURL?: string;
66
+ };
67
+ type RequestPasswordResetInput = {
68
+ email: string;
69
+ /**
70
+ * Page on your app the user lands on after clicking the link in the email.
71
+ * BetterAuth appends `?token=...` to it; your page reads the token and
72
+ * calls `resetPassword({ newPassword, token })`.
73
+ */
74
+ redirectTo: string;
75
+ };
76
+ type ResetPasswordInput = {
77
+ newPassword: string;
78
+ token: string;
79
+ };
80
+ type SendVerificationEmailInput = {
81
+ email: string;
82
+ /** URL the user lands on after the email is verified. Default: current URL. */
83
+ callbackURL?: string;
84
+ };
85
+
86
+ type Auth = {
87
+ signUp(input: SignUpInput): Promise<{
88
+ user: User;
89
+ }>;
90
+ signIn(input: SignInInput): Promise<{
91
+ user: User;
92
+ }>;
93
+ signInWithSocial(provider: SocialProvider, opts?: SignInWithSocialOptions): Promise<{
94
+ url: string;
95
+ }>;
96
+ signInWithMagicLink(email: string, opts?: SignInWithMagicLinkOptions): Promise<{
97
+ status: boolean;
98
+ }>;
99
+ signOut(): Promise<void>;
100
+ /**
101
+ * Triggers a password-reset email. Always resolves with `{ status: true }`
102
+ * even when the email is unknown — that's deliberate, BetterAuth doesn't
103
+ * leak account existence on this endpoint.
104
+ */
105
+ requestPasswordReset(input: RequestPasswordResetInput): Promise<{
106
+ status: boolean;
107
+ }>;
108
+ /**
109
+ * Completes the reset using the token from the email link. Your reset
110
+ * page reads `?token=` from the URL and passes it here alongside the
111
+ * new password.
112
+ */
113
+ resetPassword(input: ResetPasswordInput): Promise<{
114
+ status: boolean;
115
+ }>;
116
+ /**
117
+ * Sends a verification email to the address. The link in the email lands
118
+ * the user on `callbackURL` after the email is marked verified.
119
+ */
120
+ sendVerificationEmail(input: SendVerificationEmailInput): Promise<{
121
+ status: boolean;
122
+ }>;
123
+ /** Current user, or null when not signed in. */
124
+ getMe(): Promise<User | null>;
125
+ /** Active session, or null when not signed in. */
126
+ getSession(): Promise<Session | null>;
127
+ };
128
+
129
+ type Equality = string | number | boolean | null;
130
+
131
+ type QueryResult<T = Record<string, unknown>> = {
132
+ rows: T[];
133
+ meta: {
134
+ duration: number;
135
+ rows_read?: number;
136
+ rows_written?: number;
137
+ last_row_id?: number;
138
+ changes?: number;
139
+ };
140
+ };
141
+
142
+ type QueryBuilder<T = Record<string, unknown>> = PromiseLike<QueryResult<T>> & {
143
+ /** `*` is the default — call this only when you want to narrow. */
144
+ select(columns: '*' | (keyof T & string)[] | string[]): QueryBuilder<T>;
145
+ /** Equality filter, AND-chained. NULL becomes `IS NULL`. */
146
+ where(filter: Partial<Record<keyof T & string, Equality>>): QueryBuilder<T>;
147
+ orderBy(column: keyof T & string, direction?: 'asc' | 'desc'): QueryBuilder<T>;
148
+ limit(n: number): QueryBuilder<T>;
149
+ offset(n: number): QueryBuilder<T>;
150
+ };
151
+ type InsertBuilder<T = Record<string, unknown>> = PromiseLike<QueryResult<T>> & {
152
+ /** Return the inserted row(s). Without this, the promise resolves with `rows: []`. */
153
+ returning(columns?: '*' | (keyof T & string)[] | string[]): InsertBuilder<T>;
154
+ };
155
+ type UpdateBuilder<T = Record<string, unknown>> = PromiseLike<QueryResult<T>> & {
156
+ where(filter: Partial<Record<keyof T & string, Equality>>): UpdateBuilder<T>;
157
+ returning(columns?: '*' | (keyof T & string)[] | string[]): UpdateBuilder<T>;
158
+ };
159
+ type DeleteBuilder<T = Record<string, unknown>> = PromiseLike<QueryResult<T>> & {
160
+ where(filter: Partial<Record<keyof T & string, Equality>>): DeleteBuilder<T>;
161
+ };
162
+ type TableQuery<T = Record<string, unknown>> = QueryBuilder<T> & {
163
+ insert(row: Partial<T> | Partial<T>[]): InsertBuilder<T>;
164
+ update(patch: Partial<T>): UpdateBuilder<T>;
165
+ delete(): DeleteBuilder<T>;
166
+ };
167
+ type Database = {
168
+ from<T extends Record<string, unknown> = Record<string, unknown>>(table: string): TableQuery<T>;
169
+ /**
170
+ * Raw SQL escape hatch. Tagged-template syntax interpolates values as
171
+ * bind params — there's no way for an interpolated value to inject SQL:
172
+ * await flarelink.sql`SELECT * FROM users WHERE id = ${userId}`
173
+ */
174
+ sql<T extends Record<string, unknown> = Record<string, unknown>>(strings: TemplateStringsArray, ...values: unknown[]): Promise<QueryResult<T>>;
175
+ };
176
+
177
+ type StorageBucket = {
178
+ name: string;
179
+ createdAt: string;
180
+ };
181
+ type StorageObject = {
182
+ key: string;
183
+ size: number;
184
+ lastModified: string;
185
+ etag: string;
186
+ };
187
+ type StorageListResponse = {
188
+ objects: StorageObject[];
189
+ prefixes: string[];
190
+ nextCursor?: string;
191
+ };
192
+ type PresignOptions = {
193
+ /** Default 300s (5 min). Server clamps to [60s, 3600s]. */
194
+ expiresIn?: number;
195
+ contentType?: string;
196
+ };
197
+ type StorageBucketAPI = {
198
+ /**
199
+ * Mint a presigned PUT URL. Use it with a plain `fetch` (or XHR for
200
+ * progress) — bytes go direct to R2, the Worker never sees them.
201
+ *
202
+ * @returns `url` to PUT to, and `signedHeaders` you must send on the PUT
203
+ * request (currently `content-type` when supplied). Don't add extra
204
+ * headers — they'll break the signature.
205
+ */
206
+ createSignedUploadUrl(key: string, opts?: PresignOptions): Promise<{
207
+ url: string;
208
+ signedHeaders: Record<string, string>;
209
+ }>;
210
+ /**
211
+ * Mint a presigned GET URL. Open it in the browser, embed it as an
212
+ * `<img src>`, or fetch it server-side — same URL works anywhere until
213
+ * it expires.
214
+ */
215
+ createSignedDownloadUrl(key: string, opts?: PresignOptions): Promise<{
216
+ url: string;
217
+ }>;
218
+ /** Delete an object. */
219
+ remove(keys: string[]): Promise<void>;
220
+ /**
221
+ * List objects under an optional prefix. Returns up to 1000 per call;
222
+ * pass `cursor` from the previous response to page further.
223
+ */
224
+ list(opts?: {
225
+ prefix?: string;
226
+ cursor?: string;
227
+ }): Promise<StorageListResponse>;
228
+ };
229
+ type Storage = {
230
+ /** List buckets attached to the project's R2 account. */
231
+ listBuckets(): Promise<StorageBucket[]>;
232
+ /** Scope all operations to a single bucket. */
233
+ from(bucket: string): StorageBucketAPI;
234
+ };
235
+
236
+ declare class FlarelinkError extends Error {
237
+ readonly status: number;
238
+ readonly code: string | undefined;
239
+ constructor(message: string, status: number, code?: string);
240
+ }
241
+ declare class AuthError extends FlarelinkError {
242
+ constructor(message: string, status: number, code?: string);
243
+ }
244
+ declare class StorageError extends FlarelinkError {
245
+ constructor(message: string, status: number, code?: string);
246
+ }
247
+ declare class DatabaseError extends FlarelinkError {
248
+ constructor(message: string, status: number, code?: string);
249
+ }
250
+ /** Thrown when a server-only API is called without a service key. */
251
+ declare class MissingServiceKeyError extends FlarelinkError {
252
+ constructor(api: 'storage' | 'database');
253
+ }
254
+
255
+ type Flarelink = {
256
+ /** Auth surface — browser + server safe. */
257
+ readonly auth: Auth;
258
+ /** File storage (R2). Server-only — requires `serviceKey`. */
259
+ readonly storage: Storage;
260
+ /**
261
+ * Build a query against a D1 table.
262
+ * Server-only — requires `serviceKey`.
263
+ */
264
+ from<T extends Record<string, unknown> = Record<string, unknown>>(table: string): TableQuery<T>;
265
+ /**
266
+ * Raw SQL escape hatch. Tagged-template syntax interpolates values as
267
+ * bind params:
268
+ * await flarelink.sql`SELECT * FROM users WHERE id = ${userId}`
269
+ *
270
+ * Server-only — requires `serviceKey`.
271
+ */
272
+ sql<T extends Record<string, unknown> = Record<string, unknown>>(strings: TemplateStringsArray, ...values: unknown[]): Promise<QueryResult<T>>;
273
+ };
274
+ declare function createFlarelink(config: FlarelinkConfig): Flarelink;
275
+
276
+ export { type Auth, AuthError, type Database, DatabaseError, type DeleteBuilder, type Equality, type Flarelink, type FlarelinkConfig, FlarelinkError, type InsertBuilder, MissingServiceKeyError, type PresignOptions, type QueryBuilder, type QueryResult, type RequestPasswordResetInput, type ResetPasswordInput, type SendVerificationEmailInput, type Session, type SignInInput, type SignInWithMagicLinkOptions, type SignInWithSocialOptions, type SignUpInput, type SocialProvider, type Storage, type StorageBucket, type StorageBucketAPI, StorageError, type StorageListResponse, type StorageObject, type TableQuery, type UpdateBuilder, type User, createFlarelink };