@koolbase/core 12.0.0 → 12.2.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.
@@ -0,0 +1,114 @@
1
+ import { KoolbaseConfig } from './types.js';
2
+ import { KoolbaseError } from './errors.js';
3
+ /**
4
+ * The lifecycle status of a fiscal intent.
5
+ *
6
+ * A sale is durably recorded the moment `submit` returns; fiscal numbers and
7
+ * the authority's certification follow this state machine:
8
+ *
9
+ * - `queued` / `submitting` / `retrying` — sealed with allocated numbers;
10
+ * delivery to the authority is in progress.
11
+ * - `fiscalized` — the authority answered; for certifying document kinds the
12
+ * `certification` is present.
13
+ * - `blocked` — a precondition failed BEFORE any fiscal number was consumed
14
+ * (see `blockedReason`). Resubmitting the same `clientRef` after fixing the
15
+ * cause resumes it.
16
+ * - `attention` — the authority rejected the document, or its credential died
17
+ * after sealing. An operator resolves it; the register's chain waits behind
18
+ * it.
19
+ * - `voided` — terminally closed by an operator without fiscalization.
20
+ *
21
+ * `unknown` is the forward-compatible fallback: a status this SDK version has
22
+ * not heard of parses as unknown rather than throwing, so a server that grows
23
+ * a state does not break older clients.
24
+ */
25
+ export type FiscalStatus = 'created' | 'blocked' | 'queued' | 'submitting' | 'retrying' | 'fiscalized' | 'attention' | 'voided' | 'unknown';
26
+ /**
27
+ * The state of one fiscal intent.
28
+ *
29
+ * Jurisdiction-neutral by design: this SDK never learns a jurisdiction's
30
+ * vocabulary. Payloads travel as objects shaped by the device's adapter, and
31
+ * `certification` comes back as the authority granted it — for Ghana that
32
+ * means `ysdcregsig`, `ysdcrecnum`, `qr_code` and so on, which the SDK
33
+ * passes through without naming.
34
+ */
35
+ export interface FiscalIntentResult {
36
+ intentId: string;
37
+ status: FiscalStatus;
38
+ /** Why a `blocked` intent stopped, when the server said. */
39
+ blockedReason?: string;
40
+ /** Fiscal numbers allocated at sealing. */
41
+ numbers?: Record<string, number>;
42
+ /** When the intent was sealed and its numbers allocated. */
43
+ sealedAt?: string;
44
+ /**
45
+ * What the authority granted, once `status` is `fiscalized`. This is the
46
+ * receipt-rendering payload: for Ghana, the signature, receipt number and
47
+ * QR verification URL.
48
+ */
49
+ certification?: Record<string, unknown>;
50
+ }
51
+ /** True once the authority has certified the document. */
52
+ export declare function isFiscalized(r: FiscalIntentResult): boolean;
53
+ /** True while delivery to the authority is still in progress. */
54
+ export declare function isPending(r: FiscalIntentResult): boolean;
55
+ /** A fiscal request that failed. Carries the HTTP status where there was one. */
56
+ export declare class KoolbaseFiscalError extends KoolbaseError {
57
+ readonly statusCode?: number;
58
+ constructor(message: string, statusCode?: number);
59
+ }
60
+ /**
61
+ * Classify a response. Status and body in, result or error out.
62
+ *
63
+ * Exported for testability, and because auth handling belongs with the
64
+ * session hook rather than here — the same split the Flutter SDK makes.
65
+ */
66
+ export declare function decodeFiscalResponse(status: number, body: string): Promise<FiscalIntentResult>;
67
+ /**
68
+ * Koolbase Fiscal — submitting sales to a tax authority.
69
+ *
70
+ * Jurisdiction-neutral: the SDK moves payloads and reads back whatever the
71
+ * authority certified. Ghana's GRA E-VAT is the first jurisdiction; nothing
72
+ * here names it.
73
+ */
74
+ export declare class KoolbaseFiscal {
75
+ private config;
76
+ private getToken;
77
+ private onSessionExpired?;
78
+ constructor(config: KoolbaseConfig, getToken: () => Promise<string | null>, onSessionExpired?: () => Promise<void>);
79
+ private buildHeaders;
80
+ private decode;
81
+ /**
82
+ * Submit a sale for fiscalization.
83
+ *
84
+ * The sale is durably recorded the moment this returns; fiscal numbers and
85
+ * the authority's certification follow asynchronously — poll `status()`
86
+ * with the same `clientRef` to watch it.
87
+ *
88
+ * **On timeout, do not resubmit blindly.** The sale may have fiscalized
89
+ * anyway: the request reached the server and the response was lost. Poll
90
+ * `status()` with the same `clientRef` instead, which is idempotent and
91
+ * tells you what actually happened.
92
+ *
93
+ * @param clientRef your own reference for this sale; the idempotency key
94
+ * and the handle you poll and render receipts by.
95
+ */
96
+ submit(params: {
97
+ deviceId: string;
98
+ clientRef: string;
99
+ payload: Record<string, unknown>;
100
+ timeoutMs?: number;
101
+ }): Promise<FiscalIntentResult>;
102
+ /**
103
+ * Read an intent's current state by the reference it was submitted under.
104
+ *
105
+ * This is the receipt-rendering read: once the status is `fiscalized`, the
106
+ * `certification` carries what the receipt must show — for Ghana, the
107
+ * signature, receipt number and QR verification URL.
108
+ */
109
+ status(params: {
110
+ deviceId: string;
111
+ clientRef: string;
112
+ timeoutMs?: number;
113
+ }): Promise<FiscalIntentResult>;
114
+ }
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KoolbaseFiscal = exports.KoolbaseFiscalError = void 0;
4
+ exports.isFiscalized = isFiscalized;
5
+ exports.isPending = isPending;
6
+ exports.decodeFiscalResponse = decodeFiscalResponse;
7
+ const errors_js_1 = require("./errors.js");
8
+ const KNOWN_STATUSES = [
9
+ 'created', 'blocked', 'queued', 'submitting',
10
+ 'retrying', 'fiscalized', 'attention', 'voided',
11
+ ];
12
+ function parseStatus(raw) {
13
+ return typeof raw === 'string' && KNOWN_STATUSES.includes(raw)
14
+ ? raw
15
+ : 'unknown';
16
+ }
17
+ /** True once the authority has certified the document. */
18
+ function isFiscalized(r) {
19
+ return r.status === 'fiscalized';
20
+ }
21
+ /** True while delivery to the authority is still in progress. */
22
+ function isPending(r) {
23
+ return r.status === 'queued'
24
+ || r.status === 'submitting'
25
+ || r.status === 'retrying';
26
+ }
27
+ /** A fiscal request that failed. Carries the HTTP status where there was one. */
28
+ class KoolbaseFiscalError extends errors_js_1.KoolbaseError {
29
+ constructor(message, statusCode) {
30
+ super(message, 'fiscal_failed');
31
+ this.statusCode = statusCode;
32
+ this.name = 'KoolbaseFiscalError';
33
+ Object.setPrototypeOf(this, KoolbaseFiscalError.prototype);
34
+ }
35
+ }
36
+ exports.KoolbaseFiscalError = KoolbaseFiscalError;
37
+ function resultFromJson(json) {
38
+ const numbers = json.numbers;
39
+ return {
40
+ intentId: String(json.intent_id ?? ''),
41
+ status: parseStatus(json.status),
42
+ blockedReason: json.blocked_reason,
43
+ numbers: numbers ?? undefined,
44
+ sealedAt: json.sealed_at,
45
+ certification: json.certification,
46
+ };
47
+ }
48
+ /**
49
+ * Classify a response. Status and body in, result or error out.
50
+ *
51
+ * Exported for testability, and because auth handling belongs with the
52
+ * session hook rather than here — the same split the Flutter SDK makes.
53
+ */
54
+ async function decodeFiscalResponse(status, body) {
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(body);
58
+ }
59
+ catch {
60
+ throw new KoolbaseFiscalError(`fiscal: unreadable response (${status})`, status);
61
+ }
62
+ if ((status >= 200 && status < 300) || status === 202) {
63
+ return resultFromJson(parsed);
64
+ }
65
+ throw new KoolbaseFiscalError(parsed.error ?? 'fiscal: request failed', status);
66
+ }
67
+ // ─── KoolbaseFiscal ──────────────────────────────────────────────────────────
68
+ /**
69
+ * Koolbase Fiscal — submitting sales to a tax authority.
70
+ *
71
+ * Jurisdiction-neutral: the SDK moves payloads and reads back whatever the
72
+ * authority certified. Ghana's GRA E-VAT is the first jurisdiction; nothing
73
+ * here names it.
74
+ */
75
+ class KoolbaseFiscal {
76
+ constructor(config, getToken, onSessionExpired) {
77
+ this.config = config;
78
+ this.getToken = getToken;
79
+ this.onSessionExpired = onSessionExpired;
80
+ }
81
+ async buildHeaders() {
82
+ const token = await this.getToken();
83
+ return {
84
+ 'Content-Type': 'application/json',
85
+ 'x-api-key': this.config.publicKey,
86
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
87
+ };
88
+ }
89
+ async decode(res) {
90
+ if (res.status === 401 || res.status === 403) {
91
+ await this.onSessionExpired?.();
92
+ throw new errors_js_1.KoolbaseUnauthenticatedError(`fiscal: unauthenticated (${res.status})`);
93
+ }
94
+ return decodeFiscalResponse(res.status, await res.text());
95
+ }
96
+ /**
97
+ * Submit a sale for fiscalization.
98
+ *
99
+ * The sale is durably recorded the moment this returns; fiscal numbers and
100
+ * the authority's certification follow asynchronously — poll `status()`
101
+ * with the same `clientRef` to watch it.
102
+ *
103
+ * **On timeout, do not resubmit blindly.** The sale may have fiscalized
104
+ * anyway: the request reached the server and the response was lost. Poll
105
+ * `status()` with the same `clientRef` instead, which is idempotent and
106
+ * tells you what actually happened.
107
+ *
108
+ * @param clientRef your own reference for this sale; the idempotency key
109
+ * and the handle you poll and render receipts by.
110
+ */
111
+ async submit(params) {
112
+ const controller = new AbortController();
113
+ const timer = setTimeout(() => controller.abort(), params.timeoutMs ?? 30000);
114
+ try {
115
+ const res = await fetch(`${this.config.baseUrl}/v1/sdk/fiscal/submit`, {
116
+ method: 'POST',
117
+ headers: await this.buildHeaders(),
118
+ signal: controller.signal,
119
+ body: JSON.stringify({
120
+ device_id: params.deviceId,
121
+ client_ref: params.clientRef,
122
+ payload: params.payload,
123
+ }),
124
+ });
125
+ return await this.decode(res);
126
+ }
127
+ catch (e) {
128
+ if (e instanceof Error && e.name === 'AbortError') {
129
+ throw new KoolbaseFiscalError('fiscal submit timed out — the sale may still fiscalize; '
130
+ + 'poll status with the same clientRef');
131
+ }
132
+ throw e;
133
+ }
134
+ finally {
135
+ clearTimeout(timer);
136
+ }
137
+ }
138
+ /**
139
+ * Read an intent's current state by the reference it was submitted under.
140
+ *
141
+ * This is the receipt-rendering read: once the status is `fiscalized`, the
142
+ * `certification` carries what the receipt must show — for Ghana, the
143
+ * signature, receipt number and QR verification URL.
144
+ */
145
+ async status(params) {
146
+ const controller = new AbortController();
147
+ const timer = setTimeout(() => controller.abort(), params.timeoutMs ?? 15000);
148
+ try {
149
+ const q = new URLSearchParams({
150
+ device_id: params.deviceId,
151
+ client_ref: params.clientRef,
152
+ });
153
+ const res = await fetch(`${this.config.baseUrl}/v1/sdk/fiscal/status?${q.toString()}`, { method: 'GET', headers: await this.buildHeaders(), signal: controller.signal });
154
+ return await this.decode(res);
155
+ }
156
+ catch (e) {
157
+ if (e instanceof Error && e.name === 'AbortError') {
158
+ throw new KoolbaseFiscalError('fiscal status timed out');
159
+ }
160
+ throw e;
161
+ }
162
+ finally {
163
+ clearTimeout(timer);
164
+ }
165
+ }
166
+ }
167
+ exports.KoolbaseFiscal = KoolbaseFiscal;
@@ -14,6 +14,8 @@ export { KoolbaseFunctions } from './functions.js';
14
14
  export { KoolbaseRealtime } from './realtime.js';
15
15
  export { KoolbaseStorage } from './storage.js';
16
16
  export { KoolbaseAnalytics } from './analytics.js';
17
+ export { KoolbaseFiscal, KoolbaseFiscalError, decodeFiscalResponse, isFiscalized, isPending } from './fiscal.js';
18
+ export type { FiscalIntentResult, FiscalStatus } from './fiscal.js';
17
19
  export { KoolbaseMessaging } from './messaging.js';
18
20
  export type { RegisterTokenOptions } from './messaging.js';
19
21
  export { getOrCreateDeviceId } from './device-id.js';
package/dist/cjs/index.js CHANGED
@@ -19,7 +19,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
19
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
20
  };
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
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;
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
25
  __exportStar(require("./aggregate.js"), exports);
@@ -43,6 +43,12 @@ var storage_js_1 = require("./storage.js");
43
43
  Object.defineProperty(exports, "KoolbaseStorage", { enumerable: true, get: function () { return storage_js_1.KoolbaseStorage; } });
44
44
  var analytics_js_1 = require("./analytics.js");
45
45
  Object.defineProperty(exports, "KoolbaseAnalytics", { enumerable: true, get: function () { return analytics_js_1.KoolbaseAnalytics; } });
46
+ var fiscal_js_1 = require("./fiscal.js");
47
+ Object.defineProperty(exports, "KoolbaseFiscal", { enumerable: true, get: function () { return fiscal_js_1.KoolbaseFiscal; } });
48
+ Object.defineProperty(exports, "KoolbaseFiscalError", { enumerable: true, get: function () { return fiscal_js_1.KoolbaseFiscalError; } });
49
+ Object.defineProperty(exports, "decodeFiscalResponse", { enumerable: true, get: function () { return fiscal_js_1.decodeFiscalResponse; } });
50
+ Object.defineProperty(exports, "isFiscalized", { enumerable: true, get: function () { return fiscal_js_1.isFiscalized; } });
51
+ Object.defineProperty(exports, "isPending", { enumerable: true, get: function () { return fiscal_js_1.isPending; } });
46
52
  var messaging_js_1 = require("./messaging.js");
47
53
  Object.defineProperty(exports, "KoolbaseMessaging", { enumerable: true, get: function () { return messaging_js_1.KoolbaseMessaging; } });
48
54
  var device_id_js_1 = require("./device-id.js");
@@ -101,6 +101,14 @@ export declare class NetworkError extends KoolbaseAuthError {
101
101
  export declare class InvalidPhoneNumberError extends KoolbaseAuthError {
102
102
  constructor();
103
103
  }
104
+ /**
105
+ * The project has switched off signing in with an emailed code — 403
106
+ * `email_code_disabled`. Applies to every address alike, so it reveals
107
+ * nothing about which accounts exist.
108
+ */
109
+ export declare class EmailCodeDisabledError extends KoolbaseAuthError {
110
+ constructor();
111
+ }
104
112
  export declare class OtpExpiredError extends KoolbaseAuthError {
105
113
  constructor();
106
114
  }
@@ -249,3 +257,29 @@ export declare class InvalidGoogleTokenError extends KoolbaseAuthError {
249
257
  export declare class GoogleEmailRequiredError extends KoolbaseAuthError {
250
258
  constructor();
251
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
+ }
@@ -162,6 +162,18 @@ export class InvalidPhoneNumberError extends KoolbaseAuthError {
162
162
  Object.setPrototypeOf(this, InvalidPhoneNumberError.prototype);
163
163
  }
164
164
  }
165
+ /**
166
+ * The project has switched off signing in with an emailed code — 403
167
+ * `email_code_disabled`. Applies to every address alike, so it reveals
168
+ * nothing about which accounts exist.
169
+ */
170
+ export class EmailCodeDisabledError extends KoolbaseAuthError {
171
+ constructor() {
172
+ super('Signing in with an emailed code is switched off for this project', 'email_code_disabled');
173
+ this.name = 'EmailCodeDisabledError';
174
+ Object.setPrototypeOf(this, EmailCodeDisabledError.prototype);
175
+ }
176
+ }
165
177
  export class OtpExpiredError extends KoolbaseAuthError {
166
178
  constructor() {
167
179
  super('OTP has expired, please request a new code', 'otp_expired');
@@ -426,3 +438,54 @@ export class GoogleEmailRequiredError extends KoolbaseAuthError {
426
438
  Object.setPrototypeOf(this, GoogleEmailRequiredError.prototype);
427
439
  }
428
440
  }
441
+ // ─── Two-step sign-in (MFA) ─────────────────────────────────────────────────
442
+ /**
443
+ * The first factor passed and this account needs a second: sign-in is not
444
+ * finished. Pass `challengeToken` to `verifyMfa` with a code from the
445
+ * person's authenticator app, or to `verifyRecoveryCode`. Apps that never
446
+ * enable MFA never see this.
447
+ */
448
+ export class MfaRequiredError extends KoolbaseAuthError {
449
+ constructor(challengeToken, expiresAt) {
450
+ super('Two-step sign-in required', 'mfa_required');
451
+ this.name = 'MfaRequiredError';
452
+ this.challengeToken = challengeToken;
453
+ this.expiresAt = expiresAt;
454
+ Object.setPrototypeOf(this, MfaRequiredError.prototype);
455
+ }
456
+ }
457
+ export class RecentAuthRequiredError extends KoolbaseAuthError {
458
+ constructor() {
459
+ super('Sign in again to change two-step sign-in', 'recent_auth_required');
460
+ this.name = 'RecentAuthRequiredError';
461
+ Object.setPrototypeOf(this, RecentAuthRequiredError.prototype);
462
+ }
463
+ }
464
+ export class RecentMfaRequiredError extends KoolbaseAuthError {
465
+ constructor() {
466
+ super('Confirm with your authenticator first', 'recent_mfa_required');
467
+ this.name = 'RecentMfaRequiredError';
468
+ Object.setPrototypeOf(this, RecentMfaRequiredError.prototype);
469
+ }
470
+ }
471
+ export class MfaAlreadyEnabledError extends KoolbaseAuthError {
472
+ constructor() {
473
+ super('Two-step sign-in is already on for this account', 'mfa_already_enabled');
474
+ this.name = 'MfaAlreadyEnabledError';
475
+ Object.setPrototypeOf(this, MfaAlreadyEnabledError.prototype);
476
+ }
477
+ }
478
+ export class MfaEnrollmentNotFoundError extends KoolbaseAuthError {
479
+ constructor() {
480
+ super('No enrolment in progress; start again', 'mfa_enrollment_not_found');
481
+ this.name = 'MfaEnrollmentNotFoundError';
482
+ Object.setPrototypeOf(this, MfaEnrollmentNotFoundError.prototype);
483
+ }
484
+ }
485
+ export class MfaNotEnabledError extends KoolbaseAuthError {
486
+ constructor() {
487
+ super('Two-step sign-in is not on for this account', 'mfa_not_enabled');
488
+ this.name = 'MfaNotEnabledError';
489
+ Object.setPrototypeOf(this, MfaNotEnabledError.prototype);
490
+ }
491
+ }
@@ -302,12 +302,10 @@ export declare class KoolbaseAuth {
302
302
  validAccessToken(): Promise<string | null>;
303
303
  setSession(session: KoolbaseSession | null): Promise<void>;
304
304
  /**
305
- * @deprecated v1.9.0: Server endpoint /v1/sdk/auth/oauth not yet
306
- * shipped. This method previously routed to /v1/auth/oauth (dashboard
307
- * developer OAuth) which never created project-scoped end-user
308
- * sessions. Properly implemented in v1.10.0 with provider-specific
309
- * server endpoints under /v1/sdk/auth/oauth/{apple,google,github}.
310
- * Use email/password sign-in for now.
305
+ * @deprecated Never implemented; kept only so existing code compiles.
306
+ * Google and Apple sign-in are supported — use signInWithGoogle() or
307
+ * signInWithApple(). This used to say OAuth was not yet shipped and to
308
+ * use email and password instead, which stopped being true long ago.
311
309
  *
312
310
  * @throws Always throws KoolbaseAuthError('not_implemented').
313
311
  */
@@ -318,6 +316,74 @@ export declare class KoolbaseAuth {
318
316
  name?: string;
319
317
  avatarUrl?: string;
320
318
  }): Promise<never>;
319
+ /**
320
+ * Emails a six-digit sign-in code.
321
+ *
322
+ * Resolves the same way whether or not the address has an account, so it
323
+ * cannot be used to check who is registered. A new address receives a code
324
+ * only while the project accepts sign-ups; a disabled account receives
325
+ * nothing.
326
+ *
327
+ * @throws EmailCodeDisabledError if the project has switched this off
328
+ * @throws RateLimitError after too many requests for one address
329
+ */
330
+ requestEmailCode(params: {
331
+ email: string;
332
+ }): Promise<void>;
333
+ /**
334
+ * Signs in with a code from requestEmailCode(), storing the session exactly
335
+ * as login() does. An unknown address becomes an account only if the
336
+ * project still accepts sign-ups at this moment. Each code works once and
337
+ * allows three attempts.
338
+ *
339
+ * @throws OtpInvalidError, OtpExpiredError, OtpMaxAttemptsError
340
+ * @throws EmailCodeDisabledError if the project has switched this off
341
+ */
342
+ signInWithEmailCode(params: {
343
+ email: string;
344
+ code: string;
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[]>;
321
387
  sendOtp(params: SendOtpParams): Promise<OtpSendResult>;
322
388
  verifyOtp(params: VerifyOtpParams): Promise<PhoneVerifyResult>;
323
389
  linkPhone(params: LinkPhoneParams): Promise<void>;