htmx-router 1.0.0-alpha.6 → 1.0.0-pre1

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.
Files changed (70) hide show
  1. package/package.json +6 -8
  2. package/readme.md +20 -3
  3. package/cookies.d.ts +0 -25
  4. package/cookies.js +0 -60
  5. package/css.d.ts +0 -13
  6. package/css.js +0 -55
  7. package/dynamic.d.ts +0 -5
  8. package/dynamic.js +0 -42
  9. package/endpoint.d.ts +0 -13
  10. package/endpoint.js +0 -34
  11. package/event-source.d.ts +0 -26
  12. package/event-source.js +0 -123
  13. package/index.d.ts +0 -19
  14. package/index.js +0 -2
  15. package/internal/cli/config.d.ts +0 -13
  16. package/internal/cli/config.js +0 -11
  17. package/internal/cli/index.d.ts +0 -2
  18. package/internal/cli/index.js +0 -15
  19. package/internal/client.d.ts +0 -1
  20. package/internal/client.js +0 -14
  21. package/internal/compile/manifest.d.ts +0 -1
  22. package/internal/compile/manifest.js +0 -178
  23. package/internal/compile/router.d.ts +0 -1
  24. package/internal/compile/router.js +0 -51
  25. package/internal/component/dynamic.d.ts +0 -4
  26. package/internal/component/dynamic.js +0 -18
  27. package/internal/component/head.d.ts +0 -5
  28. package/internal/component/head.js +0 -22
  29. package/internal/component/scripts.d.ts +0 -4
  30. package/internal/component/scripts.js +0 -23
  31. package/internal/hash.d.ts +0 -4
  32. package/internal/hash.js +0 -10
  33. package/internal/mount.d.ts +0 -2
  34. package/internal/mount.js +0 -81
  35. package/internal/request/http.d.ts +0 -10
  36. package/internal/request/http.js +0 -61
  37. package/internal/request/index.d.ts +0 -16
  38. package/internal/request/index.js +0 -8
  39. package/internal/request/native.d.ts +0 -9
  40. package/internal/request/native.js +0 -48
  41. package/internal/util.d.ts +0 -4
  42. package/internal/util.js +0 -49
  43. package/request/http.d.ts +0 -10
  44. package/request/http.js +0 -59
  45. package/request/index.d.ts +0 -13
  46. package/request/index.js +0 -3
  47. package/request/native.d.ts +0 -9
  48. package/request/native.js +0 -46
  49. package/response.d.ts +0 -13
  50. package/response.js +0 -46
  51. package/router.d.ts +0 -51
  52. package/router.js +0 -231
  53. package/shell.d.ts +0 -120
  54. package/shell.js +0 -253
  55. package/util/parameters.d.ts +0 -7
  56. package/util/parameters.js +0 -14
  57. package/util/path-builder.d.ts +0 -1
  58. package/util/path-builder.js +0 -45
  59. package/util/route.d.ts +0 -2
  60. package/util/route.js +0 -58
  61. package/vite/bundle-splitter.d.ts +0 -4
  62. package/vite/bundle-splitter.js +0 -26
  63. package/vite/client-island.d.ts +0 -4
  64. package/vite/client-island.js +0 -14
  65. package/vite/code-splitting.d.ts +0 -4
  66. package/vite/code-splitting.js +0 -14
  67. package/vite/index.d.ts +0 -3
  68. package/vite/index.js +0 -3
  69. package/vite/router.d.ts +0 -2
  70. package/vite/router.js +0 -29
package/request/http.js DELETED
@@ -1,59 +0,0 @@
1
- import { Resolve } from "~/request/native.js";
2
- export function createRequestHandler(config) {
3
- return async (req, res) => {
4
- try {
5
- const mod = typeof config.build === "function" ? await config.build() : await config.build;
6
- const request = NativeRequest(req);
7
- let { response, headers } = await Resolve(request, mod.tree, config);
8
- res.writeHead(response.status, headers);
9
- if (response.body instanceof ReadableStream) {
10
- const reader = response.body.getReader();
11
- while (true) {
12
- const { done, value } = await reader.read();
13
- if (done)
14
- break;
15
- res.write(value); // `value` is a Uint8Array.
16
- }
17
- res.end();
18
- }
19
- else {
20
- const rendered = await response.text();
21
- res.end(rendered);
22
- }
23
- }
24
- catch (e) {
25
- res.statusCode = 500;
26
- if (e instanceof Error) {
27
- console.error(e.stack);
28
- config.viteDevServer?.ssrFixStacktrace(e);
29
- res.end(e.stack);
30
- }
31
- else {
32
- console.error(e);
33
- res.end(String(e));
34
- }
35
- }
36
- };
37
- }
38
- function NativeRequest(req) {
39
- const ctrl = new AbortController();
40
- const headers = new Headers(req.headers);
41
- const url = new URL(`http://${headers.get('host')}${req.originalUrl || req.url}`);
42
- req.once('aborted', () => ctrl.abort());
43
- const bodied = req.method !== "GET" && req.method !== "HEAD";
44
- const request = new Request(url, {
45
- headers,
46
- method: req.method,
47
- body: bodied ? req : undefined,
48
- signal: ctrl.signal,
49
- referrer: headers.get("referrer") || undefined,
50
- // @ts-ignore
51
- duplex: bodied ? 'half' : undefined
52
- });
53
- if (!request.headers.has("X-Real-IP")) {
54
- const info = req.socket.address();
55
- if ("address" in info)
56
- request.headers.set("X-Real-IP", info.address);
57
- }
58
- return request;
59
- }
@@ -1,13 +0,0 @@
1
- import type { ViteDevServer } from "vite";
2
- import type { GenericContext, RouteTree } from '~/router.js';
3
- import * as native from "~/request/native.js";
4
- import * as http from "~/request/http.js";
5
- export type Config = {
6
- build: Promise<any> | (() => Promise<Record<string, any>>);
7
- viteDevServer: ViteDevServer | null;
8
- render: GenericContext["render"];
9
- };
10
- export type RouterModule = {
11
- tree: RouteTree;
12
- };
13
- export { http, native };
package/request/index.js DELETED
@@ -1,3 +0,0 @@
1
- import * as native from "~/request/native.js";
2
- import * as http from "~/request/http.js";
3
- export { http, native };
@@ -1,9 +0,0 @@
1
- import { type RouteTree } from '~/router.js';
2
- import type { Config } from '~/request/index.js';
3
- export declare function createRequestHandler(config: Config): (req: Request) => Promise<Response>;
4
- export declare function Resolve(request: Request, tree: RouteTree, config: Config): Promise<{
5
- response: Response;
6
- headers: {
7
- [key: string]: string | string[];
8
- };
9
- }>;
package/request/native.js DELETED
@@ -1,46 +0,0 @@
1
- import { GenericContext } from '~/router.js';
2
- export function createRequestHandler(config) {
3
- return async (req) => {
4
- try {
5
- const mod = typeof config.build === "function" ? await config.build() : await config.build;
6
- let { response } = await Resolve(req, mod.tree, config);
7
- return response;
8
- }
9
- catch (e) {
10
- if (e instanceof Error) {
11
- console.error(e.stack);
12
- config.viteDevServer?.ssrFixStacktrace(e);
13
- return new Response(e.message + "\n" + e.stack, { status: 500, statusText: "Internal Server Error" });
14
- }
15
- else {
16
- console.error(e);
17
- return new Response(String(e), { status: 500, statusText: "Internal Server Error" });
18
- }
19
- }
20
- };
21
- }
22
- export async function Resolve(request, tree, config) {
23
- const url = new URL(request.url);
24
- const ctx = new GenericContext(request, url, config.render);
25
- const x = ctx.url.pathname.endsWith("/") ? ctx.url.pathname.slice(0, -1) : ctx.url.pathname;
26
- const fragments = x.split("/").slice(1);
27
- let response = await tree.resolve(fragments, ctx);
28
- if (response === null)
29
- response = new Response("No Route Found", { status: 404, statusText: "Not Found", headers: ctx.headers });
30
- // Override with context headers
31
- if (response.headers !== ctx.headers) {
32
- for (const [key, value] of ctx.headers) {
33
- if (response.headers.has(key))
34
- continue;
35
- response.headers.set(key, value);
36
- }
37
- }
38
- // Merge cookie changes
39
- const headers = Object.fromEntries(response.headers);
40
- const cookies = ctx.cookie.export();
41
- if (cookies.length > 0) {
42
- headers['set-cookie'] = cookies;
43
- response.headers.set("Set-Cookie", cookies[0]); // Response object doesn't support multi-header..[]
44
- }
45
- return { response, headers };
46
- }
package/response.d.ts DELETED
@@ -1,13 +0,0 @@
1
- export declare function text(text: string, init?: ResponseInit): Response;
2
- export type TypedResponse<T> = Omit<Response, "json"> & {
3
- json(): Promise<T>;
4
- };
5
- export type TypedJson<U extends TypedResponse<any>> = U extends TypedResponse<infer T> ? T : never;
6
- export declare function json<T>(data: T, init?: ResponseInit): TypedResponse<T>;
7
- export declare function redirect(url: string, init?: ResponseInit & {
8
- clientOnly?: boolean;
9
- }): Response;
10
- export declare function revalidate(init?: ResponseInit): Response;
11
- export declare function refresh(init?: ResponseInit & {
12
- clientOnly?: boolean;
13
- }): Response;
package/response.js DELETED
@@ -1,46 +0,0 @@
1
- export function text(text, init) {
2
- init ||= {};
3
- init.statusText ||= "ok";
4
- init.status ||= 200;
5
- const res = new Response(text, init);
6
- res.headers.set("Content-Type", "text/plain");
7
- res.headers.set("X-Caught", "true");
8
- return res;
9
- }
10
- export function json(data, init) {
11
- init ||= {};
12
- init.statusText ||= "ok";
13
- init.status ||= 200;
14
- const res = new Response(JSON.stringify(data), init);
15
- res.headers.set("Content-Type", "application/json");
16
- res.headers.set("X-Caught", "true");
17
- return res;
18
- }
19
- export function redirect(url, init) {
20
- init ||= {};
21
- init.statusText ||= "Temporary Redirect";
22
- init.status ||= 307;
23
- const res = new Response("", init);
24
- if (!init?.clientOnly)
25
- res.headers.set("Location", url);
26
- res.headers.set("HX-Location", url); // use hx-boost if applicable
27
- return res;
28
- }
29
- export function revalidate(init) {
30
- init ||= {};
31
- init.statusText ||= "ok";
32
- init.status ||= 200;
33
- const res = new Response("", init);
34
- res.headers.set("HX-Location", "");
35
- return res;
36
- }
37
- export function refresh(init) {
38
- init ||= {};
39
- init.statusText ||= "ok";
40
- init.status ||= 200;
41
- const res = new Response("", init);
42
- if (!init?.clientOnly)
43
- res.headers.set("Refresh", "0"); // fallback
44
- res.headers.set("HX-Refresh", "true");
45
- return res;
46
- }
package/router.d.ts DELETED
@@ -1,51 +0,0 @@
1
- import { Parameterized, ParameterShaper } from './util/parameters.js';
2
- import { RouteModule } from "./index.js";
3
- import { Cookies } from './cookies.js';
4
- export declare function GenerateRouteTree(modules: Record<string, unknown>): RouteTree;
5
- export declare class GenericContext {
6
- request: Request;
7
- headers: Headers;
8
- cookie: Cookies;
9
- params: {
10
- [key: string]: string;
11
- };
12
- url: URL;
13
- render: (res: JSX.Element) => Response;
14
- constructor(request: GenericContext["request"], url: GenericContext["url"], renderer: GenericContext["render"]);
15
- shape<T extends ParameterShaper>(shape: T): RouteContext<T>;
16
- }
17
- export declare class RouteContext<T extends ParameterShaper = {}> {
18
- request: Request;
19
- headers: Headers;
20
- cookie: Cookies;
21
- params: Parameterized<T>;
22
- url: URL;
23
- render: (res: JSX.Element) => Response;
24
- constructor(base: GenericContext, shape: T);
25
- }
26
- export declare class RouteTree {
27
- root: boolean;
28
- nested: Map<string, RouteTree>;
29
- index: RouteLeaf | null;
30
- slug: RouteLeaf | null;
31
- wild: RouteTree | null;
32
- wildCard: string;
33
- constructor(root?: boolean);
34
- ingest(path: string | string[], module: RouteModule<any>): void;
35
- resolve(fragments: string[], ctx: GenericContext): Promise<Response | null>;
36
- private _resolve;
37
- private resolveIndex;
38
- private resolveNext;
39
- private resolveWild;
40
- private resolveSlug;
41
- private resolveNative;
42
- private unwrap;
43
- }
44
- declare class RouteLeaf {
45
- module: RouteModule<any>;
46
- constructor(module: RouteModule<any>);
47
- resolve(ctx: GenericContext): Promise<Response | null>;
48
- error(ctx: GenericContext, e: unknown): Promise<Response>;
49
- private renderWrapper;
50
- }
51
- export {};
package/router.js DELETED
@@ -1,231 +0,0 @@
1
- import { ServerOnlyWarning } from "./internal/util.js";
2
- ServerOnlyWarning("router");
3
- import * as endpoint from './endpoint.js';
4
- import * as dynamic from './dynamic.js';
5
- import * as mount from './internal/mount.js';
6
- import * as css from './css.js';
7
- import { Parameterize } from './util/parameters.js';
8
- import { Cookies } from './cookies.js';
9
- export function GenerateRouteTree(modules) {
10
- const tree = new RouteTree();
11
- for (const path in modules) {
12
- const mod = modules[path];
13
- const tail = path.lastIndexOf(".");
14
- const url = path.slice(9, tail);
15
- tree.ingest(url, mod);
16
- if (mod.route)
17
- mod.route(url);
18
- }
19
- return tree;
20
- }
21
- export class GenericContext {
22
- request;
23
- headers; // response headers
24
- cookie;
25
- params;
26
- url;
27
- render;
28
- constructor(request, url, renderer) {
29
- this.cookie = new Cookies(request.headers);
30
- this.headers = new Headers();
31
- this.request = request;
32
- this.params = {};
33
- this.url = url;
34
- this.render = renderer;
35
- this.headers.set("x-powered-by", "htmx-router");
36
- }
37
- shape(shape) {
38
- return new RouteContext(this, shape);
39
- }
40
- }
41
- export class RouteContext {
42
- request;
43
- headers; // response headers
44
- cookie;
45
- params;
46
- url;
47
- render;
48
- constructor(base, shape) {
49
- this.params = Parameterize(base.params, shape);
50
- this.cookie = base.cookie;
51
- this.headers = base.headers;
52
- this.request = base.request;
53
- this.render = base.render;
54
- this.url = base.url;
55
- }
56
- }
57
- export class RouteTree {
58
- root;
59
- nested;
60
- // Leaf nodes
61
- index; // about._index
62
- // Wild card route
63
- slug; // $
64
- wild; // e.g. $userID
65
- wildCard;
66
- constructor(root = true) {
67
- this.root = root;
68
- this.nested = new Map();
69
- this.wildCard = "";
70
- this.slug = null;
71
- this.wild = null;
72
- this.index = null;
73
- }
74
- ingest(path, module) {
75
- if (!Array.isArray(path))
76
- path = path.split("/");
77
- if (path.length === 0 || (path.length == 1 && path[0] === "_index")) {
78
- this.index = new RouteLeaf(module);
79
- return;
80
- }
81
- if (path[0] === "$") {
82
- this.slug = new RouteLeaf(module);
83
- return;
84
- }
85
- if (path[0][0] === "$") {
86
- const wildCard = path[0].slice(1);
87
- // Check wildcard isn't being changed
88
- if (!this.wild) {
89
- this.wildCard = wildCard;
90
- this.wild = new RouteTree(false);
91
- }
92
- else if (wildCard !== this.wildCard) {
93
- throw new Error(`Redefinition of wild card ${this.wildCard} to ${wildCard}`);
94
- }
95
- path.splice(0, 1);
96
- this.wild.ingest(path, module);
97
- return;
98
- }
99
- let next = this.nested.get(path[0]);
100
- if (!next) {
101
- next = new RouteTree(false);
102
- this.nested.set(path[0], next);
103
- }
104
- path.splice(0, 1);
105
- next.ingest(path, module);
106
- }
107
- async resolve(fragments, ctx) {
108
- if (!this.slug)
109
- return await this._resolve(fragments, ctx);
110
- try {
111
- return await this._resolve(fragments, ctx);
112
- }
113
- catch (e) {
114
- return this.unwrap(ctx, e);
115
- }
116
- }
117
- async _resolve(fragments, ctx) {
118
- let res = await this.resolveNative(fragments, ctx)
119
- || await this.resolveIndex(fragments, ctx)
120
- || await this.resolveNext(fragments, ctx)
121
- || await this.resolveWild(fragments, ctx)
122
- || await this.resolveSlug(fragments, ctx);
123
- if (res instanceof Response) {
124
- if (100 <= res.status && res.status <= 399)
125
- return res;
126
- if (res.headers.has("X-Caught"))
127
- return res;
128
- return this.unwrap(ctx, res);
129
- }
130
- return res;
131
- }
132
- async resolveIndex(fragments, ctx) {
133
- if (fragments.length > 0)
134
- return null;
135
- if (!this.index)
136
- return null;
137
- return await this.index.resolve(ctx);
138
- }
139
- async resolveNext(fragments, ctx) {
140
- if (fragments.length < 1)
141
- return null;
142
- const next = this.nested.get(fragments[0]);
143
- if (!next)
144
- return null;
145
- return await next.resolve(fragments.slice(1), ctx);
146
- }
147
- async resolveWild(fragments, ctx) {
148
- if (!this.wild)
149
- return null;
150
- if (fragments.length < 1)
151
- return null;
152
- ctx.params[this.wildCard] = fragments[0];
153
- return this.wild.resolve(fragments.slice(1), ctx);
154
- }
155
- async resolveSlug(fragments, ctx) {
156
- if (!this.slug)
157
- return null;
158
- ctx.params["$"] = fragments.join("/");
159
- const res = this.slug.resolve
160
- ? await this.slug.resolve(ctx)
161
- : null;
162
- return res;
163
- }
164
- async resolveNative(fragments, ctx) {
165
- if (!this.root)
166
- return null;
167
- if (fragments.length < 2)
168
- return null;
169
- if (fragments[0] != "_")
170
- return null;
171
- return await ResolveNatively(fragments, ctx);
172
- }
173
- async unwrap(ctx, res) {
174
- if (!this.slug)
175
- throw res;
176
- const caught = await this.slug.error(ctx, res);
177
- caught.headers.set("X-Caught", "true");
178
- return caught;
179
- }
180
- }
181
- class RouteLeaf {
182
- module;
183
- constructor(module) {
184
- this.module = module;
185
- }
186
- async resolve(ctx) {
187
- const res = await this.renderWrapper(ctx);
188
- if (res === null)
189
- return null;
190
- if (res instanceof Response)
191
- return res;
192
- return ctx.render(res);
193
- }
194
- async error(ctx, e) {
195
- if (!this.module.error)
196
- throw e;
197
- const res = await this.module.error(ctx, e);
198
- if (res instanceof Response)
199
- return res;
200
- return ctx.render(res);
201
- }
202
- async renderWrapper(ctx) {
203
- try {
204
- if (!this.module.loader && !this.module.action)
205
- return null;
206
- const context = ctx.shape(this.module.parameters || {});
207
- if (ctx.request.method === "HEAD" || ctx.request.method === "GET") {
208
- if (this.module.loader)
209
- return await this.module.loader(context);
210
- else
211
- return null;
212
- }
213
- if (this.module.action)
214
- return await this.module.action(context);
215
- throw new Response("Method not Allowed", { status: 405, statusText: "Method not Allowed", headers: ctx.headers });
216
- }
217
- catch (e) {
218
- return await this.error(ctx, e);
219
- }
220
- return null;
221
- }
222
- }
223
- async function ResolveNatively(fragments, ctx) {
224
- switch (fragments[1]) {
225
- case "dynamic": return dynamic._resolve(fragments, ctx);
226
- case "endpoint": return endpoint._resolve(fragments, ctx);
227
- case "mount": return mount._resolve(fragments);
228
- case "style": return css._resolve(fragments);
229
- }
230
- return null;
231
- }
package/shell.d.ts DELETED
@@ -1,120 +0,0 @@
1
- export type ShellOptions<D = {}> = D & MetaDescriptor;
2
- export declare function ApplyMetaDescriptorDefaults(options: ShellOptions, defaults: Readonly<Partial<ShellOptions>>): void;
3
- export type InferShellOptions<F> = F extends (jsx: any, options: infer U) => any ? U : never;
4
- export type MetaDescriptor = {
5
- title?: string;
6
- description?: string;
7
- meta?: Record<string, string>;
8
- og?: OpenGraph<string>;
9
- jsonLD?: LdJsonObject[];
10
- };
11
- export declare function RenderMetaDescriptor<T>(options: ShellOptions<T>): string;
12
- export type LdJsonObject = {
13
- [Key in string]?: LdJsonValue | undefined;
14
- };
15
- type LdJsonArray = LdJsonValue[] | readonly LdJsonValue[];
16
- type LdJsonPrimitive = string | number | boolean | null;
17
- type LdJsonValue = LdJsonPrimitive | LdJsonObject | LdJsonArray;
18
- export type OpenGraphType = "website" | "article" | "book" | "profile" | "music.song" | "music.album" | "music.playlist" | "music.radio_station" | "video.movie" | "video.episode" | "video.tv_show" | "video.other" | string;
19
- export type OpenGraph<T extends OpenGraphType = string> = {
20
- type?: T;
21
- title?: string;
22
- description?: string;
23
- determiner?: string;
24
- url?: string;
25
- secure_url?: string;
26
- locale?: string | {
27
- base: string;
28
- alternative: string[];
29
- };
30
- image?: OpenGraphImage[];
31
- video?: OpenGraphVideo[];
32
- audio?: OpenGraphAudio[];
33
- } & (T extends "music.song" ? OpenGraphSong : T extends "music.album" ? OpenGraphAlbum : T extends "music.playlist" ? OpenGraphPlaylist : T extends "music.radio_station" ? OpenGraphRadioStation : T extends "video.movie" ? OpenGraphMovie : T extends "video.episode" ? OpenGraphEpisode : T extends "video.tv_show" ? OpenGraphTvShow : T extends "video.other" ? OpenGraphVideoOther : T extends "article" ? OpenGraphArticle : T extends "book" ? OpenGraphBook : T extends "profile" ? OpenGraphProfile : {});
34
- export type OpenGraphImage = {
35
- url: string;
36
- secure_url?: string;
37
- type?: string;
38
- width?: number;
39
- height?: number;
40
- alt?: string;
41
- };
42
- export type OpenGraphVideo = {
43
- url: string;
44
- type?: string;
45
- secure_url?: string;
46
- width?: number;
47
- height?: number;
48
- alt?: string;
49
- };
50
- export type OpenGraphAudio = {
51
- url: string;
52
- type?: string;
53
- secure_url?: string;
54
- };
55
- type OpenGraphSong = {
56
- duration?: number;
57
- album?: Array<string | {
58
- url: string;
59
- disc?: number;
60
- track?: number;
61
- }>;
62
- musician?: string[];
63
- };
64
- type OpenGraphAlbum = {
65
- songs?: Array<string | {
66
- url: string;
67
- disc?: number;
68
- track?: number;
69
- }>;
70
- musician?: string[];
71
- release_date?: Date;
72
- };
73
- type OpenGraphPlaylist = {
74
- songs?: Array<string | {
75
- url: string;
76
- disc?: number;
77
- track?: number;
78
- }>;
79
- creator?: string[];
80
- };
81
- type OpenGraphRadioStation = {
82
- creator?: string[];
83
- };
84
- type OpenGraphMovie = {
85
- actors?: Array<string | {
86
- url: string;
87
- role: string;
88
- }>;
89
- directors?: string[];
90
- writers?: string[];
91
- duration?: number;
92
- release_date?: Date;
93
- tag: string[];
94
- };
95
- type OpenGraphEpisode = OpenGraphMovie & {
96
- series?: string;
97
- };
98
- type OpenGraphTvShow = OpenGraphMovie;
99
- type OpenGraphVideoOther = OpenGraphMovie;
100
- type OpenGraphArticle = {
101
- published_time?: Date;
102
- modified_time?: Date;
103
- expiration_time?: Date;
104
- authors?: string[];
105
- section?: string;
106
- tag?: string;
107
- };
108
- type OpenGraphBook = {
109
- authors?: string[];
110
- isbn?: string;
111
- release_date?: Date;
112
- tag?: string;
113
- };
114
- type OpenGraphProfile = {
115
- first_name?: string;
116
- last_name?: string;
117
- username?: string;
118
- gender?: "male" | "female";
119
- };
120
- export {};