@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/CHANGELOG.md +34 -0
- package/SECURITY.md +4 -2
- package/dist/api.js +179 -58
- package/dist/checks.d.ts +2 -1
- package/dist/checks.d.ts.map +1 -1
- package/dist/checks.js +2 -1
- package/dist/cli/index.js +180 -59
- package/dist/cloud-plan.js +1 -1
- package/dist/imports.d.ts +6 -2
- package/dist/imports.d.ts.map +1 -1
- package/dist/imports.js +72 -8
- package/dist/index.js +180 -59
- package/dist/mcp/index.js +166 -47
- package/dist/service.d.ts +36 -10
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +166 -47
- package/dist/store.d.ts +13 -3
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +140 -26
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/aws-deployment-runbook.md +327 -14
- package/infra/aws/outputs.tf +35 -0
- package/infra/aws/terraform.tfvars.example +1 -1
- package/infra/aws/variables.tf +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
|
2960
|
-
const
|
|
2961
|
-
|
|
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 = "
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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}`;
|
package/dist/cloud-plan.js
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
|
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
|
package/dist/imports.d.ts.map
CHANGED
|
@@ -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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"}
|