@fragno-dev/core 0.1.6 → 0.1.8
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 +46 -54
- package/CHANGELOG.md +12 -0
- package/dist/api/api.d.ts +2 -2
- package/dist/api/api.js +3 -2
- package/dist/api/fragment-builder.d.ts +2 -4
- package/dist/api/fragment-builder.js +1 -1
- package/dist/api/fragment-instantiation.d.ts +2 -4
- package/dist/api/fragment-instantiation.js +3 -5
- package/dist/api/route.d.ts +2 -3
- package/dist/api/route.js +1 -1
- package/dist/api-BFrUCIsF.d.ts +963 -0
- package/dist/api-BFrUCIsF.d.ts.map +1 -0
- package/dist/client/client.d.ts +1 -3
- package/dist/client/client.js +4 -5
- package/dist/client/client.svelte.d.ts +2 -3
- package/dist/client/client.svelte.d.ts.map +1 -1
- package/dist/client/client.svelte.js +4 -5
- package/dist/client/client.svelte.js.map +1 -1
- package/dist/client/react.d.ts +2 -3
- package/dist/client/react.d.ts.map +1 -1
- package/dist/client/react.js +4 -5
- package/dist/client/react.js.map +1 -1
- package/dist/client/solid.d.ts +2 -3
- package/dist/client/solid.d.ts.map +1 -1
- package/dist/client/solid.js +4 -5
- package/dist/client/solid.js.map +1 -1
- package/dist/client/vanilla.d.ts +2 -3
- package/dist/client/vanilla.d.ts.map +1 -1
- package/dist/client/vanilla.js +4 -5
- package/dist/client/vanilla.js.map +1 -1
- package/dist/client/vue.d.ts +2 -3
- package/dist/client/vue.d.ts.map +1 -1
- package/dist/client/vue.js +8 -9
- package/dist/client/vue.js.map +1 -1
- package/dist/{client-DJfCJiHK.js → client-DAFHcKqA.js} +15 -8
- package/dist/client-DAFHcKqA.js.map +1 -0
- package/dist/fragment-builder-Boh2vNHq.js +108 -0
- package/dist/fragment-builder-Boh2vNHq.js.map +1 -0
- package/dist/fragment-instantiation-DUT-HLl1.js +898 -0
- package/dist/fragment-instantiation-DUT-HLl1.js.map +1 -0
- package/dist/integrations/react-ssr.js +1 -1
- package/dist/mod.d.ts +2 -4
- package/dist/mod.js +4 -6
- package/dist/{route-C5Uryylh.js → route-C4CyNHkC.js} +8 -3
- package/dist/route-C4CyNHkC.js.map +1 -0
- package/dist/{ssr-BByDVfFD.js → ssr-kyKI7pqH.js} +1 -1
- package/dist/{ssr-BByDVfFD.js.map → ssr-kyKI7pqH.js.map} +1 -1
- package/dist/test/test.d.ts +6 -7
- package/dist/test/test.d.ts.map +1 -1
- package/dist/test/test.js +9 -7
- package/dist/test/test.js.map +1 -1
- package/package.json +1 -1
- package/src/api/api.ts +45 -6
- package/src/api/fragment-builder.ts +463 -25
- package/src/api/fragment-instantiation.test.ts +249 -7
- package/src/api/fragment-instantiation.ts +283 -16
- package/src/api/fragment-services.test.ts +462 -0
- package/src/api/fragment.test.ts +65 -17
- package/src/api/internal/path-type.test.ts +7 -7
- package/src/api/internal/path.ts +1 -1
- package/src/api/request-middleware.test.ts +6 -3
- package/src/api/route.test.ts +111 -1
- package/src/api/route.ts +323 -14
- package/src/client/client-types.test.ts +4 -4
- package/src/client/client.test.ts +77 -0
- package/src/client/client.ts +31 -12
- package/src/mod.ts +11 -1
- package/src/test/test.test.ts +20 -15
- package/src/test/test.ts +48 -9
- package/dist/api-CoCkNi6h.d.ts +0 -377
- package/dist/api-CoCkNi6h.d.ts.map +0 -1
- package/dist/api-DngJDcmO.js +0 -54
- package/dist/api-DngJDcmO.js.map +0 -1
- package/dist/client-DJfCJiHK.js.map +0 -1
- package/dist/fragment-builder-8-tiECi5.d.ts +0 -408
- package/dist/fragment-builder-8-tiECi5.d.ts.map +0 -1
- package/dist/fragment-builder-DOnCVBqc.js +0 -47
- package/dist/fragment-builder-DOnCVBqc.js.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-C5Uryylh.js.map +0 -1
- package/dist/route-mGLYSUvD.d.ts +0 -26
- package/dist/route-mGLYSUvD.d.ts.map +0 -1
package/src/client/client.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { nanoquery, type FetcherStore, type MutatorStore } from "@nanostores/query";
|
|
2
2
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
-
import { task, type ReadableAtom, type Store } from "nanostores";
|
|
3
|
+
import { computed, task, type ReadableAtom, type Store } from "nanostores";
|
|
4
4
|
import type { FragnoRouteConfig, HTTPMethod, NonGetHTTPMethod } from "../api/api";
|
|
5
5
|
import {
|
|
6
6
|
buildPath,
|
|
@@ -252,11 +252,11 @@ export type FragnoClientHookData<
|
|
|
252
252
|
>;
|
|
253
253
|
query(args?: {
|
|
254
254
|
path?: MaybeExtractPathParamsOrWiden<TPath, string>;
|
|
255
|
-
query?: Record<TQueryParameters, string>;
|
|
255
|
+
query?: Record<TQueryParameters, string | undefined>;
|
|
256
256
|
}): Promise<StandardSchemaV1.InferOutput<TOutputSchema>>;
|
|
257
257
|
store(args?: {
|
|
258
258
|
path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;
|
|
259
|
-
query?: Record<TQueryParameters, string | ReadableAtom<string>>;
|
|
259
|
+
query?: Record<TQueryParameters, string | undefined | ReadableAtom<string | undefined>>;
|
|
260
260
|
}): FetcherStore<StandardSchemaV1.InferOutput<TOutputSchema>, FragnoClientError<TErrorCode>>;
|
|
261
261
|
[GET_HOOK_SYMBOL]: true;
|
|
262
262
|
} & {
|
|
@@ -287,14 +287,14 @@ export type FragnoClientMutatorData<
|
|
|
287
287
|
mutateQuery(args?: {
|
|
288
288
|
body?: InferOr<TInputSchema, undefined>;
|
|
289
289
|
path?: MaybeExtractPathParamsOrWiden<TPath, string>;
|
|
290
|
-
query?: Record<TQueryParameters, string>;
|
|
290
|
+
query?: Record<TQueryParameters, string | undefined>;
|
|
291
291
|
}): Promise<InferOr<TOutputSchema, undefined>>;
|
|
292
292
|
|
|
293
293
|
mutatorStore: MutatorStore<
|
|
294
294
|
{
|
|
295
295
|
body?: InferOr<TInputSchema, undefined>;
|
|
296
296
|
path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;
|
|
297
|
-
query?: Record<TQueryParameters, string | ReadableAtom<string>>;
|
|
297
|
+
query?: Record<TQueryParameters, string | undefined | ReadableAtom<string | undefined>>;
|
|
298
298
|
},
|
|
299
299
|
InferOr<TOutputSchema, undefined>,
|
|
300
300
|
FragnoClientError<TErrorCode>
|
|
@@ -313,7 +313,7 @@ export function buildUrl<TPath extends string>(
|
|
|
313
313
|
},
|
|
314
314
|
params: {
|
|
315
315
|
pathParams?: Record<string, string | ReadableAtom<string>>;
|
|
316
|
-
queryParams?: Record<string, string | ReadableAtom<string>>;
|
|
316
|
+
queryParams?: Record<string, string | undefined | ReadableAtom<string | undefined>>;
|
|
317
317
|
},
|
|
318
318
|
): string {
|
|
319
319
|
const { baseUrl = "", mountRoute, path } = config;
|
|
@@ -322,7 +322,12 @@ export function buildUrl<TPath extends string>(
|
|
|
322
322
|
const normalizedPathParams = unwrapObject(pathParams) as ExtractPathParams<TPath, string>;
|
|
323
323
|
const normalizedQueryParams = unwrapObject(queryParams) ?? {};
|
|
324
324
|
|
|
325
|
-
|
|
325
|
+
// Filter out undefined values to prevent URLSearchParams from converting them to string "undefined"
|
|
326
|
+
const filteredQueryParams = Object.fromEntries(
|
|
327
|
+
Object.entries(normalizedQueryParams).filter(([_, value]) => value !== undefined),
|
|
328
|
+
) as Record<string, string>;
|
|
329
|
+
|
|
330
|
+
const searchParams = new URLSearchParams(filteredQueryParams);
|
|
326
331
|
const builtPath = buildPath(path, normalizedPathParams ?? {});
|
|
327
332
|
const search = searchParams.toString() ? `?${searchParams.toString()}` : "";
|
|
328
333
|
return `${baseUrl}${mountRoute}${builtPath}${search}`;
|
|
@@ -333,6 +338,7 @@ export function buildUrl<TPath extends string>(
|
|
|
333
338
|
*
|
|
334
339
|
* The returned array is always: path, pathParams (In order they appear in the path), queryParams (In alphabetical order)
|
|
335
340
|
* Missing pathParams are replaced with "<missing>".
|
|
341
|
+
* Atoms with undefined values are wrapped in computed atoms that map undefined to "" to avoid nanoquery treating the key as incomplete.
|
|
336
342
|
* @param path
|
|
337
343
|
* @param params
|
|
338
344
|
* @returns
|
|
@@ -342,7 +348,7 @@ export function getCacheKey<TMethod extends HTTPMethod, TPath extends string>(
|
|
|
342
348
|
path: TPath,
|
|
343
349
|
params?: {
|
|
344
350
|
pathParams?: Record<string, string | ReadableAtom<string>>;
|
|
345
|
-
queryParams?: Record<string, string | ReadableAtom<string>>;
|
|
351
|
+
queryParams?: Record<string, string | undefined | ReadableAtom<string | undefined>>;
|
|
346
352
|
},
|
|
347
353
|
): (string | ReadableAtom<string>)[] {
|
|
348
354
|
if (!params) {
|
|
@@ -357,7 +363,15 @@ export function getCacheKey<TMethod extends HTTPMethod, TPath extends string>(
|
|
|
357
363
|
const queryParamValues = queryParams
|
|
358
364
|
? Object.keys(queryParams)
|
|
359
365
|
.sort()
|
|
360
|
-
.map((key) =>
|
|
366
|
+
.map((key) => {
|
|
367
|
+
const value = queryParams[key];
|
|
368
|
+
// If it's an atom, wrap it to convert undefined to ""
|
|
369
|
+
if (value && typeof value === "object" && "get" in value) {
|
|
370
|
+
return computed(value as ReadableAtom<string | undefined>, (v) => v ?? "");
|
|
371
|
+
}
|
|
372
|
+
// Plain string value (or undefined)
|
|
373
|
+
return value ?? "";
|
|
374
|
+
})
|
|
361
375
|
: [];
|
|
362
376
|
|
|
363
377
|
return [method, path, ...pathParamValues, ...queryParamValues];
|
|
@@ -668,14 +682,19 @@ export class ClientBuilder<
|
|
|
668
682
|
|
|
669
683
|
async function callServerSideHandler(params: {
|
|
670
684
|
pathParams?: Record<string, string | ReadableAtom<string>>;
|
|
671
|
-
queryParams?: Record<string, string | ReadableAtom<string>>;
|
|
685
|
+
queryParams?: Record<string, string | undefined | ReadableAtom<string | undefined>>;
|
|
672
686
|
}): Promise<Response> {
|
|
673
687
|
const { pathParams, queryParams } = params ?? {};
|
|
674
688
|
|
|
675
689
|
const normalizedPathParams = unwrapObject(pathParams) as ExtractPathParams<TPath, string>;
|
|
676
690
|
const normalizedQueryParams = unwrapObject(queryParams) ?? {};
|
|
677
691
|
|
|
678
|
-
|
|
692
|
+
// Filter out undefined values to prevent URLSearchParams from converting them to string "undefined"
|
|
693
|
+
const filteredQueryParams = Object.fromEntries(
|
|
694
|
+
Object.entries(normalizedQueryParams).filter(([_, value]) => value !== undefined),
|
|
695
|
+
) as Record<string, string>;
|
|
696
|
+
|
|
697
|
+
const searchParams = new URLSearchParams(filteredQueryParams);
|
|
679
698
|
|
|
680
699
|
const result = await route.handler(
|
|
681
700
|
RequestInputContext.fromSSRContext({
|
|
@@ -692,7 +711,7 @@ export class ClientBuilder<
|
|
|
692
711
|
|
|
693
712
|
async function executeQuery(params?: {
|
|
694
713
|
pathParams?: Record<string, string | ReadableAtom<string>>;
|
|
695
|
-
queryParams?: Record<string, string | ReadableAtom<string>>;
|
|
714
|
+
queryParams?: Record<string, string | undefined | ReadableAtom<string | undefined>>;
|
|
696
715
|
}): Promise<Response> {
|
|
697
716
|
const { pathParams, queryParams } = params ?? {};
|
|
698
717
|
|
package/src/mod.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {
|
|
2
|
+
defineFragment,
|
|
3
|
+
FragmentBuilder,
|
|
4
|
+
type FragmentDefinition,
|
|
5
|
+
type RouteHandler,
|
|
6
|
+
} from "./api/fragment-builder";
|
|
2
7
|
|
|
3
8
|
export {
|
|
4
9
|
createFragment,
|
|
10
|
+
instantiateFragment,
|
|
11
|
+
FragmentInstantiationBuilder,
|
|
5
12
|
type FragnoFragmentSharedConfig,
|
|
6
13
|
type FragnoPublicConfig,
|
|
7
14
|
type FragnoPublicClientConfig,
|
|
@@ -18,3 +25,6 @@ export {
|
|
|
18
25
|
type AnyRouteOrFactory,
|
|
19
26
|
type FlattenRouteFactories,
|
|
20
27
|
} from "./api/route";
|
|
28
|
+
|
|
29
|
+
export { RequestInputContext } from "./api/request-input-context";
|
|
30
|
+
export { RequestOutputContext } from "./api/request-output-context";
|
package/src/test/test.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, expectTypeOf } from "vitest";
|
|
1
|
+
import { describe, it, expect, expectTypeOf, assert } from "vitest";
|
|
2
2
|
import { createFragmentForTest } from "./test";
|
|
3
3
|
import { defineFragment } from "../api/fragment-builder";
|
|
4
4
|
import { defineRoute, defineRoutes } from "../api/route";
|
|
@@ -46,9 +46,11 @@ describe("createFragmentForTest", () => {
|
|
|
46
46
|
.withDependencies(({ config }) => ({
|
|
47
47
|
client: { apiKey: config.apiKey },
|
|
48
48
|
}))
|
|
49
|
-
.
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
.providesService(({ deps, defineService }) =>
|
|
50
|
+
defineService({
|
|
51
|
+
getApiKey: () => deps.client.apiKey,
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
52
54
|
|
|
53
55
|
const testFragment = createFragmentForTest(fragment, [], {
|
|
54
56
|
config: { apiKey: "test-key" },
|
|
@@ -62,9 +64,11 @@ describe("createFragmentForTest", () => {
|
|
|
62
64
|
.withDependencies(({ config }) => ({
|
|
63
65
|
client: { apiKey: config.apiKey },
|
|
64
66
|
}))
|
|
65
|
-
.
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
.providesService(({ deps, defineService }) =>
|
|
68
|
+
defineService({
|
|
69
|
+
getApiKey: () => deps.client.apiKey,
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
68
72
|
|
|
69
73
|
const testFragment = createFragmentForTest(fragment, [], {
|
|
70
74
|
config: { apiKey: "test-key" },
|
|
@@ -81,9 +85,11 @@ describe("createFragmentForTest", () => {
|
|
|
81
85
|
|
|
82
86
|
const fragment = defineFragment<Config>("test")
|
|
83
87
|
.withDependencies(() => ({ dep: "value" }))
|
|
84
|
-
.
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
.providesService(({ config, defineService }) =>
|
|
89
|
+
defineService({
|
|
90
|
+
multiply: (x: number) => x * config.multiplier,
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
87
93
|
|
|
88
94
|
const routeFactory = defineRoutes<Config, Deps, Services>().create(({ services }) => [
|
|
89
95
|
defineRoute({
|
|
@@ -233,7 +239,7 @@ describe("fragment.callRoute", () => {
|
|
|
233
239
|
});
|
|
234
240
|
|
|
235
241
|
it("should handle route factory created with defineRoutes", async () => {
|
|
236
|
-
const fragment = defineFragment<{ apiKey: string }>("test").
|
|
242
|
+
const fragment = defineFragment<{ apiKey: string }>("test").providesService(() => ({
|
|
237
243
|
getGreeting: (name: string) => `Hello, ${name}!`,
|
|
238
244
|
getCount: () => 42,
|
|
239
245
|
}));
|
|
@@ -270,10 +276,9 @@ describe("fragment.callRoute", () => {
|
|
|
270
276
|
pathParams: { name: "World" },
|
|
271
277
|
});
|
|
272
278
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
279
|
+
console.log(greetingResponse);
|
|
280
|
+
assert(greetingResponse.type === "json");
|
|
281
|
+
expect(greetingResponse.data).toEqual({ message: "Hello, World!" });
|
|
277
282
|
|
|
278
283
|
// Test second route
|
|
279
284
|
const countResponse = await testFragment.callRoute("GET", "/count");
|
package/src/test/test.ts
CHANGED
|
@@ -23,12 +23,14 @@ export interface CreateFragmentForTestOptions<
|
|
|
23
23
|
TServices,
|
|
24
24
|
TAdditionalContext extends Record<string, unknown>,
|
|
25
25
|
TOptions extends FragnoPublicConfig,
|
|
26
|
+
TRequiredInterfaces extends Record<string, unknown> = {},
|
|
26
27
|
> {
|
|
27
28
|
config: TConfig;
|
|
28
29
|
options?: Partial<TOptions>;
|
|
29
30
|
deps?: Partial<TDeps>;
|
|
30
31
|
services?: Partial<TServices>;
|
|
31
32
|
additionalContext?: Partial<TAdditionalContext>;
|
|
33
|
+
interfaceImplementations?: TRequiredInterfaces;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
/**
|
|
@@ -108,18 +110,34 @@ export function createFragmentForTest<
|
|
|
108
110
|
TServices extends Record<string, unknown>,
|
|
109
111
|
TAdditionalContext extends Record<string, unknown>,
|
|
110
112
|
TOptions extends FragnoPublicConfig,
|
|
113
|
+
TRequiredInterfaces extends Record<string, unknown>,
|
|
114
|
+
TProvidedInterfaces extends Record<string, unknown>,
|
|
111
115
|
const TRoutesOrFactories extends readonly AnyRouteOrFactory[],
|
|
112
116
|
>(
|
|
113
117
|
fragmentBuilder: {
|
|
114
|
-
definition: FragmentDefinition<
|
|
118
|
+
definition: FragmentDefinition<
|
|
119
|
+
TConfig,
|
|
120
|
+
TDeps,
|
|
121
|
+
TServices,
|
|
122
|
+
TAdditionalContext,
|
|
123
|
+
TRequiredInterfaces,
|
|
124
|
+
TProvidedInterfaces
|
|
125
|
+
>;
|
|
115
126
|
$requiredOptions: TOptions;
|
|
116
127
|
},
|
|
117
128
|
routesOrFactories: TRoutesOrFactories,
|
|
118
|
-
options: CreateFragmentForTestOptions<
|
|
129
|
+
options: CreateFragmentForTestOptions<
|
|
130
|
+
TConfig,
|
|
131
|
+
TDeps,
|
|
132
|
+
TServices,
|
|
133
|
+
TAdditionalContext,
|
|
134
|
+
TOptions,
|
|
135
|
+
TRequiredInterfaces
|
|
136
|
+
>,
|
|
119
137
|
): FragmentForTest<
|
|
120
138
|
TConfig,
|
|
121
|
-
TDeps,
|
|
122
|
-
TServices,
|
|
139
|
+
TDeps & TRequiredInterfaces,
|
|
140
|
+
TServices & TProvidedInterfaces,
|
|
123
141
|
TAdditionalContext,
|
|
124
142
|
TOptions,
|
|
125
143
|
FlattenRouteFactories<TRoutesOrFactories>
|
|
@@ -130,6 +148,7 @@ export function createFragmentForTest<
|
|
|
130
148
|
deps: depsOverride,
|
|
131
149
|
services: servicesOverride,
|
|
132
150
|
additionalContext: additionalContextOverride,
|
|
151
|
+
interfaceImplementations,
|
|
133
152
|
} = options;
|
|
134
153
|
|
|
135
154
|
// Create deps from definition or use empty object
|
|
@@ -138,16 +157,30 @@ export function createFragmentForTest<
|
|
|
138
157
|
? definition.dependencies(config, fragmentOptions)
|
|
139
158
|
: ({} as TDeps);
|
|
140
159
|
|
|
141
|
-
// Merge deps with overrides
|
|
142
|
-
const deps = {
|
|
160
|
+
// Merge deps with overrides and interface implementations
|
|
161
|
+
const deps = {
|
|
162
|
+
...baseDeps,
|
|
163
|
+
...interfaceImplementations,
|
|
164
|
+
...depsOverride,
|
|
165
|
+
} as TDeps & TRequiredInterfaces;
|
|
143
166
|
|
|
144
167
|
// Create services from definition or use empty object
|
|
145
168
|
const baseServices = definition.services
|
|
146
169
|
? definition.services(config, fragmentOptions, deps)
|
|
147
170
|
: ({} as TServices);
|
|
148
171
|
|
|
149
|
-
//
|
|
150
|
-
const
|
|
172
|
+
// Handle providedServices - can be either a factory function or a direct object
|
|
173
|
+
const providedServicesResolved =
|
|
174
|
+
typeof definition.providedServices === "function"
|
|
175
|
+
? definition.providedServices(config, fragmentOptions, deps)
|
|
176
|
+
: definition.providedServices;
|
|
177
|
+
|
|
178
|
+
// Merge services with provided services and overrides
|
|
179
|
+
const services = {
|
|
180
|
+
...baseServices,
|
|
181
|
+
...providedServicesResolved,
|
|
182
|
+
...servicesOverride,
|
|
183
|
+
} as TServices & TProvidedInterfaces;
|
|
151
184
|
|
|
152
185
|
// Merge additional context with options
|
|
153
186
|
const additionalContext = {
|
|
@@ -157,7 +190,13 @@ export function createFragmentForTest<
|
|
|
157
190
|
} as TAdditionalContext & TOptions;
|
|
158
191
|
|
|
159
192
|
// Create the actual fragment using createFragment
|
|
160
|
-
const fragment = createFragment(
|
|
193
|
+
const fragment = createFragment(
|
|
194
|
+
fragmentBuilder,
|
|
195
|
+
config,
|
|
196
|
+
routesOrFactories,
|
|
197
|
+
fragmentOptions,
|
|
198
|
+
interfaceImplementations,
|
|
199
|
+
);
|
|
161
200
|
|
|
162
201
|
return {
|
|
163
202
|
config,
|