@rawdash/core 0.15.0 → 0.17.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.js CHANGED
@@ -291,8 +291,79 @@ function computeDelay(attempt, initialDelayMs, maxDelayMs) {
291
291
  const jitter = base * 0.25 * Math.random();
292
292
  return Math.min(base + jitter, maxDelayMs);
293
293
  }
294
+ var MAX_VALUE_LEN = 120;
295
+ function truncate(s, max = MAX_VALUE_LEN) {
296
+ if (s.length <= max) {
297
+ return s;
298
+ }
299
+ return `${s.slice(0, max - 1)}\u2026`;
300
+ }
301
+ function formatValue(value) {
302
+ if (value === null) {
303
+ return "null";
304
+ }
305
+ if (value === void 0) {
306
+ return "";
307
+ }
308
+ if (typeof value === "number" || typeof value === "boolean") {
309
+ return String(value);
310
+ }
311
+ if (typeof value === "string") {
312
+ const t = truncate(value);
313
+ if (/[\s"=]/.test(t)) {
314
+ return JSON.stringify(t);
315
+ }
316
+ return t;
317
+ }
318
+ if (typeof value === "bigint") {
319
+ return value.toString();
320
+ }
321
+ let json;
322
+ try {
323
+ json = JSON.stringify(value);
324
+ } catch {
325
+ json = void 0;
326
+ }
327
+ return truncate(json ?? String(value));
328
+ }
329
+ function formatLogFields(fields) {
330
+ if (!fields) {
331
+ return "";
332
+ }
333
+ const parts = [];
334
+ for (const [k, v] of Object.entries(fields)) {
335
+ if (v === void 0) {
336
+ continue;
337
+ }
338
+ parts.push(`${k}=${formatValue(v)}`);
339
+ }
340
+ return parts.length > 0 ? ` ${parts.join(" ")}` : "";
341
+ }
342
+ function formatLogLine(scope, event, fields) {
343
+ return `[${scope}] ${event}${formatLogFields(fields)}`;
344
+ }
345
+ function createDefaultConnectorLogger(opts) {
346
+ return {
347
+ info(event, fields) {
348
+ console.info(formatLogLine(opts.scope, event, fields));
349
+ },
350
+ warn(event, fields) {
351
+ console.warn(formatLogLine(opts.scope, event, fields));
352
+ }
353
+ };
354
+ }
355
+ var NOOP_LOGGER = {
356
+ info() {
357
+ },
358
+ warn() {
359
+ }
360
+ };
361
+ function noopConnectorLogger() {
362
+ return NOOP_LOGGER;
363
+ }
294
364
 
295
365
  // src/secrets.ts
366
+ import { z } from "zod";
296
367
  function secret(name) {
297
368
  if (!/^[A-Z][A-Z0-9_]*$/.test(name)) {
298
369
  throw new Error(
@@ -304,10 +375,31 @@ function secret(name) {
304
375
  function isSecret(value) {
305
376
  return typeof value === "object" && value !== null && "$secret" in value && typeof value.$secret === "string";
306
377
  }
378
+ var secretRefSchema = z.strictObject({
379
+ $secret: z.string()
380
+ });
381
+ function withSecretRef(schema) {
382
+ return z.union([schema, secretRefSchema]);
383
+ }
307
384
  var EnvSecretsResolver = class {
308
385
  resolve(name) {
309
386
  const env = globalThis.process?.env;
310
- return env?.[name];
387
+ const raw = env?.[name];
388
+ if (raw === void 0) {
389
+ return void 0;
390
+ }
391
+ if (raw.length === 0) {
392
+ return raw;
393
+ }
394
+ const first = raw.charCodeAt(0);
395
+ if (first !== 123 && first !== 91) {
396
+ return raw;
397
+ }
398
+ try {
399
+ return JSON.parse(raw);
400
+ } catch {
401
+ return raw;
402
+ }
311
403
  }
312
404
  };
313
405
  function extractSecretNames(value) {
@@ -364,6 +456,7 @@ var BaseConnector = class {
364
456
  creds;
365
457
  rawCredInput;
366
458
  ctx;
459
+ cachedLogger;
367
460
  constructor(settings, creds, ctx) {
368
461
  this.settings = settings;
369
462
  this.rawCredInput = creds;
@@ -373,6 +466,12 @@ var BaseConnector = class {
373
466
  this.ctx.secretsResolver ?? new EnvSecretsResolver()
374
467
  ) : {};
375
468
  }
469
+ get logger() {
470
+ if (!this.cachedLogger) {
471
+ this.cachedLogger = this.ctx.logger ?? createDefaultConnectorLogger({ scope: this.id });
472
+ }
473
+ return this.cachedLogger;
474
+ }
376
475
  request(req, opts) {
377
476
  return request(req, {
378
477
  resource: opts.resource,
@@ -405,6 +504,13 @@ var BaseConnector = class {
405
504
  { resource: opts.resource, requestId: opts.requestId }
406
505
  );
407
506
  }
507
+ isResourceEnabled(resource) {
508
+ const enabled = this.settings?.resources;
509
+ if (!enabled || enabled.length === 0) {
510
+ return true;
511
+ }
512
+ return enabled.includes(resource);
513
+ }
408
514
  serializeConfig() {
409
515
  const config = {
410
516
  ...this.settings
@@ -478,8 +584,44 @@ function defineConnector() {
478
584
  }
479
585
 
480
586
  // src/paginate-chunked.ts
587
+ function selectActivePhases(resourceToPhase, order, enabled) {
588
+ if (!enabled || enabled.length === 0) {
589
+ return [...order];
590
+ }
591
+ const want = /* @__PURE__ */ new Set();
592
+ for (const r of enabled) {
593
+ want.add(resourceToPhase(r));
594
+ }
595
+ return order.filter((p) => want.has(p));
596
+ }
597
+ function makeChunkedCursorGuard(phases) {
598
+ const phaseSet = new Set(phases);
599
+ return (value) => {
600
+ if (typeof value !== "object" || value === null) {
601
+ return false;
602
+ }
603
+ const v = value;
604
+ if (typeof v.phase !== "string" || !phaseSet.has(v.phase)) {
605
+ return false;
606
+ }
607
+ if (v.page !== null && typeof v.page !== "string") {
608
+ return false;
609
+ }
610
+ return true;
611
+ };
612
+ }
613
+ function truncateCursor(page) {
614
+ if (page === null || page === void 0) {
615
+ return void 0;
616
+ }
617
+ const s = typeof page === "string" ? page : JSON.stringify(page);
618
+ if (s.length <= 80) {
619
+ return s;
620
+ }
621
+ return `${s.slice(0, 79)}\u2026`;
622
+ }
481
623
  async function paginateChunked(opts) {
482
- const { phases, cursor, signal, fetchPage, writeBatch } = opts;
624
+ const { phases, cursor, signal, fetchPage, writeBatch, logger } = opts;
483
625
  if (phases.length === 0) {
484
626
  return { done: true };
485
627
  }
@@ -489,6 +631,9 @@ async function paginateChunked(opts) {
489
631
  for (let i = startIdx; i < phases.length; i++) {
490
632
  const phase = phases[i];
491
633
  let page = i === startIdx && hasKnownResumePhase ? cursor.page : null;
634
+ let pageCount = 0;
635
+ let itemCount = 0;
636
+ const phaseStart = Date.now();
492
637
  while (true) {
493
638
  if (signal?.aborted) {
494
639
  return {
@@ -496,6 +641,7 @@ async function paginateChunked(opts) {
496
641
  cursor: { phase, page }
497
642
  };
498
643
  }
644
+ pageCount += 1;
499
645
  let items;
500
646
  let next;
501
647
  try {
@@ -507,12 +653,26 @@ async function paginateChunked(opts) {
507
653
  cursor: { phase, page }
508
654
  };
509
655
  }
656
+ logger?.warn("fetch page failed", {
657
+ resource: phase,
658
+ page: pageCount,
659
+ cursor: truncateCursor(page),
660
+ error: err instanceof Error ? err.message : String(err)
661
+ });
510
662
  return {
511
663
  done: false,
512
664
  cursor: { phase, page },
513
665
  transientError: err
514
666
  };
515
667
  }
668
+ itemCount += items.length;
669
+ logger?.info("fetched page", {
670
+ resource: phase,
671
+ page: pageCount,
672
+ items: items.length,
673
+ cursor: truncateCursor(page),
674
+ next: truncateCursor(next)
675
+ });
516
676
  try {
517
677
  await writeBatch(phase, items, page);
518
678
  } catch (err) {
@@ -522,6 +682,12 @@ async function paginateChunked(opts) {
522
682
  cursor: { phase, page }
523
683
  };
524
684
  }
685
+ logger?.warn("write batch failed", {
686
+ resource: phase,
687
+ page: pageCount,
688
+ cursor: truncateCursor(page),
689
+ error: err instanceof Error ? err.message : String(err)
690
+ });
525
691
  return {
526
692
  done: false,
527
693
  cursor: { phase, page },
@@ -533,20 +699,26 @@ async function paginateChunked(opts) {
533
699
  }
534
700
  page = next;
535
701
  }
702
+ logger?.info("resource done", {
703
+ resource: phase,
704
+ pages: pageCount,
705
+ items: itemCount,
706
+ duration_ms: Date.now() - phaseStart
707
+ });
536
708
  }
537
709
  return { done: true };
538
710
  }
539
711
 
540
712
  // src/widget-schemas.ts
541
- import { z } from "zod";
542
- var shapeSchema = z.enum([
713
+ import { z as z2 } from "zod";
714
+ var shapeSchema = z2.enum([
543
715
  "event",
544
716
  "entity",
545
717
  "metric",
546
718
  "edge",
547
719
  "distribution"
548
720
  ]);
549
- var aggFnSchema = z.enum([
721
+ var aggFnSchema = z2.enum([
550
722
  "count",
551
723
  "sum",
552
724
  "avg",
@@ -555,7 +727,7 @@ var aggFnSchema = z.enum([
555
727
  "latest",
556
728
  "first"
557
729
  ]);
558
- var filterOperatorSchema = z.enum([
730
+ var filterOperatorSchema = z2.enum([
559
731
  "eq",
560
732
  "neq",
561
733
  "gt",
@@ -564,70 +736,70 @@ var filterOperatorSchema = z.enum([
564
736
  "lte",
565
737
  "contains"
566
738
  ]);
567
- var filterConditionSchema = z.object({
568
- field: z.string(),
739
+ var filterConditionSchema = z2.object({
740
+ field: z2.string(),
569
741
  op: filterOperatorSchema,
570
- value: z.union([z.string(), z.number(), z.boolean()])
742
+ value: z2.union([z2.string(), z2.number(), z2.boolean()])
571
743
  });
572
- var filterClauseSchema = z.union([
744
+ var filterClauseSchema = z2.union([
573
745
  filterConditionSchema,
574
- z.object({ or: z.array(filterConditionSchema) })
746
+ z2.object({ or: z2.array(filterConditionSchema) })
575
747
  ]);
576
- var groupBySchema = z.object({
577
- field: z.string(),
578
- granularity: z.enum(["hour", "day", "week", "month"])
748
+ var groupBySchema = z2.object({
749
+ field: z2.string(),
750
+ granularity: z2.enum(["hour", "day", "week", "month"])
579
751
  });
580
- var computedMetricSchema = z.object({
581
- connectorId: z.string(),
752
+ var computedMetricSchema = z2.object({
753
+ connectorId: z2.string(),
582
754
  shape: shapeSchema,
583
- name: z.string().optional(),
584
- entityType: z.string().optional(),
585
- field: z.string().optional(),
755
+ name: z2.string().optional(),
756
+ entityType: z2.string().optional(),
757
+ field: z2.string().optional(),
586
758
  fn: aggFnSchema,
587
- window: z.string().optional(),
588
- filter: z.array(filterClauseSchema).optional(),
759
+ window: z2.string().optional(),
760
+ filter: z2.array(filterClauseSchema).optional(),
589
761
  groupBy: groupBySchema.optional()
590
762
  }).refine((m) => m.fn === "count" || m.field !== void 0, {
591
763
  message: 'field is required unless fn is "count"',
592
764
  path: ["field"]
593
765
  });
594
- var titleField = z.string().meta({ label: "Title", description: "Widget title." });
595
- var statWidgetSchema = z.object({
596
- kind: z.literal("stat"),
766
+ var titleField = z2.string().meta({ label: "Title", description: "Widget title." });
767
+ var statWidgetSchema = z2.object({
768
+ kind: z2.literal("stat"),
597
769
  title: titleField,
598
770
  metric: computedMetricSchema.meta({
599
771
  label: "Metric",
600
772
  description: "Computed metric definition."
601
773
  }),
602
- window: z.string().optional().meta({ label: "Window", description: "Time window, e.g. '7d'." }),
603
- compare: z.enum(["none", "previous-period"]).default("none").meta({ label: "Compare", description: "Comparison mode." })
774
+ window: z2.string().optional().meta({ label: "Window", description: "Time window, e.g. '7d'." }),
775
+ compare: z2.enum(["none", "previous-period"]).default("none").meta({ label: "Compare", description: "Comparison mode." })
604
776
  });
605
- var statusWidgetSchema = z.object({
606
- kind: z.literal("status"),
777
+ var statusWidgetSchema = z2.object({
778
+ kind: z2.literal("status"),
607
779
  title: titleField,
608
- source: z.string().meta({
780
+ source: z2.string().meta({
609
781
  label: "Source",
610
782
  description: "Connector or data source reference."
611
783
  })
612
784
  });
613
- var timeseriesWidgetSchema = z.object({
614
- kind: z.literal("timeseries"),
785
+ var timeseriesWidgetSchema = z2.object({
786
+ kind: z2.literal("timeseries"),
615
787
  title: titleField,
616
788
  metric: computedMetricSchema.meta({
617
789
  label: "Metric",
618
790
  description: "Computed metric definition."
619
791
  }),
620
- window: z.string().meta({ label: "Window", description: "Time window, e.g. '30d'." }),
621
- granularity: z.enum(["hour", "day", "week"]).default("day").meta({ label: "Granularity", description: "Time bucket size." })
792
+ window: z2.string().meta({ label: "Window", description: "Time window, e.g. '30d'." }),
793
+ granularity: z2.enum(["hour", "day", "week"]).default("day").meta({ label: "Granularity", description: "Time bucket size." })
622
794
  });
623
- var distributionWidgetSchema = z.object({
624
- kind: z.literal("distribution"),
795
+ var distributionWidgetSchema = z2.object({
796
+ kind: z2.literal("distribution"),
625
797
  title: titleField,
626
798
  metric: computedMetricSchema.meta({
627
799
  label: "Metric",
628
800
  description: "Computed metric definition."
629
801
  }),
630
- window: z.string().meta({ label: "Window", description: "Time window, e.g. '7d'." })
802
+ window: z2.string().meta({ label: "Window", description: "Time window, e.g. '7d'." })
631
803
  });
632
804
  var widgetSchemas = {
633
805
  stat: statWidgetSchema,
@@ -635,7 +807,7 @@ var widgetSchemas = {
635
807
  timeseries: timeseriesWidgetSchema,
636
808
  distribution: distributionWidgetSchema
637
809
  };
638
- var widgetSchema = z.discriminatedUnion("kind", [
810
+ var widgetSchema = z2.discriminatedUnion("kind", [
639
811
  statWidgetSchema,
640
812
  statusWidgetSchema,
641
813
  timeseriesWidgetSchema,
@@ -837,9 +1009,9 @@ async function computeRetention(handle, config, nowMs = Date.now()) {
837
1009
  }
838
1010
 
839
1011
  // src/config-fields.ts
840
- import { z as z2 } from "zod";
1012
+ import { z as z3 } from "zod";
841
1013
  function defineConfigFields(schema) {
842
- if (!(schema instanceof z2.ZodObject)) {
1014
+ if (!(schema instanceof z3.ZodObject)) {
843
1015
  throw new Error(
844
1016
  `configFields must be a Zod object schema (z.object({...})). Received: ${Object.prototype.toString.call(schema)}`
845
1017
  );
@@ -847,6 +1019,88 @@ function defineConfigFields(schema) {
847
1019
  return schema;
848
1020
  }
849
1021
 
1022
+ // src/connector-doc.ts
1023
+ import { z as z4 } from "zod";
1024
+ var connectorCategorySchema = z4.enum([
1025
+ "engineering",
1026
+ "product",
1027
+ "analytics",
1028
+ "marketing",
1029
+ "sales",
1030
+ "support",
1031
+ "finance",
1032
+ "infrastructure",
1033
+ "security"
1034
+ ]);
1035
+ var connectorDocSchema = z4.object({
1036
+ displayName: z4.string().min(1),
1037
+ category: connectorCategorySchema,
1038
+ tagline: z4.string().min(1),
1039
+ // Brand accent color (hex) for the connector's docs/landing card. The icon
1040
+ // itself is a committed `icon.svg` co-located in the connector package.
1041
+ brandColor: z4.string().regex(/^#[0-9A-Fa-f]{6}$/).optional(),
1042
+ vendor: z4.object({
1043
+ name: z4.string().min(1),
1044
+ apiDocs: z4.url().optional(),
1045
+ website: z4.url().optional()
1046
+ }),
1047
+ auth: z4.object({
1048
+ summary: z4.string().min(1),
1049
+ setup: z4.array(z4.string().min(1))
1050
+ }),
1051
+ // Upstream API rate-limit / quota notes worth surfacing (e.g. "GA4 Data API:
1052
+ // 200k tokens/day per property"). Free text, rendered in docs.
1053
+ rateLimit: z4.string().min(1).optional(),
1054
+ // Operational caveats / out-of-scope notes (API ceilings, sampling, Cloud-only,
1055
+ // data revision windows, etc.).
1056
+ limitations: z4.array(z4.string().min(1)).optional()
1057
+ });
1058
+ function defineConnectorDoc(doc) {
1059
+ return connectorDocSchema.parse(doc);
1060
+ }
1061
+
1062
+ // src/resource.ts
1063
+ var SHAPES = /* @__PURE__ */ new Set([
1064
+ "entity",
1065
+ "event",
1066
+ "metric",
1067
+ "edge",
1068
+ "distribution"
1069
+ ]);
1070
+ function defineResources(defs) {
1071
+ for (const [name, def] of Object.entries(defs)) {
1072
+ if (!name) {
1073
+ throw new Error("Resource name must be a non-empty string.");
1074
+ }
1075
+ if (!SHAPES.has(def.shape)) {
1076
+ throw new Error(
1077
+ `Resource "${name}" has invalid shape "${def.shape}". Expected one of: ${[...SHAPES].join(", ")}.`
1078
+ );
1079
+ }
1080
+ if (!def.description || def.description.trim().length === 0) {
1081
+ throw new Error(`Resource "${name}" must have a non-empty description.`);
1082
+ }
1083
+ }
1084
+ return defs;
1085
+ }
1086
+ function schemasFromResources(defs) {
1087
+ const out = {};
1088
+ for (const [name, def] of Object.entries(defs)) {
1089
+ if (!def.responses) {
1090
+ continue;
1091
+ }
1092
+ for (const [tag, schema] of Object.entries(def.responses)) {
1093
+ if (out[tag]) {
1094
+ throw new Error(
1095
+ `Duplicate response schema tag "${tag}" (declared again on resource "${name}").`
1096
+ );
1097
+ }
1098
+ out[tag] = schema;
1099
+ }
1100
+ }
1101
+ return out;
1102
+ }
1103
+
850
1104
  // src/compute.ts
851
1105
  function matchesCondition(record, cond) {
852
1106
  const val = record[cond.field];
@@ -1101,6 +1355,77 @@ async function computeMetric(storage, metric) {
1101
1355
  return computeAgg(sorted, metric.field, metric.fn);
1102
1356
  }
1103
1357
 
1358
+ // src/backfill-window.ts
1359
+ var WINDOW_UNIT_MS = {
1360
+ h: 36e5,
1361
+ d: 864e5,
1362
+ w: 6048e5,
1363
+ m: 2592e6
1364
+ };
1365
+ function parseWindowMs2(window) {
1366
+ const match = /^(\d+)(h|d|w|m)$/.exec(window);
1367
+ if (!match) {
1368
+ return void 0;
1369
+ }
1370
+ const unitMs = WINDOW_UNIT_MS[match[2]];
1371
+ if (unitMs === void 0) {
1372
+ return void 0;
1373
+ }
1374
+ return parseInt(match[1]) * unitMs;
1375
+ }
1376
+ function widgetWindow(widget) {
1377
+ switch (widget.kind) {
1378
+ case "stat":
1379
+ return widget.window ?? widget.metric.window;
1380
+ case "timeseries":
1381
+ case "distribution":
1382
+ return widget.window;
1383
+ case "status":
1384
+ return void 0;
1385
+ }
1386
+ }
1387
+ function widgetReference(widget) {
1388
+ if (widget.kind === "status") {
1389
+ return { connectorName: widget.source, resourceName: void 0 };
1390
+ }
1391
+ return {
1392
+ connectorName: widget.metric.connectorId,
1393
+ resourceName: widget.metric.name ?? widget.metric.entityType
1394
+ };
1395
+ }
1396
+ function mergeWindow(existing, next) {
1397
+ if (next === void 0) {
1398
+ return existing;
1399
+ }
1400
+ if (existing === void 0) {
1401
+ return next;
1402
+ }
1403
+ return Math.max(existing, next);
1404
+ }
1405
+ function computeConnectorBackfill(config) {
1406
+ const result = /* @__PURE__ */ new Map();
1407
+ for (const dashboard of Object.values(config.dashboards)) {
1408
+ for (const widget of Object.values(dashboard.widgets)) {
1409
+ const { connectorName, resourceName } = widgetReference(widget);
1410
+ const windowStr = widgetWindow(widget);
1411
+ const windowMs = windowStr ? parseWindowMs2(windowStr) : void 0;
1412
+ let resources = result.get(connectorName);
1413
+ if (!resources) {
1414
+ resources = /* @__PURE__ */ new Map();
1415
+ result.set(connectorName, resources);
1416
+ }
1417
+ if (resourceName === void 0) {
1418
+ continue;
1419
+ }
1420
+ const existing = resources.get(resourceName);
1421
+ resources.set(resourceName, {
1422
+ requiredWindowMs: mergeWindow(existing?.requiredWindowMs, windowMs)
1423
+ });
1424
+ }
1425
+ }
1426
+ return result;
1427
+ }
1428
+
1104
1429
  // src/resolve-widget.ts
1105
1430
  var FAILING_CONNECTOR_STATUSES = /* @__PURE__ */ new Set(["error", "auth_failed", "paused"]);
1106
1431
  function deriveSyncStateFromHealth(health) {
@@ -1124,14 +1449,17 @@ function buildMetaFromHealth(health) {
1124
1449
  }
1125
1450
  return meta;
1126
1451
  }
1127
- async function resolveWidget(widgetId, widget, connectors, storage) {
1452
+ async function resolveWidget(dashboardId, widgetId, widget, connectors, storage) {
1128
1453
  const connectorId = widget.kind === "status" ? widget.source : widget.metric.connectorId;
1129
1454
  if (connectors !== void 0 && !connectors.includes(connectorId)) {
1130
1455
  return void 0;
1131
1456
  }
1132
1457
  const handle = storage.getStorageHandle(connectorId);
1133
1458
  const health = await handle.getHealth?.() ?? null;
1134
- const data = widget.kind === "status" ? null : await computeMetric(handle, widget.metric);
1459
+ let data = null;
1460
+ if (widget.kind !== "status") {
1461
+ data = await computeMetric(handle, widget.metric);
1462
+ }
1135
1463
  let syncState;
1136
1464
  let meta;
1137
1465
  if (health) {
@@ -1148,12 +1476,40 @@ async function resolveWidget(widgetId, widget, connectors, storage) {
1148
1476
  data,
1149
1477
  cachedAt: health?.lastSyncAt ?? null,
1150
1478
  syncState,
1479
+ syncIntervalSeconds: health?.syncIntervalSeconds,
1151
1480
  meta
1152
1481
  };
1153
1482
  }
1154
1483
 
1484
+ // src/widget-etag.ts
1485
+ function stableStringify(value) {
1486
+ if (value === null || typeof value !== "object") {
1487
+ return JSON.stringify(value) ?? "null";
1488
+ }
1489
+ if (Array.isArray(value)) {
1490
+ return "[" + value.map(stableStringify).join(",") + "]";
1491
+ }
1492
+ const keys = Object.keys(value).sort();
1493
+ const parts = keys.map(
1494
+ (k) => JSON.stringify(k) + ":" + stableStringify(value[k])
1495
+ );
1496
+ return "{" + parts.join(",") + "}";
1497
+ }
1498
+ function hashWidgetConfig(widget) {
1499
+ const s = stableStringify(widget);
1500
+ let h = 2166136261;
1501
+ for (let i = 0; i < s.length; i++) {
1502
+ h ^= s.charCodeAt(i);
1503
+ h = Math.imul(h, 16777619);
1504
+ }
1505
+ return (h >>> 0).toString(16).padStart(8, "0");
1506
+ }
1507
+ function computeWidgetEtag(lastSyncAt, widget) {
1508
+ return `"${lastSyncAt ?? "null"}-${hashWidgetConfig(widget)}"`;
1509
+ }
1510
+
1155
1511
  // src/registry.ts
1156
- function instantiateConnector(entry, registry, secretsResolver) {
1512
+ function instantiateConnector(entry, registry, secretsResolver, logger) {
1157
1513
  const Cls = registry[entry.connectorId];
1158
1514
  if (!Cls) {
1159
1515
  throw new Error(
@@ -1171,7 +1527,8 @@ function instantiateConnector(entry, registry, secretsResolver) {
1171
1527
  }
1172
1528
  }
1173
1529
  return new Cls(settings, credSchema ? creds : void 0, {
1174
- secretsResolver
1530
+ secretsResolver,
1531
+ logger
1175
1532
  });
1176
1533
  }
1177
1534
 
@@ -1555,24 +1912,24 @@ var InMemoryStorage = class {
1555
1912
  };
1556
1913
 
1557
1914
  // src/wire-config.ts
1558
- import { z as z3 } from "zod";
1559
- var wireConnectorSchema = z3.object({
1560
- name: z3.string(),
1561
- connectorId: z3.string(),
1562
- displayName: z3.string().optional(),
1563
- config: z3.record(z3.string(), z3.unknown()),
1564
- syncIntervalSeconds: z3.number().optional(),
1565
- enabled: z3.boolean().optional()
1915
+ import { z as z5 } from "zod";
1916
+ var wireConnectorSchema = z5.object({
1917
+ name: z5.string(),
1918
+ connectorId: z5.string(),
1919
+ displayName: z5.string().optional(),
1920
+ config: z5.record(z5.string(), z5.unknown()),
1921
+ syncIntervalSeconds: z5.number().optional(),
1922
+ enabled: z5.boolean().optional()
1566
1923
  });
1567
- var wireDashboardSchema = z3.object({
1568
- id: z3.string().optional(),
1569
- name: z3.string(),
1570
- slug: z3.string(),
1571
- config: z3.record(z3.string(), z3.unknown())
1924
+ var wireDashboardSchema = z5.object({
1925
+ id: z5.string().optional(),
1926
+ name: z5.string(),
1927
+ slug: z5.string(),
1928
+ config: z5.record(z5.string(), z5.unknown())
1572
1929
  });
1573
- var wireConfigSchema = z3.object({
1574
- connectors: z3.array(wireConnectorSchema).optional(),
1575
- dashboards: z3.array(wireDashboardSchema).optional()
1930
+ var wireConfigSchema = z5.object({
1931
+ connectors: z5.array(wireConnectorSchema).optional(),
1932
+ dashboards: z5.array(wireDashboardSchema).optional()
1576
1933
  });
1577
1934
  function toWireConfig(config) {
1578
1935
  return {
@@ -1598,14 +1955,21 @@ export {
1598
1955
  EnvSecretsResolver,
1599
1956
  InMemoryStorage,
1600
1957
  aggFnSchema,
1958
+ computeConnectorBackfill,
1601
1959
  computeMetric,
1602
1960
  computeRetention,
1961
+ computeWidgetEtag,
1603
1962
  computedMetricSchema,
1963
+ connectorCategorySchema,
1964
+ connectorDocSchema,
1965
+ createDefaultConnectorLogger,
1604
1966
  defineConfig,
1605
1967
  defineConfigFields,
1606
1968
  defineConnector,
1969
+ defineConnectorDoc,
1607
1970
  defineDashboard,
1608
1971
  defineMetric,
1972
+ defineResources,
1609
1973
  distributionWidgetSchema,
1610
1974
  extractSecretNames,
1611
1975
  filterClauseSchema,
@@ -1613,13 +1977,19 @@ export {
1613
1977
  filterOperatorSchema,
1614
1978
  getWidgetSchema,
1615
1979
  groupBySchema,
1980
+ hashWidgetConfig,
1616
1981
  instantiateConnector,
1617
1982
  isSecret,
1618
1983
  isSyncActive,
1984
+ makeChunkedCursorGuard,
1985
+ noopConnectorLogger,
1619
1986
  paginateChunked,
1620
1987
  resolveSecrets,
1621
1988
  resolveWidget,
1989
+ schemasFromResources,
1622
1990
  secret,
1991
+ secretRefSchema,
1992
+ selectActivePhases,
1623
1993
  selectForDeletion,
1624
1994
  shapeSchema,
1625
1995
  statWidgetSchema,
@@ -1631,6 +2001,7 @@ export {
1631
2001
  wireConfigSchema,
1632
2002
  wireConnectorSchema,
1633
2003
  wireDashboardSchema,
1634
- withAbortSignal
2004
+ withAbortSignal,
2005
+ withSecretRef
1635
2006
  };
1636
2007
  //# sourceMappingURL=index.js.map