@hasna/uptime 0.1.9 → 0.1.11

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/cli/index.js CHANGED
@@ -2856,13 +2856,74 @@ function isDeniedIpv4(ip) {
2856
2856
  }
2857
2857
  function isDeniedIpv6(ip) {
2858
2858
  const normalized = ip.toLowerCase();
2859
- return normalized === "::" || normalized === "::1" || normalized.startsWith("fe80:") || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("ff") || normalized.startsWith("::ffff:127.") || normalized.startsWith("::ffff:10.") || normalized.startsWith("::ffff:169.254.") || /^::ffff:172\.(1[6-9]|2\d|3[0-1])\./.test(normalized) || normalized.startsWith("::ffff:192.168.");
2859
+ const mappedIpv4 = ipv4FromMappedIpv6(normalized);
2860
+ if (mappedIpv4)
2861
+ return isDeniedIpv4(mappedIpv4);
2862
+ const words = parseIpv6Words(normalized);
2863
+ return normalized === "::" || normalized === "::1" || words !== null && (words[0] & 65472) === 65152 || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("ff");
2864
+ }
2865
+ function ipv4FromMappedIpv6(ip) {
2866
+ const words = parseIpv6Words(ip);
2867
+ if (!words)
2868
+ return null;
2869
+ if (words[0] !== 0 || words[1] !== 0 || words[2] !== 0 || words[3] !== 0 || words[4] !== 0 || words[5] !== 65535) {
2870
+ return null;
2871
+ }
2872
+ return [
2873
+ words[6] >> 8,
2874
+ words[6] & 255,
2875
+ words[7] >> 8,
2876
+ words[7] & 255
2877
+ ].join(".");
2878
+ }
2879
+ function parseIpv6Words(value) {
2880
+ let ip = value.toLowerCase();
2881
+ const zoneIndex = ip.indexOf("%");
2882
+ if (zoneIndex >= 0)
2883
+ ip = ip.slice(0, zoneIndex);
2884
+ if (ip.includes(".")) {
2885
+ const lastColon = ip.lastIndexOf(":");
2886
+ if (lastColon < 0)
2887
+ return null;
2888
+ const ipv4 = parseIpv4Words(ip.slice(lastColon + 1));
2889
+ if (!ipv4)
2890
+ return null;
2891
+ ip = `${ip.slice(0, lastColon)}:${(ipv4[0] << 8 | ipv4[1]).toString(16)}:${(ipv4[2] << 8 | ipv4[3]).toString(16)}`;
2892
+ }
2893
+ const compressed = ip.split("::");
2894
+ if (compressed.length > 2)
2895
+ return null;
2896
+ const left = parseIpv6Side(compressed[0]);
2897
+ const right = compressed.length === 2 ? parseIpv6Side(compressed[1]) : [];
2898
+ if (!left || !right)
2899
+ return null;
2900
+ if (compressed.length === 1)
2901
+ return left.length === 8 ? left : null;
2902
+ const missing = 8 - left.length - right.length;
2903
+ if (missing < 1)
2904
+ return null;
2905
+ return [...left, ...Array(missing).fill(0), ...right];
2906
+ }
2907
+ function parseIpv6Side(value) {
2908
+ if (!value)
2909
+ return [];
2910
+ const words = value.split(":");
2911
+ if (words.some((word) => !/^[0-9a-f]{1,4}$/.test(word)))
2912
+ return null;
2913
+ return words.map((word) => Number.parseInt(word, 16));
2914
+ }
2915
+ function parseIpv4Words(value) {
2916
+ const words = value.split(".").map((part) => Number(part));
2917
+ if (words.length !== 4 || words.some((word) => !Number.isInteger(word) || word < 0 || word > 255)) {
2918
+ return null;
2919
+ }
2920
+ return words;
2860
2921
  }
2861
2922
 
2862
2923
  // src/imports.ts
2863
- function previewImport(store, request) {
2924
+ function previewImport(store, request, options = {}) {
2864
2925
  const source = normalizeSource(request.source);
2865
- const items = dedupePreviewItems(request.records.map((record) => previewRecord(store, source, record, request.defaults ?? {})));
2926
+ const items = dedupePreviewItems(request.records.map((record) => previewRecord(store, source, record, request.defaults ?? {}, options)));
2866
2927
  return {
2867
2928
  source,
2868
2929
  generatedAt: new Date().toISOString(),
@@ -2936,7 +2997,7 @@ function rollbackImport(store, batchId) {
2936
2997
  items
2937
2998
  };
2938
2999
  }
2939
- function previewRecord(store, source, record, defaults) {
3000
+ function previewRecord(store, source, record, defaults, options) {
2940
3001
  const warnings = [];
2941
3002
  let candidate;
2942
3003
  try {
@@ -2956,13 +3017,16 @@ function previewRecord(store, source, record, defaults) {
2956
3017
  reason: error instanceof Error ? error.message : String(error)
2957
3018
  };
2958
3019
  }
2959
- const provenance = store.getProvenance(candidate.source, candidate.sourceId);
2960
- const monitor = provenance ? store.getMonitor(provenance.monitorId) : store.getMonitor(candidate.name);
2961
- if (provenance && !monitor) {
3020
+ const monitorOptions = options.workspaceId ? { workspaceId: options.workspaceId } : undefined;
3021
+ const rawProvenance = store.getProvenance(candidate.source, candidate.sourceId);
3022
+ const provenanceMonitor = rawProvenance ? store.getMonitor(rawProvenance.monitorId, monitorOptions) : null;
3023
+ const provenance = provenanceMonitor ? rawProvenance : null;
3024
+ const monitor = provenanceMonitor ?? store.getMonitor(candidate.name, monitorOptions);
3025
+ if (rawProvenance && !provenanceMonitor && !options.workspaceId) {
2962
3026
  return { candidate, action: "create", monitor: null, provenance, warnings: ["source provenance points to a missing monitor"], reason: null };
2963
3027
  }
2964
3028
  if (provenance && monitor) {
2965
- const nameOwner = store.getMonitor(candidate.name);
3029
+ const nameOwner = store.getMonitor(candidate.name, monitorOptions);
2966
3030
  if (nameOwner && nameOwner.id !== monitor.id) {
2967
3031
  return {
2968
3032
  candidate,
@@ -3426,7 +3490,7 @@ var REQUIRED_TABLES = [
3426
3490
  ];
3427
3491
  var PROBE_TABLES = new Set(["probe_identities", "probe_check_jobs", "probe_submissions"]);
3428
3492
  var REPORT_AUDIT_TABLES = new Set(["report_schedules", "report_runs", "audit_events"]);
3429
- var CURRENT_SCHEMA_VERSION = "3";
3493
+ var CURRENT_SCHEMA_VERSION = "4";
3430
3494
 
3431
3495
  class StaleCheckResultError extends Error {
3432
3496
  constructor(message) {
@@ -3487,7 +3551,8 @@ class UptimeStore {
3487
3551
  this.db.run(`
3488
3552
  CREATE TABLE IF NOT EXISTS monitors (
3489
3553
  id TEXT PRIMARY KEY,
3490
- name TEXT NOT NULL UNIQUE,
3554
+ workspace_id TEXT NOT NULL DEFAULT 'local',
3555
+ name TEXT NOT NULL,
3491
3556
  kind TEXT NOT NULL CHECK (kind IN ('http', 'tcp', 'browser_page')),
3492
3557
  url TEXT,
3493
3558
  host TEXT,
@@ -3502,9 +3567,11 @@ class UptimeStore {
3502
3567
  last_checked_at TEXT,
3503
3568
  revision INTEGER NOT NULL DEFAULT 1,
3504
3569
  created_at TEXT NOT NULL,
3505
- updated_at TEXT NOT NULL
3570
+ updated_at TEXT NOT NULL,
3571
+ UNIQUE (workspace_id, name)
3506
3572
  )
3507
3573
  `);
3574
+ this.ensureColumn("monitors", "workspace_id", "TEXT NOT NULL DEFAULT 'local'");
3508
3575
  this.ensureColumn("monitors", "revision", "INTEGER NOT NULL DEFAULT 1");
3509
3576
  this.ensureMonitorKindAllowsBrowserPage();
3510
3577
  this.db.run(`
@@ -3654,6 +3721,7 @@ class UptimeStore {
3654
3721
  `);
3655
3722
  this.db.query("INSERT OR REPLACE INTO schema_migrations (key, value, updated_at) VALUES ('schema_version', ?, ?)").run(CURRENT_SCHEMA_VERSION, new Date().toISOString());
3656
3723
  this.db.run("CREATE INDEX IF NOT EXISTS idx_results_monitor_time ON check_results(monitor_id, checked_at DESC)");
3724
+ this.db.run("CREATE INDEX IF NOT EXISTS idx_monitors_workspace_enabled_name ON monitors(workspace_id, enabled, name)");
3657
3725
  this.db.run("CREATE INDEX IF NOT EXISTS idx_incidents_monitor_status ON incidents(monitor_id, status)");
3658
3726
  this.db.run("CREATE INDEX IF NOT EXISTS idx_check_leases_until ON check_leases(leased_until)");
3659
3727
  this.db.run("CREATE INDEX IF NOT EXISTS idx_monitor_provenance_monitor ON monitor_provenance(monitor_id)");
@@ -3715,8 +3783,10 @@ class UptimeStore {
3715
3783
  if (this.mode === "hosted")
3716
3784
  assertHostedTargetAllowed(normalized);
3717
3785
  const now = new Date().toISOString();
3786
+ const workspaceId = normalizeWorkspaceId(options.workspaceId ?? input.workspaceId ?? "local");
3718
3787
  const monitor = {
3719
3788
  id: newId("mon"),
3789
+ workspaceId,
3720
3790
  name: normalized.name,
3721
3791
  kind: normalized.kind,
3722
3792
  url: normalized.url ?? null,
@@ -3735,22 +3805,33 @@ class UptimeStore {
3735
3805
  updatedAt: now
3736
3806
  };
3737
3807
  this.db.query(`INSERT INTO monitors (
3738
- id, name, kind, url, host, port, method, expected_status,
3808
+ id, workspace_id, name, kind, url, host, port, method, expected_status,
3739
3809
  interval_seconds, timeout_ms, retry_count, enabled, status,
3740
3810
  last_checked_at, revision, created_at, updated_at
3741
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(monitor.id, monitor.name, monitor.kind, monitor.url, monitor.host, monitor.port, monitor.method, monitor.expectedStatus, monitor.intervalSeconds, monitor.timeoutMs, monitor.retryCount, monitor.enabled ? 1 : 0, monitor.status, monitor.lastCheckedAt, monitor.revision, monitor.createdAt, monitor.updatedAt);
3811
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(monitor.id, monitor.workspaceId, monitor.name, monitor.kind, monitor.url, monitor.host, monitor.port, monitor.method, monitor.expectedStatus, monitor.intervalSeconds, monitor.timeoutMs, monitor.retryCount, monitor.enabled ? 1 : 0, monitor.status, monitor.lastCheckedAt, monitor.revision, monitor.createdAt, monitor.updatedAt);
3742
3812
  return monitor;
3743
3813
  }
3744
3814
  listMonitors(options = {}) {
3745
- const rows = options.includeDisabled ? this.db.query("SELECT * FROM monitors ORDER BY name ASC").all() : this.db.query("SELECT * FROM monitors WHERE enabled = 1 ORDER BY name ASC").all();
3815
+ const workspaceId = options.workspaceId ? normalizeWorkspaceId(options.workspaceId) : undefined;
3816
+ const clauses = [];
3817
+ const args = [];
3818
+ if (workspaceId) {
3819
+ clauses.push("workspace_id = ?");
3820
+ args.push(workspaceId);
3821
+ }
3822
+ if (!options.includeDisabled)
3823
+ clauses.push("enabled = 1");
3824
+ const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
3825
+ const rows = this.db.query(`SELECT * FROM monitors ${where} ORDER BY name ASC`).all(...args);
3746
3826
  return rows.map(monitorFromRow);
3747
3827
  }
3748
- getMonitor(idOrName) {
3749
- const row = this.db.query("SELECT * FROM monitors WHERE id = ? OR name = ?").get(idOrName, idOrName);
3828
+ getMonitor(idOrName, options = {}) {
3829
+ const workspaceId = options.workspaceId ? normalizeWorkspaceId(options.workspaceId) : undefined;
3830
+ const row = this.db.query(`SELECT * FROM monitors WHERE (id = ? OR name = ?)${workspaceId ? " AND workspace_id = ?" : ""}`).get(...workspaceId ? [idOrName, idOrName, workspaceId] : [idOrName, idOrName]);
3750
3831
  return row ? monitorFromRow(row) : null;
3751
3832
  }
3752
3833
  updateMonitor(idOrName, input, options = {}) {
3753
- const current = this.getMonitor(idOrName);
3834
+ const current = this.getMonitor(idOrName, { workspaceId: options.workspaceId });
3754
3835
  if (!current)
3755
3836
  throw new Error(`Monitor not found: ${idOrName}`);
3756
3837
  if (this.mode === "hosted") {
@@ -3774,10 +3855,10 @@ class UptimeStore {
3774
3855
  if (definitionChanged(current, next)) {
3775
3856
  this.closeOpenIncident(current.id, updatedAt);
3776
3857
  }
3777
- return this.getMonitor(current.id);
3858
+ return this.getMonitor(current.id, { workspaceId: options.workspaceId });
3778
3859
  }
3779
- deleteMonitor(idOrName) {
3780
- const current = this.getMonitor(idOrName);
3860
+ deleteMonitor(idOrName, options = {}) {
3861
+ const current = this.getMonitor(idOrName, { workspaceId: options.workspaceId });
3781
3862
  if (!current)
3782
3863
  return false;
3783
3864
  this.db.query("DELETE FROM monitors WHERE id = ?").run(current.id);
@@ -4154,7 +4235,20 @@ class UptimeStore {
4154
4235
  }
4155
4236
  listResults(options = {}) {
4156
4237
  const limit = clampLimit(options.limit ?? 50);
4157
- const rows = options.monitorId ? this.db.query("SELECT * FROM check_results WHERE monitor_id = ? ORDER BY checked_at DESC LIMIT ?").all(options.monitorId, limit) : this.db.query("SELECT * FROM check_results ORDER BY checked_at DESC LIMIT ?").all(limit);
4238
+ const workspaceId = options.workspaceId ? normalizeWorkspaceId(options.workspaceId) : undefined;
4239
+ const clauses = [];
4240
+ const args = [];
4241
+ if (options.monitorId) {
4242
+ clauses.push("check_results.monitor_id = ?");
4243
+ args.push(options.monitorId);
4244
+ }
4245
+ if (workspaceId) {
4246
+ clauses.push("monitors.workspace_id = ?");
4247
+ args.push(workspaceId);
4248
+ }
4249
+ const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
4250
+ args.push(limit);
4251
+ const rows = this.db.query(`SELECT check_results.* FROM check_results JOIN monitors ON monitors.id = check_results.monitor_id ${where} ORDER BY checked_at DESC LIMIT ?`).all(...args);
4158
4252
  return rows.map(checkResultFromRow);
4159
4253
  }
4160
4254
  getProvenance(source, sourceId) {
@@ -4197,24 +4291,28 @@ class UptimeStore {
4197
4291
  const clauses = [];
4198
4292
  const args = [];
4199
4293
  if (options.status) {
4200
- clauses.push("status = ?");
4294
+ clauses.push("incidents.status = ?");
4201
4295
  args.push(options.status);
4202
4296
  }
4203
4297
  if (options.monitorId) {
4204
- clauses.push("monitor_id = ?");
4298
+ clauses.push("incidents.monitor_id = ?");
4205
4299
  args.push(options.monitorId);
4206
4300
  }
4301
+ if (options.workspaceId) {
4302
+ clauses.push("monitors.workspace_id = ?");
4303
+ args.push(normalizeWorkspaceId(options.workspaceId));
4304
+ }
4207
4305
  const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
4208
4306
  args.push(clampLimit(options.limit ?? 50));
4209
- const rows = this.db.query(`SELECT * FROM incidents ${where} ORDER BY opened_at DESC LIMIT ?`).all(...args);
4307
+ const rows = this.db.query(`SELECT incidents.* FROM incidents JOIN monitors ON monitors.id = incidents.monitor_id ${where} ORDER BY opened_at DESC LIMIT ?`).all(...args);
4210
4308
  return rows.map(incidentFromRow);
4211
4309
  }
4212
4310
  getOpenIncident(monitorId) {
4213
4311
  const row = this.db.query("SELECT * FROM incidents WHERE monitor_id = ? AND status = 'open' ORDER BY opened_at DESC LIMIT 1").get(monitorId);
4214
4312
  return row ? incidentFromRow(row) : null;
4215
4313
  }
4216
- summary() {
4217
- const monitors = this.listMonitors({ includeDisabled: true });
4314
+ summary(options = {}) {
4315
+ const monitors = this.listMonitors({ includeDisabled: true, workspaceId: options.workspaceId });
4218
4316
  const summaries = monitors.map((monitor) => this.monitorSummary(monitor));
4219
4317
  return {
4220
4318
  generatedAt: new Date().toISOString(),
@@ -4226,11 +4324,15 @@ class UptimeStore {
4226
4324
  down: monitors.filter((m) => m.status === "down").length,
4227
4325
  paused: monitors.filter((m) => !m.enabled || m.status === "paused").length,
4228
4326
  unknown: monitors.filter((m) => m.status === "unknown").length,
4229
- openIncidents: this.countOpenIncidents()
4327
+ openIncidents: this.countOpenIncidents(options.workspaceId)
4230
4328
  }
4231
4329
  };
4232
4330
  }
4233
- countOpenIncidents() {
4331
+ countOpenIncidents(workspaceId) {
4332
+ if (workspaceId) {
4333
+ const row2 = this.db.query("SELECT COUNT(*) AS count FROM incidents JOIN monitors ON monitors.id = incidents.monitor_id WHERE incidents.status = 'open' AND monitors.workspace_id = ?").get(normalizeWorkspaceId(workspaceId));
4334
+ return Number(row2?.count ?? 0);
4335
+ }
4234
4336
  const row = this.db.query("SELECT COUNT(*) AS count FROM incidents WHERE status = 'open'").get();
4235
4337
  return Number(row?.count ?? 0);
4236
4338
  }
@@ -4294,7 +4396,9 @@ class UptimeStore {
4294
4396
  }
4295
4397
  ensureMonitorKindAllowsBrowserPage() {
4296
4398
  const row = this.db.query("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'monitors'").get();
4297
- if (!row?.sql || row.sql.includes("browser_page"))
4399
+ const needsBrowserPage = !row?.sql?.includes("browser_page");
4400
+ const needsWorkspaceUnique = Boolean(row?.sql?.includes("name TEXT NOT NULL UNIQUE"));
4401
+ if (!row?.sql || !needsBrowserPage && !needsWorkspaceUnique)
4298
4402
  return;
4299
4403
  this.db.run("PRAGMA foreign_keys = OFF");
4300
4404
  this.db.run("PRAGMA legacy_alter_table = ON");
@@ -4304,7 +4408,8 @@ class UptimeStore {
4304
4408
  this.db.run(`
4305
4409
  CREATE TABLE monitors (
4306
4410
  id TEXT PRIMARY KEY,
4307
- name TEXT NOT NULL UNIQUE,
4411
+ workspace_id TEXT NOT NULL DEFAULT 'local',
4412
+ name TEXT NOT NULL,
4308
4413
  kind TEXT NOT NULL CHECK (kind IN ('http', 'tcp', 'browser_page')),
4309
4414
  url TEXT,
4310
4415
  host TEXT,
@@ -4319,17 +4424,18 @@ class UptimeStore {
4319
4424
  last_checked_at TEXT,
4320
4425
  revision INTEGER NOT NULL DEFAULT 1,
4321
4426
  created_at TEXT NOT NULL,
4322
- updated_at TEXT NOT NULL
4427
+ updated_at TEXT NOT NULL,
4428
+ UNIQUE (workspace_id, name)
4323
4429
  )
4324
4430
  `);
4325
4431
  this.db.run(`
4326
4432
  INSERT INTO monitors (
4327
- id, name, kind, url, host, port, method, expected_status,
4433
+ id, workspace_id, name, kind, url, host, port, method, expected_status,
4328
4434
  interval_seconds, timeout_ms, retry_count, enabled, status,
4329
4435
  last_checked_at, revision, created_at, updated_at
4330
4436
  )
4331
4437
  SELECT
4332
- id, name, kind, url, host, port, method, expected_status,
4438
+ id, workspace_id, name, kind, url, host, port, method, expected_status,
4333
4439
  interval_seconds, timeout_ms, retry_count, enabled, status,
4334
4440
  last_checked_at, revision, created_at, updated_at
4335
4441
  FROM monitors_old_kind
@@ -4529,6 +4635,16 @@ function rejectControlCharacters2(value, label) {
4529
4635
  throw new Error(`${label} must not contain control characters`);
4530
4636
  }
4531
4637
  }
4638
+ function normalizeWorkspaceId(value) {
4639
+ const normalized = value.trim();
4640
+ if (!normalized)
4641
+ throw new Error("Workspace id is required");
4642
+ rejectControlCharacters2(normalized, "Workspace id");
4643
+ if (!/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/.test(normalized)) {
4644
+ throw new Error("Workspace id contains unsupported characters");
4645
+ }
4646
+ return normalized;
4647
+ }
4532
4648
  function normalizeScheduleSlot(value) {
4533
4649
  const slot = value.trim();
4534
4650
  if (!slot)
@@ -4715,6 +4831,7 @@ function assertIsoTimestamp(value, label) {
4715
4831
  function monitorFromRow(row) {
4716
4832
  return {
4717
4833
  id: row.id,
4834
+ workspaceId: row.workspace_id ?? "local",
4718
4835
  name: row.name,
4719
4836
  kind: row.kind,
4720
4837
  url: row.url,
@@ -5195,20 +5312,20 @@ class UptimeService {
5195
5312
  close() {
5196
5313
  this.store.close();
5197
5314
  }
5198
- createMonitor(input) {
5199
- return this.store.createMonitor(input);
5315
+ createMonitor(input, options = {}) {
5316
+ return this.store.createMonitor(input, options);
5200
5317
  }
5201
- updateMonitor(idOrName, input) {
5202
- return this.store.updateMonitor(idOrName, input);
5318
+ updateMonitor(idOrName, input, options = {}) {
5319
+ return this.store.updateMonitor(idOrName, input, options);
5203
5320
  }
5204
- deleteMonitor(idOrName) {
5205
- return this.store.deleteMonitor(idOrName);
5321
+ deleteMonitor(idOrName, options = {}) {
5322
+ return this.store.deleteMonitor(idOrName, options);
5206
5323
  }
5207
5324
  listMonitors(options = {}) {
5208
5325
  return this.store.listMonitors(options);
5209
5326
  }
5210
- getMonitor(idOrName) {
5211
- return this.store.getMonitor(idOrName);
5327
+ getMonitor(idOrName, options = {}) {
5328
+ return this.store.getMonitor(idOrName, options);
5212
5329
  }
5213
5330
  listResults(options = {}) {
5214
5331
  return this.store.listResults(options);
@@ -5216,8 +5333,8 @@ class UptimeService {
5216
5333
  listIncidents(options = {}) {
5217
5334
  return this.store.listIncidents(options);
5218
5335
  }
5219
- summary() {
5220
- return this.store.summary();
5336
+ summary(options = {}) {
5337
+ return this.store.summary(options);
5221
5338
  }
5222
5339
  createProbe(input) {
5223
5340
  const store = this.probeStore();
@@ -5257,8 +5374,8 @@ class UptimeService {
5257
5374
  const execute = () => this.submitProbeResultInTransaction(input);
5258
5375
  return this.store.runInTransaction ? this.store.runInTransaction(execute) : execute();
5259
5376
  }
5260
- previewImport(request) {
5261
- return previewImport(this.store, request);
5377
+ previewImport(request, options = {}) {
5378
+ return previewImport(this.store, request, options);
5262
5379
  }
5263
5380
  applyImport(request) {
5264
5381
  return applyImport(this.store, request);
@@ -5273,7 +5390,8 @@ class UptimeService {
5273
5390
  return this.store.verifyBackup(backupPath);
5274
5391
  }
5275
5392
  buildReport(options = {}) {
5276
- return buildUptimeReport(this.summary(), options);
5393
+ const { workspaceId, ...reportOptions } = options;
5394
+ return buildUptimeReport(this.summary({ workspaceId }), reportOptions);
5277
5395
  }
5278
5396
  async sendReport(options = {}) {
5279
5397
  if (this.store.mode === "hosted" && (options.email || options.sms || options.logs)) {
@@ -5597,6 +5715,7 @@ class UptimeService {
5597
5715
  throw new Error("Probe job fencing token is invalid");
5598
5716
  if (!job.leaseExpiresAt || job.leaseExpiresAt <= new Date().toISOString())
5599
5717
  throw new Error("Probe job lease expired");
5718
+ const evidence = input.evidence ? normalizeBrowserEvidence(monitor.url ?? monitor.host ?? "https://example.invalid", input.evidence) : null;
5600
5719
  const result = this.store.recordCheckResult({
5601
5720
  monitorId: monitor.id,
5602
5721
  checkedAt: input.checkedAt,
@@ -5604,7 +5723,7 @@ class UptimeService {
5604
5723
  latencyMs: input.latencyMs,
5605
5724
  statusCode: input.statusCode ?? null,
5606
5725
  error: input.error ?? null,
5607
- evidence: input.evidence ?? null,
5726
+ evidence,
5608
5727
  attemptCount: input.attemptCount ?? 1,
5609
5728
  expectedMonitorRevision: input.monitorRevision
5610
5729
  });
@@ -6165,11 +6284,11 @@ async function handleHostedRequest(service, request, url, options) {
6165
6284
  }
6166
6285
  const apiPath = `/api${url.pathname.slice("/api/v1".length)}`;
6167
6286
  const scope = hostedScopeFor(request.method, apiPath);
6168
- requireHostedActor(request, url, options, scope);
6287
+ const actor = requireHostedActor(request, url, options, scope);
6169
6288
  if (["POST", "PATCH", "DELETE"].includes(request.method)) {
6170
6289
  validateHostedMutationOrigin(request, url, options);
6171
6290
  }
6172
- return handleApiRoute(service, request, url, apiPath, options, true);
6291
+ return handleApiRoute(service, request, url, apiPath, options, true, actor);
6173
6292
  }
6174
6293
  function validateHostedMutationOrigin(request, url, options) {
6175
6294
  const rawOrigin = request.headers.get("origin");
@@ -6184,12 +6303,12 @@ function validateHostedMutationOrigin(request, url, options) {
6184
6303
  throw new ApiError("cross-origin mutation rejected", 403);
6185
6304
  }
6186
6305
  }
6187
- async function handleApiRoute(service, request, url, apiPath, options, hosted) {
6306
+ async function handleApiRoute(service, request, url, apiPath, options, hosted, actor) {
6188
6307
  if (request.method === "GET" && apiPath === "/api/summary") {
6189
- return json(service.summary());
6308
+ return json(service.summary({ workspaceId: actor?.workspaceId }));
6190
6309
  }
6191
6310
  if (request.method === "GET" && apiPath === "/api/report") {
6192
- return json(service.buildReport());
6311
+ return json(service.buildReport({ workspaceId: actor?.workspaceId }));
6193
6312
  }
6194
6313
  if (request.method === "POST" && apiPath === "/api/report") {
6195
6314
  if (hosted)
@@ -6246,22 +6365,24 @@ async function handleApiRoute(service, request, url, apiPath, options, hosted) {
6246
6365
  }));
6247
6366
  }
6248
6367
  if (request.method === "GET" && apiPath === "/api/monitors") {
6249
- return json(service.listMonitors({ includeDisabled: url.searchParams.get("includeDisabled") === "true" }));
6368
+ return json(service.listMonitors({ includeDisabled: url.searchParams.get("includeDisabled") === "true", workspaceId: actor?.workspaceId }));
6250
6369
  }
6251
6370
  if (request.method === "POST" && apiPath === "/api/monitors") {
6252
- return json(service.createMonitor(await jsonBody(request)), 201);
6371
+ return json(service.createMonitor(await jsonBody(request), { workspaceId: actor?.workspaceId }), 201);
6253
6372
  }
6254
6373
  if (request.method === "GET" && apiPath === "/api/incidents") {
6255
6374
  const status = url.searchParams.get("status");
6256
6375
  return json(service.listIncidents({
6257
6376
  status: status === "open" || status === "closed" ? status : undefined,
6258
6377
  monitorId: url.searchParams.get("monitorId") ?? undefined,
6378
+ workspaceId: actor?.workspaceId,
6259
6379
  limit: numericParam(url, "limit", 50)
6260
6380
  }));
6261
6381
  }
6262
6382
  if (request.method === "GET" && apiPath === "/api/results") {
6263
6383
  return json(service.listResults({
6264
6384
  monitorId: url.searchParams.get("monitorId") ?? undefined,
6385
+ workspaceId: actor?.workspaceId,
6265
6386
  limit: numericParam(url, "limit", 50)
6266
6387
  }));
6267
6388
  }
@@ -6298,7 +6419,7 @@ async function handleApiRoute(service, request, url, apiPath, options, hosted) {
6298
6419
  return json(service.submitProbeResult(await jsonBody(request)), 201);
6299
6420
  }
6300
6421
  if (request.method === "POST" && apiPath === "/api/imports/preview") {
6301
- return json(service.previewImport(await jsonBody(request)));
6422
+ return json(service.previewImport(await jsonBody(request), { workspaceId: actor?.workspaceId }));
6302
6423
  }
6303
6424
  if (request.method === "POST" && apiPath === "/api/imports/apply") {
6304
6425
  if (hosted)
@@ -6320,14 +6441,14 @@ async function handleApiRoute(service, request, url, apiPath, options, hosted) {
6320
6441
  if (monitorMatch) {
6321
6442
  const id = decodeURIComponent(monitorMatch[1]);
6322
6443
  if (request.method === "GET" && !monitorMatch[2]) {
6323
- const monitor = service.getMonitor(id);
6444
+ const monitor = service.getMonitor(id, { workspaceId: actor?.workspaceId });
6324
6445
  return monitor ? json(monitor) : json({ error: "not found" }, 404);
6325
6446
  }
6326
6447
  if (request.method === "PATCH" && !monitorMatch[2]) {
6327
- return json(service.updateMonitor(id, await jsonBody(request)));
6448
+ return json(service.updateMonitor(id, await jsonBody(request), { workspaceId: actor?.workspaceId }));
6328
6449
  }
6329
6450
  if (request.method === "DELETE" && !monitorMatch[2]) {
6330
- return json({ deleted: service.deleteMonitor(id) });
6451
+ return json({ deleted: service.deleteMonitor(id, { workspaceId: actor?.workspaceId }) });
6331
6452
  }
6332
6453
  if (request.method === "POST" && monitorMatch[2] === "check") {
6333
6454
  if (hosted)
@@ -6478,7 +6599,7 @@ function buildAwsDeploymentPlan(options = {}) {
6478
6599
  const image = clean(options.image, `${imageRepositoryUri}@sha256:<image-digest>`);
6479
6600
  const evidenceBucket = clean(options.evidenceBucket, `hasna-${stage}-${prefix}-evidence`);
6480
6601
  const hostedSqliteDbPath = clean(options.hostedSqliteDbPath, DEFAULT_HOSTED_SQLITE_DB);
6481
- const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.9");
6602
+ const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.11");
6482
6603
  const protectedAccessMode = options.protectedAccessMode ?? DEFAULT_PROTECTED_ACCESS_MODE;
6483
6604
  const protectedAccessUrl = protectedAccessMode === "cloudfront_default_domain" ? "https://<cloudfront-domain>" : `https://${hostname}`;
6484
6605
  const cluster = `${prefix}-${stage}`;
@@ -21,7 +21,7 @@ function buildAwsDeploymentPlan(options = {}) {
21
21
  const image = clean(options.image, `${imageRepositoryUri}@sha256:<image-digest>`);
22
22
  const evidenceBucket = clean(options.evidenceBucket, `hasna-${stage}-${prefix}-evidence`);
23
23
  const hostedSqliteDbPath = clean(options.hostedSqliteDbPath, DEFAULT_HOSTED_SQLITE_DB);
24
- const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.9");
24
+ const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.11");
25
25
  const protectedAccessMode = options.protectedAccessMode ?? DEFAULT_PROTECTED_ACCESS_MODE;
26
26
  const protectedAccessUrl = protectedAccessMode === "cloudfront_default_domain" ? "https://<cloudfront-domain>" : `https://${hostname}`;
27
27
  const cluster = `${prefix}-${stage}`;
package/dist/imports.d.ts CHANGED
@@ -71,7 +71,9 @@ export interface UptimeImportStore {
71
71
  allowBrowserPage?: boolean;
72
72
  }): Monitor;
73
73
  deleteMonitor(idOrName: string): boolean;
74
- getMonitor(idOrName: string): Monitor | null;
74
+ getMonitor(idOrName: string, options?: {
75
+ workspaceId?: string;
76
+ }): Monitor | null;
75
77
  listResults(options?: ListResultsOptions): unknown[];
76
78
  getProvenance(source: string, sourceId: string): MonitorProvenance | null;
77
79
  upsertMonitorProvenance(input: UpsertMonitorProvenanceInput): MonitorProvenance;
@@ -84,7 +86,9 @@ export interface UptimeImportStore {
84
86
  markImportBatchRolledBack(batchId: string): StoredImportBatch;
85
87
  runInTransaction?<T>(fn: () => T): T;
86
88
  }
87
- export declare function previewImport(store: UptimeImportStore, request: ImportRequest): ImportPreview;
89
+ export declare function previewImport(store: UptimeImportStore, request: ImportRequest, options?: {
90
+ workspaceId?: string;
91
+ }): ImportPreview;
88
92
  export declare function applyImport(store: UptimeImportStore, request: ImportRequest): ImportApplyResult;
89
93
  export declare function rollbackImport(store: UptimeImportStore, batchId: string): ImportRollbackResult;
90
94
  //# sourceMappingURL=imports.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../src/imports.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../src/imports.ts"],"names":[],"mappings":"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"}