@fragno-dev/core 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +131 -64
- package/CHANGELOG.md +19 -0
- package/dist/api/api.d.ts +38 -2
- package/dist/api/api.d.ts.map +1 -0
- package/dist/api/api.js +9 -2
- package/dist/api/api.js.map +1 -0
- package/dist/api/bind-services.d.ts +6 -0
- package/dist/api/bind-services.d.ts.map +1 -0
- package/dist/api/bind-services.js +20 -0
- package/dist/api/bind-services.js.map +1 -0
- package/dist/api/error.d.ts +26 -0
- package/dist/api/error.d.ts.map +1 -0
- package/dist/{api-DngJDcmO.js → api/error.js} +2 -8
- package/dist/api/error.js.map +1 -0
- package/dist/api/fragment-definition-builder.d.ts +313 -0
- package/dist/api/fragment-definition-builder.d.ts.map +1 -0
- package/dist/api/fragment-definition-builder.js +326 -0
- package/dist/api/fragment-definition-builder.js.map +1 -0
- package/dist/api/fragment-instantiator.d.ts +216 -0
- package/dist/api/fragment-instantiator.d.ts.map +1 -0
- package/dist/api/fragment-instantiator.js +487 -0
- package/dist/api/fragment-instantiator.js.map +1 -0
- package/dist/api/fragno-response.d.ts +30 -0
- package/dist/api/fragno-response.d.ts.map +1 -0
- package/dist/api/fragno-response.js +73 -0
- package/dist/api/fragno-response.js.map +1 -0
- package/dist/api/internal/path.d.ts +50 -0
- package/dist/api/internal/path.d.ts.map +1 -0
- package/dist/api/internal/path.js +76 -0
- package/dist/api/internal/path.js.map +1 -0
- package/dist/api/internal/response-stream.d.ts +43 -0
- package/dist/api/internal/response-stream.d.ts.map +1 -0
- package/dist/api/internal/response-stream.js +81 -0
- package/dist/api/internal/response-stream.js.map +1 -0
- package/dist/api/internal/route.js +10 -0
- package/dist/api/internal/route.js.map +1 -0
- package/dist/api/mutable-request-state.d.ts +82 -0
- package/dist/api/mutable-request-state.d.ts.map +1 -0
- package/dist/api/mutable-request-state.js +97 -0
- package/dist/api/mutable-request-state.js.map +1 -0
- package/dist/api/request-context-storage.d.ts +42 -0
- package/dist/api/request-context-storage.d.ts.map +1 -0
- package/dist/api/request-context-storage.js +43 -0
- package/dist/api/request-context-storage.js.map +1 -0
- package/dist/api/request-input-context.d.ts +89 -0
- package/dist/api/request-input-context.d.ts.map +1 -0
- package/dist/api/request-input-context.js +118 -0
- package/dist/api/request-input-context.js.map +1 -0
- package/dist/api/request-middleware.d.ts +50 -0
- package/dist/api/request-middleware.d.ts.map +1 -0
- package/dist/api/request-middleware.js +83 -0
- package/dist/api/request-middleware.js.map +1 -0
- package/dist/api/request-output-context.d.ts +41 -0
- package/dist/api/request-output-context.d.ts.map +1 -0
- package/dist/api/request-output-context.js +119 -0
- package/dist/api/request-output-context.js.map +1 -0
- package/dist/api/route-handler-input-options.d.ts +21 -0
- package/dist/api/route-handler-input-options.d.ts.map +1 -0
- package/dist/api/route.d.ts +54 -3
- package/dist/api/route.d.ts.map +1 -0
- package/dist/api/route.js +29 -2
- package/dist/api/route.js.map +1 -0
- package/dist/api/shared-types.d.ts +47 -0
- package/dist/api/shared-types.d.ts.map +1 -0
- package/dist/api/shared-types.js +1 -0
- package/dist/client/client-error.d.ts +60 -0
- package/dist/client/client-error.d.ts.map +1 -0
- package/dist/client/client-error.js +92 -0
- package/dist/client/client-error.js.map +1 -0
- package/dist/client/client.d.ts +210 -4
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +397 -6
- package/dist/client/client.js.map +1 -0
- package/dist/client/client.svelte.d.ts +5 -3
- package/dist/client/client.svelte.d.ts.map +1 -1
- package/dist/client/client.svelte.js +1 -5
- package/dist/client/client.svelte.js.map +1 -1
- package/dist/client/internal/fetcher-merge.js +36 -0
- package/dist/client/internal/fetcher-merge.js.map +1 -0
- package/dist/client/internal/ndjson-streaming.js +139 -0
- package/dist/client/internal/ndjson-streaming.js.map +1 -0
- package/dist/client/react.d.ts +5 -3
- package/dist/client/react.d.ts.map +1 -1
- package/dist/client/react.js +3 -5
- package/dist/client/react.js.map +1 -1
- package/dist/client/solid.d.ts +5 -3
- package/dist/client/solid.d.ts.map +1 -1
- package/dist/client/solid.js +2 -5
- package/dist/client/solid.js.map +1 -1
- package/dist/client/vanilla.d.ts +5 -3
- package/dist/client/vanilla.d.ts.map +1 -1
- package/dist/client/vanilla.js +2 -43
- package/dist/client/vanilla.js.map +1 -1
- package/dist/client/vue.d.ts +5 -3
- package/dist/client/vue.d.ts.map +1 -1
- package/dist/client/vue.js +1 -5
- package/dist/client/vue.js.map +1 -1
- package/dist/http/http-status.d.ts +26 -0
- package/dist/http/http-status.d.ts.map +1 -0
- package/dist/integrations/react-ssr.js +1 -1
- package/dist/internal/symbols.d.ts +9 -0
- package/dist/internal/symbols.d.ts.map +1 -0
- package/dist/internal/symbols.js +10 -0
- package/dist/internal/symbols.js.map +1 -0
- package/dist/mod-client.d.ts +36 -0
- package/dist/mod-client.d.ts.map +1 -0
- package/dist/mod-client.js +21 -0
- package/dist/mod-client.js.map +1 -0
- package/dist/mod.d.ts +7 -4
- package/dist/mod.js +4 -6
- package/dist/request/request.d.ts +4 -0
- package/dist/request/request.js +5 -0
- package/dist/test/test.d.ts +62 -35
- package/dist/test/test.d.ts.map +1 -1
- package/dist/test/test.js +75 -40
- package/dist/test/test.js.map +1 -1
- package/dist/util/async.js +40 -0
- package/dist/util/async.js.map +1 -0
- package/dist/util/content-type.js +49 -0
- package/dist/util/content-type.js.map +1 -0
- package/dist/util/nanostores.js +31 -0
- package/dist/util/nanostores.js.map +1 -0
- package/dist/{ssr-BByDVfFD.js → util/ssr.js} +2 -2
- package/dist/util/ssr.js.map +1 -0
- package/dist/util/types-util.d.ts +8 -0
- package/dist/util/types-util.d.ts.map +1 -0
- package/package.json +19 -12
- package/src/api/api.ts +41 -6
- package/src/api/bind-services.ts +42 -0
- package/src/api/fragment-definition-builder.extend.test.ts +810 -0
- package/src/api/fragment-definition-builder.test.ts +499 -0
- package/src/api/fragment-definition-builder.ts +1088 -0
- package/src/api/fragment-instantiator.test.ts +1488 -0
- package/src/api/fragment-instantiator.ts +1053 -0
- package/src/api/fragment-services.test.ts +727 -0
- package/src/api/request-context-storage.ts +64 -0
- package/src/api/request-middleware.test.ts +301 -225
- package/src/api/route.test.ts +87 -1
- package/src/api/route.ts +345 -24
- package/src/api/shared-types.ts +43 -0
- package/src/client/client-builder.test.ts +23 -23
- package/src/client/client.ssr.test.ts +3 -3
- package/src/client/client.svelte.test.ts +15 -15
- package/src/client/client.test.ts +22 -22
- package/src/client/client.ts +72 -12
- package/src/client/internal/fetcher-merge.ts +1 -1
- package/src/client/react.test.ts +2 -2
- package/src/client/solid.test.ts +2 -2
- package/src/client/vanilla.test.ts +2 -2
- package/src/client/vue.test.ts +2 -2
- package/src/internal/symbols.ts +5 -0
- package/src/mod-client.ts +59 -0
- package/src/mod.ts +26 -9
- package/src/request/request.ts +8 -0
- package/src/test/test.test.ts +200 -381
- package/src/test/test.ts +190 -117
- package/tsdown.config.ts +8 -5
- package/dist/api/fragment-builder.d.ts +0 -4
- package/dist/api/fragment-builder.js +0 -3
- package/dist/api/fragment-instantiation.d.ts +0 -4
- package/dist/api/fragment-instantiation.js +0 -6
- package/dist/api-BWN97TOr.d.ts +0 -377
- package/dist/api-BWN97TOr.d.ts.map +0 -1
- package/dist/api-DngJDcmO.js.map +0 -1
- package/dist/client-C5LsYHEI.js +0 -782
- package/dist/client-C5LsYHEI.js.map +0 -1
- package/dist/fragment-builder-DOnCVBqc.js +0 -47
- package/dist/fragment-builder-DOnCVBqc.js.map +0 -1
- package/dist/fragment-builder-MGr68GNb.d.ts +0 -409
- package/dist/fragment-builder-MGr68GNb.d.ts.map +0 -1
- package/dist/fragment-instantiation-C4wvwl6V.js +0 -446
- package/dist/fragment-instantiation-C4wvwl6V.js.map +0 -1
- package/dist/request-output-context-CdIjwmEN.js +0 -320
- package/dist/request-output-context-CdIjwmEN.js.map +0 -1
- package/dist/route-Bl9Zr1Yv.d.ts +0 -26
- package/dist/route-Bl9Zr1Yv.d.ts.map +0 -1
- package/dist/route-C5Uryylh.js +0 -21
- package/dist/route-C5Uryylh.js.map +0 -1
- package/dist/ssr-BByDVfFD.js.map +0 -1
- package/src/api/fragment-builder.ts +0 -80
- package/src/api/fragment-instantiation.test.ts +0 -460
- package/src/api/fragment-instantiation.ts +0 -499
- package/src/api/fragment.test.ts +0 -537
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async.js","names":["queue: T[]","unsubscribe: UnsubscribeFn | null","resolveNext: ((value: IteratorResult<T>) => void) | null"],"sources":["../../src/util/async.ts"],"sourcesContent":["type SubscribeFn<T> = (callback: (value: T) => void) => UnsubscribeFn | void;\ntype UnsubscribeFn = () => void;\n\n/**\n * Creates an async iterator from a subscribe function that follows the observable pattern.\n *\n * @template T The type of values produced by the store.\n * @param subscribe A function that subscribes to store updates. It receives a callback to be\n * called on each update, and returns an unsubscribe function.\n * @returns An async generator that yields store values as they are produced.\n */\nexport function createAsyncIteratorFromCallback<T>(\n subscribe: SubscribeFn<T>,\n): AsyncGenerator<T, void, unknown> {\n const queue: T[] = [];\n let unsubscribe: UnsubscribeFn | null = null;\n let resolveNext: ((value: IteratorResult<T>) => void) | null = null;\n\n const unsubscribeFunc = subscribe((value) => {\n if (resolveNext) {\n // If there's a pending promise, resolve it immediately\n resolveNext({ value, done: false });\n resolveNext = null;\n } else {\n // Otherwise, queue the value\n queue.push(value);\n }\n });\n\n // Store unsubscribe function if one was returned\n if (typeof unsubscribeFunc === \"function\") {\n unsubscribe = unsubscribeFunc;\n }\n\n return (async function* () {\n try {\n while (true) {\n if (queue.length > 0) {\n // Yield queued values\n yield queue.shift()!;\n } else {\n // Wait for the next value\n yield await new Promise<T>((resolve) => {\n resolveNext = (result) => {\n if (!result.done) {\n resolve(result.value);\n }\n };\n });\n }\n }\n } finally {\n // Clean up subscription on iterator termination\n if (unsubscribe) {\n unsubscribe();\n }\n }\n })();\n}\n\n/**\n * Waits for an async iterator to yield a value that meets a condition.\n *\n * @template T The type of values produced by the iterator.\n * @param iterable The async iterable to wait for.\n * @param condition A function that checks if a value meets the condition.\n * @param options Optional configuration options.\n * @returns A promise that resolves to the first value that meets the condition.\n */\nexport async function waitForAsyncIterator<T>(\n iterable: AsyncIterable<T>,\n condition: (value: T) => boolean,\n options: { timeout?: number } = {},\n): Promise<T> {\n const { timeout = 1000 } = options;\n\n // Create a timeout promise that rejects after the specified time\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`waitForAsyncIterator: Timeout after ${timeout}ms`));\n }, timeout);\n });\n\n // Create a promise that resolves when the condition is met\n const iteratorPromise = (async () => {\n for await (const value of iterable) {\n if (condition(value)) {\n return value;\n }\n }\n throw new Error(\"waitForAsyncIterator: Iterator completed without meeting condition\");\n })();\n\n // Race between the timeout and the iterator\n return Promise.race([iteratorPromise, timeoutPromise]);\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,gCACd,WACkC;CAClC,MAAMA,QAAa,EAAE;CACrB,IAAIC,cAAoC;CACxC,IAAIC,cAA2D;CAE/D,MAAM,kBAAkB,WAAW,UAAU;AAC3C,MAAI,aAAa;AAEf,eAAY;IAAE;IAAO,MAAM;IAAO,CAAC;AACnC,iBAAc;QAGd,OAAM,KAAK,MAAM;GAEnB;AAGF,KAAI,OAAO,oBAAoB,WAC7B,eAAc;AAGhB,SAAQ,mBAAmB;AACzB,MAAI;AACF,UAAO,KACL,KAAI,MAAM,SAAS,EAEjB,OAAM,MAAM,OAAO;OAGnB,OAAM,MAAM,IAAI,SAAY,YAAY;AACtC,mBAAe,WAAW;AACxB,SAAI,CAAC,OAAO,KACV,SAAQ,OAAO,MAAM;;KAGzB;YAGE;AAER,OAAI,YACF,cAAa;;KAGf"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/util/content-type.ts
|
|
2
|
+
/**
|
|
3
|
+
* Parses a content-type header string into its components
|
|
4
|
+
*
|
|
5
|
+
* @param contentType - The content-type header value to parse
|
|
6
|
+
* @returns A ParsedContentType object or null if the input is invalid
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const { type, subtype, mediaType, parameters }
|
|
11
|
+
* = parseContentType("application/json; charset=utf-8");
|
|
12
|
+
* console.assert(type === "application");
|
|
13
|
+
* console.assert(subtype === "json");
|
|
14
|
+
* console.assert(mediaType === "application/json");
|
|
15
|
+
* console.assert(parameters["charset"] === "utf-8");
|
|
16
|
+
*/
|
|
17
|
+
function parseContentType(contentType) {
|
|
18
|
+
if (!contentType || typeof contentType !== "string") return null;
|
|
19
|
+
const trimmed = contentType.trim();
|
|
20
|
+
if (!trimmed) return null;
|
|
21
|
+
const parts = trimmed.split(";").map((part) => part.trim());
|
|
22
|
+
const mediaType = parts[0];
|
|
23
|
+
if (!mediaType) return null;
|
|
24
|
+
const typeParts = mediaType.split("/");
|
|
25
|
+
if (typeParts.length !== 2) return null;
|
|
26
|
+
const [type, subtype] = typeParts.map((part) => part.trim().toLowerCase());
|
|
27
|
+
if (!type || !subtype) return null;
|
|
28
|
+
const parameters = {};
|
|
29
|
+
for (let i = 1; i < parts.length; i++) {
|
|
30
|
+
const param = parts[i];
|
|
31
|
+
const equalIndex = param.indexOf("=");
|
|
32
|
+
if (equalIndex > 0) {
|
|
33
|
+
const key = param.slice(0, equalIndex).trim().toLowerCase();
|
|
34
|
+
let value = param.slice(equalIndex + 1).trim();
|
|
35
|
+
if (value.startsWith("\"") && value.endsWith("\"")) value = value.slice(1, -1);
|
|
36
|
+
if (key) parameters[key] = value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
type,
|
|
41
|
+
subtype,
|
|
42
|
+
mediaType: `${type}/${subtype}`,
|
|
43
|
+
parameters
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { parseContentType };
|
|
49
|
+
//# sourceMappingURL=content-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-type.js","names":["parameters: Record<string, string>"],"sources":["../../src/util/content-type.ts"],"sourcesContent":["/**\n * Represents a parsed content-type header\n */\nexport interface ParsedContentType {\n /** The main type (e.g., \"application\", \"text\", \"image\") */\n type: string;\n /** The subtype (e.g., \"json\", \"html\", \"png\") */\n subtype: string;\n /** The full media type (e.g., \"application/json\") */\n mediaType: string;\n /** Additional parameters like charset, boundary, etc. */\n parameters: Record<string, string>;\n}\n\n/**\n * Parses a content-type header string into its components\n *\n * @param contentType - The content-type header value to parse\n * @returns A ParsedContentType object or null if the input is invalid\n *\n * @example\n * ```ts\n * const { type, subtype, mediaType, parameters }\n * = parseContentType(\"application/json; charset=utf-8\");\n * console.assert(type === \"application\");\n * console.assert(subtype === \"json\");\n * console.assert(mediaType === \"application/json\");\n * console.assert(parameters[\"charset\"] === \"utf-8\");\n */\nexport function parseContentType(contentType: string | null | undefined): ParsedContentType | null {\n if (!contentType || typeof contentType !== \"string\") {\n return null;\n }\n\n const trimmed = contentType.trim();\n if (!trimmed) {\n return null;\n }\n\n const parts = trimmed.split(\";\").map((part) => part.trim());\n const mediaType = parts[0];\n\n if (!mediaType) {\n return null;\n }\n\n const typeParts = mediaType.split(\"/\");\n if (typeParts.length !== 2) {\n return null;\n }\n\n const [type, subtype] = typeParts.map((part) => part.trim().toLowerCase());\n\n if (!type || !subtype) {\n return null;\n }\n\n const parameters: Record<string, string> = {};\n\n for (let i = 1; i < parts.length; i++) {\n const param = parts[i];\n const equalIndex = param.indexOf(\"=\");\n\n if (equalIndex > 0) {\n const key = param.slice(0, equalIndex).trim().toLowerCase();\n let value = param.slice(equalIndex + 1).trim();\n\n if (value.startsWith('\"') && value.endsWith('\"')) {\n value = value.slice(1, -1);\n }\n\n if (key) {\n parameters[key] = value;\n }\n }\n }\n\n return {\n type,\n subtype,\n mediaType: `${type}/${subtype}`,\n parameters,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA6BA,SAAgB,iBAAiB,aAAkE;AACjG,KAAI,CAAC,eAAe,OAAO,gBAAgB,SACzC,QAAO;CAGT,MAAM,UAAU,YAAY,MAAM;AAClC,KAAI,CAAC,QACH,QAAO;CAGT,MAAM,QAAQ,QAAQ,MAAM,IAAI,CAAC,KAAK,SAAS,KAAK,MAAM,CAAC;CAC3D,MAAM,YAAY,MAAM;AAExB,KAAI,CAAC,UACH,QAAO;CAGT,MAAM,YAAY,UAAU,MAAM,IAAI;AACtC,KAAI,UAAU,WAAW,EACvB,QAAO;CAGT,MAAM,CAAC,MAAM,WAAW,UAAU,KAAK,SAAS,KAAK,MAAM,CAAC,aAAa,CAAC;AAE1E,KAAI,CAAC,QAAQ,CAAC,QACZ,QAAO;CAGT,MAAMA,aAAqC,EAAE;AAE7C,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,QAAQ,MAAM;EACpB,MAAM,aAAa,MAAM,QAAQ,IAAI;AAErC,MAAI,aAAa,GAAG;GAClB,MAAM,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,aAAa;GAC3D,IAAI,QAAQ,MAAM,MAAM,aAAa,EAAE,CAAC,MAAM;AAE9C,OAAI,MAAM,WAAW,KAAI,IAAI,MAAM,SAAS,KAAI,CAC9C,SAAQ,MAAM,MAAM,GAAG,GAAG;AAG5B,OAAI,IACF,YAAW,OAAO;;;AAKxB,QAAO;EACL;EACA;EACA,WAAW,GAAG,KAAK,GAAG;EACtB;EACD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/util/nanostores.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes a value that could be a plain value, an Atom, or a Vue Ref to a plain value.
|
|
4
|
+
*/
|
|
5
|
+
function unwrapAtom(value) {
|
|
6
|
+
if (value && typeof value === "object" && "get" in value && typeof value.get === "function") return value.get();
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Normalizes an object where values can be plain values, Atoms, or Vue Refs.
|
|
11
|
+
* Returns a new object with all values normalized to plain values.
|
|
12
|
+
*/
|
|
13
|
+
function unwrapObject(params) {
|
|
14
|
+
if (!params) return;
|
|
15
|
+
return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, unwrapAtom(value)]));
|
|
16
|
+
}
|
|
17
|
+
function isReadableAtom(value) {
|
|
18
|
+
if (!value) return false;
|
|
19
|
+
if (typeof value !== "object" || value === null) return false;
|
|
20
|
+
if (!("get" in value) || typeof value.get !== "function") return false;
|
|
21
|
+
if (!("lc" in value) || typeof value.lc !== "number") return false;
|
|
22
|
+
if (!("notify" in value) || typeof value.notify !== "function") return false;
|
|
23
|
+
if (!("off" in value) || typeof value.off !== "function") return false;
|
|
24
|
+
if (!("subscribe" in value) || typeof value.subscribe !== "function") return false;
|
|
25
|
+
if (!("value" in value)) return false;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { isReadableAtom, unwrapObject };
|
|
31
|
+
//# sourceMappingURL=nanostores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nanostores.js","names":[],"sources":["../../src/util/nanostores.ts"],"sourcesContent":["import type { ReadableAtom } from \"nanostores\";\n\ntype MaybeAtom<T> = T | ReadableAtom<T>;\n\n/**\n * Normalizes a value that could be a plain value, an Atom, or a Vue Ref to a plain value.\n */\nexport function unwrapAtom<T>(value: MaybeAtom<T>): T {\n // Check if it's an Atom (has .get method)\n if (value && typeof value === \"object\" && \"get\" in value && typeof value.get === \"function\") {\n return value.get();\n }\n\n return value as T;\n}\n\n/**\n * Normalizes an object where values can be plain values, Atoms, or Vue Refs.\n * Returns a new object with all values normalized to plain values.\n */\nexport function unwrapObject<T>(\n params: Record<string, MaybeAtom<T>> | undefined,\n): Record<string, T> | undefined {\n if (!params) {\n return undefined;\n }\n\n return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, unwrapAtom(value)]));\n}\n\nexport function isReadableAtom(value: unknown): value is ReadableAtom<unknown> {\n if (!value) {\n return false;\n }\n\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n if (!(\"get\" in value) || typeof value.get !== \"function\") {\n return false;\n }\n\n if (!(\"lc\" in value) || typeof value.lc !== \"number\") {\n return false;\n }\n\n if (!(\"notify\" in value) || typeof value.notify !== \"function\") {\n return false;\n }\n\n if (!(\"off\" in value) || typeof value.off !== \"function\") {\n return false;\n }\n\n if (!(\"subscribe\" in value) || typeof value.subscribe !== \"function\") {\n return false;\n }\n\n if (!(\"value\" in value)) {\n return false;\n }\n\n return true;\n}\n"],"mappings":";;;;AAOA,SAAgB,WAAc,OAAwB;AAEpD,KAAI,SAAS,OAAO,UAAU,YAAY,SAAS,SAAS,OAAO,MAAM,QAAQ,WAC/E,QAAO,MAAM,KAAK;AAGpB,QAAO;;;;;;AAOT,SAAgB,aACd,QAC+B;AAC/B,KAAI,CAAC,OACH;AAGF,QAAO,OAAO,YAAY,OAAO,QAAQ,OAAO,CAAC,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,WAAW,MAAM,CAAC,CAAC,CAAC;;AAGnG,SAAgB,eAAe,OAAgD;AAC7E,KAAI,CAAC,MACH,QAAO;AAGT,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO;AAGT,KAAI,EAAE,SAAS,UAAU,OAAO,MAAM,QAAQ,WAC5C,QAAO;AAGT,KAAI,EAAE,QAAQ,UAAU,OAAO,MAAM,OAAO,SAC1C,QAAO;AAGT,KAAI,EAAE,YAAY,UAAU,OAAO,MAAM,WAAW,WAClD,QAAO;AAGT,KAAI,EAAE,SAAS,UAAU,OAAO,MAAM,QAAQ,WAC5C,QAAO;AAGT,KAAI,EAAE,eAAe,UAAU,OAAO,MAAM,cAAc,WACxD,QAAO;AAGT,KAAI,EAAE,WAAW,OACf,QAAO;AAGT,QAAO"}
|
|
@@ -44,5 +44,5 @@ async function getFinalStoreValues() {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
//#endregion
|
|
47
|
-
export {
|
|
48
|
-
//# sourceMappingURL=ssr
|
|
47
|
+
export { SSR_ENABLED, addStore, cleanStores, getFinalStoreValues, getInitialData, hydrateFromWindow };
|
|
48
|
+
//# sourceMappingURL=ssr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssr.js","names":["stores: FetcherStore[]","clientInitialData: Map<string, unknown> | undefined","stores"],"sources":["../../src/util/ssr.ts"],"sourcesContent":["import { allTasks } from \"nanostores\";\nimport type { FetcherStore } from \"@nanostores/query\";\n\nlet stores: FetcherStore[] = [];\n\nexport const SSR_ENABLED = false;\n\nexport function getStores() {\n return stores;\n}\n\nexport function addStore(store: FetcherStore) {\n stores.push(store);\n}\n\nexport function cleanStores() {\n stores = [];\n}\n\n// Client side\ndeclare global {\n interface Window {\n __FRAGNO_INITIAL_DATA__?: [string, unknown][];\n }\n}\n\nlet clientInitialData: Map<string, unknown> | undefined;\n\nexport function hydrateFromWindow() {\n if (typeof window !== \"undefined\" && window.__FRAGNO_INITIAL_DATA__) {\n clientInitialData = new Map(window.__FRAGNO_INITIAL_DATA__);\n delete window.__FRAGNO_INITIAL_DATA__;\n console.warn(\"hydrateFromWindow\", {\n clientInitialData: Array.from(clientInitialData.entries()),\n });\n }\n}\n\nexport function getInitialData(key: string): unknown | undefined {\n if (clientInitialData?.has(key)) {\n const data = clientInitialData.get(key);\n clientInitialData.delete(key);\n return data;\n }\n return undefined;\n}\n\nfunction listenToStores(): void {\n for (const store of getStores()) {\n // By calling `listen`, we trigger the fetcher function of the store.\n // This will start the data fetching process on the server.\n // We don't need to do anything with the return value of `listen`, as we\n // are only interested in starting the data fetching.\n store.listen(() => {});\n }\n}\n\n// Server side\nexport async function getFinalStoreValues(): Promise<Map<string, unknown>> {\n listenToStores();\n await allTasks();\n\n const stores = getStores();\n const storesInitialValue = new Map<string, unknown>();\n\n for (const store of stores) {\n const value = store.get();\n if (!value || !store.key || value.loading) {\n continue;\n }\n storesInitialValue.set(store.key, value.data);\n }\n\n return storesInitialValue;\n}\n"],"mappings":";;;AAGA,IAAIA,SAAyB,EAAE;AAE/B,MAAa,cAAc;AAE3B,SAAgB,YAAY;AAC1B,QAAO;;AAGT,SAAgB,SAAS,OAAqB;AAC5C,QAAO,KAAK,MAAM;;AAGpB,SAAgB,cAAc;AAC5B,UAAS,EAAE;;AAUb,IAAIC;AAEJ,SAAgB,oBAAoB;AAClC,KAAI,OAAO,WAAW,eAAe,OAAO,yBAAyB;AACnE,sBAAoB,IAAI,IAAI,OAAO,wBAAwB;AAC3D,SAAO,OAAO;AACd,UAAQ,KAAK,qBAAqB,EAChC,mBAAmB,MAAM,KAAK,kBAAkB,SAAS,CAAC,EAC3D,CAAC;;;AAIN,SAAgB,eAAe,KAAkC;AAC/D,KAAI,mBAAmB,IAAI,IAAI,EAAE;EAC/B,MAAM,OAAO,kBAAkB,IAAI,IAAI;AACvC,oBAAkB,OAAO,IAAI;AAC7B,SAAO;;;AAKX,SAAS,iBAAuB;AAC9B,MAAK,MAAM,SAAS,WAAW,CAK7B,OAAM,aAAa,GAAG;;AAK1B,eAAsB,sBAAqD;AACzE,iBAAgB;AAChB,OAAM,UAAU;CAEhB,MAAMC,WAAS,WAAW;CAC1B,MAAM,qCAAqB,IAAI,KAAsB;AAErD,MAAK,MAAM,SAASA,UAAQ;EAC1B,MAAM,QAAQ,MAAM,KAAK;AACzB,MAAI,CAAC,SAAS,CAAC,MAAM,OAAO,MAAM,QAChC;AAEF,qBAAmB,IAAI,MAAM,KAAK,MAAM,KAAK;;AAG/C,QAAO"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
+
|
|
3
|
+
//#region src/util/types-util.d.ts
|
|
4
|
+
type InferOr<T, U> = T extends NonNullable<StandardSchemaV1> ? StandardSchemaV1.InferOutput<T> : T extends undefined ? U : U;
|
|
5
|
+
type InferOrUnknown<T> = InferOr<T, unknown>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { InferOr, InferOrUnknown };
|
|
8
|
+
//# sourceMappingURL=types-util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-util.d.ts","names":[],"sources":["../../src/util/types-util.ts"],"sourcesContent":[],"mappings":";;;KAEY,gBACV,UAAU,YAAY,oBAClB,gBAAA,CAAiB,YAAY,KAC7B,sBACE,IACA;KAEI,oBAAoB,QAAQ"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragno-dev/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": {
|
|
6
6
|
"development": "./src/mod.ts",
|
|
7
|
+
"browser": "./dist/mod-client.js",
|
|
7
8
|
"types": "./dist/mod.d.ts",
|
|
8
9
|
"default": "./dist/mod.js"
|
|
9
10
|
},
|
|
@@ -17,21 +18,26 @@
|
|
|
17
18
|
"types": "./dist/test/test.d.ts",
|
|
18
19
|
"default": "./dist/test/test.js"
|
|
19
20
|
},
|
|
20
|
-
"./
|
|
21
|
-
"development": "./src/api/fragment-builder.ts",
|
|
22
|
-
"types": "./dist/api/fragment-builder.d.ts",
|
|
23
|
-
"default": "./dist/api/fragment-builder.js"
|
|
24
|
-
},
|
|
25
|
-
"./api/fragment-instantiation": {
|
|
26
|
-
"development": "./src/api/fragment-instantiation.ts",
|
|
27
|
-
"types": "./dist/api/fragment-instantiation.d.ts",
|
|
28
|
-
"default": "./dist/api/fragment-instantiation.js"
|
|
29
|
-
},
|
|
30
|
-
"./api/route": {
|
|
21
|
+
"./route": {
|
|
31
22
|
"development": "./src/api/route.ts",
|
|
32
23
|
"types": "./dist/api/route.d.ts",
|
|
33
24
|
"default": "./dist/api/route.js"
|
|
34
25
|
},
|
|
26
|
+
"./request": {
|
|
27
|
+
"development": "./src/request/request.ts",
|
|
28
|
+
"types": "./dist/request/request.d.ts",
|
|
29
|
+
"default": "./dist/request/request.js"
|
|
30
|
+
},
|
|
31
|
+
"./internal/request-context-storage": {
|
|
32
|
+
"development": "./src/api/request-context-storage.ts",
|
|
33
|
+
"types": "./dist/api/request-context-storage.d.ts",
|
|
34
|
+
"default": "./dist/api/request-context-storage.js"
|
|
35
|
+
},
|
|
36
|
+
"./internal/symbols": {
|
|
37
|
+
"development": "./src/internal/symbols.ts",
|
|
38
|
+
"types": "./dist/internal/symbols.d.ts",
|
|
39
|
+
"default": "./dist/internal/symbols.js"
|
|
40
|
+
},
|
|
35
41
|
"./client": {
|
|
36
42
|
"development": "./src/client/client.ts",
|
|
37
43
|
"types": "./dist/client/client.d.ts",
|
|
@@ -73,6 +79,7 @@
|
|
|
73
79
|
"module": "./dist/mod.js",
|
|
74
80
|
"types": "./dist/mod.d.ts",
|
|
75
81
|
"type": "module",
|
|
82
|
+
"sideEffects": false,
|
|
76
83
|
"dependencies": {
|
|
77
84
|
"@nanostores/query": "^0.3.4",
|
|
78
85
|
"@nanostores/solid": "^1.1.1",
|
package/src/api/api.ts
CHANGED
|
@@ -23,6 +23,8 @@ export type ValidPath<T extends string = string> = T extends `/${infer Rest}`
|
|
|
23
23
|
: T
|
|
24
24
|
: PathError<T, "Path must start with '/'.">; // Excludes paths not starting with "/"
|
|
25
25
|
|
|
26
|
+
export interface RequestThisContext {}
|
|
27
|
+
|
|
26
28
|
export interface FragnoRouteConfig<
|
|
27
29
|
TMethod extends HTTPMethod,
|
|
28
30
|
TPath extends string,
|
|
@@ -30,6 +32,7 @@ export interface FragnoRouteConfig<
|
|
|
30
32
|
TOutputSchema extends StandardSchemaV1 | undefined,
|
|
31
33
|
TErrorCode extends string = string,
|
|
32
34
|
TQueryParameters extends string = string,
|
|
35
|
+
TThisContext extends RequestThisContext = RequestThisContext,
|
|
33
36
|
> {
|
|
34
37
|
method: TMethod;
|
|
35
38
|
path: TPath;
|
|
@@ -38,6 +41,7 @@ export interface FragnoRouteConfig<
|
|
|
38
41
|
errorCodes?: readonly TErrorCode[];
|
|
39
42
|
queryParameters?: readonly TQueryParameters[];
|
|
40
43
|
handler(
|
|
44
|
+
this: TThisContext,
|
|
41
45
|
inputCtx: RequestInputContext<TPath, TInputSchema>,
|
|
42
46
|
outputCtx: RequestOutputContext<TOutputSchema, TErrorCode>,
|
|
43
47
|
): Promise<Response>;
|
|
@@ -50,6 +54,7 @@ export function addRoute<
|
|
|
50
54
|
TOutputSchema extends StandardSchemaV1 | undefined,
|
|
51
55
|
TErrorCode extends string = string,
|
|
52
56
|
TQueryParameters extends string = string,
|
|
57
|
+
TThisContext extends RequestThisContext = RequestThisContext,
|
|
53
58
|
>(
|
|
54
59
|
route: FragnoRouteConfig<
|
|
55
60
|
TMethod,
|
|
@@ -57,9 +62,18 @@ export function addRoute<
|
|
|
57
62
|
undefined,
|
|
58
63
|
TOutputSchema,
|
|
59
64
|
TErrorCode,
|
|
60
|
-
TQueryParameters
|
|
65
|
+
TQueryParameters,
|
|
66
|
+
TThisContext
|
|
61
67
|
> & { inputSchema?: undefined },
|
|
62
|
-
): FragnoRouteConfig<
|
|
68
|
+
): FragnoRouteConfig<
|
|
69
|
+
TMethod,
|
|
70
|
+
TPath,
|
|
71
|
+
undefined,
|
|
72
|
+
TOutputSchema,
|
|
73
|
+
TErrorCode,
|
|
74
|
+
TQueryParameters,
|
|
75
|
+
TThisContext
|
|
76
|
+
>;
|
|
63
77
|
|
|
64
78
|
// Overload for routes with inputSchema
|
|
65
79
|
export function addRoute<
|
|
@@ -69,6 +83,7 @@ export function addRoute<
|
|
|
69
83
|
TOutputSchema extends StandardSchemaV1 | undefined,
|
|
70
84
|
TErrorCode extends string = string,
|
|
71
85
|
TQueryParameters extends string = string,
|
|
86
|
+
TThisContext extends RequestThisContext = RequestThisContext,
|
|
72
87
|
>(
|
|
73
88
|
route: FragnoRouteConfig<
|
|
74
89
|
TMethod,
|
|
@@ -76,11 +91,20 @@ export function addRoute<
|
|
|
76
91
|
TInputSchema,
|
|
77
92
|
TOutputSchema,
|
|
78
93
|
TErrorCode,
|
|
79
|
-
TQueryParameters
|
|
94
|
+
TQueryParameters,
|
|
95
|
+
TThisContext
|
|
80
96
|
> & {
|
|
81
97
|
inputSchema: TInputSchema;
|
|
82
98
|
},
|
|
83
|
-
): FragnoRouteConfig<
|
|
99
|
+
): FragnoRouteConfig<
|
|
100
|
+
TMethod,
|
|
101
|
+
TPath,
|
|
102
|
+
TInputSchema,
|
|
103
|
+
TOutputSchema,
|
|
104
|
+
TErrorCode,
|
|
105
|
+
TQueryParameters,
|
|
106
|
+
TThisContext
|
|
107
|
+
>;
|
|
84
108
|
|
|
85
109
|
// Implementation
|
|
86
110
|
export function addRoute<
|
|
@@ -90,6 +114,7 @@ export function addRoute<
|
|
|
90
114
|
TOutputSchema extends StandardSchemaV1 | undefined,
|
|
91
115
|
TErrorCode extends string = string,
|
|
92
116
|
TQueryParameters extends string = string,
|
|
117
|
+
TThisContext extends RequestThisContext = RequestThisContext,
|
|
93
118
|
>(
|
|
94
119
|
route: FragnoRouteConfig<
|
|
95
120
|
TMethod,
|
|
@@ -97,11 +122,21 @@ export function addRoute<
|
|
|
97
122
|
TInputSchema,
|
|
98
123
|
TOutputSchema,
|
|
99
124
|
TErrorCode,
|
|
100
|
-
TQueryParameters
|
|
125
|
+
TQueryParameters,
|
|
126
|
+
TThisContext
|
|
101
127
|
>,
|
|
102
|
-
): FragnoRouteConfig<
|
|
128
|
+
): FragnoRouteConfig<
|
|
129
|
+
TMethod,
|
|
130
|
+
TPath,
|
|
131
|
+
TInputSchema,
|
|
132
|
+
TOutputSchema,
|
|
133
|
+
TErrorCode,
|
|
134
|
+
TQueryParameters,
|
|
135
|
+
TThisContext
|
|
136
|
+
> {
|
|
103
137
|
return route;
|
|
104
138
|
}
|
|
105
139
|
|
|
106
140
|
export { FragnoApiError, FragnoApiValidationError } from "./error";
|
|
107
141
|
export type { RouteHandlerInputOptions } from "./route-handler-input-options";
|
|
142
|
+
export type { FragnoPublicConfig } from "./shared-types";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Type helper to remove 'this' parameter from functions
|
|
2
|
+
type OmitThisParameter<T> = T extends (this: infer _This, ...args: infer A) => infer R
|
|
3
|
+
? (...args: A) => R
|
|
4
|
+
: T;
|
|
5
|
+
|
|
6
|
+
// Recursively remove 'this' parameter from all functions in an object
|
|
7
|
+
export type BoundServices<T> = {
|
|
8
|
+
[K in keyof T]: T[K] extends (...args: never[]) => unknown
|
|
9
|
+
? OmitThisParameter<T[K]>
|
|
10
|
+
: T[K] extends Record<string, unknown>
|
|
11
|
+
? BoundServices<T[K]>
|
|
12
|
+
: T[K];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Bind all functions in a service object to a specific context.
|
|
17
|
+
* This allows services to use `this` to access the context.
|
|
18
|
+
*
|
|
19
|
+
* @param services - The service object to bind
|
|
20
|
+
* @param context - The context to bind to (e.g., { getUnitOfWork })
|
|
21
|
+
* @returns A new object with all functions bound to the context
|
|
22
|
+
*/
|
|
23
|
+
export function bindServicesToContext<T extends object, TContext extends object>(
|
|
24
|
+
services: T,
|
|
25
|
+
context: TContext,
|
|
26
|
+
): BoundServices<T> {
|
|
27
|
+
const bound = {} as BoundServices<T>;
|
|
28
|
+
|
|
29
|
+
for (const [key, value] of Object.entries(services)) {
|
|
30
|
+
if (typeof value === "function") {
|
|
31
|
+
// Bind function to the provided context
|
|
32
|
+
bound[key as keyof T] = value.bind(context) as BoundServices<T>[keyof T];
|
|
33
|
+
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
34
|
+
// Recursively bind nested service objects
|
|
35
|
+
bound[key as keyof T] = bindServicesToContext(value, context) as BoundServices<T>[keyof T];
|
|
36
|
+
} else {
|
|
37
|
+
bound[key as keyof T] = value as BoundServices<T>[keyof T];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return bound;
|
|
42
|
+
}
|