Skip to content

Commit 1f717db

Browse files
authored
Auth and Logging Refactoring (#2)
* wip * generated ocapi client * client implementations * logging * proper logging of http * lint * fix format * ignore generated files
1 parent efe0648 commit 1f717db

File tree

28 files changed

+87804
-218
lines changed

28 files changed

+87804
-218
lines changed

data-api.json

Lines changed: 28933 additions & 0 deletions
Large diffs are not rendered by default.

data.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

dw.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/Users/clavery/code/b2c-commerce-industries/dw.json

packages/b2c-cli/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"@oclif/core": "^4",
1212
"@oclif/plugin-help": "^6",
1313
"@oclif/plugin-plugins": "^5",
14-
"@salesforce/b2c-tooling": "workspace:*"
14+
"@salesforce/b2c-tooling": "workspace:*",
15+
"cliui": "^9.0.1"
1516
},
1617
"devDependencies": {
1718
"@eslint/compat": "^1",

packages/b2c-cli/src/commands/code/deploy.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,9 @@ export default class Deploy extends InstanceCommand<typeof Deploy> {
2020
];
2121

2222
async run(): Promise<void> {
23-
this.requireServer();
2423
this.requireCodeVersion();
2524
this.requireWebDavCredentials();
2625

27-
const instance = this.createWebDavInstance();
2826
const path = this.args.cartridgePath;
2927
const hostname = this.resolvedConfig.hostname!;
3028
const version = this.resolvedConfig.codeVersion!;
@@ -34,7 +32,7 @@ export default class Deploy extends InstanceCommand<typeof Deploy> {
3432
this.log(t('commands.code.deploy.codeVersion', 'Code Version: {{version}}', {version}));
3533

3634
try {
37-
await uploadCartridges(instance, path);
35+
await uploadCartridges(this.instance, path);
3836
this.log(t('commands.code.deploy.complete', 'Deployment complete'));
3937
} catch (error) {
4038
if (error instanceof Error) {
Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,82 @@
1+
import {ux} from '@oclif/core';
2+
import cliui from 'cliui';
13
import {InstanceCommand} from '@salesforce/b2c-tooling/cli';
4+
import type {OcapiComponents} from '@salesforce/b2c-tooling';
25
import {t} from '../../i18n/index.js';
36

4-
interface SitesResponse {
5-
_v: string;
6-
count: number;
7-
data: Array<{
8-
id: string;
9-
display_name?: {default?: string};
10-
status?: string;
11-
}>;
12-
total: number;
13-
}
7+
type Sites = OcapiComponents['schemas']['sites'];
8+
type Site = OcapiComponents['schemas']['site'];
149

1510
export default class SitesList extends InstanceCommand<typeof SitesList> {
1611
static description = t('commands.sites.list.description', 'List sites on a B2C Commerce instance');
1712

13+
static enableJsonFlag = true;
14+
1815
static examples = [
1916
'<%= config.bin %> <%= command.id %>',
2017
'<%= config.bin %> <%= command.id %> --server my-sandbox.demandware.net',
18+
'<%= config.bin %> <%= command.id %> --json',
2119
];
2220

23-
async run(): Promise<void> {
24-
this.requireServer();
21+
async run(): Promise<Sites> {
2522
this.requireOAuthCredentials();
2623

27-
const instance = this.createApiInstance();
2824
const hostname = this.resolvedConfig.hostname!;
2925

3026
this.log(t('commands.sites.list.fetching', 'Fetching sites from {{hostname}}...', {hostname}));
3127

32-
try {
33-
const response = await instance.ocapiDataRequest('sites?select=(**)');
34-
35-
if (!response.ok) {
36-
const errorText = await response.text();
37-
this.error(
38-
t('commands.sites.list.fetchFailed', 'Failed to fetch sites: {{status}} {{statusText}}\n{{error}}', {
39-
status: response.status,
40-
statusText: response.statusText,
41-
error: errorText,
42-
}),
43-
);
44-
}
45-
46-
const data = (await response.json()) as SitesResponse;
47-
48-
if (data.count === 0) {
49-
this.log(t('commands.sites.list.noSites', 'No sites found.'));
50-
return;
51-
}
52-
53-
this.log('');
54-
this.log(t('commands.sites.list.foundSites', 'Found {{count}} site(s):', {count: data.count}));
55-
this.log('');
56-
57-
for (const site of data.data) {
58-
const displayName = site.display_name?.default || site.id;
59-
const status = site.status || 'unknown';
60-
this.log(` ${site.id}`);
61-
this.log(` ${t('commands.sites.list.displayName', 'Display Name: {{name}}', {name: displayName})}`);
62-
this.log(` ${t('commands.sites.list.status', 'Status: {{status}}', {status})}`);
63-
this.log('');
64-
}
65-
} catch (error) {
66-
if (error instanceof Error) {
67-
this.error(t('commands.sites.list.error', 'Failed to fetch sites: {{message}}', {message: error.message}));
68-
}
69-
throw error;
28+
// eslint-disable-next-line new-cap
29+
const {data, error} = await this.instance.ocapi.GET('/sites', {
30+
params: {query: {select: '(**)'}},
31+
});
32+
33+
if (error) {
34+
this.error(t('commands.sites.list.error', 'Failed to fetch sites: {{message}}', {message: String(error)}));
35+
}
36+
37+
const sites = data as Sites;
38+
39+
// In JSON mode, just return the data - oclif handles output to stdout
40+
if (this.jsonEnabled()) {
41+
return sites;
42+
}
43+
44+
// Human-readable table output to stdout
45+
if (!sites || sites.count === 0) {
46+
ux.stdout(t('commands.sites.list.noSites', 'No sites found.'));
47+
return sites;
48+
}
49+
50+
this.printSitesTable(sites.data ?? []);
51+
52+
return sites;
53+
}
54+
55+
private printSitesTable(sites: Site[]): void {
56+
const ui = cliui({width: process.stdout.columns || 80});
57+
58+
// Header
59+
ui.div(
60+
{text: 'ID', width: 30, padding: [0, 2, 0, 0]},
61+
{text: 'Display Name', width: 30, padding: [0, 2, 0, 0]},
62+
{text: 'Status', padding: [0, 0, 0, 0]},
63+
);
64+
65+
// Separator
66+
ui.div({text: '─'.repeat(70), padding: [0, 0, 0, 0]});
67+
68+
// Rows
69+
for (const site of sites) {
70+
const displayName = site.display_name?.default || site.id || '';
71+
const status = site.storefront_status || 'unknown';
72+
73+
ui.div(
74+
{text: site.id || '', width: 30, padding: [0, 2, 0, 0]},
75+
{text: displayName, width: 30, padding: [0, 2, 0, 0]},
76+
{text: status, padding: [0, 0, 0, 0]},
77+
);
7078
}
79+
80+
ux.stdout(ui.toString());
7181
}
7282
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
declare module 'cliui' {
2+
interface Column {
3+
text: string;
4+
width?: number;
5+
align?: 'center' | 'left' | 'right';
6+
padding?: [number, number, number, number];
7+
border?: boolean;
8+
}
9+
10+
interface UIOptions {
11+
width?: number;
12+
wrap?: boolean;
13+
}
14+
15+
interface UI {
16+
div(...columns: (Column | string)[]): void;
17+
span(...columns: (Column | string)[]): void;
18+
resetOutput(): void;
19+
toString(): string;
20+
}
21+
22+
function cliui(options?: UIOptions): UI;
23+
export default cliui;
24+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.generated.ts

packages/b2c-tooling/eslint.config.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const gitignorePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)),
88

99
export default [
1010
includeIgnoreFile(gitignorePath),
11+
{
12+
ignores: ['**/*.generated.ts'],
13+
},
1114
...tseslint.configs.recommended,
1215
prettierPlugin,
1316
{

packages/b2c-tooling/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,12 @@
117117
"module": "./dist/esm/index.js",
118118
"types": "./dist/esm/index.d.ts",
119119
"files": [
120-
"dist"
120+
"dist",
121+
"specs"
121122
],
122123
"scripts": {
123-
"build": "pnpm run build:esm && pnpm run build:cjs",
124+
"generate:types": "openapi-typescript specs/data-api.json -o src/clients/ocapi.generated.ts",
125+
"build": "pnpm run generate:types && pnpm run build:esm && pnpm run build:cjs",
124126
"build:esm": "tsc -p tsconfig.esm.json",
125127
"build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
126128
"clean": "shx rm -rf dist",
@@ -139,6 +141,7 @@
139141
"eslint": "^9",
140142
"eslint-config-prettier": "^10",
141143
"eslint-plugin-prettier": "^5.5.4",
144+
"openapi-typescript": "^7.10.1",
142145
"prettier": "^3.6.2",
143146
"shx": "^0.3.3",
144147
"typescript": "^5",
@@ -157,6 +160,7 @@
157160
},
158161
"dependencies": {
159162
"i18next": "^25.6.3",
163+
"openapi-fetch": "^0.15.0",
160164
"pino": "^10.1.0",
161165
"pino-pretty": "^13.1.2"
162166
}

0 commit comments

Comments
 (0)