silgi 0.0.14 → 0.1.0-beta.10

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 (210) hide show
  1. package/README.md +102 -1
  2. package/dist/_virtual/_rolldown/runtime.mjs +5 -0
  3. package/dist/adapters/_fetch-adapter.d.mts +18 -0
  4. package/dist/adapters/_fetch-adapter.mjs +53 -0
  5. package/dist/adapters/astro.d.mts +15 -0
  6. package/dist/adapters/astro.mjs +31 -0
  7. package/dist/adapters/aws-lambda.d.mts +42 -0
  8. package/dist/adapters/aws-lambda.mjs +92 -0
  9. package/dist/adapters/express.d.mts +16 -0
  10. package/dist/adapters/express.mjs +120 -0
  11. package/dist/adapters/message-port.d.mts +42 -0
  12. package/dist/adapters/message-port.mjs +132 -0
  13. package/dist/adapters/nestjs.d.mts +25 -0
  14. package/dist/adapters/nestjs.mjs +75 -0
  15. package/dist/adapters/nextjs.d.mts +14 -0
  16. package/dist/adapters/nextjs.mjs +29 -0
  17. package/dist/adapters/peer.d.mts +27 -0
  18. package/dist/adapters/peer.mjs +36 -0
  19. package/dist/adapters/remix.d.mts +15 -0
  20. package/dist/adapters/remix.mjs +30 -0
  21. package/dist/adapters/solidstart.d.mts +12 -0
  22. package/dist/adapters/solidstart.mjs +29 -0
  23. package/dist/adapters/sveltekit.d.mts +14 -0
  24. package/dist/adapters/sveltekit.mjs +30 -0
  25. package/dist/broker/index.d.mts +62 -0
  26. package/dist/broker/index.mjs +153 -0
  27. package/dist/broker/nats.d.mts +33 -0
  28. package/dist/broker/nats.mjs +31 -0
  29. package/dist/broker/redis.d.mts +51 -0
  30. package/dist/broker/redis.mjs +92 -0
  31. package/dist/builder.d.mts +55 -0
  32. package/dist/builder.mjs +70 -0
  33. package/dist/callable.d.mts +19 -0
  34. package/dist/callable.mjs +42 -0
  35. package/dist/caller.mjs +90 -0
  36. package/dist/client/adapters/fetch/index.d.mts +19 -0
  37. package/dist/client/adapters/fetch/index.mjs +82 -0
  38. package/dist/client/adapters/ofetch/index.d.mts +57 -0
  39. package/dist/client/adapters/ofetch/index.mjs +100 -0
  40. package/dist/client/adapters/websocket/index.d.mts +20 -0
  41. package/dist/client/adapters/websocket/index.mjs +101 -0
  42. package/dist/client/client.d.mts +37 -0
  43. package/dist/client/client.mjs +80 -0
  44. package/dist/client/consume.d.mts +50 -0
  45. package/dist/client/consume.mjs +66 -0
  46. package/dist/client/dynamic-link.d.mts +16 -0
  47. package/dist/client/dynamic-link.mjs +19 -0
  48. package/dist/client/index.d.mts +6 -0
  49. package/dist/client/index.mjs +5 -0
  50. package/dist/client/interceptor.d.mts +31 -0
  51. package/dist/client/interceptor.mjs +34 -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 +26 -0
  55. package/dist/client/plugins/batch.mjs +64 -0
  56. package/dist/client/plugins/circuit-breaker.d.mts +24 -0
  57. package/dist/client/plugins/circuit-breaker.mjs +60 -0
  58. package/dist/client/plugins/csrf.d.mts +13 -0
  59. package/dist/client/plugins/csrf.mjs +20 -0
  60. package/dist/client/plugins/dedupe.d.mts +10 -0
  61. package/dist/client/plugins/dedupe.mjs +28 -0
  62. package/dist/client/plugins/index.d.mts +8 -0
  63. package/dist/client/plugins/index.mjs +8 -0
  64. package/dist/client/plugins/otel.d.mts +12 -0
  65. package/dist/client/plugins/otel.mjs +27 -0
  66. package/dist/client/plugins/retry.d.mts +34 -0
  67. package/dist/client/plugins/retry.mjs +79 -0
  68. package/dist/client/plugins/timeout.d.mts +10 -0
  69. package/dist/client/plugins/timeout.mjs +14 -0
  70. package/dist/client/server.d.mts +16 -0
  71. package/dist/client/server.mjs +62 -0
  72. package/dist/client/types.d.mts +29 -0
  73. package/dist/codec/devalue.d.mts +21 -0
  74. package/dist/codec/devalue.mjs +33 -0
  75. package/dist/codec/msgpack.d.mts +18 -0
  76. package/dist/codec/msgpack.mjs +45 -0
  77. package/dist/codec/sanitize.mjs +38 -0
  78. package/dist/compile.d.mts +46 -0
  79. package/dist/compile.mjs +332 -0
  80. package/dist/contract.d.mts +36 -0
  81. package/dist/contract.mjs +40 -0
  82. package/dist/core/codec.mjs +67 -0
  83. package/dist/core/dispatch.mjs +62 -0
  84. package/dist/core/error.d.mts +104 -0
  85. package/dist/core/error.mjs +139 -0
  86. package/dist/core/handler.d.mts +6 -0
  87. package/dist/core/handler.mjs +148 -0
  88. package/dist/core/input.mjs +49 -0
  89. package/dist/core/iterator.d.mts +17 -0
  90. package/dist/core/iterator.mjs +79 -0
  91. package/dist/core/router-utils.d.mts +25 -0
  92. package/dist/core/router-utils.mjs +98 -0
  93. package/dist/core/schema.d.mts +20 -0
  94. package/dist/core/schema.mjs +33 -0
  95. package/dist/core/serve.d.mts +51 -0
  96. package/dist/core/serve.mjs +76 -0
  97. package/dist/core/sse.d.mts +18 -0
  98. package/dist/core/sse.mjs +98 -0
  99. package/dist/core/storage.d.mts +20 -0
  100. package/dist/core/storage.mjs +61 -0
  101. package/dist/core/task.d.mts +62 -0
  102. package/dist/core/task.mjs +165 -0
  103. package/dist/core/utils.mjs +24 -0
  104. package/dist/index.d.mts +18 -37
  105. package/dist/index.mjs +15 -7
  106. package/dist/integrations/ai/index.d.mts +25 -0
  107. package/dist/integrations/ai/index.mjs +117 -0
  108. package/dist/integrations/better-auth/index.d.mts +61 -0
  109. package/dist/integrations/better-auth/index.mjs +332 -0
  110. package/dist/integrations/drizzle/index.d.mts +27 -0
  111. package/dist/integrations/drizzle/index.mjs +286 -0
  112. package/dist/integrations/hey-api/index.d.mts +2 -0
  113. package/dist/integrations/hey-api/index.mjs +2 -0
  114. package/dist/integrations/hey-api/to-client.d.mts +20 -0
  115. package/dist/integrations/hey-api/to-client.mjs +39 -0
  116. package/dist/integrations/pinia-colada/general-utils.d.mts +13 -0
  117. package/dist/integrations/pinia-colada/general-utils.mjs +9 -0
  118. package/dist/integrations/pinia-colada/index.d.mts +6 -0
  119. package/dist/integrations/pinia-colada/index.mjs +5 -0
  120. package/dist/integrations/pinia-colada/key.d.mts +11 -0
  121. package/dist/integrations/pinia-colada/key.mjs +11 -0
  122. package/dist/integrations/pinia-colada/procedure-utils.d.mts +25 -0
  123. package/dist/integrations/pinia-colada/procedure-utils.mjs +33 -0
  124. package/dist/integrations/pinia-colada/router-utils.d.mts +17 -0
  125. package/dist/integrations/pinia-colada/router-utils.mjs +30 -0
  126. package/dist/integrations/pinia-colada/types.d.mts +25 -0
  127. package/dist/integrations/react/index.d.mts +83 -0
  128. package/dist/integrations/react/index.mjs +196 -0
  129. package/dist/integrations/tanstack-query/index.d.mts +120 -0
  130. package/dist/integrations/tanstack-query/index.mjs +100 -0
  131. package/dist/integrations/tanstack-query/ssr.d.mts +60 -0
  132. package/dist/integrations/tanstack-query/ssr.mjs +102 -0
  133. package/dist/integrations/zod/converter.d.mts +75 -0
  134. package/dist/integrations/zod/converter.mjs +345 -0
  135. package/dist/integrations/zod/index.d.mts +2 -0
  136. package/dist/integrations/zod/index.mjs +2 -0
  137. package/dist/lazy.d.mts +22 -0
  138. package/dist/lazy.mjs +34 -0
  139. package/dist/lifecycle.d.mts +36 -0
  140. package/dist/lifecycle.mjs +46 -0
  141. package/dist/map-input.d.mts +17 -0
  142. package/dist/map-input.mjs +47 -0
  143. package/dist/plugins/analytics.d.mts +236 -0
  144. package/dist/plugins/analytics.mjs +816 -0
  145. package/dist/plugins/batch-server.d.mts +20 -0
  146. package/dist/plugins/batch-server.mjs +91 -0
  147. package/dist/plugins/body-limit.d.mts +19 -0
  148. package/dist/plugins/body-limit.mjs +49 -0
  149. package/dist/plugins/cache.d.mts +170 -0
  150. package/dist/plugins/cache.mjs +212 -0
  151. package/dist/plugins/coerce.d.mts +24 -0
  152. package/dist/plugins/coerce.mjs +70 -0
  153. package/dist/plugins/cookies.d.mts +14 -0
  154. package/dist/plugins/cookies.mjs +48 -0
  155. package/dist/plugins/cors.d.mts +43 -0
  156. package/dist/plugins/cors.mjs +62 -0
  157. package/dist/plugins/file-upload.d.mts +38 -0
  158. package/dist/plugins/file-upload.mjs +102 -0
  159. package/dist/plugins/index.d.mts +14 -0
  160. package/dist/plugins/index.mjs +14 -0
  161. package/dist/plugins/otel.d.mts +35 -0
  162. package/dist/plugins/otel.mjs +40 -0
  163. package/dist/plugins/pino.d.mts +60 -0
  164. package/dist/plugins/pino.mjs +42 -0
  165. package/dist/plugins/pubsub.d.mts +50 -0
  166. package/dist/plugins/pubsub.mjs +53 -0
  167. package/dist/plugins/ratelimit.d.mts +53 -0
  168. package/dist/plugins/ratelimit.mjs +92 -0
  169. package/dist/plugins/signing.d.mts +41 -0
  170. package/dist/plugins/signing.mjs +118 -0
  171. package/dist/plugins/strict-get.d.mts +10 -0
  172. package/dist/plugins/strict-get.mjs +33 -0
  173. package/dist/scalar.d.mts +49 -0
  174. package/dist/scalar.mjs +311 -0
  175. package/dist/silgi.d.mts +144 -0
  176. package/dist/silgi.mjs +156 -0
  177. package/dist/trpc-interop.d.mts +22 -0
  178. package/dist/trpc-interop.mjs +68 -0
  179. package/dist/types.d.mts +108 -0
  180. package/dist/ws.d.mts +88 -0
  181. package/dist/ws.mjs +205 -0
  182. package/lib/dashboard/index.html +123 -0
  183. package/lib/ocache.d.mts +1 -0
  184. package/lib/ocache.mjs +1 -0
  185. package/lib/ofetch.d.mts +1 -0
  186. package/lib/ofetch.mjs +1 -0
  187. package/lib/srvx.d.mts +1 -0
  188. package/lib/srvx.mjs +1 -0
  189. package/lib/unstorage.d.mts +1 -0
  190. package/lib/unstorage.mjs +1 -0
  191. package/package.json +324 -65
  192. package/bin/silgi.mjs +0 -3
  193. package/dist/chunks/generate.mjs +0 -933
  194. package/dist/chunks/init.mjs +0 -21
  195. package/dist/cli/config.d.mts +0 -19
  196. package/dist/cli/config.d.ts +0 -19
  197. package/dist/cli/config.mjs +0 -5
  198. package/dist/cli/index.d.mts +0 -2
  199. package/dist/cli/index.d.ts +0 -2
  200. package/dist/cli/index.mjs +0 -119
  201. package/dist/index.d.ts +0 -37
  202. package/dist/plugins/openapi.d.mts +0 -138
  203. package/dist/plugins/openapi.d.ts +0 -138
  204. package/dist/plugins/openapi.mjs +0 -204
  205. package/dist/plugins/scalar.d.mts +0 -14
  206. package/dist/plugins/scalar.d.ts +0 -14
  207. package/dist/plugins/scalar.mjs +0 -66
  208. package/dist/shared/silgi.BMCYk2cR.mjs +0 -841
  209. package/dist/shared/silgi.D5qK9QOm.d.mts +0 -301
  210. package/dist/shared/silgi.D5qK9QOm.d.ts +0 -301
@@ -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 createHandler<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 createModule(router: RouterDef, options?: NestAdapterOptions<any>): {
21
+ handler: (req: any, res: any) => Promise<void>;
22
+ router: RouterDef;
23
+ };
24
+ //#endregion
25
+ export { NestAdapterOptions, createHandler, createModule };
@@ -0,0 +1,75 @@
1
+ import { compileRouter } from "../compile.mjs";
2
+ import { buildContext, parseQueryData, serializeError } from "../core/dispatch.mjs";
3
+ //#region src/adapters/nestjs.ts
4
+ /**
5
+ * NestJS adapter — register Silgi as a NestJS controller.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // rpc.controller.ts
10
+ * import { Controller, All, Req, Res } from "@nestjs/common"
11
+ * import { createHandler } from "silgi/nestjs"
12
+ * import { appRouter } from "./rpc"
13
+ *
14
+ * const rpcHandler = createHandler(appRouter, {
15
+ * context: (req) => ({ db: getDB(), user: req.user }),
16
+ * })
17
+ *
18
+ * @Controller("rpc")
19
+ * export class RpcController {
20
+ * @All("*")
21
+ * async handle(@Req() req: Request, @Res() res: Response) {
22
+ * return rpcHandler(req, res)
23
+ * }
24
+ * }
25
+ * ```
26
+ */
27
+ /**
28
+ * Create a NestJS-compatible handler function.
29
+ *
30
+ * Use inside a `@Controller` with `@All("*")`.
31
+ * Handles routing internally — NestJS only needs to mount the prefix.
32
+ */
33
+ function createHandler(router, options = {}) {
34
+ const flatRouter = compileRouter(router);
35
+ return async (req, res) => {
36
+ let pathname = req.params?.[0] ?? req.path ?? req.url ?? "";
37
+ if (pathname.startsWith("/")) pathname = pathname.slice(1);
38
+ const match = flatRouter(req.method, "/" + pathname);
39
+ if (!match) {
40
+ res.status(404).json({
41
+ code: "NOT_FOUND",
42
+ status: 404,
43
+ message: "Procedure not found"
44
+ });
45
+ return;
46
+ }
47
+ const route = match.data;
48
+ try {
49
+ const ctx = buildContext(options.context ? await options.context(req) : void 0, match.params);
50
+ let input;
51
+ if (req.method === "POST" || req.method === "PUT" || req.method === "PATCH") input = req.body;
52
+ else if (req.query?.data) input = typeof req.query.data === "string" ? parseQueryData(req.query.data) : req.query.data;
53
+ const ac = new AbortController();
54
+ req.on?.("close", () => ac.abort());
55
+ const output = await route.handler(ctx, input, ac.signal);
56
+ res.json(output);
57
+ } catch (error) {
58
+ const body = serializeError(error);
59
+ res.status(body.status).json(body);
60
+ }
61
+ };
62
+ }
63
+ /**
64
+ * Create a NestJS module configuration for Silgi.
65
+ *
66
+ * Returns an object that can be used with NestJS's dynamic module pattern.
67
+ */
68
+ function createModule(router, options = {}) {
69
+ return {
70
+ handler: createHandler(router, options),
71
+ router
72
+ };
73
+ }
74
+ //#endregion
75
+ export { createHandler, createModule };
@@ -0,0 +1,14 @@
1
+ import { RouterDef } from "../types.mjs";
2
+ import { FetchAdapterConfig } from "./_fetch-adapter.mjs";
3
+
4
+ //#region src/adapters/nextjs.d.ts
5
+ interface NextjsAdapterOptions<TCtx extends Record<string, unknown>> extends FetchAdapterConfig<TCtx> {}
6
+ /**
7
+ * Create a Next.js App Router route handler.
8
+ *
9
+ * Uses Silgi's handler() internally — full Fetch API support
10
+ * including content negotiation (JSON, MessagePack, devalue).
11
+ */
12
+ declare function createHandler<TCtx extends Record<string, unknown>>(router: RouterDef, options?: NextjsAdapterOptions<TCtx>): (req: Request) => Response | Promise<Response>;
13
+ //#endregion
14
+ export { NextjsAdapterOptions, createHandler };
@@ -0,0 +1,29 @@
1
+ import { createFetchAdapter } from "./_fetch-adapter.mjs";
2
+ //#region src/adapters/nextjs.ts
3
+ /**
4
+ * Next.js adapter — use Silgi with App Router API routes.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // app/api/rpc/[...path]/route.ts
9
+ * import { createHandler } from "silgi/nextjs"
10
+ * import { appRouter } from "~/server/rpc"
11
+ *
12
+ * const handler = createHandler(appRouter, {
13
+ * context: (req) => ({ db: getDB() }),
14
+ * })
15
+ *
16
+ * export { handler as GET, handler as POST }
17
+ * ```
18
+ */
19
+ /**
20
+ * Create a Next.js App Router route handler.
21
+ *
22
+ * Uses Silgi's handler() internally — full Fetch API support
23
+ * including content negotiation (JSON, MessagePack, devalue).
24
+ */
25
+ function createHandler(router, options = {}) {
26
+ return createFetchAdapter(router, options, "/api/rpc");
27
+ }
28
+ //#endregion
29
+ export { createHandler };
@@ -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, createHandler } 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 = createHandler(localRouter, port, options);
30
+ return {
31
+ client: createClient(new MessagePortLink(port)),
32
+ dispose
33
+ };
34
+ }
35
+ //#endregion
36
+ export { createPeer };
@@ -0,0 +1,15 @@
1
+ import { RouterDef } from "../types.mjs";
2
+ import { FetchAdapterConfig } from "./_fetch-adapter.mjs";
3
+
4
+ //#region src/adapters/remix.d.ts
5
+ interface RemixAdapterOptions<TCtx extends Record<string, unknown>> extends FetchAdapterConfig<TCtx> {}
6
+ /**
7
+ * Create a Remix action/loader handler.
8
+ * Remix passes { request, params } — we extract request and delegate.
9
+ */
10
+ declare function createHandler<TCtx extends Record<string, unknown>>(router: RouterDef, options?: RemixAdapterOptions<TCtx>): (args: {
11
+ request: Request;
12
+ params: Record<string, string>;
13
+ }) => Response | Promise<Response>;
14
+ //#endregion
15
+ export { RemixAdapterOptions, createHandler };
@@ -0,0 +1,30 @@
1
+ import { createFetchAdapter } from "./_fetch-adapter.mjs";
2
+ //#region src/adapters/remix.ts
3
+ /**
4
+ * Remix adapter — use Silgi with Remix action/loader routes.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // app/routes/rpc.$.tsx
9
+ * import { createHandler } from "silgi/remix"
10
+ * import { appRouter } from "~/server/rpc"
11
+ *
12
+ * const handler = createHandler(appRouter, {
13
+ * prefix: "/rpc",
14
+ * context: (req) => ({ db: getDB() }),
15
+ * })
16
+ *
17
+ * export const action = handler
18
+ * export const loader = handler
19
+ * ```
20
+ */
21
+ /**
22
+ * Create a Remix action/loader handler.
23
+ * Remix passes { request, params } — we extract request and delegate.
24
+ */
25
+ function createHandler(router, options = {}) {
26
+ const handler = createFetchAdapter(router, options, "/rpc");
27
+ return ({ request }) => handler(request);
28
+ }
29
+ //#endregion
30
+ export { createHandler };
@@ -0,0 +1,12 @@
1
+ import { RouterDef } from "../types.mjs";
2
+ import { FetchAdapterConfigWithEvent } from "./_fetch-adapter.mjs";
3
+
4
+ //#region src/adapters/solidstart.d.ts
5
+ interface SolidStartAdapterOptions<TCtx extends Record<string, unknown>> extends FetchAdapterConfigWithEvent<TCtx> {}
6
+ /**
7
+ * Create a SolidStart API route handler.
8
+ * SolidStart uses Fetch API events — uses Silgi's handler().
9
+ */
10
+ declare function createHandler<TCtx extends Record<string, unknown>>(router: RouterDef, options?: SolidStartAdapterOptions<TCtx>): (event: any) => Response | Promise<Response>;
11
+ //#endregion
12
+ export { SolidStartAdapterOptions, createHandler };
@@ -0,0 +1,29 @@
1
+ import { createEventFetchAdapter } from "./_fetch-adapter.mjs";
2
+ //#region src/adapters/solidstart.ts
3
+ /**
4
+ * SolidStart adapter — use Silgi with SolidStart API routes.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // src/routes/api/rpc/[...path].ts
9
+ * import { createHandler } from "silgi/solidstart"
10
+ * import { appRouter } from "~/server/rpc"
11
+ *
12
+ * const handler = createHandler(appRouter, {
13
+ * prefix: "/api/rpc",
14
+ * context: (event) => ({ db: getDB() }),
15
+ * })
16
+ *
17
+ * export const GET = handler
18
+ * export const POST = handler
19
+ * ```
20
+ */
21
+ /**
22
+ * Create a SolidStart API route handler.
23
+ * SolidStart uses Fetch API events — uses Silgi's handler().
24
+ */
25
+ function createHandler(router, options = {}) {
26
+ return createEventFetchAdapter(router, options, "/api/rpc", (event) => event.request ?? event);
27
+ }
28
+ //#endregion
29
+ export { createHandler };
@@ -0,0 +1,14 @@
1
+ import { RouterDef } from "../types.mjs";
2
+ import { FetchAdapterConfigWithEvent } from "./_fetch-adapter.mjs";
3
+
4
+ //#region src/adapters/sveltekit.d.ts
5
+ interface SvelteKitAdapterOptions<TCtx extends Record<string, unknown>> extends FetchAdapterConfigWithEvent<TCtx> {}
6
+ /**
7
+ * Create a SvelteKit request handler.
8
+ *
9
+ * SvelteKit passes a RequestEvent with `.request` (standard Request).
10
+ * The handler uses Silgi's handler() for full protocol support.
11
+ */
12
+ declare function createHandler<TCtx extends Record<string, unknown>>(router: RouterDef, options?: SvelteKitAdapterOptions<TCtx>): (event: any) => Response | Promise<Response>;
13
+ //#endregion
14
+ export { SvelteKitAdapterOptions, createHandler };
@@ -0,0 +1,30 @@
1
+ import { createEventFetchAdapter } from "./_fetch-adapter.mjs";
2
+ //#region src/adapters/sveltekit.ts
3
+ /**
4
+ * SvelteKit adapter — use Silgi with SvelteKit API routes.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // src/routes/api/rpc/[...path]/+server.ts
9
+ * import { createHandler } from "silgi/sveltekit"
10
+ * import { appRouter } from "$lib/server/rpc"
11
+ *
12
+ * const handler = createHandler(appRouter, {
13
+ * context: (event) => ({ db: getDB(), user: event.locals.user }),
14
+ * })
15
+ *
16
+ * export const GET = handler
17
+ * export const POST = handler
18
+ * ```
19
+ */
20
+ /**
21
+ * Create a SvelteKit request handler.
22
+ *
23
+ * SvelteKit passes a RequestEvent with `.request` (standard Request).
24
+ * The handler uses Silgi's handler() for full protocol support.
25
+ */
26
+ function createHandler(router, options = {}) {
27
+ return createEventFetchAdapter(router, options, "/api/rpc", (event) => event.request);
28
+ }
29
+ //#endregion
30
+ export { createHandler };
@@ -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 createBroker<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, createBroker, memoryBroker };
@@ -0,0 +1,153 @@
1
+ import { ValidationError } from "../core/schema.mjs";
2
+ import { SilgiError, toSilgiError } from "../core/error.mjs";
3
+ import { compileRouter } from "../compile.mjs";
4
+ //#region src/broker/index.ts
5
+ /**
6
+ * Message Broker adapter — driver-based RPC over any message broker.
7
+ *
8
+ * Pluggable driver pattern (like unstorage) — bring your own broker client.
9
+ * Built-in memory driver for testing. NATS and Redis drivers available separately.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // Server
14
+ * import { createBroker, memoryBroker } from "silgi/broker"
15
+ *
16
+ * const driver = memoryBroker()
17
+ * const dispose = await createBroker(appRouter, driver, {
18
+ * subject: "myapp.rpc",
19
+ * context: () => ({ db: getDB() }),
20
+ * })
21
+ *
22
+ * // Client
23
+ * import { BrokerLink } from "silgi/broker"
24
+ * import { createClient } from "silgi/client"
25
+ *
26
+ * const client = createClient<AppRouter>(new BrokerLink(driver, { subject: "myapp.rpc" }))
27
+ * const users = await client.users.list({ limit: 10 })
28
+ * ```
29
+ */
30
+ /**
31
+ * Attach Silgi to a message broker (server side).
32
+ *
33
+ * Listens for RPC messages on the given subject, dispatches to the compiled
34
+ * router, and replies with results or errors.
35
+ *
36
+ * Returns a cleanup function to stop listening.
37
+ */
38
+ async function createBroker(router, driver, options = {}) {
39
+ const compiledRouter = compileRouter(router);
40
+ const subject = options.subject ?? "silgi";
41
+ const unsubscribe = await driver.subscribe(subject, (payload, reply) => {
42
+ let msg;
43
+ try {
44
+ msg = JSON.parse(payload);
45
+ } catch {
46
+ reply(JSON.stringify({ e: {
47
+ code: "BAD_REQUEST",
48
+ status: 400,
49
+ message: "Invalid payload"
50
+ } }));
51
+ return;
52
+ }
53
+ const match = compiledRouter("POST", "/" + msg.p);
54
+ if (!match) {
55
+ reply(JSON.stringify({ e: {
56
+ code: "NOT_FOUND",
57
+ status: 404,
58
+ message: "Procedure not found"
59
+ } }));
60
+ return;
61
+ }
62
+ const route = match.data;
63
+ (async () => {
64
+ try {
65
+ const ctx = Object.create(null);
66
+ if (match.params) ctx.params = match.params;
67
+ if (options.context) {
68
+ const baseCtx = await options.context();
69
+ const keys = Object.keys(baseCtx);
70
+ for (let i = 0; i < keys.length; i++) ctx[keys[i]] = baseCtx[keys[i]];
71
+ }
72
+ const signal = new AbortController().signal;
73
+ const res = { r: await route.handler(ctx, msg.i, signal) };
74
+ reply(JSON.stringify(res));
75
+ } catch (error) {
76
+ const res = { e: error instanceof ValidationError ? {
77
+ code: "BAD_REQUEST",
78
+ status: 400,
79
+ message: error.message,
80
+ data: { issues: error.issues }
81
+ } : error instanceof SilgiError ? error.toJSON() : toSilgiError(error).toJSON() };
82
+ reply(JSON.stringify(res));
83
+ }
84
+ })();
85
+ });
86
+ return typeof unsubscribe === "function" ? unsubscribe : () => {};
87
+ }
88
+ /**
89
+ * Client-side broker link — sends RPC calls via a broker driver.
90
+ */
91
+ var BrokerLink = class {
92
+ #driver;
93
+ #subject;
94
+ #timeout;
95
+ constructor(driver, options = {}) {
96
+ this.#driver = driver;
97
+ this.#subject = options.subject ?? "silgi";
98
+ this.#timeout = options.timeout ?? 1e4;
99
+ }
100
+ async call(path, input, _options) {
101
+ const req = {
102
+ p: path.join("/"),
103
+ i: input
104
+ };
105
+ const raw = await this.#driver.request(this.#subject, JSON.stringify(req), { timeout: this.#timeout });
106
+ const res = JSON.parse(raw);
107
+ if (res.e) throw new SilgiError(res.e.code, {
108
+ status: res.e.status,
109
+ message: res.e.message,
110
+ data: res.e.data
111
+ });
112
+ return res.r;
113
+ }
114
+ };
115
+ /**
116
+ * In-memory broker driver — for testing and single-process development.
117
+ * Simulates request-reply without any external broker.
118
+ */
119
+ function memoryBroker() {
120
+ const subscribers = /* @__PURE__ */ new Map();
121
+ return {
122
+ subscribe(subject, handler) {
123
+ let set = subscribers.get(subject);
124
+ if (!set) {
125
+ set = /* @__PURE__ */ new Set();
126
+ subscribers.set(subject, set);
127
+ }
128
+ set.add(handler);
129
+ return () => {
130
+ set.delete(handler);
131
+ if (set.size === 0) subscribers.delete(subject);
132
+ };
133
+ },
134
+ request(subject, payload, opts) {
135
+ return new Promise((resolve, reject) => {
136
+ const handlers = subscribers.get(subject);
137
+ if (!handlers || handlers.size === 0) {
138
+ reject(/* @__PURE__ */ new Error(`No subscriber for subject "${subject}"`));
139
+ return;
140
+ }
141
+ const timeout = opts?.timeout ?? 1e4;
142
+ const timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Broker request timeout: ${subject}`)), timeout);
143
+ const handler = handlers.values().next().value;
144
+ handler(payload, (response) => {
145
+ clearTimeout(timer);
146
+ resolve(response);
147
+ });
148
+ });
149
+ }
150
+ };
151
+ }
152
+ //#endregion
153
+ export { BrokerLink, createBroker, memoryBroker };
@@ -0,0 +1,33 @@
1
+ import { BrokerDriver } from "./index.mjs";
2
+
3
+ //#region src/broker/nats.d.ts
4
+ interface NatsMsg {
5
+ data: Uint8Array;
6
+ respond(payload: Uint8Array): boolean;
7
+ }
8
+ interface NatsSub {
9
+ unsubscribe(): void;
10
+ }
11
+ interface NatsConnection {
12
+ subscribe(subject: string, opts?: {
13
+ callback?: (err: Error | null, msg: NatsMsg) => void;
14
+ queue?: string;
15
+ }): NatsSub;
16
+ request(subject: string, payload?: Uint8Array, opts?: {
17
+ timeout?: number;
18
+ }): Promise<NatsMsg>;
19
+ }
20
+ interface NatsBrokerOptions {
21
+ /** Queue group name for load-balanced consumption across instances */
22
+ queue?: string;
23
+ }
24
+ /**
25
+ * Create a NATS broker driver from a NatsConnection.
26
+ *
27
+ * Uses NATS native request-reply for zero-overhead correlation.
28
+ * Supports queue groups for horizontal scaling — only one instance
29
+ * in the group handles each request.
30
+ */
31
+ declare function natsBroker(nc: NatsConnection, options?: NatsBrokerOptions): BrokerDriver;
32
+ //#endregion
33
+ export { NatsBrokerOptions, NatsConnection, NatsMsg, NatsSub, natsBroker };
@@ -0,0 +1,31 @@
1
+ //#region src/broker/nats.ts
2
+ const encoder = /* @__PURE__ */ new TextEncoder();
3
+ const decoder = /* @__PURE__ */ new TextDecoder();
4
+ /**
5
+ * Create a NATS broker driver from a NatsConnection.
6
+ *
7
+ * Uses NATS native request-reply for zero-overhead correlation.
8
+ * Supports queue groups for horizontal scaling — only one instance
9
+ * in the group handles each request.
10
+ */
11
+ function natsBroker(nc, options = {}) {
12
+ return {
13
+ subscribe(subject, handler) {
14
+ const sub = nc.subscribe(subject, {
15
+ queue: options.queue,
16
+ callback: (_err, msg) => {
17
+ handler(decoder.decode(msg.data), (response) => {
18
+ msg.respond(encoder.encode(response));
19
+ });
20
+ }
21
+ });
22
+ return () => sub.unsubscribe();
23
+ },
24
+ async request(subject, payload, opts) {
25
+ const msg = await nc.request(subject, encoder.encode(payload), { timeout: opts?.timeout ?? 1e4 });
26
+ return decoder.decode(msg.data);
27
+ }
28
+ };
29
+ }
30
+ //#endregion
31
+ export { natsBroker };
@@ -0,0 +1,51 @@
1
+ import { BrokerDriver } from "./index.mjs";
2
+
3
+ //#region src/broker/redis.d.ts
4
+ /**
5
+ * Minimal pub/sub transport — implement this for your Redis client.
6
+ *
7
+ * `subscribe` returns a cleanup function to unsubscribe.
8
+ * Both sync and async returns are supported.
9
+ */
10
+ interface RedisTransport {
11
+ publish(channel: string, message: string): unknown;
12
+ subscribe(channel: string, handler: (message: string) => void): (() => void) | Promise<() => void>;
13
+ }
14
+ /**
15
+ * Minimal ioredis-compatible interface.
16
+ * Works with `ioredis` and any client that matches this shape.
17
+ */
18
+ interface IORedisLike {
19
+ publish(channel: string, message: string): Promise<number>;
20
+ subscribe(...channels: string[]): Promise<unknown>;
21
+ unsubscribe(...channels: string[]): Promise<unknown>;
22
+ on(event: 'message', listener: (channel: string, message: string) => void): void;
23
+ }
24
+ /**
25
+ * Create a RedisTransport from two ioredis connections.
26
+ *
27
+ * Redis requires separate connections for publishing and subscribing
28
+ * because `SUBSCRIBE` puts the connection into subscriber mode.
29
+ *
30
+ * @param pub - Publisher connection (regular Redis client)
31
+ * @param sub - Subscriber connection (dedicated for SUBSCRIBE)
32
+ */
33
+ declare function ioredisTransport(pub: IORedisLike, sub: IORedisLike): RedisTransport;
34
+ interface RedisBrokerOptions {
35
+ /** Unique prefix for inbox channels. Auto-generated if not provided. */
36
+ inbox?: string;
37
+ }
38
+ /**
39
+ * Create a Redis broker driver from a RedisTransport.
40
+ *
41
+ * Simulates request-reply using temporary inbox channels:
42
+ * 1. Client subscribes to a unique inbox channel
43
+ * 2. Client publishes request with inbox address embedded
44
+ * 3. Server processes request, publishes response to inbox
45
+ * 4. Client receives response, unsubscribes from inbox
46
+ *
47
+ * Wire format: `"inbox-channel\npayload"` (newline separator, no double-serialization)
48
+ */
49
+ declare function redisBroker(transport: RedisTransport, options?: RedisBrokerOptions): BrokerDriver;
50
+ //#endregion
51
+ export { IORedisLike, RedisBrokerOptions, RedisTransport, ioredisTransport, redisBroker };