postbasejs 0.1.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,948 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/ssr/index.ts
21
+ var ssr_exports = {};
22
+ __export(ssr_exports, {
23
+ createBrowserClient: () => createBrowserClient,
24
+ createClient: () => createClient,
25
+ createServerClient: () => createServerClient
26
+ });
27
+ module.exports = __toCommonJS(ssr_exports);
28
+
29
+ // src/client.ts
30
+ var SESSION_STORAGE_KEY = "postbase_session";
31
+ function getStorageKey(options) {
32
+ return options?.auth?.storageKey ?? SESSION_STORAGE_KEY;
33
+ }
34
+ function isBrowser() {
35
+ return typeof window !== "undefined" && typeof document !== "undefined";
36
+ }
37
+ async function executeQuery(state) {
38
+ try {
39
+ const headers = {
40
+ "Content-Type": "application/json",
41
+ Authorization: `Bearer ${state.apiKey}`,
42
+ ...state.customHeaders
43
+ };
44
+ if (state.cookieAdapter) {
45
+ const cookies = await state.cookieAdapter.getAll();
46
+ const sessionCookie = cookies.find((c) => c.name.startsWith("postbase-session") || c.name === "next-auth.session-token" || c.name === "__Secure-next-auth.session-token");
47
+ if (sessionCookie) {
48
+ headers["X-Postbase-Session"] = sessionCookie.value;
49
+ }
50
+ }
51
+ const body = {
52
+ operation: state.operation === "upsert" ? "upsert" : state.operation,
53
+ table: state.table
54
+ };
55
+ if (state.operation === "select") {
56
+ if (state.columns && state.columns !== "*") {
57
+ body.columns = state.columns.split(",").map((c) => c.trim());
58
+ }
59
+ body.count = state.selectOptions.count;
60
+ body.head = state.selectOptions.head;
61
+ }
62
+ if (["select", "update", "delete"].includes(state.operation)) {
63
+ const filters = [...state.filters];
64
+ if (filters.length) body.filters = filters;
65
+ if (state.orFilters.length) body.orFilters = state.orFilters;
66
+ if (state.notFilters.length) body.notFilters = state.notFilters;
67
+ }
68
+ if (state.operation === "insert" || state.operation === "upsert") {
69
+ body.data = state.insertData;
70
+ if (state.upsertOnConflict) body.onConflict = state.upsertOnConflict;
71
+ }
72
+ if (state.operation === "update") {
73
+ body.data = state.updateData;
74
+ }
75
+ if (state.orderBy.length) body.order = state.orderBy;
76
+ if (state._limit !== void 0) body.limit = state._limit;
77
+ if (state._offset !== void 0) body.offset = state._offset;
78
+ if (state._range) body.range = state._range;
79
+ if (state.returning) body.returning = state.returning;
80
+ const res = await fetch(`${state.baseUrl}/api/db/query`, {
81
+ method: "POST",
82
+ headers,
83
+ body: JSON.stringify(body)
84
+ });
85
+ const json = await res.json();
86
+ if (!res.ok) return { data: null, count: null, error: json.error ?? "Query failed" };
87
+ return { data: json.data, count: json.count ?? null, error: null };
88
+ } catch (err) {
89
+ return { data: null, count: null, error: String(err) };
90
+ }
91
+ }
92
+ var QueryBuilderImpl = class _QueryBuilderImpl {
93
+ constructor(state) {
94
+ this.state = state;
95
+ }
96
+ clone(patch) {
97
+ return new _QueryBuilderImpl({ ...this.state, ...patch });
98
+ }
99
+ select(columns = "*", options = {}) {
100
+ return this.clone({ columns, selectOptions: options, operation: "select" });
101
+ }
102
+ addFilter(column, operator, value) {
103
+ return this.clone({ filters: [...this.state.filters, { column, operator, value }] });
104
+ }
105
+ eq(column, value) {
106
+ return this.addFilter(column, "eq", value);
107
+ }
108
+ neq(column, value) {
109
+ return this.addFilter(column, "neq", value);
110
+ }
111
+ gt(column, value) {
112
+ return this.addFilter(column, "gt", value);
113
+ }
114
+ gte(column, value) {
115
+ return this.addFilter(column, "gte", value);
116
+ }
117
+ lt(column, value) {
118
+ return this.addFilter(column, "lt", value);
119
+ }
120
+ lte(column, value) {
121
+ return this.addFilter(column, "lte", value);
122
+ }
123
+ like(column, pattern) {
124
+ return this.addFilter(column, "like", pattern);
125
+ }
126
+ ilike(column, pattern) {
127
+ return this.addFilter(column, "ilike", pattern);
128
+ }
129
+ in(column, values) {
130
+ return this.addFilter(column, "in", values);
131
+ }
132
+ is(column, value) {
133
+ return this.addFilter(column, "is", value);
134
+ }
135
+ contains(column, value) {
136
+ return this.addFilter(column, "contains", value);
137
+ }
138
+ overlaps(column, value) {
139
+ return this.addFilter(column, "overlaps", value);
140
+ }
141
+ textSearch(column, query, options) {
142
+ return this.addFilter(column, "textSearch", { query, config: options?.config });
143
+ }
144
+ or(filters) {
145
+ return this.clone({ orFilters: [...this.state.orFilters, filters] });
146
+ }
147
+ not(column, operator, value) {
148
+ return this.clone({ notFilters: [...this.state.notFilters, { column, operator, value }] });
149
+ }
150
+ order(column, options) {
151
+ return this.clone({
152
+ orderBy: [...this.state.orderBy, { column, ascending: options?.ascending, nullsFirst: options?.nullsFirst }]
153
+ });
154
+ }
155
+ limit(count) {
156
+ return this.clone({ _limit: count });
157
+ }
158
+ offset(count) {
159
+ return this.clone({ _offset: count });
160
+ }
161
+ range(from, to) {
162
+ return this.clone({ _range: { from, to }, _limit: to - from + 1, _offset: from });
163
+ }
164
+ insert(data, options) {
165
+ return new InsertBuilderImpl({
166
+ ...this.state,
167
+ operation: "insert",
168
+ insertData: data,
169
+ returning: options?.returning ?? "*"
170
+ });
171
+ }
172
+ upsert(data, options) {
173
+ return new InsertBuilderImpl({
174
+ ...this.state,
175
+ operation: "upsert",
176
+ insertData: data,
177
+ upsertOnConflict: options?.onConflict,
178
+ returning: options?.returning ?? "*"
179
+ });
180
+ }
181
+ update(data) {
182
+ return new UpdateBuilderImpl({
183
+ ...this.state,
184
+ operation: "update",
185
+ updateData: data,
186
+ returning: "*"
187
+ });
188
+ }
189
+ delete() {
190
+ return new DeleteBuilderImpl({
191
+ ...this.state,
192
+ operation: "delete",
193
+ returning: "*"
194
+ });
195
+ }
196
+ async single() {
197
+ const result = await executeQuery(this.clone({ _limit: 1 }).state);
198
+ if (result.error) return { data: null, error: result.error };
199
+ const rows = result.data ?? [];
200
+ if (rows.length === 0) return { data: null, error: "No rows returned" };
201
+ if (rows.length > 1) return { data: null, error: "Multiple rows returned" };
202
+ return { data: rows[0], error: null };
203
+ }
204
+ async maybeSingle() {
205
+ const result = await executeQuery(this.clone({ _limit: 1 }).state);
206
+ if (result.error) return { data: null, error: result.error };
207
+ const rows = result.data ?? [];
208
+ return { data: rows[0] ?? null, error: null };
209
+ }
210
+ // Thenable — make the builder awaitable directly
211
+ get then() {
212
+ const promise = executeQuery(this.state);
213
+ return promise.then.bind(promise);
214
+ }
215
+ };
216
+ var InsertBuilderImpl = class _InsertBuilderImpl {
217
+ constructor(state) {
218
+ this.state = state;
219
+ }
220
+ select(columns = "*") {
221
+ return new _InsertBuilderImpl({ ...this.state, returning: columns });
222
+ }
223
+ async single() {
224
+ const result = await executeQuery(this.state);
225
+ if (result.error) return { data: null, error: result.error };
226
+ const rows = result.data ?? [];
227
+ return { data: rows[0] ?? null, error: null };
228
+ }
229
+ get then() {
230
+ const promise = executeQuery(this.state);
231
+ return promise.then.bind(promise);
232
+ }
233
+ };
234
+ var UpdateBuilderImpl = class _UpdateBuilderImpl {
235
+ constructor(state) {
236
+ this.state = state;
237
+ }
238
+ addFilter(column, operator, value) {
239
+ return new _UpdateBuilderImpl({ ...this.state, filters: [...this.state.filters, { column, operator, value }] });
240
+ }
241
+ eq(column, value) {
242
+ return this.addFilter(column, "eq", value);
243
+ }
244
+ neq(column, value) {
245
+ return this.addFilter(column, "neq", value);
246
+ }
247
+ gt(column, value) {
248
+ return this.addFilter(column, "gt", value);
249
+ }
250
+ gte(column, value) {
251
+ return this.addFilter(column, "gte", value);
252
+ }
253
+ lt(column, value) {
254
+ return this.addFilter(column, "lt", value);
255
+ }
256
+ lte(column, value) {
257
+ return this.addFilter(column, "lte", value);
258
+ }
259
+ in(column, values) {
260
+ return this.addFilter(column, "in", values);
261
+ }
262
+ select(columns = "*") {
263
+ return new _UpdateBuilderImpl({ ...this.state, returning: columns });
264
+ }
265
+ async single() {
266
+ const result = await executeQuery(this.state);
267
+ if (result.error) return { data: null, error: result.error };
268
+ const rows = result.data ?? [];
269
+ return { data: rows[0] ?? null, error: null };
270
+ }
271
+ get then() {
272
+ const promise = executeQuery(this.state);
273
+ return promise.then.bind(promise);
274
+ }
275
+ };
276
+ var DeleteBuilderImpl = class _DeleteBuilderImpl {
277
+ constructor(state) {
278
+ this.state = state;
279
+ }
280
+ addFilter(column, operator, value) {
281
+ return new _DeleteBuilderImpl({ ...this.state, filters: [...this.state.filters, { column, operator, value }] });
282
+ }
283
+ eq(column, value) {
284
+ return this.addFilter(column, "eq", value);
285
+ }
286
+ neq(column, value) {
287
+ return this.addFilter(column, "neq", value);
288
+ }
289
+ gt(column, value) {
290
+ return this.addFilter(column, "gt", value);
291
+ }
292
+ gte(column, value) {
293
+ return this.addFilter(column, "gte", value);
294
+ }
295
+ lt(column, value) {
296
+ return this.addFilter(column, "lt", value);
297
+ }
298
+ lte(column, value) {
299
+ return this.addFilter(column, "lte", value);
300
+ }
301
+ in(column, values) {
302
+ return this.addFilter(column, "in", values);
303
+ }
304
+ select(columns = "*") {
305
+ return new _DeleteBuilderImpl({ ...this.state, returning: columns });
306
+ }
307
+ async single() {
308
+ const result = await executeQuery(this.state);
309
+ if (result.error) return { data: null, error: result.error };
310
+ const rows = result.data ?? [];
311
+ return { data: rows[0] ?? null, error: null };
312
+ }
313
+ get then() {
314
+ const promise = executeQuery(this.state);
315
+ return promise.then.bind(promise);
316
+ }
317
+ };
318
+ function createAuthAdmin(baseUrl, apiKey, customHeaders) {
319
+ const headers = () => ({
320
+ "Content-Type": "application/json",
321
+ Authorization: `Bearer ${apiKey}`,
322
+ ...customHeaders
323
+ });
324
+ return {
325
+ async listUsers(options) {
326
+ try {
327
+ const url = new URL(`${baseUrl}/api/auth/v1/admin/users`);
328
+ if (options?.page) url.searchParams.set("page", String(options.page));
329
+ if (options?.perPage) url.searchParams.set("perPage", String(options.perPage));
330
+ const res = await fetch(url.toString(), { headers: headers() });
331
+ const json = await res.json();
332
+ if (!res.ok) return { data: null, error: json.error ?? "Failed to list users" };
333
+ return { data: { users: json.users, total: json.total }, error: null };
334
+ } catch (err) {
335
+ return { data: null, error: String(err) };
336
+ }
337
+ },
338
+ async getUserById(id) {
339
+ try {
340
+ const res = await fetch(`${baseUrl}/api/auth/v1/admin/users/${id}`, { headers: headers() });
341
+ const json = await res.json();
342
+ if (!res.ok) return { data: { user: null }, error: json.error ?? "User not found" };
343
+ return { data: { user: json.user }, error: null };
344
+ } catch (err) {
345
+ return { data: { user: null }, error: String(err) };
346
+ }
347
+ },
348
+ async createUser(options) {
349
+ try {
350
+ const res = await fetch(`${baseUrl}/api/auth/v1/admin/users`, {
351
+ method: "POST",
352
+ headers: headers(),
353
+ body: JSON.stringify(options)
354
+ });
355
+ const json = await res.json();
356
+ if (!res.ok) return { data: { user: null }, error: json.error ?? "Failed to create user" };
357
+ return { data: { user: json.user }, error: null };
358
+ } catch (err) {
359
+ return { data: { user: null }, error: String(err) };
360
+ }
361
+ },
362
+ async updateUserById(id, attributes) {
363
+ try {
364
+ const res = await fetch(`${baseUrl}/api/auth/v1/admin/users/${id}`, {
365
+ method: "PATCH",
366
+ headers: headers(),
367
+ body: JSON.stringify(attributes)
368
+ });
369
+ const json = await res.json();
370
+ if (!res.ok) return { data: { user: null }, error: json.error ?? "Failed to update user" };
371
+ return { data: { user: json.user }, error: null };
372
+ } catch (err) {
373
+ return { data: { user: null }, error: String(err) };
374
+ }
375
+ },
376
+ async deleteUser(id) {
377
+ try {
378
+ const res = await fetch(`${baseUrl}/api/auth/v1/admin/users/${id}`, {
379
+ method: "DELETE",
380
+ headers: headers()
381
+ });
382
+ const json = await res.json();
383
+ if (!res.ok) return { data: null, error: json.error ?? "Failed to delete user" };
384
+ return { data: null, error: null };
385
+ } catch (err) {
386
+ return { data: null, error: String(err) };
387
+ }
388
+ }
389
+ };
390
+ }
391
+ function createAuthClient(baseUrl, apiKey, options, cookieAdapter) {
392
+ const storageKey = getStorageKey(options);
393
+ const listeners = [];
394
+ let refreshTimer = null;
395
+ let currentSession = null;
396
+ const customHeaders = options?.global?.headers;
397
+ const headers = () => ({
398
+ "Content-Type": "application/json",
399
+ Authorization: `Bearer ${apiKey}`,
400
+ ...customHeaders
401
+ });
402
+ function persistSession(session) {
403
+ if (!isBrowser()) return;
404
+ if (options?.auth?.persistSession === false) return;
405
+ if (session) {
406
+ localStorage.setItem(storageKey, JSON.stringify(session));
407
+ } else {
408
+ localStorage.removeItem(storageKey);
409
+ }
410
+ }
411
+ function loadPersistedSession() {
412
+ if (!isBrowser()) return null;
413
+ if (options?.auth?.persistSession === false) return null;
414
+ try {
415
+ const raw = localStorage.getItem(storageKey);
416
+ if (!raw) return null;
417
+ const session = JSON.parse(raw);
418
+ if (session.expiresAt && Date.now() / 1e3 > session.expiresAt) return null;
419
+ return session;
420
+ } catch {
421
+ return null;
422
+ }
423
+ }
424
+ function scheduleRefresh(session) {
425
+ if (!isBrowser()) return;
426
+ if (options?.auth?.autoRefreshToken === false) return;
427
+ if (refreshTimer) clearTimeout(refreshTimer);
428
+ const expiresIn = session.expiresAt - Date.now() / 1e3;
429
+ const refreshIn = Math.max((expiresIn - 60) * 1e3, 0);
430
+ refreshTimer = setTimeout(async () => {
431
+ if (session.refreshToken) {
432
+ const result = await authClient.refreshSession(session.refreshToken);
433
+ if (!result.error && result.data.session) {
434
+ notifyListeners("TOKEN_REFRESHED", result.data.session);
435
+ }
436
+ }
437
+ }, refreshIn);
438
+ }
439
+ function notifyListeners(event, session) {
440
+ currentSession = session;
441
+ persistSession(session);
442
+ if (session) scheduleRefresh(session);
443
+ listeners.forEach((fn) => fn(event, session));
444
+ }
445
+ const authClient = {
446
+ async signUp({ email, password, options: signUpOptions }) {
447
+ try {
448
+ const res = await fetch(`${baseUrl}/api/auth/v1/signup`, {
449
+ method: "POST",
450
+ headers: headers(),
451
+ body: JSON.stringify({ email, password, data: signUpOptions?.data })
452
+ });
453
+ const json = await res.json();
454
+ if (!res.ok) return { data: { user: null, session: null }, error: json.error ?? "Sign up failed" };
455
+ const session = json.session ?? null;
456
+ const user = json.user ?? null;
457
+ if (session) notifyListeners("SIGNED_IN", session);
458
+ return { data: { user, session }, error: null };
459
+ } catch (err) {
460
+ return { data: { user: null, session: null }, error: String(err) };
461
+ }
462
+ },
463
+ async signInWithPassword({ email, password }) {
464
+ try {
465
+ const res = await fetch(`${baseUrl}/api/auth/v1/token`, {
466
+ method: "POST",
467
+ headers: headers(),
468
+ body: JSON.stringify({ email, password, grant_type: "password" })
469
+ });
470
+ const json = await res.json();
471
+ if (!res.ok) return { data: { user: null, session: null }, error: json.error ?? "Sign in failed" };
472
+ const session = json.session;
473
+ const user = json.user;
474
+ notifyListeners("SIGNED_IN", session);
475
+ return { data: { user, session }, error: null };
476
+ } catch (err) {
477
+ return { data: { user: null, session: null }, error: String(err) };
478
+ }
479
+ },
480
+ async signInWithOtp({ email, options: otpOptions }) {
481
+ try {
482
+ const res = await fetch(`${baseUrl}/api/auth/v1/otp`, {
483
+ method: "POST",
484
+ headers: headers(),
485
+ body: JSON.stringify({ email, redirectTo: otpOptions?.redirectTo })
486
+ });
487
+ const json = await res.json();
488
+ if (!res.ok) return { data: null, error: json.error ?? "OTP send failed" };
489
+ return { data: null, error: null };
490
+ } catch (err) {
491
+ return { data: null, error: String(err) };
492
+ }
493
+ },
494
+ async signInWithOAuth({ provider, options: oauthOptions }) {
495
+ if (!isBrowser()) return;
496
+ const redirectTo = oauthOptions?.redirectTo ?? window.location.href;
497
+ const url = new URL(`${baseUrl}/api/auth/${provider}`);
498
+ url.searchParams.set("redirectTo", redirectTo);
499
+ if (oauthOptions?.scopes) url.searchParams.set("scopes", oauthOptions.scopes);
500
+ window.location.href = url.toString();
501
+ },
502
+ async signOut() {
503
+ try {
504
+ const session = currentSession ?? loadPersistedSession();
505
+ await fetch(`${baseUrl}/api/auth/v1/logout`, {
506
+ method: "POST",
507
+ headers: {
508
+ ...headers(),
509
+ ...session ? { "X-Postbase-Token": session.accessToken } : {}
510
+ }
511
+ });
512
+ if (refreshTimer) clearTimeout(refreshTimer);
513
+ notifyListeners("SIGNED_OUT", null);
514
+ return { error: null };
515
+ } catch (err) {
516
+ return { error: String(err) };
517
+ }
518
+ },
519
+ async getSession() {
520
+ try {
521
+ if (cookieAdapter) {
522
+ const cookies = await cookieAdapter.getAll();
523
+ const sessionCookie = cookies.find(
524
+ (c) => c.name.startsWith("postbase-session") || c.name === "next-auth.session-token" || c.name === "__Secure-next-auth.session-token"
525
+ );
526
+ if (!sessionCookie) return { data: { session: null }, error: null };
527
+ const res2 = await fetch(`${baseUrl}/api/auth/v1/session`, {
528
+ headers: { ...headers(), "X-Postbase-Session": sessionCookie.value }
529
+ });
530
+ if (!res2.ok) return { data: { session: null }, error: null };
531
+ const json2 = await res2.json();
532
+ return { data: { session: json2.session ?? null }, error: null };
533
+ }
534
+ if (isBrowser()) {
535
+ const persisted = loadPersistedSession();
536
+ if (persisted) {
537
+ currentSession = persisted;
538
+ return { data: { session: persisted }, error: null };
539
+ }
540
+ }
541
+ const res = await fetch(`${baseUrl}/api/auth/v1/session`, { headers: headers() });
542
+ if (!res.ok) return { data: { session: null }, error: null };
543
+ const json = await res.json();
544
+ return { data: { session: json.session ?? null }, error: null };
545
+ } catch (err) {
546
+ return { data: { session: null }, error: String(err) };
547
+ }
548
+ },
549
+ async getUser(jwt) {
550
+ try {
551
+ const token = jwt ?? currentSession?.accessToken ?? loadPersistedSession()?.accessToken;
552
+ const res = await fetch(`${baseUrl}/api/auth/v1/user`, {
553
+ headers: {
554
+ ...headers(),
555
+ ...token ? { "X-Postbase-Token": token } : {}
556
+ }
557
+ });
558
+ const json = await res.json();
559
+ if (!res.ok) return { data: { user: null }, error: json.error ?? "Failed to get user" };
560
+ return { data: { user: json.user }, error: null };
561
+ } catch (err) {
562
+ return { data: { user: null }, error: String(err) };
563
+ }
564
+ },
565
+ async refreshSession(refreshToken) {
566
+ try {
567
+ const token = refreshToken ?? currentSession?.refreshToken ?? loadPersistedSession()?.refreshToken;
568
+ const res = await fetch(`${baseUrl}/api/auth/v1/token`, {
569
+ method: "POST",
570
+ headers: headers(),
571
+ body: JSON.stringify({ refresh_token: token, grant_type: "refresh_token" })
572
+ });
573
+ const json = await res.json();
574
+ if (!res.ok) return { data: { user: null, session: null }, error: json.error ?? "Refresh failed" };
575
+ const session = json.session;
576
+ const user = json.user;
577
+ notifyListeners("TOKEN_REFRESHED", session);
578
+ return { data: { user, session }, error: null };
579
+ } catch (err) {
580
+ return { data: { user: null, session: null }, error: String(err) };
581
+ }
582
+ },
583
+ onAuthStateChange(callback) {
584
+ listeners.push(callback);
585
+ const session = currentSession ?? loadPersistedSession();
586
+ if (session) {
587
+ setTimeout(() => callback("SIGNED_IN", session), 0);
588
+ currentSession = session;
589
+ scheduleRefresh(session);
590
+ }
591
+ return {
592
+ data: {
593
+ subscription: {
594
+ unsubscribe() {
595
+ const idx = listeners.indexOf(callback);
596
+ if (idx > -1) listeners.splice(idx, 1);
597
+ }
598
+ }
599
+ }
600
+ };
601
+ },
602
+ admin: createAuthAdmin(baseUrl, apiKey, customHeaders)
603
+ };
604
+ return authClient;
605
+ }
606
+ function createStorageClient(baseUrl, apiKey, options) {
607
+ const customHeaders = options?.global?.headers;
608
+ const headers = () => ({ Authorization: `Bearer ${apiKey}`, ...customHeaders });
609
+ function bucketClient(bucket) {
610
+ return {
611
+ async upload(path, file, uploadOptions) {
612
+ try {
613
+ const form = new FormData();
614
+ form.append("file", file);
615
+ form.append("path", path);
616
+ if (uploadOptions?.upsert) form.append("upsert", "true");
617
+ if (uploadOptions?.cacheControl) form.append("cacheControl", uploadOptions.cacheControl);
618
+ const res = await fetch(`${baseUrl}/api/storage/v1/object/${bucket}/${encodeURIComponent(path)}`, {
619
+ method: uploadOptions?.upsert ? "PUT" : "POST",
620
+ headers: headers(),
621
+ body: form
622
+ });
623
+ const json = await res.json();
624
+ if (!res.ok) return { data: null, error: json.error ?? "Upload failed" };
625
+ return { data: { path, fullPath: `${bucket}/${path}` }, error: null };
626
+ } catch (err) {
627
+ return { data: null, error: String(err) };
628
+ }
629
+ },
630
+ async download(path) {
631
+ try {
632
+ const res = await fetch(`${baseUrl}/api/storage/v1/object/${bucket}/${encodeURIComponent(path)}`, {
633
+ headers: headers()
634
+ });
635
+ if (!res.ok) return { data: null, error: "Download failed" };
636
+ return { data: await res.blob(), error: null };
637
+ } catch (err) {
638
+ return { data: null, error: String(err) };
639
+ }
640
+ },
641
+ async remove(paths) {
642
+ try {
643
+ const res = await fetch(`${baseUrl}/api/storage/v1/object/${bucket}`, {
644
+ method: "DELETE",
645
+ headers: { ...headers(), "Content-Type": "application/json" },
646
+ body: JSON.stringify({ prefixes: paths })
647
+ });
648
+ const json = await res.json();
649
+ if (!res.ok) return { data: null, count: null, error: json.error ?? "Delete failed" };
650
+ return { data: json.data, count: json.data?.length ?? null, error: null };
651
+ } catch (err) {
652
+ return { data: null, count: null, error: String(err) };
653
+ }
654
+ },
655
+ async list(prefix, listOptions) {
656
+ try {
657
+ const res = await fetch(`${baseUrl}/api/storage/v1/object/list/${bucket}`, {
658
+ method: "POST",
659
+ headers: { ...headers(), "Content-Type": "application/json" },
660
+ body: JSON.stringify({
661
+ prefix: prefix ?? "",
662
+ limit: listOptions?.limit ?? 100,
663
+ offset: listOptions?.offset ?? 0,
664
+ sortBy: listOptions?.sortBy
665
+ })
666
+ });
667
+ const json = await res.json();
668
+ if (!res.ok) return { data: null, count: null, error: json.error ?? "List failed" };
669
+ return { data: json.data, count: json.data?.length ?? null, error: null };
670
+ } catch (err) {
671
+ return { data: null, count: null, error: String(err) };
672
+ }
673
+ },
674
+ getPublicUrl(path) {
675
+ return {
676
+ data: { publicUrl: `${baseUrl}/api/storage/v1/object/public/${bucket}/${encodeURIComponent(path)}` }
677
+ };
678
+ },
679
+ async createSignedUrl(path, expiresIn) {
680
+ try {
681
+ const res = await fetch(`${baseUrl}/api/storage/v1/object/sign/${bucket}/${encodeURIComponent(path)}`, {
682
+ method: "POST",
683
+ headers: { ...headers(), "Content-Type": "application/json" },
684
+ body: JSON.stringify({ expiresIn })
685
+ });
686
+ const json = await res.json();
687
+ if (!res.ok) return { data: null, error: json.error ?? "Sign failed" };
688
+ return { data: { signedUrl: `${baseUrl}${json.signedUrl}` }, error: null };
689
+ } catch (err) {
690
+ return { data: null, error: String(err) };
691
+ }
692
+ },
693
+ async move(fromPath, toPath) {
694
+ try {
695
+ const res = await fetch(`${baseUrl}/api/storage/v1/object/move`, {
696
+ method: "POST",
697
+ headers: { ...headers(), "Content-Type": "application/json" },
698
+ body: JSON.stringify({ bucketId: bucket, sourceKey: fromPath, destinationKey: toPath })
699
+ });
700
+ const json = await res.json();
701
+ if (!res.ok) return { error: json.error ?? "Move failed" };
702
+ return { error: null };
703
+ } catch (err) {
704
+ return { error: String(err) };
705
+ }
706
+ },
707
+ async copy(fromPath, toPath) {
708
+ try {
709
+ const res = await fetch(`${baseUrl}/api/storage/v1/object/copy`, {
710
+ method: "POST",
711
+ headers: { ...headers(), "Content-Type": "application/json" },
712
+ body: JSON.stringify({ bucketId: bucket, sourceKey: fromPath, destinationKey: toPath })
713
+ });
714
+ const json = await res.json();
715
+ if (!res.ok) return { data: null, error: json.error ?? "Copy failed" };
716
+ return { data: { path: toPath }, error: null };
717
+ } catch (err) {
718
+ return { data: null, error: String(err) };
719
+ }
720
+ }
721
+ };
722
+ }
723
+ return {
724
+ from: bucketClient,
725
+ async createBucket(name, bucketOptions) {
726
+ try {
727
+ const res = await fetch(`${baseUrl}/api/storage/v1/bucket`, {
728
+ method: "POST",
729
+ headers: { ...headers(), "Content-Type": "application/json" },
730
+ body: JSON.stringify({
731
+ name,
732
+ id: name,
733
+ public: bucketOptions?.public ?? false,
734
+ file_size_limit: bucketOptions?.fileSizeLimit,
735
+ allowed_mime_types: bucketOptions?.allowedMimeTypes
736
+ })
737
+ });
738
+ const json = await res.json();
739
+ if (!res.ok) return { data: null, error: json.error ?? "Create bucket failed" };
740
+ return { data: json.data, error: null };
741
+ } catch (err) {
742
+ return { data: null, error: String(err) };
743
+ }
744
+ },
745
+ async getBucket(id) {
746
+ try {
747
+ const res = await fetch(`${baseUrl}/api/storage/v1/bucket/${id}`, { headers: headers() });
748
+ const json = await res.json();
749
+ if (!res.ok) return { data: null, error: json.error ?? "Get bucket failed" };
750
+ return { data: json.data, error: null };
751
+ } catch (err) {
752
+ return { data: null, error: String(err) };
753
+ }
754
+ },
755
+ async listBuckets() {
756
+ try {
757
+ const res = await fetch(`${baseUrl}/api/storage/v1/bucket`, { headers: headers() });
758
+ const json = await res.json();
759
+ if (!res.ok) return { data: null, count: null, error: json.error ?? "List buckets failed" };
760
+ return { data: json.data, count: json.data?.length ?? null, error: null };
761
+ } catch (err) {
762
+ return { data: null, count: null, error: String(err) };
763
+ }
764
+ },
765
+ async updateBucket(id, bucketOptions) {
766
+ try {
767
+ const res = await fetch(`${baseUrl}/api/storage/v1/bucket/${id}`, {
768
+ method: "PUT",
769
+ headers: { ...headers(), "Content-Type": "application/json" },
770
+ body: JSON.stringify({
771
+ public: bucketOptions.public,
772
+ file_size_limit: bucketOptions.fileSizeLimit,
773
+ allowed_mime_types: bucketOptions.allowedMimeTypes
774
+ })
775
+ });
776
+ const json = await res.json();
777
+ if (!res.ok) return { data: null, error: json.error ?? "Update bucket failed" };
778
+ return { data: json.data, error: null };
779
+ } catch (err) {
780
+ return { data: null, error: String(err) };
781
+ }
782
+ },
783
+ async deleteBucket(id) {
784
+ try {
785
+ const res = await fetch(`${baseUrl}/api/storage/v1/bucket/${id}`, {
786
+ method: "DELETE",
787
+ headers: headers()
788
+ });
789
+ const json = await res.json();
790
+ if (!res.ok) return { error: json.error ?? "Delete bucket failed" };
791
+ return { error: null };
792
+ } catch (err) {
793
+ return { error: String(err) };
794
+ }
795
+ },
796
+ async emptyBucket(id) {
797
+ try {
798
+ const res = await fetch(`${baseUrl}/api/storage/v1/bucket/${id}/empty`, {
799
+ method: "POST",
800
+ headers: headers()
801
+ });
802
+ const json = await res.json();
803
+ if (!res.ok) return { error: json.error ?? "Empty bucket failed" };
804
+ return { error: null };
805
+ } catch (err) {
806
+ return { error: String(err) };
807
+ }
808
+ }
809
+ };
810
+ }
811
+ var RealtimeChannelImpl = class {
812
+ constructor(baseUrl, apiKey, channelName) {
813
+ this.baseUrl = baseUrl;
814
+ this.apiKey = apiKey;
815
+ this.channelName = channelName;
816
+ this.handlers = [];
817
+ this.ws = null;
818
+ }
819
+ on(event, callback) {
820
+ this.handlers.push({ event, callback });
821
+ return this;
822
+ }
823
+ subscribe(callback) {
824
+ if (typeof window === "undefined") return this;
825
+ this.statusCallback = callback;
826
+ const wsUrl = this.baseUrl.replace(/^http/, "ws");
827
+ try {
828
+ this.ws = new WebSocket(`${wsUrl}/api/realtime?channel=${encodeURIComponent(this.channelName)}&apikey=${this.apiKey}`);
829
+ this.ws.onopen = () => {
830
+ this.statusCallback?.("SUBSCRIBED");
831
+ };
832
+ this.ws.onmessage = (event) => {
833
+ try {
834
+ const payload = JSON.parse(event.data);
835
+ this.handlers.forEach(({ event: eventType, callback: callback2 }) => {
836
+ if (eventType === "*" || eventType === payload.eventType) {
837
+ callback2(payload);
838
+ }
839
+ });
840
+ } catch {
841
+ }
842
+ };
843
+ this.ws.onerror = () => {
844
+ this.statusCallback?.("CHANNEL_ERROR");
845
+ };
846
+ this.ws.onclose = () => {
847
+ this.statusCallback?.("CLOSED");
848
+ };
849
+ } catch {
850
+ this.statusCallback?.("CHANNEL_ERROR");
851
+ }
852
+ return this;
853
+ }
854
+ unsubscribe() {
855
+ this.ws?.close();
856
+ this.ws = null;
857
+ }
858
+ };
859
+ var channels = /* @__PURE__ */ new Set();
860
+ function createClient(url, key, options) {
861
+ const baseUrl = url.replace(/\/$/, "");
862
+ const cookieAdapter = options?.cookies;
863
+ const makeQueryState = (table) => ({
864
+ baseUrl,
865
+ apiKey: key,
866
+ table,
867
+ columns: "*",
868
+ selectOptions: {},
869
+ filters: [],
870
+ orFilters: [],
871
+ notFilters: [],
872
+ orderBy: [],
873
+ operation: "select",
874
+ customHeaders: options?.global?.headers,
875
+ cookieAdapter
876
+ });
877
+ return {
878
+ url: baseUrl,
879
+ key,
880
+ auth: createAuthClient(baseUrl, key, options, cookieAdapter),
881
+ storage: createStorageClient(baseUrl, key, options),
882
+ from(table) {
883
+ return new QueryBuilderImpl(makeQueryState(table));
884
+ },
885
+ async rpc(fn, args, rpcOptions) {
886
+ try {
887
+ const headers = {
888
+ "Content-Type": "application/json",
889
+ Authorization: `Bearer ${key}`,
890
+ ...options?.global?.headers
891
+ };
892
+ if (cookieAdapter) {
893
+ const cookies = await cookieAdapter.getAll();
894
+ const sessionCookie = cookies.find(
895
+ (c) => c.name.startsWith("postbase-session") || c.name === "next-auth.session-token" || c.name === "__Secure-next-auth.session-token"
896
+ );
897
+ if (sessionCookie) headers["X-Postbase-Session"] = sessionCookie.value;
898
+ }
899
+ const res = await fetch(`${baseUrl}/api/rpc/${fn}`, {
900
+ method: rpcOptions?.head ? "HEAD" : "POST",
901
+ headers,
902
+ body: JSON.stringify({ args: args ?? {}, count: rpcOptions?.count })
903
+ });
904
+ const json = await res.json();
905
+ if (!res.ok) return { data: null, count: null, error: json.error ?? "RPC failed" };
906
+ return { data: json.data, count: json.count ?? null, error: null };
907
+ } catch (err) {
908
+ return { data: null, count: null, error: String(err) };
909
+ }
910
+ },
911
+ channel(name) {
912
+ const ch = new RealtimeChannelImpl(baseUrl, key, name);
913
+ channels.add(ch);
914
+ return ch;
915
+ },
916
+ removeChannel(channel) {
917
+ channel.unsubscribe();
918
+ channels.delete(channel);
919
+ },
920
+ removeAllChannels() {
921
+ channels.forEach((ch) => ch.unsubscribe());
922
+ channels.clear();
923
+ }
924
+ };
925
+ }
926
+
927
+ // src/ssr/index.ts
928
+ function createServerClient(url, key, options) {
929
+ return createClient(url, key, { ...options, cookies: options.cookies });
930
+ }
931
+ function createBrowserClient(url, key, options) {
932
+ return createClient(url, key, {
933
+ ...options,
934
+ auth: {
935
+ persistSession: true,
936
+ autoRefreshToken: true,
937
+ detectSessionInUrl: true,
938
+ ...options?.auth
939
+ }
940
+ });
941
+ }
942
+ // Annotate the CommonJS export names for ESM import in node:
943
+ 0 && (module.exports = {
944
+ createBrowserClient,
945
+ createClient,
946
+ createServerClient
947
+ });
948
+ //# sourceMappingURL=index.js.map