@the-situation/indexer 0.17.0 → 0.18.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 +43 -4
- package/dist/aggregator/cohort.d.ts +30 -0
- package/dist/aggregator/cohort.d.ts.map +1 -0
- package/dist/aggregator/cohort.js +153 -0
- package/dist/aggregator/cohort.js.map +1 -0
- package/dist/aggregator/daily.d.ts +71 -0
- package/dist/aggregator/daily.d.ts.map +1 -0
- package/dist/aggregator/daily.js +249 -0
- package/dist/aggregator/daily.js.map +1 -0
- package/dist/aggregator/domains.d.ts +20 -0
- package/dist/aggregator/domains.d.ts.map +1 -0
- package/dist/aggregator/domains.js +38 -0
- package/dist/aggregator/domains.js.map +1 -0
- package/dist/aggregator/index.d.ts +31 -0
- package/dist/aggregator/index.d.ts.map +1 -0
- package/dist/aggregator/index.js +100 -0
- package/dist/aggregator/index.js.map +1 -0
- package/dist/aggregator/lifetime.d.ts +52 -0
- package/dist/aggregator/lifetime.d.ts.map +1 -0
- package/dist/aggregator/lifetime.js +222 -0
- package/dist/aggregator/lifetime.js.map +1 -0
- package/dist/aggregator/roi.d.ts +42 -0
- package/dist/aggregator/roi.d.ts.map +1 -0
- package/dist/aggregator/roi.js +153 -0
- package/dist/aggregator/roi.js.map +1 -0
- package/dist/aggregator/sources.d.ts +59 -0
- package/dist/aggregator/sources.d.ts.map +1 -0
- package/dist/aggregator/sources.js +53 -0
- package/dist/aggregator/sources.js.map +1 -0
- package/dist/aggregator/writers.d.ts +22 -0
- package/dist/aggregator/writers.d.ts.map +1 -0
- package/dist/aggregator/writers.js +147 -0
- package/dist/aggregator/writers.js.map +1 -0
- package/dist/api/app.d.ts +177 -13
- package/dist/api/app.d.ts.map +1 -1
- package/dist/api/app.js +4 -3
- package/dist/api/app.js.map +1 -1
- package/dist/api/routes/admin-subscriptions.d.ts +11 -11
- package/dist/api/routes/analytics.d.ts +205 -0
- package/dist/api/routes/analytics.d.ts.map +1 -0
- package/dist/api/routes/analytics.js +122 -0
- package/dist/api/routes/analytics.js.map +1 -0
- package/dist/api/routes/health.d.ts.map +1 -1
- package/dist/api/routes/health.js +2 -0
- package/dist/api/routes/health.js.map +1 -1
- package/dist/api/routes/index.d.ts +1 -0
- package/dist/api/routes/index.d.ts.map +1 -1
- package/dist/api/routes/index.js +1 -0
- package/dist/api/routes/index.js.map +1 -1
- package/dist/api/routes/rankings.d.ts +17 -3
- package/dist/api/routes/rankings.d.ts.map +1 -1
- package/dist/api/routes/rankings.js +44 -5
- package/dist/api/routes/rankings.js.map +1 -1
- package/dist/api/routes/trader-stats.d.ts +11 -2
- package/dist/api/routes/trader-stats.d.ts.map +1 -1
- package/dist/api/routes/trader-stats.js +72 -2
- package/dist/api/routes/trader-stats.js.map +1 -1
- package/dist/client/IndexerClient.d.ts +30 -1
- package/dist/client/IndexerClient.d.ts.map +1 -1
- package/dist/client/IndexerClient.js.map +1 -1
- package/dist/client/IndexerClientLive.d.ts.map +1 -1
- package/dist/client/IndexerClientLive.js +50 -1
- package/dist/client/IndexerClientLive.js.map +1 -1
- package/dist/client/convenience.d.ts +9 -2
- package/dist/client/convenience.d.ts.map +1 -1
- package/dist/client/convenience.js +9 -1
- package/dist/client/convenience.js.map +1 -1
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/config.d.ts +17 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +39 -3
- package/dist/config.js.map +1 -1
- package/dist/etl/event-indexer.d.ts +1 -1
- package/dist/etl/lp-position-refresher.d.ts +2 -1
- package/dist/etl/lp-position-refresher.d.ts.map +1 -1
- package/dist/etl/lp-position-refresher.js +24 -11
- package/dist/etl/lp-position-refresher.js.map +1 -1
- package/dist/index.js +64 -8
- package/dist/index.js.map +1 -1
- package/dist/layers/ChainReaderLive.d.ts.map +1 -1
- package/dist/layers/ChainReaderLive.js +15 -0
- package/dist/layers/ChainReaderLive.js.map +1 -1
- package/dist/layers/VoyagerClientLive.d.ts +2 -1
- package/dist/layers/VoyagerClientLive.d.ts.map +1 -1
- package/dist/layers/VoyagerClientLive.js +89 -55
- package/dist/layers/VoyagerClientLive.js.map +1 -1
- package/dist/services/ChainReader.d.ts +10 -0
- package/dist/services/ChainReader.d.ts.map +1 -1
- package/dist/services/ChainReader.js.map +1 -1
- package/dist/services/VoyagerRateLimit.d.ts +11 -8
- package/dist/services/VoyagerRateLimit.d.ts.map +1 -1
- package/dist/services/VoyagerRateLimit.js +51 -26
- package/dist/services/VoyagerRateLimit.js.map +1 -1
- package/dist/types/analytics.d.ts +194 -0
- package/dist/types/analytics.d.ts.map +1 -0
- package/dist/types/analytics.js +10 -0
- package/dist/types/analytics.js.map +1 -0
- package/dist/types/api.d.ts +2 -0
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/warehouse/analytics-helpers.d.ts +36 -0
- package/dist/warehouse/analytics-helpers.d.ts.map +1 -0
- package/dist/warehouse/analytics-helpers.js +142 -0
- package/dist/warehouse/analytics-helpers.js.map +1 -0
- package/dist/warehouse/backfill.d.ts +26 -0
- package/dist/warehouse/backfill.d.ts.map +1 -0
- package/dist/warehouse/backfill.js +77 -0
- package/dist/warehouse/backfill.js.map +1 -0
- package/dist/warehouse/connection.d.ts +18 -0
- package/dist/warehouse/connection.d.ts.map +1 -0
- package/dist/warehouse/connection.js +24 -0
- package/dist/warehouse/connection.js.map +1 -0
- package/dist/warehouse/index.d.ts +14 -0
- package/dist/warehouse/index.d.ts.map +1 -0
- package/dist/warehouse/index.js +14 -0
- package/dist/warehouse/index.js.map +1 -0
- package/dist/warehouse/repositories/analytics.d.ts +61 -0
- package/dist/warehouse/repositories/analytics.d.ts.map +1 -0
- package/dist/warehouse/repositories/analytics.js +418 -0
- package/dist/warehouse/repositories/analytics.js.map +1 -0
- package/dist/warehouse/schema.d.ts +9 -0
- package/dist/warehouse/schema.d.ts.map +1 -0
- package/dist/warehouse/schema.js +219 -0
- package/dist/warehouse/schema.js.map +1 -0
- package/dist/warehouse/seed-domains.d.ts +29 -0
- package/dist/warehouse/seed-domains.d.ts.map +1 -0
- package/dist/warehouse/seed-domains.js +223 -0
- package/dist/warehouse/seed-domains.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
const SCHEMA_DDL = [
|
|
2
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
3
|
+
// Domains — canonical taxonomy
|
|
4
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
5
|
+
`CREATE TABLE IF NOT EXISTS domains (
|
|
6
|
+
slug TEXT PRIMARY KEY,
|
|
7
|
+
name TEXT NOT NULL,
|
|
8
|
+
description TEXT NOT NULL DEFAULT '',
|
|
9
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
10
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
11
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
12
|
+
)`,
|
|
13
|
+
`CREATE TABLE IF NOT EXISTS market_domains (
|
|
14
|
+
market_address TEXT NOT NULL,
|
|
15
|
+
domain_slug TEXT NOT NULL REFERENCES domains(slug) ON DELETE CASCADE,
|
|
16
|
+
is_primary BOOLEAN NOT NULL DEFAULT FALSE,
|
|
17
|
+
source TEXT NOT NULL DEFAULT 'auto',
|
|
18
|
+
assigned_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
19
|
+
PRIMARY KEY (market_address, domain_slug)
|
|
20
|
+
)`,
|
|
21
|
+
`CREATE INDEX IF NOT EXISTS idx_market_domains_domain
|
|
22
|
+
ON market_domains(domain_slug)`,
|
|
23
|
+
`CREATE INDEX IF NOT EXISTS idx_market_domains_market
|
|
24
|
+
ON market_domains(market_address)`,
|
|
25
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_market_domains_one_primary
|
|
26
|
+
ON market_domains(market_address) WHERE is_primary`,
|
|
27
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
28
|
+
// Daily fact tables — date × dimension × metrics
|
|
29
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
30
|
+
`CREATE TABLE IF NOT EXISTS daily_trader_stats (
|
|
31
|
+
date DATE NOT NULL,
|
|
32
|
+
trader TEXT NOT NULL,
|
|
33
|
+
domain_slug TEXT NOT NULL REFERENCES domains(slug),
|
|
34
|
+
trade_count INTEGER NOT NULL DEFAULT 0,
|
|
35
|
+
buy_count INTEGER NOT NULL DEFAULT 0,
|
|
36
|
+
sell_count INTEGER NOT NULL DEFAULT 0,
|
|
37
|
+
volume_collateral NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
38
|
+
realized_pnl NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
39
|
+
unrealized_pnl NUMERIC(38, 6),
|
|
40
|
+
markets_traded INTEGER NOT NULL DEFAULT 0,
|
|
41
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
42
|
+
PRIMARY KEY (date, trader, domain_slug)
|
|
43
|
+
)`,
|
|
44
|
+
`CREATE INDEX IF NOT EXISTS idx_daily_trader_stats_trader
|
|
45
|
+
ON daily_trader_stats(trader, date DESC)`,
|
|
46
|
+
`CREATE INDEX IF NOT EXISTS idx_daily_trader_stats_domain_date
|
|
47
|
+
ON daily_trader_stats(domain_slug, date DESC)`,
|
|
48
|
+
`CREATE TABLE IF NOT EXISTS daily_lp_stats (
|
|
49
|
+
date DATE NOT NULL,
|
|
50
|
+
provider TEXT NOT NULL,
|
|
51
|
+
domain_slug TEXT NOT NULL REFERENCES domains(slug),
|
|
52
|
+
deposit_count INTEGER NOT NULL DEFAULT 0,
|
|
53
|
+
withdraw_count INTEGER NOT NULL DEFAULT 0,
|
|
54
|
+
deposited NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
55
|
+
withdrawn NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
56
|
+
net_position NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
57
|
+
unrealized_pnl NUMERIC(38, 6),
|
|
58
|
+
markets_active INTEGER NOT NULL DEFAULT 0,
|
|
59
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
60
|
+
PRIMARY KEY (date, provider, domain_slug)
|
|
61
|
+
)`,
|
|
62
|
+
`CREATE INDEX IF NOT EXISTS idx_daily_lp_stats_provider
|
|
63
|
+
ON daily_lp_stats(provider, date DESC)`,
|
|
64
|
+
`CREATE INDEX IF NOT EXISTS idx_daily_lp_stats_domain_date
|
|
65
|
+
ON daily_lp_stats(domain_slug, date DESC)`,
|
|
66
|
+
`CREATE TABLE IF NOT EXISTS daily_market_stats (
|
|
67
|
+
date DATE NOT NULL,
|
|
68
|
+
market_address TEXT NOT NULL,
|
|
69
|
+
trade_count INTEGER NOT NULL DEFAULT 0,
|
|
70
|
+
unique_traders INTEGER NOT NULL DEFAULT 0,
|
|
71
|
+
volume_collateral NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
72
|
+
liquidity_added NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
73
|
+
liquidity_removed NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
74
|
+
unique_lps INTEGER NOT NULL DEFAULT 0,
|
|
75
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
76
|
+
PRIMARY KEY (date, market_address)
|
|
77
|
+
)`,
|
|
78
|
+
`CREATE INDEX IF NOT EXISTS idx_daily_market_stats_market
|
|
79
|
+
ON daily_market_stats(market_address, date DESC)`,
|
|
80
|
+
`CREATE TABLE IF NOT EXISTS daily_domain_stats (
|
|
81
|
+
date DATE NOT NULL,
|
|
82
|
+
domain_slug TEXT NOT NULL REFERENCES domains(slug),
|
|
83
|
+
trade_count INTEGER NOT NULL DEFAULT 0,
|
|
84
|
+
unique_traders INTEGER NOT NULL DEFAULT 0,
|
|
85
|
+
unique_lps INTEGER NOT NULL DEFAULT 0,
|
|
86
|
+
volume_collateral NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
87
|
+
liquidity_net NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
88
|
+
active_markets INTEGER NOT NULL DEFAULT 0,
|
|
89
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
90
|
+
PRIMARY KEY (date, domain_slug)
|
|
91
|
+
)`,
|
|
92
|
+
`CREATE INDEX IF NOT EXISTS idx_daily_domain_stats_date
|
|
93
|
+
ON daily_domain_stats(date DESC)`,
|
|
94
|
+
`CREATE TABLE IF NOT EXISTS daily_platform_stats (
|
|
95
|
+
date DATE PRIMARY KEY,
|
|
96
|
+
trade_count INTEGER NOT NULL DEFAULT 0,
|
|
97
|
+
unique_traders INTEGER NOT NULL DEFAULT 0,
|
|
98
|
+
unique_lps INTEGER NOT NULL DEFAULT 0,
|
|
99
|
+
new_traders INTEGER NOT NULL DEFAULT 0,
|
|
100
|
+
new_lps INTEGER NOT NULL DEFAULT 0,
|
|
101
|
+
volume_collateral NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
102
|
+
liquidity_net NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
103
|
+
active_markets INTEGER NOT NULL DEFAULT 0,
|
|
104
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
105
|
+
)`,
|
|
106
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
107
|
+
// Lifetime / CLTV — one row per entity
|
|
108
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
109
|
+
`CREATE TABLE IF NOT EXISTS trader_lifetime (
|
|
110
|
+
trader TEXT PRIMARY KEY,
|
|
111
|
+
first_trade_at TIMESTAMPTZ,
|
|
112
|
+
last_trade_at TIMESTAMPTZ,
|
|
113
|
+
cohort_week DATE,
|
|
114
|
+
total_trades INTEGER NOT NULL DEFAULT 0,
|
|
115
|
+
buy_count INTEGER NOT NULL DEFAULT 0,
|
|
116
|
+
sell_count INTEGER NOT NULL DEFAULT 0,
|
|
117
|
+
markets_traded INTEGER NOT NULL DEFAULT 0,
|
|
118
|
+
domains_traded INTEGER NOT NULL DEFAULT 0,
|
|
119
|
+
domains_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
120
|
+
total_volume NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
121
|
+
total_collateral_at_risk NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
122
|
+
realized_pnl NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
123
|
+
unrealized_pnl NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
124
|
+
total_pnl NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
125
|
+
roi_pct NUMERIC(10, 4),
|
|
126
|
+
active_days INTEGER NOT NULL DEFAULT 0,
|
|
127
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
128
|
+
)`,
|
|
129
|
+
`CREATE INDEX IF NOT EXISTS idx_trader_lifetime_pnl
|
|
130
|
+
ON trader_lifetime(total_pnl DESC)`,
|
|
131
|
+
`CREATE INDEX IF NOT EXISTS idx_trader_lifetime_roi
|
|
132
|
+
ON trader_lifetime(roi_pct DESC NULLS LAST)`,
|
|
133
|
+
`CREATE INDEX IF NOT EXISTS idx_trader_lifetime_cohort
|
|
134
|
+
ON trader_lifetime(cohort_week)`,
|
|
135
|
+
`CREATE INDEX IF NOT EXISTS idx_trader_lifetime_volume
|
|
136
|
+
ON trader_lifetime(total_volume DESC)`,
|
|
137
|
+
`CREATE TABLE IF NOT EXISTS lp_lifetime (
|
|
138
|
+
provider TEXT PRIMARY KEY,
|
|
139
|
+
first_deposit_at TIMESTAMPTZ,
|
|
140
|
+
last_activity_at TIMESTAMPTZ,
|
|
141
|
+
cohort_week DATE,
|
|
142
|
+
deposit_count INTEGER NOT NULL DEFAULT 0,
|
|
143
|
+
withdraw_count INTEGER NOT NULL DEFAULT 0,
|
|
144
|
+
total_deposited NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
145
|
+
total_withdrawn NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
146
|
+
net_position NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
147
|
+
current_value NUMERIC(38, 6),
|
|
148
|
+
unrealized_pnl NUMERIC(38, 6),
|
|
149
|
+
realized_pnl NUMERIC(38, 6) NOT NULL DEFAULT 0,
|
|
150
|
+
markets_provided INTEGER NOT NULL DEFAULT 0,
|
|
151
|
+
domains_provided INTEGER NOT NULL DEFAULT 0,
|
|
152
|
+
domains_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
153
|
+
active_days INTEGER NOT NULL DEFAULT 0,
|
|
154
|
+
roi_pct NUMERIC(10, 4),
|
|
155
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
156
|
+
)`,
|
|
157
|
+
`CREATE INDEX IF NOT EXISTS idx_lp_lifetime_pnl
|
|
158
|
+
ON lp_lifetime(unrealized_pnl DESC)`,
|
|
159
|
+
`CREATE INDEX IF NOT EXISTS idx_lp_lifetime_cohort
|
|
160
|
+
ON lp_lifetime(cohort_week)`,
|
|
161
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
162
|
+
// Cohort retention — week × week_offset × domain
|
|
163
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
164
|
+
`CREATE TABLE IF NOT EXISTS cohort_retention (
|
|
165
|
+
cohort_week DATE NOT NULL,
|
|
166
|
+
week_offset INTEGER NOT NULL,
|
|
167
|
+
domain_slug TEXT NOT NULL,
|
|
168
|
+
entity_type TEXT NOT NULL,
|
|
169
|
+
cohort_size INTEGER NOT NULL,
|
|
170
|
+
retained INTEGER NOT NULL,
|
|
171
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
172
|
+
PRIMARY KEY (cohort_week, week_offset, domain_slug, entity_type)
|
|
173
|
+
)`,
|
|
174
|
+
`CREATE INDEX IF NOT EXISTS idx_cohort_retention_lookup
|
|
175
|
+
ON cohort_retention(domain_slug, entity_type, cohort_week)`,
|
|
176
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
177
|
+
// ROI distribution — bucketed histograms + summary stats
|
|
178
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
179
|
+
`CREATE TABLE IF NOT EXISTS roi_distribution (
|
|
180
|
+
domain_slug TEXT NOT NULL,
|
|
181
|
+
entity_type TEXT NOT NULL,
|
|
182
|
+
bucket_index INTEGER NOT NULL,
|
|
183
|
+
bucket_lower_pct NUMERIC(10, 4) NOT NULL,
|
|
184
|
+
bucket_upper_pct NUMERIC(10, 4) NOT NULL,
|
|
185
|
+
user_count INTEGER NOT NULL DEFAULT 0,
|
|
186
|
+
computed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
187
|
+
PRIMARY KEY (domain_slug, entity_type, bucket_index)
|
|
188
|
+
)`,
|
|
189
|
+
`CREATE TABLE IF NOT EXISTS roi_summary (
|
|
190
|
+
domain_slug TEXT NOT NULL,
|
|
191
|
+
entity_type TEXT NOT NULL,
|
|
192
|
+
total_users INTEGER NOT NULL DEFAULT 0,
|
|
193
|
+
positive_roi_users INTEGER NOT NULL DEFAULT 0,
|
|
194
|
+
positive_roi_pct NUMERIC(10, 4) NOT NULL DEFAULT 0,
|
|
195
|
+
median_roi_pct NUMERIC(10, 4),
|
|
196
|
+
p25_roi_pct NUMERIC(10, 4),
|
|
197
|
+
p75_roi_pct NUMERIC(10, 4),
|
|
198
|
+
p90_roi_pct NUMERIC(10, 4),
|
|
199
|
+
mean_roi_pct NUMERIC(10, 4),
|
|
200
|
+
computed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
201
|
+
PRIMARY KEY (domain_slug, entity_type)
|
|
202
|
+
)`,
|
|
203
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
204
|
+
// Aggregator bookkeeping
|
|
205
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
206
|
+
`CREATE TABLE IF NOT EXISTS aggregator_state (
|
|
207
|
+
job_name TEXT PRIMARY KEY,
|
|
208
|
+
last_event_id BIGINT NOT NULL DEFAULT 0,
|
|
209
|
+
last_run_at TIMESTAMPTZ,
|
|
210
|
+
last_success_at TIMESTAMPTZ,
|
|
211
|
+
last_error TEXT
|
|
212
|
+
)`,
|
|
213
|
+
];
|
|
214
|
+
export async function initializeWarehouseSchema(sql) {
|
|
215
|
+
for (const statement of SCHEMA_DDL) {
|
|
216
|
+
await sql.unsafe(statement);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/warehouse/schema.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,GAAsB;IACpC,yEAAyE;IACzE,+BAA+B;IAC/B,yEAAyE;IACzE;;;;;;;IAOE;IAEF;;;;;;;IAOE;IAEF;mCACiC;IAEjC;sCACoC;IAEpC;uDACqD;IAErD,yEAAyE;IACzE,iDAAiD;IACjD,yEAAyE;IACzE;;;;;;;;;;;;;IAaE;IAEF;6CAC2C;IAC3C;kDACgD;IAEhD;;;;;;;;;;;;;IAaE;IAEF;2CACyC;IACzC;8CAC4C;IAE5C;;;;;;;;;;;IAWE;IAEF;qDACmD;IAEnD;;;;;;;;;;;IAWE;IAEF;qCACmC;IAEnC;;;;;;;;;;;IAWE;IAEF,yEAAyE;IACzE,uCAAuC;IACvC,yEAAyE;IACzE;;;;;;;;;;;;;;;;;;;IAmBE;IAEF;uCACqC;IACrC;gDAC8C;IAC9C;oCACkC;IAClC;0CACwC;IAExC;;;;;;;;;;;;;;;;;;;IAmBE;IAEF;wCACsC;IACtC;gCAC8B;IAE9B,yEAAyE;IACzE,iDAAiD;IACjD,yEAAyE;IACzE;;;;;;;;;IASE;IAEF;+DAC6D;IAE7D,yEAAyE;IACzE,yDAAyD;IACzD,yEAAyE;IACzE;;;;;;;;;IASE;IAEF;;;;;;;;;;;;;IAaE;IAEF,yEAAyE;IACzE,yBAAyB;IACzB,yEAAyE;IACzE;;;;;;IAME;CACH,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,GAAQ;IACtD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical domain taxonomy seed.
|
|
3
|
+
*
|
|
4
|
+
* The slugs below are the only values analytics queries should group by.
|
|
5
|
+
* `markets.category` and `markets.topics` (the existing free-form fields in
|
|
6
|
+
* SQLite) are mapped into these slugs by `backfillMarketDomains`.
|
|
7
|
+
*
|
|
8
|
+
* To add a new domain: append to CANONICAL_DOMAINS, run the indexer once.
|
|
9
|
+
* To remap topics → domain: edit TOPIC_TO_DOMAIN and re-run the backfill.
|
|
10
|
+
*/
|
|
11
|
+
import type { SQL } from 'bun';
|
|
12
|
+
export interface CanonicalDomain {
|
|
13
|
+
readonly slug: string;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly description: string;
|
|
16
|
+
readonly sortOrder: number;
|
|
17
|
+
}
|
|
18
|
+
export declare const CANONICAL_DOMAINS: readonly CanonicalDomain[];
|
|
19
|
+
/**
|
|
20
|
+
* Map a free-form topic or category string to a canonical domain slug.
|
|
21
|
+
* Returns 'other' if no rule matches.
|
|
22
|
+
*/
|
|
23
|
+
export declare function classifyTopic(raw: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Insert canonical domains, idempotent. Updates name/description/sort_order
|
|
26
|
+
* if a slug already exists.
|
|
27
|
+
*/
|
|
28
|
+
export declare function seedCanonicalDomains(sql: SQL): Promise<void>;
|
|
29
|
+
//# sourceMappingURL=seed-domains.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-domains.d.ts","sourceRoot":"","sources":["../../src/warehouse/seed-domains.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE/B,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,eAAe,EAmE9C,CAAC;AAqHX;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkBjD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAYlE"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
export const CANONICAL_DOMAINS = [
|
|
2
|
+
{
|
|
3
|
+
slug: 'politics',
|
|
4
|
+
name: 'Politics',
|
|
5
|
+
description: 'Elections, legislation, polls, and policy outcomes.',
|
|
6
|
+
sortOrder: 10,
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
slug: 'economics',
|
|
10
|
+
name: 'Economics',
|
|
11
|
+
description: 'Macroeconomic indicators, inflation, GDP, employment, rates.',
|
|
12
|
+
sortOrder: 20,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
slug: 'crypto',
|
|
16
|
+
name: 'Crypto',
|
|
17
|
+
description: 'On-chain metrics, token prices, protocol-level outcomes.',
|
|
18
|
+
sortOrder: 30,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
slug: 'weather',
|
|
22
|
+
name: 'Weather & Climate',
|
|
23
|
+
description: 'Temperature, precipitation, storm tracks, climate indicators.',
|
|
24
|
+
sortOrder: 40,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
slug: 'sports',
|
|
28
|
+
name: 'Sports',
|
|
29
|
+
description: 'Match outcomes, season standings, performance metrics.',
|
|
30
|
+
sortOrder: 50,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
slug: 'geopolitics',
|
|
34
|
+
name: 'Geopolitics',
|
|
35
|
+
description: 'International relations, conflicts, treaties, diplomatic outcomes.',
|
|
36
|
+
sortOrder: 60,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
slug: 'science',
|
|
40
|
+
name: 'Science & Tech Research',
|
|
41
|
+
description: 'Scientific results, peer-reviewed claims, technology breakthroughs.',
|
|
42
|
+
sortOrder: 70,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
slug: 'technology',
|
|
46
|
+
name: 'Technology & Industry',
|
|
47
|
+
description: 'Product launches, company outcomes, industry events.',
|
|
48
|
+
sortOrder: 80,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
slug: 'culture',
|
|
52
|
+
name: 'Culture',
|
|
53
|
+
description: 'Awards, entertainment, social trends, cultural events.',
|
|
54
|
+
sortOrder: 90,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
slug: 'entertainment',
|
|
58
|
+
name: 'Entertainment & Media',
|
|
59
|
+
description: 'Box office, streaming, music charts, media releases.',
|
|
60
|
+
sortOrder: 100,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
slug: 'other',
|
|
64
|
+
name: 'Other',
|
|
65
|
+
description: 'Markets that have not been mapped to a specific domain yet.',
|
|
66
|
+
sortOrder: 9999,
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* Lowercase substring → canonical slug. The first match wins. Order matters:
|
|
71
|
+
* put more specific matches first.
|
|
72
|
+
*
|
|
73
|
+
* Applied to (a) `markets.category` (lowercased) and (b) each entry in
|
|
74
|
+
* `markets.topics` (lowercased) — see `backfillMarketDomains`.
|
|
75
|
+
*/
|
|
76
|
+
const TOPIC_TO_DOMAIN = [
|
|
77
|
+
// ── politics ──
|
|
78
|
+
['election', 'politics'],
|
|
79
|
+
['president', 'politics'],
|
|
80
|
+
['senate', 'politics'],
|
|
81
|
+
['congress', 'politics'],
|
|
82
|
+
['parliament', 'politics'],
|
|
83
|
+
['vote', 'politics'],
|
|
84
|
+
['poll', 'politics'],
|
|
85
|
+
['republican', 'politics'],
|
|
86
|
+
['democrat', 'politics'],
|
|
87
|
+
['politic', 'politics'],
|
|
88
|
+
// ── economics ──
|
|
89
|
+
['inflation', 'economics'],
|
|
90
|
+
['cpi', 'economics'],
|
|
91
|
+
['ppi', 'economics'],
|
|
92
|
+
['gdp', 'economics'],
|
|
93
|
+
['unemployment', 'economics'],
|
|
94
|
+
['jobs', 'economics'],
|
|
95
|
+
['payroll', 'economics'],
|
|
96
|
+
['fed', 'economics'],
|
|
97
|
+
['interest rate', 'economics'],
|
|
98
|
+
['fomc', 'economics'],
|
|
99
|
+
['recession', 'economics'],
|
|
100
|
+
['economic', 'economics'],
|
|
101
|
+
['econ', 'economics'],
|
|
102
|
+
// ── crypto ──
|
|
103
|
+
['bitcoin', 'crypto'],
|
|
104
|
+
['ethereum', 'crypto'],
|
|
105
|
+
['btc', 'crypto'],
|
|
106
|
+
['eth', 'crypto'],
|
|
107
|
+
['solana', 'crypto'],
|
|
108
|
+
['starknet', 'crypto'],
|
|
109
|
+
['stablecoin', 'crypto'],
|
|
110
|
+
['defi', 'crypto'],
|
|
111
|
+
['token', 'crypto'],
|
|
112
|
+
['crypto', 'crypto'],
|
|
113
|
+
// ── weather ──
|
|
114
|
+
['hurricane', 'weather'],
|
|
115
|
+
['typhoon', 'weather'],
|
|
116
|
+
['storm', 'weather'],
|
|
117
|
+
['temperature', 'weather'],
|
|
118
|
+
['snowfall', 'weather'],
|
|
119
|
+
['rainfall', 'weather'],
|
|
120
|
+
['climate', 'weather'],
|
|
121
|
+
['weather', 'weather'],
|
|
122
|
+
// ── sports ──
|
|
123
|
+
['nba', 'sports'],
|
|
124
|
+
['nfl', 'sports'],
|
|
125
|
+
['mlb', 'sports'],
|
|
126
|
+
['nhl', 'sports'],
|
|
127
|
+
['soccer', 'sports'],
|
|
128
|
+
['football', 'sports'],
|
|
129
|
+
['premier league', 'sports'],
|
|
130
|
+
['champions league', 'sports'],
|
|
131
|
+
['world cup', 'sports'],
|
|
132
|
+
['olympic', 'sports'],
|
|
133
|
+
['tennis', 'sports'],
|
|
134
|
+
['ufc', 'sports'],
|
|
135
|
+
['mma', 'sports'],
|
|
136
|
+
['sport', 'sports'],
|
|
137
|
+
// ── geopolitics ──
|
|
138
|
+
['ukraine', 'geopolitics'],
|
|
139
|
+
['russia', 'geopolitics'],
|
|
140
|
+
['china', 'geopolitics'],
|
|
141
|
+
['nato', 'geopolitics'],
|
|
142
|
+
['un security', 'geopolitics'],
|
|
143
|
+
['ceasefire', 'geopolitics'],
|
|
144
|
+
['sanction', 'geopolitics'],
|
|
145
|
+
['treaty', 'geopolitics'],
|
|
146
|
+
['geopolitic', 'geopolitics'],
|
|
147
|
+
// ── science ──
|
|
148
|
+
['nasa', 'science'],
|
|
149
|
+
['spacex', 'science'],
|
|
150
|
+
['rocket', 'science'],
|
|
151
|
+
['vaccine', 'science'],
|
|
152
|
+
['nobel', 'science'],
|
|
153
|
+
['physics', 'science'],
|
|
154
|
+
['biology', 'science'],
|
|
155
|
+
['research', 'science'],
|
|
156
|
+
['science', 'science'],
|
|
157
|
+
// ── technology ──
|
|
158
|
+
['ai model', 'technology'],
|
|
159
|
+
['gpt', 'technology'],
|
|
160
|
+
['claude', 'technology'],
|
|
161
|
+
['gemini', 'technology'],
|
|
162
|
+
['ipo', 'technology'],
|
|
163
|
+
['layoff', 'technology'],
|
|
164
|
+
['acquisition', 'technology'],
|
|
165
|
+
['apple', 'technology'],
|
|
166
|
+
['google', 'technology'],
|
|
167
|
+
['microsoft', 'technology'],
|
|
168
|
+
['tech', 'technology'],
|
|
169
|
+
['technology', 'technology'],
|
|
170
|
+
// ── culture / entertainment ──
|
|
171
|
+
['oscar', 'entertainment'],
|
|
172
|
+
['grammy', 'entertainment'],
|
|
173
|
+
['emmy', 'entertainment'],
|
|
174
|
+
['box office', 'entertainment'],
|
|
175
|
+
['netflix', 'entertainment'],
|
|
176
|
+
['streaming', 'entertainment'],
|
|
177
|
+
['movie', 'entertainment'],
|
|
178
|
+
['album', 'entertainment'],
|
|
179
|
+
['entertain', 'entertainment'],
|
|
180
|
+
['celebrity', 'culture'],
|
|
181
|
+
['culture', 'culture'],
|
|
182
|
+
];
|
|
183
|
+
/**
|
|
184
|
+
* Map a free-form topic or category string to a canonical domain slug.
|
|
185
|
+
* Returns 'other' if no rule matches.
|
|
186
|
+
*/
|
|
187
|
+
export function classifyTopic(raw) {
|
|
188
|
+
const lower = raw.toLowerCase().trim();
|
|
189
|
+
if (lower.length === 0) {
|
|
190
|
+
return 'other';
|
|
191
|
+
}
|
|
192
|
+
// Direct slug match (already canonical)
|
|
193
|
+
for (const domain of CANONICAL_DOMAINS) {
|
|
194
|
+
if (lower === domain.slug || lower === domain.name.toLowerCase()) {
|
|
195
|
+
return domain.slug;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Substring rules
|
|
199
|
+
for (const [needle, slug] of TOPIC_TO_DOMAIN) {
|
|
200
|
+
if (lower.includes(needle)) {
|
|
201
|
+
return slug;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return 'other';
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Insert canonical domains, idempotent. Updates name/description/sort_order
|
|
208
|
+
* if a slug already exists.
|
|
209
|
+
*/
|
|
210
|
+
export async function seedCanonicalDomains(sql) {
|
|
211
|
+
for (const domain of CANONICAL_DOMAINS) {
|
|
212
|
+
await sql `
|
|
213
|
+
INSERT INTO domains (slug, name, description, sort_order, updated_at)
|
|
214
|
+
VALUES (${domain.slug}, ${domain.name}, ${domain.description}, ${domain.sortOrder}, now())
|
|
215
|
+
ON CONFLICT (slug) DO UPDATE SET
|
|
216
|
+
name = EXCLUDED.name,
|
|
217
|
+
description = EXCLUDED.description,
|
|
218
|
+
sort_order = EXCLUDED.sort_order,
|
|
219
|
+
updated_at = now()
|
|
220
|
+
`;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=seed-domains.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-domains.js","sourceRoot":"","sources":["../../src/warehouse/seed-domains.ts"],"names":[],"mappings":"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"}
|