@koolbase/core 11.3.0 → 12.0.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/aggregate.d.ts +115 -0
- package/dist/cjs/aggregate.js +26 -0
- package/dist/cjs/auth-errors.js +13 -13
- package/dist/cjs/auth.d.ts +114 -1
- package/dist/cjs/auth.js +219 -0
- package/dist/cjs/database.d.ts +23 -0
- package/dist/cjs/database.js +64 -0
- package/dist/cjs/device-metadata.js +7 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/types.d.ts +58 -0
- package/dist/esm/aggregate.d.ts +115 -0
- package/dist/esm/aggregate.js +25 -0
- package/dist/esm/auth-errors.js +13 -13
- package/dist/esm/auth.d.ts +114 -1
- package/dist/esm/auth.js +219 -0
- package/dist/esm/database.d.ts +23 -0
- package/dist/esm/database.js +64 -0
- package/dist/esm/device-metadata.js +7 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/types.d.ts +58 -0
- package/package.json +1 -1
package/dist/cjs/database.js
CHANGED
|
@@ -424,6 +424,70 @@ class KoolbaseDatabase {
|
|
|
424
424
|
const { pending } = await (0, offline_state_js_1.readOfflineState)(userId);
|
|
425
425
|
return pending.map(pending_write_js_1.toPendingWrite);
|
|
426
426
|
}
|
|
427
|
+
/**
|
|
428
|
+
* Count and total over a whole collection, with the read rule applied
|
|
429
|
+
* inside the query.
|
|
430
|
+
*
|
|
431
|
+
* Not a paged query you add up yourself: the server aggregates the entire
|
|
432
|
+
* authorized set. And never a bare number — collections are schemaless, so
|
|
433
|
+
* a sum that quietly skipped three malformed rows would be a wrong number
|
|
434
|
+
* that looks right. Check `accounting` for what contributed.
|
|
435
|
+
*
|
|
436
|
+
* ```ts
|
|
437
|
+
* const r = await db.aggregate({
|
|
438
|
+
* collection: 'orders',
|
|
439
|
+
* groupBy: { field: 'created_at', bucket: 'month', timezone: 'Africa/Accra' },
|
|
440
|
+
* measures: [{ aggregate: 'sum', field: 'total', as: 'revenue' }],
|
|
441
|
+
* });
|
|
442
|
+
* ```
|
|
443
|
+
*
|
|
444
|
+
* A calendar bucket requires a timezone and the types enforce it: midnight
|
|
445
|
+
* means nothing without one, and Accra and UTC disagree about which day a
|
|
446
|
+
* 23:30 sale belongs to.
|
|
447
|
+
*/
|
|
448
|
+
async aggregate(request) {
|
|
449
|
+
const raw = await this.request('POST', '/v1/sdk/db/aggregate', {
|
|
450
|
+
collection: request.collection,
|
|
451
|
+
...(request.where?.length ? { where: request.where } : {}),
|
|
452
|
+
...(request.groupBy
|
|
453
|
+
? {
|
|
454
|
+
group_by: {
|
|
455
|
+
field: request.groupBy.field,
|
|
456
|
+
...(request.groupBy.bucket
|
|
457
|
+
? {
|
|
458
|
+
bucket: request.groupBy.bucket,
|
|
459
|
+
timezone: request.groupBy.timezone,
|
|
460
|
+
}
|
|
461
|
+
: {}),
|
|
462
|
+
},
|
|
463
|
+
}
|
|
464
|
+
: {}),
|
|
465
|
+
measures: request.measures.map((m) => ({
|
|
466
|
+
aggregate: m.aggregate,
|
|
467
|
+
...(m.field ? { field: m.field } : {}),
|
|
468
|
+
as: m.as,
|
|
469
|
+
})),
|
|
470
|
+
});
|
|
471
|
+
const accounting = {};
|
|
472
|
+
for (const [name, a] of Object.entries(raw.accounting ?? {})) {
|
|
473
|
+
accounting[name] = {
|
|
474
|
+
counted: Number(a.counted ?? 0),
|
|
475
|
+
skipped: Number(a.skipped ?? 0),
|
|
476
|
+
skippedReason: a.skipped_reason,
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
groups: (raw.groups ?? []).map((g) => ({
|
|
481
|
+
category: String(g.category ?? ''),
|
|
482
|
+
values: g.values ?? {},
|
|
483
|
+
})),
|
|
484
|
+
matched: Number(raw.matched ?? 0),
|
|
485
|
+
accounting,
|
|
486
|
+
// Explicitly boolean: a missing field must read as false, not
|
|
487
|
+
// undefined, or `if (!r.tooManyGroups)` passes on a refused request.
|
|
488
|
+
tooManyGroups: raw.too_many_groups === true,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
427
491
|
async conflicts() {
|
|
428
492
|
const userId = this.requireUserId('the conflict list');
|
|
429
493
|
const { conflicts } = await (0, offline_state_js_1.readOfflineState)(userId);
|
|
@@ -52,7 +52,13 @@ class DeviceMetadata {
|
|
|
52
52
|
if (this.cached)
|
|
53
53
|
return this.cached;
|
|
54
54
|
const platform = (0, platform_js_1.getPlatform)().info.os;
|
|
55
|
-
|
|
55
|
+
// 'unknown' rather than empty, matching appVersion above. A browser
|
|
56
|
+
// outside the handful browserVersion() recognises — Brave, Opera,
|
|
57
|
+
// Samsung Internet, an in-app webview — reports nothing, and an empty
|
|
58
|
+
// header stored against a session is indistinguishable from an SDK that
|
|
59
|
+
// never reported itself at all. 'unknown' says the SDK spoke and could
|
|
60
|
+
// not identify the host, which is a different and more useful fact.
|
|
61
|
+
const platformVersion = (0, platform_js_1.getPlatform)().info.version || 'unknown';
|
|
56
62
|
const deviceLabel = await this.getOrCreateDeviceLabel();
|
|
57
63
|
// No User-Agent: a browser forbids setting it, and the same header set
|
|
58
64
|
// now goes out from both hosts. The platform and version below carry
|
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.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("./aggregate.js"), exports);
|
|
25
26
|
__exportStar(require("./conflict.js"), exports);
|
|
26
27
|
__exportStar(require("./pending-write.js"), exports);
|
|
27
28
|
__exportStar(require("./function-errors.js"), exports);
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -88,6 +88,64 @@ export type SignUpResult = {
|
|
|
88
88
|
user: KoolbaseUser;
|
|
89
89
|
session: null;
|
|
90
90
|
};
|
|
91
|
+
/**
|
|
92
|
+
* One active session — somewhere the user is signed in.
|
|
93
|
+
*
|
|
94
|
+
* Token hashes are never included; the server excludes them deliberately.
|
|
95
|
+
*/
|
|
96
|
+
export interface KoolbaseSessionInfo {
|
|
97
|
+
id: string;
|
|
98
|
+
/** Where it signed in from, when the server captured it. */
|
|
99
|
+
ip?: string;
|
|
100
|
+
/** What signed in. A browser sets this; native SDKs send their own. */
|
|
101
|
+
userAgent?: string;
|
|
102
|
+
/** A per-install label, where the SDK supplied one. */
|
|
103
|
+
deviceLabel?: string;
|
|
104
|
+
createdAt: string;
|
|
105
|
+
expiresAt: string;
|
|
106
|
+
/**
|
|
107
|
+
* True for the session making the request.
|
|
108
|
+
*
|
|
109
|
+
* A device list needs this: without it a user cannot tell which row is the
|
|
110
|
+
* phone in their hand, and "sign out everywhere else" has nothing to
|
|
111
|
+
* exclude.
|
|
112
|
+
*/
|
|
113
|
+
isCurrent: boolean;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* One thing that happened to this account.
|
|
117
|
+
*
|
|
118
|
+
* The server sanitizes these: `eventData` carries only the fields allowed
|
|
119
|
+
* for that event type, so a lockout can say which address was attempted
|
|
120
|
+
* while a successful login carries nothing extra.
|
|
121
|
+
*/
|
|
122
|
+
export interface KoolbaseAuditEvent {
|
|
123
|
+
id: string;
|
|
124
|
+
/**
|
|
125
|
+
* What happened. One of: auth.login.success, auth.login.failed,
|
|
126
|
+
* auth.account.locked, auth.account.unlocked, auth.session.created,
|
|
127
|
+
* auth.session.refreshed, auth.session.revoked, auth.password.changed,
|
|
128
|
+
* auth.user.verified.
|
|
129
|
+
*
|
|
130
|
+
* A string rather than a union: the server may add one, and an app that
|
|
131
|
+
* stops compiling because it did would be worse than one that shows an
|
|
132
|
+
* event it does not recognise.
|
|
133
|
+
*/
|
|
134
|
+
eventType: string;
|
|
135
|
+
occurredAt: string;
|
|
136
|
+
ip?: string;
|
|
137
|
+
userAgent?: string;
|
|
138
|
+
/** Whatever that event type is allowed to carry. Often empty. */
|
|
139
|
+
eventData: Record<string, unknown>;
|
|
140
|
+
}
|
|
141
|
+
/** A page of audit events, and how many there are in total. */
|
|
142
|
+
export interface KoolbaseAuditPage {
|
|
143
|
+
events: KoolbaseAuditEvent[];
|
|
144
|
+
/** Across all pages, so an app knows whether to offer "show more". */
|
|
145
|
+
total: number;
|
|
146
|
+
limit: number;
|
|
147
|
+
offset: number;
|
|
148
|
+
}
|
|
91
149
|
export interface ResendVerificationResult {
|
|
92
150
|
alreadyVerified: boolean;
|
|
93
151
|
/** When the link in the email stops working. Null when nothing was sent. */
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asking "how many" and "how much" over a collection, correctly.
|
|
3
|
+
*
|
|
4
|
+
* Correct means the whole authorized set — never the first page — with the
|
|
5
|
+
* caller's read rule applied inside the query, and never a bare number:
|
|
6
|
+
* collections are schemaless, so a total that quietly excluded three
|
|
7
|
+
* malformed rows would be a wrong number that looks right. Every result
|
|
8
|
+
* carries its accounting.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const r = await Koolbase.db.aggregate({
|
|
12
|
+
* collection: 'orders',
|
|
13
|
+
* groupBy: { field: 'created_at', bucket: 'month', timezone: 'Africa/Accra' },
|
|
14
|
+
* measures: [{ aggregate: 'sum', field: 'total', as: 'revenue' }],
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* for (const g of r.groups) {
|
|
18
|
+
* console.log(g.category, g.values.revenue);
|
|
19
|
+
* }
|
|
20
|
+
* if (r.accounting.revenue.skipped > 0) {
|
|
21
|
+
* // some orders had a total that was not a number — say so
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
/** A record filter, AND-ed on top of the read rule. */
|
|
26
|
+
export interface KoolbaseAggregateFilter {
|
|
27
|
+
field: string;
|
|
28
|
+
op: 'eq' | 'neq' | 'in' | 'gt' | 'gte' | 'lt' | 'lte';
|
|
29
|
+
value: unknown;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The category axis: a field's value, or a calendar bucket of a timestamp
|
|
33
|
+
* field.
|
|
34
|
+
*
|
|
35
|
+
* A bucket REQUIRES a timezone, and the union makes omitting it a type
|
|
36
|
+
* error. "Midnight" means nothing without one — Africa/Accra and UTC
|
|
37
|
+
* disagree about which day a 23:30 sale belongs to — and the API refuses a
|
|
38
|
+
* bucket that arrives without one.
|
|
39
|
+
*/
|
|
40
|
+
export type KoolbaseGroupBy = {
|
|
41
|
+
field: string;
|
|
42
|
+
bucket?: never;
|
|
43
|
+
timezone?: never;
|
|
44
|
+
} | {
|
|
45
|
+
field: string;
|
|
46
|
+
bucket: 'day' | 'week' | 'month' | 'year';
|
|
47
|
+
timezone: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* One number per group.
|
|
51
|
+
*
|
|
52
|
+
* `count` counts RECORDS, so it takes no field and skips nothing. The others
|
|
53
|
+
* read a field, and a record whose value is missing or not a number is
|
|
54
|
+
* skipped and reported in the result's accounting.
|
|
55
|
+
*/
|
|
56
|
+
export type KoolbaseMeasure = {
|
|
57
|
+
aggregate: 'count';
|
|
58
|
+
field?: never;
|
|
59
|
+
as: string;
|
|
60
|
+
} | {
|
|
61
|
+
aggregate: 'sum' | 'avg' | 'min' | 'max';
|
|
62
|
+
field: string;
|
|
63
|
+
as: string;
|
|
64
|
+
};
|
|
65
|
+
/** One aggregation request. */
|
|
66
|
+
export interface KoolbaseAggregateRequest {
|
|
67
|
+
collection: string;
|
|
68
|
+
/** AND-ed record filters on top of the read rule. */
|
|
69
|
+
where?: KoolbaseAggregateFilter[];
|
|
70
|
+
/** Absent means one group: the measures over everything. */
|
|
71
|
+
groupBy?: KoolbaseGroupBy;
|
|
72
|
+
/** At least one. */
|
|
73
|
+
measures: KoolbaseMeasure[];
|
|
74
|
+
}
|
|
75
|
+
/** One category and its numbers. */
|
|
76
|
+
export interface KoolbaseAggregateGroup {
|
|
77
|
+
/** Empty string for the single group when there was no groupBy. */
|
|
78
|
+
category: string;
|
|
79
|
+
/** Keyed by each measure's `as`. Null where a group had nothing to measure. */
|
|
80
|
+
values: Record<string, number | null>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* How a measure arrived at its number.
|
|
84
|
+
*
|
|
85
|
+
* `skipped` is not an error. It is what you need to decide whether the
|
|
86
|
+
* number means what it appears to mean — a revenue total over 900 of 903
|
|
87
|
+
* orders is a different fact from one over all of them, and only this says
|
|
88
|
+
* which you are looking at.
|
|
89
|
+
*/
|
|
90
|
+
export interface KoolbaseAggregateAccounting {
|
|
91
|
+
counted: number;
|
|
92
|
+
skipped: number;
|
|
93
|
+
/** Present when skipped > 0. */
|
|
94
|
+
skippedReason?: 'missing' | 'not_numeric' | 'mixed';
|
|
95
|
+
}
|
|
96
|
+
/** The whole answer, including what could not be counted. */
|
|
97
|
+
export interface KoolbaseAggregateResult {
|
|
98
|
+
/**
|
|
99
|
+
* One per category, sorted — or exactly one with an empty category when
|
|
100
|
+
* there was no groupBy.
|
|
101
|
+
*/
|
|
102
|
+
groups: KoolbaseAggregateGroup[];
|
|
103
|
+
/** Records that matched the read rule and filters: the denominator. */
|
|
104
|
+
matched: number;
|
|
105
|
+
/** Per measure name, keyed by its `as`. */
|
|
106
|
+
accounting: Record<string, KoolbaseAggregateAccounting>;
|
|
107
|
+
/**
|
|
108
|
+
* True when the groupBy produced more categories than allowed and the
|
|
109
|
+
* whole request was refused.
|
|
110
|
+
*
|
|
111
|
+
* `groups` is EMPTY when this is set: a partial set drawn as the whole
|
|
112
|
+
* would be exactly the wrong number this API exists to prevent.
|
|
113
|
+
*/
|
|
114
|
+
tooManyGroups: boolean;
|
|
115
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asking "how many" and "how much" over a collection, correctly.
|
|
3
|
+
*
|
|
4
|
+
* Correct means the whole authorized set — never the first page — with the
|
|
5
|
+
* caller's read rule applied inside the query, and never a bare number:
|
|
6
|
+
* collections are schemaless, so a total that quietly excluded three
|
|
7
|
+
* malformed rows would be a wrong number that looks right. Every result
|
|
8
|
+
* carries its accounting.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const r = await Koolbase.db.aggregate({
|
|
12
|
+
* collection: 'orders',
|
|
13
|
+
* groupBy: { field: 'created_at', bucket: 'month', timezone: 'Africa/Accra' },
|
|
14
|
+
* measures: [{ aggregate: 'sum', field: 'total', as: 'revenue' }],
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* for (const g of r.groups) {
|
|
18
|
+
* console.log(g.category, g.values.revenue);
|
|
19
|
+
* }
|
|
20
|
+
* if (r.accounting.revenue.skipped > 0) {
|
|
21
|
+
* // some orders had a total that was not a number — say so
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export {};
|
package/dist/esm/auth-errors.js
CHANGED
|
@@ -21,14 +21,14 @@ export class InvalidCredentialsError extends KoolbaseAuthError {
|
|
|
21
21
|
}
|
|
22
22
|
export class EmailAlreadyInUseError extends KoolbaseAuthError {
|
|
23
23
|
constructor() {
|
|
24
|
-
super('Email is already in use', '
|
|
24
|
+
super('Email is already in use', 'email_in_use');
|
|
25
25
|
this.name = 'EmailAlreadyInUseError';
|
|
26
26
|
Object.setPrototypeOf(this, EmailAlreadyInUseError.prototype);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
export class UserDisabledError extends KoolbaseAuthError {
|
|
30
30
|
constructor() {
|
|
31
|
-
super('This account has been disabled', '
|
|
31
|
+
super('This account has been disabled', 'account_disabled');
|
|
32
32
|
this.name = 'UserDisabledError';
|
|
33
33
|
Object.setPrototypeOf(this, UserDisabledError.prototype);
|
|
34
34
|
}
|
|
@@ -49,7 +49,7 @@ export class WeakPasswordError extends KoolbaseAuthError {
|
|
|
49
49
|
// ─── Session lifecycle ─────────────────────────────────────────────────────
|
|
50
50
|
export class SessionExpiredError extends KoolbaseAuthError {
|
|
51
51
|
constructor() {
|
|
52
|
-
super('Session expired, please log in again', '
|
|
52
|
+
super('Session expired, please log in again', 'invalid_refresh_token');
|
|
53
53
|
this.name = 'SessionExpiredError';
|
|
54
54
|
Object.setPrototypeOf(this, SessionExpiredError.prototype);
|
|
55
55
|
}
|
|
@@ -95,7 +95,7 @@ export class AccountLockedError extends KoolbaseAuthError {
|
|
|
95
95
|
*/
|
|
96
96
|
export class UnlockTokenInvalidError extends KoolbaseAuthError {
|
|
97
97
|
constructor() {
|
|
98
|
-
super('Unlock link is invalid or has expired', '
|
|
98
|
+
super('Unlock link is invalid or has expired', 'invalid_unlock_token');
|
|
99
99
|
this.name = 'UnlockTokenInvalidError';
|
|
100
100
|
Object.setPrototypeOf(this, UnlockTokenInvalidError.prototype);
|
|
101
101
|
}
|
|
@@ -185,42 +185,42 @@ export class OtpMaxAttemptsError extends KoolbaseAuthError {
|
|
|
185
185
|
}
|
|
186
186
|
export class OtpRateLimitError extends KoolbaseAuthError {
|
|
187
187
|
constructor() {
|
|
188
|
-
super('Too many OTP requests, please wait before trying again', '
|
|
188
|
+
super('Too many OTP requests, please wait before trying again', 'rate_limit');
|
|
189
189
|
this.name = 'OtpRateLimitError';
|
|
190
190
|
Object.setPrototypeOf(this, OtpRateLimitError.prototype);
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
export class PhoneAlreadyLinkedError extends KoolbaseAuthError {
|
|
194
194
|
constructor() {
|
|
195
|
-
super('Phone number is already associated with another account', '
|
|
195
|
+
super('Phone number is already associated with another account', 'phone_in_use');
|
|
196
196
|
this.name = 'PhoneAlreadyLinkedError';
|
|
197
197
|
Object.setPrototypeOf(this, PhoneAlreadyLinkedError.prototype);
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
export class SmsConfigMissingError extends KoolbaseAuthError {
|
|
201
201
|
constructor() {
|
|
202
|
-
super('SMS provider not configured for this project', '
|
|
202
|
+
super('SMS provider not configured for this project', 'sms_not_configured');
|
|
203
203
|
this.name = 'SmsConfigMissingError';
|
|
204
204
|
Object.setPrototypeOf(this, SmsConfigMissingError.prototype);
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
export class AppleSignInNotConfiguredError extends KoolbaseAuthError {
|
|
208
208
|
constructor() {
|
|
209
|
-
super('Apple Sign-In is not configured for this environment', '
|
|
209
|
+
super('Apple Sign-In is not configured for this environment', 'oauth_not_configured');
|
|
210
210
|
this.name = 'AppleSignInNotConfiguredError';
|
|
211
211
|
Object.setPrototypeOf(this, AppleSignInNotConfiguredError.prototype);
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
export class InvalidAppleTokenError extends KoolbaseAuthError {
|
|
215
215
|
constructor() {
|
|
216
|
-
super('Invalid Apple identity token', '
|
|
216
|
+
super('Invalid Apple identity token', 'invalid_oauth_token');
|
|
217
217
|
this.name = 'InvalidAppleTokenError';
|
|
218
218
|
Object.setPrototypeOf(this, InvalidAppleTokenError.prototype);
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
export class AppleEmailRequiredError extends KoolbaseAuthError {
|
|
222
222
|
constructor() {
|
|
223
|
-
super('Apple did not return email for this sign-in. Revoke this app in iOS Settings → Apple ID and retry.', '
|
|
223
|
+
super('Apple did not return email for this sign-in. Revoke this app in iOS Settings → Apple ID and retry.', 'oauth_email_required');
|
|
224
224
|
this.name = 'AppleEmailRequiredError';
|
|
225
225
|
Object.setPrototypeOf(this, AppleEmailRequiredError.prototype);
|
|
226
226
|
}
|
|
@@ -234,7 +234,7 @@ export class OAuthEmailConflictError extends KoolbaseAuthError {
|
|
|
234
234
|
}
|
|
235
235
|
export class GoogleSignInNotConfiguredError extends KoolbaseAuthError {
|
|
236
236
|
constructor() {
|
|
237
|
-
super('Google Sign-In is not configured for this environment', '
|
|
237
|
+
super('Google Sign-In is not configured for this environment', 'oauth_not_configured');
|
|
238
238
|
this.name = 'GoogleSignInNotConfiguredError';
|
|
239
239
|
Object.setPrototypeOf(this, GoogleSignInNotConfiguredError.prototype);
|
|
240
240
|
}
|
|
@@ -414,14 +414,14 @@ export class MalformedSessionResponseError extends KoolbaseAuthError {
|
|
|
414
414
|
}
|
|
415
415
|
export class InvalidGoogleTokenError extends KoolbaseAuthError {
|
|
416
416
|
constructor() {
|
|
417
|
-
super('Invalid Google identity token', '
|
|
417
|
+
super('Invalid Google identity token', 'invalid_oauth_token');
|
|
418
418
|
this.name = 'InvalidGoogleTokenError';
|
|
419
419
|
Object.setPrototypeOf(this, InvalidGoogleTokenError.prototype);
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
export class GoogleEmailRequiredError extends KoolbaseAuthError {
|
|
423
423
|
constructor() {
|
|
424
|
-
super('Google did not return email for this sign-in. Ensure the email scope is requested in the native flow.', '
|
|
424
|
+
super('Google did not return email for this sign-in. Ensure the email scope is requested in the native flow.', 'oauth_email_required');
|
|
425
425
|
this.name = 'GoogleEmailRequiredError';
|
|
426
426
|
Object.setPrototypeOf(this, GoogleEmailRequiredError.prototype);
|
|
427
427
|
}
|
package/dist/esm/auth.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthStateListener, KoolbaseConfig, KoolbaseSession, KoolbaseUser, LinkPhoneParams, LoginParams, OtpSendResult, PhoneVerifyResult, RegisterParams, RestoreResult, ResendVerificationResult, SendOtpParams, SignUpResult, SignInWithAppleParams, VerifyOtpParams } from './types.js';
|
|
1
|
+
import { AuthStateListener, KoolbaseConfig, KoolbaseSession, KoolbaseUser, LinkPhoneParams, LoginParams, OtpSendResult, PhoneVerifyResult, RegisterParams, RestoreResult, KoolbaseAuditPage, KoolbaseSessionInfo, ResendVerificationResult, SendOtpParams, SignUpResult, SignInWithAppleParams, VerifyOtpParams } from './types.js';
|
|
2
2
|
import type { SignInWithGoogleParams } from './types.js';
|
|
3
3
|
export declare class KoolbaseAuth {
|
|
4
4
|
private config;
|
|
@@ -55,6 +55,18 @@ export declare class KoolbaseAuth {
|
|
|
55
55
|
* delegates to {@link authRequest} with includeAuth=true.
|
|
56
56
|
*/
|
|
57
57
|
private authedRequest;
|
|
58
|
+
/**
|
|
59
|
+
* Replace the user inside the current session and persist it.
|
|
60
|
+
*
|
|
61
|
+
* A profile update or a fresh fetch changes the user, not the tokens.
|
|
62
|
+
* Without this the new values live only in the returned object: the cached
|
|
63
|
+
* `currentUser` stays stale, anything bound to `onAuthStateChange` never
|
|
64
|
+
* hears about the change, and a reload restores the old name.
|
|
65
|
+
*
|
|
66
|
+
* No session means nobody is signed in, and there is nothing to update —
|
|
67
|
+
* the caller's own request would have failed first.
|
|
68
|
+
*/
|
|
69
|
+
private updateUserAndPersist;
|
|
58
70
|
private setSessionInternal;
|
|
59
71
|
/**
|
|
60
72
|
* Discards the stored session without contacting the server.
|
|
@@ -154,6 +166,21 @@ export declare class KoolbaseAuth {
|
|
|
154
166
|
private _doRefresh;
|
|
155
167
|
logout(): Promise<boolean>;
|
|
156
168
|
forgotPassword(email: string): Promise<void>;
|
|
169
|
+
/**
|
|
170
|
+
* Ask for a new verification email, with no session.
|
|
171
|
+
*
|
|
172
|
+
* For the state a project with verified contact required creates:
|
|
173
|
+
* registered, unverified, refused at login, and holding a link that may
|
|
174
|
+
* never have arrived or has since expired. `resendVerificationEmail()`
|
|
175
|
+
* cannot help there — it needs a session the user cannot get.
|
|
176
|
+
*
|
|
177
|
+
* Returns nothing, and throws only on a malformed request, because the
|
|
178
|
+
* server answers identically whether the address has an account, has none,
|
|
179
|
+
* or is already verified. Anything else would let anyone discover who has
|
|
180
|
+
* signed up. So there is no "we sent it" to report: show the same "check
|
|
181
|
+
* your email" either way.
|
|
182
|
+
*/
|
|
183
|
+
resendVerificationEmailToAddress(email: string): Promise<void>;
|
|
157
184
|
resetPassword(token: string, password: string): Promise<void>;
|
|
158
185
|
/**
|
|
159
186
|
* Complete email verification with a token from a verification link.
|
|
@@ -176,6 +203,92 @@ export declare class KoolbaseAuth {
|
|
|
176
203
|
* taking an email address — otherwise this would be an open mail relay.
|
|
177
204
|
*/
|
|
178
205
|
resendVerificationEmail(): Promise<ResendVerificationResult>;
|
|
206
|
+
/**
|
|
207
|
+
* The signed-in user, fetched fresh from the server.
|
|
208
|
+
*
|
|
209
|
+
* `currentUser` returns what was cached at sign-in; this asks. Use it when
|
|
210
|
+
* something may have changed the user server-side — a verification
|
|
211
|
+
* completing, a profile updated from another device — and persist the
|
|
212
|
+
* result so the cached copy stops being stale.
|
|
213
|
+
*/
|
|
214
|
+
getCurrentUser(): Promise<KoolbaseUser>;
|
|
215
|
+
/**
|
|
216
|
+
* Update the signed-in user's profile.
|
|
217
|
+
*
|
|
218
|
+
* Only the fields given are sent, so passing one leaves the other
|
|
219
|
+
* untouched. The updated user is persisted, so `currentUser` reflects it
|
|
220
|
+
* without a refetch.
|
|
221
|
+
*/
|
|
222
|
+
updateProfile(params: {
|
|
223
|
+
fullName?: string;
|
|
224
|
+
avatarUrl?: string;
|
|
225
|
+
}): Promise<KoolbaseUser>;
|
|
226
|
+
/**
|
|
227
|
+
* Change the signed-in user's password.
|
|
228
|
+
*
|
|
229
|
+
* The current password is required: a stolen session should not be enough
|
|
230
|
+
* to lock the real owner out. A wrong one throws
|
|
231
|
+
* CurrentPasswordIncorrectError — the server returns `invalid_password`,
|
|
232
|
+
* which reads like a rejected new password and means the opposite.
|
|
233
|
+
*
|
|
234
|
+
* An account that signed up through Google or Apple has no password to
|
|
235
|
+
* change and gets the same error, deliberately, so a caller cannot probe
|
|
236
|
+
* which sign-in methods an account has.
|
|
237
|
+
*/
|
|
238
|
+
changePassword(params: {
|
|
239
|
+
currentPassword: string;
|
|
240
|
+
newPassword: string;
|
|
241
|
+
}): Promise<void>;
|
|
242
|
+
/**
|
|
243
|
+
* Delete the signed-in user's account, and sign out.
|
|
244
|
+
*
|
|
245
|
+
* Deletes the caller only — there is no user id to pass, which is the
|
|
246
|
+
* security property. The server removes the auth record and every session
|
|
247
|
+
* on every device, then fires an `auth.user.deleted` trigger.
|
|
248
|
+
*
|
|
249
|
+
* It does NOT delete the account's records in your collections. Koolbase
|
|
250
|
+
* cannot know whether a row should be deleted, anonymised, or kept for a
|
|
251
|
+
* statutory retention period. Subscribe a Function to `auth.user.deleted`
|
|
252
|
+
* and clean up there — it runs server-side, so a tab closing mid-flow
|
|
253
|
+
* cannot strand anything.
|
|
254
|
+
*/
|
|
255
|
+
deleteAccount(): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Every session the signed-in user has — a "where you're signed in" list.
|
|
258
|
+
*
|
|
259
|
+
* Newest first is not guaranteed; sort by createdAt if the order matters.
|
|
260
|
+
* The entry with `isCurrent` is this device.
|
|
261
|
+
*/
|
|
262
|
+
listSessions(): Promise<KoolbaseSessionInfo[]>;
|
|
263
|
+
/**
|
|
264
|
+
* Sign out one session by id.
|
|
265
|
+
*
|
|
266
|
+
* Revoking the current one ends this session too — the server does not
|
|
267
|
+
* refuse it, and the local session is cleared here so the app does not keep
|
|
268
|
+
* a token the server has dropped. Use logout() when that is what you mean.
|
|
269
|
+
*/
|
|
270
|
+
revokeSession(sessionId: string): Promise<void>;
|
|
271
|
+
/**
|
|
272
|
+
* Sign out every OTHER session, keeping this one.
|
|
273
|
+
*
|
|
274
|
+
* What "sign out my other devices" means after a lost phone. Returns how
|
|
275
|
+
* many were ended, so an app can say so rather than guess.
|
|
276
|
+
*/
|
|
277
|
+
revokeAllOtherSessions(): Promise<number>;
|
|
278
|
+
/**
|
|
279
|
+
* What has happened to this account — sign-ins, failures, lockouts,
|
|
280
|
+
* password changes.
|
|
281
|
+
*
|
|
282
|
+
* For a "recent security activity" screen. The server sanitizes each
|
|
283
|
+
* event, so this carries what that event type is allowed to say and
|
|
284
|
+
* nothing more.
|
|
285
|
+
*
|
|
286
|
+
* @param limit up to 200; the server caps it there.
|
|
287
|
+
*/
|
|
288
|
+
auditLog(options?: {
|
|
289
|
+
limit?: number;
|
|
290
|
+
offset?: number;
|
|
291
|
+
}): Promise<KoolbaseAuditPage>;
|
|
179
292
|
unlock(token: string): Promise<void>;
|
|
180
293
|
get currentUser(): KoolbaseUser | null;
|
|
181
294
|
get accessToken(): string | null;
|