@rawdash/core 0.14.0 → 0.15.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 +10 -7
- package/dist/index.d.ts +46 -5
- package/dist/index.js +123 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,6 @@ npm install @rawdash/core @rawdash/connector-github
|
|
|
20
20
|
## Quick example
|
|
21
21
|
|
|
22
22
|
```ts
|
|
23
|
-
import { GitHubConnector } from '@rawdash/connector-github';
|
|
24
23
|
import {
|
|
25
24
|
defineConfig,
|
|
26
25
|
defineDashboard,
|
|
@@ -28,18 +27,18 @@ import {
|
|
|
28
27
|
secret,
|
|
29
28
|
} from '@rawdash/core';
|
|
30
29
|
|
|
31
|
-
const github =
|
|
32
|
-
|
|
30
|
+
const github = {
|
|
31
|
+
name: 'github',
|
|
32
|
+
connectorId: 'github-actions',
|
|
33
|
+
config: {
|
|
33
34
|
owner: 'my-org',
|
|
34
35
|
repo: 'my-repo',
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
36
|
token: secret('GITHUB_TOKEN'),
|
|
38
37
|
},
|
|
39
|
-
|
|
38
|
+
};
|
|
40
39
|
|
|
41
40
|
export default defineConfig({
|
|
42
|
-
connectors: [
|
|
41
|
+
connectors: [github],
|
|
43
42
|
dashboards: {
|
|
44
43
|
engineering: defineDashboard({
|
|
45
44
|
widgets: {
|
|
@@ -58,6 +57,10 @@ export default defineConfig({
|
|
|
58
57
|
}),
|
|
59
58
|
},
|
|
60
59
|
});
|
|
60
|
+
|
|
61
|
+
// When mounting the engine, register the connector class:
|
|
62
|
+
// import { GitHubConnector } from '@rawdash/connector-github';
|
|
63
|
+
// mountEngine(config, { connectorRegistry: { 'github-actions': GitHubConnector } });
|
|
61
64
|
```
|
|
62
65
|
|
|
63
66
|
## API
|
package/dist/index.d.ts
CHANGED
|
@@ -127,6 +127,13 @@ interface StorageHandle {
|
|
|
127
127
|
deleteOlderThan(shape: 'events' | 'metrics' | 'distributions', tsUnixMs: number): Promise<{
|
|
128
128
|
rowsDeleted: number;
|
|
129
129
|
}>;
|
|
130
|
+
getHealth?(): Promise<ConnectorHealth | null>;
|
|
131
|
+
}
|
|
132
|
+
interface ConnectorHealth {
|
|
133
|
+
status: 'idle' | 'syncing' | 'error' | 'auth_failed' | 'paused';
|
|
134
|
+
lastSyncAt: string | null;
|
|
135
|
+
lastError: string | null;
|
|
136
|
+
syncIntervalSeconds: number;
|
|
130
137
|
}
|
|
131
138
|
interface CredentialField {
|
|
132
139
|
description: string;
|
|
@@ -1219,7 +1226,7 @@ interface GroupBy {
|
|
|
1219
1226
|
}
|
|
1220
1227
|
interface Metric {
|
|
1221
1228
|
connector: {
|
|
1222
|
-
|
|
1229
|
+
name: string;
|
|
1223
1230
|
};
|
|
1224
1231
|
shape: Shape;
|
|
1225
1232
|
name?: string;
|
|
@@ -1269,7 +1276,12 @@ interface DistributionWidget {
|
|
|
1269
1276
|
type Widget = StatWidget | StatusWidget | TimeseriesWidget | DistributionWidget;
|
|
1270
1277
|
|
|
1271
1278
|
interface ConfiguredConnector {
|
|
1272
|
-
|
|
1279
|
+
name: string;
|
|
1280
|
+
connectorId: string;
|
|
1281
|
+
config: Record<string, unknown>;
|
|
1282
|
+
syncIntervalSeconds?: number;
|
|
1283
|
+
enabled?: boolean;
|
|
1284
|
+
displayName?: string;
|
|
1273
1285
|
}
|
|
1274
1286
|
interface Dashboard {
|
|
1275
1287
|
widgets: Record<string, Widget>;
|
|
@@ -1296,7 +1308,7 @@ interface SyncState {
|
|
|
1296
1308
|
declare const ACTIVE_SYNC_STATUSES: ReadonlySet<SyncStatus>;
|
|
1297
1309
|
declare function isSyncActive(status: SyncStatus): boolean;
|
|
1298
1310
|
|
|
1299
|
-
type WidgetSyncState = '
|
|
1311
|
+
type WidgetSyncState = 'fresh' | 'stale' | 'unsynced' | 'syncing' | 'failing';
|
|
1300
1312
|
interface CachedWidget<TData = unknown> {
|
|
1301
1313
|
widgetId: string;
|
|
1302
1314
|
connectorId: string;
|
|
@@ -1347,7 +1359,35 @@ interface ServerStorage {
|
|
|
1347
1359
|
markSyncFailed(error: string): Promise<void>;
|
|
1348
1360
|
}
|
|
1349
1361
|
|
|
1350
|
-
declare function resolveWidget(widgetId: string, widget: Widget, connectors:
|
|
1362
|
+
declare function resolveWidget(widgetId: string, widget: Widget, connectors: readonly string[] | undefined, storage: ServerStorage): Promise<CachedWidget | undefined>;
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* Map of resource name → Zod schema describing the raw API response shape
|
|
1366
|
+
* for that resource. Resource names must match the `resource` tag passed to
|
|
1367
|
+
* `request()` (see {@link BaseConnector.request}) so the shape-drift pipeline
|
|
1368
|
+
* can correlate observations with their declared shape.
|
|
1369
|
+
*
|
|
1370
|
+
* Consumed by:
|
|
1371
|
+
* - the cloud baseline generator, which walks this map at deploy time to
|
|
1372
|
+
* populate `connector_baselines`
|
|
1373
|
+
* - property tests in `@rawdash/connector-test-utils`, which fuzz against
|
|
1374
|
+
* each schema
|
|
1375
|
+
*
|
|
1376
|
+
* See `docs/authoring-a-connector.md` for the authoring guide.
|
|
1377
|
+
*/
|
|
1378
|
+
type ConnectorSchemas = Readonly<Record<string, z.ZodType>>;
|
|
1379
|
+
/**
|
|
1380
|
+
* Compile-time contract every connector class must satisfy. Declaring
|
|
1381
|
+
* `static schemas` is mandatory — without it, the connector cannot be added
|
|
1382
|
+
* to a {@link ConnectorRegistry} and TypeScript will fail the build.
|
|
1383
|
+
*/
|
|
1384
|
+
type ConnectorClass = {
|
|
1385
|
+
new (settings: never, creds?: never, ctx?: ConnectorContext): Connector;
|
|
1386
|
+
readonly credentials?: CredentialsSchema;
|
|
1387
|
+
readonly schemas: ConnectorSchemas;
|
|
1388
|
+
};
|
|
1389
|
+
type ConnectorRegistry = Record<string, ConnectorClass>;
|
|
1390
|
+
declare function instantiateConnector(entry: ConfiguredConnector, registry: ConnectorRegistry, secretsResolver?: SecretsResolver): Connector;
|
|
1351
1391
|
|
|
1352
1392
|
declare function withAbortSignal(handle: StorageHandle, signal: AbortSignal): StorageHandle;
|
|
1353
1393
|
|
|
@@ -1357,6 +1397,7 @@ declare class InMemoryStorage implements ServerStorage {
|
|
|
1357
1397
|
private metricStore;
|
|
1358
1398
|
private edgeStore;
|
|
1359
1399
|
private distributionStore;
|
|
1400
|
+
private lastWriteAt;
|
|
1360
1401
|
private syncState;
|
|
1361
1402
|
getStorageHandle(connectorId: string, options?: GetStorageHandleOptions): StorageHandle;
|
|
1362
1403
|
private buildHandle;
|
|
@@ -1402,4 +1443,4 @@ type WireDashboard = z.infer<typeof wireDashboardSchema>;
|
|
|
1402
1443
|
type WireConfig = z.infer<typeof wireConfigSchema>;
|
|
1403
1444
|
declare function toWireConfig(config: DashboardConfig): WireConfig;
|
|
1404
1445
|
|
|
1405
|
-
export { ACTIVE_SYNC_STATUSES, type AggFn, BaseConnector, type CachedWidget, type ChunkedSyncCursor, type ChunkedSyncOptions, type ComputedMetric, type ConfigFieldsSchema, type ConfiguredConnector, type Connector, type ConnectorContext, type ConnectorRequestOptions, type CredentialField, type CredentialsSchema, type Dashboard, type DashboardConfig, type DataSource, type Distribution, type DistributionQuery, type DistributionWidget, type Edge, type EdgeQuery, type Entity, type EntityQuery, EnvSecretsResolver, type Event, type EventQuery, type FetchPageResult, type FilterClause, type FilterCondition, type FilterOperator, type GetStorageHandleOptions, type GroupBy, type HealthResponse, InMemoryStorage, type InferCredentialInput, type InferCredentials, type JSONValue, type Metric, type MetricQuery, type MetricSample, type RetentionConfig, type RetentionDeletionPlan, type Secret, type SecretsResolver, type ServerDataSource, type ServerStorage, type Shape, type StatWidget, type StatusWidget, type StorageHandle, type SyncOptions, type SyncResult, type SyncState, type SyncStatus, type TimeseriesWidget, type TriggerSyncResponse, type Widget, type WidgetKind, type WidgetSyncState, type WidgetsListResponse, type WireConfig, type WireConnector, type WireDashboard, aggFnSchema, computeMetric, computeRetention, computedMetricSchema, defineConfig, defineConfigFields, defineConnector, defineDashboard, defineMetric, distributionWidgetSchema, extractSecretNames, filterClauseSchema, filterConditionSchema, filterOperatorSchema, getWidgetSchema, groupBySchema, isSecret, isSyncActive, paginateChunked, resolveSecrets, resolveWidget, secret, selectForDeletion, shapeSchema, statWidgetSchema, statusWidgetSchema, timeseriesWidgetSchema, toWireConfig, widgetSchema, widgetSchemas, wireConfigSchema, wireConnectorSchema, wireDashboardSchema, withAbortSignal };
|
|
1446
|
+
export { ACTIVE_SYNC_STATUSES, type AggFn, BaseConnector, type CachedWidget, type ChunkedSyncCursor, type ChunkedSyncOptions, type ComputedMetric, type ConfigFieldsSchema, type ConfiguredConnector, type Connector, type ConnectorClass, type ConnectorContext, type ConnectorHealth, type ConnectorRegistry, type ConnectorRequestOptions, type ConnectorSchemas, type CredentialField, type CredentialsSchema, type Dashboard, type DashboardConfig, type DataSource, type Distribution, type DistributionQuery, type DistributionWidget, type Edge, type EdgeQuery, type Entity, type EntityQuery, EnvSecretsResolver, type Event, type EventQuery, type FetchPageResult, type FilterClause, type FilterCondition, type FilterOperator, type GetStorageHandleOptions, type GroupBy, type HealthResponse, InMemoryStorage, type InferCredentialInput, type InferCredentials, type JSONValue, type Metric, type MetricQuery, type MetricSample, type RetentionConfig, type RetentionDeletionPlan, type Secret, type SecretsResolver, type ServerDataSource, type ServerStorage, type Shape, type StatWidget, type StatusWidget, type StorageHandle, type SyncOptions, type SyncResult, type SyncState, type SyncStatus, type TimeseriesWidget, type TriggerSyncResponse, type Widget, type WidgetKind, type WidgetSyncState, type WidgetsListResponse, type WireConfig, type WireConnector, type WireDashboard, aggFnSchema, computeMetric, computeRetention, computedMetricSchema, defineConfig, defineConfigFields, defineConnector, defineDashboard, defineMetric, distributionWidgetSchema, extractSecretNames, filterClauseSchema, filterConditionSchema, filterOperatorSchema, getWidgetSchema, groupBySchema, instantiateConnector, isSecret, isSyncActive, paginateChunked, resolveSecrets, resolveWidget, secret, selectForDeletion, shapeSchema, statWidgetSchema, statusWidgetSchema, timeseriesWidgetSchema, toWireConfig, widgetSchema, widgetSchemas, wireConfigSchema, wireConnectorSchema, wireDashboardSchema, withAbortSignal };
|
package/dist/index.js
CHANGED
|
@@ -666,7 +666,7 @@ function defineDashboard(options) {
|
|
|
666
666
|
}
|
|
667
667
|
function defineMetric(options) {
|
|
668
668
|
return {
|
|
669
|
-
connectorId: options.connector.
|
|
669
|
+
connectorId: options.connector.name,
|
|
670
670
|
shape: options.shape,
|
|
671
671
|
name: options.name,
|
|
672
672
|
entityType: options.entityType,
|
|
@@ -715,7 +715,36 @@ function validateConfig(config) {
|
|
|
715
715
|
'defineConfig: config must include a "dashboards" record \u2014 did you mean to migrate from the old flat "widgets" shape?'
|
|
716
716
|
);
|
|
717
717
|
}
|
|
718
|
-
|
|
718
|
+
if (!Array.isArray(config.connectors)) {
|
|
719
|
+
throw new Error('defineConfig: "connectors" must be an array');
|
|
720
|
+
}
|
|
721
|
+
const connectorNames = /* @__PURE__ */ new Set();
|
|
722
|
+
for (const entry of config.connectors) {
|
|
723
|
+
if (!entry || typeof entry !== "object") {
|
|
724
|
+
throw new Error(
|
|
725
|
+
'defineConfig: every connector entry must be an object with "name", "connectorId", and "config"'
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
if (!entry.name) {
|
|
729
|
+
throw new Error('defineConfig: every connector entry must have a "name"');
|
|
730
|
+
}
|
|
731
|
+
if (!entry.connectorId) {
|
|
732
|
+
throw new Error(
|
|
733
|
+
`defineConfig: connector "${entry.name}" must have a "connectorId" (the connector type id)`
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
if (entry.config === null || typeof entry.config !== "object" || Array.isArray(entry.config)) {
|
|
737
|
+
throw new Error(
|
|
738
|
+
`defineConfig: connector "${entry.name}" must have a "config" object`
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
if (connectorNames.has(entry.name)) {
|
|
742
|
+
throw new Error(
|
|
743
|
+
`defineConfig: duplicate connector name "${entry.name}". Each instance must have a unique name.`
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
connectorNames.add(entry.name);
|
|
747
|
+
}
|
|
719
748
|
for (const [dashboardKey, dashboard] of Object.entries(config.dashboards)) {
|
|
720
749
|
if (!dashboard.widgets || typeof dashboard.widgets !== "object" || Array.isArray(dashboard.widgets)) {
|
|
721
750
|
throw new Error(
|
|
@@ -738,7 +767,7 @@ function validateConfig(config) {
|
|
|
738
767
|
continue;
|
|
739
768
|
}
|
|
740
769
|
const { connectorId, shape, fn } = widget.metric;
|
|
741
|
-
if (!
|
|
770
|
+
if (!connectorNames.has(connectorId)) {
|
|
742
771
|
throw new Error(
|
|
743
772
|
`${ref}: connector "${connectorId}" is not listed in connectors`
|
|
744
773
|
);
|
|
@@ -1073,38 +1102,77 @@ async function computeMetric(storage, metric) {
|
|
|
1073
1102
|
}
|
|
1074
1103
|
|
|
1075
1104
|
// src/resolve-widget.ts
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
connectorId: widget.source,
|
|
1081
|
-
data: null,
|
|
1082
|
-
cachedAt: null
|
|
1083
|
-
};
|
|
1105
|
+
var FAILING_CONNECTOR_STATUSES = /* @__PURE__ */ new Set(["error", "auth_failed", "paused"]);
|
|
1106
|
+
function deriveSyncStateFromHealth(health) {
|
|
1107
|
+
if (health.status === "syncing") {
|
|
1108
|
+
return "syncing";
|
|
1084
1109
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1110
|
+
if (FAILING_CONNECTOR_STATUSES.has(health.status)) {
|
|
1111
|
+
return "failing";
|
|
1112
|
+
}
|
|
1113
|
+
if (!health.lastSyncAt) {
|
|
1114
|
+
return "unsynced";
|
|
1115
|
+
}
|
|
1116
|
+
const ageMs = Date.now() - new Date(health.lastSyncAt).getTime();
|
|
1117
|
+
const windowMs = 2 * health.syncIntervalSeconds * 1e3;
|
|
1118
|
+
return ageMs <= windowMs ? "fresh" : "stale";
|
|
1119
|
+
}
|
|
1120
|
+
function buildMetaFromHealth(health) {
|
|
1121
|
+
const meta = { connectorStatus: health.status };
|
|
1122
|
+
if (health.lastError) {
|
|
1123
|
+
meta["lastError"] = health.lastError;
|
|
1124
|
+
}
|
|
1125
|
+
return meta;
|
|
1126
|
+
}
|
|
1127
|
+
async function resolveWidget(widgetId, widget, connectors, storage) {
|
|
1128
|
+
const connectorId = widget.kind === "status" ? widget.source : widget.metric.connectorId;
|
|
1129
|
+
if (connectors !== void 0 && !connectors.includes(connectorId)) {
|
|
1087
1130
|
return void 0;
|
|
1088
1131
|
}
|
|
1089
1132
|
const handle = storage.getStorageHandle(connectorId);
|
|
1090
|
-
const
|
|
1133
|
+
const health = await handle.getHealth?.() ?? null;
|
|
1134
|
+
const data = widget.kind === "status" ? null : await computeMetric(handle, widget.metric);
|
|
1135
|
+
let syncState;
|
|
1136
|
+
let meta;
|
|
1137
|
+
if (health) {
|
|
1138
|
+
syncState = deriveSyncStateFromHealth(health);
|
|
1139
|
+
meta = buildMetaFromHealth(health);
|
|
1140
|
+
} else if (data === null || data === void 0) {
|
|
1141
|
+
syncState = "unsynced";
|
|
1142
|
+
} else {
|
|
1143
|
+
syncState = "fresh";
|
|
1144
|
+
}
|
|
1091
1145
|
return {
|
|
1092
1146
|
widgetId,
|
|
1093
1147
|
connectorId,
|
|
1094
1148
|
data,
|
|
1095
|
-
cachedAt:
|
|
1149
|
+
cachedAt: health?.lastSyncAt ?? null,
|
|
1150
|
+
syncState,
|
|
1151
|
+
meta
|
|
1096
1152
|
};
|
|
1097
1153
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1154
|
+
|
|
1155
|
+
// src/registry.ts
|
|
1156
|
+
function instantiateConnector(entry, registry, secretsResolver) {
|
|
1157
|
+
const Cls = registry[entry.connectorId];
|
|
1158
|
+
if (!Cls) {
|
|
1159
|
+
throw new Error(
|
|
1160
|
+
`Unknown connector type "${entry.connectorId}" for instance "${entry.name}". Add it to the connectorRegistry.`
|
|
1161
|
+
);
|
|
1101
1162
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1163
|
+
const credSchema = Cls.credentials;
|
|
1164
|
+
const settings = {};
|
|
1165
|
+
const creds = {};
|
|
1166
|
+
for (const [key, value] of Object.entries(entry.config)) {
|
|
1167
|
+
if (credSchema && Object.prototype.hasOwnProperty.call(credSchema, key)) {
|
|
1168
|
+
creds[key] = value;
|
|
1169
|
+
} else {
|
|
1170
|
+
settings[key] = value;
|
|
1171
|
+
}
|
|
1104
1172
|
}
|
|
1105
|
-
return
|
|
1106
|
-
|
|
1107
|
-
);
|
|
1173
|
+
return new Cls(settings, credSchema ? creds : void 0, {
|
|
1174
|
+
secretsResolver
|
|
1175
|
+
});
|
|
1108
1176
|
}
|
|
1109
1177
|
|
|
1110
1178
|
// src/storage-handle-guard.ts
|
|
@@ -1202,7 +1270,8 @@ function withAbortSignal(handle, signal) {
|
|
|
1202
1270
|
queryEntities: (q) => handle.queryEntities(q),
|
|
1203
1271
|
queryMetrics: (q) => handle.queryMetrics(q),
|
|
1204
1272
|
traverse: (q) => handle.traverse(q),
|
|
1205
|
-
queryDistributions: (q) => handle.queryDistributions(q)
|
|
1273
|
+
queryDistributions: (q) => handle.queryDistributions(q),
|
|
1274
|
+
...handle.getHealth ? { getHealth: handle.getHealth.bind(handle) } : {}
|
|
1206
1275
|
};
|
|
1207
1276
|
}
|
|
1208
1277
|
|
|
@@ -1213,6 +1282,7 @@ var InMemoryStorage = class {
|
|
|
1213
1282
|
metricStore = /* @__PURE__ */ new Map();
|
|
1214
1283
|
edgeStore = /* @__PURE__ */ new Map();
|
|
1215
1284
|
distributionStore = /* @__PURE__ */ new Map();
|
|
1285
|
+
lastWriteAt = /* @__PURE__ */ new Map();
|
|
1216
1286
|
syncState = {
|
|
1217
1287
|
status: "idle",
|
|
1218
1288
|
queuedAt: null,
|
|
@@ -1225,6 +1295,9 @@ var InMemoryStorage = class {
|
|
|
1225
1295
|
return options?.signal ? withAbortSignal(handle, options.signal) : handle;
|
|
1226
1296
|
}
|
|
1227
1297
|
buildHandle(connectorId) {
|
|
1298
|
+
const touch = () => {
|
|
1299
|
+
this.lastWriteAt.set(connectorId, (/* @__PURE__ */ new Date()).toISOString());
|
|
1300
|
+
};
|
|
1228
1301
|
const getEntityMap = () => {
|
|
1229
1302
|
if (!this.entityStore.has(connectorId)) {
|
|
1230
1303
|
this.entityStore.set(connectorId, /* @__PURE__ */ new Map());
|
|
@@ -1268,24 +1341,29 @@ var InMemoryStorage = class {
|
|
|
1268
1341
|
this.eventStore.set(connectorId, []);
|
|
1269
1342
|
}
|
|
1270
1343
|
this.eventStore.get(connectorId).push(e);
|
|
1344
|
+
touch();
|
|
1271
1345
|
},
|
|
1272
1346
|
entity: async (e) => {
|
|
1273
1347
|
upsertEntities([e]);
|
|
1348
|
+
touch();
|
|
1274
1349
|
},
|
|
1275
1350
|
metric: async (m) => {
|
|
1276
1351
|
if (!this.metricStore.has(connectorId)) {
|
|
1277
1352
|
this.metricStore.set(connectorId, []);
|
|
1278
1353
|
}
|
|
1279
1354
|
this.metricStore.get(connectorId).push(m);
|
|
1355
|
+
touch();
|
|
1280
1356
|
},
|
|
1281
1357
|
edge: async (e) => {
|
|
1282
1358
|
upsertEdges([e]);
|
|
1359
|
+
touch();
|
|
1283
1360
|
},
|
|
1284
1361
|
distribution: async (d) => {
|
|
1285
1362
|
if (!this.distributionStore.has(connectorId)) {
|
|
1286
1363
|
this.distributionStore.set(connectorId, []);
|
|
1287
1364
|
}
|
|
1288
1365
|
this.distributionStore.get(connectorId).push(d);
|
|
1366
|
+
touch();
|
|
1289
1367
|
},
|
|
1290
1368
|
events: async (es, scope) => {
|
|
1291
1369
|
const names = new Set(scope?.names ?? es.map((e) => e.name));
|
|
@@ -1293,6 +1371,7 @@ var InMemoryStorage = class {
|
|
|
1293
1371
|
(e) => !names.has(e.name)
|
|
1294
1372
|
);
|
|
1295
1373
|
this.eventStore.set(connectorId, [...kept, ...es]);
|
|
1374
|
+
touch();
|
|
1296
1375
|
},
|
|
1297
1376
|
entities: async (es, scope) => {
|
|
1298
1377
|
const byType = getEntityMap();
|
|
@@ -1301,6 +1380,7 @@ var InMemoryStorage = class {
|
|
|
1301
1380
|
byType.set(type, /* @__PURE__ */ new Map());
|
|
1302
1381
|
}
|
|
1303
1382
|
upsertEntities(es);
|
|
1383
|
+
touch();
|
|
1304
1384
|
},
|
|
1305
1385
|
metrics: async (ms, scope) => {
|
|
1306
1386
|
const names = new Set(scope?.names ?? ms.map((m) => m.name));
|
|
@@ -1308,6 +1388,7 @@ var InMemoryStorage = class {
|
|
|
1308
1388
|
(m) => !names.has(m.name)
|
|
1309
1389
|
);
|
|
1310
1390
|
this.metricStore.set(connectorId, [...kept, ...ms]);
|
|
1391
|
+
touch();
|
|
1311
1392
|
},
|
|
1312
1393
|
edges: async (es, scope) => {
|
|
1313
1394
|
const kinds = new Set(scope?.kinds ?? es.map((e) => e.kind));
|
|
@@ -1316,6 +1397,7 @@ var InMemoryStorage = class {
|
|
|
1316
1397
|
);
|
|
1317
1398
|
this.edgeStore.set(connectorId, kept);
|
|
1318
1399
|
upsertEdges(es);
|
|
1400
|
+
touch();
|
|
1319
1401
|
},
|
|
1320
1402
|
distributions: async (ds, scope) => {
|
|
1321
1403
|
const names = new Set(scope?.names ?? ds.map((d) => d.name));
|
|
@@ -1323,6 +1405,7 @@ var InMemoryStorage = class {
|
|
|
1323
1405
|
(d) => !names.has(d.name)
|
|
1324
1406
|
);
|
|
1325
1407
|
this.distributionStore.set(connectorId, [...kept, ...ds]);
|
|
1408
|
+
touch();
|
|
1326
1409
|
},
|
|
1327
1410
|
queryEvents: async (q) => {
|
|
1328
1411
|
let results = this.eventStore.get(connectorId) ?? [];
|
|
@@ -1413,6 +1496,14 @@ var InMemoryStorage = class {
|
|
|
1413
1496
|
`Unsupported shape for deleteOlderThan: ${String(shape)}`
|
|
1414
1497
|
);
|
|
1415
1498
|
}
|
|
1499
|
+
},
|
|
1500
|
+
getHealth: async () => {
|
|
1501
|
+
return {
|
|
1502
|
+
status: "idle",
|
|
1503
|
+
lastSyncAt: this.lastWriteAt.get(connectorId) ?? null,
|
|
1504
|
+
lastError: null,
|
|
1505
|
+
syncIntervalSeconds: 0
|
|
1506
|
+
};
|
|
1416
1507
|
}
|
|
1417
1508
|
};
|
|
1418
1509
|
}
|
|
@@ -1485,13 +1576,13 @@ var wireConfigSchema = z3.object({
|
|
|
1485
1576
|
});
|
|
1486
1577
|
function toWireConfig(config) {
|
|
1487
1578
|
return {
|
|
1488
|
-
connectors: config.connectors.map((
|
|
1489
|
-
name:
|
|
1490
|
-
connectorId:
|
|
1491
|
-
displayName:
|
|
1492
|
-
config:
|
|
1493
|
-
syncIntervalSeconds: 300,
|
|
1494
|
-
enabled: true
|
|
1579
|
+
connectors: config.connectors.map((entry) => ({
|
|
1580
|
+
name: entry.name,
|
|
1581
|
+
connectorId: entry.connectorId,
|
|
1582
|
+
displayName: entry.displayName ?? entry.name,
|
|
1583
|
+
config: entry.config,
|
|
1584
|
+
syncIntervalSeconds: entry.syncIntervalSeconds ?? 300,
|
|
1585
|
+
enabled: entry.enabled ?? true
|
|
1495
1586
|
})),
|
|
1496
1587
|
dashboards: Object.entries(config.dashboards).map(([id, dash]) => ({
|
|
1497
1588
|
id,
|
|
@@ -1522,6 +1613,7 @@ export {
|
|
|
1522
1613
|
filterOperatorSchema,
|
|
1523
1614
|
getWidgetSchema,
|
|
1524
1615
|
groupBySchema,
|
|
1616
|
+
instantiateConnector,
|
|
1525
1617
|
isSecret,
|
|
1526
1618
|
isSyncActive,
|
|
1527
1619
|
paginateChunked,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../connector-shared/src/errors.ts","../../connector-shared/src/retry.ts","../../connector-shared/src/version.ts","../../connector-shared/src/request.ts","../../connector-shared/src/rate-limit.ts","../../connector-shared/src/pagination.ts","../src/secrets.ts","../src/connector.ts","../src/paginate-chunked.ts","../src/widget-schemas.ts","../src/config.ts","../src/engine.ts","../src/retention.ts","../src/config-fields.ts","../src/compute.ts","../src/resolve-widget.ts","../src/storage-handle-guard.ts","../src/in-memory-storage.ts","../src/wire-config.ts"],"sourcesContent":["import type { HttpResponse } from './types';\n\nexport type HttpErrorKind =\n | 'transient'\n | 'rate_limit'\n | 'auth'\n | 'upstream_bug'\n | 'client_bug';\n\nexport abstract class HttpClientError extends Error {\n abstract readonly kind: HttpErrorKind;\n readonly response?: HttpResponse;\n\n constructor(message: string, response?: HttpResponse) {\n super(message);\n this.name = new.target.name;\n this.response = response;\n }\n}\n\nexport class TransientError extends HttpClientError {\n readonly kind = 'transient' as const;\n}\n\nexport class RateLimitError extends HttpClientError {\n readonly kind = 'rate_limit' as const;\n readonly retryAfter?: Date;\n\n constructor(message: string, response?: HttpResponse, retryAfter?: Date) {\n super(message, response);\n this.retryAfter = retryAfter;\n }\n}\n\nexport class AuthError extends HttpClientError {\n readonly kind = 'auth' as const;\n}\n\nexport class UpstreamBugError extends HttpClientError {\n readonly kind = 'upstream_bug' as const;\n}\n\nexport class ClientBugError extends HttpClientError {\n readonly kind = 'client_bug' as const;\n}\n\nexport function classifyStatus(status: number): HttpErrorKind {\n if (status === 429) {\n return 'rate_limit';\n }\n if (status === 401 || status === 403) {\n return 'auth';\n }\n if (status === 408) {\n return 'transient';\n }\n if (status >= 500) {\n return 'upstream_bug';\n }\n if (status >= 400) {\n return 'client_bug';\n }\n return 'client_bug';\n}\n\nexport function errorForStatus(\n message: string,\n response: HttpResponse,\n retryAfter?: Date,\n): HttpClientError {\n const kind = classifyStatus(response.status);\n switch (kind) {\n case 'rate_limit':\n return new RateLimitError(message, response, retryAfter);\n case 'auth':\n return new AuthError(message, response);\n case 'transient':\n return new TransientError(message, response);\n case 'upstream_bug':\n return new UpstreamBugError(message, response);\n case 'client_bug':\n return new ClientBugError(message, response);\n }\n}\n","import { HttpClientError, RateLimitError, TransientError } from './errors';\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n retryOn?: (status: number | null, err?: Error) => boolean;\n}\n\nexport const defaultRetryOn = (status: number | null, err?: Error): boolean => {\n if (err instanceof RateLimitError) {\n return true;\n }\n if (err instanceof TransientError) {\n return true;\n }\n if (status === null) {\n return err instanceof Error && !(err instanceof HttpClientError);\n }\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return false;\n};\n\nexport function backoffDelayMs(\n attempt: number,\n policy: Required<Pick<RetryPolicy, 'initialDelayMs' | 'maxDelayMs'>>,\n): number {\n const base = policy.initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, policy.maxDelayMs);\n}\n\nexport function parseRetryAfter(\n headerValue: string | null,\n now: Date = new Date(),\n): Date | undefined {\n if (!headerValue) {\n return undefined;\n }\n const trimmed = headerValue.trim();\n if (/^\\d+$/.test(trimmed)) {\n return new Date(now.getTime() + Number(trimmed) * 1000);\n }\n const parsed = Date.parse(trimmed);\n if (Number.isNaN(parsed)) {\n return undefined;\n }\n return new Date(parsed);\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","export const HTTP_CLIENT_VERSION = '0.0.0';\n\nexport const DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n","import {\n AuthError,\n ClientBugError,\n HttpClientError,\n RateLimitError,\n TransientError,\n UpstreamBugError,\n errorForStatus,\n} from './errors';\nimport { defaultRetryOn, parseRetryAfter, sleep } from './retry';\nimport type { FetchLike, HttpMethod, HttpRequest, HttpResponse } from './types';\nimport { DEFAULT_USER_AGENT } from './version';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY_MS = 1000;\nconst DEFAULT_MAX_DELAY_MS = 60_000;\nconst OBSERVER_TIMEOUT_MS = 250;\n\nexport interface RequestObservation {\n url: string;\n method: HttpMethod;\n status: number;\n resource: string;\n requestId: string;\n body: unknown;\n}\n\nexport type RequestObserver = (\n event: RequestObservation,\n) => void | Promise<void>;\n\nexport interface RequestOptions {\n fetch?: FetchLike;\n observer?: RequestObserver;\n resource: string;\n requestId?: string;\n}\n\nasync function notifyObserver(\n observer: RequestObserver,\n event: RequestObservation,\n): Promise<void> {\n let result: void | Promise<void>;\n try {\n result = observer(event);\n } catch (err) {\n console.warn('[connector-shared] request observer threw:', err);\n return;\n }\n if (!(result instanceof Promise)) {\n return;\n }\n const guarded = result.catch((err) => {\n console.warn('[connector-shared] request observer rejected:', err);\n });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, OBSERVER_TIMEOUT_MS);\n });\n try {\n await Promise.race([guarded, timeout]);\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n}\n\nfunction newRequestId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction mergeHeaders(\n defaults: Record<string, string>,\n overrides: Record<string, string> | undefined,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(defaults)) {\n merged[k.toLowerCase()] = v;\n }\n if (overrides) {\n for (const [k, v] of Object.entries(overrides)) {\n merged[k.toLowerCase()] = v;\n }\n }\n return merged;\n}\n\nfunction linkTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n const controller = new AbortController();\n const onParentAbort = () => {\n controller.abort(parent?.reason);\n };\n if (parent) {\n if (parent.aborted) {\n controller.abort(parent.reason);\n } else {\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n }\n const timer = setTimeout(() => {\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n if (parent) {\n parent.removeEventListener('abort', onParentAbort);\n }\n },\n };\n}\n\nasync function readBody(res: Response, parseJson: boolean): Promise<unknown> {\n if (res.status === 204 || res.status === 205) {\n return null;\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (parseJson && contentType.includes('application/json')) {\n const text = await res.text();\n if (text.length === 0) {\n return null;\n }\n return JSON.parse(text);\n }\n return res.text();\n}\n\nexport async function request<T = unknown>(\n req: HttpRequest,\n options: RequestOptions,\n): Promise<HttpResponse<T>> {\n const fetchImpl: FetchLike = options.fetch ?? (globalThis.fetch as FetchLike);\n const retry = req.retry ?? {};\n const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;\n const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n const retryOn = retry.retryOn ?? defaultRetryOn;\n const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const parseJson = req.parseJson ?? true;\n\n const headers = mergeHeaders(\n {\n 'User-Agent': DEFAULT_USER_AGENT,\n Accept: 'application/json',\n },\n req.headers,\n );\n\n let lastErr: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n req.signal?.throwIfAborted();\n\n const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);\n let res: Response;\n try {\n res = await fetchImpl(req.url, {\n method: req.method ?? 'GET',\n headers,\n body: req.body as RequestInit['body'],\n signal,\n });\n } catch (err) {\n cancel();\n if (req.signal?.aborted) {\n throw req.signal.reason ?? err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n lastErr = error;\n if (attempt < maxAttempts - 1 && retryOn(null, error)) {\n const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n await sleep(delay, req.signal);\n continue;\n }\n throw new TransientError(error.message);\n }\n cancel();\n\n const body = await readBody(res, parseJson);\n const httpResponse: HttpResponse<T> = {\n status: res.status,\n headers: res.headers,\n body: body as T,\n };\n if (req.rateLimit) {\n const state = req.rateLimit.parse(res.headers);\n if (state) {\n httpResponse.rateLimitState = state;\n }\n }\n\n if (options.observer) {\n await notifyObserver(options.observer, {\n url: req.url,\n method: req.method ?? 'GET',\n status: res.status,\n resource: options.resource,\n requestId: options.requestId ?? newRequestId(),\n body,\n });\n }\n\n if (res.ok) {\n return httpResponse;\n }\n\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? 'GET'} ${req.url}`;\n const err = errorForStatus(message, httpResponse, retryAfter);\n\n if (\n attempt < maxAttempts - 1 &&\n retryOn(res.status, err) &&\n !(err instanceof AuthError) &&\n !(err instanceof ClientBugError)\n ) {\n lastErr = err;\n let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n if (err instanceof RateLimitError && retryAfter) {\n const wait = retryAfter.getTime() - Date.now();\n if (wait > 0) {\n delay = Math.min(wait, maxDelayMs);\n }\n }\n await sleep(delay, req.signal);\n continue;\n }\n\n throw err;\n }\n\n throw lastErr ?? new UpstreamBugError('Exhausted retry attempts');\n}\n\nfunction computeDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n): number {\n const base = initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, maxDelayMs);\n}\n\nexport { HttpClientError };\n","export interface RateLimitState {\n remaining: number;\n resetAt: Date;\n}\n\nexport interface RateLimitPolicy {\n parse(headers: Headers): RateLimitState | null;\n}\n\nexport const githubRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-remaining');\n const resetRaw = h.get('x-ratelimit-reset');\n if (remainingRaw === null || resetRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n const reset = Number(resetRaw);\n if (!Number.isFinite(remaining) || !Number.isFinite(reset) || reset < 0) {\n return null;\n }\n return { remaining, resetAt: new Date(reset * 1000) };\n },\n};\n\nexport const sentryRateLimit: RateLimitPolicy = {\n parse(h) {\n const concurrent = h.get('x-sentry-rate-limit-remaining');\n const reset = h.get('x-sentry-rate-limit-reset');\n if (concurrent === null || reset === null) {\n return null;\n }\n const remaining = Number(concurrent);\n const resetSec = Number(reset);\n if (\n !Number.isFinite(remaining) ||\n !Number.isFinite(resetSec) ||\n resetSec < 0\n ) {\n return null;\n }\n return { remaining, resetAt: new Date(resetSec * 1000) };\n },\n};\n\nexport const linearRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-requests-remaining');\n const resetRaw = h.get('x-ratelimit-requests-reset');\n if (remainingRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n if (!Number.isFinite(remaining)) {\n return null;\n }\n let resetAt: Date;\n if (resetRaw !== null) {\n const reset = Number(resetRaw);\n if (!Number.isFinite(reset) || reset < 0) {\n return null;\n }\n resetAt = new Date(reset);\n } else {\n resetAt = new Date(Date.now() + 60_000);\n }\n return { remaining, resetAt };\n },\n};\n","import { request } from './request';\nimport type { HttpRequest } from './types';\n\nexport function parseLinkHeader(header: string | null): Record<string, string> {\n if (!header) {\n return {};\n }\n const result: Record<string, string> = {};\n for (const part of header.split(',')) {\n const match = part.match(/<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/);\n if (match) {\n result[match[2]!] = match[1]!;\n }\n }\n return result;\n}\n\nexport async function* paginateLink<T>(\n initial: HttpRequest,\n parse: (body: unknown) => T[],\n options: { resource: string },\n): AsyncIterable<T> {\n let next: string | null = initial.url;\n while (next) {\n const res: Awaited<ReturnType<typeof request>> = await request(\n {\n ...initial,\n url: next,\n },\n { resource: options.resource },\n );\n for (const item of parse(res.body)) {\n yield item;\n }\n const links = parseLinkHeader(res.headers.get('link'));\n next = links['next'] ?? null;\n }\n}\n\nexport async function* paginateCursor<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; nextCursor: string | null },\n buildNext: (req: HttpRequest, cursor: string) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let req: HttpRequest = initial;\n while (true) {\n const res = await request(req, { resource: options.resource });\n const { items, nextCursor } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!nextCursor) {\n return;\n }\n req = buildNext(req, nextCursor);\n }\n}\n\nexport async function* paginatePage<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; hasMore: boolean },\n buildPage: (req: HttpRequest, page: number) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let page = 1;\n while (true) {\n const req = page === 1 ? initial : buildPage(initial, page);\n const res = await request(req, { resource: options.resource });\n const { items, hasMore } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!hasMore || items.length === 0) {\n return;\n }\n page++;\n }\n}\n","export type Secret = { $secret: string };\n\nexport function secret(name: string): Secret {\n if (!/^[A-Z][A-Z0-9_]*$/.test(name)) {\n throw new Error(\n `Invalid secret name \"${name}\". Must match /^[A-Z][A-Z0-9_]*$/ ` +\n `(uppercase letters, digits, underscores; must start with a letter).`,\n );\n }\n return { $secret: name };\n}\n\nexport function isSecret(value: unknown): value is Secret {\n return (\n typeof value === 'object' &&\n value !== null &&\n '$secret' in value &&\n typeof (value as Secret).$secret === 'string'\n );\n}\n\nexport interface SecretsResolver {\n resolve(name: string): string | undefined;\n}\n\nexport class EnvSecretsResolver implements SecretsResolver {\n resolve(name: string): string | undefined {\n const env = (\n globalThis as { process?: { env?: Record<string, string | undefined> } }\n ).process?.env;\n return env?.[name];\n }\n}\n\nexport function extractSecretNames(value: unknown): string[] {\n const names: string[] = [];\n const visit = (v: unknown): void => {\n if (isSecret(v)) {\n names.push(v.$secret);\n return;\n }\n if (v && typeof v === 'object') {\n if (Array.isArray(v)) {\n v.forEach(visit);\n } else {\n Object.values(v as Record<string, unknown>).forEach(visit);\n }\n }\n };\n visit(value);\n return [...new Set(names)];\n}\n\nexport function resolveSecrets<T>(obj: T, resolver: SecretsResolver): T {\n if (isSecret(obj)) {\n const name = obj.$secret;\n const value = resolver.resolve(name);\n if (value === undefined) {\n throw new Error(\n `Missing secret \"${name}\". Set it via process.env.${name} or the CLI: rawdash secrets set ${name} ...`,\n );\n }\n return value as unknown as T;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => resolveSecrets(item, resolver)) as unknown as T;\n }\n if (typeof obj === 'object' && obj !== null) {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(obj as object)) {\n Object.defineProperty(result, key, {\n value: resolveSecrets(val, resolver),\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n return result as T;\n }\n return obj;\n}\n","import {\n type HttpRequest,\n type HttpResponse,\n type RequestObserver,\n request as sharedRequest,\n} from '@rawdash/connector-shared';\n\nimport {\n EnvSecretsResolver,\n type Secret,\n type SecretsResolver,\n resolveSecrets,\n} from './secrets';\n\nexport type JSONValue =\n | string\n | number\n | boolean\n | null\n | JSONValue[]\n | { [key: string]: JSONValue };\n\n// ---------------------------------------------------------------------------\n// Five storage shapes\n// ---------------------------------------------------------------------------\n\nexport interface Event {\n name: string;\n start_ts: number;\n end_ts: number | null;\n attributes: Record<string, JSONValue>;\n}\n\nexport interface Entity {\n type: string;\n id: string;\n attributes: Record<string, JSONValue>;\n updated_at: number;\n}\n\nexport interface MetricSample {\n name: string;\n ts: number;\n value: number;\n attributes: Record<string, JSONValue>;\n}\n\nexport interface Edge {\n from_type: string;\n from_id: string;\n kind: string;\n to_type: string;\n to_id: string;\n attributes: Record<string, JSONValue>;\n updated_at: number;\n}\n\nexport type Distribution =\n | {\n name: string;\n ts: number;\n kind: 'histogram';\n data: {\n buckets: Array<{ le: number; count: number }>;\n count: number;\n sum: number;\n };\n attributes: Record<string, JSONValue>;\n }\n | {\n name: string;\n ts: number;\n kind: 'summary';\n data: {\n quantiles: Array<{ q: number; value: number }>;\n count: number;\n sum: number;\n };\n attributes: Record<string, JSONValue>;\n };\n\n// ---------------------------------------------------------------------------\n// Storage query types\n// ---------------------------------------------------------------------------\n\nexport interface EventQuery {\n name?: string;\n start?: number;\n end?: number;\n}\n\nexport interface EntityQuery {\n type: string;\n}\n\nexport interface MetricQuery {\n name?: string;\n start?: number;\n end?: number;\n}\n\nexport interface EdgeQuery {\n fromType?: string;\n fromId?: string;\n kind?: string;\n toType?: string;\n toId?: string;\n}\n\nexport interface DistributionQuery {\n name?: string;\n start?: number;\n end?: number;\n}\n\n// ---------------------------------------------------------------------------\n// StorageHandle — write and read surface\n// ---------------------------------------------------------------------------\n\nexport interface StorageHandle {\n event(e: Event): Promise<void>;\n entity(e: Entity): Promise<void>;\n metric(m: MetricSample): Promise<void>;\n edge(e: Edge): Promise<void>;\n distribution(d: Distribution): Promise<void>;\n\n events(es: Event[], scope?: { names?: string[] }): Promise<void>;\n entities(es: Entity[], scope?: { types?: string[] }): Promise<void>;\n metrics(ms: MetricSample[], scope?: { names?: string[] }): Promise<void>;\n edges(es: Edge[], scope?: { kinds?: string[] }): Promise<void>;\n distributions(\n ds: Distribution[],\n scope?: { names?: string[] },\n ): Promise<void>;\n\n queryEvents(q: EventQuery): Promise<Event[]>;\n getEntity(type: string, id: string): Promise<Entity | null>;\n queryEntities(q: EntityQuery): Promise<Entity[]>;\n queryMetrics(q: MetricQuery): Promise<MetricSample[]>;\n traverse(q: EdgeQuery): Promise<Edge[]>;\n queryDistributions(q: DistributionQuery): Promise<Distribution[]>;\n\n // Deletes all rows in the given time-series shape whose timestamp column is\n // strictly less than `tsUnixMs`. Only covers append-only shapes (events,\n // metrics, distributions). Entities and edges are excluded because they hold\n // the latest known state per primary key — deleting by age would lose live\n // data. The right model for those shapes is \"expire when source disappears.\"\n deleteOlderThan(\n shape: 'events' | 'metrics' | 'distributions',\n tsUnixMs: number,\n ): Promise<{ rowsDeleted: number }>;\n}\n\n// ---------------------------------------------------------------------------\n// Credentials\n// ---------------------------------------------------------------------------\n\nexport interface CredentialField {\n description: string;\n auth?: 'none' | 'optional' | 'required';\n}\n\nexport type CredentialsSchema = Record<string, CredentialField>;\n\nexport type InferCredentials<TCreds extends CredentialsSchema> = {\n [K in keyof TCreds]: TCreds[K] extends { auth: 'required' }\n ? string\n : string | undefined;\n};\n\nexport type InferCredentialInput<TCreds extends CredentialsSchema> = {\n [K in keyof TCreds]: TCreds[K] extends { auth: 'required' }\n ? string | Secret\n : string | Secret | undefined;\n};\n\n// ---------------------------------------------------------------------------\n// Sync + Connector\n// ---------------------------------------------------------------------------\n\nexport interface SyncOptions {\n mode: 'full' | 'latest';\n since?: string;\n cursor?: unknown;\n}\n\nexport interface SyncResult {\n done: boolean;\n cursor?: unknown;\n transientError?: unknown;\n}\n\nexport interface Connector {\n readonly id: string;\n readonly credentials?: CredentialsSchema;\n serializeConfig(): Record<string, unknown>;\n sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult>;\n}\n\nexport interface ConnectorContext {\n observer?: RequestObserver;\n secretsResolver?: SecretsResolver;\n}\n\nexport interface ConnectorRequestOptions {\n resource: string;\n requestId?: string;\n}\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n signal?: AbortSignal;\n}\n\nexport abstract class BaseConnector<\n TSettings = unknown,\n TCreds extends CredentialsSchema = CredentialsSchema,\n> implements Connector {\n abstract readonly id: string;\n readonly credentials?: TCreds;\n\n protected settings: TSettings;\n protected creds: InferCredentials<TCreds>;\n private rawCredInput: InferCredentialInput<TCreds> | undefined;\n private ctx: ConnectorContext;\n\n constructor(\n settings: TSettings,\n creds?: InferCredentialInput<TCreds>,\n ctx?: ConnectorContext,\n ) {\n this.settings = settings;\n this.rawCredInput = creds;\n this.ctx = ctx ?? {};\n this.creds = creds\n ? (resolveSecrets(\n creds,\n this.ctx.secretsResolver ?? new EnvSecretsResolver(),\n ) as InferCredentials<TCreds>)\n : ({} as InferCredentials<TCreds>);\n }\n\n protected request<T = unknown>(\n req: HttpRequest,\n opts: ConnectorRequestOptions,\n ): Promise<HttpResponse<T>> {\n return sharedRequest<T>(req, {\n resource: opts.resource,\n requestId: opts.requestId,\n observer: this.ctx.observer,\n });\n }\n\n protected get<T = unknown>(\n url: string,\n opts: ConnectorRequestOptions & {\n headers?: Record<string, string>;\n signal?: AbortSignal;\n rateLimit?: HttpRequest['rateLimit'];\n },\n ): Promise<HttpResponse<T>> {\n return this.request<T>(\n {\n url,\n method: 'GET',\n headers: opts.headers,\n signal: opts.signal,\n rateLimit: opts.rateLimit,\n },\n { resource: opts.resource, requestId: opts.requestId },\n );\n }\n\n protected post<T = unknown>(\n url: string,\n opts: ConnectorRequestOptions & {\n body?: HttpRequest['body'];\n headers?: Record<string, string>;\n signal?: AbortSignal;\n rateLimit?: HttpRequest['rateLimit'];\n },\n ): Promise<HttpResponse<T>> {\n return this.request<T>(\n {\n url,\n method: 'POST',\n headers: opts.headers,\n body: opts.body,\n signal: opts.signal,\n rateLimit: opts.rateLimit,\n },\n { resource: opts.resource, requestId: opts.requestId },\n );\n }\n\n serializeConfig(): Record<string, unknown> {\n const config: Record<string, unknown> = {\n ...(this.settings as Record<string, unknown>),\n };\n if (this.rawCredInput) {\n for (const [key, value] of Object.entries(\n this.rawCredInput as Record<string, unknown>,\n )) {\n if (value !== undefined) {\n config[key] = value;\n }\n }\n }\n return config;\n }\n\n protected sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n protected async withRetry<T>(\n fn: (\n signal?: AbortSignal,\n ) => Promise<{ status: 'done'; value: T } | { status: 'retry' }>,\n options?: RetryPolicy,\n ): Promise<T | null> {\n const {\n maxAttempts = 10,\n initialDelayMs = 1000,\n maxDelayMs = 10000,\n signal,\n } = options ?? {};\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n signal?.throwIfAborted();\n const result = await fn(signal);\n if (result.status === 'done') {\n return result.value;\n }\n if (attempt < maxAttempts - 1) {\n const delay = Math.min(initialDelayMs * 2 ** attempt, maxDelayMs);\n await this.sleep(delay, signal);\n }\n }\n\n return null;\n }\n\n abstract sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult>;\n}\n\nexport function defineConnector<TSettings>() {\n return function <\n TCreds extends CredentialsSchema = Record<string, never>,\n >(def: {\n id: string;\n credentials?: TCreds;\n sync: (\n this: { settings: TSettings; creds: InferCredentials<TCreds> },\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ) => Promise<SyncResult>;\n }): {\n new (\n settings: TSettings,\n creds?: InferCredentialInput<TCreds>,\n ctx?: ConnectorContext,\n ): Connector;\n readonly id: string;\n readonly credentials: TCreds | undefined;\n } {\n class DynamicConnector extends BaseConnector<TSettings, TCreds> {\n static readonly id = def.id;\n static readonly credentials = def.credentials;\n\n readonly id = def.id;\n override readonly credentials = def.credentials;\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n return def.sync.call(\n { settings: this.settings, creds: this.creds },\n options,\n storage,\n signal,\n );\n }\n }\n\n return DynamicConnector as unknown as {\n new (\n settings: TSettings,\n creds?: InferCredentialInput<TCreds>,\n ctx?: ConnectorContext,\n ): Connector;\n readonly id: string;\n readonly credentials: TCreds | undefined;\n };\n };\n}\n","import type { SyncResult } from './connector';\n\nexport interface ChunkedSyncCursor<TPhase extends string, TPage> {\n phase: TPhase;\n page: TPage | null;\n}\n\nexport interface FetchPageResult<TPage> {\n items: unknown[];\n next: TPage | null;\n}\n\nexport interface ChunkedSyncOptions<TPhase extends string, TPage> {\n phases: readonly TPhase[];\n cursor: ChunkedSyncCursor<TPhase, TPage> | undefined;\n signal: AbortSignal | undefined;\n fetchPage: (\n phase: TPhase,\n page: TPage | null,\n signal: AbortSignal | undefined,\n ) => Promise<FetchPageResult<TPage>>;\n writeBatch: (\n phase: TPhase,\n items: unknown[],\n page: TPage | null,\n ) => Promise<void>;\n}\n\nexport async function paginateChunked<TPhase extends string, TPage>(\n opts: ChunkedSyncOptions<TPhase, TPage>,\n): Promise<SyncResult> {\n const { phases, cursor, signal, fetchPage, writeBatch } = opts;\n\n if (phases.length === 0) {\n return { done: true };\n }\n\n const resumeIdx = cursor ? phases.indexOf(cursor.phase) : -1;\n const hasKnownResumePhase = resumeIdx >= 0;\n const startIdx = hasKnownResumePhase ? resumeIdx : 0;\n\n for (let i = startIdx; i < phases.length; i++) {\n const phase = phases[i]!;\n let page: TPage | null =\n i === startIdx && hasKnownResumePhase ? cursor!.page : null;\n\n while (true) {\n if (signal?.aborted) {\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n };\n }\n let items: unknown[];\n let next: TPage | null;\n try {\n ({ items, next } = await fetchPage(phase, page, signal));\n } catch (err) {\n if (\n signal?.aborted ||\n (err instanceof Error && err.name === 'AbortError')\n ) {\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n };\n }\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n transientError: err,\n };\n }\n try {\n await writeBatch(phase, items, page);\n } catch (err) {\n if (\n signal?.aborted ||\n (err instanceof Error && err.name === 'AbortError')\n ) {\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n };\n }\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n transientError: err,\n };\n }\n if (next === null) {\n break;\n }\n page = next;\n }\n }\n\n return { done: true };\n}\n","import { z } from 'zod';\n\nexport const shapeSchema = z.enum([\n 'event',\n 'entity',\n 'metric',\n 'edge',\n 'distribution',\n]);\n\nexport const aggFnSchema = z.enum([\n 'count',\n 'sum',\n 'avg',\n 'min',\n 'max',\n 'latest',\n 'first',\n]);\n\nexport const filterOperatorSchema = z.enum([\n 'eq',\n 'neq',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'contains',\n]);\n\nexport const filterConditionSchema = z.object({\n field: z.string(),\n op: filterOperatorSchema,\n value: z.union([z.string(), z.number(), z.boolean()]),\n});\n\nexport const filterClauseSchema = z.union([\n filterConditionSchema,\n z.object({ or: z.array(filterConditionSchema) }),\n]);\n\nexport const groupBySchema = z.object({\n field: z.string(),\n granularity: z.enum(['hour', 'day', 'week', 'month']),\n});\n\nexport const computedMetricSchema = z\n .object({\n connectorId: z.string(),\n shape: shapeSchema,\n name: z.string().optional(),\n entityType: z.string().optional(),\n field: z.string().optional(),\n fn: aggFnSchema,\n window: z.string().optional(),\n filter: z.array(filterClauseSchema).optional(),\n groupBy: groupBySchema.optional(),\n })\n .refine((m) => m.fn === 'count' || m.field !== undefined, {\n message: 'field is required unless fn is \"count\"',\n path: ['field'],\n });\n\nconst titleField = z\n .string()\n .meta({ label: 'Title', description: 'Widget title.' });\n\nexport const statWidgetSchema = z.object({\n kind: z.literal('stat'),\n title: titleField,\n metric: computedMetricSchema.meta({\n label: 'Metric',\n description: 'Computed metric definition.',\n }),\n window: z\n .string()\n .optional()\n .meta({ label: 'Window', description: \"Time window, e.g. '7d'.\" }),\n compare: z\n .enum(['none', 'previous-period'])\n .default('none')\n .meta({ label: 'Compare', description: 'Comparison mode.' }),\n});\n\nexport const statusWidgetSchema = z.object({\n kind: z.literal('status'),\n title: titleField,\n source: z.string().meta({\n label: 'Source',\n description: 'Connector or data source reference.',\n }),\n});\n\nexport const timeseriesWidgetSchema = z.object({\n kind: z.literal('timeseries'),\n title: titleField,\n metric: computedMetricSchema.meta({\n label: 'Metric',\n description: 'Computed metric definition.',\n }),\n window: z\n .string()\n .meta({ label: 'Window', description: \"Time window, e.g. '30d'.\" }),\n granularity: z\n .enum(['hour', 'day', 'week'])\n .default('day')\n .meta({ label: 'Granularity', description: 'Time bucket size.' }),\n});\n\nexport const distributionWidgetSchema = z.object({\n kind: z.literal('distribution'),\n title: titleField,\n metric: computedMetricSchema.meta({\n label: 'Metric',\n description: 'Computed metric definition.',\n }),\n window: z\n .string()\n .meta({ label: 'Window', description: \"Time window, e.g. '7d'.\" }),\n});\n\nexport const widgetSchemas = {\n stat: statWidgetSchema,\n status: statusWidgetSchema,\n timeseries: timeseriesWidgetSchema,\n distribution: distributionWidgetSchema,\n} as const;\n\nexport const widgetSchema = z.discriminatedUnion('kind', [\n statWidgetSchema,\n statusWidgetSchema,\n timeseriesWidgetSchema,\n distributionWidgetSchema,\n]);\n\nexport type WidgetKind = keyof typeof widgetSchemas;\n\nexport function getWidgetSchema(kind: WidgetKind) {\n return widgetSchemas[kind];\n}\n","import type { Connector } from './connector';\nimport type { RetentionConfig } from './retention';\nimport { getWidgetSchema, widgetSchemas } from './widget-schemas';\nimport type { WidgetKind } from './widget-schemas';\n\n// ---------------------------------------------------------------------------\n// Aggregation functions\n// ---------------------------------------------------------------------------\n\nexport type AggFn =\n | 'count'\n | 'sum'\n | 'avg'\n | 'min'\n | 'max'\n | 'latest'\n | 'first';\n\n// ---------------------------------------------------------------------------\n// Shape\n// ---------------------------------------------------------------------------\n\nexport type Shape = 'event' | 'entity' | 'metric' | 'edge' | 'distribution';\n\n// ---------------------------------------------------------------------------\n// Filters\n// ---------------------------------------------------------------------------\n\nexport type FilterOperator =\n | 'eq'\n | 'neq'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'contains';\n\nexport interface FilterCondition {\n field: string;\n op: FilterOperator;\n value: string | number | boolean;\n}\n\nexport type FilterClause = FilterCondition | { or: FilterCondition[] };\n\n// ---------------------------------------------------------------------------\n// GroupBy\n// ---------------------------------------------------------------------------\n\nexport interface GroupBy {\n field: string;\n granularity: 'hour' | 'day' | 'week' | 'month';\n}\n\n// ---------------------------------------------------------------------------\n// Metric\n// ---------------------------------------------------------------------------\n\nexport interface Metric {\n connector: { id: string };\n shape: Shape;\n name?: string;\n entityType?: string;\n field?: string;\n fn: AggFn;\n window?: string;\n filter?: FilterClause[];\n groupBy?: GroupBy;\n}\n\nexport interface ComputedMetric {\n readonly connectorId: string;\n readonly shape: Shape;\n readonly name?: string;\n readonly entityType?: string;\n readonly field?: string;\n readonly fn: AggFn;\n readonly window?: string;\n readonly filter?: FilterClause[];\n readonly groupBy?: GroupBy;\n}\n\n// ---------------------------------------------------------------------------\n// Widget definition\n// ---------------------------------------------------------------------------\n\nexport interface StatWidget {\n kind: 'stat';\n title: string;\n metric: ComputedMetric;\n window?: string;\n compare?: 'none' | 'previous-period';\n}\n\nexport interface StatusWidget {\n kind: 'status';\n title: string;\n source: string;\n}\n\nexport interface TimeseriesWidget {\n kind: 'timeseries';\n title: string;\n metric: ComputedMetric;\n window: string;\n granularity?: 'hour' | 'day' | 'week';\n}\n\nexport interface DistributionWidget {\n kind: 'distribution';\n title: string;\n metric: ComputedMetric;\n window: string;\n}\n\nexport type Widget =\n | StatWidget\n | StatusWidget\n | TimeseriesWidget\n | DistributionWidget;\n\nexport type { WidgetKind };\n\n// ---------------------------------------------------------------------------\n// Dashboard config\n// ---------------------------------------------------------------------------\n\nexport interface ConfiguredConnector {\n connector: Connector;\n}\n\nexport interface Dashboard {\n widgets: Record<string, Widget>;\n}\n\nexport interface DashboardConfig {\n connectors: ConfiguredConnector[];\n dashboards: Record<string, Dashboard>;\n retention?: RetentionConfig;\n}\n\n// ---------------------------------------------------------------------------\n// defineDashboard\n// ---------------------------------------------------------------------------\n\nconst VALID_WIDGET_KINDS = new Set<string>(Object.keys(widgetSchemas));\n\nexport function defineDashboard(options: {\n widgets: Record<string, Widget>;\n}): Dashboard {\n for (const [key, widget] of Object.entries(options.widgets)) {\n if (!VALID_WIDGET_KINDS.has(widget.kind)) {\n throw new Error(\n `Widget \"${key}\": unknown kind \"${widget.kind}\". Must be one of: ${[...VALID_WIDGET_KINDS].join(', ')}`,\n );\n }\n const schema = getWidgetSchema(widget.kind as WidgetKind);\n const result = schema.safeParse(widget);\n if (!result.success) {\n throw new Error(\n `Widget \"${key}\" (kind \"${widget.kind}\"): ${result.error.issues.map((i) => i.message).join('; ')}`,\n );\n }\n }\n return { widgets: options.widgets };\n}\n\n// ---------------------------------------------------------------------------\n// defineMetric\n// ---------------------------------------------------------------------------\n\nexport function defineMetric(options: Metric): ComputedMetric {\n return {\n connectorId: options.connector.id,\n shape: options.shape,\n name: options.name,\n entityType: options.entityType,\n field: options.field,\n fn: options.fn,\n window: options.window,\n filter: options.filter,\n groupBy: options.groupBy,\n };\n}\n\n// ---------------------------------------------------------------------------\n// defineConfig\n// ---------------------------------------------------------------------------\n\nconst VALID_SHAPES = new Set<string>([\n 'event',\n 'entity',\n 'metric',\n 'edge',\n 'distribution',\n]);\nconst VALID_FNS = new Set<string>([\n 'count',\n 'sum',\n 'avg',\n 'min',\n 'max',\n 'latest',\n 'first',\n]);\n\nconst SAFE_KEY_RE = /^[a-zA-Z0-9_-]+$/;\n\nfunction validateConfig(config: DashboardConfig): void {\n if (config.retention) {\n const { maxAge, maxSize, floor, intervalMs } = config.retention;\n if (maxAge !== undefined && (!Number.isFinite(maxAge) || maxAge < 0)) {\n throw new Error('retention.maxAge must be a finite number >= 0');\n }\n if (maxSize !== undefined && (!Number.isInteger(maxSize) || maxSize < 0)) {\n throw new Error('retention.maxSize must be an integer >= 0');\n }\n if (floor !== undefined && (!Number.isInteger(floor) || floor < 0)) {\n throw new Error('retention.floor must be an integer >= 0');\n }\n if (\n intervalMs !== undefined &&\n (!Number.isFinite(intervalMs) || intervalMs <= 0)\n ) {\n throw new Error('retention.intervalMs must be a finite number > 0');\n }\n }\n\n if (\n !config.dashboards ||\n typeof config.dashboards !== 'object' ||\n Array.isArray(config.dashboards)\n ) {\n throw new Error(\n 'defineConfig: config must include a \"dashboards\" record — did you mean to migrate from the old flat \"widgets\" shape?',\n );\n }\n\n const connectorIds = new Set(config.connectors.map((e) => e.connector.id));\n\n for (const [dashboardKey, dashboard] of Object.entries(config.dashboards)) {\n if (\n !dashboard.widgets ||\n typeof dashboard.widgets !== 'object' ||\n Array.isArray(dashboard.widgets)\n ) {\n throw new Error(\n `Dashboard \"${dashboardKey}\" must define a \"widgets\" record`,\n );\n }\n\n if (!SAFE_KEY_RE.test(dashboardKey)) {\n throw new Error(\n `Dashboard key \"${dashboardKey}\" contains URL-unsafe characters; use only letters, digits, hyphens, and underscores`,\n );\n }\n\n for (const [widgetKey, widget] of Object.entries(dashboard.widgets)) {\n const ref = `Dashboard \"${dashboardKey}\", widget \"${widgetKey}\"`;\n\n if (!SAFE_KEY_RE.test(widgetKey)) {\n throw new Error(\n `${ref}: widget key contains URL-unsafe characters; use only letters, digits, hyphens, and underscores`,\n );\n }\n\n if (widget.kind === 'status') {\n continue;\n }\n\n const { connectorId, shape, fn } = widget.metric;\n\n if (!connectorIds.has(connectorId)) {\n throw new Error(\n `${ref}: connector \"${connectorId}\" is not listed in connectors`,\n );\n }\n\n if (!VALID_SHAPES.has(shape)) {\n throw new Error(`${ref}: invalid shape \"${shape}\"`);\n }\n\n if (!VALID_FNS.has(fn)) {\n throw new Error(`${ref}: invalid fn \"${fn}\"`);\n }\n }\n }\n}\n\nexport function defineConfig(config: DashboardConfig): DashboardConfig {\n validateConfig(config);\n return config;\n}\n","export type SyncStatus = 'idle' | 'queued' | 'running' | 'succeeded' | 'failed';\n\nexport interface SyncState {\n status: SyncStatus;\n queuedAt: string | null;\n startedAt: string | null;\n lastSyncAt: string | null;\n lastError: string | null;\n}\n\nexport const ACTIVE_SYNC_STATUSES: ReadonlySet<SyncStatus> = new Set([\n 'queued',\n 'running',\n]);\n\nexport function isSyncActive(status: SyncStatus): boolean {\n return ACTIVE_SYNC_STATUSES.has(status);\n}\n","import type {\n Distribution,\n Event,\n MetricSample,\n StorageHandle,\n} from './connector';\n\n// ---------------------------------------------------------------------------\n// RetentionConfig\n// ---------------------------------------------------------------------------\n\nexport interface RetentionConfig {\n maxAge?: number;\n maxSize?: number;\n floor?: number;\n intervalMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// RetentionDeletionPlan — rows eligible for deletion across time-series shapes\n// ---------------------------------------------------------------------------\n\nexport interface RetentionDeletionPlan {\n events: Event[];\n metrics: MetricSample[];\n distributions: Distribution[];\n}\n\n// ---------------------------------------------------------------------------\n// selectForDeletion — pure computation\n//\n// Receives rows pre-sorted newest-first (descending by timestamp).\n// Returns the subset that should be deleted given the policy.\n//\n// Rules applied in order:\n// 1. Rows beyond maxSize are candidates.\n// 2. Rows older than maxAge milliseconds are candidates.\n// 3. Rows within the newest `floor` positions are always kept (overrides 1 & 2).\n// ---------------------------------------------------------------------------\n\nexport function selectForDeletion<T>(\n rows: T[],\n getTs: (row: T) => number,\n config: RetentionConfig,\n nowMs: number = Date.now(),\n): T[] {\n const { maxAge, maxSize, floor = 0 } = config;\n\n if (maxAge === undefined && maxSize === undefined) {\n return [];\n }\n\n const toDelete: T[] = [];\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]!;\n if (i < floor) {\n continue;\n }\n\n const overSize = maxSize !== undefined && i >= maxSize;\n const tooOld = maxAge !== undefined && getTs(row) < nowMs - maxAge;\n\n if (overSize || tooOld) {\n toDelete.push(row);\n }\n }\n\n return toDelete;\n}\n\n// ---------------------------------------------------------------------------\n// computeRetention — async, queries the handle and returns deletion candidates\n//\n// Only covers time-series shapes (events, metrics, distributions) since those\n// grow unboundedly via append. Entities and edges are upsert-keyed and do not\n// accumulate the same way.\n// ---------------------------------------------------------------------------\n\nexport async function computeRetention(\n handle: StorageHandle,\n config: RetentionConfig,\n nowMs: number = Date.now(),\n): Promise<RetentionDeletionPlan> {\n const [events, metrics, distributions] = await Promise.all([\n handle.queryEvents({}),\n handle.queryMetrics({}),\n handle.queryDistributions({}),\n ]);\n\n const sortedEvents = [...events].sort((a, b) => b.start_ts - a.start_ts);\n const sortedMetrics = [...metrics].sort((a, b) => b.ts - a.ts);\n const sortedDistributions = [...distributions].sort((a, b) => b.ts - a.ts);\n\n return {\n events: selectForDeletion(sortedEvents, (e) => e.start_ts, config, nowMs),\n metrics: selectForDeletion(sortedMetrics, (m) => m.ts, config, nowMs),\n distributions: selectForDeletion(\n sortedDistributions,\n (d) => d.ts,\n config,\n nowMs,\n ),\n };\n}\n","import { z } from 'zod';\n\nexport type ConfigFieldsSchema = z.ZodObject<z.ZodRawShape>;\n\nexport function defineConfigFields<T extends z.ZodRawShape>(\n schema: z.ZodObject<T>,\n): z.ZodObject<T> {\n if (!(schema instanceof z.ZodObject)) {\n throw new Error(\n `configFields must be a Zod object schema (z.object({...})). Received: ${Object.prototype.toString.call(schema)}`,\n );\n }\n return schema;\n}\n","import type { ComputedMetric } from './config';\nimport type { StorageHandle } from './connector';\n\ntype FilterClause = NonNullable<ComputedMetric['filter']>[number];\ntype FilterCondition = Exclude<FilterClause, { or: unknown[] }>;\n\nfunction matchesCondition(\n record: Record<string, unknown>,\n cond: FilterCondition,\n): boolean {\n const val = record[cond.field];\n switch (cond.op) {\n case 'eq':\n return val === cond.value;\n case 'neq':\n return val !== cond.value;\n case 'gt':\n if (typeof val !== 'number' || typeof cond.value !== 'number') {\n return false;\n }\n return val > cond.value;\n case 'gte':\n if (typeof val !== 'number' || typeof cond.value !== 'number') {\n return false;\n }\n return val >= cond.value;\n case 'lt':\n if (typeof val !== 'number' || typeof cond.value !== 'number') {\n return false;\n }\n return val < cond.value;\n case 'lte':\n if (typeof val !== 'number' || typeof cond.value !== 'number') {\n return false;\n }\n return val <= cond.value;\n case 'contains':\n return String(val).includes(String(cond.value));\n default:\n return false;\n }\n}\n\nfunction applyFilter(\n record: Record<string, unknown>,\n filter: ComputedMetric['filter'],\n): boolean {\n if (!filter) {\n return true;\n }\n for (const clause of filter) {\n if ('or' in clause) {\n if (!clause.or.some((cond) => matchesCondition(record, cond))) {\n return false;\n }\n } else {\n if (!matchesCondition(record, clause)) {\n return false;\n }\n }\n }\n return true;\n}\n\nconst WINDOW_MS: Record<string, number> = {\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n m: 2_592_000_000,\n};\n\nfunction parseWindowMs(window: string): number | null {\n const match = /^(\\d+)(h|d|w|m)$/.exec(window);\n if (!match) {\n return null;\n }\n const unitMs = WINDOW_MS[match[2]!];\n if (unitMs === undefined) {\n return null;\n }\n return parseInt(match[1]!) * unitMs;\n}\n\nfunction truncateToGranularity(ts: number, granularity: string): string {\n const d = new Date(ts);\n switch (granularity) {\n case 'hour':\n d.setUTCMinutes(0, 0, 0);\n return d.toISOString();\n case 'day':\n d.setUTCHours(0, 0, 0, 0);\n return d.toISOString().slice(0, 10);\n case 'week': {\n d.setUTCDate(d.getUTCDate() - d.getUTCDay());\n d.setUTCHours(0, 0, 0, 0);\n return d.toISOString().slice(0, 10);\n }\n case 'month':\n d.setUTCDate(1);\n d.setUTCHours(0, 0, 0, 0);\n return d.toISOString().slice(0, 7);\n default:\n return d.toISOString().slice(0, 10);\n }\n}\n\nfunction computeAgg(\n records: Record<string, unknown>[],\n field: string | undefined,\n fn: string,\n): unknown {\n if (fn === 'count') {\n return records.length;\n }\n if (field === undefined) {\n throw new Error(`computeAgg: fn \"${fn}\" requires a field`);\n }\n if (fn === 'latest') {\n return records.at(-1)?.[field] ?? null;\n }\n if (fn === 'first') {\n return records[0]?.[field] ?? null;\n }\n const values = records\n .map((r) => r[field])\n .filter((v) => v !== undefined && v !== null);\n const nonNumeric = values.find((v) => typeof v !== 'number');\n if (nonNumeric !== undefined) {\n throw new Error(\n `computeAgg: fn \"${fn}\" requires numeric values for field \"${field}\", got ${typeof nonNumeric} (${String(nonNumeric)})`,\n );\n }\n const numbers = values as number[];\n if (fn === 'sum') {\n return numbers.reduce((a, b) => a + b, 0);\n }\n if (fn === 'avg') {\n return numbers.length > 0\n ? numbers.reduce((a, b) => a + b, 0) / numbers.length\n : null;\n }\n if (fn === 'min') {\n return numbers.length > 0\n ? numbers.reduce((a, b) => (a < b ? a : b))\n : null;\n }\n if (fn === 'max') {\n return numbers.length > 0\n ? numbers.reduce((a, b) => (a > b ? a : b))\n : null;\n }\n return null;\n}\n\nfunction sortByTs(\n records: Record<string, unknown>[],\n tsField: string,\n): Record<string, unknown>[] {\n return [...records].sort((a, b) => {\n return (a[tsField] as number) - (b[tsField] as number);\n });\n}\n\nfunction computeGroupBy(\n records: Record<string, unknown>[],\n metric: ComputedMetric,\n tsField: string,\n): unknown {\n const { field, granularity } = metric.groupBy!;\n const groups = new Map<string, Record<string, unknown>[]>();\n\n for (const record of records) {\n const ts = record[field] as number | undefined;\n if (ts === undefined || typeof ts !== 'number') {\n continue;\n }\n const key = truncateToGranularity(ts, granularity);\n if (!groups.has(key)) {\n groups.set(key, []);\n }\n groups.get(key)!.push(record);\n }\n\n return [...groups.entries()]\n .map(([key, groupRecords]) => ({\n date: key,\n value: computeAgg(\n sortByTs(groupRecords, tsField),\n metric.field,\n metric.fn,\n ),\n }))\n .sort((a, b) => (a.date < b.date ? -1 : 1));\n}\n\nfunction getTimestampField(shape: string): string {\n switch (shape) {\n case 'event':\n return 'start_ts';\n case 'metric':\n case 'distribution':\n return 'ts';\n case 'entity':\n case 'edge':\n return 'updated_at';\n default:\n return 'start_ts';\n }\n}\n\nexport async function computeMetric(\n storage: StorageHandle,\n metric: ComputedMetric,\n): Promise<unknown> {\n const tsField = getTimestampField(metric.shape);\n\n const windowMs = metric.window ? parseWindowMs(metric.window) : null;\n const windowStart = windowMs !== null ? Date.now() - windowMs : undefined;\n\n let records: Record<string, unknown>[];\n\n switch (metric.shape) {\n case 'event': {\n const events = await storage.queryEvents({\n name: metric.name,\n start: windowStart,\n });\n records = events.map((e) => ({\n ...e.attributes,\n name: e.name,\n start_ts: e.start_ts,\n end_ts: e.end_ts,\n }));\n break;\n }\n\n case 'entity': {\n const type = metric.entityType ?? metric.name ?? '';\n const entities = await storage.queryEntities({ type });\n records = entities.map((e) => ({\n ...e.attributes,\n type: e.type,\n id: e.id,\n updated_at: e.updated_at,\n }));\n if (windowStart !== undefined) {\n records = records.filter((r) => (r[tsField] as number) >= windowStart);\n }\n break;\n }\n\n case 'metric': {\n const metrics = await storage.queryMetrics({\n name: metric.name,\n start: windowStart,\n });\n records = metrics.map((m) => ({\n ...m.attributes,\n name: m.name,\n ts: m.ts,\n value: m.value,\n }));\n break;\n }\n\n case 'edge': {\n const edges = await storage.traverse({ kind: metric.name });\n records = edges.map((e) => ({\n ...e.attributes,\n from_type: e.from_type,\n from_id: e.from_id,\n kind: e.kind,\n to_type: e.to_type,\n to_id: e.to_id,\n updated_at: e.updated_at,\n }));\n if (windowStart !== undefined) {\n records = records.filter((r) => (r[tsField] as number) >= windowStart);\n }\n break;\n }\n\n case 'distribution': {\n const distributions = await storage.queryDistributions({\n name: metric.name,\n start: windowStart,\n });\n records = distributions.map((d) => ({\n ...d.attributes,\n name: d.name,\n ts: d.ts,\n kind: d.kind,\n data: d.data,\n }));\n break;\n }\n\n default:\n return null;\n }\n\n const filtered = records.filter((r) => applyFilter(r, metric.filter));\n const sorted = sortByTs(filtered, tsField);\n\n if (metric.groupBy) {\n return computeGroupBy(sorted, metric, tsField);\n }\n\n return computeAgg(sorted, metric.field, metric.fn);\n}\n","import { computeMetric } from './compute';\nimport type { ConfiguredConnector, Widget } from './config';\nimport type { ServerStorage } from './server-storage';\nimport type { CachedWidget } from './wire';\n\nexport async function resolveWidget(\n widgetId: string,\n widget: Widget,\n connectors: ConfiguredConnector[] | readonly string[] | undefined,\n storage: ServerStorage,\n): Promise<CachedWidget | undefined> {\n if (widget.kind === 'status') {\n return {\n widgetId,\n connectorId: widget.source,\n data: null,\n cachedAt: null,\n };\n }\n const { connectorId } = widget.metric;\n if (\n connectors !== undefined &&\n !isAllowedConnector(connectors, connectorId)\n ) {\n return undefined;\n }\n const handle = storage.getStorageHandle(connectorId);\n const data = await computeMetric(handle, widget.metric);\n return {\n widgetId,\n connectorId,\n data,\n cachedAt: (await storage.getSyncState()).lastSyncAt,\n };\n}\n\nfunction isAllowedConnector(\n connectors: ConfiguredConnector[] | readonly string[],\n connectorId: string,\n): boolean {\n if (connectors.length === 0) {\n return false;\n }\n if (typeof connectors[0] === 'string') {\n return (connectors as readonly string[]).includes(connectorId);\n }\n return (connectors as ConfiguredConnector[]).some(\n (e) => e.connector.id === connectorId,\n );\n}\n","import type { StorageHandle } from './connector';\n\nexport function withAbortSignal(\n handle: StorageHandle,\n signal: AbortSignal,\n): StorageHandle {\n let warned = false;\n const warnOnce = (method: string): void => {\n if (warned) {\n return;\n }\n warned = true;\n console.warn(\n `[rawdash storage] dropping post-abort write '${method}' — connector continued writing after AbortSignal fired`,\n );\n };\n\n return {\n event: async (e) => {\n if (signal.aborted) {\n warnOnce('event');\n return;\n }\n await handle.event(e);\n },\n entity: async (e) => {\n if (signal.aborted) {\n warnOnce('entity');\n return;\n }\n await handle.entity(e);\n },\n metric: async (m) => {\n if (signal.aborted) {\n warnOnce('metric');\n return;\n }\n await handle.metric(m);\n },\n edge: async (e) => {\n if (signal.aborted) {\n warnOnce('edge');\n return;\n }\n await handle.edge(e);\n },\n distribution: async (d) => {\n if (signal.aborted) {\n warnOnce('distribution');\n return;\n }\n await handle.distribution(d);\n },\n events: async (es, scope) => {\n if (signal.aborted) {\n warnOnce('events');\n return;\n }\n await handle.events(es, scope);\n },\n entities: async (es, scope) => {\n if (signal.aborted) {\n warnOnce('entities');\n return;\n }\n await handle.entities(es, scope);\n },\n metrics: async (ms, scope) => {\n if (signal.aborted) {\n warnOnce('metrics');\n return;\n }\n await handle.metrics(ms, scope);\n },\n edges: async (es, scope) => {\n if (signal.aborted) {\n warnOnce('edges');\n return;\n }\n await handle.edges(es, scope);\n },\n distributions: async (ds, scope) => {\n if (signal.aborted) {\n warnOnce('distributions');\n return;\n }\n await handle.distributions(ds, scope);\n },\n deleteOlderThan: async (shape, tsUnixMs) => {\n if (signal.aborted) {\n warnOnce('deleteOlderThan');\n return { rowsDeleted: 0 };\n }\n return handle.deleteOlderThan(shape, tsUnixMs);\n },\n queryEvents: (q) => handle.queryEvents(q),\n getEntity: (type, id) => handle.getEntity(type, id),\n queryEntities: (q) => handle.queryEntities(q),\n queryMetrics: (q) => handle.queryMetrics(q),\n traverse: (q) => handle.traverse(q),\n queryDistributions: (q) => handle.queryDistributions(q),\n };\n}\n","import type {\n Distribution,\n DistributionQuery,\n Edge,\n EdgeQuery,\n Entity,\n EntityQuery,\n Event,\n EventQuery,\n MetricQuery,\n MetricSample,\n StorageHandle,\n} from './connector';\nimport type { SyncState } from './engine';\nimport type { GetStorageHandleOptions, ServerStorage } from './server-storage';\nimport { withAbortSignal } from './storage-handle-guard';\n\nexport class InMemoryStorage implements ServerStorage {\n private eventStore = new Map<string, Event[]>();\n private entityStore = new Map<string, Map<string, Map<string, Entity>>>();\n private metricStore = new Map<string, MetricSample[]>();\n private edgeStore = new Map<string, Edge[]>();\n private distributionStore = new Map<string, Distribution[]>();\n private syncState: SyncState = {\n status: 'idle',\n queuedAt: null,\n startedAt: null,\n lastSyncAt: null,\n lastError: null,\n };\n\n getStorageHandle(\n connectorId: string,\n options?: GetStorageHandleOptions,\n ): StorageHandle {\n const handle = this.buildHandle(connectorId);\n return options?.signal ? withAbortSignal(handle, options.signal) : handle;\n }\n\n private buildHandle(connectorId: string): StorageHandle {\n const getEntityMap = (): Map<string, Map<string, Entity>> => {\n if (!this.entityStore.has(connectorId)) {\n this.entityStore.set(connectorId, new Map());\n }\n return this.entityStore.get(connectorId)!;\n };\n\n const upsertEntities = (es: Entity[]): void => {\n const byType = getEntityMap();\n for (const e of es) {\n if (!byType.has(e.type)) {\n byType.set(e.type, new Map());\n }\n byType.get(e.type)!.set(e.id, e);\n }\n };\n\n const upsertEdges = (es: Edge[]): void => {\n const existing = this.edgeStore.get(connectorId) ?? [];\n const index = new Map<string, number>();\n for (let i = 0; i < existing.length; i++) {\n const e = existing[i]!;\n index.set(\n `${e.from_type}:${e.from_id}:${e.kind}:${e.to_type}:${e.to_id}`,\n i,\n );\n }\n for (const e of es) {\n const key = `${e.from_type}:${e.from_id}:${e.kind}:${e.to_type}:${e.to_id}`;\n const idx = index.get(key);\n if (idx !== undefined) {\n existing[idx] = e;\n } else {\n index.set(key, existing.length);\n existing.push(e);\n }\n }\n this.edgeStore.set(connectorId, existing);\n };\n\n return {\n event: async (e) => {\n if (!this.eventStore.has(connectorId)) {\n this.eventStore.set(connectorId, []);\n }\n this.eventStore.get(connectorId)!.push(e);\n },\n\n entity: async (e) => {\n upsertEntities([e]);\n },\n\n metric: async (m) => {\n if (!this.metricStore.has(connectorId)) {\n this.metricStore.set(connectorId, []);\n }\n this.metricStore.get(connectorId)!.push(m);\n },\n\n edge: async (e) => {\n upsertEdges([e]);\n },\n\n distribution: async (d) => {\n if (!this.distributionStore.has(connectorId)) {\n this.distributionStore.set(connectorId, []);\n }\n this.distributionStore.get(connectorId)!.push(d);\n },\n\n events: async (es, scope) => {\n const names = new Set(scope?.names ?? es.map((e) => e.name));\n const kept = (this.eventStore.get(connectorId) ?? []).filter(\n (e) => !names.has(e.name),\n );\n this.eventStore.set(connectorId, [...kept, ...es]);\n },\n\n entities: async (es, scope) => {\n const byType = getEntityMap();\n const types = new Set(scope?.types ?? es.map((e) => e.type));\n for (const type of types) {\n byType.set(type, new Map());\n }\n upsertEntities(es);\n },\n\n metrics: async (ms, scope) => {\n const names = new Set(scope?.names ?? ms.map((m) => m.name));\n const kept = (this.metricStore.get(connectorId) ?? []).filter(\n (m) => !names.has(m.name),\n );\n this.metricStore.set(connectorId, [...kept, ...ms]);\n },\n\n edges: async (es, scope) => {\n const kinds = new Set(scope?.kinds ?? es.map((e) => e.kind));\n const kept = (this.edgeStore.get(connectorId) ?? []).filter(\n (e) => !kinds.has(e.kind),\n );\n this.edgeStore.set(connectorId, kept);\n upsertEdges(es);\n },\n\n distributions: async (ds, scope) => {\n const names = new Set(scope?.names ?? ds.map((d) => d.name));\n const kept = (this.distributionStore.get(connectorId) ?? []).filter(\n (d) => !names.has(d.name),\n );\n this.distributionStore.set(connectorId, [...kept, ...ds]);\n },\n\n queryEvents: async (q: EventQuery) => {\n let results = this.eventStore.get(connectorId) ?? [];\n if (q.name !== undefined) {\n results = results.filter((e) => e.name === q.name);\n }\n if (q.start !== undefined) {\n results = results.filter((e) => e.start_ts >= q.start!);\n }\n if (q.end !== undefined) {\n results = results.filter((e) => e.start_ts <= q.end!);\n }\n return results;\n },\n\n getEntity: async (type: string, id: string) => {\n return getEntityMap().get(type)?.get(id) ?? null;\n },\n\n queryEntities: async (q: EntityQuery) => {\n const byType = getEntityMap().get(q.type);\n if (!byType) {\n return [];\n }\n return Array.from(byType.values());\n },\n\n queryMetrics: async (q: MetricQuery) => {\n let results = this.metricStore.get(connectorId) ?? [];\n if (q.name !== undefined) {\n results = results.filter((m) => m.name === q.name);\n }\n if (q.start !== undefined) {\n results = results.filter((m) => m.ts >= q.start!);\n }\n if (q.end !== undefined) {\n results = results.filter((m) => m.ts <= q.end!);\n }\n return results;\n },\n\n traverse: async (q: EdgeQuery) => {\n let results = this.edgeStore.get(connectorId) ?? [];\n if (q.fromType !== undefined) {\n results = results.filter((e) => e.from_type === q.fromType);\n }\n if (q.fromId !== undefined) {\n results = results.filter((e) => e.from_id === q.fromId);\n }\n if (q.kind !== undefined) {\n results = results.filter((e) => e.kind === q.kind);\n }\n if (q.toType !== undefined) {\n results = results.filter((e) => e.to_type === q.toType);\n }\n if (q.toId !== undefined) {\n results = results.filter((e) => e.to_id === q.toId);\n }\n return results;\n },\n\n queryDistributions: async (q: DistributionQuery) => {\n let results = this.distributionStore.get(connectorId) ?? [];\n if (q.name !== undefined) {\n results = results.filter((d) => d.name === q.name);\n }\n if (q.start !== undefined) {\n results = results.filter((d) => d.ts >= q.start!);\n }\n if (q.end !== undefined) {\n results = results.filter((d) => d.ts <= q.end!);\n }\n return results;\n },\n\n deleteOlderThan: async (shape, tsUnixMs) => {\n if (shape === 'events') {\n const before = this.eventStore.get(connectorId) ?? [];\n const after = before.filter((e) => e.start_ts >= tsUnixMs);\n this.eventStore.set(connectorId, after);\n return { rowsDeleted: before.length - after.length };\n } else if (shape === 'metrics') {\n const before = this.metricStore.get(connectorId) ?? [];\n const after = before.filter((m) => m.ts >= tsUnixMs);\n this.metricStore.set(connectorId, after);\n return { rowsDeleted: before.length - after.length };\n } else if (shape === 'distributions') {\n const before = this.distributionStore.get(connectorId) ?? [];\n const after = before.filter((d) => d.ts >= tsUnixMs);\n this.distributionStore.set(connectorId, after);\n return { rowsDeleted: before.length - after.length };\n } else {\n throw new Error(\n `Unsupported shape for deleteOlderThan: ${String(shape)}`,\n );\n }\n },\n };\n }\n\n async getSyncState(): Promise<SyncState> {\n return { ...this.syncState };\n }\n\n async markSyncQueued(): Promise<boolean> {\n if (\n this.syncState.status === 'queued' ||\n this.syncState.status === 'running'\n ) {\n return false;\n }\n this.syncState = {\n ...this.syncState,\n status: 'queued',\n queuedAt: new Date().toISOString(),\n startedAt: null,\n };\n return true;\n }\n\n async markSyncRunning(): Promise<boolean> {\n if (this.syncState.status !== 'queued') {\n return false;\n }\n this.syncState = {\n ...this.syncState,\n status: 'running',\n startedAt: new Date().toISOString(),\n };\n return true;\n }\n\n async markSyncSucceeded(): Promise<void> {\n const now = new Date().toISOString();\n this.syncState = {\n status: 'succeeded',\n queuedAt: null,\n startedAt: null,\n lastSyncAt: now,\n lastError: null,\n };\n }\n\n async markSyncFailed(error: string): Promise<void> {\n this.syncState = {\n ...this.syncState,\n status: 'failed',\n queuedAt: null,\n startedAt: null,\n lastError: error,\n };\n }\n}\n","import { z } from 'zod';\n\nimport type { DashboardConfig } from './config';\n\nexport const wireConnectorSchema = z.object({\n name: z.string(),\n connectorId: z.string(),\n displayName: z.string().optional(),\n config: z.record(z.string(), z.unknown()),\n syncIntervalSeconds: z.number().optional(),\n enabled: z.boolean().optional(),\n});\n\nexport const wireDashboardSchema = z.object({\n id: z.string().optional(),\n name: z.string(),\n slug: z.string(),\n config: z.record(z.string(), z.unknown()),\n});\n\nexport const wireConfigSchema = z.object({\n connectors: z.array(wireConnectorSchema).optional(),\n dashboards: z.array(wireDashboardSchema).optional(),\n});\n\nexport type WireConnector = z.infer<typeof wireConnectorSchema>;\nexport type WireDashboard = z.infer<typeof wireDashboardSchema>;\nexport type WireConfig = z.infer<typeof wireConfigSchema>;\n\nexport function toWireConfig(config: DashboardConfig): WireConfig {\n return {\n connectors: config.connectors.map(({ connector }) => ({\n name: connector.id,\n connectorId: connector.id,\n displayName: connector.id,\n config: connector.serializeConfig(),\n syncIntervalSeconds: 300,\n enabled: true,\n })),\n dashboards: Object.entries(config.dashboards).map(([id, dash]) => ({\n id,\n name: id,\n slug: id,\n config: { widgets: dash.widgets },\n })),\n };\n}\n"],"mappings":"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","names":["err","z","z"]}
|
|
1
|
+
{"version":3,"sources":["../../connector-shared/src/errors.ts","../../connector-shared/src/retry.ts","../../connector-shared/src/version.ts","../../connector-shared/src/request.ts","../../connector-shared/src/rate-limit.ts","../../connector-shared/src/pagination.ts","../src/secrets.ts","../src/connector.ts","../src/paginate-chunked.ts","../src/widget-schemas.ts","../src/config.ts","../src/engine.ts","../src/retention.ts","../src/config-fields.ts","../src/compute.ts","../src/resolve-widget.ts","../src/registry.ts","../src/storage-handle-guard.ts","../src/in-memory-storage.ts","../src/wire-config.ts"],"sourcesContent":["import type { HttpResponse } from './types';\n\nexport type HttpErrorKind =\n | 'transient'\n | 'rate_limit'\n | 'auth'\n | 'upstream_bug'\n | 'client_bug';\n\nexport abstract class HttpClientError extends Error {\n abstract readonly kind: HttpErrorKind;\n readonly response?: HttpResponse;\n\n constructor(message: string, response?: HttpResponse) {\n super(message);\n this.name = new.target.name;\n this.response = response;\n }\n}\n\nexport class TransientError extends HttpClientError {\n readonly kind = 'transient' as const;\n}\n\nexport class RateLimitError extends HttpClientError {\n readonly kind = 'rate_limit' as const;\n readonly retryAfter?: Date;\n\n constructor(message: string, response?: HttpResponse, retryAfter?: Date) {\n super(message, response);\n this.retryAfter = retryAfter;\n }\n}\n\nexport class AuthError extends HttpClientError {\n readonly kind = 'auth' as const;\n}\n\nexport class UpstreamBugError extends HttpClientError {\n readonly kind = 'upstream_bug' as const;\n}\n\nexport class ClientBugError extends HttpClientError {\n readonly kind = 'client_bug' as const;\n}\n\nexport function classifyStatus(status: number): HttpErrorKind {\n if (status === 429) {\n return 'rate_limit';\n }\n if (status === 401 || status === 403) {\n return 'auth';\n }\n if (status === 408) {\n return 'transient';\n }\n if (status >= 500) {\n return 'upstream_bug';\n }\n if (status >= 400) {\n return 'client_bug';\n }\n return 'client_bug';\n}\n\nexport function errorForStatus(\n message: string,\n response: HttpResponse,\n retryAfter?: Date,\n): HttpClientError {\n const kind = classifyStatus(response.status);\n switch (kind) {\n case 'rate_limit':\n return new RateLimitError(message, response, retryAfter);\n case 'auth':\n return new AuthError(message, response);\n case 'transient':\n return new TransientError(message, response);\n case 'upstream_bug':\n return new UpstreamBugError(message, response);\n case 'client_bug':\n return new ClientBugError(message, response);\n }\n}\n","import { HttpClientError, RateLimitError, TransientError } from './errors';\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n retryOn?: (status: number | null, err?: Error) => boolean;\n}\n\nexport const defaultRetryOn = (status: number | null, err?: Error): boolean => {\n if (err instanceof RateLimitError) {\n return true;\n }\n if (err instanceof TransientError) {\n return true;\n }\n if (status === null) {\n return err instanceof Error && !(err instanceof HttpClientError);\n }\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return false;\n};\n\nexport function backoffDelayMs(\n attempt: number,\n policy: Required<Pick<RetryPolicy, 'initialDelayMs' | 'maxDelayMs'>>,\n): number {\n const base = policy.initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, policy.maxDelayMs);\n}\n\nexport function parseRetryAfter(\n headerValue: string | null,\n now: Date = new Date(),\n): Date | undefined {\n if (!headerValue) {\n return undefined;\n }\n const trimmed = headerValue.trim();\n if (/^\\d+$/.test(trimmed)) {\n return new Date(now.getTime() + Number(trimmed) * 1000);\n }\n const parsed = Date.parse(trimmed);\n if (Number.isNaN(parsed)) {\n return undefined;\n }\n return new Date(parsed);\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","export const HTTP_CLIENT_VERSION = '0.0.0';\n\nexport const DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n","import {\n AuthError,\n ClientBugError,\n HttpClientError,\n RateLimitError,\n TransientError,\n UpstreamBugError,\n errorForStatus,\n} from './errors';\nimport { defaultRetryOn, parseRetryAfter, sleep } from './retry';\nimport type { FetchLike, HttpMethod, HttpRequest, HttpResponse } from './types';\nimport { DEFAULT_USER_AGENT } from './version';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY_MS = 1000;\nconst DEFAULT_MAX_DELAY_MS = 60_000;\nconst OBSERVER_TIMEOUT_MS = 250;\n\nexport interface RequestObservation {\n url: string;\n method: HttpMethod;\n status: number;\n resource: string;\n requestId: string;\n body: unknown;\n}\n\nexport type RequestObserver = (\n event: RequestObservation,\n) => void | Promise<void>;\n\nexport interface RequestOptions {\n fetch?: FetchLike;\n observer?: RequestObserver;\n resource: string;\n requestId?: string;\n}\n\nasync function notifyObserver(\n observer: RequestObserver,\n event: RequestObservation,\n): Promise<void> {\n let result: void | Promise<void>;\n try {\n result = observer(event);\n } catch (err) {\n console.warn('[connector-shared] request observer threw:', err);\n return;\n }\n if (!(result instanceof Promise)) {\n return;\n }\n const guarded = result.catch((err) => {\n console.warn('[connector-shared] request observer rejected:', err);\n });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, OBSERVER_TIMEOUT_MS);\n });\n try {\n await Promise.race([guarded, timeout]);\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n}\n\nfunction newRequestId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction mergeHeaders(\n defaults: Record<string, string>,\n overrides: Record<string, string> | undefined,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(defaults)) {\n merged[k.toLowerCase()] = v;\n }\n if (overrides) {\n for (const [k, v] of Object.entries(overrides)) {\n merged[k.toLowerCase()] = v;\n }\n }\n return merged;\n}\n\nfunction linkTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n const controller = new AbortController();\n const onParentAbort = () => {\n controller.abort(parent?.reason);\n };\n if (parent) {\n if (parent.aborted) {\n controller.abort(parent.reason);\n } else {\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n }\n const timer = setTimeout(() => {\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n if (parent) {\n parent.removeEventListener('abort', onParentAbort);\n }\n },\n };\n}\n\nasync function readBody(res: Response, parseJson: boolean): Promise<unknown> {\n if (res.status === 204 || res.status === 205) {\n return null;\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (parseJson && contentType.includes('application/json')) {\n const text = await res.text();\n if (text.length === 0) {\n return null;\n }\n return JSON.parse(text);\n }\n return res.text();\n}\n\nexport async function request<T = unknown>(\n req: HttpRequest,\n options: RequestOptions,\n): Promise<HttpResponse<T>> {\n const fetchImpl: FetchLike = options.fetch ?? (globalThis.fetch as FetchLike);\n const retry = req.retry ?? {};\n const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;\n const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n const retryOn = retry.retryOn ?? defaultRetryOn;\n const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const parseJson = req.parseJson ?? true;\n\n const headers = mergeHeaders(\n {\n 'User-Agent': DEFAULT_USER_AGENT,\n Accept: 'application/json',\n },\n req.headers,\n );\n\n let lastErr: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n req.signal?.throwIfAborted();\n\n const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);\n let res: Response;\n try {\n res = await fetchImpl(req.url, {\n method: req.method ?? 'GET',\n headers,\n body: req.body as RequestInit['body'],\n signal,\n });\n } catch (err) {\n cancel();\n if (req.signal?.aborted) {\n throw req.signal.reason ?? err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n lastErr = error;\n if (attempt < maxAttempts - 1 && retryOn(null, error)) {\n const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n await sleep(delay, req.signal);\n continue;\n }\n throw new TransientError(error.message);\n }\n cancel();\n\n const body = await readBody(res, parseJson);\n const httpResponse: HttpResponse<T> = {\n status: res.status,\n headers: res.headers,\n body: body as T,\n };\n if (req.rateLimit) {\n const state = req.rateLimit.parse(res.headers);\n if (state) {\n httpResponse.rateLimitState = state;\n }\n }\n\n if (options.observer) {\n await notifyObserver(options.observer, {\n url: req.url,\n method: req.method ?? 'GET',\n status: res.status,\n resource: options.resource,\n requestId: options.requestId ?? newRequestId(),\n body,\n });\n }\n\n if (res.ok) {\n return httpResponse;\n }\n\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? 'GET'} ${req.url}`;\n const err = errorForStatus(message, httpResponse, retryAfter);\n\n if (\n attempt < maxAttempts - 1 &&\n retryOn(res.status, err) &&\n !(err instanceof AuthError) &&\n !(err instanceof ClientBugError)\n ) {\n lastErr = err;\n let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n if (err instanceof RateLimitError && retryAfter) {\n const wait = retryAfter.getTime() - Date.now();\n if (wait > 0) {\n delay = Math.min(wait, maxDelayMs);\n }\n }\n await sleep(delay, req.signal);\n continue;\n }\n\n throw err;\n }\n\n throw lastErr ?? new UpstreamBugError('Exhausted retry attempts');\n}\n\nfunction computeDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n): number {\n const base = initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, maxDelayMs);\n}\n\nexport { HttpClientError };\n","export interface RateLimitState {\n remaining: number;\n resetAt: Date;\n}\n\nexport interface RateLimitPolicy {\n parse(headers: Headers): RateLimitState | null;\n}\n\nexport const githubRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-remaining');\n const resetRaw = h.get('x-ratelimit-reset');\n if (remainingRaw === null || resetRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n const reset = Number(resetRaw);\n if (!Number.isFinite(remaining) || !Number.isFinite(reset) || reset < 0) {\n return null;\n }\n return { remaining, resetAt: new Date(reset * 1000) };\n },\n};\n\nexport const sentryRateLimit: RateLimitPolicy = {\n parse(h) {\n const concurrent = h.get('x-sentry-rate-limit-remaining');\n const reset = h.get('x-sentry-rate-limit-reset');\n if (concurrent === null || reset === null) {\n return null;\n }\n const remaining = Number(concurrent);\n const resetSec = Number(reset);\n if (\n !Number.isFinite(remaining) ||\n !Number.isFinite(resetSec) ||\n resetSec < 0\n ) {\n return null;\n }\n return { remaining, resetAt: new Date(resetSec * 1000) };\n },\n};\n\nexport const linearRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-requests-remaining');\n const resetRaw = h.get('x-ratelimit-requests-reset');\n if (remainingRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n if (!Number.isFinite(remaining)) {\n return null;\n }\n let resetAt: Date;\n if (resetRaw !== null) {\n const reset = Number(resetRaw);\n if (!Number.isFinite(reset) || reset < 0) {\n return null;\n }\n resetAt = new Date(reset);\n } else {\n resetAt = new Date(Date.now() + 60_000);\n }\n return { remaining, resetAt };\n },\n};\n","import { request } from './request';\nimport type { HttpRequest } from './types';\n\nexport function parseLinkHeader(header: string | null): Record<string, string> {\n if (!header) {\n return {};\n }\n const result: Record<string, string> = {};\n for (const part of header.split(',')) {\n const match = part.match(/<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/);\n if (match) {\n result[match[2]!] = match[1]!;\n }\n }\n return result;\n}\n\nexport async function* paginateLink<T>(\n initial: HttpRequest,\n parse: (body: unknown) => T[],\n options: { resource: string },\n): AsyncIterable<T> {\n let next: string | null = initial.url;\n while (next) {\n const res: Awaited<ReturnType<typeof request>> = await request(\n {\n ...initial,\n url: next,\n },\n { resource: options.resource },\n );\n for (const item of parse(res.body)) {\n yield item;\n }\n const links = parseLinkHeader(res.headers.get('link'));\n next = links['next'] ?? null;\n }\n}\n\nexport async function* paginateCursor<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; nextCursor: string | null },\n buildNext: (req: HttpRequest, cursor: string) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let req: HttpRequest = initial;\n while (true) {\n const res = await request(req, { resource: options.resource });\n const { items, nextCursor } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!nextCursor) {\n return;\n }\n req = buildNext(req, nextCursor);\n }\n}\n\nexport async function* paginatePage<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; hasMore: boolean },\n buildPage: (req: HttpRequest, page: number) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let page = 1;\n while (true) {\n const req = page === 1 ? initial : buildPage(initial, page);\n const res = await request(req, { resource: options.resource });\n const { items, hasMore } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!hasMore || items.length === 0) {\n return;\n }\n page++;\n }\n}\n","export type Secret = { $secret: string };\n\nexport function secret(name: string): Secret {\n if (!/^[A-Z][A-Z0-9_]*$/.test(name)) {\n throw new Error(\n `Invalid secret name \"${name}\". Must match /^[A-Z][A-Z0-9_]*$/ ` +\n `(uppercase letters, digits, underscores; must start with a letter).`,\n );\n }\n return { $secret: name };\n}\n\nexport function isSecret(value: unknown): value is Secret {\n return (\n typeof value === 'object' &&\n value !== null &&\n '$secret' in value &&\n typeof (value as Secret).$secret === 'string'\n );\n}\n\nexport interface SecretsResolver {\n resolve(name: string): string | undefined;\n}\n\nexport class EnvSecretsResolver implements SecretsResolver {\n resolve(name: string): string | undefined {\n const env = (\n globalThis as { process?: { env?: Record<string, string | undefined> } }\n ).process?.env;\n return env?.[name];\n }\n}\n\nexport function extractSecretNames(value: unknown): string[] {\n const names: string[] = [];\n const visit = (v: unknown): void => {\n if (isSecret(v)) {\n names.push(v.$secret);\n return;\n }\n if (v && typeof v === 'object') {\n if (Array.isArray(v)) {\n v.forEach(visit);\n } else {\n Object.values(v as Record<string, unknown>).forEach(visit);\n }\n }\n };\n visit(value);\n return [...new Set(names)];\n}\n\nexport function resolveSecrets<T>(obj: T, resolver: SecretsResolver): T {\n if (isSecret(obj)) {\n const name = obj.$secret;\n const value = resolver.resolve(name);\n if (value === undefined) {\n throw new Error(\n `Missing secret \"${name}\". Set it via process.env.${name} or the CLI: rawdash secrets set ${name} ...`,\n );\n }\n return value as unknown as T;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => resolveSecrets(item, resolver)) as unknown as T;\n }\n if (typeof obj === 'object' && obj !== null) {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(obj as object)) {\n Object.defineProperty(result, key, {\n value: resolveSecrets(val, resolver),\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n return result as T;\n }\n return obj;\n}\n","import {\n type HttpRequest,\n type HttpResponse,\n type RequestObserver,\n request as sharedRequest,\n} from '@rawdash/connector-shared';\n\nimport {\n EnvSecretsResolver,\n type Secret,\n type SecretsResolver,\n resolveSecrets,\n} from './secrets';\n\nexport type JSONValue =\n | string\n | number\n | boolean\n | null\n | JSONValue[]\n | { [key: string]: JSONValue };\n\n// ---------------------------------------------------------------------------\n// Five storage shapes\n// ---------------------------------------------------------------------------\n\nexport interface Event {\n name: string;\n start_ts: number;\n end_ts: number | null;\n attributes: Record<string, JSONValue>;\n}\n\nexport interface Entity {\n type: string;\n id: string;\n attributes: Record<string, JSONValue>;\n updated_at: number;\n}\n\nexport interface MetricSample {\n name: string;\n ts: number;\n value: number;\n attributes: Record<string, JSONValue>;\n}\n\nexport interface Edge {\n from_type: string;\n from_id: string;\n kind: string;\n to_type: string;\n to_id: string;\n attributes: Record<string, JSONValue>;\n updated_at: number;\n}\n\nexport type Distribution =\n | {\n name: string;\n ts: number;\n kind: 'histogram';\n data: {\n buckets: Array<{ le: number; count: number }>;\n count: number;\n sum: number;\n };\n attributes: Record<string, JSONValue>;\n }\n | {\n name: string;\n ts: number;\n kind: 'summary';\n data: {\n quantiles: Array<{ q: number; value: number }>;\n count: number;\n sum: number;\n };\n attributes: Record<string, JSONValue>;\n };\n\n// ---------------------------------------------------------------------------\n// Storage query types\n// ---------------------------------------------------------------------------\n\nexport interface EventQuery {\n name?: string;\n start?: number;\n end?: number;\n}\n\nexport interface EntityQuery {\n type: string;\n}\n\nexport interface MetricQuery {\n name?: string;\n start?: number;\n end?: number;\n}\n\nexport interface EdgeQuery {\n fromType?: string;\n fromId?: string;\n kind?: string;\n toType?: string;\n toId?: string;\n}\n\nexport interface DistributionQuery {\n name?: string;\n start?: number;\n end?: number;\n}\n\n// ---------------------------------------------------------------------------\n// StorageHandle — write and read surface\n// ---------------------------------------------------------------------------\n\nexport interface StorageHandle {\n event(e: Event): Promise<void>;\n entity(e: Entity): Promise<void>;\n metric(m: MetricSample): Promise<void>;\n edge(e: Edge): Promise<void>;\n distribution(d: Distribution): Promise<void>;\n\n events(es: Event[], scope?: { names?: string[] }): Promise<void>;\n entities(es: Entity[], scope?: { types?: string[] }): Promise<void>;\n metrics(ms: MetricSample[], scope?: { names?: string[] }): Promise<void>;\n edges(es: Edge[], scope?: { kinds?: string[] }): Promise<void>;\n distributions(\n ds: Distribution[],\n scope?: { names?: string[] },\n ): Promise<void>;\n\n queryEvents(q: EventQuery): Promise<Event[]>;\n getEntity(type: string, id: string): Promise<Entity | null>;\n queryEntities(q: EntityQuery): Promise<Entity[]>;\n queryMetrics(q: MetricQuery): Promise<MetricSample[]>;\n traverse(q: EdgeQuery): Promise<Edge[]>;\n queryDistributions(q: DistributionQuery): Promise<Distribution[]>;\n\n // Deletes all rows in the given time-series shape whose timestamp column is\n // strictly less than `tsUnixMs`. Only covers append-only shapes (events,\n // metrics, distributions). Entities and edges are excluded because they hold\n // the latest known state per primary key — deleting by age would lose live\n // data. The right model for those shapes is \"expire when source disappears.\"\n deleteOlderThan(\n shape: 'events' | 'metrics' | 'distributions',\n tsUnixMs: number,\n ): Promise<{ rowsDeleted: number }>;\n\n getHealth?(): Promise<ConnectorHealth | null>;\n}\n\nexport interface ConnectorHealth {\n status: 'idle' | 'syncing' | 'error' | 'auth_failed' | 'paused';\n lastSyncAt: string | null;\n lastError: string | null;\n syncIntervalSeconds: number;\n}\n\n// ---------------------------------------------------------------------------\n// Credentials\n// ---------------------------------------------------------------------------\n\nexport interface CredentialField {\n description: string;\n auth?: 'none' | 'optional' | 'required';\n}\n\nexport type CredentialsSchema = Record<string, CredentialField>;\n\nexport type InferCredentials<TCreds extends CredentialsSchema> = {\n [K in keyof TCreds]: TCreds[K] extends { auth: 'required' }\n ? string\n : string | undefined;\n};\n\nexport type InferCredentialInput<TCreds extends CredentialsSchema> = {\n [K in keyof TCreds]: TCreds[K] extends { auth: 'required' }\n ? string | Secret\n : string | Secret | undefined;\n};\n\n// ---------------------------------------------------------------------------\n// Sync + Connector\n// ---------------------------------------------------------------------------\n\nexport interface SyncOptions {\n mode: 'full' | 'latest';\n since?: string;\n cursor?: unknown;\n}\n\nexport interface SyncResult {\n done: boolean;\n cursor?: unknown;\n transientError?: unknown;\n}\n\nexport interface Connector {\n readonly id: string;\n readonly credentials?: CredentialsSchema;\n serializeConfig(): Record<string, unknown>;\n sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult>;\n}\n\nexport interface ConnectorContext {\n observer?: RequestObserver;\n secretsResolver?: SecretsResolver;\n}\n\nexport interface ConnectorRequestOptions {\n resource: string;\n requestId?: string;\n}\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n signal?: AbortSignal;\n}\n\nexport abstract class BaseConnector<\n TSettings = unknown,\n TCreds extends CredentialsSchema = CredentialsSchema,\n> implements Connector {\n abstract readonly id: string;\n readonly credentials?: TCreds;\n\n protected settings: TSettings;\n protected creds: InferCredentials<TCreds>;\n private rawCredInput: InferCredentialInput<TCreds> | undefined;\n private ctx: ConnectorContext;\n\n constructor(\n settings: TSettings,\n creds?: InferCredentialInput<TCreds>,\n ctx?: ConnectorContext,\n ) {\n this.settings = settings;\n this.rawCredInput = creds;\n this.ctx = ctx ?? {};\n this.creds = creds\n ? (resolveSecrets(\n creds,\n this.ctx.secretsResolver ?? new EnvSecretsResolver(),\n ) as InferCredentials<TCreds>)\n : ({} as InferCredentials<TCreds>);\n }\n\n protected request<T = unknown>(\n req: HttpRequest,\n opts: ConnectorRequestOptions,\n ): Promise<HttpResponse<T>> {\n return sharedRequest<T>(req, {\n resource: opts.resource,\n requestId: opts.requestId,\n observer: this.ctx.observer,\n });\n }\n\n protected get<T = unknown>(\n url: string,\n opts: ConnectorRequestOptions & {\n headers?: Record<string, string>;\n signal?: AbortSignal;\n rateLimit?: HttpRequest['rateLimit'];\n },\n ): Promise<HttpResponse<T>> {\n return this.request<T>(\n {\n url,\n method: 'GET',\n headers: opts.headers,\n signal: opts.signal,\n rateLimit: opts.rateLimit,\n },\n { resource: opts.resource, requestId: opts.requestId },\n );\n }\n\n protected post<T = unknown>(\n url: string,\n opts: ConnectorRequestOptions & {\n body?: HttpRequest['body'];\n headers?: Record<string, string>;\n signal?: AbortSignal;\n rateLimit?: HttpRequest['rateLimit'];\n },\n ): Promise<HttpResponse<T>> {\n return this.request<T>(\n {\n url,\n method: 'POST',\n headers: opts.headers,\n body: opts.body,\n signal: opts.signal,\n rateLimit: opts.rateLimit,\n },\n { resource: opts.resource, requestId: opts.requestId },\n );\n }\n\n serializeConfig(): Record<string, unknown> {\n const config: Record<string, unknown> = {\n ...(this.settings as Record<string, unknown>),\n };\n if (this.rawCredInput) {\n for (const [key, value] of Object.entries(\n this.rawCredInput as Record<string, unknown>,\n )) {\n if (value !== undefined) {\n config[key] = value;\n }\n }\n }\n return config;\n }\n\n protected sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n protected async withRetry<T>(\n fn: (\n signal?: AbortSignal,\n ) => Promise<{ status: 'done'; value: T } | { status: 'retry' }>,\n options?: RetryPolicy,\n ): Promise<T | null> {\n const {\n maxAttempts = 10,\n initialDelayMs = 1000,\n maxDelayMs = 10000,\n signal,\n } = options ?? {};\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n signal?.throwIfAborted();\n const result = await fn(signal);\n if (result.status === 'done') {\n return result.value;\n }\n if (attempt < maxAttempts - 1) {\n const delay = Math.min(initialDelayMs * 2 ** attempt, maxDelayMs);\n await this.sleep(delay, signal);\n }\n }\n\n return null;\n }\n\n abstract sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult>;\n}\n\nexport function defineConnector<TSettings>() {\n return function <\n TCreds extends CredentialsSchema = Record<string, never>,\n >(def: {\n id: string;\n credentials?: TCreds;\n sync: (\n this: { settings: TSettings; creds: InferCredentials<TCreds> },\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ) => Promise<SyncResult>;\n }): {\n new (\n settings: TSettings,\n creds?: InferCredentialInput<TCreds>,\n ctx?: ConnectorContext,\n ): Connector;\n readonly id: string;\n readonly credentials: TCreds | undefined;\n } {\n class DynamicConnector extends BaseConnector<TSettings, TCreds> {\n static readonly id = def.id;\n static readonly credentials = def.credentials;\n\n readonly id = def.id;\n override readonly credentials = def.credentials;\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n return def.sync.call(\n { settings: this.settings, creds: this.creds },\n options,\n storage,\n signal,\n );\n }\n }\n\n return DynamicConnector as unknown as {\n new (\n settings: TSettings,\n creds?: InferCredentialInput<TCreds>,\n ctx?: ConnectorContext,\n ): Connector;\n readonly id: string;\n readonly credentials: TCreds | undefined;\n };\n };\n}\n","import type { SyncResult } from './connector';\n\nexport interface ChunkedSyncCursor<TPhase extends string, TPage> {\n phase: TPhase;\n page: TPage | null;\n}\n\nexport interface FetchPageResult<TPage> {\n items: unknown[];\n next: TPage | null;\n}\n\nexport interface ChunkedSyncOptions<TPhase extends string, TPage> {\n phases: readonly TPhase[];\n cursor: ChunkedSyncCursor<TPhase, TPage> | undefined;\n signal: AbortSignal | undefined;\n fetchPage: (\n phase: TPhase,\n page: TPage | null,\n signal: AbortSignal | undefined,\n ) => Promise<FetchPageResult<TPage>>;\n writeBatch: (\n phase: TPhase,\n items: unknown[],\n page: TPage | null,\n ) => Promise<void>;\n}\n\nexport async function paginateChunked<TPhase extends string, TPage>(\n opts: ChunkedSyncOptions<TPhase, TPage>,\n): Promise<SyncResult> {\n const { phases, cursor, signal, fetchPage, writeBatch } = opts;\n\n if (phases.length === 0) {\n return { done: true };\n }\n\n const resumeIdx = cursor ? phases.indexOf(cursor.phase) : -1;\n const hasKnownResumePhase = resumeIdx >= 0;\n const startIdx = hasKnownResumePhase ? resumeIdx : 0;\n\n for (let i = startIdx; i < phases.length; i++) {\n const phase = phases[i]!;\n let page: TPage | null =\n i === startIdx && hasKnownResumePhase ? cursor!.page : null;\n\n while (true) {\n if (signal?.aborted) {\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n };\n }\n let items: unknown[];\n let next: TPage | null;\n try {\n ({ items, next } = await fetchPage(phase, page, signal));\n } catch (err) {\n if (\n signal?.aborted ||\n (err instanceof Error && err.name === 'AbortError')\n ) {\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n };\n }\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n transientError: err,\n };\n }\n try {\n await writeBatch(phase, items, page);\n } catch (err) {\n if (\n signal?.aborted ||\n (err instanceof Error && err.name === 'AbortError')\n ) {\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n };\n }\n return {\n done: false,\n cursor: { phase, page } satisfies ChunkedSyncCursor<TPhase, TPage>,\n transientError: err,\n };\n }\n if (next === null) {\n break;\n }\n page = next;\n }\n }\n\n return { done: true };\n}\n","import { z } from 'zod';\n\nexport const shapeSchema = z.enum([\n 'event',\n 'entity',\n 'metric',\n 'edge',\n 'distribution',\n]);\n\nexport const aggFnSchema = z.enum([\n 'count',\n 'sum',\n 'avg',\n 'min',\n 'max',\n 'latest',\n 'first',\n]);\n\nexport const filterOperatorSchema = z.enum([\n 'eq',\n 'neq',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'contains',\n]);\n\nexport const filterConditionSchema = z.object({\n field: z.string(),\n op: filterOperatorSchema,\n value: z.union([z.string(), z.number(), z.boolean()]),\n});\n\nexport const filterClauseSchema = z.union([\n filterConditionSchema,\n z.object({ or: z.array(filterConditionSchema) }),\n]);\n\nexport const groupBySchema = z.object({\n field: z.string(),\n granularity: z.enum(['hour', 'day', 'week', 'month']),\n});\n\nexport const computedMetricSchema = z\n .object({\n connectorId: z.string(),\n shape: shapeSchema,\n name: z.string().optional(),\n entityType: z.string().optional(),\n field: z.string().optional(),\n fn: aggFnSchema,\n window: z.string().optional(),\n filter: z.array(filterClauseSchema).optional(),\n groupBy: groupBySchema.optional(),\n })\n .refine((m) => m.fn === 'count' || m.field !== undefined, {\n message: 'field is required unless fn is \"count\"',\n path: ['field'],\n });\n\nconst titleField = z\n .string()\n .meta({ label: 'Title', description: 'Widget title.' });\n\nexport const statWidgetSchema = z.object({\n kind: z.literal('stat'),\n title: titleField,\n metric: computedMetricSchema.meta({\n label: 'Metric',\n description: 'Computed metric definition.',\n }),\n window: z\n .string()\n .optional()\n .meta({ label: 'Window', description: \"Time window, e.g. '7d'.\" }),\n compare: z\n .enum(['none', 'previous-period'])\n .default('none')\n .meta({ label: 'Compare', description: 'Comparison mode.' }),\n});\n\nexport const statusWidgetSchema = z.object({\n kind: z.literal('status'),\n title: titleField,\n source: z.string().meta({\n label: 'Source',\n description: 'Connector or data source reference.',\n }),\n});\n\nexport const timeseriesWidgetSchema = z.object({\n kind: z.literal('timeseries'),\n title: titleField,\n metric: computedMetricSchema.meta({\n label: 'Metric',\n description: 'Computed metric definition.',\n }),\n window: z\n .string()\n .meta({ label: 'Window', description: \"Time window, e.g. '30d'.\" }),\n granularity: z\n .enum(['hour', 'day', 'week'])\n .default('day')\n .meta({ label: 'Granularity', description: 'Time bucket size.' }),\n});\n\nexport const distributionWidgetSchema = z.object({\n kind: z.literal('distribution'),\n title: titleField,\n metric: computedMetricSchema.meta({\n label: 'Metric',\n description: 'Computed metric definition.',\n }),\n window: z\n .string()\n .meta({ label: 'Window', description: \"Time window, e.g. '7d'.\" }),\n});\n\nexport const widgetSchemas = {\n stat: statWidgetSchema,\n status: statusWidgetSchema,\n timeseries: timeseriesWidgetSchema,\n distribution: distributionWidgetSchema,\n} as const;\n\nexport const widgetSchema = z.discriminatedUnion('kind', [\n statWidgetSchema,\n statusWidgetSchema,\n timeseriesWidgetSchema,\n distributionWidgetSchema,\n]);\n\nexport type WidgetKind = keyof typeof widgetSchemas;\n\nexport function getWidgetSchema(kind: WidgetKind) {\n return widgetSchemas[kind];\n}\n","import type { RetentionConfig } from './retention';\nimport { getWidgetSchema, widgetSchemas } from './widget-schemas';\nimport type { WidgetKind } from './widget-schemas';\n\n// ---------------------------------------------------------------------------\n// Aggregation functions\n// ---------------------------------------------------------------------------\n\nexport type AggFn =\n | 'count'\n | 'sum'\n | 'avg'\n | 'min'\n | 'max'\n | 'latest'\n | 'first';\n\n// ---------------------------------------------------------------------------\n// Shape\n// ---------------------------------------------------------------------------\n\nexport type Shape = 'event' | 'entity' | 'metric' | 'edge' | 'distribution';\n\n// ---------------------------------------------------------------------------\n// Filters\n// ---------------------------------------------------------------------------\n\nexport type FilterOperator =\n | 'eq'\n | 'neq'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'contains';\n\nexport interface FilterCondition {\n field: string;\n op: FilterOperator;\n value: string | number | boolean;\n}\n\nexport type FilterClause = FilterCondition | { or: FilterCondition[] };\n\n// ---------------------------------------------------------------------------\n// GroupBy\n// ---------------------------------------------------------------------------\n\nexport interface GroupBy {\n field: string;\n granularity: 'hour' | 'day' | 'week' | 'month';\n}\n\n// ---------------------------------------------------------------------------\n// Metric\n// ---------------------------------------------------------------------------\n\nexport interface Metric {\n connector: { name: string };\n shape: Shape;\n name?: string;\n entityType?: string;\n field?: string;\n fn: AggFn;\n window?: string;\n filter?: FilterClause[];\n groupBy?: GroupBy;\n}\n\nexport interface ComputedMetric {\n readonly connectorId: string;\n readonly shape: Shape;\n readonly name?: string;\n readonly entityType?: string;\n readonly field?: string;\n readonly fn: AggFn;\n readonly window?: string;\n readonly filter?: FilterClause[];\n readonly groupBy?: GroupBy;\n}\n\n// ---------------------------------------------------------------------------\n// Widget definition\n// ---------------------------------------------------------------------------\n\nexport interface StatWidget {\n kind: 'stat';\n title: string;\n metric: ComputedMetric;\n window?: string;\n compare?: 'none' | 'previous-period';\n}\n\nexport interface StatusWidget {\n kind: 'status';\n title: string;\n source: string;\n}\n\nexport interface TimeseriesWidget {\n kind: 'timeseries';\n title: string;\n metric: ComputedMetric;\n window: string;\n granularity?: 'hour' | 'day' | 'week';\n}\n\nexport interface DistributionWidget {\n kind: 'distribution';\n title: string;\n metric: ComputedMetric;\n window: string;\n}\n\nexport type Widget =\n | StatWidget\n | StatusWidget\n | TimeseriesWidget\n | DistributionWidget;\n\nexport type { WidgetKind };\n\n// ---------------------------------------------------------------------------\n// Dashboard config\n// ---------------------------------------------------------------------------\n\nexport interface ConfiguredConnector {\n name: string;\n connectorId: string;\n config: Record<string, unknown>;\n syncIntervalSeconds?: number;\n enabled?: boolean;\n displayName?: string;\n}\n\nexport interface Dashboard {\n widgets: Record<string, Widget>;\n}\n\nexport interface DashboardConfig {\n connectors: ConfiguredConnector[];\n dashboards: Record<string, Dashboard>;\n retention?: RetentionConfig;\n}\n\n// ---------------------------------------------------------------------------\n// defineDashboard\n// ---------------------------------------------------------------------------\n\nconst VALID_WIDGET_KINDS = new Set<string>(Object.keys(widgetSchemas));\n\nexport function defineDashboard(options: {\n widgets: Record<string, Widget>;\n}): Dashboard {\n for (const [key, widget] of Object.entries(options.widgets)) {\n if (!VALID_WIDGET_KINDS.has(widget.kind)) {\n throw new Error(\n `Widget \"${key}\": unknown kind \"${widget.kind}\". Must be one of: ${[...VALID_WIDGET_KINDS].join(', ')}`,\n );\n }\n const schema = getWidgetSchema(widget.kind as WidgetKind);\n const result = schema.safeParse(widget);\n if (!result.success) {\n throw new Error(\n `Widget \"${key}\" (kind \"${widget.kind}\"): ${result.error.issues.map((i) => i.message).join('; ')}`,\n );\n }\n }\n return { widgets: options.widgets };\n}\n\n// ---------------------------------------------------------------------------\n// defineMetric\n// ---------------------------------------------------------------------------\n\nexport function defineMetric(options: Metric): ComputedMetric {\n return {\n connectorId: options.connector.name,\n shape: options.shape,\n name: options.name,\n entityType: options.entityType,\n field: options.field,\n fn: options.fn,\n window: options.window,\n filter: options.filter,\n groupBy: options.groupBy,\n };\n}\n\n// ---------------------------------------------------------------------------\n// defineConfig\n// ---------------------------------------------------------------------------\n\nconst VALID_SHAPES = new Set<string>([\n 'event',\n 'entity',\n 'metric',\n 'edge',\n 'distribution',\n]);\nconst VALID_FNS = new Set<string>([\n 'count',\n 'sum',\n 'avg',\n 'min',\n 'max',\n 'latest',\n 'first',\n]);\n\nconst SAFE_KEY_RE = /^[a-zA-Z0-9_-]+$/;\n\nfunction validateConfig(config: DashboardConfig): void {\n if (config.retention) {\n const { maxAge, maxSize, floor, intervalMs } = config.retention;\n if (maxAge !== undefined && (!Number.isFinite(maxAge) || maxAge < 0)) {\n throw new Error('retention.maxAge must be a finite number >= 0');\n }\n if (maxSize !== undefined && (!Number.isInteger(maxSize) || maxSize < 0)) {\n throw new Error('retention.maxSize must be an integer >= 0');\n }\n if (floor !== undefined && (!Number.isInteger(floor) || floor < 0)) {\n throw new Error('retention.floor must be an integer >= 0');\n }\n if (\n intervalMs !== undefined &&\n (!Number.isFinite(intervalMs) || intervalMs <= 0)\n ) {\n throw new Error('retention.intervalMs must be a finite number > 0');\n }\n }\n\n if (\n !config.dashboards ||\n typeof config.dashboards !== 'object' ||\n Array.isArray(config.dashboards)\n ) {\n throw new Error(\n 'defineConfig: config must include a \"dashboards\" record — did you mean to migrate from the old flat \"widgets\" shape?',\n );\n }\n\n if (!Array.isArray(config.connectors)) {\n throw new Error('defineConfig: \"connectors\" must be an array');\n }\n\n const connectorNames = new Set<string>();\n for (const entry of config.connectors) {\n if (!entry || typeof entry !== 'object') {\n throw new Error(\n 'defineConfig: every connector entry must be an object with \"name\", \"connectorId\", and \"config\"',\n );\n }\n if (!entry.name) {\n throw new Error('defineConfig: every connector entry must have a \"name\"');\n }\n if (!entry.connectorId) {\n throw new Error(\n `defineConfig: connector \"${entry.name}\" must have a \"connectorId\" (the connector type id)`,\n );\n }\n if (\n entry.config === null ||\n typeof entry.config !== 'object' ||\n Array.isArray(entry.config)\n ) {\n throw new Error(\n `defineConfig: connector \"${entry.name}\" must have a \"config\" object`,\n );\n }\n if (connectorNames.has(entry.name)) {\n throw new Error(\n `defineConfig: duplicate connector name \"${entry.name}\". Each instance must have a unique name.`,\n );\n }\n connectorNames.add(entry.name);\n }\n\n for (const [dashboardKey, dashboard] of Object.entries(config.dashboards)) {\n if (\n !dashboard.widgets ||\n typeof dashboard.widgets !== 'object' ||\n Array.isArray(dashboard.widgets)\n ) {\n throw new Error(\n `Dashboard \"${dashboardKey}\" must define a \"widgets\" record`,\n );\n }\n\n if (!SAFE_KEY_RE.test(dashboardKey)) {\n throw new Error(\n `Dashboard key \"${dashboardKey}\" contains URL-unsafe characters; use only letters, digits, hyphens, and underscores`,\n );\n }\n\n for (const [widgetKey, widget] of Object.entries(dashboard.widgets)) {\n const ref = `Dashboard \"${dashboardKey}\", widget \"${widgetKey}\"`;\n\n if (!SAFE_KEY_RE.test(widgetKey)) {\n throw new Error(\n `${ref}: widget key contains URL-unsafe characters; use only letters, digits, hyphens, and underscores`,\n );\n }\n\n if (widget.kind === 'status') {\n continue;\n }\n\n const { connectorId, shape, fn } = widget.metric;\n\n if (!connectorNames.has(connectorId)) {\n throw new Error(\n `${ref}: connector \"${connectorId}\" is not listed in connectors`,\n );\n }\n\n if (!VALID_SHAPES.has(shape)) {\n throw new Error(`${ref}: invalid shape \"${shape}\"`);\n }\n\n if (!VALID_FNS.has(fn)) {\n throw new Error(`${ref}: invalid fn \"${fn}\"`);\n }\n }\n }\n}\n\nexport function defineConfig(config: DashboardConfig): DashboardConfig {\n validateConfig(config);\n return config;\n}\n","export type SyncStatus = 'idle' | 'queued' | 'running' | 'succeeded' | 'failed';\n\nexport interface SyncState {\n status: SyncStatus;\n queuedAt: string | null;\n startedAt: string | null;\n lastSyncAt: string | null;\n lastError: string | null;\n}\n\nexport const ACTIVE_SYNC_STATUSES: ReadonlySet<SyncStatus> = new Set([\n 'queued',\n 'running',\n]);\n\nexport function isSyncActive(status: SyncStatus): boolean {\n return ACTIVE_SYNC_STATUSES.has(status);\n}\n","import type {\n Distribution,\n Event,\n MetricSample,\n StorageHandle,\n} from './connector';\n\n// ---------------------------------------------------------------------------\n// RetentionConfig\n// ---------------------------------------------------------------------------\n\nexport interface RetentionConfig {\n maxAge?: number;\n maxSize?: number;\n floor?: number;\n intervalMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// RetentionDeletionPlan — rows eligible for deletion across time-series shapes\n// ---------------------------------------------------------------------------\n\nexport interface RetentionDeletionPlan {\n events: Event[];\n metrics: MetricSample[];\n distributions: Distribution[];\n}\n\n// ---------------------------------------------------------------------------\n// selectForDeletion — pure computation\n//\n// Receives rows pre-sorted newest-first (descending by timestamp).\n// Returns the subset that should be deleted given the policy.\n//\n// Rules applied in order:\n// 1. Rows beyond maxSize are candidates.\n// 2. Rows older than maxAge milliseconds are candidates.\n// 3. Rows within the newest `floor` positions are always kept (overrides 1 & 2).\n// ---------------------------------------------------------------------------\n\nexport function selectForDeletion<T>(\n rows: T[],\n getTs: (row: T) => number,\n config: RetentionConfig,\n nowMs: number = Date.now(),\n): T[] {\n const { maxAge, maxSize, floor = 0 } = config;\n\n if (maxAge === undefined && maxSize === undefined) {\n return [];\n }\n\n const toDelete: T[] = [];\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]!;\n if (i < floor) {\n continue;\n }\n\n const overSize = maxSize !== undefined && i >= maxSize;\n const tooOld = maxAge !== undefined && getTs(row) < nowMs - maxAge;\n\n if (overSize || tooOld) {\n toDelete.push(row);\n }\n }\n\n return toDelete;\n}\n\n// ---------------------------------------------------------------------------\n// computeRetention — async, queries the handle and returns deletion candidates\n//\n// Only covers time-series shapes (events, metrics, distributions) since those\n// grow unboundedly via append. Entities and edges are upsert-keyed and do not\n// accumulate the same way.\n// ---------------------------------------------------------------------------\n\nexport async function computeRetention(\n handle: StorageHandle,\n config: RetentionConfig,\n nowMs: number = Date.now(),\n): Promise<RetentionDeletionPlan> {\n const [events, metrics, distributions] = await Promise.all([\n handle.queryEvents({}),\n handle.queryMetrics({}),\n handle.queryDistributions({}),\n ]);\n\n const sortedEvents = [...events].sort((a, b) => b.start_ts - a.start_ts);\n const sortedMetrics = [...metrics].sort((a, b) => b.ts - a.ts);\n const sortedDistributions = [...distributions].sort((a, b) => b.ts - a.ts);\n\n return {\n events: selectForDeletion(sortedEvents, (e) => e.start_ts, config, nowMs),\n metrics: selectForDeletion(sortedMetrics, (m) => m.ts, config, nowMs),\n distributions: selectForDeletion(\n sortedDistributions,\n (d) => d.ts,\n config,\n nowMs,\n ),\n };\n}\n","import { z } from 'zod';\n\nexport type ConfigFieldsSchema = z.ZodObject<z.ZodRawShape>;\n\nexport function defineConfigFields<T extends z.ZodRawShape>(\n schema: z.ZodObject<T>,\n): z.ZodObject<T> {\n if (!(schema instanceof z.ZodObject)) {\n throw new Error(\n `configFields must be a Zod object schema (z.object({...})). Received: ${Object.prototype.toString.call(schema)}`,\n );\n }\n return schema;\n}\n","import type { ComputedMetric } from './config';\nimport type { StorageHandle } from './connector';\n\ntype FilterClause = NonNullable<ComputedMetric['filter']>[number];\ntype FilterCondition = Exclude<FilterClause, { or: unknown[] }>;\n\nfunction matchesCondition(\n record: Record<string, unknown>,\n cond: FilterCondition,\n): boolean {\n const val = record[cond.field];\n switch (cond.op) {\n case 'eq':\n return val === cond.value;\n case 'neq':\n return val !== cond.value;\n case 'gt':\n if (typeof val !== 'number' || typeof cond.value !== 'number') {\n return false;\n }\n return val > cond.value;\n case 'gte':\n if (typeof val !== 'number' || typeof cond.value !== 'number') {\n return false;\n }\n return val >= cond.value;\n case 'lt':\n if (typeof val !== 'number' || typeof cond.value !== 'number') {\n return false;\n }\n return val < cond.value;\n case 'lte':\n if (typeof val !== 'number' || typeof cond.value !== 'number') {\n return false;\n }\n return val <= cond.value;\n case 'contains':\n return String(val).includes(String(cond.value));\n default:\n return false;\n }\n}\n\nfunction applyFilter(\n record: Record<string, unknown>,\n filter: ComputedMetric['filter'],\n): boolean {\n if (!filter) {\n return true;\n }\n for (const clause of filter) {\n if ('or' in clause) {\n if (!clause.or.some((cond) => matchesCondition(record, cond))) {\n return false;\n }\n } else {\n if (!matchesCondition(record, clause)) {\n return false;\n }\n }\n }\n return true;\n}\n\nconst WINDOW_MS: Record<string, number> = {\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n m: 2_592_000_000,\n};\n\nfunction parseWindowMs(window: string): number | null {\n const match = /^(\\d+)(h|d|w|m)$/.exec(window);\n if (!match) {\n return null;\n }\n const unitMs = WINDOW_MS[match[2]!];\n if (unitMs === undefined) {\n return null;\n }\n return parseInt(match[1]!) * unitMs;\n}\n\nfunction truncateToGranularity(ts: number, granularity: string): string {\n const d = new Date(ts);\n switch (granularity) {\n case 'hour':\n d.setUTCMinutes(0, 0, 0);\n return d.toISOString();\n case 'day':\n d.setUTCHours(0, 0, 0, 0);\n return d.toISOString().slice(0, 10);\n case 'week': {\n d.setUTCDate(d.getUTCDate() - d.getUTCDay());\n d.setUTCHours(0, 0, 0, 0);\n return d.toISOString().slice(0, 10);\n }\n case 'month':\n d.setUTCDate(1);\n d.setUTCHours(0, 0, 0, 0);\n return d.toISOString().slice(0, 7);\n default:\n return d.toISOString().slice(0, 10);\n }\n}\n\nfunction computeAgg(\n records: Record<string, unknown>[],\n field: string | undefined,\n fn: string,\n): unknown {\n if (fn === 'count') {\n return records.length;\n }\n if (field === undefined) {\n throw new Error(`computeAgg: fn \"${fn}\" requires a field`);\n }\n if (fn === 'latest') {\n return records.at(-1)?.[field] ?? null;\n }\n if (fn === 'first') {\n return records[0]?.[field] ?? null;\n }\n const values = records\n .map((r) => r[field])\n .filter((v) => v !== undefined && v !== null);\n const nonNumeric = values.find((v) => typeof v !== 'number');\n if (nonNumeric !== undefined) {\n throw new Error(\n `computeAgg: fn \"${fn}\" requires numeric values for field \"${field}\", got ${typeof nonNumeric} (${String(nonNumeric)})`,\n );\n }\n const numbers = values as number[];\n if (fn === 'sum') {\n return numbers.reduce((a, b) => a + b, 0);\n }\n if (fn === 'avg') {\n return numbers.length > 0\n ? numbers.reduce((a, b) => a + b, 0) / numbers.length\n : null;\n }\n if (fn === 'min') {\n return numbers.length > 0\n ? numbers.reduce((a, b) => (a < b ? a : b))\n : null;\n }\n if (fn === 'max') {\n return numbers.length > 0\n ? numbers.reduce((a, b) => (a > b ? a : b))\n : null;\n }\n return null;\n}\n\nfunction sortByTs(\n records: Record<string, unknown>[],\n tsField: string,\n): Record<string, unknown>[] {\n return [...records].sort((a, b) => {\n return (a[tsField] as number) - (b[tsField] as number);\n });\n}\n\nfunction computeGroupBy(\n records: Record<string, unknown>[],\n metric: ComputedMetric,\n tsField: string,\n): unknown {\n const { field, granularity } = metric.groupBy!;\n const groups = new Map<string, Record<string, unknown>[]>();\n\n for (const record of records) {\n const ts = record[field] as number | undefined;\n if (ts === undefined || typeof ts !== 'number') {\n continue;\n }\n const key = truncateToGranularity(ts, granularity);\n if (!groups.has(key)) {\n groups.set(key, []);\n }\n groups.get(key)!.push(record);\n }\n\n return [...groups.entries()]\n .map(([key, groupRecords]) => ({\n date: key,\n value: computeAgg(\n sortByTs(groupRecords, tsField),\n metric.field,\n metric.fn,\n ),\n }))\n .sort((a, b) => (a.date < b.date ? -1 : 1));\n}\n\nfunction getTimestampField(shape: string): string {\n switch (shape) {\n case 'event':\n return 'start_ts';\n case 'metric':\n case 'distribution':\n return 'ts';\n case 'entity':\n case 'edge':\n return 'updated_at';\n default:\n return 'start_ts';\n }\n}\n\nexport async function computeMetric(\n storage: StorageHandle,\n metric: ComputedMetric,\n): Promise<unknown> {\n const tsField = getTimestampField(metric.shape);\n\n const windowMs = metric.window ? parseWindowMs(metric.window) : null;\n const windowStart = windowMs !== null ? Date.now() - windowMs : undefined;\n\n let records: Record<string, unknown>[];\n\n switch (metric.shape) {\n case 'event': {\n const events = await storage.queryEvents({\n name: metric.name,\n start: windowStart,\n });\n records = events.map((e) => ({\n ...e.attributes,\n name: e.name,\n start_ts: e.start_ts,\n end_ts: e.end_ts,\n }));\n break;\n }\n\n case 'entity': {\n const type = metric.entityType ?? metric.name ?? '';\n const entities = await storage.queryEntities({ type });\n records = entities.map((e) => ({\n ...e.attributes,\n type: e.type,\n id: e.id,\n updated_at: e.updated_at,\n }));\n if (windowStart !== undefined) {\n records = records.filter((r) => (r[tsField] as number) >= windowStart);\n }\n break;\n }\n\n case 'metric': {\n const metrics = await storage.queryMetrics({\n name: metric.name,\n start: windowStart,\n });\n records = metrics.map((m) => ({\n ...m.attributes,\n name: m.name,\n ts: m.ts,\n value: m.value,\n }));\n break;\n }\n\n case 'edge': {\n const edges = await storage.traverse({ kind: metric.name });\n records = edges.map((e) => ({\n ...e.attributes,\n from_type: e.from_type,\n from_id: e.from_id,\n kind: e.kind,\n to_type: e.to_type,\n to_id: e.to_id,\n updated_at: e.updated_at,\n }));\n if (windowStart !== undefined) {\n records = records.filter((r) => (r[tsField] as number) >= windowStart);\n }\n break;\n }\n\n case 'distribution': {\n const distributions = await storage.queryDistributions({\n name: metric.name,\n start: windowStart,\n });\n records = distributions.map((d) => ({\n ...d.attributes,\n name: d.name,\n ts: d.ts,\n kind: d.kind,\n data: d.data,\n }));\n break;\n }\n\n default:\n return null;\n }\n\n const filtered = records.filter((r) => applyFilter(r, metric.filter));\n const sorted = sortByTs(filtered, tsField);\n\n if (metric.groupBy) {\n return computeGroupBy(sorted, metric, tsField);\n }\n\n return computeAgg(sorted, metric.field, metric.fn);\n}\n","import { computeMetric } from './compute';\nimport type { Widget } from './config';\nimport type { ConnectorHealth } from './connector';\nimport type { ServerStorage } from './server-storage';\nimport type { CachedWidget, WidgetSyncState } from './wire';\n\nconst FAILING_CONNECTOR_STATUSES: ReadonlySet<ConnectorHealth['status']> =\n new Set(['error', 'auth_failed', 'paused']);\n\nfunction deriveSyncStateFromHealth(health: ConnectorHealth): WidgetSyncState {\n if (health.status === 'syncing') {\n return 'syncing';\n }\n if (FAILING_CONNECTOR_STATUSES.has(health.status)) {\n return 'failing';\n }\n if (!health.lastSyncAt) {\n return 'unsynced';\n }\n const ageMs = Date.now() - new Date(health.lastSyncAt).getTime();\n const windowMs = 2 * health.syncIntervalSeconds * 1000;\n return ageMs <= windowMs ? 'fresh' : 'stale';\n}\n\nfunction buildMetaFromHealth(health: ConnectorHealth): Record<string, unknown> {\n const meta: Record<string, unknown> = { connectorStatus: health.status };\n if (health.lastError) {\n meta['lastError'] = health.lastError;\n }\n return meta;\n}\n\nexport async function resolveWidget(\n widgetId: string,\n widget: Widget,\n connectors: readonly string[] | undefined,\n storage: ServerStorage,\n): Promise<CachedWidget | undefined> {\n const connectorId =\n widget.kind === 'status' ? widget.source : widget.metric.connectorId;\n if (connectors !== undefined && !connectors.includes(connectorId)) {\n return undefined;\n }\n const handle = storage.getStorageHandle(connectorId);\n const health = (await handle.getHealth?.()) ?? null;\n const data =\n widget.kind === 'status'\n ? null\n : await computeMetric(handle, widget.metric);\n\n let syncState: WidgetSyncState | undefined;\n let meta: Record<string, unknown> | undefined;\n if (health) {\n syncState = deriveSyncStateFromHealth(health);\n meta = buildMetaFromHealth(health);\n } else if (data === null || data === undefined) {\n syncState = 'unsynced';\n } else {\n syncState = 'fresh';\n }\n\n return {\n widgetId,\n connectorId,\n data,\n cachedAt: health?.lastSyncAt ?? null,\n syncState,\n meta,\n };\n}\n","import type { z } from 'zod';\n\nimport type { ConfiguredConnector } from './config';\nimport type {\n Connector,\n ConnectorContext,\n CredentialsSchema,\n} from './connector';\nimport type { SecretsResolver } from './secrets';\n\n/**\n * Map of resource name → Zod schema describing the raw API response shape\n * for that resource. Resource names must match the `resource` tag passed to\n * `request()` (see {@link BaseConnector.request}) so the shape-drift pipeline\n * can correlate observations with their declared shape.\n *\n * Consumed by:\n * - the cloud baseline generator, which walks this map at deploy time to\n * populate `connector_baselines`\n * - property tests in `@rawdash/connector-test-utils`, which fuzz against\n * each schema\n *\n * See `docs/authoring-a-connector.md` for the authoring guide.\n */\nexport type ConnectorSchemas = Readonly<Record<string, z.ZodType>>;\n\n/**\n * Compile-time contract every connector class must satisfy. Declaring\n * `static schemas` is mandatory — without it, the connector cannot be added\n * to a {@link ConnectorRegistry} and TypeScript will fail the build.\n */\nexport type ConnectorClass = {\n new (settings: never, creds?: never, ctx?: ConnectorContext): Connector;\n readonly credentials?: CredentialsSchema;\n readonly schemas: ConnectorSchemas;\n};\n\nexport type ConnectorRegistry = Record<string, ConnectorClass>;\n\nexport function instantiateConnector(\n entry: ConfiguredConnector,\n registry: ConnectorRegistry,\n secretsResolver?: SecretsResolver,\n): Connector {\n const Cls = registry[entry.connectorId];\n if (!Cls) {\n throw new Error(\n `Unknown connector type \"${entry.connectorId}\" for instance \"${entry.name}\". ` +\n `Add it to the connectorRegistry.`,\n );\n }\n const credSchema = Cls.credentials;\n const settings: Record<string, unknown> = {};\n const creds: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(entry.config)) {\n if (credSchema && Object.prototype.hasOwnProperty.call(credSchema, key)) {\n creds[key] = value;\n } else {\n settings[key] = value;\n }\n }\n return new Cls(settings as never, (credSchema ? creds : undefined) as never, {\n secretsResolver,\n });\n}\n","import type { StorageHandle } from './connector';\n\nexport function withAbortSignal(\n handle: StorageHandle,\n signal: AbortSignal,\n): StorageHandle {\n let warned = false;\n const warnOnce = (method: string): void => {\n if (warned) {\n return;\n }\n warned = true;\n console.warn(\n `[rawdash storage] dropping post-abort write '${method}' — connector continued writing after AbortSignal fired`,\n );\n };\n\n return {\n event: async (e) => {\n if (signal.aborted) {\n warnOnce('event');\n return;\n }\n await handle.event(e);\n },\n entity: async (e) => {\n if (signal.aborted) {\n warnOnce('entity');\n return;\n }\n await handle.entity(e);\n },\n metric: async (m) => {\n if (signal.aborted) {\n warnOnce('metric');\n return;\n }\n await handle.metric(m);\n },\n edge: async (e) => {\n if (signal.aborted) {\n warnOnce('edge');\n return;\n }\n await handle.edge(e);\n },\n distribution: async (d) => {\n if (signal.aborted) {\n warnOnce('distribution');\n return;\n }\n await handle.distribution(d);\n },\n events: async (es, scope) => {\n if (signal.aborted) {\n warnOnce('events');\n return;\n }\n await handle.events(es, scope);\n },\n entities: async (es, scope) => {\n if (signal.aborted) {\n warnOnce('entities');\n return;\n }\n await handle.entities(es, scope);\n },\n metrics: async (ms, scope) => {\n if (signal.aborted) {\n warnOnce('metrics');\n return;\n }\n await handle.metrics(ms, scope);\n },\n edges: async (es, scope) => {\n if (signal.aborted) {\n warnOnce('edges');\n return;\n }\n await handle.edges(es, scope);\n },\n distributions: async (ds, scope) => {\n if (signal.aborted) {\n warnOnce('distributions');\n return;\n }\n await handle.distributions(ds, scope);\n },\n deleteOlderThan: async (shape, tsUnixMs) => {\n if (signal.aborted) {\n warnOnce('deleteOlderThan');\n return { rowsDeleted: 0 };\n }\n return handle.deleteOlderThan(shape, tsUnixMs);\n },\n queryEvents: (q) => handle.queryEvents(q),\n getEntity: (type, id) => handle.getEntity(type, id),\n queryEntities: (q) => handle.queryEntities(q),\n queryMetrics: (q) => handle.queryMetrics(q),\n traverse: (q) => handle.traverse(q),\n queryDistributions: (q) => handle.queryDistributions(q),\n ...(handle.getHealth ? { getHealth: handle.getHealth.bind(handle) } : {}),\n };\n}\n","import type {\n ConnectorHealth,\n Distribution,\n DistributionQuery,\n Edge,\n EdgeQuery,\n Entity,\n EntityQuery,\n Event,\n EventQuery,\n MetricQuery,\n MetricSample,\n StorageHandle,\n} from './connector';\nimport type { SyncState } from './engine';\nimport type { GetStorageHandleOptions, ServerStorage } from './server-storage';\nimport { withAbortSignal } from './storage-handle-guard';\n\nexport class InMemoryStorage implements ServerStorage {\n private eventStore = new Map<string, Event[]>();\n private entityStore = new Map<string, Map<string, Map<string, Entity>>>();\n private metricStore = new Map<string, MetricSample[]>();\n private edgeStore = new Map<string, Edge[]>();\n private distributionStore = new Map<string, Distribution[]>();\n private lastWriteAt = new Map<string, string>();\n private syncState: SyncState = {\n status: 'idle',\n queuedAt: null,\n startedAt: null,\n lastSyncAt: null,\n lastError: null,\n };\n\n getStorageHandle(\n connectorId: string,\n options?: GetStorageHandleOptions,\n ): StorageHandle {\n const handle = this.buildHandle(connectorId);\n return options?.signal ? withAbortSignal(handle, options.signal) : handle;\n }\n\n private buildHandle(connectorId: string): StorageHandle {\n const touch = (): void => {\n this.lastWriteAt.set(connectorId, new Date().toISOString());\n };\n const getEntityMap = (): Map<string, Map<string, Entity>> => {\n if (!this.entityStore.has(connectorId)) {\n this.entityStore.set(connectorId, new Map());\n }\n return this.entityStore.get(connectorId)!;\n };\n\n const upsertEntities = (es: Entity[]): void => {\n const byType = getEntityMap();\n for (const e of es) {\n if (!byType.has(e.type)) {\n byType.set(e.type, new Map());\n }\n byType.get(e.type)!.set(e.id, e);\n }\n };\n\n const upsertEdges = (es: Edge[]): void => {\n const existing = this.edgeStore.get(connectorId) ?? [];\n const index = new Map<string, number>();\n for (let i = 0; i < existing.length; i++) {\n const e = existing[i]!;\n index.set(\n `${e.from_type}:${e.from_id}:${e.kind}:${e.to_type}:${e.to_id}`,\n i,\n );\n }\n for (const e of es) {\n const key = `${e.from_type}:${e.from_id}:${e.kind}:${e.to_type}:${e.to_id}`;\n const idx = index.get(key);\n if (idx !== undefined) {\n existing[idx] = e;\n } else {\n index.set(key, existing.length);\n existing.push(e);\n }\n }\n this.edgeStore.set(connectorId, existing);\n };\n\n return {\n event: async (e) => {\n if (!this.eventStore.has(connectorId)) {\n this.eventStore.set(connectorId, []);\n }\n this.eventStore.get(connectorId)!.push(e);\n touch();\n },\n\n entity: async (e) => {\n upsertEntities([e]);\n touch();\n },\n\n metric: async (m) => {\n if (!this.metricStore.has(connectorId)) {\n this.metricStore.set(connectorId, []);\n }\n this.metricStore.get(connectorId)!.push(m);\n touch();\n },\n\n edge: async (e) => {\n upsertEdges([e]);\n touch();\n },\n\n distribution: async (d) => {\n if (!this.distributionStore.has(connectorId)) {\n this.distributionStore.set(connectorId, []);\n }\n this.distributionStore.get(connectorId)!.push(d);\n touch();\n },\n\n events: async (es, scope) => {\n const names = new Set(scope?.names ?? es.map((e) => e.name));\n const kept = (this.eventStore.get(connectorId) ?? []).filter(\n (e) => !names.has(e.name),\n );\n this.eventStore.set(connectorId, [...kept, ...es]);\n touch();\n },\n\n entities: async (es, scope) => {\n const byType = getEntityMap();\n const types = new Set(scope?.types ?? es.map((e) => e.type));\n for (const type of types) {\n byType.set(type, new Map());\n }\n upsertEntities(es);\n touch();\n },\n\n metrics: async (ms, scope) => {\n const names = new Set(scope?.names ?? ms.map((m) => m.name));\n const kept = (this.metricStore.get(connectorId) ?? []).filter(\n (m) => !names.has(m.name),\n );\n this.metricStore.set(connectorId, [...kept, ...ms]);\n touch();\n },\n\n edges: async (es, scope) => {\n const kinds = new Set(scope?.kinds ?? es.map((e) => e.kind));\n const kept = (this.edgeStore.get(connectorId) ?? []).filter(\n (e) => !kinds.has(e.kind),\n );\n this.edgeStore.set(connectorId, kept);\n upsertEdges(es);\n touch();\n },\n\n distributions: async (ds, scope) => {\n const names = new Set(scope?.names ?? ds.map((d) => d.name));\n const kept = (this.distributionStore.get(connectorId) ?? []).filter(\n (d) => !names.has(d.name),\n );\n this.distributionStore.set(connectorId, [...kept, ...ds]);\n touch();\n },\n\n queryEvents: async (q: EventQuery) => {\n let results = this.eventStore.get(connectorId) ?? [];\n if (q.name !== undefined) {\n results = results.filter((e) => e.name === q.name);\n }\n if (q.start !== undefined) {\n results = results.filter((e) => e.start_ts >= q.start!);\n }\n if (q.end !== undefined) {\n results = results.filter((e) => e.start_ts <= q.end!);\n }\n return results;\n },\n\n getEntity: async (type: string, id: string) => {\n return getEntityMap().get(type)?.get(id) ?? null;\n },\n\n queryEntities: async (q: EntityQuery) => {\n const byType = getEntityMap().get(q.type);\n if (!byType) {\n return [];\n }\n return Array.from(byType.values());\n },\n\n queryMetrics: async (q: MetricQuery) => {\n let results = this.metricStore.get(connectorId) ?? [];\n if (q.name !== undefined) {\n results = results.filter((m) => m.name === q.name);\n }\n if (q.start !== undefined) {\n results = results.filter((m) => m.ts >= q.start!);\n }\n if (q.end !== undefined) {\n results = results.filter((m) => m.ts <= q.end!);\n }\n return results;\n },\n\n traverse: async (q: EdgeQuery) => {\n let results = this.edgeStore.get(connectorId) ?? [];\n if (q.fromType !== undefined) {\n results = results.filter((e) => e.from_type === q.fromType);\n }\n if (q.fromId !== undefined) {\n results = results.filter((e) => e.from_id === q.fromId);\n }\n if (q.kind !== undefined) {\n results = results.filter((e) => e.kind === q.kind);\n }\n if (q.toType !== undefined) {\n results = results.filter((e) => e.to_type === q.toType);\n }\n if (q.toId !== undefined) {\n results = results.filter((e) => e.to_id === q.toId);\n }\n return results;\n },\n\n queryDistributions: async (q: DistributionQuery) => {\n let results = this.distributionStore.get(connectorId) ?? [];\n if (q.name !== undefined) {\n results = results.filter((d) => d.name === q.name);\n }\n if (q.start !== undefined) {\n results = results.filter((d) => d.ts >= q.start!);\n }\n if (q.end !== undefined) {\n results = results.filter((d) => d.ts <= q.end!);\n }\n return results;\n },\n\n deleteOlderThan: async (shape, tsUnixMs) => {\n if (shape === 'events') {\n const before = this.eventStore.get(connectorId) ?? [];\n const after = before.filter((e) => e.start_ts >= tsUnixMs);\n this.eventStore.set(connectorId, after);\n return { rowsDeleted: before.length - after.length };\n } else if (shape === 'metrics') {\n const before = this.metricStore.get(connectorId) ?? [];\n const after = before.filter((m) => m.ts >= tsUnixMs);\n this.metricStore.set(connectorId, after);\n return { rowsDeleted: before.length - after.length };\n } else if (shape === 'distributions') {\n const before = this.distributionStore.get(connectorId) ?? [];\n const after = before.filter((d) => d.ts >= tsUnixMs);\n this.distributionStore.set(connectorId, after);\n return { rowsDeleted: before.length - after.length };\n } else {\n throw new Error(\n `Unsupported shape for deleteOlderThan: ${String(shape)}`,\n );\n }\n },\n\n getHealth: async (): Promise<ConnectorHealth> => {\n return {\n status: 'idle',\n lastSyncAt: this.lastWriteAt.get(connectorId) ?? null,\n lastError: null,\n syncIntervalSeconds: 0,\n };\n },\n };\n }\n\n async getSyncState(): Promise<SyncState> {\n return { ...this.syncState };\n }\n\n async markSyncQueued(): Promise<boolean> {\n if (\n this.syncState.status === 'queued' ||\n this.syncState.status === 'running'\n ) {\n return false;\n }\n this.syncState = {\n ...this.syncState,\n status: 'queued',\n queuedAt: new Date().toISOString(),\n startedAt: null,\n };\n return true;\n }\n\n async markSyncRunning(): Promise<boolean> {\n if (this.syncState.status !== 'queued') {\n return false;\n }\n this.syncState = {\n ...this.syncState,\n status: 'running',\n startedAt: new Date().toISOString(),\n };\n return true;\n }\n\n async markSyncSucceeded(): Promise<void> {\n const now = new Date().toISOString();\n this.syncState = {\n status: 'succeeded',\n queuedAt: null,\n startedAt: null,\n lastSyncAt: now,\n lastError: null,\n };\n }\n\n async markSyncFailed(error: string): Promise<void> {\n this.syncState = {\n ...this.syncState,\n status: 'failed',\n queuedAt: null,\n startedAt: null,\n lastError: error,\n };\n }\n}\n","import { z } from 'zod';\n\nimport type { DashboardConfig } from './config';\n\nexport const wireConnectorSchema = z.object({\n name: z.string(),\n connectorId: z.string(),\n displayName: z.string().optional(),\n config: z.record(z.string(), z.unknown()),\n syncIntervalSeconds: z.number().optional(),\n enabled: z.boolean().optional(),\n});\n\nexport const wireDashboardSchema = z.object({\n id: z.string().optional(),\n name: z.string(),\n slug: z.string(),\n config: z.record(z.string(), z.unknown()),\n});\n\nexport const wireConfigSchema = z.object({\n connectors: z.array(wireConnectorSchema).optional(),\n dashboards: z.array(wireDashboardSchema).optional(),\n});\n\nexport type WireConnector = z.infer<typeof wireConnectorSchema>;\nexport type WireDashboard = z.infer<typeof wireDashboardSchema>;\nexport type WireConfig = z.infer<typeof wireConfigSchema>;\n\nexport function toWireConfig(config: DashboardConfig): WireConfig {\n return {\n connectors: config.connectors.map((entry) => ({\n name: entry.name,\n connectorId: entry.connectorId,\n displayName: entry.displayName ?? entry.name,\n config: entry.config,\n syncIntervalSeconds: entry.syncIntervalSeconds ?? 300,\n enabled: entry.enabled ?? true,\n })),\n dashboards: Object.entries(config.dashboards).map(([id, dash]) => ({\n id,\n name: id,\n slug: id,\n config: { widgets: dash.widgets },\n })),\n };\n}\n"],"mappings":"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","names":["err","z","z"]}
|