@absolutejs/sync 1.7.8 → 1.7.9

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.
@@ -0,0 +1,107 @@
1
+ /**
2
+ * `@absolutejs/sync/mcp` — a Model Context Protocol server that surfaces
3
+ * a {@link SyncEngine}'s public read + mutate surface to MCP-aware
4
+ * clients (Claude Code, Cursor, custom agents).
5
+ *
6
+ * The agent gets four tools out of the box:
7
+ *
8
+ * - `list_collections` — registered collection names + kinds + tables.
9
+ * - `list_mutations` — registered mutation names.
10
+ * - `inspect_engine` — full {@link EngineInspection} snapshot
11
+ * (collections, mutations, schedules, readers, writers, recent
12
+ * changes).
13
+ * - `get_snapshot` — `{ collection, params?, ctx? }` → current rows.
14
+ * - `run_mutation` — `{ mutation, args, ctx? }` → result.
15
+ *
16
+ * Tools that take a `ctx` accept the agent's per-call override; if
17
+ * omitted, the server's `defaultCtx` is used. That's how multi-tenant
18
+ * gating works: the platform spawns one MCP server per tenant with
19
+ * `defaultCtx: { tenantId }`, and the agent can't reach across.
20
+ *
21
+ * ## Why
22
+ *
23
+ * Val.town's MCP server ([val.town/mcp](https://blog.val.town/mcp))
24
+ * exposes its entire UI through 36+ tools — that's the 2026 entry
25
+ * point for "let me run code on a platform." Cloudflare's MCP server
26
+ * does the same for the Cloudflare API, fitting "the entire surface
27
+ * through just two tools in under 1,000 tokens" via Code Mode
28
+ * ([blog.cloudflare.com/dynamic-workers](https://blog.cloudflare.com/dynamic-workers/)).
29
+ *
30
+ * Sync's MCP server is the same play for the sync engine itself: an
31
+ * agent can wire up a real-time leaderboard in three messages, then
32
+ * `run_mutation` to drive it without ever touching source files.
33
+ *
34
+ * ## Usage (stdio)
35
+ *
36
+ * ```ts
37
+ * // mcp-stdio-server.ts — point your MCP client (claude-code, etc.)
38
+ * // at this file's path.
39
+ * import { createSyncEngine, ... } from '@absolutejs/sync/engine';
40
+ * import { createSyncMcpServer, serveStdio } from '@absolutejs/sync/mcp';
41
+ *
42
+ * const engine = createSyncEngine();
43
+ * // ... register your collections / mutations ...
44
+ *
45
+ * const server = createSyncMcpServer({
46
+ * engine,
47
+ * defaultCtx: { tenantId: 'demo' },
48
+ * });
49
+ * await serveStdio(server);
50
+ * ```
51
+ *
52
+ * Run it as the MCP server: in your client's MCP config, add an entry
53
+ * like:
54
+ *
55
+ * ```json
56
+ * {
57
+ * "mcpServers": {
58
+ * "my-sync": {
59
+ * "command": "bun",
60
+ * "args": ["./mcp-stdio-server.ts"]
61
+ * }
62
+ * }
63
+ * }
64
+ * ```
65
+ *
66
+ * ## Optional peer dep
67
+ *
68
+ * `@modelcontextprotocol/sdk` is an optional peer — install only if
69
+ * you use the MCP surface. The dynamic `import()` below makes this
70
+ * subpath load-free when not used.
71
+ */
72
+ import type { SyncEngine } from '../engine/syncEngine';
73
+ /** Per-call context default + override behaviour. */
74
+ export type SyncMcpServerOptions = {
75
+ /** The engine to expose. */
76
+ engine: SyncEngine;
77
+ /**
78
+ * Default `ctx` for `get_snapshot` and `run_mutation`. Tools accept
79
+ * an optional `ctx` override on each call; if absent, this default
80
+ * is used. Set per-tenant when running one server per tenant.
81
+ */
82
+ defaultCtx?: unknown;
83
+ /**
84
+ * Display name advertised to the MCP client. Defaults to
85
+ * `'sync-engine'`. Useful when one client connects to multiple
86
+ * sync MCP servers (e.g. `'sync-prod'` / `'sync-staging'`).
87
+ */
88
+ name?: string;
89
+ /** Semver string surfaced to the MCP client. Defaults to `'0.1.0'`. */
90
+ version?: string;
91
+ };
92
+ /** A precompiled MCP server with the sync tools already registered. */
93
+ export type SyncMcpServer = {
94
+ /** The underlying SDK server — register additional tools on it if you want. */
95
+ server: import('@modelcontextprotocol/sdk/server/mcp.js').McpServer;
96
+ /** Wire to a transport (stdio, sse, custom). The SDK handles the rest. */
97
+ connect: (transport: import('@modelcontextprotocol/sdk/shared/transport.js').Transport) => Promise<void>;
98
+ };
99
+ export declare const createSyncMcpServer: (options: SyncMcpServerOptions) => Promise<SyncMcpServer>;
100
+ /**
101
+ * Convenience: wire a {@link SyncMcpServer} to stdio. This is the
102
+ * normal path for "I want claude-code to talk to my sync engine."
103
+ *
104
+ * Blocks until the transport closes. The server stays alive across
105
+ * many tool calls.
106
+ */
107
+ export declare const serveStdio: (syncMcp: SyncMcpServer | Promise<SyncMcpServer>) => Promise<void>;
package/dist/scheduled.js CHANGED
@@ -1,4 +1,18 @@
1
1
  // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
2
16
  var __require = import.meta.require;
3
17
 
4
18
  // src/scheduled.ts
@@ -31,5 +45,5 @@ export {
31
45
  scheduled
32
46
  };
33
47
 
34
- //# debugId=E19FF3C14F5836C764756E2164756E21
48
+ //# debugId=8CB5CC79F76D462364756E2164756E21
35
49
  //# sourceMappingURL=scheduled.js.map
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "import { Elysia } from 'elysia';\nimport { cron } from '@elysiajs/cron';\nimport type { SyncEngine } from './engine/syncEngine';\n\nexport type ScheduledOptions = {\n\t/** The engine whose registered schedules (see `registerSchedule`) to run. */\n\tengine: SyncEngine;\n\t/** Prefix for the cron job names registered on Elysia's store. Default `sync`. */\n\tprefix?: string;\n\t/** Called when a scheduled run throws (the batch is rolled back). */\n\tonError?: (name: string, error: unknown) => void;\n};\n\n/**\n * Elysia plugin that fires the engine's registered scheduled functions on their\n * cron patterns, via `@elysiajs/cron`. Cron decides *when*; the engine runs the\n * schedule and makes its writes go live through the change feed (and a schedule\n * can `enqueue` into `@absolutejs/queue` for durable, retryable work).\n *\n * Register schedules with `engine.registerSchedule(...)` before mounting this, so\n * each one becomes a cron job named `<prefix>:<schedule.name>`. Mount once.\n */\nexport const scheduled = ({\n\tengine,\n\tprefix = 'sync',\n\tonError\n}: ScheduledOptions) => {\n\tconst run = (name: string) => () => {\n\t\tvoid engine.runSchedule(name).catch((error) => {\n\t\t\tif (onError === undefined) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tonError(name, error);\n\t\t});\n\t};\n\n\t// `.use` registers the cron job on this instance (mutating), so a loop builds\n\t// one plugin carrying every schedule's cron trigger.\n\tconst app = new Elysia({ name: '@absolutejs/sync/scheduled' });\n\tfor (const schedule of engine.listSchedules()) {\n\t\tapp.use(\n\t\t\tcron({\n\t\t\t\tname: `${prefix}:${schedule.name}`,\n\t\t\t\tpattern: schedule.pattern,\n\t\t\t\trun: run(schedule.name)\n\t\t\t})\n\t\t);\n\t}\n\treturn app;\n};\n"
6
6
  ],
7
- "mappings": ";;;;AAAA;AACA;AAqBO,IAAM,YAAY;AAAA,EACxB;AAAA,EACA,SAAS;AAAA,EACT;AAAA,MACuB;AAAA,EACvB,MAAM,MAAM,CAAC,SAAiB,MAAM;AAAA,IAC9B,OAAO,YAAY,IAAI,EAAE,MAAM,CAAC,UAAU;AAAA,MAC9C,IAAI,YAAY,WAAW;AAAA,QAC1B,MAAM;AAAA,MACP;AAAA,MACA,QAAQ,MAAM,KAAK;AAAA,KACnB;AAAA;AAAA,EAKF,MAAM,MAAM,IAAI,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAAA,EAC7D,WAAW,YAAY,OAAO,cAAc,GAAG;AAAA,IAC9C,IAAI,IACH,KAAK;AAAA,MACJ,MAAM,GAAG,UAAU,SAAS;AAAA,MAC5B,SAAS,SAAS;AAAA,MAClB,KAAK,IAAI,SAAS,IAAI;AAAA,IACvB,CAAC,CACF;AAAA,EACD;AAAA,EACA,OAAO;AAAA;",
8
- "debugId": "E19FF3C14F5836C764756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AACA;AAqBO,IAAM,YAAY;AAAA,EACxB;AAAA,EACA,SAAS;AAAA,EACT;AAAA,MACuB;AAAA,EACvB,MAAM,MAAM,CAAC,SAAiB,MAAM;AAAA,IAC9B,OAAO,YAAY,IAAI,EAAE,MAAM,CAAC,UAAU;AAAA,MAC9C,IAAI,YAAY,WAAW;AAAA,QAC1B,MAAM;AAAA,MACP;AAAA,MACA,QAAQ,MAAM,KAAK;AAAA,KACnB;AAAA;AAAA,EAKF,MAAM,MAAM,IAAI,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAAA,EAC7D,WAAW,YAAY,OAAO,cAAc,GAAG;AAAA,IAC9C,IAAI,IACH,KAAK;AAAA,MACJ,MAAM,GAAG,UAAU,SAAS;AAAA,MAC5B,SAAS,SAAS;AAAA,MAClB,KAAK,IAAI,SAAS,IAAI;AAAA,IACvB,CAAC,CACF;AAAA,EACD;AAAA,EACA,OAAO;AAAA;",
8
+ "debugId": "8CB5CC79F76D462364756E2164756E21",
9
9
  "names": []
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/sync",
3
- "version": "1.7.8",
3
+ "version": "1.7.9",
4
4
  "description": "Lightweight reactive-push and write-behind-cache primitives for Elysia and the AbsoluteJS ecosystem — kill polling and keep a remote store off your hot path, without adopting a whole sync-engine backend.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,6 +23,11 @@
23
23
  "import": "./dist/scheduled.js",
24
24
  "default": "./dist/scheduled.js"
25
25
  },
26
+ "./mcp": {
27
+ "types": "./dist/mcp/index.d.ts",
28
+ "import": "./dist/mcp/index.js",
29
+ "default": "./dist/mcp/index.js"
30
+ },
26
31
  "./client": {
27
32
  "types": "./dist/client/index.d.ts",
28
33
  "import": "./dist/client/index.js",
@@ -121,6 +126,7 @@
121
126
  ],
122
127
  "peerDependencies": {
123
128
  "@absolutejs/isolated-jsc": ">= 0.6.0",
129
+ "@modelcontextprotocol/sdk": ">= 1.29.0",
124
130
  "@angular/core": ">= 21.0.0",
125
131
  "@elysiajs/cron": ">= 1.4.0",
126
132
  "drizzle-orm": ">= 0.44.0",
@@ -133,6 +139,9 @@
133
139
  "@absolutejs/isolated-jsc": {
134
140
  "optional": true
135
141
  },
142
+ "@modelcontextprotocol/sdk": {
143
+ "optional": true
144
+ },
136
145
  "@angular/core": {
137
146
  "optional": true
138
147
  },
@@ -161,6 +170,7 @@
161
170
  "@angular/core": "^21.0.0",
162
171
  "@elysiajs/cron": "^1.4.2",
163
172
  "@elysiajs/eden": "^1.4.9",
173
+ "@modelcontextprotocol/sdk": "^1.29.0",
164
174
  "@types/bun": "latest",
165
175
  "@types/react": "^19.2.0",
166
176
  "drizzle-orm": "^0.45.2",