@23blocks/angular 14.4.0 β 14.5.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 +27 -0
- package/dist/fesm2022/23blocks-angular.mjs +352 -19
- package/dist/fesm2022/23blocks-angular.mjs.map +1 -1
- package/dist/index.d.ts +59 -4
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
## 14.5.1 (2026-03-14)
|
|
2
|
+
|
|
3
|
+
### π©Ή Fixes
|
|
4
|
+
|
|
5
|
+
- **@23blocks/angular:** start lifecycle on OAuth login methods ([6af5acd](https://github.com/23blocks-OS/frontend-sdk/commit/6af5acd))
|
|
6
|
+
- **@23blocks/angular:** fix lifecycle stop-before-signOut and token storage race ([e009c86](https://github.com/23blocks-OS/frontend-sdk/commit/e009c86))
|
|
7
|
+
|
|
8
|
+
### π Documentation
|
|
9
|
+
|
|
10
|
+
- update llms.txt and JSDoc for token lifecycle across all packages ([74d8319](https://github.com/23blocks-OS/frontend-sdk/commit/74d8319))
|
|
11
|
+
|
|
12
|
+
### β€οΈ Thank You
|
|
13
|
+
|
|
14
|
+
- Claude Opus 4.6
|
|
15
|
+
- Juan Pelaez
|
|
16
|
+
|
|
17
|
+
## 14.5.0 (2026-03-14)
|
|
18
|
+
|
|
19
|
+
### π Features
|
|
20
|
+
|
|
21
|
+
- **@23blocks/angular:** integrate token lifecycle with AuthenticationService ([df3c6c3](https://github.com/23blocks-OS/frontend-sdk/commit/df3c6c3))
|
|
22
|
+
|
|
23
|
+
### β€οΈ Thank You
|
|
24
|
+
|
|
25
|
+
- Claude Opus 4.6
|
|
26
|
+
- Juan Pelaez
|
|
27
|
+
|
|
1
28
|
## 14.4.0 (2026-03-09)
|
|
2
29
|
|
|
3
30
|
### π Features
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, makeEnvironmentProviders, Optional, Inject, Injectable } from '@angular/core';
|
|
3
3
|
import { createHttpTransport } from '@23blocks/transport-http';
|
|
4
|
-
import {
|
|
4
|
+
import { BlockErrorException } from '@23blocks/contracts';
|
|
5
5
|
import { createAuthenticationBlock } from '@23blocks/block-authentication';
|
|
6
|
+
import { from, tap } from 'rxjs';
|
|
6
7
|
import { createSearchBlock } from '@23blocks/block-search';
|
|
7
8
|
import { createProductsBlock } from '@23blocks/block-products';
|
|
8
9
|
import { createCrmBlock } from '@23blocks/block-crm';
|
|
@@ -148,6 +149,10 @@ const WALLET_CONFIG = new InjectionToken('23blocks.wallet.config');
|
|
|
148
149
|
*/
|
|
149
150
|
const RAG_CONFIG = new InjectionToken('23blocks.rag.config');
|
|
150
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Injection token for the token lifecycle manager
|
|
154
|
+
*/
|
|
155
|
+
const TOKEN_LIFECYCLE = new InjectionToken('23blocks.token-lifecycle');
|
|
151
156
|
/**
|
|
152
157
|
* Injection token for the token manager (internal use)
|
|
153
158
|
*/
|
|
@@ -287,6 +292,220 @@ function createTransportWithAuth(baseUrl, config, tokenManager) {
|
|
|
287
292
|
},
|
|
288
293
|
});
|
|
289
294
|
}
|
|
295
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
296
|
+
// Token Lifecycle Helpers
|
|
297
|
+
// CANONICAL SOURCE: packages/sdk/src/lib/token-lifecycle.ts
|
|
298
|
+
// These are inlined here to avoid adding @23blocks/sdk as a dependency
|
|
299
|
+
// (which would change ng-packagr and consumer dependency requirements).
|
|
300
|
+
// When fixing bugs, update all three copies: sdk, react, angular.
|
|
301
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
302
|
+
function decodeJwtExp(token) {
|
|
303
|
+
try {
|
|
304
|
+
const parts = token.split('.');
|
|
305
|
+
if (parts.length !== 3)
|
|
306
|
+
return null;
|
|
307
|
+
let payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
308
|
+
const pad = payload.length % 4;
|
|
309
|
+
if (pad)
|
|
310
|
+
payload += '='.repeat(4 - pad);
|
|
311
|
+
let decoded;
|
|
312
|
+
if (typeof atob === 'function') {
|
|
313
|
+
decoded = atob(payload);
|
|
314
|
+
}
|
|
315
|
+
else if (typeof Buffer !== 'undefined') {
|
|
316
|
+
decoded = Buffer.from(payload, 'base64').toString('utf-8');
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
const parsed = JSON.parse(decoded);
|
|
322
|
+
return typeof parsed.exp === 'number' ? parsed.exp : null;
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function isBrowserEnv() {
|
|
329
|
+
try {
|
|
330
|
+
return typeof window !== 'undefined'
|
|
331
|
+
&& typeof window.localStorage !== 'undefined'
|
|
332
|
+
&& typeof window.localStorage.getItem === 'function';
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function createLifecycleManager(tokenManager, refreshFn, config = {}) {
|
|
339
|
+
const { refreshBufferSeconds = 120, enableVisibilityRefresh = true, enableProactiveRefresh = true, } = config;
|
|
340
|
+
const listeners = new Set();
|
|
341
|
+
let refreshTimer = null;
|
|
342
|
+
let refreshPromise = null;
|
|
343
|
+
let visibilityHandler = null;
|
|
344
|
+
let destroyed = false;
|
|
345
|
+
let running = false;
|
|
346
|
+
function notify(event) {
|
|
347
|
+
listeners.forEach((l) => { try {
|
|
348
|
+
l(event);
|
|
349
|
+
}
|
|
350
|
+
catch { } });
|
|
351
|
+
}
|
|
352
|
+
function clearTimer() {
|
|
353
|
+
if (refreshTimer !== null) {
|
|
354
|
+
clearTimeout(refreshTimer);
|
|
355
|
+
refreshTimer = null;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function scheduleRefresh() {
|
|
359
|
+
if (!enableProactiveRefresh || destroyed || !running)
|
|
360
|
+
return;
|
|
361
|
+
clearTimer();
|
|
362
|
+
const accessToken = tokenManager.getAccessToken();
|
|
363
|
+
if (!accessToken)
|
|
364
|
+
return;
|
|
365
|
+
const exp = decodeJwtExp(accessToken);
|
|
366
|
+
if (!exp)
|
|
367
|
+
return;
|
|
368
|
+
const refreshInSeconds = (exp - Math.floor(Date.now() / 1000)) - refreshBufferSeconds;
|
|
369
|
+
if (refreshInSeconds <= 0) {
|
|
370
|
+
refreshNow().catch(() => { });
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
refreshTimer = setTimeout(() => {
|
|
374
|
+
if (!destroyed && running)
|
|
375
|
+
refreshNow().catch(() => { });
|
|
376
|
+
}, refreshInSeconds * 1000);
|
|
377
|
+
}
|
|
378
|
+
function handleVisibilityChange() {
|
|
379
|
+
if (destroyed || !running || typeof document === 'undefined')
|
|
380
|
+
return;
|
|
381
|
+
if (document.visibilityState === 'visible') {
|
|
382
|
+
const accessToken = tokenManager.getAccessToken();
|
|
383
|
+
if (!accessToken)
|
|
384
|
+
return;
|
|
385
|
+
const exp = decodeJwtExp(accessToken);
|
|
386
|
+
if (!exp) {
|
|
387
|
+
refreshNow().catch(() => { });
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const secondsUntilExpiry = exp - Math.floor(Date.now() / 1000);
|
|
391
|
+
if (secondsUntilExpiry <= refreshBufferSeconds) {
|
|
392
|
+
refreshNow().catch(() => { });
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
scheduleRefresh();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async function refreshNow() {
|
|
400
|
+
if (destroyed)
|
|
401
|
+
throw new Error('[23blocks] Lifecycle destroyed');
|
|
402
|
+
if (refreshPromise)
|
|
403
|
+
return refreshPromise;
|
|
404
|
+
refreshPromise = (async () => {
|
|
405
|
+
try {
|
|
406
|
+
const rt = tokenManager.getRefreshToken();
|
|
407
|
+
if (!rt)
|
|
408
|
+
throw new Error('No refresh token');
|
|
409
|
+
const result = await refreshFn(rt);
|
|
410
|
+
// Guard: don't store tokens if lifecycle was stopped/destroyed during the async call
|
|
411
|
+
if (!running || destroyed)
|
|
412
|
+
return result.accessToken;
|
|
413
|
+
tokenManager.setTokens(result.accessToken, result.refreshToken);
|
|
414
|
+
scheduleRefresh();
|
|
415
|
+
notify('TOKEN_REFRESHED');
|
|
416
|
+
return result.accessToken;
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
clearTimer();
|
|
420
|
+
tokenManager.clearTokens();
|
|
421
|
+
running = false;
|
|
422
|
+
notify('SESSION_EXPIRED');
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
425
|
+
finally {
|
|
426
|
+
refreshPromise = null;
|
|
427
|
+
}
|
|
428
|
+
})();
|
|
429
|
+
return refreshPromise;
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
start() {
|
|
433
|
+
if (destroyed)
|
|
434
|
+
return;
|
|
435
|
+
running = true;
|
|
436
|
+
scheduleRefresh();
|
|
437
|
+
if (enableVisibilityRefresh && isBrowserEnv() && !visibilityHandler && typeof document !== 'undefined') {
|
|
438
|
+
visibilityHandler = handleVisibilityChange;
|
|
439
|
+
document.addEventListener('visibilitychange', visibilityHandler);
|
|
440
|
+
}
|
|
441
|
+
notify('SIGNED_IN');
|
|
442
|
+
},
|
|
443
|
+
stop() {
|
|
444
|
+
running = false;
|
|
445
|
+
clearTimer();
|
|
446
|
+
refreshPromise = null;
|
|
447
|
+
notify('SIGNED_OUT');
|
|
448
|
+
},
|
|
449
|
+
onAuthStateChanged(listener) {
|
|
450
|
+
listeners.add(listener);
|
|
451
|
+
return () => { listeners.delete(listener); };
|
|
452
|
+
},
|
|
453
|
+
refreshNow,
|
|
454
|
+
destroy() {
|
|
455
|
+
destroyed = true;
|
|
456
|
+
running = false;
|
|
457
|
+
clearTimer();
|
|
458
|
+
refreshPromise = null;
|
|
459
|
+
if (visibilityHandler && typeof document !== 'undefined') {
|
|
460
|
+
document.removeEventListener('visibilitychange', visibilityHandler);
|
|
461
|
+
visibilityHandler = null;
|
|
462
|
+
}
|
|
463
|
+
listeners.clear();
|
|
464
|
+
},
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
function createRetryTransport(baseTransport, getLifecycle) {
|
|
468
|
+
async function withRetry(fn) {
|
|
469
|
+
try {
|
|
470
|
+
return await fn();
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
if (error instanceof BlockErrorException && error.status === 401) {
|
|
474
|
+
const lc = getLifecycle();
|
|
475
|
+
if (lc) {
|
|
476
|
+
try {
|
|
477
|
+
await lc.refreshNow();
|
|
478
|
+
return await fn();
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
throw error;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
throw error;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
get(path, options) {
|
|
490
|
+
return withRetry(() => baseTransport.get(path, options));
|
|
491
|
+
},
|
|
492
|
+
post(path, body, options) {
|
|
493
|
+
return withRetry(() => baseTransport.post(path, body, options));
|
|
494
|
+
},
|
|
495
|
+
patch(path, body, options) {
|
|
496
|
+
return withRetry(() => baseTransport.patch(path, body, options));
|
|
497
|
+
},
|
|
498
|
+
put(path, body, options) {
|
|
499
|
+
return withRetry(() => baseTransport.put(path, body, options));
|
|
500
|
+
},
|
|
501
|
+
delete(path, options) {
|
|
502
|
+
return withRetry(() => baseTransport.delete(path, options));
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
507
|
+
// Providers
|
|
508
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
290
509
|
/**
|
|
291
510
|
* Provide 23blocks services with simplified configuration.
|
|
292
511
|
*
|
|
@@ -335,15 +554,20 @@ function createTransportWithAuth(baseUrl, config, tokenManager) {
|
|
|
335
554
|
function provideBlocks23(config) {
|
|
336
555
|
// Block config for all services
|
|
337
556
|
const blockConfig = { apiKey: config.apiKey, tenantId: config.tenantId };
|
|
557
|
+
const lifecycleEnabled = config.authMode !== 'cookie' && config.tokenLifecycle !== false;
|
|
338
558
|
// Helper to create transport provider for a service URL
|
|
339
559
|
const createTransportProvider = (token, url) => ({
|
|
340
560
|
provide: token,
|
|
341
|
-
useFactory: (tokenManager) => {
|
|
561
|
+
useFactory: (tokenManager, lifecycle) => {
|
|
342
562
|
if (!url)
|
|
343
563
|
return null;
|
|
344
|
-
|
|
564
|
+
const base = createTransportWithAuth(url, config, tokenManager);
|
|
565
|
+
if (lifecycleEnabled && lifecycle) {
|
|
566
|
+
return createRetryTransport(base, () => lifecycle);
|
|
567
|
+
}
|
|
568
|
+
return base;
|
|
345
569
|
},
|
|
346
|
-
deps: [TOKEN_MANAGER],
|
|
570
|
+
deps: [TOKEN_MANAGER, TOKEN_LIFECYCLE],
|
|
347
571
|
});
|
|
348
572
|
const providers = [
|
|
349
573
|
// Store config for injection
|
|
@@ -356,7 +580,34 @@ function provideBlocks23(config) {
|
|
|
356
580
|
return createTokenManager(config.apiKey, storage, config.tenantId);
|
|
357
581
|
},
|
|
358
582
|
},
|
|
359
|
-
//
|
|
583
|
+
// Token lifecycle manager - uses a dedicated refresh transport (avoids circular retry)
|
|
584
|
+
{
|
|
585
|
+
provide: TOKEN_LIFECYCLE,
|
|
586
|
+
useFactory: (tokenManager) => {
|
|
587
|
+
if (!lifecycleEnabled || !config.urls.authentication)
|
|
588
|
+
return null;
|
|
589
|
+
// Dedicated transport for refresh calls β NOT wrapped with retry
|
|
590
|
+
const refreshTransport = createTransportWithAuth(config.urls.authentication, config, tokenManager);
|
|
591
|
+
const authBlock = createAuthenticationBlock(refreshTransport, blockConfig);
|
|
592
|
+
const refreshFn = async (refreshToken) => {
|
|
593
|
+
const response = await authBlock.auth.refreshToken({ refreshToken });
|
|
594
|
+
return {
|
|
595
|
+
accessToken: response.accessToken,
|
|
596
|
+
refreshToken: response.refreshToken,
|
|
597
|
+
expiresIn: response.expiresIn,
|
|
598
|
+
};
|
|
599
|
+
};
|
|
600
|
+
const lcConfig = typeof config.tokenLifecycle === 'object' ? config.tokenLifecycle : {};
|
|
601
|
+
const lc = createLifecycleManager(tokenManager, refreshFn, lcConfig);
|
|
602
|
+
// Auto-start if tokens exist (page reload)
|
|
603
|
+
if (tokenManager.getAccessToken() && tokenManager.getRefreshToken()) {
|
|
604
|
+
lc.start();
|
|
605
|
+
}
|
|
606
|
+
return lc;
|
|
607
|
+
},
|
|
608
|
+
deps: [TOKEN_MANAGER],
|
|
609
|
+
},
|
|
610
|
+
// Per-service transport factories (null if URL not configured, wrapped with retry if lifecycle enabled)
|
|
360
611
|
createTransportProvider(AUTHENTICATION_TRANSPORT, config.urls.authentication),
|
|
361
612
|
createTransportProvider(SEARCH_TRANSPORT, config.urls.search),
|
|
362
613
|
createTransportProvider(PRODUCTS_TRANSPORT, config.urls.products),
|
|
@@ -448,15 +699,20 @@ function provideBlocks23(config) {
|
|
|
448
699
|
function getBlocks23Providers(config) {
|
|
449
700
|
// Block config for all services
|
|
450
701
|
const blockConfig = { apiKey: config.apiKey, tenantId: config.tenantId };
|
|
702
|
+
const lifecycleEnabled = config.authMode !== 'cookie' && config.tokenLifecycle !== false;
|
|
451
703
|
// Helper to create transport provider for a service URL
|
|
452
704
|
const createTransportProvider = (token, url) => ({
|
|
453
705
|
provide: token,
|
|
454
|
-
useFactory: (tokenManager) => {
|
|
706
|
+
useFactory: (tokenManager, lifecycle) => {
|
|
455
707
|
if (!url)
|
|
456
708
|
return null;
|
|
457
|
-
|
|
709
|
+
const base = createTransportWithAuth(url, config, tokenManager);
|
|
710
|
+
if (lifecycleEnabled && lifecycle) {
|
|
711
|
+
return createRetryTransport(base, () => lifecycle);
|
|
712
|
+
}
|
|
713
|
+
return base;
|
|
458
714
|
},
|
|
459
|
-
deps: [TOKEN_MANAGER],
|
|
715
|
+
deps: [TOKEN_MANAGER, TOKEN_LIFECYCLE],
|
|
460
716
|
});
|
|
461
717
|
return [
|
|
462
718
|
// Store config for injection
|
|
@@ -469,7 +725,28 @@ function getBlocks23Providers(config) {
|
|
|
469
725
|
return createTokenManager(config.apiKey, storage, config.tenantId);
|
|
470
726
|
},
|
|
471
727
|
},
|
|
472
|
-
//
|
|
728
|
+
// Token lifecycle manager
|
|
729
|
+
{
|
|
730
|
+
provide: TOKEN_LIFECYCLE,
|
|
731
|
+
useFactory: (tokenManager) => {
|
|
732
|
+
if (!lifecycleEnabled || !config.urls.authentication)
|
|
733
|
+
return null;
|
|
734
|
+
const refreshTransport = createTransportWithAuth(config.urls.authentication, config, tokenManager);
|
|
735
|
+
const authBlock = createAuthenticationBlock(refreshTransport, blockConfig);
|
|
736
|
+
const refreshFn = async (refreshToken) => {
|
|
737
|
+
const response = await authBlock.auth.refreshToken({ refreshToken });
|
|
738
|
+
return { accessToken: response.accessToken, refreshToken: response.refreshToken, expiresIn: response.expiresIn };
|
|
739
|
+
};
|
|
740
|
+
const lcConfig = typeof config.tokenLifecycle === 'object' ? config.tokenLifecycle : {};
|
|
741
|
+
const lc = createLifecycleManager(tokenManager, refreshFn, lcConfig);
|
|
742
|
+
if (tokenManager.getAccessToken() && tokenManager.getRefreshToken()) {
|
|
743
|
+
lc.start();
|
|
744
|
+
}
|
|
745
|
+
return lc;
|
|
746
|
+
},
|
|
747
|
+
deps: [TOKEN_MANAGER],
|
|
748
|
+
},
|
|
749
|
+
// Per-service transport factories (null if URL not configured, wrapped with retry if lifecycle enabled)
|
|
473
750
|
createTransportProvider(AUTHENTICATION_TRANSPORT, config.urls.authentication),
|
|
474
751
|
createTransportProvider(SEARCH_TRANSPORT, config.urls.search),
|
|
475
752
|
createTransportProvider(PRODUCTS_TRANSPORT, config.urls.products),
|
|
@@ -729,11 +1006,13 @@ class AuthenticationService {
|
|
|
729
1006
|
block;
|
|
730
1007
|
tokenManager;
|
|
731
1008
|
simpleConfig;
|
|
732
|
-
|
|
1009
|
+
lifecycle;
|
|
1010
|
+
constructor(serviceTransport, legacyTransport, config, tokenManager, simpleConfig, lifecycle) {
|
|
733
1011
|
const transport = serviceTransport ?? legacyTransport;
|
|
734
1012
|
this.block = transport ? createAuthenticationBlock(transport, config) : null;
|
|
735
1013
|
this.tokenManager = tokenManager;
|
|
736
1014
|
this.simpleConfig = simpleConfig;
|
|
1015
|
+
this.lifecycle = lifecycle;
|
|
737
1016
|
}
|
|
738
1017
|
ensureConfigured() {
|
|
739
1018
|
if (!this.block) {
|
|
@@ -768,7 +1047,11 @@ class AuthenticationService {
|
|
|
768
1047
|
* ```
|
|
769
1048
|
*/
|
|
770
1049
|
signIn(request) {
|
|
771
|
-
return from(this.ensureConfigured().auth.signIn(request)).pipe(tap((response) =>
|
|
1050
|
+
return from(this.ensureConfigured().auth.signIn(request)).pipe(tap((response) => {
|
|
1051
|
+
this.storeTokens(response);
|
|
1052
|
+
if (response.accessToken)
|
|
1053
|
+
this.lifecycle?.start();
|
|
1054
|
+
}));
|
|
772
1055
|
}
|
|
773
1056
|
/**
|
|
774
1057
|
* Sign up a new user.
|
|
@@ -784,6 +1067,7 @@ class AuthenticationService {
|
|
|
784
1067
|
return from(this.ensureConfigured().auth.signUp(request)).pipe(tap((response) => {
|
|
785
1068
|
if (this.isTokenMode && this.tokenManager && response.accessToken) {
|
|
786
1069
|
this.tokenManager.setTokens(response.accessToken);
|
|
1070
|
+
this.lifecycle?.start();
|
|
787
1071
|
}
|
|
788
1072
|
}));
|
|
789
1073
|
}
|
|
@@ -794,6 +1078,8 @@ class AuthenticationService {
|
|
|
794
1078
|
* @returns Observable that completes on successful sign-out
|
|
795
1079
|
*/
|
|
796
1080
|
signOut() {
|
|
1081
|
+
// Stop lifecycle BEFORE the API call to prevent refresh during signOut
|
|
1082
|
+
this.lifecycle?.stop();
|
|
797
1083
|
return from(this.ensureConfigured().auth.signOut()).pipe(tap(() => {
|
|
798
1084
|
if (this.isTokenMode && this.tokenManager) {
|
|
799
1085
|
this.tokenManager.clearTokens();
|
|
@@ -819,7 +1105,11 @@ class AuthenticationService {
|
|
|
819
1105
|
* @returns Observable emitting SignInResponse with `user`, `accessToken`, optional `refreshToken`
|
|
820
1106
|
*/
|
|
821
1107
|
verifyMagicLink(request) {
|
|
822
|
-
return from(this.ensureConfigured().auth.verifyMagicLink(request)).pipe(tap((response) =>
|
|
1108
|
+
return from(this.ensureConfigured().auth.verifyMagicLink(request)).pipe(tap((response) => {
|
|
1109
|
+
this.storeTokens(response);
|
|
1110
|
+
if (response.accessToken)
|
|
1111
|
+
this.lifecycle?.start();
|
|
1112
|
+
}));
|
|
823
1113
|
}
|
|
824
1114
|
/**
|
|
825
1115
|
* Accept an invitation and create the user's account.
|
|
@@ -830,7 +1120,11 @@ class AuthenticationService {
|
|
|
830
1120
|
* optional `refreshToken`
|
|
831
1121
|
*/
|
|
832
1122
|
acceptInvitation(request) {
|
|
833
|
-
return from(this.ensureConfigured().auth.acceptInvitation(request)).pipe(tap((response) =>
|
|
1123
|
+
return from(this.ensureConfigured().auth.acceptInvitation(request)).pipe(tap((response) => {
|
|
1124
|
+
this.storeTokens(response);
|
|
1125
|
+
if (response.accessToken)
|
|
1126
|
+
this.lifecycle?.start();
|
|
1127
|
+
}));
|
|
834
1128
|
}
|
|
835
1129
|
/**
|
|
836
1130
|
* Sign in via Facebook OAuth.
|
|
@@ -840,7 +1134,11 @@ class AuthenticationService {
|
|
|
840
1134
|
* @returns Observable emitting SignInResponse with `user` and tokens
|
|
841
1135
|
*/
|
|
842
1136
|
facebookLogin(request) {
|
|
843
|
-
return from(this.ensureConfigured().oauth.facebookLogin(request)).pipe(tap((response) =>
|
|
1137
|
+
return from(this.ensureConfigured().oauth.facebookLogin(request)).pipe(tap((response) => {
|
|
1138
|
+
this.storeTokens(response);
|
|
1139
|
+
if (response.accessToken)
|
|
1140
|
+
this.lifecycle?.start();
|
|
1141
|
+
}));
|
|
844
1142
|
}
|
|
845
1143
|
/**
|
|
846
1144
|
* Sign in via Google OAuth.
|
|
@@ -850,7 +1148,11 @@ class AuthenticationService {
|
|
|
850
1148
|
* @returns Observable emitting SignInResponse with `user` and tokens
|
|
851
1149
|
*/
|
|
852
1150
|
googleLogin(request) {
|
|
853
|
-
return from(this.ensureConfigured().oauth.googleLogin(request)).pipe(tap((response) =>
|
|
1151
|
+
return from(this.ensureConfigured().oauth.googleLogin(request)).pipe(tap((response) => {
|
|
1152
|
+
this.storeTokens(response);
|
|
1153
|
+
if (response.accessToken)
|
|
1154
|
+
this.lifecycle?.start();
|
|
1155
|
+
}));
|
|
854
1156
|
}
|
|
855
1157
|
/**
|
|
856
1158
|
* Sign in via tenant-specific login (white-label authentication).
|
|
@@ -860,7 +1162,11 @@ class AuthenticationService {
|
|
|
860
1162
|
* @returns Observable emitting SignInResponse with `user` and tokens
|
|
861
1163
|
*/
|
|
862
1164
|
tenantLogin(request) {
|
|
863
|
-
return from(this.ensureConfigured().oauth.tenantLogin(request)).pipe(tap((response) =>
|
|
1165
|
+
return from(this.ensureConfigured().oauth.tenantLogin(request)).pipe(tap((response) => {
|
|
1166
|
+
this.storeTokens(response);
|
|
1167
|
+
if (response.accessToken)
|
|
1168
|
+
this.lifecycle?.start();
|
|
1169
|
+
}));
|
|
864
1170
|
}
|
|
865
1171
|
/**
|
|
866
1172
|
* Request a 6-digit OTP code for password reset (mobile flow).
|
|
@@ -935,6 +1241,28 @@ class AuthenticationService {
|
|
|
935
1241
|
return !!this.tokenManager.getAccessToken();
|
|
936
1242
|
}
|
|
937
1243
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1244
|
+
// Token Lifecycle
|
|
1245
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1246
|
+
/**
|
|
1247
|
+
* Subscribe to auth state changes (token refreshed, session expired, etc.).
|
|
1248
|
+
* Returns an unsubscribe function.
|
|
1249
|
+
* Only active when tokenLifecycle is enabled.
|
|
1250
|
+
*/
|
|
1251
|
+
onAuthStateChanged(listener) {
|
|
1252
|
+
return this.lifecycle?.onAuthStateChanged(listener) ?? (() => { });
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Force an immediate token refresh.
|
|
1256
|
+
* Returns the new access token. Throws if lifecycle is unavailable or refresh fails.
|
|
1257
|
+
*/
|
|
1258
|
+
refreshSession() {
|
|
1259
|
+
if (!this.lifecycle) {
|
|
1260
|
+
return Promise.reject(new Error('[23blocks] Token lifecycle is not available. ' +
|
|
1261
|
+
'Ensure authMode is "token" and tokenLifecycle is not disabled.'));
|
|
1262
|
+
}
|
|
1263
|
+
return this.lifecycle.refreshNow();
|
|
1264
|
+
}
|
|
1265
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
938
1266
|
// Delegated sub-services (Promise-based, auto-sync with block API)
|
|
939
1267
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
940
1268
|
/** Core auth operations (signIn, signUp, signOut, password reset link+OTP, magic links, invitations). Promise-based. */
|
|
@@ -999,7 +1327,7 @@ class AuthenticationService {
|
|
|
999
1327
|
get oidc() { return this.ensureConfigured().oidc; }
|
|
1000
1328
|
/** Direct access to the underlying AuthenticationBlock instance */
|
|
1001
1329
|
get authenticationBlock() { return this.ensureConfigured(); }
|
|
1002
|
-
static Ι΅fac = i0.Ι΅Ι΅ngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthenticationService, deps: [{ token: AUTHENTICATION_TRANSPORT, optional: true }, { token: TRANSPORT, optional: true }, { token: AUTHENTICATION_CONFIG }, { token: TOKEN_MANAGER, optional: true }, { token: SIMPLE_CONFIG, optional: true }], target: i0.Ι΅Ι΅FactoryTarget.Injectable });
|
|
1330
|
+
static Ι΅fac = i0.Ι΅Ι΅ngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthenticationService, deps: [{ token: AUTHENTICATION_TRANSPORT, optional: true }, { token: TRANSPORT, optional: true }, { token: AUTHENTICATION_CONFIG }, { token: TOKEN_MANAGER, optional: true }, { token: SIMPLE_CONFIG, optional: true }, { token: TOKEN_LIFECYCLE, optional: true }], target: i0.Ι΅Ι΅FactoryTarget.Injectable });
|
|
1003
1331
|
static Ι΅prov = i0.Ι΅Ι΅ngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthenticationService, providedIn: 'root' });
|
|
1004
1332
|
}
|
|
1005
1333
|
i0.Ι΅Ι΅ngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthenticationService, decorators: [{
|
|
@@ -1028,6 +1356,11 @@ i0.Ι΅Ι΅ngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1028
1356
|
}, {
|
|
1029
1357
|
type: Inject,
|
|
1030
1358
|
args: [SIMPLE_CONFIG]
|
|
1359
|
+
}] }, { type: undefined, decorators: [{
|
|
1360
|
+
type: Optional
|
|
1361
|
+
}, {
|
|
1362
|
+
type: Inject,
|
|
1363
|
+
args: [TOKEN_LIFECYCLE]
|
|
1031
1364
|
}] }] });
|
|
1032
1365
|
|
|
1033
1366
|
/**
|
|
@@ -2121,7 +2454,7 @@ i0.Ι΅Ι΅ngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2121
2454
|
}] }] });
|
|
2122
2455
|
|
|
2123
2456
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
2124
|
-
// Main API (Recommended) β
|
|
2457
|
+
// Main API (Recommended) β token lifecycle with auto-refresh and 401 retry
|
|
2125
2458
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
2126
2459
|
|
|
2127
2460
|
// Angular bindings β search, crm, files, onboarding aligned with API strong params
|
|
@@ -2130,5 +2463,5 @@ i0.Ι΅Ι΅ngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2130
2463
|
* Generated bundle index. Do not edit.
|
|
2131
2464
|
*/
|
|
2132
2465
|
|
|
2133
|
-
export { ASSETS_CONFIG, ASSETS_TRANSPORT, AUTHENTICATION_CONFIG, AUTHENTICATION_TRANSPORT, AssetsService, AuthenticationService, CAMPAIGNS_CONFIG, CAMPAIGNS_TRANSPORT, COMPANY_CONFIG, COMPANY_TRANSPORT, CONTENT_CONFIG, CONTENT_TRANSPORT, CONVERSATIONS_CONFIG, CONVERSATIONS_TRANSPORT, CRM_CONFIG, CRM_TRANSPORT, CampaignsService, CompanyService, ContentService, ConversationsService, CrmService, FILES_CONFIG, FILES_TRANSPORT, FORMS_CONFIG, FORMS_TRANSPORT, FilesService, FormsService, GEOLOCATION_CONFIG, GEOLOCATION_TRANSPORT, GeolocationService, JARVIS_CONFIG, JARVIS_TRANSPORT, JarvisService, ONBOARDING_CONFIG, ONBOARDING_TRANSPORT, OnboardingService, PRODUCTS_CONFIG, PRODUCTS_TRANSPORT, PROVIDER_CONFIG, ProductsService, RAG_CONFIG, RAG_TRANSPORT, REWARDS_CONFIG, REWARDS_TRANSPORT, RagService, RewardsService, SALES_CONFIG, SALES_TRANSPORT, SEARCH_CONFIG, SEARCH_TRANSPORT, SIMPLE_CONFIG, SalesService, SearchService, TOKEN_MANAGER, TRANSPORT, UNIVERSITY_CONFIG, UNIVERSITY_TRANSPORT, UniversityService, WALLET_CONFIG, WALLET_TRANSPORT, WalletService, get23BlocksProviders, getBlocks23Providers, provide23Blocks, provideBlocks23 };
|
|
2466
|
+
export { ASSETS_CONFIG, ASSETS_TRANSPORT, AUTHENTICATION_CONFIG, AUTHENTICATION_TRANSPORT, AssetsService, AuthenticationService, CAMPAIGNS_CONFIG, CAMPAIGNS_TRANSPORT, COMPANY_CONFIG, COMPANY_TRANSPORT, CONTENT_CONFIG, CONTENT_TRANSPORT, CONVERSATIONS_CONFIG, CONVERSATIONS_TRANSPORT, CRM_CONFIG, CRM_TRANSPORT, CampaignsService, CompanyService, ContentService, ConversationsService, CrmService, FILES_CONFIG, FILES_TRANSPORT, FORMS_CONFIG, FORMS_TRANSPORT, FilesService, FormsService, GEOLOCATION_CONFIG, GEOLOCATION_TRANSPORT, GeolocationService, JARVIS_CONFIG, JARVIS_TRANSPORT, JarvisService, ONBOARDING_CONFIG, ONBOARDING_TRANSPORT, OnboardingService, PRODUCTS_CONFIG, PRODUCTS_TRANSPORT, PROVIDER_CONFIG, ProductsService, RAG_CONFIG, RAG_TRANSPORT, REWARDS_CONFIG, REWARDS_TRANSPORT, RagService, RewardsService, SALES_CONFIG, SALES_TRANSPORT, SEARCH_CONFIG, SEARCH_TRANSPORT, SIMPLE_CONFIG, SalesService, SearchService, TOKEN_LIFECYCLE, TOKEN_MANAGER, TRANSPORT, UNIVERSITY_CONFIG, UNIVERSITY_TRANSPORT, UniversityService, WALLET_CONFIG, WALLET_TRANSPORT, WalletService, get23BlocksProviders, getBlocks23Providers, provide23Blocks, provideBlocks23 };
|
|
2134
2467
|
//# sourceMappingURL=23blocks-angular.mjs.map
|