silgi 0.0.13 → 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.
Files changed (186) hide show
  1. package/README.md +102 -1
  2. package/dist/_virtual/_rolldown/runtime.mjs +5 -0
  3. package/dist/adapters/astro.d.mts +17 -0
  4. package/dist/adapters/astro.mjs +24 -0
  5. package/dist/adapters/aws-lambda.d.mts +31 -0
  6. package/dist/adapters/aws-lambda.mjs +85 -0
  7. package/dist/adapters/elysia.d.mts +17 -0
  8. package/dist/adapters/elysia.mjs +76 -0
  9. package/dist/adapters/express.d.mts +16 -0
  10. package/dist/adapters/express.mjs +78 -0
  11. package/dist/adapters/fastify.d.mts +15 -0
  12. package/dist/adapters/fastify.mjs +78 -0
  13. package/dist/adapters/message-port.d.mts +37 -0
  14. package/dist/adapters/message-port.mjs +129 -0
  15. package/dist/adapters/nestjs.d.mts +25 -0
  16. package/dist/adapters/nestjs.mjs +91 -0
  17. package/dist/adapters/nextjs.d.mts +21 -0
  18. package/dist/adapters/nextjs.mjs +30 -0
  19. package/dist/adapters/peer.d.mts +27 -0
  20. package/dist/adapters/peer.mjs +36 -0
  21. package/dist/adapters/remix.d.mts +17 -0
  22. package/dist/adapters/remix.mjs +24 -0
  23. package/dist/adapters/solidstart.d.mts +14 -0
  24. package/dist/adapters/solidstart.mjs +30 -0
  25. package/dist/adapters/sveltekit.d.mts +18 -0
  26. package/dist/adapters/sveltekit.mjs +33 -0
  27. package/dist/analyze.mjs +26 -0
  28. package/dist/broker/index.d.mts +62 -0
  29. package/dist/broker/index.mjs +153 -0
  30. package/dist/broker/nats.d.mts +33 -0
  31. package/dist/broker/nats.mjs +31 -0
  32. package/dist/broker/redis.d.mts +51 -0
  33. package/dist/broker/redis.mjs +92 -0
  34. package/dist/builder.d.mts +36 -0
  35. package/dist/builder.mjs +51 -0
  36. package/dist/callable.d.mts +17 -0
  37. package/dist/callable.mjs +42 -0
  38. package/dist/client/adapters/fetch/index.d.mts +17 -0
  39. package/dist/client/adapters/fetch/index.mjs +61 -0
  40. package/dist/client/adapters/ofetch/index.d.mts +41 -0
  41. package/dist/client/adapters/ofetch/index.mjs +92 -0
  42. package/dist/client/client.d.mts +29 -0
  43. package/dist/client/client.mjs +54 -0
  44. package/dist/client/dynamic-link.d.mts +15 -0
  45. package/dist/client/dynamic-link.mjs +16 -0
  46. package/dist/client/index.d.mts +7 -0
  47. package/dist/client/index.mjs +6 -0
  48. package/dist/client/interceptor.d.mts +31 -0
  49. package/dist/client/interceptor.mjs +34 -0
  50. package/dist/client/merge.d.mts +28 -0
  51. package/dist/client/merge.mjs +30 -0
  52. package/dist/client/openapi.d.mts +29 -0
  53. package/dist/client/openapi.mjs +89 -0
  54. package/dist/client/plugins/batch.d.mts +20 -0
  55. package/dist/client/plugins/batch.mjs +64 -0
  56. package/dist/client/plugins/csrf.d.mts +13 -0
  57. package/dist/client/plugins/csrf.mjs +20 -0
  58. package/dist/client/plugins/dedupe.d.mts +10 -0
  59. package/dist/client/plugins/dedupe.mjs +28 -0
  60. package/dist/client/plugins/index.d.mts +5 -0
  61. package/dist/client/plugins/index.mjs +5 -0
  62. package/dist/client/plugins/retry.d.mts +11 -0
  63. package/dist/client/plugins/retry.mjs +21 -0
  64. package/dist/client/server.d.mts +16 -0
  65. package/dist/client/server.mjs +60 -0
  66. package/dist/client/types.d.mts +29 -0
  67. package/dist/codec/devalue.d.mts +21 -0
  68. package/dist/codec/devalue.mjs +32 -0
  69. package/dist/codec/msgpack.d.mts +21 -0
  70. package/dist/codec/msgpack.mjs +59 -0
  71. package/dist/compile.d.mts +52 -0
  72. package/dist/compile.mjs +304 -0
  73. package/dist/contract.d.mts +36 -0
  74. package/dist/contract.mjs +40 -0
  75. package/dist/core/error.d.mts +104 -0
  76. package/dist/core/error.mjs +139 -0
  77. package/dist/core/handler.mjs +546 -0
  78. package/dist/core/iterator.d.mts +17 -0
  79. package/dist/core/iterator.mjs +79 -0
  80. package/dist/core/router-utils.mjs +16 -0
  81. package/dist/core/schema.d.mts +19 -0
  82. package/dist/core/schema.mjs +26 -0
  83. package/dist/core/serve.mjs +38 -0
  84. package/dist/core/sse.d.mts +16 -0
  85. package/dist/core/sse.mjs +95 -0
  86. package/dist/core/storage.d.mts +21 -0
  87. package/dist/core/storage.mjs +63 -0
  88. package/dist/core/utils.mjs +21 -0
  89. package/dist/fast-stringify.mjs +125 -0
  90. package/dist/index.d.mts +15 -37
  91. package/dist/index.mjs +13 -7
  92. package/dist/integrations/ai/index.d.mts +25 -0
  93. package/dist/integrations/ai/index.mjs +116 -0
  94. package/dist/integrations/react/index.d.mts +83 -0
  95. package/dist/integrations/react/index.mjs +197 -0
  96. package/dist/integrations/tanstack-query/index.d.mts +120 -0
  97. package/dist/integrations/tanstack-query/index.mjs +100 -0
  98. package/dist/integrations/tanstack-query/ssr.d.mts +51 -0
  99. package/dist/integrations/tanstack-query/ssr.mjs +89 -0
  100. package/dist/integrations/zod/converter.d.mts +75 -0
  101. package/dist/integrations/zod/converter.mjs +345 -0
  102. package/dist/integrations/zod/index.d.mts +2 -0
  103. package/dist/integrations/zod/index.mjs +2 -0
  104. package/dist/lazy.d.mts +24 -0
  105. package/dist/lazy.mjs +27 -0
  106. package/dist/lifecycle.d.mts +36 -0
  107. package/dist/lifecycle.mjs +46 -0
  108. package/dist/map-input.d.mts +17 -0
  109. package/dist/map-input.mjs +24 -0
  110. package/dist/plugins/analytics.d.mts +168 -0
  111. package/dist/plugins/analytics.mjs +459 -0
  112. package/dist/plugins/batch-server.d.mts +20 -0
  113. package/dist/plugins/batch-server.mjs +86 -0
  114. package/dist/plugins/body-limit.d.mts +16 -0
  115. package/dist/plugins/body-limit.mjs +44 -0
  116. package/dist/plugins/cache.d.mts +170 -0
  117. package/dist/plugins/cache.mjs +200 -0
  118. package/dist/plugins/coerce.d.mts +21 -0
  119. package/dist/plugins/coerce.mjs +46 -0
  120. package/dist/plugins/compression.d.mts +19 -0
  121. package/dist/plugins/compression.mjs +23 -0
  122. package/dist/plugins/cookies.d.mts +44 -0
  123. package/dist/plugins/cookies.mjs +67 -0
  124. package/dist/plugins/cors.d.mts +39 -0
  125. package/dist/plugins/cors.mjs +56 -0
  126. package/dist/plugins/custom-serializer.d.mts +57 -0
  127. package/dist/plugins/custom-serializer.mjs +40 -0
  128. package/dist/plugins/file-upload.d.mts +38 -0
  129. package/dist/plugins/file-upload.mjs +100 -0
  130. package/dist/plugins/index.d.mts +16 -0
  131. package/dist/plugins/index.mjs +16 -0
  132. package/dist/plugins/otel.d.mts +35 -0
  133. package/dist/plugins/otel.mjs +40 -0
  134. package/dist/plugins/pino.d.mts +60 -0
  135. package/dist/plugins/pino.mjs +42 -0
  136. package/dist/plugins/pubsub.d.mts +50 -0
  137. package/dist/plugins/pubsub.mjs +53 -0
  138. package/dist/plugins/ratelimit.d.mts +51 -0
  139. package/dist/plugins/ratelimit.mjs +81 -0
  140. package/dist/plugins/signing.d.mts +41 -0
  141. package/dist/plugins/signing.mjs +115 -0
  142. package/dist/plugins/strict-get.d.mts +10 -0
  143. package/dist/plugins/strict-get.mjs +33 -0
  144. package/dist/route/add.mjs +240 -0
  145. package/dist/route/compiler.mjs +373 -0
  146. package/dist/route/context.mjs +12 -0
  147. package/dist/route/types.d.mts +11 -0
  148. package/dist/route/utils.mjs +17 -0
  149. package/dist/scalar.d.mts +53 -0
  150. package/dist/scalar.mjs +315 -0
  151. package/dist/silgi.d.mts +139 -0
  152. package/dist/silgi.mjs +113 -0
  153. package/dist/trpc-interop.d.mts +22 -0
  154. package/dist/trpc-interop.mjs +68 -0
  155. package/dist/types.d.mts +82 -0
  156. package/dist/ws.d.mts +42 -0
  157. package/dist/ws.mjs +137 -0
  158. package/lib/dashboard/index.html +123 -0
  159. package/lib/ocache.d.mts +1 -0
  160. package/lib/ocache.mjs +1 -0
  161. package/lib/ofetch.d.mts +1 -0
  162. package/lib/ofetch.mjs +1 -0
  163. package/lib/srvx.d.mts +1 -0
  164. package/lib/srvx.mjs +1 -0
  165. package/lib/unstorage.d.mts +1 -0
  166. package/lib/unstorage.mjs +1 -0
  167. package/package.json +291 -65
  168. package/bin/silgi.mjs +0 -3
  169. package/dist/chunks/generate.mjs +0 -933
  170. package/dist/chunks/init.mjs +0 -21
  171. package/dist/cli/config.d.mts +0 -19
  172. package/dist/cli/config.d.ts +0 -19
  173. package/dist/cli/config.mjs +0 -5
  174. package/dist/cli/index.d.mts +0 -2
  175. package/dist/cli/index.d.ts +0 -2
  176. package/dist/cli/index.mjs +0 -119
  177. package/dist/index.d.ts +0 -37
  178. package/dist/plugins/openapi.d.mts +0 -138
  179. package/dist/plugins/openapi.d.ts +0 -138
  180. package/dist/plugins/openapi.mjs +0 -204
  181. package/dist/plugins/scalar.d.mts +0 -14
  182. package/dist/plugins/scalar.d.ts +0 -14
  183. package/dist/plugins/scalar.mjs +0 -66
  184. package/dist/shared/silgi.BMCYk2cR.mjs +0 -841
  185. package/dist/shared/silgi.D5qK9QOm.d.mts +0 -301
  186. 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 };
@@ -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 };