@invinite-org/invinite-data-cli 0.1.22 → 0.2.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 +304 -6
- package/claude-plugin/.claude-plugin/plugin.json +2 -2
- package/claude-plugin/agents/invinite-data.md +5 -1
- package/claude-plugin/commands/analyze-earnings-call.md +24 -0
- package/claude-plugin/commands/financial-research.md +2 -1
- package/claude-plugin/skills/invinite-data-cli/SKILL.md +82 -1
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +22 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/client/api-client.d.ts +13 -1
- package/dist/src/client/api-client.js +46 -13
- package/dist/src/client/api-client.js.map +1 -1
- package/dist/src/client/download.d.ts +23 -0
- package/dist/src/client/download.js +116 -0
- package/dist/src/client/download.js.map +1 -0
- package/dist/src/client/earnings-live.d.ts +79 -0
- package/dist/src/client/earnings-live.js +156 -0
- package/dist/src/client/earnings-live.js.map +1 -0
- package/dist/src/client/pagination.js +2 -1
- package/dist/src/client/pagination.js.map +1 -1
- package/dist/src/client/websocket-client.d.ts +12 -1
- package/dist/src/client/websocket-client.js +114 -37
- package/dist/src/client/websocket-client.js.map +1 -1
- package/dist/src/commands/earnings-selector.d.ts +15 -0
- package/dist/src/commands/earnings-selector.js +29 -0
- package/dist/src/commands/earnings-selector.js.map +1 -0
- package/dist/src/commands/earnings.d.ts +13 -0
- package/dist/src/commands/earnings.js +705 -0
- package/dist/src/commands/earnings.js.map +1 -0
- package/dist/src/commands/plugin.d.ts +11 -0
- package/dist/src/commands/plugin.js +23 -8
- package/dist/src/commands/plugin.js.map +1 -1
- package/dist/src/commands/webhooks.d.ts +6 -0
- package/dist/src/commands/webhooks.js +144 -0
- package/dist/src/commands/webhooks.js.map +1 -0
- package/dist/src/commands/ws.js +23 -3
- package/dist/src/commands/ws.js.map +1 -1
- package/dist/src/formatters/flatten.d.ts +4 -0
- package/dist/src/formatters/flatten.js +15 -0
- package/dist/src/formatters/flatten.js.map +1 -0
- package/dist/src/formatters/time.d.ts +2 -0
- package/dist/src/formatters/time.js +14 -0
- package/dist/src/formatters/time.js.map +1 -0
- package/dist/src/shared/errors.d.ts +2 -1
- package/dist/src/shared/errors.js +5 -1
- package/dist/src/shared/errors.js.map +1 -1
- package/dist/src/shared/options.d.ts +2 -0
- package/dist/src/shared/options.js +6 -0
- package/dist/src/shared/options.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,28 +7,47 @@ function buildUrl(path, params) {
|
|
|
7
7
|
const url = new URL(`${base}${path}`);
|
|
8
8
|
if (params) {
|
|
9
9
|
for (const [key, value] of Object.entries(params)) {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
for (const item of Array.isArray(value) ? value : [value]) {
|
|
11
|
+
if (item !== undefined && item !== '') {
|
|
12
|
+
url.searchParams.append(key, item);
|
|
13
|
+
}
|
|
12
14
|
}
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
return url.toString();
|
|
16
18
|
}
|
|
19
|
+
async function apiErrorFrom(response) {
|
|
20
|
+
const body = await response.json().catch(() => null);
|
|
21
|
+
return new ApiError(response.status, body?.error || response.statusText || 'Unknown Error', body?.message || `Request failed with status ${response.status}`);
|
|
22
|
+
}
|
|
23
|
+
async function request(opts, accept, init = {}) {
|
|
24
|
+
const apiKey = await getApiKey();
|
|
25
|
+
const url = buildUrl(opts.path, opts.params);
|
|
26
|
+
const headers = {
|
|
27
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
28
|
+
'Accept': accept,
|
|
29
|
+
};
|
|
30
|
+
if (init.body !== undefined)
|
|
31
|
+
headers['Content-Type'] = 'application/json';
|
|
32
|
+
const response = await fetch(url, {
|
|
33
|
+
headers,
|
|
34
|
+
...(init.method ? { method: init.method } : {}),
|
|
35
|
+
...(init.body !== undefined ? { body: JSON.stringify(init.body) } : {}),
|
|
36
|
+
});
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
throw await apiErrorFrom(response);
|
|
39
|
+
}
|
|
40
|
+
return response;
|
|
41
|
+
}
|
|
42
|
+
/** Same auth / URL building as `apiGet`, without the JSON parse; a non-2xx throws `ApiError`. */
|
|
43
|
+
export async function apiGetRaw(opts) {
|
|
44
|
+
return request(opts, opts.accept ?? '*/*');
|
|
45
|
+
}
|
|
17
46
|
export async function apiGet(opts) {
|
|
18
47
|
const spinner = opts.silent ? null : createSpinner('Fetching data...');
|
|
19
48
|
try {
|
|
20
|
-
const
|
|
21
|
-
const url = buildUrl(opts.path, opts.params);
|
|
22
|
-
const response = await fetch(url, {
|
|
23
|
-
headers: {
|
|
24
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
25
|
-
'Accept': 'application/json',
|
|
26
|
-
},
|
|
27
|
-
});
|
|
49
|
+
const response = await request(opts, 'application/json');
|
|
28
50
|
const body = await response.json();
|
|
29
|
-
if (!response.ok) {
|
|
30
|
-
throw new ApiError(response.status, body?.error || 'Unknown Error', body?.message || `Request failed with status ${response.status}`);
|
|
31
|
-
}
|
|
32
51
|
spinner?.succeed('Done');
|
|
33
52
|
return body;
|
|
34
53
|
}
|
|
@@ -37,4 +56,18 @@ export async function apiGet(opts) {
|
|
|
37
56
|
throw error;
|
|
38
57
|
}
|
|
39
58
|
}
|
|
59
|
+
/** A write with a JSON body; same auth / `ApiError` handling as `apiGet`. A 204 / empty body → `undefined`. */
|
|
60
|
+
export async function apiRequest(opts) {
|
|
61
|
+
const spinner = opts.silent ? null : createSpinner('Sending request...');
|
|
62
|
+
try {
|
|
63
|
+
const response = await request(opts, 'application/json', { method: opts.method, body: opts.body });
|
|
64
|
+
const text = response.status === 204 ? '' : await response.text();
|
|
65
|
+
spinner?.succeed('Done');
|
|
66
|
+
return (text ? JSON.parse(text) : undefined);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
spinner?.fail('Failed');
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
40
73
|
//# sourceMappingURL=api-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../../src/client/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../../src/client/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AASrD,SAAS,QAAQ,CAAC,IAAY,EAAE,MAAiC;IAC/D,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;IACtC,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1D,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;oBACtC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,QAAkB;IAC5C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAQ,CAAC;IAC5D,OAAO,IAAI,QAAQ,CACjB,QAAQ,CAAC,MAAM,EACf,IAAI,EAAE,KAAK,IAAI,QAAQ,CAAC,UAAU,IAAI,eAAe,EACrD,IAAI,EAAE,OAAO,IAAI,8BAA8B,QAAQ,CAAC,MAAM,EAAE,CACjE,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,IAAoB,EACpB,MAAc,EACd,OAA4C,EAAE;IAE9C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,OAAO,GAA2B;QACtC,eAAe,EAAE,UAAU,MAAM,EAAE;QACnC,QAAQ,EAAE,MAAM;KACjB,CAAC;IACF,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;IAC1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,OAAO;QACP,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxE,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAA0C;IACxE,OAAO,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAc,IAAoB;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAO,CAAC;QACxC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAQD,+GAA+G;AAC/G,MAAM,CAAC,KAAK,UAAU,UAAU,CAAc,IAAuB;IACnE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;IACzE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,kBAAkB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACnG,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAClE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAM,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface SaveOptions {
|
|
2
|
+
/** Replace an existing file. */
|
|
3
|
+
force?: boolean;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Streams a presigned URL to disk. Plain fetch: NO Authorization header — the URL is a
|
|
7
|
+
* bearer URL and R2 would reject the extra header. Written through `writeViaPart`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function downloadToFile(url: string, file: string, opts?: SaveOptions & {
|
|
10
|
+
spinnerText?: string;
|
|
11
|
+
}): Promise<{
|
|
12
|
+
path: string;
|
|
13
|
+
bytes: number;
|
|
14
|
+
}>;
|
|
15
|
+
/** Writes text (transcript, press release) to `file`; refuses an existing target unless `force`. */
|
|
16
|
+
export declare function writeTextFile(file: string, text: string, opts?: SaveOptions): Promise<{
|
|
17
|
+
path: string;
|
|
18
|
+
bytes: number;
|
|
19
|
+
}>;
|
|
20
|
+
/** `mkdir -p` of a directory target (`documents --output dir/`); returns its absolute path. */
|
|
21
|
+
export declare function ensureDir(dir: string): Promise<string>;
|
|
22
|
+
/** File extension for a `content_type` (parameters ignored); `bin` when unknown. */
|
|
23
|
+
export declare function extensionFor(contentType: string | null | undefined): string;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { createWriteStream, rmSync } from 'node:fs';
|
|
2
|
+
import { access, mkdir, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { Readable } from 'node:stream';
|
|
5
|
+
import { pipeline } from 'node:stream/promises';
|
|
6
|
+
import { createSpinner } from '../shared/spinner.js';
|
|
7
|
+
async function exists(path) {
|
|
8
|
+
try {
|
|
9
|
+
await access(path);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Resolves `file` against cwd and refuses an existing target unless `force`. */
|
|
17
|
+
async function prepareTarget(file, opts) {
|
|
18
|
+
const path = resolve(file);
|
|
19
|
+
if (!opts.force && await exists(path)) {
|
|
20
|
+
throw new Error(`${path} already exists (use --force to overwrite)`);
|
|
21
|
+
}
|
|
22
|
+
await mkdir(dirname(path), { recursive: true });
|
|
23
|
+
return path;
|
|
24
|
+
}
|
|
25
|
+
/** Exit codes of the signals that abort a write (128 + signal number, as a shell reports them). */
|
|
26
|
+
const ABORT_SIGNALS = { SIGINT: 130, SIGTERM: 143 };
|
|
27
|
+
/**
|
|
28
|
+
* Runs `write(part, signal)` against `<path>.part` and renames it onto `path` on success, so a
|
|
29
|
+
* failed write never leaves a partial file or clobbers an existing one. While it runs, SIGINT /
|
|
30
|
+
* SIGTERM (Ctrl-C) abort `signal`, remove the `.part` file synchronously and exit with 130 / 143 —
|
|
31
|
+
* a listener replaces Node's default exit, which would skip the cleanup.
|
|
32
|
+
*/
|
|
33
|
+
async function writeViaPart(path, write) {
|
|
34
|
+
const part = `${path}.part`;
|
|
35
|
+
const controller = new AbortController();
|
|
36
|
+
const onSignal = (signal) => {
|
|
37
|
+
controller.abort();
|
|
38
|
+
rmSync(part, { force: true });
|
|
39
|
+
process.exit(ABORT_SIGNALS[signal]);
|
|
40
|
+
};
|
|
41
|
+
for (const signal of Object.keys(ABORT_SIGNALS))
|
|
42
|
+
process.once(signal, onSignal);
|
|
43
|
+
try {
|
|
44
|
+
await write(part, controller.signal);
|
|
45
|
+
await rename(part, path);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
await rm(part, { force: true });
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
for (const signal of Object.keys(ABORT_SIGNALS))
|
|
53
|
+
process.off(signal, onSignal);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Streams a presigned URL to disk. Plain fetch: NO Authorization header — the URL is a
|
|
58
|
+
* bearer URL and R2 would reject the extra header. Written through `writeViaPart`.
|
|
59
|
+
*/
|
|
60
|
+
export async function downloadToFile(url, file, opts = {}) {
|
|
61
|
+
const path = await prepareTarget(file, opts);
|
|
62
|
+
const spinner = createSpinner(opts.spinnerText ?? 'Downloading...');
|
|
63
|
+
try {
|
|
64
|
+
await writeViaPart(path, async (part, signal) => {
|
|
65
|
+
const response = await fetch(url, { signal });
|
|
66
|
+
if (!response.ok || !response.body) {
|
|
67
|
+
throw new Error(`Download failed with status ${response.status}`);
|
|
68
|
+
}
|
|
69
|
+
await pipeline(Readable.fromWeb(response.body), createWriteStream(part), { signal });
|
|
70
|
+
});
|
|
71
|
+
const { size } = await stat(path);
|
|
72
|
+
spinner.succeed('Downloaded');
|
|
73
|
+
return { path, bytes: size };
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
spinner.fail('Download failed');
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Writes text (transcript, press release) to `file`; refuses an existing target unless `force`. */
|
|
81
|
+
export async function writeTextFile(file, text, opts = {}) {
|
|
82
|
+
const path = await prepareTarget(file, opts);
|
|
83
|
+
await writeViaPart(path, (part, signal) => writeFile(part, text, { encoding: 'utf8', signal }));
|
|
84
|
+
return { path, bytes: Buffer.byteLength(text, 'utf8') };
|
|
85
|
+
}
|
|
86
|
+
/** `mkdir -p` of a directory target (`documents --output dir/`); returns its absolute path. */
|
|
87
|
+
export async function ensureDir(dir) {
|
|
88
|
+
const path = resolve(dir);
|
|
89
|
+
await mkdir(path, { recursive: true });
|
|
90
|
+
return path;
|
|
91
|
+
}
|
|
92
|
+
const EXTENSIONS = {
|
|
93
|
+
'application/pdf': 'pdf',
|
|
94
|
+
'text/html': 'html',
|
|
95
|
+
'text/plain': 'txt',
|
|
96
|
+
'text/csv': 'csv',
|
|
97
|
+
'application/json': 'json',
|
|
98
|
+
'application/xml': 'xml',
|
|
99
|
+
'text/xml': 'xml',
|
|
100
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
|
101
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
|
102
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
|
|
103
|
+
'application/msword': 'doc',
|
|
104
|
+
'application/vnd.ms-excel': 'xls',
|
|
105
|
+
'application/vnd.ms-powerpoint': 'ppt',
|
|
106
|
+
'image/png': 'png',
|
|
107
|
+
'image/jpeg': 'jpg',
|
|
108
|
+
'image/gif': 'gif',
|
|
109
|
+
'audio/mpeg': 'mp3',
|
|
110
|
+
};
|
|
111
|
+
/** File extension for a `content_type` (parameters ignored); `bin` when unknown. */
|
|
112
|
+
export function extensionFor(contentType) {
|
|
113
|
+
const type = (contentType ?? '').split(';')[0].trim().toLowerCase();
|
|
114
|
+
return EXTENSIONS[type] ?? 'bin';
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=download.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download.js","sourceRoot":"","sources":["../../../src/client/download.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure pieces of `invd ws listen --earnings`: the subscribe frame and one step per server
|
|
3
|
+
* frame of IDA's `earnings-calls.live` channel (`src/routes/websocket/types/earningsMessages.ts`).
|
|
4
|
+
*/
|
|
5
|
+
export declare const EARNINGS_LIVE_CHANNEL = "earnings-calls.live";
|
|
6
|
+
export type LiveTarget = {
|
|
7
|
+
event_id: string;
|
|
8
|
+
} | {
|
|
9
|
+
cik: string;
|
|
10
|
+
};
|
|
11
|
+
export interface SpeakerAssignment {
|
|
12
|
+
speaker_label: string;
|
|
13
|
+
from_seq: number;
|
|
14
|
+
to_seq: number | null;
|
|
15
|
+
name: string;
|
|
16
|
+
role?: string;
|
|
17
|
+
title?: string | null;
|
|
18
|
+
firm?: string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface LiveSegment {
|
|
21
|
+
seq: number;
|
|
22
|
+
start_ms: number;
|
|
23
|
+
speaker_label: string | null;
|
|
24
|
+
text: string;
|
|
25
|
+
is_final: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface LiveState {
|
|
28
|
+
/** Highest final seq printed (or the `since_seq` asked for): a reconnect resumes after it. */
|
|
29
|
+
lastSeq: number;
|
|
30
|
+
eventId: string | null;
|
|
31
|
+
names: {
|
|
32
|
+
revision: number;
|
|
33
|
+
assignments: SpeakerAssignment[];
|
|
34
|
+
} | null;
|
|
35
|
+
}
|
|
36
|
+
export interface LiveOptions {
|
|
37
|
+
partials: boolean;
|
|
38
|
+
names: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface LiveStep {
|
|
41
|
+
state: LiveState;
|
|
42
|
+
lines: string[];
|
|
43
|
+
/** A partial to show in place of the previous one (TTY only). */
|
|
44
|
+
partial?: string;
|
|
45
|
+
/** Stop: exit code + a closing line. */
|
|
46
|
+
end?: {
|
|
47
|
+
code: 0 | 1;
|
|
48
|
+
message: string;
|
|
49
|
+
};
|
|
50
|
+
/** Close the socket and resubscribe through the backoff. */
|
|
51
|
+
reconnect?: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** `--earnings`: a UUID is an event_id, 1–10 digits a CIK. */
|
|
54
|
+
export declare function parseTarget(value: string): LiveTarget;
|
|
55
|
+
/** `--since-seq`: an integer ≥ -1; default -1 (the whole call from its first final). */
|
|
56
|
+
export declare function parseSinceSeq(value: string | undefined): number;
|
|
57
|
+
export declare function subscribeFrame(target: LiveTarget, sinceSeq: number, partials: boolean): {
|
|
58
|
+
since_seq: number;
|
|
59
|
+
partials: boolean;
|
|
60
|
+
event_id: string;
|
|
61
|
+
type: string;
|
|
62
|
+
channel: string;
|
|
63
|
+
} | {
|
|
64
|
+
since_seq: number;
|
|
65
|
+
partials: boolean;
|
|
66
|
+
cik: string;
|
|
67
|
+
type: string;
|
|
68
|
+
channel: string;
|
|
69
|
+
};
|
|
70
|
+
export declare function initialLiveState(sinceSeq: number): LiveState;
|
|
71
|
+
/** The assignment of `label` covering `seq` (the latest-starting one wins), else null. */
|
|
72
|
+
export declare function nameFor(assignments: SpeakerAssignment[], label: string | null, seq: number): string | null;
|
|
73
|
+
/** `[m:ss] name: text`, the name from the snapshot, else `Speaker <label>`. */
|
|
74
|
+
export declare function formatSegment(segment: LiveSegment, assignments: SpeakerAssignment[]): string;
|
|
75
|
+
export declare function finalTranscriptHint(eventId: string | null): string;
|
|
76
|
+
/** One server frame → the new state and what to print / do. Unknown frames are ignored. */
|
|
77
|
+
export declare function liveStep(state: LiveState, frame: Record<string, any>, opts: LiveOptions): LiveStep;
|
|
78
|
+
/** Frames of the earnings channel (the socket also carries `new_filing` broadcasts and pings). */
|
|
79
|
+
export declare function isEarningsFrame(frame: Record<string, any>): boolean;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { formatMs } from '../formatters/time.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pure pieces of `invd ws listen --earnings`: the subscribe frame and one step per server
|
|
5
|
+
* frame of IDA's `earnings-calls.live` channel (`src/routes/websocket/types/earningsMessages.ts`).
|
|
6
|
+
*/
|
|
7
|
+
export const EARNINGS_LIVE_CHANNEL = 'earnings-calls.live';
|
|
8
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9
|
+
/** Ends the run with exit 1. */
|
|
10
|
+
const FATAL_ERRORS = new Set(['forbidden_tier', 'not_live', 'not_found', 'subscription_limit', 'bad_message']);
|
|
11
|
+
/** Retried through the reconnect backoff. */
|
|
12
|
+
const RETRY_ERRORS = new Set(['attach_failed', 'unavailable']);
|
|
13
|
+
/** `--earnings`: a UUID is an event_id, 1–10 digits a CIK. */
|
|
14
|
+
export function parseTarget(value) {
|
|
15
|
+
const target = value.trim();
|
|
16
|
+
if (UUID_RE.test(target))
|
|
17
|
+
return { event_id: target.toLowerCase() };
|
|
18
|
+
if (/^\d{1,10}$/.test(target))
|
|
19
|
+
return { cik: target };
|
|
20
|
+
throw new Error('--earnings takes an event ID (UUID) or a CIK (digits)');
|
|
21
|
+
}
|
|
22
|
+
/** `--since-seq`: an integer ≥ -1; default -1 (the whole call from its first final). */
|
|
23
|
+
export function parseSinceSeq(value) {
|
|
24
|
+
if (value === undefined)
|
|
25
|
+
return -1;
|
|
26
|
+
const seq = Number(value);
|
|
27
|
+
if (!Number.isInteger(seq) || seq < -1)
|
|
28
|
+
throw new Error('--since-seq takes an integer ≥ -1');
|
|
29
|
+
return seq;
|
|
30
|
+
}
|
|
31
|
+
export function subscribeFrame(target, sinceSeq, partials) {
|
|
32
|
+
return { type: 'subscribe', channel: EARNINGS_LIVE_CHANNEL, ...target, since_seq: sinceSeq, partials };
|
|
33
|
+
}
|
|
34
|
+
export function initialLiveState(sinceSeq) {
|
|
35
|
+
return { lastSeq: sinceSeq, eventId: null, names: null };
|
|
36
|
+
}
|
|
37
|
+
/** The assignment of `label` covering `seq` (the latest-starting one wins), else null. */
|
|
38
|
+
export function nameFor(assignments, label, seq) {
|
|
39
|
+
let best = null;
|
|
40
|
+
for (const a of assignments) {
|
|
41
|
+
if (a.speaker_label !== label || a.from_seq > seq || (a.to_seq !== null && seq > a.to_seq))
|
|
42
|
+
continue;
|
|
43
|
+
if (!best || a.from_seq > best.from_seq)
|
|
44
|
+
best = a;
|
|
45
|
+
}
|
|
46
|
+
return best?.name ?? null;
|
|
47
|
+
}
|
|
48
|
+
/** `[m:ss] name: text`, the name from the snapshot, else `Speaker <label>`. */
|
|
49
|
+
export function formatSegment(segment, assignments) {
|
|
50
|
+
const name = nameFor(assignments, segment.speaker_label, segment.seq)
|
|
51
|
+
?? (segment.speaker_label === null ? 'Speaker' : `Speaker ${segment.speaker_label}`);
|
|
52
|
+
return `[${formatMs(segment.start_ms)}] ${name}: ${segment.text}`;
|
|
53
|
+
}
|
|
54
|
+
export function finalTranscriptHint(eventId) {
|
|
55
|
+
return `final transcript: invd earnings transcript --event ${eventId ?? '<event_id>'}`;
|
|
56
|
+
}
|
|
57
|
+
/** IDA `UNSUBSCRIBE_REASONS` → the closing line; the transcript hint only where a transcript follows. */
|
|
58
|
+
function unsubscribedNote(reason, eventId) {
|
|
59
|
+
switch (reason) {
|
|
60
|
+
case 'transcript_ready':
|
|
61
|
+
return finalTranscriptHint(eventId);
|
|
62
|
+
case 'rescheduled':
|
|
63
|
+
return 'the call was rescheduled; listen again at the new time';
|
|
64
|
+
case 'no_transcript':
|
|
65
|
+
return `no final transcript yet; check later with: invd earnings transcript --event ${eventId ?? '<event_id>'}`;
|
|
66
|
+
default:
|
|
67
|
+
return 'this call produces no more live segments';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function namesLines(revision, assignments) {
|
|
71
|
+
return [
|
|
72
|
+
chalk.dim(`speaker names (revision ${revision})`),
|
|
73
|
+
...assignments.map(a => {
|
|
74
|
+
const detail = [a.title, a.firm].filter(Boolean).join(', ');
|
|
75
|
+
const range = `seq ${a.from_seq}–${a.to_seq ?? '…'}`;
|
|
76
|
+
return chalk.dim(` ${a.speaker_label} → ${a.name}${detail ? ` (${detail})` : ''}${a.role ? ` [${a.role}]` : ''} ${range}`);
|
|
77
|
+
}),
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
/** One server frame → the new state and what to print / do. Unknown frames are ignored. */
|
|
81
|
+
export function liveStep(state, frame, opts) {
|
|
82
|
+
switch (frame.type) {
|
|
83
|
+
case 'subscribed': {
|
|
84
|
+
const latest = frame.current_seq === null ? 'none yet' : `latest ${frame.current_seq}`;
|
|
85
|
+
return {
|
|
86
|
+
state: { ...state, eventId: frame.event_id },
|
|
87
|
+
lines: [chalk.bold(`${frame.symbol} ${frame.conference_date} · ${frame.state} · from seq ${state.lastSeq + 1} (${latest})`)],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
case 'transcript_segment': {
|
|
91
|
+
const assignments = state.names?.assignments ?? [];
|
|
92
|
+
if (!frame.is_final) {
|
|
93
|
+
return opts.partials ? { state, lines: [], partial: chalk.dim(formatSegment(frame, assignments)) } : { state, lines: [] };
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
state: { ...state, lastSeq: Math.max(state.lastSeq, frame.seq) },
|
|
97
|
+
lines: [formatSegment(frame, assignments)],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
case 'speaker_names': {
|
|
101
|
+
if (state.names && frame.revision <= state.names.revision)
|
|
102
|
+
return { state, lines: [] };
|
|
103
|
+
const names = { revision: frame.revision, assignments: frame.assignments ?? [] };
|
|
104
|
+
return { state: { ...state, names }, lines: opts.names ? namesLines(names.revision, names.assignments) : [] };
|
|
105
|
+
}
|
|
106
|
+
// `gap` and `resume_unavailable` are notes only — never a re-subscribe. Verified against IDA
|
|
107
|
+
// (invinite-data-api, 2026-10-10): a final inside a reported gap is still delivered once on
|
|
108
|
+
// the SAME subscription (`deliverFinal`, src/lib/earningsLiveBridge.ts:462-476), and so are
|
|
109
|
+
// gaps of a `since_seq` replay (`recordReportedGaps`, src/routes/websocket/earningsSubscriptions.ts:273).
|
|
110
|
+
// `resume_unavailable` is sent after a successful `subscribed` (earningsSubscriptions.ts:286-293);
|
|
111
|
+
// live delivery continues, and once the call's Ably history becomes readable the bridge
|
|
112
|
+
// back-fills missed finals into the existing subscriptions (`repass`, earningsLiveBridge.ts:660-690).
|
|
113
|
+
// A second subscribe would replay from the same ring and add a duplicate subscription.
|
|
114
|
+
case 'gap':
|
|
115
|
+
return { state, lines: [chalk.dim(`gap after seq ${frame.after_seq} (next ${frame.next_seq}); late segments still arrive`)] };
|
|
116
|
+
case 'call_started':
|
|
117
|
+
return { state, lines: [chalk.bold(`call started ${frame.at}`)] };
|
|
118
|
+
case 'call_ended':
|
|
119
|
+
return { state, lines: [chalk.bold(`call ended ${frame.at}`)] };
|
|
120
|
+
case 'transcript_provisional':
|
|
121
|
+
return { state, lines: [chalk.bold(`provisional transcript v${frame.version} (${frame.word_count} words, speakers not named yet)`)] };
|
|
122
|
+
case 'rescheduled':
|
|
123
|
+
return { state, lines: [chalk.bold(`rescheduled to ${frame.new_conference_date}`)] };
|
|
124
|
+
case 'transcript_ready':
|
|
125
|
+
return {
|
|
126
|
+
state,
|
|
127
|
+
lines: [chalk.bold(`transcript ready ${frame.at}`)],
|
|
128
|
+
end: { code: 0, message: finalTranscriptHint(state.eventId) },
|
|
129
|
+
};
|
|
130
|
+
case 'unsubscribed':
|
|
131
|
+
return {
|
|
132
|
+
state,
|
|
133
|
+
lines: [chalk.bold(`subscription ended: ${frame.reason}`)],
|
|
134
|
+
end: { code: 0, message: unsubscribedNote(frame.reason, state.eventId) },
|
|
135
|
+
};
|
|
136
|
+
case 'error': {
|
|
137
|
+
if (frame.code === 'resume_unavailable') {
|
|
138
|
+
return { state, lines: [chalk.dim('missed segments cannot be replayed for this call; live delivery continues')] };
|
|
139
|
+
}
|
|
140
|
+
if (RETRY_ERRORS.has(frame.code)) {
|
|
141
|
+
return { state, lines: [chalk.dim(`${frame.code}: ${frame.message}; retrying`)], reconnect: true };
|
|
142
|
+
}
|
|
143
|
+
const message = frame.code === 'forbidden_tier'
|
|
144
|
+
? `earnings-calls.live needs the PRO plan (${frame.message})`
|
|
145
|
+
: `${frame.code}: ${frame.message}`;
|
|
146
|
+
return { state, lines: [], end: { code: 1, message: FATAL_ERRORS.has(frame.code) ? message : `${message} (unknown error code)` } };
|
|
147
|
+
}
|
|
148
|
+
default:
|
|
149
|
+
return { state, lines: [] };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** Frames of the earnings channel (the socket also carries `new_filing` broadcasts and pings). */
|
|
153
|
+
export function isEarningsFrame(frame) {
|
|
154
|
+
return frame.type === 'error' || frame.type === 'unsubscribed' || typeof frame.subscription_id === 'string';
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=earnings-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"earnings-live.js","sourceRoot":"","sources":["../../../src/client/earnings-live.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,8 +10,9 @@ export async function fetchAllPages(initialData, extractNextUrl, mergeResults) {
|
|
|
10
10
|
try {
|
|
11
11
|
// nextUrl is absolute, extract path+query
|
|
12
12
|
const url = new URL(nextUrl);
|
|
13
|
+
// Repeated keys (`status=a&status=b`) stay repeated.
|
|
13
14
|
const params = {};
|
|
14
|
-
url.searchParams.forEach((v, k) => { params[k]
|
|
15
|
+
url.searchParams.forEach((v, k) => { (params[k] ??= []).push(v); });
|
|
15
16
|
const pageData = await apiGet({ path: url.pathname, params, silent: true });
|
|
16
17
|
result = mergeResults(result, pageData);
|
|
17
18
|
nextUrl = extractNextUrl(pageData);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../src/client/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,WAAc,EACd,cAAmC,EACnC,YAA4C;IAE5C,IAAI,MAAM,GAAG,WAAW,CAAC;IACzB,IAAI,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,OAAO,OAAO,EAAE,CAAC;QACf,IAAI,EAAE,CAAC;QACP,MAAM,OAAO,GAAG,aAAa,CAAC,iBAAiB,IAAI,KAAK,CAAC,CAAC;QAC1D,IAAI,CAAC;YACH,0CAA0C;YAC1C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YAC7B,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../src/client/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,WAAc,EACd,cAAmC,EACnC,YAA4C;IAE5C,IAAI,MAAM,GAAG,WAAW,CAAC;IACzB,IAAI,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,OAAO,OAAO,EAAE,CAAC;QACf,IAAI,EAAE,CAAC;QACP,MAAM,OAAO,GAAG,aAAa,CAAC,iBAAiB,IAAI,KAAK,CAAC,CAAC;QAC1D,IAAI,CAAC;YACH,0CAA0C;YAC1C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YAC7B,qDAAqD;YACrD,MAAM,MAAM,GAA6B,EAAE,CAAC;YAC5C,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAI,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/E,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACxC,OAAO,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YACnC,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC;YACpC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { type LiveTarget } from './earnings-live.js';
|
|
2
|
+
export interface EarningsListenOptions {
|
|
3
|
+
target: LiveTarget;
|
|
4
|
+
sinceSeq: number;
|
|
5
|
+
partials: boolean;
|
|
6
|
+
names: boolean;
|
|
7
|
+
/** NDJSON: every earnings frame as one line, nothing else on stdout. */
|
|
8
|
+
json: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function connectWebSocket(opts?: {
|
|
11
|
+
earnings?: EarningsListenOptions;
|
|
12
|
+
}): Promise<void>;
|