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 CHANGED
@@ -17,14 +17,37 @@ pnpm add @krisspy/sdk
17
17
  ## Quick Start
18
18
 
19
19
  ```typescript
20
- import { createClient } from '@krisspy/sdk'
20
+ import { createClient } from 'krisspy-sdk'
21
21
 
22
22
  const krisspy = createClient({
23
23
  backendId: 'your-backend-id',
24
- apiKey: 'your-api-key', // optional for public access
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
- apiKey: 'your-api-key', // For authenticated requests
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
- * When true, uses /rls/data/* endpoints which require app user authentication
24
- * and enforce row-level security policies.
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 useRLS;
824
- constructor(http: HttpClient, backendId: string, tableName: string, useRLS?: boolean);
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
- * Uses /rls/data for RLS-enabled queries (requires auth)
828
- * Uses /data for legacy queries (admin/owner only)
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 useRLS;
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
- * url: 'https://krisspy-cloud-backend.thankfulhill-66fc9e74.westeurope.azurecontainerapps.io', // optional
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
- * When true, uses /rls/data/* endpoints which require app user authentication
24
- * and enforce row-level security policies.
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 useRLS;
824
- constructor(http: HttpClient, backendId: string, tableName: string, useRLS?: boolean);
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
- * Uses /rls/data for RLS-enabled queries (requires auth)
828
- * Uses /data for legacy queries (admin/owner only)
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 useRLS;
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
- * url: 'https://krisspy-cloud-backend.thankfulhill-66fc9e74.westeurope.azurecontainerapps.io', // optional
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 if (result) {
290
- this.hydrateSession(result);
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, useRLS = true) {
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.useRLS = useRLS;
1484
+ this.dataMode = dataMode;
1468
1485
  }
1469
1486
  /**
1470
1487
  * Get the base path for data endpoints
1471
- * Uses /rls/data for RLS-enabled queries (requires auth)
1472
- * Uses /data for legacy queries (admin/owner only)
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
- if (this.useRLS) {
1476
- return `/api/v1/cloud-backends/${this.backendId}/rls/data/${this.tableName}`;
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 `/api/v1/cloud-backends/${this.backendId}/data/${this.tableName}`;
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.useRLS = options.useRLS !== false;
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: __spreadProps(__spreadValues({}, options.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.useRLS);
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 path = `/api/v1/cloud-backends/${this.backendId}/sql`;
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 if (result) {
256
- this.hydrateSession(result);
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, useRLS = true) {
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.useRLS = useRLS;
1450
+ this.dataMode = dataMode;
1434
1451
  }
1435
1452
  /**
1436
1453
  * Get the base path for data endpoints
1437
- * Uses /rls/data for RLS-enabled queries (requires auth)
1438
- * Uses /data for legacy queries (admin/owner only)
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
- if (this.useRLS) {
1442
- return `/api/v1/cloud-backends/${this.backendId}/rls/data/${this.tableName}`;
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 `/api/v1/cloud-backends/${this.backendId}/data/${this.tableName}`;
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.useRLS = options.useRLS !== false;
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: __spreadProps(__spreadValues({}, options.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.useRLS);
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 path = `/api/v1/cloud-backends/${this.backendId}/sql`;
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "krisspy-sdk",
3
- "version": "0.5.6",
3
+ "version": "0.7.0",
4
4
  "description": "Krisspy Cloud SDK - Database, Auth, Storage, and Functions for your apps",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",