@koolbase/react-native 9.0.0 → 9.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 CHANGED
@@ -897,14 +897,17 @@ await Koolbase.messaging.registerToken({
897
897
  token: fcmToken,
898
898
  platform: 'android', // or 'ios'
899
899
  });
900
+ ```
900
901
 
901
- // Send to a specific device
902
- await Koolbase.messaging.send({
903
- to: deviceToken,
904
- title: 'Your order is ready',
905
- body: 'Pick up at counter 3',
906
- data: { order_id: '123' },
907
- });
902
+ Sending is server-initiated — from your backend or a Koolbase Function with a
903
+ secret `kb_live_` key, never the app (the publishable key ships in your bundle
904
+ and can't send). See the [Cloud Messaging docs](https://docs.koolbase.com/sdk/messaging).
905
+
906
+ ```bash
907
+ curl -X POST https://api.koolbase.com/v1/messaging/send \
908
+ -H "Authorization: Bearer kb_live_..." \
909
+ -H "Content-Type: application/json" \
910
+ --data '{"project_id":"...","token":"...","title":"Your order is ready","body":"Pick up at counter 3"}'
908
911
  ```
909
912
 
910
913
  ---
@@ -21,6 +21,4 @@ export declare class KoolbaseAnalytics {
21
21
  reset(): void;
22
22
  flush(): Promise<void>;
23
23
  dispose(): Promise<void>;
24
- private getOrCreateDeviceId;
25
- private generateUUID;
26
24
  }
package/dist/analytics.js CHANGED
@@ -1,11 +1,8 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.KoolbaseAnalytics = void 0;
7
- const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
8
4
  const react_native_1 = require("react-native");
5
+ const device_id_1 = require("./device-id");
9
6
  // ─── KoolbaseAnalytics ───────────────────────────────────────────────────────
10
7
  const SDK_VERSION = '1.3.0';
11
8
  const DEVICE_ID_KEY = 'koolbase:device_id';
@@ -25,7 +22,7 @@ class KoolbaseAnalytics {
25
22
  async init(appVersion) {
26
23
  if (this.initialized)
27
24
  return;
28
- this.deviceId = await this.getOrCreateDeviceId();
25
+ this.deviceId = await (0, device_id_1.getOrCreateDeviceId)();
29
26
  this.sessionId = `${this.deviceId}-${Date.now()}`;
30
27
  this.appVersion = appVersion ?? '1.0.0';
31
28
  // Auto flush on app background
@@ -113,26 +110,5 @@ class KoolbaseAnalytics {
113
110
  this.track('session_end');
114
111
  await this.flush();
115
112
  }
116
- // ─── Device ID ────────────────────────────────────────────────────────────
117
- async getOrCreateDeviceId() {
118
- try {
119
- const existing = await async_storage_1.default.getItem(DEVICE_ID_KEY);
120
- if (existing)
121
- return existing;
122
- const newId = this.generateUUID();
123
- await async_storage_1.default.setItem(DEVICE_ID_KEY, newId);
124
- return newId;
125
- }
126
- catch {
127
- return this.generateUUID();
128
- }
129
- }
130
- generateUUID() {
131
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
132
- const r = (Math.random() * 16) | 0;
133
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
134
- return v.toString(16);
135
- });
136
- }
137
113
  }
138
114
  exports.KoolbaseAnalytics = KoolbaseAnalytics;
@@ -0,0 +1 @@
1
+ export declare function getOrCreateDeviceId(): Promise<string>;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getOrCreateDeviceId = getOrCreateDeviceId;
7
+ const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
8
+ // Single source of the anonymous device identifier for the whole SDK.
9
+ // Generated once, persisted, and shared by messaging (registration keying),
10
+ // feature flags (rollout bucketing: stableHash(deviceId + ":" + key) % 100),
11
+ // code push (targeting), and analytics. Previously each subsystem was handed a
12
+ // hardcoded 'rn-device' literal, so every RN device collided on one messaging
13
+ // registration row and bucketed identically for every rollout — a 10% flag was
14
+ // on for everyone or no one, never 10%.
15
+ //
16
+ // The id is anonymous, not a secret: what matters is uniform DISTRIBUTION so
17
+ // hash(id) % 100 is even, not unpredictability. We use crypto.getRandomValues
18
+ // when the runtime provides it (best distribution, no modulo bias) and fall
19
+ // back to Math.random otherwise — mirroring the runtime-guarded crypto use
20
+ // already in code-push.ts, and adding no dependency (per the SDK's stated
21
+ // preference against a crypto-grade UUID dependency for non-security ids).
22
+ const DEVICE_ID_KEY = 'koolbase:device_id';
23
+ let _cached = null;
24
+ async function getOrCreateDeviceId() {
25
+ if (_cached)
26
+ return _cached;
27
+ try {
28
+ const existing = await async_storage_1.default.getItem(DEVICE_ID_KEY);
29
+ if (existing) {
30
+ _cached = existing;
31
+ return existing;
32
+ }
33
+ const newId = generateUUID();
34
+ await async_storage_1.default.setItem(DEVICE_ID_KEY, newId);
35
+ _cached = newId;
36
+ return newId;
37
+ }
38
+ catch {
39
+ // Storage unavailable — return an ephemeral (unpersisted) id so the SDK
40
+ // stays functional rather than throwing. Not stable across launches.
41
+ return generateUUID();
42
+ }
43
+ }
44
+ // UUID v4. Uses crypto.getRandomValues where available for uniform,
45
+ // modulo-bias-free bytes; Math.random fallback keeps it dependency-free.
46
+ function generateUUID() {
47
+ const bytes = new Uint8Array(16);
48
+ const c = typeof crypto !== 'undefined' ? crypto : undefined;
49
+ if (c && typeof c.getRandomValues === 'function') {
50
+ c.getRandomValues(bytes);
51
+ }
52
+ else {
53
+ for (let i = 0; i < 16; i++)
54
+ bytes[i] = (Math.random() * 256) | 0;
55
+ }
56
+ bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
57
+ bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant
58
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
59
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
60
+ }
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { KoolbaseAnalytics } from './analytics';
4
4
  import { KoolbaseMessaging } from './messaging';
5
5
  export { KoolbaseMessaging } from './messaging';
6
6
  export { KoolbaseAppleAuth } from './apple-auth';
7
- export type { RegisterTokenOptions, SendOptions } from './messaging';
7
+ export type { RegisterTokenOptions } from './messaging';
8
8
  import { FlowResult } from './logic-engine';
9
9
  export { KoolbaseAnalytics } from './analytics';
10
10
  export type { FlowResult } from './logic-engine';
package/dist/index.js CHANGED
@@ -13,12 +13,8 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
13
13
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
- var __importDefault = (this && this.__importDefault) || function (mod) {
17
- return (mod && mod.__esModule) ? mod : { "default": mod };
18
- };
19
16
  Object.defineProperty(exports, "__esModule", { value: true });
20
17
  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 = exports.SecureAuthStorage = exports.RestoreResult = exports.koolbaseSdkVersion = exports.Koolbase = exports.KoolbaseStorage = exports.KoolbaseRealtime = exports.KoolbaseFunctions = exports.KoolbaseFlags = exports.KoolbaseDatabase = exports.KoolbaseAuth = exports.KoolbaseCodePush = exports.KoolbaseAnalytics = exports.KoolbaseAppleAuth = exports.KoolbaseMessaging = void 0;
21
- const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
22
18
  const auth_1 = require("./auth");
23
19
  Object.defineProperty(exports, "KoolbaseAuth", { enumerable: true, get: function () { return auth_1.KoolbaseAuth; } });
24
20
  const code_push_1 = require("./code-push");
@@ -43,6 +39,7 @@ const realtime_1 = require("./realtime");
43
39
  Object.defineProperty(exports, "KoolbaseRealtime", { enumerable: true, get: function () { return realtime_1.KoolbaseRealtime; } });
44
40
  const storage_1 = require("./storage");
45
41
  Object.defineProperty(exports, "KoolbaseStorage", { enumerable: true, get: function () { return storage_1.KoolbaseStorage; } });
42
+ const device_id_1 = require("./device-id");
46
43
  __exportStar(require("./types"), exports);
47
44
  __exportStar(require("./auth-errors"), exports);
48
45
  __exportStar(require("./database-errors"), exports);
@@ -72,13 +69,16 @@ exports.Koolbase = {
72
69
  _storage = new storage_1.KoolbaseStorage(config, () => _auth?.validAccessToken() ?? Promise.resolve(null));
73
70
  _realtime = new realtime_1.KoolbaseRealtime(config, () => _auth?.validAccessToken() ?? Promise.resolve(null));
74
71
  _functions = new functions_1.KoolbaseFunctions(config, () => _auth?.validAccessToken() ?? Promise.resolve(null));
75
- _flags = new flags_1.KoolbaseFlags(config, 'rn-device');
72
+ // One anonymous device id for the whole SDK — bucketing (flags), targeting
73
+ // (code push), and registration keying (messaging) must all agree on it.
74
+ const deviceId = await (0, device_id_1.getOrCreateDeviceId)();
75
+ _flags = new flags_1.KoolbaseFlags(config, deviceId);
76
76
  _codePush = new code_push_1.KoolbaseCodePush(config, config.codePushChannel ?? 'stable');
77
77
  // Initialize code push — loads cached bundle then checks in background
78
78
  await _codePush.init({
79
79
  appVersion: '1.0.0', // override with your app version
80
80
  platform: 'react-native',
81
- deviceId: 'rn-device',
81
+ deviceId,
82
82
  });
83
83
  // Initialize analytics
84
84
  if (config.analyticsEnabled !== false) {
@@ -88,8 +88,7 @@ exports.Koolbase = {
88
88
  // Initialize messaging
89
89
  if (config.messagingEnabled !== false) {
90
90
  _messaging = new messaging_1.KoolbaseMessaging(config);
91
- const storedDeviceId = await async_storage_1.default.getItem('koolbase:device_id');
92
- _messaging.setDeviceId(storedDeviceId ?? 'rn-device');
91
+ _messaging.setDeviceId(deviceId);
93
92
  }
94
93
  _initialized = true;
95
94
  },
@@ -4,17 +4,10 @@ export interface RegisterTokenOptions {
4
4
  platform: 'android' | 'ios';
5
5
  userId?: string;
6
6
  }
7
- export interface SendOptions {
8
- to: string;
9
- title: string;
10
- body: string;
11
- data?: Record<string, unknown>;
12
- }
13
7
  export declare class KoolbaseMessaging {
14
8
  private config;
15
9
  private deviceId;
16
10
  constructor(config: KoolbaseConfig);
17
11
  setDeviceId(deviceId: string): void;
18
12
  registerToken(options: RegisterTokenOptions): Promise<boolean>;
19
- send(options: SendOptions): Promise<boolean>;
20
13
  }
package/dist/messaging.js CHANGED
@@ -32,27 +32,5 @@ class KoolbaseMessaging {
32
32
  return false;
33
33
  }
34
34
  }
35
- // ─── Send notification ────────────────────────────────────────────────────
36
- async send(options) {
37
- try {
38
- const response = await fetch(`${this.config.baseUrl}/v1/messaging/send`, {
39
- method: 'POST',
40
- headers: {
41
- 'Content-Type': 'application/json',
42
- 'x-api-key': this.config.publicKey,
43
- },
44
- body: JSON.stringify({
45
- token: options.to,
46
- title: options.title,
47
- body: options.body,
48
- data: options.data ?? {},
49
- }),
50
- });
51
- return response.ok;
52
- }
53
- catch {
54
- return false;
55
- }
56
- }
57
35
  }
58
36
  exports.KoolbaseMessaging = KoolbaseMessaging;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koolbase/react-native",
3
- "version": "9.0.0",
3
+ "version": "9.1.0",
4
4
  "description": "React Native SDK for Koolbase — auth, database, storage, realtime, feature flags, and functions in one package.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",