@expo/router-server 0.1.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 ADDED
@@ -0,0 +1 @@
1
+ # @expo/router-server
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Copyright © 2023 650 Industries.
3
+ * Copyright © 2023 Vercel, Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * Based on https://github.com/vercel/next.js/blob/1df2686bc9964f1a86c444701fa5cbf178669833/packages/next/src/shared/lib/router/utils/route-regex.ts
9
+ */
10
+ import type { RouteNode } from 'expo-router/build/Route';
11
+ export type ExpoRouterServerManifestV1Route<TRegex = string> = {
12
+ file: string;
13
+ page: string;
14
+ /**
15
+ * Keys are route param names that have been normalized for a regex named-matcher, values are the original route param names.
16
+ */
17
+ routeKeys: Record<string, string>;
18
+ /**
19
+ * Regex for matching a path against the route.
20
+ * The regex is normalized for named matchers so keys must be looked up against the `routeKeys` object to collect the original route param names.
21
+ * Regex matching alone cannot accurately route to a file, the order in which routes are matched is equally important to ensure correct priority.
22
+ */
23
+ namedRegex: TRegex;
24
+ /** Indicates that the route was generated and does not map to any file in the project's routes directory. */
25
+ generated?: boolean;
26
+ /** Indicates that this is a redirect that should use 301 instead of 307 */
27
+ permanent?: boolean;
28
+ /** If a redirect, which methods are allowed. Undefined represents all methods */
29
+ methods?: string[];
30
+ };
31
+ export type ExpoRouterServerManifestV1Middleware = {
32
+ /**
33
+ * Path to the module that contains the middleware function as a default export.
34
+ *
35
+ * @example _expo/functions/+middleware.js
36
+ */
37
+ file: string;
38
+ };
39
+ export type ExpoRouterServerManifestV1<TRegex = string> = {
40
+ /**
41
+ * Middleware function that runs before any route matching.
42
+ * Only allowed at the root level and requires web.output: "server".
43
+ */
44
+ middleware?: ExpoRouterServerManifestV1Middleware;
45
+ /**
46
+ * Headers to be applied to all responses from the server.
47
+ */
48
+ headers?: Record<string, string | string[]>;
49
+ /**
50
+ * Rewrites. After middleware has processed and regular routing resumes, these occur first.
51
+ */
52
+ rewrites: ExpoRouterServerManifestV1Route<TRegex>[];
53
+ /**
54
+ * List of routes that match second. Returns 301 and redirects to another path.
55
+ */
56
+ redirects: ExpoRouterServerManifestV1Route<TRegex>[];
57
+ /**
58
+ * Routes that return static HTML files for a given path.
59
+ * These are only matched against requests with method `GET` and `HEAD`.
60
+ */
61
+ htmlRoutes: ExpoRouterServerManifestV1Route<TRegex>[];
62
+ /**
63
+ * Routes that are matched after HTML routes and invoke WinterCG-compliant functions.
64
+ */
65
+ apiRoutes: ExpoRouterServerManifestV1Route<TRegex>[];
66
+ /** List of routes that are matched last and return with status code 404. */
67
+ notFoundRoutes: ExpoRouterServerManifestV1Route<TRegex>[];
68
+ };
69
+ export interface Group {
70
+ pos: number;
71
+ repeat: boolean;
72
+ optional: boolean;
73
+ }
74
+ export interface RouteRegex {
75
+ groups: Record<string, Group>;
76
+ re: RegExp;
77
+ }
78
+ type GetServerManifestOptions = {
79
+ headers?: Record<string, string | string[]>;
80
+ };
81
+ export declare function getServerManifest(route: RouteNode, options: GetServerManifestOptions | undefined): ExpoRouterServerManifestV1;
82
+ export declare function parseParameter(param: string): {
83
+ name: string;
84
+ repeat: boolean;
85
+ optional: boolean;
86
+ };
87
+ export {};
88
+ //# sourceMappingURL=getServerManifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getServerManifest.d.ts","sourceRoot":"","sources":["../src/getServerManifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAMzD,MAAM,MAAM,+BAA+B,CAAC,MAAM,GAAG,MAAM,IAAI;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,6GAA6G;IAC7G,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,MAAM,GAAG,MAAM,IAAI;IACxD;;;OAGG;IACH,UAAU,CAAC,EAAE,oCAAoC,CAAC;IAClD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5C;;OAEG;IACH,QAAQ,EAAE,+BAA+B,CAAC,MAAM,CAAC,EAAE,CAAC;IACpD;;OAEG;IACH,SAAS,EAAE,+BAA+B,CAAC,MAAM,CAAC,EAAE,CAAC;IACrD;;;OAGG;IACH,UAAU,EAAE,+BAA+B,CAAC,MAAM,CAAC,EAAE,CAAC;IACtD;;OAEG;IACH,SAAS,EAAE,+BAA+B,CAAC,MAAM,CAAC,EAAE,CAAC;IACrD,4EAA4E;IAC5E,cAAc,EAAE,+BAA+B,CAAC,MAAM,CAAC,EAAE,CAAC;CAC3D,CAAC;AAEF,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC9B,EAAE,EAAE,MAAM,CAAC;CACZ;AAqBD,KAAK,wBAAwB,GAAG;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;CAC7C,CAAC;AAGF,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,wBAAwB,GAAG,SAAS,GAC5C,0BAA0B,CA8F5B;AA6JD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM;;;;EAgB3C"}
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getServerManifest = getServerManifest;
4
+ exports.parseParameter = parseParameter;
5
+ const matchers_1 = require("expo-router/build/matchers");
6
+ const sortRoutes_1 = require("expo-router/build/sortRoutes");
7
+ const url_1 = require("expo-router/build/utils/url");
8
+ function isNotFoundRoute(route) {
9
+ return route.dynamic && route.dynamic[route.dynamic.length - 1].notFound;
10
+ }
11
+ function uniqueBy(arr, key) {
12
+ const seen = new Set();
13
+ return arr.filter((item) => {
14
+ const id = key(item);
15
+ if (seen.has(id)) {
16
+ return false;
17
+ }
18
+ seen.add(id);
19
+ return true;
20
+ });
21
+ }
22
+ // Given a nested route tree, return a flattened array of all routes that can be matched.
23
+ function getServerManifest(route, options) {
24
+ function getFlatNodes(route, parentRoute = '') {
25
+ // Use a recreated route instead of contextKey because we duplicate nodes to support array syntax.
26
+ const absoluteRoute = [parentRoute, route.route].filter(Boolean).join('/');
27
+ if (route.children.length) {
28
+ return route.children.map((child) => getFlatNodes(child, absoluteRoute)).flat();
29
+ }
30
+ // API Routes are handled differently to HTML routes because they have no nested behavior.
31
+ // An HTML route can be different based on parent segments due to layout routes, therefore multiple
32
+ // copies should be rendered. However, an API route is always the same regardless of parent segments.
33
+ let key;
34
+ if (route.type.includes('api')) {
35
+ key = getNormalizedContextKey(route.contextKey);
36
+ }
37
+ else {
38
+ key = getNormalizedContextKey(absoluteRoute);
39
+ }
40
+ return [[key, '/' + absoluteRoute, route]];
41
+ }
42
+ // Remove duplicates from the runtime manifest which expands array syntax.
43
+ const flat = getFlatNodes(route)
44
+ .sort(([, , a], [, , b]) => (0, sortRoutes_1.sortRoutes)(b, a))
45
+ .reverse();
46
+ const apiRoutes = uniqueBy(flat.filter(([, , route]) => route.type === 'api'), ([path]) => path);
47
+ const otherRoutes = uniqueBy(flat.filter(([, , route]) => route.type === 'route' ||
48
+ (route.type === 'rewrite' && (route.methods === undefined || route.methods.includes('GET')))), ([path]) => path);
49
+ const redirects = uniqueBy(flat.filter(([, , route]) => route.type === 'redirect'), ([path]) => path)
50
+ .map((redirect) => {
51
+ // TODO(@hassankhan): ENG-16577
52
+ // For external redirects, use `destinationContextKey` as the destination URL
53
+ if ((0, url_1.shouldLinkExternally)(redirect[2].destinationContextKey)) {
54
+ redirect[1] = redirect[2].destinationContextKey;
55
+ }
56
+ else {
57
+ redirect[1] =
58
+ flat.find(([, , route]) => route.contextKey === redirect[2].destinationContextKey)?.[0] ??
59
+ '/';
60
+ }
61
+ return redirect;
62
+ })
63
+ .reverse();
64
+ const rewrites = uniqueBy(flat.filter(([, , route]) => route.type === 'rewrite'), ([path]) => path)
65
+ .map((rewrite) => {
66
+ rewrite[1] =
67
+ flat.find(([, , route]) => route.contextKey === rewrite[2].destinationContextKey)?.[0] ??
68
+ '/';
69
+ return rewrite;
70
+ })
71
+ .reverse();
72
+ const standardRoutes = otherRoutes.filter(([, , route]) => !isNotFoundRoute(route));
73
+ const notFoundRoutes = otherRoutes.filter(([, , route]) => isNotFoundRoute(route));
74
+ const manifest = {
75
+ apiRoutes: getMatchableManifestForPaths(apiRoutes),
76
+ htmlRoutes: getMatchableManifestForPaths(standardRoutes),
77
+ notFoundRoutes: getMatchableManifestForPaths(notFoundRoutes),
78
+ redirects: getMatchableManifestForPaths(redirects),
79
+ rewrites: getMatchableManifestForPaths(rewrites),
80
+ };
81
+ if (route.middleware) {
82
+ manifest.middleware = {
83
+ file: route.middleware.contextKey,
84
+ };
85
+ }
86
+ if (options?.headers) {
87
+ manifest.headers = options.headers;
88
+ }
89
+ return manifest;
90
+ }
91
+ function getMatchableManifestForPaths(paths) {
92
+ return paths.map(([normalizedRoutePath, absoluteRoute, node]) => {
93
+ const matcher = getNamedRouteRegex(normalizedRoutePath, absoluteRoute, node.contextKey);
94
+ if (node.generated) {
95
+ matcher.generated = true;
96
+ }
97
+ if (node.permanent) {
98
+ matcher.permanent = true;
99
+ }
100
+ if (node.methods) {
101
+ matcher.methods = node.methods;
102
+ }
103
+ return matcher;
104
+ });
105
+ }
106
+ function getNamedRouteRegex(normalizedRoute, page, file) {
107
+ const result = getNamedParametrizedRoute(normalizedRoute);
108
+ return {
109
+ file,
110
+ page,
111
+ namedRegex: `^${result.namedParameterizedRoute}(?:/)?$`,
112
+ routeKeys: result.routeKeys,
113
+ };
114
+ }
115
+ /**
116
+ * Builds a function to generate a minimal routeKey using only a-z and minimal
117
+ * number of characters.
118
+ */
119
+ function buildGetSafeRouteKey() {
120
+ let currentCharCode = 96; // Starting one before 'a' to make the increment logic simpler
121
+ let currentLength = 1;
122
+ return () => {
123
+ let result = '';
124
+ let incrementNext = true;
125
+ // Iterate from right to left to build the key
126
+ for (let i = 0; i < currentLength; i++) {
127
+ if (incrementNext) {
128
+ currentCharCode++;
129
+ if (currentCharCode > 122) {
130
+ currentCharCode = 97; // Reset to 'a'
131
+ incrementNext = true; // Continue to increment the next character
132
+ }
133
+ else {
134
+ incrementNext = false;
135
+ }
136
+ }
137
+ result = String.fromCharCode(currentCharCode) + result;
138
+ }
139
+ // If all characters are 'z', increase the length of the key
140
+ if (incrementNext) {
141
+ currentLength++;
142
+ currentCharCode = 96; // This will make the next key start with 'a'
143
+ }
144
+ return result;
145
+ };
146
+ }
147
+ function removeTrailingSlash(route) {
148
+ return route.replace(/\/$/, '') || '/';
149
+ }
150
+ function getNamedParametrizedRoute(route) {
151
+ const segments = removeTrailingSlash(route).slice(1).split('/');
152
+ const getSafeRouteKey = buildGetSafeRouteKey();
153
+ const routeKeys = {};
154
+ return {
155
+ namedParameterizedRoute: segments
156
+ .map((segment, index) => {
157
+ if (segment === '+not-found' && index === segments.length - 1) {
158
+ segment = '[...not-found]';
159
+ }
160
+ if (/^\[.*\]$/.test(segment)) {
161
+ const { name, optional, repeat } = parseParameter(segment);
162
+ // replace any non-word characters since they can break
163
+ // the named regex
164
+ let cleanedKey = name.replace(/\W/g, '');
165
+ let invalidKey = false;
166
+ // check if the key is still invalid and fallback to using a known
167
+ // safe key
168
+ if (cleanedKey.length === 0 || cleanedKey.length > 30) {
169
+ invalidKey = true;
170
+ }
171
+ if (!isNaN(parseInt(cleanedKey.slice(0, 1), 10))) {
172
+ invalidKey = true;
173
+ }
174
+ // Prevent duplicates after sanitizing the key
175
+ if (cleanedKey in routeKeys) {
176
+ invalidKey = true;
177
+ }
178
+ if (invalidKey) {
179
+ cleanedKey = getSafeRouteKey();
180
+ }
181
+ routeKeys[cleanedKey] = name;
182
+ return repeat
183
+ ? optional
184
+ ? `(?:/(?<${cleanedKey}>.+?))?`
185
+ : `/(?<${cleanedKey}>.+?)`
186
+ : `/(?<${cleanedKey}>[^/]+?)`;
187
+ }
188
+ else if (/^\(.*\)$/.test(segment)) {
189
+ const groupName = (0, matchers_1.matchGroupName)(segment)
190
+ .split(',')
191
+ .map((group) => group.trim())
192
+ .filter(Boolean);
193
+ if (groupName.length > 1) {
194
+ const optionalSegment = `\\((?:${groupName.map(escapeStringRegexp).join('|')})\\)`;
195
+ // Make section optional
196
+ return `(?:/${optionalSegment})?`;
197
+ }
198
+ else {
199
+ // Use simpler regex for single groups
200
+ return `(?:/${escapeStringRegexp(segment)})?`;
201
+ }
202
+ }
203
+ else {
204
+ return `/${escapeStringRegexp(segment)}`;
205
+ }
206
+ })
207
+ .join(''),
208
+ routeKeys,
209
+ };
210
+ }
211
+ // regexp is based on https://github.com/sindresorhus/escape-string-regexp
212
+ const reHasRegExp = /[|\\{}()[\]^$+*?.-]/;
213
+ const reReplaceRegExp = /[|\\{}()[\]^$+*?.-]/g;
214
+ function escapeStringRegexp(str) {
215
+ // see also: https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/escapeRegExp.js#L23
216
+ if (reHasRegExp.test(str)) {
217
+ return str.replace(reReplaceRegExp, '\\$&');
218
+ }
219
+ return str;
220
+ }
221
+ function parseParameter(param) {
222
+ let repeat = false;
223
+ let optional = false;
224
+ let name = param;
225
+ if (/^\[.*\]$/.test(name)) {
226
+ optional = true;
227
+ name = name.slice(1, -1);
228
+ }
229
+ if (/^\.\.\./.test(name)) {
230
+ repeat = true;
231
+ name = name.slice(3);
232
+ }
233
+ return { name, repeat, optional };
234
+ }
235
+ function getNormalizedContextKey(contextKey) {
236
+ return (0, matchers_1.getContextKey)(contextKey).replace(/\/index$/, '') ?? '/';
237
+ }
238
+ //# sourceMappingURL=getServerManifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getServerManifest.js","sourceRoot":"","sources":["../src/getServerManifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright © 2023 650 Industries.\n * Copyright © 2023 Vercel, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * Based on https://github.com/vercel/next.js/blob/1df2686bc9964f1a86c444701fa5cbf178669833/packages/next/src/shared/lib/router/utils/route-regex.ts\n */\nimport type { RouteNode } from 'expo-router/build/Route';\nimport { getContextKey, matchGroupName } from 'expo-router/build/matchers';\nimport { sortRoutes } from 'expo-router/build/sortRoutes';\nimport { shouldLinkExternally } from 'expo-router/build/utils/url';\n\n// TODO: Share these types across cli, server, router, etc.\nexport type ExpoRouterServerManifestV1Route<TRegex = string> = {\n file: string;\n page: string;\n /**\n * Keys are route param names that have been normalized for a regex named-matcher, values are the original route param names.\n */\n routeKeys: Record<string, string>;\n /**\n * Regex for matching a path against the route.\n * The regex is normalized for named matchers so keys must be looked up against the `routeKeys` object to collect the original route param names.\n * Regex matching alone cannot accurately route to a file, the order in which routes are matched is equally important to ensure correct priority.\n */\n namedRegex: TRegex;\n /** Indicates that the route was generated and does not map to any file in the project's routes directory. */\n generated?: boolean;\n /** Indicates that this is a redirect that should use 301 instead of 307 */\n permanent?: boolean;\n /** If a redirect, which methods are allowed. Undefined represents all methods */\n methods?: string[];\n};\n\nexport type ExpoRouterServerManifestV1Middleware = {\n /**\n * Path to the module that contains the middleware function as a default export.\n *\n * @example _expo/functions/+middleware.js\n */\n file: string;\n};\n\nexport type ExpoRouterServerManifestV1<TRegex = string> = {\n /**\n * Middleware function that runs before any route matching.\n * Only allowed at the root level and requires web.output: \"server\".\n */\n middleware?: ExpoRouterServerManifestV1Middleware;\n /**\n * Headers to be applied to all responses from the server.\n */\n headers?: Record<string, string | string[]>;\n /**\n * Rewrites. After middleware has processed and regular routing resumes, these occur first.\n */\n rewrites: ExpoRouterServerManifestV1Route<TRegex>[];\n /**\n * List of routes that match second. Returns 301 and redirects to another path.\n */\n redirects: ExpoRouterServerManifestV1Route<TRegex>[];\n /**\n * Routes that return static HTML files for a given path.\n * These are only matched against requests with method `GET` and `HEAD`.\n */\n htmlRoutes: ExpoRouterServerManifestV1Route<TRegex>[];\n /**\n * Routes that are matched after HTML routes and invoke WinterCG-compliant functions.\n */\n apiRoutes: ExpoRouterServerManifestV1Route<TRegex>[];\n /** List of routes that are matched last and return with status code 404. */\n notFoundRoutes: ExpoRouterServerManifestV1Route<TRegex>[];\n};\n\nexport interface Group {\n pos: number;\n repeat: boolean;\n optional: boolean;\n}\n\nexport interface RouteRegex {\n groups: Record<string, Group>;\n re: RegExp;\n}\n\nfunction isNotFoundRoute(route: RouteNode) {\n return route.dynamic && route.dynamic[route.dynamic.length - 1].notFound;\n}\n\nfunction uniqueBy<T>(arr: T[], key: (item: T) => string): T[] {\n const seen = new Set<string>();\n return arr.filter((item) => {\n const id = key(item);\n if (seen.has(id)) {\n return false;\n }\n seen.add(id);\n return true;\n });\n}\n\n// TODO(@hassankhan): ENG-16575\ntype FlatNodeTuple = [contextKey: string, absoluteRoute: string, node: RouteNode];\n\ntype GetServerManifestOptions = {\n headers?: Record<string, string | string[]>;\n};\n\n// Given a nested route tree, return a flattened array of all routes that can be matched.\nexport function getServerManifest(\n route: RouteNode,\n options: GetServerManifestOptions | undefined\n): ExpoRouterServerManifestV1 {\n function getFlatNodes(route: RouteNode, parentRoute: string = ''): FlatNodeTuple[] {\n // Use a recreated route instead of contextKey because we duplicate nodes to support array syntax.\n const absoluteRoute = [parentRoute, route.route].filter(Boolean).join('/');\n\n if (route.children.length) {\n return route.children.map((child) => getFlatNodes(child, absoluteRoute)).flat();\n }\n\n // API Routes are handled differently to HTML routes because they have no nested behavior.\n // An HTML route can be different based on parent segments due to layout routes, therefore multiple\n // copies should be rendered. However, an API route is always the same regardless of parent segments.\n let key: string;\n if (route.type.includes('api')) {\n key = getNormalizedContextKey(route.contextKey);\n } else {\n key = getNormalizedContextKey(absoluteRoute);\n }\n return [[key, '/' + absoluteRoute, route]];\n }\n\n // Remove duplicates from the runtime manifest which expands array syntax.\n const flat = getFlatNodes(route)\n .sort(([, , a], [, , b]) => sortRoutes(b, a))\n .reverse();\n\n const apiRoutes = uniqueBy(\n flat.filter(([, , route]) => route.type === 'api'),\n ([path]) => path\n );\n\n const otherRoutes = uniqueBy(\n flat.filter(\n ([, , route]) =>\n route.type === 'route' ||\n (route.type === 'rewrite' && (route.methods === undefined || route.methods.includes('GET')))\n ),\n ([path]) => path\n );\n\n const redirects = uniqueBy(\n flat.filter(([, , route]) => route.type === 'redirect'),\n ([path]) => path\n )\n .map((redirect) => {\n // TODO(@hassankhan): ENG-16577\n // For external redirects, use `destinationContextKey` as the destination URL\n if (shouldLinkExternally(redirect[2].destinationContextKey!)) {\n redirect[1] = redirect[2].destinationContextKey!;\n } else {\n redirect[1] =\n flat.find(([, , route]) => route.contextKey === redirect[2].destinationContextKey)?.[0] ??\n '/';\n }\n\n return redirect;\n })\n .reverse();\n\n const rewrites = uniqueBy(\n flat.filter(([, , route]) => route.type === 'rewrite'),\n ([path]) => path\n )\n .map((rewrite) => {\n rewrite[1] =\n flat.find(([, , route]) => route.contextKey === rewrite[2].destinationContextKey)?.[0] ??\n '/';\n\n return rewrite;\n })\n .reverse();\n\n const standardRoutes = otherRoutes.filter(([, , route]) => !isNotFoundRoute(route));\n const notFoundRoutes = otherRoutes.filter(([, , route]) => isNotFoundRoute(route));\n\n const manifest: ExpoRouterServerManifestV1 = {\n apiRoutes: getMatchableManifestForPaths(apiRoutes),\n htmlRoutes: getMatchableManifestForPaths(standardRoutes),\n notFoundRoutes: getMatchableManifestForPaths(notFoundRoutes),\n redirects: getMatchableManifestForPaths(redirects),\n rewrites: getMatchableManifestForPaths(rewrites),\n };\n\n if (route.middleware) {\n manifest.middleware = {\n file: route.middleware.contextKey,\n };\n }\n\n if (options?.headers) {\n manifest.headers = options.headers;\n }\n\n return manifest;\n}\n\nfunction getMatchableManifestForPaths(\n paths: [string, string, RouteNode][]\n): ExpoRouterServerManifestV1Route[] {\n return paths.map(([normalizedRoutePath, absoluteRoute, node]) => {\n const matcher: ExpoRouterServerManifestV1Route = getNamedRouteRegex(\n normalizedRoutePath,\n absoluteRoute,\n node.contextKey\n );\n\n if (node.generated) {\n matcher.generated = true;\n }\n\n if (node.permanent) {\n matcher.permanent = true;\n }\n\n if (node.methods) {\n matcher.methods = node.methods;\n }\n\n return matcher;\n });\n}\n\nfunction getNamedRouteRegex(\n normalizedRoute: string,\n page: string,\n file: string\n): ExpoRouterServerManifestV1Route {\n const result = getNamedParametrizedRoute(normalizedRoute);\n return {\n file,\n page,\n namedRegex: `^${result.namedParameterizedRoute}(?:/)?$`,\n routeKeys: result.routeKeys,\n };\n}\n\n/**\n * Builds a function to generate a minimal routeKey using only a-z and minimal\n * number of characters.\n */\nfunction buildGetSafeRouteKey() {\n let currentCharCode = 96; // Starting one before 'a' to make the increment logic simpler\n let currentLength = 1;\n\n return () => {\n let result = '';\n let incrementNext = true;\n\n // Iterate from right to left to build the key\n for (let i = 0; i < currentLength; i++) {\n if (incrementNext) {\n currentCharCode++;\n if (currentCharCode > 122) {\n currentCharCode = 97; // Reset to 'a'\n incrementNext = true; // Continue to increment the next character\n } else {\n incrementNext = false;\n }\n }\n result = String.fromCharCode(currentCharCode) + result;\n }\n\n // If all characters are 'z', increase the length of the key\n if (incrementNext) {\n currentLength++;\n currentCharCode = 96; // This will make the next key start with 'a'\n }\n\n return result;\n };\n}\n\nfunction removeTrailingSlash(route: string): string {\n return route.replace(/\\/$/, '') || '/';\n}\n\nfunction getNamedParametrizedRoute(route: string) {\n const segments = removeTrailingSlash(route).slice(1).split('/');\n const getSafeRouteKey = buildGetSafeRouteKey();\n const routeKeys: Record<string, string> = {};\n return {\n namedParameterizedRoute: segments\n .map((segment, index) => {\n if (segment === '+not-found' && index === segments.length - 1) {\n segment = '[...not-found]';\n }\n if (/^\\[.*\\]$/.test(segment)) {\n const { name, optional, repeat } = parseParameter(segment);\n // replace any non-word characters since they can break\n // the named regex\n let cleanedKey = name.replace(/\\W/g, '');\n let invalidKey = false;\n\n // check if the key is still invalid and fallback to using a known\n // safe key\n if (cleanedKey.length === 0 || cleanedKey.length > 30) {\n invalidKey = true;\n }\n if (!isNaN(parseInt(cleanedKey.slice(0, 1), 10))) {\n invalidKey = true;\n }\n\n // Prevent duplicates after sanitizing the key\n if (cleanedKey in routeKeys) {\n invalidKey = true;\n }\n\n if (invalidKey) {\n cleanedKey = getSafeRouteKey();\n }\n\n routeKeys[cleanedKey] = name;\n return repeat\n ? optional\n ? `(?:/(?<${cleanedKey}>.+?))?`\n : `/(?<${cleanedKey}>.+?)`\n : `/(?<${cleanedKey}>[^/]+?)`;\n } else if (/^\\(.*\\)$/.test(segment)) {\n const groupName = matchGroupName(segment)!\n .split(',')\n .map((group) => group.trim())\n .filter(Boolean);\n if (groupName.length > 1) {\n const optionalSegment = `\\\\((?:${groupName.map(escapeStringRegexp).join('|')})\\\\)`;\n // Make section optional\n return `(?:/${optionalSegment})?`;\n } else {\n // Use simpler regex for single groups\n return `(?:/${escapeStringRegexp(segment)})?`;\n }\n } else {\n return `/${escapeStringRegexp(segment)}`;\n }\n })\n .join(''),\n routeKeys,\n };\n}\n\n// regexp is based on https://github.com/sindresorhus/escape-string-regexp\nconst reHasRegExp = /[|\\\\{}()[\\]^$+*?.-]/;\nconst reReplaceRegExp = /[|\\\\{}()[\\]^$+*?.-]/g;\n\nfunction escapeStringRegexp(str: string) {\n // see also: https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/escapeRegExp.js#L23\n if (reHasRegExp.test(str)) {\n return str.replace(reReplaceRegExp, '\\\\$&');\n }\n return str;\n}\n\nexport function parseParameter(param: string) {\n let repeat = false;\n let optional = false;\n let name = param;\n\n if (/^\\[.*\\]$/.test(name)) {\n optional = true;\n name = name.slice(1, -1);\n }\n\n if (/^\\.\\.\\./.test(name)) {\n repeat = true;\n name = name.slice(3);\n }\n\n return { name, repeat, optional };\n}\n\nfunction getNormalizedContextKey(contextKey: string): string {\n return getContextKey(contextKey).replace(/\\/index$/, '') ?? '/';\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { type Options } from 'expo-router/build/getRoutesSSR';
2
+ export { Options };
3
+ export type RouteInfo<TRegex = string> = {
4
+ file: string;
5
+ page: string;
6
+ namedRegex: TRegex;
7
+ routeKeys: Record<string, string>;
8
+ permanent?: boolean;
9
+ methods?: string[];
10
+ };
11
+ export type MiddlewareInfo = {
12
+ /**
13
+ * Path to the module that contains the middleware function as a default export.
14
+ *
15
+ * @example _expo/functions/+middleware.js
16
+ */
17
+ file: string;
18
+ };
19
+ export type ExpoRoutesManifestV1<TRegex = string> = {
20
+ middleware?: MiddlewareInfo;
21
+ apiRoutes: RouteInfo<TRegex>[];
22
+ htmlRoutes: RouteInfo<TRegex>[];
23
+ notFoundRoutes: RouteInfo<TRegex>[];
24
+ redirects: RouteInfo<TRegex>[];
25
+ rewrites: RouteInfo<TRegex>[];
26
+ };
27
+ export declare function createRoutesManifest(paths: string[], options: Options): ExpoRoutesManifestV1 | null;
28
+ //# sourceMappingURL=routes-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-manifest.d.ts","sourceRoot":"","sources":["../src/routes-manifest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAa,MAAM,gCAAgC,CAAC;AAIzE,OAAO,EAAE,OAAO,EAAE,CAAC;AAEnB,MAAM,MAAM,SAAS,CAAC,MAAM,GAAG,MAAM,IAAI;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,CAAC,MAAM,GAAG,MAAM,IAAI;IAClD,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/B,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;IAChC,cAAc,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;IACpC,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;CAC/B,CAAC;AAYF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE,OAAO,GACf,oBAAoB,GAAG,IAAI,CAe7B"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRoutesManifest = createRoutesManifest;
4
+ const getRoutesSSR_1 = require("expo-router/build/getRoutesSSR");
5
+ const getServerManifest_1 = require("./getServerManifest");
6
+ function createMockContextModule(map = []) {
7
+ const contextModule = (_key) => ({ default() { } });
8
+ Object.defineProperty(contextModule, 'keys', {
9
+ value: () => map,
10
+ });
11
+ return contextModule;
12
+ }
13
+ function createRoutesManifest(paths, options) {
14
+ // TODO: Drop this part for Node.js
15
+ const routeTree = (0, getRoutesSSR_1.getRoutes)(createMockContextModule(paths), {
16
+ ...options,
17
+ preserveApiRoutes: true,
18
+ preserveRedirectAndRewrites: true,
19
+ ignoreRequireErrors: true,
20
+ ignoreEntryPoints: true,
21
+ platform: 'web',
22
+ });
23
+ if (!routeTree) {
24
+ return null;
25
+ }
26
+ return (0, getServerManifest_1.getServerManifest)(routeTree, { headers: options.headers });
27
+ }
28
+ //# sourceMappingURL=routes-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-manifest.js","sourceRoot":"","sources":["../src/routes-manifest.ts"],"names":[],"mappings":";;AA8CA,oDAkBC;AA7DD,iEAAyE;AAEzE,2DAAwD;AA+BxD,SAAS,uBAAuB,CAAC,MAAgB,EAAE;IACjD,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,KAAI,CAAC,EAAE,CAAC,CAAC;IAE3D,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE;QAC3C,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG;KACjB,CAAC,CAAC;IAEH,OAAO,aAA+B,CAAC;AACzC,CAAC;AAED,SAAgB,oBAAoB,CAClC,KAAe,EACf,OAAgB;IAEhB,mCAAmC;IACnC,MAAM,SAAS,GAAG,IAAA,wBAAS,EAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE;QAC1D,GAAG,OAAO;QACV,iBAAiB,EAAE,IAAI;QACvB,2BAA2B,EAAE,IAAI;QACjC,mBAAmB,EAAE,IAAI;QACzB,iBAAiB,EAAE,IAAI;QACvB,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAA,qCAAiB,EAAC,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AACpE,CAAC","sourcesContent":["// This file runs in Node.js environments.\n// no relative imports\nimport { type RequireContext } from 'expo-router';\nimport { type Options, getRoutes } from 'expo-router/build/getRoutesSSR';\n\nimport { getServerManifest } from './getServerManifest';\n\nexport { Options };\n\nexport type RouteInfo<TRegex = string> = {\n file: string;\n page: string;\n namedRegex: TRegex;\n routeKeys: Record<string, string>;\n permanent?: boolean;\n methods?: string[];\n};\n\nexport type MiddlewareInfo = {\n /**\n * Path to the module that contains the middleware function as a default export.\n *\n * @example _expo/functions/+middleware.js\n */\n file: string;\n};\n\nexport type ExpoRoutesManifestV1<TRegex = string> = {\n middleware?: MiddlewareInfo;\n apiRoutes: RouteInfo<TRegex>[];\n htmlRoutes: RouteInfo<TRegex>[];\n notFoundRoutes: RouteInfo<TRegex>[];\n redirects: RouteInfo<TRegex>[];\n rewrites: RouteInfo<TRegex>[];\n};\n\nfunction createMockContextModule(map: string[] = []) {\n const contextModule = (_key: string) => ({ default() {} });\n\n Object.defineProperty(contextModule, 'keys', {\n value: () => map,\n });\n\n return contextModule as RequireContext;\n}\n\nexport function createRoutesManifest(\n paths: string[],\n options: Options\n): ExpoRoutesManifestV1 | null {\n // TODO: Drop this part for Node.js\n const routeTree = getRoutes(createMockContextModule(paths), {\n ...options,\n preserveApiRoutes: true,\n preserveRedirectAndRewrites: true,\n ignoreRequireErrors: true,\n ignoreEntryPoints: true,\n platform: 'web',\n });\n\n if (!routeTree) {\n return null;\n }\n return getServerManifest(routeTree, { headers: options.headers });\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright © 2023 650 Industries.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ export declare function getRootComponent(): any;
8
+ //# sourceMappingURL=getRootComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getRootComponent.d.ts","sourceRoot":"","sources":["../../src/static/getRootComponent.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,wBAAgB,gBAAgB,QAe/B"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright © 2023 650 Industries.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getRootComponent = getRootComponent;
10
+ const _ctx_html_1 = require("expo-router/_ctx-html");
11
+ function getRootComponent() {
12
+ const keys = _ctx_html_1.ctx.keys();
13
+ if (!keys.length) {
14
+ return require('./html').Html;
15
+ }
16
+ if (keys.length > 1) {
17
+ throw new Error(`Multiple components match the root HTML element: ${keys.join(', ')}`);
18
+ }
19
+ const exp = (0, _ctx_html_1.ctx)(keys[0]);
20
+ if (!exp.default) {
21
+ throw new Error(`The root HTML element "${keys[0]}" is missing the required default export.`);
22
+ }
23
+ return exp.default;
24
+ }
25
+ //# sourceMappingURL=getRootComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getRootComponent.js","sourceRoot":"","sources":["../../src/static/getRootComponent.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAIH,4CAeC;AAjBD,qDAA2D;AAE3D,SAAgB,gBAAgB;IAC9B,MAAM,IAAI,GAAG,eAAW,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,OAAQ,OAAO,CAAC,QAAQ,CAA6B,CAAC,IAAI,CAAC;IAC7D,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,oDAAoD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,MAAM,GAAG,GAAG,IAAA,eAAW,EAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC","sourcesContent":["/**\n * Copyright © 2023 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { ctx as rootContext } from 'expo-router/_ctx-html';\n\nexport function getRootComponent() {\n const keys = rootContext.keys();\n if (!keys.length) {\n return (require('./html') as typeof import('./html')).Html;\n }\n if (keys.length > 1) {\n throw new Error(`Multiple components match the root HTML element: ${keys.join(', ')}`);\n }\n const exp = rootContext(keys[0]);\n\n if (!exp.default) {\n throw new Error(`The root HTML element \"${keys[0]}\" is missing the required default export.`);\n }\n\n return exp.default;\n}\n"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Copyright © 2024 650 Industries.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { type Options } from 'expo-router/build/getRoutes';
8
+ import { type ExpoRouterServerManifestV1 } from '../getServerManifest';
9
+ /**
10
+ * Get the server manifest with all dynamic routes loaded with `generateStaticParams`.
11
+ * Unlike the `@expo/router-server/src/routes-manifest.ts` method, this requires loading the entire app in-memory, which
12
+ * takes substantially longer and requires Metro bundling.
13
+ *
14
+ * This is used for the production manifest where we pre-render certain pages and should no longer treat them as dynamic.
15
+ */
16
+ export declare function getBuildTimeServerManifestAsync(options?: Options): Promise<ExpoRouterServerManifestV1>;
17
+ /** Get the linking manifest from a Node.js process. */
18
+ export declare function getManifest(options?: Options): Promise<{
19
+ initialRouteName: undefined;
20
+ screens: Record<string, import("expo-router/build/getReactNavigationConfig").Screen>;
21
+ }>;
22
+ //# sourceMappingURL=getServerManifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getServerManifest.d.ts","sourceRoot":"","sources":["../../src/static/getServerManifest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAGtE,OAAO,EAAE,KAAK,0BAA0B,EAAqB,MAAM,sBAAsB,CAAC;AAE1F;;;;;;GAMG;AACH,wBAAsB,+BAA+B,CACnD,OAAO,GAAE,OAAY,GACpB,OAAO,CAAC,0BAA0B,CAAC,CAcrC;AAED,uDAAuD;AACvD,wBAAsB,WAAW,CAAC,OAAO,GAAE,OAAY;;;GAgBtD"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright © 2024 650 Industries.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getBuildTimeServerManifestAsync = getBuildTimeServerManifestAsync;
10
+ exports.getManifest = getManifest;
11
+ const _ctx_1 = require("expo-router/_ctx");
12
+ const getReactNavigationConfig_1 = require("expo-router/build/getReactNavigationConfig");
13
+ const getRoutes_1 = require("expo-router/build/getRoutes");
14
+ const loadStaticParamsAsync_1 = require("expo-router/build/loadStaticParamsAsync");
15
+ const getServerManifest_1 = require("../getServerManifest");
16
+ /**
17
+ * Get the server manifest with all dynamic routes loaded with `generateStaticParams`.
18
+ * Unlike the `@expo/router-server/src/routes-manifest.ts` method, this requires loading the entire app in-memory, which
19
+ * takes substantially longer and requires Metro bundling.
20
+ *
21
+ * This is used for the production manifest where we pre-render certain pages and should no longer treat them as dynamic.
22
+ */
23
+ async function getBuildTimeServerManifestAsync(options = {}) {
24
+ const routeTree = (0, getRoutes_1.getRoutes)(_ctx_1.ctx, {
25
+ platform: 'web',
26
+ ...options,
27
+ });
28
+ if (!routeTree) {
29
+ throw new Error('No routes found');
30
+ }
31
+ // Evaluate all static params
32
+ await (0, loadStaticParamsAsync_1.loadStaticParamsAsync)(routeTree);
33
+ return (0, getServerManifest_1.getServerManifest)(routeTree, options);
34
+ }
35
+ /** Get the linking manifest from a Node.js process. */
36
+ async function getManifest(options = {}) {
37
+ const routeTree = (0, getRoutes_1.getRoutes)(_ctx_1.ctx, {
38
+ preserveApiRoutes: true,
39
+ preserveRedirectAndRewrites: true,
40
+ platform: 'web',
41
+ ...options,
42
+ });
43
+ if (!routeTree) {
44
+ throw new Error('No routes found');
45
+ }
46
+ // Evaluate all static params
47
+ await (0, loadStaticParamsAsync_1.loadStaticParamsAsync)(routeTree);
48
+ return (0, getReactNavigationConfig_1.getReactNavigationConfig)(routeTree, false);
49
+ }
50
+ //# sourceMappingURL=getServerManifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getServerManifest.js","sourceRoot":"","sources":["../../src/static/getServerManifest.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAgBH,0EAgBC;AAGD,kCAgBC;AAjDD,2CAAuC;AACvC,yFAAsF;AACtF,2DAAsE;AACtE,mFAAgF;AAEhF,4DAA0F;AAE1F;;;;;;GAMG;AACI,KAAK,UAAU,+BAA+B,CACnD,UAAmB,EAAE;IAErB,MAAM,SAAS,GAAG,IAAA,qBAAS,EAAC,UAAG,EAAE;QAC/B,QAAQ,EAAE,KAAK;QACf,GAAG,OAAO;KACX,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,6BAA6B;IAC7B,MAAM,IAAA,6CAAqB,EAAC,SAAS,CAAC,CAAC;IAEvC,OAAO,IAAA,qCAAiB,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,uDAAuD;AAChD,KAAK,UAAU,WAAW,CAAC,UAAmB,EAAE;IACrD,MAAM,SAAS,GAAG,IAAA,qBAAS,EAAC,UAAG,EAAE;QAC/B,iBAAiB,EAAE,IAAI;QACvB,2BAA2B,EAAE,IAAI;QACjC,QAAQ,EAAE,KAAK;QACf,GAAG,OAAO;KACX,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,6BAA6B;IAC7B,MAAM,IAAA,6CAAqB,EAAC,SAAS,CAAC,CAAC;IAEvC,OAAO,IAAA,mDAAwB,EAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AACpD,CAAC","sourcesContent":["/**\n * Copyright © 2024 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { ctx } from 'expo-router/_ctx';\nimport { getReactNavigationConfig } from 'expo-router/build/getReactNavigationConfig';\nimport { getRoutes, type Options } from 'expo-router/build/getRoutes';\nimport { loadStaticParamsAsync } from 'expo-router/build/loadStaticParamsAsync';\n\nimport { type ExpoRouterServerManifestV1, getServerManifest } from '../getServerManifest';\n\n/**\n * Get the server manifest with all dynamic routes loaded with `generateStaticParams`.\n * Unlike the `@expo/router-server/src/routes-manifest.ts` method, this requires loading the entire app in-memory, which\n * takes substantially longer and requires Metro bundling.\n *\n * This is used for the production manifest where we pre-render certain pages and should no longer treat them as dynamic.\n */\nexport async function getBuildTimeServerManifestAsync(\n options: Options = {}\n): Promise<ExpoRouterServerManifestV1> {\n const routeTree = getRoutes(ctx, {\n platform: 'web',\n ...options,\n });\n\n if (!routeTree) {\n throw new Error('No routes found');\n }\n\n // Evaluate all static params\n await loadStaticParamsAsync(routeTree);\n\n return getServerManifest(routeTree, options);\n}\n\n/** Get the linking manifest from a Node.js process. */\nexport async function getManifest(options: Options = {}) {\n const routeTree = getRoutes(ctx, {\n preserveApiRoutes: true,\n preserveRedirectAndRewrites: true,\n platform: 'web',\n ...options,\n });\n\n if (!routeTree) {\n throw new Error('No routes found');\n }\n\n // Evaluate all static params\n await loadStaticParamsAsync(routeTree);\n\n return getReactNavigationConfig(routeTree, false);\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import React, { type PropsWithChildren } from 'react';
2
+ /**
3
+ * Injects loader data into the HTML as a script tag for client-side hydration.
4
+ * The data is serialized as JSON and made available on the `globalThis.__EXPO_ROUTER_LOADER_DATA__` global.
5
+ */
6
+ export declare function PreloadedDataScript({ data }: {
7
+ data: Record<string, unknown>;
8
+ }): React.JSX.Element;
9
+ export declare function Html({ children }: PropsWithChildren): React.JSX.Element;
10
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/static/html.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAItD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,qBAc9E;AAED,wBAAgB,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,iBAAiB,qBAYnD"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PreloadedDataScript = PreloadedDataScript;
7
+ exports.Html = Html;
8
+ /**
9
+ * Copyright © 2023 650 Industries.
10
+ *
11
+ * This source code is licensed under the MIT license found in the
12
+ * LICENSE file in the root directory of this source tree.
13
+ */
14
+ const html_1 = require("expo-router/html");
15
+ const react_1 = __importDefault(require("react"));
16
+ const html_2 = require("../utils/html");
17
+ /**
18
+ * Injects loader data into the HTML as a script tag for client-side hydration.
19
+ * The data is serialized as JSON and made available on the `globalThis.__EXPO_ROUTER_LOADER_DATA__` global.
20
+ */
21
+ function PreloadedDataScript({ data }) {
22
+ const safeJson = (0, html_2.escapeUnsafeCharacters)(JSON.stringify(data));
23
+ return (<script id="expo-router-data" type="module" dangerouslySetInnerHTML={{
24
+ // NOTE(@hassankhan): The double serialization used here isn't as much of a problem server-side, but allows faster
25
+ // client-side parsing using native `JSON.parse()`. See https://v8.dev/blog/cost-of-javascript-2019#json
26
+ __html: `globalThis.__EXPO_ROUTER_LOADER_DATA__ = JSON.parse(${JSON.stringify(safeJson)});`,
27
+ }}/>);
28
+ }
29
+ function Html({ children }) {
30
+ return (<html lang="en">
31
+ <head>
32
+ <meta charSet="utf-8"/>
33
+ <meta httpEquiv="X-UA-Compatible" content="IE=edge"/>
34
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
35
+ <html_1.ScrollViewStyleReset />
36
+ </head>
37
+ <body>{children}</body>
38
+ </html>);
39
+ }
40
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/static/html.tsx"],"names":[],"mappings":";;;;;AAeA,kDAcC;AAED,oBAYC;AA3CD;;;;;GAKG;AACH,2CAAwD;AACxD,kDAAsD;AAEtD,wCAAuD;AAEvD;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAqC;IAC7E,MAAM,QAAQ,GAAG,IAAA,6BAAsB,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAE9D,OAAO,CACL,CAAC,MAAM,CACL,EAAE,CAAC,kBAAkB,CACrB,IAAI,CAAC,QAAQ,CACb,uBAAuB,CAAC,CAAC;YACvB,kHAAkH;YAClH,wGAAwG;YACxG,MAAM,EAAE,uDAAuD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI;SAC5F,CAAC,EACF,CACH,CAAC;AACJ,CAAC;AAED,SAAgB,IAAI,CAAC,EAAE,QAAQ,EAAqB;IAClD,OAAO,CACL,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CACb;MAAA,CAAC,IAAI,CACH;QAAA,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EACrB;QAAA,CAAC,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,OAAO,CAAC,SAAS,EACnD;QAAA,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,uDAAuD,EACrF;QAAA,CAAC,2BAAoB,CAAC,AAAD,EACvB;MAAA,EAAE,IAAI,CACN;MAAA,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CACxB;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Copyright © 2023 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport { ScrollViewStyleReset } from 'expo-router/html';\nimport React, { type PropsWithChildren } from 'react';\n\nimport { escapeUnsafeCharacters } from '../utils/html';\n\n/**\n * Injects loader data into the HTML as a script tag for client-side hydration.\n * The data is serialized as JSON and made available on the `globalThis.__EXPO_ROUTER_LOADER_DATA__` global.\n */\nexport function PreloadedDataScript({ data }: { data: Record<string, unknown> }) {\n const safeJson = escapeUnsafeCharacters(JSON.stringify(data));\n\n return (\n <script\n id=\"expo-router-data\"\n type=\"module\"\n dangerouslySetInnerHTML={{\n // NOTE(@hassankhan): The double serialization used here isn't as much of a problem server-side, but allows faster\n // client-side parsing using native `JSON.parse()`. See https://v8.dev/blog/cost-of-javascript-2019#json\n __html: `globalThis.__EXPO_ROUTER_LOADER_DATA__ = JSON.parse(${JSON.stringify(safeJson)});`,\n }}\n />\n );\n}\n\nexport function Html({ children }: PropsWithChildren) {\n return (\n <html lang=\"en\">\n <head>\n <meta charSet=\"utf-8\" />\n <meta httpEquiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\" />\n <ScrollViewStyleReset />\n </head>\n <body>{children}</body>\n </html>\n );\n}\n"]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright © 2023 650 Industries.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import '@expo/metro-runtime';
8
+ type GetStaticContentOptions = {
9
+ loader?: {
10
+ data?: any;
11
+ };
12
+ };
13
+ export declare function getStaticContent(location: URL, options?: GetStaticContentOptions): Promise<string>;
14
+ export { getBuildTimeServerManifestAsync, getManifest } from './getServerManifest';
15
+ //# sourceMappingURL=renderStaticContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderStaticContent.d.ts","sourceRoot":"","sources":["../../src/static/renderStaticContent.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,qBAAqB,CAAC;AA8B7B,KAAK,uBAAuB,GAAG;IAC7B,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,GAAG,CAAC;KACZ,CAAC;CACH,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,GAAG,EACb,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,MAAM,CAAC,CA+DjB;AAmBD,OAAO,EAAE,+BAA+B,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getManifest = exports.getBuildTimeServerManifestAsync = void 0;
40
+ exports.getStaticContent = getStaticContent;
41
+ /**
42
+ * Copyright © 2023 650 Industries.
43
+ *
44
+ * This source code is licensed under the MIT license found in the
45
+ * LICENSE file in the root directory of this source tree.
46
+ */
47
+ require("@expo/metro-runtime");
48
+ const native_1 = require("@react-navigation/native");
49
+ const Font = __importStar(require("expo-font/build/server"));
50
+ const expo_router_1 = require("expo-router");
51
+ const _ctx_1 = require("expo-router/_ctx");
52
+ const ServerDataLoaderContext_1 = require("expo-router/build/loaders/ServerDataLoaderContext");
53
+ const head_1 = __importDefault(require("expo-router/head"));
54
+ const react_1 = __importDefault(require("react"));
55
+ const server_node_1 = __importDefault(require("react-dom/server.node"));
56
+ // @ts-expect-error: TODO(@kitten): Define this type (seems to differ from react-native)
57
+ const react_native_web_1 = require("react-native-web");
58
+ const getRootComponent_1 = require("./getRootComponent");
59
+ const html_1 = require("./html");
60
+ const debug = require('debug')('expo:router:server:renderStaticContent');
61
+ react_native_web_1.AppRegistry.registerComponent('App', () => expo_router_1.ExpoRoot);
62
+ function resetReactNavigationContexts() {
63
+ // https://github.com/expo/router/discussions/588
64
+ // https://github.com/react-navigation/react-navigation/blob/9fe34b445fcb86e5666f61e144007d7540f014fa/packages/elements/src/getNamedContext.tsx#LL3C1-L4C1
65
+ // React Navigation is storing providers in a global, this is fine for the first static render
66
+ // but subsequent static renders of Stack or Tabs will cause React to throw a warning. To prevent this warning, we'll reset the globals before rendering.
67
+ const contexts = '__react_navigation__elements_contexts';
68
+ globalThis[contexts] = new Map();
69
+ }
70
+ async function getStaticContent(location, options) {
71
+ const headContext = {};
72
+ const ref = react_1.default.createRef();
73
+ const {
74
+ // NOTE: The `element` that's returned adds two extra Views and
75
+ // the seemingly unused `RootTagContext.Provider`.
76
+ element, getStyleElement, } = react_native_web_1.AppRegistry.getApplication('App', {
77
+ initialProps: {
78
+ location,
79
+ context: _ctx_1.ctx,
80
+ wrapper: ({ children }) => (<Root>
81
+ <div id="root">{children}</div>
82
+ </Root>),
83
+ },
84
+ });
85
+ const Root = (0, getRootComponent_1.getRootComponent)();
86
+ // Clear any existing static resources from the global scope to attempt to prevent leaking between pages.
87
+ // This could break if pages are rendered in parallel or if fonts are loaded outside of the React tree
88
+ Font.resetServerContext();
89
+ // This MUST be run before `ReactDOMServer.renderToString` to prevent
90
+ // "Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported."
91
+ resetReactNavigationContexts();
92
+ const loadedData = options?.loader?.data ? { [location.pathname]: options.loader.data } : null;
93
+ const html = await server_node_1.default.renderToString(<head_1.default.Provider context={headContext}>
94
+ <ServerDataLoaderContext_1.ServerDataLoaderContext value={loadedData}>
95
+ <native_1.ServerContainer ref={ref}>{element}</native_1.ServerContainer>
96
+ </ServerDataLoaderContext_1.ServerDataLoaderContext>
97
+ </head_1.default.Provider>);
98
+ // Eval the CSS after the HTML is rendered so that the CSS is in the same order
99
+ const css = server_node_1.default.renderToStaticMarkup(getStyleElement());
100
+ let output = mixHeadComponentsWithStaticResults(headContext.helmet, html);
101
+ output = output.replace('</head>', `${css}</head>`);
102
+ const fonts = Font.getServerResources();
103
+ debug(`Pushing static fonts: (count: ${fonts.length})`, fonts);
104
+ // debug('Push static fonts:', fonts)
105
+ // Inject static fonts loaded with expo-font
106
+ output = output.replace('</head>', `${fonts.join('')}</head>`);
107
+ if (loadedData) {
108
+ const loaderDataScript = server_node_1.default.renderToStaticMarkup(<html_1.PreloadedDataScript data={loadedData}/>);
109
+ output = output.replace('</head>', `${loaderDataScript}</head>`);
110
+ }
111
+ return '<!DOCTYPE html>' + output;
112
+ }
113
+ function mixHeadComponentsWithStaticResults(helmet, html) {
114
+ // Head components
115
+ for (const key of ['title', 'priority', 'meta', 'link', 'script', 'style'].reverse()) {
116
+ const result = helmet?.[key]?.toString();
117
+ if (result) {
118
+ html = html.replace('<head>', `<head>${result}`);
119
+ }
120
+ }
121
+ // attributes
122
+ html = html.replace('<html ', `<html ${helmet?.htmlAttributes.toString()} `);
123
+ html = html.replace('<body ', `<body ${helmet?.bodyAttributes.toString()} `);
124
+ return html;
125
+ }
126
+ // Re-export for use in server
127
+ var getServerManifest_1 = require("./getServerManifest");
128
+ Object.defineProperty(exports, "getBuildTimeServerManifestAsync", { enumerable: true, get: function () { return getServerManifest_1.getBuildTimeServerManifestAsync; } });
129
+ Object.defineProperty(exports, "getManifest", { enumerable: true, get: function () { return getServerManifest_1.getManifest; } });
130
+ //# sourceMappingURL=renderStaticContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderStaticContent.js","sourceRoot":"","sources":["../../src/static/renderStaticContent.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright © 2023 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport '@expo/metro-runtime';\n\nimport { ServerContainer, ServerContainerRef } from '@react-navigation/native';\nimport * as Font from 'expo-font/build/server';\nimport { ExpoRoot } from 'expo-router';\nimport { ctx } from 'expo-router/_ctx';\nimport { ServerDataLoaderContext } from 'expo-router/build/loaders/ServerDataLoaderContext';\nimport Head from 'expo-router/head';\nimport React from 'react';\nimport ReactDOMServer from 'react-dom/server.node';\n// @ts-expect-error: TODO(@kitten): Define this type (seems to differ from react-native)\nimport { AppRegistry } from 'react-native-web';\n\nimport { getRootComponent } from './getRootComponent';\nimport { PreloadedDataScript } from './html';\n\nconst debug = require('debug')('expo:router:server:renderStaticContent');\n\nAppRegistry.registerComponent('App', () => ExpoRoot);\n\nfunction resetReactNavigationContexts() {\n // https://github.com/expo/router/discussions/588\n // https://github.com/react-navigation/react-navigation/blob/9fe34b445fcb86e5666f61e144007d7540f014fa/packages/elements/src/getNamedContext.tsx#LL3C1-L4C1\n\n // React Navigation is storing providers in a global, this is fine for the first static render\n // but subsequent static renders of Stack or Tabs will cause React to throw a warning. To prevent this warning, we'll reset the globals before rendering.\n const contexts = '__react_navigation__elements_contexts';\n (globalThis as any)[contexts] = new Map<string, React.Context<any>>();\n}\n\ntype GetStaticContentOptions = {\n loader?: {\n data?: any;\n };\n};\n\nexport async function getStaticContent(\n location: URL,\n options?: GetStaticContentOptions\n): Promise<string> {\n const headContext: { helmet?: any } = {};\n\n const ref = React.createRef<ServerContainerRef>();\n\n const {\n // NOTE: The `element` that's returned adds two extra Views and\n // the seemingly unused `RootTagContext.Provider`.\n element,\n getStyleElement,\n } = AppRegistry.getApplication('App', {\n initialProps: {\n location,\n context: ctx,\n wrapper: ({ children }: React.ComponentProps<any>) => (\n <Root>\n <div id=\"root\">{children}</div>\n </Root>\n ),\n },\n });\n\n const Root = getRootComponent();\n\n // Clear any existing static resources from the global scope to attempt to prevent leaking between pages.\n // This could break if pages are rendered in parallel or if fonts are loaded outside of the React tree\n Font.resetServerContext();\n\n // This MUST be run before `ReactDOMServer.renderToString` to prevent\n // \"Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.\"\n resetReactNavigationContexts();\n\n const loadedData = options?.loader?.data ? { [location.pathname]: options.loader.data } : null;\n\n const html = await ReactDOMServer.renderToString(\n <Head.Provider context={headContext}>\n <ServerDataLoaderContext value={loadedData}>\n <ServerContainer ref={ref}>{element}</ServerContainer>\n </ServerDataLoaderContext>\n </Head.Provider>\n );\n\n // Eval the CSS after the HTML is rendered so that the CSS is in the same order\n const css = ReactDOMServer.renderToStaticMarkup(getStyleElement());\n\n let output = mixHeadComponentsWithStaticResults(headContext.helmet, html);\n\n output = output.replace('</head>', `${css}</head>`);\n\n const fonts = Font.getServerResources();\n debug(`Pushing static fonts: (count: ${fonts.length})`, fonts);\n // debug('Push static fonts:', fonts)\n // Inject static fonts loaded with expo-font\n output = output.replace('</head>', `${fonts.join('')}</head>`);\n\n if (loadedData) {\n const loaderDataScript = ReactDOMServer.renderToStaticMarkup(\n <PreloadedDataScript data={loadedData} />\n );\n output = output.replace('</head>', `${loaderDataScript}</head>`);\n }\n\n return '<!DOCTYPE html>' + output;\n}\n\nfunction mixHeadComponentsWithStaticResults(helmet: any, html: string) {\n // Head components\n for (const key of ['title', 'priority', 'meta', 'link', 'script', 'style'].reverse()) {\n const result = helmet?.[key]?.toString();\n if (result) {\n html = html.replace('<head>', `<head>${result}`);\n }\n }\n\n // attributes\n html = html.replace('<html ', `<html ${helmet?.htmlAttributes.toString()} `);\n html = html.replace('<body ', `<body ${helmet?.bodyAttributes.toString()} `);\n\n return html;\n}\n\n// Re-export for use in server\nexport { getBuildTimeServerManifestAsync, getManifest } from './getServerManifest';\n"]}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright © 2023 650 Industries.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ /**
8
+ * Replaces unsafe characters in a string with their escaped equivalents. This is to safely
9
+ * embed data in an HTML context to prevent XSS.
10
+ */
11
+ export declare function escapeUnsafeCharacters(str: string): string;
12
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/utils/html.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1D"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright © 2023 650 Industries.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.escapeUnsafeCharacters = escapeUnsafeCharacters;
10
+ // See: https://github.com/urql-graphql/urql/blob/ad0276ae616b2b2f2cd01a527b4217ae35c3fa2d/packages/next-urql/src/htmlescape.ts#L10
11
+ // License: https://github.com/urql-graphql/urql/blob/ad0276ae616b2b2f2cd01a527b4217ae35c3fa2d/LICENSE
12
+ // This utility is based on https://github.com/zertosh/htmlescape
13
+ // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
14
+ const UNSAFE_CHARACTERS_REGEX = /[&><\u2028\u2029]/g;
15
+ const ESCAPED_CHARACTERS = {
16
+ '&': '\\u0026',
17
+ '>': '\\u003e',
18
+ '<': '\\u003c',
19
+ '\u2028': '\\u2028',
20
+ '\u2029': '\\u2029',
21
+ };
22
+ /**
23
+ * Replaces unsafe characters in a string with their escaped equivalents. This is to safely
24
+ * embed data in an HTML context to prevent XSS.
25
+ */
26
+ function escapeUnsafeCharacters(str) {
27
+ return str.replace(UNSAFE_CHARACTERS_REGEX, (match) => ESCAPED_CHARACTERS[match]);
28
+ }
29
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/utils/html.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAqBH,wDAEC;AArBD,mIAAmI;AACnI,sGAAsG;AAEtG,iEAAiE;AACjE,uGAAuG;AAEvG,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AACrD,MAAM,kBAAkB,GAAgC;IACtD,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,SAAS;CACpB,CAAC;AAEF;;;GAGG;AACH,SAAgB,sBAAsB,CAAC,GAAW;IAChD,OAAO,GAAG,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;AACpF,CAAC","sourcesContent":["/**\n * Copyright © 2023 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n// See: https://github.com/urql-graphql/urql/blob/ad0276ae616b2b2f2cd01a527b4217ae35c3fa2d/packages/next-urql/src/htmlescape.ts#L10\n// License: https://github.com/urql-graphql/urql/blob/ad0276ae616b2b2f2cd01a527b4217ae35c3fa2d/LICENSE\n\n// This utility is based on https://github.com/zertosh/htmlescape\n// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE\n\nconst UNSAFE_CHARACTERS_REGEX = /[&><\\u2028\\u2029]/g;\nconst ESCAPED_CHARACTERS: { [match: string]: string } = {\n '&': '\\\\u0026',\n '>': '\\\\u003e',\n '<': '\\\\u003c',\n '\\u2028': '\\\\u2028',\n '\\u2029': '\\\\u2029',\n};\n\n/**\n * Replaces unsafe characters in a string with their escaped equivalents. This is to safely\n * embed data in an HTML context to prevent XSS.\n */\nexport function escapeUnsafeCharacters(str: string): string {\n return str.replace(UNSAFE_CHARACTERS_REGEX, (match) => ESCAPED_CHARACTERS[match]);\n}\n"]}
package/node/render.js ADDED
@@ -0,0 +1,3 @@
1
+ // Assumes Metro handles this import.
2
+ // NOTE(EvanBacon): No relative imports!
3
+ module.exports = require('@expo/router-server/build/static/renderStaticContent');
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@expo/router-server",
3
+ "version": "0.1.0",
4
+ "description": "Expo Router is a file-based router for React Native and web applications.",
5
+ "author": "650 Industries, Inc.",
6
+ "license": "MIT",
7
+ "main": "build/index",
8
+ "types": "build/index.d.ts",
9
+ "files": [
10
+ "build",
11
+ "node"
12
+ ],
13
+ "repository": {
14
+ "url": "https://github.com/expo/expo.git",
15
+ "type": "git",
16
+ "directory": "packages/@expo/router-server"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/expo/expo/issues"
20
+ },
21
+ "homepage": "https://docs.expo.dev/routing/introduction/",
22
+ "scripts": {
23
+ "build": "expo-module build",
24
+ "clean": "expo-module clean",
25
+ "lint": "expo-module lint",
26
+ "test": "expo-module test",
27
+ "test:rsc": "jest --config jest-rsc.config.js",
28
+ "test:tsd": "EXPORT_ROUTER_JEST_TSD=true expo-module test",
29
+ "prepublishOnly": "expo-module prepublishOnly",
30
+ "expo-module": "expo-module"
31
+ },
32
+ "keywords": [
33
+ "react-native",
34
+ "expo"
35
+ ],
36
+ "peerDependencies": {
37
+ "@expo/metro-runtime": "^6.1.2",
38
+ "@react-navigation/native": "^7.1.8",
39
+ "react": "*",
40
+ "react-dom": "*",
41
+ "react-native-web": "*",
42
+ "expo": "*",
43
+ "expo-font": "*",
44
+ "expo-router": "*"
45
+ },
46
+ "dependencies": {
47
+ "debug": "^4.3.4"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ }
52
+ }