@salesforce/b2c-tooling-sdk 0.9.0 → 0.11.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/data/content-schemas/aspecttype.json +39 -0
- package/data/content-schemas/attributedefinition.json +283 -0
- package/data/content-schemas/attributedefinitiongroup.json +35 -0
- package/data/content-schemas/cmsrecord.json +45 -0
- package/data/content-schemas/common.json +27 -0
- package/data/content-schemas/componentconstructor.json +31 -0
- package/data/content-schemas/componenttype.json +24 -0
- package/data/content-schemas/componenttypeexclusion.json +11 -0
- package/data/content-schemas/componenttypeinclusion.json +11 -0
- package/data/content-schemas/contentassetcomponentconfig.json +32 -0
- package/data/content-schemas/contentassetpageconfig.json +14 -0
- package/data/content-schemas/contentassetstructuredcontentdata.json +5 -0
- package/data/content-schemas/customeditortype.json +28 -0
- package/data/content-schemas/databindingcontext.json +17 -0
- package/data/content-schemas/editordefinition.json +27 -0
- package/data/content-schemas/image.json +37 -0
- package/data/content-schemas/pagetype.json +38 -0
- package/data/content-schemas/regiondefinition.json +33 -0
- package/data/content-schemas/visibilityrule.json +70 -0
- package/dist/cjs/auth/index.d.ts +4 -0
- package/dist/cjs/auth/index.js +3 -0
- package/dist/cjs/auth/index.js.map +1 -1
- package/dist/cjs/auth/stateful-oauth-strategy.d.ts +39 -0
- package/dist/cjs/auth/stateful-oauth-strategy.js +136 -0
- package/dist/cjs/auth/stateful-oauth-strategy.js.map +1 -0
- package/dist/cjs/auth/stateful-store.d.ts +49 -0
- package/dist/cjs/auth/stateful-store.js +168 -0
- package/dist/cjs/auth/stateful-store.js.map +1 -0
- package/dist/cjs/cli/am-command.d.ts +1 -1
- package/dist/cjs/cli/am-command.js +9 -4
- package/dist/cjs/cli/am-command.js.map +1 -1
- package/dist/cjs/cli/base-command.d.ts +41 -0
- package/dist/cjs/cli/base-command.js +84 -2
- package/dist/cjs/cli/base-command.js.map +1 -1
- package/dist/cjs/cli/instance-command.d.ts +3 -3
- package/dist/cjs/cli/oauth-command.d.ts +19 -4
- package/dist/cjs/cli/oauth-command.js +57 -2
- package/dist/cjs/cli/oauth-command.js.map +1 -1
- package/dist/cjs/cli/ods-command.d.ts +3 -3
- package/dist/cjs/cli/webdav-command.d.ts +3 -3
- package/dist/cjs/clients/am-api.js +7 -1
- package/dist/cjs/clients/am-api.js.map +1 -1
- package/dist/cjs/clients/index.d.ts +1 -1
- package/dist/cjs/clients/index.js +1 -1
- package/dist/cjs/clients/index.js.map +1 -1
- package/dist/cjs/clients/middleware.d.ts +21 -0
- package/dist/cjs/clients/middleware.js +30 -0
- package/dist/cjs/clients/middleware.js.map +1 -1
- package/dist/cjs/config/sources/env-source.js +4 -0
- package/dist/cjs/config/sources/env-source.js.map +1 -1
- package/dist/cjs/docs/schema.d.ts +2 -0
- package/dist/cjs/docs/schema.js +2 -2
- package/dist/cjs/docs/schema.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/operations/content/index.d.ts +15 -2
- package/dist/cjs/operations/content/index.js +14 -2
- package/dist/cjs/operations/content/index.js.map +1 -1
- package/dist/cjs/operations/content/validate.d.ts +64 -0
- package/dist/cjs/operations/content/validate.js +170 -0
- package/dist/cjs/operations/content/validate.js.map +1 -0
- package/dist/cjs/operations/mrt/bundle.js +13 -13
- package/dist/cjs/operations/mrt/bundle.js.map +1 -1
- package/dist/cjs/safety/index.d.ts +7 -0
- package/dist/cjs/safety/index.js +7 -0
- package/dist/cjs/safety/index.js.map +1 -0
- package/dist/cjs/safety/safety-middleware.d.ts +45 -0
- package/dist/cjs/safety/safety-middleware.js +99 -0
- package/dist/cjs/safety/safety-middleware.js.map +1 -0
- package/dist/esm/auth/index.d.ts +4 -0
- package/dist/esm/auth/index.js +3 -0
- package/dist/esm/auth/index.js.map +1 -1
- package/dist/esm/auth/stateful-oauth-strategy.d.ts +39 -0
- package/dist/esm/auth/stateful-oauth-strategy.js +136 -0
- package/dist/esm/auth/stateful-oauth-strategy.js.map +1 -0
- package/dist/esm/auth/stateful-store.d.ts +49 -0
- package/dist/esm/auth/stateful-store.js +168 -0
- package/dist/esm/auth/stateful-store.js.map +1 -0
- package/dist/esm/cli/am-command.d.ts +1 -1
- package/dist/esm/cli/am-command.js +9 -4
- package/dist/esm/cli/am-command.js.map +1 -1
- package/dist/esm/cli/base-command.d.ts +41 -0
- package/dist/esm/cli/base-command.js +84 -2
- package/dist/esm/cli/base-command.js.map +1 -1
- package/dist/esm/cli/instance-command.d.ts +3 -3
- package/dist/esm/cli/oauth-command.d.ts +19 -4
- package/dist/esm/cli/oauth-command.js +57 -2
- package/dist/esm/cli/oauth-command.js.map +1 -1
- package/dist/esm/cli/ods-command.d.ts +3 -3
- package/dist/esm/cli/webdav-command.d.ts +3 -3
- package/dist/esm/clients/am-api.js +7 -1
- package/dist/esm/clients/am-api.js.map +1 -1
- package/dist/esm/clients/index.d.ts +1 -1
- package/dist/esm/clients/index.js +1 -1
- package/dist/esm/clients/index.js.map +1 -1
- package/dist/esm/clients/middleware.d.ts +21 -0
- package/dist/esm/clients/middleware.js +30 -0
- package/dist/esm/clients/middleware.js.map +1 -1
- package/dist/esm/config/sources/env-source.js +4 -0
- package/dist/esm/config/sources/env-source.js.map +1 -1
- package/dist/esm/docs/schema.d.ts +2 -0
- package/dist/esm/docs/schema.js +2 -2
- package/dist/esm/docs/schema.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/operations/content/index.d.ts +15 -2
- package/dist/esm/operations/content/index.js +14 -2
- package/dist/esm/operations/content/index.js.map +1 -1
- package/dist/esm/operations/content/validate.d.ts +64 -0
- package/dist/esm/operations/content/validate.js +170 -0
- package/dist/esm/operations/content/validate.js.map +1 -0
- package/dist/esm/operations/mrt/bundle.js +13 -13
- package/dist/esm/operations/mrt/bundle.js.map +1 -1
- package/dist/esm/safety/index.d.ts +7 -0
- package/dist/esm/safety/index.js +7 -0
- package/dist/esm/safety/index.js.map +1 -0
- package/dist/esm/safety/safety-middleware.d.ts +45 -0
- package/dist/esm/safety/safety-middleware.js +99 -0
- package/dist/esm/safety/safety-middleware.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
3
|
+
|
|
4
|
+
"type":"object",
|
|
5
|
+
|
|
6
|
+
"definitions": {
|
|
7
|
+
"fraction" : {
|
|
8
|
+
"type": "number",
|
|
9
|
+
"minimum": 0,
|
|
10
|
+
"maximum": 1
|
|
11
|
+
},
|
|
12
|
+
"focal_point": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"x" : { "$ref": "#/definitions/fraction" },
|
|
16
|
+
"y" : { "$ref": "#/definitions/fraction" }
|
|
17
|
+
},
|
|
18
|
+
"required": ["x","y"]
|
|
19
|
+
},
|
|
20
|
+
"meta_data": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"height" : { "type": "integer" },
|
|
24
|
+
"width" : { "type": "integer" }
|
|
25
|
+
},
|
|
26
|
+
"required": ["height","width"]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
"properties": {
|
|
31
|
+
"path": {"type": "string"},
|
|
32
|
+
"focal_point": {"$ref":"#/definitions/focal_point"},
|
|
33
|
+
"meta_data": {"$ref":"#/definitions/meta_data"}
|
|
34
|
+
},
|
|
35
|
+
"required": ["path"],
|
|
36
|
+
"additionalProperties": false
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
3
|
+
|
|
4
|
+
"type":"object",
|
|
5
|
+
|
|
6
|
+
"properties": {
|
|
7
|
+
"name": {
|
|
8
|
+
"$ref": "common.json#/definitions/name"
|
|
9
|
+
},
|
|
10
|
+
"description": {
|
|
11
|
+
"$ref": "common.json#/definitions/description"
|
|
12
|
+
},
|
|
13
|
+
"arch_type": {
|
|
14
|
+
"$ref": "common.json#/definitions/arch_type"
|
|
15
|
+
},
|
|
16
|
+
"route": {
|
|
17
|
+
"$ref": "common.json#/definitions/route"
|
|
18
|
+
},
|
|
19
|
+
"region_definitions": {
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": {"$ref": "regiondefinition.json"}
|
|
22
|
+
},
|
|
23
|
+
"supported_aspect_types": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": {"$ref":"common.json#/definitions/full_qualified_id"}
|
|
26
|
+
},
|
|
27
|
+
"attribute_definition_groups": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"items": {
|
|
30
|
+
"$ref": "attributedefinitiongroup.json"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"required": [
|
|
35
|
+
"region_definitions"
|
|
36
|
+
],
|
|
37
|
+
"additionalProperties": false
|
|
38
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
3
|
+
|
|
4
|
+
"type":"object",
|
|
5
|
+
|
|
6
|
+
"properties": {
|
|
7
|
+
"id": {"$ref":"common.json#/definitions/id"},
|
|
8
|
+
"name": {"$ref":"common.json#/definitions/name"},
|
|
9
|
+
"max_components": {
|
|
10
|
+
"type": "integer",
|
|
11
|
+
"minimum": 1
|
|
12
|
+
},
|
|
13
|
+
"component_type_exclusions": {
|
|
14
|
+
"type": "array",
|
|
15
|
+
"items": {"$ref": "componenttypeexclusion.json"}
|
|
16
|
+
},
|
|
17
|
+
"component_type_inclusions": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"items": {"$ref": "componenttypeinclusion.json"}
|
|
20
|
+
},
|
|
21
|
+
"default_component_constructors": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {"$ref": "componentconstructor.json"}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": ["id"],
|
|
27
|
+
"additionalProperties": false,
|
|
28
|
+
"anyOf": [
|
|
29
|
+
{"required": ["component_type_exclusions"], "not": {"required": ["component_type_inclusions"]}},
|
|
30
|
+
{"required": ["component_type_inclusions"], "not": {"required": ["component_type_exclusions"]}},
|
|
31
|
+
{"not": {"required": ["component_type_exclusions", "component_type_inclusions"]}}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
3
|
+
|
|
4
|
+
"type":"object",
|
|
5
|
+
|
|
6
|
+
"definitions": {
|
|
7
|
+
"time_period": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"valid_from": {
|
|
11
|
+
"format": "date-time"
|
|
12
|
+
},
|
|
13
|
+
"valid_to": {
|
|
14
|
+
"format": "date-time"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"additionalProperties": false
|
|
18
|
+
},
|
|
19
|
+
"customer_group_id_listing": {
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": {
|
|
22
|
+
"type": "string"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"locale_id_listing": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "string"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"campaign_qualifier": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"properties": {
|
|
34
|
+
"campaign_id": {
|
|
35
|
+
"type": "string"
|
|
36
|
+
},
|
|
37
|
+
"promotion_id": {
|
|
38
|
+
"type": "string"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"additionalProperties": false
|
|
42
|
+
},
|
|
43
|
+
"aspect_attribute_qualifiers": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"items": { "$ref": "#/definitions/aspect_attribute_qualifier" }
|
|
46
|
+
},
|
|
47
|
+
"aspect_attribute_qualifier": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"properties": {
|
|
50
|
+
"id": {"$ref":"common.json#/definitions/id"},
|
|
51
|
+
"values": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"maxItems": 20,
|
|
54
|
+
"items": {}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"required": ["id", "values"],
|
|
58
|
+
"additionalProperties": false
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
"properties": {
|
|
63
|
+
"schedule": {"$ref": "#/definitions/time_period"},
|
|
64
|
+
"customer_group_ids": {"$ref": "#/definitions/customer_group_id_listing"},
|
|
65
|
+
"locale_ids": {"$ref": "#/definitions/locale_id_listing"},
|
|
66
|
+
"campaign_qualifier": {"$ref": "#/definitions/campaign_qualifier"},
|
|
67
|
+
"aspect_attribute_qualifiers" : {"$ref": "#/definitions/aspect_attribute_qualifiers"}
|
|
68
|
+
},
|
|
69
|
+
"additionalProperties": false
|
|
70
|
+
}
|
package/dist/cjs/auth/index.d.ts
CHANGED
|
@@ -61,6 +61,10 @@ export type { OAuthConfig } from './oauth.js';
|
|
|
61
61
|
export { ImplicitOAuthStrategy } from './oauth-implicit.js';
|
|
62
62
|
export type { ImplicitOAuthConfig } from './oauth-implicit.js';
|
|
63
63
|
export { ApiKeyStrategy } from './api-key.js';
|
|
64
|
+
export { StatefulOAuthStrategy } from './stateful-oauth-strategy.js';
|
|
65
|
+
export type { StatefulOAuthStrategyOptions } from './stateful-oauth-strategy.js';
|
|
66
|
+
export { initializeStatefulStore, getStoredSession, setStoredSession, clearStoredSession, isStatefulTokenValid, resetStatefulStoreForTesting, } from './stateful-store.js';
|
|
67
|
+
export type { StatefulSession } from './stateful-store.js';
|
|
64
68
|
export { resolveAuthStrategy, checkAvailableAuthMethods } from './resolve.js';
|
|
65
69
|
export type { ResolveAuthStrategyOptions, AvailableAuthMethods } from './resolve.js';
|
|
66
70
|
export { globalAuthMiddlewareRegistry, AuthMiddlewareRegistry, applyAuthRequestMiddleware, applyAuthResponseMiddleware, } from './middleware.js';
|
package/dist/cjs/auth/index.js
CHANGED
|
@@ -64,6 +64,9 @@ export { BasicAuthStrategy } from './basic.js';
|
|
|
64
64
|
export { OAuthStrategy, decodeJWT } from './oauth.js';
|
|
65
65
|
export { ImplicitOAuthStrategy } from './oauth-implicit.js';
|
|
66
66
|
export { ApiKeyStrategy } from './api-key.js';
|
|
67
|
+
export { StatefulOAuthStrategy } from './stateful-oauth-strategy.js';
|
|
68
|
+
// Stateful auth store
|
|
69
|
+
export { initializeStatefulStore, getStoredSession, setStoredSession, clearStoredSession, isStatefulTokenValid, resetStatefulStoreForTesting, } from './stateful-store.js';
|
|
67
70
|
// Resolution helpers
|
|
68
71
|
export { resolveAuthStrategy, checkAvailableAuthMethods } from './resolve.js';
|
|
69
72
|
// Auth middleware
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAeH,OAAO,EAAC,gBAAgB,EAAC,MAAM,YAAY,CAAC;AAE5C,aAAa;AACb,OAAO,EAAC,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAC,aAAa,EAAE,SAAS,EAAC,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAC,qBAAqB,EAAC,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAC,cAAc,EAAC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAeH,OAAO,EAAC,gBAAgB,EAAC,MAAM,YAAY,CAAC;AAE5C,aAAa;AACb,OAAO,EAAC,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAC,aAAa,EAAE,SAAS,EAAC,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAC,qBAAqB,EAAC,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAC,cAAc,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAC,qBAAqB,EAAC,MAAM,8BAA8B,CAAC;AAGnE,sBAAsB;AACtB,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC;AAG7B,qBAAqB;AACrB,OAAO,EAAC,mBAAmB,EAAE,yBAAyB,EAAC,MAAM,cAAc,CAAC;AAG5E,kBAAkB;AAClB,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth strategy that uses stateful (persisted) tokens from the same store as sfcc-ci.
|
|
3
|
+
* Uses stateful auth only when present and valid; on 401 attempts refresh when renew
|
|
4
|
+
* credentials or refresh_token are stored.
|
|
5
|
+
*
|
|
6
|
+
* @module auth/stateful-oauth-strategy
|
|
7
|
+
*/
|
|
8
|
+
import type { AuthStrategy, AccessTokenResponse, DecodedJWT, FetchInit } from './types.js';
|
|
9
|
+
import { type StatefulSession } from './stateful-store.js';
|
|
10
|
+
export interface StatefulOAuthStrategyOptions {
|
|
11
|
+
accountManagerHost: string;
|
|
12
|
+
scopes?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Auth strategy that uses the stateful store (sfcc-ci compatible).
|
|
16
|
+
* On 401, attempts to refresh using stored refresh_token or client_credentials (renew base);
|
|
17
|
+
* on refresh failure clears the stored session.
|
|
18
|
+
*/
|
|
19
|
+
export declare class StatefulOAuthStrategy implements AuthStrategy {
|
|
20
|
+
private accountManagerHost;
|
|
21
|
+
private scopes;
|
|
22
|
+
private _session;
|
|
23
|
+
private _hasHadSuccess;
|
|
24
|
+
constructor(session: StatefulSession, options: StatefulOAuthStrategyOptions);
|
|
25
|
+
fetch(url: string, init?: FetchInit): Promise<Response>;
|
|
26
|
+
getAuthorizationHeader(): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the current token as AccessTokenResponse (expires/scopes from JWT).
|
|
29
|
+
*/
|
|
30
|
+
getTokenResponse(): Promise<AccessTokenResponse>;
|
|
31
|
+
getJWT(): Promise<DecodedJWT>;
|
|
32
|
+
invalidateToken(): void;
|
|
33
|
+
private getAccessToken;
|
|
34
|
+
/**
|
|
35
|
+
* Attempts to refresh the access token using stored refresh_token or client_credentials (renew base).
|
|
36
|
+
* Requires SFCC_CLIENT_RENEW_BASE (client:secret) for both flows; updates store on success.
|
|
37
|
+
*/
|
|
38
|
+
private tryRefresh;
|
|
39
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { getLogger } from '../logging/logger.js';
|
|
2
|
+
import { decodeJWT } from './oauth.js';
|
|
3
|
+
import { DEFAULT_ACCOUNT_MANAGER_HOST } from '../defaults.js';
|
|
4
|
+
import { getStoredSession, setStoredSession, clearStoredSession } from './stateful-store.js';
|
|
5
|
+
import { globalAuthMiddlewareRegistry, applyAuthRequestMiddleware, applyAuthResponseMiddleware } from './middleware.js';
|
|
6
|
+
/**
|
|
7
|
+
* Auth strategy that uses the stateful store (sfcc-ci compatible).
|
|
8
|
+
* On 401, attempts to refresh using stored refresh_token or client_credentials (renew base);
|
|
9
|
+
* on refresh failure clears the stored session.
|
|
10
|
+
*/
|
|
11
|
+
export class StatefulOAuthStrategy {
|
|
12
|
+
accountManagerHost;
|
|
13
|
+
scopes;
|
|
14
|
+
_session;
|
|
15
|
+
_hasHadSuccess = false;
|
|
16
|
+
constructor(session, options) {
|
|
17
|
+
this._session = session;
|
|
18
|
+
this.accountManagerHost = options.accountManagerHost || DEFAULT_ACCOUNT_MANAGER_HOST;
|
|
19
|
+
this.scopes = options.scopes ?? [];
|
|
20
|
+
}
|
|
21
|
+
async fetch(url, init = {}) {
|
|
22
|
+
const logger = getLogger();
|
|
23
|
+
const token = await this.getAccessToken();
|
|
24
|
+
const headers = new Headers(init.headers);
|
|
25
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
26
|
+
headers.set('x-dw-client-id', this._session.clientId);
|
|
27
|
+
let res = await fetch(url, { ...init, headers });
|
|
28
|
+
if (res.status !== 401) {
|
|
29
|
+
this._hasHadSuccess = true;
|
|
30
|
+
}
|
|
31
|
+
if (res.status === 401 && this._hasHadSuccess) {
|
|
32
|
+
logger.debug('[StatefulAuth] 401 received, attempting refresh');
|
|
33
|
+
const refreshed = await this.tryRefresh();
|
|
34
|
+
if (refreshed) {
|
|
35
|
+
const newToken = await this.getAccessToken();
|
|
36
|
+
headers.set('Authorization', `Bearer ${newToken}`);
|
|
37
|
+
res = await fetch(url, { ...init, headers });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return res;
|
|
41
|
+
}
|
|
42
|
+
async getAuthorizationHeader() {
|
|
43
|
+
const token = await this.getAccessToken();
|
|
44
|
+
return `Bearer ${token}`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Returns the current token as AccessTokenResponse (expires/scopes from JWT).
|
|
48
|
+
*/
|
|
49
|
+
async getTokenResponse() {
|
|
50
|
+
const token = await this.getAccessToken();
|
|
51
|
+
const decoded = decodeJWT(token);
|
|
52
|
+
const exp = decoded.payload.exp ?? 0;
|
|
53
|
+
const scope = decoded.payload.scope;
|
|
54
|
+
const scopes = scope == null ? [] : Array.isArray(scope) ? scope : scope.split(' ');
|
|
55
|
+
return {
|
|
56
|
+
accessToken: token,
|
|
57
|
+
expires: new Date(exp * 1000),
|
|
58
|
+
scopes,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async getJWT() {
|
|
62
|
+
const token = await this.getAccessToken();
|
|
63
|
+
return decodeJWT(token);
|
|
64
|
+
}
|
|
65
|
+
invalidateToken() {
|
|
66
|
+
clearStoredSession();
|
|
67
|
+
this._session = { ...this._session, accessToken: '' };
|
|
68
|
+
}
|
|
69
|
+
async getAccessToken() {
|
|
70
|
+
const session = getStoredSession();
|
|
71
|
+
if (session?.accessToken) {
|
|
72
|
+
this._session = session;
|
|
73
|
+
return session.accessToken;
|
|
74
|
+
}
|
|
75
|
+
throw new Error('Stateful session lost; please run auth:login or configure client credentials.');
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Attempts to refresh the access token using stored refresh_token or client_credentials (renew base).
|
|
79
|
+
* Requires SFCC_CLIENT_RENEW_BASE (client:secret) for both flows; updates store on success.
|
|
80
|
+
*/
|
|
81
|
+
async tryRefresh() {
|
|
82
|
+
const logger = getLogger();
|
|
83
|
+
const session = getStoredSession();
|
|
84
|
+
if (!session?.renewBase) {
|
|
85
|
+
logger.debug('[StatefulAuth] No renew credentials (SFCC_CLIENT_RENEW_BASE); cannot refresh');
|
|
86
|
+
clearStoredSession();
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const url = `https://${this.accountManagerHost}/dwsso/oauth2/access_token`;
|
|
90
|
+
const grantPayload = session.refreshToken != null && session.refreshToken !== ''
|
|
91
|
+
? { grant_type: 'refresh_token', refresh_token: session.refreshToken }
|
|
92
|
+
: { grant_type: 'client_credentials' };
|
|
93
|
+
if (this.scopes.length > 0) {
|
|
94
|
+
grantPayload.scope = this.scopes.join(' ');
|
|
95
|
+
}
|
|
96
|
+
const body = new URLSearchParams(grantPayload).toString();
|
|
97
|
+
let request = new Request(url, {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: {
|
|
100
|
+
Authorization: `Basic ${session.renewBase}`,
|
|
101
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
102
|
+
},
|
|
103
|
+
body,
|
|
104
|
+
});
|
|
105
|
+
const middleware = globalAuthMiddlewareRegistry.getMiddleware();
|
|
106
|
+
request = await applyAuthRequestMiddleware(request, middleware);
|
|
107
|
+
let response;
|
|
108
|
+
try {
|
|
109
|
+
response = await fetch(request);
|
|
110
|
+
response = await applyAuthResponseMiddleware(request, response, middleware);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
logger.debug({ err }, '[StatefulAuth] Refresh request failed');
|
|
114
|
+
clearStoredSession();
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
const text = await response.text();
|
|
119
|
+
logger.debug({ status: response.status, body: text }, '[StatefulAuth] Refresh failed');
|
|
120
|
+
clearStoredSession();
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
const data = (await response.json());
|
|
124
|
+
setStoredSession({
|
|
125
|
+
clientId: session.clientId,
|
|
126
|
+
accessToken: data.access_token,
|
|
127
|
+
refreshToken: data.refresh_token ?? session.refreshToken ?? null,
|
|
128
|
+
renewBase: session.renewBase ?? null,
|
|
129
|
+
user: session.user ?? null,
|
|
130
|
+
});
|
|
131
|
+
this._session = getStoredSession();
|
|
132
|
+
logger.debug('[StatefulAuth] Token refreshed successfully');
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=stateful-oauth-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateful-oauth-strategy.js","sourceRoot":"","sources":["../../../src/auth/stateful-oauth-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize the stateful store with the oclif data directory.
|
|
3
|
+
* Call this from BaseCommand.init() with this.config.dataDir so the session
|
|
4
|
+
* file is stored alongside other CLI data (e.g. ~/Library/Application Support/@salesforce/b2c-cli).
|
|
5
|
+
*/
|
|
6
|
+
export declare function initializeStatefulStore(dataDir: string): void;
|
|
7
|
+
/**
|
|
8
|
+
* Stored session persisted by stateful auth commands.
|
|
9
|
+
*/
|
|
10
|
+
export interface StatefulSession {
|
|
11
|
+
clientId: string;
|
|
12
|
+
accessToken: string;
|
|
13
|
+
refreshToken?: string | null;
|
|
14
|
+
/** Base64-encoded "clientId:clientSecret" for token renewal. */
|
|
15
|
+
renewBase?: string | null;
|
|
16
|
+
user?: string | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Reads the current stateful session from the JSON file.
|
|
20
|
+
* Returns null if no session file exists or the file is invalid.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getStoredSession(): StatefulSession | null;
|
|
23
|
+
/**
|
|
24
|
+
* Writes a session to the JSON file, creating the directory if needed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function setStoredSession(session: StatefulSession): void;
|
|
27
|
+
/**
|
|
28
|
+
* Clears the stored session by removing the session file.
|
|
29
|
+
*/
|
|
30
|
+
export declare function clearStoredSession(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Checks whether the stored access token is present and valid: not expired
|
|
33
|
+
* (with a small buffer), optionally satisfies required scopes, and optionally
|
|
34
|
+
* matches the expected client ID.
|
|
35
|
+
* Does not perform network calls.
|
|
36
|
+
*
|
|
37
|
+
* @param session - Session from getStoredSession()
|
|
38
|
+
* @param requiredScopes - If provided, token must include all of these scopes
|
|
39
|
+
* @param expiryBufferSec - Seconds before exp to treat token as expired (default 60)
|
|
40
|
+
* @param requiredClientId - If provided, session clientId must match
|
|
41
|
+
* @returns true if token is present and valid for use
|
|
42
|
+
*/
|
|
43
|
+
export declare function isStatefulTokenValid(session: StatefulSession, requiredScopes?: string[], expiryBufferSec?: number, requiredClientId?: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Resets the store path (for tests). After calling this, the next operation
|
|
46
|
+
* will use the default data directory unless initializeStatefulStore() is called again.
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
export declare function resetStatefulStoreForTesting(): void;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Stateful auth store backed by a JSON file in the oclif data directory
|
|
8
|
+
* (e.g. ~/Library/Application Support/@salesforce/b2c-cli/auth-session.json on macOS).
|
|
9
|
+
*
|
|
10
|
+
* Initialize via initializeStatefulStore(dataDir) from BaseCommand.init() so the
|
|
11
|
+
* session file is co-located with other CLI data. Falls back to an OS-appropriate
|
|
12
|
+
* default path when used standalone (outside a CLI command).
|
|
13
|
+
*
|
|
14
|
+
* The stateful auth workflow (b2c auth client / b2c auth login / b2c auth logout)
|
|
15
|
+
* is compatible with sfcc-ci command patterns. Session data is stored internally
|
|
16
|
+
* in the CLI data directory, not in the sfcc-ci config store.
|
|
17
|
+
*
|
|
18
|
+
* @module auth/stateful-store
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { homedir, platform } from 'node:os';
|
|
23
|
+
import { decodeJWT } from './oauth.js';
|
|
24
|
+
import { getLogger } from '../logging/logger.js';
|
|
25
|
+
const STATEFUL_AUTH_SESSION_STORE = 'auth-session.json';
|
|
26
|
+
/** Default buffer (seconds) before token exp to consider it expired */
|
|
27
|
+
const EXPIRY_BUFFER_SEC = 60;
|
|
28
|
+
let storePath = null;
|
|
29
|
+
/**
|
|
30
|
+
* Computes the oclif-compatible data directory for @salesforce/b2c-cli.
|
|
31
|
+
* Used as a fallback when initializeStatefulStore() has not been called.
|
|
32
|
+
*/
|
|
33
|
+
function getDefaultDataDir() {
|
|
34
|
+
const home = homedir();
|
|
35
|
+
const name = '@salesforce/b2c-cli';
|
|
36
|
+
switch (platform()) {
|
|
37
|
+
case 'darwin':
|
|
38
|
+
return join(home, 'Library', 'Application Support', name);
|
|
39
|
+
case 'win32':
|
|
40
|
+
return join(process.env.LOCALAPPDATA ?? join(home, 'AppData', 'Local'), name);
|
|
41
|
+
default:
|
|
42
|
+
return join(process.env.XDG_DATA_HOME ?? join(home, '.local', 'share'), name);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function getSessionFilePath() {
|
|
46
|
+
return join(storePath ?? getDefaultDataDir(), STATEFUL_AUTH_SESSION_STORE);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Initialize the stateful store with the oclif data directory.
|
|
50
|
+
* Call this from BaseCommand.init() with this.config.dataDir so the session
|
|
51
|
+
* file is stored alongside other CLI data (e.g. ~/Library/Application Support/@salesforce/b2c-cli).
|
|
52
|
+
*/
|
|
53
|
+
export function initializeStatefulStore(dataDir) {
|
|
54
|
+
storePath = dataDir;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Reads the current stateful session from the JSON file.
|
|
58
|
+
* Returns null if no session file exists or the file is invalid.
|
|
59
|
+
*/
|
|
60
|
+
export function getStoredSession() {
|
|
61
|
+
const filePath = getSessionFilePath();
|
|
62
|
+
if (!existsSync(filePath)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const data = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
67
|
+
if (!data.clientId || !data.accessToken) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
clientId: data.clientId,
|
|
72
|
+
accessToken: data.accessToken,
|
|
73
|
+
refreshToken: data.refreshToken ?? null,
|
|
74
|
+
renewBase: data.renewBase ?? null,
|
|
75
|
+
user: data.user ?? null,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Writes a session to the JSON file, creating the directory if needed.
|
|
84
|
+
*/
|
|
85
|
+
export function setStoredSession(session) {
|
|
86
|
+
const filePath = getSessionFilePath();
|
|
87
|
+
const dir = join(filePath, '..');
|
|
88
|
+
if (!existsSync(dir)) {
|
|
89
|
+
mkdirSync(dir, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
const data = {
|
|
92
|
+
clientId: session.clientId,
|
|
93
|
+
accessToken: session.accessToken,
|
|
94
|
+
refreshToken: session.refreshToken ?? null,
|
|
95
|
+
renewBase: session.renewBase ?? null,
|
|
96
|
+
user: session.user ?? null,
|
|
97
|
+
};
|
|
98
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Clears the stored session by removing the session file.
|
|
102
|
+
*/
|
|
103
|
+
export function clearStoredSession() {
|
|
104
|
+
const filePath = getSessionFilePath();
|
|
105
|
+
if (existsSync(filePath)) {
|
|
106
|
+
try {
|
|
107
|
+
unlinkSync(filePath);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// ignore — file may have already been removed
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Checks whether the stored access token is present and valid: not expired
|
|
116
|
+
* (with a small buffer), optionally satisfies required scopes, and optionally
|
|
117
|
+
* matches the expected client ID.
|
|
118
|
+
* Does not perform network calls.
|
|
119
|
+
*
|
|
120
|
+
* @param session - Session from getStoredSession()
|
|
121
|
+
* @param requiredScopes - If provided, token must include all of these scopes
|
|
122
|
+
* @param expiryBufferSec - Seconds before exp to treat token as expired (default 60)
|
|
123
|
+
* @param requiredClientId - If provided, session clientId must match
|
|
124
|
+
* @returns true if token is present and valid for use
|
|
125
|
+
*/
|
|
126
|
+
export function isStatefulTokenValid(session, requiredScopes = [], expiryBufferSec = EXPIRY_BUFFER_SEC, requiredClientId) {
|
|
127
|
+
const logger = getLogger();
|
|
128
|
+
try {
|
|
129
|
+
if (requiredClientId && session.clientId !== requiredClientId) {
|
|
130
|
+
logger.debug({ storedClientId: session.clientId, requiredClientId }, '[StatefulAuth] Token client ID mismatch');
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
const decoded = decodeJWT(session.accessToken);
|
|
134
|
+
const exp = decoded.payload.exp;
|
|
135
|
+
if (typeof exp !== 'number') {
|
|
136
|
+
logger.debug('[StatefulAuth] Token has no exp claim; treating as invalid');
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
140
|
+
if (nowSec >= exp - expiryBufferSec) {
|
|
141
|
+
logger.debug('[StatefulAuth] Token missing or expired');
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
if (requiredScopes.length > 0) {
|
|
145
|
+
const tokenScopes = decoded.payload.scope ?? [];
|
|
146
|
+
const scopeList = Array.isArray(tokenScopes) ? tokenScopes : tokenScopes.split(' ');
|
|
147
|
+
const hasAll = requiredScopes.every((s) => scopeList.includes(s));
|
|
148
|
+
if (!hasAll) {
|
|
149
|
+
logger.debug({ requiredScopes, tokenScopes: scopeList }, '[StatefulAuth] Token missing required scopes');
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
logger.debug({ err: e }, '[StatefulAuth] Token invalid (e.g. not a JWT)');
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Resets the store path (for tests). After calling this, the next operation
|
|
162
|
+
* will use the default data directory unless initializeStatefulStore() is called again.
|
|
163
|
+
* @internal
|
|
164
|
+
*/
|
|
165
|
+
export function resetStatefulStoreForTesting() {
|
|
166
|
+
storePath = null;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=stateful-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateful-store.js","sourceRoot":"","sources":["../../../src/auth/stateful-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ export declare abstract class AmCommand<T extends typeof Command> extends OAuthC
|
|
|
30
30
|
/**
|
|
31
31
|
* Gets the auth method type that was used, based on the stored strategy.
|
|
32
32
|
*/
|
|
33
|
-
protected get authMethodUsed(): 'implicit' | 'client-credentials' | undefined;
|
|
33
|
+
protected get authMethodUsed(): 'implicit' | 'client-credentials' | 'stateful' | undefined;
|
|
34
34
|
/**
|
|
35
35
|
* Gets the unified Account Manager client, creating it if necessary.
|
|
36
36
|
* This provides direct access to all Account Manager API methods (users, roles, orgs).
|