@koolbase/react-native 11.4.0 → 12.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/CHANGELOG.md CHANGED
@@ -7,6 +7,155 @@ adheres to [Semantic Versioning][semver].
7
7
  [kac]: https://keepachangelog.com/en/1.1.0/
8
8
  [semver]: https://semver.org/
9
9
 
10
+ ## 12.1.0
11
+
12
+ ### Added
13
+
14
+ - **Sign in with an emailed code.** `auth.requestEmailCode({ email })` sends a
15
+ six-digit code; `auth.signInWithEmailCode({ email, code })` signs in and
16
+ stores the session exactly as `login()` does. An unknown address becomes an
17
+ account only while the project accepts sign-ups. Each code works once and
18
+ allows three attempts. The request resolves the same way whether or not the
19
+ address has an account. A project can switch this off; requests then throw
20
+ `EmailCodeDisabledError`.
21
+ - **Fiscal.** `KoolbaseFiscal` with `submit()` and `status()`, and
22
+ `KoolbaseFiscalError`. A timeout on `submit` means poll `status()` with the
23
+ same `clientRef` — do not submit again, or the sale may be recorded twice.
24
+ - **Reference errors are catchable.** `KoolbaseReferenceInvalidError`,
25
+ `KoolbaseReferenceInUseError`, `KoolbaseDanglingReferencesError` (carrying
26
+ the offending records) and `KoolbaseCollectionReferencedError`.
27
+
28
+ ### Changed
29
+
30
+ - The OTP errors (`OtpInvalidError`, `OtpExpiredError`,
31
+ `OtpMaxAttemptsError`) now come from the shared error mapping, so every path
32
+ that returns them throws the class an app catches.
33
+ - `oauthLogin()`'s deprecation now points to `signInWithGoogle()` and
34
+ `signInWithApple()`. It said OAuth was not yet shipped and to use email and
35
+ password instead, which had long stopped being true.
36
+
37
+ ## 12.0.0
38
+
39
+ ### Breaking
40
+
41
+ - **Fourteen error classes now report the code the server actually sends.**
42
+
43
+ `error.code` is a public field, and on these fourteen classes it carried a
44
+ value the Koolbase API has never emitted. Catching by type has always
45
+ worked and is unaffected — no class, constructor or export has changed.
46
+ Only the string in `code` moves.
47
+
48
+ If you compare `error.code` against a literal, update these comparisons.
49
+ If you assert on `code` in tests, or build fixtures from these values, the
50
+ same applies.
51
+
52
+ | Class | Was | Now |
53
+ |---|---|---|
54
+ | `EmailAlreadyInUseError` | `email_taken` | `email_in_use` |
55
+ | `UserDisabledError` | `user_disabled` | `account_disabled` |
56
+ | `SessionExpiredError` | `session_expired` | `invalid_refresh_token` |
57
+ | `UnlockTokenInvalidError` | `unlock_token_invalid` | `invalid_unlock_token` |
58
+ | `OtpRateLimitError` | `otp_rate_limit` | `rate_limit` |
59
+ | `PhoneAlreadyInUseError` | `phone_taken` | `phone_in_use` |
60
+ | `SmsConfigMissingError` | `sms_config_missing` | `sms_not_configured` |
61
+ | `AppleNotConfiguredError` | `apple_not_configured` | `oauth_not_configured` |
62
+ | `InvalidAppleTokenError` | `invalid_apple_token` | `invalid_oauth_token` |
63
+ | `AppleEmailRequiredError` | `apple_email_required` | `oauth_email_required` |
64
+ | `GoogleEmailRequiredError` | `google_email_required` | `oauth_email_required` |
65
+ | `GoogleNotConfiguredError` | `google_not_configured` | `oauth_not_configured` |
66
+ | `InvalidGoogleTokenError` | `invalid_google_token` | `invalid_oauth_token` |
67
+
68
+ The Apple and Google pairs are the clearest case: the SDK split them by
69
+ provider while the server has always sent one unified code for both.
70
+
71
+ Why this was invisible: the mapping tests checked which class a server code
72
+ produces, never what code that class reports. Both directions are now
73
+ asserted, so a class cannot report a code the API does not send.
74
+
75
+ **Nothing that worked before breaks in behaviour.** A comparison against
76
+ the old value could never have matched a real response — but it can match a
77
+ mock, which is why this is a major release rather than a patch.
78
+
79
+ ### Added
80
+
81
+ - **Account settings.** A web application could not offer one: these existed
82
+ on the server and in the Flutter SDK, and not here.
83
+
84
+ - `auth.getCurrentUser()` — the signed-in user, fetched fresh rather than
85
+ from the cached session, and persisted so `currentUser` stops being
86
+ stale.
87
+ - `auth.updateProfile({ fullName?, avatarUrl? })` — only the fields given
88
+ are sent, so passing one leaves the other untouched.
89
+ - `auth.changePassword({ currentPassword, newPassword })` — the current
90
+ password is required: a stolen session should not be enough to lock the
91
+ real owner out. A wrong one throws `CurrentPasswordIncorrectError`.
92
+ - `auth.deleteAccount()` — deletes the caller only; there is no user id to
93
+ pass, which is the security property. It does **not** delete the
94
+ account's records in your collections. Subscribe a Function to
95
+ `auth.user.deleted` and clean up there.
96
+
97
+ - **Session management.** Three endpoints had been live on the server the
98
+ whole time and no SDK exposed any of them.
99
+
100
+ - `auth.listSessions()` — where the user is signed in. Each entry carries
101
+ the device label, IP, user agent and timestamps, and `isCurrent` marks
102
+ this device. Token hashes are never included.
103
+ - `auth.revokeSession(id)` — sign one out. Revoking the current session
104
+ ends this one too; the next request's 401 clears it locally. A UI that
105
+ knows a row is current should call `logout()` instead.
106
+ - `auth.revokeAllOtherSessions()` — sign out every other device, keeping
107
+ this one, and return how many ended. What "sign out my other devices"
108
+ means after a lost phone.
109
+
110
+ - **`auth.auditLog({ limit?, offset? })`** — the account's own security
111
+ history, for a "recent activity" screen: sign-ins, failures, lockouts,
112
+ password changes, verification. The server sanitizes each event against a
113
+ per-type field allowlist, so an entry carries what its type may say and
114
+ nothing more. Returns a page with the total across all pages.
115
+
116
+ - **`db.aggregate(request)`** — count and total over a whole collection.
117
+
118
+ Not a paged query you add up in the client: the server aggregates the
119
+ entire authorized set with the read rule applied inside the query. And
120
+ never a bare number — collections are schemaless, so a sum that quietly
121
+ skipped three malformed rows would be a wrong number that looks right.
122
+ Every result carries its `accounting`: how many records contributed to each
123
+ measure, how many were skipped, and why.
124
+
125
+ ```ts
126
+ const r = await Koolbase.db.aggregate({
127
+ collection: 'orders',
128
+ groupBy: { field: 'created_at', bucket: 'month', timezone: 'Africa/Accra' },
129
+ measures: [{ aggregate: 'sum', field: 'total', as: 'revenue' }],
130
+ })
131
+
132
+ if (r.accounting.revenue.skipped > 0) {
133
+ // some orders had a total that was not a number — say so
134
+ }
135
+ ```
136
+
137
+ A calendar bucket requires a timezone and the types enforce it: midnight
138
+ means nothing without one, and Accra and UTC disagree about which day a
139
+ 23:30 sale belongs to.
140
+
141
+ ### Changed
142
+
143
+ - **`x-koolbase-platform-version` falls back to `unknown`** rather than being
144
+ sent empty. The browser version is read from the user agent, which
145
+ recognises Chrome, Firefox, Safari and Edge — so Brave, Opera, Samsung
146
+ Internet and in-app webviews reported nothing. An empty header stored
147
+ against a session is indistinguishable from an SDK that never reported
148
+ itself; `unknown` says the SDK spoke and could not identify the host.
149
+
150
+ ### Fixed
151
+
152
+ - The six `x-koolbase-*` identity headers are now pinned by a test against
153
+ the set the API allows. They are sent on every request, and a browser
154
+ refuses a request whose preflight does not list them — which is how every
155
+ authenticated call from `@koolbase/js` came to be blocked on 18 September.
156
+ The API derives its CORS allowance from one declaration now, and this test
157
+ is the other end of that contract.
158
+
10
159
  ## 11.4.0
11
160
 
12
161
  ### Added
@@ -1,11 +1,12 @@
1
1
  export * from '@koolbase/core';
2
2
  export { reactNativePlatform } from './platform.js';
3
- import { KoolbaseAuth, KoolbaseDatabase, KoolbaseStorage, KoolbaseRealtime, KoolbaseFunctions, KoolbaseAnalytics, KoolbaseMessaging, type KoolbaseConfig, type VersionCheckResult } from '@koolbase/core';
3
+ import { KoolbaseAuth, KoolbaseDatabase, KoolbaseFiscal, KoolbaseStorage, KoolbaseRealtime, KoolbaseFunctions, KoolbaseAnalytics, KoolbaseMessaging, type KoolbaseConfig, type VersionCheckResult } from '@koolbase/core';
4
4
  export declare const Koolbase: {
5
5
  initialize(config: KoolbaseConfig): Promise<void>;
6
6
  readonly auth: KoolbaseAuth;
7
7
  readonly db: KoolbaseDatabase;
8
8
  readonly storage: KoolbaseStorage;
9
+ readonly fiscal: KoolbaseFiscal;
9
10
  readonly realtime: KoolbaseRealtime;
10
11
  readonly functions: KoolbaseFunctions;
11
12
  isEnabled(key: string): boolean;
package/dist/cjs/index.js CHANGED
@@ -29,6 +29,7 @@ const platform_js_2 = require("./platform.js");
29
29
  let _auth = null;
30
30
  let _db = null;
31
31
  let _storage = null;
32
+ let _fiscal = null;
32
33
  let _realtime = null;
33
34
  let _functions = null;
34
35
  let _flags = null;
@@ -66,6 +67,7 @@ exports.Koolbase = {
66
67
  // route to login, rather than looping on a dead token.
67
68
  async () => { await _auth?.clearStoredSession(); });
68
69
  _storage = new core_1.KoolbaseStorage(config, () => _auth?.validAccessToken() ?? Promise.resolve(null), async () => { await _auth?.clearStoredSession(); });
70
+ _fiscal = new core_1.KoolbaseFiscal(config, () => _auth?.validAccessToken() ?? Promise.resolve(null), async () => { await _auth?.clearStoredSession(); });
69
71
  _realtime = new core_1.KoolbaseRealtime(config, () => _auth?.validAccessToken() ?? Promise.resolve(null), () => _auth?.currentUser?.id ?? null);
70
72
  _functions = new core_1.KoolbaseFunctions(config, () => _auth?.validAccessToken() ?? Promise.resolve(null), async () => { await _auth?.clearStoredSession(); });
71
73
  // One anonymous device id for the whole SDK — bucketing (flags), targeting
@@ -105,6 +107,10 @@ exports.Koolbase = {
105
107
  ensureInitialized();
106
108
  return _storage;
107
109
  },
110
+ get fiscal() {
111
+ ensureInitialized();
112
+ return _fiscal;
113
+ },
108
114
  get realtime() {
109
115
  ensureInitialized();
110
116
  return _realtime;
@@ -1,11 +1,12 @@
1
1
  export * from '@koolbase/core';
2
2
  export { reactNativePlatform } from './platform.js';
3
- import { KoolbaseAuth, KoolbaseDatabase, KoolbaseStorage, KoolbaseRealtime, KoolbaseFunctions, KoolbaseAnalytics, KoolbaseMessaging, type KoolbaseConfig, type VersionCheckResult } from '@koolbase/core';
3
+ import { KoolbaseAuth, KoolbaseDatabase, KoolbaseFiscal, KoolbaseStorage, KoolbaseRealtime, KoolbaseFunctions, KoolbaseAnalytics, KoolbaseMessaging, type KoolbaseConfig, type VersionCheckResult } from '@koolbase/core';
4
4
  export declare const Koolbase: {
5
5
  initialize(config: KoolbaseConfig): Promise<void>;
6
6
  readonly auth: KoolbaseAuth;
7
7
  readonly db: KoolbaseDatabase;
8
8
  readonly storage: KoolbaseStorage;
9
+ readonly fiscal: KoolbaseFiscal;
9
10
  readonly realtime: KoolbaseRealtime;
10
11
  readonly functions: KoolbaseFunctions;
11
12
  isEnabled(key: string): boolean;
package/dist/esm/index.js CHANGED
@@ -6,11 +6,12 @@
6
6
  // React Native platform adapter and keychain-backed session storage.
7
7
  export * from '@koolbase/core';
8
8
  export { reactNativePlatform } from './platform.js';
9
- import { KoolbaseAuth, KoolbaseDatabase, KoolbaseStorage, KoolbaseRealtime, KoolbaseFunctions, KoolbaseFlags, KoolbaseAnalytics, KoolbaseMessaging, getOrCreateDeviceId, setPlatform, } from '@koolbase/core';
9
+ import { KoolbaseAuth, KoolbaseDatabase, KoolbaseFiscal, KoolbaseStorage, KoolbaseRealtime, KoolbaseFunctions, KoolbaseFlags, KoolbaseAnalytics, KoolbaseMessaging, getOrCreateDeviceId, setPlatform, } from '@koolbase/core';
10
10
  import { reactNativePlatform } from './platform.js';
11
11
  let _auth = null;
12
12
  let _db = null;
13
13
  let _storage = null;
14
+ let _fiscal = null;
14
15
  let _realtime = null;
15
16
  let _functions = null;
16
17
  let _flags = null;
@@ -48,6 +49,7 @@ export const Koolbase = {
48
49
  // route to login, rather than looping on a dead token.
49
50
  async () => { await _auth?.clearStoredSession(); });
50
51
  _storage = new KoolbaseStorage(config, () => _auth?.validAccessToken() ?? Promise.resolve(null), async () => { await _auth?.clearStoredSession(); });
52
+ _fiscal = new KoolbaseFiscal(config, () => _auth?.validAccessToken() ?? Promise.resolve(null), async () => { await _auth?.clearStoredSession(); });
51
53
  _realtime = new KoolbaseRealtime(config, () => _auth?.validAccessToken() ?? Promise.resolve(null), () => _auth?.currentUser?.id ?? null);
52
54
  _functions = new KoolbaseFunctions(config, () => _auth?.validAccessToken() ?? Promise.resolve(null), async () => { await _auth?.clearStoredSession(); });
53
55
  // One anonymous device id for the whole SDK — bucketing (flags), targeting
@@ -87,6 +89,10 @@ export const Koolbase = {
87
89
  ensureInitialized();
88
90
  return _storage;
89
91
  },
92
+ get fiscal() {
93
+ ensureInitialized();
94
+ return _fiscal;
95
+ },
90
96
  get realtime() {
91
97
  ensureInitialized();
92
98
  return _realtime;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koolbase/react-native",
3
- "version": "11.4.0",
3
+ "version": "12.1.0",
4
4
  "description": "React Native SDK for Koolbase \u2014 auth, database, storage, realtime, feature flags, and functions in one package.",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "types": "./dist/esm/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "url": "https://github.com/koolbase/koolbase-react-native"
25
25
  },
26
26
  "dependencies": {
27
- "@koolbase/core": "11.4.0"
27
+ "@koolbase/core": "12.1.0"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@react-native-async-storage/async-storage": "^3.0.2",