@koolbase/core 12.1.0 → 12.3.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/dist/cjs/analytics.js +2 -1
- package/dist/cjs/auth-errors.d.ts +26 -0
- package/dist/cjs/auth-errors.js +58 -1
- package/dist/cjs/auth.d.ts +41 -0
- package/dist/cjs/auth.js +116 -1
- package/dist/cjs/database.d.ts +6 -0
- package/dist/cjs/database.js +18 -6
- package/dist/cjs/fiscal.js +3 -2
- package/dist/cjs/flags.d.ts +1 -1
- package/dist/cjs/flags.js +3 -2
- package/dist/cjs/functions.js +3 -2
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/messaging.js +2 -1
- package/dist/cjs/network.d.ts +19 -0
- package/dist/cjs/network.js +52 -0
- package/dist/cjs/storage.js +12 -11
- package/dist/cjs/sync-engine.js +4 -3
- package/dist/cjs/types.d.ts +7 -0
- package/dist/esm/analytics.js +2 -1
- package/dist/esm/auth-errors.d.ts +26 -0
- package/dist/esm/auth-errors.js +51 -0
- package/dist/esm/auth.d.ts +41 -0
- package/dist/esm/auth.js +117 -2
- package/dist/esm/database.d.ts +6 -0
- package/dist/esm/database.js +18 -6
- package/dist/esm/fiscal.js +3 -2
- package/dist/esm/flags.d.ts +1 -1
- package/dist/esm/flags.js +3 -2
- package/dist/esm/functions.js +3 -2
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/messaging.js +2 -1
- package/dist/esm/network.d.ts +19 -0
- package/dist/esm/network.js +47 -0
- package/dist/esm/storage.js +12 -11
- package/dist/esm/sync-engine.js +4 -3
- package/dist/esm/types.d.ts +7 -0
- package/package.json +2 -2
package/dist/cjs/analytics.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KoolbaseAnalytics = void 0;
|
|
4
|
+
const network_js_1 = require("./network.js");
|
|
4
5
|
const platform_js_1 = require("./platform.js");
|
|
5
6
|
const device_id_js_1 = require("./device-id.js");
|
|
6
7
|
// ─── KoolbaseAnalytics ───────────────────────────────────────────────────────
|
|
@@ -102,7 +103,7 @@ class KoolbaseAnalytics {
|
|
|
102
103
|
const batch = [...this.queue];
|
|
103
104
|
this.queue = [];
|
|
104
105
|
try {
|
|
105
|
-
const response = await
|
|
106
|
+
const response = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}/v1/analytics/events`, {
|
|
106
107
|
method: 'POST',
|
|
107
108
|
headers: {
|
|
108
109
|
'Content-Type': 'application/json',
|
|
@@ -257,3 +257,29 @@ export declare class InvalidGoogleTokenError extends KoolbaseAuthError {
|
|
|
257
257
|
export declare class GoogleEmailRequiredError extends KoolbaseAuthError {
|
|
258
258
|
constructor();
|
|
259
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* The first factor passed and this account needs a second: sign-in is not
|
|
262
|
+
* finished. Pass `challengeToken` to `verifyMfa` with a code from the
|
|
263
|
+
* person's authenticator app, or to `verifyRecoveryCode`. Apps that never
|
|
264
|
+
* enable MFA never see this.
|
|
265
|
+
*/
|
|
266
|
+
export declare class MfaRequiredError extends KoolbaseAuthError {
|
|
267
|
+
readonly challengeToken: string;
|
|
268
|
+
readonly expiresAt?: string;
|
|
269
|
+
constructor(challengeToken: string, expiresAt?: string);
|
|
270
|
+
}
|
|
271
|
+
export declare class RecentAuthRequiredError extends KoolbaseAuthError {
|
|
272
|
+
constructor();
|
|
273
|
+
}
|
|
274
|
+
export declare class RecentMfaRequiredError extends KoolbaseAuthError {
|
|
275
|
+
constructor();
|
|
276
|
+
}
|
|
277
|
+
export declare class MfaAlreadyEnabledError extends KoolbaseAuthError {
|
|
278
|
+
constructor();
|
|
279
|
+
}
|
|
280
|
+
export declare class MfaEnrollmentNotFoundError extends KoolbaseAuthError {
|
|
281
|
+
constructor();
|
|
282
|
+
}
|
|
283
|
+
export declare class MfaNotEnabledError extends KoolbaseAuthError {
|
|
284
|
+
constructor();
|
|
285
|
+
}
|
package/dist/cjs/auth-errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GoogleEmailRequiredError = exports.InvalidGoogleTokenError = exports.MalformedSessionResponseError = exports.ProviderIdentityAlreadyLinkedError = exports.IdentityNotFoundError = exports.InsufficientScopeError = exports.HideRequiresVerificationError = exports.LastCredentialError = exports.InsufficientAuthorityError = exports.SessionRequiredError = exports.UnsupportedOAuthProviderError = exports.OAuthOnlyAccountError = exports.AccountExistsError = exports.CurrentPasswordIncorrectError = exports.TokenAlreadyUsedError = exports.TokenExpiredError = exports.SignupsDisabledError = exports.ContactNotVerifiedError = exports.GoogleSignInNotConfiguredError = exports.OAuthEmailConflictError = exports.AppleEmailRequiredError = exports.InvalidAppleTokenError = exports.AppleSignInNotConfiguredError = exports.SmsConfigMissingError = exports.PhoneAlreadyLinkedError = exports.OtpRateLimitError = exports.OtpMaxAttemptsError = exports.OtpInvalidError = exports.OtpExpiredError = exports.EmailCodeDisabledError = exports.InvalidPhoneNumberError = exports.NetworkError = exports.VerificationResendDailyCapError = exports.VerificationResendCooldownError = exports.RateLimitError = exports.UnlockTokenInvalidError = exports.AccountLockedError = exports.TokenRevokedError = exports.SessionExpiredError = exports.WeakPasswordError = exports.UserDisabledError = exports.EmailAlreadyInUseError = exports.InvalidCredentialsError = exports.KoolbaseAuthError = void 0;
|
|
3
|
+
exports.MfaNotEnabledError = exports.MfaEnrollmentNotFoundError = exports.MfaAlreadyEnabledError = exports.RecentMfaRequiredError = exports.RecentAuthRequiredError = exports.MfaRequiredError = exports.GoogleEmailRequiredError = exports.InvalidGoogleTokenError = exports.MalformedSessionResponseError = exports.ProviderIdentityAlreadyLinkedError = exports.IdentityNotFoundError = exports.InsufficientScopeError = exports.HideRequiresVerificationError = exports.LastCredentialError = exports.InsufficientAuthorityError = exports.SessionRequiredError = exports.UnsupportedOAuthProviderError = exports.OAuthOnlyAccountError = exports.AccountExistsError = exports.CurrentPasswordIncorrectError = exports.TokenAlreadyUsedError = exports.TokenExpiredError = exports.SignupsDisabledError = exports.ContactNotVerifiedError = exports.GoogleSignInNotConfiguredError = exports.OAuthEmailConflictError = exports.AppleEmailRequiredError = exports.InvalidAppleTokenError = exports.AppleSignInNotConfiguredError = exports.SmsConfigMissingError = exports.PhoneAlreadyLinkedError = exports.OtpRateLimitError = exports.OtpMaxAttemptsError = exports.OtpInvalidError = exports.OtpExpiredError = exports.EmailCodeDisabledError = exports.InvalidPhoneNumberError = exports.NetworkError = exports.VerificationResendDailyCapError = exports.VerificationResendCooldownError = exports.RateLimitError = exports.UnlockTokenInvalidError = exports.AccountLockedError = exports.TokenRevokedError = exports.SessionExpiredError = exports.WeakPasswordError = exports.UserDisabledError = exports.EmailAlreadyInUseError = exports.InvalidCredentialsError = exports.KoolbaseAuthError = void 0;
|
|
4
4
|
const errors_js_1 = require("./errors.js");
|
|
5
5
|
/**
|
|
6
6
|
* Base error type for all Koolbase auth errors. Catchable via
|
|
@@ -485,3 +485,60 @@ class GoogleEmailRequiredError extends KoolbaseAuthError {
|
|
|
485
485
|
}
|
|
486
486
|
}
|
|
487
487
|
exports.GoogleEmailRequiredError = GoogleEmailRequiredError;
|
|
488
|
+
// ─── Two-step sign-in (MFA) ─────────────────────────────────────────────────
|
|
489
|
+
/**
|
|
490
|
+
* The first factor passed and this account needs a second: sign-in is not
|
|
491
|
+
* finished. Pass `challengeToken` to `verifyMfa` with a code from the
|
|
492
|
+
* person's authenticator app, or to `verifyRecoveryCode`. Apps that never
|
|
493
|
+
* enable MFA never see this.
|
|
494
|
+
*/
|
|
495
|
+
class MfaRequiredError extends KoolbaseAuthError {
|
|
496
|
+
constructor(challengeToken, expiresAt) {
|
|
497
|
+
super('Two-step sign-in required', 'mfa_required');
|
|
498
|
+
this.name = 'MfaRequiredError';
|
|
499
|
+
this.challengeToken = challengeToken;
|
|
500
|
+
this.expiresAt = expiresAt;
|
|
501
|
+
Object.setPrototypeOf(this, MfaRequiredError.prototype);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
exports.MfaRequiredError = MfaRequiredError;
|
|
505
|
+
class RecentAuthRequiredError extends KoolbaseAuthError {
|
|
506
|
+
constructor() {
|
|
507
|
+
super('Sign in again to change two-step sign-in', 'recent_auth_required');
|
|
508
|
+
this.name = 'RecentAuthRequiredError';
|
|
509
|
+
Object.setPrototypeOf(this, RecentAuthRequiredError.prototype);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
exports.RecentAuthRequiredError = RecentAuthRequiredError;
|
|
513
|
+
class RecentMfaRequiredError extends KoolbaseAuthError {
|
|
514
|
+
constructor() {
|
|
515
|
+
super('Confirm with your authenticator first', 'recent_mfa_required');
|
|
516
|
+
this.name = 'RecentMfaRequiredError';
|
|
517
|
+
Object.setPrototypeOf(this, RecentMfaRequiredError.prototype);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
exports.RecentMfaRequiredError = RecentMfaRequiredError;
|
|
521
|
+
class MfaAlreadyEnabledError extends KoolbaseAuthError {
|
|
522
|
+
constructor() {
|
|
523
|
+
super('Two-step sign-in is already on for this account', 'mfa_already_enabled');
|
|
524
|
+
this.name = 'MfaAlreadyEnabledError';
|
|
525
|
+
Object.setPrototypeOf(this, MfaAlreadyEnabledError.prototype);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
exports.MfaAlreadyEnabledError = MfaAlreadyEnabledError;
|
|
529
|
+
class MfaEnrollmentNotFoundError extends KoolbaseAuthError {
|
|
530
|
+
constructor() {
|
|
531
|
+
super('No enrolment in progress; start again', 'mfa_enrollment_not_found');
|
|
532
|
+
this.name = 'MfaEnrollmentNotFoundError';
|
|
533
|
+
Object.setPrototypeOf(this, MfaEnrollmentNotFoundError.prototype);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
exports.MfaEnrollmentNotFoundError = MfaEnrollmentNotFoundError;
|
|
537
|
+
class MfaNotEnabledError extends KoolbaseAuthError {
|
|
538
|
+
constructor() {
|
|
539
|
+
super('Two-step sign-in is not on for this account', 'mfa_not_enabled');
|
|
540
|
+
this.name = 'MfaNotEnabledError';
|
|
541
|
+
Object.setPrototypeOf(this, MfaNotEnabledError.prototype);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
exports.MfaNotEnabledError = MfaNotEnabledError;
|
package/dist/cjs/auth.d.ts
CHANGED
|
@@ -343,6 +343,47 @@ export declare class KoolbaseAuth {
|
|
|
343
343
|
email: string;
|
|
344
344
|
code: string;
|
|
345
345
|
}): Promise<KoolbaseSession>;
|
|
346
|
+
private mfaRequired;
|
|
347
|
+
/** Finishes sign-in with a code from the person's authenticator app. */
|
|
348
|
+
verifyMfa(params: {
|
|
349
|
+
challengeToken: string;
|
|
350
|
+
code: string;
|
|
351
|
+
}): Promise<KoolbaseSession>;
|
|
352
|
+
/**
|
|
353
|
+
* Finishes sign-in with a recovery code. Each works once; prompt the person
|
|
354
|
+
* to regenerate when recoveryCodesRemaining reaches zero.
|
|
355
|
+
*/
|
|
356
|
+
verifyRecoveryCode(params: {
|
|
357
|
+
challengeToken: string;
|
|
358
|
+
code: string;
|
|
359
|
+
}): Promise<{
|
|
360
|
+
session: KoolbaseSession;
|
|
361
|
+
recoveryCodesRemaining: number;
|
|
362
|
+
}>;
|
|
363
|
+
/**
|
|
364
|
+
* Starts adding an authenticator; needs a sign-in within ten minutes. Show
|
|
365
|
+
* otpauthUri as a QR code, then call confirmMfaEnrollment with the first
|
|
366
|
+
* code the app shows.
|
|
367
|
+
*/
|
|
368
|
+
enrollMfa(): Promise<{
|
|
369
|
+
otpauthUri: string;
|
|
370
|
+
secret: string;
|
|
371
|
+
}>;
|
|
372
|
+
/** Turns MFA on and returns ten recovery codes, shown this once only. Other devices are signed out. */
|
|
373
|
+
confirmMfaEnrollment(code: string): Promise<string[]>;
|
|
374
|
+
mfaStatus(): Promise<{
|
|
375
|
+
enabled: boolean;
|
|
376
|
+
recoveryCodesRemaining: number;
|
|
377
|
+
}>;
|
|
378
|
+
/** Re-confirms the second factor, opening ten minutes to change MFA. */
|
|
379
|
+
stepUpMfa(params: {
|
|
380
|
+
code?: string;
|
|
381
|
+
recoveryCode?: string;
|
|
382
|
+
}): Promise<void>;
|
|
383
|
+
/** Turns MFA off. Needs stepUpMfa() within the last ten minutes. */
|
|
384
|
+
disableMfa(): Promise<void>;
|
|
385
|
+
/** Replaces all recovery codes; the old ones stop working. Needs stepUpMfa() within ten minutes. */
|
|
386
|
+
regenerateRecoveryCodes(): Promise<string[]>;
|
|
346
387
|
sendOtp(params: SendOtpParams): Promise<OtpSendResult>;
|
|
347
388
|
verifyOtp(params: VerifyOtpParams): Promise<PhoneVerifyResult>;
|
|
348
389
|
linkPhone(params: LinkPhoneParams): Promise<void>;
|
package/dist/cjs/auth.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KoolbaseAuth = void 0;
|
|
4
|
+
const network_js_1 = require("./network.js");
|
|
4
5
|
const types_js_1 = require("./types.js");
|
|
5
6
|
const auth_errors_js_1 = require("./auth-errors.js");
|
|
6
7
|
const platform_js_1 = require("./platform.js");
|
|
@@ -12,7 +13,7 @@ class KoolbaseAuth {
|
|
|
12
13
|
this.listeners = new Set();
|
|
13
14
|
this.config = config;
|
|
14
15
|
this.metadata = new device_metadata_js_1.DeviceMetadata(config.appVersion);
|
|
15
|
-
this.fetchFn = config.fetch ?? ((url, init) =>
|
|
16
|
+
this.fetchFn = config.fetch ?? ((url, init) => (0, network_js_1.koolbaseFetch)(url, init));
|
|
16
17
|
this.timeoutMs = config.authTimeout ?? 10000;
|
|
17
18
|
if (config.authStorage) {
|
|
18
19
|
this.storage = config.authStorage;
|
|
@@ -388,6 +389,8 @@ class KoolbaseAuth {
|
|
|
388
389
|
const errorMessage = body?.error ?? '';
|
|
389
390
|
// ─── code-first ───
|
|
390
391
|
switch (code) {
|
|
392
|
+
case 'mfa_required':
|
|
393
|
+
throw this.mfaRequired(body);
|
|
391
394
|
case 'oauth_not_configured':
|
|
392
395
|
throw new auth_errors_js_1.GoogleSignInNotConfiguredError();
|
|
393
396
|
case 'invalid_oauth_token':
|
|
@@ -442,6 +445,8 @@ class KoolbaseAuth {
|
|
|
442
445
|
const errorMessage = body?.error ?? '';
|
|
443
446
|
// ─── code-first ───
|
|
444
447
|
switch (code) {
|
|
448
|
+
case 'mfa_required':
|
|
449
|
+
throw this.mfaRequired(body);
|
|
445
450
|
case 'oauth_not_configured':
|
|
446
451
|
throw new auth_errors_js_1.AppleSignInNotConfiguredError();
|
|
447
452
|
case 'invalid_oauth_token':
|
|
@@ -873,6 +878,102 @@ class KoolbaseAuth {
|
|
|
873
878
|
await this.setSessionInternal(session);
|
|
874
879
|
return session;
|
|
875
880
|
}
|
|
881
|
+
// ─── Two-step sign-in (MFA) ─────────────────────────────────────────────
|
|
882
|
+
//
|
|
883
|
+
// When an account has MFA on, every sign-in method throws MfaRequiredError.
|
|
884
|
+
// Finish with verifyMfa() or verifyRecoveryCode().
|
|
885
|
+
// One builder for every parser, so the four cannot drift apart in how the
|
|
886
|
+
// challenge reaches the app.
|
|
887
|
+
mfaRequired(body) {
|
|
888
|
+
const d = body?.details ?? {};
|
|
889
|
+
return new auth_errors_js_1.MfaRequiredError(String(d.challenge_token ?? ''), d.expires_at);
|
|
890
|
+
}
|
|
891
|
+
/** Finishes sign-in with a code from the person's authenticator app. */
|
|
892
|
+
async verifyMfa(params) {
|
|
893
|
+
const res = await this.authRequest('/v1/sdk/auth/mfa/verify', {
|
|
894
|
+
method: 'POST',
|
|
895
|
+
body: { challenge_token: params.challengeToken, code: params.code },
|
|
896
|
+
});
|
|
897
|
+
const session = await this.parseSessionResponse(res, false);
|
|
898
|
+
await this.setSessionInternal(session);
|
|
899
|
+
return session;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Finishes sign-in with a recovery code. Each works once; prompt the person
|
|
903
|
+
* to regenerate when recoveryCodesRemaining reaches zero.
|
|
904
|
+
*/
|
|
905
|
+
async verifyRecoveryCode(params) {
|
|
906
|
+
const res = await this.authRequest('/v1/sdk/auth/mfa/verify-recovery', {
|
|
907
|
+
method: 'POST',
|
|
908
|
+
body: { challenge_token: params.challengeToken, code: params.code },
|
|
909
|
+
});
|
|
910
|
+
if (!res.ok)
|
|
911
|
+
await this.throwTypedError(res, false);
|
|
912
|
+
// Read once: the session and the remaining count come from one body.
|
|
913
|
+
const data = await res.json();
|
|
914
|
+
if (!data?.access_token)
|
|
915
|
+
throw new auth_errors_js_1.MalformedSessionResponseError('an access token');
|
|
916
|
+
if (!data?.refresh_token)
|
|
917
|
+
throw new auth_errors_js_1.MalformedSessionResponseError('a refresh token');
|
|
918
|
+
const session = {
|
|
919
|
+
accessToken: data.access_token,
|
|
920
|
+
refreshToken: data.refresh_token,
|
|
921
|
+
expiresAt: data.expires_at,
|
|
922
|
+
user: this.mapUser(data.user),
|
|
923
|
+
};
|
|
924
|
+
await this.setSessionInternal(session);
|
|
925
|
+
return { session, recoveryCodesRemaining: Number(data.recovery_codes_remaining ?? 0) };
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Starts adding an authenticator; needs a sign-in within ten minutes. Show
|
|
929
|
+
* otpauthUri as a QR code, then call confirmMfaEnrollment with the first
|
|
930
|
+
* code the app shows.
|
|
931
|
+
*/
|
|
932
|
+
async enrollMfa() {
|
|
933
|
+
const res = await this.authRequest('/v1/sdk/auth/mfa/enroll', { method: 'POST', includeAuth: true });
|
|
934
|
+
await this.checkResponse(res);
|
|
935
|
+
const d = await res.json();
|
|
936
|
+
return { otpauthUri: d.otpauth_uri, secret: d.secret };
|
|
937
|
+
}
|
|
938
|
+
/** Turns MFA on and returns ten recovery codes, shown this once only. Other devices are signed out. */
|
|
939
|
+
async confirmMfaEnrollment(code) {
|
|
940
|
+
const res = await this.authRequest('/v1/sdk/auth/mfa/enroll/confirm', {
|
|
941
|
+
method: 'POST',
|
|
942
|
+
body: { code },
|
|
943
|
+
includeAuth: true,
|
|
944
|
+
});
|
|
945
|
+
await this.checkResponse(res);
|
|
946
|
+
return (await res.json()).recovery_codes;
|
|
947
|
+
}
|
|
948
|
+
async mfaStatus() {
|
|
949
|
+
const res = await this.authRequest('/v1/sdk/auth/mfa', { method: 'GET', includeAuth: true });
|
|
950
|
+
await this.checkResponse(res);
|
|
951
|
+
const d = await res.json();
|
|
952
|
+
return { enabled: !!d.enabled, recoveryCodesRemaining: Number(d.recovery_codes_remaining ?? 0) };
|
|
953
|
+
}
|
|
954
|
+
/** Re-confirms the second factor, opening ten minutes to change MFA. */
|
|
955
|
+
async stepUpMfa(params) {
|
|
956
|
+
const res = await this.authRequest('/v1/sdk/auth/mfa/step-up', {
|
|
957
|
+
method: 'POST',
|
|
958
|
+
body: {
|
|
959
|
+
...(params.code ? { code: params.code } : {}),
|
|
960
|
+
...(params.recoveryCode ? { recovery_code: params.recoveryCode } : {}),
|
|
961
|
+
},
|
|
962
|
+
includeAuth: true,
|
|
963
|
+
});
|
|
964
|
+
await this.checkResponse(res);
|
|
965
|
+
}
|
|
966
|
+
/** Turns MFA off. Needs stepUpMfa() within the last ten minutes. */
|
|
967
|
+
async disableMfa() {
|
|
968
|
+
const res = await this.authRequest('/v1/sdk/auth/mfa/disable', { method: 'POST', includeAuth: true });
|
|
969
|
+
await this.checkResponse(res);
|
|
970
|
+
}
|
|
971
|
+
/** Replaces all recovery codes; the old ones stop working. Needs stepUpMfa() within ten minutes. */
|
|
972
|
+
async regenerateRecoveryCodes() {
|
|
973
|
+
const res = await this.authRequest('/v1/sdk/auth/mfa/recovery-codes', { method: 'POST', includeAuth: true });
|
|
974
|
+
await this.checkResponse(res);
|
|
975
|
+
return (await res.json()).recovery_codes;
|
|
976
|
+
}
|
|
876
977
|
// ─── Phone OTP ──────────────────────────────────────────────────────────
|
|
877
978
|
async sendOtp(params) {
|
|
878
979
|
this.validatePhone(params.phoneNumber);
|
|
@@ -1040,6 +1141,18 @@ class KoolbaseAuth {
|
|
|
1040
1141
|
const msg = body.error ?? '';
|
|
1041
1142
|
// ─── code-first ───
|
|
1042
1143
|
switch (code) {
|
|
1144
|
+
case 'mfa_required':
|
|
1145
|
+
throw this.mfaRequired(body);
|
|
1146
|
+
case 'recent_auth_required':
|
|
1147
|
+
throw new auth_errors_js_1.RecentAuthRequiredError();
|
|
1148
|
+
case 'recent_mfa_required':
|
|
1149
|
+
throw new auth_errors_js_1.RecentMfaRequiredError();
|
|
1150
|
+
case 'mfa_already_enabled':
|
|
1151
|
+
throw new auth_errors_js_1.MfaAlreadyEnabledError();
|
|
1152
|
+
case 'mfa_enrollment_not_found':
|
|
1153
|
+
throw new auth_errors_js_1.MfaEnrollmentNotFoundError();
|
|
1154
|
+
case 'mfa_not_enabled':
|
|
1155
|
+
throw new auth_errors_js_1.MfaNotEnabledError();
|
|
1043
1156
|
case 'invalid_credentials':
|
|
1044
1157
|
throw new auth_errors_js_1.InvalidCredentialsError();
|
|
1045
1158
|
case 'email_in_use':
|
|
@@ -1160,6 +1273,8 @@ class KoolbaseAuth {
|
|
|
1160
1273
|
const msg = body.error ?? '';
|
|
1161
1274
|
// ─── code-first ───
|
|
1162
1275
|
switch (code) {
|
|
1276
|
+
case 'mfa_required':
|
|
1277
|
+
throw this.mfaRequired(body);
|
|
1163
1278
|
case 'invalid_phone':
|
|
1164
1279
|
throw new auth_errors_js_1.InvalidPhoneNumberError();
|
|
1165
1280
|
case 'otp_expired':
|
package/dist/cjs/database.d.ts
CHANGED
|
@@ -47,6 +47,12 @@ export declare class KoolbaseDatabase {
|
|
|
47
47
|
* store for `update`/`delete`.
|
|
48
48
|
*/
|
|
49
49
|
query(collection: string, options?: QueryOptions): Promise<QueryResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Forget this client's cached query results for a collection, so the next
|
|
52
|
+
* `query` waits for the server. For data changed elsewhere: by a Function,
|
|
53
|
+
* a server, or another user. The SDK's own writes already do this.
|
|
54
|
+
*/
|
|
55
|
+
invalidate(collection: string): Promise<void>;
|
|
50
56
|
/**
|
|
51
57
|
* Insert a new record into a collection.
|
|
52
58
|
*
|
package/dist/cjs/database.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KoolbaseDatabase = void 0;
|
|
4
|
+
const network_js_1 = require("./network.js");
|
|
4
5
|
const errors_js_1 = require("./errors.js");
|
|
5
6
|
const cache_store_js_1 = require("./cache-store.js");
|
|
6
7
|
const offline_state_js_1 = require("./offline-state.js");
|
|
@@ -88,7 +89,7 @@ class KoolbaseDatabase {
|
|
|
88
89
|
};
|
|
89
90
|
}
|
|
90
91
|
async request(method, path, body) {
|
|
91
|
-
const res = await
|
|
92
|
+
const res = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}${path}`, {
|
|
92
93
|
method,
|
|
93
94
|
headers: await this.buildHeaders(),
|
|
94
95
|
body: body ? JSON.stringify(body) : undefined,
|
|
@@ -126,7 +127,7 @@ class KoolbaseDatabase {
|
|
|
126
127
|
* none of them clearing a rejected session. One path, two shapes of result.
|
|
127
128
|
*/
|
|
128
129
|
async requestWithStatus(method, path, body) {
|
|
129
|
-
const res = await
|
|
130
|
+
const res = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}${path}`, {
|
|
130
131
|
method,
|
|
131
132
|
headers: await this.buildHeaders(),
|
|
132
133
|
body: body ? JSON.stringify(body) : undefined,
|
|
@@ -197,20 +198,31 @@ class KoolbaseDatabase {
|
|
|
197
198
|
*/
|
|
198
199
|
async query(collection, options = {}) {
|
|
199
200
|
const userId = this.getUserId() ?? 'anonymous';
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
// The cache policy is how to read, not what to read: it stays out of the
|
|
202
|
+
// query's identity, so both policies share one cache entry.
|
|
203
|
+
const { cache: cachePolicy, ...queryOptions } = options;
|
|
204
|
+
const queryHash = (0, cache_store_js_2.hashQuery)(collection, queryOptions);
|
|
205
|
+
const cached = cachePolicy === 'network-only' ? null : await (0, cache_store_js_2.getCached)(userId, collection, queryHash);
|
|
202
206
|
if (cached) {
|
|
203
|
-
this.runQuery(collection,
|
|
207
|
+
this.runQuery(collection, queryOptions)
|
|
204
208
|
.then(result => (0, cache_store_js_2.setCached)(userId, collection, queryHash, result))
|
|
205
209
|
.catch(() => {
|
|
206
210
|
// Network unavailable — cached data already returned
|
|
207
211
|
});
|
|
208
212
|
return { ...cached, isFromCache: true };
|
|
209
213
|
}
|
|
210
|
-
const result = await this.runQuery(collection,
|
|
214
|
+
const result = await this.runQuery(collection, queryOptions);
|
|
211
215
|
await (0, cache_store_js_2.setCached)(userId, collection, queryHash, result);
|
|
212
216
|
return { ...result, isFromCache: false };
|
|
213
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Forget this client's cached query results for a collection, so the next
|
|
220
|
+
* `query` waits for the server. For data changed elsewhere: by a Function,
|
|
221
|
+
* a server, or another user. The SDK's own writes already do this.
|
|
222
|
+
*/
|
|
223
|
+
async invalidate(collection) {
|
|
224
|
+
await (0, cache_store_js_2.invalidateCache)(this.getUserId() ?? 'anonymous', collection);
|
|
225
|
+
}
|
|
214
226
|
// ─── Insert (online-first with offline fallback) ───────────────────────────
|
|
215
227
|
/**
|
|
216
228
|
* Insert a new record into a collection.
|
package/dist/cjs/fiscal.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.KoolbaseFiscal = exports.KoolbaseFiscalError = void 0;
|
|
|
4
4
|
exports.isFiscalized = isFiscalized;
|
|
5
5
|
exports.isPending = isPending;
|
|
6
6
|
exports.decodeFiscalResponse = decodeFiscalResponse;
|
|
7
|
+
const network_js_1 = require("./network.js");
|
|
7
8
|
const errors_js_1 = require("./errors.js");
|
|
8
9
|
const KNOWN_STATUSES = [
|
|
9
10
|
'created', 'blocked', 'queued', 'submitting',
|
|
@@ -112,7 +113,7 @@ class KoolbaseFiscal {
|
|
|
112
113
|
const controller = new AbortController();
|
|
113
114
|
const timer = setTimeout(() => controller.abort(), params.timeoutMs ?? 30000);
|
|
114
115
|
try {
|
|
115
|
-
const res = await
|
|
116
|
+
const res = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}/v1/sdk/fiscal/submit`, {
|
|
116
117
|
method: 'POST',
|
|
117
118
|
headers: await this.buildHeaders(),
|
|
118
119
|
signal: controller.signal,
|
|
@@ -150,7 +151,7 @@ class KoolbaseFiscal {
|
|
|
150
151
|
device_id: params.deviceId,
|
|
151
152
|
client_ref: params.clientRef,
|
|
152
153
|
});
|
|
153
|
-
const res = await
|
|
154
|
+
const res = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}/v1/sdk/fiscal/status?${q.toString()}`, { method: 'GET', headers: await this.buildHeaders(), signal: controller.signal });
|
|
154
155
|
return await this.decode(res);
|
|
155
156
|
}
|
|
156
157
|
catch (e) {
|
package/dist/cjs/flags.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare class KoolbaseFlags {
|
|
|
4
4
|
private payload;
|
|
5
5
|
private deviceId;
|
|
6
6
|
constructor(config: KoolbaseConfig, deviceId: string);
|
|
7
|
-
|
|
7
|
+
koolbaseFetch(appVersion: string, platform: string): Promise<void>;
|
|
8
8
|
isEnabled(key: string): boolean;
|
|
9
9
|
getString(key: string, fallback?: string): string;
|
|
10
10
|
getNumber(key: string, fallback?: number): number;
|
package/dist/cjs/flags.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KoolbaseFlags = void 0;
|
|
4
|
+
const network_js_1 = require("./network.js");
|
|
4
5
|
class KoolbaseFlags {
|
|
5
6
|
constructor(config, deviceId) {
|
|
6
7
|
this.payload = null;
|
|
7
8
|
this.config = config;
|
|
8
9
|
this.deviceId = deviceId;
|
|
9
10
|
}
|
|
10
|
-
async
|
|
11
|
+
async koolbaseFetch(appVersion, platform) {
|
|
11
12
|
try {
|
|
12
|
-
const res = await
|
|
13
|
+
const res = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}/v1/bootstrap?public_key=${this.config.publicKey}&device_id=${this.deviceId}&app_version=${appVersion}&platform=${platform}`);
|
|
13
14
|
if (res.ok) {
|
|
14
15
|
this.payload = await res.json();
|
|
15
16
|
}
|
package/dist/cjs/functions.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KoolbaseFunctions = void 0;
|
|
4
|
+
const network_js_1 = require("./network.js");
|
|
4
5
|
const function_errors_js_1 = require("./function-errors.js");
|
|
5
6
|
const errors_js_1 = require("./errors.js");
|
|
6
7
|
const types_js_1 = require("./types.js");
|
|
@@ -13,7 +14,7 @@ class KoolbaseFunctions {
|
|
|
13
14
|
// ─── Deploy ────────────────────────────────────────────────────────────────
|
|
14
15
|
async deploy(options) {
|
|
15
16
|
const runtime = options.runtime ?? types_js_1.FunctionRuntime.Deno;
|
|
16
|
-
const res = await
|
|
17
|
+
const res = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}/v1/sdk/functions/deploy`, {
|
|
17
18
|
method: 'POST',
|
|
18
19
|
headers: {
|
|
19
20
|
'Content-Type': 'application/json',
|
|
@@ -57,7 +58,7 @@ class KoolbaseFunctions {
|
|
|
57
58
|
if (userToken) {
|
|
58
59
|
headers['Authorization'] = `Bearer ${userToken}`;
|
|
59
60
|
}
|
|
60
|
-
const res = await
|
|
61
|
+
const res = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}/v1/sdk/functions/${name}`, {
|
|
61
62
|
method: 'POST',
|
|
62
63
|
headers,
|
|
63
64
|
body: JSON.stringify({ body: body ?? {} }),
|
package/dist/cjs/index.d.ts
CHANGED
package/dist/cjs/index.js
CHANGED
|
@@ -22,6 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
22
22
|
exports.memoryPlatform = exports.getPlatform = exports.setPlatform = exports.RestoreResult = exports.koolbaseSdkVersion = exports.getOrCreateDeviceId = exports.KoolbaseMessaging = exports.isPending = exports.isFiscalized = exports.decodeFiscalResponse = exports.KoolbaseFiscalError = exports.KoolbaseFiscal = exports.KoolbaseAnalytics = exports.KoolbaseStorage = exports.KoolbaseRealtime = exports.KoolbaseFunctions = exports.KoolbaseFlags = exports.KoolbaseDatabase = exports.KoolbaseAuth = void 0;
|
|
23
23
|
__exportStar(require("./types.js"), exports);
|
|
24
24
|
__exportStar(require("./errors.js"), exports);
|
|
25
|
+
__exportStar(require("./network.js"), exports);
|
|
25
26
|
__exportStar(require("./aggregate.js"), exports);
|
|
26
27
|
__exportStar(require("./conflict.js"), exports);
|
|
27
28
|
__exportStar(require("./pending-write.js"), exports);
|
package/dist/cjs/messaging.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KoolbaseMessaging = void 0;
|
|
4
|
+
const network_js_1 = require("./network.js");
|
|
4
5
|
// ─── KoolbaseMessaging ────────────────────────────────────────────────────────
|
|
5
6
|
class KoolbaseMessaging {
|
|
6
7
|
constructor(config) {
|
|
@@ -13,7 +14,7 @@ class KoolbaseMessaging {
|
|
|
13
14
|
// ─── Register token ───────────────────────────────────────────────────────
|
|
14
15
|
async registerToken(options) {
|
|
15
16
|
try {
|
|
16
|
-
const response = await
|
|
17
|
+
const response = await (0, network_js_1.koolbaseFetch)(`${this.config.baseUrl}/v1/messaging/register`, {
|
|
17
18
|
method: 'POST',
|
|
18
19
|
headers: {
|
|
19
20
|
'Content-Type': 'application/json',
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network failures, made actionable.
|
|
3
|
+
*
|
|
4
|
+
* A browser rejects a request it may not make cross-origin with the same bare
|
|
5
|
+
* TypeError ("Failed to fetch") as a dead network, and deliberately hides which
|
|
6
|
+
* it was. The SDK cannot tell them apart either, so it names the likely causes,
|
|
7
|
+
* starting with the one only the app's developer can fix: Trusted Origins.
|
|
8
|
+
*
|
|
9
|
+
* It stays a TypeError, so code that tells a network failure from a server
|
|
10
|
+
* rejection that way (the offline queue) behaves exactly as before.
|
|
11
|
+
*/
|
|
12
|
+
export declare class KoolbaseNetworkError extends TypeError {
|
|
13
|
+
code: string;
|
|
14
|
+
readonly url: string;
|
|
15
|
+
readonly origin?: string;
|
|
16
|
+
constructor(url: string, cause: unknown);
|
|
17
|
+
}
|
|
18
|
+
/** fetch, with network failures turned into a KoolbaseNetworkError. */
|
|
19
|
+
export declare function koolbaseFetch(input: string, init?: RequestInit): Promise<Response>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KoolbaseNetworkError = void 0;
|
|
4
|
+
exports.koolbaseFetch = koolbaseFetch;
|
|
5
|
+
/**
|
|
6
|
+
* Network failures, made actionable.
|
|
7
|
+
*
|
|
8
|
+
* A browser rejects a request it may not make cross-origin with the same bare
|
|
9
|
+
* TypeError ("Failed to fetch") as a dead network, and deliberately hides which
|
|
10
|
+
* it was. The SDK cannot tell them apart either, so it names the likely causes,
|
|
11
|
+
* starting with the one only the app's developer can fix: Trusted Origins.
|
|
12
|
+
*
|
|
13
|
+
* It stays a TypeError, so code that tells a network failure from a server
|
|
14
|
+
* rejection that way (the offline queue) behaves exactly as before.
|
|
15
|
+
*/
|
|
16
|
+
class KoolbaseNetworkError extends TypeError {
|
|
17
|
+
constructor(url, cause) {
|
|
18
|
+
const loc = globalThis.location;
|
|
19
|
+
const origin = loc?.origin && loc.origin !== 'null' ? loc.origin : undefined;
|
|
20
|
+
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
21
|
+
let host = url;
|
|
22
|
+
try {
|
|
23
|
+
host = new URL(url).origin;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// keep the raw url
|
|
27
|
+
}
|
|
28
|
+
let message = `Could not reach Koolbase at ${host} (${reason}).`;
|
|
29
|
+
message += origin
|
|
30
|
+
? ` If you are online, check that this site's address (${origin}) is in the project's Trusted Origins in the Koolbase dashboard.`
|
|
31
|
+
: ' Check the network connection and the configured base URL.';
|
|
32
|
+
super(message);
|
|
33
|
+
this.code = 'network_error';
|
|
34
|
+
this.name = 'KoolbaseNetworkError';
|
|
35
|
+
this.url = url;
|
|
36
|
+
this.origin = origin;
|
|
37
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.KoolbaseNetworkError = KoolbaseNetworkError;
|
|
41
|
+
/** fetch, with network failures turned into a KoolbaseNetworkError. */
|
|
42
|
+
async function koolbaseFetch(input, init) {
|
|
43
|
+
try {
|
|
44
|
+
return await fetch(input, init);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
// A request the caller cancelled keeps its meaning.
|
|
48
|
+
if (e?.name === 'AbortError')
|
|
49
|
+
throw e;
|
|
50
|
+
throw new KoolbaseNetworkError(input, e);
|
|
51
|
+
}
|
|
52
|
+
}
|