Skip to content

Commit 5a99989

Browse files
committed
feat: 对齐云端转换参数并改进 CLI 体验
将 cloud params 限制为 API 实际支持的字段,移除过时的 cloud-only 选项;按当前模式调整字体嵌入提示;升级 @deckops/sdk 并增强 API 错误输出与 space-id 配置。
1 parent a560a3a commit 5a99989

10 files changed

Lines changed: 301 additions & 126 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@deckflow/deckhtml",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "Convert HTML to PPTX, PDF, or PNG presentations",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
@@ -40,7 +40,7 @@
4040
"homepage": "https://github.com/deckflow/deckhtml#readme",
4141
"license": "MIT",
4242
"dependencies": {
43-
"@deckops/sdk": "^0.7.0",
43+
"@deckops/sdk": "^0.7.2",
4444
"commander": "^11.1.0",
4545
"jszip": "^3.10.1",
4646
"mathml2omml": "^0.5.0",

pnpm-lock.yaml

Lines changed: 5 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cli.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ async function main(): Promise<void> {
6262
}
6363
outputError(
6464
error instanceof Error ? error : new Error(String(error)),
65-
ctx.jsonOutput
65+
ctx.jsonOutput,
66+
'ERROR',
67+
{ apiBase: ctx.config.apiBase }
6668
);
6769
process.exit(ExitCode.ERROR);
6870
}

src/cli/commands/config.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export function registerConfigCommands(program: Command, ctx: Context): void {
77
config
88
.command('set')
99
.description('Set a configuration value')
10-
.argument('<key>', 'api-key | webhook | retention-hours')
10+
.argument('<key>', 'api-key | space-id | webhook | retention-hours')
1111
.argument('<value>', 'Configuration value')
1212
.action(async (key: string, value: string) => {
1313
try {
@@ -19,6 +19,14 @@ export function registerConfigCommands(program: Command, ctx: Context): void {
1919
() => 'API key set successfully'
2020
);
2121
break;
22+
case 'space-id':
23+
await ctx.config.setSpaceId(value);
24+
ctx.resetDeck();
25+
ctx.output(
26+
{ key, value, message: 'Space ID set successfully' },
27+
() => `Space ID set to ${value}`
28+
);
29+
break;
2230
case 'webhook':
2331
await ctx.config.set('webhook', value);
2432
ctx.output(
@@ -40,7 +48,7 @@ export function registerConfigCommands(program: Command, ctx: Context): void {
4048
}
4149
default:
4250
throw new Error(
43-
`Unknown config key: ${key}. Supported: api-key, webhook, retention-hours`
51+
`Unknown config key: ${key}. Supported: api-key, space-id, webhook, retention-hours`
4452
);
4553
}
4654
} catch (error) {

src/cli/commands/convert.ts

Lines changed: 28 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,18 @@ import {
3030
import { resolveMode, validateCloudOnlyFlags } from '../utils/mode';
3131
import { resolveViewport } from '../utils/size';
3232

33-
const DEFAULT_RENDER_WAIT = 3;
3433
const DEFAULT_TIMEOUT = 600;
3534

3635
const VALID_PLATFORMS = ['win', 'mac', 'ios', 'android', 'linux'] as const;
36+
type CloudPlatform = 'mac' | 'win';
3737

3838
export interface ConvertOptions {
3939
output?: string;
4040
mode: string;
4141
format: string;
4242
width?: string;
4343
platform?: string;
44-
renderWait: string;
45-
rebuildSvg?: boolean;
46-
rebuildChart?: boolean;
4744
embedFonts?: boolean;
48-
mapMotion?: boolean;
49-
webhook?: string;
50-
retentionHours?: string;
5145
report?: boolean;
5246
}
5347

@@ -63,45 +57,25 @@ function resolvePlatformOption(platform?: string): PlatformTarget {
6357
return platform as PlatformTarget;
6458
}
6559

66-
function parsePositiveInt(value: string, flag: string): number {
67-
const n = parseInt(value, 10);
68-
if (!Number.isFinite(n) || n < 0) {
69-
throw new Error(`Invalid ${flag}: ${value}`);
70-
}
71-
return n;
60+
function toCloudPlatform(platform: PlatformTarget): CloudPlatform {
61+
return platform === 'mac' || platform === 'ios' ? 'mac' : 'win';
7262
}
7363

7464
function buildCloudParams(
75-
ctx: Context,
7665
options: ConvertOptions,
77-
platform: PlatformTarget,
66+
platform: CloudPlatform,
7867
viewport?: { width: number; height: number }
7968
): Record<string, unknown> {
80-
const retentionHours = options.retentionHours
81-
? parsePositiveInt(options.retentionHours, '--retention-hours')
82-
: ctx.config.retentionHours;
83-
84-
if (retentionHours < 0 || retentionHours > 99) {
85-
throw new Error('--retention-hours must be between 0 and 99');
86-
}
87-
8869
const params: Record<string, unknown> = {
8970
needEmbedFonts: Boolean(options.embedFonts),
90-
renderWait: parsePositiveInt(options.renderWait, '--render-wait'),
91-
rebuildSvg: Boolean(options.rebuildSvg),
92-
rebuildChart: Boolean(options.rebuildChart),
93-
mapMotion: Boolean(options.mapMotion),
94-
webhook: options.webhook ?? ctx.config.get('webhook'),
95-
retentionHours,
71+
platform,
9672
};
9773

9874
if (viewport) {
9975
params.width = viewport.width;
10076
params.height = viewport.height;
10177
}
10278

103-
params.platform = platform;
104-
10579
return params;
10680
}
10781

@@ -177,41 +151,33 @@ async function runCloudConvert(
177151

178152
const deck = await ctx.getDeck();
179153
const spaceId = ctx.config.get('spaceId');
180-
if (!spaceId) {
181-
throw new Error(
182-
'Space ID is missing. Run `deckhtml auth login` first or ensure your API key includes workspace context.'
183-
);
184-
}
185154

186-
const params = buildCloudParams(ctx, options, platform, viewport);
155+
const params = buildCloudParams(options, toCloudPlatform(platform), viewport);
187156
const taskName = path.basename(inputPaths[0]!, path.extname(inputPaths[0]!));
188157

158+
logVerbose(ctx.verbose, ctx.quiet, `API base: ${ctx.config.apiBase}`);
159+
logVerbose(
160+
ctx.verbose,
161+
ctx.quiet,
162+
spaceId ? `Space ID: ${spaceId}` : 'Space ID: auto (GET /user/self)'
163+
);
189164
logProgress(ctx.quiet, `Uploading ${inputPaths.length} file(s)...`);
190165

191-
let task;
192-
if (format === 'png') {
193-
task = await deck.convertHtmlToPng({
194-
spaceId,
195-
files: inputPaths,
196-
name: taskName,
197-
params: params as never,
198-
upload: {
199-
onProgress: (p: number) =>
200-
logProgress(ctx.quiet, `Uploading: ${(p * 100).toFixed(1)}%`),
201-
},
202-
});
203-
} else {
204-
task = await deck.convertHtmlToPptx({
205-
spaceId,
206-
files: inputPaths,
207-
name: taskName,
208-
params: params as never,
209-
upload: {
210-
onProgress: (p: number) =>
211-
logProgress(ctx.quiet, `Uploading: ${(p * 100).toFixed(1)}%`),
212-
},
213-
});
214-
}
166+
const taskInput = {
167+
...(spaceId ? { spaceId } : {}),
168+
files: inputPaths,
169+
name: taskName,
170+
params: params as never,
171+
upload: {
172+
onProgress: (p: number) =>
173+
logProgress(ctx.quiet, `Uploading: ${(p * 100).toFixed(1)}%`),
174+
},
175+
};
176+
177+
const task =
178+
format === 'png'
179+
? await deck.convertHtmlToPng(taskInput)
180+
: await deck.convertHtmlToPptx(taskInput);
215181

216182
logProgress(ctx.quiet, `Task created: ${task.id}`);
217183
logProgress(ctx.quiet, 'Converting...');
@@ -271,19 +237,9 @@ export function registerConvertCommand(program: Command, ctx: Context): void {
271237
)
272238
.option(
273239
'--platform <platform>',
274-
'Target platform for generic font mapping: win, mac, ios, android, linux (default: current OS; script/lang auto-detected from text)'
275-
)
276-
.option(
277-
'--render-wait <seconds>',
278-
'Per-page wait before capture (cloud)',
279-
String(DEFAULT_RENDER_WAIT)
240+
'Target platform: local supports win, mac, ios, android, linux; cloud uses mac or win (ios→mac, others→win)'
280241
)
281-
.option('--rebuild-svg', 'Rebuild SVG objects (cloud only)', false)
282-
.option('--rebuild-chart', 'Rebuild chart objects (cloud only)', false)
283242
.option('--embed-fonts', 'Embed fonts (cloud only)', false)
284-
.option('--map-motion', 'Map animations (cloud only)', false)
285-
.option('--webhook <url>', 'Callback URL (cloud)')
286-
.option('--retention-hours <n>', 'Cloud file retention hours (0-99)')
287243
.option('--report', 'Generate conversion report next to output', false)
288244
.action(async (inputs: string[], options: ConvertOptions) => {
289245
if (inputs.length === 0) {
@@ -321,10 +277,7 @@ export function registerConvertCommand(program: Command, ctx: Context): void {
321277
);
322278

323279
validateCloudOnlyFlags(mode, {
324-
rebuildSvg: options.rebuildSvg,
325-
rebuildChart: options.rebuildChart,
326280
embedFonts: options.embedFonts,
327-
mapMotion: options.mapMotion,
328281
});
329282

330283
const platform = resolvePlatformOption(options.platform);

src/cli/context.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import {
99
runLoginFlow,
1010
DEFAULT_PORT,
1111
} from './core/auth';
12+
import {
13+
installApiErrorCapture,
14+
shouldLogHttpRequests,
15+
} from './utils/api-error';
1216
import { ExitCode, outputError } from './utils/errors';
1317

1418
export class Context {
@@ -46,6 +50,9 @@ export class Context {
4650
}
4751

4852
if (!this.deck) {
53+
await installApiErrorCapture({
54+
logRequests: shouldLogHttpRequests(this.verbose),
55+
});
4956
const { createDeck } = await import('@deckops/sdk');
5057
this.deck = createDeck({
5158
root: this.config.apiBase,
@@ -146,7 +153,7 @@ export class Context {
146153
error(input: unknown, code = 'ERROR', exitCode: number = ExitCode.ERROR): never {
147154
const err =
148155
input instanceof Error ? input : new Error(String(input ?? 'Unknown error'));
149-
outputError(err, this.jsonOutput, code);
156+
outputError(err, this.jsonOutput, code, { apiBase: this.config.apiBase });
150157
process.exit(exitCode);
151158
}
152159

0 commit comments

Comments
 (0)