@genesislcap/foundation-auth 15.19.3 → 15.19.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/routes/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAA2B,mBAAmB,EAAS,MAAM,wBAAwB,CAAC;AAC7F,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAS9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIxC;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,mBAAmB,CAAC,QAAQ,CAAC;IAEzD,OAAO,CAAC,IAAI;IACP,OAAO,CAAC,SAAS;IAChB,OAAO,CAAC,UAAU;IACjB,OAAO,CAAC,WAAW;gBAHlB,IAAI,EAAE,IAAI,EACL,SAAS,EAAE,SAAS,EACnB,UAAU,EAAE,UAAU,EACrB,WAAW,EAAE,WAAW;IAK/C,SAAS;IA0IT,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC;CAGxC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/routes/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAGL,mBAAmB,EAEpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAS9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKxC;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,mBAAmB,CAAC,QAAQ,CAAC;IAEzD,OAAO,CAAC,IAAI;IACP,OAAO,CAAC,SAAS;IAChB,OAAO,CAAC,UAAU;IACjB,OAAO,CAAC,WAAW;gBAHlB,IAAI,EAAE,IAAI,EACL,SAAS,EAAE,SAAS,EACnB,UAAU,EAAE,UAAU,EACrB,WAAW,EAAE,WAAW;IAK/C,SAAS;IA0JT,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC;CAGxC"}
@@ -27,4 +27,20 @@ export declare function navigateTo(route: AuthRoutes | string): void;
27
27
  * @public
28
28
  */
29
29
  export declare function getRoutePath(route: AuthRoutes | string, hostPath?: string): string;
30
+ /**
31
+ * Whether `pathname` lies outside this micro frontend's host path — i.e. it belongs to the
32
+ * HOST application, not to us. Only meaningful for a scoping `hostPath` (embedded use);
33
+ * standalone — `hostPath` empty or `/` — the micro frontend owns every path and this is
34
+ * always false. Both sides are normalised (leading slash on, trailing slash off) before
35
+ * comparing, because `hostPath` is commonly configured without a leading slash
36
+ * (`hostPath: 'auth'` — the documented example) and must scope the same either way.
37
+ * Matching is on segment boundaries, so `/login-history` is outside `/login` while
38
+ * `/login/not-found` is in.
39
+ *
40
+ * @param pathname - The pathname to classify, typically `location.pathname`.
41
+ * @param hostPath - The configured host path, e.g. `/login` or `login`.
42
+ *
43
+ * @public
44
+ */
45
+ export declare function isOutsideHostPath(pathname: string, hostPath: string): boolean;
30
46
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/routes/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,QAAQ,GAAE,MAA0B,GAAG,OAAO,CAKvE;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,QAGpD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,QAAQ,GAAE,MAAW,GAAG,MAAM,CAQtF"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/routes/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,QAAQ,GAAE,MAA0B,GAAG,OAAO,CAKvE;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,QAGpD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,QAAQ,GAAE,MAAW,GAAG,MAAM,CAQtF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAO7E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../../src/routes/utils.test.ts"],"names":[],"mappings":""}
@@ -1,7 +1,7 @@
1
1
  import { __awaiter, __decorate, __param } from "tslib";
2
2
  import { User } from '@genesislcap/foundation-user';
3
3
  import { Container } from '@microsoft/fast-foundation';
4
- import { RouterConfiguration, Route } from '@microsoft/fast-router';
4
+ import { Ignore, RouterConfiguration, Route, } from '@microsoft/fast-router';
5
5
  import { AuthConfig } from '../config/config';
6
6
  import { defaultLayout } from '../layouts';
7
7
  import { logger } from '../utils';
@@ -13,6 +13,7 @@ import { RequestAccount } from './request-account/request-account';
13
13
  import { ResetPassword } from './reset-password/reset-password';
14
14
  import { AuthRouting } from './routing';
15
15
  import { TermsConditions } from './terms-conditions/terms-conditions';
16
+ import { isOutsideHostPath } from './utils';
16
17
  import { Verify } from './verify/verify';
17
18
  /**
18
19
  * Base implementation of a routing used with the Auth class
@@ -117,6 +118,19 @@ let AuthRouterConfig = class AuthRouterConfig extends RouterConfiguration {
117
118
  * Example of a FallbackRouteDefinition
118
119
  */
119
120
  this.routes.fallback(() => {
121
+ // The router hears every app-wide URL change, so an unmatched path is not necessarily
122
+ // ours to handle. Embedded in a host application (a non-empty hostPath, e.g. '/login'
123
+ // inside a react-router app), the host's own routes land in this fallback too — most
124
+ // visibly right after a successful login, when the host's post-login navigation races
125
+ // this micro frontend's teardown: an authenticated fallback then rewrote the host's
126
+ // URL to `<hostPath>/not-found`, and the app was stranded on that poisoned URL at its
127
+ // next full reload. A path outside the host path is the host application's business —
128
+ // stand down and navigate nowhere. Standalone (hostPath '') keeps the old behaviour:
129
+ // this micro frontend owns every path there.
130
+ if (!this.parent && isOutsideHostPath(location.pathname, this.authConfig.hostPath)) {
131
+ logger.debug('AuthRouterConfig.routes.fallback. Path outside hostPath, ignoring:', location.pathname);
132
+ return { command: new Ignore() };
133
+ }
120
134
  this.user.trackPath();
121
135
  const result = this.user.isAuthenticated
122
136
  ? { redirect: getRoutePath('not-found') }
@@ -44,3 +44,34 @@ export function getRoutePath(route, hostPath = '') {
44
44
  }
45
45
  return hostPath ? `${hostPath}/${route}` : route;
46
46
  }
47
+ /**
48
+ * Whether `pathname` lies outside this micro frontend's host path — i.e. it belongs to the
49
+ * HOST application, not to us. Only meaningful for a scoping `hostPath` (embedded use);
50
+ * standalone — `hostPath` empty or `/` — the micro frontend owns every path and this is
51
+ * always false. Both sides are normalised (leading slash on, trailing slash off) before
52
+ * comparing, because `hostPath` is commonly configured without a leading slash
53
+ * (`hostPath: 'auth'` — the documented example) and must scope the same either way.
54
+ * Matching is on segment boundaries, so `/login-history` is outside `/login` while
55
+ * `/login/not-found` is in.
56
+ *
57
+ * @param pathname - The pathname to classify, typically `location.pathname`.
58
+ * @param hostPath - The configured host path, e.g. `/login` or `login`.
59
+ *
60
+ * @public
61
+ */
62
+ export function isOutsideHostPath(pathname, hostPath) {
63
+ const host = normalizePathname(hostPath);
64
+ if (!host || host === '/') {
65
+ return false;
66
+ }
67
+ const path = normalizePathname(pathname);
68
+ return path !== host && !path.startsWith(`${host}/`);
69
+ }
70
+ /** Leading slash on, trailing slash off; `''` stays `''` so an unset hostPath keeps meaning "owns everything". */
71
+ function normalizePathname(value) {
72
+ if (!value) {
73
+ return '';
74
+ }
75
+ const led = value.startsWith('/') ? value : `/${value}`;
76
+ return led.length > 1 && led.endsWith('/') ? led.slice(0, -1) : led;
77
+ }
@@ -0,0 +1,33 @@
1
+ import { assert, createLogicSuite } from '@genesislcap/foundation-testing';
2
+ import { isOutsideHostPath } from './utils';
3
+ const Suite = createLogicSuite('isOutsideHostPath');
4
+ Suite('standalone (empty hostPath) owns every path', () => {
5
+ assert.is(isOutsideHostPath('/anything', ''), false);
6
+ assert.is(isOutsideHostPath('/', ''), false);
7
+ });
8
+ Suite('the host path itself and its sub routes are inside', () => {
9
+ assert.is(isOutsideHostPath('/login', '/login'), false);
10
+ assert.is(isOutsideHostPath('/login/not-found', '/login'), false);
11
+ assert.is(isOutsideHostPath('/login/reset-password', '/login'), false);
12
+ });
13
+ Suite('the host application routes are outside', () => {
14
+ // The teardown race this classifier exists for: the host app navigates to its own route
15
+ // right after login, and the fallback must NOT rewrite it to `<hostPath>/not-found`.
16
+ assert.is(isOutsideHostPath('/home', '/login'), true);
17
+ assert.is(isOutsideHostPath('/', '/login'), true);
18
+ });
19
+ Suite('matching is on segment boundaries, not string prefixes', () => {
20
+ assert.is(isOutsideHostPath('/login-history', '/login'), true);
21
+ });
22
+ Suite('hostPath and pathname are normalized (leading/trailing slashes)', () => {
23
+ // The documented configuration style omits the leading slash (`hostPath: 'auth'`) — it
24
+ // must scope identically to `/auth`, or the fallback would ignore its own routes.
25
+ assert.is(isOutsideHostPath('/login', 'login'), false);
26
+ assert.is(isOutsideHostPath('/login/', '/login'), false);
27
+ assert.is(isOutsideHostPath('/login/not-found', 'login/'), false);
28
+ assert.is(isOutsideHostPath('/home', 'login'), true);
29
+ });
30
+ Suite('a root hostPath owns every path, like an empty one', () => {
31
+ assert.is(isOutsideHostPath('/anything', '/'), false);
32
+ });
33
+ Suite.run();
@@ -11286,6 +11286,67 @@
11286
11286
  ],
11287
11287
  "name": "isNackEntity"
11288
11288
  },
11289
+ {
11290
+ "kind": "Function",
11291
+ "canonicalReference": "@genesislcap/foundation-auth!isOutsideHostPath:function(1)",
11292
+ "docComment": "/**\n * Whether `pathname` lies outside this micro frontend's host path — i.e. it belongs to the HOST application, not to us. Only meaningful for a scoping `hostPath` (embedded use); standalone — `hostPath` empty or `/` — the micro frontend owns every path and this is always false. Both sides are normalised (leading slash on, trailing slash off) before comparing, because `hostPath` is commonly configured without a leading slash (`hostPath: 'auth'` — the documented example) and must scope the same either way. Matching is on segment boundaries, so `/login-history` is outside `/login` while `/login/not-found` is in.\n *\n * @param pathname - The pathname to classify, typically `location.pathname`.\n *\n * @param hostPath - The configured host path, e.g. `/login` or `login`.\n *\n * @public\n */\n",
11293
+ "excerptTokens": [
11294
+ {
11295
+ "kind": "Content",
11296
+ "text": "export declare function isOutsideHostPath(pathname: "
11297
+ },
11298
+ {
11299
+ "kind": "Content",
11300
+ "text": "string"
11301
+ },
11302
+ {
11303
+ "kind": "Content",
11304
+ "text": ", hostPath: "
11305
+ },
11306
+ {
11307
+ "kind": "Content",
11308
+ "text": "string"
11309
+ },
11310
+ {
11311
+ "kind": "Content",
11312
+ "text": "): "
11313
+ },
11314
+ {
11315
+ "kind": "Content",
11316
+ "text": "boolean"
11317
+ },
11318
+ {
11319
+ "kind": "Content",
11320
+ "text": ";"
11321
+ }
11322
+ ],
11323
+ "fileUrlPath": "src/routes/utils.ts",
11324
+ "returnTypeTokenRange": {
11325
+ "startIndex": 5,
11326
+ "endIndex": 6
11327
+ },
11328
+ "releaseTag": "Public",
11329
+ "overloadIndex": 1,
11330
+ "parameters": [
11331
+ {
11332
+ "parameterName": "pathname",
11333
+ "parameterTypeTokenRange": {
11334
+ "startIndex": 1,
11335
+ "endIndex": 2
11336
+ },
11337
+ "isOptional": false
11338
+ },
11339
+ {
11340
+ "parameterName": "hostPath",
11341
+ "parameterTypeTokenRange": {
11342
+ "startIndex": 3,
11343
+ "endIndex": 4
11344
+ },
11345
+ "isOptional": false
11346
+ }
11347
+ ],
11348
+ "name": "isOutsideHostPath"
11349
+ },
11289
11350
  {
11290
11351
  "kind": "Function",
11291
11352
  "canonicalReference": "@genesislcap/foundation-auth!isQueryParams:function(1)",
@@ -2143,6 +2143,23 @@ export declare function isNackDTO(dto: unknown): dto is NACK;
2143
2143
  */
2144
2144
  export declare function isNackEntity(entity: unknown): entity is Nack;
2145
2145
 
2146
+ /**
2147
+ * Whether `pathname` lies outside this micro frontend's host path — i.e. it belongs to the
2148
+ * HOST application, not to us. Only meaningful for a scoping `hostPath` (embedded use);
2149
+ * standalone — `hostPath` empty or `/` — the micro frontend owns every path and this is
2150
+ * always false. Both sides are normalised (leading slash on, trailing slash off) before
2151
+ * comparing, because `hostPath` is commonly configured without a leading slash
2152
+ * (`hostPath: 'auth'` — the documented example) and must scope the same either way.
2153
+ * Matching is on segment boundaries, so `/login-history` is outside `/login` while
2154
+ * `/login/not-found` is in.
2155
+ *
2156
+ * @param pathname - The pathname to classify, typically `location.pathname`.
2157
+ * @param hostPath - The configured host path, e.g. `/login` or `login`.
2158
+ *
2159
+ * @public
2160
+ */
2161
+ export declare function isOutsideHostPath(pathname: string, hostPath: string): boolean;
2162
+
2146
2163
  /**
2147
2164
  * isQueryParams.
2148
2165
  * @param params - Potential QueryParams.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/foundation-auth",
3
3
  "description": "Genesis Foundation Auth",
4
- "version": "15.19.3",
4
+ "version": "15.19.4",
5
5
  "license": "SEE LICENSE IN license.txt",
6
6
  "main": "dist/esm/index.js",
7
7
  "types": "dist/foundation-auth.d.ts",
@@ -134,25 +134,25 @@
134
134
  }
135
135
  },
136
136
  "devDependencies": {
137
- "@genesislcap/foundation-testing": "15.19.3",
138
- "@genesislcap/genx": "15.19.3",
139
- "@genesislcap/rollup-builder": "15.19.3",
140
- "@genesislcap/ts-builder": "15.19.3",
141
- "@genesislcap/uvu-playwright-builder": "15.19.3",
142
- "@genesislcap/vite-builder": "15.19.3",
143
- "@genesislcap/webpack-builder": "15.19.3"
137
+ "@genesislcap/foundation-testing": "15.19.4",
138
+ "@genesislcap/genx": "15.19.4",
139
+ "@genesislcap/rollup-builder": "15.19.4",
140
+ "@genesislcap/ts-builder": "15.19.4",
141
+ "@genesislcap/uvu-playwright-builder": "15.19.4",
142
+ "@genesislcap/vite-builder": "15.19.4",
143
+ "@genesislcap/webpack-builder": "15.19.4"
144
144
  },
145
145
  "dependencies": {
146
- "@genesislcap/foundation-comms": "15.19.3",
147
- "@genesislcap/foundation-events": "15.19.3",
148
- "@genesislcap/foundation-i18n": "15.19.3",
149
- "@genesislcap/foundation-logger": "15.19.3",
150
- "@genesislcap/foundation-state-machine": "15.19.3",
151
- "@genesislcap/foundation-store": "15.19.3",
152
- "@genesislcap/foundation-ui": "15.19.3",
153
- "@genesislcap/foundation-user": "15.19.3",
154
- "@genesislcap/foundation-utils": "15.19.3",
155
- "@genesislcap/foundation-zero": "15.19.3",
146
+ "@genesislcap/foundation-comms": "15.19.4",
147
+ "@genesislcap/foundation-events": "15.19.4",
148
+ "@genesislcap/foundation-i18n": "15.19.4",
149
+ "@genesislcap/foundation-logger": "15.19.4",
150
+ "@genesislcap/foundation-state-machine": "15.19.4",
151
+ "@genesislcap/foundation-store": "15.19.4",
152
+ "@genesislcap/foundation-ui": "15.19.4",
153
+ "@genesislcap/foundation-user": "15.19.4",
154
+ "@genesislcap/foundation-utils": "15.19.4",
155
+ "@genesislcap/foundation-zero": "15.19.4",
156
156
  "@microsoft/fast-components": "2.30.6",
157
157
  "@microsoft/fast-element": "1.14.0",
158
158
  "@microsoft/fast-foundation": "2.50.0",