@xh/hoist 71.0.0-SNAPSHOT.1734633945544 → 71.0.0-SNAPSHOT.1735061018823
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 +2 -0
- package/build/types/data/filter/CompoundFilter.d.ts +1 -4
- package/build/types/data/filter/FieldFilter.d.ts +1 -7
- package/build/types/data/filter/Filter.d.ts +3 -1
- package/build/types/data/filter/FunctionFilter.d.ts +1 -0
- package/build/types/data/filter/Types.d.ts +2 -1
- package/build/types/security/authzero/AuthZeroClient.d.ts +16 -5
- package/data/filter/CompoundFilter.ts +7 -7
- package/data/filter/FieldFilter.ts +5 -5
- package/data/filter/Filter.ts +4 -1
- package/data/filter/FunctionFilter.ts +5 -0
- package/data/filter/Types.ts +3 -7
- package/desktop/cmp/grid/impl/filter/GridFilterDialog.ts +2 -10
- package/package.json +1 -1
- package/security/authzero/AuthZeroClient.ts +38 -21
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* Support for "global" views.
|
|
13
13
|
* New `SessionStorageService` and associated persistence provider provides support for saving
|
|
14
14
|
tab local data across reloads.
|
|
15
|
+
* Added support for `AuthZeroClientConfig.audience` to support improved configuration of Auth0 OAuth
|
|
16
|
+
clients requesting access tokens, covering cases when third-party cookies are blocked.
|
|
15
17
|
|
|
16
18
|
### ⚙️ Technical
|
|
17
19
|
|
|
@@ -16,10 +16,7 @@ export declare class CompoundFilter extends Filter {
|
|
|
16
16
|
* @internal
|
|
17
17
|
*/
|
|
18
18
|
constructor({ filters, op }: CompoundFilterSpec);
|
|
19
|
-
toJSON(): {
|
|
20
|
-
filters: any[];
|
|
21
|
-
op: CompoundFilterOperator;
|
|
22
|
-
};
|
|
23
19
|
getTestFn(store?: Store): FilterTestFn;
|
|
24
20
|
equals(other: Filter): boolean;
|
|
21
|
+
toJSON(): CompoundFilterSpec;
|
|
25
22
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { FieldType } from '../Field';
|
|
2
1
|
import { Store } from '../Store';
|
|
3
2
|
import { Filter } from './Filter';
|
|
4
3
|
import { FieldFilterOperator, FieldFilterSpec, FilterTestFn } from './Types';
|
|
@@ -23,13 +22,8 @@ export declare class FieldFilter extends Filter {
|
|
|
23
22
|
* @internal
|
|
24
23
|
*/
|
|
25
24
|
constructor({ field, op, value, valueType }: FieldFilterSpec);
|
|
26
|
-
toJSON(): {
|
|
27
|
-
valueType?: FieldType;
|
|
28
|
-
field: string;
|
|
29
|
-
op: FieldFilterOperator;
|
|
30
|
-
value: any;
|
|
31
|
-
};
|
|
32
25
|
getTestFn(store?: Store): FilterTestFn;
|
|
33
26
|
equals(other: Filter): boolean;
|
|
27
|
+
toJSON(): FieldFilterSpec;
|
|
34
28
|
private get serializedValueType();
|
|
35
29
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Store } from '../Store';
|
|
2
|
-
import { FilterTestFn } from './Types';
|
|
2
|
+
import { FilterSpec, FilterTestFn } from './Types';
|
|
3
3
|
/**
|
|
4
4
|
* Base class for Hoist data package Filters.
|
|
5
5
|
*
|
|
@@ -21,4 +21,6 @@ export declare abstract class Filter {
|
|
|
21
21
|
abstract getTestFn(store?: Store): FilterTestFn;
|
|
22
22
|
/** @returns true if the provided other Filter is equivalent to this instance.*/
|
|
23
23
|
abstract equals(other: Filter): boolean;
|
|
24
|
+
/** @returns a JSON serializable spec that can be used to persist and recreate this filter.*/
|
|
25
|
+
abstract toJSON(): FilterSpec;
|
|
24
26
|
}
|
|
@@ -30,4 +30,5 @@ export interface FunctionFilterSpec {
|
|
|
30
30
|
* @returns true if the candidate passes and should be included in filtered results.
|
|
31
31
|
*/
|
|
32
32
|
export type FilterTestFn = (candidate: PlainObject | StoreRecord) => boolean;
|
|
33
|
-
export type
|
|
33
|
+
export type FilterSpec = FieldFilterSpec | FunctionFilterSpec | CompoundFilterSpec;
|
|
34
|
+
export type FilterLike = Filter | FilterSpec | FilterTestFn | FilterLike[];
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import { Auth0ClientOptions } from '@auth0/auth0-spa-js';
|
|
1
|
+
import type { Auth0ClientOptions } from '@auth0/auth0-spa-js';
|
|
2
2
|
import { Token, TokenMap } from '@xh/hoist/security/Token';
|
|
3
3
|
import { BaseOAuthClient, BaseOAuthClientConfig } from '../BaseOAuthClient';
|
|
4
4
|
export interface AuthZeroClientConfig extends BaseOAuthClientConfig<AuthZeroTokenSpec> {
|
|
5
|
-
/** Domain of your app registered with Auth0
|
|
5
|
+
/** Domain of your app registered with Auth0. */
|
|
6
6
|
domain: string;
|
|
7
|
+
/**
|
|
8
|
+
* Audience to pass to interactive login and ID token requests.
|
|
9
|
+
*
|
|
10
|
+
* If you are also requesting an *access* token for a single audience, pass that value here to
|
|
11
|
+
* ensure that the initial login/token request returns a ready-to-use access token (and refresh
|
|
12
|
+
* token) with a single request to the Auth0 API, instead of requiring two.
|
|
13
|
+
*
|
|
14
|
+
* This also avoids issues with browsers that block third party cookies when running on
|
|
15
|
+
* localhost or with an Auth0 domain that does not match the app's own domain. In those cases,
|
|
16
|
+
* Auth0 must use refresh tokens to obtain access tokens, and a single audience allows that
|
|
17
|
+
* exchange to work without extra user interaction that this class does not currently support.
|
|
18
|
+
*/
|
|
19
|
+
audience?: string;
|
|
7
20
|
/**
|
|
8
21
|
* Additional options for the Auth0Client ctor. Will be deep merged with defaults, with options
|
|
9
22
|
* supplied here taking precedence. Use with care, as overriding defaults may have unintended
|
|
@@ -16,9 +29,7 @@ export interface AuthZeroTokenSpec {
|
|
|
16
29
|
scopes: string[];
|
|
17
30
|
/**
|
|
18
31
|
* Audience (i.e. API) identifier for AccessToken. Must be registered with Auth0.
|
|
19
|
-
*
|
|
20
|
-
* Note that this is required to ensure that issued token is a JWT and not
|
|
21
|
-
* an opaque string.
|
|
32
|
+
* Note that this is required to ensure that issued token is a JWT and not an opaque string.
|
|
22
33
|
*/
|
|
23
34
|
audience: string;
|
|
24
35
|
}
|
|
@@ -46,13 +46,6 @@ export class CompoundFilter extends Filter {
|
|
|
46
46
|
Object.freeze(this);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
toJSON() {
|
|
50
|
-
return {
|
|
51
|
-
filters: this.filters.map((f: any) => f.toJSON()),
|
|
52
|
-
op: this.op
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
49
|
//-----------------
|
|
57
50
|
// Overrides
|
|
58
51
|
//-----------------
|
|
@@ -74,4 +67,11 @@ export class CompoundFilter extends Filter {
|
|
|
74
67
|
)
|
|
75
68
|
);
|
|
76
69
|
}
|
|
70
|
+
|
|
71
|
+
override toJSON(): CompoundFilterSpec {
|
|
72
|
+
return {
|
|
73
|
+
filters: this.filters.map(f => f.toJSON()),
|
|
74
|
+
op: this.op
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
77
|
}
|
|
@@ -98,11 +98,6 @@ export class FieldFilter extends Filter {
|
|
|
98
98
|
Object.freeze(this);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
toJSON() {
|
|
102
|
-
const {field, op, value, serializedValueType} = this;
|
|
103
|
-
return {field, op, value, ...(serializedValueType ? {valueType: serializedValueType} : {})};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
101
|
//-----------------
|
|
107
102
|
// Overrides
|
|
108
103
|
//-----------------
|
|
@@ -204,6 +199,11 @@ export class FieldFilter extends Filter {
|
|
|
204
199
|
);
|
|
205
200
|
}
|
|
206
201
|
|
|
202
|
+
override toJSON(): FieldFilterSpec {
|
|
203
|
+
const {field, op, value, serializedValueType} = this;
|
|
204
|
+
return {field, op, value, ...(serializedValueType ? {valueType: serializedValueType} : {})};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
207
|
//-----------------
|
|
208
208
|
// Implementation
|
|
209
209
|
//-----------------
|
package/data/filter/Filter.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {Store} from '../Store';
|
|
9
|
-
import {FilterTestFn} from './Types';
|
|
9
|
+
import {FilterSpec, FilterTestFn} from './Types';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Base class for Hoist data package Filters.
|
|
@@ -33,4 +33,7 @@ export abstract class Filter {
|
|
|
33
33
|
|
|
34
34
|
/** @returns true if the provided other Filter is equivalent to this instance.*/
|
|
35
35
|
abstract equals(other: Filter): boolean;
|
|
36
|
+
|
|
37
|
+
/** @returns a JSON serializable spec that can be used to persist and recreate this filter.*/
|
|
38
|
+
abstract toJSON(): FilterSpec;
|
|
36
39
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import {XH} from '@xh/hoist/core';
|
|
8
9
|
import {throwIf} from '@xh/hoist/utils/js';
|
|
9
10
|
import {isFunction} from 'lodash';
|
|
10
11
|
import {Store} from '../Store';
|
|
@@ -51,4 +52,8 @@ export class FunctionFilter extends Filter {
|
|
|
51
52
|
if (other === this) return true;
|
|
52
53
|
return other instanceof FunctionFilter && this.testFn === other.testFn;
|
|
53
54
|
}
|
|
55
|
+
|
|
56
|
+
override toJSON(): FunctionFilterSpec {
|
|
57
|
+
throw XH.exception('FunctionFilter.toJSON() not supported.');
|
|
58
|
+
}
|
|
54
59
|
}
|
package/data/filter/Types.ts
CHANGED
|
@@ -59,10 +59,6 @@ export interface FunctionFilterSpec {
|
|
|
59
59
|
*/
|
|
60
60
|
export type FilterTestFn = (candidate: PlainObject | StoreRecord) => boolean;
|
|
61
61
|
|
|
62
|
-
export type
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
| FieldFilterSpec
|
|
66
|
-
| FunctionFilterSpec
|
|
67
|
-
| FilterTestFn
|
|
68
|
-
| FilterLike[];
|
|
62
|
+
export type FilterSpec = FieldFilterSpec | FunctionFilterSpec | CompoundFilterSpec;
|
|
63
|
+
|
|
64
|
+
export type FilterLike = Filter | FilterSpec | FilterTestFn | FilterLike[];
|
|
@@ -8,13 +8,7 @@ import {form, FormModel} from '@xh/hoist/cmp/form';
|
|
|
8
8
|
import {GridFilterModel} from '@xh/hoist/cmp/grid';
|
|
9
9
|
import {filler} from '@xh/hoist/cmp/layout';
|
|
10
10
|
import {hoistCmp, HoistModel, lookup, managed, useLocalModel, uses} from '@xh/hoist/core';
|
|
11
|
-
import {
|
|
12
|
-
CompoundFilter,
|
|
13
|
-
FieldFilter,
|
|
14
|
-
parseFilter,
|
|
15
|
-
required,
|
|
16
|
-
withFilterByTypes
|
|
17
|
-
} from '@xh/hoist/data';
|
|
11
|
+
import {parseFilter, required, withFilterByTypes} from '@xh/hoist/data';
|
|
18
12
|
import {button} from '@xh/hoist/desktop/cmp/button';
|
|
19
13
|
import {formField} from '@xh/hoist/desktop/cmp/form';
|
|
20
14
|
import {jsonInput} from '@xh/hoist/desktop/cmp/input';
|
|
@@ -151,9 +145,7 @@ class GridFilterDialogLocalModel extends HoistModel {
|
|
|
151
145
|
}
|
|
152
146
|
|
|
153
147
|
loadForm() {
|
|
154
|
-
const filter = withFilterByTypes(this.model.filter, null, 'FunctionFilter')
|
|
155
|
-
| CompoundFilter
|
|
156
|
-
| FieldFilter;
|
|
148
|
+
const filter = withFilterByTypes(this.model.filter, null, 'FunctionFilter');
|
|
157
149
|
this.formModel.init({
|
|
158
150
|
filter: JSON.stringify(filter?.toJSON() ?? null, undefined, 2)
|
|
159
151
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "71.0.0-SNAPSHOT.
|
|
3
|
+
"version": "71.0.0-SNAPSHOT.1735061018823",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import type {Auth0ClientOptions} from '@auth0/auth0-spa-js';
|
|
8
|
+
import {Auth0Client} from '@auth0/auth0-spa-js';
|
|
8
9
|
import {XH} from '@xh/hoist/core';
|
|
9
10
|
import {never, wait} from '@xh/hoist/promise';
|
|
10
11
|
import {Token, TokenMap} from '@xh/hoist/security/Token';
|
|
@@ -14,9 +15,23 @@ import {flatMap, union} from 'lodash';
|
|
|
14
15
|
import {BaseOAuthClient, BaseOAuthClientConfig} from '../BaseOAuthClient';
|
|
15
16
|
|
|
16
17
|
export interface AuthZeroClientConfig extends BaseOAuthClientConfig<AuthZeroTokenSpec> {
|
|
17
|
-
/** Domain of your app registered with Auth0
|
|
18
|
+
/** Domain of your app registered with Auth0. */
|
|
18
19
|
domain: string;
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Audience to pass to interactive login and ID token requests.
|
|
23
|
+
*
|
|
24
|
+
* If you are also requesting an *access* token for a single audience, pass that value here to
|
|
25
|
+
* ensure that the initial login/token request returns a ready-to-use access token (and refresh
|
|
26
|
+
* token) with a single request to the Auth0 API, instead of requiring two.
|
|
27
|
+
*
|
|
28
|
+
* This also avoids issues with browsers that block third party cookies when running on
|
|
29
|
+
* localhost or with an Auth0 domain that does not match the app's own domain. In those cases,
|
|
30
|
+
* Auth0 must use refresh tokens to obtain access tokens, and a single audience allows that
|
|
31
|
+
* exchange to work without extra user interaction that this class does not currently support.
|
|
32
|
+
*/
|
|
33
|
+
audience?: string;
|
|
34
|
+
|
|
20
35
|
/**
|
|
21
36
|
* Additional options for the Auth0Client ctor. Will be deep merged with defaults, with options
|
|
22
37
|
* supplied here taking precedence. Use with care, as overriding defaults may have unintended
|
|
@@ -31,9 +46,7 @@ export interface AuthZeroTokenSpec {
|
|
|
31
46
|
|
|
32
47
|
/**
|
|
33
48
|
* Audience (i.e. API) identifier for AccessToken. Must be registered with Auth0.
|
|
34
|
-
*
|
|
35
|
-
* Note that this is required to ensure that issued token is a JWT and not
|
|
36
|
-
* an opaque string.
|
|
49
|
+
* Note that this is required to ensure that issued token is a JWT and not an opaque string.
|
|
37
50
|
*/
|
|
38
51
|
audience: string;
|
|
39
52
|
}
|
|
@@ -95,7 +108,9 @@ export class AuthZeroClient extends BaseOAuthClient<AuthZeroClientConfig, AuthZe
|
|
|
95
108
|
|
|
96
109
|
protected override async doLoginPopupAsync(): Promise<void> {
|
|
97
110
|
try {
|
|
98
|
-
await this.client.loginWithPopup({
|
|
111
|
+
await this.client.loginWithPopup({
|
|
112
|
+
authorizationParams: {scope: this.loginScope}
|
|
113
|
+
});
|
|
99
114
|
await this.noteUserAuthenticatedAsync();
|
|
100
115
|
} catch (e) {
|
|
101
116
|
const msg = e.message?.toLowerCase();
|
|
@@ -167,25 +182,27 @@ export class AuthZeroClient extends BaseOAuthClient<AuthZeroClientConfig, AuthZe
|
|
|
167
182
|
// Private implementation
|
|
168
183
|
//------------------------
|
|
169
184
|
private createClient(): Auth0Client {
|
|
170
|
-
const {clientId, domain, authZeroClientOptions} = this.config;
|
|
185
|
+
const {clientId, domain, audience, authZeroClientOptions} = this.config;
|
|
171
186
|
throwIf(!domain, 'Missing Auth0 "domain". Please review your config.');
|
|
172
187
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
},
|
|
184
|
-
cacheLocation: 'localstorage'
|
|
188
|
+
const mergedConfig = mergeDeep(
|
|
189
|
+
{
|
|
190
|
+
clientId,
|
|
191
|
+
domain,
|
|
192
|
+
useRefreshTokens: true,
|
|
193
|
+
useRefreshTokensFallback: true,
|
|
194
|
+
authorizationParams: {
|
|
195
|
+
scope: this.loginScope,
|
|
196
|
+
redirect_uri: this.redirectUrl,
|
|
197
|
+
audience
|
|
185
198
|
},
|
|
186
|
-
|
|
187
|
-
|
|
199
|
+
cacheLocation: 'localstorage'
|
|
200
|
+
},
|
|
201
|
+
authZeroClientOptions
|
|
188
202
|
);
|
|
203
|
+
|
|
204
|
+
this.logDebug(`Creating Auth0Client with merged config`, mergedConfig);
|
|
205
|
+
return new Auth0Client(mergedConfig);
|
|
189
206
|
}
|
|
190
207
|
|
|
191
208
|
private get loginScope(): string {
|