@ecomweb/cli 0.7.0 → 0.9.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/README.md +56 -32
- package/dist/base-command.d.ts +8 -0
- package/dist/base-command.js +43 -4
- package/dist/base-command.js.map +1 -1
- package/dist/commands/auth/login.d.ts +6 -4
- package/dist/commands/auth/login.js +117 -89
- package/dist/commands/auth/login.js.map +1 -1
- package/dist/commands/auth/logout.js +28 -9
- package/dist/commands/auth/logout.js.map +1 -1
- package/dist/commands/auth/profiles/delete.js +11 -0
- package/dist/commands/auth/profiles/delete.js.map +1 -1
- package/dist/commands/auth/profiles/list.js +2 -2
- package/dist/commands/auth/profiles/list.js.map +1 -1
- package/dist/commands/auth/status.js +17 -9
- package/dist/commands/auth/status.js.map +1 -1
- package/dist/commands/storefront/init.d.ts +2 -1
- package/dist/commands/storefront/init.js +10 -5
- package/dist/commands/storefront/init.js.map +1 -1
- package/dist/commands/{auth/register.d.ts → stores/create.d.ts} +4 -3
- package/dist/commands/stores/create.js +68 -0
- package/dist/commands/stores/create.js.map +1 -0
- package/dist/commands/stores/current.js +1 -1
- package/dist/commands/stores/current.js.map +1 -1
- package/dist/commands/stores/list.js +3 -3
- package/dist/commands/stores/list.js.map +1 -1
- package/dist/commands/stores/switch.js +14 -6
- package/dist/commands/stores/switch.js.map +1 -1
- package/dist/lib/api-client.d.ts +5 -4
- package/dist/lib/api-client.js +32 -16
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/codex-skill.d.ts +1 -1
- package/dist/lib/codex-skill.js +12 -8
- package/dist/lib/codex-skill.js.map +1 -1
- package/dist/lib/config.d.ts +6 -18
- package/dist/lib/config.js +35 -64
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/credential-store.d.ts +44 -0
- package/dist/lib/credential-store.js +137 -0
- package/dist/lib/credential-store.js.map +1 -0
- package/dist/lib/device-login.d.ts +22 -0
- package/dist/lib/device-login.js +66 -0
- package/dist/lib/device-login.js.map +1 -0
- package/dist/lib/errors.d.ts +1 -0
- package/dist/lib/errors.js +6 -1
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/file-lock.d.ts +6 -0
- package/dist/lib/file-lock.js +66 -0
- package/dist/lib/file-lock.js.map +1 -0
- package/dist/lib/open-browser.d.ts +13 -0
- package/dist/lib/open-browser.js +38 -0
- package/dist/lib/open-browser.js.map +1 -0
- package/dist/lib/pending-login.d.ts +5 -0
- package/dist/lib/pending-login.js +39 -0
- package/dist/lib/pending-login.js.map +1 -0
- package/dist/lib/project-setup.d.ts +1 -0
- package/dist/lib/project-setup.js +12 -0
- package/dist/lib/project-setup.js.map +1 -1
- package/dist/lib/secure-file.d.ts +1 -0
- package/dist/lib/secure-file.js +15 -0
- package/dist/lib/secure-file.js.map +1 -0
- package/dist/lib/session.d.ts +40 -0
- package/dist/lib/session.js +80 -0
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/store-selection.d.ts +19 -0
- package/dist/lib/store-selection.js +23 -0
- package/dist/lib/store-selection.js.map +1 -0
- package/oclif.manifest.json +1482 -1833
- package/package.json +2 -1
- package/dist/commands/auth/register.js +0 -35
- package/dist/commands/auth/register.js.map +0 -1
- package/dist/commands/auth/verify.d.ts +0 -20
- package/dist/commands/auth/verify.js +0 -43
- package/dist/commands/auth/verify.js.map +0 -1
- package/dist/commands/init.d.ts +0 -22
- package/dist/commands/init.js +0 -84
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/setup.d.ts +0 -19
- package/dist/commands/setup.js +0 -186
- package/dist/commands/setup.js.map +0 -1
- package/dist/lib/email-login.d.ts +0 -35
- package/dist/lib/email-login.js +0 -86
- package/dist/lib/email-login.js.map +0 -1
package/dist/lib/codex-skill.js
CHANGED
|
@@ -30,12 +30,16 @@ project. Follow its \`AGENTS.md\`, which points to the project's own skill.
|
|
|
30
30
|
1. Check the prerequisites: \`node --version\` (24 or newer), \`pnpm --version\`,
|
|
31
31
|
\`git --version\`. If one is missing, stop and give the install links:
|
|
32
32
|
https://nodejs.org, https://pnpm.io/installation, https://git-scm.com/downloads.
|
|
33
|
-
2. Check the login: \`npx @ecomweb/cli auth status\`. If
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
2. Check the login: \`npx @ecomweb/cli auth status\`. If \`logged_in\` is false,
|
|
34
|
+
run \`npx @ecomweb/cli auth login\`. Show the user the
|
|
35
|
+
\`verification_uri_complete\` link and the \`user_code\`, and ask them to open
|
|
36
|
+
the link and approve (the code on the page must match). Then run
|
|
37
|
+
\`npx @ecomweb/cli auth login --wait\`; run it again while it still answers
|
|
38
|
+
\`authorization_pending\`.
|
|
39
|
+
3. The login picks the store when there is one; if it lists several, ask which
|
|
40
|
+
and run \`npx @ecomweb/cli stores switch <ref>\`. With none, ask for a name and
|
|
41
|
+
run \`npx @ecomweb/cli stores create --name "<name>"\`.
|
|
42
|
+
\`npx @ecomweb/cli stores current\` shows the store.
|
|
39
43
|
4. Ask whether to create the project on this machine or as a new GitHub
|
|
40
44
|
repository (add \`--github\`).
|
|
41
45
|
5. Create it: \`npx @ecomweb/cli storefront init\`. It
|
|
@@ -43,8 +47,8 @@ project. Follow its \`AGENTS.md\`, which points to the project's own skill.
|
|
|
43
47
|
6. Tell the user to start \`codex\` inside the new folder and describe the
|
|
44
48
|
storefront they want; \`pnpm dev\` shows it at http://localhost:3002.
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
Never ask for codes, keys or tokens, and never write them into files: the
|
|
51
|
+
user approves the login in their own browser.
|
|
48
52
|
`;
|
|
49
53
|
function codexSkillPath(home) {
|
|
50
54
|
return node_path_1.default.join(home, ".agents/skills/ecomweb/SKILL.md");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-skill.js","sourceRoot":"","sources":["../../src/lib/codex-skill.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"codex-skill.js","sourceRoot":"","sources":["../../src/lib/codex-skill.ts"],"names":[],"mappings":";;;;;;AAmDA,wCAEC;AAED,8CAkBC;AAzED,qCAA6E;AAC7E,0DAA6B;AAC7B,qCAA8C;AAOjC,QAAA,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwC1B,CAAC;AAEF,SAAgB,cAAc,CAAC,IAAY;IACzC,OAAO,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,iCAAiC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAgB,iBAAiB,CAC/B,IAAY,EACZ,OAA8C,EAAE;IAEhD,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,IAAA,oBAAU,EAAC,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,OAAO,KAAK,mBAAW;YAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QACxE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,iBAAQ,CAAC,cAAc,EAAE,uCAAuC,IAAI,EAAE,EAAE,iBAAQ,CAAC,UAAU,EAAE;gBACrG,IAAI,EAAE,6BAA6B;aACpC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAChE,IAAA,mBAAS,EAAC,mBAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,IAAA,uBAAa,EAAC,IAAI,EAAE,mBAAW,CAAC,CAAC;IACjC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC7C,CAAC"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -8,39 +8,27 @@ export interface AppConfig {
|
|
|
8
8
|
active_profile: string;
|
|
9
9
|
profiles: Record<string, ProfileConfig>;
|
|
10
10
|
}
|
|
11
|
+
export declare const CREDENTIALS_DIR: string;
|
|
12
|
+
export declare function assertValidProfileName(name: string, source?: "flag" | "config"): void;
|
|
11
13
|
export declare class ConfigManager {
|
|
12
14
|
private config;
|
|
13
|
-
|
|
15
|
+
private readonly selected;
|
|
16
|
+
constructor(selectedProfile?: string);
|
|
14
17
|
private ensureDir;
|
|
15
18
|
private loadConfig;
|
|
16
19
|
save(): void;
|
|
17
20
|
getActiveProfileName(): string;
|
|
21
|
+
getProfileName(): string;
|
|
18
22
|
getProfile(name?: string): ProfileConfig;
|
|
19
23
|
setProfile(name: string, profile: Partial<ProfileConfig>): void;
|
|
20
24
|
setActiveProfile(name: string): void;
|
|
21
25
|
setStoreRef(storeRef: string, storeName?: string, profileName?: string): void;
|
|
22
26
|
getStoreRef(): string | undefined;
|
|
23
|
-
getApiKey(profileName?: string): string | undefined;
|
|
24
|
-
setApiKey(key: string, profileName?: string): void;
|
|
25
|
-
removeApiKey(profileName?: string): void;
|
|
26
|
-
getJwtTokens(profileName?: string): {
|
|
27
|
-
access_token: string;
|
|
28
|
-
refresh_token: string;
|
|
29
|
-
expires_at: number;
|
|
30
|
-
email?: string;
|
|
31
|
-
} | undefined;
|
|
32
|
-
setJwtTokens(tokens: {
|
|
33
|
-
access_token: string;
|
|
34
|
-
refresh_token: string;
|
|
35
|
-
expires_at: number;
|
|
36
|
-
email?: string;
|
|
37
|
-
}, profileName?: string): void;
|
|
38
|
-
removeJwtTokens(profileName?: string): void;
|
|
39
|
-
isJwtExpired(profileName?: string): boolean;
|
|
40
27
|
getProfileNames(): string[];
|
|
41
28
|
deleteProfile(name: string): void;
|
|
42
29
|
resolve<T>(flag: T | undefined, envVar: string, profileValue: T | undefined, defaultValue: T): T;
|
|
43
30
|
resolveApiUrl(flag?: string): string;
|
|
44
31
|
resolveApiKey(flag?: string): string | undefined;
|
|
32
|
+
removeLegacyCredentials(profileName: string): void;
|
|
45
33
|
resolveStoreRef(flag?: string): string | undefined;
|
|
46
34
|
}
|
package/dist/lib/config.js
CHANGED
|
@@ -33,13 +33,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.ConfigManager = void 0;
|
|
36
|
+
exports.ConfigManager = exports.CREDENTIALS_DIR = void 0;
|
|
37
|
+
exports.assertValidProfileName = assertValidProfileName;
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
38
39
|
const path = __importStar(require("path"));
|
|
39
40
|
const os = __importStar(require("os"));
|
|
41
|
+
const errors_1 = require("./errors");
|
|
40
42
|
const CONFIG_DIR = path.join(os.homedir(), ".config", "ecomweb");
|
|
41
43
|
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
42
|
-
|
|
44
|
+
exports.CREDENTIALS_DIR = path.join(CONFIG_DIR, "credentials");
|
|
43
45
|
const DEFAULT_PROFILE = {
|
|
44
46
|
api_url: "https://apibase.ecomweb.app/api/v1",
|
|
45
47
|
default_output: "json",
|
|
@@ -50,9 +52,24 @@ const DEFAULT_CONFIG = {
|
|
|
50
52
|
default: { ...DEFAULT_PROFILE },
|
|
51
53
|
},
|
|
52
54
|
};
|
|
55
|
+
function assertValidProfileName(name, source) {
|
|
56
|
+
if (!/^[A-Za-z0-9._-]+$/.test(name) || name === "." || name.includes("..")) {
|
|
57
|
+
const allowed = "Use only letters, digits, dot, underscore and hyphen (no \"..\").";
|
|
58
|
+
const from = source === "flag"
|
|
59
|
+
? " (from --profile)"
|
|
60
|
+
: source === "config"
|
|
61
|
+
? ` (from active_profile in ${CONFIG_FILE})`
|
|
62
|
+
: "";
|
|
63
|
+
throw new errors_1.CliError("INVALID_PROFILE_NAME", `Invalid profile name: ${JSON.stringify(name)}${from}`, errors_1.ExitCode.VALIDATION, {
|
|
64
|
+
hint: source === "config" ? `${allowed} Fix active_profile in ${CONFIG_FILE}, or pass --profile default.` : allowed,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
53
68
|
class ConfigManager {
|
|
54
|
-
constructor() {
|
|
69
|
+
constructor(selectedProfile) {
|
|
55
70
|
this.config = this.loadConfig();
|
|
71
|
+
this.selected = selectedProfile || this.config.active_profile;
|
|
72
|
+
assertValidProfileName(this.selected, selectedProfile ? "flag" : "config");
|
|
56
73
|
}
|
|
57
74
|
ensureDir(dir) {
|
|
58
75
|
if (!fs.existsSync(dir)) {
|
|
@@ -68,7 +85,7 @@ class ConfigManager {
|
|
|
68
85
|
}
|
|
69
86
|
catch {
|
|
70
87
|
}
|
|
71
|
-
return
|
|
88
|
+
return structuredClone(DEFAULT_CONFIG);
|
|
72
89
|
}
|
|
73
90
|
save() {
|
|
74
91
|
this.ensureDir(CONFIG_DIR);
|
|
@@ -77,11 +94,15 @@ class ConfigManager {
|
|
|
77
94
|
getActiveProfileName() {
|
|
78
95
|
return this.config.active_profile;
|
|
79
96
|
}
|
|
97
|
+
getProfileName() {
|
|
98
|
+
return this.selected;
|
|
99
|
+
}
|
|
80
100
|
getProfile(name) {
|
|
81
|
-
const profileName = name || this.
|
|
101
|
+
const profileName = name || this.selected;
|
|
82
102
|
return this.config.profiles[profileName] || { ...DEFAULT_PROFILE };
|
|
83
103
|
}
|
|
84
104
|
setProfile(name, profile) {
|
|
105
|
+
assertValidProfileName(name);
|
|
85
106
|
this.config.profiles[name] = {
|
|
86
107
|
...DEFAULT_PROFILE,
|
|
87
108
|
...this.config.profiles[name],
|
|
@@ -90,11 +111,12 @@ class ConfigManager {
|
|
|
90
111
|
this.save();
|
|
91
112
|
}
|
|
92
113
|
setActiveProfile(name) {
|
|
114
|
+
assertValidProfileName(name);
|
|
93
115
|
this.config.active_profile = name;
|
|
94
116
|
this.save();
|
|
95
117
|
}
|
|
96
118
|
setStoreRef(storeRef, storeName, profileName) {
|
|
97
|
-
const name = profileName || this.
|
|
119
|
+
const name = profileName || this.selected;
|
|
98
120
|
const profile = this.getProfile(name);
|
|
99
121
|
profile.store_ref = storeRef;
|
|
100
122
|
if (storeName)
|
|
@@ -105,62 +127,6 @@ class ConfigManager {
|
|
|
105
127
|
getStoreRef() {
|
|
106
128
|
return this.getProfile().store_ref;
|
|
107
129
|
}
|
|
108
|
-
getApiKey(profileName) {
|
|
109
|
-
const name = profileName || this.config.active_profile;
|
|
110
|
-
const keyFile = path.join(CREDENTIALS_DIR, `${name}.key`);
|
|
111
|
-
try {
|
|
112
|
-
if (fs.existsSync(keyFile)) {
|
|
113
|
-
return fs.readFileSync(keyFile, "utf-8").trim();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
}
|
|
118
|
-
return undefined;
|
|
119
|
-
}
|
|
120
|
-
setApiKey(key, profileName) {
|
|
121
|
-
const name = profileName || this.config.active_profile;
|
|
122
|
-
this.ensureDir(CREDENTIALS_DIR);
|
|
123
|
-
const keyFile = path.join(CREDENTIALS_DIR, `${name}.key`);
|
|
124
|
-
fs.writeFileSync(keyFile, key, { mode: 0o600 });
|
|
125
|
-
}
|
|
126
|
-
removeApiKey(profileName) {
|
|
127
|
-
const name = profileName || this.config.active_profile;
|
|
128
|
-
const keyFile = path.join(CREDENTIALS_DIR, `${name}.key`);
|
|
129
|
-
if (fs.existsSync(keyFile)) {
|
|
130
|
-
fs.unlinkSync(keyFile);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
getJwtTokens(profileName) {
|
|
134
|
-
const name = profileName || this.config.active_profile;
|
|
135
|
-
const tokenFile = path.join(CREDENTIALS_DIR, `${name}.jwt`);
|
|
136
|
-
try {
|
|
137
|
-
if (fs.existsSync(tokenFile)) {
|
|
138
|
-
return JSON.parse(fs.readFileSync(tokenFile, "utf-8"));
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
}
|
|
143
|
-
return undefined;
|
|
144
|
-
}
|
|
145
|
-
setJwtTokens(tokens, profileName) {
|
|
146
|
-
const name = profileName || this.config.active_profile;
|
|
147
|
-
this.ensureDir(CREDENTIALS_DIR);
|
|
148
|
-
const tokenFile = path.join(CREDENTIALS_DIR, `${name}.jwt`);
|
|
149
|
-
fs.writeFileSync(tokenFile, JSON.stringify(tokens), { mode: 0o600 });
|
|
150
|
-
}
|
|
151
|
-
removeJwtTokens(profileName) {
|
|
152
|
-
const name = profileName || this.config.active_profile;
|
|
153
|
-
const tokenFile = path.join(CREDENTIALS_DIR, `${name}.jwt`);
|
|
154
|
-
if (fs.existsSync(tokenFile)) {
|
|
155
|
-
fs.unlinkSync(tokenFile);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
isJwtExpired(profileName) {
|
|
159
|
-
const tokens = this.getJwtTokens(profileName);
|
|
160
|
-
if (!tokens)
|
|
161
|
-
return true;
|
|
162
|
-
return Date.now() / 1000 >= tokens.expires_at - 60;
|
|
163
|
-
}
|
|
164
130
|
getProfileNames() {
|
|
165
131
|
return Object.keys(this.config.profiles);
|
|
166
132
|
}
|
|
@@ -170,7 +136,7 @@ class ConfigManager {
|
|
|
170
136
|
this.config.active_profile = "default";
|
|
171
137
|
}
|
|
172
138
|
this.save();
|
|
173
|
-
this.
|
|
139
|
+
this.removeLegacyCredentials(name);
|
|
174
140
|
}
|
|
175
141
|
resolve(flag, envVar, profileValue, defaultValue) {
|
|
176
142
|
if (flag !== undefined)
|
|
@@ -186,7 +152,12 @@ class ConfigManager {
|
|
|
186
152
|
return this.resolve(flag, "ECOMWEB_API_URL", this.getProfile().api_url, "https://apibase.ecomweb.app/api/v1");
|
|
187
153
|
}
|
|
188
154
|
resolveApiKey(flag) {
|
|
189
|
-
return this.resolve(flag, "ECOMWEB_API_KEY",
|
|
155
|
+
return this.resolve(flag, "ECOMWEB_API_KEY", undefined, undefined);
|
|
156
|
+
}
|
|
157
|
+
removeLegacyCredentials(profileName) {
|
|
158
|
+
for (const ext of ["key", "jwt"]) {
|
|
159
|
+
fs.rmSync(path.join(exports.CREDENTIALS_DIR, `${profileName}.${ext}`), { force: true });
|
|
160
|
+
}
|
|
190
161
|
}
|
|
191
162
|
resolveStoreRef(flag) {
|
|
192
163
|
const envVal = process.env["ECOMWEB_STORE_REF"];
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface StoredSession {
|
|
2
|
+
access_token: string;
|
|
3
|
+
refresh_token: string;
|
|
4
|
+
expires_at: number;
|
|
5
|
+
email: string | null;
|
|
6
|
+
user_id: string;
|
|
7
|
+
api_url?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CredentialStore {
|
|
10
|
+
readonly kind: "keychain" | "file";
|
|
11
|
+
get(profile: string): StoredSession | undefined;
|
|
12
|
+
set(profile: string, session: StoredSession): void;
|
|
13
|
+
delete(profile: string): void;
|
|
14
|
+
}
|
|
15
|
+
export declare const KEYCHAIN_SERVICE = "ecomweb-cli";
|
|
16
|
+
export interface KeyringEntry {
|
|
17
|
+
getPassword(): string | null;
|
|
18
|
+
setPassword(password: string): void;
|
|
19
|
+
deletePassword(): boolean;
|
|
20
|
+
}
|
|
21
|
+
export type EntryFactory = (service: string, account: string) => KeyringEntry;
|
|
22
|
+
export declare class FileCredentialStore implements CredentialStore {
|
|
23
|
+
private readonly dir;
|
|
24
|
+
readonly kind: "file";
|
|
25
|
+
constructor(dir: string);
|
|
26
|
+
private file;
|
|
27
|
+
get(profile: string): StoredSession | undefined;
|
|
28
|
+
set(profile: string, session: StoredSession): void;
|
|
29
|
+
delete(profile: string): void;
|
|
30
|
+
}
|
|
31
|
+
export declare class KeychainCredentialStore implements CredentialStore {
|
|
32
|
+
private readonly entry;
|
|
33
|
+
readonly kind: "keychain";
|
|
34
|
+
constructor(entry: EntryFactory);
|
|
35
|
+
get(profile: string): StoredSession | undefined;
|
|
36
|
+
set(profile: string, session: StoredSession): void;
|
|
37
|
+
delete(profile: string): void;
|
|
38
|
+
}
|
|
39
|
+
export declare function openCredentialStore(opts: {
|
|
40
|
+
dir: string;
|
|
41
|
+
env?: NodeJS.ProcessEnv;
|
|
42
|
+
loadEntry?: () => EntryFactory;
|
|
43
|
+
}): CredentialStore;
|
|
44
|
+
export declare function lazyCredentialStore(open: () => CredentialStore): CredentialStore;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.KeychainCredentialStore = exports.FileCredentialStore = exports.KEYCHAIN_SERVICE = void 0;
|
|
7
|
+
exports.openCredentialStore = openCredentialStore;
|
|
8
|
+
exports.lazyCredentialStore = lazyCredentialStore;
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const errors_1 = require("./errors");
|
|
12
|
+
const secure_file_1 = require("./secure-file");
|
|
13
|
+
exports.KEYCHAIN_SERVICE = "ecomweb-cli";
|
|
14
|
+
function parseSession(raw) {
|
|
15
|
+
try {
|
|
16
|
+
const s = JSON.parse(raw);
|
|
17
|
+
if (typeof s?.access_token === "string" &&
|
|
18
|
+
typeof s.refresh_token === "string" &&
|
|
19
|
+
typeof s.expires_at === "number" &&
|
|
20
|
+
typeof s.user_id === "string") {
|
|
21
|
+
return {
|
|
22
|
+
access_token: s.access_token,
|
|
23
|
+
refresh_token: s.refresh_token,
|
|
24
|
+
expires_at: s.expires_at,
|
|
25
|
+
email: s.email ?? null,
|
|
26
|
+
user_id: s.user_id,
|
|
27
|
+
...(typeof s.api_url === "string" && { api_url: s.api_url }),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
class FileCredentialStore {
|
|
36
|
+
constructor(dir) {
|
|
37
|
+
this.dir = dir;
|
|
38
|
+
this.kind = "file";
|
|
39
|
+
}
|
|
40
|
+
file(profile) {
|
|
41
|
+
return node_path_1.default.join(this.dir, `${profile}.session.json`);
|
|
42
|
+
}
|
|
43
|
+
get(profile) {
|
|
44
|
+
try {
|
|
45
|
+
return parseSession((0, node_fs_1.readFileSync)(this.file(profile), "utf8"));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
set(profile, session) {
|
|
52
|
+
(0, secure_file_1.writePrivateFile)(this.file(profile), JSON.stringify(session));
|
|
53
|
+
}
|
|
54
|
+
delete(profile) {
|
|
55
|
+
(0, node_fs_1.rmSync)(this.file(profile), { force: true });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.FileCredentialStore = FileCredentialStore;
|
|
59
|
+
function keychainRefused(error) {
|
|
60
|
+
return new errors_1.CliError("CREDENTIAL_STORE_UNAVAILABLE", `The OS keychain refused access: ${error instanceof Error ? error.message : String(error)}`, errors_1.ExitCode.AUTH_FAILURE, { hint: "Unlock the keychain, or keep the login in a file instead: export ECOMWEB_CREDENTIAL_STORE=file" });
|
|
61
|
+
}
|
|
62
|
+
class KeychainCredentialStore {
|
|
63
|
+
constructor(entry) {
|
|
64
|
+
this.entry = entry;
|
|
65
|
+
this.kind = "keychain";
|
|
66
|
+
}
|
|
67
|
+
get(profile) {
|
|
68
|
+
let raw;
|
|
69
|
+
try {
|
|
70
|
+
raw = this.entry(exports.KEYCHAIN_SERVICE, profile).getPassword();
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw keychainRefused(error);
|
|
74
|
+
}
|
|
75
|
+
return raw ? parseSession(raw) : undefined;
|
|
76
|
+
}
|
|
77
|
+
set(profile, session) {
|
|
78
|
+
try {
|
|
79
|
+
this.entry(exports.KEYCHAIN_SERVICE, profile).setPassword(JSON.stringify(session));
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
throw keychainRefused(error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
delete(profile) {
|
|
86
|
+
try {
|
|
87
|
+
this.entry(exports.KEYCHAIN_SERVICE, profile).deletePassword();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.KeychainCredentialStore = KeychainCredentialStore;
|
|
94
|
+
function loadNapiKeyring() {
|
|
95
|
+
const { Entry } = require("@napi-rs/keyring");
|
|
96
|
+
return (service, account) => new Entry(service, account);
|
|
97
|
+
}
|
|
98
|
+
function probeKeychain(load) {
|
|
99
|
+
try {
|
|
100
|
+
const entry = load();
|
|
101
|
+
entry(exports.KEYCHAIN_SERVICE, "__probe__").getPassword();
|
|
102
|
+
return entry;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function openCredentialStore(opts) {
|
|
109
|
+
const forced = (opts.env ?? process.env).ECOMWEB_CREDENTIAL_STORE;
|
|
110
|
+
if (forced !== undefined && forced !== "file" && forced !== "keychain") {
|
|
111
|
+
throw new errors_1.CliError("INVALID_CREDENTIAL_STORE", `ECOMWEB_CREDENTIAL_STORE must be "file" or "keychain", not "${forced}"`, errors_1.ExitCode.VALIDATION);
|
|
112
|
+
}
|
|
113
|
+
if (forced === "file")
|
|
114
|
+
return new FileCredentialStore(opts.dir);
|
|
115
|
+
const entry = probeKeychain(opts.loadEntry ?? loadNapiKeyring);
|
|
116
|
+
if (entry)
|
|
117
|
+
return new KeychainCredentialStore(entry);
|
|
118
|
+
if (forced === "keychain") {
|
|
119
|
+
throw new errors_1.CliError("KEYCHAIN_UNAVAILABLE", "No OS keychain is available on this machine", errors_1.ExitCode.ERROR, {
|
|
120
|
+
hint: "Unset ECOMWEB_CREDENTIAL_STORE to keep the login in a file instead",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return new FileCredentialStore(opts.dir);
|
|
124
|
+
}
|
|
125
|
+
function lazyCredentialStore(open) {
|
|
126
|
+
let inner;
|
|
127
|
+
const store = () => (inner ??= open());
|
|
128
|
+
return {
|
|
129
|
+
get kind() {
|
|
130
|
+
return store().kind;
|
|
131
|
+
},
|
|
132
|
+
get: (profile) => store().get(profile),
|
|
133
|
+
set: (profile, session) => store().set(profile, session),
|
|
134
|
+
delete: (profile) => store().delete(profile),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=credential-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/lib/credential-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CliError } from "./errors";
|
|
2
|
+
import { TokenResponse } from "./session";
|
|
3
|
+
export interface PendingLogin {
|
|
4
|
+
device_code: string;
|
|
5
|
+
user_code: string;
|
|
6
|
+
verification_uri_complete: string;
|
|
7
|
+
interval: number;
|
|
8
|
+
expires_at: number;
|
|
9
|
+
api_url: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DevicePoster {
|
|
12
|
+
post<T = any>(path: string, body?: unknown): Promise<T>;
|
|
13
|
+
}
|
|
14
|
+
export declare function deviceAuthExpired(): CliError;
|
|
15
|
+
export declare function deviceAuthDenied(): CliError;
|
|
16
|
+
export declare function requestDeviceCode(api: DevicePoster, deviceName: string, apiUrl: string, now: number): Promise<PendingLogin>;
|
|
17
|
+
export declare function pollUntil(api: DevicePoster, pending: PendingLogin, opts: {
|
|
18
|
+
deadline: number;
|
|
19
|
+
now: () => number;
|
|
20
|
+
sleep: (ms: number) => Promise<void>;
|
|
21
|
+
onInterval?: (interval: number) => void;
|
|
22
|
+
}): Promise<TokenResponse | undefined>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deviceAuthExpired = deviceAuthExpired;
|
|
4
|
+
exports.deviceAuthDenied = deviceAuthDenied;
|
|
5
|
+
exports.requestDeviceCode = requestDeviceCode;
|
|
6
|
+
exports.pollUntil = pollUntil;
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
|
+
function deviceAuthExpired() {
|
|
9
|
+
return new errors_1.CliError("DEVICE_AUTH_EXPIRED", "The sign-in code expired before it was approved", errors_1.ExitCode.AUTH_FAILURE, {
|
|
10
|
+
hint: "Run: ecomweb auth login",
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function deviceAuthDenied() {
|
|
14
|
+
return new errors_1.CliError("DEVICE_AUTH_DENIED", "The sign-in was denied in the browser", errors_1.ExitCode.AUTH_FAILURE, {
|
|
15
|
+
hint: "Run: ecomweb auth login",
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async function requestDeviceCode(api, deviceName, apiUrl, now) {
|
|
19
|
+
const r = await api.post("/auth/device/code", { device_name: deviceName.slice(0, 100) });
|
|
20
|
+
return {
|
|
21
|
+
device_code: r.device_code,
|
|
22
|
+
user_code: r.user_code,
|
|
23
|
+
verification_uri_complete: r.verification_uri_complete,
|
|
24
|
+
interval: r.interval,
|
|
25
|
+
expires_at: now + r.expires_in * 1000,
|
|
26
|
+
api_url: apiUrl,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async function pollOnce(api, deviceCode, interval) {
|
|
30
|
+
try {
|
|
31
|
+
return { status: "approved", tokens: await api.post("/auth/device/token", { device_code: deviceCode }) };
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
switch ((0, errors_1.apiErrorCode)(error)) {
|
|
35
|
+
case "DEVICE_AUTH_PENDING":
|
|
36
|
+
return { status: "pending", interval };
|
|
37
|
+
case "DEVICE_AUTH_SLOW_DOWN":
|
|
38
|
+
return { status: "pending", interval: interval + 5 };
|
|
39
|
+
case "DEVICE_AUTH_DENIED":
|
|
40
|
+
throw deviceAuthDenied();
|
|
41
|
+
case "DEVICE_AUTH_EXPIRED":
|
|
42
|
+
case "DEVICE_AUTH_INVALID_CODE":
|
|
43
|
+
throw deviceAuthExpired();
|
|
44
|
+
default:
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function pollUntil(api, pending, opts) {
|
|
50
|
+
let interval = pending.interval;
|
|
51
|
+
for (;;) {
|
|
52
|
+
if (opts.now() >= pending.expires_at)
|
|
53
|
+
throw deviceAuthExpired();
|
|
54
|
+
const outcome = await pollOnce(api, pending.device_code, interval);
|
|
55
|
+
if (outcome.status === "approved")
|
|
56
|
+
return outcome.tokens;
|
|
57
|
+
if (outcome.interval !== interval) {
|
|
58
|
+
interval = outcome.interval;
|
|
59
|
+
opts.onInterval?.(interval);
|
|
60
|
+
}
|
|
61
|
+
if (opts.now() + interval * 1000 > opts.deadline)
|
|
62
|
+
return undefined;
|
|
63
|
+
await opts.sleep(interval * 1000);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=device-login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-login.js","sourceRoot":"","sources":["../../src/lib/device-login.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/errors.d.ts
CHANGED
package/dist/lib/errors.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CliError = exports.ExitCode = void 0;
|
|
4
4
|
exports.formatError = formatError;
|
|
5
|
+
exports.apiErrorCode = apiErrorCode;
|
|
5
6
|
var ExitCode;
|
|
6
7
|
(function (ExitCode) {
|
|
7
8
|
ExitCode[ExitCode["SUCCESS"] = 0] = "SUCCESS";
|
|
@@ -67,7 +68,7 @@ function mapHttpError(err) {
|
|
|
67
68
|
error: {
|
|
68
69
|
code: "FORBIDDEN",
|
|
69
70
|
message: serverMessage || "Insufficient permissions.",
|
|
70
|
-
hint: "
|
|
71
|
+
hint: "Your role in this store (or your API key's scopes) does not allow this.",
|
|
71
72
|
},
|
|
72
73
|
},
|
|
73
74
|
exitCode: ExitCode.AUTH_FAILURE,
|
|
@@ -115,4 +116,8 @@ function mapHttpError(err) {
|
|
|
115
116
|
};
|
|
116
117
|
}
|
|
117
118
|
}
|
|
119
|
+
function apiErrorCode(error) {
|
|
120
|
+
const code = error?.response?.data?.code;
|
|
121
|
+
return typeof code === "string" ? code : undefined;
|
|
122
|
+
}
|
|
118
123
|
//# sourceMappingURL=errors.js.map
|
package/dist/lib/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":";;;AAwDA,kCAcC;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"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"}
|