silgi 0.0.14 → 0.1.0-beta.2

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 +54 -0
  72. package/dist/compile.mjs +305 -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 +330 -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,83 @@
1
+ import { ProcedureDef, RouterDef } from "../../types.mjs";
2
+
3
+ //#region src/integrations/react/index.d.ts
4
+ type ActionResult<TOutput> = [error: null, data: TOutput] | [error: {
5
+ code: string;
6
+ status: number;
7
+ message: string;
8
+ data?: unknown;
9
+ }, data: undefined];
10
+ /**
11
+ * Create a server action from a v2 ProcedureDef.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * // app/actions.ts
16
+ * "use server"
17
+ * import { createAction } from "silgi/react"
18
+ *
19
+ * export const createUser = createAction(appRouter.users.create)
20
+ *
21
+ * // app/page.tsx
22
+ * const [error, user] = await createUser({ name: "Alice" })
23
+ * ```
24
+ */
25
+ declare function createAction<TInput = unknown, TOutput = unknown>(procedure: ProcedureDef): (input: TInput) => Promise<ActionResult<TOutput>>;
26
+ /**
27
+ * Create a FormData-accepting server action from a v2 procedure.
28
+ */
29
+ declare function createFormAction<TOutput = unknown>(procedure: ProcedureDef, options?: {
30
+ parseFormData?: (fd: FormData) => unknown;
31
+ }): (formData: FormData) => Promise<ActionResult<TOutput>>;
32
+ /**
33
+ * Create actions for all procedures in a router.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const actions = createActions(appRouter)
38
+ * const [error, users] = await actions.users.list({ limit: 10 })
39
+ * ```
40
+ */
41
+ declare function createActions<T extends RouterDef>(router: T): ActionRouter<T>;
42
+ /**
43
+ * React hook for calling server actions with loading/error state.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * const { execute, data, error, isPending } = useServerAction(createUser)
48
+ *
49
+ * <button onClick={() => execute({ name: "Alice" })} disabled={isPending}>
50
+ * {isPending ? "Creating..." : "Create User"}
51
+ * </button>
52
+ * ```
53
+ */
54
+ declare function useServerAction<TInput, TOutput>(action: (input: TInput) => Promise<ActionResult<TOutput>>): {
55
+ execute: any;
56
+ data: any;
57
+ error: any;
58
+ isPending: any;
59
+ reset: any;
60
+ };
61
+ /**
62
+ * React hook for server actions with optimistic UI updates.
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * const { execute, data, optimisticData, isPending } = useOptimisticServerAction(updateUser, {
67
+ * optimistic: (input) => ({ ...currentUser, ...input }),
68
+ * })
69
+ * ```
70
+ */
71
+ declare function useOptimisticServerAction<TInput, TOutput>(action: (input: TInput) => Promise<ActionResult<TOutput>>, options: {
72
+ optimistic: (input: TInput) => TOutput;
73
+ }): {
74
+ execute: any; /** Confirmed server data */
75
+ data: any; /** Optimistic data (shown while pending, cleared on settle) */
76
+ optimisticData: any; /** The value to display: optimistic while pending, confirmed otherwise */
77
+ displayData: any;
78
+ error: any;
79
+ isPending: any;
80
+ };
81
+ type ActionRouter<T extends RouterDef> = { [K in keyof T]: T[K] extends ProcedureDef<any, infer TInput, infer TOutput> ? (input: TInput extends undefined ? void : TInput) => Promise<ActionResult<TOutput>> : T[K] extends RouterDef ? ActionRouter<T[K]> : never };
82
+ //#endregion
83
+ export { ActionResult, createAction, createActions, createFormAction, useOptimisticServerAction, useServerAction };
@@ -0,0 +1,197 @@
1
+ import { __require } from "../../_virtual/_rolldown/runtime.mjs";
2
+ import { SilgiError, toSilgiError } from "../../core/error.mjs";
3
+ import { compileProcedure } from "../../compile.mjs";
4
+ //#region src/integrations/react/index.ts
5
+ /**
6
+ * React Server Actions — v2 integration.
7
+ *
8
+ * Creates type-safe server actions from v2 procedures.
9
+ * Returns [error, data] tuples instead of throwing.
10
+ */
11
+ /**
12
+ * Create a server action from a v2 ProcedureDef.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * // app/actions.ts
17
+ * "use server"
18
+ * import { createAction } from "silgi/react"
19
+ *
20
+ * export const createUser = createAction(appRouter.users.create)
21
+ *
22
+ * // app/page.tsx
23
+ * const [error, user] = await createUser({ name: "Alice" })
24
+ * ```
25
+ */
26
+ function createAction(procedure) {
27
+ const handler = compileProcedure(procedure);
28
+ const signal = new AbortController().signal;
29
+ return async (input) => {
30
+ try {
31
+ const result = handler(Object.create(null), input, signal);
32
+ return [null, result instanceof Promise ? await result : result];
33
+ } catch (error) {
34
+ if (isFrameworkError(error)) throw error;
35
+ return [(error instanceof SilgiError ? error : toSilgiError(error)).toJSON(), void 0];
36
+ }
37
+ };
38
+ }
39
+ /**
40
+ * Create a FormData-accepting server action from a v2 procedure.
41
+ */
42
+ function createFormAction(procedure, options) {
43
+ const action = createAction(procedure);
44
+ const parse = options?.parseFormData ?? defaultFormDataParser;
45
+ return (formData) => action(parse(formData));
46
+ }
47
+ /**
48
+ * Create actions for all procedures in a router.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const actions = createActions(appRouter)
53
+ * const [error, users] = await actions.users.list({ limit: 10 })
54
+ * ```
55
+ */
56
+ function createActions(router) {
57
+ const result = {};
58
+ for (const [key, value] of Object.entries(router)) if (isProcedureDef(value)) result[key] = createAction(value);
59
+ else if (typeof value === "object" && value !== null) result[key] = createActions(value);
60
+ return result;
61
+ }
62
+ /**
63
+ * React hook for calling server actions with loading/error state.
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * const { execute, data, error, isPending } = useServerAction(createUser)
68
+ *
69
+ * <button onClick={() => execute({ name: "Alice" })} disabled={isPending}>
70
+ * {isPending ? "Creating..." : "Create User"}
71
+ * </button>
72
+ * ```
73
+ */
74
+ function useServerAction(action) {
75
+ const { useState, useCallback, useRef } = __require("react");
76
+ const [data, setData] = useState(void 0);
77
+ const [error, setError] = useState(null);
78
+ const [isPending, setIsPending] = useState(false);
79
+ const mountedRef = useRef(true);
80
+ const { useEffect } = __require("react");
81
+ useEffect(() => {
82
+ mountedRef.current = true;
83
+ return () => {
84
+ mountedRef.current = false;
85
+ };
86
+ }, []);
87
+ return {
88
+ execute: useCallback(async (input) => {
89
+ setIsPending(true);
90
+ setError(null);
91
+ try {
92
+ const [err, result] = await action(input);
93
+ if (!mountedRef.current) return;
94
+ if (err) {
95
+ setError(err);
96
+ setData(void 0);
97
+ } else {
98
+ setData(result);
99
+ setError(null);
100
+ }
101
+ return [err, result];
102
+ } finally {
103
+ if (mountedRef.current) setIsPending(false);
104
+ }
105
+ }, [action]),
106
+ data,
107
+ error,
108
+ isPending,
109
+ reset: useCallback(() => {
110
+ setData(void 0);
111
+ setError(null);
112
+ setIsPending(false);
113
+ }, [])
114
+ };
115
+ }
116
+ /**
117
+ * React hook for server actions with optimistic UI updates.
118
+ *
119
+ * @example
120
+ * ```tsx
121
+ * const { execute, data, optimisticData, isPending } = useOptimisticServerAction(updateUser, {
122
+ * optimistic: (input) => ({ ...currentUser, ...input }),
123
+ * })
124
+ * ```
125
+ */
126
+ function useOptimisticServerAction(action, options) {
127
+ const { useState, useCallback, useRef } = __require("react");
128
+ const { useEffect } = __require("react");
129
+ const [data, setData] = useState(void 0);
130
+ const [optimisticData, setOptimisticData] = useState(void 0);
131
+ const [error, setError] = useState(null);
132
+ const [isPending, setIsPending] = useState(false);
133
+ const mountedRef = useRef(true);
134
+ useEffect(() => {
135
+ mountedRef.current = true;
136
+ return () => {
137
+ mountedRef.current = false;
138
+ };
139
+ }, []);
140
+ return {
141
+ execute: useCallback(async (input) => {
142
+ setIsPending(true);
143
+ setError(null);
144
+ setOptimisticData(options.optimistic(input));
145
+ try {
146
+ const [err, result] = await action(input);
147
+ if (!mountedRef.current) return;
148
+ if (err) {
149
+ setError(err);
150
+ setOptimisticData(void 0);
151
+ } else {
152
+ setData(result);
153
+ setOptimisticData(void 0);
154
+ }
155
+ return [err, result];
156
+ } catch (e) {
157
+ if (mountedRef.current) setOptimisticData(void 0);
158
+ throw e;
159
+ } finally {
160
+ if (mountedRef.current) setIsPending(false);
161
+ }
162
+ }, [action, options.optimistic]),
163
+ data,
164
+ optimisticData,
165
+ displayData: optimisticData ?? data,
166
+ error,
167
+ isPending
168
+ };
169
+ }
170
+ function isProcedureDef(v) {
171
+ return typeof v === "object" && v !== null && "type" in v && "resolve" in v;
172
+ }
173
+ function isFrameworkError(error) {
174
+ if (typeof error !== "object" || error === null) return false;
175
+ if (typeof error.digest === "string" && error.digest.startsWith("NEXT_")) return true;
176
+ if (error.isNotFound === true) return true;
177
+ if (error instanceof Response) return true;
178
+ return false;
179
+ }
180
+ function defaultFormDataParser(formData) {
181
+ const result = {};
182
+ for (const [key, value] of formData.entries()) setNestedValue(result, key, value instanceof File && value.size === 0 ? void 0 : value);
183
+ return result;
184
+ }
185
+ function setNestedValue(obj, path, value) {
186
+ const keys = path.split("[").map((k) => k.replace("]", ""));
187
+ let current = obj;
188
+ for (let i = 0; i < keys.length - 1; i++) {
189
+ const k = keys[i];
190
+ const next = keys[i + 1];
191
+ if (!(k in current)) current[k] = /^\d+$/.test(next) ? [] : {};
192
+ current = current[k];
193
+ }
194
+ current[keys[keys.length - 1]] = value;
195
+ }
196
+ //#endregion
197
+ export { createAction, createActions, createFormAction, useOptimisticServerAction, useServerAction };
@@ -0,0 +1,120 @@
1
+ import { Client, NestedClient } from "../../client/types.mjs";
2
+
3
+ //#region src/integrations/tanstack-query/index.d.ts
4
+ type OperationType = 'query' | 'infinite' | 'mutation';
5
+ type OperationKey = [path: readonly string[], options: {
6
+ type?: OperationType;
7
+ input?: unknown;
8
+ }];
9
+ declare function generateKey(path: readonly string[], options?: {
10
+ type?: OperationType;
11
+ input?: unknown;
12
+ }): OperationKey;
13
+ interface QueryOptionsIn<TInput, TOutput, _TError> {
14
+ input: TInput;
15
+ queryKey?: unknown[];
16
+ enabled?: boolean;
17
+ staleTime?: number;
18
+ gcTime?: number;
19
+ refetchInterval?: number | false;
20
+ retry?: boolean | number;
21
+ select?: (data: TOutput) => unknown;
22
+ }
23
+ interface MutationOptionsIn<TInput, TOutput, TError> {
24
+ onSuccess?: (data: TOutput, input: TInput) => void;
25
+ onError?: (error: TError, input: TInput) => void;
26
+ onSettled?: (data: TOutput | undefined, error: TError | null, input: TInput) => void;
27
+ retry?: boolean | number;
28
+ }
29
+ /** Sentinel value to disable a query in a type-safe way. */
30
+ declare const skipToken: unique symbol;
31
+ type SkipToken = typeof skipToken;
32
+ interface InfiniteQueryOptionsIn<TInput, TOutput, _TError, TPageParam> {
33
+ input: (pageParam: TPageParam) => TInput;
34
+ initialPageParam: TPageParam;
35
+ getNextPageParam: (lastPage: TOutput, allPages: TOutput[], lastPageParam: TPageParam) => TPageParam | undefined;
36
+ queryKey?: unknown[];
37
+ enabled?: boolean;
38
+ staleTime?: number;
39
+ gcTime?: number;
40
+ }
41
+ interface ProcedureQueryUtils<TInput, TOutput, TError> {
42
+ /** Direct call to the procedure */
43
+ call: (input: TInput, options?: {
44
+ signal?: AbortSignal;
45
+ }) => Promise<TOutput>;
46
+ /** Generate a query key for this procedure */
47
+ queryKey: (input?: TInput) => OperationKey;
48
+ /** Generate full query options for useQuery. Pass `skipToken` as input to disable. */
49
+ queryOptions: (options: QueryOptionsIn<TInput | SkipToken, TOutput, TError>) => {
50
+ queryKey: OperationKey;
51
+ queryFn: (ctx: {
52
+ signal: AbortSignal;
53
+ }) => Promise<TOutput>;
54
+ enabled?: boolean;
55
+ staleTime?: number;
56
+ gcTime?: number;
57
+ refetchInterval?: number | false;
58
+ retry?: boolean | number;
59
+ select?: (data: TOutput) => unknown;
60
+ };
61
+ /** Generate infinite query options for useInfiniteQuery */
62
+ infiniteOptions: <TPageParam = number>(options: InfiniteQueryOptionsIn<TInput, TOutput, TError, TPageParam>) => {
63
+ queryKey: OperationKey;
64
+ queryFn: (ctx: {
65
+ signal: AbortSignal;
66
+ pageParam: TPageParam;
67
+ }) => Promise<TOutput>;
68
+ initialPageParam: TPageParam;
69
+ getNextPageParam: (lastPage: TOutput, allPages: TOutput[], lastPageParam: TPageParam) => TPageParam | undefined;
70
+ enabled?: boolean;
71
+ staleTime?: number;
72
+ gcTime?: number;
73
+ };
74
+ /** Generate streamed query options — data appends to array as events arrive */
75
+ streamedOptions: (options: QueryOptionsIn<TInput, TOutput[], TError>) => {
76
+ queryKey: OperationKey;
77
+ queryFn: (ctx: {
78
+ signal: AbortSignal;
79
+ }) => Promise<TOutput[]>;
80
+ enabled?: boolean;
81
+ staleTime?: number;
82
+ gcTime?: number;
83
+ };
84
+ /** Generate live query options — latest event replaces previous data */
85
+ liveOptions: (options: QueryOptionsIn<TInput, TOutput, TError>) => {
86
+ queryKey: OperationKey;
87
+ queryFn: (ctx: {
88
+ signal: AbortSignal;
89
+ }) => Promise<TOutput>;
90
+ refetchInterval: number;
91
+ enabled?: boolean;
92
+ staleTime?: number;
93
+ gcTime?: number;
94
+ };
95
+ /** Generate a mutation key */
96
+ mutationKey: () => OperationKey;
97
+ /** Generate full mutation options for useMutation */
98
+ mutationOptions: (options?: MutationOptionsIn<TInput, TOutput, TError>) => {
99
+ mutationKey: OperationKey;
100
+ mutationFn: (input: TInput) => Promise<TOutput>;
101
+ onSuccess?: (data: TOutput, input: TInput) => void;
102
+ onError?: (error: TError, input: TInput) => void;
103
+ onSettled?: (data: TOutput | undefined, error: TError | null, input: TInput) => void;
104
+ retry?: boolean | number;
105
+ };
106
+ }
107
+ interface GeneralUtils {
108
+ /** Generate a key prefix for bulk invalidation */
109
+ key: (input?: unknown) => OperationKey;
110
+ }
111
+ type QueryUtils<T extends NestedClient> = T extends Client<any, infer TInput, infer TOutput, infer TError> ? ProcedureQueryUtils<TInput, TOutput, TError> & GeneralUtils : T extends Record<string, NestedClient> ? { [K in keyof T]: QueryUtils<T[K]> } & GeneralUtils : GeneralUtils;
112
+ /**
113
+ * Create TanStack Query utilities from a Silgi client.
114
+ *
115
+ * Returns a recursive proxy that mirrors the client structure,
116
+ * with `.queryOptions()`, `.mutationOptions()`, `.queryKey()` at each level.
117
+ */
118
+ declare function createQueryUtils<T extends NestedClient>(client: T, path?: readonly string[]): QueryUtils<T>;
119
+ //#endregion
120
+ export { GeneralUtils, InfiniteQueryOptionsIn, MutationOptionsIn, OperationKey, OperationType, ProcedureQueryUtils, QueryOptionsIn, QueryUtils, SkipToken, createQueryUtils, generateKey, skipToken };
@@ -0,0 +1,100 @@
1
+ //#region src/integrations/tanstack-query/index.ts
2
+ function generateKey(path, options) {
3
+ const keyOptions = {};
4
+ if (options?.type) keyOptions.type = options.type;
5
+ if (options?.input !== void 0) keyOptions.input = options.input;
6
+ return [path, keyOptions];
7
+ }
8
+ /** Sentinel value to disable a query in a type-safe way. */
9
+ const skipToken = Symbol.for("silgi.skipToken");
10
+ function createProcedureUtils(client, path) {
11
+ return {
12
+ call: (input, options) => client(input, options),
13
+ queryKey: (input) => generateKey(path, {
14
+ type: "query",
15
+ input
16
+ }),
17
+ queryOptions: (options) => {
18
+ const isSkipped = options.input === skipToken;
19
+ return {
20
+ queryKey: options.queryKey ? options.queryKey : generateKey(path, {
21
+ type: "query",
22
+ input: isSkipped ? void 0 : options.input
23
+ }),
24
+ queryFn: ({ signal }) => client(options.input, { signal }),
25
+ ...isSkipped && { enabled: false },
26
+ ...options.enabled !== void 0 && { enabled: options.enabled },
27
+ ...options.staleTime !== void 0 && { staleTime: options.staleTime },
28
+ ...options.gcTime !== void 0 && { gcTime: options.gcTime },
29
+ ...options.refetchInterval !== void 0 && { refetchInterval: options.refetchInterval },
30
+ ...options.retry !== void 0 && { retry: options.retry },
31
+ ...options.select !== void 0 && { select: options.select }
32
+ };
33
+ },
34
+ infiniteOptions: (options) => ({
35
+ queryKey: options.queryKey ? options.queryKey : generateKey(path, { type: "infinite" }),
36
+ queryFn: ({ signal, pageParam }) => client(options.input(pageParam), { signal }),
37
+ initialPageParam: options.initialPageParam,
38
+ getNextPageParam: options.getNextPageParam,
39
+ ...options.enabled !== void 0 && { enabled: options.enabled },
40
+ ...options.staleTime !== void 0 && { staleTime: options.staleTime },
41
+ ...options.gcTime !== void 0 && { gcTime: options.gcTime }
42
+ }),
43
+ streamedOptions: (options) => ({
44
+ queryKey: options.queryKey ? options.queryKey : generateKey(path, {
45
+ type: "query",
46
+ input: options.input
47
+ }),
48
+ queryFn: async ({ signal }) => {
49
+ const result = await client(options.input, { signal });
50
+ if (result && typeof result === "object" && Symbol.asyncIterator in result) {
51
+ const items = [];
52
+ for await (const item of result) items.push(item);
53
+ return items;
54
+ }
55
+ return Array.isArray(result) ? result : [result];
56
+ },
57
+ ...options.enabled !== void 0 && { enabled: options.enabled },
58
+ ...options.staleTime !== void 0 && { staleTime: options.staleTime },
59
+ ...options.gcTime !== void 0 && { gcTime: options.gcTime }
60
+ }),
61
+ liveOptions: (options) => ({
62
+ queryKey: options.queryKey ? options.queryKey : generateKey(path, {
63
+ type: "query",
64
+ input: options.input
65
+ }),
66
+ queryFn: ({ signal }) => client(options.input, { signal }),
67
+ refetchInterval: options.refetchInterval ?? 1e3,
68
+ ...options.enabled !== void 0 && { enabled: options.enabled },
69
+ ...options.staleTime !== void 0 && { staleTime: options.staleTime },
70
+ ...options.gcTime !== void 0 && { gcTime: options.gcTime }
71
+ }),
72
+ mutationKey: () => generateKey(path, { type: "mutation" }),
73
+ mutationOptions: (options) => ({
74
+ mutationKey: generateKey(path, { type: "mutation" }),
75
+ mutationFn: (input) => client(input),
76
+ ...options
77
+ })
78
+ };
79
+ }
80
+ /**
81
+ * Create TanStack Query utilities from a Silgi client.
82
+ *
83
+ * Returns a recursive proxy that mirrors the client structure,
84
+ * with `.queryOptions()`, `.mutationOptions()`, `.queryKey()` at each level.
85
+ */
86
+ function createQueryUtils(client, path = []) {
87
+ const generalUtils = { key: (input) => generateKey(path, input !== void 0 ? { input } : void 0) };
88
+ const procedureUtils = typeof client === "function" ? createProcedureUtils(client, path) : {};
89
+ return new Proxy({}, { get(_target, prop) {
90
+ if (prop === "then") return void 0;
91
+ if (prop === "key") return generalUtils.key;
92
+ if (typeof prop === "string" && prop in procedureUtils) return procedureUtils[prop];
93
+ if (typeof prop === "string") {
94
+ const child = client[prop];
95
+ if (child) return createQueryUtils(child, [...path, prop]);
96
+ }
97
+ } });
98
+ }
99
+ //#endregion
100
+ export { createQueryUtils, generateKey, skipToken };
@@ -0,0 +1,51 @@
1
+ //#region src/integrations/tanstack-query/ssr.d.ts
2
+ /**
3
+ * SSR Hydration for TanStack Query — prevent refetch waterfalls.
4
+ *
5
+ * Prefetch queries on the server and dehydrate them for the client.
6
+ * The client hydrates without refetching — zero waterfall.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // Server (SSR)
11
+ * import { prefetchQueries, dehydrate } from "silgi/tanstack-query/ssr"
12
+ *
13
+ * const queryClient = new QueryClient()
14
+ * await prefetchQueries(queryClient, utils, [
15
+ * utils.users.list.queryOptions({ input: { limit: 10 } }),
16
+ * utils.health.queryOptions({ input: undefined }),
17
+ * ])
18
+ * const dehydratedState = dehydrate(queryClient)
19
+ *
20
+ * // Client
21
+ * <HydrationBoundary state={dehydratedState}>
22
+ * <App />
23
+ * </HydrationBoundary>
24
+ * ```
25
+ */
26
+ /**
27
+ * Prefetch multiple queries on the server.
28
+ * Pass the same options you'd use with `useQuery`.
29
+ */
30
+ declare function prefetchQueries(queryClient: any, ...optionsArray: Array<{
31
+ queryKey: unknown;
32
+ queryFn: Function;
33
+ } | Array<{
34
+ queryKey: unknown;
35
+ queryFn: Function;
36
+ }>>): Promise<void>;
37
+ /**
38
+ * Dehydrate the query client for SSR transfer.
39
+ * Wraps TanStack Query's dehydrate with Silgi-aware serialization.
40
+ */
41
+ declare function dehydrate(queryClient: any): unknown;
42
+ /**
43
+ * Create a custom serializer for SSR hydration that handles
44
+ * Silgi-specific types (Date, Map, etc.) during dehydration.
45
+ */
46
+ declare function createSSRSerializer(): {
47
+ serialize: (value: unknown) => string;
48
+ deserialize: (text: string) => unknown;
49
+ };
50
+ //#endregion
51
+ export { createSSRSerializer, dehydrate, prefetchQueries };
@@ -0,0 +1,89 @@
1
+ //#region src/integrations/tanstack-query/ssr.ts
2
+ /**
3
+ * SSR Hydration for TanStack Query — prevent refetch waterfalls.
4
+ *
5
+ * Prefetch queries on the server and dehydrate them for the client.
6
+ * The client hydrates without refetching — zero waterfall.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // Server (SSR)
11
+ * import { prefetchQueries, dehydrate } from "silgi/tanstack-query/ssr"
12
+ *
13
+ * const queryClient = new QueryClient()
14
+ * await prefetchQueries(queryClient, utils, [
15
+ * utils.users.list.queryOptions({ input: { limit: 10 } }),
16
+ * utils.health.queryOptions({ input: undefined }),
17
+ * ])
18
+ * const dehydratedState = dehydrate(queryClient)
19
+ *
20
+ * // Client
21
+ * <HydrationBoundary state={dehydratedState}>
22
+ * <App />
23
+ * </HydrationBoundary>
24
+ * ```
25
+ */
26
+ /**
27
+ * Prefetch multiple queries on the server.
28
+ * Pass the same options you'd use with `useQuery`.
29
+ */
30
+ async function prefetchQueries(queryClient, ...optionsArray) {
31
+ const flat = optionsArray.flat();
32
+ await Promise.all(flat.map((opts) => queryClient.prefetchQuery(opts)));
33
+ }
34
+ /**
35
+ * Dehydrate the query client for SSR transfer.
36
+ * Wraps TanStack Query's dehydrate with Silgi-aware serialization.
37
+ */
38
+ function dehydrate(queryClient) {
39
+ if (typeof queryClient.dehydrate === "function") return queryClient.dehydrate();
40
+ const cache = queryClient.getQueryCache?.();
41
+ if (!cache) return {};
42
+ return { queries: cache.getAll().map((query) => ({
43
+ queryKey: query.queryKey,
44
+ state: query.state
45
+ })) };
46
+ }
47
+ /**
48
+ * Create a custom serializer for SSR hydration that handles
49
+ * Silgi-specific types (Date, Map, etc.) during dehydration.
50
+ */
51
+ function createSSRSerializer() {
52
+ return {
53
+ serialize: (value) => {
54
+ return JSON.stringify(value, function(_key, val) {
55
+ const original = this[_key];
56
+ if (original instanceof Date) return {
57
+ __type: "Date",
58
+ value: original.toISOString()
59
+ };
60
+ if (original instanceof Map) return {
61
+ __type: "Map",
62
+ value: Array.from(original.entries())
63
+ };
64
+ if (original instanceof Set) return {
65
+ __type: "Set",
66
+ value: Array.from(original)
67
+ };
68
+ if (typeof original === "bigint") return {
69
+ __type: "BigInt",
70
+ value: original.toString()
71
+ };
72
+ return val;
73
+ });
74
+ },
75
+ deserialize: (text) => {
76
+ return JSON.parse(text, (_key, val) => {
77
+ if (val && typeof val === "object" && "__type" in val) switch (val.__type) {
78
+ case "Date": return new Date(val.value);
79
+ case "Map": return new Map(val.value);
80
+ case "Set": return new Set(val.value);
81
+ case "BigInt": return BigInt(val.value);
82
+ }
83
+ return val;
84
+ });
85
+ }
86
+ };
87
+ }
88
+ //#endregion
89
+ export { createSSRSerializer, dehydrate, prefetchQueries };