@techfinityedge/koolbase-react-native 1.9.0 → 1.10.1

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
@@ -12,15 +12,13 @@ Auth, database, storage, realtime, functions, feature flags, remote config, vers
12
12
  ## Get started in 2 minutes
13
13
 
14
14
  1. Create a free account at [app.koolbase.com](https://app.koolbase.com)
15
-
16
15
  2. Create a project and copy your public key from Environments
17
-
18
16
  3. Add the SDK:
19
17
 
20
18
  ```bash
21
- npm install @techfinityedge/koolbase-react-native@^1.8.0
19
+ npm install @techfinityedge/koolbase-react-native@^1.10.0
22
20
  # or
23
- yarn add @techfinityedge/koolbase-react-native@^1.8.0
21
+ yarn add @techfinityedge/koolbase-react-native@^1.10.0
24
22
  ```
25
23
 
26
24
  **4. Initialize at app startup:**
@@ -40,7 +38,7 @@ That's it. Every feature below is now available via `Koolbase.*`.
40
38
 
41
39
  ## Authentication
42
40
 
43
- Email + password, Google, Apple, and phone + OTP — out of the box.
41
+ Email + password, Apple Sign-In, and phone + OTP — out of the box.
44
42
 
45
43
  ```typescript
46
44
  // Register
@@ -57,30 +55,41 @@ await Koolbase.auth.logout();
57
55
 
58
56
  // Password reset
59
57
  await Koolbase.auth.forgotPassword('user@example.com');
58
+
59
+ // Listen to auth state changes (fires immediately with current state)
60
+ const unsubscribe = Koolbase.auth.onAuthStateChange((user) => {
61
+ console.log(user ? 'signed in' : 'signed out');
62
+ });
60
63
  ```
61
64
 
62
- ### OAuth — Google & Apple
65
+ ### OAuth — Apple
66
+
67
+ Apple Sign-In uses the native authentication flow via `@invertase/react-native-apple-authentication` as a peer dependency:
63
68
 
64
69
  ```typescript
65
- // Google
66
- await Koolbase.auth.signInWithGoogle({ idToken: googleIdToken });
67
- ```
70
+ import appleAuth from '@invertase/react-native-apple-authentication';
71
+ import { Koolbase } from '@techfinityedge/koolbase-react-native';
68
72
 
69
- Apple uses the native authentication flow via `@invertase/react-native-apple-authentication` as a peer dependency:
73
+ const response = await appleAuth.performRequest({
74
+ requestedOperation: appleAuth.Operation.LOGIN,
75
+ requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
76
+ });
70
77
 
71
- ```typescript
72
- import { KoolbaseAppleAuth } from '@techfinityedge/koolbase-react-native';
73
- import { appleAuth } from '@invertase/react-native-apple-authentication';
74
-
75
- const session = await KoolbaseAppleAuth.signIn(async () => {
76
- return await appleAuth.performRequest({
77
- requestedOperation: appleAuth.Operation.LOGIN,
78
- requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
79
- });
78
+ const session = await Koolbase.auth.signInWithApple({
79
+ identityToken: response.identityToken!,
80
+ nonce: response.nonce,
81
+ fullName: response.fullName
82
+ ? {
83
+ givenName: response.fullName.givenName ?? undefined,
84
+ familyName: response.fullName.familyName ?? undefined,
85
+ }
86
+ : undefined,
80
87
  });
81
88
  ```
82
89
 
83
- Full setup guide at [docs.koolbase.com/auth/oauth](https://docs.koolbase.com/auth/oauth).
90
+ Before users can sign in, configure Apple Sign-In for your environment with your iOS app's Bundle ID. Full setup guide at [docs.koolbase.com/auth/oauth](https://docs.koolbase.com/auth/oauth).
91
+
92
+ > **Google Sign-In** — coming in v1.11.0.
84
93
 
85
94
  ### Phone + OTP
86
95
 
@@ -150,6 +159,7 @@ const { url } = await Koolbase.storage.upload({
150
159
  });
151
160
 
152
161
  const downloadUrl = await Koolbase.storage.getDownloadUrl('avatars', `user-${userId}.jpg`);
162
+
153
163
  await Koolbase.storage.delete('avatars', `user-${userId}.jpg`);
154
164
  ```
155
165
 
@@ -177,11 +187,10 @@ Invoke deployed serverless functions. When a user is signed in via `Koolbase.aut
177
187
  const result = await Koolbase.functions.invoke('send-welcome-email', {
178
188
  userId: '123',
179
189
  });
180
-
181
190
  if (result.success) console.log(result.data);
182
191
  ```
183
192
 
184
- Inside the function (Deno runtime), read the caller:
193
+ Inside the function, read the caller:
185
194
 
186
195
  ```typescript
187
196
  export async function handler(ctx) {
@@ -325,20 +334,18 @@ await Koolbase.messaging.send({
325
334
 
326
335
  ## What's included
327
336
 
328
- | Feature | Koolbase | Firebase | Supabase |
329
- | --- | --- | --- | --- |
330
- | TypeScript SDK | Yes | Yes | Yes |
331
- | Feature flags | Yes | — | — |
332
- | Remote config | Yes | Yes | — |
333
- | Version enforcement | Yes | — | — |
334
- | Offline-first database | Yes | Yes | — |
335
- | Code push | Yes | | |
336
- | Logic engine (flows OTA) | Yes | — | — |
337
- | Analytics | Yes | Yes | — |
338
- | Cloud Messaging | Yes | Yes | — |
339
- | Sign in with Apple | Yes | Yes | Yes |
340
- | Phone + OTP | Yes | Yes | Yes |
341
- | Authenticated functions (`ctx.auth`) | Yes | Yes | Yes |
337
+ - Authentication: email + password, Apple Sign-In, phone + OTP
338
+ - Database with offline-first cache, realtime subscriptions, and populate
339
+ - Storage with download URLs
340
+ - Realtime subscriptions over WebSocket
341
+ - Authenticated functions (`ctx.auth` exposes the caller automatically)
342
+ - Feature flags and remote config
343
+ - Version enforcement
344
+ - Code push (config + flag overrides + directives, no store release)
345
+ - Logic engine (conditional flows as data, updatable OTA)
346
+ - Analytics (DAU/WAU/MAU, funnels, retention)
347
+ - Cloud Messaging (FCM token registration, targeted send, broadcast)
348
+ - TypeScript-native with full type definitions
342
349
 
343
350
  ---
344
351
 
@@ -94,3 +94,15 @@ export declare class PhoneAlreadyLinkedError extends KoolbaseAuthError {
94
94
  export declare class SmsConfigMissingError extends KoolbaseAuthError {
95
95
  constructor();
96
96
  }
97
+ export declare class AppleSignInNotConfiguredError extends KoolbaseAuthError {
98
+ constructor();
99
+ }
100
+ export declare class InvalidAppleTokenError extends KoolbaseAuthError {
101
+ constructor();
102
+ }
103
+ export declare class AppleEmailRequiredError extends KoolbaseAuthError {
104
+ constructor();
105
+ }
106
+ export declare class OAuthEmailConflictError extends KoolbaseAuthError {
107
+ constructor();
108
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SmsConfigMissingError = exports.PhoneAlreadyLinkedError = exports.OtpRateLimitError = exports.OtpMaxAttemptsError = exports.OtpInvalidError = exports.OtpExpiredError = exports.InvalidPhoneNumberError = exports.NetworkError = exports.RateLimitError = exports.UnlockTokenInvalidError = exports.AccountLockedError = exports.TokenRevokedError = exports.SessionExpiredError = exports.WeakPasswordError = exports.UserDisabledError = exports.EmailAlreadyInUseError = exports.InvalidCredentialsError = exports.KoolbaseAuthError = void 0;
3
+ exports.OAuthEmailConflictError = exports.AppleEmailRequiredError = exports.InvalidAppleTokenError = exports.AppleSignInNotConfiguredError = exports.SmsConfigMissingError = exports.PhoneAlreadyLinkedError = exports.OtpRateLimitError = exports.OtpMaxAttemptsError = exports.OtpInvalidError = exports.OtpExpiredError = exports.InvalidPhoneNumberError = exports.NetworkError = exports.RateLimitError = exports.UnlockTokenInvalidError = exports.AccountLockedError = exports.TokenRevokedError = exports.SessionExpiredError = exports.WeakPasswordError = exports.UserDisabledError = exports.EmailAlreadyInUseError = exports.InvalidCredentialsError = exports.KoolbaseAuthError = void 0;
4
4
  /**
5
5
  * Base error type for all Koolbase auth errors. Catchable via
6
6
  * `instanceof KoolbaseAuthError` to handle any auth-related failure
@@ -192,3 +192,35 @@ class SmsConfigMissingError extends KoolbaseAuthError {
192
192
  }
193
193
  }
194
194
  exports.SmsConfigMissingError = SmsConfigMissingError;
195
+ class AppleSignInNotConfiguredError extends KoolbaseAuthError {
196
+ constructor() {
197
+ super('Apple Sign-In is not configured for this environment', 'apple_not_configured');
198
+ this.name = 'AppleSignInNotConfiguredError';
199
+ Object.setPrototypeOf(this, AppleSignInNotConfiguredError.prototype);
200
+ }
201
+ }
202
+ exports.AppleSignInNotConfiguredError = AppleSignInNotConfiguredError;
203
+ class InvalidAppleTokenError extends KoolbaseAuthError {
204
+ constructor() {
205
+ super('Invalid Apple identity token', 'invalid_apple_token');
206
+ this.name = 'InvalidAppleTokenError';
207
+ Object.setPrototypeOf(this, InvalidAppleTokenError.prototype);
208
+ }
209
+ }
210
+ exports.InvalidAppleTokenError = InvalidAppleTokenError;
211
+ class AppleEmailRequiredError extends KoolbaseAuthError {
212
+ constructor() {
213
+ super('Apple did not return email for this sign-in. Revoke this app in iOS Settings → Apple ID and retry.', 'apple_email_required');
214
+ this.name = 'AppleEmailRequiredError';
215
+ Object.setPrototypeOf(this, AppleEmailRequiredError.prototype);
216
+ }
217
+ }
218
+ exports.AppleEmailRequiredError = AppleEmailRequiredError;
219
+ class OAuthEmailConflictError extends KoolbaseAuthError {
220
+ constructor() {
221
+ super('Email is already in use by another account. Sign in with your existing method and link Apple from settings.', 'oauth_email_conflict');
222
+ this.name = 'OAuthEmailConflictError';
223
+ Object.setPrototypeOf(this, OAuthEmailConflictError.prototype);
224
+ }
225
+ }
226
+ exports.OAuthEmailConflictError = OAuthEmailConflictError;
package/dist/auth.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AuthStateListener, KoolbaseConfig, KoolbaseSession, KoolbaseUser, LinkPhoneParams, LoginParams, OtpSendResult, PhoneVerifyResult, RegisterParams, RestoreResult, SendOtpParams, VerifyOtpParams } from './types';
1
+ import { AuthStateListener, KoolbaseConfig, KoolbaseSession, KoolbaseUser, LinkPhoneParams, LoginParams, OtpSendResult, PhoneVerifyResult, RegisterParams, RestoreResult, SendOtpParams, SignInWithAppleParams, VerifyOtpParams } from './types';
2
2
  export declare class KoolbaseAuth {
3
3
  private config;
4
4
  private storage;
@@ -59,6 +59,38 @@ export declare class KoolbaseAuth {
59
59
  restoreSession(): Promise<RestoreResult>;
60
60
  register(params: RegisterParams): Promise<KoolbaseUser>;
61
61
  login(params: LoginParams): Promise<KoolbaseSession>;
62
+ /**
63
+ * Sign in with Apple using a credential obtained from a native Apple
64
+ * Sign-In SDK.
65
+ *
66
+ * The SDK is library-agnostic — use any native Apple Sign-In package
67
+ * (`@invertase/react-native-apple-authentication`, etc.) and pass the
68
+ * resulting `identityToken`, optional `nonce`, and optional `fullName`.
69
+ *
70
+ * `fullName` is meaningful only on first sign-in — Apple omits name
71
+ * data on subsequent sign-ins. The server persists at link time and
72
+ * ignores on subsequent sign-ins.
73
+ *
74
+ * On success the session is persisted via the configured storage and
75
+ * `onAuthStateChange` fires with the resolved user.
76
+ *
77
+ * @throws AppleSignInNotConfiguredError when Apple is not enabled in
78
+ * the dashboard OAuth config for this environment (400).
79
+ * @throws InvalidAppleTokenError when the token signature, audience,
80
+ * expiry, replay, or nonce check failed server-side (401).
81
+ * @throws UserDisabledError when the account flag is set to disabled (403).
82
+ * @throws AppleEmailRequiredError when Apple did not return email for
83
+ * a new-account sign-in (400).
84
+ * @throws OAuthEmailConflictError when email matches existing user
85
+ * but auto-link rule blocked (409).
86
+ */
87
+ signInWithApple(params: SignInWithAppleParams): Promise<KoolbaseSession>;
88
+ /**
89
+ * Parses a /v1/sdk/auth/oauth/apple response. Distinct from
90
+ * parseSessionResponse because OAuth error semantics differ from
91
+ * credential auth — status codes map to a separate error set.
92
+ */
93
+ private parseAppleSessionResponse;
62
94
  refresh(refreshToken?: string): Promise<KoolbaseSession>;
63
95
  private _doRefresh;
64
96
  logout(): Promise<boolean>;
package/dist/auth.js CHANGED
@@ -209,6 +209,98 @@ class KoolbaseAuth {
209
209
  await this.setSessionInternal(session);
210
210
  return session;
211
211
  }
212
+ /**
213
+ * Sign in with Apple using a credential obtained from a native Apple
214
+ * Sign-In SDK.
215
+ *
216
+ * The SDK is library-agnostic — use any native Apple Sign-In package
217
+ * (`@invertase/react-native-apple-authentication`, etc.) and pass the
218
+ * resulting `identityToken`, optional `nonce`, and optional `fullName`.
219
+ *
220
+ * `fullName` is meaningful only on first sign-in — Apple omits name
221
+ * data on subsequent sign-ins. The server persists at link time and
222
+ * ignores on subsequent sign-ins.
223
+ *
224
+ * On success the session is persisted via the configured storage and
225
+ * `onAuthStateChange` fires with the resolved user.
226
+ *
227
+ * @throws AppleSignInNotConfiguredError when Apple is not enabled in
228
+ * the dashboard OAuth config for this environment (400).
229
+ * @throws InvalidAppleTokenError when the token signature, audience,
230
+ * expiry, replay, or nonce check failed server-side (401).
231
+ * @throws UserDisabledError when the account flag is set to disabled (403).
232
+ * @throws AppleEmailRequiredError when Apple did not return email for
233
+ * a new-account sign-in (400).
234
+ * @throws OAuthEmailConflictError when email matches existing user
235
+ * but auto-link rule blocked (409).
236
+ */
237
+ async signInWithApple(params) {
238
+ const body = {
239
+ identity_token: params.identityToken,
240
+ };
241
+ if (params.nonce && params.nonce.length > 0) {
242
+ body.nonce = params.nonce;
243
+ }
244
+ if (params.fullName) {
245
+ const nameJson = {};
246
+ if (params.fullName.givenName)
247
+ nameJson.given_name = params.fullName.givenName;
248
+ if (params.fullName.familyName)
249
+ nameJson.family_name = params.fullName.familyName;
250
+ if (Object.keys(nameJson).length > 0) {
251
+ body.full_name = nameJson;
252
+ }
253
+ }
254
+ const res = await this.authRequest('/v1/sdk/auth/oauth/apple', {
255
+ method: 'POST',
256
+ body,
257
+ });
258
+ const session = await this.parseAppleSessionResponse(res);
259
+ await this.setSessionInternal(session);
260
+ return session;
261
+ }
262
+ /**
263
+ * Parses a /v1/sdk/auth/oauth/apple response. Distinct from
264
+ * parseSessionResponse because OAuth error semantics differ from
265
+ * credential auth — status codes map to a separate error set.
266
+ */
267
+ async parseAppleSessionResponse(res) {
268
+ if (res.status === 200) {
269
+ const data = await res.json();
270
+ return {
271
+ accessToken: data.access_token,
272
+ refreshToken: data.refresh_token,
273
+ expiresAt: data.expires_at,
274
+ user: this.mapUser(data.user),
275
+ };
276
+ }
277
+ let errorMessage = '';
278
+ try {
279
+ const data = await res.json();
280
+ errorMessage = data?.error ?? '';
281
+ }
282
+ catch {
283
+ // best-effort error message extraction
284
+ }
285
+ if (res.status === 400) {
286
+ if (errorMessage.includes('not configured')) {
287
+ throw new auth_errors_1.AppleSignInNotConfiguredError();
288
+ }
289
+ if (errorMessage.includes('did not return email')) {
290
+ throw new auth_errors_1.AppleEmailRequiredError();
291
+ }
292
+ throw new auth_errors_1.KoolbaseAuthError(`apple sign-in failed: ${errorMessage}`, 'apple_signin_failed');
293
+ }
294
+ if (res.status === 401)
295
+ throw new auth_errors_1.InvalidAppleTokenError();
296
+ if (res.status === 403)
297
+ throw new auth_errors_1.UserDisabledError();
298
+ if (res.status === 409)
299
+ throw new auth_errors_1.OAuthEmailConflictError();
300
+ if (res.status === 429)
301
+ throw new auth_errors_1.RateLimitError(errorMessage);
302
+ throw new auth_errors_1.KoolbaseAuthError(`apple sign-in failed: ${res.status} ${errorMessage}`, `apple_signin_http_${res.status}`);
303
+ }
212
304
  async refresh(refreshToken) {
213
305
  if (this.ongoingRefresh) {
214
306
  return this.ongoingRefresh;
@@ -4,7 +4,7 @@
4
4
  * version-conditional logic (deprecation warnings, schema migrations,
5
5
  * feature flags). Must match the `version` field in package.json.
6
6
  */
7
- export declare const koolbaseSdkVersion = "1.9.0";
7
+ export declare const koolbaseSdkVersion = "1.10.1";
8
8
  /**
9
9
  * Builds device-identifying headers attached to every Koolbase auth
10
10
  * request. Mirrors the Flutter SDK's `DeviceMetadata` for parity. Apps
@@ -9,7 +9,7 @@ const auth_storage_1 = require("./auth-storage");
9
9
  * version-conditional logic (deprecation warnings, schema migrations,
10
10
  * feature flags). Must match the `version` field in package.json.
11
11
  */
12
- exports.koolbaseSdkVersion = '1.9.0';
12
+ exports.koolbaseSdkVersion = '1.10.1';
13
13
  /**
14
14
  * Generate a UUIDv4-shaped string for use as a stable per-install
15
15
  * device label. Not cryptographically secure — this is a label, not a
package/dist/types.d.ts CHANGED
@@ -201,3 +201,26 @@ export interface FunctionInvokeResult {
201
201
  data: Record<string, unknown> | null;
202
202
  success: boolean;
203
203
  }
204
+ /**
205
+ * Apple's optional full-name structure returned only on a user's FIRST
206
+ * Sign in with Apple. Both fields nullable; subsequent sign-ins omit
207
+ * this entirely.
208
+ *
209
+ * Pass to `KoolbaseAuth.signInWithApple` only on first sign-in. The
210
+ * server persists at link time and ignores on subsequent sign-ins
211
+ * (matches Apple's documented contract).
212
+ */
213
+ export interface AppleFullName {
214
+ givenName?: string;
215
+ familyName?: string;
216
+ }
217
+ /**
218
+ * Parameters for `KoolbaseAuth.signInWithApple`. The SDK is
219
+ * library-agnostic — `identityToken` should come from any native
220
+ * Apple Sign-In package (e.g. `@invertase/react-native-apple-authentication`).
221
+ */
222
+ export interface SignInWithAppleParams {
223
+ identityToken: string;
224
+ nonce?: string;
225
+ fullName?: AppleFullName;
226
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techfinityedge/koolbase-react-native",
3
- "version": "1.9.0",
3
+ "version": "1.10.1",
4
4
  "description": "React Native SDK for Koolbase \u2014 auth, database, storage, realtime, feature flags, and functions in one package.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",