openship 0.4.8 → 0.6.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.
Files changed (112) hide show
  1. package/README.md +27 -1
  2. package/dist/bare-FSUAM5V5.js +23 -0
  3. package/dist/{bowser-O3AEA6AN.js → bowser-HNOTPGJO.js} +2 -2
  4. package/dist/{chunk-5MZ624VX.js → chunk-2GWYYHOR.js} +1 -1
  5. package/dist/chunk-3FYIXVX5.js +8051 -0
  6. package/dist/{chunk-ILFETZOM.js → chunk-3LDWWY7U.js} +21 -1
  7. package/dist/{chunk-W73X43R7.js → chunk-3NQQXMDR.js} +3 -3
  8. package/dist/{chunk-OWED2GRM.js → chunk-42WQABXM.js} +2 -2
  9. package/dist/{chunk-TYVME3XD.js → chunk-6FH4AXVY.js} +20 -3
  10. package/dist/{chunk-OXWDY22G.js → chunk-6ODUBKUB.js} +3 -3
  11. package/dist/{chunk-DYPH4HCI.js → chunk-AO252K7Z.js} +1 -1
  12. package/dist/{chunk-XPPZ7B2J.js → chunk-B3CE2OMR.js} +14 -12
  13. package/dist/{chunk-IXCHURVK.js → chunk-DOD2BXHQ.js} +4 -4
  14. package/dist/{chunk-VWPEKOH6.js → chunk-DRK3MEDS.js} +3 -3
  15. package/dist/{chunk-V6AN6XLZ.js → chunk-EMXI4UCU.js} +125 -47
  16. package/dist/{chunk-GKHUSZCD.js → chunk-EP2TNALB.js} +2 -2
  17. package/dist/{chunk-SLTYVHU7.js → chunk-GUQ3QCJ7.js} +942 -519
  18. package/dist/chunk-I3DPMTSF.js +29 -0
  19. package/dist/{chunk-L2VOGB2X.js → chunk-IW2UKBVF.js} +3 -3
  20. package/dist/{chunk-VDMQJHPI.js → chunk-IXM5245F.js} +228 -13
  21. package/dist/{chunk-MZ2WEHHY.js → chunk-JIMUYEKN.js} +4 -4
  22. package/dist/chunk-OGY63DGD.js +705 -0
  23. package/dist/{chunk-O6ZZF52V.js → chunk-ONKEYSMY.js} +2 -2
  24. package/dist/{chunk-6APULWSU.js → chunk-OTLSJYAC.js} +1744 -118
  25. package/dist/{chunk-EI575GHN.js → chunk-PDW4L3NV.js} +3 -3
  26. package/dist/{chunk-5NYUCONN.js → chunk-PSZSKEPA.js} +33 -51
  27. package/dist/{chunk-KI2EY3WB.js → chunk-PXKCZB2I.js} +1 -1
  28. package/dist/{chunk-FXTBHTWY.js → chunk-QEH4QUBX.js} +649 -85
  29. package/dist/{chunk-6APIPIJY.js → chunk-QWHBRY2K.js} +5 -5
  30. package/dist/{chunk-6B5YCFFV.js → chunk-RVER2EOO.js} +5 -5
  31. package/dist/{chunk-Q2CIRAOK.js → chunk-RXQBD4ZY.js} +1 -1
  32. package/dist/{chunk-TGIINPVM.js → chunk-TWJCLD4W.js} +60 -10
  33. package/dist/{chunk-4Z5QO7N6.js → chunk-VDDMADOF.js} +3 -3
  34. package/dist/{chunk-BBHX7T4R.js → chunk-VE2YOK4I.js} +991 -254
  35. package/dist/{chunk-2D3I5G6P.js → chunk-VZ2ZHPS2.js} +73 -43
  36. package/dist/{chunk-AVIB7CT7.js → chunk-WNWQBB7F.js} +2 -2
  37. package/dist/{chunk-FRNAR33O.js → chunk-XZYFZ6A5.js} +3 -3
  38. package/dist/{chunk-RPHRPFEH.js → chunk-ZCFVHA25.js} +1 -1
  39. package/dist/{chunk-FPRHYBY2.js → chunk-ZFJXPCQP.js} +1 -1
  40. package/dist/{chunk-JYGD5WSN.js → chunk-ZWLDLTJP.js} +1 -1
  41. package/dist/cloud-E5M6VMCG.js +31 -0
  42. package/dist/{cloud-7QYOGF7F.js → cloud-KRTZ2IL5.js} +3 -3
  43. package/dist/{detect-AZLOHUFX.js → detect-ALF4GXRX.js} +7 -8
  44. package/dist/{dist-IQJ6H6UZ.js → dist-BM6NPWIH.js} +3 -3
  45. package/dist/{dist-es-X3B5QYKB.js → dist-es-2YRDXMUU.js} +6 -6
  46. package/dist/{dist-es-OSNJBLXB.js → dist-es-CCVZEFRZ.js} +5 -5
  47. package/dist/{dist-es-VNKHQVIB.js → dist-es-IOH6G4GM.js} +4 -4
  48. package/dist/{dist-es-RYHIPOTN.js → dist-es-JGBPABJI.js} +14 -14
  49. package/dist/{dist-es-JSTDUS7Q.js → dist-es-KWSMDPIP.js} +6 -6
  50. package/dist/{dist-es-5DY7K32L.js → dist-es-UYDDOVZ3.js} +6 -6
  51. package/dist/{dist-es-WV4AMOII.js → dist-es-XUOR4NQN.js} +8 -8
  52. package/dist/docker-QECQJ5P4.js +32 -0
  53. package/dist/docker-edge-executor-62N64MGS.js +17 -0
  54. package/dist/edge-import-CQWHN2Q3.js +48 -0
  55. package/dist/ensure-container-edge-MJVXJQG5.js +32 -0
  56. package/dist/{event-streams-EHRAKL75.js → event-streams-TR4GAC53.js} +4 -4
  57. package/dist/{executor-XJ6RP4Q2.js → executor-JELARVKC.js} +8 -8
  58. package/dist/index.js +1209 -560
  59. package/dist/{loadSso-46FQRIZS.js → loadSso-UGF4JMRK.js} +10 -10
  60. package/dist/{local-executor-V7U5VOZW.js → local-executor-WOFZD72X.js} +4 -4
  61. package/dist/nginx-AXGNWRKZ.js +31 -0
  62. package/dist/node-entry.js +4 -0
  63. package/dist/{noop-FMMFG2EZ.js → noop-NJ72F46T.js} +3 -3
  64. package/dist/openresty-lua-IE4P5YQX.js +81 -0
  65. package/dist/server/index.js +116248 -94749
  66. package/dist/server/lua/geo_country.lua +31 -6
  67. package/dist/server/lua/maxminddb.lua +403 -0
  68. package/dist/server/lua/mgmt_api.lua +431 -68
  69. package/dist/server/lua/pipe_log.lua +10 -4
  70. package/dist/server/lua/site_logger.lua +220 -12
  71. package/dist/server/migrations/0073_project_volumes_object_storage.sql +3 -0
  72. package/dist/server/migrations/0074_project_compose_path.sql +1 -0
  73. package/dist/server/migrations/0075_service_command_argv.sql +1 -0
  74. package/dist/server/migrations/0076_rollback_retention.sql +17 -0
  75. package/dist/server/migrations/0077_domain_redirect.sql +13 -0
  76. package/dist/server/migrations/0078_grant_source_scope.sql +30 -0
  77. package/dist/server/migrations/0079_project_readiness.sql +18 -0
  78. package/dist/server/migrations/0080_deployment_error_classification.sql +26 -0
  79. package/dist/server/migrations/0081_project_readiness_repair.sql +34 -0
  80. package/dist/server/migrations/0082_edge_target_verification.sql +39 -0
  81. package/dist/server/migrations/0083_service_incident.sql +84 -0
  82. package/dist/server/migrations/0084_analytics_daily_rollup.sql +72 -0
  83. package/dist/server/migrations/0085_resource_usage.sql +68 -0
  84. package/dist/server/migrations/0086_remote_infra_updates.sql +41 -0
  85. package/dist/server/migrations/0087_server_container_version_columns.sql +17 -0
  86. package/dist/server/migrations/0088_audit_source_and_settings.sql +27 -0
  87. package/dist/server/migrations/0089_auto_scan_infra.sql +7 -0
  88. package/dist/server/migrations/0090_project_collect_paths.sql +18 -0
  89. package/dist/server/migrations/0091_project_server_id.sql +26 -0
  90. package/dist/server/migrations/0092_project_internal_alias.sql +13 -0
  91. package/dist/server/migrations/0093_service_incident_org_index.sql +13 -0
  92. package/dist/server/migrations/0094_backup_restore_meta.sql +15 -0
  93. package/dist/server/migrations/0095_backup_restore_cancel.sql +19 -0
  94. package/dist/server/migrations/0096_backup_policy_retention_defaults.sql +20 -0
  95. package/dist/server/migrations/0097_update_status_upstream_only.sql +35 -0
  96. package/dist/server/migrations/meta/_journal.json +175 -0
  97. package/dist/setup-FA4PW4NU.js +21 -0
  98. package/dist/{signin-ITOPKKUB.js → signin-3M3UPB6K.js} +10 -10
  99. package/dist/{sso-oidc-NON2PD7Y.js → sso-oidc-3VDIYOEJ.js} +10 -10
  100. package/dist/{sts-HHFFSAY2.js → sts-B3WIYLXR.js} +9 -9
  101. package/package.json +6 -3
  102. package/dist/bare-JY5Y5ELU.js +0 -23
  103. package/dist/chunk-SJIFLLX4.js +0 -2931
  104. package/dist/chunk-VFINNTUL.js +0 -362
  105. package/dist/cloud-KYWY3RP4.js +0 -30
  106. package/dist/docker-LODK5Y2S.js +0 -16
  107. package/dist/docker-edge-executor-VHW3JPJS.js +0 -13
  108. package/dist/edge-import-ABUDKKJI.js +0 -45
  109. package/dist/ensure-container-edge-SW6HENSG.js +0 -31
  110. package/dist/nginx-3L4SIBJA.js +0 -24
  111. package/dist/openresty-lua-4WLGDSER.js +0 -42
  112. package/dist/setup-NU6T2PDU.js +0 -20
@@ -0,0 +1,68 @@
1
+ -- Resource usage history: the persisted series behind the Monitoring tab's
2
+ -- CPU/memory chart.
3
+ --
4
+ -- Usage existed only as a live 5-second SSE stream, so closing the tab discarded
5
+ -- everything. "Was memory climbing before the OOM at 3am" was unanswerable, which is
6
+ -- the question the data exists to answer.
7
+ --
8
+ -- ── Why this is a SAMPLED series, not a counter series like server_analytics ──
9
+ --
10
+ -- Traffic is counted for free: the edge increments a shared-dict key on every
11
+ -- request, so per-minute granularity costs nothing and is exact. Resource usage has
12
+ -- to be PROBED, and `docker stats` occupies the daemon for roughly a second per
13
+ -- container because it must collect two CPU samples to compute a delta — about 500x
14
+ -- a `docker inspect`. The sampling cadence therefore IS the resolution, and the cost
15
+ -- scales with container count. 5-minute buckets are the compromise between catching
16
+ -- a spike and not pinning every daemon on the estate; ~288 rows/day/service.
17
+ --
18
+ -- ── serviceKey is NOT NULL text, not a nullable service_id FK ────────────────
19
+ --
20
+ -- Postgres treats NULLs as DISTINCT in a unique index, so a nullable column cannot
21
+ -- carry the "this row is the project itself" case without the partial-index
22
+ -- workaround migration 0083 needed for service_incident. A sentinel ('__app__',
23
+ -- matching the health watch's own constant so both features name the same workload
24
+ -- identically) keeps one plain unique index correct.
25
+ --
26
+ -- Accepted consequence: deleting a service leaves its samples behind until retention
27
+ -- prunes them. That is the right trade — history should outlive the thing it
28
+ -- describes — and the project cascade still bounds the growth.
29
+ --
30
+ -- ── What is deliberately absent ─────────────────────────────────────────────
31
+ --
32
+ -- No project-total row. For a compose project the total is the per-bucket SUM of its
33
+ -- services, computed at read. Storing it too would duplicate rows that are free to
34
+ -- drift from their own sources, and would be wrong the moment a service is added or
35
+ -- removed mid-window.
36
+ CREATE TABLE IF NOT EXISTS "resource_usage" (
37
+ "id" text PRIMARY KEY NOT NULL,
38
+ "project_id" text NOT NULL REFERENCES "project"("id") ON DELETE CASCADE,
39
+ -- service.id, or '__app__' for a single-container project.
40
+ "service_key" text NOT NULL,
41
+ -- Bucket start in epoch MINUTES (not a timestamp), floored to a multiple of 5 —
42
+ -- same integer-bucket convention as server_analytics.
43
+ "minute" integer NOT NULL,
44
+ -- Per-CORE percent, as the runtimes report it: >100 is correct on a multi-core box
45
+ -- and must not be clamped. Readers divide by core count for "share of this host".
46
+ "cpu_percent" real DEFAULT 0 NOT NULL,
47
+ "memory_mb" real DEFAULT 0 NOT NULL,
48
+ -- CUMULATIVE since container start, not per-bucket deltas — that is what the
49
+ -- runtimes expose. Readers difference consecutive buckets and clamp negatives to
50
+ -- zero, because a restart resets the counter and would otherwise plot as a large
51
+ -- negative spike. bigint: a long-lived busy container passes int4 in days.
52
+ -- Always 0 for bare deploys (per-process accounting needs eBPF or a netns), so a
53
+ -- reader must not present 0 here as "no network traffic".
54
+ "network_rx_bytes" bigint DEFAULT 0 NOT NULL,
55
+ "network_tx_bytes" bigint DEFAULT 0 NOT NULL,
56
+ "created_at" timestamp DEFAULT now() NOT NULL
57
+ );
58
+ --> statement-breakpoint
59
+
60
+ -- Makes a repeated sample for the same bucket a no-op (insert ... on conflict do
61
+ -- nothing) rather than a double count, so the whole sweep is safely re-runnable.
62
+ CREATE UNIQUE INDEX IF NOT EXISTS "uq_resource_usage_project_service_minute"
63
+ ON "resource_usage" ("project_id", "service_key", "minute");
64
+ --> statement-breakpoint
65
+
66
+ -- Every read is "this project over this window".
67
+ CREATE INDEX IF NOT EXISTS "idx_resource_usage_project_minute"
68
+ ON "resource_usage" ("project_id", "minute");
@@ -0,0 +1,41 @@
1
+ -- Remote infra (edge / mail container) update tracking.
2
+ --
3
+ -- When the control plane's APP_VERSION moves forward, the edge/mail containers
4
+ -- already deployed on remote servers stay on their old image tag. Two additions
5
+ -- drive the "monitor → advise → apply" loop for that drift:
6
+ --
7
+ -- instance_settings.auto_update_infra / last_seen_version — the instance-wide
8
+ -- auto-update toggle and the version the infra reconcile last ran for (so the
9
+ -- boot hook fires exactly once per upgrade). Both additive: the boolean
10
+ -- carries a DEFAULT, last_seen_version is nullable.
11
+ --
12
+ -- server_container_status — the container sibling of server_module_status.
13
+ -- One row per (server, component); "behind" is a plain tag comparison
14
+ -- (running image ref != pinned image ref), since infra images are pinned to
15
+ -- APP_VERSION. Mirrors the module table's org+behind index and unique key.
16
+ ALTER TABLE "instance_settings" ADD COLUMN IF NOT EXISTS "auto_update_infra" boolean DEFAULT false NOT NULL;
17
+ --> statement-breakpoint
18
+ ALTER TABLE "instance_settings" ADD COLUMN IF NOT EXISTS "last_seen_version" text;
19
+ --> statement-breakpoint
20
+ CREATE TABLE IF NOT EXISTS "server_container_status" (
21
+ "id" text PRIMARY KEY NOT NULL,
22
+ "organization_id" text REFERENCES "organization"("id") ON DELETE CASCADE,
23
+ "server_id" text NOT NULL REFERENCES "servers"("id") ON DELETE CASCADE,
24
+ "component" text NOT NULL,
25
+ "running_label" text,
26
+ "pinned_label" text,
27
+ "running_version" text,
28
+ "pinned_version" text,
29
+ "behind" boolean DEFAULT false NOT NULL,
30
+ "latest_in_progress" boolean DEFAULT false NOT NULL,
31
+ "detail" jsonb,
32
+ "checked_at" timestamp DEFAULT now() NOT NULL,
33
+ "created_at" timestamp DEFAULT now() NOT NULL,
34
+ "updated_at" timestamp DEFAULT now() NOT NULL
35
+ );
36
+ --> statement-breakpoint
37
+ CREATE UNIQUE INDEX IF NOT EXISTS "uq_server_container_status"
38
+ ON "server_container_status" ("server_id", "component");
39
+ --> statement-breakpoint
40
+ CREATE INDEX IF NOT EXISTS "idx_server_container_status_org_behind"
41
+ ON "server_container_status" ("organization_id", "behind");
@@ -0,0 +1,17 @@
1
+ -- Repair: add `server_container_status.running_version` / `pinned_version` on a
2
+ -- database that ran an earlier form of 0086.
3
+ --
4
+ -- 0086 was edited in place after it had already been applied: the version columns
5
+ -- were added to its CREATE TABLE, but that create is `IF NOT EXISTS`, so on any
6
+ -- database that had already run the older 0086 the table exists and the amended
7
+ -- create is a silent no-op — the columns never appear. drizzle's migrator then
8
+ -- refuses to re-run 0086 (its `when` equals the last-applied stamp, and the
9
+ -- comparison is strict `<`; see 0081_project_readiness_repair for the same trap),
10
+ -- so nothing else patches it either. Every `listByOrg` then dies with
11
+ -- `column "running_version" does not exist` (42703).
12
+ --
13
+ -- Idempotent and stamped after 0086, so it sorts as a fresh migration: a database
14
+ -- created cleanly gets the columns at 0086 and this is a no-op; a database that
15
+ -- ran the stale 0086 gets them here. Safe to keep in history permanently.
16
+ ALTER TABLE "server_container_status" ADD COLUMN IF NOT EXISTS "running_version" text;--> statement-breakpoint
17
+ ALTER TABLE "server_container_status" ADD COLUMN IF NOT EXISTS "pinned_version" text;
@@ -0,0 +1,27 @@
1
+ -- Audit log: call source + per-org recording switch.
2
+ --
3
+ -- audit_event.source — WHERE the action came in from: "dashboard", "mcp",
4
+ -- "cli", "api", "webhook", "system". Nullable on purpose: rows written
5
+ -- before this migration have no knowable source and must not be
6
+ -- mislabelled as any particular one, so they render as "Unknown". This is
7
+ -- what makes "show me only what the AI assistant did" answerable at all —
8
+ -- MCP tool calls re-enter the app through app.fetch() with nothing but an
9
+ -- Authorization header, so until now an MCP-driven write and a CLI write
10
+ -- produced identical rows.
11
+ --
12
+ -- audit_settings — recording on/off + retention, PER ORGANIZATION. Not
13
+ -- instance_settings (one row would let a single tenant disable auditing for
14
+ -- every org on a CLOUD_MODE instance) and not organization.metadata (Better
15
+ -- Auth owns those writes, which is why the auditRetentionDays documented
16
+ -- there never got a writer). Default enabled = true: auditing stays on
17
+ -- unless an admin turns it off.
18
+ ALTER TABLE "audit_event" ADD COLUMN IF NOT EXISTS "source" text;
19
+ --> statement-breakpoint
20
+ CREATE INDEX IF NOT EXISTS "audit_event_org_source_idx" ON "audit_event" ("organization_id","source","created_at" DESC);
21
+ --> statement-breakpoint
22
+ CREATE TABLE IF NOT EXISTS "audit_settings" (
23
+ "organization_id" text PRIMARY KEY NOT NULL REFERENCES "organization"("id") ON DELETE CASCADE,
24
+ "enabled" boolean DEFAULT true NOT NULL,
25
+ "retention_days" integer DEFAULT 90 NOT NULL,
26
+ "updated_at" timestamp DEFAULT now() NOT NULL
27
+ );
@@ -0,0 +1,7 @@
1
+ -- instance_settings.auto_scan_infra — when on (default), the dashboard runs one
2
+ -- detect-only container scan on a relevant surface load (Infrastructure tab /
3
+ -- home) if the cached drift state is stale, so the attention dot + issue list
4
+ -- stay fresh without a manual Scan. Detect-only; auto-APPLY stays the separate
5
+ -- auto_update_infra. Idempotent ADD COLUMN IF NOT EXISTS + DEFAULT true so both
6
+ -- a clean create and an existing settings row converge on "on".
7
+ ALTER TABLE "instance_settings" ADD COLUMN IF NOT EXISTS "auto_scan_infra" boolean DEFAULT true NOT NULL;
@@ -0,0 +1,18 @@
1
+ -- Top Paths becomes opt-in.
2
+ --
3
+ -- The per-path aggregation is the one analytics dimension that isn't effectively free.
4
+ -- Measured on the shipped edge image, per request:
5
+ --
6
+ -- paths (whole block) 1.72 us <- 57% of the log handler's counter path
7
+ -- of which string work 1.38 us normalize_path + is_static_asset
8
+ -- minute buckets 0.61 us
9
+ -- country 0.24 us
10
+ -- status 0.14 us
11
+ --
12
+ -- It is also the highest-cardinality dimension (up to 2000 keys per domain per day) and
13
+ -- the largest column in the daily rollup. So it is now a per-project switch, read on the
14
+ -- hot path from the edge's `rules` shared dict and pushed there on every route apply.
15
+ --
16
+ -- DEFAULT false, which turns it off for existing projects as well. Deliberate: no one
17
+ -- opted into the cost, so no one should keep paying it without asking.
18
+ ALTER TABLE "project" ADD COLUMN IF NOT EXISTS "collect_paths" boolean DEFAULT false NOT NULL;
@@ -0,0 +1,26 @@
1
+ -- Durable server ownership on the project.
2
+ --
3
+ -- A project's deploy target lived ONLY in the active deployment's volatile
4
+ -- meta.serverId. When resolveSnapshotTarget couldn't re-derive that binding from
5
+ -- a fresh/partial snapshot, the deploy fell back to "local", which then nulled
6
+ -- the project's verified custom-domain ports and regressed the Access URL to
7
+ -- localhost:3000. This makes the server binding a durable, first-class column.
8
+ --
9
+ -- cloudWorkspaceId still owns "is this a cloud project", so we deliberately do
10
+ -- NOT add a deployTarget column (that would be a second source of truth for the
11
+ -- same fact); the effective target is derived — cloudWorkspaceId ? "cloud" :
12
+ -- server_id ? "server" : "local".
13
+ --
14
+ -- ON DELETE SET NULL: removing a server unbinds its projects rather than
15
+ -- cascade-deleting them.
16
+ ALTER TABLE "project" ADD COLUMN IF NOT EXISTS "server_id" text REFERENCES "servers"("id") ON DELETE SET NULL;
17
+ --> statement-breakpoint
18
+ -- Backfill the binding from each project's active-deployment meta so existing
19
+ -- server-hosted projects survive the next redeploy without regressing to local.
20
+ UPDATE "project" SET "server_id" = (
21
+ SELECT d."meta"->>'serverId'
22
+ FROM "deployment" d
23
+ WHERE d."id" = "project"."active_deployment_id"
24
+ )
25
+ WHERE "server_id" IS NULL
26
+ AND "active_deployment_id" IS NOT NULL;
@@ -0,0 +1,13 @@
1
+ -- User-chosen internal DNS alias for a single-app native project.
2
+ --
3
+ -- Single-app containers now join their own `openship-<slug>` network with a
4
+ -- stable default alias (`<slug>`), the same east-west reachability compose
5
+ -- services already have. This column lets an operator add a custom hostname
6
+ -- that resolves ALONGSIDE the default (both point at the container) — it never
7
+ -- replaces the default and never changes public exposure (the edge stays the
8
+ -- sole public ingress; publishing is loopback-only).
9
+ --
10
+ -- Nullable, no default: absence means "default alias only" and existing rows
11
+ -- need no backfill. Compose services store the equivalent in the zero-migration
12
+ -- `service.advanced.alias` JSONB, so only single-app needs a column.
13
+ ALTER TABLE "project" ADD COLUMN IF NOT EXISTS "internal_alias" text;
@@ -0,0 +1,13 @@
1
+ -- Org-wide incident reads for the global issue tracker.
2
+ --
3
+ -- The existing indexes on this table are project-keyed (`idx_service_incident_project`)
4
+ -- or exist to enforce the one-open-incident invariant. Both are wrong shapes for the
5
+ -- new question: "every incident in THIS organization, newest first" — the Issues feed's
6
+ -- Open tab and its Resolved tab, which sorts org-wide across up to 30 days of retained
7
+ -- history. Without this the feed sequentially scans the whole table and filters, which
8
+ -- gets slower exactly as an instance accumulates the history that makes the tab useful.
9
+ --
10
+ -- Covers both scopes: server-scoped rows have `project_id IS NULL`, so a project-keyed
11
+ -- index can't serve them at all.
12
+ CREATE INDEX IF NOT EXISTS "idx_service_incident_org"
13
+ ON "service_incident" ("organization_id", "opened_at" DESC);
@@ -0,0 +1,15 @@
1
+ -- Record WHICH integrity check a restore actually performed.
2
+ --
3
+ -- Prepare used to comment that it verified every artifact's sha256 while
4
+ -- comparing only byte sizes. Now that it really re-hashes the archive, the row
5
+ -- has to say so — because the check is downgradeable (a run with no recorded
6
+ -- digest falls back to size-only, and a policy can defer verification to apply
7
+ -- time), and "restore succeeded" means something different in each case. An
8
+ -- operator reading a month-old restore has no other way to tell a re-hashed
9
+ -- archive from a length-matched one.
10
+ --
11
+ -- Keys written today: `integrity` ("sha256" | "size-only" | "deferred"),
12
+ -- `verifiedBytes`, `verifyMs`, `manifest` ("verified" | "missing").
13
+ -- JSONB rather than columns so the cancel/partial-write facts that follow need
14
+ -- no further migration.
15
+ ALTER TABLE "backup_restore" ADD COLUMN IF NOT EXISTS "meta" jsonb DEFAULT '{}'::jsonb;
@@ -0,0 +1,19 @@
1
+ -- Make "cancel a restore" durable.
2
+ --
3
+ -- Cancel used to be advisory at best: it refused `applying` outright, and for
4
+ -- `preparing` it wrote the row while the running phase carried on and
5
+ -- overwrote it with `prepared` — so the operator saw a cancel that never
6
+ -- happened. Cancelling has to survive the phase it interrupts, and the node
7
+ -- receiving the request is not guaranteed to be the node running the apply, so
8
+ -- the in-process AbortController cannot be the only signal.
9
+ --
10
+ -- `cancel_requested_at` is also the force-terminal window: an `applying` row
11
+ -- whose request is older than a couple of minutes (operator pressed cancel,
12
+ -- waited, pressed again) can be force-terminaled without a second endpoint,
13
+ -- which is the only escape from a wedged row that otherwise blocks project
14
+ -- deletion.
15
+ ALTER TABLE "backup_restore" ADD COLUMN IF NOT EXISTS "cancel_requested" boolean DEFAULT false NOT NULL;
16
+ --> statement-breakpoint
17
+ ALTER TABLE "backup_restore" ADD COLUMN IF NOT EXISTS "cancel_requested_at" timestamp;
18
+ --> statement-breakpoint
19
+ ALTER TABLE "backup_restore" ADD COLUMN IF NOT EXISTS "cancelled_at" timestamp;
@@ -0,0 +1,20 @@
1
+ -- Turn retention on for policies that never said anything about it.
2
+ --
3
+ -- `retain_count` and `retain_days` were the only two fields on the policy
4
+ -- insert with neither an API default nor a column default, so every policy
5
+ -- created through the API or MCP stored NULL for both. `prunePolicy`
6
+ -- short-circuits on "no retention configured", so retention silently never ran
7
+ -- for those policies and their runs accumulated until the destination filled.
8
+ -- The dashboard's form defaults to 7, so a human creating a policy in the UI
9
+ -- got retention and the same policy created over the API did not.
10
+ --
11
+ -- 7 = the dashboard's own default (PolicyEditor), now shared as
12
+ -- DEFAULT_RETAIN_COUNT so the column, the API fallback, and the form agree.
13
+ --
14
+ -- The backfill is what actually fixes instances running today, and it is
15
+ -- narrowed to rows where BOTH fields are null: a policy with only `retain_days`
16
+ -- set has retention configured deliberately, and writing a count there would
17
+ -- silently tighten a window the operator chose.
18
+ ALTER TABLE "backup_policy" ALTER COLUMN "retain_count" SET DEFAULT 7;
19
+ --> statement-breakpoint
20
+ UPDATE "backup_policy" SET "retain_count" = 7 WHERE "retain_count" IS NULL AND "retain_days" IS NULL;
@@ -0,0 +1,35 @@
1
+ -- update_status becomes an UPSTREAM-only cache.
2
+ --
3
+ -- The table used to cache both halves of the drift answer: what the source offers
4
+ -- (upstream) and what is currently deployed. Only the first half is expensive and
5
+ -- poll-only. The second half — `behind`, `latest_in_progress`, `current_label` —
6
+ -- is derived from the project's ACTIVE deployment, which seven separate code paths
7
+ -- write (deploy success, rollback, reconcile, activate, clear, self-deploy,
8
+ -- migrate). Caching it meant each of those needed an invalidation hook; only one
9
+ -- ever had it, so rows froze mid-window and the dashboard advertised updates for
10
+ -- commits the operator had already shipped.
11
+ --
12
+ -- Those columns are now computed on read, so keeping them would leave a copy that
13
+ -- looks authoritative while describing a superseded release. `latest_label` goes
14
+ -- too: it's rendered from `detail` alongside the live current label, in one code
15
+ -- path, so the two can never disagree.
16
+ --
17
+ -- Existing rows keep `detail`, but rows written before this migration carry only
18
+ -- the 7-char sha prefix in the dropped `latest_label` — never a full `latestSha`
19
+ -- in `detail` — so a commit row cannot be compared until it is re-polled. Clear
20
+ -- them and let `updates:scan` (or the dashboard's explicit check) repopulate;
21
+ -- until then those projects simply report no update, which is the conservative
22
+ -- direction.
23
+ DELETE FROM "update_status";
24
+ --> statement-breakpoint
25
+ DROP INDEX IF EXISTS "idx_update_status_org_behind";
26
+ --> statement-breakpoint
27
+ CREATE INDEX IF NOT EXISTS "idx_update_status_org" ON "update_status" ("organization_id");
28
+ --> statement-breakpoint
29
+ ALTER TABLE "update_status" DROP COLUMN IF EXISTS "behind";
30
+ --> statement-breakpoint
31
+ ALTER TABLE "update_status" DROP COLUMN IF EXISTS "latest_in_progress";
32
+ --> statement-breakpoint
33
+ ALTER TABLE "update_status" DROP COLUMN IF EXISTS "current_label";
34
+ --> statement-breakpoint
35
+ ALTER TABLE "update_status" DROP COLUMN IF EXISTS "latest_label";
@@ -512,6 +512,181 @@
512
512
  "when": 1785358400651,
513
513
  "tag": "0072_gh_device_token_method",
514
514
  "breakpoints": true
515
+ },
516
+ {
517
+ "idx": 73,
518
+ "version": "7",
519
+ "when": 1785358401651,
520
+ "tag": "0073_project_volumes_object_storage",
521
+ "breakpoints": true
522
+ },
523
+ {
524
+ "idx": 74,
525
+ "version": "7",
526
+ "when": 1785450107324,
527
+ "tag": "0074_project_compose_path",
528
+ "breakpoints": true
529
+ },
530
+ {
531
+ "idx": 75,
532
+ "version": "7",
533
+ "when": 1785536507324,
534
+ "tag": "0075_service_command_argv",
535
+ "breakpoints": true
536
+ },
537
+ {
538
+ "idx": 76,
539
+ "version": "7",
540
+ "when": 1785622907324,
541
+ "tag": "0076_rollback_retention",
542
+ "breakpoints": true
543
+ },
544
+ {
545
+ "idx": 77,
546
+ "version": "7",
547
+ "when": 1785709307324,
548
+ "tag": "0077_domain_redirect",
549
+ "breakpoints": true
550
+ },
551
+ {
552
+ "idx": 78,
553
+ "version": "7",
554
+ "when": 1785795707324,
555
+ "tag": "0078_grant_source_scope",
556
+ "breakpoints": true
557
+ },
558
+ {
559
+ "idx": 79,
560
+ "version": "7",
561
+ "when": 1785882107324,
562
+ "tag": "0079_project_readiness",
563
+ "breakpoints": true
564
+ },
565
+ {
566
+ "idx": 80,
567
+ "version": "7",
568
+ "when": 1785968507324,
569
+ "tag": "0080_deployment_error_classification",
570
+ "breakpoints": true
571
+ },
572
+ {
573
+ "idx": 81,
574
+ "version": "7",
575
+ "when": 1786054907324,
576
+ "tag": "0081_project_readiness_repair",
577
+ "breakpoints": true
578
+ },
579
+ {
580
+ "idx": 82,
581
+ "version": "7",
582
+ "when": 1786141307324,
583
+ "tag": "0082_edge_target_verification",
584
+ "breakpoints": true
585
+ },
586
+ {
587
+ "idx": 83,
588
+ "version": "7",
589
+ "when": 1786227707324,
590
+ "tag": "0083_service_incident",
591
+ "breakpoints": true
592
+ },
593
+ {
594
+ "idx": 84,
595
+ "version": "7",
596
+ "when": 1786314107324,
597
+ "tag": "0084_analytics_daily_rollup",
598
+ "breakpoints": true
599
+ },
600
+ {
601
+ "idx": 85,
602
+ "version": "7",
603
+ "when": 1786400507324,
604
+ "tag": "0085_resource_usage",
605
+ "breakpoints": true
606
+ },
607
+ {
608
+ "idx": 86,
609
+ "version": "7",
610
+ "when": 1786486907324,
611
+ "tag": "0086_remote_infra_updates",
612
+ "breakpoints": true
613
+ },
614
+ {
615
+ "idx": 87,
616
+ "version": "7",
617
+ "when": 1786573307324,
618
+ "tag": "0087_server_container_version_columns",
619
+ "breakpoints": true
620
+ },
621
+ {
622
+ "idx": 88,
623
+ "version": "7",
624
+ "when": 1786659707324,
625
+ "tag": "0088_audit_source_and_settings",
626
+ "breakpoints": true
627
+ },
628
+ {
629
+ "idx": 89,
630
+ "version": "7",
631
+ "when": 1786746107324,
632
+ "tag": "0089_auto_scan_infra",
633
+ "breakpoints": true
634
+ },
635
+ {
636
+ "idx": 90,
637
+ "version": "7",
638
+ "when": 1786746107325,
639
+ "tag": "0090_project_collect_paths",
640
+ "breakpoints": true
641
+ },
642
+ {
643
+ "idx": 91,
644
+ "version": "7",
645
+ "when": 1786832507325,
646
+ "tag": "0091_project_server_id",
647
+ "breakpoints": true
648
+ },
649
+ {
650
+ "idx": 92,
651
+ "version": "7",
652
+ "when": 1786918907325,
653
+ "tag": "0092_project_internal_alias",
654
+ "breakpoints": true
655
+ },
656
+ {
657
+ "idx": 93,
658
+ "version": "7",
659
+ "when": 1787005307325,
660
+ "tag": "0093_service_incident_org_index",
661
+ "breakpoints": true
662
+ },
663
+ {
664
+ "idx": 94,
665
+ "version": "7",
666
+ "when": 1787091707325,
667
+ "tag": "0094_backup_restore_meta",
668
+ "breakpoints": true
669
+ },
670
+ {
671
+ "idx": 95,
672
+ "version": "7",
673
+ "when": 1787178107325,
674
+ "tag": "0095_backup_restore_cancel",
675
+ "breakpoints": true
676
+ },
677
+ {
678
+ "idx": 96,
679
+ "version": "7",
680
+ "when": 1787264507325,
681
+ "tag": "0096_backup_policy_retention_defaults",
682
+ "breakpoints": true
683
+ },
684
+ {
685
+ "idx": 97,
686
+ "version": "7",
687
+ "when": 1787350907325,
688
+ "tag": "0097_update_status_upstream_only",
689
+ "breakpoints": true
515
690
  }
516
691
  ]
517
692
  }
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env sh
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
+ import { createRequire as __ospCreateRequire } from "node:module";
4
+ const require = __ospCreateRequire(import.meta.url);
5
+ import {
6
+ SystemManager
7
+ } from "./chunk-EP2TNALB.js";
8
+ import "./chunk-GUQ3QCJ7.js";
9
+ import "./chunk-IW2UKBVF.js";
10
+ import "./chunk-ZCFVHA25.js";
11
+ import "./chunk-QEH4QUBX.js";
12
+ import "./chunk-I3DPMTSF.js";
13
+ import "./chunk-VZ2ZHPS2.js";
14
+ import "./chunk-3LDWWY7U.js";
15
+ import "./chunk-OGY63DGD.js";
16
+ import "./chunk-ZFJXPCQP.js";
17
+ import "./chunk-OTLSJYAC.js";
18
+ import "./chunk-PXKCZB2I.js";
19
+ export {
20
+ SystemManager
21
+ };
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v bun || command -v node)" "$0" "$@"
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
3
  import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  AwsRestJsonProtocol
7
- } from "./chunk-6B5YCFFV.js";
7
+ } from "./chunk-RVER2EOO.js";
8
8
  import {
9
9
  NoAuthSigner,
10
10
  package_default
11
- } from "./chunk-DYPH4HCI.js";
12
- import "./chunk-EI575GHN.js";
11
+ } from "./chunk-AO252K7Z.js";
12
+ import "./chunk-PDW4L3NV.js";
13
13
  import {
14
14
  AwsSdkSigV4Signer,
15
15
  DefaultIdentityProviderConfig,
@@ -19,10 +19,10 @@ import {
19
19
  getSchemaSerdePlugin,
20
20
  resolveAwsSdkSigV4Config,
21
21
  streamCollector
22
- } from "./chunk-IXCHURVK.js";
22
+ } from "./chunk-DOD2BXHQ.js";
23
23
  import {
24
24
  NodeHttpHandler
25
- } from "./chunk-OWED2GRM.js";
25
+ } from "./chunk-42WQABXM.js";
26
26
  import {
27
27
  BinaryDecisionDiagram,
28
28
  Client,
@@ -56,7 +56,7 @@ import {
56
56
  resolveHostHeaderConfig,
57
57
  resolveRetryConfig,
58
58
  resolveUserAgentConfig
59
- } from "./chunk-VWPEKOH6.js";
59
+ } from "./chunk-DRK3MEDS.js";
60
60
  import {
61
61
  NODE_REGION_CONFIG_FILE_OPTIONS,
62
62
  NODE_REGION_CONFIG_OPTIONS,
@@ -72,7 +72,7 @@ import {
72
72
  resolveDefaultsModeConfig,
73
73
  resolveHttpHandlerRuntimeConfig,
74
74
  resolveRegionConfig
75
- } from "./chunk-W73X43R7.js";
75
+ } from "./chunk-3NQQXMDR.js";
76
76
  import {
77
77
  Hash,
78
78
  calculateBodyLength,
@@ -80,8 +80,8 @@ import {
80
80
  fromUtf8,
81
81
  toBase64,
82
82
  toUtf8
83
- } from "./chunk-JYGD5WSN.js";
84
- import "./chunk-KI2EY3WB.js";
83
+ } from "./chunk-ZWLDLTJP.js";
84
+ import "./chunk-PXKCZB2I.js";
85
85
 
86
86
  // ../../node_modules/@aws-sdk/nested-clients/dist-es/submodules/signin/auth/httpAuthSchemeProvider.js
87
87
  var defaultSigninHttpAuthSchemeParametersProvider = async (config, context, input) => {
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v bun || command -v node)" "$0" "$@"
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
3
  import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  AwsRestJsonProtocol
7
- } from "./chunk-6B5YCFFV.js";
7
+ } from "./chunk-RVER2EOO.js";
8
8
  import {
9
9
  NoAuthSigner,
10
10
  package_default
11
- } from "./chunk-DYPH4HCI.js";
12
- import "./chunk-EI575GHN.js";
11
+ } from "./chunk-AO252K7Z.js";
12
+ import "./chunk-PDW4L3NV.js";
13
13
  import {
14
14
  AwsSdkSigV4Signer,
15
15
  DefaultIdentityProviderConfig,
@@ -19,10 +19,10 @@ import {
19
19
  getSchemaSerdePlugin,
20
20
  resolveAwsSdkSigV4Config,
21
21
  streamCollector
22
- } from "./chunk-IXCHURVK.js";
22
+ } from "./chunk-DOD2BXHQ.js";
23
23
  import {
24
24
  NodeHttpHandler
25
- } from "./chunk-OWED2GRM.js";
25
+ } from "./chunk-42WQABXM.js";
26
26
  import {
27
27
  BinaryDecisionDiagram,
28
28
  Client,
@@ -56,7 +56,7 @@ import {
56
56
  resolveHostHeaderConfig,
57
57
  resolveRetryConfig,
58
58
  resolveUserAgentConfig
59
- } from "./chunk-VWPEKOH6.js";
59
+ } from "./chunk-DRK3MEDS.js";
60
60
  import {
61
61
  NODE_REGION_CONFIG_FILE_OPTIONS,
62
62
  NODE_REGION_CONFIG_OPTIONS,
@@ -72,7 +72,7 @@ import {
72
72
  resolveDefaultsModeConfig,
73
73
  resolveHttpHandlerRuntimeConfig,
74
74
  resolveRegionConfig
75
- } from "./chunk-W73X43R7.js";
75
+ } from "./chunk-3NQQXMDR.js";
76
76
  import {
77
77
  Hash,
78
78
  calculateBodyLength,
@@ -80,8 +80,8 @@ import {
80
80
  fromUtf8,
81
81
  toBase64,
82
82
  toUtf8
83
- } from "./chunk-JYGD5WSN.js";
84
- import "./chunk-KI2EY3WB.js";
83
+ } from "./chunk-ZWLDLTJP.js";
84
+ import "./chunk-PXKCZB2I.js";
85
85
 
86
86
  // ../../node_modules/@aws-sdk/nested-clients/dist-es/submodules/sso-oidc/auth/httpAuthSchemeProvider.js
87
87
  var defaultSSOOIDCHttpAuthSchemeParametersProvider = async (config, context, input) => {