@primate/core 0.6.2 → 0.7.0
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/lib/private/App.d.ts +76 -149
- package/lib/private/App.js +22 -6
- package/lib/private/Flags.d.ts +5 -3
- package/lib/private/Flags.js +4 -2
- package/lib/private/app/Facade.d.ts +77 -156
- package/lib/private/app/Facade.js +4 -1
- package/lib/private/build/App.d.ts +4 -2
- package/lib/private/build/App.js +13 -4
- package/lib/private/build/client/index.js +24 -10
- package/lib/private/build/client/plugin/routes.d.ts +4 -0
- package/lib/private/build/client/plugin/routes.js +74 -0
- package/lib/private/build/hook.js +14 -6
- package/lib/private/build/index.d.ts +3 -2
- package/lib/private/build/index.js +9 -15
- package/lib/private/build/preclient/index.d.ts +3 -0
- package/lib/private/build/preclient/index.js +69 -0
- package/lib/private/build/preclient/plugin/routes.d.ts +4 -0
- package/lib/private/build/preclient/plugin/routes.js +44 -0
- package/lib/private/build/server/index.js +8 -5
- package/lib/private/build/server/plugin/assets.js +3 -3
- package/lib/private/build/server/plugin/native-addons.js +6 -8
- package/lib/private/build/server/plugin/node-imports.js +5 -7
- package/lib/private/build/server/plugin/route-client.d.ts +4 -0
- package/lib/private/build/server/plugin/route-client.js +110 -0
- package/lib/private/build/server/plugin/route.js +3 -10
- package/lib/private/build/server/plugin/virtual-pages.js +3 -3
- package/lib/private/build/server/plugin/virtual-routes.d.ts +2 -1
- package/lib/private/build/server/plugin/virtual-routes.js +27 -8
- package/lib/private/build/server/plugin/wasm.js +3 -2
- package/lib/private/client/Data.d.ts +1 -1
- package/lib/private/client/boot.js +2 -2
- package/lib/private/client/create-form.d.ts +11 -1
- package/lib/private/client/create-form.js +21 -3
- package/lib/private/client/index.d.ts +2 -2
- package/lib/private/client/navigate.d.ts +1 -0
- package/lib/private/client/navigate.js +7 -6
- package/lib/private/client/submit.d.ts +2 -1
- package/lib/private/client/submit.js +8 -7
- package/lib/private/client/{http.d.ts → transport.d.ts} +3 -3
- package/lib/private/client/{http.js → transport.js} +7 -9
- package/lib/private/config/schema.d.ts +5 -13
- package/lib/private/config/schema.js +1 -5
- package/lib/private/db/DB.d.ts +3 -1
- package/lib/private/db/MemoryDB.d.ts +5 -2
- package/lib/private/db/MemoryDB.js +33 -19
- package/lib/private/db/SQLDB.d.ts +23 -0
- package/lib/private/db/SQLDB.js +2 -0
- package/lib/private/db/errors.d.ts +74 -7
- package/lib/private/db/errors.js +31 -7
- package/lib/private/db/migrate/apply.js +8 -9
- package/lib/private/db/migrate/bundle.js +3 -2
- package/lib/private/db/migrate/create.js +18 -20
- package/lib/private/db/migrate/status.js +9 -10
- package/lib/private/db/migrate/store.d.ts +3 -3
- package/lib/private/db/migrate/store.js +5 -5
- package/lib/private/db/test.js +256 -115
- package/lib/private/db/testSQL.d.ts +50 -0
- package/lib/private/db/testSQL.js +196 -0
- package/lib/private/errors.d.ts +66 -9
- package/lib/private/errors.js +37 -16
- package/lib/private/frontend.d.ts +4 -4
- package/lib/private/frontend.js +11 -8
- package/lib/private/i18n/errors.d.ts +7 -1
- package/lib/private/i18n/errors.js +1 -1
- package/lib/private/i18n/index/types.d.ts +1 -1
- package/lib/private/i18n/locale.d.ts +1 -1
- package/lib/private/i18n/module.js +6 -5
- package/lib/private/index.d.ts +10 -2
- package/lib/private/index.js +13 -1
- package/lib/private/logger.d.ts +24 -0
- package/lib/private/logger.js +66 -0
- package/lib/private/module/Setup.d.ts +3 -0
- package/lib/private/module/create.d.ts +2 -1
- package/lib/private/module/create.js +4 -0
- package/lib/private/paths.d.ts +2 -3
- package/lib/private/paths.js +6 -12
- package/lib/private/request/ContentType.d.ts +3 -0
- package/lib/private/request/ContentType.js +2 -0
- package/lib/private/request/RequestBag.d.ts +2 -18
- package/lib/private/request/RequestBag.js +4 -16
- package/lib/private/request/RequestBody.d.ts +20 -28
- package/lib/private/request/RequestBody.js +63 -86
- package/lib/private/request/RequestFacade.d.ts +2 -2
- package/lib/private/request/handle.js +2 -2
- package/lib/private/request/parse.js +2 -4
- package/lib/private/request/route.js +15 -8
- package/lib/private/response/binary.d.ts +2 -2
- package/lib/private/response/binary.js +6 -6
- package/lib/private/response/error.js +6 -2
- package/lib/private/response/json.js +2 -2
- package/lib/private/response/null.d.ts +3 -0
- package/lib/private/response/null.js +6 -0
- package/lib/private/response/redirect.js +4 -3
- package/lib/private/response/respond.js +4 -4
- package/lib/private/response/sse.js +2 -2
- package/lib/private/response/text.js +2 -2
- package/lib/private/route/ContentTypeMap.d.ts +10 -0
- package/lib/private/route/ContentTypeMap.js +2 -0
- package/lib/private/route/Handler.d.ts +3 -2
- package/lib/private/route/NarrowedRequest.d.ts +23 -0
- package/lib/private/route/NarrowedRequest.js +2 -0
- package/lib/private/route/Options.d.ts +6 -1
- package/lib/private/route/Path.d.ts +2 -2
- package/lib/private/route/hook.d.ts +3 -1
- package/lib/private/route/hook.js +1 -2
- package/lib/private/route/router.d.ts +7 -11
- package/lib/private/route/router.js +13 -20
- package/lib/private/route.client.d.ts +36 -0
- package/lib/private/route.client.js +8 -0
- package/lib/private/route.d.ts +21 -5
- package/lib/private/route.js +21 -5
- package/lib/private/serve/App.d.ts +1 -2
- package/lib/private/serve/App.js +64 -58
- package/lib/private/serve/Init.d.ts +2 -0
- package/lib/private/serve/dev-module.js +2 -3
- package/lib/private/serve/index.js +5 -6
- package/lib/private/server/TAG.d.ts +1 -1
- package/lib/private/server/TAG.js +1 -1
- package/lib/private/session/index.d.ts +1 -1
- package/lib/private/session/index.js +3 -2
- package/lib/private/session/module.js +3 -3
- package/lib/private/session/schema.d.ts +3 -3
- package/lib/private/session/schema.js +4 -3
- package/lib/private/store/ExtractRelation.d.ts +7 -0
- package/lib/private/store/ExtractRelation.js +2 -0
- package/lib/private/store/ExtractSchema.d.ts +10 -0
- package/lib/private/{orm → store}/ForeignKey.d.ts +1 -1
- package/lib/private/store/Init.d.ts +13 -0
- package/lib/private/store/Init.js +2 -0
- package/lib/private/{orm/store.d.ts → store/Store.d.ts} +50 -50
- package/lib/private/{orm/store.js → store/Store.js} +163 -107
- package/lib/private/store/StoreInput.d.ts +11 -0
- package/lib/private/store/key.d.ts +8 -0
- package/lib/private/store/key.js +8 -0
- package/lib/private/{orm → store}/parse.d.ts +3 -3
- package/lib/private/{orm → store}/parse.js +7 -2
- package/lib/private/store/relation.d.ts +29 -0
- package/lib/private/store/relation.js +26 -0
- package/lib/private/store.d.ts +24 -0
- package/lib/private/store.js +10 -0
- package/lib/public/db/errors.d.ts +1 -1
- package/lib/public/db/errors.js +1 -1
- package/lib/public/db/testSQL.d.ts +2 -0
- package/lib/public/db/testSQL.js +2 -0
- package/lib/public/db.d.ts +1 -0
- package/lib/public/index.d.ts +1 -0
- package/lib/public/index.js +1 -1
- package/lib/public/response.d.ts +6 -6
- package/lib/public/response.js +4 -1
- package/lib/public/route.client.d.ts +2 -0
- package/lib/public/route.client.js +2 -0
- package/lib/public/store.d.ts +2 -0
- package/lib/public/store.js +2 -0
- package/package.json +24 -17
- package/lib/private/bye.d.ts +0 -3
- package/lib/private/bye.js +0 -4
- package/lib/private/log.d.ts +0 -20
- package/lib/private/log.js +0 -47
- package/lib/private/orm/ExtractSchema.d.ts +0 -9
- package/lib/private/orm/StoreInput.d.ts +0 -10
- package/lib/private/orm/key.d.ts +0 -8
- package/lib/private/orm/key.js +0 -8
- package/lib/private/orm/relation.d.ts +0 -43
- package/lib/private/orm/relation.js +0 -26
- package/lib/private/request/Verb.d.ts +0 -4
- package/lib/private/request/Verb.js +0 -2
- package/lib/private/request/verbs.d.ts +0 -3
- package/lib/private/request/verbs.js +0 -12
- package/lib/private/route/wrap.d.ts +0 -2
- package/lib/private/route/wrap.js +0 -12
- package/lib/public/log.d.ts +0 -2
- package/lib/public/log.js +0 -2
- package/lib/public/orm/key.d.ts +0 -2
- package/lib/public/orm/key.js +0 -2
- package/lib/public/orm/relation.d.ts +0 -2
- package/lib/public/orm/relation.js +0 -2
- package/lib/public/orm/store.d.ts +0 -2
- package/lib/public/orm/store.js +0 -2
- package/lib/public/request/verbs.d.ts +0 -2
- package/lib/public/request/verbs.js +0 -2
- /package/lib/private/{orm → store}/ExtractSchema.js +0 -0
- /package/lib/private/{orm → store}/ForeignKey.js +0 -0
- /package/lib/private/{orm → store}/PrimaryKey.d.ts +0 -0
- /package/lib/private/{orm → store}/PrimaryKey.js +0 -0
- /package/lib/private/{orm → store}/StoreInput.js +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type SQLDB from "#db/SQLDB";
|
|
2
|
+
import test from "@rcompat/test";
|
|
3
|
+
declare const users: {
|
|
4
|
+
table: string;
|
|
5
|
+
pk: string;
|
|
6
|
+
types: {
|
|
7
|
+
id: "u32";
|
|
8
|
+
name: "string";
|
|
9
|
+
age: "u8";
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
declare const posts: {
|
|
13
|
+
table: string;
|
|
14
|
+
pk: string;
|
|
15
|
+
types: {
|
|
16
|
+
id: "u32";
|
|
17
|
+
user_id: "u32";
|
|
18
|
+
title: "string";
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
declare const transactions: {
|
|
22
|
+
table: string;
|
|
23
|
+
pk: string;
|
|
24
|
+
types: {
|
|
25
|
+
id: "u64";
|
|
26
|
+
amount: "u128";
|
|
27
|
+
memo: "string";
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
declare const json: {
|
|
31
|
+
table: string;
|
|
32
|
+
pk: string;
|
|
33
|
+
types: {
|
|
34
|
+
readonly id: "string";
|
|
35
|
+
readonly data: "json";
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
type Setup = {
|
|
39
|
+
$: (body: () => Promise<void>) => Promise<void>;
|
|
40
|
+
users: typeof users;
|
|
41
|
+
posts: typeof posts;
|
|
42
|
+
transactions: typeof transactions;
|
|
43
|
+
json: typeof json;
|
|
44
|
+
test: typeof test;
|
|
45
|
+
query_equals: (name: string, work: Work, expected: string) => void;
|
|
46
|
+
};
|
|
47
|
+
type Work = () => Promise<unknown>;
|
|
48
|
+
export default function testSQL(db: SQLDB, cb: (setup: Setup) => void): void;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=testSQL.d.ts.map
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { Code } from "#db/errors";
|
|
2
|
+
import test from "@rcompat/test";
|
|
3
|
+
import p from "pema";
|
|
4
|
+
const dt = {
|
|
5
|
+
u8: p.u8.datatype,
|
|
6
|
+
u32: p.u32.datatype,
|
|
7
|
+
u64: p.u64.datatype,
|
|
8
|
+
u128: p.u128.datatype,
|
|
9
|
+
string: p.string.datatype,
|
|
10
|
+
};
|
|
11
|
+
const users = {
|
|
12
|
+
table: "users",
|
|
13
|
+
pk: "id",
|
|
14
|
+
types: { id: dt.u32, name: dt.string, age: dt.u8 },
|
|
15
|
+
};
|
|
16
|
+
const posts = {
|
|
17
|
+
table: "posts",
|
|
18
|
+
pk: "id",
|
|
19
|
+
types: {
|
|
20
|
+
id: dt.u32, user_id: dt.u32, title: dt.string,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const transactions = {
|
|
24
|
+
table: "transactions",
|
|
25
|
+
pk: "id",
|
|
26
|
+
types: {
|
|
27
|
+
id: dt.u64, amount: dt.u128, memo: dt.string,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const json = {
|
|
31
|
+
table: "json",
|
|
32
|
+
pk: "id",
|
|
33
|
+
types: { id: dt.string, data: "json" },
|
|
34
|
+
};
|
|
35
|
+
const pk_config = { name: "id", generate: true };
|
|
36
|
+
function normalize(sql) {
|
|
37
|
+
return sql.replace(/\s+/g, " ").trim();
|
|
38
|
+
}
|
|
39
|
+
export default function testSQL(db, cb) {
|
|
40
|
+
async function $(body) {
|
|
41
|
+
await db.schema.create("users", pk_config, users.types);
|
|
42
|
+
await db.schema.create("posts", pk_config, posts.types);
|
|
43
|
+
await db.schema.create("transactions", pk_config, transactions.types);
|
|
44
|
+
await db.schema.create("json", pk_config, json.types);
|
|
45
|
+
await body();
|
|
46
|
+
await db.schema.delete("users");
|
|
47
|
+
await db.schema.delete("posts");
|
|
48
|
+
await db.schema.delete("transactions");
|
|
49
|
+
await db.schema.delete("json");
|
|
50
|
+
}
|
|
51
|
+
function query_equals(name, work, expected) {
|
|
52
|
+
test.case(name, async (assert) => {
|
|
53
|
+
await $(async () => {
|
|
54
|
+
await work();
|
|
55
|
+
assert(normalize(db.explain.users.query)).equals(normalize(expected));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
cb({
|
|
60
|
+
$,
|
|
61
|
+
users,
|
|
62
|
+
posts,
|
|
63
|
+
transactions,
|
|
64
|
+
json,
|
|
65
|
+
test,
|
|
66
|
+
query_equals,
|
|
67
|
+
});
|
|
68
|
+
test.ended(() => db.close());
|
|
69
|
+
test.group("sql", () => {
|
|
70
|
+
test.case("select with input and output", async (assert) => {
|
|
71
|
+
await $(async () => {
|
|
72
|
+
await db.create(users, { id: 1, name: "alice", age: 30 });
|
|
73
|
+
await db.create(users, { id: 2, name: "bob", age: 25 });
|
|
74
|
+
const findByAge = db.sql({
|
|
75
|
+
input: p({ age: p.u8 }),
|
|
76
|
+
query: "SELECT name FROM users WHERE age > :age",
|
|
77
|
+
output: p.array(p({ name: p.string })),
|
|
78
|
+
});
|
|
79
|
+
const results = await findByAge({ age: 24 });
|
|
80
|
+
assert(results.length).equals(2);
|
|
81
|
+
assert(results[0].name).equals("alice");
|
|
82
|
+
assert(results[1].name).equals("bob");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
test.case("select with no input", async (assert) => {
|
|
86
|
+
await $(async () => {
|
|
87
|
+
await db.create(users, { id: 1, name: "alice", age: 30 });
|
|
88
|
+
await db.create(users, { id: 2, name: "bob", age: 25 });
|
|
89
|
+
const findAll = db.sql({
|
|
90
|
+
query: "SELECT name FROM users",
|
|
91
|
+
output: p.array(p({ name: p.string })),
|
|
92
|
+
});
|
|
93
|
+
const results = await findAll();
|
|
94
|
+
assert(results.length).equals(2);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
test.case("insert with no output", async (assert) => {
|
|
98
|
+
await $(async () => {
|
|
99
|
+
const insert = db.sql({
|
|
100
|
+
input: p({ name: p.string, age: p.u8 }),
|
|
101
|
+
query: "INSERT INTO users (name, age) VALUES (:name, :age)",
|
|
102
|
+
});
|
|
103
|
+
await insert({ name: "charlie", age: 20 });
|
|
104
|
+
const rows = await db.read(users, { where: { name: "charlie" } });
|
|
105
|
+
assert(rows.length).equals(1);
|
|
106
|
+
assert(rows[0].name).equals("charlie");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
test.case("update with no output", async (assert) => {
|
|
110
|
+
await $(async () => {
|
|
111
|
+
await db.create(users, { id: 1, name: "alice", age: 30 });
|
|
112
|
+
const updateAge = db.sql({
|
|
113
|
+
input: p({ age: p.u8, name: p.string }),
|
|
114
|
+
query: "UPDATE users SET age = :age WHERE name = :name",
|
|
115
|
+
});
|
|
116
|
+
await updateAge({ age: 31, name: "alice" });
|
|
117
|
+
const rows = await db.read(users, { where: { name: "alice" } });
|
|
118
|
+
assert(rows[0].age).equals(31);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
test.case("delete with no output", async (assert) => {
|
|
122
|
+
await $(async () => {
|
|
123
|
+
await db.create(users, { id: 1, name: "alice", age: 30 });
|
|
124
|
+
const deleteByName = db.sql({
|
|
125
|
+
input: p({ name: p.string }),
|
|
126
|
+
query: "DELETE FROM users WHERE name = :name",
|
|
127
|
+
});
|
|
128
|
+
await deleteByName({ name: "alice" });
|
|
129
|
+
const rows = await db.read(users, { where: {} });
|
|
130
|
+
assert(rows.length).equals(0);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
test.case("input validation fails", async (assert) => {
|
|
134
|
+
await $(async () => {
|
|
135
|
+
const findByAge = db.sql({
|
|
136
|
+
input: p({ age: p.u8 }),
|
|
137
|
+
query: "SELECT name FROM users WHERE age > :age",
|
|
138
|
+
output: p.array(p({ name: p.string })),
|
|
139
|
+
});
|
|
140
|
+
try {
|
|
141
|
+
await findByAge({ age: -1 });
|
|
142
|
+
assert(false).true();
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
assert(true).true();
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
test.case("empty result", async (assert) => {
|
|
150
|
+
await $(async () => {
|
|
151
|
+
const findByAge = db.sql({
|
|
152
|
+
input: p({ age: p.u8 }),
|
|
153
|
+
query: "SELECT name FROM users WHERE age > :age",
|
|
154
|
+
output: p.array(p({ name: p.string })),
|
|
155
|
+
});
|
|
156
|
+
const results = await findByAge({ age: 100 });
|
|
157
|
+
assert(results.length).equals(0);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
test.case("placeholder in input but not in query", async (assert) => {
|
|
161
|
+
await $(async () => {
|
|
162
|
+
assert(() => db.sql({
|
|
163
|
+
// @ts-expect-error 'name' in put but missing in query
|
|
164
|
+
input: p({ age: p.u8, name: p.string }),
|
|
165
|
+
query: "SELECT name FROM users WHERE age > :age",
|
|
166
|
+
})).throws(Code.sql_placeholder_missing);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
test.case("placeholder in query but not in input", async (assert) => {
|
|
170
|
+
await $(async () => {
|
|
171
|
+
assert(() => db.sql({
|
|
172
|
+
// @ts-expect-error 'name' required but missing in input
|
|
173
|
+
input: p({ age: p.u8 }),
|
|
174
|
+
query: "SELECT name FROM users WHERE age > :age AND name = :name",
|
|
175
|
+
})).throws(Code.sql_input_missing);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
test.case("output validation fails", async (assert) => {
|
|
179
|
+
await $(async () => {
|
|
180
|
+
await db.create(users, { id: 1, name: "alice", age: 30 });
|
|
181
|
+
const findAll = db.sql({
|
|
182
|
+
query: "SELECT name FROM users",
|
|
183
|
+
output: p.array(p({ name: p.u8 })),
|
|
184
|
+
});
|
|
185
|
+
try {
|
|
186
|
+
await findAll();
|
|
187
|
+
assert(false).true();
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
assert(true).true();
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=testSQL.js.map
|
package/lib/private/errors.d.ts
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
import type { FileRef } from "@rcompat/fs";
|
|
2
|
+
import type http from "@rcompat/http";
|
|
3
|
+
import type { Method } from "@rcompat/http";
|
|
2
4
|
import type ParseError from "pema/ParseError";
|
|
5
|
+
type MIME = typeof http.MIME;
|
|
6
|
+
type MIMEValue = MIME[keyof MIME];
|
|
3
7
|
declare function app_reserved_directory(directory: string): import("@rcompat/error").TemplateError;
|
|
4
8
|
declare function app_duplicate_module(name: string): import("@rcompat/error").TemplateError;
|
|
5
9
|
declare function build_missing_binary_addon(): import("@rcompat/error").TemplateError;
|
|
6
10
|
declare function build_missing_route(route: string, file: FileRef): import("@rcompat/error").TemplateError;
|
|
7
|
-
declare function build_multiple_db_drivers(drivers: string[]): import("@rcompat/error").TemplateError;
|
|
8
11
|
declare function build_live_reload_failed(filename: string, cause: Error): import("@rcompat/error").TemplateError;
|
|
9
12
|
declare function build_previous_build_exists(file: FileRef): import("@rcompat/error").TemplateError;
|
|
10
|
-
declare function
|
|
13
|
+
declare function build_no_path_schema(route: string): import("@rcompat/error").TemplateError;
|
|
14
|
+
declare function build_body_requires_content_type(): import("@rcompat/error").TemplateError;
|
|
11
15
|
declare function config_file_missing(): import("@rcompat/error").TemplateError;
|
|
12
16
|
declare function config_file_empty(file: FileRef): import("@rcompat/error").TemplateError;
|
|
13
17
|
declare function config_file_error(file: FileRef, cause: Error): import("@rcompat/error").TemplateError;
|
|
14
18
|
declare function config_missing(property: string): import("@rcompat/error").TemplateError;
|
|
19
|
+
declare function config_failed_to_parse_tsconfig(path: FileRef, cause: Error): import("@rcompat/error").TemplateError;
|
|
15
20
|
declare function frontend_missing(view: string, module?: string): import("@rcompat/error").TemplateError;
|
|
16
21
|
declare function frontend_missing_app_js(): import("@rcompat/error").TemplateError;
|
|
17
22
|
declare function request_unsupported_mime(path: string, mime: string): import("@rcompat/error").TemplateError;
|
|
18
23
|
declare function request_unparsable_mime(path: string, mime: string, cause: Error): import("@rcompat/error").TemplateError;
|
|
19
|
-
declare function
|
|
24
|
+
declare function request_body_already_parsed(): import("@rcompat/error").TemplateError;
|
|
20
25
|
declare function request_bag_missing_key(bag: string, key: string): import("@rcompat/error").TemplateError;
|
|
26
|
+
declare function request_content_type_mismatch(expected: MIMEValue, actual: string): import("@rcompat/error").TemplateError;
|
|
21
27
|
declare function response_invalid_body(body: string): import("@rcompat/error").TemplateError;
|
|
22
28
|
declare function hook_route_functions_not_allowed(file: string): import("@rcompat/error").TemplateError;
|
|
23
29
|
declare function hook_not_allowed(file: string): import("@rcompat/error").TemplateError;
|
|
@@ -28,9 +34,10 @@ declare function hook_bad_return(): import("@rcompat/error").TemplateError;
|
|
|
28
34
|
declare function session_missing_id(): import("@rcompat/error").TemplateError;
|
|
29
35
|
declare function session_id_string(): import("@rcompat/error").TemplateError;
|
|
30
36
|
declare function session_id_data(): import("@rcompat/error").TemplateError;
|
|
37
|
+
declare function session_handle_unavailable(): import("@rcompat/error").TemplateError;
|
|
31
38
|
declare function target_missing(target: string, targets: string[]): import("@rcompat/error").TemplateError;
|
|
32
39
|
declare function target_duplicate(target: string): import("@rcompat/error").TemplateError;
|
|
33
|
-
declare function
|
|
40
|
+
declare function route_missing_method(route: string, method: Method): import("@rcompat/error").TemplateError;
|
|
34
41
|
declare function route_invalid_special_file(route: string): import("@rcompat/error").TemplateError;
|
|
35
42
|
declare function route_invalid_parameter(route: string, parameter: string): import("@rcompat/error").TemplateError;
|
|
36
43
|
declare function route_invalid_characters(route: string, regexp: RegExp): import("@rcompat/error").TemplateError;
|
|
@@ -40,7 +47,9 @@ declare function view_duplicate_extension(extension: string): import("@rcompat/e
|
|
|
40
47
|
declare function view_error(view: string, cause: Error): import("@rcompat/error").TemplateError;
|
|
41
48
|
declare function env_invalid_schema(cause: ParseError): import("@rcompat/error").TemplateError;
|
|
42
49
|
declare function env_missing_key(key: string): import("@rcompat/error").TemplateError;
|
|
50
|
+
declare function openapi_no_operation_for(method: Method, path: string): import("@rcompat/error").TemplateError;
|
|
43
51
|
declare const errors: {
|
|
52
|
+
openapi_no_operation_for: typeof openapi_no_operation_for;
|
|
44
53
|
env_invalid_schema: typeof env_invalid_schema;
|
|
45
54
|
env_missing_key: typeof env_missing_key;
|
|
46
55
|
view_missing: typeof view_missing;
|
|
@@ -52,6 +61,7 @@ declare const errors: {
|
|
|
52
61
|
session_missing_id: typeof session_missing_id;
|
|
53
62
|
session_id_string: typeof session_id_string;
|
|
54
63
|
session_id_data: typeof session_id_data;
|
|
64
|
+
session_handle_unavailable: typeof session_handle_unavailable;
|
|
55
65
|
hook_route_functions_not_allowed: typeof hook_route_functions_not_allowed;
|
|
56
66
|
hook_not_allowed: typeof hook_not_allowed;
|
|
57
67
|
hook_unused: typeof hook_unused;
|
|
@@ -61,9 +71,10 @@ declare const errors: {
|
|
|
61
71
|
response_invalid_body: typeof response_invalid_body;
|
|
62
72
|
request_unsupported_mime: typeof request_unsupported_mime;
|
|
63
73
|
request_unparsable_mime: typeof request_unparsable_mime;
|
|
64
|
-
|
|
74
|
+
request_body_already_parsed: typeof request_body_already_parsed;
|
|
65
75
|
request_bag_missing_key: typeof request_bag_missing_key;
|
|
66
|
-
|
|
76
|
+
request_content_type_mismatch: typeof request_content_type_mismatch;
|
|
77
|
+
route_missing_method: typeof route_missing_method;
|
|
67
78
|
route_invalid_special_file: typeof route_invalid_special_file;
|
|
68
79
|
route_invalid_parameter: typeof route_invalid_parameter;
|
|
69
80
|
route_invalid_characters: typeof route_invalid_characters;
|
|
@@ -71,18 +82,64 @@ declare const errors: {
|
|
|
71
82
|
frontend_missing_app_js: typeof frontend_missing_app_js;
|
|
72
83
|
config_file_missing: typeof config_file_missing;
|
|
73
84
|
config_missing: typeof config_missing;
|
|
74
|
-
config_tsconfig_has_paths: typeof config_tsconfig_has_paths;
|
|
75
85
|
config_file_empty: typeof config_file_empty;
|
|
76
86
|
config_file_error: typeof config_file_error;
|
|
87
|
+
config_failed_to_parse_tsconfig: typeof config_failed_to_parse_tsconfig;
|
|
77
88
|
build_missing_binary_addon: typeof build_missing_binary_addon;
|
|
78
89
|
build_missing_route: typeof build_missing_route;
|
|
79
|
-
build_multiple_db_drivers: typeof build_multiple_db_drivers;
|
|
80
90
|
build_live_reload_failed: typeof build_live_reload_failed;
|
|
81
91
|
build_previous_build_exists: typeof build_previous_build_exists;
|
|
92
|
+
build_no_path_schema: typeof build_no_path_schema;
|
|
93
|
+
build_body_requires_content_type: typeof build_body_requires_content_type;
|
|
82
94
|
app_reserved_directory: typeof app_reserved_directory;
|
|
83
95
|
app_duplicate_module: typeof app_duplicate_module;
|
|
84
96
|
};
|
|
97
|
+
export declare const Code: {
|
|
98
|
+
openapi_no_operation_for: "openapi_no_operation_for";
|
|
99
|
+
env_invalid_schema: "env_invalid_schema";
|
|
100
|
+
env_missing_key: "env_missing_key";
|
|
101
|
+
view_missing: "view_missing";
|
|
102
|
+
view_missing_default_export: "view_missing_default_export";
|
|
103
|
+
view_duplicate_extension: "view_duplicate_extension";
|
|
104
|
+
view_error: "view_error";
|
|
105
|
+
target_missing: "target_missing";
|
|
106
|
+
target_duplicate: "target_duplicate";
|
|
107
|
+
session_missing_id: "session_missing_id";
|
|
108
|
+
session_id_string: "session_id_string";
|
|
109
|
+
session_id_data: "session_id_data";
|
|
110
|
+
session_handle_unavailable: "session_handle_unavailable";
|
|
111
|
+
hook_route_functions_not_allowed: "hook_route_functions_not_allowed";
|
|
112
|
+
hook_not_allowed: "hook_not_allowed";
|
|
113
|
+
hook_unused: "hook_unused";
|
|
114
|
+
hook_reused_next: "hook_reused_next";
|
|
115
|
+
hook_no_return: "hook_no_return";
|
|
116
|
+
hook_bad_return: "hook_bad_return";
|
|
117
|
+
response_invalid_body: "response_invalid_body";
|
|
118
|
+
request_unsupported_mime: "request_unsupported_mime";
|
|
119
|
+
request_unparsable_mime: "request_unparsable_mime";
|
|
120
|
+
request_body_already_parsed: "request_body_already_parsed";
|
|
121
|
+
request_bag_missing_key: "request_bag_missing_key";
|
|
122
|
+
request_content_type_mismatch: "request_content_type_mismatch";
|
|
123
|
+
route_missing_method: "route_missing_method";
|
|
124
|
+
route_invalid_special_file: "route_invalid_special_file";
|
|
125
|
+
route_invalid_parameter: "route_invalid_parameter";
|
|
126
|
+
route_invalid_characters: "route_invalid_characters";
|
|
127
|
+
frontend_missing: "frontend_missing";
|
|
128
|
+
frontend_missing_app_js: "frontend_missing_app_js";
|
|
129
|
+
config_file_missing: "config_file_missing";
|
|
130
|
+
config_missing: "config_missing";
|
|
131
|
+
config_file_empty: "config_file_empty";
|
|
132
|
+
config_file_error: "config_file_error";
|
|
133
|
+
config_failed_to_parse_tsconfig: "config_failed_to_parse_tsconfig";
|
|
134
|
+
build_missing_binary_addon: "build_missing_binary_addon";
|
|
135
|
+
build_missing_route: "build_missing_route";
|
|
136
|
+
build_live_reload_failed: "build_live_reload_failed";
|
|
137
|
+
build_previous_build_exists: "build_previous_build_exists";
|
|
138
|
+
build_no_path_schema: "build_no_path_schema";
|
|
139
|
+
build_body_requires_content_type: "build_body_requires_content_type";
|
|
140
|
+
app_reserved_directory: "app_reserved_directory";
|
|
141
|
+
app_duplicate_module: "app_duplicate_module";
|
|
142
|
+
};
|
|
85
143
|
export type Code = keyof typeof errors;
|
|
86
|
-
export declare const Code: { [K in Code]: K; };
|
|
87
144
|
export default errors;
|
|
88
145
|
//# sourceMappingURL=errors.d.ts.map
|
package/lib/private/errors.js
CHANGED
|
@@ -16,26 +16,29 @@ function build_missing_binary_addon() {
|
|
|
16
16
|
function build_missing_route(route, file) {
|
|
17
17
|
return t `cannot find route source for ${route} under ${file.path}`;
|
|
18
18
|
}
|
|
19
|
-
function build_multiple_db_drivers(drivers) {
|
|
20
|
-
const defaults = ["index.ts", "index.js", "default.ts", "default.js"];
|
|
21
|
-
return t `multiple database drivers ${drivers}, add one of ${defaults}`;
|
|
22
|
-
}
|
|
23
19
|
function build_live_reload_failed(filename, cause) {
|
|
24
20
|
return t `failed to live-reload ${filename}: ${cause}`;
|
|
25
21
|
}
|
|
26
22
|
function build_previous_build_exists(file) {
|
|
27
23
|
return t `${file.path} exists but does not contain a previous build`;
|
|
28
24
|
}
|
|
25
|
+
function build_no_path_schema(route) {
|
|
26
|
+
const example = "route.with({ path: ... })";
|
|
27
|
+
return t `route ${route} has dynamic segments but no path schema — declare a path schema in ${example} to use this route from a client`;
|
|
28
|
+
}
|
|
29
|
+
function build_body_requires_content_type() {
|
|
30
|
+
const b = "contentType";
|
|
31
|
+
const c = "route.with({ contentType: ..., body: ... })";
|
|
32
|
+
return t `body schema requires ${b} to be set — declare a contentType in ${c}`;
|
|
33
|
+
}
|
|
29
34
|
const BUILD = error.coded({
|
|
30
35
|
build_missing_binary_addon,
|
|
31
36
|
build_missing_route,
|
|
32
|
-
build_multiple_db_drivers,
|
|
33
37
|
build_live_reload_failed,
|
|
34
38
|
build_previous_build_exists,
|
|
39
|
+
build_no_path_schema,
|
|
40
|
+
build_body_requires_content_type,
|
|
35
41
|
});
|
|
36
|
-
function config_tsconfig_has_paths() {
|
|
37
|
-
return t `tsconfig.json exists with paths, remove config paths`;
|
|
38
|
-
}
|
|
39
42
|
function config_file_missing() {
|
|
40
43
|
return t `missing ${"config/app.ts"}`;
|
|
41
44
|
}
|
|
@@ -48,12 +51,15 @@ function config_file_error(file, cause) {
|
|
|
48
51
|
function config_missing(property) {
|
|
49
52
|
return t `${property} not configured`;
|
|
50
53
|
}
|
|
54
|
+
function config_failed_to_parse_tsconfig(path, cause) {
|
|
55
|
+
return t `failed to parse tsconfig at ${path}: ${cause}`;
|
|
56
|
+
}
|
|
51
57
|
const CONFIG = error.coded({
|
|
52
58
|
config_file_missing,
|
|
53
59
|
config_missing,
|
|
54
|
-
config_tsconfig_has_paths,
|
|
55
60
|
config_file_empty,
|
|
56
61
|
config_file_error,
|
|
62
|
+
config_failed_to_parse_tsconfig,
|
|
57
63
|
});
|
|
58
64
|
function frontend_missing(view, module) {
|
|
59
65
|
if (module === undefined)
|
|
@@ -74,17 +80,21 @@ function request_unsupported_mime(path, mime) {
|
|
|
74
80
|
function request_unparsable_mime(path, mime, cause) {
|
|
75
81
|
return t `${path}: unparsable MIME type ${mime} (${cause})`;
|
|
76
82
|
}
|
|
77
|
-
function
|
|
78
|
-
return t `
|
|
83
|
+
function request_body_already_parsed() {
|
|
84
|
+
return t `body is already parsed`;
|
|
79
85
|
}
|
|
80
86
|
function request_bag_missing_key(bag, key) {
|
|
81
87
|
return t `${bag} has no key ${key}`;
|
|
82
88
|
}
|
|
89
|
+
function request_content_type_mismatch(expected, actual) {
|
|
90
|
+
return t `content-type mismatch: expected ${expected}, got ${actual}`;
|
|
91
|
+
}
|
|
83
92
|
const REQUEST = error.coded({
|
|
84
93
|
request_unsupported_mime,
|
|
85
94
|
request_unparsable_mime,
|
|
86
|
-
|
|
95
|
+
request_body_already_parsed,
|
|
87
96
|
request_bag_missing_key,
|
|
97
|
+
request_content_type_mismatch,
|
|
88
98
|
});
|
|
89
99
|
function response_invalid_body(body) {
|
|
90
100
|
return t `invalid body ${body} returned from route`;
|
|
@@ -128,10 +138,14 @@ function session_id_string() {
|
|
|
128
138
|
function session_id_data() {
|
|
129
139
|
return t `"both ${"id"} and ${"data"} must be defined or undefined`;
|
|
130
140
|
}
|
|
141
|
+
function session_handle_unavailable() {
|
|
142
|
+
return t `session handle not available in this context`;
|
|
143
|
+
}
|
|
131
144
|
const SESSION = error.coded({
|
|
132
145
|
session_missing_id,
|
|
133
146
|
session_id_string,
|
|
134
147
|
session_id_data,
|
|
148
|
+
session_handle_unavailable,
|
|
135
149
|
});
|
|
136
150
|
function target_missing(target, targets) {
|
|
137
151
|
return t `no target ${target}, available targets ${targets}`;
|
|
@@ -143,8 +157,8 @@ const TARGET = error.coded({
|
|
|
143
157
|
target_missing,
|
|
144
158
|
target_duplicate,
|
|
145
159
|
});
|
|
146
|
-
function
|
|
147
|
-
return t `${route} has no
|
|
160
|
+
function route_missing_method(route, method) {
|
|
161
|
+
return t `${route} has no method ${method}`;
|
|
148
162
|
}
|
|
149
163
|
function route_invalid_special_file(route) {
|
|
150
164
|
return t `${route} is not a valid special file`;
|
|
@@ -156,7 +170,7 @@ function route_invalid_characters(route, regexp) {
|
|
|
156
170
|
return t `${route} may only contain any of ${regexp.source.slice(1, -1)}`;
|
|
157
171
|
}
|
|
158
172
|
const ROUTE = error.coded({
|
|
159
|
-
|
|
173
|
+
route_missing_method,
|
|
160
174
|
route_invalid_special_file,
|
|
161
175
|
route_invalid_parameter,
|
|
162
176
|
route_invalid_characters,
|
|
@@ -192,6 +206,12 @@ const ENV = error.coded({
|
|
|
192
206
|
env_invalid_schema,
|
|
193
207
|
env_missing_key,
|
|
194
208
|
});
|
|
209
|
+
function openapi_no_operation_for(method, path) {
|
|
210
|
+
return t `no operation for ${path} (${method}`;
|
|
211
|
+
}
|
|
212
|
+
const OPENAPI = error.coded({
|
|
213
|
+
openapi_no_operation_for,
|
|
214
|
+
});
|
|
195
215
|
const errors = {
|
|
196
216
|
...APP,
|
|
197
217
|
...BUILD,
|
|
@@ -205,7 +225,8 @@ const errors = {
|
|
|
205
225
|
...TARGET,
|
|
206
226
|
...VIEW,
|
|
207
227
|
...ENV,
|
|
228
|
+
...OPENAPI,
|
|
208
229
|
};
|
|
209
|
-
export const Code =
|
|
230
|
+
export const Code = error.names(errors);
|
|
210
231
|
export default errors;
|
|
211
232
|
//# sourceMappingURL=errors.js.map
|
|
@@ -12,11 +12,11 @@ import type { ObjectType } from "pema";
|
|
|
12
12
|
export type { Module };
|
|
13
13
|
declare const base_schema: ObjectType<import("pema").NormalizeSchemaObject<{
|
|
14
14
|
readonly extensions: import("pema").OptionalType<import("pema").ArrayType<import("pema").StringType>>;
|
|
15
|
-
readonly
|
|
15
|
+
readonly csr: import("pema").DefaultType<import("pema").BooleanType, true>;
|
|
16
16
|
readonly ssr: import("pema").DefaultType<import("pema").BooleanType, true>;
|
|
17
17
|
}>, {
|
|
18
18
|
extensions: string[] | undefined;
|
|
19
|
-
|
|
19
|
+
csr: boolean;
|
|
20
20
|
ssr: boolean;
|
|
21
21
|
}>;
|
|
22
22
|
type C = typeof base_schema.Complement;
|
|
@@ -62,11 +62,11 @@ export interface Init<S = ServerView, E extends C = ObjectType<never>> {
|
|
|
62
62
|
}
|
|
63
63
|
export default function frontend_module<S = ServerView, E extends C = ObjectType<never>>(init: Init<S, E>): (input?: E extends ObjectType<never, never> ? {
|
|
64
64
|
extensions?: string[] | undefined;
|
|
65
|
-
|
|
65
|
+
csr?: boolean | undefined;
|
|
66
66
|
ssr?: boolean | undefined;
|
|
67
67
|
} | undefined : Unpack<({
|
|
68
68
|
extensions?: string[] | undefined;
|
|
69
|
-
|
|
69
|
+
csr?: boolean | undefined;
|
|
70
70
|
ssr?: boolean | undefined;
|
|
71
71
|
} | undefined) & E["input"]>) => Module;
|
|
72
72
|
//# sourceMappingURL=frontend.d.ts.map
|
package/lib/private/frontend.js
CHANGED
|
@@ -4,11 +4,11 @@ import location from "#location";
|
|
|
4
4
|
import hash from "@rcompat/crypto/hash";
|
|
5
5
|
import fn from "@rcompat/fn";
|
|
6
6
|
import fs from "@rcompat/fs";
|
|
7
|
-
import
|
|
7
|
+
import http from "@rcompat/http";
|
|
8
8
|
import p from "pema";
|
|
9
9
|
const base_schema = p({
|
|
10
10
|
extensions: p.array(p.string).optional(),
|
|
11
|
-
|
|
11
|
+
csr: p.boolean.default(true),
|
|
12
12
|
ssr: p.boolean.default(true),
|
|
13
13
|
});
|
|
14
14
|
export default function frontend_module(init) {
|
|
@@ -24,7 +24,7 @@ export default function frontend_module(init) {
|
|
|
24
24
|
}
|
|
25
25
|
return (input) => {
|
|
26
26
|
const options = schema.parse(input);
|
|
27
|
-
const
|
|
27
|
+
const csr = options.csr;
|
|
28
28
|
const extensions = options.extensions ?? init.extensions;
|
|
29
29
|
let mode = "development";
|
|
30
30
|
function ssr() {
|
|
@@ -50,12 +50,15 @@ export default function frontend_module(init) {
|
|
|
50
50
|
}
|
|
51
51
|
return { body, head, headers };
|
|
52
52
|
}
|
|
53
|
+
const interactive = !ssr() || csr;
|
|
54
|
+
if (!interactive)
|
|
55
|
+
return { body, head, headers };
|
|
53
56
|
const app_asset = app.assets.find(asset => asset.src?.includes("app") && asset.src.endsWith(".js"));
|
|
54
57
|
if (app_asset === undefined)
|
|
55
58
|
throw E.frontend_missing_app_js();
|
|
56
59
|
const app_script = `<script type="module" src="${app_asset.src}"></script>`;
|
|
57
60
|
const props = JSON.stringify({ frontend: init.name, ...client });
|
|
58
|
-
const hydrated = await inline(props, MIME.APPLICATION_JSON, "hydration");
|
|
61
|
+
const hydrated = await inline(props, http.MIME.APPLICATION_JSON, "hydration");
|
|
59
62
|
const script_src = [hydrated.integrity];
|
|
60
63
|
return {
|
|
61
64
|
body,
|
|
@@ -81,21 +84,21 @@ export default function frontend_module(init) {
|
|
|
81
84
|
: { props, request: $request };
|
|
82
85
|
const client = {
|
|
83
86
|
view: init.layouts ? "root" : await normalize(view),
|
|
84
|
-
|
|
87
|
+
csr,
|
|
85
88
|
ssr: ssr(),
|
|
86
89
|
mode: app.mode,
|
|
87
90
|
...$props,
|
|
88
91
|
};
|
|
89
|
-
if (
|
|
92
|
+
if (csr && request.headers.try("Accept") === http.MIME.APPLICATION_JSON) {
|
|
90
93
|
const json_body = JSON.stringify(client);
|
|
91
94
|
return new Response(json_body, {
|
|
92
95
|
headers: {
|
|
93
96
|
...app.headers(),
|
|
94
|
-
"Content-Type": MIME.APPLICATION_JSON,
|
|
97
|
+
"Content-Type": http.MIME.APPLICATION_JSON,
|
|
95
98
|
"Content-Length": String(app.body_length(json_body)),
|
|
96
99
|
"Cache-Control": "no-store",
|
|
97
100
|
},
|
|
98
|
-
status: options.status ?? Status.OK,
|
|
101
|
+
status: options.status ?? http.Status.OK,
|
|
99
102
|
});
|
|
100
103
|
}
|
|
101
104
|
if (!ssr()) {
|
|
@@ -10,7 +10,13 @@ declare const errors: {
|
|
|
10
10
|
unit_not_supported: typeof unit_not_supported;
|
|
11
11
|
no_dots_catalog_keys: typeof no_dots_catalog_keys;
|
|
12
12
|
};
|
|
13
|
+
export declare const Code: {
|
|
14
|
+
at_least_one_locale: "at_least_one_locale";
|
|
15
|
+
missing_default_locale: "missing_default_locale";
|
|
16
|
+
unused_default_locale: "unused_default_locale";
|
|
17
|
+
unit_not_supported: "unit_not_supported";
|
|
18
|
+
no_dots_catalog_keys: "no_dots_catalog_keys";
|
|
19
|
+
};
|
|
13
20
|
export type Code = keyof typeof errors;
|
|
14
|
-
export declare const Code: { [K in Code]: K; };
|
|
15
21
|
export default errors;
|
|
16
22
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -22,6 +22,6 @@ const errors = error.coded({
|
|
|
22
22
|
unit_not_supported,
|
|
23
23
|
no_dots_catalog_keys,
|
|
24
24
|
});
|
|
25
|
-
export const Code =
|
|
25
|
+
export const Code = error.names(errors);
|
|
26
26
|
export default errors;
|
|
27
27
|
//# sourceMappingURL=errors.js.map
|
|
@@ -7,7 +7,7 @@ type EntryOf<Body extends string> = Body extends `${infer Name}:${infer Spec}` ?
|
|
|
7
7
|
__name: Body & string;
|
|
8
8
|
__type: string;
|
|
9
9
|
};
|
|
10
|
-
export type EntriesOf<S extends string> = string extends S ? never : S extends `${infer _}{${infer Body}}${infer Rest}` ? EntryOf<Body> | EntriesOf<Rest> : never;
|
|
10
|
+
export type EntriesOf<S extends string> = string extends S ? never : S extends `${infer _}{{${infer _}}}${infer Rest}` ? EntriesOf<Rest> : S extends `${infer _}{${infer Body}}${infer Rest}` ? EntryOf<Body> | EntriesOf<Rest> : never;
|
|
11
11
|
export type ParamsFromEntries<E> = [
|
|
12
12
|
E
|
|
13
13
|
] extends [never] ? Dict : {
|
|
@@ -6,6 +6,6 @@ type EnforceNoDots<T, D extends number = 6> = [
|
|
|
6
6
|
] extends [never] ? T : T extends string ? T : T extends readonly (infer E)[] ? readonly EnforceNoDots<E, Prev[D]>[] : T extends object ? {
|
|
7
7
|
[K in keyof T]: K extends string ? K extends `${string}.${string}` ? DotKeyMessage<K> : EnforceNoDots<T[K], Prev[D]> : EnforceNoDots<T[K], Prev[D]>;
|
|
8
8
|
} : T;
|
|
9
|
-
export default function locale<const M
|
|
9
|
+
export default function locale<const M>(messages: EnforceNoDots<M> & Catalog): M;
|
|
10
10
|
export {};
|
|
11
11
|
//# sourceMappingURL=locale.d.ts.map
|