@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.
- package/.turbo/turbo-build.log +61 -0
- package/.turbo/turbo-types$colon$check.log +2 -0
- package/dist/api/api.d.ts +2 -0
- package/dist/api/api.js +3 -0
- package/dist/api-CBDGZiLC.d.ts +278 -0
- package/dist/api-CBDGZiLC.d.ts.map +1 -0
- package/dist/api-DgHfYjq2.js +54 -0
- package/dist/api-DgHfYjq2.js.map +1 -0
- package/dist/client/client.d.ts +3 -0
- package/dist/client/client.js +6 -0
- package/dist/client/client.svelte.d.ts +33 -0
- package/dist/client/client.svelte.d.ts.map +1 -0
- package/dist/client/client.svelte.js +123 -0
- package/dist/client/client.svelte.js.map +1 -0
- package/dist/client/react.d.ts +58 -0
- package/dist/client/react.d.ts.map +1 -0
- package/dist/client/react.js +80 -0
- package/dist/client/react.js.map +1 -0
- package/dist/client/vanilla.d.ts +61 -0
- package/dist/client/vanilla.d.ts.map +1 -0
- package/dist/client/vanilla.js +136 -0
- package/dist/client/vanilla.js.map +1 -0
- package/dist/client/vue.d.ts +39 -0
- package/dist/client/vue.d.ts.map +1 -0
- package/dist/client/vue.js +108 -0
- package/dist/client/vue.js.map +1 -0
- package/dist/client-DWjxKDnE.js +703 -0
- package/dist/client-DWjxKDnE.js.map +1 -0
- package/dist/client-XFdAy-IQ.d.ts +287 -0
- package/dist/client-XFdAy-IQ.d.ts.map +1 -0
- package/dist/integrations/astro.d.ts +18 -0
- package/dist/integrations/astro.d.ts.map +1 -0
- package/dist/integrations/astro.js +16 -0
- package/dist/integrations/astro.js.map +1 -0
- package/dist/integrations/next-js.d.ts +15 -0
- package/dist/integrations/next-js.d.ts.map +1 -0
- package/dist/integrations/next-js.js +17 -0
- package/dist/integrations/next-js.js.map +1 -0
- package/dist/integrations/react-ssr.d.ts +19 -0
- package/dist/integrations/react-ssr.d.ts.map +1 -0
- package/dist/integrations/react-ssr.js +38 -0
- package/dist/integrations/react-ssr.js.map +1 -0
- package/dist/integrations/svelte-kit.d.ts +21 -0
- package/dist/integrations/svelte-kit.d.ts.map +1 -0
- package/dist/integrations/svelte-kit.js +18 -0
- package/dist/integrations/svelte-kit.js.map +1 -0
- package/dist/mod.d.ts +3 -0
- package/dist/mod.js +177 -0
- package/dist/mod.js.map +1 -0
- package/dist/route-Bp6eByhz.js +331 -0
- package/dist/route-Bp6eByhz.js.map +1 -0
- package/dist/ssr-tJHqcNSw.js +48 -0
- package/dist/ssr-tJHqcNSw.js.map +1 -0
- package/package.json +127 -0
- package/src/api/api.test.ts +140 -0
- package/src/api/api.ts +106 -0
- package/src/api/error.ts +47 -0
- package/src/api/fragment.test.ts +509 -0
- package/src/api/fragment.ts +277 -0
- package/src/api/internal/path-runtime.test.ts +121 -0
- package/src/api/internal/path-type.test.ts +602 -0
- package/src/api/internal/path.ts +322 -0
- package/src/api/internal/response-stream.ts +118 -0
- package/src/api/internal/route.test.ts +56 -0
- package/src/api/internal/route.ts +9 -0
- package/src/api/request-input-context.test.ts +437 -0
- package/src/api/request-input-context.ts +201 -0
- package/src/api/request-middleware.test.ts +544 -0
- package/src/api/request-middleware.ts +126 -0
- package/src/api/request-output-context.test.ts +626 -0
- package/src/api/request-output-context.ts +175 -0
- package/src/api/route.test.ts +176 -0
- package/src/api/route.ts +152 -0
- package/src/client/client-builder.test.ts +264 -0
- package/src/client/client-error.test.ts +15 -0
- package/src/client/client-error.ts +141 -0
- package/src/client/client-types.test.ts +493 -0
- package/src/client/client.ssr.test.ts +173 -0
- package/src/client/client.svelte.test.ts +837 -0
- package/src/client/client.svelte.ts +278 -0
- package/src/client/client.test.ts +1690 -0
- package/src/client/client.ts +1035 -0
- package/src/client/component.test.svelte +21 -0
- package/src/client/internal/ndjson-streaming.test.ts +457 -0
- package/src/client/internal/ndjson-streaming.ts +248 -0
- package/src/client/react.test.ts +947 -0
- package/src/client/react.ts +241 -0
- package/src/client/vanilla.test.ts +867 -0
- package/src/client/vanilla.ts +265 -0
- package/src/client/vue.test.ts +754 -0
- package/src/client/vue.ts +242 -0
- package/src/http/http-status.ts +60 -0
- package/src/integrations/astro.ts +17 -0
- package/src/integrations/next-js.ts +31 -0
- package/src/integrations/react-ssr.ts +40 -0
- package/src/integrations/svelte-kit.ts +41 -0
- package/src/mod.ts +20 -0
- package/src/util/async.test.ts +85 -0
- package/src/util/async.ts +96 -0
- package/src/util/content-type.test.ts +136 -0
- package/src/util/content-type.ts +84 -0
- package/src/util/nanostores.test.ts +28 -0
- package/src/util/nanostores.ts +65 -0
- package/src/util/ssr.ts +75 -0
- package/src/util/types-util.ts +16 -0
- package/tsconfig.json +10 -0
- package/tsdown.config.ts +21 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { parseContentType } from "./content-type";
|
|
3
|
+
|
|
4
|
+
describe("parseContentType", () => {
|
|
5
|
+
it("should parse simple content types", () => {
|
|
6
|
+
const result = parseContentType("application/json");
|
|
7
|
+
expect(result).toEqual({
|
|
8
|
+
type: "application",
|
|
9
|
+
subtype: "json",
|
|
10
|
+
mediaType: "application/json",
|
|
11
|
+
parameters: {},
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should parse content types with parameters", () => {
|
|
16
|
+
const result = parseContentType("application/x-ndjson; charset=utf-8");
|
|
17
|
+
expect(result).toEqual({
|
|
18
|
+
type: "application",
|
|
19
|
+
subtype: "x-ndjson",
|
|
20
|
+
mediaType: "application/x-ndjson",
|
|
21
|
+
parameters: { charset: "utf-8" },
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should parse multiple parameters", () => {
|
|
26
|
+
const result = parseContentType(
|
|
27
|
+
"multipart/form-data; boundary=----WebKitFormBoundary; charset=utf-8",
|
|
28
|
+
);
|
|
29
|
+
expect(result).toEqual({
|
|
30
|
+
type: "multipart",
|
|
31
|
+
subtype: "form-data",
|
|
32
|
+
mediaType: "multipart/form-data",
|
|
33
|
+
parameters: {
|
|
34
|
+
boundary: "----WebKitFormBoundary",
|
|
35
|
+
charset: "utf-8",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should handle quoted parameter values", () => {
|
|
41
|
+
const result = parseContentType('text/plain; charset="utf-8"');
|
|
42
|
+
expect(result).toEqual({
|
|
43
|
+
type: "text",
|
|
44
|
+
subtype: "plain",
|
|
45
|
+
mediaType: "text/plain",
|
|
46
|
+
parameters: { charset: "utf-8" },
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should normalize to lowercase", () => {
|
|
51
|
+
const result = parseContentType("Application/JSON; Charset=UTF-8");
|
|
52
|
+
expect(result).toEqual({
|
|
53
|
+
type: "application",
|
|
54
|
+
subtype: "json",
|
|
55
|
+
mediaType: "application/json",
|
|
56
|
+
parameters: { charset: "UTF-8" },
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should handle extra whitespace", () => {
|
|
61
|
+
const result = parseContentType(" text/html ; charset = utf-8 ");
|
|
62
|
+
expect(result).toEqual({
|
|
63
|
+
type: "text",
|
|
64
|
+
subtype: "html",
|
|
65
|
+
mediaType: "text/html",
|
|
66
|
+
parameters: { charset: "utf-8" },
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should return null for invalid input", () => {
|
|
71
|
+
expect(parseContentType("")).toBeNull();
|
|
72
|
+
expect(parseContentType(null as unknown as string)).toBeNull();
|
|
73
|
+
expect(parseContentType(undefined as unknown as string)).toBeNull();
|
|
74
|
+
expect(parseContentType(123 as unknown as string)).toBeNull();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should return null for invalid media types", () => {
|
|
78
|
+
expect(parseContentType("invalid")).toBeNull();
|
|
79
|
+
expect(parseContentType("/")).toBeNull();
|
|
80
|
+
expect(parseContentType("text/")).toBeNull();
|
|
81
|
+
expect(parseContentType("/json")).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should handle parameters without values gracefully", () => {
|
|
85
|
+
const result = parseContentType("text/plain; charset");
|
|
86
|
+
expect(result).toEqual({
|
|
87
|
+
type: "text",
|
|
88
|
+
subtype: "plain",
|
|
89
|
+
mediaType: "text/plain",
|
|
90
|
+
parameters: {},
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should handle complex real-world examples", () => {
|
|
95
|
+
const result = parseContentType("application/vnd.api+json; charset=utf-8; version=1");
|
|
96
|
+
expect(result).toEqual({
|
|
97
|
+
type: "application",
|
|
98
|
+
subtype: "vnd.api+json",
|
|
99
|
+
mediaType: "application/vnd.api+json",
|
|
100
|
+
parameters: {
|
|
101
|
+
charset: "utf-8",
|
|
102
|
+
version: "1",
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should handle text/event-stream", () => {
|
|
108
|
+
const result = parseContentType("text/event-stream; charset=utf-8");
|
|
109
|
+
expect(result).toEqual({
|
|
110
|
+
type: "text",
|
|
111
|
+
subtype: "event-stream",
|
|
112
|
+
mediaType: "text/event-stream",
|
|
113
|
+
parameters: { charset: "utf-8" },
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should parse application/octet-stream", () => {
|
|
118
|
+
const result = parseContentType("application/octet-stream");
|
|
119
|
+
expect(result).toEqual({
|
|
120
|
+
type: "application",
|
|
121
|
+
subtype: "octet-stream",
|
|
122
|
+
mediaType: "application/octet-stream",
|
|
123
|
+
parameters: {},
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should handle empty string parameters", () => {
|
|
128
|
+
const result = parseContentType('text/plain; charset=""');
|
|
129
|
+
expect(result).toEqual({
|
|
130
|
+
type: "text",
|
|
131
|
+
subtype: "plain",
|
|
132
|
+
mediaType: "text/plain",
|
|
133
|
+
parameters: { charset: "" },
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a parsed content-type header
|
|
3
|
+
*/
|
|
4
|
+
export interface ParsedContentType {
|
|
5
|
+
/** The main type (e.g., "application", "text", "image") */
|
|
6
|
+
type: string;
|
|
7
|
+
/** The subtype (e.g., "json", "html", "png") */
|
|
8
|
+
subtype: string;
|
|
9
|
+
/** The full media type (e.g., "application/json") */
|
|
10
|
+
mediaType: string;
|
|
11
|
+
/** Additional parameters like charset, boundary, etc. */
|
|
12
|
+
parameters: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parses a content-type header string into its components
|
|
17
|
+
*
|
|
18
|
+
* @param contentType - The content-type header value to parse
|
|
19
|
+
* @returns A ParsedContentType object or null if the input is invalid
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const { type, subtype, mediaType, parameters }
|
|
24
|
+
* = parseContentType("application/json; charset=utf-8");
|
|
25
|
+
* console.assert(type === "application");
|
|
26
|
+
* console.assert(subtype === "json");
|
|
27
|
+
* console.assert(mediaType === "application/json");
|
|
28
|
+
* console.assert(parameters["charset"] === "utf-8");
|
|
29
|
+
*/
|
|
30
|
+
export function parseContentType(contentType: string | null | undefined): ParsedContentType | null {
|
|
31
|
+
if (!contentType || typeof contentType !== "string") {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const trimmed = contentType.trim();
|
|
36
|
+
if (!trimmed) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const parts = trimmed.split(";").map((part) => part.trim());
|
|
41
|
+
const mediaType = parts[0];
|
|
42
|
+
|
|
43
|
+
if (!mediaType) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const typeParts = mediaType.split("/");
|
|
48
|
+
if (typeParts.length !== 2) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const [type, subtype] = typeParts.map((part) => part.trim().toLowerCase());
|
|
53
|
+
|
|
54
|
+
if (!type || !subtype) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const parameters: Record<string, string> = {};
|
|
59
|
+
|
|
60
|
+
for (let i = 1; i < parts.length; i++) {
|
|
61
|
+
const param = parts[i];
|
|
62
|
+
const equalIndex = param.indexOf("=");
|
|
63
|
+
|
|
64
|
+
if (equalIndex > 0) {
|
|
65
|
+
const key = param.slice(0, equalIndex).trim().toLowerCase();
|
|
66
|
+
let value = param.slice(equalIndex + 1).trim();
|
|
67
|
+
|
|
68
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
69
|
+
value = value.slice(1, -1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (key) {
|
|
73
|
+
parameters[key] = value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
type,
|
|
80
|
+
subtype,
|
|
81
|
+
mediaType: `${type}/${subtype}`,
|
|
82
|
+
parameters,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { isReadableAtom } from "./nanostores";
|
|
3
|
+
import { atom, map } from "nanostores";
|
|
4
|
+
|
|
5
|
+
describe("nanostores", () => {
|
|
6
|
+
test("isReadableAtom should return true for a readable atom", () => {
|
|
7
|
+
const store = atom(0);
|
|
8
|
+
expect(isReadableAtom(store)).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("isReadableAtom should return false for a non-readable atom", () => {
|
|
12
|
+
const store = { get: () => 0 };
|
|
13
|
+
expect(isReadableAtom(store)).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("isReadableAtom should return false for a non-object", () => {
|
|
17
|
+
expect(isReadableAtom(0)).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("isReadableAtom should return false for a null value", () => {
|
|
21
|
+
expect(isReadableAtom(null)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("isReadableAtom should return true for map", () => {
|
|
25
|
+
const store = map({ a: 1 });
|
|
26
|
+
expect(isReadableAtom(store)).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ReadableAtom } from "nanostores";
|
|
2
|
+
|
|
3
|
+
type MaybeAtom<T> = T | ReadableAtom<T>;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes a value that could be a plain value, an Atom, or a Vue Ref to a plain value.
|
|
7
|
+
*/
|
|
8
|
+
export function unwrapAtom<T>(value: MaybeAtom<T>): T {
|
|
9
|
+
// Check if it's an Atom (has .get method)
|
|
10
|
+
if (value && typeof value === "object" && "get" in value && typeof value.get === "function") {
|
|
11
|
+
return value.get();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return value as T;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Normalizes an object where values can be plain values, Atoms, or Vue Refs.
|
|
19
|
+
* Returns a new object with all values normalized to plain values.
|
|
20
|
+
*/
|
|
21
|
+
export function unwrapObject<T>(
|
|
22
|
+
params: Record<string, MaybeAtom<T>> | undefined,
|
|
23
|
+
): Record<string, T> | undefined {
|
|
24
|
+
if (!params) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, unwrapAtom(value)]));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function isReadableAtom(value: unknown): value is ReadableAtom<unknown> {
|
|
32
|
+
if (!value) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (typeof value !== "object" || value === null) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!("get" in value) || typeof value.get !== "function") {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!("lc" in value) || typeof value.lc !== "number") {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!("notify" in value) || typeof value.notify !== "function") {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!("off" in value) || typeof value.off !== "function") {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!("subscribe" in value) || typeof value.subscribe !== "function") {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!("value" in value)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return true;
|
|
65
|
+
}
|
package/src/util/ssr.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { allTasks } from "nanostores";
|
|
2
|
+
import type { FetcherStore } from "@nanostores/query";
|
|
3
|
+
|
|
4
|
+
let stores: FetcherStore[] = [];
|
|
5
|
+
|
|
6
|
+
export const SSR_ENABLED = false;
|
|
7
|
+
|
|
8
|
+
export function getStores() {
|
|
9
|
+
return stores;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function addStore(store: FetcherStore) {
|
|
13
|
+
stores.push(store);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function cleanStores() {
|
|
17
|
+
stores = [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Client side
|
|
21
|
+
declare global {
|
|
22
|
+
interface Window {
|
|
23
|
+
__FRAGNO_INITIAL_DATA__?: [string, unknown][];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let clientInitialData: Map<string, unknown> | undefined;
|
|
28
|
+
|
|
29
|
+
export function hydrateFromWindow() {
|
|
30
|
+
if (typeof window !== "undefined" && window.__FRAGNO_INITIAL_DATA__) {
|
|
31
|
+
clientInitialData = new Map(window.__FRAGNO_INITIAL_DATA__);
|
|
32
|
+
delete window.__FRAGNO_INITIAL_DATA__;
|
|
33
|
+
console.warn("hydrateFromWindow", {
|
|
34
|
+
clientInitialData: Array.from(clientInitialData.entries()),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getInitialData(key: string): unknown | undefined {
|
|
40
|
+
if (clientInitialData?.has(key)) {
|
|
41
|
+
const data = clientInitialData.get(key);
|
|
42
|
+
clientInitialData.delete(key);
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function listenToStores(): void {
|
|
49
|
+
for (const store of getStores()) {
|
|
50
|
+
// By calling `listen`, we trigger the fetcher function of the store.
|
|
51
|
+
// This will start the data fetching process on the server.
|
|
52
|
+
// We don't need to do anything with the return value of `listen`, as we
|
|
53
|
+
// are only interested in starting the data fetching.
|
|
54
|
+
store.listen(() => {});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Server side
|
|
59
|
+
export async function getFinalStoreValues(): Promise<Map<string, unknown>> {
|
|
60
|
+
listenToStores();
|
|
61
|
+
await allTasks();
|
|
62
|
+
|
|
63
|
+
const stores = getStores();
|
|
64
|
+
const storesInitialValue = new Map<string, unknown>();
|
|
65
|
+
|
|
66
|
+
for (const store of stores) {
|
|
67
|
+
const value = store.get();
|
|
68
|
+
if (!value || !store.key || value.loading) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
storesInitialValue.set(store.key, value.data);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return storesInitialValue;
|
|
75
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
+
|
|
3
|
+
export type InferOr<T, U> =
|
|
4
|
+
T extends NonNullable<StandardSchemaV1>
|
|
5
|
+
? StandardSchemaV1.InferOutput<T>
|
|
6
|
+
: T extends undefined
|
|
7
|
+
? U
|
|
8
|
+
: U;
|
|
9
|
+
|
|
10
|
+
export type InferOrUnknown<T> = InferOr<T, unknown>;
|
|
11
|
+
|
|
12
|
+
export type Prettify<T> = {
|
|
13
|
+
[K in keyof T]: T[K];
|
|
14
|
+
} & {};
|
|
15
|
+
|
|
16
|
+
export type EmptyObject = Record<never, never>;
|
package/tsconfig.json
ADDED
package/tsdown.config.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineConfig } from "tsdown";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: [
|
|
5
|
+
"./src/mod.ts",
|
|
6
|
+
"./src/api/api.ts",
|
|
7
|
+
"./src/client/client.ts",
|
|
8
|
+
"./src/client/vanilla.ts",
|
|
9
|
+
"./src/client/client.svelte.ts",
|
|
10
|
+
"./src/client/react.ts",
|
|
11
|
+
"./src/client/vue.ts",
|
|
12
|
+
"./src/integrations/astro.ts",
|
|
13
|
+
"./src/integrations/next-js.ts",
|
|
14
|
+
"./src/integrations/react-ssr.ts",
|
|
15
|
+
"./src/integrations/svelte-kit.ts",
|
|
16
|
+
],
|
|
17
|
+
dts: true,
|
|
18
|
+
// TODO: This should be true, but we need some additional type exports in chatno/src/index.ts
|
|
19
|
+
// to make it work.
|
|
20
|
+
unbundle: false,
|
|
21
|
+
});
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
|
3
|
+
import { svelteTesting } from "@testing-library/svelte/vite";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [svelte(), svelteTesting()],
|
|
7
|
+
test: {
|
|
8
|
+
environment: "happy-dom",
|
|
9
|
+
},
|
|
10
|
+
});
|