@revealui/mcp 0.0.1-pre.0 → 0.1.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.
- package/.env.example +9 -0
- package/MCP_MAINTENANCE.md +265 -0
- package/README.md +260 -0
- package/__tests__/crdt.integration.test.ts +156 -0
- package/configs/README.md +77 -0
- package/configs/claude-template.json +54 -0
- package/dist/packages/core/src/database/ssl-config.d.ts +9 -0
- package/dist/packages/core/src/database/ssl-config.d.ts.map +1 -0
- package/dist/packages/core/src/database/ssl-config.js +8 -0
- package/dist/packages/core/src/database/ssl-config.js.map +1 -0
- package/dist/packages/core/src/features.d.ts +86 -0
- package/dist/packages/core/src/features.d.ts.map +1 -0
- package/dist/packages/core/src/features.js +93 -0
- package/dist/packages/core/src/features.js.map +1 -0
- package/dist/packages/core/src/license.d.ts +75 -0
- package/dist/packages/core/src/license.d.ts.map +1 -0
- package/dist/packages/core/src/license.js +174 -0
- package/dist/packages/core/src/license.js.map +1 -0
- package/dist/packages/core/src/monitoring/alerts.d.ts +118 -0
- package/dist/packages/core/src/monitoring/alerts.d.ts.map +1 -0
- package/dist/packages/core/src/monitoring/alerts.js +325 -0
- package/dist/packages/core/src/monitoring/alerts.js.map +1 -0
- package/dist/packages/core/src/monitoring/cleanup-manager.d.ts +71 -0
- package/dist/packages/core/src/monitoring/cleanup-manager.d.ts.map +1 -0
- package/dist/packages/core/src/monitoring/cleanup-manager.js +227 -0
- package/dist/packages/core/src/monitoring/cleanup-manager.js.map +1 -0
- package/dist/packages/core/src/monitoring/health-monitor.d.ts +22 -0
- package/dist/packages/core/src/monitoring/health-monitor.d.ts.map +1 -0
- package/dist/packages/core/src/monitoring/health-monitor.js +143 -0
- package/dist/packages/core/src/monitoring/health-monitor.js.map +1 -0
- package/dist/packages/core/src/monitoring/index.d.ts +14 -0
- package/dist/packages/core/src/monitoring/index.d.ts.map +1 -0
- package/dist/packages/core/src/monitoring/index.js +18 -0
- package/dist/packages/core/src/monitoring/index.js.map +1 -0
- package/dist/packages/core/src/monitoring/process-registry.d.ts +97 -0
- package/dist/packages/core/src/monitoring/process-registry.d.ts.map +1 -0
- package/dist/packages/core/src/monitoring/process-registry.js +223 -0
- package/dist/packages/core/src/monitoring/process-registry.js.map +1 -0
- package/dist/packages/core/src/monitoring/types.d.ts +231 -0
- package/dist/packages/core/src/monitoring/types.d.ts.map +1 -0
- package/dist/packages/core/src/monitoring/types.js +43 -0
- package/dist/packages/core/src/monitoring/types.js.map +1 -0
- package/dist/packages/core/src/monitoring/zombie-detector.d.ts +81 -0
- package/dist/packages/core/src/monitoring/zombie-detector.d.ts.map +1 -0
- package/dist/packages/core/src/monitoring/zombie-detector.js +232 -0
- package/dist/packages/core/src/monitoring/zombie-detector.js.map +1 -0
- package/dist/packages/core/src/observability/logger.d.ts +47 -0
- package/dist/packages/core/src/observability/logger.d.ts.map +1 -0
- package/dist/packages/core/src/observability/logger.js +141 -0
- package/dist/packages/core/src/observability/logger.js.map +1 -0
- package/dist/packages/core/src/utils/logger-server.d.ts +32 -0
- package/dist/packages/core/src/utils/logger-server.d.ts.map +1 -0
- package/dist/packages/core/src/utils/logger-server.js +69 -0
- package/dist/packages/core/src/utils/logger-server.js.map +1 -0
- package/dist/packages/core/src/utils/request-context.d.ts +143 -0
- package/dist/packages/core/src/utils/request-context.d.ts.map +1 -0
- package/dist/packages/core/src/utils/request-context.js +169 -0
- package/dist/packages/core/src/utils/request-context.js.map +1 -0
- package/dist/packages/dev/src/code-validator/index.d.ts +20 -0
- package/dist/packages/dev/src/code-validator/index.d.ts.map +1 -0
- package/dist/packages/dev/src/code-validator/index.js +20 -0
- package/dist/packages/dev/src/code-validator/index.js.map +1 -0
- package/dist/packages/dev/src/code-validator/types.d.ts +67 -0
- package/dist/packages/dev/src/code-validator/types.d.ts.map +1 -0
- package/dist/packages/dev/src/code-validator/types.js +7 -0
- package/dist/packages/dev/src/code-validator/types.js.map +1 -0
- package/dist/packages/dev/src/code-validator/validator.d.ts +48 -0
- package/dist/packages/dev/src/code-validator/validator.d.ts.map +1 -0
- package/dist/packages/dev/src/code-validator/validator.js +176 -0
- package/dist/packages/dev/src/code-validator/validator.js.map +1 -0
- package/dist/packages/mcp/src/adapters/db.d.ts +46 -0
- package/dist/packages/mcp/src/adapters/db.d.ts.map +1 -0
- package/dist/packages/mcp/src/adapters/db.js +127 -0
- package/dist/packages/mcp/src/adapters/db.js.map +1 -0
- package/dist/packages/mcp/src/config/index.d.ts +11 -0
- package/dist/packages/mcp/src/config/index.d.ts.map +1 -0
- package/dist/packages/mcp/src/config/index.js +18 -0
- package/dist/packages/mcp/src/config/index.js.map +1 -0
- package/dist/packages/mcp/src/contracts.d.ts +131 -0
- package/dist/packages/mcp/src/contracts.d.ts.map +1 -0
- package/dist/packages/mcp/src/contracts.js +153 -0
- package/dist/packages/mcp/src/contracts.js.map +1 -0
- package/dist/packages/mcp/src/hypervisor.d.ts +132 -0
- package/dist/packages/mcp/src/hypervisor.d.ts.map +1 -0
- package/dist/packages/mcp/src/hypervisor.js +359 -0
- package/dist/packages/mcp/src/hypervisor.js.map +1 -0
- package/dist/packages/mcp/src/index.d.ts +25 -0
- package/dist/packages/mcp/src/index.d.ts.map +1 -0
- package/dist/packages/mcp/src/index.js +41 -0
- package/dist/packages/mcp/src/index.js.map +1 -0
- package/dist/packages/mcp/src/servers/adapter.d.ts +199 -0
- package/dist/packages/mcp/src/servers/adapter.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/adapter.js +487 -0
- package/dist/packages/mcp/src/servers/adapter.js.map +1 -0
- package/dist/packages/mcp/src/servers/code-validator.d.ts +24 -0
- package/dist/packages/mcp/src/servers/code-validator.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/code-validator.js +156 -0
- package/dist/packages/mcp/src/servers/code-validator.js.map +1 -0
- package/dist/packages/mcp/src/servers/neon.d.ts +11 -0
- package/dist/packages/mcp/src/servers/neon.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/neon.js +90 -0
- package/dist/packages/mcp/src/servers/neon.js.map +1 -0
- package/dist/packages/mcp/src/servers/next-devtools.d.ts +11 -0
- package/dist/packages/mcp/src/servers/next-devtools.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/next-devtools.js +215 -0
- package/dist/packages/mcp/src/servers/next-devtools.js.map +1 -0
- package/dist/packages/mcp/src/servers/playwright.d.ts +11 -0
- package/dist/packages/mcp/src/servers/playwright.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/playwright.js +68 -0
- package/dist/packages/mcp/src/servers/playwright.js.map +1 -0
- package/dist/packages/mcp/src/servers/stripe.d.ts +11 -0
- package/dist/packages/mcp/src/servers/stripe.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/stripe.js +86 -0
- package/dist/packages/mcp/src/servers/stripe.js.map +1 -0
- package/dist/packages/mcp/src/servers/supabase.d.ts +11 -0
- package/dist/packages/mcp/src/servers/supabase.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/supabase.js +144 -0
- package/dist/packages/mcp/src/servers/supabase.js.map +1 -0
- package/dist/packages/mcp/src/servers/vercel.d.ts +11 -0
- package/dist/packages/mcp/src/servers/vercel.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/vercel.js +87 -0
- package/dist/packages/mcp/src/servers/vercel.js.map +1 -0
- package/dist/packages/mcp/src/servers/vultr-test.d.ts +3 -0
- package/dist/packages/mcp/src/servers/vultr-test.d.ts.map +1 -0
- package/dist/packages/mcp/src/servers/vultr-test.js +82 -0
- package/dist/packages/mcp/src/servers/vultr-test.js.map +1 -0
- package/dist/scripts/lib/analyzers/console-analyzer.d.ts +188 -0
- package/dist/scripts/lib/analyzers/console-analyzer.d.ts.map +1 -0
- package/dist/scripts/lib/analyzers/console-analyzer.js +432 -0
- package/dist/scripts/lib/analyzers/console-analyzer.js.map +1 -0
- package/dist/scripts/lib/analyzers/index.d.ts +11 -0
- package/dist/scripts/lib/analyzers/index.d.ts.map +1 -0
- package/dist/scripts/lib/analyzers/index.js +11 -0
- package/dist/scripts/lib/analyzers/index.js.map +1 -0
- package/dist/scripts/lib/args.d.ts +104 -0
- package/dist/scripts/lib/args.d.ts.map +1 -0
- package/dist/scripts/lib/args.js +304 -0
- package/dist/scripts/lib/args.js.map +1 -0
- package/dist/scripts/lib/cache.d.ts +185 -0
- package/dist/scripts/lib/cache.d.ts.map +1 -0
- package/dist/scripts/lib/cache.js +390 -0
- package/dist/scripts/lib/cache.js.map +1 -0
- package/dist/scripts/lib/cli/dispatch.d.ts +116 -0
- package/dist/scripts/lib/cli/dispatch.d.ts.map +1 -0
- package/dist/scripts/lib/cli/dispatch.js +206 -0
- package/dist/scripts/lib/cli/dispatch.js.map +1 -0
- package/dist/scripts/lib/cli/index.d.ts +10 -0
- package/dist/scripts/lib/cli/index.d.ts.map +1 -0
- package/dist/scripts/lib/cli/index.js +10 -0
- package/dist/scripts/lib/cli/index.js.map +1 -0
- package/dist/scripts/lib/database/ssl-config.d.ts +26 -0
- package/dist/scripts/lib/database/ssl-config.d.ts.map +1 -0
- package/dist/scripts/lib/database/ssl-config.js +47 -0
- package/dist/scripts/lib/database/ssl-config.js.map +1 -0
- package/dist/scripts/lib/errors.d.ts +218 -0
- package/dist/scripts/lib/errors.d.ts.map +1 -0
- package/dist/scripts/lib/errors.js +543 -0
- package/dist/scripts/lib/errors.js.map +1 -0
- package/dist/scripts/lib/exec.d.ts +107 -0
- package/dist/scripts/lib/exec.d.ts.map +1 -0
- package/dist/scripts/lib/exec.js +232 -0
- package/dist/scripts/lib/exec.js.map +1 -0
- package/dist/scripts/lib/index.d.ts +50 -0
- package/dist/scripts/lib/index.d.ts.map +1 -0
- package/dist/scripts/lib/index.js +65 -0
- package/dist/scripts/lib/index.js.map +1 -0
- package/dist/scripts/lib/logger.d.ts +50 -0
- package/dist/scripts/lib/logger.d.ts.map +1 -0
- package/dist/scripts/lib/logger.js +159 -0
- package/dist/scripts/lib/logger.js.map +1 -0
- package/dist/scripts/lib/output.d.ts +149 -0
- package/dist/scripts/lib/output.d.ts.map +1 -0
- package/dist/scripts/lib/output.js +263 -0
- package/dist/scripts/lib/output.js.map +1 -0
- package/dist/scripts/lib/parallel.d.ts +164 -0
- package/dist/scripts/lib/parallel.d.ts.map +1 -0
- package/dist/scripts/lib/parallel.js +355 -0
- package/dist/scripts/lib/parallel.js.map +1 -0
- package/dist/scripts/lib/paths.d.ts +92 -0
- package/dist/scripts/lib/paths.d.ts.map +1 -0
- package/dist/scripts/lib/paths.js +171 -0
- package/dist/scripts/lib/paths.js.map +1 -0
- package/dist/scripts/lib/state/adapters/memory.d.ts +42 -0
- package/dist/scripts/lib/state/adapters/memory.d.ts.map +1 -0
- package/dist/scripts/lib/state/adapters/memory.js +110 -0
- package/dist/scripts/lib/state/adapters/memory.js.map +1 -0
- package/dist/scripts/lib/state/adapters/pglite.d.ts +46 -0
- package/dist/scripts/lib/state/adapters/pglite.d.ts.map +1 -0
- package/dist/scripts/lib/state/adapters/pglite.js +256 -0
- package/dist/scripts/lib/state/adapters/pglite.js.map +1 -0
- package/dist/scripts/lib/state/index.d.ts +16 -0
- package/dist/scripts/lib/state/index.d.ts.map +1 -0
- package/dist/scripts/lib/state/index.js +16 -0
- package/dist/scripts/lib/state/index.js.map +1 -0
- package/dist/scripts/lib/state/types.d.ts +111 -0
- package/dist/scripts/lib/state/types.d.ts.map +1 -0
- package/dist/scripts/lib/state/types.js +8 -0
- package/dist/scripts/lib/state/types.js.map +1 -0
- package/dist/scripts/lib/state/workflow-state.d.ts +110 -0
- package/dist/scripts/lib/state/workflow-state.d.ts.map +1 -0
- package/dist/scripts/lib/state/workflow-state.js +331 -0
- package/dist/scripts/lib/state/workflow-state.js.map +1 -0
- package/dist/scripts/lib/telemetry.d.ts +194 -0
- package/dist/scripts/lib/telemetry.d.ts.map +1 -0
- package/dist/scripts/lib/telemetry.js +394 -0
- package/dist/scripts/lib/telemetry.js.map +1 -0
- package/dist/scripts/lib/utils.d.ts +270 -0
- package/dist/scripts/lib/utils.d.ts.map +1 -0
- package/dist/scripts/lib/utils.js +473 -0
- package/dist/scripts/lib/utils.js.map +1 -0
- package/dist/scripts/lib/validation/database.d.ts +83 -0
- package/dist/scripts/lib/validation/database.d.ts.map +1 -0
- package/dist/scripts/lib/validation/database.js +199 -0
- package/dist/scripts/lib/validation/database.js.map +1 -0
- package/dist/scripts/lib/validation/env.d.ts +80 -0
- package/dist/scripts/lib/validation/env.d.ts.map +1 -0
- package/dist/scripts/lib/validation/env.js +246 -0
- package/dist/scripts/lib/validation/env.js.map +1 -0
- package/dist/scripts/lib/validation/index.d.ts +16 -0
- package/dist/scripts/lib/validation/index.d.ts.map +1 -0
- package/dist/scripts/lib/validation/index.js +16 -0
- package/dist/scripts/lib/validation/index.js.map +1 -0
- package/dist/scripts/lib/validation/post-execution.d.ts +74 -0
- package/dist/scripts/lib/validation/post-execution.d.ts.map +1 -0
- package/dist/scripts/lib/validation/post-execution.js +110 -0
- package/dist/scripts/lib/validation/post-execution.js.map +1 -0
- package/dist/scripts/lib/validation/pre-execution.d.ts +165 -0
- package/dist/scripts/lib/validation/pre-execution.d.ts.map +1 -0
- package/dist/scripts/lib/validation/pre-execution.js +466 -0
- package/dist/scripts/lib/validation/pre-execution.js.map +1 -0
- package/dist/scripts/lib/validators/documentation-validator.d.ts +242 -0
- package/dist/scripts/lib/validators/documentation-validator.d.ts.map +1 -0
- package/dist/scripts/lib/validators/documentation-validator.js +584 -0
- package/dist/scripts/lib/validators/documentation-validator.js.map +1 -0
- package/dist/scripts/lib/validators/index.d.ts +11 -0
- package/dist/scripts/lib/validators/index.d.ts.map +1 -0
- package/dist/scripts/lib/validators/index.js +11 -0
- package/dist/scripts/lib/validators/index.js.map +1 -0
- package/docker-compose.yml +46 -0
- package/docs/INDEX.md +88 -0
- package/docs/README.md +774 -0
- package/docs/SETUP.md +264 -0
- package/docs/servers/code-validator.md +586 -0
- package/eslint.config.js +7 -0
- package/migrations/0001_add_crdt_columns.sql +8 -0
- package/migrations/0001_rollback.sql +6 -0
- package/migrations/005_performance_indexes.sql +190 -0
- package/migrations/backfill_crdt_meta.js +45 -0
- package/package.json +21 -85
- package/src/__tests__/hypervisor.test.ts +212 -0
- package/src/adapters/db.ts +180 -0
- package/src/config/config.json +49 -0
- package/src/config/index.ts +30 -0
- package/src/contracts.ts +221 -0
- package/src/hypervisor.ts +464 -0
- package/src/index.ts +87 -0
- package/src/servers/adapter.ts +643 -0
- package/src/servers/code-validator.ts +188 -0
- package/src/servers/neon.ts +103 -0
- package/src/servers/next-devtools.ts +230 -0
- package/src/servers/playwright.ts +77 -0
- package/src/servers/stripe.ts +99 -0
- package/src/servers/supabase.ts +161 -0
- package/src/servers/vercel.ts +100 -0
- package/src/servers/vultr-test.ts +97 -0
- package/tsconfig.json +12 -0
- package/vitest.config.ts +22 -0
- package/LICENSE +0 -202
- package/dist/index.js +0 -10990
- package/dist/index.js.map +0 -1
package/.env.example
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MCP_PERSISTENCE_DRIVER=pglite
|
|
2
|
+
ELECTRIC_DATABASE_URL=postgres://dev:dev@localhost:5432/revealui_mcp
|
|
3
|
+
ELECTRIC_API_KEY=replace-me
|
|
4
|
+
MCP_METRICS_MODE=logs
|
|
5
|
+
PGVECTOR_ENABLED=false
|
|
6
|
+
|
|
7
|
+
# Notes:
|
|
8
|
+
# - Do NOT commit real credentials. Store real secrets in CI/Vault.
|
|
9
|
+
# - Set `PGVECTOR_ENABLED=true` when using local Postgres with pgvector for vector testing.
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# MCP Maintenance Guide
|
|
2
|
+
|
|
3
|
+
This document consolidates all MCP-related maintenance information including CRDT audit strategy, key decisions, migration procedures, and metrics/observability approach.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Decision Log](#decision-log)
|
|
10
|
+
2. [CRDT Audit](#crdt-audit)
|
|
11
|
+
3. [Migration Checklist](#migration-checklist)
|
|
12
|
+
4. [Metrics & Observability](#metrics--observability)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Decision Log
|
|
17
|
+
|
|
18
|
+
### MCP Decision — pglite (ElectricSQL) + Logs‑First Metrics
|
|
19
|
+
|
|
20
|
+
**TL;DR** — Default to ElectricSQL (`pglite`) for local development to get Postgres parity, CRDT sync, and smooth production migration. Start observability with a logs‑first approach (`MCP_METRICS_MODE=logs`). Provide a documented migration path to managed Postgres + `pgvector` for production, and TODOs to add Prometheus + Grafana later.
|
|
21
|
+
|
|
22
|
+
#### Why `pglite` (ElectricSQL)
|
|
23
|
+
|
|
24
|
+
- Local Postgres parity: preserves SQL semantics developers expect while providing Electric sync.
|
|
25
|
+
- CRDT & sync primitives: built-in conflict resolution and metadata for replicated state.
|
|
26
|
+
- Smooth prod path: same logical model maps to managed Postgres (Neon / Supabase) with minimal code changes.
|
|
27
|
+
|
|
28
|
+
#### Default configuration
|
|
29
|
+
|
|
30
|
+
- `MCP_PERSISTENCE_DRIVER=pglite` (dev default)
|
|
31
|
+
- `ELECTRIC_DATABASE_URL=` (placeholder for local pglite path/URL)
|
|
32
|
+
- `MCP_METRICS_MODE=logs`
|
|
33
|
+
|
|
34
|
+
#### Local vector testing
|
|
35
|
+
|
|
36
|
+
- Use a compose variant with local Postgres + `pgvector` when testing vector queries or index behavior. `pglite` remains the default for state and CRDT behavior.
|
|
37
|
+
|
|
38
|
+
#### Security stance
|
|
39
|
+
|
|
40
|
+
- Never commit credentials. Use `packages/mcp/.env.example` with placeholders only.
|
|
41
|
+
- Store `ELECTRIC_DATABASE_URL`, `ELECTRIC_API_KEY`, `PROD_DATABASE_URL` in CI secrets or Vault for staging/prod.
|
|
42
|
+
|
|
43
|
+
#### Migration path (dev → prod)
|
|
44
|
+
|
|
45
|
+
- Dev: `pglite` (local ElectricSQL)
|
|
46
|
+
- Stage: Local Postgres with `pgvector` + Electric sync metadata
|
|
47
|
+
- Prod: Managed Postgres (enable `pgvector`), Electric sync metadata preserved
|
|
48
|
+
|
|
49
|
+
(See [Migration Checklist](#migration-checklist) section for a detailed plan.)
|
|
50
|
+
|
|
51
|
+
#### Observability
|
|
52
|
+
|
|
53
|
+
- Start with logs-first metrics (Option C). Emit structured log events for conflicts, merges, and error rates.
|
|
54
|
+
- TODO: add Prometheus + Grafana manifests under `packages/mcp/k8s/` when operational budget permits.
|
|
55
|
+
|
|
56
|
+
#### TODOs (short)
|
|
57
|
+
|
|
58
|
+
- Add `packages/mcp/docker-compose.yml` with `pglite` dev service and `postgres+pgvector` variant.
|
|
59
|
+
- Add `packages/mcp/src/adapters/db.ts` with `connectPglite()` / `connectPostgres()`.
|
|
60
|
+
- Add CRDT migrations & backfill scripts.
|
|
61
|
+
- Add integration tests that spin up compose and validate CRDT merges.
|
|
62
|
+
- Add `packages/mcp/metrics.md` (logs-first) and TODOs for Option A (Prometheus + Grafana).
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## CRDT Audit
|
|
67
|
+
|
|
68
|
+
### CRDT Audit — Candidate Entities & Strategy
|
|
69
|
+
|
|
70
|
+
**Goal** — ensure all replicated, collaborative, or concurrent state uses CRDT semantics to avoid manual conflict resolution.
|
|
71
|
+
|
|
72
|
+
#### Scope
|
|
73
|
+
|
|
74
|
+
- Applies to MCP persistence: local `pglite` (dev) and managed Postgres (prod).
|
|
75
|
+
- Targets entity categories that are concurrently updated or replicated.
|
|
76
|
+
|
|
77
|
+
#### Candidate entities and recommended CRDT types
|
|
78
|
+
|
|
79
|
+
- `documents` / `shared_documents`
|
|
80
|
+
- Use: collaborative edits
|
|
81
|
+
- CRDT: delta CRDT (RGA / JSON CRDT / operation-based)
|
|
82
|
+
- Policy: preserve operations and causal order
|
|
83
|
+
- `subscription_state` / `cursors`
|
|
84
|
+
- Use: client offsets, cursors
|
|
85
|
+
- CRDT: LWW register or monotonic counter
|
|
86
|
+
- Policy: LWW with server-side monotonic enforcement where possible
|
|
87
|
+
- `presence` / `ephemeral_status`
|
|
88
|
+
- Use: frequent transient updates
|
|
89
|
+
- CRDT: OR-Set with TTL or presence map
|
|
90
|
+
- Policy: TTL-based garbage collection
|
|
91
|
+
- `message_ack` / `delivered_acks`
|
|
92
|
+
- Use: dedup across replicas
|
|
93
|
+
- CRDT: OR-Set or G-Set with tombstones
|
|
94
|
+
- Policy: idempotent ack addition, compact tombstones periodically
|
|
95
|
+
- `user_settings` / `shared_settings`
|
|
96
|
+
- Use: small multi-client updates
|
|
97
|
+
- CRDT: observed-remove map / JSON CRDT
|
|
98
|
+
- Policy: field-level merge, operator override protected
|
|
99
|
+
|
|
100
|
+
#### Implementation notes
|
|
101
|
+
|
|
102
|
+
- Adapter responsibilities:
|
|
103
|
+
- `connectPglite()` should declare CRDT columns via Electric APIs (where available).
|
|
104
|
+
- `connectPostgres()` must keep Electric metadata columns and map CRDT metadata to Postgres-compatible storage.
|
|
105
|
+
- Schema:
|
|
106
|
+
- Add `_electric_meta` or `_crdt_meta` columns near payloads.
|
|
107
|
+
- Store operation deltas if possible for efficient merges.
|
|
108
|
+
- Rollout:
|
|
109
|
+
- Feature-flag per-entity CRDT enablement for staged rollout.
|
|
110
|
+
- Small-sample backfills prior to full backfill.
|
|
111
|
+
- Storage & compaction:
|
|
112
|
+
- Implement delta compaction for large-delta CRDTs.
|
|
113
|
+
- Schedule periodic compaction jobs to remove tombstones and shrink op logs.
|
|
114
|
+
|
|
115
|
+
#### Testing
|
|
116
|
+
|
|
117
|
+
- Unit tests: CRDT op merges for each primitive (OR-Set, PNCounter, LWW register).
|
|
118
|
+
- Integration tests: concurrent writers with `pglite` stack asserting deterministic merged state.
|
|
119
|
+
- Migration tests: backfill scripts run on sample data and validate checksum diffs.
|
|
120
|
+
|
|
121
|
+
#### Risk & mitigation
|
|
122
|
+
|
|
123
|
+
- Existing payload types incompatible with CRDT fields — use non-destructive migrations and backfill.
|
|
124
|
+
- Vector index (pgvector) mapping must be preserved during schema changes — treat embedding columns as orthogonal.
|
|
125
|
+
|
|
126
|
+
#### Suggested tests to add
|
|
127
|
+
|
|
128
|
+
- `packages/mcp/__tests__/crdt.unit.test.ts` — unit semantics.
|
|
129
|
+
- `packages/mcp/__tests__/crdt.integration.test.ts` — compose-based concurrent writes.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Migration Checklist
|
|
134
|
+
|
|
135
|
+
### MCP Migration Checklist — pglite → Managed Postgres + pgvector
|
|
136
|
+
|
|
137
|
+
**Goal** — safely cut over from `pglite` dev workflows to managed Postgres in production while preserving CRDT semantics and vector index integrity.
|
|
138
|
+
|
|
139
|
+
#### Pre‑reqs
|
|
140
|
+
|
|
141
|
+
- Staging Postgres provisioned with `pgvector` enabled.
|
|
142
|
+
- Backups and CI/Vault secrets available: `ELECTRIC_DATABASE_URL`, `ELECTRIC_API_KEY`, `PROD_DATABASE_URL`.
|
|
143
|
+
- Smoke test harness and CRDT integration tests present.
|
|
144
|
+
|
|
145
|
+
#### Ordered checklist
|
|
146
|
+
|
|
147
|
+
1. **Backup source DB**
|
|
148
|
+
```bash
|
|
149
|
+
pg_dump -Fc -f backup.before.mcp.dump "$CURRENT_DB_URL"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
2. **Provision staging DB with `pgvector`**
|
|
153
|
+
```sql
|
|
154
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
3. **Apply schema migrations to staging (include CRDT metadata columns)**
|
|
158
|
+
- Add migration files: `packages/mcp/migrations/0001_add_crdt_columns.sql` and rollback script.
|
|
159
|
+
|
|
160
|
+
4. **Small backfill (sample subset)**
|
|
161
|
+
- Run `packages/mcp/migrations/backfill_crdt_meta.js` for representative rows; validate merges.
|
|
162
|
+
|
|
163
|
+
5. **Run integration smoke tests**
|
|
164
|
+
- Execute CRDT integration test suite against staging.
|
|
165
|
+
|
|
166
|
+
6. **Export/import full snapshot (if migrating data)**
|
|
167
|
+
```bash
|
|
168
|
+
pg_restore -d "$STAGING_DB_URL" backup.before.mcp.dump
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
7. **Create `pgvector` indexes (maintenance window suggested)**
|
|
172
|
+
```sql
|
|
173
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
174
|
+
CREATE INDEX IF NOT EXISTS documents_embedding_idx ON documents USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
8. **Full backfill & compaction**
|
|
178
|
+
- Run full backfill; compact delta-CRDT ops as needed.
|
|
179
|
+
|
|
180
|
+
9. **Switch app config (canary first)**
|
|
181
|
+
- Set `MCP_PERSISTENCE_DRIVER=postgres`
|
|
182
|
+
- Update `ELECTRIC_DATABASE_URL` to prod managed DB via secrets
|
|
183
|
+
|
|
184
|
+
10. **Canary / canary tests**
|
|
185
|
+
- Route small traffic, monitor conflict events and query correctness.
|
|
186
|
+
|
|
187
|
+
11. **Full cutover**
|
|
188
|
+
- Promote config change to all instances.
|
|
189
|
+
|
|
190
|
+
12. **Post-migration validation**
|
|
191
|
+
- Run full test suite, verify vector results, verify merge/conflict telemetry.
|
|
192
|
+
|
|
193
|
+
13. **Rollback readiness**
|
|
194
|
+
```bash
|
|
195
|
+
pg_restore -d "$PROD_DB_URL" backup.before.mcp.dump
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### Operational notes
|
|
199
|
+
|
|
200
|
+
- Prefer online migration with feature flags and small maintenance windows for index builds.
|
|
201
|
+
- Validate checksums and sample-row diffs after every major migration step.
|
|
202
|
+
- Keep rollback scripts next to each migration file.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Metrics & Observability
|
|
207
|
+
|
|
208
|
+
### MCP Metrics & Observability — Logs‑First (Option C)
|
|
209
|
+
|
|
210
|
+
#### Decision
|
|
211
|
+
|
|
212
|
+
- Start with logs-first metrics to avoid hosted monitoring costs and reduce infra.
|
|
213
|
+
- Emit structured logs for conflicts, merges, errors, and key latencies.
|
|
214
|
+
- Provide clear TODOs and skeletons to add Prometheus + Grafana later.
|
|
215
|
+
|
|
216
|
+
#### Env & modes
|
|
217
|
+
|
|
218
|
+
- `MCP_METRICS_MODE=logs` (default)
|
|
219
|
+
- Other modes: `otel` (collector), `prometheus` (future Option A)
|
|
220
|
+
|
|
221
|
+
#### Structured log schema (recommended JSON fields)
|
|
222
|
+
|
|
223
|
+
- `timestamp`
|
|
224
|
+
- `service = "mcp"`
|
|
225
|
+
- `event` = `conflict|merge|error|operation`
|
|
226
|
+
- `entity` = `documents|cursors|presence|...`
|
|
227
|
+
- `entity_id`
|
|
228
|
+
- `op_type` = `write|merge|backfill|index`
|
|
229
|
+
- `details` = short summary
|
|
230
|
+
- `duration_ms`
|
|
231
|
+
- `trace_id` (optional)
|
|
232
|
+
|
|
233
|
+
#### Conflict/merge logging example (concept)
|
|
234
|
+
|
|
235
|
+
- Log a `conflict` event when CRDT merge produces non-trivial resolution; include `before`, `ops_count`, `merged_summary`.
|
|
236
|
+
|
|
237
|
+
#### Log collection options (free)
|
|
238
|
+
|
|
239
|
+
- Use file logs + `loki` (self-hosted) and Grafana Loki datasource for queries (both OSS).
|
|
240
|
+
- Or aggregate logs to a central file/CI artifact and analyze with `rg`/`jq` for small teams.
|
|
241
|
+
|
|
242
|
+
#### Quick local setup (suggested)
|
|
243
|
+
|
|
244
|
+
- Start compose with `loki` (optional) to collect logs, or rely on local file logs.
|
|
245
|
+
```bash
|
|
246
|
+
docker-compose -f packages/mcp/docker-compose.yml up -d loki
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
#### TODOs for Option A (Prometheus + Grafana)
|
|
250
|
+
|
|
251
|
+
- Add `packages/mcp/k8s/` manifests and Helm chart scaffolding for Prometheus exporters and Grafana dashboards.
|
|
252
|
+
- Instrument code with Prometheus client metrics (conflict counters, merge latencies).
|
|
253
|
+
- Add dashboards and alert rules for high conflict rates.
|
|
254
|
+
|
|
255
|
+
#### Implementation guidance
|
|
256
|
+
|
|
257
|
+
- Implement `packages/mcp/src/telemetry.ts` that:
|
|
258
|
+
- Emits structured logs for every conflict/merge.
|
|
259
|
+
- In `MCP_METRICS_MODE=logs`, write JSON lines to stdout and rotate to file if needed.
|
|
260
|
+
- Provide quick grep/jq scripts in `packages/mcp/` to extract conflict rates.
|
|
261
|
+
|
|
262
|
+
#### Security & privacy
|
|
263
|
+
|
|
264
|
+
- Avoid logging sensitive payloads (mask user PII).
|
|
265
|
+
- Keep telemetry ingestion endpoints protected; local logs are preferred during dev.
|
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# @revealui/mcp
|
|
2
|
+
|
|
3
|
+
**Model Context Protocol (MCP) - Complete Integration Package**
|
|
4
|
+
|
|
5
|
+
Centralized MCP server infrastructure, configuration, and documentation for RevealUI.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
This package contains everything MCP-related:
|
|
10
|
+
|
|
11
|
+
- **7 MCP Servers** - Code validator, Vercel, Stripe, Neon, Supabase, Playwright, Next.js DevTools
|
|
12
|
+
- **Configuration Templates** - For Claude Code / Claude Desktop
|
|
13
|
+
- **Utilities** - Config management, database adapters
|
|
14
|
+
- **Documentation** - Complete guides and per-server docs
|
|
15
|
+
- **Database Migrations** - MCP-related schema
|
|
16
|
+
|
|
17
|
+
> **Pro Package** — `@revealui/mcp` is available to RevealUI Pro subscribers via GitHub Packages.
|
|
18
|
+
> Install: `pnpm add @revealui/mcp --registry https://npm.pkg.github.com`
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### 1. Install Dependencies
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# In the monorepo:
|
|
26
|
+
pnpm install
|
|
27
|
+
|
|
28
|
+
# As an external Pro subscriber:
|
|
29
|
+
pnpm add @revealui/mcp --registry https://npm.pkg.github.com
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Configure MCP Client
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Use template for your IDE
|
|
36
|
+
cp packages/mcp/configs/claude-template.json ~/.claude/config.json
|
|
37
|
+
|
|
38
|
+
# Replace <REPO_PATH> with actual path
|
|
39
|
+
sed -i "s|<REPO_PATH>|$(pwd)|g" ~/.claude/config.json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. Test Server
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Test code validator
|
|
46
|
+
tsx packages/mcp/src/servers/code-validator.ts
|
|
47
|
+
# Should start (Ctrl+C to exit)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Structure
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
packages/mcp/
|
|
54
|
+
├── src/
|
|
55
|
+
│ ├── servers/ # 7 MCP server implementations
|
|
56
|
+
│ │ ├── code-validator.ts ← AI code standards enforcer
|
|
57
|
+
│ │ ├── vercel.ts
|
|
58
|
+
│ │ ├── stripe.ts
|
|
59
|
+
│ │ ├── neon.ts
|
|
60
|
+
│ │ ├── supabase.ts
|
|
61
|
+
│ │ ├── playwright.ts
|
|
62
|
+
│ │ └── next-devtools.ts
|
|
63
|
+
│ ├── config/ # Configuration utilities
|
|
64
|
+
│ │ ├── index.ts
|
|
65
|
+
│ │ ├── config.json
|
|
66
|
+
│ │ └── README.md
|
|
67
|
+
│ └── adapters/ # Database adapters
|
|
68
|
+
│ └── db.ts
|
|
69
|
+
├── configs/ # Template configurations
|
|
70
|
+
│ ├── claude-template.json
|
|
71
|
+
│ └── README.md
|
|
72
|
+
├── docs/ # Complete documentation
|
|
73
|
+
│ ├── INDEX.md ← Start here
|
|
74
|
+
│ ├── README.md # Main MCP guide
|
|
75
|
+
│ ├── SETUP.md # Setup instructions
|
|
76
|
+
│ └── servers/ # Per-server documentation
|
|
77
|
+
│ └── code-validator.md
|
|
78
|
+
├── migrations/ # Database migrations
|
|
79
|
+
│ ├── 0001_add_crdt_columns.sql
|
|
80
|
+
│ └── ...
|
|
81
|
+
└── package.json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Available MCP Servers
|
|
85
|
+
|
|
86
|
+
### 1. Code Validator ⭐
|
|
87
|
+
**Status:** ✅ Active and configured
|
|
88
|
+
|
|
89
|
+
Prevents AI-generated technical debt by validating code before it's written.
|
|
90
|
+
|
|
91
|
+
- **Rules:** console.log, any types, TODO refs, debugger, skip tests
|
|
92
|
+
- **Integration:** Pre-commit hook + MCP server
|
|
93
|
+
- **Docs:** [docs/servers/code-validator.md](./docs/servers/code-validator.md)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
tsx packages/mcp/src/servers/code-validator.ts
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 2. Vercel
|
|
100
|
+
**Status:** Available (requires API key)
|
|
101
|
+
|
|
102
|
+
Deploy and manage Vercel projects.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pnpm mcp:vercel
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 3. Stripe
|
|
109
|
+
**Status:** Available (requires API key)
|
|
110
|
+
|
|
111
|
+
Payment processing and billing operations.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pnpm mcp:stripe
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 4. Neon
|
|
118
|
+
**Status:** Available (requires API key)
|
|
119
|
+
|
|
120
|
+
Database operations and SQL queries.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pnpm mcp:neon
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 5. Supabase
|
|
127
|
+
**Status:** Available (requires API key)
|
|
128
|
+
|
|
129
|
+
Supabase project management and CRUD operations.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pnpm mcp:supabase
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 6. Playwright
|
|
136
|
+
**Status:** Available
|
|
137
|
+
|
|
138
|
+
Browser automation and web scraping.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
pnpm mcp:playwright
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 7. Next.js DevTools
|
|
145
|
+
**Status:** Available
|
|
146
|
+
|
|
147
|
+
Next.js 16+ runtime diagnostics and automation.
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
pnpm mcp:next-devtools
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Configuration
|
|
154
|
+
|
|
155
|
+
All configuration templates are in `configs/`:
|
|
156
|
+
|
|
157
|
+
- **`claude-template.json`** - Claude Code / Claude Desktop
|
|
158
|
+
|
|
159
|
+
See [configs/README.md](./configs/README.md) for details.
|
|
160
|
+
|
|
161
|
+
## Environment Variables
|
|
162
|
+
|
|
163
|
+
```env
|
|
164
|
+
# Code Validator (no env vars needed)
|
|
165
|
+
|
|
166
|
+
# Vercel MCP
|
|
167
|
+
VERCEL_API_KEY=vercel_...
|
|
168
|
+
|
|
169
|
+
# Stripe MCP
|
|
170
|
+
STRIPE_SECRET_KEY=sk_test_...
|
|
171
|
+
|
|
172
|
+
# Neon MCP
|
|
173
|
+
NEON_API_KEY=neon_...
|
|
174
|
+
|
|
175
|
+
# Supabase MCP
|
|
176
|
+
SUPABASE_URL=https://....supabase.co
|
|
177
|
+
SUPABASE_ANON_KEY=eyJ...
|
|
178
|
+
SUPABASE_SERVICE_ROLE_KEY=...
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Documentation
|
|
182
|
+
|
|
183
|
+
📚 **[Complete Documentation Index](./docs/INDEX.md)**
|
|
184
|
+
|
|
185
|
+
- **[Main Guide](./docs/README.md)** - MCP overview
|
|
186
|
+
- **[Setup Guide](./docs/SETUP.md)** - Configuration steps
|
|
187
|
+
- **[Code Validator](./docs/servers/code-validator.md)** - Validator guide
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Build package
|
|
193
|
+
pnpm build
|
|
194
|
+
|
|
195
|
+
# Run tests
|
|
196
|
+
pnpm test
|
|
197
|
+
|
|
198
|
+
# Type check
|
|
199
|
+
pnpm typecheck
|
|
200
|
+
|
|
201
|
+
# Lint
|
|
202
|
+
pnpm lint
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Package Scripts (Root)
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# Start individual MCP servers
|
|
209
|
+
pnpm mcp:vercel
|
|
210
|
+
pnpm mcp:stripe
|
|
211
|
+
pnpm mcp:neon
|
|
212
|
+
pnpm mcp:supabase
|
|
213
|
+
pnpm mcp:playwright
|
|
214
|
+
pnpm mcp:next-devtools
|
|
215
|
+
|
|
216
|
+
# Setup MCP configuration
|
|
217
|
+
pnpm setup:mcp
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Exports
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// Config utilities
|
|
224
|
+
import { getMCPConfig } from '@revealui/mcp/config'
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Migration from Old Structure
|
|
228
|
+
|
|
229
|
+
This package consolidates MCP code from multiple locations:
|
|
230
|
+
|
|
231
|
+
**Before:**
|
|
232
|
+
- `scripts/mcp/` → Now `src/servers/`
|
|
233
|
+
- `packages/config/src/mcp/` → Now `src/config/`
|
|
234
|
+
- Multiple config files → Now `configs/` templates
|
|
235
|
+
- Scattered docs → Now `docs/`
|
|
236
|
+
|
|
237
|
+
**After:**
|
|
238
|
+
- Everything in `packages/mcp/` ✅
|
|
239
|
+
|
|
240
|
+
## Related Documentation
|
|
241
|
+
|
|
242
|
+
- [Root MCP Guide](../../docs/MCP.md)
|
|
243
|
+
- [Automation Guide](../../docs/AUTOMATION.md) - AI agent integration
|
|
244
|
+
- [Project Overview](../../docs/OVERVIEW.md) - Framework overview
|
|
245
|
+
|
|
246
|
+
## References
|
|
247
|
+
|
|
248
|
+
- [Model Context Protocol Specification](https://modelcontextprotocol.io/)
|
|
249
|
+
- [Anthropic MCP Servers](https://github.com/anthropics/mcp-servers)
|
|
250
|
+
- [MCP SDK Documentation](https://github.com/modelcontextprotocol/sdk)
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
Commercial — see [LICENSE.commercial](../../LICENSE.commercial)
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
**Status:** ✅ Consolidated and Active
|
|
259
|
+
**Servers:** 7 available (1 active, 6 optional)
|
|
260
|
+
**Last Updated:** 2026-03-04
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import adapters, { connectPglite, type McpDbClient } from '../src/adapters/db.js'
|
|
3
|
+
|
|
4
|
+
describe('CRDT integration (smoke)', () => {
|
|
5
|
+
it('adapter functions exist', () => {
|
|
6
|
+
expect(typeof adapters.connectPglite).toBe('function')
|
|
7
|
+
expect(typeof adapters.connectPostgres).toBe('function')
|
|
8
|
+
expect(typeof adapters.createMcpDbClient).toBe('function')
|
|
9
|
+
})
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
// Skip integration tests in unit test mode
|
|
13
|
+
// Integration tests need TEST_DATABASE_URL explicitly set or PGlite in test environment
|
|
14
|
+
// Don't run by default as PGlite initialization can be slow
|
|
15
|
+
const testDatabaseUrl = process.env.TEST_DATABASE_URL
|
|
16
|
+
const isTestMode = process.env.NODE_ENV === 'test'
|
|
17
|
+
|
|
18
|
+
describe.skipIf(!testDatabaseUrl || isTestMode)('CRDT integration with PGlite', () => {
|
|
19
|
+
let client: McpDbClient
|
|
20
|
+
|
|
21
|
+
beforeAll(async () => {
|
|
22
|
+
// Use in-memory PGlite for testing
|
|
23
|
+
client = await connectPglite({ dataDir: ':memory:' })
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
afterAll(async () => {
|
|
27
|
+
if (client) {
|
|
28
|
+
await client.close()
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should create crdt_operations table', async () => {
|
|
33
|
+
// Verify table exists by querying it
|
|
34
|
+
const result = await client.query(
|
|
35
|
+
`SELECT column_name FROM information_schema.columns WHERE table_name = 'crdt_operations'`,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
const columns = result.rows.map((r) => r.column_name)
|
|
39
|
+
expect(columns).toContain('id')
|
|
40
|
+
expect(columns).toContain('document_id')
|
|
41
|
+
expect(columns).toContain('operation_type')
|
|
42
|
+
expect(columns).toContain('payload')
|
|
43
|
+
expect(columns).toContain('vector_clock')
|
|
44
|
+
expect(columns).toContain('node_id')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should insert and query CRDT operations', async () => {
|
|
48
|
+
const opId = `op-${Date.now()}`
|
|
49
|
+
const docId = 'doc-test-1'
|
|
50
|
+
const nodeId = 'node-a'
|
|
51
|
+
|
|
52
|
+
// Insert a CRDT operation
|
|
53
|
+
await client.query(
|
|
54
|
+
`INSERT INTO crdt_operations (id, document_id, operation_type, payload, vector_clock, node_id)
|
|
55
|
+
VALUES ($1, $2, $3, $4, $5, $6)`,
|
|
56
|
+
[
|
|
57
|
+
opId,
|
|
58
|
+
docId,
|
|
59
|
+
'insert',
|
|
60
|
+
JSON.stringify({ field: 'title', value: 'Test' }),
|
|
61
|
+
JSON.stringify({ [nodeId]: 1 }),
|
|
62
|
+
nodeId,
|
|
63
|
+
],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
// Query it back
|
|
67
|
+
const result = await client.query(`SELECT * FROM crdt_operations WHERE id = $1`, [opId])
|
|
68
|
+
|
|
69
|
+
expect(result.rows).toHaveLength(1)
|
|
70
|
+
expect(result.rows[0]?.document_id).toBe(docId)
|
|
71
|
+
expect(result.rows[0]?.operation_type).toBe('insert')
|
|
72
|
+
expect(result.rows[0]?.node_id).toBe(nodeId)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('should support concurrent operations from multiple nodes', async () => {
|
|
76
|
+
const docId = `doc-concurrent-${Date.now()}`
|
|
77
|
+
const nodeA = 'node-a'
|
|
78
|
+
const nodeB = 'node-b'
|
|
79
|
+
|
|
80
|
+
// Simulate concurrent writes from two nodes
|
|
81
|
+
await Promise.all([
|
|
82
|
+
client.query(
|
|
83
|
+
`INSERT INTO crdt_operations (id, document_id, operation_type, payload, vector_clock, node_id)
|
|
84
|
+
VALUES ($1, $2, $3, $4, $5, $6)`,
|
|
85
|
+
[
|
|
86
|
+
`op-a-${Date.now()}`,
|
|
87
|
+
docId,
|
|
88
|
+
'update',
|
|
89
|
+
JSON.stringify({ field: 'content', value: 'From A' }),
|
|
90
|
+
JSON.stringify({ [nodeA]: 1 }),
|
|
91
|
+
nodeA,
|
|
92
|
+
],
|
|
93
|
+
),
|
|
94
|
+
client.query(
|
|
95
|
+
`INSERT INTO crdt_operations (id, document_id, operation_type, payload, vector_clock, node_id)
|
|
96
|
+
VALUES ($1, $2, $3, $4, $5, $6)`,
|
|
97
|
+
[
|
|
98
|
+
`op-b-${Date.now()}`,
|
|
99
|
+
docId,
|
|
100
|
+
'update',
|
|
101
|
+
JSON.stringify({ field: 'content', value: 'From B' }),
|
|
102
|
+
JSON.stringify({ [nodeB]: 1 }),
|
|
103
|
+
nodeB,
|
|
104
|
+
],
|
|
105
|
+
),
|
|
106
|
+
])
|
|
107
|
+
|
|
108
|
+
// Query all operations for this document
|
|
109
|
+
const result = await client.query(
|
|
110
|
+
`SELECT * FROM crdt_operations WHERE document_id = $1 ORDER BY created_at`,
|
|
111
|
+
[docId],
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
// Both operations should be preserved (CRDT property)
|
|
115
|
+
expect(result.rows).toHaveLength(2)
|
|
116
|
+
|
|
117
|
+
const nodes = result.rows.map((r) => r.node_id)
|
|
118
|
+
expect(nodes).toContain(nodeA)
|
|
119
|
+
expect(nodes).toContain(nodeB)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should handle vector clock ordering', async () => {
|
|
123
|
+
const docId = `doc-clock-${Date.now()}`
|
|
124
|
+
const nodeId = 'node-clock'
|
|
125
|
+
|
|
126
|
+
// Insert operations with incrementing vector clock
|
|
127
|
+
for (let i = 1; i <= 3; i++) {
|
|
128
|
+
await client.query(
|
|
129
|
+
`INSERT INTO crdt_operations (id, document_id, operation_type, payload, vector_clock, node_id)
|
|
130
|
+
VALUES ($1, $2, $3, $4, $5, $6)`,
|
|
131
|
+
[
|
|
132
|
+
`op-${docId}-${i}`,
|
|
133
|
+
docId,
|
|
134
|
+
'update',
|
|
135
|
+
JSON.stringify({ field: 'counter', value: i }),
|
|
136
|
+
JSON.stringify({ [nodeId]: i }),
|
|
137
|
+
nodeId,
|
|
138
|
+
],
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const result = await client.query(
|
|
143
|
+
`SELECT * FROM crdt_operations WHERE document_id = $1 ORDER BY created_at`,
|
|
144
|
+
[docId],
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
expect(result.rows).toHaveLength(3)
|
|
148
|
+
|
|
149
|
+
// Verify vector clocks are preserved and can be used for ordering
|
|
150
|
+
const clocks = result.rows.map((r) => {
|
|
151
|
+
const vc = r.vector_clock as Record<string, number>
|
|
152
|
+
return vc[nodeId]
|
|
153
|
+
})
|
|
154
|
+
expect(clocks).toEqual([1, 2, 3])
|
|
155
|
+
})
|
|
156
|
+
})
|