@airostack/client 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.
- package/README.md +85 -0
- package/dist/auth.d.ts +62 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +155 -0
- package/dist/auth.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/query-builder.d.ts +56 -0
- package/dist/query-builder.d.ts.map +1 -0
- package/dist/query-builder.js +132 -0
- package/dist/query-builder.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @airostack/client
|
|
2
|
+
|
|
3
|
+
Isomorphic client for [AiroStack](https://console.airoxlab.com) projects — Supabase-style database queries and end-user auth. Zero dependencies, works in **Node.js**, **browsers**, and **React Native / Expo**.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @airostack/client
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { createClient } from '@airostack/client';
|
|
13
|
+
|
|
14
|
+
const client = createClient(
|
|
15
|
+
'https://<project-ref>.db.airoxlab.com', // project URL (dashboard → Connect)
|
|
16
|
+
'<publishable-key>', // API settings → publishable key
|
|
17
|
+
);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**React Native:** pass AsyncStorage so sessions persist:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
24
|
+
|
|
25
|
+
const client = createClient(url, key, { auth: { storage: AsyncStorage } });
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Database
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// read
|
|
32
|
+
const { data, error } = await client
|
|
33
|
+
.from('orders')
|
|
34
|
+
.select('id, item, qty')
|
|
35
|
+
.eq('status', 'paid')
|
|
36
|
+
.order('created_at', { ascending: false })
|
|
37
|
+
.limit(20);
|
|
38
|
+
|
|
39
|
+
// one row
|
|
40
|
+
const { data: order } = await client.from('orders').select().eq('id', id).single();
|
|
41
|
+
|
|
42
|
+
// insert (returns the created rows)
|
|
43
|
+
const { data: created } = await client.from('orders').insert({ item: 'Burger', qty: 2 });
|
|
44
|
+
|
|
45
|
+
// update / delete
|
|
46
|
+
await client.from('orders').update({ status: 'done' }).eq('id', id);
|
|
47
|
+
await client.from('orders').delete().eq('id', id);
|
|
48
|
+
|
|
49
|
+
// count
|
|
50
|
+
const { count } = await client.from('orders').select('*', { count: 'exact' }).limit(1);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Filters: `eq neq gt gte lt lte like ilike`, plus the generic `.filter(col, op, value)`.
|
|
54
|
+
Pagination: `.range(from, to)`. Errors never throw — check `error` on the result.
|
|
55
|
+
|
|
56
|
+
## Auth
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
await client.auth.signUp({ email, password, options: { data: { name: 'Ada' } } });
|
|
60
|
+
await client.auth.signInWithPassword({ email, password });
|
|
61
|
+
const { data: { user } } = await client.auth.getUser();
|
|
62
|
+
await client.auth.signOut();
|
|
63
|
+
|
|
64
|
+
client.auth.onAuthStateChange((event, session) => {
|
|
65
|
+
// 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Sessions persist automatically and access tokens refresh on demand. While a
|
|
70
|
+
user is signed in, every `.from()` query carries their JWT — so your
|
|
71
|
+
**Row Level Security** policies (`auth.uid()` etc.) apply per user, exactly
|
|
72
|
+
like Supabase.
|
|
73
|
+
|
|
74
|
+
## Server-side with the secret key
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const admin = createClient(url, process.env.AIROSTACK_SECRET_KEY!, {
|
|
78
|
+
auth: { persistSession: false },
|
|
79
|
+
});
|
|
80
|
+
// full access, bypasses RLS — server only, never ship this key to a client
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ApiError, type AuthResult, type Session, type StorageAdapter, type User } from './types.js';
|
|
2
|
+
type AuthEvent = 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED';
|
|
3
|
+
type AuthListener = (event: AuthEvent, session: Session | null) => void;
|
|
4
|
+
/**
|
|
5
|
+
* End-user authentication against the project's Auth API (GoTrue-style).
|
|
6
|
+
* Sessions persist via the storage adapter (localStorage by default; pass
|
|
7
|
+
* AsyncStorage in React Native) and access tokens auto-refresh on read.
|
|
8
|
+
*/
|
|
9
|
+
export declare class AuthClient {
|
|
10
|
+
private url;
|
|
11
|
+
private key;
|
|
12
|
+
private fetcher;
|
|
13
|
+
private storage;
|
|
14
|
+
private storageKey;
|
|
15
|
+
private persist;
|
|
16
|
+
private cached;
|
|
17
|
+
private listeners;
|
|
18
|
+
constructor(url: string, key: string, fetcher: typeof fetch, opts?: {
|
|
19
|
+
persistSession?: boolean;
|
|
20
|
+
storage?: StorageAdapter;
|
|
21
|
+
storageKey?: string;
|
|
22
|
+
});
|
|
23
|
+
private saveSession;
|
|
24
|
+
private readSession;
|
|
25
|
+
private request;
|
|
26
|
+
private toResult;
|
|
27
|
+
signUp(creds: {
|
|
28
|
+
email: string;
|
|
29
|
+
password: string;
|
|
30
|
+
options?: {
|
|
31
|
+
data?: Record<string, unknown>;
|
|
32
|
+
};
|
|
33
|
+
}): Promise<AuthResult>;
|
|
34
|
+
signInWithPassword(creds: {
|
|
35
|
+
email: string;
|
|
36
|
+
password: string;
|
|
37
|
+
}): Promise<AuthResult>;
|
|
38
|
+
signOut(): Promise<{
|
|
39
|
+
error: ApiError | null;
|
|
40
|
+
}>;
|
|
41
|
+
/** Current session — refreshes automatically when the access token expired. */
|
|
42
|
+
getSession(): Promise<{
|
|
43
|
+
data: {
|
|
44
|
+
session: Session | null;
|
|
45
|
+
};
|
|
46
|
+
error: ApiError | null;
|
|
47
|
+
}>;
|
|
48
|
+
/** Current user, validated against the server. */
|
|
49
|
+
getUser(): Promise<{
|
|
50
|
+
data: {
|
|
51
|
+
user: User | null;
|
|
52
|
+
};
|
|
53
|
+
error: ApiError | null;
|
|
54
|
+
}>;
|
|
55
|
+
onAuthStateChange(callback: AuthListener): {
|
|
56
|
+
unsubscribe: () => void;
|
|
57
|
+
};
|
|
58
|
+
/** Valid access token for Data API requests, or null (anon). */
|
|
59
|
+
accessToken(): Promise<string | null>;
|
|
60
|
+
}
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAqBrG,KAAK,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,iBAAiB,CAAC;AAChE,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;AAExE;;;;GAIG;AACH,qBAAa,UAAU;IAQnB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,OAAO;IATjB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAA2B;gBAGlC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,KAAK,EAC7B,IAAI,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,cAAc,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;YAQtE,WAAW;YASX,WAAW;YAYX,OAAO;IASrB,OAAO,CAAC,QAAQ;IAWV,MAAM,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAUrH,kBAAkB,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAUnF,OAAO,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,CAAC;IAMpD,+EAA+E;IACzE,UAAU,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE;YAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;SAAE,CAAC;QAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,CAAC;IAmB1F,kDAAkD;IAC5C,OAAO,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE;YAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;SAAE,CAAC;QAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,CAAC;IAWjF,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG;QAAE,WAAW,EAAE,MAAM,IAAI,CAAA;KAAE;IAKtE,gEAAgE;IAC1D,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAI5C"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { ApiError } from './types.js';
|
|
2
|
+
const memoryStore = () => {
|
|
3
|
+
const m = new Map();
|
|
4
|
+
return {
|
|
5
|
+
getItem: (k) => m.get(k) ?? null,
|
|
6
|
+
setItem: (k, v) => void m.set(k, v),
|
|
7
|
+
removeItem: (k) => void m.delete(k),
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
function defaultStorage() {
|
|
11
|
+
try {
|
|
12
|
+
const ls = globalThis.localStorage;
|
|
13
|
+
if (ls)
|
|
14
|
+
return ls;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// SSR / React Native — fall through
|
|
18
|
+
}
|
|
19
|
+
return memoryStore();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* End-user authentication against the project's Auth API (GoTrue-style).
|
|
23
|
+
* Sessions persist via the storage adapter (localStorage by default; pass
|
|
24
|
+
* AsyncStorage in React Native) and access tokens auto-refresh on read.
|
|
25
|
+
*/
|
|
26
|
+
export class AuthClient {
|
|
27
|
+
url;
|
|
28
|
+
key;
|
|
29
|
+
fetcher;
|
|
30
|
+
storage;
|
|
31
|
+
storageKey;
|
|
32
|
+
persist;
|
|
33
|
+
cached = null;
|
|
34
|
+
listeners = new Set();
|
|
35
|
+
constructor(url, key, fetcher, opts) {
|
|
36
|
+
this.url = url;
|
|
37
|
+
this.key = key;
|
|
38
|
+
this.fetcher = fetcher;
|
|
39
|
+
this.persist = opts?.persistSession !== false;
|
|
40
|
+
this.storage = opts?.storage ?? defaultStorage();
|
|
41
|
+
this.storageKey = opts?.storageKey ?? 'airostack.auth.token';
|
|
42
|
+
}
|
|
43
|
+
// ── session plumbing ─────────────────────────────────────────────────
|
|
44
|
+
async saveSession(session, event) {
|
|
45
|
+
this.cached = session;
|
|
46
|
+
if (this.persist) {
|
|
47
|
+
if (session)
|
|
48
|
+
await this.storage.setItem(this.storageKey, JSON.stringify(session));
|
|
49
|
+
else
|
|
50
|
+
await this.storage.removeItem(this.storageKey);
|
|
51
|
+
}
|
|
52
|
+
for (const l of this.listeners)
|
|
53
|
+
l(event, session);
|
|
54
|
+
}
|
|
55
|
+
async readSession() {
|
|
56
|
+
if (this.cached)
|
|
57
|
+
return this.cached;
|
|
58
|
+
if (!this.persist)
|
|
59
|
+
return null;
|
|
60
|
+
try {
|
|
61
|
+
const raw = await this.storage.getItem(this.storageKey);
|
|
62
|
+
this.cached = raw ? JSON.parse(raw) : null;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
this.cached = null;
|
|
66
|
+
}
|
|
67
|
+
return this.cached;
|
|
68
|
+
}
|
|
69
|
+
async request(path, init) {
|
|
70
|
+
const res = await this.fetcher(`${this.url}${path}`, {
|
|
71
|
+
...init,
|
|
72
|
+
headers: { apikey: this.key, 'content-type': 'application/json', ...init.headers },
|
|
73
|
+
});
|
|
74
|
+
const body = res.status === 204 ? null : await res.json().catch(() => null);
|
|
75
|
+
return { ok: res.ok, status: res.status, body };
|
|
76
|
+
}
|
|
77
|
+
toResult(ok, status, body) {
|
|
78
|
+
if (!ok) {
|
|
79
|
+
const msg = body?.message ?? 'authentication failed';
|
|
80
|
+
return { data: { user: null, session: null }, error: new ApiError(String(msg), status) };
|
|
81
|
+
}
|
|
82
|
+
const session = body;
|
|
83
|
+
session.expires_at = Math.floor(Date.now() / 1000) + (session.expires_in ?? 3600);
|
|
84
|
+
return { data: { user: session.user, session }, error: null };
|
|
85
|
+
}
|
|
86
|
+
// ── public API (supabase-shaped) ─────────────────────────────────────
|
|
87
|
+
async signUp(creds) {
|
|
88
|
+
const { ok, status, body } = await this.request('/auth/v1/signup', {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
body: JSON.stringify({ email: creds.email, password: creds.password, data: creds.options?.data }),
|
|
91
|
+
});
|
|
92
|
+
const result = this.toResult(ok, status, body);
|
|
93
|
+
if (result.data.session)
|
|
94
|
+
await this.saveSession(result.data.session, 'SIGNED_IN');
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
async signInWithPassword(creds) {
|
|
98
|
+
const { ok, status, body } = await this.request('/auth/v1/token?grant_type=password', {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
body: JSON.stringify(creds),
|
|
101
|
+
});
|
|
102
|
+
const result = this.toResult(ok, status, body);
|
|
103
|
+
if (result.data.session)
|
|
104
|
+
await this.saveSession(result.data.session, 'SIGNED_IN');
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
async signOut() {
|
|
108
|
+
await this.request('/auth/v1/logout', { method: 'POST' }).catch(() => null);
|
|
109
|
+
await this.saveSession(null, 'SIGNED_OUT');
|
|
110
|
+
return { error: null };
|
|
111
|
+
}
|
|
112
|
+
/** Current session — refreshes automatically when the access token expired. */
|
|
113
|
+
async getSession() {
|
|
114
|
+
let session = await this.readSession();
|
|
115
|
+
if (session?.expires_at && session.expires_at - 30 < Math.floor(Date.now() / 1000)) {
|
|
116
|
+
const { ok, status, body } = await this.request('/auth/v1/token?grant_type=refresh_token', {
|
|
117
|
+
method: 'POST',
|
|
118
|
+
body: JSON.stringify({ refresh_token: session.refresh_token }),
|
|
119
|
+
});
|
|
120
|
+
const refreshed = this.toResult(ok, status, body);
|
|
121
|
+
if (refreshed.data.session) {
|
|
122
|
+
session = refreshed.data.session;
|
|
123
|
+
await this.saveSession(session, 'TOKEN_REFRESHED');
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
await this.saveSession(null, 'SIGNED_OUT');
|
|
127
|
+
return { data: { session: null }, error: refreshed.error };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return { data: { session }, error: null };
|
|
131
|
+
}
|
|
132
|
+
/** Current user, validated against the server. */
|
|
133
|
+
async getUser() {
|
|
134
|
+
const { data } = await this.getSession();
|
|
135
|
+
if (!data.session)
|
|
136
|
+
return { data: { user: null }, error: new ApiError('not signed in', 401) };
|
|
137
|
+
const { ok, status, body } = await this.request('/auth/v1/user', {
|
|
138
|
+
method: 'GET',
|
|
139
|
+
headers: { authorization: `Bearer ${data.session.access_token}` },
|
|
140
|
+
});
|
|
141
|
+
if (!ok)
|
|
142
|
+
return { data: { user: null }, error: new ApiError('invalid or expired token', status) };
|
|
143
|
+
return { data: { user: body }, error: null };
|
|
144
|
+
}
|
|
145
|
+
onAuthStateChange(callback) {
|
|
146
|
+
this.listeners.add(callback);
|
|
147
|
+
return { unsubscribe: () => this.listeners.delete(callback) };
|
|
148
|
+
}
|
|
149
|
+
/** Valid access token for Data API requests, or null (anon). */
|
|
150
|
+
async accessToken() {
|
|
151
|
+
const { data } = await this.getSession();
|
|
152
|
+
return data.session?.access_token ?? null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAiE,MAAM,YAAY,CAAC;AAErG,MAAM,WAAW,GAAG,GAAmB,EAAE;IACvC,MAAM,CAAC,GAAG,IAAI,GAAG,EAAkB,CAAC;IACpC,OAAO;QACL,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI;QAChC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;QACnC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;KACpC,CAAC;AACJ,CAAC,CAAC;AAEF,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,EAAE,GAAI,UAAgD,CAAC,YAAY,CAAC;QAC1E,IAAI,EAAE;YAAE,OAAO,EAAE,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;IACD,OAAO,WAAW,EAAE,CAAC;AACvB,CAAC;AAKD;;;;GAIG;AACH,MAAM,OAAO,UAAU;IAQX;IACA;IACA;IATF,OAAO,CAAiB;IACxB,UAAU,CAAS;IACnB,OAAO,CAAU;IACjB,MAAM,GAAmB,IAAI,CAAC;IAC9B,SAAS,GAAG,IAAI,GAAG,EAAgB,CAAC;IAE5C,YACU,GAAW,EACX,GAAW,EACX,OAAqB,EAC7B,IAAkF;QAH1E,QAAG,GAAH,GAAG,CAAQ;QACX,QAAG,GAAH,GAAG,CAAQ;QACX,YAAO,GAAP,OAAO,CAAc;QAG7B,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,cAAc,KAAK,KAAK,CAAC;QAC9C,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,cAAc,EAAE,CAAC;QACjD,IAAI,CAAC,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,sBAAsB,CAAC;IAC/D,CAAC;IAED,wEAAwE;IAChE,KAAK,CAAC,WAAW,CAAC,OAAuB,EAAE,KAAgB;QACjE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,OAAO;gBAAE,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;;gBAC7E,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS;YAAE,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAEO,KAAK,CAAC,WAAW;QACvB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACxD,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,IAAiB;QACnD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,EAAE,EAAE;YACnD,GAAG,IAAI;YACP,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAI,IAAI,CAAC,OAAkC,EAAE;SAC/G,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC5E,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IAClD,CAAC;IAEO,QAAQ,CAAC,EAAW,EAAE,MAAc,EAAE,IAAa;QACzD,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,GAAG,GAAI,IAA6B,EAAE,OAAO,IAAI,uBAAuB,CAAC;YAC/E,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;QAC3F,CAAC;QACD,MAAM,OAAO,GAAG,IAAe,CAAC;QAChC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;QAClF,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAChE,CAAC;IAED,wEAAwE;IACxE,KAAK,CAAC,MAAM,CAAC,KAAwF;QACnG,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE;YACjE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;SAClG,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAClF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,KAA0C;QACjE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,oCAAoC,EAAE;YACpF,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAClF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC5E,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC3C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,+EAA+E;IAC/E,KAAK,CAAC,UAAU;QACd,IAAI,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,OAAO,EAAE,UAAU,IAAI,OAAO,CAAC,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YACnF,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,yCAAyC,EAAE;gBACzF,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC;aAC/D,CAAC,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YAClD,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC3B,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;gBACjC,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;gBAC3C,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC;YAC7D,CAAC;QACH,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,kDAAkD;IAClD,KAAK,CAAC,OAAO;QACX,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,EAAE,CAAC;QAC9F,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE;YAC/D,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE;SAClE,CAAC,CAAC;QACH,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,QAAQ,CAAC,0BAA0B,EAAE,MAAM,CAAC,EAAE,CAAC;QAClG,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACvD,CAAC;IAED,iBAAiB,CAAC,QAAsB;QACtC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;IAChE,CAAC;IAED,gEAAgE;IAChE,KAAK,CAAC,WAAW;QACf,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACzC,OAAO,IAAI,CAAC,OAAO,EAAE,YAAY,IAAI,IAAI,CAAC;IAC5C,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AuthClient } from './auth.js';
|
|
2
|
+
import { QueryBuilder } from './query-builder.js';
|
|
3
|
+
import type { ClientOptions } from './types.js';
|
|
4
|
+
export { ApiError } from './types.js';
|
|
5
|
+
export type { ApiResult, AuthResult, ClientOptions, Session, StorageAdapter, User } from './types.js';
|
|
6
|
+
export { AuthClient } from './auth.js';
|
|
7
|
+
export { QueryBuilder } from './query-builder.js';
|
|
8
|
+
/**
|
|
9
|
+
* AiroStack client — Supabase-style API over your project's Data API + Auth.
|
|
10
|
+
*
|
|
11
|
+
* import { createClient } from '@airostack/client';
|
|
12
|
+
* const client = createClient(process.env.AIROSTACK_URL!, process.env.AIROSTACK_KEY!);
|
|
13
|
+
*
|
|
14
|
+
* const { data, error } = await client.from('orders').select().eq('status', 'paid');
|
|
15
|
+
* await client.auth.signInWithPassword({ email, password });
|
|
16
|
+
*/
|
|
17
|
+
export declare class AiroStackClient {
|
|
18
|
+
private url;
|
|
19
|
+
private key;
|
|
20
|
+
readonly auth: AuthClient;
|
|
21
|
+
private fetcher;
|
|
22
|
+
constructor(url: string, key: string, options?: ClientOptions);
|
|
23
|
+
/** Query a table through the Data API (RLS applies per the caller's key/JWT). */
|
|
24
|
+
from<T = Record<string, unknown>>(table: string): QueryBuilder<T>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createClient(url: string, key: string, options?: ClientOptions): AiroStackClient;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACtG,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAId,OAAO,CAAC,GAAG;IAAU,OAAO,CAAC,GAAG;IAH5C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,OAAO,CAAC,OAAO,CAAe;gBAEV,GAAG,EAAE,MAAM,EAAU,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;IAO7E,iFAAiF;IACjF,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC;CAMlE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,eAAe,CAE/F"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AuthClient } from './auth.js';
|
|
2
|
+
import { QueryBuilder } from './query-builder.js';
|
|
3
|
+
export { ApiError } from './types.js';
|
|
4
|
+
export { AuthClient } from './auth.js';
|
|
5
|
+
export { QueryBuilder } from './query-builder.js';
|
|
6
|
+
/**
|
|
7
|
+
* AiroStack client — Supabase-style API over your project's Data API + Auth.
|
|
8
|
+
*
|
|
9
|
+
* import { createClient } from '@airostack/client';
|
|
10
|
+
* const client = createClient(process.env.AIROSTACK_URL!, process.env.AIROSTACK_KEY!);
|
|
11
|
+
*
|
|
12
|
+
* const { data, error } = await client.from('orders').select().eq('status', 'paid');
|
|
13
|
+
* await client.auth.signInWithPassword({ email, password });
|
|
14
|
+
*/
|
|
15
|
+
export class AiroStackClient {
|
|
16
|
+
url;
|
|
17
|
+
key;
|
|
18
|
+
auth;
|
|
19
|
+
fetcher;
|
|
20
|
+
constructor(url, key, options) {
|
|
21
|
+
this.url = url;
|
|
22
|
+
this.key = key;
|
|
23
|
+
if (!url || !key)
|
|
24
|
+
throw new Error('createClient(url, key) — both are required');
|
|
25
|
+
this.url = url.replace(/\/+$/, '');
|
|
26
|
+
this.fetcher = options?.fetch ?? ((...args) => fetch(...args));
|
|
27
|
+
this.auth = new AuthClient(this.url, key, this.fetcher, options?.auth);
|
|
28
|
+
}
|
|
29
|
+
/** Query a table through the Data API (RLS applies per the caller's key/JWT). */
|
|
30
|
+
from(table) {
|
|
31
|
+
return new QueryBuilder({ url: this.url, key: this.key, fetch: this.fetcher, accessToken: () => this.auth.accessToken() }, table);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function createClient(url, key, options) {
|
|
35
|
+
return new AiroStackClient(url, key, options);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;;;;GAQG;AACH,MAAM,OAAO,eAAe;IAIN;IAAqB;IAHhC,IAAI,CAAa;IAClB,OAAO,CAAe;IAE9B,YAAoB,GAAW,EAAU,GAAW,EAAE,OAAuB;QAAzD,QAAG,GAAH,GAAG,CAAQ;QAAU,QAAG,GAAH,GAAG,CAAQ;QAClD,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChF,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,IAA8B,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACzF,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACzE,CAAC;IAED,iFAAiF;IACjF,IAAI,CAA8B,KAAa;QAC7C,OAAO,IAAI,YAAY,CACrB,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,EACjG,KAAK,CACN,CAAC;IACJ,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,GAAW,EAAE,OAAuB;IAC5E,OAAO,IAAI,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type ApiResult } from './types.js';
|
|
2
|
+
type Fetcher = typeof fetch;
|
|
3
|
+
type TokenProvider = () => Promise<string | null>;
|
|
4
|
+
interface Ctx {
|
|
5
|
+
url: string;
|
|
6
|
+
key: string;
|
|
7
|
+
fetch: Fetcher;
|
|
8
|
+
accessToken: TokenProvider;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Supabase-style fluent query builder over the AiroStack Data API
|
|
12
|
+
* (PostgREST dialect). Thenable — `await` it anywhere in the chain.
|
|
13
|
+
*
|
|
14
|
+
* const { data, error } = await client.from('orders')
|
|
15
|
+
* .select('id, item, qty').eq('status', 'paid')
|
|
16
|
+
* .order('created_at', { ascending: false }).limit(20);
|
|
17
|
+
*/
|
|
18
|
+
export declare class QueryBuilder<T = Record<string, unknown>> implements PromiseLike<ApiResult<T[]>> {
|
|
19
|
+
private ctx;
|
|
20
|
+
private table;
|
|
21
|
+
private params;
|
|
22
|
+
private method;
|
|
23
|
+
private body;
|
|
24
|
+
private wantCount;
|
|
25
|
+
private takeSingle;
|
|
26
|
+
constructor(ctx: Ctx, table: string);
|
|
27
|
+
select(columns?: string, opts?: {
|
|
28
|
+
count?: 'exact';
|
|
29
|
+
}): this;
|
|
30
|
+
order(column: string, opts?: {
|
|
31
|
+
ascending?: boolean;
|
|
32
|
+
}): this;
|
|
33
|
+
limit(n: number): this;
|
|
34
|
+
range(from: number, to: number): this;
|
|
35
|
+
/** resolve a single row — errors if none found */
|
|
36
|
+
single(): this;
|
|
37
|
+
/** resolve a single row or null */
|
|
38
|
+
maybeSingle(): this;
|
|
39
|
+
eq(column: string, value: unknown): this;
|
|
40
|
+
neq(column: string, value: unknown): this;
|
|
41
|
+
gt(column: string, value: unknown): this;
|
|
42
|
+
gte(column: string, value: unknown): this;
|
|
43
|
+
lt(column: string, value: unknown): this;
|
|
44
|
+
lte(column: string, value: unknown): this;
|
|
45
|
+
like(column: string, pattern: string): this;
|
|
46
|
+
ilike(column: string, pattern: string): this;
|
|
47
|
+
/** generic escape hatch: .filter('qty', 'gte', 10) */
|
|
48
|
+
filter(column: string, operator: string, value: unknown): this;
|
|
49
|
+
insert(values: Partial<T> | Partial<T>[]): this;
|
|
50
|
+
update(values: Partial<T>): this;
|
|
51
|
+
delete(): this;
|
|
52
|
+
then<R1 = ApiResult<T[]>, R2 = never>(onfulfilled?: ((value: ApiResult<T[]>) => R1 | PromiseLike<R1>) | null, onrejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | null): PromiseLike<R1 | R2>;
|
|
53
|
+
private execute;
|
|
54
|
+
}
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=query-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-builder.d.ts","sourceRoot":"","sources":["../src/query-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { ApiError } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Supabase-style fluent query builder over the AiroStack Data API
|
|
4
|
+
* (PostgREST dialect). Thenable — `await` it anywhere in the chain.
|
|
5
|
+
*
|
|
6
|
+
* const { data, error } = await client.from('orders')
|
|
7
|
+
* .select('id, item, qty').eq('status', 'paid')
|
|
8
|
+
* .order('created_at', { ascending: false }).limit(20);
|
|
9
|
+
*/
|
|
10
|
+
export class QueryBuilder {
|
|
11
|
+
ctx;
|
|
12
|
+
table;
|
|
13
|
+
params = new URLSearchParams();
|
|
14
|
+
method = 'GET';
|
|
15
|
+
body = undefined;
|
|
16
|
+
wantCount = false;
|
|
17
|
+
takeSingle = null;
|
|
18
|
+
constructor(ctx, table) {
|
|
19
|
+
this.ctx = ctx;
|
|
20
|
+
this.table = table;
|
|
21
|
+
}
|
|
22
|
+
// ── shape ────────────────────────────────────────────────────────────
|
|
23
|
+
select(columns = '*', opts) {
|
|
24
|
+
if (columns && columns !== '*')
|
|
25
|
+
this.params.set('select', columns.replace(/\s+/g, ''));
|
|
26
|
+
if (opts?.count === 'exact')
|
|
27
|
+
this.wantCount = true;
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
order(column, opts) {
|
|
31
|
+
this.params.set('order', `${column}.${opts?.ascending === false ? 'desc' : 'asc'}`);
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
limit(n) {
|
|
35
|
+
this.params.set('limit', String(n));
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
range(from, to) {
|
|
39
|
+
this.params.set('offset', String(from));
|
|
40
|
+
this.params.set('limit', String(to - from + 1));
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
/** resolve a single row — errors if none found */
|
|
44
|
+
single() {
|
|
45
|
+
this.takeSingle = 'strict';
|
|
46
|
+
this.params.set('limit', '2');
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
/** resolve a single row or null */
|
|
50
|
+
maybeSingle() {
|
|
51
|
+
this.takeSingle = 'maybe';
|
|
52
|
+
this.params.set('limit', '2');
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
// ── filters (PostgREST operators) ────────────────────────────────────
|
|
56
|
+
eq(column, value) { return this.filter(column, 'eq', value); }
|
|
57
|
+
neq(column, value) { return this.filter(column, 'neq', value); }
|
|
58
|
+
gt(column, value) { return this.filter(column, 'gt', value); }
|
|
59
|
+
gte(column, value) { return this.filter(column, 'gte', value); }
|
|
60
|
+
lt(column, value) { return this.filter(column, 'lt', value); }
|
|
61
|
+
lte(column, value) { return this.filter(column, 'lte', value); }
|
|
62
|
+
like(column, pattern) { return this.filter(column, 'like', pattern); }
|
|
63
|
+
ilike(column, pattern) { return this.filter(column, 'ilike', pattern); }
|
|
64
|
+
/** generic escape hatch: .filter('qty', 'gte', 10) */
|
|
65
|
+
filter(column, operator, value) {
|
|
66
|
+
this.params.append(column, `${operator}.${String(value)}`);
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
// ── writes ───────────────────────────────────────────────────────────
|
|
70
|
+
insert(values) {
|
|
71
|
+
this.method = 'POST';
|
|
72
|
+
this.body = values;
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
update(values) {
|
|
76
|
+
this.method = 'PATCH';
|
|
77
|
+
this.body = values;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
delete() {
|
|
81
|
+
this.method = 'DELETE';
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
// ── execution ────────────────────────────────────────────────────────
|
|
85
|
+
then(onfulfilled, onrejected) {
|
|
86
|
+
return this.execute().then(onfulfilled, onrejected);
|
|
87
|
+
}
|
|
88
|
+
async execute() {
|
|
89
|
+
try {
|
|
90
|
+
const qs = this.params.toString();
|
|
91
|
+
const url = `${this.ctx.url}/rest/v1/${this.table}${qs ? `?${qs}` : ''}`;
|
|
92
|
+
const headers = { apikey: this.ctx.key };
|
|
93
|
+
const token = await this.ctx.accessToken();
|
|
94
|
+
if (token)
|
|
95
|
+
headers.authorization = `Bearer ${token}`;
|
|
96
|
+
if (this.wantCount)
|
|
97
|
+
headers.prefer = 'count=exact';
|
|
98
|
+
if (this.body !== undefined)
|
|
99
|
+
headers['content-type'] = 'application/json';
|
|
100
|
+
const res = await this.ctx.fetch(url, {
|
|
101
|
+
method: this.method,
|
|
102
|
+
headers,
|
|
103
|
+
body: this.body !== undefined ? JSON.stringify(this.body) : undefined,
|
|
104
|
+
});
|
|
105
|
+
if (!res.ok) {
|
|
106
|
+
const body = (await res.json().catch(() => ({})));
|
|
107
|
+
const msg = typeof body.message === 'string' ? body.message : `request failed (${res.status})`;
|
|
108
|
+
return { data: null, error: new ApiError(msg, res.status), count: null, status: res.status };
|
|
109
|
+
}
|
|
110
|
+
let count = null;
|
|
111
|
+
const range = res.headers.get('content-range');
|
|
112
|
+
if (range?.includes('/'))
|
|
113
|
+
count = Number(range.split('/')[1]) || 0;
|
|
114
|
+
let rows = (res.status === 204 ? [] : (await res.json())) ?? [];
|
|
115
|
+
if (!Array.isArray(rows))
|
|
116
|
+
rows = [rows];
|
|
117
|
+
if (this.takeSingle) {
|
|
118
|
+
const row = rows[0] ?? null;
|
|
119
|
+
if (this.takeSingle === 'strict' && !row) {
|
|
120
|
+
return { data: null, error: new ApiError('no rows returned', 406), count, status: res.status };
|
|
121
|
+
}
|
|
122
|
+
// .single() resolves an object, not an array — cast keeps the thenable type simple
|
|
123
|
+
return { data: row, error: null, count, status: res.status };
|
|
124
|
+
}
|
|
125
|
+
return { data: rows, error: null, count, status: res.status };
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
return { data: null, error: new ApiError(err.message, 0), count: null, status: 0 };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=query-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-builder.js","sourceRoot":"","sources":["../src/query-builder.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Shape of every data response — supabase-style: never throws, always
|
|
2
|
+
* `{ data, error }`. */
|
|
3
|
+
export interface ApiResult<T> {
|
|
4
|
+
data: T | null;
|
|
5
|
+
error: ApiError | null;
|
|
6
|
+
/** total row count — present when `count: 'exact'` was requested */
|
|
7
|
+
count: number | null;
|
|
8
|
+
status: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class ApiError extends Error {
|
|
11
|
+
status: number;
|
|
12
|
+
constructor(message: string, status: number);
|
|
13
|
+
}
|
|
14
|
+
export interface User {
|
|
15
|
+
id: string;
|
|
16
|
+
email: string;
|
|
17
|
+
user_metadata?: Record<string, unknown>;
|
|
18
|
+
created_at?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface Session {
|
|
21
|
+
access_token: string;
|
|
22
|
+
refresh_token: string;
|
|
23
|
+
token_type: 'bearer';
|
|
24
|
+
expires_in: number;
|
|
25
|
+
/** unix seconds — computed client-side when the session is stored */
|
|
26
|
+
expires_at?: number;
|
|
27
|
+
user: User;
|
|
28
|
+
}
|
|
29
|
+
export interface AuthResult {
|
|
30
|
+
data: {
|
|
31
|
+
user: User | null;
|
|
32
|
+
session: Session | null;
|
|
33
|
+
};
|
|
34
|
+
error: ApiError | null;
|
|
35
|
+
}
|
|
36
|
+
/** Pluggable persistence — localStorage in browsers (default), AsyncStorage in
|
|
37
|
+
* React Native, or anything with this shape. */
|
|
38
|
+
export interface StorageAdapter {
|
|
39
|
+
getItem(key: string): string | null | Promise<string | null>;
|
|
40
|
+
setItem(key: string, value: string): void | Promise<void>;
|
|
41
|
+
removeItem(key: string): void | Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
export interface ClientOptions {
|
|
44
|
+
/** custom fetch implementation (defaults to globalThis.fetch) */
|
|
45
|
+
fetch?: typeof fetch;
|
|
46
|
+
auth?: {
|
|
47
|
+
/** persist the session (default true) */
|
|
48
|
+
persistSession?: boolean;
|
|
49
|
+
/** where to persist it — pass AsyncStorage in React Native */
|
|
50
|
+
storage?: StorageAdapter;
|
|
51
|
+
/** storage key (default 'airostack.auth.token') */
|
|
52
|
+
storageKey?: string;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;yBACyB;AACzB,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,oEAAoE;IACpE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;gBACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAK5C;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,QAAQ,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE;QAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,CAAC;IACrD,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;CACxB;AAED;iDACiD;AACjD,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,IAAI,CAAC,EAAE;QACL,yCAAyC;QACzC,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,8DAA8D;QAC9D,OAAO,CAAC,EAAE,cAAc,CAAC;QACzB,mDAAmD;QACnD,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAUA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,MAAM,CAAS;IACf,YAAY,OAAe,EAAE,MAAc;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@airostack/client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Isomorphic client for AiroStack projects — Supabase-style Data API queries and Auth. Works in Node.js, browsers, and React Native.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/airoxlab/baseway.git",
|
|
9
|
+
"directory": "packages/client"
|
|
10
|
+
},
|
|
11
|
+
"keywords": ["airostack", "postgrest", "database", "auth", "baas", "react-native"],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": ["dist", "README.md"],
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -p tsconfig.build.json",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"clean": "rimraf dist .turbo",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typescript": "^5.7.2"
|
|
33
|
+
}
|
|
34
|
+
}
|