gangtise-openapi-cli 0.17.0 → 0.17.1

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/cli.js CHANGED
@@ -261,10 +261,19 @@ insight.addCommand(foreignOpinion);
261
261
  insight.addCommand(independentOpinion);
262
262
  program.addCommand(insight);
263
263
  const quote = new Command("quote").description("Quote APIs");
264
- quote.command("day-kline").option("--security <code>", "Security code (A-share: .SH/.SZ/.BJ, or 'all' for full market)", collectList, []).option("--start-date <date>", "Start date (default: 1 year before end-date)").option("--end-date <date>", "End date (default: latest)").option("--limit <number>", "Max rows per request (default: 6000, max: 10000)").option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => callKlineWithSharding(client, "quote.day-kline", buildQuoteKlineBody(options), { shardDays: 1 })));
265
- quote.command("day-kline-hk").option("--security <code>", "Security code (HK stock: .HK, or 'all' for full market)", collectList, []).option("--start-date <date>", "Start date (default: 1 year before end-date)").option("--end-date <date>", "End date (default: latest)").option("--limit <number>", "Max rows per request (default: 6000, max: 10000)").option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => callKlineWithSharding(client, "quote.day-kline-hk", buildQuoteKlineBody(options), { shardDays: 2 })));
266
- quote.command("day-kline-us").option("--security <code>", "Security code (US stock: e.g. AAPL.O, or 'all' for full market)", collectList, []).option("--start-date <date>", "Start date (default: 1 year before end-date)").option("--end-date <date>", "End date (default: latest)").option("--limit <number>", "Max rows per request (default: 6000, max: 10000)").option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => callKlineWithSharding(client, "quote.day-kline-us", buildQuoteKlineBody(options), { shardDays: 1 })));
267
- quote.command("index-day-kline").option("--security <code>", "Index code (.SH/.SZ/.BJ, or 'all' for full market)", collectList, []).option("--start-date <date>", "Start date (default: 1 year before end-date)").option("--end-date <date>", "End date (default: latest)").option("--limit <number>", "Max rows per request (default: 6000, max: 10000)").option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => callKlineWithSharding(client, "quote.index-day-kline", buildQuoteKlineBody(options), { shardDays: 30 })));
264
+ const addKlineCommand = (name, endpointKey, securityHelp, shardDays) => quote.command(name)
265
+ .option("--security <code>", securityHelp, collectList, [])
266
+ .option("--start-date <date>", "Start date (default: 1 year before end-date)")
267
+ .option("--end-date <date>", "End date (default: latest)")
268
+ .option("--limit <number>", "Max rows per request (default: 6000, max: 10000)")
269
+ .option("--field <field>", "Field", collectList, [])
270
+ .option("--format <format>", "Output format", "table")
271
+ .option("--output <path>")
272
+ .action((options) => emit(options, (client) => callKlineWithSharding(client, endpointKey, buildQuoteKlineBody(options), { shardDays })));
273
+ addKlineCommand("day-kline", "quote.day-kline", "Security code (A-share: .SH/.SZ/.BJ, or 'all' for full market)", 1);
274
+ addKlineCommand("day-kline-hk", "quote.day-kline-hk", "Security code (HK stock: .HK, or 'all' for full market)", 2);
275
+ addKlineCommand("day-kline-us", "quote.day-kline-us", "Security code (US stock: e.g. AAPL.O, or 'all' for full market)", 1);
276
+ addKlineCommand("index-day-kline", "quote.index-day-kline", "Index code (.SH/.SZ/.BJ, or 'all' for full market)", 30);
268
277
  quote.command("minute-kline").option("--security <code>", "Security code (A-share only: .SH/.SZ/.BJ)").option("--start-time <datetime>", "Start time (yyyy-MM-dd HH:mm:ss)").option("--end-time <datetime>", "End time (yyyy-MM-dd HH:mm:ss)").option("--limit <number>", "Max rows per request (default: 5000, max: 10000)").option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("quote.minute-kline", { securityCode: options.security, startTime: options.startTime, endTime: options.endTime, limit: parseOptionalNumberOption(options.limit, "--limit", { integer: true, min: 1 }), fieldList: maybeArray(options.field) })));
269
278
  quote.command("realtime").description("Realtime quote snapshot (A-share / HK / US)").option("--security <code>", "Security code (e.g. 600519.SH / 00700.HK / AAPL.O), or market keyword: aShares / hkStocks / usStocks", collectList, []).option("--field <field>", "Field", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => emit(options, (client) => client.call("quote.realtime", { securityList: maybeArray(options.security), fieldList: maybeArray(options.field) })));
270
279
  program.addCommand(quote);
@@ -165,8 +165,10 @@ export class GangtiseClient {
165
165
  nextFrom += size;
166
166
  }
167
167
  const MAX_PAGES = 1000;
168
+ let truncatedByPageCap = false;
168
169
  if (pageRequests.length + 1 > MAX_PAGES) {
169
170
  pageRequests.length = MAX_PAGES - 1;
171
+ truncatedByPageCap = true;
170
172
  }
171
173
  let unexpectedShape = false;
172
174
  let totalDrift = false;
@@ -195,6 +197,12 @@ export class GangtiseClient {
195
197
  if (totalDrift && isVerbose()) {
196
198
  process.stderr.write(`[gangtise] warning: 'total' changed across pages (data shifted during fetch)\n`);
197
199
  }
200
+ // Always surface a cap-induced truncation (not gated on verbose): the user
201
+ // asked for everything and is silently getting a subset, mirroring the
202
+ // partial-result warning in quoteSharding.
203
+ if (truncatedByPageCap) {
204
+ process.stderr.write(`[gangtise] warning: hit the ${MAX_PAGES}-page safety cap; fetched ${collected.length} of ${total} rows. Narrow the query (e.g. a shorter date range) or pass --size to fetch a bounded subset.\n`);
205
+ }
198
206
  return {
199
207
  ...firstPage,
200
208
  total,
@@ -330,7 +338,16 @@ export class GangtiseClient {
330
338
  // Stream directly to disk when caller already knows the destination
331
339
  if (options?.streamTo) {
332
340
  await fs.mkdir(path.dirname(options.streamTo), { recursive: true });
333
- await pipeline(response.body, createWriteStream(options.streamTo));
341
+ try {
342
+ await pipeline(response.body, createWriteStream(options.streamTo));
343
+ }
344
+ catch (error) {
345
+ // A mid-stream failure leaves a truncated file on disk; remove it so a
346
+ // failed download never looks like a complete one. withRetry may still
347
+ // replay the request (the next attempt re-creates the file).
348
+ await fs.unlink(options.streamTo).catch(() => { });
349
+ throw error;
350
+ }
334
351
  logTiming(`GET ${endpoint.path} (stream)`, Date.now() - startedAt, `${response.statusCode}`);
335
352
  return { contentType, filename, savedPath: options.streamTo };
336
353
  }
@@ -1,2 +1,2 @@
1
1
  // Auto-generated — DO NOT EDIT
2
- export const CLI_VERSION = "0.17.0";
2
+ export const CLI_VERSION = "0.17.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gangtise-openapi-cli",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "description": "CLI for Gangtise OpenAPI",
5
5
  "license": "MIT",
6
6
  "repository": {