feat: establish NekoNest Cloud control and relay

This commit is contained in:
2026-08-12 23:25:43 +08:00
commit f27606b709
222 changed files with 71456 additions and 0 deletions
+240
View File
@@ -0,0 +1,240 @@
CREATE TABLE `accounts` (
`id` text PRIMARY KEY NOT NULL,
`auth_subject` text NOT NULL,
`email` text NOT NULL,
`display_name` text NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_accounts_auth_subject` ON `accounts` (`auth_subject`);--> statement-breakpoint
CREATE INDEX `idx_accounts_email` ON `accounts` (`email`);--> statement-breakpoint
CREATE TABLE `audit_events` (
`id` text PRIMARY KEY NOT NULL,
`actor_id` text NOT NULL,
`action` text NOT NULL,
`target_type` text NOT NULL,
`target_id` text NOT NULL,
`reason` text NOT NULL,
`before_json` text,
`after_json` text,
`correlation_id` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
);
--> statement-breakpoint
CREATE INDEX `idx_audit_target_time` ON `audit_events` (`target_type`,`target_id`,`created_at`);--> statement-breakpoint
CREATE INDEX `idx_audit_actor_time` ON `audit_events` (`actor_id`,`created_at`);--> statement-breakpoint
CREATE TABLE `beta_programs` (
`id` text PRIMARY KEY NOT NULL,
`state` text NOT NULL,
`capacity_slots` integer,
`starts_at` text NOT NULL,
`ends_at` text,
`grace_days` integer DEFAULT 7 NOT NULL,
`created_by` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`retired_at` text
);
--> statement-breakpoint
CREATE INDEX `idx_beta_state_time` ON `beta_programs` (`state`,`starts_at`);--> statement-breakpoint
CREATE TABLE `entitlement_grants` (
`id` text PRIMARY KEY NOT NULL,
`account_id` text NOT NULL,
`host_id` text,
`source` text NOT NULL,
`source_ref` text,
`capacity_slots` integer,
`starts_at` text NOT NULL,
`ends_at` text,
`state` text DEFAULT 'scheduled' NOT NULL,
`reason` text NOT NULL,
`created_by` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`revoked_at` text,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`host_id`) REFERENCES `hosts`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `idx_grants_account_state_time` ON `entitlement_grants` (`account_id`,`state`,`starts_at`);--> statement-breakpoint
CREATE UNIQUE INDEX `idx_grants_source_ref` ON `entitlement_grants` (`source`,`source_ref`);--> statement-breakpoint
CREATE TABLE `hosts` (
`id` text PRIMARY KEY NOT NULL,
`account_id` text NOT NULL,
`name` text NOT NULL,
`os` text NOT NULL,
`lifecycle` text DEFAULT 'active' NOT NULL,
`slot_state` text DEFAULT 'active' NOT NULL,
`connection_state` text DEFAULT 'unknown' NOT NULL,
`daemon_version` text,
`recovery_fingerprint` text,
`last_seen_at` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`deactivated_at` text,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `idx_hosts_account_lifecycle` ON `hosts` (`account_id`,`lifecycle`);--> statement-breakpoint
CREATE UNIQUE INDEX `idx_hosts_recovery_fingerprint` ON `hosts` (`recovery_fingerprint`);--> statement-breakpoint
CREATE TABLE `idempotency_records` (
`scope` text NOT NULL,
`key` text NOT NULL,
`request_hash` text NOT NULL,
`response_json` text NOT NULL,
`status_code` integer NOT NULL,
`expires_at` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY(`scope`, `key`)
);
--> statement-breakpoint
CREATE INDEX `idx_idempotency_expires` ON `idempotency_records` (`expires_at`);--> statement-breakpoint
CREATE TABLE `invoices` (
`id` text PRIMARY KEY NOT NULL,
`order_id` text NOT NULL,
`invoice_type` text DEFAULT 'commercial' NOT NULL,
`invoice_number` text,
`amount_minor` integer NOT NULL,
`tax_minor` integer,
`currency` text NOT NULL,
`status` text DEFAULT 'draft' NOT NULL,
`document_ref` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_invoices_order` ON `invoices` (`order_id`);--> statement-breakpoint
CREATE TABLE `launch_gates` (
`key` text PRIMARY KEY NOT NULL,
`priority` text NOT NULL,
`category` text NOT NULL,
`title` text NOT NULL,
`status` text DEFAULT 'blocked' NOT NULL,
`owner` text,
`evidence_url` text,
`notes` text DEFAULT '' NOT NULL,
`reviewed_at` text,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
);
--> statement-breakpoint
CREATE INDEX `idx_launch_gates_status` ON `launch_gates` (`priority`,`status`);--> statement-breakpoint
CREATE TABLE `orders` (
`id` text PRIMARY KEY NOT NULL,
`account_id` text NOT NULL,
`client_order_id` text NOT NULL,
`kind` text DEFAULT 'purchase' NOT NULL,
`price_version_id` text NOT NULL,
`slot_quantity` integer NOT NULL,
`term_start` text NOT NULL,
`term_end` text NOT NULL,
`amount_minor` integer NOT NULL,
`currency` text NOT NULL,
`status` text DEFAULT 'draft' NOT NULL,
`quote_expires_at` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`price_version_id`) REFERENCES `price_versions`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_orders_account_client` ON `orders` (`account_id`,`client_order_id`);--> statement-breakpoint
CREATE INDEX `idx_orders_account_status` ON `orders` (`account_id`,`status`);--> statement-breakpoint
CREATE TABLE `pairing_requests` (
`id` text PRIMARY KEY NOT NULL,
`account_id` text NOT NULL,
`requested_name` text NOT NULL,
`os` text NOT NULL,
`code_hash` text NOT NULL,
`status` text DEFAULT 'waiting' NOT NULL,
`expires_at` text NOT NULL,
`claimed_host_id` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`claimed_at` text,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`claimed_host_id`) REFERENCES `hosts`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_pairing_code_hash` ON `pairing_requests` (`code_hash`);--> statement-breakpoint
CREATE INDEX `idx_pairing_account_status` ON `pairing_requests` (`account_id`,`status`);--> statement-breakpoint
CREATE TABLE `payment_attempts` (
`id` text PRIMARY KEY NOT NULL,
`order_id` text NOT NULL,
`provider` text NOT NULL,
`provider_payment_ref` text,
`provider_event_id` text,
`amount_minor` integer NOT NULL,
`currency` text NOT NULL,
`status` text DEFAULT 'created' NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_payments_provider_event` ON `payment_attempts` (`provider`,`provider_event_id`);--> statement-breakpoint
CREATE UNIQUE INDEX `idx_payments_provider_ref` ON `payment_attempts` (`provider`,`provider_payment_ref`);--> statement-breakpoint
CREATE TABLE `price_versions` (
`id` text PRIMARY KEY NOT NULL,
`product_code` text DEFAULT 'host_slot' NOT NULL,
`billing_period` text NOT NULL,
`unit_slots` integer DEFAULT 1 NOT NULL,
`amount_minor` integer NOT NULL,
`currency` text DEFAULT 'CNY' NOT NULL,
`tax_mode` text DEFAULT 'undecided' NOT NULL,
`quote_ttl_seconds` integer DEFAULT 900 NOT NULL,
`status` text DEFAULT 'draft' NOT NULL,
`effective_from` text NOT NULL,
`effective_to` text,
`created_by` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
);
--> statement-breakpoint
CREATE INDEX `idx_prices_catalog` ON `price_versions` (`product_code`,`billing_period`,`status`);--> statement-breakpoint
CREATE TABLE `provisioning_operations` (
`id` text PRIMARY KEY NOT NULL,
`tenant_id` text NOT NULL,
`operation` text NOT NULL,
`idempotency_key` text NOT NULL,
`correlation_id` text NOT NULL,
`target_generation` integer NOT NULL,
`status` text DEFAULT 'requested' NOT NULL,
`error_code` text,
`error_detail` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_operations_idempotency` ON `provisioning_operations` (`tenant_id`,`idempotency_key`);--> statement-breakpoint
CREATE INDEX `idx_operations_status` ON `provisioning_operations` (`status`);--> statement-breakpoint
CREATE TABLE `refunds` (
`id` text PRIMARY KEY NOT NULL,
`payment_attempt_id` text NOT NULL,
`invoice_id` text,
`amount_minor` integer NOT NULL,
`currency` text NOT NULL,
`reason` text NOT NULL,
`status` text DEFAULT 'requested' NOT NULL,
`entitlement_effect` text DEFAULT 'pending' NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`payment_attempt_id`) REFERENCES `payment_attempts`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`invoice_id`) REFERENCES `invoices`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `idx_refunds_payment` ON `refunds` (`payment_attempt_id`);--> statement-breakpoint
CREATE TABLE `tenant_instances` (
`id` text PRIMARY KEY NOT NULL,
`account_id` text NOT NULL,
`slug` text NOT NULL,
`lifecycle` text DEFAULT 'requested' NOT NULL,
`desired_generation` integer DEFAULT 1 NOT NULL,
`active_generation` integer,
`runtime_version` text,
`last_health_at` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_tenants_account` ON `tenant_instances` (`account_id`);--> statement-breakpoint
CREATE UNIQUE INDEX `idx_tenants_slug` ON `tenant_instances` (`slug`);
+46
View File
@@ -0,0 +1,46 @@
CREATE TABLE `cloud_schema_migrations` (
`id` text PRIMARY KEY NOT NULL,
`applied_at` text NOT NULL
);
--> statement-breakpoint
CREATE TABLE `device_credentials` (
`id` text PRIMARY KEY NOT NULL,
`host_id` text NOT NULL,
`token_hash` text NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`issued_at` text NOT NULL,
`expires_at` text,
`last_used_at` text,
`revoked_at` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`host_id`) REFERENCES `hosts`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_device_credentials_token_hash` ON `device_credentials` (`token_hash`);--> statement-breakpoint
CREATE INDEX `idx_device_credentials_host_status` ON `device_credentials` (`host_id`,`status`);--> statement-breakpoint
CREATE TABLE `pairing_claim_attempts` (
`id` text PRIMARY KEY NOT NULL,
`pairing_request_id` text NOT NULL,
`source_hash` text NOT NULL,
`outcome` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
);
--> statement-breakpoint
CREATE INDEX `idx_pairing_claim_attempts_target_time` ON `pairing_claim_attempts` (`pairing_request_id`,`created_at`);--> statement-breakpoint
CREATE INDEX `idx_pairing_claim_attempts_source_time` ON `pairing_claim_attempts` (`source_hash`,`created_at`);--> statement-breakpoint
CREATE TABLE `pairing_claim_rate_limits` (
`source_hash` text NOT NULL,
`window_start` text NOT NULL,
`attempts` integer DEFAULT 1 NOT NULL,
`updated_at` text NOT NULL,
PRIMARY KEY(`source_hash`, `window_start`)
);
--> statement-breakpoint
ALTER TABLE `hosts` ADD `ed25519_public` text;--> statement-breakpoint
ALTER TABLE `hosts` ADD `x25519_public` text;--> statement-breakpoint
ALTER TABLE `hosts` ADD `identity_fingerprint` text;--> statement-breakpoint
ALTER TABLE `hosts` ADD `claimed_at` text;--> statement-breakpoint
CREATE UNIQUE INDEX `idx_hosts_identity_fingerprint` ON `hosts` (`identity_fingerprint`);--> statement-breakpoint
ALTER TABLE `pairing_requests` ADD `failed_attempts` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
ALTER TABLE `pairing_requests` ADD `locked_at` text;--> statement-breakpoint
ALTER TABLE `pairing_requests` ADD `last_attempt_at` text;
+1
View File
@@ -0,0 +1 @@
ALTER TABLE `hosts` ADD `claim_request_id` text;
+40
View File
@@ -0,0 +1,40 @@
ALTER TABLE `provisioning_operations` ADD `requested_by` text DEFAULT 'system:legacy' NOT NULL;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `reason` text DEFAULT 'legacy provisioning request' NOT NULL;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `lifecycle_before` text DEFAULT 'requested' NOT NULL;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `payload_version` integer DEFAULT 1 NOT NULL;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `lease_owner` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `lease_token_hash` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `lease_expires_at` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `attempt_count` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `max_attempts` integer DEFAULT 5 NOT NULL;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `started_at` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `completed_at` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `completion_hash` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `observed_generation` integer;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `result_runtime_ref` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `result_runtime_version` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `result_relay_origin` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `result_secret_bundle_ref` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `health_status` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `health_checked_at` text;--> statement-breakpoint
UPDATE `provisioning_operations`
SET `status` = 'canceled',
`error_code` = 'legacy_duplicate_active_operation',
`error_detail` = 'Migration kept only the newest active operation for this tenant.',
`completed_at` = CURRENT_TIMESTAMP,
`updated_at` = CURRENT_TIMESTAMP
WHERE `status` IN ('requested', 'leased')
AND `id` <> (
SELECT newer.`id`
FROM `provisioning_operations` AS newer
WHERE newer.`tenant_id` = `provisioning_operations`.`tenant_id`
AND newer.`status` IN ('requested', 'leased')
ORDER BY newer.`created_at` DESC, newer.`id` DESC
LIMIT 1
);--> statement-breakpoint
CREATE UNIQUE INDEX `idx_operations_one_active_tenant` ON `provisioning_operations` (`tenant_id`) WHERE "provisioning_operations"."status" IN ('requested', 'leased');--> statement-breakpoint
CREATE INDEX `idx_operations_lease_expiry` ON `provisioning_operations` (`status`,`lease_expires_at`);--> statement-breakpoint
ALTER TABLE `tenant_instances` ADD `runtime_ref` text;--> statement-breakpoint
ALTER TABLE `tenant_instances` ADD `relay_origin` text;--> statement-breakpoint
ALTER TABLE `tenant_instances` ADD `secret_bundle_ref` text;--> statement-breakpoint
ALTER TABLE `tenant_instances` ADD `relay_ready` integer DEFAULT false NOT NULL;
+8
View File
@@ -0,0 +1,8 @@
ALTER TABLE `provisioning_operations` ADD `predecessor_id` text;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `credential_revision` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `fence_epoch` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
ALTER TABLE `provisioning_operations` ADD `result_version` integer;--> statement-breakpoint
ALTER TABLE `tenant_instances` ADD `desired_state` text DEFAULT 'requested' NOT NULL;--> statement-breakpoint
ALTER TABLE `tenant_instances` ADD `observed_state` text DEFAULT 'absent' NOT NULL;--> statement-breakpoint
ALTER TABLE `tenant_instances` ADD `credential_revision` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
ALTER TABLE `tenant_instances` ADD `tombstoned_at` text;
+16
View File
@@ -0,0 +1,16 @@
CREATE TABLE `beta_feedback` (
`id` text PRIMARY KEY NOT NULL,
`account_id` text NOT NULL,
`category` text NOT NULL,
`message` text NOT NULL,
`status` text DEFAULT 'open' NOT NULL,
`admin_response` text,
`handled_by` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`resolved_at` text,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `idx_beta_feedback_account_time` ON `beta_feedback` (`account_id`,`created_at`);--> statement-breakpoint
CREATE INDEX `idx_beta_feedback_status_time` ON `beta_feedback` (`status`,`created_at`);
+16
View File
@@ -0,0 +1,16 @@
CREATE TABLE `service_incidents` (
`id` text PRIMARY KEY NOT NULL,
`severity` text NOT NULL,
`title` text NOT NULL,
`message` text NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`created_by` text NOT NULL,
`resolved_by` text,
`resolution` text,
`started_at` text NOT NULL,
`resolved_at` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
);
--> statement-breakpoint
CREATE INDEX `idx_service_incidents_status_started` ON `service_incidents` (`status`,`started_at`);
+14
View File
@@ -0,0 +1,14 @@
CREATE TABLE `account_deletion_requests` (
`id` text PRIMARY KEY NOT NULL,
`account_id` text NOT NULL,
`status` text DEFAULT 'requested' NOT NULL,
`reason` text,
`requested_at` text NOT NULL,
`cancelled_at` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_account_deletion_one_requested` ON `account_deletion_requests` (`account_id`) WHERE "account_deletion_requests"."status" = 'requested';--> statement-breakpoint
CREATE INDEX `idx_account_deletion_status_time` ON `account_deletion_requests` (`status`,`requested_at`);
+9
View File
@@ -0,0 +1,9 @@
CREATE TABLE `provisioner_workers` (
`tenant_id` text PRIMARY KEY NOT NULL,
`worker_id` text NOT NULL,
`poll_count` integer DEFAULT 1 NOT NULL,
`last_seen_at` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
);
+16
View File
@@ -0,0 +1,16 @@
CREATE TABLE `maintenance_jobs` (
`key` text PRIMARY KEY NOT NULL,
`state` text NOT NULL,
`run_id` text,
`trigger` text,
`scheduled_at` text,
`started_at` text,
`completed_at` text,
`last_success_at` text,
`result_json` text,
`error_code` text,
`consecutive_failures` integer DEFAULT 0 NOT NULL,
`run_count` integer DEFAULT 0 NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
);
+22
View File
@@ -0,0 +1,22 @@
CREATE TABLE `beta_access_requests` (
`id` text PRIMARY KEY NOT NULL,
`account_id` text NOT NULL,
`status` text DEFAULT 'requested' NOT NULL,
`preferred_os` text NOT NULL,
`requested_slots` integer DEFAULT 1 NOT NULL,
`use_case` text NOT NULL,
`admin_response` text,
`resolved_by` text,
`invitation_grant_id` text,
`requested_at` text NOT NULL,
`resolved_at` text,
`cancelled_at` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`invitation_grant_id`) REFERENCES `entitlement_grants`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_beta_access_requests_one_pending` ON `beta_access_requests` (`account_id`) WHERE "beta_access_requests"."status" = 'requested';--> statement-breakpoint
CREATE INDEX `idx_beta_access_requests_status_time` ON `beta_access_requests` (`status`,`requested_at`);--> statement-breakpoint
CREATE INDEX `idx_beta_access_requests_account_time` ON `beta_access_requests` (`account_id`,`requested_at`);
+1
View File
@@ -0,0 +1 @@
CREATE INDEX `idx_beta_access_requests_requested_time` ON `beta_access_requests` (`requested_at`);
+182
View File
@@ -0,0 +1,182 @@
CREATE TABLE `relay_regions` (
`id` text PRIMARY KEY NOT NULL,
`code` text NOT NULL,
`display_name` text NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`public_origin` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_relay_regions_code` ON `relay_regions` (`code`);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_relay_regions_public_origin` ON `relay_regions` (`public_origin`);
--> statement-breakpoint
CREATE TABLE `relay_nodes` (
`id` text PRIMARY KEY NOT NULL,
`region_id` text NOT NULL,
`status` text DEFAULT 'provisioning' NOT NULL,
`internal_endpoint_ref` text NOT NULL,
`capacity_tenants` integer DEFAULT 0 NOT NULL,
`last_heartbeat_at` text,
`heartbeat_generation` integer DEFAULT 0 NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`region_id`) REFERENCES `relay_regions`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `idx_relay_nodes_region_status` ON `relay_nodes` (`region_id`,`status`);
--> statement-breakpoint
CREATE TABLE `tenant_placements` (
`tenant_id` text PRIMARY KEY NOT NULL,
`home_region_id` text NOT NULL,
`relay_node_id` text,
`generation` integer DEFAULT 1 NOT NULL,
`state` text DEFAULT 'provisioning' NOT NULL,
`last_error_code` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`home_region_id`) REFERENCES `relay_regions`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`relay_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `idx_tenant_placements_region_state` ON `tenant_placements` (`home_region_id`,`state`);
--> statement-breakpoint
CREATE INDEX `idx_tenant_placements_node_state` ON `tenant_placements` (`relay_node_id`,`state`);
--> statement-breakpoint
CREATE TABLE `tenant_authorization_state` (
`tenant_id` text PRIMARY KEY NOT NULL,
`revision` integer DEFAULT 0 NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `idx_tenant_authorization_revision` ON `tenant_authorization_state` (`revision`);
--> statement-breakpoint
CREATE TABLE `relay_signing_keys` (
`kid` text PRIMARY KEY NOT NULL,
`algorithm` text DEFAULT 'Ed25519' NOT NULL,
`public_key_jwk` text NOT NULL,
`private_key_ref` text NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`not_before` text NOT NULL,
`not_after` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`retired_at` text
);
--> statement-breakpoint
CREATE TABLE `relay_node_credentials` (
`id` text PRIMARY KEY NOT NULL,
`node_id` text NOT NULL,
`mtls_spiffe_id` text NOT NULL,
`certificate_fingerprint_sha256` text NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`bootstrap_reason` text NOT NULL,
`issued_by` text NOT NULL,
`issued_at` text NOT NULL,
`expires_at` text,
`last_used_at` text,
`revoked_at` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_relay_node_credentials_mtls` ON `relay_node_credentials` (`mtls_spiffe_id`,`certificate_fingerprint_sha256`);
--> statement-breakpoint
CREATE INDEX `idx_relay_node_credentials_node_status` ON `relay_node_credentials` (`node_id`,`status`);
--> statement-breakpoint
CREATE TABLE `phone_handoff_tickets` (
`id` text PRIMARY KEY NOT NULL,
`ticket_hash` text NOT NULL,
`account_id` text NOT NULL,
`tenant_id` text NOT NULL,
`expected_origin` text NOT NULL,
`expires_at` text NOT NULL,
`consumed_at` text,
`consumed_by_node_id` text,
`pending_phone_name` text,
`pending_ed25519_public` text,
`pending_x25519_public` text,
`pending_identity_fingerprint` text,
`completed_at` text,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`consumed_by_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_phone_handoff_ticket_hash` ON `phone_handoff_tickets` (`ticket_hash`);
--> statement-breakpoint
CREATE INDEX `idx_phone_handoff_account_expiry` ON `phone_handoff_tickets` (`account_id`,`expires_at`);
--> statement-breakpoint
CREATE TABLE `phone_route_handles` (
`id` text PRIMARY KEY NOT NULL,
`handle_hash` text NOT NULL,
`tenant_id` text NOT NULL,
`phone_id` text NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`last_used_at` text,
`revoked_at` text,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_phone_route_handle_hash` ON `phone_route_handles` (`handle_hash`);
--> statement-breakpoint
CREATE INDEX `idx_phone_route_tenant_status` ON `phone_route_handles` (`tenant_id`,`status`);
--> statement-breakpoint
CREATE TABLE `relay_phone_principals` (
`phone_id` text PRIMARY KEY NOT NULL,
`tenant_id` text NOT NULL,
`token_hash` text NOT NULL,
`name` text NOT NULL,
`ed25519_public` text NOT NULL,
`x25519_public` text NOT NULL,
`identity_fingerprint` text NOT NULL,
`status` text DEFAULT 'active' NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
`last_used_at` text,
`revoked_at` text,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_relay_phone_token_hash` ON `relay_phone_principals` (`token_hash`);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_relay_phone_tenant_identity` ON `relay_phone_principals` (`tenant_id`,`identity_fingerprint`);
--> statement-breakpoint
CREATE INDEX `idx_relay_phone_tenant_status` ON `relay_phone_principals` (`tenant_id`,`status`);
--> statement-breakpoint
CREATE TABLE `device_registration_replays` (
`pairing_id` text PRIMARY KEY NOT NULL,
`request_hash` text NOT NULL,
`response_ciphertext` text NOT NULL,
`response_nonce` text NOT NULL,
`expires_at` text NOT NULL,
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (`pairing_id`) REFERENCES `pairing_requests`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `idx_device_registration_replay_expiry` ON `device_registration_replays` (`expires_at`);
--> statement-breakpoint
INSERT OR IGNORE INTO `relay_regions`
(`id`, `code`, `display_name`, `status`, `public_origin`, `created_at`, `updated_at`)
VALUES
('region_default', 'default', 'Default region', 'active', 'https://connect.invalid', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
--> statement-breakpoint
INSERT OR IGNORE INTO `tenant_placements`
(`tenant_id`, `home_region_id`, `generation`, `state`, `created_at`, `updated_at`)
SELECT `id`, 'region_default', 1, 'provisioning', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
FROM `tenant_instances`;
--> statement-breakpoint
DROP TABLE IF EXISTS `provisioner_workers`;
--> statement-breakpoint
DROP TABLE IF EXISTS `provisioning_operations`;
--> statement-breakpoint
INSERT OR IGNORE INTO `tenant_authorization_state`
(`tenant_id`, `revision`, `status`, `updated_at`)
SELECT `id`, `credential_revision`,
CASE WHEN `tombstoned_at` IS NULL THEN 'active' ELSE 'suspended' END,
CURRENT_TIMESTAMP
FROM `tenant_instances`;
+34
View File
@@ -0,0 +1,34 @@
CREATE TABLE `relay_migrations` (
`id` text PRIMARY KEY NOT NULL,
`tenant_id` text NOT NULL,
`source_node_id` text NOT NULL,
`target_node_id` text NOT NULL,
`source_generation` integer NOT NULL,
`target_generation` integer NOT NULL,
`state` text DEFAULT 'quiescing' NOT NULL,
`backup_ref` text,
`manifest_sha256` text,
`requested_by` text NOT NULL,
`reason` text NOT NULL,
`started_at` text NOT NULL,
`updated_at` text NOT NULL,
`switched_at` text,
`completed_at` text,
`last_error_code` text,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`source_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`target_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action,
CHECK (`target_generation` = `source_generation` + 1),
CHECK (`source_node_id` <> `target_node_id`),
CHECK (`state` IN ('quiescing', 'copying', 'switching', 'draining', 'completed', 'failed'))
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_relay_migrations_one_active`
ON `relay_migrations` (`tenant_id`)
WHERE `state` IN ('quiescing', 'copying', 'switching', 'draining');
--> statement-breakpoint
CREATE INDEX `idx_relay_migrations_source_state`
ON `relay_migrations` (`source_node_id`, `state`, `updated_at`);
--> statement-breakpoint
CREATE INDEX `idx_relay_migrations_target_state`
ON `relay_migrations` (`target_node_id`, `state`, `updated_at`);
+26
View File
@@ -0,0 +1,26 @@
CREATE TABLE `relay_purge_jobs` (
`id` text PRIMARY KEY NOT NULL,
`deletion_request_id` text NOT NULL,
`tenant_id` text NOT NULL,
`relay_node_id` text NOT NULL,
`placement_generation` integer NOT NULL,
`state` text DEFAULT 'quiescing' NOT NULL,
`requested_by` text NOT NULL,
`reason` text NOT NULL,
`started_at` text NOT NULL,
`updated_at` text NOT NULL,
`completed_at` text,
`evidence_sha256` text,
`last_error_code` text,
FOREIGN KEY (`deletion_request_id`) REFERENCES `account_deletion_requests`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`relay_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action,
CONSTRAINT `relay_purge_generation_positive` CHECK (`placement_generation` > 0),
CONSTRAINT `relay_purge_state_valid` CHECK (`state` IN ('quiescing', 'completed', 'failed'))
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_relay_purge_deletion_request` ON `relay_purge_jobs` (`deletion_request_id`);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_relay_purge_tenant` ON `relay_purge_jobs` (`tenant_id`);
--> statement-breakpoint
CREATE INDEX `idx_relay_purge_node_state` ON `relay_purge_jobs` (`relay_node_id`,`state`,`updated_at`);
@@ -0,0 +1,5 @@
ALTER TABLE `phone_handoff_tickets` ADD `completed_phone_id` text;
--> statement-breakpoint
ALTER TABLE `phone_handoff_tickets` ADD `completed_phone_token_hash` text;
--> statement-breakpoint
ALTER TABLE `phone_handoff_tickets` ADD `completed_route_handle_hash` text;
@@ -0,0 +1,6 @@
ALTER TABLE `phone_handoff_tickets` ADD `activation_nonce` text;
--> statement-breakpoint
ALTER TABLE `phone_handoff_tickets` ADD `activated_at` text;
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_phone_handoff_activation_nonce`
ON `phone_handoff_tickets` (`activation_nonce`);
+111
View File
@@ -0,0 +1,111 @@
CREATE TRIGGER `provisioning_queue_guard`
BEFORE INSERT ON `provisioning_operations`
WHEN NEW.`status` = 'requested'
BEGIN
SELECT CASE WHEN NOT EXISTS (
SELECT 1
FROM `tenant_instances`
WHERE `id` = NEW.`tenant_id`
AND `desired_generation` + 1 = NEW.`target_generation`
AND `credential_revision` = NEW.`credential_revision`
AND `tombstoned_at` IS NULL
AND (
(NEW.`operation` = 'ensure' AND `lifecycle` IN ('requested', 'failed', 'degraded'))
OR (NEW.`operation` = 'suspend' AND `lifecycle` IN ('ready', 'degraded'))
OR (NEW.`operation` = 'resume' AND `lifecycle` IN ('suspended', 'failed'))
OR (NEW.`operation` = 'deprovision' AND `lifecycle` IN ('requested', 'ready', 'suspended', 'failed', 'degraded'))
)
) THEN RAISE(ABORT, 'invalid_provisioning_transition') END;
END;--> statement-breakpoint
CREATE TRIGGER `provisioning_queue_tenant_update`
AFTER INSERT ON `provisioning_operations`
WHEN NEW.`status` = 'requested'
BEGIN
UPDATE `tenant_instances`
SET `lifecycle` = CASE NEW.`operation`
WHEN 'suspend' THEN 'suspending'
WHEN 'deprovision' THEN 'deprovisioning'
ELSE 'provisioning'
END,
`desired_state` = CASE NEW.`operation`
WHEN 'suspend' THEN 'suspended'
WHEN 'deprovision' THEN 'deleted'
ELSE 'running'
END,
`desired_generation` = NEW.`target_generation`,
`relay_ready` = 0,
`updated_at` = NEW.`created_at`
WHERE `id` = NEW.`tenant_id`;
END;--> statement-breakpoint
CREATE TRIGGER `provisioning_completion_guard`
BEFORE UPDATE OF `status` ON `provisioning_operations`
WHEN OLD.`status` IN ('requested', 'leased') AND NEW.`status` IN ('succeeded', 'failed')
BEGIN
SELECT CASE WHEN NOT EXISTS (
SELECT 1
FROM `tenant_instances`
WHERE `id` = OLD.`tenant_id`
AND `desired_generation` = OLD.`target_generation`
AND (
NEW.`status` = 'failed'
OR `credential_revision` = OLD.`credential_revision`
)
) THEN RAISE(ABORT, 'stale_provisioning_generation') END;
END;--> statement-breakpoint
CREATE TRIGGER `provisioning_completion_tenant_update`
AFTER UPDATE OF `status` ON `provisioning_operations`
WHEN OLD.`status` IN ('requested', 'leased') AND NEW.`status` IN ('succeeded', 'failed')
BEGIN
UPDATE `tenant_instances`
SET `lifecycle` = CASE
WHEN NEW.`status` = 'failed' AND NEW.`operation` IN ('ensure', 'resume') THEN 'failed'
WHEN NEW.`status` = 'failed' THEN 'degraded'
WHEN NEW.`operation` IN ('ensure', 'resume') THEN 'ready'
WHEN NEW.`operation` = 'suspend' THEN 'suspended'
ELSE 'deleted'
END,
`observed_state` = CASE
WHEN NEW.`status` = 'failed' THEN `observed_state`
WHEN NEW.`operation` IN ('ensure', 'resume') THEN 'running'
WHEN NEW.`operation` = 'suspend' THEN 'suspended'
ELSE 'absent'
END,
`active_generation` = CASE
WHEN NEW.`status` = 'succeeded' THEN NEW.`target_generation`
ELSE `active_generation`
END,
`runtime_version` = CASE
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` IN ('ensure', 'resume') THEN NEW.`result_runtime_version`
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NULL
ELSE `runtime_version`
END,
`runtime_ref` = CASE
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` IN ('ensure', 'resume') THEN NEW.`result_runtime_ref`
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NULL
ELSE `runtime_ref`
END,
`relay_origin` = CASE
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` IN ('ensure', 'resume') THEN NEW.`result_relay_origin`
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NULL
ELSE `relay_origin`
END,
`secret_bundle_ref` = CASE
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` IN ('ensure', 'resume') THEN NEW.`result_secret_bundle_ref`
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NULL
ELSE `secret_bundle_ref`
END,
`last_health_at` = CASE
WHEN NEW.`status` = 'succeeded' THEN NEW.`health_checked_at`
ELSE `last_health_at`
END,
`tombstoned_at` = CASE
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NEW.`completed_at`
ELSE `tombstoned_at`
END,
`relay_ready` = 0,
`updated_at` = NEW.`completed_at`
WHERE `id` = NEW.`tenant_id`;
END;
@@ -0,0 +1,24 @@
INSERT OR IGNORE INTO `audit_events`
(`id`, `actor_id`, `action`, `target_type`, `target_id`, `reason`,
`before_json`, `after_json`, `correlation_id`, `created_at`)
SELECT 'audit_slug_backfill_' || `id`,
'system:migration',
'tenant.slug_backfilled',
'tenant',
`id`,
'旧版短租户 slug 不满足隔离域名契约,按不可变 tenant ID 扩展',
json_object('slug', `slug`),
json_object('slug', 'n-' || substr(`id`, -32)),
'corr_slug_backfill_' || `id`,
CURRENT_TIMESTAMP
FROM `tenant_instances`
WHERE `id` LIKE 'tenant_%'
AND length(`id`) = 39
AND (`slug` NOT LIKE 'n-%' OR length(`slug`) <> 34);--> statement-breakpoint
UPDATE `tenant_instances`
SET `slug` = 'n-' || substr(`id`, -32),
`updated_at` = CURRENT_TIMESTAMP
WHERE `id` LIKE 'tenant_%'
AND length(`id`) = 39
AND (`slug` NOT LIKE 'n-%' OR length(`slug`) <> 34);
@@ -0,0 +1,21 @@
DROP TRIGGER IF EXISTS `provisioning_queue_guard`;--> statement-breakpoint
CREATE TRIGGER `provisioning_queue_guard`
BEFORE INSERT ON `provisioning_operations`
WHEN NEW.`status` = 'requested'
BEGIN
SELECT CASE WHEN NOT EXISTS (
SELECT 1
FROM `tenant_instances`
WHERE `id` = NEW.`tenant_id`
AND `desired_generation` + 1 = NEW.`target_generation`
AND `credential_revision` = NEW.`credential_revision`
AND `tombstoned_at` IS NULL
AND (
(NEW.`operation` = 'ensure' AND `lifecycle` IN ('requested', 'ready', 'failed', 'degraded'))
OR (NEW.`operation` = 'suspend' AND `lifecycle` IN ('ready', 'degraded'))
OR (NEW.`operation` = 'resume' AND `lifecycle` IN ('suspended', 'failed'))
OR (NEW.`operation` = 'deprovision' AND `lifecycle` IN ('requested', 'ready', 'suspended', 'failed', 'degraded'))
)
) THEN RAISE(ABORT, 'invalid_provisioning_transition') END;
END;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+97
View File
@@ -0,0 +1,97 @@
{
"version": "7",
"dialect": "sqlite",
"entries": [
{
"idx": 0,
"version": "6",
"when": 1786458686828,
"tag": "0000_condemned_legion",
"breakpoints": true
},
{
"idx": 1,
"version": "6",
"when": 1786471272276,
"tag": "0001_mushy_vance_astro",
"breakpoints": true
},
{
"idx": 2,
"version": "6",
"when": 1786473834384,
"tag": "0002_wild_ravenous",
"breakpoints": true
},
{
"idx": 3,
"version": "6",
"when": 1786474656600,
"tag": "0003_medical_rocket_racer",
"breakpoints": true
},
{
"idx": 4,
"version": "6",
"when": 1786474813520,
"tag": "0004_loud_prodigy",
"breakpoints": true
},
{
"idx": 5,
"version": "6",
"when": 1786488227508,
"tag": "0005_pale_corsair",
"breakpoints": true
},
{
"idx": 6,
"version": "6",
"when": 1786490421386,
"tag": "0006_clever_shocker",
"breakpoints": true
},
{
"idx": 7,
"version": "6",
"when": 1786491408443,
"tag": "0007_zippy_nomad",
"breakpoints": true
},
{
"idx": 8,
"version": "6",
"when": 1786499791158,
"tag": "0008_far_justice",
"breakpoints": true
},
{
"idx": 9,
"version": "6",
"when": 1786500924681,
"tag": "0009_flat_robbie_robertson",
"breakpoints": true
},
{
"idx": 10,
"version": "6",
"when": 1786504111648,
"tag": "0010_windy_toxin",
"breakpoints": true
},
{
"idx": 11,
"version": "6",
"when": 1786506592910,
"tag": "0011_next_thunderball",
"breakpoints": true
},
{
"idx": 12,
"version": "6",
"when": 1786520000000,
"tag": "0012_shared_relay_control_plane",
"breakpoints": true
}
]
}