@cyanheads/secedgar-mcp-server 0.7.0 → 0.7.2
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 +4 -0
- package/dist/config/server-config.d.ts +4 -0
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +22 -0
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +37 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-frames.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-frames.tool.js +2 -0
- package/dist/mcp-server/tools/definitions/fetch-frames.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-financials.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-financials.tool.js +2 -0
- package/dist/mcp-server/tools/definitions/get-financials.tool.js.map +1 -1
- package/dist/services/edgar/edgar-api-service.d.ts +27 -2
- package/dist/services/edgar/edgar-api-service.d.ts.map +1 -1
- package/dist/services/edgar/edgar-api-service.js +62 -10
- package/dist/services/edgar/edgar-api-service.js.map +1 -1
- package/dist/services/edgar/mirror/companyfacts-sync.d.ts +34 -0
- package/dist/services/edgar/mirror/companyfacts-sync.d.ts.map +1 -0
- package/dist/services/edgar/mirror/companyfacts-sync.js +157 -0
- package/dist/services/edgar/mirror/companyfacts-sync.js.map +1 -0
- package/dist/services/edgar/mirror/edgar-mirror.d.ts +71 -0
- package/dist/services/edgar/mirror/edgar-mirror.d.ts.map +1 -0
- package/dist/services/edgar/mirror/edgar-mirror.js +190 -0
- package/dist/services/edgar/mirror/edgar-mirror.js.map +1 -0
- package/dist/services/edgar/mirror/index.d.ts +15 -0
- package/dist/services/edgar/mirror/index.d.ts.map +1 -0
- package/dist/services/edgar/mirror/index.js +21 -0
- package/dist/services/edgar/mirror/index.js.map +1 -0
- package/dist/services/edgar/mirror/tickers-sync.d.ts +17 -0
- package/dist/services/edgar/mirror/tickers-sync.d.ts.map +1 -0
- package/dist/services/edgar/mirror/tickers-sync.js +43 -0
- package/dist/services/edgar/mirror/tickers-sync.js.map +1 -0
- package/dist/services/edgar/mirror/types.d.ts +56 -0
- package/dist/services/edgar/mirror/types.d.ts.map +1 -0
- package/dist/services/edgar/mirror/types.js +30 -0
- package/dist/services/edgar/mirror/types.js.map +1 -0
- package/package.json +9 -3
- package/server.json +3 -3
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Ingester for the XBRL company-facts layer. Streams SEC's
|
|
3
|
+
* `companyfacts.zip` (~1.3 GB) through fflate, parsing each `CIK*.json` entry
|
|
4
|
+
* into one row per (cik, taxonomy, tag) with the concept's `units` map stored as
|
|
5
|
+
* a JSON blob. Bounded memory: one entry is buffered at a time and rows drain to
|
|
6
|
+
* the framework in batched pages. Upsert-only — a company dropped from the bulk
|
|
7
|
+
* archive lingers (low-harm; re-upserted whenever it reappears).
|
|
8
|
+
* @module services/edgar/mirror/companyfacts-sync
|
|
9
|
+
*/
|
|
10
|
+
import { serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
|
|
11
|
+
import { Unzip, UnzipInflate } from 'fflate';
|
|
12
|
+
import { COMPANY_FACTS_ZIP_URL, lastModifiedToIso } from './types.js';
|
|
13
|
+
/** Rows drained to the framework per page (one transaction each). */
|
|
14
|
+
const BATCH_ROWS = 2000;
|
|
15
|
+
const EMPTY = new Uint8Array(0);
|
|
16
|
+
/** Expand one company's `facts` into per-(taxonomy, tag) rows. Exported for tests. */
|
|
17
|
+
export function fileToRows(json) {
|
|
18
|
+
const rows = [];
|
|
19
|
+
if (typeof json.cik !== 'number' || !json.facts)
|
|
20
|
+
return rows;
|
|
21
|
+
const cik = String(json.cik).padStart(10, '0');
|
|
22
|
+
const entityName = json.entityName ?? '';
|
|
23
|
+
for (const [taxonomy, tags] of Object.entries(json.facts)) {
|
|
24
|
+
for (const [tag, concept] of Object.entries(tags)) {
|
|
25
|
+
if (!concept?.units)
|
|
26
|
+
continue;
|
|
27
|
+
rows.push({
|
|
28
|
+
id: `${cik}|${taxonomy}|${tag}`,
|
|
29
|
+
cik,
|
|
30
|
+
taxonomy,
|
|
31
|
+
tag,
|
|
32
|
+
entity_name: entityName,
|
|
33
|
+
label: concept.label ?? tag,
|
|
34
|
+
description: concept.description ?? null,
|
|
35
|
+
units_json: JSON.stringify(concept.units),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return rows;
|
|
40
|
+
}
|
|
41
|
+
/** HEAD the bulk archive for its `Last-Modified`, normalized to ISO. Best-effort. */
|
|
42
|
+
async function headLastModifiedIso(userAgent, signal) {
|
|
43
|
+
try {
|
|
44
|
+
const res = await fetch(COMPANY_FACTS_ZIP_URL, {
|
|
45
|
+
method: 'HEAD',
|
|
46
|
+
headers: { 'User-Agent': userAgent },
|
|
47
|
+
signal,
|
|
48
|
+
});
|
|
49
|
+
const lm = res.headers.get('last-modified');
|
|
50
|
+
return lm ? lastModifiedToIso(lm) : undefined;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build the company-facts ingester. On `refresh`, a HEAD check short-circuits
|
|
58
|
+
* when the archive has not been rebuilt since the stored checkpoint. The bulk
|
|
59
|
+
* archive is a full nightly snapshot, so a sync re-streams it whole and relies
|
|
60
|
+
* on idempotent upserts; the framework persists each page transactionally, so an
|
|
61
|
+
* interrupted run is crash-safe (a resume re-applies harmlessly).
|
|
62
|
+
*/
|
|
63
|
+
export function makeCompanyFactsSync(opts) {
|
|
64
|
+
return async function* companyFactsSync(ctx) {
|
|
65
|
+
const lastModified = await headLastModifiedIso(opts.userAgent, ctx.signal);
|
|
66
|
+
if (ctx.mode === 'refresh' &&
|
|
67
|
+
ctx.checkpoint &&
|
|
68
|
+
lastModified &&
|
|
69
|
+
lastModified <= ctx.checkpoint) {
|
|
70
|
+
opts.log?.info?.('companyfacts.zip unchanged since last sync; skipping', {
|
|
71
|
+
checkpoint: ctx.checkpoint,
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const response = await fetch(COMPANY_FACTS_ZIP_URL, {
|
|
76
|
+
headers: { 'User-Agent': opts.userAgent },
|
|
77
|
+
signal: ctx.signal,
|
|
78
|
+
});
|
|
79
|
+
if (!response.ok || !response.body) {
|
|
80
|
+
throw serviceUnavailable(`SEC companyfacts.zip download failed (HTTP ${response.status})`, {
|
|
81
|
+
url: COMPANY_FACTS_ZIP_URL,
|
|
82
|
+
status: response.status,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const checkpoint = lastModifiedToIso(response.headers.get('last-modified')) || lastModified;
|
|
86
|
+
const pending = [];
|
|
87
|
+
let completedFiles = 0;
|
|
88
|
+
let skipped = 0;
|
|
89
|
+
let streamError;
|
|
90
|
+
const unzip = new Unzip();
|
|
91
|
+
unzip.register(UnzipInflate);
|
|
92
|
+
unzip.onfile = (file) => {
|
|
93
|
+
const isCik = /CIK\d+\.json$/i.test(file.name);
|
|
94
|
+
const chunks = [];
|
|
95
|
+
file.ondata = (err, chunk, final) => {
|
|
96
|
+
if (err) {
|
|
97
|
+
streamError ??= err;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!isCik)
|
|
101
|
+
return;
|
|
102
|
+
if (chunk?.length)
|
|
103
|
+
chunks.push(chunk);
|
|
104
|
+
if (!final)
|
|
105
|
+
return;
|
|
106
|
+
try {
|
|
107
|
+
const json = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
108
|
+
const rows = fileToRows(json);
|
|
109
|
+
if (rows.length)
|
|
110
|
+
pending.push(...rows);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
skipped += 1;
|
|
114
|
+
opts.log?.warning?.('Skipping unparseable companyfacts entry', { name: file.name });
|
|
115
|
+
}
|
|
116
|
+
completedFiles += 1;
|
|
117
|
+
chunks.length = 0;
|
|
118
|
+
};
|
|
119
|
+
file.start();
|
|
120
|
+
};
|
|
121
|
+
const reader = response.body.getReader();
|
|
122
|
+
try {
|
|
123
|
+
for (;;) {
|
|
124
|
+
if (ctx.signal.aborted) {
|
|
125
|
+
throw ctx.signal.reason instanceof Error
|
|
126
|
+
? ctx.signal.reason
|
|
127
|
+
: new Error('companyfacts sync aborted');
|
|
128
|
+
}
|
|
129
|
+
const { done, value } = await reader.read();
|
|
130
|
+
if (done)
|
|
131
|
+
break;
|
|
132
|
+
unzip.push(value, false);
|
|
133
|
+
if (streamError)
|
|
134
|
+
throw streamError;
|
|
135
|
+
while (pending.length >= BATCH_ROWS) {
|
|
136
|
+
yield {
|
|
137
|
+
records: pending.splice(0, BATCH_ROWS),
|
|
138
|
+
cursor: String(completedFiles),
|
|
139
|
+
checkpoint,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
unzip.push(EMPTY, true);
|
|
144
|
+
if (streamError)
|
|
145
|
+
throw streamError;
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
reader.releaseLock();
|
|
149
|
+
}
|
|
150
|
+
if (skipped > 0)
|
|
151
|
+
opts.log?.notice?.('companyfacts sync complete with skips', { completedFiles, skipped });
|
|
152
|
+
while (pending.length) {
|
|
153
|
+
yield { records: pending.splice(0, BATCH_ROWS), cursor: String(completedFiles), checkpoint };
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=companyfacts-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companyfacts-sync.js","sourceRoot":"","sources":["../../../../src/services/edgar/mirror/companyfacts-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `EdgarMirror` — owns the two framework `Mirror` instances (the
|
|
3
|
+
* ticker/CIK layer and the XBRL company-facts layer) and the read helpers that
|
|
4
|
+
* reconstruct the live API's `companyconcept` and `frames` response shapes off
|
|
5
|
+
* the local SQLite stores. The service routes through these when the mirror is
|
|
6
|
+
* ready; callers gate on `tickersReady()` / `companyFactsReady()`.
|
|
7
|
+
* @module services/edgar/mirror/edgar-mirror
|
|
8
|
+
*/
|
|
9
|
+
import { type Mirror, type MirrorLogger, type SyncProgress, type SyncResult } from '@cyanheads/mcp-ts-core/mirror';
|
|
10
|
+
import type { CompanyConceptResponse, FramesResponse } from '../types.js';
|
|
11
|
+
import { type TickerRow } from './types.js';
|
|
12
|
+
export interface EdgarMirrorOptions {
|
|
13
|
+
/** Directory holding the SQLite databases (`EDGAR_MIRROR_PATH`). */
|
|
14
|
+
dir: string;
|
|
15
|
+
/** Logger for ingester warnings (per-file skips, refresh no-ops). */
|
|
16
|
+
log?: MirrorLogger;
|
|
17
|
+
/** SEC User-Agent for the bulk downloads. */
|
|
18
|
+
userAgent: string;
|
|
19
|
+
}
|
|
20
|
+
type MirrorLayer = 'tickers' | 'companyfacts';
|
|
21
|
+
export interface MirrorRunArgs {
|
|
22
|
+
onProgress?: (layer: MirrorLayer, info: Parameters<SyncProgress>[0]) => void;
|
|
23
|
+
signal: AbortSignal;
|
|
24
|
+
}
|
|
25
|
+
export declare class EdgarMirror {
|
|
26
|
+
readonly tickers: Mirror;
|
|
27
|
+
readonly companyFacts: Mirror;
|
|
28
|
+
private _tickersReady;
|
|
29
|
+
private _companyFactsReady;
|
|
30
|
+
constructor(opts: EdgarMirrorOptions);
|
|
31
|
+
/** Memoized readiness — the durable completion marker only flips false→true. */
|
|
32
|
+
tickersReady(): Promise<boolean>;
|
|
33
|
+
companyFactsReady(): Promise<boolean>;
|
|
34
|
+
/** All ticker rows, for rebuilding the in-memory CIK index. Assumes the layer is ready. */
|
|
35
|
+
getTickerRows(): Promise<TickerRow[]>;
|
|
36
|
+
/**
|
|
37
|
+
* One company's full concept series in `companyconcept` API shape, or null when
|
|
38
|
+
* the mirror has no row for this (cik, taxonomy, tag). Assumes the layer is ready.
|
|
39
|
+
*/
|
|
40
|
+
getCompanyConcept(cik: string, taxonomy: string, tag: string): Promise<CompanyConceptResponse | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Cross-company frame in `frames` API shape, assembled by scanning every company
|
|
43
|
+
* reporting (taxonomy, tag) and extracting the period's frame-aligned value.
|
|
44
|
+
* Returns null when no company reports the combination. Assumes the layer is ready.
|
|
45
|
+
*
|
|
46
|
+
* `unit` arrives in the dashed wire form the tool uses (`USD-per-shares`); the
|
|
47
|
+
* `units` map is keyed by the slashed form (`USD/shares`). `loc` (business
|
|
48
|
+
* location) is absent — companyfacts carries no location; the live frames API
|
|
49
|
+
* adds it. The tool treats an empty `loc` as absent.
|
|
50
|
+
*/
|
|
51
|
+
getFrames(taxonomy: string, tag: string, unit: string, period: string): Promise<FramesResponse | null>;
|
|
52
|
+
/** Full init (bootstrap) of both layers — tickers first (fast), then company-facts. */
|
|
53
|
+
runInit(args: MirrorRunArgs): Promise<{
|
|
54
|
+
tickers: SyncResult;
|
|
55
|
+
companyFacts: SyncResult;
|
|
56
|
+
}>;
|
|
57
|
+
/** Incremental refresh of both layers. */
|
|
58
|
+
runRefresh(args: MirrorRunArgs): Promise<{
|
|
59
|
+
tickers: SyncResult;
|
|
60
|
+
companyFacts: SyncResult;
|
|
61
|
+
}>;
|
|
62
|
+
private runBothLayers;
|
|
63
|
+
/** Combined status of both layers, for the verify script and operability checks. */
|
|
64
|
+
status(): Promise<{
|
|
65
|
+
tickers: import("@cyanheads/mcp-ts-core/mirror").MirrorStatus;
|
|
66
|
+
companyFacts: import("@cyanheads/mcp-ts-core/mirror").MirrorStatus;
|
|
67
|
+
}>;
|
|
68
|
+
close(): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=edgar-mirror.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edgar-mirror.d.ts","sourceRoot":"","sources":["../../../../src/services/edgar/mirror/edgar-mirror.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,YAAY,EAEjB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACV,sBAAsB,EAGtB,cAAc,EACf,MAAM,aAAa,CAAC;AAGrB,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,WAAW,GAAG,SAAS,GAAG,cAAc,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC7E,MAAM,EAAE,WAAW,CAAC;CACrB;AAWD,qBAAa,WAAW;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,kBAAkB,CAAS;gBAEvB,IAAI,EAAE,kBAAkB;IAuCpC,gFAAgF;IAC1E,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAKhC,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAK3C,2FAA2F;IACrF,aAAa,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAK3C;;;OAGG;IACG,iBAAiB,CACrB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC;IAgBzC;;;;;;;;;OASG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAoDjC,uFAAuF;IACvF,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,UAAU,CAAA;KAAE,CAAC;IAIxF,0CAA0C;IAC1C,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,UAAU,CAAA;KAAE,CAAC;YAI7E,aAAa;IAiB3B,oFAAoF;IAC9E,MAAM;;;;IAON,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `EdgarMirror` — owns the two framework `Mirror` instances (the
|
|
3
|
+
* ticker/CIK layer and the XBRL company-facts layer) and the read helpers that
|
|
4
|
+
* reconstruct the live API's `companyconcept` and `frames` response shapes off
|
|
5
|
+
* the local SQLite stores. The service routes through these when the mirror is
|
|
6
|
+
* ready; callers gate on `tickersReady()` / `companyFactsReady()`.
|
|
7
|
+
* @module services/edgar/mirror/edgar-mirror
|
|
8
|
+
*/
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { defineMirror, sqliteMirrorStore, } from '@cyanheads/mcp-ts-core/mirror';
|
|
11
|
+
import { makeCompanyFactsSync } from './companyfacts-sync.js';
|
|
12
|
+
import { makeTickersSync } from './tickers-sync.js';
|
|
13
|
+
import { COMPANY_CONCEPTS_TABLE, COMPANY_FACTS_DB_FILE, TICKERS_DB_FILE, TICKERS_TABLE, } from './types.js';
|
|
14
|
+
export class EdgarMirror {
|
|
15
|
+
tickers;
|
|
16
|
+
companyFacts;
|
|
17
|
+
_tickersReady = false;
|
|
18
|
+
_companyFactsReady = false;
|
|
19
|
+
constructor(opts) {
|
|
20
|
+
this.tickers = defineMirror({
|
|
21
|
+
name: 'edgar-tickers',
|
|
22
|
+
store: sqliteMirrorStore({
|
|
23
|
+
path: join(opts.dir, TICKERS_DB_FILE),
|
|
24
|
+
table: TICKERS_TABLE,
|
|
25
|
+
primaryKey: 'ticker',
|
|
26
|
+
columns: { ticker: 'TEXT', cik: 'TEXT', name: 'TEXT' },
|
|
27
|
+
indexes: [{ columns: ['cik'] }],
|
|
28
|
+
}),
|
|
29
|
+
sync: makeTickersSync({ userAgent: opts.userAgent }),
|
|
30
|
+
...(opts.log ? { logger: opts.log } : {}),
|
|
31
|
+
});
|
|
32
|
+
this.companyFacts = defineMirror({
|
|
33
|
+
name: 'edgar-companyfacts',
|
|
34
|
+
store: sqliteMirrorStore({
|
|
35
|
+
path: join(opts.dir, COMPANY_FACTS_DB_FILE),
|
|
36
|
+
table: COMPANY_CONCEPTS_TABLE,
|
|
37
|
+
primaryKey: 'id',
|
|
38
|
+
columns: {
|
|
39
|
+
id: 'TEXT',
|
|
40
|
+
cik: 'TEXT',
|
|
41
|
+
taxonomy: 'TEXT',
|
|
42
|
+
tag: 'TEXT',
|
|
43
|
+
entity_name: 'TEXT',
|
|
44
|
+
label: 'TEXT',
|
|
45
|
+
description: 'TEXT',
|
|
46
|
+
units_json: 'TEXT',
|
|
47
|
+
},
|
|
48
|
+
indexes: [{ columns: ['taxonomy', 'tag'] }],
|
|
49
|
+
}),
|
|
50
|
+
sync: makeCompanyFactsSync({
|
|
51
|
+
userAgent: opts.userAgent,
|
|
52
|
+
...(opts.log ? { log: opts.log } : {}),
|
|
53
|
+
}),
|
|
54
|
+
...(opts.log ? { logger: opts.log } : {}),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Memoized readiness — the durable completion marker only flips false→true. */
|
|
58
|
+
async tickersReady() {
|
|
59
|
+
if (!this._tickersReady)
|
|
60
|
+
this._tickersReady = await this.tickers.ready();
|
|
61
|
+
return this._tickersReady;
|
|
62
|
+
}
|
|
63
|
+
async companyFactsReady() {
|
|
64
|
+
if (!this._companyFactsReady)
|
|
65
|
+
this._companyFactsReady = await this.companyFacts.ready();
|
|
66
|
+
return this._companyFactsReady;
|
|
67
|
+
}
|
|
68
|
+
/** All ticker rows, for rebuilding the in-memory CIK index. Assumes the layer is ready. */
|
|
69
|
+
async getTickerRows() {
|
|
70
|
+
const handle = await this.tickers.raw();
|
|
71
|
+
return handle.prepare(`SELECT ticker, cik, name FROM ${TICKERS_TABLE}`).all();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* One company's full concept series in `companyconcept` API shape, or null when
|
|
75
|
+
* the mirror has no row for this (cik, taxonomy, tag). Assumes the layer is ready.
|
|
76
|
+
*/
|
|
77
|
+
async getCompanyConcept(cik, taxonomy, tag) {
|
|
78
|
+
const id = `${cik.padStart(10, '0')}|${taxonomy}|${tag}`;
|
|
79
|
+
const [row] = await this.companyFacts.getByIds([id]);
|
|
80
|
+
if (!row)
|
|
81
|
+
return null;
|
|
82
|
+
const description = row.description == null ? undefined : String(row.description);
|
|
83
|
+
return {
|
|
84
|
+
cik: Number(row.cik),
|
|
85
|
+
entityName: String(row.entity_name ?? ''),
|
|
86
|
+
taxonomy: String(row.taxonomy ?? taxonomy),
|
|
87
|
+
tag: String(row.tag ?? tag),
|
|
88
|
+
label: String(row.label ?? tag),
|
|
89
|
+
units: JSON.parse(String(row.units_json ?? '{}')),
|
|
90
|
+
...(description !== undefined ? { description } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Cross-company frame in `frames` API shape, assembled by scanning every company
|
|
95
|
+
* reporting (taxonomy, tag) and extracting the period's frame-aligned value.
|
|
96
|
+
* Returns null when no company reports the combination. Assumes the layer is ready.
|
|
97
|
+
*
|
|
98
|
+
* `unit` arrives in the dashed wire form the tool uses (`USD-per-shares`); the
|
|
99
|
+
* `units` map is keyed by the slashed form (`USD/shares`). `loc` (business
|
|
100
|
+
* location) is absent — companyfacts carries no location; the live frames API
|
|
101
|
+
* adds it. The tool treats an empty `loc` as absent.
|
|
102
|
+
*/
|
|
103
|
+
async getFrames(taxonomy, tag, unit, period) {
|
|
104
|
+
const unitKey = unit.replace('-per-', '/');
|
|
105
|
+
const handle = await this.companyFacts.raw();
|
|
106
|
+
const rows = handle
|
|
107
|
+
.prepare(`SELECT cik, entity_name, label, description, units_json FROM ${COMPANY_CONCEPTS_TABLE} WHERE taxonomy = ? AND tag = ?`)
|
|
108
|
+
.all(taxonomy, tag);
|
|
109
|
+
if (rows.length === 0)
|
|
110
|
+
return null;
|
|
111
|
+
const data = [];
|
|
112
|
+
let label = tag;
|
|
113
|
+
let description;
|
|
114
|
+
for (const row of rows) {
|
|
115
|
+
const units = JSON.parse(row.units_json);
|
|
116
|
+
const series = units[unitKey];
|
|
117
|
+
if (!series)
|
|
118
|
+
continue;
|
|
119
|
+
// The frame members are the datapoints whose `frame` equals the period; if a
|
|
120
|
+
// value was re-filed, the latest filing wins (matches get_financials dedup).
|
|
121
|
+
let best;
|
|
122
|
+
for (const u of series) {
|
|
123
|
+
if (u.frame !== period)
|
|
124
|
+
continue;
|
|
125
|
+
if (!best || u.filed > best.filed)
|
|
126
|
+
best = u;
|
|
127
|
+
}
|
|
128
|
+
if (!best)
|
|
129
|
+
continue;
|
|
130
|
+
if (label === tag && row.label) {
|
|
131
|
+
label = row.label;
|
|
132
|
+
description = row.description ?? undefined;
|
|
133
|
+
}
|
|
134
|
+
data.push({
|
|
135
|
+
accn: best.accn,
|
|
136
|
+
cik: Number(row.cik),
|
|
137
|
+
end: best.end,
|
|
138
|
+
entityName: row.entity_name,
|
|
139
|
+
loc: '',
|
|
140
|
+
...(best.start !== undefined ? { start: best.start } : {}),
|
|
141
|
+
val: best.val,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (data.length === 0)
|
|
145
|
+
return null;
|
|
146
|
+
return {
|
|
147
|
+
ccp: period,
|
|
148
|
+
data,
|
|
149
|
+
label,
|
|
150
|
+
pts: data.length,
|
|
151
|
+
tag,
|
|
152
|
+
taxonomy,
|
|
153
|
+
uom: unit,
|
|
154
|
+
...(description !== undefined ? { description } : {}),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/** Full init (bootstrap) of both layers — tickers first (fast), then company-facts. */
|
|
158
|
+
runInit(args) {
|
|
159
|
+
return this.runBothLayers('init', args);
|
|
160
|
+
}
|
|
161
|
+
/** Incremental refresh of both layers. */
|
|
162
|
+
runRefresh(args) {
|
|
163
|
+
return this.runBothLayers('refresh', args);
|
|
164
|
+
}
|
|
165
|
+
async runBothLayers(mode, args) {
|
|
166
|
+
const tickers = await this.tickers.runSync({
|
|
167
|
+
mode,
|
|
168
|
+
signal: args.signal,
|
|
169
|
+
...(args.onProgress ? { onProgress: (i) => args.onProgress?.('tickers', i) } : {}),
|
|
170
|
+
});
|
|
171
|
+
const companyFacts = await this.companyFacts.runSync({
|
|
172
|
+
mode,
|
|
173
|
+
signal: args.signal,
|
|
174
|
+
...(args.onProgress ? { onProgress: (i) => args.onProgress?.('companyfacts', i) } : {}),
|
|
175
|
+
});
|
|
176
|
+
return { tickers, companyFacts };
|
|
177
|
+
}
|
|
178
|
+
/** Combined status of both layers, for the verify script and operability checks. */
|
|
179
|
+
async status() {
|
|
180
|
+
return {
|
|
181
|
+
tickers: await this.tickers.status(),
|
|
182
|
+
companyFacts: await this.companyFacts.status(),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
async close() {
|
|
186
|
+
await this.tickers.close();
|
|
187
|
+
await this.companyFacts.close();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=edgar-mirror.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edgar-mirror.js","sourceRoot":"","sources":["../../../../src/services/edgar/mirror/edgar-mirror.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public barrel and server-side singleton for the EDGAR local
|
|
3
|
+
* mirror. The singleton is constructed in `setup()` only when the mirror is
|
|
4
|
+
* enabled and the runtime supports it (Node/Bun, not Workers); `getEdgarMirror()`
|
|
5
|
+
* returns `undefined` otherwise and the service stays on the live API.
|
|
6
|
+
* @module services/edgar/mirror
|
|
7
|
+
*/
|
|
8
|
+
import { EdgarMirror, type EdgarMirrorOptions } from './edgar-mirror.js';
|
|
9
|
+
export { EdgarMirror, type EdgarMirrorOptions, type MirrorRunArgs } from './edgar-mirror.js';
|
|
10
|
+
export * from './types.js';
|
|
11
|
+
/** Construct and register the server-side mirror singleton. */
|
|
12
|
+
export declare function initEdgarMirror(opts: EdgarMirrorOptions): EdgarMirror;
|
|
13
|
+
/** The registered mirror singleton, or `undefined` when the mirror is disabled. */
|
|
14
|
+
export declare function getEdgarMirror(): EdgarMirror | undefined;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/services/edgar/mirror/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC7F,cAAc,YAAY,CAAC;AAI3B,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,WAAW,CAGrE;AAED,mFAAmF;AACnF,wBAAgB,cAAc,IAAI,WAAW,GAAG,SAAS,CAExD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public barrel and server-side singleton for the EDGAR local
|
|
3
|
+
* mirror. The singleton is constructed in `setup()` only when the mirror is
|
|
4
|
+
* enabled and the runtime supports it (Node/Bun, not Workers); `getEdgarMirror()`
|
|
5
|
+
* returns `undefined` otherwise and the service stays on the live API.
|
|
6
|
+
* @module services/edgar/mirror
|
|
7
|
+
*/
|
|
8
|
+
import { EdgarMirror } from './edgar-mirror.js';
|
|
9
|
+
export { EdgarMirror } from './edgar-mirror.js';
|
|
10
|
+
export * from './types.js';
|
|
11
|
+
let _mirror;
|
|
12
|
+
/** Construct and register the server-side mirror singleton. */
|
|
13
|
+
export function initEdgarMirror(opts) {
|
|
14
|
+
_mirror = new EdgarMirror(opts);
|
|
15
|
+
return _mirror;
|
|
16
|
+
}
|
|
17
|
+
/** The registered mirror singleton, or `undefined` when the mirror is disabled. */
|
|
18
|
+
export function getEdgarMirror() {
|
|
19
|
+
return _mirror;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/services/edgar/mirror/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,WAAW,EAA+C,MAAM,mBAAmB,CAAC;AAC7F,cAAc,YAAY,CAAC;AAE3B,IAAI,OAAgC,CAAC;AAErC,+DAA+D;AAC/D,MAAM,UAAU,eAAe,CAAC,IAAwB;IACtD,OAAO,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Ingester for the ticker/CIK layer. Downloads SEC's
|
|
3
|
+
* `company_tickers.json` (small direct-download JSON) and yields one page of
|
|
4
|
+
* rows. Upsert-only: the directory rarely drops entries and CIKs are permanent,
|
|
5
|
+
* so a delisted ticker lingering with its historical CIK is low-harm.
|
|
6
|
+
* @module services/edgar/mirror/tickers-sync
|
|
7
|
+
*/
|
|
8
|
+
import type { SyncGenerator } from '@cyanheads/mcp-ts-core/mirror';
|
|
9
|
+
/**
|
|
10
|
+
* Build the ticker-layer ingester. The returned generator downloads the full
|
|
11
|
+
* directory and yields it as a single page; the file is tiny, so refresh simply
|
|
12
|
+
* re-downloads and re-upserts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function makeTickersSync(opts: {
|
|
15
|
+
userAgent: string;
|
|
16
|
+
}): SyncGenerator;
|
|
17
|
+
//# sourceMappingURL=tickers-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tickers-sync.d.ts","sourceRoot":"","sources":["../../../../src/services/edgar/mirror/tickers-sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAGV,aAAa,EAEd,MAAM,+BAA+B,CAAC;AAUvC;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CA+B1E"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Ingester for the ticker/CIK layer. Downloads SEC's
|
|
3
|
+
* `company_tickers.json` (small direct-download JSON) and yields one page of
|
|
4
|
+
* rows. Upsert-only: the directory rarely drops entries and CIKs are permanent,
|
|
5
|
+
* so a delisted ticker lingering with its historical CIK is low-harm.
|
|
6
|
+
* @module services/edgar/mirror/tickers-sync
|
|
7
|
+
*/
|
|
8
|
+
import { serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
|
|
9
|
+
import { lastModifiedToIso, TICKERS_URL } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Build the ticker-layer ingester. The returned generator downloads the full
|
|
12
|
+
* directory and yields it as a single page; the file is tiny, so refresh simply
|
|
13
|
+
* re-downloads and re-upserts.
|
|
14
|
+
*/
|
|
15
|
+
export function makeTickersSync(opts) {
|
|
16
|
+
return async function* tickersSync(ctx) {
|
|
17
|
+
const response = await fetch(TICKERS_URL, {
|
|
18
|
+
headers: { 'User-Agent': opts.userAgent, Accept: 'application/json' },
|
|
19
|
+
signal: ctx.signal,
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw serviceUnavailable(`SEC company_tickers.json download failed (HTTP ${response.status})`, {
|
|
23
|
+
url: TICKERS_URL,
|
|
24
|
+
status: response.status,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const raw = (await response.json());
|
|
28
|
+
const records = [];
|
|
29
|
+
for (const entry of Object.values(raw)) {
|
|
30
|
+
if (!entry?.ticker)
|
|
31
|
+
continue;
|
|
32
|
+
records.push({
|
|
33
|
+
ticker: entry.ticker.toUpperCase(),
|
|
34
|
+
cik: String(entry.cik_str).padStart(10, '0'),
|
|
35
|
+
name: entry.title ?? '',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// Checkpoint must be lexicographically monotonic — store ISO 8601, not the raw HTTP-date.
|
|
39
|
+
const checkpoint = lastModifiedToIso(response.headers.get('last-modified'));
|
|
40
|
+
yield { records, checkpoint };
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=tickers-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tickers-sync.js","sourceRoot":"","sources":["../../../../src/services/edgar/mirror/tickers-sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAOnE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS5D;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAA2B;IACzD,OAAO,KAAK,SAAS,CAAC,CAAC,WAAW,CAAC,GAAgB;QACjD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,WAAW,EAAE;YACxC,OAAO,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACrE,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,kBAAkB,CACtB,kDAAkD,QAAQ,CAAC,MAAM,GAAG,EACpE;gBACE,GAAG,EAAE,WAAW;gBAChB,MAAM,EAAE,QAAQ,CAAC,MAAM;aACxB,CACF,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAmC,CAAC;QACtE,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,KAAK,EAAE,MAAM;gBAAE,SAAS;YAC7B,OAAO,CAAC,IAAI,CAAC;gBACX,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE;gBAClC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;gBAC5C,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;aACxB,CAAC,CAAC;QACL,CAAC;QAED,0FAA0F;QAC1F,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;QAC5E,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAChC,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Constants and row shapes for the EDGAR local mirror — the two
|
|
3
|
+
* bounded SEC reference layers (ticker/CIK resolution and XBRL company-facts)
|
|
4
|
+
* mirrored into embedded SQLite via the framework `MirrorService`.
|
|
5
|
+
* @module services/edgar/mirror/types
|
|
6
|
+
*/
|
|
7
|
+
/** SEC ticker→CIK directory (small direct-download JSON, ~200 KB). */
|
|
8
|
+
export declare const TICKERS_URL = "https://www.sec.gov/files/company_tickers.json";
|
|
9
|
+
/** SEC bulk XBRL company-facts archive, recompiled nightly (~1.3 GB). */
|
|
10
|
+
export declare const COMPANY_FACTS_ZIP_URL = "https://www.sec.gov/Archives/edgar/daily-index/xbrl/companyfacts.zip";
|
|
11
|
+
/** Primary table for the ticker/CIK layer. */
|
|
12
|
+
export declare const TICKERS_TABLE = "tickers";
|
|
13
|
+
/** Primary table for the XBRL company-facts layer (one row per cik×taxonomy×tag). */
|
|
14
|
+
export declare const COMPANY_CONCEPTS_TABLE = "company_concepts";
|
|
15
|
+
/** SQLite filenames inside the mirror directory (`EDGAR_MIRROR_PATH`). */
|
|
16
|
+
export declare const TICKERS_DB_FILE = "tickers.sqlite";
|
|
17
|
+
export declare const COMPANY_FACTS_DB_FILE = "companyfacts.sqlite";
|
|
18
|
+
/**
|
|
19
|
+
* Convert an HTTP `Last-Modified` value to a lexicographically-monotonic ISO 8601
|
|
20
|
+
* checkpoint string, falling back to the current timestamp when absent or unparseable.
|
|
21
|
+
*/
|
|
22
|
+
export declare function lastModifiedToIso(httpDate: string | null | undefined): string;
|
|
23
|
+
/** One row of the `tickers` table — a single entry from company_tickers.json. */
|
|
24
|
+
export interface TickerRow {
|
|
25
|
+
/** Zero-padded 10-digit CIK. */
|
|
26
|
+
cik: string;
|
|
27
|
+
/** SEC-conformed entity name (the `title` field). */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Uppercased ticker symbol — primary key (e.g. "AAPL", "BRK-A"). */
|
|
30
|
+
ticker: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* One row of the `company_concepts` table — a single (cik, taxonomy, tag) concept
|
|
34
|
+
* from a company's `companyfacts` entry. The full `units` map is stored verbatim
|
|
35
|
+
* as a JSON blob so a point read reconstructs the `companyconcept` API shape and a
|
|
36
|
+
* `taxonomy+tag` scan reconstructs the `frames` API shape, both off one table.
|
|
37
|
+
*/
|
|
38
|
+
export interface CompanyConceptRow {
|
|
39
|
+
/** Zero-padded 10-digit CIK. */
|
|
40
|
+
cik: string;
|
|
41
|
+
/** Taxonomy description; null when the source omits it. */
|
|
42
|
+
description: string | null;
|
|
43
|
+
/** SEC-conformed entity name. */
|
|
44
|
+
entity_name: string;
|
|
45
|
+
/** `${cik}|${taxonomy}|${tag}` — primary key. */
|
|
46
|
+
id: string;
|
|
47
|
+
/** Concept label. */
|
|
48
|
+
label: string;
|
|
49
|
+
/** XBRL tag (e.g. "Revenues"). */
|
|
50
|
+
tag: string;
|
|
51
|
+
/** XBRL taxonomy (e.g. "us-gaap", "ifrs-full", "dei"). */
|
|
52
|
+
taxonomy: string;
|
|
53
|
+
/** `JSON.stringify` of the concept's `units` map (`{ [unit]: CompanyConceptUnit[] }`). */
|
|
54
|
+
units_json: string;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/services/edgar/mirror/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sEAAsE;AACtE,eAAO,MAAM,WAAW,mDAAmD,CAAC;AAE5E,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,yEACsC,CAAC;AAEzE,8CAA8C;AAC9C,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,qFAAqF;AACrF,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD,0EAA0E;AAC1E,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAChD,eAAO,MAAM,qBAAqB,wBAAwB,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAM7E;AAED,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,UAAU,EAAE,MAAM,CAAC;CACpB"}
|