@fragno-dev/core 0.0.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 (108) hide show
  1. package/.turbo/turbo-build.log +61 -0
  2. package/.turbo/turbo-types$colon$check.log +2 -0
  3. package/dist/api/api.d.ts +2 -0
  4. package/dist/api/api.js +3 -0
  5. package/dist/api-CBDGZiLC.d.ts +278 -0
  6. package/dist/api-CBDGZiLC.d.ts.map +1 -0
  7. package/dist/api-DgHfYjq2.js +54 -0
  8. package/dist/api-DgHfYjq2.js.map +1 -0
  9. package/dist/client/client.d.ts +3 -0
  10. package/dist/client/client.js +6 -0
  11. package/dist/client/client.svelte.d.ts +33 -0
  12. package/dist/client/client.svelte.d.ts.map +1 -0
  13. package/dist/client/client.svelte.js +123 -0
  14. package/dist/client/client.svelte.js.map +1 -0
  15. package/dist/client/react.d.ts +58 -0
  16. package/dist/client/react.d.ts.map +1 -0
  17. package/dist/client/react.js +80 -0
  18. package/dist/client/react.js.map +1 -0
  19. package/dist/client/vanilla.d.ts +61 -0
  20. package/dist/client/vanilla.d.ts.map +1 -0
  21. package/dist/client/vanilla.js +136 -0
  22. package/dist/client/vanilla.js.map +1 -0
  23. package/dist/client/vue.d.ts +39 -0
  24. package/dist/client/vue.d.ts.map +1 -0
  25. package/dist/client/vue.js +108 -0
  26. package/dist/client/vue.js.map +1 -0
  27. package/dist/client-DWjxKDnE.js +703 -0
  28. package/dist/client-DWjxKDnE.js.map +1 -0
  29. package/dist/client-XFdAy-IQ.d.ts +287 -0
  30. package/dist/client-XFdAy-IQ.d.ts.map +1 -0
  31. package/dist/integrations/astro.d.ts +18 -0
  32. package/dist/integrations/astro.d.ts.map +1 -0
  33. package/dist/integrations/astro.js +16 -0
  34. package/dist/integrations/astro.js.map +1 -0
  35. package/dist/integrations/next-js.d.ts +15 -0
  36. package/dist/integrations/next-js.d.ts.map +1 -0
  37. package/dist/integrations/next-js.js +17 -0
  38. package/dist/integrations/next-js.js.map +1 -0
  39. package/dist/integrations/react-ssr.d.ts +19 -0
  40. package/dist/integrations/react-ssr.d.ts.map +1 -0
  41. package/dist/integrations/react-ssr.js +38 -0
  42. package/dist/integrations/react-ssr.js.map +1 -0
  43. package/dist/integrations/svelte-kit.d.ts +21 -0
  44. package/dist/integrations/svelte-kit.d.ts.map +1 -0
  45. package/dist/integrations/svelte-kit.js +18 -0
  46. package/dist/integrations/svelte-kit.js.map +1 -0
  47. package/dist/mod.d.ts +3 -0
  48. package/dist/mod.js +177 -0
  49. package/dist/mod.js.map +1 -0
  50. package/dist/route-Bp6eByhz.js +331 -0
  51. package/dist/route-Bp6eByhz.js.map +1 -0
  52. package/dist/ssr-tJHqcNSw.js +48 -0
  53. package/dist/ssr-tJHqcNSw.js.map +1 -0
  54. package/package.json +127 -0
  55. package/src/api/api.test.ts +140 -0
  56. package/src/api/api.ts +106 -0
  57. package/src/api/error.ts +47 -0
  58. package/src/api/fragment.test.ts +509 -0
  59. package/src/api/fragment.ts +277 -0
  60. package/src/api/internal/path-runtime.test.ts +121 -0
  61. package/src/api/internal/path-type.test.ts +602 -0
  62. package/src/api/internal/path.ts +322 -0
  63. package/src/api/internal/response-stream.ts +118 -0
  64. package/src/api/internal/route.test.ts +56 -0
  65. package/src/api/internal/route.ts +9 -0
  66. package/src/api/request-input-context.test.ts +437 -0
  67. package/src/api/request-input-context.ts +201 -0
  68. package/src/api/request-middleware.test.ts +544 -0
  69. package/src/api/request-middleware.ts +126 -0
  70. package/src/api/request-output-context.test.ts +626 -0
  71. package/src/api/request-output-context.ts +175 -0
  72. package/src/api/route.test.ts +176 -0
  73. package/src/api/route.ts +152 -0
  74. package/src/client/client-builder.test.ts +264 -0
  75. package/src/client/client-error.test.ts +15 -0
  76. package/src/client/client-error.ts +141 -0
  77. package/src/client/client-types.test.ts +493 -0
  78. package/src/client/client.ssr.test.ts +173 -0
  79. package/src/client/client.svelte.test.ts +837 -0
  80. package/src/client/client.svelte.ts +278 -0
  81. package/src/client/client.test.ts +1690 -0
  82. package/src/client/client.ts +1035 -0
  83. package/src/client/component.test.svelte +21 -0
  84. package/src/client/internal/ndjson-streaming.test.ts +457 -0
  85. package/src/client/internal/ndjson-streaming.ts +248 -0
  86. package/src/client/react.test.ts +947 -0
  87. package/src/client/react.ts +241 -0
  88. package/src/client/vanilla.test.ts +867 -0
  89. package/src/client/vanilla.ts +265 -0
  90. package/src/client/vue.test.ts +754 -0
  91. package/src/client/vue.ts +242 -0
  92. package/src/http/http-status.ts +60 -0
  93. package/src/integrations/astro.ts +17 -0
  94. package/src/integrations/next-js.ts +31 -0
  95. package/src/integrations/react-ssr.ts +40 -0
  96. package/src/integrations/svelte-kit.ts +41 -0
  97. package/src/mod.ts +20 -0
  98. package/src/util/async.test.ts +85 -0
  99. package/src/util/async.ts +96 -0
  100. package/src/util/content-type.test.ts +136 -0
  101. package/src/util/content-type.ts +84 -0
  102. package/src/util/nanostores.test.ts +28 -0
  103. package/src/util/nanostores.ts +65 -0
  104. package/src/util/ssr.ts +75 -0
  105. package/src/util/types-util.ts +16 -0
  106. package/tsconfig.json +10 -0
  107. package/tsdown.config.ts +21 -0
  108. package/vitest.config.ts +10 -0
@@ -0,0 +1,278 @@
1
+ import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+ import { atom, type ReadableAtom } from "nanostores";
3
+ import type { NonGetHTTPMethod } from "../api/api";
4
+ import {
5
+ isGetHook,
6
+ isMutatorHook,
7
+ isStore,
8
+ type FragnoClientHookData,
9
+ type FragnoClientMutatorData,
10
+ type FragnoStoreData,
11
+ } from "./client";
12
+ import type { FragnoClientError } from "./client-error";
13
+ import type { InferOr } from "../util/types-util";
14
+ import type { MaybeExtractPathParamsOrWiden, QueryParamsHint } from "../api/internal/path";
15
+
16
+ import { writable, type Readable, get } from "svelte/store";
17
+ import { onDestroy } from "svelte";
18
+
19
+ export type FragnoSvelteHook<
20
+ _TMethod extends "GET",
21
+ TPath extends string,
22
+ TOutputSchema extends StandardSchemaV1,
23
+ TErrorCode extends string,
24
+ TQueryParameters extends string,
25
+ > = (args?: {
26
+ path?:
27
+ | MaybeExtractPathParamsOrWiden<TPath, string | Readable<string> | ReadableAtom<string>>
28
+ | (() => string);
29
+ query?: QueryParamsHint<
30
+ TQueryParameters,
31
+ string | Readable<string> | ReadableAtom<string> | (() => string)
32
+ >;
33
+ }) => {
34
+ data: Readable<InferOr<TOutputSchema, undefined>>;
35
+ loading: Readable<boolean>;
36
+ error: Readable<FragnoClientError<TErrorCode[number]> | undefined>;
37
+ };
38
+
39
+ export type FragnoSvelteMutator<
40
+ _TMethod extends NonGetHTTPMethod,
41
+ TPath extends string,
42
+ TInputSchema extends StandardSchemaV1 | undefined,
43
+ TOutputSchema extends StandardSchemaV1 | undefined,
44
+ TErrorCode extends string,
45
+ TQueryParameters extends string,
46
+ > = () => {
47
+ mutate: (args: {
48
+ body?: InferOr<TInputSchema, undefined>;
49
+ path?: MaybeExtractPathParamsOrWiden<
50
+ TPath,
51
+ string | Readable<string> | ReadableAtom<string> | (() => string)
52
+ >;
53
+ query?: QueryParamsHint<
54
+ TQueryParameters,
55
+ string | Readable<string> | ReadableAtom<string> | (() => string)
56
+ >;
57
+ }) => Promise<InferOr<TOutputSchema, undefined>>;
58
+ loading: Readable<boolean | undefined>;
59
+ error: Readable<FragnoClientError<TErrorCode[number]> | undefined>;
60
+ data: Readable<InferOr<TOutputSchema, undefined>>;
61
+ };
62
+
63
+ function isReadable(value: unknown): value is Readable<string> {
64
+ return typeof value === "object" && value !== null && "subscribe" in value;
65
+ }
66
+
67
+ function isCallable(value: unknown): value is () => string {
68
+ return typeof value === "function";
69
+ }
70
+
71
+ export function readableToAtom<T>(value: Readable<T>): ReadableAtom<T> {
72
+ const a = atom(get(value));
73
+
74
+ value.subscribe((newVal) => {
75
+ a.set(newVal);
76
+ });
77
+
78
+ return a;
79
+ }
80
+
81
+ export function runeToAtom<T>(value: () => T): ReadableAtom<T> {
82
+ const a = atom(value());
83
+
84
+ $effect(() => {
85
+ a.set(value());
86
+ });
87
+
88
+ return a;
89
+ }
90
+
91
+ function createSvelteHook<
92
+ TMethod extends "GET",
93
+ TPath extends string,
94
+ TOutputSchema extends StandardSchemaV1,
95
+ TErrorCode extends string,
96
+ TQueryParameters extends string,
97
+ >(
98
+ hook: FragnoClientHookData<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters>,
99
+ ): FragnoSvelteHook<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters> {
100
+ return ({ path, query } = {}) => {
101
+ const pathParams: Record<string, string | ReadableAtom<string>> = {};
102
+ const queryParams: Record<string, string | ReadableAtom<string>> = {};
103
+
104
+ for (const [key, value] of Object.entries(path ?? {})) {
105
+ const v = value as string | Readable<string> | ReadableAtom<string> | (() => string);
106
+ if (isCallable(v)) {
107
+ pathParams[key] = runeToAtom(v);
108
+ } else {
109
+ pathParams[key] = isReadable(v) ? readableToAtom(v) : v;
110
+ }
111
+ }
112
+
113
+ for (const [key, value] of Object.entries(query ?? {})) {
114
+ const v = value as string | Readable<string> | ReadableAtom<string> | (() => string);
115
+ if (isCallable(v)) {
116
+ queryParams[key] = runeToAtom(v);
117
+ } else {
118
+ queryParams[key] = isReadable(v) ? readableToAtom(v) : v;
119
+ }
120
+ }
121
+
122
+ const store = hook.store({
123
+ path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,
124
+ query: queryParams,
125
+ });
126
+
127
+ const data = writable<InferOr<TOutputSchema, undefined>>(undefined);
128
+ const loading = writable<boolean>(false);
129
+ const error = writable<FragnoClientError<TErrorCode[number]> | undefined>(undefined);
130
+
131
+ const unsubscribe = store.subscribe((updatedStoreValue) => {
132
+ data.set(updatedStoreValue.data as InferOr<TOutputSchema, undefined>);
133
+ loading.set(updatedStoreValue.loading);
134
+ error.set(updatedStoreValue.error);
135
+ });
136
+
137
+ onDestroy(() => {
138
+ unsubscribe();
139
+ });
140
+
141
+ return {
142
+ data,
143
+ loading,
144
+ error,
145
+ };
146
+ };
147
+ }
148
+
149
+ function createSvelteMutator<
150
+ TMethod extends NonGetHTTPMethod,
151
+ TPath extends string,
152
+ TInputSchema extends StandardSchemaV1 | undefined,
153
+ TOutputSchema extends StandardSchemaV1 | undefined,
154
+ TErrorCode extends string,
155
+ TQueryParameters extends string,
156
+ >(
157
+ hook: FragnoClientMutatorData<
158
+ TMethod,
159
+ TPath,
160
+ TInputSchema,
161
+ TOutputSchema,
162
+ TErrorCode,
163
+ TQueryParameters
164
+ >,
165
+ ): FragnoSvelteMutator<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters> {
166
+ return () => {
167
+ const data = writable<InferOr<TOutputSchema, undefined>>(undefined);
168
+ const loading = writable<boolean | undefined>(undefined);
169
+ const error = writable<FragnoClientError<TErrorCode[number]> | undefined>(undefined);
170
+
171
+ // Subscribe to the mutator store and sync with our Svelte stores
172
+ const unsubscribe = hook.mutatorStore.subscribe((storeValue) => {
173
+ data.set(storeValue.data as InferOr<TOutputSchema, undefined>);
174
+ loading.set(storeValue.loading);
175
+ error.set(storeValue.error);
176
+ });
177
+
178
+ onDestroy(() => {
179
+ unsubscribe();
180
+ });
181
+
182
+ // Create a wrapped mutate function that handles Svelte readable stores
183
+ const mutate = async (args: {
184
+ body?: InferOr<TInputSchema, undefined>;
185
+ path?: MaybeExtractPathParamsOrWiden<
186
+ TPath,
187
+ string | Readable<string> | ReadableAtom<string> | (() => string)
188
+ >;
189
+ query?: QueryParamsHint<
190
+ TQueryParameters,
191
+ string | Readable<string> | ReadableAtom<string> | (() => string)
192
+ >;
193
+ }) => {
194
+ const { body, path, query } = args;
195
+
196
+ const pathParams: Record<string, string | ReadableAtom<string>> = {};
197
+ const queryParams: Record<string, string | ReadableAtom<string>> = {};
198
+
199
+ for (const [key, value] of Object.entries(path ?? {})) {
200
+ const v = value as string | Readable<string> | ReadableAtom<string>;
201
+ pathParams[key] = isReadable(v) ? readableToAtom(v) : v;
202
+ }
203
+
204
+ for (const [key, value] of Object.entries(query ?? {})) {
205
+ const v = value as string | Readable<string> | ReadableAtom<string>;
206
+ queryParams[key] = isReadable(v) ? readableToAtom(v) : v;
207
+ }
208
+
209
+ // Call the store's mutate function with normalized params
210
+ return hook.mutatorStore.mutate({
211
+ body,
212
+ path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,
213
+ query: queryParams,
214
+ });
215
+ };
216
+
217
+ return {
218
+ mutate,
219
+ loading,
220
+ error,
221
+ data,
222
+ };
223
+ };
224
+ }
225
+
226
+ export function createSvelteStore<T extends object>(hook: FragnoStoreData<T>): T {
227
+ // Since nanostores already implement Svelte's store contract,
228
+ // we can return the store object directly for use with $ syntax
229
+ return hook.obj;
230
+ }
231
+
232
+ export function useFragno<T extends Record<string, unknown>>(
233
+ clientObj: T,
234
+ ): {
235
+ [K in keyof T]: T[K] extends FragnoClientHookData<
236
+ "GET",
237
+ infer TPath,
238
+ infer TOutputSchema,
239
+ infer TErrorCode,
240
+ infer TQueryParameters
241
+ >
242
+ ? FragnoSvelteHook<"GET", TPath, TOutputSchema, TErrorCode, TQueryParameters>
243
+ : T[K] extends FragnoClientMutatorData<
244
+ infer M,
245
+ infer TPath,
246
+ infer TInputSchema,
247
+ infer TOutputSchema,
248
+ infer TErrorCode,
249
+ infer TQueryParameters
250
+ >
251
+ ? FragnoSvelteMutator<M, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters>
252
+ : T[K] extends FragnoStoreData<infer TStoreObj>
253
+ ? TStoreObj
254
+ : T[K];
255
+ } {
256
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
257
+ const result = {} as any;
258
+
259
+ for (const key in clientObj) {
260
+ if (!Object.prototype.hasOwnProperty.call(clientObj, key)) {
261
+ continue;
262
+ }
263
+
264
+ const hook = clientObj[key];
265
+ if (isGetHook(hook)) {
266
+ result[key] = createSvelteHook(hook);
267
+ } else if (isMutatorHook(hook)) {
268
+ result[key] = createSvelteMutator(hook);
269
+ } else if (isStore(hook)) {
270
+ result[key] = createSvelteStore(hook);
271
+ } else {
272
+ // Pass through non-hook values unchanged
273
+ result[key] = hook;
274
+ }
275
+ }
276
+
277
+ return result;
278
+ }