@electric-ax/agents-server 0.3.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 (68) hide show
  1. package/LICENSE +177 -0
  2. package/dist/chunk-Cl8Af3a2.js +11 -0
  3. package/dist/entrypoint.js +7319 -0
  4. package/dist/index.cjs +7090 -0
  5. package/dist/index.d.cts +4262 -0
  6. package/dist/index.d.ts +4263 -0
  7. package/dist/index.js +7053 -0
  8. package/drizzle/0000_baseline.sql +97 -0
  9. package/drizzle/0001_entity_tags_and_bridges.sql +45 -0
  10. package/drizzle/0002_tag_outbox_hardening.sql +14 -0
  11. package/drizzle/0003_entity_manifest_sources.sql +11 -0
  12. package/drizzle/0004_tenant_scoping.sql +139 -0
  13. package/drizzle/0005_pull_wake_control_plane.sql +156 -0
  14. package/drizzle/meta/0000_snapshot.json +593 -0
  15. package/drizzle/meta/_journal.json +48 -0
  16. package/package.json +89 -0
  17. package/src/authenticated-user-format.ts +17 -0
  18. package/src/claim-write-token-store.ts +74 -0
  19. package/src/db/index.ts +53 -0
  20. package/src/db/schema.ts +490 -0
  21. package/src/dev-asserted-auth.ts +46 -0
  22. package/src/dispatch-policy-schema.ts +52 -0
  23. package/src/electric-agents/adapter-types.ts +70 -0
  24. package/src/electric-agents/default-entity-schemas.ts +1 -0
  25. package/src/electric-agents/schema-validator.ts +143 -0
  26. package/src/electric-agents-http.ts +46 -0
  27. package/src/electric-agents-types.ts +335 -0
  28. package/src/entity-bridge-manager.ts +694 -0
  29. package/src/entity-manager.ts +2601 -0
  30. package/src/entity-projector.ts +765 -0
  31. package/src/entity-registry.ts +1162 -0
  32. package/src/entrypoint-lib.ts +295 -0
  33. package/src/entrypoint.ts +11 -0
  34. package/src/host.ts +323 -0
  35. package/src/index.ts +49 -0
  36. package/src/manifest-side-effects.ts +183 -0
  37. package/src/routing/agent-ui-router.ts +81 -0
  38. package/src/routing/context.ts +35 -0
  39. package/src/routing/cron-router.ts +45 -0
  40. package/src/routing/dispatch-policy.ts +248 -0
  41. package/src/routing/durable-streams-router.ts +407 -0
  42. package/src/routing/durable-streams-routing-adapter.ts +96 -0
  43. package/src/routing/electric-proxy-router.ts +61 -0
  44. package/src/routing/entities-router.ts +484 -0
  45. package/src/routing/entity-types-router.ts +229 -0
  46. package/src/routing/global-router.ts +33 -0
  47. package/src/routing/hooks.ts +123 -0
  48. package/src/routing/internal-router.ts +741 -0
  49. package/src/routing/oss-server-router.ts +56 -0
  50. package/src/routing/runners-router.ts +416 -0
  51. package/src/routing/schema.ts +141 -0
  52. package/src/routing/stream-append.ts +196 -0
  53. package/src/routing/tenant-stream-paths.ts +26 -0
  54. package/src/runtime-registry.ts +49 -0
  55. package/src/runtime.ts +537 -0
  56. package/src/scheduler.ts +788 -0
  57. package/src/schema-validation.ts +15 -0
  58. package/src/server.ts +374 -0
  59. package/src/standalone-runtime.ts +188 -0
  60. package/src/stream-client.ts +842 -0
  61. package/src/tag-stream-outbox-drainer.ts +188 -0
  62. package/src/tenant.ts +25 -0
  63. package/src/tracing.ts +57 -0
  64. package/src/utils/electric-url.ts +15 -0
  65. package/src/utils/log.ts +95 -0
  66. package/src/utils/server-utils.ts +245 -0
  67. package/src/utils/webhook-url.ts +33 -0
  68. package/src/wake-registry.ts +946 -0
@@ -0,0 +1,97 @@
1
+ CREATE TABLE "consumer_callbacks" (
2
+ "consumer_id" text PRIMARY KEY NOT NULL,
3
+ "callback_url" text NOT NULL,
4
+ "primary_stream" text,
5
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
6
+ );
7
+ --> statement-breakpoint
8
+ CREATE TABLE "entities" (
9
+ "url" text PRIMARY KEY NOT NULL,
10
+ "type" text NOT NULL,
11
+ "status" text DEFAULT 'idle' NOT NULL,
12
+ "subscription_id" text NOT NULL,
13
+ "write_token" text NOT NULL,
14
+ "metadata" jsonb DEFAULT '{}'::jsonb,
15
+ "spawn_args" jsonb DEFAULT '{}'::jsonb,
16
+ "parent" text,
17
+ "type_revision" integer,
18
+ "inbox_schemas" jsonb,
19
+ "state_schemas" jsonb,
20
+ "metadata_schema" jsonb,
21
+ "created_at" bigint NOT NULL,
22
+ "updated_at" bigint NOT NULL,
23
+ CONSTRAINT "chk_entities_status" CHECK ("entities"."status" IN ('spawning', 'running', 'idle', 'stopped'))
24
+ );
25
+ --> statement-breakpoint
26
+ CREATE TABLE "entity_types" (
27
+ "name" text PRIMARY KEY NOT NULL,
28
+ "description" text NOT NULL,
29
+ "creation_schema" jsonb,
30
+ "inbox_schemas" jsonb,
31
+ "state_schemas" jsonb,
32
+ "metadata_schema" jsonb,
33
+ "serve_endpoint" text,
34
+ "revision" integer DEFAULT 1 NOT NULL,
35
+ "created_at" text NOT NULL,
36
+ "updated_at" text NOT NULL
37
+ );
38
+ --> statement-breakpoint
39
+ CREATE TABLE "scheduled_tasks" (
40
+ "id" bigserial PRIMARY KEY NOT NULL,
41
+ "kind" text NOT NULL,
42
+ "payload" jsonb NOT NULL,
43
+ "fire_at" timestamp with time zone NOT NULL,
44
+ "cron_expression" text,
45
+ "cron_timezone" text,
46
+ "cron_tick_number" integer,
47
+ "owner_entity_url" text,
48
+ "manifest_key" text,
49
+ "claimed_by" text,
50
+ "claimed_at" timestamp with time zone,
51
+ "completed_at" timestamp with time zone,
52
+ "last_error" text,
53
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
54
+ CONSTRAINT "uq_cron_tick" UNIQUE("cron_expression","cron_timezone","cron_tick_number"),
55
+ CONSTRAINT "chk_scheduled_tasks_kind" CHECK ("scheduled_tasks"."kind" IN ('delayed_send', 'cron_tick'))
56
+ );
57
+ --> statement-breakpoint
58
+ CREATE TABLE "subscription_webhooks" (
59
+ "subscription_id" text PRIMARY KEY NOT NULL,
60
+ "webhook_url" text NOT NULL,
61
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
62
+ );
63
+ --> statement-breakpoint
64
+ CREATE TABLE "wake_registrations" (
65
+ "id" serial PRIMARY KEY NOT NULL,
66
+ "subscriber_url" text NOT NULL,
67
+ "source_url" text NOT NULL,
68
+ "condition" jsonb NOT NULL,
69
+ "debounce_ms" integer DEFAULT 0 NOT NULL,
70
+ "timeout_ms" integer DEFAULT 0 NOT NULL,
71
+ "one_shot" boolean DEFAULT false NOT NULL,
72
+ "timeout_consumed" boolean DEFAULT false NOT NULL,
73
+ "include_response" boolean DEFAULT true NOT NULL,
74
+ "manifest_key" text,
75
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
76
+ CONSTRAINT "uq_wake_registration" UNIQUE("subscriber_url","source_url","one_shot","debounce_ms","timeout_ms","condition","manifest_key")
77
+ );
78
+ --> statement-breakpoint
79
+ CREATE OR REPLACE FUNCTION notify_scheduled_tasks_wake() RETURNS trigger AS $$
80
+ BEGIN
81
+ PERFORM pg_notify('scheduled_tasks_wake', '');
82
+ RETURN NEW;
83
+ END;
84
+ $$ LANGUAGE plpgsql;
85
+ --> statement-breakpoint
86
+ CREATE TRIGGER scheduled_tasks_notify
87
+ AFTER INSERT ON "scheduled_tasks"
88
+ FOR EACH ROW
89
+ EXECUTE FUNCTION notify_scheduled_tasks_wake();
90
+ --> statement-breakpoint
91
+ CREATE INDEX "idx_entities_type" ON "entities" USING btree ("type");--> statement-breakpoint
92
+ CREATE INDEX "idx_entities_status" ON "entities" USING btree ("status");--> statement-breakpoint
93
+ CREATE INDEX "idx_entities_parent" ON "entities" USING btree ("parent");--> statement-breakpoint
94
+ CREATE INDEX "idx_scheduled_tasks_fire_ready" ON "scheduled_tasks" USING btree ("fire_at") WHERE "scheduled_tasks"."completed_at" IS NULL AND "scheduled_tasks"."claimed_at" IS NULL;--> statement-breakpoint
95
+ CREATE INDEX "idx_scheduled_tasks_manifest_pending" ON "scheduled_tasks" USING btree ("owner_entity_url","manifest_key") WHERE "scheduled_tasks"."kind" = 'delayed_send' AND "scheduled_tasks"."completed_at" IS NULL AND "scheduled_tasks"."manifest_key" IS NOT NULL;--> statement-breakpoint
96
+ CREATE INDEX "idx_scheduled_tasks_stale_claims" ON "scheduled_tasks" USING btree ("claimed_at") WHERE "scheduled_tasks"."completed_at" IS NULL AND "scheduled_tasks"."claimed_at" IS NOT NULL;--> statement-breakpoint
97
+ CREATE INDEX "idx_wake_source_url" ON "wake_registrations" USING btree ("source_url");
@@ -0,0 +1,45 @@
1
+ -- tags_index is a text[] shadow of tags jsonb. Electric shape `where` supports
2
+ -- `@>` on text[] but not on jsonb, so membership queries for
3
+ -- observe(entities({ tags })) must scan tags_index.
4
+ ALTER TABLE entities
5
+ DROP COLUMN metadata,
6
+ ADD COLUMN tags jsonb NOT NULL DEFAULT '{}'::jsonb,
7
+ ADD COLUMN tags_index text[] NOT NULL DEFAULT '{}'::text[];
8
+
9
+ CREATE INDEX entities_tags_index_gin ON entities USING gin (tags_index);
10
+
11
+ -- REPLICA IDENTITY FULL is required so Electric's logical replication emits
12
+ -- full-row payloads on UPDATE/DELETE. Without it, shape consumers can't
13
+ -- compute diffs and bridge reconcile breaks.
14
+ ALTER TABLE entities REPLICA IDENTITY FULL;
15
+
16
+ CREATE TABLE entity_bridges (
17
+ source_ref text PRIMARY KEY,
18
+ tags jsonb NOT NULL,
19
+ stream_url text NOT NULL UNIQUE,
20
+ shape_handle text,
21
+ shape_offset text,
22
+ last_observer_activity_at timestamptz NOT NULL DEFAULT now(),
23
+ created_at timestamptz NOT NULL DEFAULT now(),
24
+ updated_at timestamptz NOT NULL DEFAULT now()
25
+ );
26
+
27
+ CREATE TABLE tag_stream_outbox (
28
+ id bigserial PRIMARY KEY,
29
+ entity_url text NOT NULL,
30
+ collection text NOT NULL,
31
+ op text NOT NULL,
32
+ key text NOT NULL,
33
+ row_data jsonb,
34
+ claimed_by text,
35
+ claimed_at timestamptz,
36
+ created_at timestamptz NOT NULL DEFAULT now()
37
+ );
38
+
39
+ CREATE INDEX idx_tag_stream_outbox_unclaimed
40
+ ON tag_stream_outbox (created_at)
41
+ WHERE claimed_at IS NULL;
42
+
43
+ CREATE INDEX idx_tag_stream_outbox_stale_claims
44
+ ON tag_stream_outbox (claimed_at)
45
+ WHERE claimed_at IS NOT NULL;
@@ -0,0 +1,14 @@
1
+ ALTER TABLE tag_stream_outbox
2
+ ADD COLUMN attempt_count integer NOT NULL DEFAULT 0,
3
+ ADD COLUMN last_error text,
4
+ ADD COLUMN dead_lettered_at timestamptz;
5
+
6
+ DROP INDEX IF EXISTS idx_tag_stream_outbox_unclaimed;
7
+ CREATE INDEX idx_tag_stream_outbox_unclaimed
8
+ ON tag_stream_outbox (created_at)
9
+ WHERE claimed_at IS NULL AND dead_lettered_at IS NULL;
10
+
11
+ DROP INDEX IF EXISTS idx_tag_stream_outbox_stale_claims;
12
+ CREATE INDEX idx_tag_stream_outbox_stale_claims
13
+ ON tag_stream_outbox (claimed_at)
14
+ WHERE claimed_at IS NOT NULL AND dead_lettered_at IS NULL;
@@ -0,0 +1,11 @@
1
+ CREATE TABLE entity_manifest_sources (
2
+ owner_entity_url text NOT NULL,
3
+ manifest_key text NOT NULL,
4
+ source_ref text NOT NULL,
5
+ created_at timestamptz NOT NULL DEFAULT now(),
6
+ updated_at timestamptz NOT NULL DEFAULT now(),
7
+ CONSTRAINT uq_entity_manifest_source UNIQUE (owner_entity_url, manifest_key)
8
+ );
9
+
10
+ CREATE INDEX idx_entity_manifest_sources_source_ref
11
+ ON entity_manifest_sources (source_ref);
@@ -0,0 +1,139 @@
1
+ ALTER TABLE entity_types
2
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
3
+ --> statement-breakpoint
4
+ ALTER TABLE entities
5
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
6
+ --> statement-breakpoint
7
+ ALTER TABLE wake_registrations
8
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
9
+ --> statement-breakpoint
10
+ ALTER TABLE subscription_webhooks
11
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
12
+ --> statement-breakpoint
13
+ ALTER TABLE consumer_callbacks
14
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
15
+ --> statement-breakpoint
16
+ ALTER TABLE scheduled_tasks
17
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
18
+ --> statement-breakpoint
19
+ ALTER TABLE entity_bridges
20
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
21
+ --> statement-breakpoint
22
+ ALTER TABLE entity_manifest_sources
23
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
24
+ --> statement-breakpoint
25
+ ALTER TABLE tag_stream_outbox
26
+ ADD COLUMN tenant_id text NOT NULL DEFAULT 'default';
27
+ --> statement-breakpoint
28
+ ALTER TABLE entity_types
29
+ DROP CONSTRAINT entity_types_pkey,
30
+ ADD CONSTRAINT entity_types_pkey PRIMARY KEY (tenant_id, name);
31
+ --> statement-breakpoint
32
+ ALTER TABLE entities
33
+ DROP CONSTRAINT entities_pkey,
34
+ ADD CONSTRAINT entities_pkey PRIMARY KEY (tenant_id, url);
35
+ --> statement-breakpoint
36
+ ALTER TABLE subscription_webhooks
37
+ DROP CONSTRAINT subscription_webhooks_pkey,
38
+ ADD CONSTRAINT subscription_webhooks_pkey PRIMARY KEY (tenant_id, subscription_id);
39
+ --> statement-breakpoint
40
+ ALTER TABLE consumer_callbacks
41
+ DROP CONSTRAINT consumer_callbacks_pkey,
42
+ ADD CONSTRAINT consumer_callbacks_pkey PRIMARY KEY (tenant_id, consumer_id);
43
+ --> statement-breakpoint
44
+ ALTER TABLE entity_bridges
45
+ DROP CONSTRAINT entity_bridges_pkey,
46
+ DROP CONSTRAINT IF EXISTS entity_bridges_stream_url_unique,
47
+ DROP CONSTRAINT IF EXISTS entity_bridges_stream_url_key,
48
+ ADD CONSTRAINT entity_bridges_pkey PRIMARY KEY (tenant_id, source_ref),
49
+ ADD CONSTRAINT uq_entity_bridges_stream_url UNIQUE (tenant_id, stream_url);
50
+ --> statement-breakpoint
51
+ ALTER TABLE wake_registrations
52
+ DROP CONSTRAINT uq_wake_registration,
53
+ ADD CONSTRAINT uq_wake_registration UNIQUE (
54
+ tenant_id,
55
+ subscriber_url,
56
+ source_url,
57
+ one_shot,
58
+ debounce_ms,
59
+ timeout_ms,
60
+ condition,
61
+ manifest_key
62
+ );
63
+ --> statement-breakpoint
64
+ ALTER TABLE scheduled_tasks
65
+ DROP CONSTRAINT uq_cron_tick,
66
+ ADD CONSTRAINT uq_cron_tick UNIQUE (
67
+ tenant_id,
68
+ cron_expression,
69
+ cron_timezone,
70
+ cron_tick_number
71
+ );
72
+ --> statement-breakpoint
73
+ ALTER TABLE entity_manifest_sources
74
+ DROP CONSTRAINT uq_entity_manifest_source,
75
+ ADD CONSTRAINT uq_entity_manifest_source UNIQUE (
76
+ tenant_id,
77
+ owner_entity_url,
78
+ manifest_key
79
+ );
80
+ --> statement-breakpoint
81
+ DROP INDEX IF EXISTS idx_entities_type;
82
+ --> statement-breakpoint
83
+ DROP INDEX IF EXISTS idx_entities_status;
84
+ --> statement-breakpoint
85
+ DROP INDEX IF EXISTS idx_entities_parent;
86
+ --> statement-breakpoint
87
+ DROP INDEX IF EXISTS idx_wake_source_url;
88
+ --> statement-breakpoint
89
+ DROP INDEX IF EXISTS idx_scheduled_tasks_fire_ready;
90
+ --> statement-breakpoint
91
+ DROP INDEX IF EXISTS idx_scheduled_tasks_manifest_pending;
92
+ --> statement-breakpoint
93
+ DROP INDEX IF EXISTS idx_scheduled_tasks_stale_claims;
94
+ --> statement-breakpoint
95
+ DROP INDEX IF EXISTS idx_entity_manifest_sources_source_ref;
96
+ --> statement-breakpoint
97
+ DROP INDEX IF EXISTS idx_tag_stream_outbox_unclaimed;
98
+ --> statement-breakpoint
99
+ DROP INDEX IF EXISTS idx_tag_stream_outbox_stale_claims;
100
+ --> statement-breakpoint
101
+ CREATE INDEX idx_entities_type
102
+ ON entities (tenant_id, type);
103
+ --> statement-breakpoint
104
+ CREATE INDEX idx_entities_status
105
+ ON entities (tenant_id, status);
106
+ --> statement-breakpoint
107
+ CREATE INDEX idx_entities_parent
108
+ ON entities (tenant_id, parent);
109
+ --> statement-breakpoint
110
+ CREATE INDEX idx_wake_source_url
111
+ ON wake_registrations (tenant_id, source_url);
112
+ --> statement-breakpoint
113
+ CREATE INDEX idx_consumer_callbacks_primary_stream
114
+ ON consumer_callbacks (tenant_id, primary_stream);
115
+ --> statement-breakpoint
116
+ CREATE INDEX idx_scheduled_tasks_fire_ready
117
+ ON scheduled_tasks (tenant_id, fire_at)
118
+ WHERE completed_at IS NULL AND claimed_at IS NULL;
119
+ --> statement-breakpoint
120
+ CREATE INDEX idx_scheduled_tasks_manifest_pending
121
+ ON scheduled_tasks (tenant_id, owner_entity_url, manifest_key)
122
+ WHERE kind = 'delayed_send'
123
+ AND completed_at IS NULL
124
+ AND manifest_key IS NOT NULL;
125
+ --> statement-breakpoint
126
+ CREATE INDEX idx_scheduled_tasks_stale_claims
127
+ ON scheduled_tasks (tenant_id, claimed_at)
128
+ WHERE completed_at IS NULL AND claimed_at IS NOT NULL;
129
+ --> statement-breakpoint
130
+ CREATE INDEX idx_entity_manifest_sources_source_ref
131
+ ON entity_manifest_sources (tenant_id, source_ref);
132
+ --> statement-breakpoint
133
+ CREATE INDEX idx_tag_stream_outbox_unclaimed
134
+ ON tag_stream_outbox (tenant_id, created_at)
135
+ WHERE claimed_at IS NULL AND dead_lettered_at IS NULL;
136
+ --> statement-breakpoint
137
+ CREATE INDEX idx_tag_stream_outbox_stale_claims
138
+ ON tag_stream_outbox (tenant_id, claimed_at)
139
+ WHERE claimed_at IS NOT NULL AND dead_lettered_at IS NULL;
@@ -0,0 +1,156 @@
1
+ ALTER TABLE entity_types
2
+ ADD COLUMN default_dispatch_policy jsonb;
3
+ --> statement-breakpoint
4
+ ALTER TABLE entities
5
+ ADD COLUMN dispatch_policy jsonb;
6
+ --> statement-breakpoint
7
+ CREATE TABLE users (
8
+ tenant_id text NOT NULL DEFAULT 'default',
9
+ id text NOT NULL,
10
+ display_name text,
11
+ email text,
12
+ avatar_url text,
13
+ auth_provider text,
14
+ auth_subject text,
15
+ profile jsonb NOT NULL DEFAULT '{}'::jsonb,
16
+ metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
17
+ created_at timestamptz NOT NULL DEFAULT now(),
18
+ updated_at timestamptz NOT NULL DEFAULT now(),
19
+ PRIMARY KEY (tenant_id, id)
20
+ );
21
+ --> statement-breakpoint
22
+ CREATE INDEX idx_users_email ON users (tenant_id, email);
23
+ --> statement-breakpoint
24
+ CREATE INDEX idx_users_auth_identity
25
+ ON users (tenant_id, auth_provider, auth_subject);
26
+ --> statement-breakpoint
27
+ CREATE TABLE runners (
28
+ tenant_id text NOT NULL DEFAULT 'default',
29
+ id text NOT NULL,
30
+ owner_user_id text NOT NULL,
31
+ label text NOT NULL,
32
+ kind text NOT NULL DEFAULT 'local',
33
+ admin_status text NOT NULL DEFAULT 'enabled',
34
+ wake_stream text NOT NULL,
35
+ wake_stream_offset text,
36
+ last_seen_at timestamptz,
37
+ liveness_lease_expires_at timestamptz,
38
+ created_at timestamptz NOT NULL DEFAULT now(),
39
+ updated_at timestamptz NOT NULL DEFAULT now(),
40
+ PRIMARY KEY (tenant_id, id),
41
+ CONSTRAINT uq_runners_wake_stream UNIQUE (tenant_id, wake_stream),
42
+ CONSTRAINT chk_runners_kind CHECK (kind IN ('local', 'cloud-worker', 'sandbox', 'ci', 'server')),
43
+ CONSTRAINT chk_runners_admin_status CHECK (admin_status IN ('enabled', 'disabled'))
44
+ );
45
+ --> statement-breakpoint
46
+ CREATE INDEX idx_runners_owner_user_id ON runners (tenant_id, owner_user_id);
47
+ --> statement-breakpoint
48
+ CREATE INDEX idx_runners_admin_status ON runners (tenant_id, admin_status);
49
+ --> statement-breakpoint
50
+ CREATE INDEX idx_runners_liveness_lease_expires_at
51
+ ON runners (tenant_id, liveness_lease_expires_at);
52
+ --> statement-breakpoint
53
+ CREATE TABLE entity_dispatch_state (
54
+ tenant_id text NOT NULL DEFAULT 'default',
55
+ entity_url text NOT NULL,
56
+ pending_source_streams jsonb NOT NULL DEFAULT '[]'::jsonb,
57
+ pending_reason text,
58
+ pending_since timestamptz,
59
+ outstanding_wake_id text,
60
+ outstanding_wake_target jsonb,
61
+ outstanding_wake_created_at timestamptz,
62
+ active_consumer_id text,
63
+ active_runner_id text,
64
+ active_epoch integer,
65
+ active_claimed_at timestamptz,
66
+ active_lease_expires_at timestamptz,
67
+ last_wake_id text,
68
+ last_claimed_at timestamptz,
69
+ last_released_at timestamptz,
70
+ last_completed_at timestamptz,
71
+ last_error text,
72
+ updated_at timestamptz NOT NULL DEFAULT now(),
73
+ PRIMARY KEY (tenant_id, entity_url)
74
+ );
75
+ --> statement-breakpoint
76
+ CREATE INDEX idx_entity_dispatch_state_active_runner
77
+ ON entity_dispatch_state (tenant_id, active_runner_id);
78
+ --> statement-breakpoint
79
+ CREATE INDEX idx_entity_dispatch_state_outstanding_wake
80
+ ON entity_dispatch_state (tenant_id, outstanding_wake_id);
81
+ --> statement-breakpoint
82
+ CREATE INDEX idx_entity_dispatch_state_active_lease
83
+ ON entity_dispatch_state (tenant_id, active_lease_expires_at);
84
+ --> statement-breakpoint
85
+ INSERT INTO entity_dispatch_state (tenant_id, entity_url)
86
+ SELECT tenant_id, url FROM entities
87
+ ON CONFLICT (tenant_id, entity_url) DO NOTHING;
88
+ --> statement-breakpoint
89
+ CREATE TABLE wake_notifications (
90
+ tenant_id text NOT NULL DEFAULT 'default',
91
+ wake_id text NOT NULL,
92
+ entity_url text NOT NULL,
93
+ target_type text NOT NULL,
94
+ target_runner_id text,
95
+ target_webhook_url text,
96
+ target_worker_pool_id text,
97
+ runner_wake_stream text,
98
+ runner_wake_stream_offset text,
99
+ notification_public jsonb NOT NULL,
100
+ delivery_status text NOT NULL DEFAULT 'queued',
101
+ claim_status text NOT NULL DEFAULT 'unclaimed',
102
+ created_at timestamptz NOT NULL DEFAULT now(),
103
+ delivered_at timestamptz,
104
+ claimed_at timestamptz,
105
+ resolved_at timestamptz,
106
+ PRIMARY KEY (tenant_id, wake_id),
107
+ CONSTRAINT chk_wake_notifications_target_type CHECK (target_type IN ('webhook', 'runner', 'worker-pool')),
108
+ CONSTRAINT chk_wake_notifications_delivery_status CHECK (delivery_status IN ('queued', 'delivered', 'failed', 'superseded')),
109
+ CONSTRAINT chk_wake_notifications_claim_status CHECK (claim_status IN ('unclaimed', 'claimed', 'completed', 'expired'))
110
+ );
111
+ --> statement-breakpoint
112
+ CREATE INDEX idx_wake_notifications_entity_url
113
+ ON wake_notifications (tenant_id, entity_url);
114
+ --> statement-breakpoint
115
+ CREATE INDEX idx_wake_notifications_target_runner
116
+ ON wake_notifications (tenant_id, target_runner_id);
117
+ --> statement-breakpoint
118
+ CREATE INDEX idx_wake_notifications_delivery_status
119
+ ON wake_notifications (tenant_id, delivery_status);
120
+ --> statement-breakpoint
121
+ CREATE INDEX idx_wake_notifications_claim_status
122
+ ON wake_notifications (tenant_id, claim_status);
123
+ --> statement-breakpoint
124
+ CREATE INDEX idx_wake_notifications_created_at
125
+ ON wake_notifications (tenant_id, created_at);
126
+ --> statement-breakpoint
127
+ CREATE TABLE consumer_claims (
128
+ tenant_id text NOT NULL DEFAULT 'default',
129
+ consumer_id text NOT NULL,
130
+ epoch integer NOT NULL,
131
+ wake_id text,
132
+ entity_url text NOT NULL,
133
+ stream_path text NOT NULL,
134
+ runner_id text,
135
+ status text NOT NULL DEFAULT 'active',
136
+ claimed_at timestamptz NOT NULL DEFAULT now(),
137
+ last_heartbeat_at timestamptz,
138
+ lease_expires_at timestamptz,
139
+ released_at timestamptz,
140
+ acked_streams jsonb,
141
+ updated_at timestamptz NOT NULL DEFAULT now(),
142
+ PRIMARY KEY (tenant_id, consumer_id, epoch),
143
+ CONSTRAINT chk_consumer_claims_status CHECK (status IN ('active', 'released', 'expired', 'failed'))
144
+ );
145
+ --> statement-breakpoint
146
+ CREATE INDEX idx_consumer_claims_entity_status
147
+ ON consumer_claims (tenant_id, entity_url, status);
148
+ --> statement-breakpoint
149
+ CREATE INDEX idx_consumer_claims_runner
150
+ ON consumer_claims (tenant_id, runner_id);
151
+ --> statement-breakpoint
152
+ CREATE INDEX idx_consumer_claims_wake_id
153
+ ON consumer_claims (tenant_id, wake_id);
154
+ --> statement-breakpoint
155
+ CREATE INDEX idx_consumer_claims_lease_expires_at
156
+ ON consumer_claims (tenant_id, lease_expires_at);