@mandujs/core 0.20.10 → 0.22.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/README.md +2 -1
- package/package.json +28 -3
- package/src/auth/__tests__/login.test.ts +419 -0
- package/src/auth/__tests__/password.test.ts +122 -0
- package/src/auth/__tests__/reset.test.ts +296 -0
- package/src/auth/__tests__/tokens.test.ts +274 -0
- package/src/auth/__tests__/verification.test.ts +274 -0
- package/src/auth/index.ts +76 -0
- package/src/auth/login.ts +225 -0
- package/src/auth/password.ts +120 -0
- package/src/auth/reset.ts +243 -0
- package/src/auth/tokens.ts +612 -0
- package/src/auth/verification.ts +253 -0
- package/src/bundler/__tests__/cli-bench-utils.test.ts +149 -0
- package/src/bundler/__tests__/cold-start.test.ts +504 -0
- package/src/bundler/__tests__/csp-nonce.test.ts +278 -0
- package/src/bundler/__tests__/dev-reliability.test.ts +619 -0
- package/src/bundler/__tests__/extended-watch.test.ts +710 -0
- package/src/bundler/__tests__/fast-refresh.test.ts +596 -0
- package/src/bundler/__tests__/hdr.test.ts +353 -0
- package/src/bundler/__tests__/hmr-client.test.ts +532 -0
- package/src/bundler/__tests__/manifest-schema.test.ts +266 -0
- package/src/bundler/__tests__/prod-smoke.test.ts +138 -0
- package/src/bundler/__tests__/slot-dispatch.test.ts +573 -0
- package/src/bundler/__tests__/url-cap-and-slot-regex.test.ts +286 -0
- package/src/bundler/__tests__/vendor-cache.test.ts +455 -0
- package/src/bundler/build.test.ts +8 -1
- package/src/bundler/build.ts +495 -37
- package/src/bundler/css.ts +326 -323
- package/src/bundler/dev.ts +1671 -80
- package/src/bundler/fast-refresh-plugin.ts +307 -0
- package/src/bundler/hmr-types.ts +252 -0
- package/src/bundler/manifest-schema.ts +301 -0
- package/src/bundler/safe-build.test.ts +128 -0
- package/src/bundler/safe-build.ts +77 -0
- package/src/bundler/scenario-matrix.ts +229 -0
- package/src/bundler/types.ts +19 -0
- package/src/bundler/vendor-cache-types.ts +130 -0
- package/src/bundler/vendor-cache.ts +526 -0
- package/src/client/router.ts +214 -56
- package/src/config/validate.ts +1 -0
- package/src/db/__tests__/db.test.ts +485 -0
- package/src/db/index.ts +513 -0
- package/src/db/migrations/__tests__/runner.test.ts +661 -0
- package/src/db/migrations/history-table.ts +345 -0
- package/src/db/migrations/lock.ts +269 -0
- package/src/db/migrations/runner.ts +633 -0
- package/src/desktop/__tests__/smoke.test.ts +100 -0
- package/src/desktop/__tests__/window.test.ts +172 -0
- package/src/desktop/__tests__/worker.test.ts +266 -0
- package/src/desktop/index.ts +43 -0
- package/src/desktop/types.ts +158 -0
- package/src/desktop/window.ts +492 -0
- package/src/desktop/worker.ts +180 -0
- package/src/devtools/ai/mcp-connector.ts +18 -16
- package/src/devtools/client/components/mandu-character.tsx +4 -1
- package/src/devtools/client/components/panel/panel-container.tsx +20 -5
- package/src/email/__tests__/email.test.ts +355 -0
- package/src/email/index.ts +282 -0
- package/src/email/resend.ts +163 -0
- package/src/email/smtp.ts +64 -0
- package/src/filling/__tests__/session-sqlite.test.ts +454 -0
- package/src/filling/context.ts +72 -78
- package/src/filling/cookie-codec.ts +299 -0
- package/src/filling/deps.ts +25 -1
- package/src/filling/filling.ts +28 -3
- package/src/filling/session-sqlite.ts +617 -0
- package/src/filling/session.ts +265 -216
- package/src/guard/decision-memory.test.ts +52 -22
- package/src/id/__tests__/id.test.ts +120 -0
- package/src/id/index.ts +105 -0
- package/src/kitchen/index.ts +2 -2
- package/src/kitchen/kitchen-handler.ts +86 -0
- package/src/kitchen/stream/activity-sse.ts +2 -1
- package/src/middleware/csrf.ts +328 -0
- package/src/middleware/index.ts +40 -0
- package/src/middleware/oauth/__tests__/oauth.test.ts +574 -0
- package/src/middleware/oauth/index.ts +505 -0
- package/src/middleware/oauth/providers.ts +115 -0
- package/src/middleware/rate-limit/__tests__/rate-limit.test.ts +642 -0
- package/src/middleware/rate-limit/index.ts +522 -0
- package/src/middleware/rate-limit/sqlite-store.ts +382 -0
- package/src/middleware/secure/__tests__/secure.test.ts +360 -0
- package/src/middleware/secure/csp.ts +193 -0
- package/src/middleware/secure/index.ts +417 -0
- package/src/middleware/session.ts +174 -0
- package/src/observability/event-bus.ts +81 -79
- package/src/paths.ts +37 -0
- package/src/perf/hmr-markers.ts +215 -0
- package/src/perf/index.ts +104 -0
- package/src/resource/__tests__/generator.test.ts +603 -2
- package/src/resource/ddl/__tests__/diff.test.ts +639 -0
- package/src/resource/ddl/__tests__/emit.test.ts +799 -0
- package/src/resource/ddl/__tests__/snapshot.test.ts +499 -0
- package/src/resource/ddl/diff.ts +392 -0
- package/src/resource/ddl/emit.ts +548 -0
- package/src/resource/ddl/persistence-types.ts +218 -0
- package/src/resource/ddl/snapshot.ts +447 -0
- package/src/resource/ddl/type-map.ts +223 -0
- package/src/resource/ddl/types.ts +232 -0
- package/src/resource/generator-repo.ts +610 -0
- package/src/resource/generator-schema.ts +476 -0
- package/src/resource/generator.ts +117 -1
- package/src/resource/index.ts +17 -1
- package/src/resource/schema.ts +30 -0
- package/src/router/fs-scanner.ts +3 -0
- package/src/runtime/__tests__/error-boundary-redaction.test.ts +141 -0
- package/src/runtime/__tests__/hdr-client.test.ts +223 -0
- package/src/runtime/__tests__/http-errors.test.ts +117 -0
- package/src/runtime/__tests__/not-found.test.ts +152 -0
- package/src/runtime/boundary.tsx +21 -1
- package/src/runtime/fast-refresh-runtime.ts +322 -0
- package/src/runtime/fast-refresh-types.ts +128 -0
- package/src/runtime/hmr-client.ts +409 -0
- package/src/runtime/http-errors.ts +113 -0
- package/src/runtime/index.ts +6 -0
- package/src/runtime/logger.ts +678 -677
- package/src/runtime/not-found.ts +93 -0
- package/src/runtime/redirect.ts +133 -0
- package/src/runtime/server.ts +679 -23
- package/src/runtime/ssr.ts +340 -10
- package/src/runtime/streaming-ssr.ts +222 -19
- package/src/scheduler/__tests__/scheduler.test.ts +514 -0
- package/src/scheduler/index.ts +343 -0
- package/src/storage/s3/__tests__/s3.test.ts +479 -0
- package/src/storage/s3/index.ts +412 -0
- package/src/testing/index.ts +247 -189
package/src/testing/index.ts
CHANGED
|
@@ -1,189 +1,247 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mandu Testing Utilities
|
|
3
|
-
* 서버 없이 라우트/filling 단위 테스트
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
body = { _action: action };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
requestInit.body =
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* ```
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
requestInit.body =
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Mandu Testing Utilities
|
|
3
|
+
* 서버 없이 라우트/filling 단위 테스트
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import path from "path";
|
|
7
|
+
import os from "os";
|
|
8
|
+
import { ManduContext } from "../filling/context";
|
|
9
|
+
import type { ManduFilling } from "../filling/filling";
|
|
10
|
+
import type { RouteSpec, RoutesManifest } from "../spec/schema";
|
|
11
|
+
|
|
12
|
+
// ========== Types ==========
|
|
13
|
+
|
|
14
|
+
export interface TestRequestOptions {
|
|
15
|
+
method?: string;
|
|
16
|
+
query?: Record<string, string>;
|
|
17
|
+
body?: unknown;
|
|
18
|
+
headers?: Record<string, string>;
|
|
19
|
+
params?: Record<string, string>;
|
|
20
|
+
/** Action 이름 — 자동으로 _action을 body에 삽입하고 ManduAction 헤더를 추가 */
|
|
21
|
+
action?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ========== testFilling ==========
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Filling 단위 테스트 — 서버 없이 직접 실행
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { testFilling } from "@mandujs/core/testing";
|
|
32
|
+
* import todoRoute from "./app/api/todos/route";
|
|
33
|
+
*
|
|
34
|
+
* const res = await testFilling(todoRoute, {
|
|
35
|
+
* method: "GET",
|
|
36
|
+
* query: { page: "2" },
|
|
37
|
+
* });
|
|
38
|
+
* expect(res.status).toBe(200);
|
|
39
|
+
*
|
|
40
|
+
* const data = await res.json();
|
|
41
|
+
* expect(data.todos).toHaveLength(10);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export async function testFilling(
|
|
45
|
+
filling: ManduFilling,
|
|
46
|
+
options: TestRequestOptions = {}
|
|
47
|
+
): Promise<Response> {
|
|
48
|
+
const {
|
|
49
|
+
method: rawMethod,
|
|
50
|
+
query,
|
|
51
|
+
body: rawBody,
|
|
52
|
+
headers: rawHeaders = {},
|
|
53
|
+
params = {},
|
|
54
|
+
action,
|
|
55
|
+
} = options;
|
|
56
|
+
|
|
57
|
+
// action 지정 시 자동으로 POST + _action body + ManduAction 헤더
|
|
58
|
+
const method = rawMethod ?? (action ? "POST" : "GET");
|
|
59
|
+
const headers = { ...rawHeaders };
|
|
60
|
+
let body = rawBody;
|
|
61
|
+
|
|
62
|
+
if (action) {
|
|
63
|
+
headers["X-Requested-With"] = "ManduAction";
|
|
64
|
+
headers["Accept"] = "application/json";
|
|
65
|
+
if (body && typeof body === "object" && !(body instanceof FormData)) {
|
|
66
|
+
body = { _action: action, ...(body as Record<string, unknown>) };
|
|
67
|
+
} else if (!body) {
|
|
68
|
+
body = { _action: action };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const url = new URL("http://localhost/test");
|
|
73
|
+
if (query) {
|
|
74
|
+
for (const [key, value] of Object.entries(query)) {
|
|
75
|
+
url.searchParams.set(key, value);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const requestInit: RequestInit = {
|
|
80
|
+
method,
|
|
81
|
+
headers,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
if (body !== undefined && method !== "GET" && method !== "HEAD") {
|
|
85
|
+
if (body instanceof FormData) {
|
|
86
|
+
requestInit.body = body;
|
|
87
|
+
} else {
|
|
88
|
+
requestInit.body = JSON.stringify(body);
|
|
89
|
+
(requestInit.headers as Record<string, string>)["Content-Type"] = "application/json";
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const request = new Request(url.toString(), requestInit);
|
|
94
|
+
return filling.handle(request, params);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 간단한 Request 생성 헬퍼
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const req = createTestRequest("/api/todos", { method: "POST", body: { title: "test" } });
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export function createTestRequest(
|
|
106
|
+
path: string,
|
|
107
|
+
options: TestRequestOptions = {}
|
|
108
|
+
): Request {
|
|
109
|
+
const { method = "GET", query, body, headers = {} } = options;
|
|
110
|
+
|
|
111
|
+
const url = new URL(`http://localhost${path}`);
|
|
112
|
+
if (query) {
|
|
113
|
+
for (const [key, value] of Object.entries(query)) {
|
|
114
|
+
url.searchParams.set(key, value);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const requestInit: RequestInit = { method, headers: { ...headers } };
|
|
119
|
+
|
|
120
|
+
if (body !== undefined && method !== "GET" && method !== "HEAD") {
|
|
121
|
+
if (body instanceof FormData) {
|
|
122
|
+
requestInit.body = body;
|
|
123
|
+
} else {
|
|
124
|
+
requestInit.body = JSON.stringify(body);
|
|
125
|
+
(requestInit.headers as Record<string, string>)["Content-Type"] = "application/json";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return new Request(url.toString(), requestInit);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* ManduContext 테스트용 생성 헬퍼
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const ctx = createTestContext("/api/users/123", { params: { id: "123" } });
|
|
138
|
+
* expect(ctx.params.id).toBe("123");
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function createTestContext(
|
|
142
|
+
path: string,
|
|
143
|
+
options: TestRequestOptions = {}
|
|
144
|
+
): ManduContext {
|
|
145
|
+
const request = createTestRequest(path, options);
|
|
146
|
+
return new ManduContext(request, options.params);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ========== Test Factories ==========
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Create a RoutesManifest from partial route definitions.
|
|
153
|
+
* Fills in sensible defaults so tests only specify the fields they care about.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const manifest = createTestManifest([
|
|
158
|
+
* { id: "home", kind: "page", pattern: "/" },
|
|
159
|
+
* { id: "api-users", kind: "api", pattern: "/api/users" },
|
|
160
|
+
* ]);
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export function createTestManifest(routes: Partial<RouteSpec>[]): RoutesManifest {
|
|
164
|
+
return {
|
|
165
|
+
version: 1,
|
|
166
|
+
routes: routes.map((r, i) => ({
|
|
167
|
+
id: r.id ?? `test-route-${i}`,
|
|
168
|
+
kind: r.kind ?? "page",
|
|
169
|
+
pattern: r.pattern ?? `/test-${i}`,
|
|
170
|
+
module: r.module ?? `app/test-${i}/page.tsx`,
|
|
171
|
+
componentModule:
|
|
172
|
+
(r.kind ?? "page") === "page"
|
|
173
|
+
? (r.componentModule ?? r.module ?? `app/test-${i}/page.tsx`)
|
|
174
|
+
: undefined,
|
|
175
|
+
...r,
|
|
176
|
+
})) as RouteSpec[],
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Create a minimal island descriptor for testing hydration logic.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const island = createTestIsland("counter", "interaction");
|
|
186
|
+
* expect(island.__hydrate).toBe("interaction");
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export function createTestIsland(name: string, strategy: string = "visible") {
|
|
190
|
+
return { __island: true, __hydrate: strategy, __name: name };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ========== createMockMcpContext ==========
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Mock MCP context shape mirroring the real MCP server context
|
|
197
|
+
* (see `packages/mcp/src/utils/project.ts`).
|
|
198
|
+
*
|
|
199
|
+
* Use this in tests for MCP tool plugins and slot/contract validators
|
|
200
|
+
* that accept an MCP-context-like object.
|
|
201
|
+
*/
|
|
202
|
+
export interface MockMcpContext {
|
|
203
|
+
paths: {
|
|
204
|
+
repoRoot: string;
|
|
205
|
+
manduDir: string;
|
|
206
|
+
manifestPath: string;
|
|
207
|
+
specsDir: string;
|
|
208
|
+
slotsDir: string;
|
|
209
|
+
};
|
|
210
|
+
readConfig: () => Promise<Record<string, unknown>>;
|
|
211
|
+
readManifest: () => Promise<RoutesManifest>;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Create a mock MCP context suitable for unit-testing MCP tools without
|
|
216
|
+
* spinning up an actual project on disk.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* const ctx = createMockMcpContext({
|
|
221
|
+
* config: { guard: { preset: "fsd" } },
|
|
222
|
+
* manifest: createTestManifest([{ id: "home", kind: "page", pattern: "/" }]),
|
|
223
|
+
* });
|
|
224
|
+
* await myTool.execute(ctx, { input: "..." });
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
export function createMockMcpContext(options: {
|
|
228
|
+
root?: string;
|
|
229
|
+
config?: Record<string, unknown>;
|
|
230
|
+
manifest?: RoutesManifest;
|
|
231
|
+
} = {}): MockMcpContext {
|
|
232
|
+
const root = options.root ?? path.join(os.tmpdir(), "mandu-mock-mcp");
|
|
233
|
+
const config = options.config ?? {};
|
|
234
|
+
const manifest = options.manifest ?? { version: 1, routes: [] };
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
paths: {
|
|
238
|
+
repoRoot: root,
|
|
239
|
+
manduDir: path.join(root, ".mandu"),
|
|
240
|
+
manifestPath: path.join(root, ".mandu", "routes.manifest.json"),
|
|
241
|
+
specsDir: path.join(root, "spec"),
|
|
242
|
+
slotsDir: path.join(root, "spec", "slots"),
|
|
243
|
+
},
|
|
244
|
+
readConfig: async () => config,
|
|
245
|
+
readManifest: async () => manifest,
|
|
246
|
+
};
|
|
247
|
+
}
|