@rawdash/server 0.18.0 → 0.20.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/dist/index.d.ts CHANGED
@@ -1,26 +1,11 @@
1
1
  import { DashboardConfig, ServerStorage, ConnectorLogger, ConnectorRegistry, SecretsResolver, Widget, CachedWidget, HealthResponse, SyncState, WidgetsListResponse, TriggerSyncResponse, RetentionConfig } from '@rawdash/core';
2
2
  export { ACTIVE_SYNC_STATUSES, CachedWidget, ConfiguredConnector, ConnectorClass, ConnectorHealth, ConnectorRegistry, DashboardConfig, HealthResponse, InMemoryStorage, SecretsResolver, ServerStorage, SyncState, SyncStatus, TriggerSyncResponse, Widget, WidgetSyncState, WidgetsListResponse, computeMetric, instantiateConnector, isSyncActive } from '@rawdash/core';
3
3
 
4
- /**
5
- * Per-request lookup functions an HTTP adapter passes to engine handlers.
6
- *
7
- * Adapters can close over per-request data (e.g. an id extracted from a
8
- * path parameter or auth header) when constructing `getConfig` /
9
- * `getStorage`. The handlers themselves only know how to operate on a
10
- * given `DashboardConfig` and `ServerStorage` — they don't know or care
11
- * how those are obtained.
12
- */
13
4
  interface EngineContext {
14
5
  getConfig: () => DashboardConfig | Promise<DashboardConfig>;
15
6
  getStorage: () => ServerStorage | Promise<ServerStorage>;
16
7
  }
17
8
 
18
- /**
19
- * Thrown by `@rawdash/server` handlers when a request fails in a way the
20
- * HTTP adapter should translate to a structured response (e.g. 404, 400).
21
- * Framework adapters (`@rawdash/hono`, etc.) should catch this and map
22
- * `status` to the appropriate HTTP status code.
23
- */
24
9
  declare class RawdashError extends Error {
25
10
  readonly status: number;
26
11
  readonly code: string;
@@ -28,13 +13,6 @@ declare class RawdashError extends Error {
28
13
  }
29
14
  declare function isRawdashError(err: unknown): err is RawdashError;
30
15
 
31
- /**
32
- * Canonical URL path conventions for the rawdash HTTP wire contract.
33
- *
34
- * Framework adapters (`@rawdash/hono`, etc.) and clients
35
- * (`@rawdash/sdk-client`) should use these constants instead of hard-coding
36
- * paths, so the contract stays in one place.
37
- */
38
16
  declare const ROUTES: {
39
17
  readonly health: "/health";
40
18
  readonly syncState: "/sync/state";
@@ -52,42 +30,8 @@ type ConnectorLoggerFactory = (scope: string) => ConnectorLogger;
52
30
  interface RunSyncOptions {
53
31
  connectorRegistry: ConnectorRegistry;
54
32
  secretsResolver?: SecretsResolver;
55
- /**
56
- * Build a logger for the runner and for each connector instance. Called
57
- * with `'runner'` for the start/settled envelopes and with each
58
- * `connector.name` for the per-connector progress logs. Defaults to
59
- * {@link createDefaultConnectorLogger}, which writes a single-line
60
- * `[scope] event key=value …` record to stdout/stderr.
61
- */
62
33
  loggerFactory?: ConnectorLoggerFactory;
63
34
  }
64
- /**
65
- * Run a full sync across all connectors in the config in parallel via
66
- * `Promise.allSettled`, so one failure doesn't abort the others. Each
67
- * connector run is wrapped in a hard timeout (`FULL_SYNC_TIMEOUT_MS`)
68
- * raced against the connector's own `Promise`, so a connector that
69
- * ignores `AbortSignal` (or a storage call that hangs) can still not
70
- * pin sync state in `running` indefinitely.
71
- *
72
- * Connectors that return `{ done: false, cursor }` are looped in-process,
73
- * threading the cursor back into the next `sync` call until `done: true`
74
- * or the shared timeout / `FULL_SYNC_MAX_CHUNKS` cap fires. Cloud
75
- * deployments layer cross-restart cursor persistence on top of the same
76
- * contract; the OSS runner is the trivial in-process case.
77
- *
78
- * The per-run storage handle is bound to the same `AbortController`, so
79
- * once the timeout fires every subsequent write call on that handle
80
- * becomes a no-op. That makes tail writes from a timed-out connector
81
- * invisible to the next sync even if the connector itself keeps running
82
- * — see `withAbortSignal` in `@rawdash/core` and the safety-net note in
83
- * `docs/authoring-a-connector.md`.
84
- *
85
- * Transitions storage through `queued` → `running` → `succeeded`/`failed`.
86
- * The `queued` step is a no-op if the caller (typically `triggerSync`)
87
- * already marked the run as queued.
88
- *
89
- * Returns silently if another sync acquired the `running` lock first.
90
- */
91
35
  declare function runSync(config: DashboardConfig, storage: ServerStorage, options: RunSyncOptions): Promise<void>;
92
36
 
93
37
  interface WidgetCacheKey {
@@ -100,24 +44,10 @@ interface WidgetCache {
100
44
  set(key: WidgetCacheKey, value: CachedWidget): Promise<void>;
101
45
  }
102
46
 
103
- /**
104
- * Per-request lookup shape accepted by `triggerSync` in deferred mode.
105
- * `getConfig` is optional because the trigger handler never calls
106
- * `runSync` — deployments that delegate the actual sync work to an
107
- * external runner may not be able to materialize a `DashboardConfig` at
108
- * request time.
109
- */
110
47
  interface DeferredTriggerSyncContext {
111
48
  getConfig?: () => DashboardConfig | Promise<DashboardConfig>;
112
49
  getStorage: () => ServerStorage | Promise<ServerStorage>;
113
50
  }
114
- /**
115
- * Per-request lookup shape accepted by `triggerSync` in in-process
116
- * mode. `getConfig` is required because the trigger handler kicks off
117
- * `runSync(config, storage)` in the background. `connectorRegistry` is
118
- * required so the background runner can instantiate connector
119
- * implementations on demand from the declarative `DashboardConfig`.
120
- */
121
51
  interface InProcessTriggerSyncContext {
122
52
  getConfig: () => DashboardConfig | Promise<DashboardConfig>;
123
53
  getStorage: () => ServerStorage | Promise<ServerStorage>;
@@ -125,35 +55,11 @@ interface InProcessTriggerSyncContext {
125
55
  secretsResolver?: SecretsResolver;
126
56
  loggerFactory?: ConnectorLoggerFactory;
127
57
  }
128
- /**
129
- * @deprecated Prefer `InProcessTriggerSyncContext` /
130
- * `DeferredTriggerSyncContext`. Retained as the union for callers that
131
- * need a single type covering both modes.
132
- */
133
58
  type TriggerSyncContext = DeferredTriggerSyncContext;
134
59
  type TriggerSyncMode = 'in-process' | 'deferred';
135
60
  interface TriggerSyncOptions {
136
- /**
137
- * `'in-process'` (default): the trigger handler also runs the sync in
138
- * the background by invoking `runSync(config, storage)`. Suitable for
139
- * self-hosted, single-process deployments.
140
- *
141
- * `'deferred'`: the trigger handler only persists the `queued`
142
- * transition and returns. The `running → succeeded/failed` transitions
143
- * are the responsibility of an external runner (e.g. a queue consumer
144
- * worker), which must drive the storage accordingly.
145
- */
146
61
  mode?: TriggerSyncMode;
147
62
  }
148
- /**
149
- * Framework-agnostic request handlers for the rawdash wire contract.
150
- *
151
- * Each function takes an `EngineContext` (providing per-request access to
152
- * the config + storage) and returns the response body, or throws a
153
- * `RawdashError` on a client-visible failure. HTTP adapters
154
- * (`@rawdash/hono`, etc.) wrap these in their framework's request/response
155
- * cycle and translate `RawdashError` into a structured error response.
156
- */
157
63
  declare function getHealth(): HealthResponse;
158
64
  declare function getSyncStateHandler(ctx: EngineContext): Promise<SyncState>;
159
65
  declare function triggerSync(ctx: InProcessTriggerSyncContext, opts?: {
@@ -180,11 +86,6 @@ declare function runRetentionOnce(ctx: EngineContext): Promise<void>;
180
86
 
181
87
  declare const DEFAULT_RETENTION_INTERVAL_MS: number;
182
88
  declare function hasPruningPolicy(config: RetentionConfig): boolean;
183
- /**
184
- * Apply the retention policy in `config` to every connector's stored data.
185
- * No-op if the config has no pruning policy. Throws an aggregated error if
186
- * any connector fails.
187
- */
188
89
  declare function runRetention(config: DashboardConfig, storage: ServerStorage): Promise<void>;
189
90
 
190
91
  interface EngineOptions {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/routes.ts","../src/handlers.ts","../src/retention.ts","../src/sync.ts","../src/engine.ts","../src/compute.ts","../src/storage.ts","../src/index.ts"],"sourcesContent":["/**\n * Thrown by `@rawdash/server` handlers when a request fails in a way the\n * HTTP adapter should translate to a structured response (e.g. 404, 400).\n * Framework adapters (`@rawdash/hono`, etc.) should catch this and map\n * `status` to the appropriate HTTP status code.\n */\nexport class RawdashError extends Error {\n constructor(\n readonly status: number,\n readonly code: string,\n message: string,\n ) {\n super(message);\n this.name = 'RawdashError';\n }\n}\n\nexport function isRawdashError(err: unknown): err is RawdashError {\n return err instanceof RawdashError;\n}\n","/**\n * Canonical URL path conventions for the rawdash HTTP wire contract.\n *\n * Framework adapters (`@rawdash/hono`, etc.) and clients\n * (`@rawdash/sdk-client`) should use these constants instead of hard-coding\n * paths, so the contract stays in one place.\n */\nexport const ROUTES = {\n health: '/health',\n syncState: '/sync/state',\n sync: '/sync',\n retention: '/retention/retain',\n widgets: {\n list: (dashboardId: string): string =>\n `/dashboards/${encodeURIComponent(dashboardId)}/widgets`,\n single: (dashboardId: string, widgetId: string): string =>\n `/dashboards/${encodeURIComponent(dashboardId)}/widgets/${encodeURIComponent(widgetId)}`,\n },\n} as const;\n","import type {\n CachedWidget,\n ConnectorRegistry,\n HealthResponse,\n SecretsResolver,\n SyncState,\n TriggerSyncResponse,\n Widget,\n WidgetsListResponse,\n} from '@rawdash/core';\nimport { computeWidgetEtag, isSyncActive, resolveWidget } from '@rawdash/core';\nimport type { DashboardConfig, ServerStorage } from '@rawdash/core';\n\nimport type { EngineContext } from './context';\nimport { RawdashError } from './errors';\nimport { runRetention } from './retention';\nimport { type ConnectorLoggerFactory, runSync } from './sync';\nimport type { WidgetCache } from './widget-cache';\n\nasync function cacheGetSafe(\n cache: WidgetCache,\n dashboardId: string,\n widgetId: string,\n widget: Widget,\n): Promise<CachedWidget | undefined> {\n try {\n return await cache.get({ dashboardId, widgetId, widget });\n } catch (err) {\n console.warn('Rawdash widget cache get failed', err);\n return undefined;\n }\n}\n\nasync function cacheSetSafe(\n cache: WidgetCache,\n dashboardId: string,\n widgetId: string,\n widget: Widget,\n value: CachedWidget,\n): Promise<void> {\n try {\n await cache.set({ dashboardId, widgetId, widget }, value);\n } catch (err) {\n console.warn('Rawdash widget cache set failed', err);\n }\n}\n\nasync function resolveWithCache(\n dashboardId: string,\n widgetId: string,\n widget: Widget,\n connectorNames: readonly string[],\n storage: ServerStorage,\n cache: WidgetCache | undefined,\n): Promise<CachedWidget | undefined> {\n if (cache) {\n const hit = await cacheGetSafe(cache, dashboardId, widgetId, widget);\n if (hit) {\n return hit;\n }\n }\n const fresh = await resolveWidget(\n dashboardId,\n widgetId,\n widget,\n connectorNames,\n storage,\n );\n if (fresh && cache) {\n await cacheSetSafe(cache, dashboardId, widgetId, widget, fresh);\n }\n return fresh;\n}\n\n/**\n * Per-request lookup shape accepted by `triggerSync` in deferred mode.\n * `getConfig` is optional because the trigger handler never calls\n * `runSync` — deployments that delegate the actual sync work to an\n * external runner may not be able to materialize a `DashboardConfig` at\n * request time.\n */\nexport interface DeferredTriggerSyncContext {\n getConfig?: () => DashboardConfig | Promise<DashboardConfig>;\n getStorage: () => ServerStorage | Promise<ServerStorage>;\n}\n\n/**\n * Per-request lookup shape accepted by `triggerSync` in in-process\n * mode. `getConfig` is required because the trigger handler kicks off\n * `runSync(config, storage)` in the background. `connectorRegistry` is\n * required so the background runner can instantiate connector\n * implementations on demand from the declarative `DashboardConfig`.\n */\nexport interface InProcessTriggerSyncContext {\n getConfig: () => DashboardConfig | Promise<DashboardConfig>;\n getStorage: () => ServerStorage | Promise<ServerStorage>;\n connectorRegistry: ConnectorRegistry;\n secretsResolver?: SecretsResolver;\n loggerFactory?: ConnectorLoggerFactory;\n}\n\n/**\n * @deprecated Prefer `InProcessTriggerSyncContext` /\n * `DeferredTriggerSyncContext`. Retained as the union for callers that\n * need a single type covering both modes.\n */\nexport type TriggerSyncContext = DeferredTriggerSyncContext;\n\nexport type TriggerSyncMode = 'in-process' | 'deferred';\n\nexport interface TriggerSyncOptions {\n /**\n * `'in-process'` (default): the trigger handler also runs the sync in\n * the background by invoking `runSync(config, storage)`. Suitable for\n * self-hosted, single-process deployments.\n *\n * `'deferred'`: the trigger handler only persists the `queued`\n * transition and returns. The `running → succeeded/failed` transitions\n * are the responsibility of an external runner (e.g. a queue consumer\n * worker), which must drive the storage accordingly.\n */\n mode?: TriggerSyncMode;\n}\n\n/**\n * Framework-agnostic request handlers for the rawdash wire contract.\n *\n * Each function takes an `EngineContext` (providing per-request access to\n * the config + storage) and returns the response body, or throws a\n * `RawdashError` on a client-visible failure. HTTP adapters\n * (`@rawdash/hono`, etc.) wrap these in their framework's request/response\n * cycle and translate `RawdashError` into a structured error response.\n */\n\nexport function getHealth(): HealthResponse {\n return { status: 'ok' };\n}\n\nexport async function getSyncStateHandler(\n ctx: EngineContext,\n): Promise<SyncState> {\n const storage = await ctx.getStorage();\n return storage.getSyncState();\n}\n\nexport function triggerSync(\n ctx: InProcessTriggerSyncContext,\n opts?: { mode?: 'in-process' },\n): Promise<TriggerSyncResponse>;\nexport function triggerSync(\n ctx: DeferredTriggerSyncContext,\n opts: { mode: 'deferred' },\n): Promise<TriggerSyncResponse>;\nexport async function triggerSync(\n ctx: InProcessTriggerSyncContext | DeferredTriggerSyncContext,\n opts: TriggerSyncOptions = {},\n): Promise<TriggerSyncResponse> {\n const mode: TriggerSyncMode = opts.mode ?? 'in-process';\n const storage = await ctx.getStorage();\n const state = await storage.getSyncState();\n if (isSyncActive(state.status)) {\n return { queued: false };\n }\n let config: DashboardConfig | undefined;\n if (mode === 'in-process') {\n if (!ctx.getConfig) {\n throw new Error(\n 'triggerSync: getConfig is required when mode is \"in-process\"',\n );\n }\n config = await ctx.getConfig();\n }\n const queued = await storage.markSyncQueued();\n if (!queued) {\n return { queued: false };\n }\n if (mode === 'deferred') {\n return { queued: true };\n }\n const inProcessCtx = ctx as InProcessTriggerSyncContext;\n void runSync(config!, storage, {\n connectorRegistry: inProcessCtx.connectorRegistry,\n secretsResolver: inProcessCtx.secretsResolver,\n loggerFactory: inProcessCtx.loggerFactory,\n }).catch((err) => {\n console.error('Rawdash sync failed', err);\n });\n return { queued: true };\n}\n\nexport async function listWidgets(\n ctx: EngineContext,\n dashboardId: string,\n cache?: WidgetCache,\n): Promise<WidgetsListResponse> {\n const config = await ctx.getConfig();\n const dashboard = config.dashboards[dashboardId];\n if (!dashboard) {\n throw new RawdashError(404, 'DASHBOARD_NOT_FOUND', 'Dashboard not found');\n }\n const storage = await ctx.getStorage();\n const connectorNames = config.connectors.map((c) => c.name);\n const entries = Object.entries(dashboard.widgets);\n const resolved = await Promise.all(\n entries.map(([key, widget]) =>\n resolveWithCache(\n dashboardId,\n key,\n widget,\n connectorNames,\n storage,\n cache,\n ),\n ),\n );\n const widgets = resolved.filter((w): w is CachedWidget => w !== undefined);\n return { widgets };\n}\n\nexport interface GetWidgetOptions {\n cache?: WidgetCache;\n ifNoneMatch?: string;\n}\n\nexport type GetWidgetResult =\n | { status: 'ok'; etag: string | undefined; widget: CachedWidget }\n | { status: 'not-modified'; etag: string };\n\nexport async function getWidget(\n ctx: EngineContext,\n dashboardId: string,\n widgetId: string,\n opts: GetWidgetOptions = {},\n): Promise<GetWidgetResult> {\n const { cache, ifNoneMatch } = opts;\n const config = await ctx.getConfig();\n const dashboard = config.dashboards[dashboardId];\n if (!dashboard) {\n throw new RawdashError(404, 'DASHBOARD_NOT_FOUND', 'Dashboard not found');\n }\n const widget = dashboard.widgets[widgetId];\n if (!widget) {\n throw new RawdashError(404, 'WIDGET_NOT_FOUND', 'Widget not found');\n }\n const storage = await ctx.getStorage();\n const connectorNames = config.connectors.map((c) => c.name);\n const connectorId =\n widget.kind === 'status' ? widget.source : widget.metric.connectorId;\n if (!connectorNames.includes(connectorId)) {\n throw new RawdashError(404, 'WIDGET_NOT_FOUND', 'Widget not found');\n }\n\n if (ifNoneMatch) {\n const handle = storage.getStorageHandle(connectorId);\n const health = (await handle.getHealth?.()) ?? null;\n if (health?.lastSyncAt) {\n const probeEtag = computeWidgetEtag(health.lastSyncAt, widget);\n if (probeEtag === ifNoneMatch) {\n return { status: 'not-modified', etag: probeEtag };\n }\n }\n }\n\n const result = await resolveWithCache(\n dashboardId,\n widgetId,\n widget,\n connectorNames,\n storage,\n cache,\n );\n if (!result) {\n throw new RawdashError(404, 'WIDGET_NOT_FOUND', 'Widget not found');\n }\n const etag = result.cachedAt\n ? computeWidgetEtag(result.cachedAt, widget)\n : undefined;\n return { status: 'ok', etag, widget: result };\n}\n\nexport async function runRetentionOnce(ctx: EngineContext): Promise<void> {\n const config = await ctx.getConfig();\n const storage = await ctx.getStorage();\n await runRetention(config, storage);\n}\n","import type {\n DashboardConfig,\n RetentionConfig,\n ServerStorage,\n} from '@rawdash/core';\nimport { selectForDeletion } from '@rawdash/core';\n\nexport const DEFAULT_RETENTION_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\n\nexport function hasPruningPolicy(config: RetentionConfig): boolean {\n return config.maxAge !== undefined || config.maxSize !== undefined;\n}\n\n/**\n * Apply the retention policy in `config` to every connector's stored data.\n * No-op if the config has no pruning policy. Throws an aggregated error if\n * any connector fails.\n */\nexport async function runRetention(\n config: DashboardConfig,\n storage: ServerStorage,\n): Promise<void> {\n const retentionConfig = config.retention;\n if (!retentionConfig || !hasPruningPolicy(retentionConfig)) {\n return;\n }\n\n const nowMs = Date.now();\n\n const results = await Promise.allSettled(\n config.connectors.map(async (entry) => {\n const handle = storage.getStorageHandle(entry.name);\n\n const [events, metrics, distributions] = await Promise.all([\n handle.queryEvents({}),\n handle.queryMetrics({}),\n handle.queryDistributions({}),\n ]);\n\n await applyRetentionToShape(\n events,\n (e) => e.start_ts,\n retentionConfig,\n nowMs,\n (survivors, names) => handle.events(survivors, { names }),\n );\n\n await applyRetentionToShape(\n metrics,\n (m) => m.ts,\n retentionConfig,\n nowMs,\n (survivors, names) => handle.metrics(survivors, { names }),\n );\n\n await applyRetentionToShape(\n distributions,\n (d) => d.ts,\n retentionConfig,\n nowMs,\n (survivors, names) => handle.distributions(survivors, { names }),\n );\n }),\n );\n\n const failures = results.filter(\n (r): r is PromiseRejectedResult => r.status === 'rejected',\n );\n if (failures.length > 0) {\n throw new Error(\n `Retention failed for ${failures.length} connector(s): ${failures.map((f) => String(f.reason)).join('; ')}`,\n );\n }\n}\n\nasync function applyRetentionToShape<T extends { name: string }>(\n rows: T[],\n getTs: (row: T) => number,\n config: RetentionConfig,\n nowMs: number,\n writeSurvivors: (survivors: T[], names: string[]) => Promise<void>,\n): Promise<void> {\n if (rows.length === 0) {\n return;\n }\n\n const sorted = [...rows].sort((a, b) => getTs(b) - getTs(a));\n const toDeleteSet = new Set(selectForDeletion(sorted, getTs, config, nowMs));\n\n if (toDeleteSet.size === 0) {\n return;\n }\n\n const survivors = sorted.filter((r) => !toDeleteSet.has(r));\n const allNames = [...new Set(rows.map((r) => r.name))];\n\n await writeSurvivors(survivors, allNames);\n}\n","import type {\n ConnectorLogger,\n ConnectorRegistry,\n DashboardConfig,\n SecretsResolver,\n ServerStorage,\n} from '@rawdash/core';\nimport {\n computeConnectorBackfill,\n createDefaultConnectorLogger,\n instantiateConnector,\n} from '@rawdash/core';\n\nexport const FULL_SYNC_TIMEOUT_MS = 300_000;\nexport const FULL_SYNC_MAX_CHUNKS = 1_000;\nexport const BACKFILL_BUFFER_MS = 86_400_000;\n\nexport type ConnectorLoggerFactory = (scope: string) => ConnectorLogger;\n\nexport interface RunSyncOptions {\n connectorRegistry: ConnectorRegistry;\n secretsResolver?: SecretsResolver;\n /**\n * Build a logger for the runner and for each connector instance. Called\n * with `'runner'` for the start/settled envelopes and with each\n * `connector.name` for the per-connector progress logs. Defaults to\n * {@link createDefaultConnectorLogger}, which writes a single-line\n * `[scope] event key=value …` record to stdout/stderr.\n */\n loggerFactory?: ConnectorLoggerFactory;\n}\n\n/**\n * Run a full sync across all connectors in the config in parallel via\n * `Promise.allSettled`, so one failure doesn't abort the others. Each\n * connector run is wrapped in a hard timeout (`FULL_SYNC_TIMEOUT_MS`)\n * raced against the connector's own `Promise`, so a connector that\n * ignores `AbortSignal` (or a storage call that hangs) can still not\n * pin sync state in `running` indefinitely.\n *\n * Connectors that return `{ done: false, cursor }` are looped in-process,\n * threading the cursor back into the next `sync` call until `done: true`\n * or the shared timeout / `FULL_SYNC_MAX_CHUNKS` cap fires. Cloud\n * deployments layer cross-restart cursor persistence on top of the same\n * contract; the OSS runner is the trivial in-process case.\n *\n * The per-run storage handle is bound to the same `AbortController`, so\n * once the timeout fires every subsequent write call on that handle\n * becomes a no-op. That makes tail writes from a timed-out connector\n * invisible to the next sync even if the connector itself keeps running\n * — see `withAbortSignal` in `@rawdash/core` and the safety-net note in\n * `docs/authoring-a-connector.md`.\n *\n * Transitions storage through `queued` → `running` → `succeeded`/`failed`.\n * The `queued` step is a no-op if the caller (typically `triggerSync`)\n * already marked the run as queued.\n *\n * Returns silently if another sync acquired the `running` lock first.\n */\nexport async function runSync(\n config: DashboardConfig,\n storage: ServerStorage,\n options: RunSyncOptions,\n): Promise<void> {\n await storage.markSyncQueued();\n if (typeof storage.markSyncRunning === 'function') {\n const acquired = await storage.markSyncRunning();\n if (!acquired) {\n return;\n }\n }\n const errors: string[] = [];\n const backfill = computeConnectorBackfill(config);\n const now = Date.now();\n const rawLoggerFactory: ConnectorLoggerFactory =\n options.loggerFactory ??\n ((scope) => createDefaultConnectorLogger({ scope }));\n const safeLogger = (scope: string): ConnectorLogger => {\n let inner: ConnectorLogger;\n try {\n inner = rawLoggerFactory(scope);\n } catch (err) {\n console.warn(\n `[runner] loggerFactory threw for scope=${scope}; falling back to default`,\n err,\n );\n inner = createDefaultConnectorLogger({ scope });\n }\n return {\n info(event, fields) {\n try {\n inner.info(event, fields);\n } catch (err) {\n console.warn(\n `[runner] logger.info threw for scope=${scope} event=${event}`,\n err,\n );\n }\n },\n warn(event, fields) {\n try {\n inner.warn(event, fields);\n } catch (err) {\n console.warn(\n `[runner] logger.warn threw for scope=${scope} event=${event}`,\n err,\n );\n }\n },\n };\n };\n const runnerLogger = safeLogger('runner');\n await Promise.allSettled(\n config.connectors.map(async (entry) => {\n if (entry.enabled === false) {\n return;\n }\n const scope = backfill.get(entry.name);\n if (!scope) {\n return;\n }\n const controller = new AbortController();\n const handle = storage.getStorageHandle(entry.name, {\n signal: controller.signal,\n });\n const connectorLogger = safeLogger(entry.name);\n const syncStart = Date.now();\n let timer: ReturnType<typeof setTimeout> | undefined;\n let status: 'succeeded' | 'failed' = 'succeeded';\n let failureReason: string | undefined;\n try {\n const connector = instantiateConnector(\n entry,\n options.connectorRegistry,\n options.secretsResolver,\n connectorLogger,\n );\n const timeoutPromise = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n const err = new Error(\n `${entry.name} timed out after ${FULL_SYNC_TIMEOUT_MS}ms`,\n );\n err.name = 'AbortError';\n reject(err);\n }, FULL_SYNC_TIMEOUT_MS);\n });\n\n const resources: ReadonlySet<string> = new Set(scope.keys());\n\n let maxWindowMs: number | undefined;\n for (const [, { requiredWindowMs }] of scope.entries()) {\n if (requiredWindowMs === undefined) {\n continue;\n }\n if (maxWindowMs === undefined || requiredWindowMs > maxWindowMs) {\n maxWindowMs = requiredWindowMs;\n }\n }\n const since =\n maxWindowMs !== undefined\n ? new Date(now - maxWindowMs - BACKFILL_BUFFER_MS).toISOString()\n : undefined;\n\n runnerLogger.info('sync started', {\n connector: entry.name,\n resources: Array.from(resources),\n mode: 'full',\n since,\n });\n\n let cursor: unknown = undefined;\n let chunks = 0;\n while (true) {\n chunks += 1;\n if (chunks > FULL_SYNC_MAX_CHUNKS) {\n controller.abort();\n throw new Error(\n `${entry.name} exceeded ${FULL_SYNC_MAX_CHUNKS} sync chunks without completing`,\n );\n }\n const syncPromise = connector.sync(\n { mode: 'full', since, cursor, resources },\n handle,\n controller.signal,\n );\n const result = await Promise.race([syncPromise, timeoutPromise]);\n if (result.done) {\n break;\n }\n cursor = result.cursor;\n }\n } catch (err) {\n status = 'failed';\n if (err instanceof Error && err.name === 'AbortError') {\n failureReason = `${entry.name} timed out after ${FULL_SYNC_TIMEOUT_MS}ms`;\n } else {\n failureReason = err instanceof Error ? err.message : String(err);\n }\n errors.push(failureReason);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n runnerLogger.info('sync settled', {\n connector: entry.name,\n status,\n duration_ms: Date.now() - syncStart,\n error: failureReason,\n });\n }\n }),\n );\n if (errors.length > 0) {\n await storage.markSyncFailed(errors.join('; '));\n } else {\n await storage.markSyncSucceeded();\n }\n}\n","import type {\n CachedWidget,\n ConnectorRegistry,\n DashboardConfig,\n HealthResponse,\n SecretsResolver,\n ServerStorage,\n SyncState,\n TriggerSyncResponse,\n} from '@rawdash/core';\nimport { InMemoryStorage, isSyncActive, resolveWidget } from '@rawdash/core';\n\nimport { type ConnectorLoggerFactory, runSync } from './sync';\n\nexport interface EngineOptions {\n storage?: ServerStorage;\n connectorRegistry?: ConnectorRegistry;\n secretsResolver?: SecretsResolver;\n loggerFactory?: ConnectorLoggerFactory;\n}\n\nexport interface Engine {\n getWidget(\n dashboardId: string,\n widgetId: string,\n ): Promise<CachedWidget | undefined>;\n getWidgets(dashboardId: string): Promise<CachedWidget[]>;\n getHealth(): Promise<HealthResponse>;\n getSyncState(): Promise<SyncState>;\n triggerSync(): Promise<TriggerSyncResponse>;\n}\n\nexport function createEngine(\n config: DashboardConfig,\n options: EngineOptions = {},\n): Engine {\n const storage: ServerStorage = options.storage ?? new InMemoryStorage();\n const connectorNames = config.connectors.map((c) => c.name);\n\n return {\n async getWidget(dashboardId, widgetId) {\n const dashboard = config.dashboards[dashboardId];\n if (!dashboard) {\n return undefined;\n }\n const widget = dashboard.widgets[widgetId];\n if (!widget) {\n return undefined;\n }\n return resolveWidget(\n dashboardId,\n widgetId,\n widget,\n connectorNames,\n storage,\n );\n },\n\n async getWidgets(dashboardId) {\n const dashboard = config.dashboards[dashboardId];\n if (!dashboard) {\n return [];\n }\n const entries = Object.entries(dashboard.widgets);\n const resolved = await Promise.all(\n entries.map(([key, widget]) =>\n resolveWidget(dashboardId, key, widget, connectorNames, storage),\n ),\n );\n return resolved.filter((w): w is CachedWidget => w !== undefined);\n },\n\n async getHealth() {\n return { status: 'ok' };\n },\n\n async getSyncState() {\n return storage.getSyncState();\n },\n\n async triggerSync() {\n if (!options.connectorRegistry) {\n throw new Error(\n 'createEngine: connectorRegistry is required to triggerSync',\n );\n }\n const state = await storage.getSyncState();\n if (isSyncActive(state.status)) {\n return { queued: false };\n }\n const queued = await storage.markSyncQueued();\n if (!queued) {\n return { queued: false };\n }\n void runSync(config, storage, {\n connectorRegistry: options.connectorRegistry,\n secretsResolver: options.secretsResolver,\n loggerFactory: options.loggerFactory,\n }).catch((error) => {\n console.error('Rawdash sync failed', error);\n });\n return { queued: true };\n },\n };\n}\n","export { computeMetric } from '@rawdash/core';\n","export { InMemoryStorage } from '@rawdash/core';\n","export type { EngineContext } from './context';\nexport { RawdashError, isRawdashError } from './errors';\nexport { ROUTES } from './routes';\nexport {\n getHealth,\n getSyncStateHandler,\n getWidget,\n listWidgets,\n runRetentionOnce,\n triggerSync,\n} from './handlers';\nexport type {\n DeferredTriggerSyncContext,\n GetWidgetOptions,\n GetWidgetResult,\n InProcessTriggerSyncContext,\n TriggerSyncContext,\n TriggerSyncMode,\n TriggerSyncOptions,\n} from './handlers';\nexport type { WidgetCache, WidgetCacheKey } from './widget-cache';\nexport { runSync, FULL_SYNC_TIMEOUT_MS, FULL_SYNC_MAX_CHUNKS } from './sync';\nexport type { ConnectorLoggerFactory, RunSyncOptions } from './sync';\nexport {\n runRetention,\n hasPruningPolicy,\n DEFAULT_RETENTION_INTERVAL_MS,\n} from './retention';\nexport { createEngine } from './engine';\nexport type { Engine, EngineOptions } from './engine';\nexport { computeMetric } from './compute';\nexport { InMemoryStorage } from './storage';\nexport type {\n CachedWidget,\n ConfiguredConnector,\n ConnectorHealth,\n DashboardConfig,\n HealthResponse,\n ServerStorage,\n SyncState,\n SyncStatus,\n TriggerSyncResponse,\n Widget,\n WidgetSyncState,\n WidgetsListResponse,\n} from './types';\nexport { isSyncActive, ACTIVE_SYNC_STATUSES } from '@rawdash/core';\nexport { instantiateConnector } from '@rawdash/core';\nexport type {\n ConnectorClass,\n ConnectorRegistry,\n SecretsResolver,\n} from '@rawdash/core';\n"],"mappings":"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","names":["isSyncActive","resolveWidget","resolveWidget","isSyncActive","InMemoryStorage","isSyncActive","instantiateConnector"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/routes.ts","../src/handlers.ts","../src/retention.ts","../src/sync.ts","../src/engine.ts","../src/compute.ts","../src/storage.ts","../src/index.ts"],"sourcesContent":["export class RawdashError extends Error {\n constructor(\n readonly status: number,\n readonly code: string,\n message: string,\n ) {\n super(message);\n this.name = 'RawdashError';\n }\n}\n\nexport function isRawdashError(err: unknown): err is RawdashError {\n return err instanceof RawdashError;\n}\n","export const ROUTES = {\n health: '/health',\n syncState: '/sync/state',\n sync: '/sync',\n retention: '/retention/retain',\n widgets: {\n list: (dashboardId: string): string =>\n `/dashboards/${encodeURIComponent(dashboardId)}/widgets`,\n single: (dashboardId: string, widgetId: string): string =>\n `/dashboards/${encodeURIComponent(dashboardId)}/widgets/${encodeURIComponent(widgetId)}`,\n },\n} as const;\n","import type {\n CachedWidget,\n ConnectorRegistry,\n HealthResponse,\n SecretsResolver,\n SyncState,\n TriggerSyncResponse,\n Widget,\n WidgetsListResponse,\n} from '@rawdash/core';\nimport { computeWidgetEtag, isSyncActive, resolveWidget } from '@rawdash/core';\nimport type { DashboardConfig, ServerStorage } from '@rawdash/core';\n\nimport type { EngineContext } from './context';\nimport { RawdashError } from './errors';\nimport { runRetention } from './retention';\nimport { type ConnectorLoggerFactory, runSync } from './sync';\nimport type { WidgetCache } from './widget-cache';\n\nasync function cacheGetSafe(\n cache: WidgetCache,\n dashboardId: string,\n widgetId: string,\n widget: Widget,\n): Promise<CachedWidget | undefined> {\n try {\n return await cache.get({ dashboardId, widgetId, widget });\n } catch (err) {\n console.warn('Rawdash widget cache get failed', err);\n return undefined;\n }\n}\n\nasync function cacheSetSafe(\n cache: WidgetCache,\n dashboardId: string,\n widgetId: string,\n widget: Widget,\n value: CachedWidget,\n): Promise<void> {\n try {\n await cache.set({ dashboardId, widgetId, widget }, value);\n } catch (err) {\n console.warn('Rawdash widget cache set failed', err);\n }\n}\n\nasync function resolveWithCache(\n dashboardId: string,\n widgetId: string,\n widget: Widget,\n connectorNames: readonly string[],\n storage: ServerStorage,\n cache: WidgetCache | undefined,\n): Promise<CachedWidget | undefined> {\n if (cache) {\n const hit = await cacheGetSafe(cache, dashboardId, widgetId, widget);\n if (hit) {\n return hit;\n }\n }\n const fresh = await resolveWidget(\n dashboardId,\n widgetId,\n widget,\n connectorNames,\n storage,\n );\n if (fresh && cache) {\n await cacheSetSafe(cache, dashboardId, widgetId, widget, fresh);\n }\n return fresh;\n}\n\nexport interface DeferredTriggerSyncContext {\n getConfig?: () => DashboardConfig | Promise<DashboardConfig>;\n getStorage: () => ServerStorage | Promise<ServerStorage>;\n}\n\nexport interface InProcessTriggerSyncContext {\n getConfig: () => DashboardConfig | Promise<DashboardConfig>;\n getStorage: () => ServerStorage | Promise<ServerStorage>;\n connectorRegistry: ConnectorRegistry;\n secretsResolver?: SecretsResolver;\n loggerFactory?: ConnectorLoggerFactory;\n}\n\nexport type TriggerSyncContext = DeferredTriggerSyncContext;\n\nexport type TriggerSyncMode = 'in-process' | 'deferred';\n\nexport interface TriggerSyncOptions {\n mode?: TriggerSyncMode;\n}\n\nexport function getHealth(): HealthResponse {\n return { status: 'ok' };\n}\n\nexport async function getSyncStateHandler(\n ctx: EngineContext,\n): Promise<SyncState> {\n const storage = await ctx.getStorage();\n return storage.getSyncState();\n}\n\nexport function triggerSync(\n ctx: InProcessTriggerSyncContext,\n opts?: { mode?: 'in-process' },\n): Promise<TriggerSyncResponse>;\nexport function triggerSync(\n ctx: DeferredTriggerSyncContext,\n opts: { mode: 'deferred' },\n): Promise<TriggerSyncResponse>;\nexport async function triggerSync(\n ctx: InProcessTriggerSyncContext | DeferredTriggerSyncContext,\n opts: TriggerSyncOptions = {},\n): Promise<TriggerSyncResponse> {\n const mode: TriggerSyncMode = opts.mode ?? 'in-process';\n const storage = await ctx.getStorage();\n const state = await storage.getSyncState();\n if (isSyncActive(state.status)) {\n return { queued: false };\n }\n let config: DashboardConfig | undefined;\n if (mode === 'in-process') {\n if (!ctx.getConfig) {\n throw new Error(\n 'triggerSync: getConfig is required when mode is \"in-process\"',\n );\n }\n config = await ctx.getConfig();\n }\n const queued = await storage.markSyncQueued();\n if (!queued) {\n return { queued: false };\n }\n if (mode === 'deferred') {\n return { queued: true };\n }\n const inProcessCtx = ctx as InProcessTriggerSyncContext;\n void runSync(config!, storage, {\n connectorRegistry: inProcessCtx.connectorRegistry,\n secretsResolver: inProcessCtx.secretsResolver,\n loggerFactory: inProcessCtx.loggerFactory,\n }).catch((err) => {\n console.error('Rawdash sync failed', err);\n });\n return { queued: true };\n}\n\nexport async function listWidgets(\n ctx: EngineContext,\n dashboardId: string,\n cache?: WidgetCache,\n): Promise<WidgetsListResponse> {\n const config = await ctx.getConfig();\n const dashboard = config.dashboards[dashboardId];\n if (!dashboard) {\n throw new RawdashError(404, 'DASHBOARD_NOT_FOUND', 'Dashboard not found');\n }\n const storage = await ctx.getStorage();\n const connectorNames = config.connectors.map((c) => c.name);\n const entries = Object.entries(dashboard.widgets);\n const resolved = await Promise.all(\n entries.map(([key, widget]) =>\n resolveWithCache(\n dashboardId,\n key,\n widget,\n connectorNames,\n storage,\n cache,\n ),\n ),\n );\n const widgets = resolved.filter((w): w is CachedWidget => w !== undefined);\n return { widgets };\n}\n\nexport interface GetWidgetOptions {\n cache?: WidgetCache;\n ifNoneMatch?: string;\n}\n\nexport type GetWidgetResult =\n | { status: 'ok'; etag: string | undefined; widget: CachedWidget }\n | { status: 'not-modified'; etag: string };\n\nexport async function getWidget(\n ctx: EngineContext,\n dashboardId: string,\n widgetId: string,\n opts: GetWidgetOptions = {},\n): Promise<GetWidgetResult> {\n const { cache, ifNoneMatch } = opts;\n const config = await ctx.getConfig();\n const dashboard = config.dashboards[dashboardId];\n if (!dashboard) {\n throw new RawdashError(404, 'DASHBOARD_NOT_FOUND', 'Dashboard not found');\n }\n const widget = dashboard.widgets[widgetId];\n if (!widget) {\n throw new RawdashError(404, 'WIDGET_NOT_FOUND', 'Widget not found');\n }\n const storage = await ctx.getStorage();\n const connectorNames = config.connectors.map((c) => c.name);\n const connectorId =\n widget.kind === 'status' ? widget.source : widget.metric.connectorId;\n if (!connectorNames.includes(connectorId)) {\n throw new RawdashError(404, 'WIDGET_NOT_FOUND', 'Widget not found');\n }\n\n if (ifNoneMatch) {\n const handle = storage.getStorageHandle(connectorId);\n const health = (await handle.getHealth?.()) ?? null;\n if (health?.lastSyncAt) {\n const probeEtag = computeWidgetEtag(health.lastSyncAt, widget);\n if (probeEtag === ifNoneMatch) {\n return { status: 'not-modified', etag: probeEtag };\n }\n }\n }\n\n const result = await resolveWithCache(\n dashboardId,\n widgetId,\n widget,\n connectorNames,\n storage,\n cache,\n );\n if (!result) {\n throw new RawdashError(404, 'WIDGET_NOT_FOUND', 'Widget not found');\n }\n const etag = result.cachedAt\n ? computeWidgetEtag(result.cachedAt, widget)\n : undefined;\n return { status: 'ok', etag, widget: result };\n}\n\nexport async function runRetentionOnce(ctx: EngineContext): Promise<void> {\n const config = await ctx.getConfig();\n const storage = await ctx.getStorage();\n await runRetention(config, storage);\n}\n","import type {\n DashboardConfig,\n RetentionConfig,\n ServerStorage,\n} from '@rawdash/core';\nimport { selectForDeletion } from '@rawdash/core';\n\nexport const DEFAULT_RETENTION_INTERVAL_MS = 60 * 60 * 1000;\n\nexport function hasPruningPolicy(config: RetentionConfig): boolean {\n return config.maxAge !== undefined || config.maxSize !== undefined;\n}\n\nexport async function runRetention(\n config: DashboardConfig,\n storage: ServerStorage,\n): Promise<void> {\n const retentionConfig = config.retention;\n if (!retentionConfig || !hasPruningPolicy(retentionConfig)) {\n return;\n }\n\n const nowMs = Date.now();\n\n const results = await Promise.allSettled(\n config.connectors.map(async (entry) => {\n const handle = storage.getStorageHandle(entry.name);\n\n const [events, metrics, distributions] = await Promise.all([\n handle.queryEvents({}),\n handle.queryMetrics({}),\n handle.queryDistributions({}),\n ]);\n\n await applyRetentionToShape(\n events,\n (e) => e.start_ts,\n retentionConfig,\n nowMs,\n (survivors, names) => handle.events(survivors, { names }),\n );\n\n await applyRetentionToShape(\n metrics,\n (m) => m.ts,\n retentionConfig,\n nowMs,\n (survivors, names) => handle.metrics(survivors, { names }),\n );\n\n await applyRetentionToShape(\n distributions,\n (d) => d.ts,\n retentionConfig,\n nowMs,\n (survivors, names) => handle.distributions(survivors, { names }),\n );\n }),\n );\n\n const failures = results.filter(\n (r): r is PromiseRejectedResult => r.status === 'rejected',\n );\n if (failures.length > 0) {\n throw new Error(\n `Retention failed for ${failures.length} connector(s): ${failures.map((f) => String(f.reason)).join('; ')}`,\n );\n }\n}\n\nasync function applyRetentionToShape<T extends { name: string }>(\n rows: T[],\n getTs: (row: T) => number,\n config: RetentionConfig,\n nowMs: number,\n writeSurvivors: (survivors: T[], names: string[]) => Promise<void>,\n): Promise<void> {\n if (rows.length === 0) {\n return;\n }\n\n const sorted = [...rows].sort((a, b) => getTs(b) - getTs(a));\n const toDeleteSet = new Set(selectForDeletion(sorted, getTs, config, nowMs));\n\n if (toDeleteSet.size === 0) {\n return;\n }\n\n const survivors = sorted.filter((r) => !toDeleteSet.has(r));\n const allNames = [...new Set(rows.map((r) => r.name))];\n\n await writeSurvivors(survivors, allNames);\n}\n","import type {\n ConnectorLogger,\n ConnectorRegistry,\n DashboardConfig,\n SecretsResolver,\n ServerStorage,\n} from '@rawdash/core';\nimport {\n computeConnectorBackfill,\n createDefaultConnectorLogger,\n instantiateConnector,\n} from '@rawdash/core';\n\nexport const FULL_SYNC_TIMEOUT_MS = 300_000;\nexport const FULL_SYNC_MAX_CHUNKS = 1_000;\nexport const BACKFILL_BUFFER_MS = 86_400_000;\n\nexport type ConnectorLoggerFactory = (scope: string) => ConnectorLogger;\n\nexport interface RunSyncOptions {\n connectorRegistry: ConnectorRegistry;\n secretsResolver?: SecretsResolver;\n loggerFactory?: ConnectorLoggerFactory;\n}\n\nexport async function runSync(\n config: DashboardConfig,\n storage: ServerStorage,\n options: RunSyncOptions,\n): Promise<void> {\n await storage.markSyncQueued();\n if (typeof storage.markSyncRunning === 'function') {\n const acquired = await storage.markSyncRunning();\n if (!acquired) {\n return;\n }\n }\n const errors: string[] = [];\n const backfill = computeConnectorBackfill(config);\n const now = Date.now();\n const rawLoggerFactory: ConnectorLoggerFactory =\n options.loggerFactory ??\n ((scope) => createDefaultConnectorLogger({ scope }));\n const safeLogger = (scope: string): ConnectorLogger => {\n let inner: ConnectorLogger;\n try {\n inner = rawLoggerFactory(scope);\n } catch (err) {\n console.warn(\n `[runner] loggerFactory threw for scope=${scope}; falling back to default`,\n err,\n );\n inner = createDefaultConnectorLogger({ scope });\n }\n return {\n info(event, fields) {\n try {\n inner.info(event, fields);\n } catch (err) {\n console.warn(\n `[runner] logger.info threw for scope=${scope} event=${event}`,\n err,\n );\n }\n },\n warn(event, fields) {\n try {\n inner.warn(event, fields);\n } catch (err) {\n console.warn(\n `[runner] logger.warn threw for scope=${scope} event=${event}`,\n err,\n );\n }\n },\n };\n };\n const runnerLogger = safeLogger('runner');\n await Promise.allSettled(\n config.connectors.map(async (entry) => {\n if (entry.enabled === false) {\n return;\n }\n const scope = backfill.get(entry.name);\n if (!scope) {\n return;\n }\n const controller = new AbortController();\n const handle = storage.getStorageHandle(entry.name, {\n signal: controller.signal,\n });\n const connectorLogger = safeLogger(entry.name);\n const syncStart = Date.now();\n let timer: ReturnType<typeof setTimeout> | undefined;\n let status: 'succeeded' | 'failed' = 'succeeded';\n let failureReason: string | undefined;\n try {\n const connector = instantiateConnector(\n entry,\n options.connectorRegistry,\n options.secretsResolver,\n connectorLogger,\n );\n const timeoutPromise = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n const err = new Error(\n `${entry.name} timed out after ${FULL_SYNC_TIMEOUT_MS}ms`,\n );\n err.name = 'AbortError';\n reject(err);\n }, FULL_SYNC_TIMEOUT_MS);\n });\n\n const resources: ReadonlySet<string> = new Set(scope.keys());\n\n let maxWindowMs: number | undefined;\n for (const [, { requiredWindowMs }] of scope.entries()) {\n if (requiredWindowMs === undefined) {\n continue;\n }\n if (maxWindowMs === undefined || requiredWindowMs > maxWindowMs) {\n maxWindowMs = requiredWindowMs;\n }\n }\n const since =\n maxWindowMs !== undefined\n ? new Date(now - maxWindowMs - BACKFILL_BUFFER_MS).toISOString()\n : undefined;\n\n runnerLogger.info('sync started', {\n connector: entry.name,\n resources: Array.from(resources),\n mode: 'full',\n since,\n });\n\n let cursor: unknown = undefined;\n let chunks = 0;\n while (true) {\n chunks += 1;\n if (chunks > FULL_SYNC_MAX_CHUNKS) {\n controller.abort();\n throw new Error(\n `${entry.name} exceeded ${FULL_SYNC_MAX_CHUNKS} sync chunks without completing`,\n );\n }\n const syncPromise = connector.sync(\n { mode: 'full', since, cursor, resources },\n handle,\n controller.signal,\n );\n const result = await Promise.race([syncPromise, timeoutPromise]);\n if (result.done) {\n break;\n }\n cursor = result.cursor;\n }\n } catch (err) {\n status = 'failed';\n if (err instanceof Error && err.name === 'AbortError') {\n failureReason = `${entry.name} timed out after ${FULL_SYNC_TIMEOUT_MS}ms`;\n } else {\n failureReason = err instanceof Error ? err.message : String(err);\n }\n errors.push(failureReason);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n runnerLogger.info('sync settled', {\n connector: entry.name,\n status,\n duration_ms: Date.now() - syncStart,\n error: failureReason,\n });\n }\n }),\n );\n if (errors.length > 0) {\n await storage.markSyncFailed(errors.join('; '));\n } else {\n await storage.markSyncSucceeded();\n }\n}\n","import type {\n CachedWidget,\n ConnectorRegistry,\n DashboardConfig,\n HealthResponse,\n SecretsResolver,\n ServerStorage,\n SyncState,\n TriggerSyncResponse,\n} from '@rawdash/core';\nimport { InMemoryStorage, isSyncActive, resolveWidget } from '@rawdash/core';\n\nimport { type ConnectorLoggerFactory, runSync } from './sync';\n\nexport interface EngineOptions {\n storage?: ServerStorage;\n connectorRegistry?: ConnectorRegistry;\n secretsResolver?: SecretsResolver;\n loggerFactory?: ConnectorLoggerFactory;\n}\n\nexport interface Engine {\n getWidget(\n dashboardId: string,\n widgetId: string,\n ): Promise<CachedWidget | undefined>;\n getWidgets(dashboardId: string): Promise<CachedWidget[]>;\n getHealth(): Promise<HealthResponse>;\n getSyncState(): Promise<SyncState>;\n triggerSync(): Promise<TriggerSyncResponse>;\n}\n\nexport function createEngine(\n config: DashboardConfig,\n options: EngineOptions = {},\n): Engine {\n const storage: ServerStorage = options.storage ?? new InMemoryStorage();\n const connectorNames = config.connectors.map((c) => c.name);\n\n return {\n async getWidget(dashboardId, widgetId) {\n const dashboard = config.dashboards[dashboardId];\n if (!dashboard) {\n return undefined;\n }\n const widget = dashboard.widgets[widgetId];\n if (!widget) {\n return undefined;\n }\n return resolveWidget(\n dashboardId,\n widgetId,\n widget,\n connectorNames,\n storage,\n );\n },\n\n async getWidgets(dashboardId) {\n const dashboard = config.dashboards[dashboardId];\n if (!dashboard) {\n return [];\n }\n const entries = Object.entries(dashboard.widgets);\n const resolved = await Promise.all(\n entries.map(([key, widget]) =>\n resolveWidget(dashboardId, key, widget, connectorNames, storage),\n ),\n );\n return resolved.filter((w): w is CachedWidget => w !== undefined);\n },\n\n async getHealth() {\n return { status: 'ok' };\n },\n\n async getSyncState() {\n return storage.getSyncState();\n },\n\n async triggerSync() {\n if (!options.connectorRegistry) {\n throw new Error(\n 'createEngine: connectorRegistry is required to triggerSync',\n );\n }\n const state = await storage.getSyncState();\n if (isSyncActive(state.status)) {\n return { queued: false };\n }\n const queued = await storage.markSyncQueued();\n if (!queued) {\n return { queued: false };\n }\n void runSync(config, storage, {\n connectorRegistry: options.connectorRegistry,\n secretsResolver: options.secretsResolver,\n loggerFactory: options.loggerFactory,\n }).catch((error) => {\n console.error('Rawdash sync failed', error);\n });\n return { queued: true };\n },\n };\n}\n","export { computeMetric } from '@rawdash/core';\n","export { InMemoryStorage } from '@rawdash/core';\n","export type { EngineContext } from './context';\nexport { RawdashError, isRawdashError } from './errors';\nexport { ROUTES } from './routes';\nexport {\n getHealth,\n getSyncStateHandler,\n getWidget,\n listWidgets,\n runRetentionOnce,\n triggerSync,\n} from './handlers';\nexport type {\n DeferredTriggerSyncContext,\n GetWidgetOptions,\n GetWidgetResult,\n InProcessTriggerSyncContext,\n TriggerSyncContext,\n TriggerSyncMode,\n TriggerSyncOptions,\n} from './handlers';\nexport type { WidgetCache, WidgetCacheKey } from './widget-cache';\nexport { runSync, FULL_SYNC_TIMEOUT_MS, FULL_SYNC_MAX_CHUNKS } from './sync';\nexport type { ConnectorLoggerFactory, RunSyncOptions } from './sync';\nexport {\n runRetention,\n hasPruningPolicy,\n DEFAULT_RETENTION_INTERVAL_MS,\n} from './retention';\nexport { createEngine } from './engine';\nexport type { Engine, EngineOptions } from './engine';\nexport { computeMetric } from './compute';\nexport { InMemoryStorage } from './storage';\nexport type {\n CachedWidget,\n ConfiguredConnector,\n ConnectorHealth,\n DashboardConfig,\n HealthResponse,\n ServerStorage,\n SyncState,\n SyncStatus,\n TriggerSyncResponse,\n Widget,\n WidgetSyncState,\n WidgetsListResponse,\n} from './types';\nexport { isSyncActive, ACTIVE_SYNC_STATUSES } from '@rawdash/core';\nexport { instantiateConnector } from '@rawdash/core';\nexport type {\n ConnectorClass,\n ConnectorRegistry,\n SecretsResolver,\n} from '@rawdash/core';\n"],"mappings":"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","names":["isSyncActive","resolveWidget","resolveWidget","isSyncActive","InMemoryStorage","isSyncActive","instantiateConnector"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rawdash/server",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "Framework-agnostic rawdash request handlers, engine, and wire contract. Wrap with @rawdash/hono (or another adapter) to serve over HTTP.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -22,7 +22,7 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@rawdash/core": "0.18.0"
25
+ "@rawdash/core": "0.20.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "tsup": "^8.0.0",