silgi 0.0.14 → 0.1.0-beta.1
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/README.md +102 -1
- package/dist/_virtual/_rolldown/runtime.mjs +5 -0
- package/dist/adapters/astro.d.mts +17 -0
- package/dist/adapters/astro.mjs +24 -0
- package/dist/adapters/aws-lambda.d.mts +31 -0
- package/dist/adapters/aws-lambda.mjs +85 -0
- package/dist/adapters/elysia.d.mts +17 -0
- package/dist/adapters/elysia.mjs +76 -0
- package/dist/adapters/express.d.mts +16 -0
- package/dist/adapters/express.mjs +78 -0
- package/dist/adapters/fastify.d.mts +15 -0
- package/dist/adapters/fastify.mjs +78 -0
- package/dist/adapters/message-port.d.mts +37 -0
- package/dist/adapters/message-port.mjs +129 -0
- package/dist/adapters/nestjs.d.mts +25 -0
- package/dist/adapters/nestjs.mjs +91 -0
- package/dist/adapters/nextjs.d.mts +21 -0
- package/dist/adapters/nextjs.mjs +30 -0
- package/dist/adapters/peer.d.mts +27 -0
- package/dist/adapters/peer.mjs +36 -0
- package/dist/adapters/remix.d.mts +17 -0
- package/dist/adapters/remix.mjs +24 -0
- package/dist/adapters/solidstart.d.mts +14 -0
- package/dist/adapters/solidstart.mjs +30 -0
- package/dist/adapters/sveltekit.d.mts +18 -0
- package/dist/adapters/sveltekit.mjs +33 -0
- package/dist/analyze.mjs +26 -0
- package/dist/broker/index.d.mts +62 -0
- package/dist/broker/index.mjs +153 -0
- package/dist/broker/nats.d.mts +33 -0
- package/dist/broker/nats.mjs +31 -0
- package/dist/broker/redis.d.mts +51 -0
- package/dist/broker/redis.mjs +92 -0
- package/dist/builder.d.mts +36 -0
- package/dist/builder.mjs +51 -0
- package/dist/callable.d.mts +17 -0
- package/dist/callable.mjs +42 -0
- package/dist/client/adapters/fetch/index.d.mts +17 -0
- package/dist/client/adapters/fetch/index.mjs +61 -0
- package/dist/client/adapters/ofetch/index.d.mts +41 -0
- package/dist/client/adapters/ofetch/index.mjs +92 -0
- package/dist/client/client.d.mts +29 -0
- package/dist/client/client.mjs +54 -0
- package/dist/client/dynamic-link.d.mts +15 -0
- package/dist/client/dynamic-link.mjs +16 -0
- package/dist/client/index.d.mts +7 -0
- package/dist/client/index.mjs +6 -0
- package/dist/client/interceptor.d.mts +31 -0
- package/dist/client/interceptor.mjs +34 -0
- package/dist/client/merge.d.mts +28 -0
- package/dist/client/merge.mjs +30 -0
- package/dist/client/openapi.d.mts +29 -0
- package/dist/client/openapi.mjs +89 -0
- package/dist/client/plugins/batch.d.mts +20 -0
- package/dist/client/plugins/batch.mjs +64 -0
- package/dist/client/plugins/csrf.d.mts +13 -0
- package/dist/client/plugins/csrf.mjs +20 -0
- package/dist/client/plugins/dedupe.d.mts +10 -0
- package/dist/client/plugins/dedupe.mjs +28 -0
- package/dist/client/plugins/index.d.mts +5 -0
- package/dist/client/plugins/index.mjs +5 -0
- package/dist/client/plugins/retry.d.mts +11 -0
- package/dist/client/plugins/retry.mjs +21 -0
- package/dist/client/server.d.mts +16 -0
- package/dist/client/server.mjs +60 -0
- package/dist/client/types.d.mts +29 -0
- package/dist/codec/devalue.d.mts +21 -0
- package/dist/codec/devalue.mjs +32 -0
- package/dist/codec/msgpack.d.mts +21 -0
- package/dist/codec/msgpack.mjs +59 -0
- package/dist/compile.d.mts +52 -0
- package/dist/compile.mjs +304 -0
- package/dist/contract.d.mts +36 -0
- package/dist/contract.mjs +40 -0
- package/dist/core/error.d.mts +104 -0
- package/dist/core/error.mjs +139 -0
- package/dist/core/handler.mjs +546 -0
- package/dist/core/iterator.d.mts +17 -0
- package/dist/core/iterator.mjs +79 -0
- package/dist/core/router-utils.mjs +16 -0
- package/dist/core/schema.d.mts +19 -0
- package/dist/core/schema.mjs +26 -0
- package/dist/core/serve.mjs +38 -0
- package/dist/core/sse.d.mts +16 -0
- package/dist/core/sse.mjs +95 -0
- package/dist/core/storage.d.mts +21 -0
- package/dist/core/storage.mjs +63 -0
- package/dist/core/utils.mjs +21 -0
- package/dist/fast-stringify.mjs +125 -0
- package/dist/index.d.mts +15 -37
- package/dist/index.mjs +13 -7
- package/dist/integrations/ai/index.d.mts +25 -0
- package/dist/integrations/ai/index.mjs +116 -0
- package/dist/integrations/react/index.d.mts +83 -0
- package/dist/integrations/react/index.mjs +197 -0
- package/dist/integrations/tanstack-query/index.d.mts +120 -0
- package/dist/integrations/tanstack-query/index.mjs +100 -0
- package/dist/integrations/tanstack-query/ssr.d.mts +51 -0
- package/dist/integrations/tanstack-query/ssr.mjs +89 -0
- package/dist/integrations/zod/converter.d.mts +75 -0
- package/dist/integrations/zod/converter.mjs +345 -0
- package/dist/integrations/zod/index.d.mts +2 -0
- package/dist/integrations/zod/index.mjs +2 -0
- package/dist/lazy.d.mts +24 -0
- package/dist/lazy.mjs +27 -0
- package/dist/lifecycle.d.mts +36 -0
- package/dist/lifecycle.mjs +46 -0
- package/dist/map-input.d.mts +17 -0
- package/dist/map-input.mjs +24 -0
- package/dist/plugins/analytics.d.mts +168 -0
- package/dist/plugins/analytics.mjs +459 -0
- package/dist/plugins/batch-server.d.mts +20 -0
- package/dist/plugins/batch-server.mjs +86 -0
- package/dist/plugins/body-limit.d.mts +16 -0
- package/dist/plugins/body-limit.mjs +44 -0
- package/dist/plugins/cache.d.mts +170 -0
- package/dist/plugins/cache.mjs +200 -0
- package/dist/plugins/coerce.d.mts +21 -0
- package/dist/plugins/coerce.mjs +46 -0
- package/dist/plugins/compression.d.mts +19 -0
- package/dist/plugins/compression.mjs +23 -0
- package/dist/plugins/cookies.d.mts +44 -0
- package/dist/plugins/cookies.mjs +67 -0
- package/dist/plugins/cors.d.mts +39 -0
- package/dist/plugins/cors.mjs +56 -0
- package/dist/plugins/custom-serializer.d.mts +57 -0
- package/dist/plugins/custom-serializer.mjs +40 -0
- package/dist/plugins/file-upload.d.mts +38 -0
- package/dist/plugins/file-upload.mjs +100 -0
- package/dist/plugins/index.d.mts +16 -0
- package/dist/plugins/index.mjs +16 -0
- package/dist/plugins/otel.d.mts +35 -0
- package/dist/plugins/otel.mjs +40 -0
- package/dist/plugins/pino.d.mts +60 -0
- package/dist/plugins/pino.mjs +42 -0
- package/dist/plugins/pubsub.d.mts +50 -0
- package/dist/plugins/pubsub.mjs +53 -0
- package/dist/plugins/ratelimit.d.mts +51 -0
- package/dist/plugins/ratelimit.mjs +81 -0
- package/dist/plugins/signing.d.mts +41 -0
- package/dist/plugins/signing.mjs +115 -0
- package/dist/plugins/strict-get.d.mts +10 -0
- package/dist/plugins/strict-get.mjs +33 -0
- package/dist/route/add.mjs +240 -0
- package/dist/route/compiler.mjs +373 -0
- package/dist/route/context.mjs +12 -0
- package/dist/route/types.d.mts +11 -0
- package/dist/route/utils.mjs +17 -0
- package/dist/scalar.d.mts +53 -0
- package/dist/scalar.mjs +315 -0
- package/dist/silgi.d.mts +139 -0
- package/dist/silgi.mjs +113 -0
- package/dist/trpc-interop.d.mts +22 -0
- package/dist/trpc-interop.mjs +68 -0
- package/dist/types.d.mts +82 -0
- package/dist/ws.d.mts +42 -0
- package/dist/ws.mjs +137 -0
- package/lib/dashboard/index.html +123 -0
- package/lib/ocache.d.mts +1 -0
- package/lib/ocache.mjs +1 -0
- package/lib/ofetch.d.mts +1 -0
- package/lib/ofetch.mjs +1 -0
- package/lib/srvx.d.mts +1 -0
- package/lib/srvx.mjs +1 -0
- package/lib/unstorage.d.mts +1 -0
- package/lib/unstorage.mjs +1 -0
- package/package.json +291 -65
- package/bin/silgi.mjs +0 -3
- package/dist/chunks/generate.mjs +0 -933
- package/dist/chunks/init.mjs +0 -21
- package/dist/cli/config.d.mts +0 -19
- package/dist/cli/config.d.ts +0 -19
- package/dist/cli/config.mjs +0 -5
- package/dist/cli/index.d.mts +0 -2
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.mjs +0 -119
- package/dist/index.d.ts +0 -37
- package/dist/plugins/openapi.d.mts +0 -138
- package/dist/plugins/openapi.d.ts +0 -138
- package/dist/plugins/openapi.mjs +0 -204
- package/dist/plugins/scalar.d.mts +0 -14
- package/dist/plugins/scalar.d.ts +0 -14
- package/dist/plugins/scalar.mjs +0 -66
- package/dist/shared/silgi.BMCYk2cR.mjs +0 -841
- package/dist/shared/silgi.D5qK9QOm.d.mts +0 -301
- package/dist/shared/silgi.D5qK9QOm.d.ts +0 -301
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { SilgiError, toSilgiError } from "../core/error.mjs";
|
|
2
|
+
import { ValidationError } from "../core/schema.mjs";
|
|
3
|
+
import { compileRouter } from "../compile.mjs";
|
|
4
|
+
//#region src/adapters/message-port.ts
|
|
5
|
+
/**
|
|
6
|
+
* Message Port adapter — use Silgi over MessagePort/MessageChannel.
|
|
7
|
+
*
|
|
8
|
+
* Works with Electron (main↔renderer), browser extensions (background↔popup),
|
|
9
|
+
* Web Workers, and Node.js Worker Threads.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // Worker / Electron main
|
|
14
|
+
* import { silgiMessagePort } from "silgi/message-port"
|
|
15
|
+
*
|
|
16
|
+
* const dispose = silgiMessagePort(appRouter, port, {
|
|
17
|
+
* context: () => ({ db: getDB() }),
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* // Client side
|
|
21
|
+
* import { MessagePortLink } from "silgi/message-port"
|
|
22
|
+
* import { createClient } from "silgi/client"
|
|
23
|
+
*
|
|
24
|
+
* const client = createClient<AppRouter>(new MessagePortLink(port))
|
|
25
|
+
* const users = await client.users.list({ limit: 10 })
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Attach Silgi to a MessagePort (server side).
|
|
30
|
+
* Listens for RPC messages and responds with results.
|
|
31
|
+
* Returns a dispose function to stop listening.
|
|
32
|
+
*/
|
|
33
|
+
function silgiMessagePort(router, port, options = {}) {
|
|
34
|
+
const flatRouter = compileRouter(router);
|
|
35
|
+
const handler = async (event) => {
|
|
36
|
+
const msg = event.data;
|
|
37
|
+
if (!msg || typeof msg !== "object" || !msg.__silgi || msg.__type !== "request") return;
|
|
38
|
+
const match = flatRouter("POST", "/" + msg.path);
|
|
39
|
+
if (!match) {
|
|
40
|
+
port.postMessage({
|
|
41
|
+
__silgi: true,
|
|
42
|
+
__type: "response",
|
|
43
|
+
id: msg.id,
|
|
44
|
+
error: {
|
|
45
|
+
code: "NOT_FOUND",
|
|
46
|
+
status: 404,
|
|
47
|
+
message: "Procedure not found"
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const route = match.data;
|
|
53
|
+
try {
|
|
54
|
+
const ctx = Object.create(null);
|
|
55
|
+
if (match.params) ctx.params = match.params;
|
|
56
|
+
if (options.context) {
|
|
57
|
+
const baseCtx = await options.context();
|
|
58
|
+
const keys = Object.keys(baseCtx);
|
|
59
|
+
for (let i = 0; i < keys.length; i++) ctx[keys[i]] = baseCtx[keys[i]];
|
|
60
|
+
}
|
|
61
|
+
const signal = new AbortController().signal;
|
|
62
|
+
const result = await route.handler(ctx, msg.input, signal);
|
|
63
|
+
port.postMessage({
|
|
64
|
+
__silgi: true,
|
|
65
|
+
__type: "response",
|
|
66
|
+
id: msg.id,
|
|
67
|
+
result
|
|
68
|
+
});
|
|
69
|
+
} catch (error) {
|
|
70
|
+
const e = error instanceof ValidationError ? {
|
|
71
|
+
code: "BAD_REQUEST",
|
|
72
|
+
status: 400,
|
|
73
|
+
message: error.message,
|
|
74
|
+
data: { issues: error.issues }
|
|
75
|
+
} : error instanceof SilgiError ? error.toJSON() : toSilgiError(error).toJSON();
|
|
76
|
+
port.postMessage({
|
|
77
|
+
__silgi: true,
|
|
78
|
+
__type: "response",
|
|
79
|
+
id: msg.id,
|
|
80
|
+
error: e
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
port.addEventListener("message", handler);
|
|
85
|
+
return () => port.removeEventListener("message", handler);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Client-side MessagePort link.
|
|
89
|
+
* Sends RPC messages and resolves promises when responses arrive.
|
|
90
|
+
*/
|
|
91
|
+
var MessagePortLink = class {
|
|
92
|
+
#port;
|
|
93
|
+
#pending = /* @__PURE__ */ new Map();
|
|
94
|
+
#nextId = 1;
|
|
95
|
+
constructor(port) {
|
|
96
|
+
this.#port = port;
|
|
97
|
+
port.addEventListener("message", (event) => {
|
|
98
|
+
const msg = event.data;
|
|
99
|
+
if (!msg || typeof msg !== "object" || !msg.__silgi || msg.__type !== "response") return;
|
|
100
|
+
const pending = this.#pending.get(msg.id);
|
|
101
|
+
if (!pending) return;
|
|
102
|
+
this.#pending.delete(msg.id);
|
|
103
|
+
if (msg.error) pending.reject(new SilgiError(msg.error.code, {
|
|
104
|
+
status: msg.error.status,
|
|
105
|
+
message: msg.error.message,
|
|
106
|
+
data: msg.error.data
|
|
107
|
+
}));
|
|
108
|
+
else pending.resolve(msg.result);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
call(path, input, _options) {
|
|
112
|
+
return new Promise((resolve, reject) => {
|
|
113
|
+
const id = String(this.#nextId++);
|
|
114
|
+
this.#pending.set(id, {
|
|
115
|
+
resolve,
|
|
116
|
+
reject
|
|
117
|
+
});
|
|
118
|
+
this.#port.postMessage({
|
|
119
|
+
__silgi: true,
|
|
120
|
+
__type: "request",
|
|
121
|
+
id,
|
|
122
|
+
path: path.join("/"),
|
|
123
|
+
input
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
//#endregion
|
|
129
|
+
export { MessagePortLink, silgiMessagePort };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { RouterDef } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/nestjs.d.ts
|
|
4
|
+
interface NestAdapterOptions<TCtx extends Record<string, unknown>> {
|
|
5
|
+
/** Context factory — receives the NestJS/Express request */
|
|
6
|
+
context?: (req: any) => TCtx | Promise<TCtx>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a NestJS-compatible handler function.
|
|
10
|
+
*
|
|
11
|
+
* Use inside a `@Controller` with `@All("*")`.
|
|
12
|
+
* Handles routing internally — NestJS only needs to mount the prefix.
|
|
13
|
+
*/
|
|
14
|
+
declare function silgiNestHandler<TCtx extends Record<string, unknown>>(router: RouterDef, options?: NestAdapterOptions<TCtx>): (req: any, res: any) => Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Create a NestJS module configuration for Silgi.
|
|
17
|
+
*
|
|
18
|
+
* Returns an object that can be used with NestJS's dynamic module pattern.
|
|
19
|
+
*/
|
|
20
|
+
declare function createSilgiModule(router: RouterDef, options?: NestAdapterOptions<any>): {
|
|
21
|
+
handler: (req: any, res: any) => Promise<void>;
|
|
22
|
+
router: RouterDef;
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { NestAdapterOptions, createSilgiModule, silgiNestHandler };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { SilgiError, toSilgiError } from "../core/error.mjs";
|
|
2
|
+
import { ValidationError } from "../core/schema.mjs";
|
|
3
|
+
import { compileRouter } from "../compile.mjs";
|
|
4
|
+
//#region src/adapters/nestjs.ts
|
|
5
|
+
/**
|
|
6
|
+
* NestJS adapter — register Silgi as a NestJS controller.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // rpc.controller.ts
|
|
11
|
+
* import { Controller, All, Req, Res } from "@nestjs/common"
|
|
12
|
+
* import { silgiNestHandler } from "silgi/nestjs"
|
|
13
|
+
* import { appRouter } from "./rpc"
|
|
14
|
+
*
|
|
15
|
+
* const rpcHandler = silgiNestHandler(appRouter, {
|
|
16
|
+
* context: (req) => ({ db: getDB(), user: req.user }),
|
|
17
|
+
* })
|
|
18
|
+
*
|
|
19
|
+
* @Controller("rpc")
|
|
20
|
+
* export class RpcController {
|
|
21
|
+
* @All("*")
|
|
22
|
+
* async handle(@Req() req: Request, @Res() res: Response) {
|
|
23
|
+
* return rpcHandler(req, res)
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Create a NestJS-compatible handler function.
|
|
30
|
+
*
|
|
31
|
+
* Use inside a `@Controller` with `@All("*")`.
|
|
32
|
+
* Handles routing internally — NestJS only needs to mount the prefix.
|
|
33
|
+
*/
|
|
34
|
+
function silgiNestHandler(router, options = {}) {
|
|
35
|
+
const flatRouter = compileRouter(router);
|
|
36
|
+
return async (req, res) => {
|
|
37
|
+
let pathname = req.params?.[0] ?? req.path ?? req.url ?? "";
|
|
38
|
+
if (pathname.startsWith("/")) pathname = pathname.slice(1);
|
|
39
|
+
const match = flatRouter(req.method, "/" + pathname);
|
|
40
|
+
if (!match) {
|
|
41
|
+
res.status(404).json({
|
|
42
|
+
code: "NOT_FOUND",
|
|
43
|
+
status: 404,
|
|
44
|
+
message: "Procedure not found"
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const route = match.data;
|
|
49
|
+
try {
|
|
50
|
+
const ctx = Object.create(null);
|
|
51
|
+
if (match.params) ctx.params = match.params;
|
|
52
|
+
if (options.context) {
|
|
53
|
+
const baseCtx = await options.context(req);
|
|
54
|
+
const keys = Object.keys(baseCtx);
|
|
55
|
+
for (let i = 0; i < keys.length; i++) ctx[keys[i]] = baseCtx[keys[i]];
|
|
56
|
+
}
|
|
57
|
+
let input;
|
|
58
|
+
if (req.method === "POST" || req.method === "PUT" || req.method === "PATCH") input = req.body;
|
|
59
|
+
else if (req.query?.data) input = typeof req.query.data === "string" ? JSON.parse(req.query.data) : req.query.data;
|
|
60
|
+
const ac = new AbortController();
|
|
61
|
+
req.on?.("close", () => ac.abort());
|
|
62
|
+
const output = await route.handler(ctx, input, ac.signal);
|
|
63
|
+
res.json(output);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (error instanceof ValidationError) {
|
|
66
|
+
res.status(400).json({
|
|
67
|
+
code: "BAD_REQUEST",
|
|
68
|
+
status: 400,
|
|
69
|
+
message: error.message,
|
|
70
|
+
data: { issues: error.issues }
|
|
71
|
+
});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const e = error instanceof SilgiError ? error : toSilgiError(error);
|
|
75
|
+
res.status(e.status).json(e.toJSON());
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Create a NestJS module configuration for Silgi.
|
|
81
|
+
*
|
|
82
|
+
* Returns an object that can be used with NestJS's dynamic module pattern.
|
|
83
|
+
*/
|
|
84
|
+
function createSilgiModule(router, options = {}) {
|
|
85
|
+
return {
|
|
86
|
+
handler: silgiNestHandler(router, options),
|
|
87
|
+
router
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
export { createSilgiModule, silgiNestHandler };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { RouterDef } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/nextjs.d.ts
|
|
4
|
+
interface NextjsAdapterOptions<TCtx extends Record<string, unknown>> {
|
|
5
|
+
/** Context factory — receives the Next.js Request */
|
|
6
|
+
context?: (req: Request) => TCtx | Promise<TCtx>;
|
|
7
|
+
/** Route prefix to strip. Default: "/api/rpc" */
|
|
8
|
+
prefix?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create a Next.js App Router route handler.
|
|
12
|
+
*
|
|
13
|
+
* Uses Silgi's handler() internally — full Fetch API support
|
|
14
|
+
* including content negotiation (JSON, MessagePack, devalue).
|
|
15
|
+
*
|
|
16
|
+
* The handler strips the prefix from the URL path before dispatching
|
|
17
|
+
* to the Silgi router.
|
|
18
|
+
*/
|
|
19
|
+
declare function silgiNextjs<TCtx extends Record<string, unknown>>(router: RouterDef, options?: NextjsAdapterOptions<TCtx>): (req: Request) => Promise<Response>;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { NextjsAdapterOptions, silgiNextjs };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/adapters/nextjs.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a Next.js App Router route handler.
|
|
4
|
+
*
|
|
5
|
+
* Uses Silgi's handler() internally — full Fetch API support
|
|
6
|
+
* including content negotiation (JSON, MessagePack, devalue).
|
|
7
|
+
*
|
|
8
|
+
* The handler strips the prefix from the URL path before dispatching
|
|
9
|
+
* to the Silgi router.
|
|
10
|
+
*/
|
|
11
|
+
function silgiNextjs(router, options = {}) {
|
|
12
|
+
const prefix = options.prefix ?? "/api/rpc";
|
|
13
|
+
let _handler = null;
|
|
14
|
+
return async (req) => {
|
|
15
|
+
if (!_handler) {
|
|
16
|
+
const { silgi } = await import("../silgi.mjs");
|
|
17
|
+
_handler = silgi({ context: options.context ?? (() => ({})) }).handler(router);
|
|
18
|
+
}
|
|
19
|
+
const url = new URL(req.url);
|
|
20
|
+
let pathname = url.pathname;
|
|
21
|
+
if (pathname.startsWith(prefix)) {
|
|
22
|
+
pathname = pathname.slice(prefix.length);
|
|
23
|
+
if (!pathname.startsWith("/")) pathname = "/" + pathname;
|
|
24
|
+
}
|
|
25
|
+
const rewritten = new Request(new URL(pathname + url.search, url.origin), req);
|
|
26
|
+
return _handler(rewritten);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { silgiNextjs };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { RouterDef } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/peer.d.ts
|
|
4
|
+
interface PeerOptions<TCtx extends Record<string, unknown>> {
|
|
5
|
+
context?: () => TCtx | Promise<TCtx>;
|
|
6
|
+
}
|
|
7
|
+
interface Peer {
|
|
8
|
+
/** Client proxy to call the remote peer's procedures */
|
|
9
|
+
client: any;
|
|
10
|
+
/** Stop listening for incoming calls */
|
|
11
|
+
dispose: () => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create a bidirectional peer — serves your router AND creates a client
|
|
15
|
+
* for the remote peer's router.
|
|
16
|
+
*/
|
|
17
|
+
declare function createPeer(localRouter: RouterDef, port: {
|
|
18
|
+
postMessage(msg: unknown): void;
|
|
19
|
+
addEventListener(type: 'message', handler: (event: {
|
|
20
|
+
data: unknown;
|
|
21
|
+
}) => void): void;
|
|
22
|
+
removeEventListener(type: 'message', handler: (event: {
|
|
23
|
+
data: unknown;
|
|
24
|
+
}) => void): void;
|
|
25
|
+
}, options?: PeerOptions<Record<string, unknown>>): Peer;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { Peer, PeerOptions, createPeer };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createClient } from "../client/client.mjs";
|
|
2
|
+
import { MessagePortLink, silgiMessagePort } from "./message-port.mjs";
|
|
3
|
+
//#region src/adapters/peer.ts
|
|
4
|
+
/**
|
|
5
|
+
* Peer-to-peer adapter — bidirectional RPC between two Silgi instances.
|
|
6
|
+
*
|
|
7
|
+
* Both sides can be client AND server simultaneously. Uses MessagePort
|
|
8
|
+
* or any bidirectional channel (WebSocket, WebRTC DataChannel, etc.).
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { createPeer } from "silgi/peer"
|
|
13
|
+
*
|
|
14
|
+
* const peerA = createPeer(routerA, channel.port1)
|
|
15
|
+
* const peerB = createPeer(routerB, channel.port2)
|
|
16
|
+
*
|
|
17
|
+
* // A calls B's procedures
|
|
18
|
+
* const result = await peerA.client.hello()
|
|
19
|
+
*
|
|
20
|
+
* // B calls A's procedures
|
|
21
|
+
* const result = await peerB.client.ping()
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Create a bidirectional peer — serves your router AND creates a client
|
|
26
|
+
* for the remote peer's router.
|
|
27
|
+
*/
|
|
28
|
+
function createPeer(localRouter, port, options = {}) {
|
|
29
|
+
const dispose = silgiMessagePort(localRouter, port, options);
|
|
30
|
+
return {
|
|
31
|
+
client: createClient(new MessagePortLink(port)),
|
|
32
|
+
dispose
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { createPeer };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RouterDef } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/remix.d.ts
|
|
4
|
+
interface RemixAdapterOptions<TCtx extends Record<string, unknown>> {
|
|
5
|
+
context?: (request: Request) => TCtx | Promise<TCtx>;
|
|
6
|
+
prefix?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a Remix action/loader handler.
|
|
10
|
+
* Uses Silgi's handler() — full Fetch API + content negotiation.
|
|
11
|
+
*/
|
|
12
|
+
declare function silgiRemix<TCtx extends Record<string, unknown>>(router: RouterDef, options?: RemixAdapterOptions<TCtx>): (args: {
|
|
13
|
+
request: Request;
|
|
14
|
+
params: Record<string, string>;
|
|
15
|
+
}) => Promise<Response>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { RemixAdapterOptions, silgiRemix };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/adapters/remix.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a Remix action/loader handler.
|
|
4
|
+
* Uses Silgi's handler() — full Fetch API + content negotiation.
|
|
5
|
+
*/
|
|
6
|
+
function silgiRemix(router, options = {}) {
|
|
7
|
+
const prefix = options.prefix ?? "/rpc";
|
|
8
|
+
let _handler = null;
|
|
9
|
+
return async ({ request }) => {
|
|
10
|
+
if (!_handler) {
|
|
11
|
+
const { silgi } = await import("../silgi.mjs");
|
|
12
|
+
_handler = silgi({ context: options.context ?? (() => ({})) }).handler(router);
|
|
13
|
+
}
|
|
14
|
+
const url = new URL(request.url);
|
|
15
|
+
let pathname = url.pathname;
|
|
16
|
+
if (pathname.startsWith(prefix)) {
|
|
17
|
+
pathname = pathname.slice(prefix.length);
|
|
18
|
+
if (!pathname.startsWith("/")) pathname = "/" + pathname;
|
|
19
|
+
}
|
|
20
|
+
return _handler(new Request(new URL(pathname + url.search, url.origin), request));
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { silgiRemix };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RouterDef } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/solidstart.d.ts
|
|
4
|
+
interface SolidStartAdapterOptions<TCtx extends Record<string, unknown>> {
|
|
5
|
+
context?: (event: any) => TCtx | Promise<TCtx>;
|
|
6
|
+
prefix?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a SolidStart API route handler.
|
|
10
|
+
* SolidStart uses Fetch API events — uses Silgi's handler().
|
|
11
|
+
*/
|
|
12
|
+
declare function silgiSolidStart<TCtx extends Record<string, unknown>>(router: RouterDef, options?: SolidStartAdapterOptions<TCtx>): (event: any) => Promise<Response>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { SolidStartAdapterOptions, silgiSolidStart };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/adapters/solidstart.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a SolidStart API route handler.
|
|
4
|
+
* SolidStart uses Fetch API events — uses Silgi's handler().
|
|
5
|
+
*/
|
|
6
|
+
function silgiSolidStart(router, options = {}) {
|
|
7
|
+
const prefix = options.prefix ?? "/api/rpc";
|
|
8
|
+
let _handler = null;
|
|
9
|
+
let _currentEvent = null;
|
|
10
|
+
return async (event) => {
|
|
11
|
+
_currentEvent = event;
|
|
12
|
+
if (!_handler) {
|
|
13
|
+
const { silgi } = await import("../silgi.mjs");
|
|
14
|
+
_handler = silgi({ context: (_req) => {
|
|
15
|
+
if (options.context) return options.context(_currentEvent);
|
|
16
|
+
return {};
|
|
17
|
+
} }).handler(router);
|
|
18
|
+
}
|
|
19
|
+
const request = event.request ?? event;
|
|
20
|
+
const url = new URL(request.url);
|
|
21
|
+
let pathname = url.pathname;
|
|
22
|
+
if (pathname.startsWith(prefix)) {
|
|
23
|
+
pathname = pathname.slice(prefix.length);
|
|
24
|
+
if (!pathname.startsWith("/")) pathname = "/" + pathname;
|
|
25
|
+
}
|
|
26
|
+
return _handler(new Request(new URL(pathname + url.search, url.origin), request));
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { silgiSolidStart };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { RouterDef } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/sveltekit.d.ts
|
|
4
|
+
interface SvelteKitAdapterOptions<TCtx extends Record<string, unknown>> {
|
|
5
|
+
/** Context factory — receives the SvelteKit RequestEvent */
|
|
6
|
+
context?: (event: any) => TCtx | Promise<TCtx>;
|
|
7
|
+
/** Route prefix to strip. Default: "/api/rpc" */
|
|
8
|
+
prefix?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create a SvelteKit request handler.
|
|
12
|
+
*
|
|
13
|
+
* SvelteKit passes a RequestEvent with `.request` (standard Request).
|
|
14
|
+
* The handler uses Silgi's handler() for full protocol support.
|
|
15
|
+
*/
|
|
16
|
+
declare function silgiSvelteKit<TCtx extends Record<string, unknown>>(router: RouterDef, options?: SvelteKitAdapterOptions<TCtx>): (event: any) => Promise<Response>;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { SvelteKitAdapterOptions, silgiSvelteKit };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/adapters/sveltekit.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a SvelteKit request handler.
|
|
4
|
+
*
|
|
5
|
+
* SvelteKit passes a RequestEvent with `.request` (standard Request).
|
|
6
|
+
* The handler uses Silgi's handler() for full protocol support.
|
|
7
|
+
*/
|
|
8
|
+
function silgiSvelteKit(router, options = {}) {
|
|
9
|
+
const prefix = options.prefix ?? "/api/rpc";
|
|
10
|
+
let _handler = null;
|
|
11
|
+
let _currentEvent = null;
|
|
12
|
+
return async (event) => {
|
|
13
|
+
_currentEvent = event;
|
|
14
|
+
if (!_handler) {
|
|
15
|
+
const { silgi } = await import("../silgi.mjs");
|
|
16
|
+
_handler = silgi({ context: (_req) => {
|
|
17
|
+
if (options.context) return options.context(_currentEvent);
|
|
18
|
+
return {};
|
|
19
|
+
} }).handler(router);
|
|
20
|
+
}
|
|
21
|
+
const req = event.request;
|
|
22
|
+
const url = new URL(req.url);
|
|
23
|
+
let pathname = url.pathname;
|
|
24
|
+
if (pathname.startsWith(prefix)) {
|
|
25
|
+
pathname = pathname.slice(prefix.length);
|
|
26
|
+
if (!pathname.startsWith("/")) pathname = "/" + pathname;
|
|
27
|
+
}
|
|
28
|
+
const rewritten = new Request(new URL(pathname + url.search, url.origin), req);
|
|
29
|
+
return _handler(rewritten);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { silgiSvelteKit };
|
package/dist/analyze.mjs
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/analyze.ts
|
|
2
|
+
/**
|
|
3
|
+
* Analyze a resolve function to determine what it actually uses.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* analyzeHandler(({ ctx }) => ctx.db.users.findMany())
|
|
8
|
+
* // → { usesContext: true, usesInput: false, usesFail: false, usesSignal: false, isAsync: false }
|
|
9
|
+
*
|
|
10
|
+
* analyzeHandler(async ({ input }) => input.name)
|
|
11
|
+
* // → { usesContext: false, usesInput: true, usesFail: false, usesSignal: false, isAsync: true }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
function analyzeHandler(fn) {
|
|
15
|
+
const src = fn.toString();
|
|
16
|
+
const isAsync = src.startsWith("async ") || src.includes("__async");
|
|
17
|
+
return {
|
|
18
|
+
usesContext: /\bctx\b/.test(src) || /\.ctx\b/.test(src) || /\bcontext\b/.test(src),
|
|
19
|
+
usesInput: /\binput\b/.test(src) || /\.input\b/.test(src),
|
|
20
|
+
usesFail: /\bfail\b/.test(src) || /\.fail\b/.test(src),
|
|
21
|
+
usesSignal: /\bsignal\b/.test(src) || /\.signal\b/.test(src),
|
|
22
|
+
isAsync
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { analyzeHandler };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { RouterDef } from "../types.mjs";
|
|
2
|
+
import { ClientContext, ClientLink, ClientOptions } from "../client/types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/broker/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Universal broker transport — implement this for any message broker.
|
|
7
|
+
*
|
|
8
|
+
* Two methods: `subscribe` (server listens) and `request` (client calls).
|
|
9
|
+
* The driver handles serialization, correlation, and reply routing internally.
|
|
10
|
+
*/
|
|
11
|
+
interface BrokerDriver {
|
|
12
|
+
/**
|
|
13
|
+
* Subscribe to a subject. Handler receives a serialized payload and a
|
|
14
|
+
* `reply` callback to send the response back to the caller.
|
|
15
|
+
*
|
|
16
|
+
* Returns a cleanup function (sync or async) to unsubscribe.
|
|
17
|
+
*/
|
|
18
|
+
subscribe(subject: string, handler: (payload: string, reply: (data: string) => void) => void): (() => void) | Promise<() => void>;
|
|
19
|
+
/**
|
|
20
|
+
* Request-reply: publish payload to a subject and wait for the response.
|
|
21
|
+
* The driver handles correlation and reply routing internally.
|
|
22
|
+
*/
|
|
23
|
+
request(subject: string, payload: string, opts?: {
|
|
24
|
+
timeout?: number;
|
|
25
|
+
}): Promise<string>;
|
|
26
|
+
}
|
|
27
|
+
interface BrokerOptions<TCtx extends Record<string, unknown>> {
|
|
28
|
+
/** Subject/topic to listen on. Default: `"silgi"` */
|
|
29
|
+
subject?: string;
|
|
30
|
+
/** Context factory — called per request */
|
|
31
|
+
context?: () => TCtx | Promise<TCtx>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Attach Silgi to a message broker (server side).
|
|
35
|
+
*
|
|
36
|
+
* Listens for RPC messages on the given subject, dispatches to the compiled
|
|
37
|
+
* router, and replies with results or errors.
|
|
38
|
+
*
|
|
39
|
+
* Returns a cleanup function to stop listening.
|
|
40
|
+
*/
|
|
41
|
+
declare function silgiBroker<TCtx extends Record<string, unknown>>(router: RouterDef, driver: BrokerDriver, options?: BrokerOptions<TCtx>): Promise<() => void>;
|
|
42
|
+
interface BrokerLinkOptions {
|
|
43
|
+
/** Subject/topic to send requests to. Default: `"silgi"` */
|
|
44
|
+
subject?: string;
|
|
45
|
+
/** Request timeout in ms. Default: `10_000` */
|
|
46
|
+
timeout?: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Client-side broker link — sends RPC calls via a broker driver.
|
|
50
|
+
*/
|
|
51
|
+
declare class BrokerLink<TCtx extends ClientContext = ClientContext> implements ClientLink<TCtx> {
|
|
52
|
+
#private;
|
|
53
|
+
constructor(driver: BrokerDriver, options?: BrokerLinkOptions);
|
|
54
|
+
call(path: readonly string[], input: unknown, _options: ClientOptions<TCtx>): Promise<unknown>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* In-memory broker driver — for testing and single-process development.
|
|
58
|
+
* Simulates request-reply without any external broker.
|
|
59
|
+
*/
|
|
60
|
+
declare function memoryBroker(): BrokerDriver;
|
|
61
|
+
//#endregion
|
|
62
|
+
export { BrokerDriver, BrokerLink, BrokerLinkOptions, BrokerOptions, memoryBroker, silgiBroker };
|