@koolbase/react-native 9.2.0 → 10.0.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/CHANGELOG.md +1348 -0
- package/README.md +403 -568
- package/dist/{auth-storage.d.ts → cjs/auth-storage.d.ts} +1 -1
- package/dist/cjs/index.d.ts +19 -0
- package/dist/cjs/index.js +125 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/platform.d.ts +2 -0
- package/dist/cjs/platform.js +43 -0
- package/dist/esm/auth-storage.d.ts +26 -0
- package/dist/esm/auth-storage.js +100 -0
- package/dist/esm/index.d.ts +19 -0
- package/dist/esm/index.js +106 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/platform.d.ts +2 -0
- package/dist/esm/platform.js +37 -0
- package/package.json +30 -30
- package/dist/analytics.d.ts +0 -24
- package/dist/analytics.js +0 -114
- package/dist/apple-auth.d.ts +0 -22
- package/dist/apple-auth.js +0 -74
- package/dist/auth-errors.d.ts +0 -117
- package/dist/auth-errors.js +0 -250
- package/dist/auth.d.ts +0 -213
- package/dist/auth.js +0 -810
- package/dist/cache-store.d.ts +0 -50
- package/dist/cache-store.js +0 -197
- package/dist/code-push.d.ts +0 -59
- package/dist/code-push.js +0 -255
- package/dist/conflict.d.ts +0 -80
- package/dist/conflict.js +0 -84
- package/dist/database-errors.d.ts +0 -101
- package/dist/database-errors.js +0 -200
- package/dist/database.d.ts +0 -298
- package/dist/database.js +0 -852
- package/dist/device-id.d.ts +0 -1
- package/dist/device-id.js +0 -60
- package/dist/device-metadata.d.ts +0 -36
- package/dist/device-metadata.js +0 -102
- package/dist/errors.d.ts +0 -64
- package/dist/errors.js +0 -85
- package/dist/flags.d.ts +0 -15
- package/dist/flags.js +0 -76
- package/dist/function-errors.d.ts +0 -51
- package/dist/function-errors.js +0 -103
- package/dist/functions.d.ts +0 -15
- package/dist/functions.js +0 -83
- package/dist/index.d.ts +0 -49
- package/dist/index.js +0 -204
- package/dist/logic-engine.d.ts +0 -17
- package/dist/logic-engine.js +0 -193
- package/dist/messaging.d.ts +0 -13
- package/dist/messaging.js +0 -36
- package/dist/offline-state.d.ts +0 -97
- package/dist/offline-state.js +0 -200
- package/dist/pending-write.d.ts +0 -47
- package/dist/pending-write.js +0 -22
- package/dist/realtime.d.ts +0 -44
- package/dist/realtime.js +0 -195
- package/dist/record.d.ts +0 -2
- package/dist/record.js +0 -23
- package/dist/storage-errors.d.ts +0 -163
- package/dist/storage-errors.js +0 -253
- package/dist/storage.d.ts +0 -198
- package/dist/storage.js +0 -451
- package/dist/sync-engine.d.ts +0 -30
- package/dist/sync-engine.js +0 -290
- package/dist/types.d.ts +0 -487
- package/dist/types.js +0 -40
- /package/dist/{auth-storage.js → cjs/auth-storage.js} +0 -0
package/dist/device-id.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getOrCreateDeviceId(): Promise<string>;
|
package/dist/device-id.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Koolbase React Native SDK version. Sent in the `x-koolbase-sdk-version`
|
|
3
|
-
* header on every authenticated request so the server can route
|
|
4
|
-
* version-conditional logic (deprecation warnings, schema migrations,
|
|
5
|
-
* feature flags). Must match the `version` field in package.json.
|
|
6
|
-
*/
|
|
7
|
-
export declare const koolbaseSdkVersion = "1.11.0";
|
|
8
|
-
/**
|
|
9
|
-
* Builds device-identifying headers attached to every Koolbase auth
|
|
10
|
-
* request. Mirrors the Flutter SDK's `DeviceMetadata` for parity. Apps
|
|
11
|
-
* with privacy concerns can swap in a custom storage adapter to avoid
|
|
12
|
-
* persisting the device label.
|
|
13
|
-
*
|
|
14
|
-
* Headers emitted:
|
|
15
|
-
* - User-Agent: koolbase-react-native/<sdk> (<platform> <version>)
|
|
16
|
-
* - x-koolbase-sdk: react-native
|
|
17
|
-
* - x-koolbase-sdk-version: <koolbaseSdkVersion>
|
|
18
|
-
* - x-koolbase-platform: ios | android | web | etc.
|
|
19
|
-
* - x-koolbase-platform-version: numeric SDK level or OS version string
|
|
20
|
-
* - x-koolbase-app-version: from KoolbaseConfig.appVersion or 'unknown'
|
|
21
|
-
* - x-koolbase-device-label: persistent UUID per install
|
|
22
|
-
*/
|
|
23
|
-
export declare class DeviceMetadata {
|
|
24
|
-
private cached;
|
|
25
|
-
private ephemeralLabel;
|
|
26
|
-
private readonly appVersion;
|
|
27
|
-
constructor(appVersion?: string);
|
|
28
|
-
/**
|
|
29
|
-
* Build (or return cached) device headers. The first call may perform
|
|
30
|
-
* an async keychain read to look up the persisted device label;
|
|
31
|
-
* subsequent calls return the in-memory cache synchronously via the
|
|
32
|
-
* returned Promise.
|
|
33
|
-
*/
|
|
34
|
-
build(): Promise<Record<string, string>>;
|
|
35
|
-
private getOrCreateDeviceLabel;
|
|
36
|
-
}
|
package/dist/device-metadata.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DeviceMetadata = exports.koolbaseSdkVersion = void 0;
|
|
4
|
-
const react_native_1 = require("react-native");
|
|
5
|
-
const auth_storage_1 = require("./auth-storage");
|
|
6
|
-
/**
|
|
7
|
-
* Koolbase React Native SDK version. Sent in the `x-koolbase-sdk-version`
|
|
8
|
-
* header on every authenticated request so the server can route
|
|
9
|
-
* version-conditional logic (deprecation warnings, schema migrations,
|
|
10
|
-
* feature flags). Must match the `version` field in package.json.
|
|
11
|
-
*/
|
|
12
|
-
exports.koolbaseSdkVersion = '1.11.0';
|
|
13
|
-
/**
|
|
14
|
-
* Generate a UUIDv4-shaped string for use as a stable per-install
|
|
15
|
-
* device label. Not cryptographically secure — this is a label, not a
|
|
16
|
-
* security primitive. Avoids pulling in a crypto-grade UUID dependency.
|
|
17
|
-
*/
|
|
18
|
-
function generateDeviceLabel() {
|
|
19
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
20
|
-
const r = (Math.random() * 16) | 0;
|
|
21
|
-
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
22
|
-
return v.toString(16);
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Builds device-identifying headers attached to every Koolbase auth
|
|
27
|
-
* request. Mirrors the Flutter SDK's `DeviceMetadata` for parity. Apps
|
|
28
|
-
* with privacy concerns can swap in a custom storage adapter to avoid
|
|
29
|
-
* persisting the device label.
|
|
30
|
-
*
|
|
31
|
-
* Headers emitted:
|
|
32
|
-
* - User-Agent: koolbase-react-native/<sdk> (<platform> <version>)
|
|
33
|
-
* - x-koolbase-sdk: react-native
|
|
34
|
-
* - x-koolbase-sdk-version: <koolbaseSdkVersion>
|
|
35
|
-
* - x-koolbase-platform: ios | android | web | etc.
|
|
36
|
-
* - x-koolbase-platform-version: numeric SDK level or OS version string
|
|
37
|
-
* - x-koolbase-app-version: from KoolbaseConfig.appVersion or 'unknown'
|
|
38
|
-
* - x-koolbase-device-label: persistent UUID per install
|
|
39
|
-
*/
|
|
40
|
-
class DeviceMetadata {
|
|
41
|
-
constructor(appVersion) {
|
|
42
|
-
this.cached = null;
|
|
43
|
-
this.ephemeralLabel = null;
|
|
44
|
-
this.appVersion = appVersion ?? 'unknown';
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Build (or return cached) device headers. The first call may perform
|
|
48
|
-
* an async keychain read to look up the persisted device label;
|
|
49
|
-
* subsequent calls return the in-memory cache synchronously via the
|
|
50
|
-
* returned Promise.
|
|
51
|
-
*/
|
|
52
|
-
async build() {
|
|
53
|
-
if (this.cached)
|
|
54
|
-
return this.cached;
|
|
55
|
-
const platform = String(react_native_1.Platform.OS);
|
|
56
|
-
const platformVersion = String(react_native_1.Platform.Version);
|
|
57
|
-
const deviceLabel = await this.getOrCreateDeviceLabel();
|
|
58
|
-
const userAgent = `koolbase-react-native/${exports.koolbaseSdkVersion} (${platform} ${platformVersion})`;
|
|
59
|
-
this.cached = {
|
|
60
|
-
'User-Agent': userAgent,
|
|
61
|
-
'x-koolbase-sdk': 'react-native',
|
|
62
|
-
'x-koolbase-sdk-version': exports.koolbaseSdkVersion,
|
|
63
|
-
'x-koolbase-platform': platform,
|
|
64
|
-
'x-koolbase-platform-version': platformVersion,
|
|
65
|
-
'x-koolbase-app-version': this.appVersion,
|
|
66
|
-
'x-koolbase-device-label': deviceLabel,
|
|
67
|
-
};
|
|
68
|
-
return this.cached;
|
|
69
|
-
}
|
|
70
|
-
async getOrCreateDeviceLabel() {
|
|
71
|
-
// No keychain available → ephemeral per-session label.
|
|
72
|
-
// (Better than no label — still useful for in-session debugging.)
|
|
73
|
-
if (!(0, auth_storage_1.isKeychainAvailable)()) {
|
|
74
|
-
if (!this.ephemeralLabel) {
|
|
75
|
-
this.ephemeralLabel = generateDeviceLabel();
|
|
76
|
-
}
|
|
77
|
-
return this.ephemeralLabel;
|
|
78
|
-
}
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
80
|
-
const Keychain = require('react-native-keychain');
|
|
81
|
-
const service = 'koolbase_device_label_v1';
|
|
82
|
-
try {
|
|
83
|
-
const existing = await Keychain.getGenericPassword({ service });
|
|
84
|
-
if (existing && existing.password) {
|
|
85
|
-
return existing.password;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
// fall through to create
|
|
90
|
-
}
|
|
91
|
-
const newLabel = generateDeviceLabel();
|
|
92
|
-
try {
|
|
93
|
-
await Keychain.setGenericPassword('device', newLabel, { service });
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
// Persistence failed — return the generated label anyway, but
|
|
97
|
-
// don't cache it as ephemeral since future requests may persist.
|
|
98
|
-
}
|
|
99
|
-
return newLabel;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
exports.DeviceMetadata = DeviceMetadata;
|
package/dist/errors.d.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The root of every error the SDK raises.
|
|
3
|
-
*
|
|
4
|
-
* Each subsystem has its own family beneath this — data, storage, auth — so an
|
|
5
|
-
* application can catch narrowly where it wants to and broadly where it does
|
|
6
|
-
* not:
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* try {
|
|
10
|
-
* await Koolbase.storage.upload(...);
|
|
11
|
-
* } catch (e) {
|
|
12
|
-
* if (e instanceof KoolbaseUnauthenticatedError) return goToLogin();
|
|
13
|
-
* if (e instanceof KoolbaseStorageError) return showError(e.message);
|
|
14
|
-
* throw e;
|
|
15
|
-
* }
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* The families used to be unrelated roots, which meant a failure belonging to no
|
|
19
|
-
* single subsystem — a rejected credential, discovered by whichever call
|
|
20
|
-
* happened to make it — had to be redefined in each one.
|
|
21
|
-
*/
|
|
22
|
-
export declare class KoolbaseError extends Error {
|
|
23
|
-
code?: string;
|
|
24
|
-
constructor(message: string, code?: string);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* The server would not accept the caller's credentials.
|
|
28
|
-
*
|
|
29
|
-
* Raised by any surface — a query, an upload, a Function invoke — because a
|
|
30
|
-
* session stops working for the whole SDK at once, not one subsystem at a time.
|
|
31
|
-
*
|
|
32
|
-
* Named for what the server actually reports. A 401 covers an expired session, a
|
|
33
|
-
* revoked key, a malformed header, and no credentials at all, and the server
|
|
34
|
-
* does not distinguish them: calling this "session expired" would claim a
|
|
35
|
-
* precision that does not exist, and an app that signed a user out on a revoked
|
|
36
|
-
* API key would be acting on it.
|
|
37
|
-
*
|
|
38
|
-
* When the SDK holds a session it clears it before throwing, so by the time an
|
|
39
|
-
* application catches this the user is already signed out.
|
|
40
|
-
*/
|
|
41
|
-
export declare class KoolbaseUnauthenticatedError extends KoolbaseError {
|
|
42
|
-
constructor(message: string);
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* An offline update or delete could not be queued, because the SDK has no
|
|
46
|
-
* record of what the change was composed against.
|
|
47
|
-
*
|
|
48
|
-
* Replaying a mutation without knowing the state it was based on means applying
|
|
49
|
-
* it blindly: whatever changed on the server in the meantime is overwritten,
|
|
50
|
-
* silently, with nobody able to tell it happened.
|
|
51
|
-
*
|
|
52
|
-
* A baseline is available when the record is in the local cache — read through
|
|
53
|
-
* a query, a single fetch, or seen over the socket — or when it was created
|
|
54
|
-
* offline and its insert is still queued. It is unavailable when the record has
|
|
55
|
-
* never been seen on this device, so read it first, or make the change while
|
|
56
|
-
* online where the server arbitrates directly.
|
|
57
|
-
*
|
|
58
|
-
* Deliberate rather than lenient. Queueing these anyway would mean most offline
|
|
59
|
-
* updates are conflict-safe and some quietly are not, which is a worse guarantee
|
|
60
|
-
* than a clear refusal.
|
|
61
|
-
*/
|
|
62
|
-
export declare class KoolbaseOfflineBaselineUnavailableError extends KoolbaseError {
|
|
63
|
-
constructor(message: string);
|
|
64
|
-
}
|
package/dist/errors.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.KoolbaseOfflineBaselineUnavailableError = exports.KoolbaseUnauthenticatedError = exports.KoolbaseError = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* The root of every error the SDK raises.
|
|
6
|
-
*
|
|
7
|
-
* Each subsystem has its own family beneath this — data, storage, auth — so an
|
|
8
|
-
* application can catch narrowly where it wants to and broadly where it does
|
|
9
|
-
* not:
|
|
10
|
-
*
|
|
11
|
-
* ```ts
|
|
12
|
-
* try {
|
|
13
|
-
* await Koolbase.storage.upload(...);
|
|
14
|
-
* } catch (e) {
|
|
15
|
-
* if (e instanceof KoolbaseUnauthenticatedError) return goToLogin();
|
|
16
|
-
* if (e instanceof KoolbaseStorageError) return showError(e.message);
|
|
17
|
-
* throw e;
|
|
18
|
-
* }
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* The families used to be unrelated roots, which meant a failure belonging to no
|
|
22
|
-
* single subsystem — a rejected credential, discovered by whichever call
|
|
23
|
-
* happened to make it — had to be redefined in each one.
|
|
24
|
-
*/
|
|
25
|
-
class KoolbaseError extends Error {
|
|
26
|
-
constructor(message, code) {
|
|
27
|
-
super(message);
|
|
28
|
-
this.code = code;
|
|
29
|
-
this.name = 'KoolbaseError';
|
|
30
|
-
// Required for `instanceof` to work across the prototype chain when
|
|
31
|
-
// targeting ES5-era output, which TypeScript's class extension otherwise
|
|
32
|
-
// breaks. Every subclass repeats it for the same reason.
|
|
33
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
exports.KoolbaseError = KoolbaseError;
|
|
37
|
-
/**
|
|
38
|
-
* The server would not accept the caller's credentials.
|
|
39
|
-
*
|
|
40
|
-
* Raised by any surface — a query, an upload, a Function invoke — because a
|
|
41
|
-
* session stops working for the whole SDK at once, not one subsystem at a time.
|
|
42
|
-
*
|
|
43
|
-
* Named for what the server actually reports. A 401 covers an expired session, a
|
|
44
|
-
* revoked key, a malformed header, and no credentials at all, and the server
|
|
45
|
-
* does not distinguish them: calling this "session expired" would claim a
|
|
46
|
-
* precision that does not exist, and an app that signed a user out on a revoked
|
|
47
|
-
* API key would be acting on it.
|
|
48
|
-
*
|
|
49
|
-
* When the SDK holds a session it clears it before throwing, so by the time an
|
|
50
|
-
* application catches this the user is already signed out.
|
|
51
|
-
*/
|
|
52
|
-
class KoolbaseUnauthenticatedError extends KoolbaseError {
|
|
53
|
-
constructor(message) {
|
|
54
|
-
super(message, 'unauthenticated');
|
|
55
|
-
this.name = 'KoolbaseUnauthenticatedError';
|
|
56
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
exports.KoolbaseUnauthenticatedError = KoolbaseUnauthenticatedError;
|
|
60
|
-
/**
|
|
61
|
-
* An offline update or delete could not be queued, because the SDK has no
|
|
62
|
-
* record of what the change was composed against.
|
|
63
|
-
*
|
|
64
|
-
* Replaying a mutation without knowing the state it was based on means applying
|
|
65
|
-
* it blindly: whatever changed on the server in the meantime is overwritten,
|
|
66
|
-
* silently, with nobody able to tell it happened.
|
|
67
|
-
*
|
|
68
|
-
* A baseline is available when the record is in the local cache — read through
|
|
69
|
-
* a query, a single fetch, or seen over the socket — or when it was created
|
|
70
|
-
* offline and its insert is still queued. It is unavailable when the record has
|
|
71
|
-
* never been seen on this device, so read it first, or make the change while
|
|
72
|
-
* online where the server arbitrates directly.
|
|
73
|
-
*
|
|
74
|
-
* Deliberate rather than lenient. Queueing these anyway would mean most offline
|
|
75
|
-
* updates are conflict-safe and some quietly are not, which is a worse guarantee
|
|
76
|
-
* than a clear refusal.
|
|
77
|
-
*/
|
|
78
|
-
class KoolbaseOfflineBaselineUnavailableError extends KoolbaseError {
|
|
79
|
-
constructor(message) {
|
|
80
|
-
super(message, 'offline_baseline_unavailable');
|
|
81
|
-
this.name = 'KoolbaseOfflineBaselineUnavailableError';
|
|
82
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
exports.KoolbaseOfflineBaselineUnavailableError = KoolbaseOfflineBaselineUnavailableError;
|
package/dist/flags.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { KoolbaseConfig, VersionCheckResult } from './types';
|
|
2
|
-
export declare class KoolbaseFlags {
|
|
3
|
-
private config;
|
|
4
|
-
private payload;
|
|
5
|
-
private deviceId;
|
|
6
|
-
constructor(config: KoolbaseConfig, deviceId: string);
|
|
7
|
-
fetch(appVersion: string, platform: string): Promise<void>;
|
|
8
|
-
isEnabled(key: string): boolean;
|
|
9
|
-
getString(key: string, fallback?: string): string;
|
|
10
|
-
getNumber(key: string, fallback?: number): number;
|
|
11
|
-
getBool(key: string, fallback?: boolean): boolean;
|
|
12
|
-
checkVersion(currentVersion: string): VersionCheckResult;
|
|
13
|
-
private parseVersion;
|
|
14
|
-
private stableHash;
|
|
15
|
-
}
|
package/dist/flags.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.KoolbaseFlags = void 0;
|
|
4
|
-
class KoolbaseFlags {
|
|
5
|
-
constructor(config, deviceId) {
|
|
6
|
-
this.payload = null;
|
|
7
|
-
this.config = config;
|
|
8
|
-
this.deviceId = deviceId;
|
|
9
|
-
}
|
|
10
|
-
async fetch(appVersion, platform) {
|
|
11
|
-
try {
|
|
12
|
-
const res = await fetch(`${this.config.baseUrl}/v1/bootstrap?public_key=${this.config.publicKey}&device_id=${this.deviceId}&app_version=${appVersion}&platform=${platform}`);
|
|
13
|
-
if (res.ok) {
|
|
14
|
-
this.payload = await res.json();
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
catch (_) { }
|
|
18
|
-
}
|
|
19
|
-
isEnabled(key) {
|
|
20
|
-
const flag = this.payload?.flags[key];
|
|
21
|
-
if (!flag || !flag.enabled || flag.kill_switch)
|
|
22
|
-
return false;
|
|
23
|
-
const bucket = this.stableHash(`${this.deviceId}:${key}`) % 100;
|
|
24
|
-
return bucket < flag.rollout_percentage;
|
|
25
|
-
}
|
|
26
|
-
getString(key, fallback = '') {
|
|
27
|
-
const val = this.payload?.config[key];
|
|
28
|
-
return val !== undefined ? String(val) : fallback;
|
|
29
|
-
}
|
|
30
|
-
getNumber(key, fallback = 0) {
|
|
31
|
-
const val = this.payload?.config[key];
|
|
32
|
-
return typeof val === 'number' ? val : Number(val) || fallback;
|
|
33
|
-
}
|
|
34
|
-
getBool(key, fallback = false) {
|
|
35
|
-
const val = this.payload?.config[key];
|
|
36
|
-
if (typeof val === 'boolean')
|
|
37
|
-
return val;
|
|
38
|
-
return val === 'true' ? true : fallback;
|
|
39
|
-
}
|
|
40
|
-
checkVersion(currentVersion) {
|
|
41
|
-
const policy = this.payload?.version;
|
|
42
|
-
if (!policy?.min_version) {
|
|
43
|
-
return { status: 'up_to_date', message: '', latestVersion: '' };
|
|
44
|
-
}
|
|
45
|
-
const current = this.parseVersion(currentVersion);
|
|
46
|
-
const min = this.parseVersion(policy.min_version);
|
|
47
|
-
const latest = this.parseVersion(policy.latest_version);
|
|
48
|
-
if (current < min) {
|
|
49
|
-
return {
|
|
50
|
-
status: 'force_update',
|
|
51
|
-
message: policy.update_message,
|
|
52
|
-
latestVersion: policy.latest_version,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
if (policy.latest_version && current < latest) {
|
|
56
|
-
return {
|
|
57
|
-
status: policy.force_update ? 'force_update' : 'soft_update',
|
|
58
|
-
message: policy.update_message,
|
|
59
|
-
latestVersion: policy.latest_version,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
return { status: 'up_to_date', message: '', latestVersion: policy.latest_version };
|
|
63
|
-
}
|
|
64
|
-
parseVersion(v) {
|
|
65
|
-
const parts = v.split('.').map(Number);
|
|
66
|
-
return (parts[0] ?? 0) * 10000 + (parts[1] ?? 0) * 100 + (parts[2] ?? 0);
|
|
67
|
-
}
|
|
68
|
-
stableHash(s) {
|
|
69
|
-
let hash = 0;
|
|
70
|
-
for (let i = 0; i < s.length; i++) {
|
|
71
|
-
hash = (Math.imul(31, hash) + s.charCodeAt(i)) | 0;
|
|
72
|
-
}
|
|
73
|
-
return Math.abs(hash);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
exports.KoolbaseFlags = KoolbaseFlags;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { KoolbaseError } from './errors';
|
|
2
|
-
/**
|
|
3
|
-
* A Function call did not succeed.
|
|
4
|
-
*
|
|
5
|
-
* Every failure used to be a bare `Error`, so an application could only match on
|
|
6
|
-
* message text — and a missing Function, a caller without permission, a Function
|
|
7
|
-
* that threw, and an exhausted plan limit all looked alike, though they call for
|
|
8
|
-
* entirely different responses.
|
|
9
|
-
*/
|
|
10
|
-
export declare class FunctionInvokeError extends KoolbaseError {
|
|
11
|
-
statusCode?: number;
|
|
12
|
-
constructor(message: string, statusCode?: number, code?: string);
|
|
13
|
-
}
|
|
14
|
-
/** No Function by that name is deployed to this project. */
|
|
15
|
-
export declare class FunctionNotFoundError extends FunctionInvokeError {
|
|
16
|
-
constructor(message: string);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* The caller may not invoke this Function.
|
|
20
|
-
*
|
|
21
|
-
* Distinct from an authentication failure: the credentials were accepted and
|
|
22
|
-
* this caller is not permitted. Retrying will not help, and signing the user out
|
|
23
|
-
* would be wrong.
|
|
24
|
-
*/
|
|
25
|
-
export declare class FunctionPermissionError extends FunctionInvokeError {
|
|
26
|
-
constructor(message: string);
|
|
27
|
-
}
|
|
28
|
-
/** The Function rejected its arguments. */
|
|
29
|
-
export declare class FunctionValidationError extends FunctionInvokeError {
|
|
30
|
-
constructor(message: string);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* The project's Function invocations are used up.
|
|
34
|
-
*
|
|
35
|
-
* Nothing about the call is wrong — retrying will not help until the plan
|
|
36
|
-
* allows it. The one failure here fixed by changing a plan rather than code.
|
|
37
|
-
*/
|
|
38
|
-
export declare class FunctionQuotaExceededError extends FunctionInvokeError {
|
|
39
|
-
constructor(message: string);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* The Function ran and threw.
|
|
43
|
-
*
|
|
44
|
-
* The message is the Function's own, not the platform's — it comes from the code
|
|
45
|
-
* that was deployed.
|
|
46
|
-
*/
|
|
47
|
-
export declare class FunctionExecutionError extends FunctionInvokeError {
|
|
48
|
-
constructor(message: string, statusCode?: number);
|
|
49
|
-
}
|
|
50
|
-
/** Builds the right error for a failed invocation. */
|
|
51
|
-
export declare function functionInvokeError(status: number, message: string): KoolbaseError;
|
package/dist/function-errors.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FunctionExecutionError = exports.FunctionQuotaExceededError = exports.FunctionValidationError = exports.FunctionPermissionError = exports.FunctionNotFoundError = exports.FunctionInvokeError = void 0;
|
|
4
|
-
exports.functionInvokeError = functionInvokeError;
|
|
5
|
-
const errors_1 = require("./errors");
|
|
6
|
-
/**
|
|
7
|
-
* A Function call did not succeed.
|
|
8
|
-
*
|
|
9
|
-
* Every failure used to be a bare `Error`, so an application could only match on
|
|
10
|
-
* message text — and a missing Function, a caller without permission, a Function
|
|
11
|
-
* that threw, and an exhausted plan limit all looked alike, though they call for
|
|
12
|
-
* entirely different responses.
|
|
13
|
-
*/
|
|
14
|
-
class FunctionInvokeError extends errors_1.KoolbaseError {
|
|
15
|
-
constructor(message, statusCode, code) {
|
|
16
|
-
super(message, code);
|
|
17
|
-
this.statusCode = statusCode;
|
|
18
|
-
this.name = 'FunctionInvokeError';
|
|
19
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
exports.FunctionInvokeError = FunctionInvokeError;
|
|
23
|
-
/** No Function by that name is deployed to this project. */
|
|
24
|
-
class FunctionNotFoundError extends FunctionInvokeError {
|
|
25
|
-
constructor(message) {
|
|
26
|
-
super(message, 404, 'not_found');
|
|
27
|
-
this.name = 'FunctionNotFoundError';
|
|
28
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
exports.FunctionNotFoundError = FunctionNotFoundError;
|
|
32
|
-
/**
|
|
33
|
-
* The caller may not invoke this Function.
|
|
34
|
-
*
|
|
35
|
-
* Distinct from an authentication failure: the credentials were accepted and
|
|
36
|
-
* this caller is not permitted. Retrying will not help, and signing the user out
|
|
37
|
-
* would be wrong.
|
|
38
|
-
*/
|
|
39
|
-
class FunctionPermissionError extends FunctionInvokeError {
|
|
40
|
-
constructor(message) {
|
|
41
|
-
super(message, 403, 'permission_denied');
|
|
42
|
-
this.name = 'FunctionPermissionError';
|
|
43
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
exports.FunctionPermissionError = FunctionPermissionError;
|
|
47
|
-
/** The Function rejected its arguments. */
|
|
48
|
-
class FunctionValidationError extends FunctionInvokeError {
|
|
49
|
-
constructor(message) {
|
|
50
|
-
super(message, 400, 'validation_error');
|
|
51
|
-
this.name = 'FunctionValidationError';
|
|
52
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
exports.FunctionValidationError = FunctionValidationError;
|
|
56
|
-
/**
|
|
57
|
-
* The project's Function invocations are used up.
|
|
58
|
-
*
|
|
59
|
-
* Nothing about the call is wrong — retrying will not help until the plan
|
|
60
|
-
* allows it. The one failure here fixed by changing a plan rather than code.
|
|
61
|
-
*/
|
|
62
|
-
class FunctionQuotaExceededError extends FunctionInvokeError {
|
|
63
|
-
constructor(message) {
|
|
64
|
-
super(message, 402, 'limit_reached');
|
|
65
|
-
this.name = 'FunctionQuotaExceededError';
|
|
66
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
exports.FunctionQuotaExceededError = FunctionQuotaExceededError;
|
|
70
|
-
/**
|
|
71
|
-
* The Function ran and threw.
|
|
72
|
-
*
|
|
73
|
-
* The message is the Function's own, not the platform's — it comes from the code
|
|
74
|
-
* that was deployed.
|
|
75
|
-
*/
|
|
76
|
-
class FunctionExecutionError extends FunctionInvokeError {
|
|
77
|
-
constructor(message, statusCode) {
|
|
78
|
-
super(message, statusCode, 'execution_failed');
|
|
79
|
-
this.name = 'FunctionExecutionError';
|
|
80
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
exports.FunctionExecutionError = FunctionExecutionError;
|
|
84
|
-
/** Builds the right error for a failed invocation. */
|
|
85
|
-
function functionInvokeError(status, message) {
|
|
86
|
-
switch (status) {
|
|
87
|
-
case 401:
|
|
88
|
-
// Not a Function failure. A rejected credential stops the whole SDK
|
|
89
|
-
// working, so it raises the shared type.
|
|
90
|
-
return new errors_1.KoolbaseUnauthenticatedError(message);
|
|
91
|
-
case 403:
|
|
92
|
-
return new FunctionPermissionError(message);
|
|
93
|
-
case 404:
|
|
94
|
-
return new FunctionNotFoundError(message);
|
|
95
|
-
case 400:
|
|
96
|
-
return new FunctionValidationError(message);
|
|
97
|
-
case 402:
|
|
98
|
-
return new FunctionQuotaExceededError(message);
|
|
99
|
-
}
|
|
100
|
-
if (status >= 500)
|
|
101
|
-
return new FunctionExecutionError(message, status);
|
|
102
|
-
return new FunctionInvokeError(message, status);
|
|
103
|
-
}
|
package/dist/functions.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { KoolbaseConfig, FunctionInvokeResult, DeployOptions, DeployResult } from './types';
|
|
2
|
-
export declare class KoolbaseFunctions {
|
|
3
|
-
private config;
|
|
4
|
-
private getUserAccessToken?;
|
|
5
|
-
/**
|
|
6
|
-
* Called when the server rejects the caller's credentials.
|
|
7
|
-
*
|
|
8
|
-
* A session stops working for the whole SDK at once, so an app whose failing
|
|
9
|
-
* call happens to be a Function invoke must not keep believing it is signed in.
|
|
10
|
-
*/
|
|
11
|
-
private onSessionExpired?;
|
|
12
|
-
constructor(config: KoolbaseConfig, getUserAccessToken?: () => Promise<string | null>, onSessionExpired?: () => Promise<void>);
|
|
13
|
-
deploy(options: DeployOptions): Promise<DeployResult>;
|
|
14
|
-
invoke(name: string, body?: Record<string, unknown>): Promise<FunctionInvokeResult>;
|
|
15
|
-
}
|