@forgecart/cli 2.202610130131.0 → 2.202610130431.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/dist/src/admin-api/admin-api-refusal.error.d.ts +2 -2
- package/dist/src/admin-api/admin-api-refusal.error.js +2 -2
- package/dist/src/admin-api/admin-api.client.d.ts +8 -4
- package/dist/src/admin-api/admin-api.client.js +11 -9
- package/dist/src/admin-api/admin-api.client.js.map +1 -1
- package/dist/src/admin-api/admin-api.result.d.ts +7 -0
- package/dist/src/admin-api/admin-api.result.js +31 -2
- package/dist/src/admin-api/admin-api.result.js.map +1 -1
- package/dist/src/authorization/cli-authorization-flow.d.ts +21 -14
- package/dist/src/authorization/cli-authorization-flow.js +40 -31
- package/dist/src/authorization/cli-authorization-flow.js.map +1 -1
- package/dist/src/authorization/cli-credential-check.d.ts +6 -13
- package/dist/src/authorization/cli-credential-check.js +6 -23
- package/dist/src/authorization/cli-credential-check.js.map +1 -1
- package/dist/src/authorization/cli-credential-step.d.ts +74 -0
- package/dist/src/authorization/cli-credential-step.js +154 -0
- package/dist/src/authorization/cli-credential-step.js.map +1 -0
- package/dist/src/authorization/cli-unauthorized-refusal.d.ts +18 -8
- package/dist/src/authorization/cli-unauthorized-refusal.js +26 -11
- package/dist/src/authorization/cli-unauthorized-refusal.js.map +1 -1
- package/dist/src/authorization/type/cli-authorization.types.d.ts +36 -4
- package/dist/src/authorization/type/cli-authorization.types.js +16 -3
- package/dist/src/authorization/type/cli-authorization.types.js.map +1 -1
- package/dist/src/commands/init.d.ts +0 -10
- package/dist/src/commands/init.js +17 -42
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/sync.js +2 -2
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/deploy/deploy.runner.d.ts +15 -8
- package/dist/src/deploy/deploy.runner.js +19 -10
- package/dist/src/deploy/deploy.runner.js.map +1 -1
- package/dist/src/sync/sync-bundle-push.d.ts +34 -0
- package/dist/src/sync/sync-bundle-push.js +97 -0
- package/dist/src/sync/sync-bundle-push.js.map +1 -0
- package/dist/src/sync/sync-dotenv.file.d.ts +30 -22
- package/dist/src/sync/sync-dotenv.file.js +49 -54
- package/dist/src/sync/sync-dotenv.file.js.map +1 -1
- package/dist/src/sync/sync-env-channel.d.ts +47 -0
- package/dist/src/sync/sync-env-channel.js +106 -0
- package/dist/src/sync/sync-env-channel.js.map +1 -0
- package/dist/src/sync/sync-env.runner.d.ts +26 -10
- package/dist/src/sync/sync-env.runner.js +73 -40
- package/dist/src/sync/sync-env.runner.js.map +1 -1
- package/dist/src/sync/sync-record.file.d.ts +18 -10
- package/dist/src/sync/sync-record.file.js +30 -10
- package/dist/src/sync/sync-record.file.js.map +1 -1
- package/dist/src/sync/sync-repository.d.ts +7 -2
- package/dist/src/sync/sync-repository.js +26 -5
- package/dist/src/sync/sync-repository.js.map +1 -1
- package/dist/src/sync/sync-round.d.ts +28 -15
- package/dist/src/sync/sync-round.js +78 -39
- package/dist/src/sync/sync-round.js.map +1 -1
- package/dist/src/sync/sync-watch.d.ts +2 -1
- package/dist/src/sync/sync-watch.js +2 -1
- package/dist/src/sync/sync-watch.js.map +1 -1
- package/dist/src/sync/sync.runner.d.ts +16 -8
- package/dist/src/sync/sync.runner.js +30 -26
- package/dist/src/sync/sync.runner.js.map +1 -1
- package/dist/src/sync/type/sync.types.d.ts +78 -16
- package/dist/src/sync/type/sync.types.js.map +1 -1
- package/dist/src/sync/workspace-sync.client.d.ts +43 -16
- package/dist/src/sync/workspace-sync.client.js +125 -31
- package/dist/src/sync/workspace-sync.client.js.map +1 -1
- package/dist/src/util/dotenv.util.d.ts +19 -5
- package/dist/src/util/dotenv.util.js +42 -5
- package/dist/src/util/dotenv.util.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type CliCredentials, type CliCredentialStepInput, type CliSettledCredentials } from './type/cli-authorization.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default shop API base, INCLUDING the mounted path. The API serves the shop
|
|
4
|
+
* GraphQL endpoint at `/shop-api` (`app/forgecart/src/main.ts`), and the SDK
|
|
5
|
+
* takes this value verbatim as its endpoint. The SDK swaps the scheme for the
|
|
6
|
+
* websocket and appends nothing to the path, so a pathless origin scaffolds a
|
|
7
|
+
* storefront whose every read dials a socket nothing answers (#2102): the
|
|
8
|
+
* operation rides graphql-ws's whole retry ladder and the page hangs with
|
|
9
|
+
* nothing logged. `init`'s `--api-url` defaults to it, and the credential step
|
|
10
|
+
* authorizes against its admin API when no source names an API.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_SHOP_API_URL = "https://api.forgecart.com/shop-api";
|
|
13
|
+
/**
|
|
14
|
+
* The ONE credential step (launch#62 N3). Every command that needs the four
|
|
15
|
+
* `FORGECART_*` keys reads them through this step. It looks for each key in
|
|
16
|
+
* the environment, then the storefront's `.env`, then its
|
|
17
|
+
* `.forgecart/config.json`.
|
|
18
|
+
*
|
|
19
|
+
* When a key is in no source, or the admin API refuses the credentials as one
|
|
20
|
+
* of the {@link CliCredentialRefusalCode} codes, the step authorizes this
|
|
21
|
+
* machine at `/authorize` with the project's store preselected. The four keys
|
|
22
|
+
* the approval delivers land in the storefront's `.env` the moment the poll
|
|
23
|
+
* delivers them, so a run that is interrupted afterwards keeps them and its
|
|
24
|
+
* re-run opens no browser. The command then continues on the delivered keys.
|
|
25
|
+
* A denial, an expiry or an elapsed wait exits 3 with
|
|
26
|
+
* FORGECART_CLI_UNAUTHORIZED and writes nothing. The step authorizes at most
|
|
27
|
+
* once per run: if the admin API refuses the credentials an approval has just
|
|
28
|
+
* delivered, the run exits 3 and never 1.
|
|
29
|
+
*/
|
|
30
|
+
export declare class CliCredentialStep {
|
|
31
|
+
private readonly input;
|
|
32
|
+
constructor(input: CliCredentialStepInput);
|
|
33
|
+
/**
|
|
34
|
+
* The four credentials the sources carry. When a key is in no source, the
|
|
35
|
+
* step returns the four an authorization delivers. Use this for a command
|
|
36
|
+
* that sends nothing to the admin API before its own work ends, as `init`
|
|
37
|
+
* does.
|
|
38
|
+
*/
|
|
39
|
+
settle(): Promise<CliSettledCredentials>;
|
|
40
|
+
/**
|
|
41
|
+
* Run `command` on the settled credentials. If the admin API refuses the
|
|
42
|
+
* credentials the sources carried, the step authorizes this machine and runs
|
|
43
|
+
* `command` once more on the delivered keys. A refusal of keys an
|
|
44
|
+
* authorization delivered ends the run on exit 3.
|
|
45
|
+
*/
|
|
46
|
+
run<T>(command: (credentials: CliCredentials) => Promise<T>): Promise<T>;
|
|
47
|
+
private settleFrom;
|
|
48
|
+
/**
|
|
49
|
+
* The command's run on the credentials the sources carry. The admin API
|
|
50
|
+
* refusing those credentials is the one failure that does not end the run:
|
|
51
|
+
* the step answers it by authorizing. Every other error propagates as
|
|
52
|
+
* thrown.
|
|
53
|
+
*/
|
|
54
|
+
private runOnSourced;
|
|
55
|
+
/** Authorize this machine for the project's store, and keep what the approval delivers in `.env` at once. */
|
|
56
|
+
private authorize;
|
|
57
|
+
/** Why a run whose credentials were all found authorizes: the code the admin API refused them with. */
|
|
58
|
+
private refusalReport;
|
|
59
|
+
/**
|
|
60
|
+
* The admin API that answers the authorization. The step uses
|
|
61
|
+
* FORGECART_ADMIN_API_URL when a source names it. Otherwise it uses
|
|
62
|
+
* {@link ADMIN_API_PATH} on the origin of the caller's shop API, else the
|
|
63
|
+
* shop API the sources name, else the platform's.
|
|
64
|
+
*/
|
|
65
|
+
private adminApiUrlOf;
|
|
66
|
+
/**
|
|
67
|
+
* Merge the four delivered keys into the storefront's `.env`. Each key is
|
|
68
|
+
* refreshed in place, and every other line is kept verbatim. The step
|
|
69
|
+
* creates the storefront directory if it does not exist yet.
|
|
70
|
+
*/
|
|
71
|
+
private writeDotenv;
|
|
72
|
+
/** Read a file that may legitimately not exist yet. Any other failure propagates. */
|
|
73
|
+
private readIfPresent;
|
|
74
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { print } from '../output.js';
|
|
4
|
+
import { mergeDotenv } from '../util/dotenv.util.js';
|
|
5
|
+
import { CliAuthorizationFlow } from './cli-authorization-flow.js';
|
|
6
|
+
import { CliAuthorizationClient } from './cli-authorization.client.js';
|
|
7
|
+
import { CliCredentialCheck } from './cli-credential-check.js';
|
|
8
|
+
import { CliCredentialsRefusal } from './cli-unauthorized-refusal.js';
|
|
9
|
+
import { CliCredentialKey, } from './type/cli-authorization.types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Default shop API base, INCLUDING the mounted path. The API serves the shop
|
|
12
|
+
* GraphQL endpoint at `/shop-api` (`app/forgecart/src/main.ts`), and the SDK
|
|
13
|
+
* takes this value verbatim as its endpoint. The SDK swaps the scheme for the
|
|
14
|
+
* websocket and appends nothing to the path, so a pathless origin scaffolds a
|
|
15
|
+
* storefront whose every read dials a socket nothing answers (#2102): the
|
|
16
|
+
* operation rides graphql-ws's whole retry ladder and the page hangs with
|
|
17
|
+
* nothing logged. `init`'s `--api-url` defaults to it, and the credential step
|
|
18
|
+
* authorizes against its admin API when no source names an API.
|
|
19
|
+
*/
|
|
20
|
+
export const DEFAULT_SHOP_API_URL = 'https://api.forgecart.com/shop-api';
|
|
21
|
+
/**
|
|
22
|
+
* The admin API's path beside the shop API's on every platform origin: the
|
|
23
|
+
* server's `ADMIN_API_PATH`. When no FORGECART_ADMIN_API_URL names the admin
|
|
24
|
+
* API outright, the authorization is requested at this path on the shop API's
|
|
25
|
+
* origin (#2772, ruling R2).
|
|
26
|
+
*/
|
|
27
|
+
const ADMIN_API_PATH = '/admin-api';
|
|
28
|
+
/**
|
|
29
|
+
* The ONE credential step (launch#62 N3). Every command that needs the four
|
|
30
|
+
* `FORGECART_*` keys reads them through this step. It looks for each key in
|
|
31
|
+
* the environment, then the storefront's `.env`, then its
|
|
32
|
+
* `.forgecart/config.json`.
|
|
33
|
+
*
|
|
34
|
+
* When a key is in no source, or the admin API refuses the credentials as one
|
|
35
|
+
* of the {@link CliCredentialRefusalCode} codes, the step authorizes this
|
|
36
|
+
* machine at `/authorize` with the project's store preselected. The four keys
|
|
37
|
+
* the approval delivers land in the storefront's `.env` the moment the poll
|
|
38
|
+
* delivers them, so a run that is interrupted afterwards keeps them and its
|
|
39
|
+
* re-run opens no browser. The command then continues on the delivered keys.
|
|
40
|
+
* A denial, an expiry or an elapsed wait exits 3 with
|
|
41
|
+
* FORGECART_CLI_UNAUTHORIZED and writes nothing. The step authorizes at most
|
|
42
|
+
* once per run: if the admin API refuses the credentials an approval has just
|
|
43
|
+
* delivered, the run exits 3 and never 1.
|
|
44
|
+
*/
|
|
45
|
+
export class CliCredentialStep {
|
|
46
|
+
input;
|
|
47
|
+
constructor(input) {
|
|
48
|
+
this.input = input;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The four credentials the sources carry. When a key is in no source, the
|
|
52
|
+
* step returns the four an authorization delivers. Use this for a command
|
|
53
|
+
* that sends nothing to the admin API before its own work ends, as `init`
|
|
54
|
+
* does.
|
|
55
|
+
*/
|
|
56
|
+
async settle() {
|
|
57
|
+
return this.settleFrom(await CliCredentialCheck.read(this.input.targetDir));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run `command` on the settled credentials. If the admin API refuses the
|
|
61
|
+
* credentials the sources carried, the step authorizes this machine and runs
|
|
62
|
+
* `command` once more on the delivered keys. A refusal of keys an
|
|
63
|
+
* authorization delivered ends the run on exit 3.
|
|
64
|
+
*/
|
|
65
|
+
async run(command) {
|
|
66
|
+
const check = await CliCredentialCheck.read(this.input.targetDir);
|
|
67
|
+
const settled = await this.settleFrom(check);
|
|
68
|
+
if (settled.authorized)
|
|
69
|
+
return command(settled.credentials);
|
|
70
|
+
const sourced = await this.runOnSourced(command, settled.credentials);
|
|
71
|
+
if (!sourced.refused)
|
|
72
|
+
return sourced.result;
|
|
73
|
+
return command(await this.authorize(check, this.refusalReport(sourced.code)));
|
|
74
|
+
}
|
|
75
|
+
async settleFrom(check) {
|
|
76
|
+
const found = check.credentials();
|
|
77
|
+
if (found !== undefined)
|
|
78
|
+
return { credentials: found, authorized: false };
|
|
79
|
+
return { credentials: await this.authorize(check, check.report()), authorized: true };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The command's run on the credentials the sources carry. The admin API
|
|
83
|
+
* refusing those credentials is the one failure that does not end the run:
|
|
84
|
+
* the step answers it by authorizing. Every other error propagates as
|
|
85
|
+
* thrown.
|
|
86
|
+
*/
|
|
87
|
+
async runOnSourced(command, credentials) {
|
|
88
|
+
try {
|
|
89
|
+
return { refused: false, result: await command(credentials) };
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (error instanceof CliCredentialsRefusal)
|
|
93
|
+
return { refused: true, code: error.code };
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Authorize this machine for the project's store, and keep what the approval delivers in `.env` at once. */
|
|
98
|
+
async authorize(check, report) {
|
|
99
|
+
const client = new CliAuthorizationClient(this.adminApiUrlOf(check));
|
|
100
|
+
const flow = new CliAuthorizationFlow(client, this.input.timeoutSec);
|
|
101
|
+
const credentials = await flow.authorize(report, check.value(CliCredentialKey.CHANNEL_TOKEN));
|
|
102
|
+
await this.writeDotenv(credentials);
|
|
103
|
+
return credentials;
|
|
104
|
+
}
|
|
105
|
+
/** Why a run whose credentials were all found authorizes: the code the admin API refused them with. */
|
|
106
|
+
refusalReport(code) {
|
|
107
|
+
return ['', ` The admin API refused the credentials: ${code}.`];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The admin API that answers the authorization. The step uses
|
|
111
|
+
* FORGECART_ADMIN_API_URL when a source names it. Otherwise it uses
|
|
112
|
+
* {@link ADMIN_API_PATH} on the origin of the caller's shop API, else the
|
|
113
|
+
* shop API the sources name, else the platform's.
|
|
114
|
+
*/
|
|
115
|
+
adminApiUrlOf(check) {
|
|
116
|
+
const named = check.value(CliCredentialKey.ADMIN_API_URL);
|
|
117
|
+
if (named !== undefined)
|
|
118
|
+
return named;
|
|
119
|
+
const shopApiUrl = this.input.shopApiUrl ?? check.value(CliCredentialKey.SHOP_API_URL) ?? DEFAULT_SHOP_API_URL;
|
|
120
|
+
if (!URL.canParse(shopApiUrl)) {
|
|
121
|
+
throw new Error(`${shopApiUrl} is not a URL, so the admin API to authorize against cannot be found.`);
|
|
122
|
+
}
|
|
123
|
+
return new URL(ADMIN_API_PATH, shopApiUrl).toString();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Merge the four delivered keys into the storefront's `.env`. Each key is
|
|
127
|
+
* refreshed in place, and every other line is kept verbatim. The step
|
|
128
|
+
* creates the storefront directory if it does not exist yet.
|
|
129
|
+
*/
|
|
130
|
+
async writeDotenv(credentials) {
|
|
131
|
+
await mkdir(this.input.targetDir, { recursive: true });
|
|
132
|
+
const path = join(this.input.targetDir, '.env');
|
|
133
|
+
const managed = new Map([
|
|
134
|
+
[CliCredentialKey.CHANNEL_TOKEN, credentials.channelToken],
|
|
135
|
+
[CliCredentialKey.SHOP_API_URL, credentials.shopApiUrl],
|
|
136
|
+
[CliCredentialKey.ADMIN_SECRET, credentials.adminSecret],
|
|
137
|
+
[CliCredentialKey.ADMIN_API_URL, credentials.adminApiUrl],
|
|
138
|
+
]);
|
|
139
|
+
await writeFile(path, mergeDotenv(await this.readIfPresent(path), managed), 'utf8');
|
|
140
|
+
print(` ✓ Wrote the four FORGECART_* keys to ${path}`);
|
|
141
|
+
}
|
|
142
|
+
/** Read a file that may legitimately not exist yet. Any other failure propagates. */
|
|
143
|
+
async readIfPresent(path) {
|
|
144
|
+
try {
|
|
145
|
+
return await readFile(path, 'utf8');
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (error.code === 'ENOENT')
|
|
149
|
+
return '';
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=cli-credential-step.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-credential-step.js","sourceRoot":"","sources":["../../../src/authorization/cli-credential-step.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CliRefusal } from '../exit-ladder.js';
|
|
2
|
+
import { CliCredentialRefusalCode } from './type/cli-authorization.types.js';
|
|
2
3
|
/** The code a scripted caller routes on beside exit 3 — never the prose after it. */
|
|
3
4
|
export declare const CLI_UNAUTHORIZED_CODE = "FORGECART_CLI_UNAUTHORIZED";
|
|
4
5
|
/** Why no approval delivered the credentials. */
|
|
@@ -9,19 +10,28 @@ export declare enum CliUnauthorizedReason {
|
|
|
9
10
|
EXPIRED = "expired",
|
|
10
11
|
/** `--timeout` elapsed before an approval. */
|
|
11
12
|
TIMED_OUT = "timed-out",
|
|
12
|
-
/**
|
|
13
|
-
MISSING = "missing",
|
|
14
|
-
/** The admin API refused the credentials the run settled — UNAUTHORIZED or FORBIDDEN. */
|
|
13
|
+
/** The admin API refused the credentials the run settled, as one of {@link CliCredentialRefusalCode}. */
|
|
15
14
|
REFUSED = "refused"
|
|
16
15
|
}
|
|
17
16
|
/**
|
|
18
|
-
* Credentials a run cannot use
|
|
19
|
-
* {@link CLI_UNAUTHORIZED_CODE}
|
|
20
|
-
* end approved (#2772, record `refs/design/cli-improvements`,
|
|
21
|
-
* `init?case=headless`), or
|
|
22
|
-
*
|
|
17
|
+
* Credentials a run cannot use. It exits {@link CliExitLadder.unauthorized}
|
|
18
|
+
* with {@link CLI_UNAUTHORIZED_CODE} and never hangs. Either an authorization
|
|
19
|
+
* did not end approved (#2772, record `refs/design/cli-improvements`,
|
|
20
|
+
* `init?case=headless`), or the admin API refused the credentials an
|
|
21
|
+
* authorization had just delivered ({@link CliCredentialsRefusal}).
|
|
23
22
|
*/
|
|
24
23
|
export declare class CliUnauthorizedRefusal extends CliRefusal {
|
|
25
24
|
readonly reason: CliUnauthorizedReason;
|
|
26
25
|
constructor(reason: CliUnauthorizedReason);
|
|
27
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Credentials the admin API refused, with the code it refused them with. The
|
|
29
|
+
* credential step answers this refusal by authorizing this machine once
|
|
30
|
+
* (launch#62 N3). If the refusal reaches the run, the run exits 3 and never 1.
|
|
31
|
+
*/
|
|
32
|
+
export declare class CliCredentialsRefusal extends CliUnauthorizedRefusal {
|
|
33
|
+
readonly code: CliCredentialRefusalCode;
|
|
34
|
+
constructor(code: CliCredentialRefusalCode);
|
|
35
|
+
/** Whether the admin API refuses credentials with `code`. Every other code is a refusal of the operation. */
|
|
36
|
+
static isRefusalCode(code: string): code is CliCredentialRefusalCode;
|
|
37
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CliExitLadder, CliRefusal } from '../exit-ladder.js';
|
|
2
|
+
import { CliCredentialRefusalCode } from './type/cli-authorization.types.js';
|
|
2
3
|
/** The code a scripted caller routes on beside exit 3 — never the prose after it. */
|
|
3
4
|
export const CLI_UNAUTHORIZED_CODE = 'FORGECART_CLI_UNAUTHORIZED';
|
|
4
5
|
/** Why no approval delivered the credentials. */
|
|
@@ -10,25 +11,22 @@ export var CliUnauthorizedReason;
|
|
|
10
11
|
CliUnauthorizedReason["EXPIRED"] = "expired";
|
|
11
12
|
/** `--timeout` elapsed before an approval. */
|
|
12
13
|
CliUnauthorizedReason["TIMED_OUT"] = "timed-out";
|
|
13
|
-
/**
|
|
14
|
-
CliUnauthorizedReason["MISSING"] = "missing";
|
|
15
|
-
/** The admin API refused the credentials the run settled — UNAUTHORIZED or FORBIDDEN. */
|
|
14
|
+
/** The admin API refused the credentials the run settled, as one of {@link CliCredentialRefusalCode}. */
|
|
16
15
|
CliUnauthorizedReason["REFUSED"] = "refused";
|
|
17
16
|
})(CliUnauthorizedReason || (CliUnauthorizedReason = {}));
|
|
18
|
-
/** What each reason tells the merchant: what happened,
|
|
17
|
+
/** What each reason tells the merchant: what happened, what was written, and the two ways on. */
|
|
19
18
|
const REASON_LINES = {
|
|
20
19
|
[CliUnauthorizedReason.DENIED]: 'the authorization was denied at /authorize; nothing was written.',
|
|
21
20
|
[CliUnauthorizedReason.EXPIRED]: 'the authorization window closed before an approval; nothing was written. Re-run to open a new one, or export the four FORGECART_* keys.',
|
|
22
21
|
[CliUnauthorizedReason.TIMED_OUT]: 'no credentials in the environment, in .env or in .forgecart/config.json, and no approval within --timeout; nothing was written. Export the four FORGECART_* keys, or authorize at the URL above.',
|
|
23
|
-
[CliUnauthorizedReason.
|
|
24
|
-
[CliUnauthorizedReason.REFUSED]: 'the admin API refused the credentials; nothing was written. Export the four FORGECART_* keys of a channel admin, or run `forgecart init` to authorize this machine.',
|
|
22
|
+
[CliUnauthorizedReason.REFUSED]: 'the admin API refused the credentials. Export the four FORGECART_* keys of a channel admin, or re-run to authorize this machine at /authorize.',
|
|
25
23
|
};
|
|
26
24
|
/**
|
|
27
|
-
* Credentials a run cannot use
|
|
28
|
-
* {@link CLI_UNAUTHORIZED_CODE}
|
|
29
|
-
* end approved (#2772, record `refs/design/cli-improvements`,
|
|
30
|
-
* `init?case=headless`), or
|
|
31
|
-
*
|
|
25
|
+
* Credentials a run cannot use. It exits {@link CliExitLadder.unauthorized}
|
|
26
|
+
* with {@link CLI_UNAUTHORIZED_CODE} and never hangs. Either an authorization
|
|
27
|
+
* did not end approved (#2772, record `refs/design/cli-improvements`,
|
|
28
|
+
* `init?case=headless`), or the admin API refused the credentials an
|
|
29
|
+
* authorization had just delivered ({@link CliCredentialsRefusal}).
|
|
32
30
|
*/
|
|
33
31
|
export class CliUnauthorizedRefusal extends CliRefusal {
|
|
34
32
|
reason;
|
|
@@ -38,4 +36,21 @@ export class CliUnauthorizedRefusal extends CliRefusal {
|
|
|
38
36
|
this.name = 'CliUnauthorizedRefusal';
|
|
39
37
|
}
|
|
40
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Credentials the admin API refused, with the code it refused them with. The
|
|
41
|
+
* credential step answers this refusal by authorizing this machine once
|
|
42
|
+
* (launch#62 N3). If the refusal reaches the run, the run exits 3 and never 1.
|
|
43
|
+
*/
|
|
44
|
+
export class CliCredentialsRefusal extends CliUnauthorizedRefusal {
|
|
45
|
+
code;
|
|
46
|
+
constructor(code) {
|
|
47
|
+
super(CliUnauthorizedReason.REFUSED);
|
|
48
|
+
this.code = code;
|
|
49
|
+
this.name = 'CliCredentialsRefusal';
|
|
50
|
+
}
|
|
51
|
+
/** Whether the admin API refuses credentials with `code`. Every other code is a refusal of the operation. */
|
|
52
|
+
static isRefusalCode(code) {
|
|
53
|
+
return Object.values(CliCredentialRefusalCode).includes(code);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
41
56
|
//# sourceMappingURL=cli-unauthorized-refusal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-unauthorized-refusal.js","sourceRoot":"","sources":["../../../src/authorization/cli-unauthorized-refusal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE9D,qFAAqF;AACrF,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAElE,iDAAiD;AACjD,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"cli-unauthorized-refusal.js","sourceRoot":"","sources":["../../../src/authorization/cli-unauthorized-refusal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAE7E,qFAAqF;AACrF,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAElE,iDAAiD;AACjD,MAAM,CAAN,IAAY,qBASX;AATD,WAAY,qBAAqB;IAC/B,8DAA8D;IAC9D,0CAAiB,CAAA;IACjB,kFAAkF;IAClF,4CAAmB,CAAA;IACnB,8CAA8C;IAC9C,gDAAuB,CAAA;IACvB,yGAAyG;IACzG,4CAAmB,CAAA;AACrB,CAAC,EATW,qBAAqB,KAArB,qBAAqB,QAShC;AAED,iGAAiG;AACjG,MAAM,YAAY,GAAoD;IACpE,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAC5B,kEAAkE;IACpE,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAC7B,yIAAyI;IAC3I,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAC/B,kMAAkM;IACpM,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAC7B,gJAAgJ;CACnJ,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,OAAO,sBAAuB,SAAQ,UAAU;IAC/B;IAArB,YAAqB,MAA6B;QAChD,KAAK,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC,GAAG,qBAAqB,MAAM,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QADvE,WAAM,GAAN,MAAM,CAAuB;QAEhD,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,qBAAsB,SAAQ,sBAAsB;IAC1C;IAArB,YAAqB,IAA8B;QACjD,KAAK,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;QADlB,SAAI,GAAJ,IAAI,CAA0B;QAEjD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;IAED,6GAA6G;IAC7G,MAAM,CAAC,aAAa,CAAC,IAAY;QAC/B,OAAO,MAAM,CAAC,MAAM,CAAS,wBAAwB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxE,CAAC;CACF"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The four credentials a storefront runs on (#2772),
|
|
3
|
-
*
|
|
4
|
-
* writes them.
|
|
2
|
+
* The four credentials a storefront runs on (#2772), each under the `.env` key
|
|
3
|
+
* the credential step writes it to, in the order the check names them.
|
|
5
4
|
*/
|
|
6
5
|
export declare enum CliCredentialKey {
|
|
7
6
|
CHANNEL_TOKEN = "FORGECART_CHANNEL_TOKEN",
|
|
@@ -30,10 +29,43 @@ export interface CliCredentials {
|
|
|
30
29
|
shopApiUrl: string;
|
|
31
30
|
adminApiUrl: string;
|
|
32
31
|
}
|
|
33
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* The codes the admin API refuses an admin operation's credentials with, each
|
|
34
|
+
* of which runs the credential step (launch#62 N3): no grant for the request
|
|
35
|
+
* (UNAUTHORIZED, FORBIDDEN), an admin secret the channel no longer carries
|
|
36
|
+
* (INVALID_ADMIN_SECRET), and a channel token no store carries
|
|
37
|
+
* (CHANNEL_NOT_FOUND).
|
|
38
|
+
*/
|
|
39
|
+
export declare enum CliCredentialRefusalCode {
|
|
40
|
+
UNAUTHORIZED = "UNAUTHORIZED",
|
|
41
|
+
FORBIDDEN = "FORBIDDEN",
|
|
42
|
+
INVALID_ADMIN_SECRET = "INVALID_ADMIN_SECRET",
|
|
43
|
+
CHANNEL_NOT_FOUND = "CHANNEL_NOT_FOUND"
|
|
44
|
+
}
|
|
45
|
+
/** What the CLI names when it opens an authorization: the machine, itself, and the project's store. */
|
|
34
46
|
export interface CliAuthorizationRequestInput {
|
|
35
47
|
deviceName: string;
|
|
36
48
|
cliVersion: string;
|
|
49
|
+
/** The channel token the project's sources name: the store `/authorize` preselects. Absent when they name none. */
|
|
50
|
+
channelToken?: string;
|
|
51
|
+
}
|
|
52
|
+
/** Where the credential step reads the four keys, where an approval writes them, and how long it waits for one. */
|
|
53
|
+
export interface CliCredentialStepInput {
|
|
54
|
+
/** The storefront. The step reads its `.env` and `.forgecart/config.json`, and an approval's keys land in its `.env`. */
|
|
55
|
+
targetDir: string;
|
|
56
|
+
/**
|
|
57
|
+
* The shop API whose origin's admin API answers the authorization when no
|
|
58
|
+
* source names FORGECART_ADMIN_API_URL: `init`'s `--api-url`. When absent,
|
|
59
|
+
* the step uses the shop API the sources name, else the platform's.
|
|
60
|
+
*/
|
|
61
|
+
shopApiUrl?: string;
|
|
62
|
+
/** The longest the wait for an approval may last, in seconds. When absent, the authorization's window bounds it. */
|
|
63
|
+
timeoutSec?: number;
|
|
64
|
+
}
|
|
65
|
+
/** The four credentials the step settled, and whether an approval in this run delivered them. */
|
|
66
|
+
export interface CliSettledCredentials {
|
|
67
|
+
credentials: CliCredentials;
|
|
68
|
+
authorized: boolean;
|
|
37
69
|
}
|
|
38
70
|
/** The authorization the admin API opened, in the request result's wire shape. */
|
|
39
71
|
export interface CliAuthorizationRequestResult {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The four credentials a storefront runs on (#2772),
|
|
3
|
-
*
|
|
4
|
-
* writes them.
|
|
2
|
+
* The four credentials a storefront runs on (#2772), each under the `.env` key
|
|
3
|
+
* the credential step writes it to, in the order the check names them.
|
|
5
4
|
*/
|
|
6
5
|
export var CliCredentialKey;
|
|
7
6
|
(function (CliCredentialKey) {
|
|
@@ -21,4 +20,18 @@ export var CliAuthorizationState;
|
|
|
21
20
|
CliAuthorizationState["DENIED"] = "DENIED";
|
|
22
21
|
CliAuthorizationState["EXPIRED"] = "EXPIRED";
|
|
23
22
|
})(CliAuthorizationState || (CliAuthorizationState = {}));
|
|
23
|
+
/**
|
|
24
|
+
* The codes the admin API refuses an admin operation's credentials with, each
|
|
25
|
+
* of which runs the credential step (launch#62 N3): no grant for the request
|
|
26
|
+
* (UNAUTHORIZED, FORBIDDEN), an admin secret the channel no longer carries
|
|
27
|
+
* (INVALID_ADMIN_SECRET), and a channel token no store carries
|
|
28
|
+
* (CHANNEL_NOT_FOUND).
|
|
29
|
+
*/
|
|
30
|
+
export var CliCredentialRefusalCode;
|
|
31
|
+
(function (CliCredentialRefusalCode) {
|
|
32
|
+
CliCredentialRefusalCode["UNAUTHORIZED"] = "UNAUTHORIZED";
|
|
33
|
+
CliCredentialRefusalCode["FORBIDDEN"] = "FORBIDDEN";
|
|
34
|
+
CliCredentialRefusalCode["INVALID_ADMIN_SECRET"] = "INVALID_ADMIN_SECRET";
|
|
35
|
+
CliCredentialRefusalCode["CHANNEL_NOT_FOUND"] = "CHANNEL_NOT_FOUND";
|
|
36
|
+
})(CliCredentialRefusalCode || (CliCredentialRefusalCode = {}));
|
|
24
37
|
//# sourceMappingURL=cli-authorization.types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-authorization.types.js","sourceRoot":"","sources":["../../../../src/authorization/type/cli-authorization.types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cli-authorization.types.js","sourceRoot":"","sources":["../../../../src/authorization/type/cli-authorization.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,gBAKX;AALD,WAAY,gBAAgB;IAC1B,6DAAyC,CAAA;IACzC,2DAAuC,CAAA;IACvC,2DAAuC,CAAA;IACvC,6DAAyC,CAAA;AAC3C,CAAC,EALW,gBAAgB,KAAhB,gBAAgB,QAK3B;AAED;;;GAGG;AACH,MAAM,CAAN,IAAY,qBAKX;AALD,WAAY,qBAAqB;IAC/B,4CAAmB,CAAA;IACnB,8CAAqB,CAAA;IACrB,0CAAiB,CAAA;IACjB,4CAAmB,CAAA;AACrB,CAAC,EALW,qBAAqB,KAArB,qBAAqB,QAKhC;AAcD;;;;;;GAMG;AACH,MAAM,CAAN,IAAY,wBAKX;AALD,WAAY,wBAAwB;IAClC,yDAA6B,CAAA;IAC7B,mDAAuB,CAAA;IACvB,yEAA6C,CAAA;IAC7C,mEAAuC,CAAA;AACzC,CAAC,EALW,wBAAwB,KAAxB,wBAAwB,QAKnC"}
|
|
@@ -2,16 +2,6 @@ import { Command } from 'commander';
|
|
|
2
2
|
import type { QuestionPromptInput } from '../question/type/question-prompt.input.js';
|
|
3
3
|
import { TemplateSet } from '../template/template-set.js';
|
|
4
4
|
import type { InitQuestionsInput } from './type/init.input.js';
|
|
5
|
-
/**
|
|
6
|
-
* Default shop API base, INCLUDING the mounted path. The API serves the shop
|
|
7
|
-
* GraphQL endpoint at `/shop-api` (`app/forgecart/src/main.ts`), and the SDK
|
|
8
|
-
* takes this value verbatim as its endpoint — it swaps the scheme for the
|
|
9
|
-
* websocket and appends nothing to the path — so a pathless origin scaffolds a
|
|
10
|
-
* storefront whose every read dials a socket nothing answers (#2102): the
|
|
11
|
-
* operation rides graphql-ws's whole retry ladder and the page hangs with
|
|
12
|
-
* nothing logged. Overridable via `--api-url`.
|
|
13
|
-
*/
|
|
14
|
-
export declare const DEFAULT_SHOP_API_URL = "https://api.forgecart.com/shop-api";
|
|
15
5
|
/**
|
|
16
6
|
* Environment variable naming a dependency-warmed storefront template — a copy
|
|
17
7
|
* of one bundled template with `node_modules` (and the generated
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { mkdir, cp, readFile, rm, writeFile, stat } from 'node:fs/promises';
|
|
2
2
|
import { join, resolve } from 'node:path';
|
|
3
3
|
import { Command, InvalidArgumentError, Option } from 'commander';
|
|
4
|
-
import {
|
|
5
|
-
import { CliAuthorizationClient } from '../authorization/cli-authorization.client.js';
|
|
6
|
-
import { CliCredentialCheck } from '../authorization/cli-credential-check.js';
|
|
7
|
-
import { CliCredentialKey, } from '../authorization/type/cli-authorization.types.js';
|
|
4
|
+
import { CliCredentialStep, DEFAULT_SHOP_API_URL } from '../authorization/cli-credential-step.js';
|
|
8
5
|
import { print } from '../output.js';
|
|
9
6
|
import { QuestionPromptAdapter } from '../question/question-prompt.adapter.js';
|
|
10
7
|
import { TemplateSet } from '../template/template-set.js';
|
|
@@ -14,23 +11,6 @@ import { readPackageVersion } from '../version.js';
|
|
|
14
11
|
import { stampDesignSystem, templateDesignSystem, } from './design-system-seat.js';
|
|
15
12
|
import { InitQuestions } from './init-questions.js';
|
|
16
13
|
import { inventoryTemplate, manifestTemplate, readTemplateManifest, serializeTemplateManifest, templateManifestPath, writeTemplateManifest, } from './template-manifest.js';
|
|
17
|
-
/**
|
|
18
|
-
* Default shop API base, INCLUDING the mounted path. The API serves the shop
|
|
19
|
-
* GraphQL endpoint at `/shop-api` (`app/forgecart/src/main.ts`), and the SDK
|
|
20
|
-
* takes this value verbatim as its endpoint — it swaps the scheme for the
|
|
21
|
-
* websocket and appends nothing to the path — so a pathless origin scaffolds a
|
|
22
|
-
* storefront whose every read dials a socket nothing answers (#2102): the
|
|
23
|
-
* operation rides graphql-ws's whole retry ladder and the page hangs with
|
|
24
|
-
* nothing logged. Overridable via `--api-url`.
|
|
25
|
-
*/
|
|
26
|
-
export const DEFAULT_SHOP_API_URL = 'https://api.forgecart.com/shop-api';
|
|
27
|
-
/**
|
|
28
|
-
* The admin API's path beside the shop API's on every platform origin — the
|
|
29
|
-
* server's `ADMIN_API_PATH`. With no FORGECART_ADMIN_API_URL to name the admin
|
|
30
|
-
* API outright, the authorization is requested here on the `--api-url` origin
|
|
31
|
-
* (#2772, ruling R2).
|
|
32
|
-
*/
|
|
33
|
-
const ADMIN_API_PATH = '/admin-api';
|
|
34
14
|
/**
|
|
35
15
|
* Environment variable naming a dependency-warmed storefront template — a copy
|
|
36
16
|
* of one bundled template with `node_modules` (and the generated
|
|
@@ -431,24 +411,27 @@ function printConfigOnly(targetDir, blank) {
|
|
|
431
411
|
/**
|
|
432
412
|
* Resolve the channel a run wires (#2772). `--token` is the pod's drive: its
|
|
433
413
|
* flags are the whole configuration and nothing is checked. Otherwise the four
|
|
434
|
-
* credentials
|
|
435
|
-
*
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
414
|
+
* credentials come through the credential step (launch#62 N3), which looks for
|
|
415
|
+
* them in the environment, `.env` and `.forgecart/config.json`. With all four
|
|
416
|
+
* found, init asks nothing. With any absent, the browser authorization runs
|
|
417
|
+
* against the admin API of the `--api-url` origin, unless a source names
|
|
418
|
+
* FORGECART_ADMIN_API_URL. The four keys the approval delivers land in `.env`
|
|
419
|
+
* the moment the poll delivers them. A run that later ends at a question
|
|
420
|
+
* keeps them, and its re-run asks for no authorization. An authorization that
|
|
421
|
+
* ends unapproved writes nothing.
|
|
439
422
|
*/
|
|
440
423
|
async function resolveChannelWiring(targetDir, options) {
|
|
441
424
|
const token = options.token?.trim();
|
|
442
425
|
if (token)
|
|
443
426
|
return { channelToken: token, options, authorized: false };
|
|
444
427
|
assertNoPodDriveFlags(options);
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const
|
|
451
|
-
return wiredWith(options,
|
|
428
|
+
const step = new CliCredentialStep({
|
|
429
|
+
targetDir,
|
|
430
|
+
shopApiUrl: options.apiUrl,
|
|
431
|
+
timeoutSec: options.timeout,
|
|
432
|
+
});
|
|
433
|
+
const { credentials, authorized } = await step.settle();
|
|
434
|
+
return wiredWith(options, credentials, authorized);
|
|
452
435
|
}
|
|
453
436
|
/** The run's wiring once the four credentials are known: they take the seats of the flags they name. */
|
|
454
437
|
function wiredWith(options, credentials, authorized) {
|
|
@@ -469,13 +452,6 @@ function assertNoPodDriveFlags(options) {
|
|
|
469
452
|
return;
|
|
470
453
|
throw new Error('--admin-secret and --admin-api-url belong to the pod drive beside --token. Export FORGECART_ADMIN_SECRET and FORGECART_ADMIN_API_URL instead, or let init authorize this machine in the browser.');
|
|
471
454
|
}
|
|
472
|
-
/** The admin API on the `--api-url` origin — the platform's fixed path pair (ruling R2). */
|
|
473
|
-
function adminApiOf(apiUrl) {
|
|
474
|
-
if (!URL.canParse(apiUrl)) {
|
|
475
|
-
throw new Error(`--api-url ${apiUrl} is not a URL, so the admin API to authorize against cannot be found.`);
|
|
476
|
-
}
|
|
477
|
-
return new URL(ADMIN_API_PATH, apiUrl).toString();
|
|
478
|
-
}
|
|
479
455
|
/**
|
|
480
456
|
* What an approval wrote, and where — printed on the run the approval landed in,
|
|
481
457
|
* and only there. A blank workspace (#2775) renders no template, so no template
|
|
@@ -509,8 +485,7 @@ function printEnvCommitNote(blank) {
|
|
|
509
485
|
* tree already has its template identity, and its config keeps the scaffold
|
|
510
486
|
* record it carries and mirrors the design-system seat the workspace records
|
|
511
487
|
* (#2773), settled first ({@link settleInPlaceDesignSystem}, #2808).
|
|
512
|
-
* The channel is resolved
|
|
513
|
-
* ({@link resolveChannelWiring}, #2772).
|
|
488
|
+
* The channel is resolved first ({@link resolveChannelWiring}, #2772).
|
|
514
489
|
*/
|
|
515
490
|
async function configureInPlace(targetDir, options, manifest) {
|
|
516
491
|
if (!(await isScaffolded(targetDir, manifest))) {
|