@ziprack/sdk 0.1.1 → 0.2.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/dist/broadcast/index.d.ts +8 -1
- package/dist/core/mock/MockRack.d.ts +6 -0
- package/dist/core/types.d.ts +4 -0
- package/dist/docs/README.md +52 -0
- package/dist/docs/activity.md +140 -0
- package/dist/docs/ai.md +159 -0
- package/dist/docs/applet-packages.md +118 -0
- package/dist/docs/attempts.md +184 -0
- package/dist/docs/auth.md +106 -0
- package/dist/docs/broadcast.md +226 -0
- package/dist/docs/conformance.md +102 -0
- package/dist/docs/database.md +176 -0
- package/dist/docs/extending.md +256 -0
- package/dist/docs/installation.md +185 -0
- package/dist/docs/introduction.md +124 -0
- package/dist/docs/manifest.md +209 -0
- package/dist/docs/media.md +85 -0
- package/dist/docs/protocol.md +121 -0
- package/dist/docs/publishing.md +127 -0
- package/dist/docs/reporting.md +146 -0
- package/dist/docs/sdk.md +258 -0
- package/dist/docs/security.md +127 -0
- package/dist/docs/storage.md +131 -0
- package/dist/docs/studio.md +425 -0
- package/dist/docs/versioning.md +101 -0
- package/dist/docs/ziprack-1-authoring.md +182 -0
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/bin.d.ts +2 -0
- package/dist/mcp/bin.js +3 -0
- package/dist/mcp/docs.d.ts +31 -0
- package/dist/mcp/docs.js +107 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/rpc.d.ts +33 -0
- package/dist/mcp/rpc.js +86 -0
- package/dist/mcp/server.d.ts +23 -0
- package/dist/mcp/server.js +55 -0
- package/dist/mcp/tools.d.ts +20 -0
- package/dist/mcp/tools.js +106 -0
- package/dist/{store-DSV5q7C7.js → store-BXGon4iJ.js} +15 -5
- package/dist/store-BXGon4iJ.js.map +1 -0
- package/dist/testing.js +1 -1
- package/dist/ziprack-sdk.iife.js +1 -1
- package/dist/ziprack-sdk.iife.js.map +1 -1
- package/package.json +10 -4
- package/dist/store-DSV5q7C7.js.map +0 -1
package/dist/mcp/docs.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
export const GUIDELINES = 'ziprack-1-authoring';
|
|
4
|
+
/**
|
|
5
|
+
* The docs are copied into `dist/docs/` when the SDK is built, so the set an
|
|
6
|
+
* applet project reads is the set published with the SDK version it installed.
|
|
7
|
+
*/
|
|
8
|
+
export function loadDocs(directory = fileURLToPath(new URL('../docs/', import.meta.url))) {
|
|
9
|
+
const files = readdirSync(directory).filter((file) => file.endsWith('.md'));
|
|
10
|
+
const read = (name) => readFileSync(`${directory}/${name}.md`, 'utf8');
|
|
11
|
+
// docs/README.md is the index: its link order is the reading order.
|
|
12
|
+
const ordered = [];
|
|
13
|
+
if (files.includes('README.md')) {
|
|
14
|
+
for (const match of read('README').matchAll(/\]\(([\w.-]+)\.md\)/g)) {
|
|
15
|
+
if (!ordered.includes(match[1])) {
|
|
16
|
+
ordered.push(match[1]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
for (const file of files.sort()) {
|
|
21
|
+
const name = file.slice(0, -3);
|
|
22
|
+
if (name !== 'README' && !ordered.includes(name)) {
|
|
23
|
+
ordered.push(name);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return ordered
|
|
27
|
+
.filter((name) => files.includes(`${name}.md`))
|
|
28
|
+
.map((name) => parseDoc(name, read(name)));
|
|
29
|
+
}
|
|
30
|
+
export function parseDoc(name, text) {
|
|
31
|
+
const lines = text.split('\n');
|
|
32
|
+
const title = lines.find((line) => line.startsWith('# '))?.slice(2).trim() ?? name;
|
|
33
|
+
const sections = [];
|
|
34
|
+
let current = { anchor: null, heading: title, text: '' };
|
|
35
|
+
let buffer = [];
|
|
36
|
+
let pendingAnchor = null;
|
|
37
|
+
let fenced = false;
|
|
38
|
+
const flush = () => {
|
|
39
|
+
current.text = buffer.join('\n').trim();
|
|
40
|
+
if (current.text !== '') {
|
|
41
|
+
sections.push(current);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
for (const line of lines) {
|
|
45
|
+
if (line.startsWith('```')) {
|
|
46
|
+
fenced = !fenced;
|
|
47
|
+
}
|
|
48
|
+
const anchor = fenced ? null : /^<a name="([^"]+)"><\/a>\s*$/.exec(line);
|
|
49
|
+
if (anchor !== null) {
|
|
50
|
+
pendingAnchor = anchor[1];
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!fenced && line.startsWith('## ')) {
|
|
54
|
+
flush();
|
|
55
|
+
const heading = line.slice(3).trim();
|
|
56
|
+
current = { anchor: pendingAnchor ?? slug(heading), heading, text: '' };
|
|
57
|
+
buffer = [line];
|
|
58
|
+
pendingAnchor = null;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
buffer.push(line);
|
|
62
|
+
}
|
|
63
|
+
flush();
|
|
64
|
+
return { name, title, text, sections };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Plain term frequency, with heading and title hits weighted up and an exact
|
|
68
|
+
* phrase match weighted most. The corpus is a few hundred sections; anything
|
|
69
|
+
* cleverer would be harder to predict than it is worth.
|
|
70
|
+
*/
|
|
71
|
+
export function searchDocs(docs, queries, limit) {
|
|
72
|
+
const hits = [];
|
|
73
|
+
for (const doc of docs) {
|
|
74
|
+
const title = doc.title.toLowerCase();
|
|
75
|
+
for (const section of doc.sections) {
|
|
76
|
+
const heading = section.heading.toLowerCase();
|
|
77
|
+
const body = section.text.toLowerCase();
|
|
78
|
+
let score = 0;
|
|
79
|
+
for (const query of queries) {
|
|
80
|
+
const phrase = query.trim().toLowerCase();
|
|
81
|
+
const terms = phrase.match(/[a-z0-9_@$.-]+/g)?.map((term) => term.replace(/^[.-]+|[.-]+$/g, '')).filter((term) => term.length > 1) ?? [];
|
|
82
|
+
if (terms.length > 1 && body.includes(phrase)) {
|
|
83
|
+
score += 10;
|
|
84
|
+
}
|
|
85
|
+
for (const term of terms) {
|
|
86
|
+
score += occurrences(body, term) + 5 * occurrences(heading, term) + 3 * occurrences(title, term);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (score > 0) {
|
|
90
|
+
hits.push({ doc, section, score });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return hits.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
95
|
+
}
|
|
96
|
+
function occurrences(haystack, needle) {
|
|
97
|
+
let count = 0;
|
|
98
|
+
let at = haystack.indexOf(needle);
|
|
99
|
+
while (at !== -1) {
|
|
100
|
+
count++;
|
|
101
|
+
at = haystack.indexOf(needle, at + needle.length);
|
|
102
|
+
}
|
|
103
|
+
return count;
|
|
104
|
+
}
|
|
105
|
+
function slug(heading) {
|
|
106
|
+
return heading.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
107
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Readable, Writable } from 'node:stream';
|
|
2
|
+
/**
|
|
3
|
+
* MCP over stdio is line-delimited JSON-RPC 2.0. That is little enough protocol
|
|
4
|
+
* to own outright, which keeps the studio dependency-free the way the SDK is.
|
|
5
|
+
*/
|
|
6
|
+
export interface RpcRequest {
|
|
7
|
+
jsonrpc: '2.0';
|
|
8
|
+
id?: string | number | null;
|
|
9
|
+
method: string;
|
|
10
|
+
params?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export interface RpcError {
|
|
13
|
+
code: number;
|
|
14
|
+
message: string;
|
|
15
|
+
data?: unknown;
|
|
16
|
+
}
|
|
17
|
+
export declare const PARSE_ERROR = -32700;
|
|
18
|
+
export declare const INVALID_REQUEST = -32600;
|
|
19
|
+
export declare const METHOD_NOT_FOUND = -32601;
|
|
20
|
+
export declare const INVALID_PARAMS = -32602;
|
|
21
|
+
export declare const INTERNAL_ERROR = -32603;
|
|
22
|
+
export declare class RpcFailure extends Error {
|
|
23
|
+
readonly code: number;
|
|
24
|
+
readonly data?: unknown | undefined;
|
|
25
|
+
constructor(code: number, message: string, data?: unknown | undefined);
|
|
26
|
+
}
|
|
27
|
+
export type RpcHandler = (params: Record<string, unknown>, method: string) => Promise<unknown> | unknown;
|
|
28
|
+
export interface RpcConnection {
|
|
29
|
+
/** Resolves when the input stream ends. */
|
|
30
|
+
done: Promise<void>;
|
|
31
|
+
notify(method: string, params?: Record<string, unknown>): void;
|
|
32
|
+
}
|
|
33
|
+
export declare function serve(input: Readable, output: Writable, handlers: Map<string, RpcHandler>): RpcConnection;
|
package/dist/mcp/rpc.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const PARSE_ERROR = -32700;
|
|
2
|
+
export const INVALID_REQUEST = -32600;
|
|
3
|
+
export const METHOD_NOT_FOUND = -32601;
|
|
4
|
+
export const INVALID_PARAMS = -32602;
|
|
5
|
+
export const INTERNAL_ERROR = -32603;
|
|
6
|
+
export class RpcFailure extends Error {
|
|
7
|
+
code;
|
|
8
|
+
data;
|
|
9
|
+
constructor(code, message, data) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.data = data;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function serve(input, output, handlers) {
|
|
16
|
+
const write = (payload) => {
|
|
17
|
+
output.write(`${JSON.stringify(payload)}\n`);
|
|
18
|
+
};
|
|
19
|
+
// One request at a time. Tools read and write the document, so overlapping
|
|
20
|
+
// them would let a later call answer from the state before an earlier one's
|
|
21
|
+
// save — the kind of ordering bug an assistant cannot see or work around.
|
|
22
|
+
let queue = Promise.resolve();
|
|
23
|
+
const done = new Promise((resolve) => {
|
|
24
|
+
let buffer = '';
|
|
25
|
+
input.setEncoding('utf8');
|
|
26
|
+
input.on('data', (chunk) => {
|
|
27
|
+
buffer += chunk;
|
|
28
|
+
let newline = buffer.indexOf('\n');
|
|
29
|
+
while (newline !== -1) {
|
|
30
|
+
const line = buffer.slice(0, newline).trim();
|
|
31
|
+
buffer = buffer.slice(newline + 1);
|
|
32
|
+
if (line !== '') {
|
|
33
|
+
queue = queue.then(() => handle(line, handlers, write));
|
|
34
|
+
}
|
|
35
|
+
newline = buffer.indexOf('\n');
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
// The queue is drained before the caller is told the connection is over,
|
|
39
|
+
// so a request on the last line still gets its answer.
|
|
40
|
+
input.on('end', () => void queue.then(resolve));
|
|
41
|
+
input.on('close', () => void queue.then(resolve));
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
done,
|
|
45
|
+
notify: (method, params) => write({ jsonrpc: '2.0', method, params: params ?? {} }),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function handle(line, handlers, write) {
|
|
49
|
+
let request;
|
|
50
|
+
try {
|
|
51
|
+
request = JSON.parse(line);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
write({ jsonrpc: '2.0', id: null, error: { code: PARSE_ERROR, message: 'Invalid JSON.' } });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (typeof request.method !== 'string') {
|
|
58
|
+
write({ jsonrpc: '2.0', id: request.id ?? null, error: { code: INVALID_REQUEST, message: 'Missing method.' } });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const handler = handlers.get(request.method);
|
|
62
|
+
// A notification has no id and, per JSON-RPC, gets no answer at all —
|
|
63
|
+
// including for `notifications/initialized`, which every client sends.
|
|
64
|
+
const isNotification = request.id === undefined || request.id === null;
|
|
65
|
+
if (handler === undefined) {
|
|
66
|
+
if (!isNotification) {
|
|
67
|
+
write({ jsonrpc: '2.0', id: request.id, error: { code: METHOD_NOT_FOUND, message: `Unknown method [${request.method}].` } });
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const result = await handler(request.params ?? {}, request.method);
|
|
73
|
+
if (!isNotification) {
|
|
74
|
+
write({ jsonrpc: '2.0', id: request.id, result });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (isNotification) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const failure = error instanceof RpcFailure
|
|
82
|
+
? { code: error.code, message: error.message, data: error.data }
|
|
83
|
+
: { code: INTERNAL_ERROR, message: error instanceof Error ? error.message : String(error) };
|
|
84
|
+
write({ jsonrpc: '2.0', id: request.id, error: failure });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type RpcHandler } from './rpc.js';
|
|
2
|
+
import { type ToolDefinition } from './tools.js';
|
|
3
|
+
export declare const PROTOCOL_VERSION = "2024-11-05";
|
|
4
|
+
export interface ServerInfo {
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
instructions: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const DOCS_INSTRUCTIONS = "zipRACK applet docs, matched to the installed @ziprack/sdk. Call ziprack_guidelines before writing or changing applet code, and ziprack_search_docs before guessing at an SDK method, manifest field or error code.";
|
|
10
|
+
/** Wires a tool set onto the MCP method surface a client expects. */
|
|
11
|
+
export declare function session(tools: ToolDefinition[], info: ServerInfo): Map<string, RpcHandler>;
|
|
12
|
+
/**
|
|
13
|
+
* Tool results are text content blocks. Structured payloads go through as
|
|
14
|
+
* indented JSON, which is what an assistant can actually read back.
|
|
15
|
+
*/
|
|
16
|
+
export declare function content(payload: unknown): {
|
|
17
|
+
content: Array<{
|
|
18
|
+
type: 'text';
|
|
19
|
+
text: string;
|
|
20
|
+
}>;
|
|
21
|
+
isError?: boolean;
|
|
22
|
+
};
|
|
23
|
+
export declare function startDocsMcp(): Promise<void>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { INVALID_PARAMS, RpcFailure, serve } from './rpc.js';
|
|
2
|
+
import { SDK_VERSION, docsTools } from './tools.js';
|
|
3
|
+
export const PROTOCOL_VERSION = '2024-11-05';
|
|
4
|
+
export const DOCS_INSTRUCTIONS = 'zipRACK applet docs, matched to the installed @ziprack/sdk. Call ziprack_guidelines before writing or changing applet code, and ziprack_search_docs before guessing at an SDK method, manifest field or error code.';
|
|
5
|
+
/** Wires a tool set onto the MCP method surface a client expects. */
|
|
6
|
+
export function session(tools, info) {
|
|
7
|
+
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
8
|
+
const handlers = new Map();
|
|
9
|
+
handlers.set('initialize', () => ({
|
|
10
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
11
|
+
capabilities: { tools: { listChanged: false } },
|
|
12
|
+
serverInfo: { name: info.name, version: info.version },
|
|
13
|
+
instructions: info.instructions,
|
|
14
|
+
}));
|
|
15
|
+
handlers.set('notifications/initialized', () => null);
|
|
16
|
+
handlers.set('ping', () => ({}));
|
|
17
|
+
handlers.set('tools/list', () => ({
|
|
18
|
+
tools: tools.map((tool) => ({
|
|
19
|
+
name: tool.name,
|
|
20
|
+
description: tool.description,
|
|
21
|
+
inputSchema: tool.inputSchema,
|
|
22
|
+
})),
|
|
23
|
+
}));
|
|
24
|
+
handlers.set('tools/call', async (params) => {
|
|
25
|
+
const name = params.name;
|
|
26
|
+
if (typeof name !== 'string') {
|
|
27
|
+
throw new RpcFailure(INVALID_PARAMS, 'tools/call needs a tool name.');
|
|
28
|
+
}
|
|
29
|
+
const tool = byName.get(name);
|
|
30
|
+
if (tool === undefined) {
|
|
31
|
+
throw new RpcFailure(INVALID_PARAMS, `Unknown tool [${name}].`);
|
|
32
|
+
}
|
|
33
|
+
const args = params.arguments;
|
|
34
|
+
return content(await tool.run(args === null || typeof args !== 'object' ? {} : args));
|
|
35
|
+
});
|
|
36
|
+
return handlers;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Tool results are text content blocks. Structured payloads go through as
|
|
40
|
+
* indented JSON, which is what an assistant can actually read back.
|
|
41
|
+
*/
|
|
42
|
+
export function content(payload) {
|
|
43
|
+
if (typeof payload === 'string') {
|
|
44
|
+
return { content: [{ type: 'text', text: payload }] };
|
|
45
|
+
}
|
|
46
|
+
if (payload !== null && typeof payload === 'object' && 'isError' in payload) {
|
|
47
|
+
const { isError, ...rest } = payload;
|
|
48
|
+
return { content: [{ type: 'text', text: JSON.stringify(rest, null, 2) }], isError };
|
|
49
|
+
}
|
|
50
|
+
return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
|
|
51
|
+
}
|
|
52
|
+
export async function startDocsMcp() {
|
|
53
|
+
const handlers = session(docsTools(), { name: 'ziprack', version: SDK_VERSION, instructions: DOCS_INSTRUCTIONS });
|
|
54
|
+
await serve(process.stdin, process.stdout, handlers).done;
|
|
55
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Doc } from './docs.js';
|
|
2
|
+
export interface ToolDefinition {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: 'object';
|
|
7
|
+
properties?: Record<string, object>;
|
|
8
|
+
required?: string[];
|
|
9
|
+
additionalProperties?: boolean;
|
|
10
|
+
};
|
|
11
|
+
/** Returned as the tool result; objects are serialised as JSON text. */
|
|
12
|
+
run(args: Record<string, unknown>): Promise<unknown> | unknown;
|
|
13
|
+
}
|
|
14
|
+
export declare const SDK_VERSION: string;
|
|
15
|
+
/**
|
|
16
|
+
* Docs and guidelines for the SDK version this server was installed with.
|
|
17
|
+
* Every answer names that version, so an assistant never mistakes it for
|
|
18
|
+
* whatever it remembers of an older one.
|
|
19
|
+
*/
|
|
20
|
+
export declare function docsTools(docs?: Doc[]): ToolDefinition[];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { GUIDELINES, loadDocs, searchDocs } from './docs.js';
|
|
3
|
+
export const SDK_VERSION = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8')).version;
|
|
4
|
+
/**
|
|
5
|
+
* Docs and guidelines for the SDK version this server was installed with.
|
|
6
|
+
* Every answer names that version, so an assistant never mistakes it for
|
|
7
|
+
* whatever it remembers of an older one.
|
|
8
|
+
*/
|
|
9
|
+
export function docsTools(docs = loadDocs()) {
|
|
10
|
+
const byName = new Map(docs.map((doc) => [doc.name, doc]));
|
|
11
|
+
const header = `zipRACK docs for @ziprack/sdk ${SDK_VERSION}`;
|
|
12
|
+
const unknownDoc = (name) => ({
|
|
13
|
+
isError: true,
|
|
14
|
+
error: `Unknown doc [${name}].`,
|
|
15
|
+
sdk_version: SDK_VERSION,
|
|
16
|
+
docs: docs.map((doc) => doc.name),
|
|
17
|
+
});
|
|
18
|
+
return [
|
|
19
|
+
{
|
|
20
|
+
name: 'ziprack_guidelines',
|
|
21
|
+
description: 'The rules every zipRACK applet must follow: mental model, package layout, manifest, SDK usage, runtime constraints and the pre-upload checklist. Read this before writing or changing applet code.',
|
|
22
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
23
|
+
run: () => {
|
|
24
|
+
const guidelines = byName.get(GUIDELINES);
|
|
25
|
+
return guidelines === undefined ? unknownDoc(GUIDELINES) : `${header}\n\n${guidelines.text}`;
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'ziprack_list_docs',
|
|
30
|
+
description: 'Every zipRACK doc in reading order, with its section anchors. Use the names with ziprack_read_doc.',
|
|
31
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
32
|
+
run: () => ({
|
|
33
|
+
sdk_version: SDK_VERSION,
|
|
34
|
+
docs: docs.map((doc) => ({
|
|
35
|
+
name: doc.name,
|
|
36
|
+
title: doc.title,
|
|
37
|
+
sections: doc.sections
|
|
38
|
+
.filter((section) => section.anchor !== null)
|
|
39
|
+
.map((section) => ({ anchor: section.anchor, heading: section.heading })),
|
|
40
|
+
})),
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'ziprack_search_docs',
|
|
45
|
+
description: 'Search the zipRACK docs for the installed SDK version and return the best-matching sections in full. Pass several phrasings at once, e.g. ["setState resume", "attempt state"]. Search before guessing at an SDK method, manifest field or error code.',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
queries: { type: 'array', items: { type: 'string' }, minItems: 1, description: 'Search phrases; a section scores on any of them.' },
|
|
50
|
+
limit: { type: 'integer', minimum: 1, maximum: 20, description: 'Sections to return. Defaults to 5.' },
|
|
51
|
+
},
|
|
52
|
+
required: ['queries'],
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
},
|
|
55
|
+
run: (args) => {
|
|
56
|
+
const queries = Array.isArray(args.queries) ? args.queries.filter((query) => typeof query === 'string') : [];
|
|
57
|
+
if (queries.length === 0) {
|
|
58
|
+
return { isError: true, error: 'queries must be a non-empty array of strings.' };
|
|
59
|
+
}
|
|
60
|
+
const limit = typeof args.limit === 'number' ? Math.min(Math.max(Math.trunc(args.limit), 1), 20) : 5;
|
|
61
|
+
const hits = searchDocs(docs, queries, limit);
|
|
62
|
+
if (hits.length === 0) {
|
|
63
|
+
return `${header}\n\nNo section matches ${JSON.stringify(queries)}. ziprack_list_docs shows what is covered.`;
|
|
64
|
+
}
|
|
65
|
+
return [header, ...hits.map(({ doc, section }) => {
|
|
66
|
+
const where = section.anchor === null ? doc.name : `${doc.name}#${section.anchor}`;
|
|
67
|
+
return `---\n[${where}] ${doc.title}\n\n${section.text}`;
|
|
68
|
+
})].join('\n\n');
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'ziprack_read_doc',
|
|
73
|
+
description: 'One zipRACK doc in full, or one section of it by anchor.',
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {
|
|
77
|
+
doc: { type: 'string', description: 'A doc name from ziprack_list_docs, e.g. manifest.' },
|
|
78
|
+
section: { type: 'string', description: 'A section anchor, e.g. acks-and-errors.' },
|
|
79
|
+
},
|
|
80
|
+
required: ['doc'],
|
|
81
|
+
additionalProperties: false,
|
|
82
|
+
},
|
|
83
|
+
run: (args) => {
|
|
84
|
+
const name = String(args.doc ?? '').replace(/\.md$/, '');
|
|
85
|
+
const doc = byName.get(name);
|
|
86
|
+
if (doc === undefined) {
|
|
87
|
+
return unknownDoc(name);
|
|
88
|
+
}
|
|
89
|
+
if (typeof args.section !== 'string' || args.section === '') {
|
|
90
|
+
return `${header}\n\n${doc.text}`;
|
|
91
|
+
}
|
|
92
|
+
const anchor = args.section.replace(/^#/, '');
|
|
93
|
+
const section = doc.sections.find((candidate) => candidate.anchor === anchor);
|
|
94
|
+
if (section === undefined) {
|
|
95
|
+
return {
|
|
96
|
+
isError: true,
|
|
97
|
+
error: `Doc [${name}] has no section [${anchor}].`,
|
|
98
|
+
sdk_version: SDK_VERSION,
|
|
99
|
+
sections: doc.sections.flatMap((candidate) => candidate.anchor === null ? [] : [candidate.anchor]),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return `${header}\n\n${section.text}`;
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
}
|
|
@@ -125,6 +125,8 @@ class O {
|
|
|
125
125
|
return this.stateSet(e);
|
|
126
126
|
case "broadcast:presence":
|
|
127
127
|
return { ok: !0, data: { members: this.members() } };
|
|
128
|
+
case "broadcast:invite":
|
|
129
|
+
return this.invite();
|
|
128
130
|
case "broadcast:claim":
|
|
129
131
|
return this.claim();
|
|
130
132
|
case "broadcast:transfer":
|
|
@@ -377,6 +379,14 @@ class O {
|
|
|
377
379
|
break;
|
|
378
380
|
}
|
|
379
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* A mock room is two tabs of the dev server, so the invite is this page:
|
|
384
|
+
* scan it and the second tab joins over BroadcastChannel, exactly as the
|
|
385
|
+
* real join URL would.
|
|
386
|
+
*/
|
|
387
|
+
invite() {
|
|
388
|
+
return { ok: !0, data: { code: "MOCK01", url: typeof location > "u" ? "https://rack.test/r/MOCK01" : location.origin + location.pathname } };
|
|
389
|
+
}
|
|
380
390
|
setRole(t) {
|
|
381
391
|
this.role = t, this.send({ t: "role", from: this.member() }), this.pushEvent({ channel: "$room", event: "role", payload: { role: t, participant_id: this.participantId } });
|
|
382
392
|
}
|
|
@@ -413,7 +423,7 @@ function u(n, t) {
|
|
|
413
423
|
}
|
|
414
424
|
return e === "array" ? [u(n.items, t)] : e === "number" || e === "integer" ? typeof n.minimum == "number" ? n.minimum : 3 : e === "boolean" ? !0 : Array.isArray(n.enum) ? n.enum[0] : "mock";
|
|
415
425
|
}
|
|
416
|
-
class
|
|
426
|
+
class M {
|
|
417
427
|
constructor(t) {
|
|
418
428
|
this.rack = t, this.kind = "mock";
|
|
419
429
|
}
|
|
@@ -436,7 +446,7 @@ class I {
|
|
|
436
446
|
this.rack.dispose();
|
|
437
447
|
}
|
|
438
448
|
}
|
|
439
|
-
class
|
|
449
|
+
class I {
|
|
440
450
|
constructor() {
|
|
441
451
|
this.data = /* @__PURE__ */ new Map();
|
|
442
452
|
}
|
|
@@ -491,14 +501,14 @@ class E {
|
|
|
491
501
|
export {
|
|
492
502
|
y as F,
|
|
493
503
|
E as L,
|
|
494
|
-
|
|
504
|
+
M,
|
|
495
505
|
b as P,
|
|
496
506
|
v as a,
|
|
497
507
|
O as b,
|
|
498
508
|
w as c,
|
|
499
509
|
S as d,
|
|
500
|
-
|
|
510
|
+
I as e,
|
|
501
511
|
$ as i,
|
|
502
512
|
_ as n
|
|
503
513
|
};
|
|
504
|
-
//# sourceMappingURL=store-
|
|
514
|
+
//# sourceMappingURL=store-BXGon4iJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-BXGon4iJ.js","sources":["../src/core/protocol.ts","../src/core/mock/MockRack.ts","../src/core/mock/MockTransport.ts","../src/core/mock/store.ts"],"sourcesContent":["export const PROTOCOL_NAMESPACE = 'ziprack' as const;\nexport const PROTOCOL_VERSION = 1 as const;\nexport const FORMAT = 'ziprack/1' as const;\n\nexport interface Envelope<T = unknown> {\n ns: typeof PROTOCOL_NAMESPACE;\n v: typeof PROTOCOL_VERSION;\n type: string;\n requestId?: string;\n payload?: T;\n}\n\nlet requestCounter = 0;\n\nexport function newRequestId(): string {\n const cryptoRef = typeof globalThis.crypto !== 'undefined' ? globalThis.crypto : undefined;\n if (cryptoRef && typeof cryptoRef.randomUUID === 'function') {\n return cryptoRef.randomUUID();\n }\n requestCounter += 1;\n\n return `req-${Date.now().toString(36)}-${requestCounter.toString(36)}`;\n}\n\nexport function createEnvelope<T>(type: string, payload?: T, requestId?: string): Envelope<T> {\n const envelope: Envelope<T> = { ns: PROTOCOL_NAMESPACE, v: PROTOCOL_VERSION, type, payload };\n if (requestId !== undefined) {\n envelope.requestId = requestId;\n }\n\n return envelope;\n}\n\nexport function isEnvelope(data: unknown): data is Envelope {\n if (typeof data !== 'object' || data === null) {\n return false;\n }\n const candidate = data as Partial<Envelope>;\n\n return candidate.ns === PROTOCOL_NAMESPACE && candidate.v === PROTOCOL_VERSION && typeof candidate.type === 'string';\n}\n\n/** Capability id from a message type (\"db:create\" -> \"db\"). */\nexport function capabilityOf(type: string): string {\n const index = type.indexOf(':');\n\n return index === -1 ? type : type.slice(0, index);\n}\n","import { capabilityOf } from '../protocol';\nimport type { AckResult, JsonObject, LaunchData, RackEvent, RoomMember, RoomRole } from '../types';\nimport type { RecordRow, WhereClause } from '../../db';\nimport type { StoredFile } from '../../storage';\nimport type { Store } from './store';\n\nexport interface MockManifest {\n schema?: string;\n slug: string;\n name: string;\n version: string;\n requires?: { capabilities?: string[]; profile?: string[] };\n media?: Array<{ id: string; provider: string; key: string }>;\n activities?: Array<{ id: string; type: string; label: string; scale?: unknown; segment?: string | null; sequence?: number }>;\n collections?: Array<{ name: string; scope: string; schema?: JsonObject }>;\n uploads?: Array<{ name: string; scope: string; mime?: string[]; max_bytes?: number }>;\n prompts?: Array<{ id: string; mode: 'analysis' | 'chat'; output_schema?: JsonObject }>;\n broadcast?: { facilitator_events?: string[]; channels?: string[]; mock_mode?: 'first_in' | 'opt_in' };\n [key: string]: unknown;\n}\n\nexport type AiMockHandler = (vars: JsonObject, mode: 'analysis' | 'chat', message?: string) => unknown | Promise<unknown>;\n\nexport interface MockRackOptions {\n /** Whether undeclared capabilities are refused, as a real Rack would. Default true when a manifest is present. */\n strict?: boolean;\n log?: (type: string, payload: unknown) => void;\n participantId?: number;\n participantName?: string;\n /** Force the mock room role instead of deriving it from the assignment mode. */\n role?: RoomRole;\n}\n\nexport type MockOutcome = AckResult | { stream: AsyncIterable<JsonObject>; final: () => JsonObject };\n\n/**\n * An in-memory Rack that services every capability so an applet can be built\n * and QA'd standalone. Shared by the browser mock transport (localStorage) and\n * the testing FakeHost (memory).\n */\nexport class MockRack {\n public readonly participantId: number;\n\n public readonly participantName: string;\n\n public readonly statements: Array<JsonObject & { id: string }> = [];\n\n public readonly events: RackEvent[] = [];\n\n private readonly aiHandlers = new Map<string, AiMockHandler>();\n\n private readonly chatHistory = new Map<string, Array<{ role: string; content: string }>>();\n\n private readonly blobs = new Map<string, string>();\n\n private readonly eventListeners = new Set<(event: RackEvent) => void>();\n\n private readonly roomMembers = new Map<number, RoomMember & { lastSeen: number; joinedAt?: number }>();\n\n private roomState: Record<string, { value: unknown; version: number }> = {};\n\n private role: RoomRole = 'participant';\n\n private readonly joinedAt = Date.now() + Math.random();\n\n private channel: BroadcastChannel | null = null;\n\n private heartbeat: ReturnType<typeof setInterval> | null = null;\n\n public constructor(\n public readonly manifest: MockManifest | null,\n private readonly store: Store,\n private readonly options: MockRackOptions = {},\n ) {\n this.participantId = options.participantId ?? Math.floor(Math.random() * 1_000_000) + 1;\n this.participantName = options.participantName ?? 'Dev User';\n }\n\n public get slug(): string {\n return this.manifest?.slug ?? 'applet';\n }\n\n private key(...parts: string[]): string {\n return `ziprack-mock:${this.slug}:${parts.join(':')}`;\n }\n\n public declares(capability: string): boolean {\n if (!this.manifest) {\n return true;\n }\n\n return (this.manifest.requires?.capabilities ?? []).some((ref) => ref.split('@')[0] === capability);\n }\n\n public onEvent(listener: (event: RackEvent) => void): () => void {\n this.eventListeners.add(listener);\n\n return () => {\n this.eventListeners.delete(listener);\n };\n }\n\n public pushEvent(event: RackEvent): void {\n this.events.push(event);\n this.eventListeners.forEach((l) => l(event));\n }\n\n public launchData(nameHint?: string): LaunchData {\n const m = this.manifest;\n const launch: LaunchData = {\n schema: 'ziprack/1',\n actor: { id: this.participantId, name: this.participantName },\n applet: { slug: this.slug, name: `${m?.name ?? nameHint ?? 'Applet'} (mock)`, version: m?.version ?? 'dev' },\n capabilities: m?.requires?.capabilities ?? [],\n media: Object.fromEntries((m?.media ?? []).map((item) => [item.id, {\n provider: item.provider,\n embedUrl: item.provider === 'vimeo' ? `https://player.vimeo.com/video/${item.key}?dnt=1` : `https://www.youtube-nocookie.com/embed/${item.key}?rel=0`,\n meta: null,\n }])),\n };\n\n if (this.declares('auth')) {\n const user: LaunchData['auth'] = { user: { id: this.participantId, display_name: this.participantName } };\n for (const attribute of m?.requires?.profile ?? []) {\n user.user[attribute] = user.user[attribute] ?? `mock-${attribute}`;\n }\n launch.auth = user;\n }\n if (this.declares('attempt')) {\n launch.attempt = this.attempt();\n }\n if (this.declares('activity')) {\n launch.activity = { activities: [...(m?.activities ?? [])].sort((a, b) => (a.sequence ?? 0) - (b.sequence ?? 0)) };\n }\n if (this.declares('db')) {\n launch.db = { collections: (m?.collections ?? []).map((c) => ({ name: c.name, scope: c.scope })) };\n }\n if (this.declares('storage')) {\n launch.storage = { uploads: (m?.uploads ?? []).map((u) => ({ name: u.name, scope: u.scope, mime: u.mime ?? [], max_bytes: u.max_bytes ?? 10 * 1024 * 1024 })) };\n }\n if (this.declares('ai')) {\n launch.ai = { prompts: (m?.prompts ?? []).map((p) => ({ id: p.id, mode: p.mode })) };\n }\n if (this.declares('broadcast')) {\n this.joinRoom();\n launch.broadcast = {\n room: { id: 1, code: 'MOCK01', name: `${this.slug} room`, status: 'open', mode: m?.broadcast?.mock_mode ?? 'first_in' },\n role: this.role,\n members: this.members(),\n state: this.stateSnapshot(),\n channels: m?.broadcast?.channels ?? ['main'],\n };\n }\n\n return launch;\n }\n\n public mockAi(promptId: string, handler: AiMockHandler): void {\n this.aiHandlers.set(promptId, handler);\n }\n\n public dispose(): void {\n if (this.heartbeat) {\n clearInterval(this.heartbeat);\n }\n if (this.channel) {\n this.send({ t: 'bye', from: this.member() });\n this.channel.close();\n }\n }\n\n // ---------------------------------------------------------------- dispatch\n\n public async handle(type: string, payload: JsonObject): Promise<MockOutcome> {\n this.options.log?.(type, payload);\n\n if (type === 'rack:eject') {\n return { ok: true };\n }\n\n const capability = capabilityOf(type);\n if ((this.options.strict ?? this.manifest !== null) && !this.declares(capability)) {\n return { ok: false, error: 'undeclared_capability', message: `The manifest does not declare the [${capability}] capability.` };\n }\n\n switch (type) {\n case 'attempt:state': return this.attemptState(payload);\n case 'attempt:segment': return this.attemptSegment(payload);\n case 'attempt:complete': return this.attemptComplete(payload);\n case 'activity:statement': return this.statement(payload);\n case 'db:create': return this.dbCreate(payload);\n case 'db:get': return this.dbGet(payload);\n case 'db:update': return this.dbUpdate(payload);\n case 'db:delete': return this.dbDelete(payload);\n case 'db:list': return this.dbList(payload);\n case 'db:count': return this.dbCount(payload);\n case 'storage:put': return this.storagePut(payload);\n case 'storage:url': return this.storageUrl(payload);\n case 'storage:list': return this.storageList(payload);\n case 'storage:delete': return this.storageDelete(payload);\n case 'ai:ask': return this.aiAsk(payload);\n case 'ai:chat': return this.aiChat(payload);\n case 'ai:chat.reset': this.chatHistory.delete(String(payload.prompt)); return { ok: true };\n case 'broadcast:join': return { ok: true, data: { members: this.members(), state: this.stateSnapshot() } };\n case 'broadcast:leave': return { ok: true };\n case 'broadcast:publish': return this.publish(payload);\n case 'broadcast:state.get': return { ok: true, data: { state: this.stateSnapshot(Array.isArray(payload.keys) ? (payload.keys as string[]) : undefined) } };\n case 'broadcast:state.set': return this.stateSet(payload);\n case 'broadcast:presence': return { ok: true, data: { members: this.members() } };\n case 'broadcast:invite': return this.invite();\n case 'broadcast:claim': return this.claim();\n case 'broadcast:transfer': return this.transfer(payload);\n default:\n return { ok: false, error: 'unknown_type', message: `Unknown message type [${type}].` };\n }\n }\n\n // ---------------------------------------------------------------- attempt\n\n public attempt(): NonNullable<LaunchData['attempt']> {\n return this.store.get(this.key('attempt')) ?? { id: 1, status: 'in_progress', state: null, segment: null };\n }\n\n private saveAttempt(attempt: NonNullable<LaunchData['attempt']>): void {\n this.store.set(this.key('attempt'), attempt);\n }\n\n private attemptState(payload: JsonObject): AckResult {\n const attempt = this.attempt();\n if (attempt.status === 'completed') {\n return { ok: false, error: 'completed', message: 'This attempt is already completed.' };\n }\n const size = JSON.stringify(payload.state ?? {}).length;\n if (size > 65536) {\n return { ok: false, error: 'validation', message: `State is ${size} bytes; the limit is 65536.` };\n }\n this.saveAttempt({ ...attempt, state: (payload.state as JsonObject) ?? null });\n\n return { ok: true };\n }\n\n private attemptSegment(payload: JsonObject): AckResult {\n const attempt = this.attempt();\n if (attempt.status === 'completed') {\n return { ok: false, error: 'completed' };\n }\n this.saveAttempt({ ...attempt, segment: (payload.segment as Record<string, string>) ?? null });\n\n return { ok: true };\n }\n\n private attemptComplete(payload: JsonObject): AckResult {\n const attempt = this.attempt();\n const completedAt = new Date().toISOString();\n if (attempt.status !== 'completed') {\n this.saveAttempt({ ...attempt, status: 'completed' });\n if (this.declares('activity')) {\n this.statement({ verb: 'completed', activity: { id: 'attempt', type: 'attempt' }, result: payload.summary ?? null, occurred_at: completedAt });\n }\n }\n\n return { ok: true, data: { status: 'completed', completed_at: completedAt } };\n }\n\n /** Clear a completed mock attempt so the experience can be run again. */\n public resetAttempt(): void {\n this.store.remove(this.key('attempt'));\n }\n\n // ---------------------------------------------------------------- activity\n\n private statement(payload: JsonObject): AckResult<{ id: string }> {\n const verb = String(payload.verb ?? '');\n if (!/^[a-z][a-z0-9_.:-]*$/.test(verb) || verb.length > 100) {\n return { ok: false, error: 'validation', message: `Invalid verb [${verb}].` };\n }\n const activity = payload.activity as { id?: string } | undefined;\n if (!activity?.id) {\n return { ok: false, error: 'validation', message: 'activity.id is required.' };\n }\n const id = `mock-${Date.now().toString(36)}-${this.statements.length + 1}`;\n this.statements.push({ id, ...payload });\n\n return { ok: true, data: { id } };\n }\n\n // ---------------------------------------------------------------- db\n\n private collectionKey(name: string): string {\n return this.key('db', name);\n }\n\n public records(collection: string): RecordRow[] {\n return this.store.get<RecordRow[]>(this.collectionKey(collection)) ?? [];\n }\n\n private saveRecords(collection: string, records: RecordRow[]): void {\n this.store.set(this.collectionKey(collection), records);\n }\n\n private collectionDeclared(name: string): AckResult | null {\n if (this.manifest && !(this.manifest.collections ?? []).some((c) => c.name === name)) {\n return { ok: false, error: 'not_found', message: `Collection [${name}] is not declared in the manifest.` };\n }\n const scope = (this.manifest?.collections ?? []).find((c) => c.name === name)?.scope;\n if (scope === 'attempt' && this.attempt().status === 'completed') {\n return { ok: false, error: 'completed', message: 'Attempt-scoped records are frozen after completion.' };\n }\n\n return null;\n }\n\n private dbCreate(payload: JsonObject): AckResult {\n const name = String(payload.collection);\n const declared = this.collectionDeclared(name);\n if (declared) {\n return declared;\n }\n const now = new Date().toISOString();\n const record: RecordRow = {\n id: `rec-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`,\n data: (payload.data as JsonObject) ?? {},\n owner_id: this.participantId,\n created_at: now,\n updated_at: now,\n };\n this.saveRecords(name, [...this.records(name), record]);\n\n return { ok: true, data: { record } };\n }\n\n private dbGet(payload: JsonObject): AckResult {\n const record = this.records(String(payload.collection)).find((r) => r.id === payload.id);\n\n return record ? { ok: true, data: { record } } : { ok: false, error: 'not_found' };\n }\n\n private dbUpdate(payload: JsonObject): AckResult {\n const name = String(payload.collection);\n const frozen = this.collectionDeclared(name);\n if (frozen && frozen.error === 'completed') {\n return frozen;\n }\n const records = this.records(name);\n const index = records.findIndex((r) => r.id === payload.id);\n if (index === -1) {\n return { ok: false, error: 'not_found' };\n }\n const merge = payload.merge !== false;\n const data = (payload.data as JsonObject) ?? {};\n records[index] = { ...records[index], data: merge ? { ...records[index].data, ...data } : data, updated_at: new Date().toISOString() };\n this.saveRecords(name, records);\n\n return { ok: true, data: { record: records[index] } };\n }\n\n private dbDelete(payload: JsonObject): AckResult {\n const name = String(payload.collection);\n const records = this.records(name);\n if (!records.some((r) => r.id === payload.id)) {\n return { ok: false, error: 'not_found' };\n }\n this.saveRecords(name, records.filter((r) => r.id !== payload.id));\n\n return { ok: true, data: { id: payload.id } };\n }\n\n private filter(records: RecordRow[], where: WhereClause[] | undefined): RecordRow[] {\n if (!where) {\n return records;\n }\n\n return records.filter((record) => where.every(([path, op, value]) => {\n const actual = path.split('.').reduce<unknown>((acc, part) => (acc as JsonObject | undefined)?.[part], record.data);\n switch (op) {\n case '=': return actual === value;\n case '!=': return actual !== value;\n case '<': return (actual as number) < (value as number);\n case '<=': return (actual as number) <= (value as number);\n case '>': return (actual as number) > (value as number);\n case '>=': return (actual as number) >= (value as number);\n case 'in': return Array.isArray(value) && value.includes(actual);\n default: return false;\n }\n }));\n }\n\n private dbList(payload: JsonObject): AckResult {\n const name = String(payload.collection);\n if (this.manifest && !(this.manifest.collections ?? []).some((c) => c.name === name)) {\n return { ok: false, error: 'not_found', message: `Collection [${name}] is not declared in the manifest.` };\n }\n let records = this.filter(this.records(name), payload.where as WhereClause[] | undefined);\n if (typeof payload.orderBy === 'string') {\n const path = payload.orderBy;\n const dir = payload.direction === 'desc' ? -1 : 1;\n records = [...records].sort((a, b) => {\n const av = path.split('.').reduce<unknown>((acc, p) => (acc as JsonObject | undefined)?.[p], a.data) as number | string;\n const bv = path.split('.').reduce<unknown>((acc, p) => (acc as JsonObject | undefined)?.[p], b.data) as number | string;\n\n return av < bv ? -dir : av > bv ? dir : 0;\n });\n }\n const limit = Math.min(Number(payload.limit ?? 50), 100);\n const offset = payload.cursor ? Number(payload.cursor) : 0;\n const page = records.slice(offset, offset + limit);\n const nextCursor = offset + limit < records.length ? String(offset + limit) : null;\n\n return { ok: true, data: { records: page, nextCursor } };\n }\n\n private dbCount(payload: JsonObject): AckResult {\n return { ok: true, data: { count: this.filter(this.records(String(payload.collection)), payload.where as WhereClause[] | undefined).length } };\n }\n\n // ---------------------------------------------------------------- storage\n\n public files(): StoredFile[] {\n return this.store.get<StoredFile[]>(this.key('files')) ?? [];\n }\n\n private storagePut(payload: JsonObject): AckResult {\n const upload = String(payload.upload);\n const slot = (this.manifest?.uploads ?? []).find((u) => u.name === upload);\n if (this.manifest && !slot) {\n return { ok: false, error: 'not_found', message: `Upload [${upload}] is not declared in the manifest.` };\n }\n const mime = String(payload.mime ?? '');\n if (slot?.mime && slot.mime.length > 0 && !slot.mime.some((m) => m === mime || (m.endsWith('/*') && mime.startsWith(m.slice(0, -1))))) {\n return { ok: false, error: 'validation', message: `MIME type [${mime}] is not allowed for upload [${upload}].` };\n }\n const bytes = Number(payload.bytes ?? 0);\n if (slot?.max_bytes && bytes > slot.max_bytes) {\n return { ok: false, error: 'quota_exceeded', message: `File is ${bytes} bytes; the limit is ${slot.max_bytes}.` };\n }\n const file: StoredFile = {\n id: `file-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`,\n upload,\n name: String(payload.name ?? 'blob'),\n mime,\n bytes,\n status: 'clean',\n created_at: new Date().toISOString(),\n };\n const blob = payload.file;\n if (typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function' && blob instanceof Blob) {\n this.blobs.set(file.id, URL.createObjectURL(blob));\n }\n this.store.set(this.key('files'), [...this.files(), file]);\n\n return { ok: true, data: { file } };\n }\n\n private storageUrl(payload: JsonObject): AckResult {\n const file = this.files().find((f) => f.id === payload.id);\n if (!file) {\n return { ok: false, error: 'not_found' };\n }\n\n return { ok: true, data: { url: this.blobs.get(file.id) ?? `mock://files/${file.id}`, expires_at: new Date(Date.now() + 600_000).toISOString() } };\n }\n\n private storageList(payload: JsonObject): AckResult {\n const files = this.files().filter((f) => !payload.upload || f.upload === payload.upload);\n\n return { ok: true, data: { files } };\n }\n\n private storageDelete(payload: JsonObject): AckResult {\n this.store.set(this.key('files'), this.files().filter((f) => f.id !== payload.id));\n\n return { ok: true, data: { id: payload.id } };\n }\n\n // ---------------------------------------------------------------- ai\n\n private prompt(id: string): { id: string; mode: 'analysis' | 'chat'; output_schema?: JsonObject } | null {\n return (this.manifest?.prompts ?? []).find((p) => p.id === id) ?? (this.manifest ? null : { id, mode: 'analysis' });\n }\n\n private async aiAsk(payload: JsonObject): Promise<AckResult> {\n const prompt = this.prompt(String(payload.prompt));\n if (!prompt) {\n return { ok: false, error: 'not_found', message: `Prompt [${payload.prompt}] is not declared in the manifest.` };\n }\n const handler = this.aiHandlers.get(prompt.id);\n const vars = (payload.vars as JsonObject) ?? {};\n const output = handler ? await handler(vars, 'analysis') : stubFromSchema(prompt.output_schema, vars);\n\n return { ok: true, data: { output, usage: { input_tokens: 42, output_tokens: 17 } } };\n }\n\n private async aiChat(payload: JsonObject): Promise<MockOutcome> {\n const prompt = this.prompt(String(payload.prompt));\n if (!prompt) {\n return { ok: false, error: 'not_found', message: `Prompt [${payload.prompt}] is not declared in the manifest.` };\n }\n const message = String(payload.message ?? '');\n const history = this.chatHistory.get(prompt.id) ?? [];\n history.push({ role: 'user', content: message });\n const handler = this.aiHandlers.get(prompt.id);\n const reply = handler ? String(await handler({ history }, 'chat', message)) : `[mock ${prompt.id}] You said: ${message}`;\n history.push({ role: 'assistant', content: reply });\n this.chatHistory.set(prompt.id, history);\n\n const words = reply.split(' ');\n const messageId = `msg-${Date.now().toString(36)}`;\n\n return {\n stream: (async function* () {\n for (let i = 0; i < words.length; i++) {\n yield { delta: (i === 0 ? '' : ' ') + words[i] };\n }\n })(),\n final: () => ({ message_id: messageId, text: reply, usage: { input_tokens: message.length, output_tokens: reply.length } }),\n };\n }\n\n // ---------------------------------------------------------------- broadcast (BroadcastChannel across tabs)\n\n private member(): RoomMember & { joinedAt: number } {\n return { id: this.participantId, name: this.participantName, role: this.role, present: true, joinedAt: this.joinedAt };\n }\n\n public members(): RoomMember[] {\n const now = Date.now();\n const others = [...this.roomMembers.values()].filter((m) => now - m.lastSeen < 15_000).map(({ lastSeen: _l, joinedAt: _j, ...m }) => m);\n const { joinedAt: _joined, ...self } = this.member();\n\n return [self, ...others].sort((a, b) => a.id - b.id);\n }\n\n private stateSnapshot(keys?: string[]): JsonObject {\n const snapshot: JsonObject = {};\n for (const [key, entry] of Object.entries(this.roomState)) {\n if (!keys || keys.includes(key)) {\n snapshot[key] = entry.value;\n }\n }\n\n return snapshot;\n }\n\n private send(message: JsonObject): void {\n this.channel?.postMessage({ ...message, sender: this.participantId });\n }\n\n private joinRoom(): void {\n if (this.channel) {\n return;\n }\n const mode = this.manifest?.broadcast?.mock_mode ?? 'first_in';\n // Optimistic first_in: this tab takes the role until an earlier facilitator answers.\n this.role = this.options.role ?? (mode === 'first_in' ? 'facilitator' : 'participant');\n\n if (typeof BroadcastChannel === 'undefined') {\n return;\n }\n this.channel = new BroadcastChannel(this.key('room'));\n this.channel.onmessage = (event: MessageEvent<JsonObject>) => this.onRoomMessage(event.data);\n this.send({ t: 'hello', from: this.member() });\n this.heartbeat = setInterval(() => this.send({ t: 'here', from: this.member() }), 5000);\n }\n\n /** An earlier facilitator wins; a later optimistic one steps down. */\n private reconcileFacilitator(from: RoomMember & { joinedAt?: number }): void {\n if (from.role === 'facilitator' && this.role === 'facilitator' && (from.joinedAt ?? 0) < this.joinedAt) {\n this.role = 'participant';\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: 'participant', participant_id: this.participantId } });\n }\n }\n\n private onRoomMessage(data: JsonObject): void {\n const from = data.from as (RoomMember & { joinedAt?: number }) | undefined;\n if (data.sender === this.participantId) {\n return;\n }\n switch (data.t) {\n case 'hello':\n if (from) {\n this.roomMembers.set(from.id, { ...from, lastSeen: Date.now() });\n this.reconcileFacilitator(from);\n this.send({ t: 'here', from: this.member() });\n this.send({ t: 'state-sync', state: this.roomState });\n this.pushEvent({ channel: '$room', event: 'presence', payload: { members: this.members() } });\n }\n break;\n case 'here':\n if (from) {\n const known = this.roomMembers.has(from.id);\n this.roomMembers.set(from.id, { ...from, lastSeen: Date.now() });\n this.reconcileFacilitator(from);\n if (!known) {\n this.pushEvent({ channel: '$room', event: 'presence', payload: { members: this.members() } });\n }\n }\n break;\n case 'bye':\n if (from) {\n this.roomMembers.delete(from.id);\n this.pushEvent({ channel: '$room', event: 'presence', payload: { members: this.members() } });\n }\n break;\n case 'event':\n this.pushEvent({ channel: String(data.channel), event: String(data.event), payload: data.payload, from: { participant_id: Number(data.sender), role: (from?.role ?? 'participant') as RoomRole } });\n break;\n case 'state': {\n const key = String(data.key);\n const version = Number(data.version);\n if ((this.roomState[key]?.version ?? 0) <= version) {\n this.roomState[key] = { value: data.value, version };\n this.pushEvent({ channel: '$room', event: 'state', payload: { key, value: data.value, version } });\n }\n break;\n }\n case 'state-sync':\n for (const [key, entry] of Object.entries(data.state as Record<string, { value: unknown; version: number }>)) {\n if ((this.roomState[key]?.version ?? 0) < entry.version) {\n this.roomState[key] = entry;\n }\n }\n break;\n case 'role':\n if (from) {\n this.roomMembers.set(from.id, { ...from, lastSeen: Date.now() });\n if (from.role === 'facilitator' && this.role === 'facilitator') {\n this.role = 'participant';\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: 'participant', participant_id: this.participantId } });\n }\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: from.role, participant_id: from.id } });\n this.pushEvent({ channel: '$room', event: 'presence', payload: { members: this.members() } });\n }\n break;\n default:\n break;\n }\n }\n\n /**\n * A mock room is two tabs of the dev server, so the invite is this page:\n * scan it and the second tab joins over BroadcastChannel, exactly as the\n * real join URL would.\n */\n private invite(): AckResult {\n const url = typeof location === 'undefined' ? 'https://rack.test/r/MOCK01' : location.origin + location.pathname;\n\n return { ok: true, data: { code: 'MOCK01', url } };\n }\n\n private setRole(role: RoomRole): void {\n this.role = role;\n this.send({ t: 'role', from: this.member() });\n this.pushEvent({ channel: '$room', event: 'role', payload: { role, participant_id: this.participantId } });\n }\n\n private publish(payload: JsonObject): AckResult {\n const event = String(payload.event);\n const facilitatorOnly = this.manifest?.broadcast?.facilitator_events ?? [];\n if (facilitatorOnly.includes(event) && this.role !== 'facilitator') {\n return { ok: false, error: 'forbidden', message: `Event [${event}] may only be sent by the facilitator.` };\n }\n const from = { participant_id: this.participantId, role: this.role };\n this.send({ t: 'event', channel: payload.channel, event, payload: payload.payload, from: this.member() });\n this.pushEvent({ channel: String(payload.channel ?? 'main'), event, payload: payload.payload, from });\n\n return { ok: true };\n }\n\n private stateSet(payload: JsonObject): AckResult {\n const key = String(payload.key);\n const version = (this.roomState[key]?.version ?? 0) + 1;\n this.roomState[key] = { value: payload.value, version };\n this.send({ t: 'state', key, value: payload.value, version });\n this.pushEvent({ channel: '$room', event: 'state', payload: { key, value: payload.value, version } });\n\n return { ok: true, data: { version } };\n }\n\n private claim(): AckResult {\n this.setRole('facilitator');\n\n return { ok: true, data: { role: 'facilitator' } };\n }\n\n private transfer(payload: JsonObject): AckResult {\n if (this.role !== 'facilitator') {\n return { ok: false, error: 'forbidden', message: 'Only the facilitator can transfer the role.' };\n }\n const target = this.roomMembers.get(Number(payload.to));\n if (!target) {\n return { ok: false, error: 'not_found' };\n }\n this.role = 'participant';\n target.role = 'facilitator';\n this.send({ t: 'role', from: { ...target } });\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: 'participant', participant_id: this.participantId } });\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: 'facilitator', participant_id: target.id } });\n\n return { ok: true };\n }\n}\n\n/** A plausible object for an analysis prompt's output_schema, so UIs render in mock mode. */\nexport function stubFromSchema(schema: JsonObject | undefined, vars: JsonObject): unknown {\n if (!schema) {\n return { summary: `Mock analysis of ${JSON.stringify(vars).slice(0, 60)}` };\n }\n const type = schema.type;\n if (type === 'object') {\n const out: JsonObject = {};\n for (const [key, prop] of Object.entries((schema.properties as Record<string, JsonObject>) ?? {})) {\n out[key] = stubFromSchema(prop, vars);\n }\n\n return out;\n }\n if (type === 'array') {\n return [stubFromSchema(schema.items as JsonObject, vars)];\n }\n if (type === 'number' || type === 'integer') {\n return typeof schema.minimum === 'number' ? schema.minimum : 3;\n }\n if (type === 'boolean') {\n return true;\n }\n if (Array.isArray(schema.enum)) {\n return schema.enum[0];\n }\n\n return 'mock';\n}\n","import type { AckResult, JsonObject, RackEvent, SendOptions, Transport } from '../types';\nimport type { MockRack } from './MockRack';\n\n/**\n * Transport that fulfils every message locally through a MockRack.\n */\nexport class MockTransport implements Transport {\n public readonly kind = 'mock' as const;\n\n public constructor(public readonly rack: MockRack) {}\n\n public async send<T = JsonObject>(type: string, payload: unknown, options: SendOptions = {}): Promise<AckResult<T>> {\n const outcome = await this.rack.handle(type, (payload as JsonObject) ?? {});\n\n if ('stream' in outcome) {\n for await (const chunk of outcome.stream) {\n options.onPartial?.(chunk);\n }\n\n return { ok: true, data: outcome.final() as T };\n }\n\n return outcome as AckResult<T>;\n }\n\n public fire(type: string, payload: unknown = {}): void {\n void this.rack.handle(type, (payload as JsonObject) ?? {});\n }\n\n public onEvent(listener: (event: RackEvent) => void): () => void {\n return this.rack.onEvent(listener);\n }\n\n public dispose(): void {\n this.rack.dispose();\n }\n}\n","/**\n * Key/value persistence for the mock Rack. localStorage in the browser so a\n * standalone session survives a refresh; memory in tests.\n */\nexport interface Store {\n get<T>(key: string): T | null;\n set(key: string, value: unknown): void;\n remove(key: string): void;\n keys(prefix: string): string[];\n}\n\nexport class MemoryStore implements Store {\n private readonly data = new Map<string, string>();\n\n public get<T>(key: string): T | null {\n const raw = this.data.get(key);\n\n return raw === undefined ? null : (JSON.parse(raw) as T);\n }\n\n public set(key: string, value: unknown): void {\n this.data.set(key, JSON.stringify(value));\n }\n\n public remove(key: string): void {\n this.data.delete(key);\n }\n\n public keys(prefix: string): string[] {\n return [...this.data.keys()].filter((k) => k.startsWith(prefix));\n }\n}\n\nexport class LocalStore implements Store {\n public get<T>(key: string): T | null {\n try {\n const raw = window.localStorage.getItem(key);\n\n return raw === null ? null : (JSON.parse(raw) as T);\n } catch {\n return null;\n }\n }\n\n public set(key: string, value: unknown): void {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n } catch {\n // Storage may be unavailable; mock mode tolerates that silently.\n }\n }\n\n public remove(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n // ignore\n }\n }\n\n public keys(prefix: string): string[] {\n try {\n const keys: string[] = [];\n for (let i = 0; i < window.localStorage.length; i++) {\n const key = window.localStorage.key(i);\n if (key && key.startsWith(prefix)) {\n keys.push(key);\n }\n }\n\n return keys;\n } catch {\n return [];\n }\n }\n}\n"],"names":["PROTOCOL_NAMESPACE","PROTOCOL_VERSION","FORMAT","requestCounter","newRequestId","cryptoRef","createEnvelope","type","payload","requestId","envelope","isEnvelope","data","candidate","capabilityOf","index","MockRack","manifest","store","options","parts","capability","ref","listener","event","l","nameHint","m","launch","item","user","attribute","a","b","c","u","p","promptId","handler","attempt","size","completedAt","verb","id","name","collection","records","declared","now","record","r","frozen","merge","where","path","op","value","actual","acc","part","dir","av","bv","limit","offset","page","nextCursor","upload","slot","mime","bytes","file","blob","f","prompt","vars","stubFromSchema","message","history","reply","words","messageId","i","others","_l","_j","_joined","self","keys","snapshot","key","entry","mode","from","known","version","role","target","schema","out","prop","MockTransport","rack","outcome","chunk","MemoryStore","raw","prefix","k","LocalStore"],"mappings":"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"}
|