stitchkit 0.0.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/LICENSE +21 -0
- package/README.md +376 -4
- package/dist/browser/client.d.ts +30 -0
- package/dist/browser/client.d.ts.map +1 -0
- package/dist/browser/http.d.ts +77 -0
- package/dist/browser/http.d.ts.map +1 -0
- package/dist/browser/socket-io.d.ts +69 -0
- package/dist/browser/socket-io.d.ts.map +1 -0
- package/dist/browser/stream.d.ts +2 -0
- package/dist/browser/stream.d.ts.map +1 -0
- package/dist/contract/define.d.ts +94 -0
- package/dist/contract/define.d.ts.map +1 -0
- package/dist/contract/errors.d.ts +47 -0
- package/dist/contract/errors.d.ts.map +1 -0
- package/dist/contract/index.d.ts +4 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +26 -0
- package/dist/contract/pagination.d.ts +19 -0
- package/dist/contract/pagination.d.ts.map +1 -0
- package/dist/index-5sxnvwb1.js +368 -0
- package/dist/index-809wc1tt.js +18 -0
- package/dist/index-a35v22fh.js +29 -0
- package/dist/index-kckky6zw.js +96 -0
- package/dist/index-ke4mx4ea.js +38 -0
- package/dist/index-n7bmdwmz.js +68 -0
- package/dist/index-v2z2v3mq.js +587 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +111 -0
- package/dist/internal/errors.d.ts +5 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/typed.d.ts +9 -0
- package/dist/internal/typed.d.ts.map +1 -0
- package/dist/node.d.ts +4 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +26 -0
- package/dist/observability/audit.d.ts +32 -0
- package/dist/observability/audit.d.ts.map +1 -0
- package/dist/observability/context.d.ts +60 -0
- package/dist/observability/context.d.ts.map +1 -0
- package/dist/observability/event.d.ts +49 -0
- package/dist/observability/event.d.ts.map +1 -0
- package/dist/observability/index.d.ts +14 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +266 -0
- package/dist/observability/sanitize.d.ts +42 -0
- package/dist/observability/sanitize.d.ts.map +1 -0
- package/dist/observability/trace.d.ts +42 -0
- package/dist/observability/trace.d.ts.map +1 -0
- package/dist/react/cache-bridge.d.ts +53 -0
- package/dist/react/cache-bridge.d.ts.map +1 -0
- package/dist/react/cursor-query.d.ts +37 -0
- package/dist/react/cursor-query.d.ts.map +1 -0
- package/dist/react.d.ts +3 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +52 -0
- package/dist/server/cache.d.ts +15 -0
- package/dist/server/cache.d.ts.map +1 -0
- package/dist/server/context.d.ts +9 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/create.d.ts +4 -0
- package/dist/server/create.d.ts.map +1 -0
- package/dist/server/event-bus.d.ts +24 -0
- package/dist/server/event-bus.d.ts.map +1 -0
- package/dist/server/implement.d.ts +16 -0
- package/dist/server/implement.d.ts.map +1 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +399 -0
- package/dist/server/logger.d.ts +21 -0
- package/dist/server/logger.d.ts.map +1 -0
- package/dist/server/middleware/auth.d.ts +50 -0
- package/dist/server/middleware/auth.d.ts.map +1 -0
- package/dist/server/middleware/cookies.d.ts +34 -0
- package/dist/server/middleware/cookies.d.ts.map +1 -0
- package/dist/server/middleware/cors.d.ts +9 -0
- package/dist/server/middleware/cors.d.ts.map +1 -0
- package/dist/server/multipart.d.ts +14 -0
- package/dist/server/multipart.d.ts.map +1 -0
- package/dist/server/node.d.ts +12 -0
- package/dist/server/node.d.ts.map +1 -0
- package/dist/server/rate-limit.d.ts +17 -0
- package/dist/server/rate-limit.d.ts.map +1 -0
- package/dist/server/request.d.ts +22 -0
- package/dist/server/request.d.ts.map +1 -0
- package/dist/server/router.d.ts +42 -0
- package/dist/server/router.d.ts.map +1 -0
- package/dist/server/socket-io.d.ts +42 -0
- package/dist/server/socket-io.d.ts.map +1 -0
- package/dist/server/stream.d.ts +18 -0
- package/dist/server/stream.d.ts.map +1 -0
- package/dist/server/swept-map.d.ts +22 -0
- package/dist/server/swept-map.d.ts.map +1 -0
- package/dist/server/types.d.ts +127 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/tools/agent.d.ts +27 -0
- package/dist/tools/agent.d.ts.map +1 -0
- package/dist/tools/coerce.d.ts +8 -0
- package/dist/tools/coerce.d.ts.map +1 -0
- package/dist/tools/execute.d.ts +45 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/flatten.d.ts +15 -0
- package/dist/tools/flatten.d.ts.map +1 -0
- package/dist/tools/json-schema.d.ts +18 -0
- package/dist/tools/json-schema.d.ts.map +1 -0
- package/dist/tools/manifest.d.ts +13 -0
- package/dist/tools/manifest.d.ts.map +1 -0
- package/dist/tools/mcp-handler.d.ts +21 -0
- package/dist/tools/mcp-handler.d.ts.map +1 -0
- package/dist/tools/mcp-stdio.d.ts +25 -0
- package/dist/tools/mcp-stdio.d.ts.map +1 -0
- package/dist/tools/mcp.d.ts +92 -0
- package/dist/tools/mcp.d.ts.map +1 -0
- package/dist/tools/mount.d.ts +73 -0
- package/dist/tools/mount.d.ts.map +1 -0
- package/dist/tools/names.d.ts +2 -0
- package/dist/tools/names.d.ts.map +1 -0
- package/dist/tools/remote.d.ts +22 -0
- package/dist/tools/remote.d.ts.map +1 -0
- package/dist/tools/schema.d.ts +21 -0
- package/dist/tools/schema.d.ts.map +1 -0
- package/dist/tools/view-file.d.ts +57 -0
- package/dist/tools/view-file.d.ts.map +1 -0
- package/dist/tools.d.ts +12 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +837 -0
- package/package.json +147 -4
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/contract/define.ts
|
|
2
|
+
var ALL_TRANSPORTS = ["HTTP", "MCP", "AGENT"];
|
|
3
|
+
function defineContract(meta, endpoints) {
|
|
4
|
+
const toolTransports = new Map;
|
|
5
|
+
for (const [key, ep] of Object.entries(endpoints)) {
|
|
6
|
+
if (ep.desc.trim() === "") {
|
|
7
|
+
throw new Error(`Contract "${meta.prefix}": endpoint "${key}" has an empty desc`);
|
|
8
|
+
}
|
|
9
|
+
if (!("toolName" in ep) || !ep.toolName)
|
|
10
|
+
continue;
|
|
11
|
+
const transports = new Set(ep.expose ? ep.expose.filter((t) => t !== "HTTP") : ["MCP", "AGENT"]);
|
|
12
|
+
if (transports.size === 0) {
|
|
13
|
+
throw new Error(`Contract "${meta.prefix}": endpoint "${key}" sets toolName "${ep.toolName}" but is not exposed on any tool transport (MCP / AGENT)`);
|
|
14
|
+
}
|
|
15
|
+
const existing = toolTransports.get(ep.toolName);
|
|
16
|
+
if (existing) {
|
|
17
|
+
for (const t of transports) {
|
|
18
|
+
if (existing.transports.has(t)) {
|
|
19
|
+
throw new Error(`Contract "${meta.prefix}": duplicate toolName "${ep.toolName}" on transport "${t}" (endpoints: "${existing.key}" and "${key}")`);
|
|
20
|
+
}
|
|
21
|
+
existing.transports.add(t);
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
toolTransports.set(ep.toolName, { key, transports });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { meta, endpoints };
|
|
28
|
+
}
|
|
29
|
+
// src/contract/errors.ts
|
|
30
|
+
class AppError extends Error {
|
|
31
|
+
code;
|
|
32
|
+
status;
|
|
33
|
+
details;
|
|
34
|
+
hint;
|
|
35
|
+
constructor(code, message, status = 500, details, hint) {
|
|
36
|
+
super(message ?? code);
|
|
37
|
+
this.code = code;
|
|
38
|
+
this.status = status;
|
|
39
|
+
this.details = details;
|
|
40
|
+
this.hint = hint;
|
|
41
|
+
this.name = "AppError";
|
|
42
|
+
}
|
|
43
|
+
static is(err) {
|
|
44
|
+
return err instanceof AppError;
|
|
45
|
+
}
|
|
46
|
+
toJSON() {
|
|
47
|
+
return {
|
|
48
|
+
error: {
|
|
49
|
+
code: this.code,
|
|
50
|
+
message: this.message,
|
|
51
|
+
...this.details && { details: this.details },
|
|
52
|
+
...this.hint && { hint: this.hint }
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function notFound(message = "Not found") {
|
|
58
|
+
throw new AppError("NOT_FOUND", message, 404);
|
|
59
|
+
}
|
|
60
|
+
function badRequest(message, details) {
|
|
61
|
+
throw new AppError("BAD_REQUEST", message, 400, details);
|
|
62
|
+
}
|
|
63
|
+
function unauthorized(message = "Unauthorized") {
|
|
64
|
+
throw new AppError("UNAUTHORIZED", message, 401);
|
|
65
|
+
}
|
|
66
|
+
function forbidden(message = "Forbidden") {
|
|
67
|
+
throw new AppError("FORBIDDEN", message, 403);
|
|
68
|
+
}
|
|
69
|
+
function conflict(message = "Conflict", details) {
|
|
70
|
+
throw new AppError("CONFLICT", message, 409, details);
|
|
71
|
+
}
|
|
72
|
+
function rateLimited(message = "Too many requests") {
|
|
73
|
+
throw new AppError("RATE_LIMITED", message, 429);
|
|
74
|
+
}
|
|
75
|
+
var ERROR_STATUS = {
|
|
76
|
+
NOT_FOUND: 404,
|
|
77
|
+
BAD_REQUEST: 400,
|
|
78
|
+
UNAUTHORIZED: 401,
|
|
79
|
+
FORBIDDEN: 403,
|
|
80
|
+
CONFLICT: 409,
|
|
81
|
+
RATE_LIMITED: 429,
|
|
82
|
+
VALIDATION_ERROR: 400,
|
|
83
|
+
INTERNAL_SERVER_ERROR: 500
|
|
84
|
+
};
|
|
85
|
+
function appError(code, message, details) {
|
|
86
|
+
throw new AppError(code, message, ERROR_STATUS[code] ?? 500, details);
|
|
87
|
+
}
|
|
88
|
+
// src/contract/pagination.ts
|
|
89
|
+
import { z } from "zod";
|
|
90
|
+
function paginatedSchema(itemSchema) {
|
|
91
|
+
return z.object({
|
|
92
|
+
items: z.array(itemSchema),
|
|
93
|
+
nextCursor: z.string().nullable()
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
export { ALL_TRANSPORTS, defineContract, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, appError, paginatedSchema };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/server/request.ts
|
|
2
|
+
function generateTraceId() {
|
|
3
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
4
|
+
}
|
|
5
|
+
function resolveTraceId(req) {
|
|
6
|
+
const header = req.headers.get("x-request-id") ?? req.headers.get("x-trace-id");
|
|
7
|
+
const trimmed = header?.trim();
|
|
8
|
+
if (trimmed && trimmed.length <= 128 && /^[\w.-]+$/.test(trimmed)) {
|
|
9
|
+
return trimmed;
|
|
10
|
+
}
|
|
11
|
+
return generateTraceId();
|
|
12
|
+
}
|
|
13
|
+
function extractIp(req) {
|
|
14
|
+
const forwarded = req.headers.get("x-forwarded-for");
|
|
15
|
+
if (forwarded)
|
|
16
|
+
return (forwarded.split(",")[0] ?? "").trim().replace("::ffff:", "");
|
|
17
|
+
const realIp = req.headers.get("x-real-ip");
|
|
18
|
+
if (realIp)
|
|
19
|
+
return realIp.trim().replace("::ffff:", "");
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
function getClientInfo(req) {
|
|
23
|
+
return {
|
|
24
|
+
ipAddress: extractIp(req) || undefined,
|
|
25
|
+
userAgent: req.headers.get("user-agent") ?? undefined
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function parseQueryParams(url) {
|
|
29
|
+
const query = {};
|
|
30
|
+
for (const key of new Set(url.searchParams.keys())) {
|
|
31
|
+
const values = url.searchParams.getAll(key);
|
|
32
|
+
const [first] = values;
|
|
33
|
+
query[key] = values.length === 1 && first !== undefined ? first : values;
|
|
34
|
+
}
|
|
35
|
+
return query;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { generateTraceId, resolveTraceId, extractIp, getClientInfo, parseQueryParams };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/server/stream.ts
|
|
2
|
+
function streamSSE(generator) {
|
|
3
|
+
const encoder = new TextEncoder;
|
|
4
|
+
const stream = new ReadableStream({
|
|
5
|
+
async start(controller) {
|
|
6
|
+
try {
|
|
7
|
+
for await (const chunk of generator) {
|
|
8
|
+
const data = JSON.stringify(chunk);
|
|
9
|
+
controller.enqueue(encoder.encode(`data: ${data}
|
|
10
|
+
|
|
11
|
+
`));
|
|
12
|
+
}
|
|
13
|
+
controller.enqueue(encoder.encode(`data: [DONE]
|
|
14
|
+
|
|
15
|
+
`));
|
|
16
|
+
controller.close();
|
|
17
|
+
} catch (err) {
|
|
18
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
19
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: msg })}
|
|
20
|
+
|
|
21
|
+
`));
|
|
22
|
+
controller.close();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return new Response(stream, {
|
|
27
|
+
headers: {
|
|
28
|
+
"Content-Type": "text/event-stream",
|
|
29
|
+
"Cache-Control": "no-cache",
|
|
30
|
+
Connection: "keep-alive"
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function* parseSSE(response, options) {
|
|
35
|
+
const reader = response.body?.getReader();
|
|
36
|
+
if (!reader)
|
|
37
|
+
return;
|
|
38
|
+
const decoder = new TextDecoder;
|
|
39
|
+
let buffer = "";
|
|
40
|
+
try {
|
|
41
|
+
while (true) {
|
|
42
|
+
const { done, value } = await reader.read();
|
|
43
|
+
if (done)
|
|
44
|
+
break;
|
|
45
|
+
buffer += decoder.decode(value, { stream: true });
|
|
46
|
+
const lines = buffer.split(`
|
|
47
|
+
`);
|
|
48
|
+
buffer = lines.pop() ?? "";
|
|
49
|
+
for (const rawLine of lines) {
|
|
50
|
+
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
51
|
+
if (!line.startsWith("data: "))
|
|
52
|
+
continue;
|
|
53
|
+
const data = line.slice(6);
|
|
54
|
+
if (data === "[DONE]")
|
|
55
|
+
return;
|
|
56
|
+
try {
|
|
57
|
+
yield JSON.parse(data);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
options?.onParseError?.(data, err instanceof Error ? err : new Error(String(err)));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} finally {
|
|
64
|
+
reader.releaseLock();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { streamSSE, parseSSE };
|