krisspy-sdk 0.5.6 → 0.7.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 +30 -3
- package/dist/index.d.mts +53 -11
- package/dist/index.d.ts +53 -11
- package/dist/index.js +88 -15
- package/dist/index.mjs +88 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,14 +17,37 @@ pnpm add @krisspy/sdk
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
|
-
import { createClient } from '
|
|
20
|
+
import { createClient } from 'krisspy-sdk'
|
|
21
21
|
|
|
22
22
|
const krisspy = createClient({
|
|
23
23
|
backendId: 'your-backend-id',
|
|
24
|
-
apiKey: 'your-api-key',
|
|
24
|
+
apiKey: 'your-api-key',
|
|
25
25
|
})
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
### React Native / Expo
|
|
29
|
+
|
|
30
|
+
When using AsyncStorage, call `initialize()` before accessing auth state:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { createClient } from 'krisspy-sdk'
|
|
34
|
+
import AsyncStorage from '@react-native-async-storage/async-storage'
|
|
35
|
+
|
|
36
|
+
const krisspy = createClient({
|
|
37
|
+
backendId: 'your-backend-id',
|
|
38
|
+
apiKey: 'your-api-key',
|
|
39
|
+
storage: AsyncStorage,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Required — waits for cached session to load from AsyncStorage
|
|
43
|
+
await krisspy.initialize()
|
|
44
|
+
|
|
45
|
+
// Now safe to use
|
|
46
|
+
const user = krisspy.auth.user()
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
On web (localStorage is synchronous), `initialize()` resolves instantly — calling it is optional but harmless.
|
|
50
|
+
|
|
28
51
|
## Authentication
|
|
29
52
|
|
|
30
53
|
### Sign Up
|
|
@@ -227,15 +250,19 @@ console.log('Products:', data)
|
|
|
227
250
|
const krisspy = createClient({
|
|
228
251
|
// Required
|
|
229
252
|
backendId: 'your-backend-id',
|
|
253
|
+
apiKey: 'your-api-key',
|
|
230
254
|
|
|
231
255
|
// Optional
|
|
232
256
|
url: 'https://api.krisspy.ai', // Custom API URL
|
|
233
|
-
|
|
257
|
+
storage: AsyncStorage, // React Native: session persistence
|
|
234
258
|
headers: { // Custom headers
|
|
235
259
|
'X-Custom-Header': 'value'
|
|
236
260
|
},
|
|
237
261
|
debug: true, // Enable debug logging
|
|
238
262
|
})
|
|
263
|
+
|
|
264
|
+
// React Native only — wait for cached session
|
|
265
|
+
await krisspy.initialize()
|
|
239
266
|
```
|
|
240
267
|
|
|
241
268
|
## License
|
package/dist/index.d.mts
CHANGED
|
@@ -12,18 +12,30 @@ interface KrisspyClientOptions {
|
|
|
12
12
|
* Get it from your backend settings in the Krisspy dashboard.
|
|
13
13
|
*/
|
|
14
14
|
apiKey: string;
|
|
15
|
+
/**
|
|
16
|
+
* Service key for server-side access (bypasses RLS).
|
|
17
|
+
* NEVER expose this in frontend code. Use only in server-side code (Azure Functions, Node.js, etc.)
|
|
18
|
+
* When provided, uses /service/data/* endpoints which bypass row-level security.
|
|
19
|
+
*/
|
|
20
|
+
serviceKey?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Base URL of your Azure Function App.
|
|
23
|
+
* When set, functions.invoke() calls the Azure Function directly
|
|
24
|
+
* instead of going through the Krisspy backend.
|
|
25
|
+
*
|
|
26
|
+
* @example 'https://krisspy-kb-abc123.azurewebsites.net'
|
|
27
|
+
*/
|
|
28
|
+
functionsUrl?: string;
|
|
15
29
|
/** Custom headers to include in all requests */
|
|
16
30
|
headers?: Record<string, string>;
|
|
17
31
|
/** Enable debug logging */
|
|
18
32
|
debug?: boolean;
|
|
19
33
|
/**
|
|
20
34
|
* Use RLS (Row Level Security) endpoints for data access
|
|
21
|
-
* Default: true
|
|
35
|
+
* Default: true (uses /rls/data/* with apiKey)
|
|
22
36
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* When false, uses legacy /data/* endpoints which require backend owner auth.
|
|
37
|
+
* Automatically set to false when serviceKey is provided
|
|
38
|
+
* (uses /service/data/* which bypasses RLS).
|
|
27
39
|
*/
|
|
28
40
|
useRLS?: boolean;
|
|
29
41
|
/**
|
|
@@ -226,7 +238,16 @@ declare class KrisspyAuth {
|
|
|
226
238
|
private listeners;
|
|
227
239
|
private refreshInterval?;
|
|
228
240
|
private storage;
|
|
241
|
+
/** Resolves when session restoration is complete (including async storage) */
|
|
242
|
+
private _initialized;
|
|
243
|
+
private _resolveInit;
|
|
229
244
|
constructor(http: HttpClient, backendId: string, storage?: StorageAdapter);
|
|
245
|
+
/**
|
|
246
|
+
* Wait until session has been restored from storage.
|
|
247
|
+
* On web (localStorage), this resolves immediately.
|
|
248
|
+
* On React Native (AsyncStorage), this waits for the async read to complete.
|
|
249
|
+
*/
|
|
250
|
+
initialize(): Promise<void>;
|
|
230
251
|
/**
|
|
231
252
|
* Get current session from storage
|
|
232
253
|
*/
|
|
@@ -820,12 +841,13 @@ declare class QueryBuilder<T = any> {
|
|
|
820
841
|
private limitValue?;
|
|
821
842
|
private offsetValue?;
|
|
822
843
|
private isSingle;
|
|
823
|
-
private
|
|
824
|
-
constructor(http: HttpClient, backendId: string, tableName: string,
|
|
844
|
+
private dataMode;
|
|
845
|
+
constructor(http: HttpClient, backendId: string, tableName: string, dataMode?: 'rls' | 'service' | 'legacy');
|
|
825
846
|
/**
|
|
826
847
|
* Get the base path for data endpoints
|
|
827
|
-
*
|
|
828
|
-
*
|
|
848
|
+
* - rls: /rls/data (requires apiKey + optional JWT, enforces RLS)
|
|
849
|
+
* - service: /service/data (requires serviceKey, bypasses RLS)
|
|
850
|
+
* - legacy: /data (requires backend owner auth)
|
|
829
851
|
*/
|
|
830
852
|
private getBasePath;
|
|
831
853
|
/**
|
|
@@ -954,13 +976,25 @@ declare class KrisspyClient {
|
|
|
954
976
|
private http;
|
|
955
977
|
private backendId;
|
|
956
978
|
private baseUrl;
|
|
979
|
+
private functionsUrl;
|
|
957
980
|
private _auth;
|
|
958
981
|
private _storage;
|
|
959
982
|
private _realtime;
|
|
960
983
|
private _analytics;
|
|
961
|
-
private
|
|
984
|
+
private dataMode;
|
|
962
985
|
private debug;
|
|
963
986
|
constructor(options: KrisspyClientOptions);
|
|
987
|
+
/**
|
|
988
|
+
* Wait until the client is fully initialized (session restored from storage).
|
|
989
|
+
* **Required on React Native / Expo** when using AsyncStorage.
|
|
990
|
+
* On web (localStorage), this resolves instantly.
|
|
991
|
+
*
|
|
992
|
+
* @example
|
|
993
|
+
* const krisspy = createClient({ backendId: '...', apiKey: '...' });
|
|
994
|
+
* await krisspy.initialize(); // wait for cached session to load
|
|
995
|
+
* const user = krisspy.auth.user(); // now safe to use
|
|
996
|
+
*/
|
|
997
|
+
initialize(): Promise<void>;
|
|
964
998
|
/**
|
|
965
999
|
* Auth module for user authentication
|
|
966
1000
|
*
|
|
@@ -1199,11 +1233,19 @@ declare class KrisspyClient {
|
|
|
1199
1233
|
* @returns KrisspyClient instance
|
|
1200
1234
|
*
|
|
1201
1235
|
* @example
|
|
1236
|
+
* // Web (localStorage is sync — works immediately)
|
|
1237
|
+
* const krisspy = createClient({
|
|
1238
|
+
* backendId: 'abc123',
|
|
1239
|
+
* apiKey: 'your-api-key',
|
|
1240
|
+
* })
|
|
1241
|
+
*
|
|
1242
|
+
* // React Native / Expo (AsyncStorage is async — call initialize())
|
|
1202
1243
|
* const krisspy = createClient({
|
|
1203
1244
|
* backendId: 'abc123',
|
|
1204
1245
|
* apiKey: 'your-api-key',
|
|
1205
|
-
*
|
|
1246
|
+
* storage: AsyncStorage,
|
|
1206
1247
|
* })
|
|
1248
|
+
* await krisspy.initialize() // wait for cached session to load
|
|
1207
1249
|
*/
|
|
1208
1250
|
declare function createClient(options: KrisspyClientOptions): KrisspyClient;
|
|
1209
1251
|
|
package/dist/index.d.ts
CHANGED
|
@@ -12,18 +12,30 @@ interface KrisspyClientOptions {
|
|
|
12
12
|
* Get it from your backend settings in the Krisspy dashboard.
|
|
13
13
|
*/
|
|
14
14
|
apiKey: string;
|
|
15
|
+
/**
|
|
16
|
+
* Service key for server-side access (bypasses RLS).
|
|
17
|
+
* NEVER expose this in frontend code. Use only in server-side code (Azure Functions, Node.js, etc.)
|
|
18
|
+
* When provided, uses /service/data/* endpoints which bypass row-level security.
|
|
19
|
+
*/
|
|
20
|
+
serviceKey?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Base URL of your Azure Function App.
|
|
23
|
+
* When set, functions.invoke() calls the Azure Function directly
|
|
24
|
+
* instead of going through the Krisspy backend.
|
|
25
|
+
*
|
|
26
|
+
* @example 'https://krisspy-kb-abc123.azurewebsites.net'
|
|
27
|
+
*/
|
|
28
|
+
functionsUrl?: string;
|
|
15
29
|
/** Custom headers to include in all requests */
|
|
16
30
|
headers?: Record<string, string>;
|
|
17
31
|
/** Enable debug logging */
|
|
18
32
|
debug?: boolean;
|
|
19
33
|
/**
|
|
20
34
|
* Use RLS (Row Level Security) endpoints for data access
|
|
21
|
-
* Default: true
|
|
35
|
+
* Default: true (uses /rls/data/* with apiKey)
|
|
22
36
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* When false, uses legacy /data/* endpoints which require backend owner auth.
|
|
37
|
+
* Automatically set to false when serviceKey is provided
|
|
38
|
+
* (uses /service/data/* which bypasses RLS).
|
|
27
39
|
*/
|
|
28
40
|
useRLS?: boolean;
|
|
29
41
|
/**
|
|
@@ -226,7 +238,16 @@ declare class KrisspyAuth {
|
|
|
226
238
|
private listeners;
|
|
227
239
|
private refreshInterval?;
|
|
228
240
|
private storage;
|
|
241
|
+
/** Resolves when session restoration is complete (including async storage) */
|
|
242
|
+
private _initialized;
|
|
243
|
+
private _resolveInit;
|
|
229
244
|
constructor(http: HttpClient, backendId: string, storage?: StorageAdapter);
|
|
245
|
+
/**
|
|
246
|
+
* Wait until session has been restored from storage.
|
|
247
|
+
* On web (localStorage), this resolves immediately.
|
|
248
|
+
* On React Native (AsyncStorage), this waits for the async read to complete.
|
|
249
|
+
*/
|
|
250
|
+
initialize(): Promise<void>;
|
|
230
251
|
/**
|
|
231
252
|
* Get current session from storage
|
|
232
253
|
*/
|
|
@@ -820,12 +841,13 @@ declare class QueryBuilder<T = any> {
|
|
|
820
841
|
private limitValue?;
|
|
821
842
|
private offsetValue?;
|
|
822
843
|
private isSingle;
|
|
823
|
-
private
|
|
824
|
-
constructor(http: HttpClient, backendId: string, tableName: string,
|
|
844
|
+
private dataMode;
|
|
845
|
+
constructor(http: HttpClient, backendId: string, tableName: string, dataMode?: 'rls' | 'service' | 'legacy');
|
|
825
846
|
/**
|
|
826
847
|
* Get the base path for data endpoints
|
|
827
|
-
*
|
|
828
|
-
*
|
|
848
|
+
* - rls: /rls/data (requires apiKey + optional JWT, enforces RLS)
|
|
849
|
+
* - service: /service/data (requires serviceKey, bypasses RLS)
|
|
850
|
+
* - legacy: /data (requires backend owner auth)
|
|
829
851
|
*/
|
|
830
852
|
private getBasePath;
|
|
831
853
|
/**
|
|
@@ -954,13 +976,25 @@ declare class KrisspyClient {
|
|
|
954
976
|
private http;
|
|
955
977
|
private backendId;
|
|
956
978
|
private baseUrl;
|
|
979
|
+
private functionsUrl;
|
|
957
980
|
private _auth;
|
|
958
981
|
private _storage;
|
|
959
982
|
private _realtime;
|
|
960
983
|
private _analytics;
|
|
961
|
-
private
|
|
984
|
+
private dataMode;
|
|
962
985
|
private debug;
|
|
963
986
|
constructor(options: KrisspyClientOptions);
|
|
987
|
+
/**
|
|
988
|
+
* Wait until the client is fully initialized (session restored from storage).
|
|
989
|
+
* **Required on React Native / Expo** when using AsyncStorage.
|
|
990
|
+
* On web (localStorage), this resolves instantly.
|
|
991
|
+
*
|
|
992
|
+
* @example
|
|
993
|
+
* const krisspy = createClient({ backendId: '...', apiKey: '...' });
|
|
994
|
+
* await krisspy.initialize(); // wait for cached session to load
|
|
995
|
+
* const user = krisspy.auth.user(); // now safe to use
|
|
996
|
+
*/
|
|
997
|
+
initialize(): Promise<void>;
|
|
964
998
|
/**
|
|
965
999
|
* Auth module for user authentication
|
|
966
1000
|
*
|
|
@@ -1199,11 +1233,19 @@ declare class KrisspyClient {
|
|
|
1199
1233
|
* @returns KrisspyClient instance
|
|
1200
1234
|
*
|
|
1201
1235
|
* @example
|
|
1236
|
+
* // Web (localStorage is sync — works immediately)
|
|
1237
|
+
* const krisspy = createClient({
|
|
1238
|
+
* backendId: 'abc123',
|
|
1239
|
+
* apiKey: 'your-api-key',
|
|
1240
|
+
* })
|
|
1241
|
+
*
|
|
1242
|
+
* // React Native / Expo (AsyncStorage is async — call initialize())
|
|
1202
1243
|
* const krisspy = createClient({
|
|
1203
1244
|
* backendId: 'abc123',
|
|
1204
1245
|
* apiKey: 'your-api-key',
|
|
1205
|
-
*
|
|
1246
|
+
* storage: AsyncStorage,
|
|
1206
1247
|
* })
|
|
1248
|
+
* await krisspy.initialize() // wait for cached session to load
|
|
1207
1249
|
*/
|
|
1208
1250
|
declare function createClient(options: KrisspyClientOptions): KrisspyClient;
|
|
1209
1251
|
|
package/dist/index.js
CHANGED
|
@@ -273,8 +273,19 @@ var KrisspyAuth = class {
|
|
|
273
273
|
this.http = http;
|
|
274
274
|
this.backendId = backendId;
|
|
275
275
|
this.storage = resolveStorage(storage);
|
|
276
|
+
this._initialized = new Promise((resolve) => {
|
|
277
|
+
this._resolveInit = resolve;
|
|
278
|
+
});
|
|
276
279
|
this.restoreSession();
|
|
277
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Wait until session has been restored from storage.
|
|
283
|
+
* On web (localStorage), this resolves immediately.
|
|
284
|
+
* On React Native (AsyncStorage), this waits for the async read to complete.
|
|
285
|
+
*/
|
|
286
|
+
async initialize() {
|
|
287
|
+
return this._initialized;
|
|
288
|
+
}
|
|
278
289
|
/**
|
|
279
290
|
* Get current session from storage
|
|
280
291
|
*/
|
|
@@ -285,12 +296,18 @@ var KrisspyAuth = class {
|
|
|
285
296
|
result.then((stored) => {
|
|
286
297
|
if (stored) this.hydrateSession(stored);
|
|
287
298
|
}).catch(() => {
|
|
299
|
+
}).finally(() => {
|
|
300
|
+
this._resolveInit();
|
|
288
301
|
});
|
|
289
|
-
} else
|
|
290
|
-
|
|
302
|
+
} else {
|
|
303
|
+
if (result) {
|
|
304
|
+
this.hydrateSession(result);
|
|
305
|
+
}
|
|
306
|
+
this._resolveInit();
|
|
291
307
|
}
|
|
292
308
|
} catch (err) {
|
|
293
309
|
console.warn("[Krisspy Auth] Failed to restore session:", err);
|
|
310
|
+
this._resolveInit();
|
|
294
311
|
}
|
|
295
312
|
}
|
|
296
313
|
hydrateSession(stored) {
|
|
@@ -1456,7 +1473,7 @@ var KrisspyAnalytics = class {
|
|
|
1456
1473
|
|
|
1457
1474
|
// src/query-builder.ts
|
|
1458
1475
|
var QueryBuilder = class {
|
|
1459
|
-
constructor(http, backendId, tableName,
|
|
1476
|
+
constructor(http, backendId, tableName, dataMode = "rls") {
|
|
1460
1477
|
this.queryParams = {};
|
|
1461
1478
|
this.selectColumns = [];
|
|
1462
1479
|
this.orderClauses = [];
|
|
@@ -1464,18 +1481,23 @@ var QueryBuilder = class {
|
|
|
1464
1481
|
this.http = http;
|
|
1465
1482
|
this.backendId = backendId;
|
|
1466
1483
|
this.tableName = tableName;
|
|
1467
|
-
this.
|
|
1484
|
+
this.dataMode = dataMode;
|
|
1468
1485
|
}
|
|
1469
1486
|
/**
|
|
1470
1487
|
* Get the base path for data endpoints
|
|
1471
|
-
*
|
|
1472
|
-
*
|
|
1488
|
+
* - rls: /rls/data (requires apiKey + optional JWT, enforces RLS)
|
|
1489
|
+
* - service: /service/data (requires serviceKey, bypasses RLS)
|
|
1490
|
+
* - legacy: /data (requires backend owner auth)
|
|
1473
1491
|
*/
|
|
1474
1492
|
getBasePath() {
|
|
1475
|
-
|
|
1476
|
-
|
|
1493
|
+
const base = `/api/v1/cloud-backends/${this.backendId}`;
|
|
1494
|
+
if (this.dataMode === "service") {
|
|
1495
|
+
return `${base}/service/data/${this.tableName}`;
|
|
1496
|
+
}
|
|
1497
|
+
if (this.dataMode === "legacy") {
|
|
1498
|
+
return `${base}/data/${this.tableName}`;
|
|
1477
1499
|
}
|
|
1478
|
-
return
|
|
1500
|
+
return `${base}/rls/data/${this.tableName}`;
|
|
1479
1501
|
}
|
|
1480
1502
|
/**
|
|
1481
1503
|
* Select specific columns
|
|
@@ -1737,15 +1759,27 @@ var QueryBuilder = class {
|
|
|
1737
1759
|
// src/client.ts
|
|
1738
1760
|
var KrisspyClient = class {
|
|
1739
1761
|
constructor(options) {
|
|
1762
|
+
var _a;
|
|
1740
1763
|
this.baseUrl = options.url || "https://krisspy-cloud-backend.thankfulhill-66fc9e74.westeurope.azurecontainerapps.io";
|
|
1741
1764
|
this.backendId = options.backendId;
|
|
1742
1765
|
this.debug = options.debug || false;
|
|
1743
|
-
this.
|
|
1766
|
+
this.functionsUrl = ((_a = options.functionsUrl) == null ? void 0 : _a.replace(/\/$/, "")) || null;
|
|
1767
|
+
if (options.serviceKey) {
|
|
1768
|
+
this.dataMode = "service";
|
|
1769
|
+
} else if (options.useRLS === false) {
|
|
1770
|
+
this.dataMode = "legacy";
|
|
1771
|
+
} else {
|
|
1772
|
+
this.dataMode = "rls";
|
|
1773
|
+
}
|
|
1774
|
+
const keyHeaders = {
|
|
1775
|
+
"apikey": options.apiKey
|
|
1776
|
+
};
|
|
1777
|
+
if (options.serviceKey) {
|
|
1778
|
+
keyHeaders["servicekey"] = options.serviceKey;
|
|
1779
|
+
}
|
|
1744
1780
|
this.http = new HttpClient({
|
|
1745
1781
|
baseUrl: this.baseUrl,
|
|
1746
|
-
headers:
|
|
1747
|
-
"apikey": options.apiKey
|
|
1748
|
-
}),
|
|
1782
|
+
headers: __spreadValues(__spreadValues({}, options.headers), keyHeaders),
|
|
1749
1783
|
debug: options.debug
|
|
1750
1784
|
});
|
|
1751
1785
|
this._auth = new KrisspyAuth(this.http, this.backendId, options.storage);
|
|
@@ -1763,6 +1797,19 @@ var KrisspyClient = class {
|
|
|
1763
1797
|
}
|
|
1764
1798
|
});
|
|
1765
1799
|
}
|
|
1800
|
+
/**
|
|
1801
|
+
* Wait until the client is fully initialized (session restored from storage).
|
|
1802
|
+
* **Required on React Native / Expo** when using AsyncStorage.
|
|
1803
|
+
* On web (localStorage), this resolves instantly.
|
|
1804
|
+
*
|
|
1805
|
+
* @example
|
|
1806
|
+
* const krisspy = createClient({ backendId: '...', apiKey: '...' });
|
|
1807
|
+
* await krisspy.initialize(); // wait for cached session to load
|
|
1808
|
+
* const user = krisspy.auth.user(); // now safe to use
|
|
1809
|
+
*/
|
|
1810
|
+
async initialize() {
|
|
1811
|
+
await this._auth.initialize();
|
|
1812
|
+
}
|
|
1766
1813
|
/**
|
|
1767
1814
|
* Auth module for user authentication
|
|
1768
1815
|
*
|
|
@@ -1913,7 +1960,7 @@ var KrisspyClient = class {
|
|
|
1913
1960
|
* .eq('id', 123)
|
|
1914
1961
|
*/
|
|
1915
1962
|
from(table) {
|
|
1916
|
-
return new QueryBuilder(this.http, this.backendId, table, this.
|
|
1963
|
+
return new QueryBuilder(this.http, this.backendId, table, this.dataMode);
|
|
1917
1964
|
}
|
|
1918
1965
|
/**
|
|
1919
1966
|
* Execute raw SQL query
|
|
@@ -1923,7 +1970,8 @@ var KrisspyClient = class {
|
|
|
1923
1970
|
*/
|
|
1924
1971
|
async rpc(sql, params) {
|
|
1925
1972
|
var _a, _b;
|
|
1926
|
-
const
|
|
1973
|
+
const suffix = this.dataMode === "service" ? "/service/sql" : "/sql";
|
|
1974
|
+
const path = `/api/v1/cloud-backends/${this.backendId}${suffix}`;
|
|
1927
1975
|
const response = await this.http.post(path, { sql, params });
|
|
1928
1976
|
if (response.error) {
|
|
1929
1977
|
return { data: null, error: response.error };
|
|
@@ -1941,6 +1989,31 @@ var KrisspyClient = class {
|
|
|
1941
1989
|
get functions() {
|
|
1942
1990
|
return {
|
|
1943
1991
|
invoke: async (functionName, options) => {
|
|
1992
|
+
if (this.functionsUrl) {
|
|
1993
|
+
const url = `${this.functionsUrl}/api/${functionName}`;
|
|
1994
|
+
try {
|
|
1995
|
+
const res = await fetch(url, {
|
|
1996
|
+
method: "POST",
|
|
1997
|
+
headers: __spreadValues({
|
|
1998
|
+
"Content-Type": "application/json"
|
|
1999
|
+
}, options == null ? void 0 : options.headers),
|
|
2000
|
+
body: (options == null ? void 0 : options.body) ? JSON.stringify(options.body) : void 0
|
|
2001
|
+
});
|
|
2002
|
+
const contentType = res.headers.get("content-type");
|
|
2003
|
+
let data = null;
|
|
2004
|
+
if (contentType == null ? void 0 : contentType.includes("application/json")) {
|
|
2005
|
+
data = await res.json();
|
|
2006
|
+
} else {
|
|
2007
|
+
data = await res.text();
|
|
2008
|
+
}
|
|
2009
|
+
if (!res.ok) {
|
|
2010
|
+
return { data: null, error: { message: (data == null ? void 0 : data.error) || (data == null ? void 0 : data.message) || `Request failed with status ${res.status}`, status: res.status } };
|
|
2011
|
+
}
|
|
2012
|
+
return { data, error: null };
|
|
2013
|
+
} catch (err) {
|
|
2014
|
+
return { data: null, error: { message: err.message || "Network error", code: "NETWORK_ERROR", status: 0 } };
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
1944
2017
|
const path = `/api/v1/cloud-backends/${this.backendId}/functions/${functionName}/invoke`;
|
|
1945
2018
|
const response = await this.http.post(path, options == null ? void 0 : options.body, void 0);
|
|
1946
2019
|
if (response.error) {
|
package/dist/index.mjs
CHANGED
|
@@ -239,8 +239,19 @@ var KrisspyAuth = class {
|
|
|
239
239
|
this.http = http;
|
|
240
240
|
this.backendId = backendId;
|
|
241
241
|
this.storage = resolveStorage(storage);
|
|
242
|
+
this._initialized = new Promise((resolve) => {
|
|
243
|
+
this._resolveInit = resolve;
|
|
244
|
+
});
|
|
242
245
|
this.restoreSession();
|
|
243
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Wait until session has been restored from storage.
|
|
249
|
+
* On web (localStorage), this resolves immediately.
|
|
250
|
+
* On React Native (AsyncStorage), this waits for the async read to complete.
|
|
251
|
+
*/
|
|
252
|
+
async initialize() {
|
|
253
|
+
return this._initialized;
|
|
254
|
+
}
|
|
244
255
|
/**
|
|
245
256
|
* Get current session from storage
|
|
246
257
|
*/
|
|
@@ -251,12 +262,18 @@ var KrisspyAuth = class {
|
|
|
251
262
|
result.then((stored) => {
|
|
252
263
|
if (stored) this.hydrateSession(stored);
|
|
253
264
|
}).catch(() => {
|
|
265
|
+
}).finally(() => {
|
|
266
|
+
this._resolveInit();
|
|
254
267
|
});
|
|
255
|
-
} else
|
|
256
|
-
|
|
268
|
+
} else {
|
|
269
|
+
if (result) {
|
|
270
|
+
this.hydrateSession(result);
|
|
271
|
+
}
|
|
272
|
+
this._resolveInit();
|
|
257
273
|
}
|
|
258
274
|
} catch (err) {
|
|
259
275
|
console.warn("[Krisspy Auth] Failed to restore session:", err);
|
|
276
|
+
this._resolveInit();
|
|
260
277
|
}
|
|
261
278
|
}
|
|
262
279
|
hydrateSession(stored) {
|
|
@@ -1422,7 +1439,7 @@ var KrisspyAnalytics = class {
|
|
|
1422
1439
|
|
|
1423
1440
|
// src/query-builder.ts
|
|
1424
1441
|
var QueryBuilder = class {
|
|
1425
|
-
constructor(http, backendId, tableName,
|
|
1442
|
+
constructor(http, backendId, tableName, dataMode = "rls") {
|
|
1426
1443
|
this.queryParams = {};
|
|
1427
1444
|
this.selectColumns = [];
|
|
1428
1445
|
this.orderClauses = [];
|
|
@@ -1430,18 +1447,23 @@ var QueryBuilder = class {
|
|
|
1430
1447
|
this.http = http;
|
|
1431
1448
|
this.backendId = backendId;
|
|
1432
1449
|
this.tableName = tableName;
|
|
1433
|
-
this.
|
|
1450
|
+
this.dataMode = dataMode;
|
|
1434
1451
|
}
|
|
1435
1452
|
/**
|
|
1436
1453
|
* Get the base path for data endpoints
|
|
1437
|
-
*
|
|
1438
|
-
*
|
|
1454
|
+
* - rls: /rls/data (requires apiKey + optional JWT, enforces RLS)
|
|
1455
|
+
* - service: /service/data (requires serviceKey, bypasses RLS)
|
|
1456
|
+
* - legacy: /data (requires backend owner auth)
|
|
1439
1457
|
*/
|
|
1440
1458
|
getBasePath() {
|
|
1441
|
-
|
|
1442
|
-
|
|
1459
|
+
const base = `/api/v1/cloud-backends/${this.backendId}`;
|
|
1460
|
+
if (this.dataMode === "service") {
|
|
1461
|
+
return `${base}/service/data/${this.tableName}`;
|
|
1462
|
+
}
|
|
1463
|
+
if (this.dataMode === "legacy") {
|
|
1464
|
+
return `${base}/data/${this.tableName}`;
|
|
1443
1465
|
}
|
|
1444
|
-
return
|
|
1466
|
+
return `${base}/rls/data/${this.tableName}`;
|
|
1445
1467
|
}
|
|
1446
1468
|
/**
|
|
1447
1469
|
* Select specific columns
|
|
@@ -1703,15 +1725,27 @@ var QueryBuilder = class {
|
|
|
1703
1725
|
// src/client.ts
|
|
1704
1726
|
var KrisspyClient = class {
|
|
1705
1727
|
constructor(options) {
|
|
1728
|
+
var _a;
|
|
1706
1729
|
this.baseUrl = options.url || "https://krisspy-cloud-backend.thankfulhill-66fc9e74.westeurope.azurecontainerapps.io";
|
|
1707
1730
|
this.backendId = options.backendId;
|
|
1708
1731
|
this.debug = options.debug || false;
|
|
1709
|
-
this.
|
|
1732
|
+
this.functionsUrl = ((_a = options.functionsUrl) == null ? void 0 : _a.replace(/\/$/, "")) || null;
|
|
1733
|
+
if (options.serviceKey) {
|
|
1734
|
+
this.dataMode = "service";
|
|
1735
|
+
} else if (options.useRLS === false) {
|
|
1736
|
+
this.dataMode = "legacy";
|
|
1737
|
+
} else {
|
|
1738
|
+
this.dataMode = "rls";
|
|
1739
|
+
}
|
|
1740
|
+
const keyHeaders = {
|
|
1741
|
+
"apikey": options.apiKey
|
|
1742
|
+
};
|
|
1743
|
+
if (options.serviceKey) {
|
|
1744
|
+
keyHeaders["servicekey"] = options.serviceKey;
|
|
1745
|
+
}
|
|
1710
1746
|
this.http = new HttpClient({
|
|
1711
1747
|
baseUrl: this.baseUrl,
|
|
1712
|
-
headers:
|
|
1713
|
-
"apikey": options.apiKey
|
|
1714
|
-
}),
|
|
1748
|
+
headers: __spreadValues(__spreadValues({}, options.headers), keyHeaders),
|
|
1715
1749
|
debug: options.debug
|
|
1716
1750
|
});
|
|
1717
1751
|
this._auth = new KrisspyAuth(this.http, this.backendId, options.storage);
|
|
@@ -1729,6 +1763,19 @@ var KrisspyClient = class {
|
|
|
1729
1763
|
}
|
|
1730
1764
|
});
|
|
1731
1765
|
}
|
|
1766
|
+
/**
|
|
1767
|
+
* Wait until the client is fully initialized (session restored from storage).
|
|
1768
|
+
* **Required on React Native / Expo** when using AsyncStorage.
|
|
1769
|
+
* On web (localStorage), this resolves instantly.
|
|
1770
|
+
*
|
|
1771
|
+
* @example
|
|
1772
|
+
* const krisspy = createClient({ backendId: '...', apiKey: '...' });
|
|
1773
|
+
* await krisspy.initialize(); // wait for cached session to load
|
|
1774
|
+
* const user = krisspy.auth.user(); // now safe to use
|
|
1775
|
+
*/
|
|
1776
|
+
async initialize() {
|
|
1777
|
+
await this._auth.initialize();
|
|
1778
|
+
}
|
|
1732
1779
|
/**
|
|
1733
1780
|
* Auth module for user authentication
|
|
1734
1781
|
*
|
|
@@ -1879,7 +1926,7 @@ var KrisspyClient = class {
|
|
|
1879
1926
|
* .eq('id', 123)
|
|
1880
1927
|
*/
|
|
1881
1928
|
from(table) {
|
|
1882
|
-
return new QueryBuilder(this.http, this.backendId, table, this.
|
|
1929
|
+
return new QueryBuilder(this.http, this.backendId, table, this.dataMode);
|
|
1883
1930
|
}
|
|
1884
1931
|
/**
|
|
1885
1932
|
* Execute raw SQL query
|
|
@@ -1889,7 +1936,8 @@ var KrisspyClient = class {
|
|
|
1889
1936
|
*/
|
|
1890
1937
|
async rpc(sql, params) {
|
|
1891
1938
|
var _a, _b;
|
|
1892
|
-
const
|
|
1939
|
+
const suffix = this.dataMode === "service" ? "/service/sql" : "/sql";
|
|
1940
|
+
const path = `/api/v1/cloud-backends/${this.backendId}${suffix}`;
|
|
1893
1941
|
const response = await this.http.post(path, { sql, params });
|
|
1894
1942
|
if (response.error) {
|
|
1895
1943
|
return { data: null, error: response.error };
|
|
@@ -1907,6 +1955,31 @@ var KrisspyClient = class {
|
|
|
1907
1955
|
get functions() {
|
|
1908
1956
|
return {
|
|
1909
1957
|
invoke: async (functionName, options) => {
|
|
1958
|
+
if (this.functionsUrl) {
|
|
1959
|
+
const url = `${this.functionsUrl}/api/${functionName}`;
|
|
1960
|
+
try {
|
|
1961
|
+
const res = await fetch(url, {
|
|
1962
|
+
method: "POST",
|
|
1963
|
+
headers: __spreadValues({
|
|
1964
|
+
"Content-Type": "application/json"
|
|
1965
|
+
}, options == null ? void 0 : options.headers),
|
|
1966
|
+
body: (options == null ? void 0 : options.body) ? JSON.stringify(options.body) : void 0
|
|
1967
|
+
});
|
|
1968
|
+
const contentType = res.headers.get("content-type");
|
|
1969
|
+
let data = null;
|
|
1970
|
+
if (contentType == null ? void 0 : contentType.includes("application/json")) {
|
|
1971
|
+
data = await res.json();
|
|
1972
|
+
} else {
|
|
1973
|
+
data = await res.text();
|
|
1974
|
+
}
|
|
1975
|
+
if (!res.ok) {
|
|
1976
|
+
return { data: null, error: { message: (data == null ? void 0 : data.error) || (data == null ? void 0 : data.message) || `Request failed with status ${res.status}`, status: res.status } };
|
|
1977
|
+
}
|
|
1978
|
+
return { data, error: null };
|
|
1979
|
+
} catch (err) {
|
|
1980
|
+
return { data: null, error: { message: err.message || "Network error", code: "NETWORK_ERROR", status: 0 } };
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1910
1983
|
const path = `/api/v1/cloud-backends/${this.backendId}/functions/${functionName}/invoke`;
|
|
1911
1984
|
const response = await this.http.post(path, options == null ? void 0 : options.body, void 0);
|
|
1912
1985
|
if (response.error) {
|