Files
2026-07-13 12:58:18 +08:00

69 lines
2.4 KiB
JavaScript

/// <reference path="../pb_data/types.d.ts" />
//
// PUBLIC-READ INVARIANT: `status` is served with listRule/viewRule = ""
// (unauthenticated read). NEVER put secrets into the `signal` JSON blob
// — any value stored here is trivially exposable via the PB collection
// API from any browser. Sanitize at the writer (see status-writer.ts)
// before anything reaches this collection.
migrate(
(db) => {
const dao = new Dao(db);
// Idempotency: on an existing volume the `status` collection may
// already exist while this migration is NOT recorded in `_migrations`.
// A bare saveCollection(new Collection(...)) then throws
// `UNIQUE constraint failed: _collections.name`, aborting the entire
// migration chain. Mirror the proven probe_runs / resource_snapshots
// guard: find-or-skip. PB JSVM has no typed error discrimination, so
// catch broadly and treat a present collection as a clean no-op.
// (The later 1776789000/100 reconcile migrations own field-level
// schema corrections for an existing `status`.)
try {
dao.findCollectionByNameOrId("status");
return;
} catch {
// Not present — fall through to create.
}
const c = new Collection({
name: "status",
type: "base",
schema: [
{ name: "key", type: "text", required: true },
{ name: "dimension", type: "text", required: true },
{
name: "state",
type: "select",
required: true,
options: { values: ["green", "red", "degraded"], maxSelect: 1 },
},
{ name: "signal", type: "json", options: { maxSize: 2000000 } },
{ name: "observed_at", type: "date", required: true },
{ name: "transitioned_at", type: "date", required: true },
{ name: "fail_count", type: "number" },
{ name: "first_failure_at", type: "date" },
],
indexes: [
"CREATE UNIQUE INDEX idx_status_key ON status (key)",
"CREATE INDEX idx_status_dimension ON status (dimension)",
"CREATE INDEX idx_status_state ON status (state)",
],
listRule: "",
viewRule: "",
createRule: null,
updateRule: null,
deleteRule: null,
});
dao.saveCollection(c);
},
(db) => {
const dao = new Dao(db);
let c;
try {
c = dao.findCollectionByNameOrId("status");
} catch {
// Already absent — nothing to do.
return;
}
dao.deleteCollection(c);
},
);