first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

1
node_modules/@expo/router-server/README.md generated vendored Normal file
View File

@@ -0,0 +1 @@
# @expo/router-server

View File

@@ -0,0 +1,19 @@
import type { RequireContext } from 'expo-router';
import { type GetRoutesCoreOptions, type RouteNode } from 'expo-router/internal/routing';
export type Options = Omit<GetRoutesCoreOptions, 'getSystemRoute'>;
/**
* Given a Metro context module, return an array of nested routes.
*
* This is a two step process:
* 1. Convert the RequireContext keys (file paths) into a directory tree.
* - This should extrapolate array syntax into multiple routes
* - Routes are given a specificity score
* 2. Flatten the directory tree into routes
* - Routes in directories without _layout files are hoisted to the nearest _layout
* - The name of the route is relative to the nearest _layout
* - If multiple routes have the same name, the most specific route is used
*/
export declare function getRoutes(contextModule: RequireContext, options?: Options): RouteNode | null;
export declare function getExactRoutes(contextModule: RequireContext, options?: Options): RouteNode | null;
export { generateDynamic, extrapolateGroups } from 'expo-router/internal/routing';
//# sourceMappingURL=getRoutesSSR.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getRoutesSSR.d.ts","sourceRoot":"","sources":["../src/getRoutesSSR.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACf,MAAM,8BAA8B,CAAC;AAEtC,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;AACnE;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,OAAO,GAAE,OAAY,GAAG,SAAS,GAAG,IAAI,CAoEhG;AAED,wBAAgB,cAAc,CAC5B,aAAa,EAAE,cAAc,EAC7B,OAAO,GAAE,OAAY,GACpB,SAAS,GAAG,IAAI,CAKlB;AAED,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC"}

97
node_modules/@expo/router-server/build/getRoutesSSR.js generated vendored Normal file
View File

@@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extrapolateGroups = exports.generateDynamic = void 0;
exports.getRoutes = getRoutes;
exports.getExactRoutes = getExactRoutes;
const routing_1 = require("expo-router/internal/routing");
/**
* Given a Metro context module, return an array of nested routes.
*
* This is a two step process:
* 1. Convert the RequireContext keys (file paths) into a directory tree.
* - This should extrapolate array syntax into multiple routes
* - Routes are given a specificity score
* 2. Flatten the directory tree into routes
* - Routes in directories without _layout files are hoisted to the nearest _layout
* - The name of the route is relative to the nearest _layout
* - If multiple routes have the same name, the most specific route is used
*/
function getRoutes(contextModule, options = {}) {
return (0, routing_1.getRoutesCore)(contextModule, {
getSystemRoute({ route, type, defaults, redirectConfig, rewriteConfig }) {
if (route === '' && type === 'layout') {
// Root layout when no layout is defined.
return {
type: 'layout',
loadRoute: () => ({
default: () => null,
}),
// Generate a fake file name for the directory
contextKey: 'expo-router/build/views/Navigator.js',
route: '',
generated: true,
dynamic: null,
children: [],
};
}
else if (route === '_sitemap' && type === 'route') {
return {
loadRoute: () => ({
default: () => null,
}),
route: '_sitemap',
type: 'route',
contextKey: 'expo-router/build/views/Sitemap.js',
generated: true,
internal: true,
dynamic: null,
children: [],
};
}
else if (route === '+not-found' && type === 'route') {
return {
loadRoute: () => ({
default: () => null,
}),
type: 'route',
route: '+not-found',
contextKey: 'expo-router/build/views/Unmatched.js',
generated: true,
internal: true,
dynamic: [{ name: '+not-found', deep: true, notFound: true }],
children: [],
};
}
else if (type === 'redirect' && redirectConfig && defaults) {
return {
...defaults,
loadRoute() {
return require('expo-router/build/getRoutesRedirects').getRedirectModule(redirectConfig);
},
};
}
else if (type === 'rewrite' && rewriteConfig && defaults) {
return {
...defaults,
loadRoute() {
return {
default: contextModule(rewriteConfig.destinationContextKey).default,
};
},
};
}
throw new Error(`Unknown system route: ${route} and type: ${type} and redirectConfig: ${redirectConfig} and rewriteConfig: ${rewriteConfig}`);
},
...options,
});
}
function getExactRoutes(contextModule, options = {}) {
return getRoutes(contextModule, {
...options,
skipGenerated: true,
});
}
var routing_2 = require("expo-router/internal/routing");
Object.defineProperty(exports, "generateDynamic", { enumerable: true, get: function () { return routing_2.generateDynamic; } });
Object.defineProperty(exports, "extrapolateGroups", { enumerable: true, get: function () { return routing_2.extrapolateGroups; } });
//# sourceMappingURL=getRoutesSSR.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,31 @@
/**
* Copyright © 2023 650 Industries.
* Copyright © 2023 Vercel, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Based on https://github.com/vercel/next.js/blob/1df2686bc9964f1a86c444701fa5cbf178669833/packages/next/src/shared/lib/router/utils/route-regex.ts
*/
import { type RouteNode } from 'expo-router/internal/routing';
import { type RoutesManifest } from 'expo-server/private';
export interface Group {
pos: number;
repeat: boolean;
optional: boolean;
}
export interface RouteRegex {
groups: Record<string, Group>;
re: RegExp;
}
type GetServerManifestOptions = {
headers?: Record<string, string | string[]>;
};
export declare function getServerManifest(route: RouteNode, options: GetServerManifestOptions | undefined): RoutesManifest<string>;
export declare function parseParameter(param: string): {
name: string;
repeat: boolean;
optional: boolean;
};
export {};
//# sourceMappingURL=getServerManifest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getServerManifest.d.ts","sourceRoot":"","sources":["../src/getServerManifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1E,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;AA2BD,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,cAAc,CAAC,MAAM,CAAC,CAqGxB;AAuJD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM;;;;EAgB3C"}

View File

@@ -0,0 +1,252 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getServerManifest = getServerManifest;
exports.parseParameter = parseParameter;
/**
* Copyright © 2023 650 Industries.
* Copyright © 2023 Vercel, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Based on https://github.com/vercel/next.js/blob/1df2686bc9964f1a86c444701fa5cbf178669833/packages/next/src/shared/lib/router/utils/route-regex.ts
*/
const routing_1 = require("expo-router/internal/routing");
const utils_1 = require("expo-router/internal/utils");
function isNotFoundRoute(route) {
return route.dynamic && route.dynamic[route.dynamic.length - 1].notFound;
}
function uniqueBy(arr, key) {
const seen = new Set();
return arr.filter((item) => {
const id = key(item);
if (seen.has(id)) {
return false;
}
seen.add(id);
return true;
});
}
// Given a nested route tree, return a flattened array of all routes that can be matched.
function getServerManifest(route, options) {
function getFlatNodes(route, parentRoute = '') {
// Use a recreated route instead of contextKey because we duplicate nodes to support array syntax.
const absoluteRoute = [parentRoute, route.route].filter(Boolean).join('/');
if (route.children.length) {
return route.children.map((child) => getFlatNodes(child, absoluteRoute)).flat();
}
// API Routes are handled differently to HTML routes because they have no nested behavior.
// An HTML route can be different based on parent segments due to layout routes, therefore multiple
// copies should be rendered. However, an API route is always the same regardless of parent segments.
let key;
if (route.type.includes('api')) {
key = getNormalizedContextKey(route.contextKey);
}
else {
key = getNormalizedContextKey(absoluteRoute);
}
return [
{
normalizedContextKey: key,
absoluteRoutePath: '/' + absoluteRoute,
route,
},
];
}
// Remove duplicates from the runtime manifest which expands array syntax.
const flat = getFlatNodes(route)
.sort(({ route: a }, { route: b }) => (0, routing_1.sortRoutes)(b, a))
.reverse();
const apiRoutes = uniqueBy(flat.filter(({ route }) => route.type === 'api'), ({ normalizedContextKey }) => normalizedContextKey);
const otherRoutes = uniqueBy(flat.filter(({ route }) => route.type === 'route' ||
(route.type === 'rewrite' && (route.methods === undefined || route.methods.includes('GET')))), ({ normalizedContextKey }) => normalizedContextKey);
const redirects = uniqueBy(flat.filter(({ route }) => route.type === 'redirect'), ({ normalizedContextKey }) => normalizedContextKey)
.map((redirect) => {
// TODO(@hassankhan): ENG-16577
// For external redirects, use `destinationContextKey` as the destination URL
if ((0, utils_1.shouldLinkExternally)(redirect.route.destinationContextKey)) {
redirect.absoluteRoutePath = redirect.route.destinationContextKey;
}
else {
redirect.absoluteRoutePath =
flat.find(({ route }) => route.contextKey === redirect.route.destinationContextKey)
?.normalizedContextKey ?? '/';
}
return redirect;
})
.reverse();
const rewrites = uniqueBy(flat.filter(({ route }) => route.type === 'rewrite'), ({ normalizedContextKey }) => normalizedContextKey)
.map((rewrite) => {
rewrite.absoluteRoutePath =
flat.find(({ route }) => route.contextKey === rewrite.route.destinationContextKey)
?.normalizedContextKey ?? '/';
return rewrite;
})
.reverse();
const standardRoutes = otherRoutes.filter(({ route }) => !isNotFoundRoute(route));
const notFoundRoutes = otherRoutes.filter(({ route }) => isNotFoundRoute(route));
const manifest = {
apiRoutes: getMatchableManifestForPaths(apiRoutes),
htmlRoutes: getMatchableManifestForPaths(standardRoutes),
notFoundRoutes: getMatchableManifestForPaths(notFoundRoutes),
redirects: getMatchableManifestForPaths(redirects),
rewrites: getMatchableManifestForPaths(rewrites),
};
if (route.middleware) {
manifest.middleware = {
file: route.middleware.contextKey,
};
}
if (options?.headers) {
manifest.headers = options.headers;
}
return manifest;
}
function getMatchableManifestForPaths(paths) {
return paths.map(({ normalizedContextKey, absoluteRoutePath, route }) => {
const matcher = getNamedRouteRegex(normalizedContextKey, absoluteRoutePath, route.contextKey);
if (route.generated) {
matcher.generated = true;
}
if (route.permanent) {
matcher.permanent = true;
}
if (route.methods) {
matcher.methods = route.methods;
}
return matcher;
});
}
function getNamedRouteRegex(normalizedRoute, page, file) {
const result = getNamedParametrizedRoute(normalizedRoute);
return {
file,
page,
namedRegex: `^${result.namedParameterizedRoute}(?:/)?$`,
routeKeys: result.routeKeys,
};
}
/**
* Builds a function to generate a minimal routeKey using only a-z and minimal
* number of characters.
*/
function buildGetSafeRouteKey() {
let currentCharCode = 96; // Starting one before 'a' to make the increment logic simpler
let currentLength = 1;
return () => {
let result = '';
let incrementNext = true;
// Iterate from right to left to build the key
for (let i = 0; i < currentLength; i++) {
if (incrementNext) {
currentCharCode++;
if (currentCharCode > 122) {
currentCharCode = 97; // Reset to 'a'
incrementNext = true; // Continue to increment the next character
}
else {
incrementNext = false;
}
}
result = String.fromCharCode(currentCharCode) + result;
}
// If all characters are 'z', increase the length of the key
if (incrementNext) {
currentLength++;
currentCharCode = 96; // This will make the next key start with 'a'
}
return result;
};
}
function removeTrailingSlash(route) {
return route.replace(/\/$/, '') || '/';
}
function getNamedParametrizedRoute(route) {
const segments = removeTrailingSlash(route).slice(1).split('/');
const getSafeRouteKey = buildGetSafeRouteKey();
const routeKeys = {};
return {
namedParameterizedRoute: segments
.map((segment, index) => {
if (segment === '+not-found' && index === segments.length - 1) {
segment = '[...not-found]';
}
if (/^\[.*\]$/.test(segment)) {
const { name, optional, repeat } = parseParameter(segment);
// replace any non-word characters since they can break
// the named regex
let cleanedKey = name.replace(/\W/g, '');
let invalidKey = false;
// check if the key is still invalid and fallback to using a known
// safe key
if (cleanedKey.length === 0 || cleanedKey.length > 30) {
invalidKey = true;
}
if (!isNaN(parseInt(cleanedKey.slice(0, 1), 10))) {
invalidKey = true;
}
// Prevent duplicates after sanitizing the key
if (cleanedKey in routeKeys) {
invalidKey = true;
}
if (invalidKey) {
cleanedKey = getSafeRouteKey();
}
routeKeys[cleanedKey] = name;
return repeat
? optional
? `(?:/(?<${cleanedKey}>.+?))?`
: `/(?<${cleanedKey}>.+?)`
: `/(?<${cleanedKey}>[^/]+?)`;
}
else if (/^\(.*\)$/.test(segment)) {
const groupName = (0, routing_1.matchGroupName)(segment)
.split(',')
.map((group) => group.trim())
.filter(Boolean);
if (groupName.length > 1) {
const optionalSegment = `\\((?:${groupName.map(escapeStringRegexp).join('|')})\\)`;
// Make section optional
return `(?:/${optionalSegment})?`;
}
else {
// Use simpler regex for single groups
return `(?:/${escapeStringRegexp(segment)})?`;
}
}
else {
return `/${escapeStringRegexp(segment)}`;
}
})
.join(''),
routeKeys,
};
}
// regexp is based on https://github.com/sindresorhus/escape-string-regexp
const reHasRegExp = /[|\\{}()[\]^$+*?.-]/;
const reReplaceRegExp = /[|\\{}()[\]^$+*?.-]/g;
function escapeStringRegexp(str) {
// see also: https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/escapeRegExp.js#L23
if (reHasRegExp.test(str)) {
return str.replace(reReplaceRegExp, '\\$&');
}
return str;
}
function parseParameter(param) {
let repeat = false;
let optional = false;
let name = param;
if (/^\[.*\]$/.test(name)) {
optional = true;
name = name.slice(1, -1);
}
if (/^\.\.\./.test(name)) {
repeat = true;
name = name.slice(3);
}
return { name, repeat, optional };
}
function getNormalizedContextKey(contextKey) {
return (0, routing_1.getContextKey)(contextKey).replace(/\/index$/, '') ?? '/';
}
//# sourceMappingURL=getServerManifest.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
import type { RouteNode } from 'expo-router/internal/routing';
export declare function loadStaticParamsAsync(route: RouteNode): Promise<RouteNode>;
export declare function evalStaticParamsAsync(route: RouteNode, props: {
parentParams: any;
}, generateStaticParams?: (props: {
params?: Record<string, string | string[]>;
}) => Record<string, string | string[]>[]): Promise<Record<string, string | string[]>[] | null>;
export declare function assertStaticParams(route: Pick<RouteNode, 'contextKey' | 'dynamic'>, params: Record<string, string | string[]>): void;
//# sourceMappingURL=loadStaticParamsAsync.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"loadStaticParamsAsync.d.ts","sourceRoot":"","sources":["../src/loadStaticParamsAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEjF,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAMhF;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE;IAAE,YAAY,EAAE,GAAG,CAAA;CAAE,EAC5B,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;CAC5C,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,GACxC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,CAmBrD;AA6HD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,CAAC,EAChD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,QA2D1C"}

View File

@@ -0,0 +1,167 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadStaticParamsAsync = loadStaticParamsAsync;
exports.evalStaticParamsAsync = evalStaticParamsAsync;
exports.assertStaticParams = assertStaticParams;
async function loadStaticParamsAsync(route) {
const expandedChildren = await Promise.all(route.children.map((route) => loadStaticParamsRecursive(route, { parentParams: {} })));
route.children = expandedChildren.flat();
return route;
}
async function evalStaticParamsAsync(route, props, generateStaticParams) {
if (!route.dynamic && generateStaticParams) {
throw new Error('Cannot use generateStaticParams in a route without dynamic segments: ' + route.contextKey);
}
if (generateStaticParams) {
const staticParams = await generateStaticParams({
params: props.parentParams || {},
});
assertStaticParamsType(staticParams);
// Assert that at least one param from each matches the dynamic route.
staticParams.forEach((params) => assertStaticParams(route, params));
return staticParams;
}
return null;
}
async function loadStaticParamsRecursive(route, props) {
if (!route?.dynamic && !route?.children?.length) {
return [route];
}
const loaded = await route.loadRoute();
const staticParams = (await evalStaticParamsAsync(route, props, loaded.generateStaticParams)) ?? [];
const traverseForNode = async (nextParams) => {
const nextChildren = [];
for (const child of route.children) {
const children = await loadStaticParamsRecursive(child, {
...props,
parentParams: nextParams,
});
nextChildren.push(...children);
}
return uniqBy(nextChildren, (i) => i.route);
};
if (!staticParams.length) {
const nextParams = {
...props.parentParams,
};
route.children = await traverseForNode(nextParams);
return [route];
}
const createParsedRouteName = (input, params) => {
let parsedRouteName = input;
route.dynamic?.map((query) => {
const param = params[query.name];
const formattedParameter = Array.isArray(param) ? param.join('/') : param;
if (query.deep) {
parsedRouteName = parsedRouteName.replace(`[...${query.name}]`, formattedParameter);
}
else {
parsedRouteName = parsedRouteName.replace(`[${query.name}]`, param);
}
});
return parsedRouteName;
};
const generatedRoutes = await Promise.all(staticParams.map(async (params) => {
const nextParams = {
...props.parentParams,
...params,
};
const dynamicChildren = await traverseForNode(nextParams);
const parsedRoute = createParsedRouteName(route.route, params);
const generatedContextKey = createParsedRouteName(route.contextKey, params);
const generatedRoute = {
...route,
// TODO: Add a new field for this
contextKey: generatedContextKey,
// Convert the dynamic route to a static route.
dynamic: null,
route: parsedRoute,
children: dynamicChildren,
};
if (route.type === 'route') {
generatedRoute.parentContextKey = route.contextKey;
}
return generatedRoute;
}));
return [route, ...generatedRoutes];
}
/** lodash.uniqBy */
function uniqBy(array, key) {
const seen = {};
return array.filter((item) => {
const k = key(item);
if (seen[k]) {
return false;
}
seen[k] = true;
return true;
});
}
function assertStaticParamsType(params) {
if (!Array.isArray(params)) {
throw new Error(`generateStaticParams() must return an array of params, received ${params}`);
}
}
function formatExpected(expected, received) {
const total = {
...received,
};
for (const item of expected) {
if (total[item] == null) {
total[item] = String(total[item]);
}
else {
total[item] = `"${total[item]}"`;
}
}
return [
'{',
Object.entries(total)
.map(([key, value]) => ` "${key}": ${value}`)
.join(',\n'),
'}',
].join('\n');
}
function assertStaticParams(route, params) {
// Type checking
if (!route.dynamic) {
throw new Error('assertStaticParams() must be called on a dynamic route.');
}
const matches = route.dynamic.every((dynamic) => {
const value = params[dynamic.name];
return value !== undefined && value !== null;
});
if (!matches) {
const plural = route.dynamic.length > 1 ? 's' : '';
const expected = route.dynamic.map((dynamic) => dynamic.name);
throw new Error(`[${route.contextKey}]: generateStaticParams() must return an array of params that match the dynamic route${plural}. Expected non-nullish values for key${plural}: ${expected
.map((v) => `"${v}"`)
.join(', ')}.\nReceived:\n${formatExpected(expected, params)}`);
}
const validateSingleParam = (dynamic, value, allowMultipleSegments) => {
if (typeof value !== 'string') {
throw new Error(`generateStaticParams() for route "${route.contextKey}" expected param "${dynamic.name}" to be of type string, instead found "${typeof value}" while parsing "${value}".`);
}
const parts = value.split('/').filter(Boolean);
if (parts.length > 1 && !allowMultipleSegments) {
throw new Error(`generateStaticParams() for route "${route.contextKey}" expected param "${dynamic.name}" to not contain "/" (multiple segments) while parsing "${value}".`);
}
if (parts.length === 0) {
throw new Error(`generateStaticParams() for route "${route.contextKey}" expected param "${dynamic.name}" not to be empty while parsing "${value}".`);
}
};
// `[shape]/bar/[...colors]` -> `[shape]`, `[...colors]`
for (const dynamic of route.dynamic) {
let parameter = params[dynamic.name];
if (dynamic.deep) {
if (Array.isArray(parameter)) {
parameter = parameter.filter(Boolean).join('/');
}
validateSingleParam(dynamic, parameter, true);
}
else {
validateSingleParam(dynamic, parameter);
}
}
}
//# sourceMappingURL=loadStaticParamsAsync.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
import { type RoutesManifest } from 'expo-server/private';
import { type Options } from './getRoutesSSR';
export { Options };
export declare function createRoutesManifest(paths: string[], options: Options): RoutesManifest<string> | null;
//# sourceMappingURL=routes-manifest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"routes-manifest.d.ts","sourceRoot":"","sources":["../src/routes-manifest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,KAAK,OAAO,EAAa,MAAM,gBAAgB,CAAC;AAGzD,OAAO,EAAE,OAAO,EAAE,CAAC;AAYnB,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE,OAAO,GACf,cAAc,CAAC,MAAM,CAAC,GAAG,IAAI,CAe/B"}

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createRoutesManifest = createRoutesManifest;
const getRoutesSSR_1 = require("./getRoutesSSR");
const getServerManifest_1 = require("./getServerManifest");
function createMockContextModule(map = []) {
const contextModule = (_key) => ({ default() { } });
Object.defineProperty(contextModule, 'keys', {
value: () => map,
});
return contextModule;
}
function createRoutesManifest(paths, options) {
// TODO: Drop this part for Node.js
const routeTree = (0, getRoutesSSR_1.getRoutes)(createMockContextModule(paths), {
...options,
preserveApiRoutes: true,
preserveRedirectAndRewrites: true,
ignoreRequireErrors: true,
ignoreEntryPoints: true,
platform: 'web',
});
if (!routeTree) {
return null;
}
return (0, getServerManifest_1.getServerManifest)(routeTree, { headers: options.headers });
}
//# sourceMappingURL=routes-manifest.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"routes-manifest.js","sourceRoot":"","sources":["../src/routes-manifest.ts"],"names":[],"mappings":";;AAoBA,oDAkBC;AAjCD,iDAAyD;AACzD,2DAAwD;AAIxD,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 RoutesManifest } from 'expo-server/private';\n\nimport { type Options, getRoutes } from './getRoutesSSR';\nimport { getServerManifest } from './getServerManifest';\n\nexport { Options };\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): RoutesManifest<string> | 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"]}

View File

@@ -0,0 +1,8 @@
import type { RenderRscArgs } from 'expo-server/private';
type ImportMap = {
router: () => Promise<typeof import('./router/expo-definedRouter')>;
};
export declare function renderRscWithImportsAsync(distFolder: string, imports: ImportMap, { body, platform, searchParams, config, method, input, contentType, headers }: RenderRscArgs): Promise<ReadableStream<any>>;
export declare function renderRscAsync(distFolder: string, args: RenderRscArgs): Promise<ReadableStream<any>>;
export {};
//# sourceMappingURL=middleware.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/rsc/middleware.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAkEzD,KAAK,SAAS,GAAG;IACf,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,6BAA6B,CAAC,CAAC,CAAC;CACrE,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,SAAS,EAClB,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,aAAa,GAC3F,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAiE9B;AAED,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAY9B"}

View File

@@ -0,0 +1,106 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderRscWithImportsAsync = renderRscWithImportsAsync;
exports.renderRscAsync = renderRscAsync;
/**
* Copyright © 2024 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// This module is bundled with Metro in web/react-server mode and redirects to platform specific renderers.
const expo_constants_1 = __importDefault(require("expo-constants"));
const node_path_1 = __importDefault(require("node:path"));
const rsc_renderer_1 = require("./rsc-renderer");
const debug_1 = require("../utils/debug");
const debug = (0, debug_1.createDebug)('expo:router:server:rsc-renderer');
// Tracking the implementation in expo/cli's MetroBundlerDevServer
const rscRenderContext = new Map();
function serverRequire(...targetOutputModulePath) {
// NOTE(@kitten): This `__dirname` will be located in the output file system, e.g. `dist/server/*`
const filePath = node_path_1.default.join(__dirname, ...targetOutputModulePath);
return $$require_external(filePath);
}
function getRscRenderContext(platform) {
// NOTE(EvanBacon): We memoize this now that there's a persistent server storage cache for Server Actions.
if (rscRenderContext.has(platform)) {
return rscRenderContext.get(platform);
}
const context = {};
rscRenderContext.set(platform, context);
return context;
}
function getServerActionManifest(_distFolder, platform) {
const filePath = `../../rsc/${platform}/action-manifest.js`;
return serverRequire(filePath);
}
function getSSRManifest(_distFolder, platform) {
const filePath = `../../rsc/${platform}/ssr-manifest.js`;
return serverRequire(filePath);
}
async function renderRscWithImportsAsync(distFolder, imports, { body, platform, searchParams, config, method, input, contentType, headers }) {
globalThis.__expo_platform_header = platform;
if (method === 'POST' && !body) {
throw new Error('Server request must be provided when method is POST (server actions)');
}
const context = getRscRenderContext(platform);
context['__expo_requestHeaders'] = headers;
const router = await imports.router();
const entries = router.default({
redirects: expo_constants_1.default.expoConfig?.extra?.router?.redirects,
rewrites: expo_constants_1.default.expoConfig?.extra?.router?.rewrites,
});
const ssrManifest = getSSRManifest(distFolder, platform);
const actionManifest = getServerActionManifest(distFolder, platform);
return (0, rsc_renderer_1.renderRsc)({
body: body ?? undefined,
context,
config,
input,
contentType,
decodedBody: searchParams.get('x-expo-params'),
}, {
isExporting: true,
resolveClientEntry(file, isServer) {
debug('resolveClientEntry', file, { isServer });
if (isServer) {
if (!(file in actionManifest)) {
throw new Error(`Could not find file in server action manifest: ${file}. ${JSON.stringify(actionManifest)}`);
}
const [id, chunk] = actionManifest[file];
return {
id,
chunks: chunk ? [chunk] : [],
};
}
if (!(file in ssrManifest)) {
throw new Error(`Could not find file in SSR manifest: ${file}`);
}
const [id, chunk] = ssrManifest[file];
return {
id,
chunks: chunk ? [chunk] : [],
};
},
async loadServerModuleRsc(file) {
debug('loadServerModuleRsc', file);
// NOTE(@kitten): [WORKAROUND] Assumes __dirname is at `dist/server/_expo/functions/_flight`
return serverRequire('../../../', file);
},
entries: entries,
});
}
async function renderRscAsync(distFolder, args) {
const platform = args.platform;
return renderRscWithImportsAsync(distFolder, {
router: () => {
// NOTE(@kitten): [WORKAROUND] Assumes __dirname is at `dist/server/_expo/functions/_flight`
return serverRequire(`../../rsc/${platform}/router.js`);
},
}, args);
}
//# sourceMappingURL=middleware.js.map

File diff suppressed because one or more lines are too long

34
node_modules/@expo/router-server/build/rsc/path.d.ts generated vendored Normal file
View File

@@ -0,0 +1,34 @@
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 2023 Daishi Kato
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* https://github.com/dai-shi/waku/blob/32d52242c1450b5f5965860e671ff73c42da8bd0/packages/waku/src/lib/utils/path.ts#L1
*/
export declare const encodeFilePathToAbsolute: (filePath: string) => string;
export declare const decodeFilePathFromAbsolute: (filePath: string) => string;
export declare const filePathToFileURL: (filePath: string) => string;
/** Return the original "osPath" based on the file URL */
export declare const fileURLToFilePath: (fileURL: string) => string;
export declare const joinPath: (...paths: string[]) => string;
export declare const extname: (filePath: string) => string;
export type PathSpecItem = {
type: 'literal';
name: string;
} | {
type: 'group';
name?: string;
} | {
type: 'wildcard';
name?: string;
};
export type PathSpec = readonly PathSpecItem[];
export declare const parsePathWithSlug: (path: string) => PathSpec;
export declare const getPathMapping: (pathSpec: PathSpec, pathname: string) => Record<string, string | string[]> | null;
/**
* Transform a path spec to a regular expression.
*/
export declare const path2regexp: (path: PathSpec) => string;
//# sourceMappingURL=path.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/rsc/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAYH,eAAO,MAAM,wBAAwB,GAAI,UAAU,MAAM,WAQxD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,UAAU,MAAM,WAK1D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,WAAoC,CAAC;AAEvF,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,WAahD,CAAC;AAGF,eAAO,MAAM,QAAQ,GAAI,GAAG,OAAO,MAAM,EAAE,WAmB1C,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,UAAU,MAAM,WAGvC,CAAC;AAEF,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACxC,MAAM,MAAM,QAAQ,GAAG,SAAS,YAAY,EAAE,CAAC;AAE/C,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,QAiB3C,CAAC;AAEP,eAAO,MAAM,cAAc,GACzB,UAAU,QAAQ,EAClB,UAAU,MAAM,KACf,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,IAgDtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,QAAQ,WAWzC,CAAC"}

174
node_modules/@expo/router-server/build/rsc/path.js generated vendored Normal file
View File

@@ -0,0 +1,174 @@
"use strict";
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 2023 Daishi Kato
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* https://github.com/dai-shi/waku/blob/32d52242c1450b5f5965860e671ff73c42da8bd0/packages/waku/src/lib/utils/path.ts#L1
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.path2regexp = exports.getPathMapping = exports.parsePathWithSlug = exports.extname = exports.joinPath = exports.fileURLToFilePath = exports.filePathToFileURL = exports.decodeFilePathFromAbsolute = exports.encodeFilePathToAbsolute = void 0;
// Terminology:
// - filePath: posix-like file path, e.g. `/foo/bar.js` or `c:/foo/bar.js`
// This is used by Vite.
// - fileURL: file URL, e.g. `file:///foo/bar.js` or `file:///c:/foo/bar.js`
// This is used by import().
// - osPath: os dependent path, e.g. `/foo/bar.js` or `c:\foo\bar.js`
// This is used by node:fs.
const ABSOLUTE_WIN32_PATH_REGEXP = /^\/[a-zA-Z]:\//;
const encodeFilePathToAbsolute = (filePath) => {
if (ABSOLUTE_WIN32_PATH_REGEXP.test(filePath)) {
throw new Error('Unsupported absolute file path');
}
if (filePath.startsWith('/')) {
return filePath;
}
return '/' + filePath;
};
exports.encodeFilePathToAbsolute = encodeFilePathToAbsolute;
const decodeFilePathFromAbsolute = (filePath) => {
if (ABSOLUTE_WIN32_PATH_REGEXP.test(filePath)) {
return filePath.slice(1);
}
return filePath;
};
exports.decodeFilePathFromAbsolute = decodeFilePathFromAbsolute;
const filePathToFileURL = (filePath) => 'file://' + encodeURI(filePath);
exports.filePathToFileURL = filePathToFileURL;
/** Return the original "osPath" based on the file URL */
const fileURLToFilePath = (fileURL) => {
if (!fileURL.startsWith('file://')) {
throw new Error('Not a file URL');
}
const filePath = decodeURI(fileURL.slice('file://'.length));
// File URLs are always formatted in POSIX, using a leading `/` (URL pathname) separator.
// On POSIX systems, this leading `/` is the root directory, which is valid for absolute file paths.
// On UNIX systems, this leading `/` needs to be stripped, and the actual UNIX formatted path is returned - to match Metro's behavior
return ABSOLUTE_WIN32_PATH_REGEXP.test(filePath)
? filePath.slice(1).replace(/\//g, '\\')
: filePath;
};
exports.fileURLToFilePath = fileURLToFilePath;
// for filePath
const joinPath = (...paths) => {
const isAbsolute = paths[0]?.startsWith('/');
const items = [].concat(...paths.map((path) => path.split('/')));
let i = 0;
while (i < items.length) {
if (items[i] === '.' || items[i] === '') {
items.splice(i, 1);
}
else if (items[i] === '..') {
if (i > 0) {
items.splice(i - 1, 2);
--i;
}
else {
items.splice(i, 1);
}
}
else {
++i;
}
}
return (isAbsolute ? '/' : '') + items.join('/') || '.';
};
exports.joinPath = joinPath;
const extname = (filePath) => {
const index = filePath.lastIndexOf('.');
return index > 0 ? filePath.slice(index) : '';
};
exports.extname = extname;
const parsePathWithSlug = (path) => path
.split('/')
.filter(Boolean)
.map((name) => {
let type = 'literal';
const isSlug = name.startsWith('[') && name.endsWith(']');
if (isSlug) {
type = 'group';
name = name.slice(1, -1);
}
const isWildcard = name.startsWith('...');
if (isWildcard) {
type = 'wildcard';
name = name.slice(3);
}
return { type, name };
});
exports.parsePathWithSlug = parsePathWithSlug;
const getPathMapping = (pathSpec, pathname) => {
const actual = pathname.split('/').filter(Boolean);
if (pathSpec.length > actual.length) {
return null;
}
const mapping = {};
let wildcardStartIndex = -1;
for (let i = 0; i < pathSpec.length; i++) {
const { type, name } = pathSpec[i];
if (type === 'literal') {
if (name !== actual[i]) {
return null;
}
}
else if (type === 'wildcard') {
wildcardStartIndex = i;
break;
}
else if (name) {
mapping[name] = actual[i];
}
}
if (wildcardStartIndex === -1) {
if (pathSpec.length !== actual.length) {
return null;
}
return mapping;
}
let wildcardEndIndex = -1;
for (let i = 0; i < pathSpec.length; i++) {
const { type, name } = pathSpec[pathSpec.length - i - 1];
if (type === 'literal') {
if (name !== actual[actual.length - i - 1]) {
return null;
}
}
else if (type === 'wildcard') {
wildcardEndIndex = actual.length - i - 1;
break;
}
else if (name) {
mapping[name] = actual[actual.length - i - 1];
}
}
if (wildcardStartIndex === -1 || wildcardEndIndex === -1) {
throw new Error('Invalid wildcard path');
}
const wildcardName = pathSpec[wildcardStartIndex].name;
if (wildcardName) {
mapping[wildcardName] = actual.slice(wildcardStartIndex, wildcardEndIndex + 1);
}
return mapping;
};
exports.getPathMapping = getPathMapping;
/**
* Transform a path spec to a regular expression.
*/
const path2regexp = (path) => {
const parts = path.map(({ type, name }) => {
if (type === 'literal') {
return name;
}
else if (type === 'group') {
return `([^/]+)`;
}
else {
return `(.*)`;
}
});
return `^/${parts.join('/')}$`;
};
exports.path2regexp = path2regexp;
//# sourceMappingURL=path.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,20 @@
import { type GetRoutesOptions } from 'expo-router/internal/routing';
import { createPages } from './create-pages';
import { EntriesDev } from '../server';
type CreatePagesFn = Parameters<typeof createPages>[0];
type CreatePagesFns = Parameters<CreatePagesFn>[0];
type CreatePagesOptions = Parameters<CreatePagesFn>[1] & {
getRouteOptions?: GetRoutesOptions;
};
/**
* Wrapper around `createPages` to pass data from the server to the fn
*
* This is separated from the `createPages` function allowing us to keep the createPages
* in sync with the original Waku implementation.
*
* @param fn
* @returns
*/
export declare function createExpoPages(fn: (fn: CreatePagesFns, options: CreatePagesOptions) => ReturnType<CreatePagesFn>): (getRouteOptions?: GetRoutesOptions) => EntriesDev;
export {};
//# sourceMappingURL=create-expo-pages.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"create-expo-pages.d.ts","sourceRoot":"","sources":["../../../src/rsc/router/create-expo-pages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,KAAK,cAAc,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,KAAK,kBAAkB,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG;IACvD,eAAe,CAAC,EAAE,gBAAgB,CAAC;CACpC,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,CAAC,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,kBAAkB,KAAK,UAAU,CAAC,aAAa,CAAC,IAE1E,kBAAkB,gBAAgB,KAAG,UAAU,CAKxD"}

View File

@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createExpoPages = createExpoPages;
const create_pages_1 = require("./create-pages");
/**
* Wrapper around `createPages` to pass data from the server to the fn
*
* This is separated from the `createPages` function allowing us to keep the createPages
* in sync with the original Waku implementation.
*
* @param fn
* @returns
*/
function createExpoPages(fn) {
return (getRouteOptions) => {
return {
default: (0, create_pages_1.createPages)((a, b) => fn(a, { ...b, getRouteOptions })),
};
};
}
//# sourceMappingURL=create-expo-pages.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"create-expo-pages.js","sourceRoot":"","sources":["../../../src/rsc/router/create-expo-pages.ts"],"names":[],"mappings":";;AAoBA,0CAQC;AA1BD,iDAA6C;AAS7C;;;;;;;;GAQG;AACH,SAAgB,eAAe,CAC7B,EAAkF;IAElF,OAAO,CAAC,eAAkC,EAAc,EAAE;QACxD,OAAO;YACL,OAAO,EAAE,IAAA,0BAAW,EAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;SACjE,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { type GetRoutesOptions } from 'expo-router/internal/routing';\n\nimport { createPages } from './create-pages';\nimport { EntriesDev } from '../server';\n\ntype CreatePagesFn = Parameters<typeof createPages>[0];\ntype CreatePagesFns = Parameters<CreatePagesFn>[0];\ntype CreatePagesOptions = Parameters<CreatePagesFn>[1] & {\n getRouteOptions?: GetRoutesOptions;\n};\n\n/**\n * Wrapper around `createPages` to pass data from the server to the fn\n *\n * This is separated from the `createPages` function allowing us to keep the createPages\n * in sync with the original Waku implementation.\n *\n * @param fn\n * @returns\n */\nexport function createExpoPages(\n fn: (fn: CreatePagesFns, options: CreatePagesOptions) => ReturnType<CreatePagesFn>\n) {\n return (getRouteOptions?: GetRoutesOptions): EntriesDev => {\n return {\n default: createPages((a, b) => fn(a, { ...b, getRouteOptions })),\n };\n };\n}\n"]}

View File

@@ -0,0 +1,80 @@
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 2023 Daishi Kato
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* https://github.com/dai-shi/waku/blob/3d1cc7d714b67b142c847e879c30f0724fc457a7/packages/waku/src/router/create-pages.ts#L1
*/
import type { RouteProps } from 'expo-router/internal/rsc';
import type { FunctionComponent, ReactNode } from 'react';
import type { BuildConfig } from '../server';
/**
* Type version of `String.prototype.split()`. Splits the first string argument by the second string argument
* @example
* ```ts
* // ['a', 'b', 'c']
* type Case1 = Split<'abc', ''>
* // ['a', 'b', 'c']
* type Case2 = Split<'a,b,c', ','>
* ```
*/
type Split<Str extends string, Del extends string | number> = string extends Str ? string[] : '' extends Str ? [] : Str extends `${infer T}${Del}${infer U}` ? [T, ...Split<U, Del>] : [Str];
/** Assumes that the path is a part of a slug path. */
type IsValidPathItem<T> = T extends `/${infer _}` ? false : T extends '[]' | '' ? false : true;
/**
* This is a helper type to check if a path is valid in a slug path.
*/
export type IsValidPathInSlugPath<T> = T extends `/${infer L}/${infer R}` ? IsValidPathItem<L> extends true ? IsValidPathInSlugPath<`/${R}`> : false : T extends `/${infer U}` ? IsValidPathItem<U> : false;
/** Checks if a particular slug name exists in a path. */
export type HasSlugInPath<T, K extends string> = T extends `/[${K}]/${infer _}` ? true : T extends `/${infer _}/${infer U}` ? HasSlugInPath<`/${U}`, K> : T extends `/[${K}]` ? true : false;
export type HasWildcardInPath<T> = T extends `/[...${string}]/${string}` ? true : T extends `/${infer _}/${infer U}` ? HasWildcardInPath<`/${U}`> : T extends `/[...${string}]` ? true : false;
export type PathWithSlug<T, K extends string> = IsValidPathInSlugPath<T> extends true ? (HasSlugInPath<T, K> extends true ? T : never) : never;
type _GetSlugs<Route extends string, SplitRoute extends string[] = Split<Route, '/'>, Result extends string[] = []> = SplitRoute extends [] ? Result : SplitRoute extends [`${infer MaybeSlug}`, ...infer Rest] ? Rest extends string[] ? MaybeSlug extends `[${infer Slug}]` ? _GetSlugs<Route, Rest, [...Result, Slug]> : _GetSlugs<Route, Rest, Result> : never : Result;
export type GetSlugs<Route extends string> = _GetSlugs<Route>;
export type StaticSlugRoutePathsTuple<T extends string, Slugs extends unknown[] = GetSlugs<T>, Result extends string[] = []> = Slugs extends [] ? Result : Slugs extends [infer _, ...infer Rest] ? StaticSlugRoutePathsTuple<T, Rest, [...Result, string]> : never;
type StaticSlugRoutePaths<T extends string> = HasWildcardInPath<T> extends true ? string[] | string[][] : StaticSlugRoutePathsTuple<T> extends [string] ? string[] : StaticSlugRoutePathsTuple<T>[];
export type PathWithoutSlug<T> = T extends '/' ? T : IsValidPathInSlugPath<T> extends true ? HasSlugInPath<T, string> extends true ? never : T : never;
type PathWithStaticSlugs<T extends string> = T extends `/` ? T : IsValidPathInSlugPath<T> extends true ? T : never;
export type PathWithWildcard<Path, SlugKey extends string, WildSlugKey extends string> = PathWithSlug<Path, SlugKey | `...${WildSlugKey}`>;
export type CreatePage = <Path extends string, SlugKey extends string, WildSlugKey extends string>(page: ({
render: 'static';
path: PathWithoutSlug<Path>;
component: FunctionComponent<RouteProps>;
} | {
render: 'static';
path: PathWithStaticSlugs<Path>;
staticPaths: StaticSlugRoutePaths<Path>;
component: FunctionComponent<RouteProps & Record<SlugKey, string>>;
} | {
render: 'dynamic';
path: PathWithoutSlug<Path>;
component: FunctionComponent<RouteProps>;
} | {
render: 'dynamic';
path: PathWithWildcard<Path, SlugKey, WildSlugKey>;
component: FunctionComponent<RouteProps & Record<SlugKey, string> & Record<WildSlugKey, string[]>>;
}) & {
unstable_disableSSR?: boolean;
}) => void;
export type CreateLayout = <T extends string>(layout: {
render: 'static' | 'dynamic';
path: PathWithoutSlug<T>;
component: FunctionComponent<Omit<RouteProps, 'searchParams'> & {
children: ReactNode;
}>;
}) => void;
export declare function createPages(fn: (fns: {
createPage: CreatePage;
createLayout: CreateLayout;
unstable_setBuildData: (path: string, data: unknown) => void;
}, opts: {
unstable_buildConfig: BuildConfig | undefined;
}) => Promise<void>): {
renderEntries: import("../server").RenderEntries;
getBuildConfig: import("../server").GetBuildConfig | undefined;
getSsrConfig: import("../server").GetSsrConfig | undefined;
};
export {};
//# sourceMappingURL=create-pages.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"create-pages.d.ts","sourceRoot":"","sources":["../../../src/rsc/router/create-pages.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,232 @@
"use strict";
/* eslint-disable @typescript-eslint/no-unused-vars */
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 2023 Daishi Kato
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* https://github.com/dai-shi/waku/blob/3d1cc7d714b67b142c847e879c30f0724fc457a7/packages/waku/src/router/create-pages.ts#L1
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPages = createPages;
const react_1 = require("react");
const defineRouter_1 = require("./defineRouter");
const path_1 = require("../path");
const hasPathSpecPrefix = (prefix, path) => {
for (let i = 0; i < prefix.length; i++) {
if (i >= path.length ||
prefix[i].type !== path[i].type ||
prefix[i].name !== path[i].name) {
return false;
}
}
return true;
};
const sanitizeSlug = (slug) => slug.replace(/\./g, '').replace(/ /g, '-');
function createPages(fn) {
let configured = false;
// TODO I think there's room for improvement to refactor these structures
const staticPathSet = new Set();
const dynamicPagePathMap = new Map();
const wildcardPagePathMap = new Map();
const dynamicLayoutPathMap = new Map();
const staticComponentMap = new Map();
const noSsrSet = new WeakSet();
const buildDataMap = new Map();
const registerStaticComponent = (id, component) => {
if (staticComponentMap.has(id) && staticComponentMap.get(id) !== component) {
throw new Error(`Duplicated component for: ${id}`);
}
staticComponentMap.set(id, component);
};
const createPage = (page) => {
if (configured) {
throw new Error('no longer available');
}
const pathSpec = (0, path_1.parsePathWithSlug)(page.path);
if (page.unstable_disableSSR) {
noSsrSet.add(pathSpec);
}
const { numSlugs, numWildcards } = (() => {
let numSlugs = 0;
let numWildcards = 0;
for (const slug of pathSpec) {
if (slug.type !== 'literal') {
numSlugs++;
}
if (slug.type === 'wildcard') {
numWildcards++;
}
}
return { numSlugs, numWildcards };
})();
if (page.render === 'static' && numSlugs === 0) {
staticPathSet.add([page.path, pathSpec]);
const id = (0, path_1.joinPath)(page.path, 'page').replace(/^\//, '');
registerStaticComponent(id, page.component);
}
else if (page.render === 'static' && numSlugs > 0 && 'staticPaths' in page) {
const staticPaths = page.staticPaths.map((item) => (Array.isArray(item) ? item : [item]).map(sanitizeSlug));
for (const staticPath of staticPaths) {
if (staticPath.length !== numSlugs && numWildcards === 0) {
throw new Error('staticPaths does not match with slug pattern');
}
const mapping = {};
let slugIndex = 0;
const pathItems = [];
pathSpec.forEach(({ type, name }) => {
switch (type) {
case 'literal':
pathItems.push(name);
break;
case 'wildcard':
mapping[name] = staticPath.slice(slugIndex);
staticPath.slice(slugIndex++).forEach((slug) => {
pathItems.push(slug);
});
break;
case 'group':
pathItems.push(staticPath[slugIndex++]);
mapping[name] = pathItems[pathItems.length - 1];
break;
}
});
staticPathSet.add([page.path, pathItems.map((name) => ({ type: 'literal', name }))]);
const id = (0, path_1.joinPath)(...pathItems, 'page');
const WrappedComponent = (props) => (0, react_1.createElement)(page.component, { ...props, ...mapping });
registerStaticComponent(id, WrappedComponent);
}
}
else if (page.render === 'dynamic' && numWildcards === 0) {
if (dynamicPagePathMap.has(page.path)) {
throw new Error(`Duplicated dynamic path: ${page.path}`);
}
dynamicPagePathMap.set(page.path, [pathSpec, page.component]);
}
else if (page.render === 'dynamic' && numWildcards === 1) {
if (wildcardPagePathMap.has(page.path)) {
throw new Error(`Duplicated dynamic path: ${page.path}`);
}
wildcardPagePathMap.set(page.path, [pathSpec, page.component]);
}
else {
throw new Error('Invalid page configuration: ' + page.path);
}
};
const createLayout = (layout) => {
if (configured) {
throw new Error('no longer available');
}
if (layout.render === 'static') {
const id = (0, path_1.joinPath)(layout.path, 'layout').replace(/^\//, '');
registerStaticComponent(id, layout.component);
}
else if (layout.render === 'dynamic') {
if (dynamicLayoutPathMap.has(layout.path)) {
throw new Error(`Duplicated dynamic path: ${layout.path}`);
}
const pathSpec = (0, path_1.parsePathWithSlug)(layout.path);
dynamicLayoutPathMap.set(layout.path, [pathSpec, layout.component]);
}
else {
throw new Error('Invalid layout configuration');
}
};
const unstable_setBuildData = (path, data) => {
buildDataMap.set(path, data);
};
let ready;
const configure = async (buildConfig) => {
if (!configured && !ready) {
ready = fn({ createPage, createLayout, unstable_setBuildData }, { unstable_buildConfig: buildConfig });
await ready;
configured = true;
}
await ready;
};
return (0, defineRouter_1.unstable_defineRouter)(async () => {
await configure();
const paths = [];
for (const [path, pathSpec] of staticPathSet) {
const noSsr = noSsrSet.has(pathSpec);
const isStatic = (() => {
for (const [_, [layoutPathSpec]] of dynamicLayoutPathMap) {
if (hasPathSpecPrefix(layoutPathSpec, pathSpec)) {
return false;
}
}
return true;
})();
paths.push({
pattern: (0, path_1.path2regexp)((0, path_1.parsePathWithSlug)(path)),
path: pathSpec,
isStatic,
noSsr,
data: buildDataMap.get(path),
});
}
for (const [path, [pathSpec]] of dynamicPagePathMap) {
const noSsr = noSsrSet.has(pathSpec);
paths.push({
pattern: (0, path_1.path2regexp)((0, path_1.parsePathWithSlug)(path)),
path: pathSpec,
isStatic: false,
noSsr,
data: buildDataMap.get(path),
});
}
for (const [path, [pathSpec]] of wildcardPagePathMap) {
const noSsr = noSsrSet.has(pathSpec);
paths.push({
pattern: (0, path_1.path2regexp)((0, path_1.parsePathWithSlug)(path)),
path: pathSpec,
isStatic: false,
noSsr,
data: buildDataMap.get(path),
});
}
return paths;
}, async (id, { unstable_setShouldSkip, unstable_buildConfig }) => {
await configure(unstable_buildConfig);
const staticComponent = staticComponentMap.get(id);
if (staticComponent) {
unstable_setShouldSkip([]);
return staticComponent;
}
for (const [_, [pathSpec, Component]] of dynamicPagePathMap) {
const mapping = (0, path_1.getPathMapping)([...pathSpec, { type: 'literal', name: 'page' }], id);
if (mapping) {
if (Object.keys(mapping).length === 0) {
unstable_setShouldSkip();
return Component;
}
const WrappedComponent = (props) => (0, react_1.createElement)(Component, { ...props, ...mapping });
unstable_setShouldSkip();
return WrappedComponent;
}
}
for (const [_, [pathSpec, Component]] of wildcardPagePathMap) {
const mapping = (0, path_1.getPathMapping)([...pathSpec, { type: 'literal', name: 'page' }], id);
if (mapping) {
const WrappedComponent = (props) => (0, react_1.createElement)(Component, { ...props, ...mapping });
unstable_setShouldSkip();
return WrappedComponent;
}
}
for (const [_, [pathSpec, Component]] of dynamicLayoutPathMap) {
const mapping = (0, path_1.getPathMapping)([...pathSpec, { type: 'literal', name: 'layout' }], id);
if (mapping) {
if (Object.keys(mapping).length) {
throw new Error('[Bug] layout should not have slugs');
}
unstable_setShouldSkip();
return Component;
}
}
unstable_setShouldSkip([]); // negative cache
return null; // not found
});
}
//# sourceMappingURL=create-pages.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,30 @@
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 2023 Daishi Kato
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { type RouteProps, type ShouldSkip } from 'expo-router/internal/rsc';
import type { FunctionComponent, ReactNode } from 'react';
import type { PathSpec } from '../path';
import { defineEntries } from '../server';
import type { BuildConfig } from '../server';
type RoutePropsForLayout = Omit<RouteProps, 'searchParams'> & {
children: ReactNode;
};
type ShouldSkipValue = ShouldSkip[number][1];
export declare function unstable_defineRouter(getPathConfig: () => Promise<Iterable<{
pattern: string;
path: PathSpec;
isStatic?: boolean;
noSsr?: boolean;
data?: unknown;
}>>, getComponent: (componentId: string, // "**/layout" or "**/page"
options: {
unstable_setShouldSkip: (val?: ShouldSkipValue) => void;
unstable_buildConfig: BuildConfig | undefined;
}) => Promise<FunctionComponent<RouteProps> | FunctionComponent<RoutePropsForLayout> | null>): ReturnType<typeof defineEntries>;
export declare function unstable_redirect(pathname: string, searchParams?: URLSearchParams, skip?: string[]): void;
export {};
//# sourceMappingURL=defineRouter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"defineRouter.d.ts","sourceRoot":"","sources":["../../../src/rsc/router/defineRouter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAUL,KAAK,UAAU,EACf,KAAK,UAAU,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAkB,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,aAAa,EAAY,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAA+C,MAAM,WAAW,CAAC;AAE1F,KAAK,mBAAmB,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,GAAG;IAC5D,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,KAAK,eAAe,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAgB7C,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,OAAO,CAC1B,QAAQ,CAAC;IACP,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC,CACH,EACD,YAAY,EAAE,CACZ,WAAW,EAAE,MAAM,EAAE,2BAA2B;AAChD,OAAO,EAAE;IAEP,sBAAsB,EAAE,CAAC,GAAG,CAAC,EAAE,eAAe,KAAK,IAAI,CAAC;IACxD,oBAAoB,EAAE,WAAW,GAAG,SAAS,CAAC;CAC/C,KACE,OAAO,CAAC,iBAAiB,CAAC,UAAU,CAAC,GAAG,iBAAiB,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC,GAC1F,UAAU,CAAC,OAAO,aAAa,CAAC,CAmKlC;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,eAAe,EAC9B,IAAI,CAAC,EAAE,MAAM,EAAE,QAUhB"}

View File

@@ -0,0 +1,169 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unstable_defineRouter = unstable_defineRouter;
exports.unstable_redirect = unstable_redirect;
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 2023 Daishi Kato
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const rsc_1 = require("expo-router/internal/rsc");
const react_1 = require("react");
const path_1 = require("../path");
const server_1 = require("../server");
const safeJsonParse = (str) => {
if (typeof str === 'string') {
try {
const obj = JSON.parse(str);
if (typeof obj === 'object') {
return obj;
}
}
catch {
// ignore
}
}
return undefined;
};
function unstable_defineRouter(getPathConfig, getComponent) {
let cachedPathConfig;
const getMyPathConfig = async (buildConfig) => {
if (buildConfig) {
return buildConfig;
}
if (!cachedPathConfig) {
cachedPathConfig = Array.from(await getPathConfig()).map((item) => {
const is404 = item.path.length === 1 &&
item.path[0].type === 'literal' &&
item.path[0].name === '404';
return {
pattern: item.pattern,
pathname: item.path,
isStatic: item.isStatic,
customData: { is404, noSsr: !!item.noSsr, data: item.data },
};
});
}
return cachedPathConfig;
};
const existsPath = async (pathname, buildConfig) => {
const pathConfig = await getMyPathConfig(buildConfig);
const found = pathConfig.find(({ pathname: pathSpec }) => (0, path_1.getPathMapping)(pathSpec, pathname));
return found
? found.customData.noSsr
? ['FOUND', 'NO_SSR']
: ['FOUND']
: pathConfig.some(({ customData: { is404 } }) => is404) // FIXMEs should avoid re-computation
? ['NOT_FOUND', 'HAS_404']
: ['NOT_FOUND'];
};
const renderEntries = async (input, { params, buildConfig }) => {
const pathname = (0, rsc_1.parseInputString)(input);
if ((await existsPath(pathname, buildConfig))[0] === 'NOT_FOUND') {
return null;
}
const shouldSkipObj = {};
const parsedParams = safeJsonParse(params);
const query = typeof parsedParams?.query === 'string' ? parsedParams.query : '';
const skip = Array.isArray(parsedParams?.skip) ? parsedParams?.skip : [];
const componentIds = (0, rsc_1.getComponentIds)(pathname);
const entries = (await Promise.all(componentIds.map(async (id) => {
if (skip?.includes(id)) {
return [];
}
const setShouldSkip = (val) => {
if (val) {
shouldSkipObj[id] = val;
}
else {
delete shouldSkipObj[id];
}
};
const component = await getComponent(id, {
unstable_setShouldSkip: setShouldSkip,
unstable_buildConfig: buildConfig,
});
if (!component) {
return [];
}
const element = (0, react_1.createElement)(component, id.endsWith('/layout') ? { path: pathname } : { path: pathname, query }, (0, react_1.createElement)(rsc_1.Children));
return [[id, element]];
}))).flat();
entries.push([rsc_1.SHOULD_SKIP_ID, Object.entries(shouldSkipObj)]);
entries.push([rsc_1.LOCATION_ID, [pathname, query]]);
return Object.fromEntries(entries);
};
const getBuildConfig = async (unstable_collectClientModules) => {
const pathConfig = await getMyPathConfig();
const path2moduleIds = {};
for (const { pathname: pathSpec } of pathConfig) {
if (pathSpec.some(({ type }) => type !== 'literal')) {
continue;
}
const pathname = '/' + pathSpec.map(({ name }) => name).join('/');
const input = (0, rsc_1.getInputString)(pathname);
const moduleIds = await unstable_collectClientModules(input);
path2moduleIds[pathname] = moduleIds;
}
const customCode = `
globalThis.__EXPO_ROUTER_PREFETCH__ = (path) => {
const path2ids = ${JSON.stringify(path2moduleIds)};
for (const id of path2ids[path] || []) {
import(id);
}
};`;
const buildConfig = [];
for (const { pathname: pathSpec, isStatic, customData } of pathConfig) {
const entries = [];
if (pathSpec.every(({ type }) => type === 'literal')) {
const pathname = '/' + pathSpec.map(({ name }) => name).join('/');
const input = (0, rsc_1.getInputString)(pathname);
entries.push({ input, isStatic });
}
buildConfig.push({
pathname: pathSpec,
isStatic,
entries,
customCode,
customData,
});
}
return buildConfig;
};
const getSsrConfig = async (pathname, { searchParams, buildConfig }) => {
const pathStatus = await existsPath(pathname, buildConfig);
if (pathStatus[1] === 'NO_SSR') {
return null;
}
if (pathStatus[0] === 'NOT_FOUND') {
if (pathStatus[1] === 'HAS_404') {
pathname = '/404';
}
else {
return null;
}
}
const componentIds = (0, rsc_1.getComponentIds)(pathname);
const input = (0, rsc_1.getInputString)(pathname);
const html = (0, react_1.createElement)(rsc_1.ServerRouter, { route: { path: pathname, query: searchParams.toString(), hash: '' } }, componentIds.reduceRight((acc, id) => (0, react_1.createElement)(rsc_1.Slot, { id, fallback: acc }, acc), null));
return {
input,
params: JSON.stringify({ query: searchParams.toString() }),
html,
};
};
return { renderEntries, getBuildConfig, getSsrConfig };
}
function unstable_redirect(pathname, searchParams, skip) {
if (skip) {
searchParams = new URLSearchParams(searchParams);
for (const id of skip) {
searchParams.append(rsc_1.PARAM_KEY_SKIP, id);
}
}
const input = (0, rsc_1.getInputString)(pathname);
(0, server_1.rerender)(input, searchParams);
}
//# sourceMappingURL=defineRouter.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
declare const _default: (getRouteOptions?: import("expo-router/build/getRoutes").Options) => import("../server").EntriesDev;
export default _default;
//# sourceMappingURL=expo-definedRouter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"expo-definedRouter.d.ts","sourceRoot":"","sources":["../../../src/rsc/router/expo-definedRouter.ts"],"names":[],"mappings":";AAiBA,wBAyHG"}

View File

@@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _ctx_1 = require("expo-router/_ctx");
const routing_1 = require("expo-router/internal/routing");
const create_expo_pages_1 = require("./create-expo-pages");
const getRoutesSSR_1 = require("../../getRoutesSSR");
const loadStaticParamsAsync_1 = require("../../loadStaticParamsAsync");
const UNIMPLEMENTED_PARAMS = new Proxy({}, {
// Assert that params is unimplemented when accessed.
get() {
throw new Error('generateStaticParams(): params is not implemented yet');
},
});
exports.default = (0, create_expo_pages_1.createExpoPages)(async ({ createPage, createLayout }, { getRouteOptions }) => {
const routes = (0, getRoutesSSR_1.getRoutes)(_ctx_1.ctx, {
...getRouteOptions,
platform: process.env.EXPO_OS,
skipGenerated: true,
importMode: 'lazy',
});
if (!routes)
return;
async function loadAndConvertStaticParamsAsync(route) {
const loaded = route.loadRoute();
let staticPaths = undefined;
if (route.dynamic) {
const params = await (0, loadStaticParamsAsync_1.evalStaticParamsAsync)(route, { parentParams: UNIMPLEMENTED_PARAMS }, loaded.generateStaticParams);
// Sort `params` like `[{a: 'x', b: 'y'}, { a: 'z', b: 'w' }]` for a route.dynamic like `[{name: 'a', deep: false}, {name: 'b', deep: false}]` to `[['a', 'y'], ['z', 'w]]`
staticPaths = params?.map((p) => {
const grouped = [];
for (const dynamic of route.dynamic) {
const defined = p[dynamic.name];
if (!defined) {
throw new Error('generateStaticParams is missing param: ' +
dynamic.name +
'. In route: ' +
route.contextKey);
}
if (Array.isArray(defined)) {
if (defined.length > 1) {
throw new Error('generateStaticParams does not support returning multiple static paths for deep dynamic routes in React Server Components yet. Update route: ' +
route.contextKey);
}
}
const first = Array.isArray(defined) ? defined[0] : defined;
grouped.push(first);
}
return grouped;
});
}
else if (loaded.generateStaticParams) {
throw new Error('Cannot use generateStaticParams without a dynamic route: ' + route.contextKey);
}
return staticPaths;
}
async function addLayout(route) {
const normal = (0, routing_1.getContextKey)(route.contextKey).replace(/\/index$/, '');
const loaded = route.loadRoute();
if (loaded.generateStaticParams) {
throw new Error('generateStaticParams is not supported in _layout routes with React Server Components enabled yet.');
}
createLayout({
// NOTE(EvanBacon): Support routes with top-level "use client"
component: loaded.default,
path: normal,
render: 'static',
...loaded.unstable_settings,
});
await Promise.all(route.children.sort(routing_1.sortRoutes).map(async (child) => {
if (child.type === 'layout') {
await addLayout(child);
}
else {
const normal = (0, routing_1.getContextKey)(child.contextKey).replace(/\/index$/, '');
const loaded = child.loadRoute();
const settings = loaded.unstable_settings;
// Support generateStaticParams for dynamic routes by defining the route twice.
if (loaded.generateStaticParams) {
createPage({
// NOTE(EvanBacon): Support routes with top-level "use client"
component: loaded.default,
path: normal,
render: 'static',
...loaded.unstable_settings,
staticPaths: (await loadAndConvertStaticParamsAsync(child)),
});
if (settings?.render !== 'static') {
createPage({
// NOTE(EvanBacon): Support routes with top-level "use client"
component: loaded.default,
path: normal,
render: 'dynamic',
...settings,
});
}
}
else {
createPage({
// NOTE(EvanBacon): Support routes with top-level "use client"
component: loaded.default,
path: normal,
render: 'dynamic',
...settings,
});
}
}
}));
}
await addLayout(routes);
});
//# sourceMappingURL=expo-definedRouter.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
declare const _default: (getRouteOptions?: import("expo-router/build/getRoutes").Options) => import("../server").EntriesDev;
export default _default;
//# sourceMappingURL=noopRouter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"noopRouter.d.ts","sourceRoot":"","sources":["../../../src/rsc/router/noopRouter.ts"],"names":[],"mappings":";AAEA,wBAEG"}

View File

@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const create_expo_pages_1 = require("./create-expo-pages");
exports.default = (0, create_expo_pages_1.createExpoPages)(async () => {
// noop the router for client-only mode. This ensures we skip loading the routes in react-server mode.
});
//# sourceMappingURL=noopRouter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"noopRouter.js","sourceRoot":"","sources":["../../../src/rsc/router/noopRouter.ts"],"names":[],"mappings":";;AAAA,2DAAsD;AAEtD,kBAAe,IAAA,mCAAe,EAAC,KAAK,IAAI,EAAE;IACxC,sGAAsG;AACxG,CAAC,CAAC,CAAC","sourcesContent":["import { createExpoPages } from './create-expo-pages';\n\nexport default createExpoPages(async () => {\n // noop the router for client-only mode. This ensures we skip loading the routes in react-server mode.\n});\n"]}

View File

@@ -0,0 +1,44 @@
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 dai-shi.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* From waku https://github.com/dai-shi/waku/blob/32d52242c1450b5f5965860e671ff73c42da8bd0/packages/waku/src/lib/renderers/rsc-renderer.ts
*/
import '@expo/metro-runtime/rsc/runtime';
import { type EntriesDev } from './server';
export interface RenderContext<T = unknown> {
rerender: (input: string, searchParams?: URLSearchParams) => void;
context: T;
}
type ResolvedConfig = any;
export type RenderRscArgs = {
config: ResolvedConfig;
input: string;
context: Record<string, unknown> | undefined;
body?: ReadableStream | undefined;
contentType?: string | undefined;
decodedBody?: unknown;
moduleIdCallback?: (module: {
id: string;
chunks: string[];
name: string;
async: boolean;
}) => void;
onError?: (err: unknown) => void;
};
type ResolveClientEntry = (id: string, server: boolean) => {
id: string;
chunks: string[];
};
type RenderRscOpts = {
isExporting: boolean;
entries: EntriesDev;
resolveClientEntry: ResolveClientEntry;
loadServerModuleRsc: (url: string) => Promise<any>;
};
export declare function renderRsc(args: RenderRscArgs, opts: RenderRscOpts): Promise<ReadableStream>;
export {};
//# sourceMappingURL=rsc-renderer.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"rsc-renderer.d.ts","sourceRoot":"","sources":["../../src/rsc/rsc-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,iCAAiC,CAAC;AAOzC,OAAO,EAAsB,KAAK,UAAU,EAAmB,MAAM,UAAU,CAAC;AAOhF,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,eAAe,KAAK,IAAI,CAAC;IAClE,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,KAAK,cAAc,GAAG,GAAG,CAAC;AAE1B,MAAM,MAAM,aAAa,GAAG;IAE1B,MAAM,EAAE,cAAc,CAAC;IAGvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC7C,IAAI,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE;QAC1B,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,OAAO,CAAC;KAChB,KAAK,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,KAAK,kBAAkB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE5F,KAAK,aAAa,GAAG;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,mBAAmB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CACpD,CAAC;AAEF,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAwKjG"}

View File

@@ -0,0 +1,200 @@
"use strict";
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 dai-shi.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* From waku https://github.com/dai-shi/waku/blob/32d52242c1450b5f5965860e671ff73c42da8bd0/packages/waku/src/lib/renderers/rsc-renderer.ts
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderRsc = renderRsc;
// This file must remain platform agnostic for production exports.
// Import the runtime to support polyfills for webpack to load modules in the server using Metro.
require("@expo/metro-runtime/rsc/runtime");
const rsc_1 = require("expo-router/internal/rsc");
const server_1 = require("react-server-dom-webpack/server");
const path_1 = require("./path");
const server_2 = require("./server");
async function renderRsc(args, opts) {
const { input, body, contentType, context, onError } = args;
const { resolveClientEntry, entries } = opts;
const { default: { renderEntries },
// @ts-expect-error
buildConfig, } = entries;
function resolveRequest(isServer, encodedId) {
const [
// File is the on-disk location of the module, this is injected during the "use client" transformation (babel).
file,
// The name of the import (e.g. "default" or "")
// This will be empty when using `module.exports = ` and `require('...')`.
name = '',] = encodedId.split('#');
const filePath = file.startsWith('file://') ? (0, path_1.fileURLToFilePath)(file) : file;
args.moduleIdCallback?.({
id: filePath,
chunks: [
// TODO: Add a lookup later which reads from the SSR manifest to get the correct chunk.
// NOTE(EvanBacon): This is a placeholder since we need to render RSC to get the client boundaries, which we then inject later.
'chunk:' + filePath,
],
name,
async: true,
});
// We'll augment the file path with the incoming RSC request which will forward the metro props required to make a cache hit, e.g. platform=web&...
// This is similar to how we handle lazy bundling.
const resolved = resolveClientEntry(filePath, isServer);
return { id: resolved.id, chunks: resolved.chunks, name, async: true };
}
const bundlerConfig = new Proxy({}, {
get(_target, encodedId) {
return resolveRequest(false, encodedId);
},
});
const serverConfig = new Proxy({}, {
get(_target, encodedId) {
return resolveRequest(true, encodedId);
},
});
// @ts-ignore: Not part of global types. This is added to support server actions loading more actions.
global[`${__METRO_GLOBAL_PREFIX__}__loadBundleAsync`] = opts.loadServerModuleRsc;
const renderWithContext = async (context, input, params) => {
const renderStore = {
context: context || {},
rerender: () => {
throw new Error('Cannot rerender');
},
};
return (0, server_2.runWithRenderStore)(renderStore, async () => {
const elements = await renderEntries(input, {
params,
buildConfig,
});
if (elements === null) {
const err = new Error('No function component found at: ' + input);
err.statusCode = 404;
throw err;
}
if (Object.keys(elements).some((key) => key.startsWith('_'))) {
throw new Error('"_" prefix is reserved');
}
return (0, server_1.renderToReadableStream)(elements, bundlerConfig, {
onError,
});
});
};
const renderWithContextWithAction = async (context, actionFn, actionArgs) => {
let elementsPromise = Promise.resolve({});
let rendered = false;
const renderStore = {
context: context || {},
rerender: async (input, params) => {
if (rendered) {
throw new Error('already rendered');
}
elementsPromise = Promise.all([
elementsPromise,
renderEntries(input, { params, buildConfig }),
]).then(([oldElements, newElements]) => ({
...oldElements,
// FIXME we should actually check if newElements is null and send an error
...newElements,
}));
},
};
return (0, server_2.runWithRenderStore)(renderStore, async () => {
const actionValue = await actionFn(...actionArgs);
const elements = await elementsPromise;
rendered = true;
if (Object.keys(elements).some((key) => key.startsWith('_'))) {
throw new Error('"_" prefix is reserved');
}
return (0, server_1.renderToReadableStream)({ ...elements, _value: actionValue }, bundlerConfig, {
onError,
});
});
};
let decodedBody = args.decodedBody;
if (body) {
const bodyStr = await streamToString(body);
if (typeof contentType === 'string' && contentType.startsWith('multipart/form-data')) {
// XXX This doesn't support streaming unlike busboy
const formData = parseFormData(bodyStr, contentType);
decodedBody = await (0, server_1.decodeReply)(formData, serverConfig);
}
else if (bodyStr) {
decodedBody = await (0, server_1.decodeReply)(bodyStr, serverConfig);
}
}
const actionId = (0, rsc_1.decodeActionId)(input);
if (actionId) {
if (!opts.isExporting &&
// @ts-ignore
!process.env.EXPO_UNSTABLE_SERVER_FUNCTIONS) {
throw new Error('Experimental support for React Server Functions is not enabled');
}
const args = Array.isArray(decodedBody) ? decodedBody : [];
const chunkInfo = serverConfig[actionId];
// Load module into memory.
await Promise.all(chunkInfo.chunks.map((chunk) => globalThis.__webpack_chunk_load__(chunk)));
// Import module.
const mod = globalThis.__webpack_require__(chunkInfo.id);
const fn = chunkInfo.name === '*' ? chunkInfo.name : mod[chunkInfo.name] || mod;
if (!fn) {
throw new Error(`Could not find server action: ${actionId}. Module: ${JSON.stringify(chunkInfo, null, 2)}`);
}
return renderWithContextWithAction(context, fn, args);
}
// method === 'GET'
return renderWithContext(context, input, decodedBody);
}
// TODO is this correct? better to use a library?
const parseFormData = (body, contentType) => {
const boundary = contentType.split('boundary=')[1];
const parts = body.split(`--${boundary}`);
const formData = new FormData();
for (const part of parts) {
if (part.trim() === '' || part === '--')
continue;
const [rawHeaders, content] = part.split('\r\n\r\n', 2);
const headers = rawHeaders.split('\r\n').reduce((acc, currentHeader) => {
const [key, value] = currentHeader.split(': ');
acc[key.toLowerCase()] = value;
return acc;
}, {});
const contentDisposition = headers['content-disposition'];
const nameMatch = /name="([^"]+)"/.exec(contentDisposition);
const filenameMatch = /filename="([^"]+)"/.exec(contentDisposition);
if (nameMatch) {
const name = nameMatch[1];
if (filenameMatch) {
const filename = filenameMatch[1];
const type = headers['content-type'] || 'application/octet-stream';
const blob = new Blob([content], { type });
formData.append(name, blob, filename);
}
else {
formData.append(name, content.trim());
}
}
}
return formData;
};
const streamToString = async (stream) => {
const decoder = new TextDecoder();
const reader = stream.getReader();
const outs = [];
let result;
do {
result = await reader.read();
if (result.value) {
if (!(result.value instanceof Uint8Array)) {
throw new Error('Unexepected buffer type');
}
outs.push(decoder.decode(result.value, { stream: true }));
}
} while (!result.done);
outs.push(decoder.decode());
return outs.join('');
};
//# sourceMappingURL=rsc-renderer.js.map

File diff suppressed because one or more lines are too long

63
node_modules/@expo/router-server/build/rsc/server.d.ts generated vendored Normal file
View File

@@ -0,0 +1,63 @@
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 2023 Daishi Kato
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import type { ReactNode } from 'react';
import type { PathSpec } from './path';
export declare const REQUEST_HEADERS = "__expo_requestHeaders";
type Config = any;
type Elements = Record<string, ReactNode>;
export type BuildConfig = {
pathname: string | PathSpec;
isStatic?: boolean | undefined;
entries?: {
input: string;
skipPrefetch?: boolean | undefined;
isStatic?: boolean | undefined;
}[];
context?: Record<string, unknown>;
customCode?: string;
customData?: unknown;
}[];
export type RenderEntries = (input: string, options: {
params: unknown | undefined;
buildConfig: BuildConfig | undefined;
}) => Promise<Elements | null>;
export type GetBuildConfig = (unstable_collectClientModules: (input: string) => Promise<string[]>) => Promise<BuildConfig>;
export type GetSsrConfig = (pathname: string, options: {
searchParams: URLSearchParams;
buildConfig?: BuildConfig | undefined;
}) => Promise<{
input: string;
searchParams?: URLSearchParams;
html: ReactNode;
} | null>;
export declare function defineEntries(renderEntries: RenderEntries, getBuildConfig?: GetBuildConfig, getSsrConfig?: GetSsrConfig): {
renderEntries: RenderEntries;
getBuildConfig: GetBuildConfig | undefined;
getSsrConfig: GetSsrConfig | undefined;
};
export type EntriesDev = {
default: ReturnType<typeof defineEntries>;
};
export type EntriesPrd = EntriesDev & {
loadConfig: () => Promise<Config>;
loadModule: (id: string) => Promise<unknown>;
dynamicHtmlPaths: [pathSpec: PathSpec, htmlHead: string][];
publicIndexHtml: string;
};
type RenderStore = {
rerender: (input: string, params?: unknown) => void;
context: Record<string, unknown>;
};
/**
* This is an internal function and not for public use.
*/
export declare const runWithRenderStore: <T>(renderStore: RenderStore, fn: () => T) => T;
export declare function rerender(input: string, params?: unknown): Promise<void>;
export declare function getContext<RscContext extends Record<string, unknown> = Record<string, unknown>>(): RscContext;
export {};
//# sourceMappingURL=server.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/rsc/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEvC,eAAO,MAAM,eAAe,0BAA0B,CAAC;AASvD,KAAK,MAAM,GAAG,GAAG,CAAC;AAElB,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAE1C,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QACnC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;KAChC,EAAE,CAAC;IACJ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,EAAE,CAAC;AAEJ,MAAM,MAAM,aAAa,GAAG,CAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IACP,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;CACtC,KACE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE9B,MAAM,MAAM,cAAc,GAAG,CAC3B,6BAA6B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,KAChE,OAAO,CAAC,WAAW,CAAC,CAAC;AAE1B,MAAM,MAAM,YAAY,GAAG,CACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;IACP,YAAY,EAAE,eAAe,CAAC;IAC9B,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CACvC,KACE,OAAO,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,eAAe,CAAC;IAC/B,IAAI,EAAE,SAAS,CAAC;CACjB,GAAG,IAAI,CAAC,CAAC;AAEV,wBAAgB,aAAa,CAC3B,aAAa,EAAE,aAAa,EAC5B,cAAc,CAAC,EAAE,cAAc,EAC/B,YAAY,CAAC,EAAE,YAAY;;;;EAG5B;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG;IACpC,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;IAC3D,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,WAAW,GAAK;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC;AA2BF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAAE,aAAa,WAAW,EAAE,IAAI,MAAM,CAAC,KAAG,CAY7E,CAAC;AAEF,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,iBAO7D;AAED,wBAAgB,UAAU,CACxB,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACjE,UAAU,CAOd"}

72
node_modules/@expo/router-server/build/rsc/server.js generated vendored Normal file
View File

@@ -0,0 +1,72 @@
"use strict";
/**
* Copyright © 2024 650 Industries.
* Copyright © 2024 2023 Daishi Kato
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.runWithRenderStore = exports.REQUEST_HEADERS = void 0;
exports.defineEntries = defineEntries;
exports.rerender = rerender;
exports.getContext = getContext;
const node_async_hooks_1 = require("node:async_hooks");
exports.REQUEST_HEADERS = '__expo_requestHeaders';
function defineEntries(renderEntries, getBuildConfig, getSsrConfig) {
return { renderEntries, getBuildConfig, getSsrConfig };
}
// TODO(EvanBacon): This can leak between platforms and runs.
// We need to share this module between the server action module and the renderer module, per platform, and invalidate on refreshes.
function getGlobalCacheForPlatform() {
// HACK: This is a workaround for the shared middleware being shared between web and native.
// In production the shared middleware is web-only and that causes the first version of this module
// to be bound to web.
const platform = globalThis.__expo_platform_header ?? process.env.EXPO_OS;
if (!globalThis.__EXPO_RSC_CACHE__) {
globalThis.__EXPO_RSC_CACHE__ = new Map();
}
if (globalThis.__EXPO_RSC_CACHE__.has(platform)) {
return globalThis.__EXPO_RSC_CACHE__.get(platform);
}
const serverCache = new node_async_hooks_1.AsyncLocalStorage();
globalThis.__EXPO_RSC_CACHE__.set(platform, serverCache);
return serverCache;
}
let previousRenderStore;
let currentRenderStore;
/**
* This is an internal function and not for public use.
*/
const runWithRenderStore = (renderStore, fn) => {
const renderStorage = getGlobalCacheForPlatform();
if (renderStorage) {
return renderStorage.run(renderStore, fn);
}
previousRenderStore = currentRenderStore;
currentRenderStore = renderStore;
try {
return fn();
}
finally {
currentRenderStore = previousRenderStore;
}
};
exports.runWithRenderStore = runWithRenderStore;
async function rerender(input, params) {
const renderStorage = getGlobalCacheForPlatform();
const renderStore = renderStorage.getStore() ?? currentRenderStore;
if (!renderStore) {
throw new Error('Render store is not available for rerender');
}
renderStore.rerender(input, params);
}
function getContext() {
const renderStorage = getGlobalCacheForPlatform();
const renderStore = renderStorage.getStore() ?? currentRenderStore;
if (!renderStore) {
throw new Error('Render store is not available for accessing context');
}
return renderStore.context;
}
//# sourceMappingURL=server.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
export declare function getRootComponent(): any;
//# sourceMappingURL=getRootComponent.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getRootComponent.d.ts","sourceRoot":"","sources":["../../src/static/getRootComponent.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,wBAAgB,gBAAgB,QAe/B"}

View File

@@ -0,0 +1,25 @@
"use strict";
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRootComponent = getRootComponent;
const _ctx_html_1 = require("expo-router/_ctx-html");
function getRootComponent() {
const keys = _ctx_html_1.ctx.keys();
if (!keys.length) {
return require('./html').Html;
}
if (keys.length > 1) {
throw new Error(`Multiple components match the root HTML element: ${keys.join(', ')}`);
}
const exp = (0, _ctx_html_1.ctx)(keys[0]);
if (!exp.default) {
throw new Error(`The root HTML element "${keys[0]}" is missing the required default export.`);
}
return exp.default;
}
//# sourceMappingURL=getRootComponent.js.map

View File

@@ -0,0 +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"]}

View File

@@ -0,0 +1,22 @@
/**
* Copyright © 2024 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { type GetRoutesOptions } from 'expo-router/internal/routing';
import { type RoutesManifest } from 'expo-server/private';
/**
* Get the server manifest with all dynamic routes loaded with `generateStaticParams`.
* Unlike the `@expo/router-server/src/routes-manifest.ts` method, this requires loading the entire app in-memory, which
* takes substantially longer and requires Metro bundling.
*
* This is used for the production manifest where we pre-render certain pages and should no longer treat them as dynamic.
*/
export declare function getBuildTimeServerManifestAsync(options?: GetRoutesOptions): Promise<RoutesManifest<string>>;
/** Get the linking manifest from a Node.js process. */
export declare function getManifest(options?: GetRoutesOptions): Promise<{
initialRouteName: undefined;
screens: Record<string, import("expo-router/build/getReactNavigationConfig").Screen>;
}>;
//# sourceMappingURL=getServerManifest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getServerManifest.d.ts","sourceRoot":"","sources":["../../src/static/getServerManifest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D;;;;;;GAMG;AACH,wBAAsB,+BAA+B,CACnD,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAgBjC;AAED,uDAAuD;AACvD,wBAAsB,WAAW,CAAC,OAAO,GAAE,gBAAqB;;;GAgB/D"}

View File

@@ -0,0 +1,51 @@
"use strict";
/**
* Copyright © 2024 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBuildTimeServerManifestAsync = getBuildTimeServerManifestAsync;
exports.getManifest = getManifest;
const _ctx_1 = require("expo-router/_ctx");
const routing_1 = require("expo-router/internal/routing");
const getServerManifest_1 = require("../getServerManifest");
const loadStaticParamsAsync_1 = require("../loadStaticParamsAsync");
/**
* Get the server manifest with all dynamic routes loaded with `generateStaticParams`.
* Unlike the `@expo/router-server/src/routes-manifest.ts` method, this requires loading the entire app in-memory, which
* takes substantially longer and requires Metro bundling.
*
* This is used for the production manifest where we pre-render certain pages and should no longer treat them as dynamic.
*/
async function getBuildTimeServerManifestAsync(options = {}) {
const routeTree = (0, routing_1.getRoutes)(_ctx_1.ctx, {
platform: 'web',
...options,
});
if (!routeTree) {
throw new Error('No routes found');
}
// Evaluate all static params; skip for SSR mode where routes are matched at runtime
if (!options.skipStaticParams) {
await (0, loadStaticParamsAsync_1.loadStaticParamsAsync)(routeTree);
}
return (0, getServerManifest_1.getServerManifest)(routeTree, options);
}
/** Get the linking manifest from a Node.js process. */
async function getManifest(options = {}) {
const routeTree = (0, routing_1.getRoutes)(_ctx_1.ctx, {
preserveApiRoutes: true,
preserveRedirectAndRewrites: true,
platform: 'web',
...options,
});
if (!routeTree) {
throw new Error('No routes found');
}
// Evaluate all static params
await (0, loadStaticParamsAsync_1.loadStaticParamsAsync)(routeTree);
return (0, routing_1.getReactNavigationConfig)(routeTree, false);
}
//# sourceMappingURL=getServerManifest.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getServerManifest.js","sourceRoot":"","sources":["../../src/static/getServerManifest.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAoBH,0EAkBC;AAGD,kCAgBC;AAvDD,2CAAuC;AACvC,0DAIsC;AAGtC,4DAAyD;AACzD,oEAAiE;AAEjE;;;;;;GAMG;AACI,KAAK,UAAU,+BAA+B,CACnD,UAA4B,EAAE;IAE9B,MAAM,SAAS,GAAG,IAAA,mBAAS,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,oFAAoF;IACpF,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAC9B,MAAM,IAAA,6CAAqB,EAAC,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,IAAA,qCAAiB,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,uDAAuD;AAChD,KAAK,UAAU,WAAW,CAAC,UAA4B,EAAE;IAC9D,MAAM,SAAS,GAAG,IAAA,mBAAS,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,kCAAwB,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 {\n getReactNavigationConfig,\n getRoutes,\n type GetRoutesOptions,\n} from 'expo-router/internal/routing';\nimport { type RoutesManifest } from 'expo-server/private';\n\nimport { getServerManifest } from '../getServerManifest';\nimport { loadStaticParamsAsync } from '../loadStaticParamsAsync';\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: GetRoutesOptions = {}\n): Promise<RoutesManifest<string>> {\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; skip for SSR mode where routes are matched at runtime\n if (!options.skipStaticParams) {\n await loadStaticParamsAsync(routeTree);\n }\n\n return getServerManifest(routeTree, options);\n}\n\n/** Get the linking manifest from a Node.js process. */\nexport async function getManifest(options: GetRoutesOptions = {}) {\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"]}

View File

@@ -0,0 +1,10 @@
import React, { type PropsWithChildren } from 'react';
/**
* Injects loader data into the HTML as a script tag for client-side hydration.
* The data is serialized as JSON and made available on the `globalThis.__EXPO_ROUTER_LOADER_DATA__` global.
*/
export declare function PreloadedDataScript({ data }: {
data: Record<string, unknown>;
}): React.JSX.Element;
export declare function Html({ children }: PropsWithChildren): React.JSX.Element;
//# sourceMappingURL=html.d.ts.map

View File

@@ -0,0 +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"}

40
node_modules/@expo/router-server/build/static/html.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PreloadedDataScript = PreloadedDataScript;
exports.Html = Html;
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const html_1 = require("expo-router/html");
const react_1 = __importDefault(require("react"));
const html_2 = require("../utils/html");
/**
* Injects loader data into the HTML as a script tag for client-side hydration.
* The data is serialized as JSON and made available on the `globalThis.__EXPO_ROUTER_LOADER_DATA__` global.
*/
function PreloadedDataScript({ data }) {
const safeJson = (0, html_2.escapeUnsafeCharacters)(JSON.stringify(data));
return (<script id="expo-router-data" type="module" dangerouslySetInnerHTML={{
// NOTE(@hassankhan): The double serialization used here isn't as much of a problem server-side, but allows faster
// client-side parsing using native `JSON.parse()`. See https://v8.dev/blog/cost-of-javascript-2019#json
__html: `globalThis.__EXPO_ROUTER_LOADER_DATA__ = JSON.parse(${JSON.stringify(safeJson)});`,
}}/>);
}
function Html({ children }) {
return (<html lang="en">
<head>
<meta charSet="utf-8"/>
<meta httpEquiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<html_1.ScrollViewStyleReset />
</head>
<body>{children}</body>
</html>);
}
//# sourceMappingURL=html.js.map

View File

@@ -0,0 +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"]}

View File

@@ -0,0 +1,23 @@
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import '@expo/metro-runtime';
export type GetStaticContentOptions = {
loader?: {
data?: any;
/** Unique key for the route. Derived from the route's contextKey */
key: string;
};
request?: Request;
/** Asset manifest for hydration bundles (JS/CSS). Used in SSR. */
assets?: {
css: string[];
js: string[];
};
};
export declare function getStaticContent(location: URL, options?: GetStaticContentOptions): Promise<string>;
export { getBuildTimeServerManifestAsync, getManifest } from './getServerManifest';
//# sourceMappingURL=renderStaticContent.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"renderStaticContent.d.ts","sourceRoot":"","sources":["../../src/static/renderStaticContent.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,qBAAqB,CAAC;AA0B7B,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,oEAAoE;QACpE,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,MAAM,CAAC,EAAE;QACP,GAAG,EAAE,MAAM,EAAE,CAAC;QACd,EAAE,EAAE,MAAM,EAAE,CAAC;KACd,CAAC;CACH,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,GAAG,EACb,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,MAAM,CAAC,CAuFjB;AAmBD,OAAO,EAAE,+BAA+B,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}

View File

@@ -0,0 +1,151 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getManifest = exports.getBuildTimeServerManifestAsync = void 0;
exports.getStaticContent = getStaticContent;
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
require("@expo/metro-runtime");
const Font = __importStar(require("expo-font/build/server"));
const expo_router_1 = require("expo-router");
const _ctx_1 = require("expo-router/_ctx");
const head_1 = __importDefault(require("expo-router/head"));
const static_1 = require("expo-router/internal/static");
const react_1 = __importDefault(require("react"));
const server_node_1 = __importDefault(require("react-dom/server.node"));
const getRootComponent_1 = require("./getRootComponent");
const html_1 = require("./html");
const debug_1 = require("../utils/debug");
const debug = (0, debug_1.createDebug)('expo:router:server:renderStaticContent');
function resetReactNavigationContexts() {
// https://github.com/expo/router/discussions/588
// https://github.com/react-navigation/react-navigation/blob/9fe34b445fcb86e5666f61e144007d7540f014fa/packages/elements/src/getNamedContext.tsx#LL3C1-L4C1
// React Navigation is storing providers in a global, this is fine for the first static render
// 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.
const contexts = '__react_navigation__elements_contexts';
globalThis[contexts] = new Map();
}
async function getStaticContent(location, options) {
const headContext = {};
const Root = (0, getRootComponent_1.getRootComponent)();
const {
// NOTE: The `element` that's returned adds two extra Views and
// the seemingly unused `RootTagContext.Provider`.
element, getStyleElement, } = (0, static_1.registerStaticRootComponent)(expo_router_1.ExpoRoot, {
location,
context: _ctx_1.ctx,
wrapper: ({ children }) => (<Root>
<div id="root">{children}</div>
</Root>),
});
// Clear any existing static resources from the global scope to attempt to prevent leaking between pages.
// This could break if pages are rendered in parallel or if fonts are loaded outside of the React tree
Font.resetServerContext();
// This MUST be run before `ReactDOMServer.renderToString` to prevent
// "Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported."
resetReactNavigationContexts();
const loaderKey = options?.loader ? options.loader.key + location.search : null;
const loadedData = loaderKey
? {
[loaderKey]: options?.loader?.data ?? null,
}
: null;
const html = server_node_1.default.renderToString(<head_1.default.Provider context={headContext}>
<static_1.InnerRoot loadedData={loadedData}>{element}</static_1.InnerRoot>
</head_1.default.Provider>);
// Eval the CSS after the HTML is rendered so that the CSS is in the same order
const css = server_node_1.default.renderToStaticMarkup(getStyleElement());
let output = mixHeadComponentsWithStaticResults(headContext.helmet, html);
output = output.replace('</head>', `${css}</head>`);
const fonts = Font.getServerResources();
debug(`Pushing static fonts: (count: ${fonts.length})`, fonts);
// debug('Push static fonts:', fonts)
// Inject static fonts loaded with expo-font
output = output.replace('</head>', `${fonts.join('')}</head>`);
if (loadedData) {
const loaderDataScript = server_node_1.default.renderToStaticMarkup(<html_1.PreloadedDataScript data={loadedData}/>);
output = output.replace('</head>', `${loaderDataScript}</head>`);
}
// Inject hydration assets (JS/CSS bundles). Used in SSR mode
if (options?.assets) {
if (options.assets.css.length > 0) {
/**
* For each CSS file, inject two link elements; one for preloading and one as the actual
* stylesheet. This matches what we do for SSG
*
* @see @expo/cli/src/start/server/metro/serializeHtml.ts
*/
const injectedCSS = options.assets.css
.flatMap((href) => [
`<link rel="preload" href="${href}" as="style">`,
`<link rel="stylesheet" href="${href}">`,
])
.join('\n');
output = output.replace('</head>', `${injectedCSS}\n</head>`);
}
if (options.assets.js.length > 0) {
const injectedJS = options.assets.js
.map((src) => `<script src="${src}" defer></script>`)
.join('\n');
output = output.replace('</body>', `${injectedJS}\n</body>`);
}
}
return '<!DOCTYPE html>' + output;
}
function mixHeadComponentsWithStaticResults(helmet, html) {
// Head components
for (const key of ['title', 'priority', 'meta', 'link', 'script', 'style'].reverse()) {
const result = helmet?.[key]?.toString();
if (result) {
html = html.replace('<head>', `<head>${result}`);
}
}
// attributes
html = html.replace('<html ', `<html ${helmet?.htmlAttributes.toString()} `);
html = html.replace('<body ', `<body ${helmet?.bodyAttributes.toString()} `);
return html;
}
// Re-export for use in server
var getServerManifest_1 = require("./getServerManifest");
Object.defineProperty(exports, "getBuildTimeServerManifestAsync", { enumerable: true, get: function () { return getServerManifest_1.getBuildTimeServerManifestAsync; } });
Object.defineProperty(exports, "getManifest", { enumerable: true, get: function () { return getServerManifest_1.getManifest; } });
//# sourceMappingURL=renderStaticContent.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
import { type RequireContext } from 'expo-router';
export type GetTypedRoutesDeclarationFileOptions = {
partialTypedGroups?: boolean;
testIgnoreComments?: boolean;
unstable_useServerMiddleware?: boolean;
};
export declare function getTypedRoutesDeclarationFile(ctx: RequireContext, { partialTypedGroups, testIgnoreComments, unstable_useServerMiddleware, }?: GetTypedRoutesDeclarationFileOptions): string;
//# sourceMappingURL=generate.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/typed-routes/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAYlD,MAAM,MAAM,oCAAoC,GAAG;IACjD,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAEF,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,cAAc,EACnB,EACE,kBAA0B,EAC1B,kBAA0B,EAC1B,4BAAoC,GACrC,GAAE,oCAAyC,UA4G7C"}

View File

@@ -0,0 +1,185 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTypedRoutesDeclarationFile = getTypedRoutesDeclarationFile;
const routing_1 = require("expo-router/internal/routing");
// /[...param1]/ - Match [...param1]
const CATCH_ALL = /\[\.\.\..+?\]/g;
// /[param1] - Match [param1]
const SLUG = /\[.+?\]/g;
// /(group)/path/(group2)/route - Match [(group), (group2)]
const GROUP = /(?:^|\/)\(.*?\)/g;
const urlParams = "${`?${string}` | `#${string}` | ''}";
function getTypedRoutesDeclarationFile(ctx, { partialTypedGroups = false, testIgnoreComments = false, unstable_useServerMiddleware = false, } = {}) {
let routeNode = null;
try {
routeNode = (0, routing_1.getRoutes)(ctx, {
ignore: [/_layout\.[tj]sx?$/], // Skip layout files
platformRoutes: false, // We don't need to generate platform specific routes
notFound: false, // We don't need +not-found routes either
ignoreEntryPoints: true,
ignoreRequireErrors: true,
importMode: 'async', // Don't load the file
// NOTE(@hassankhan): We should ensure that getRoutes() doesn't have optional options in the future
unstable_useServerMiddleware,
});
}
catch {
// Ignore errors from `getRoutes`. This is also called inside the app, which has
// a nicer UX for showing error messages
}
const groupedNodes = groupRouteNodes(routeNode);
const staticRoutesStrings = ['Router.RelativePathString', 'Router.ExternalPathString'];
const staticRouteInputObjects = [
'{ pathname: Router.RelativePathString, params?: Router.UnknownInputParams }',
'{ pathname: Router.ExternalPathString, params?: Router.UnknownInputParams }',
];
const staticRouteOutputObjects = [
'{ pathname: Router.RelativePathString, params?: Router.UnknownOutputParams }',
'{ pathname: Router.ExternalPathString, params?: Router.UnknownOutputParams }',
];
for (const type of groupedNodes.static) {
staticRoutesStrings.push(contextKeyToType(type + urlParams, partialTypedGroups));
staticRouteInputObjects.push(`{ pathname: ${contextKeyToType(type, partialTypedGroups)}; params?: Router.UnknownInputParams; }`);
staticRouteOutputObjects.push(`{ pathname: ${contextKeyToType(type, partialTypedGroups)}; params?: Router.UnknownOutputParams; }`);
}
const dynamicRouteStrings = [];
const dynamicRouteInputObjects = [];
const dynamicRouteOutputObjects = [];
for (const [dynamicRouteTemplate, paramsNames] of groupedNodes.dynamic) {
const inputParams = paramsNames
.map((param) => {
const key = param.startsWith('...') ? param.slice(3) : param;
const value = param.startsWith('...') ? '(string | number)[]' : 'string | number';
return `${contextKeyToProperty(key)}: ${value};`;
})
.join('');
const outputParams = paramsNames
.map((param) => {
const key = param.startsWith('...') ? param.slice(3) : param;
const value = param.startsWith('...') ? 'string[]' : 'string';
return `${contextKeyToProperty(key)}: ${value};`;
})
.join('');
dynamicRouteStrings.push(contextKeyToType(dynamicRouteTemplate
.replaceAll(CATCH_ALL, '${string}')
.replaceAll(SLUG, '${Router.SingleRoutePart<T>}') + urlParams, partialTypedGroups));
dynamicRouteInputObjects.push(`{ pathname: ${contextKeyToType(dynamicRouteTemplate, partialTypedGroups)}, params: Router.UnknownInputParams & { ${inputParams} } }`);
dynamicRouteOutputObjects.push(`{ pathname: ${contextKeyToType(dynamicRouteTemplate, partialTypedGroups)}, params: Router.UnknownOutputParams & { ${outputParams} } }`);
}
const href = [
...staticRoutesStrings,
...staticRouteInputObjects,
...dynamicRouteStrings,
...dynamicRouteInputObjects,
].join(' | ');
const hrefInputParams = [...staticRouteInputObjects, ...dynamicRouteInputObjects].join(' | ');
const hrefOutputParams = [...staticRouteOutputObjects, ...dynamicRouteOutputObjects].join(' | ');
const tsExpectError = testIgnoreComments
? '// @ts-ignore-error -- During tests we need to ignore the "duplicate" declaration error, as multiple fixture declare types \n '
: '';
return `/* eslint-disable */
import * as Router from 'expo-router';
export * from 'expo-router';
declare module 'expo-router' {
export namespace ExpoRouter {
export interface __routes<T extends string | object = string> {
${tsExpectError}hrefInputParams: ${hrefInputParams};
${tsExpectError}hrefOutputParams: ${hrefOutputParams};
${tsExpectError}href: ${href};
}
}
}
`;
}
function groupRouteNodes(routeNode, groupedContextKeys = {
static: new Set(),
dynamic: new Map(),
}) {
if (!routeNode) {
return groupedContextKeys;
}
// Skip non-route files
if (routeNode.type !== 'route') {
// Except the root layout
if (routeNode.route === '') {
for (const child of routeNode.children) {
groupRouteNodes(child, groupedContextKeys);
}
return groupedContextKeys;
}
return groupedContextKeys;
}
let routeKey;
if (routeNode.generated) {
// Some routes like the root _layout, _sitemap, +not-found are generated.
// We cannot use the contextKey, as their context key does not specify a route
routeKey = routeNode.route;
}
else {
routeKey = (0, routing_1.removeSupportedExtensions)(routeNode.contextKey)
.replace(/\/index$/, '') // Remove any trailing /index
.replace(/^\./, ''); // Remove any leading .
}
routeKey ||= '/'; // A routeKey may be empty for contextKey '' or './index.js'
if (!routeKey.startsWith('/')) {
// Not all generated files will have the `/` prefix
routeKey = `/${routeKey}`;
}
routeKey = routeKey.replace(/\\/g, '/');
if (routeNode.dynamic) {
groupedContextKeys.dynamic.set(routeKey, routeKey
.split('/')
.filter((segment) => {
return segment.startsWith('[') && segment.endsWith(']');
})
.map((segment) => {
return segment.slice(1, -1);
}));
}
else {
groupedContextKeys.static.add(routeKey);
}
for (const child of routeNode.children) {
groupRouteNodes(child, groupedContextKeys);
}
return groupedContextKeys;
}
function contextKeyToProperty(contextKey) {
return !/^(?!\d)[\w$]+$/.test(contextKey) ? JSON.stringify(contextKey) : contextKey;
}
function contextKeyToType(contextKey, partialTypedGroups) {
if (contextKey.match(GROUP) === null) {
return `\`${contextKey}\``;
}
// If the route has groups, turn them into template strings
const typeWithGroups = contextKey.replaceAll(GROUP, (match) => {
const groups = match.slice(2, -1); // Remove the leading ( and the trailing )
// When `partialRoutes` is enabled, we always change a group to a template
if (groups.length > 1 || partialTypedGroups) {
// Ensure each group has the trailing slash
const groupsAsType = groups.split(',').map((group) => `'/(${group})'`);
// `partialRoutes` allow you to skip a group
if (partialTypedGroups) {
groupsAsType.push("''");
}
// Combine together into a union
return `\${${groupsAsType.join(' | ')}}`;
}
else {
return match;
}
});
let typeWithoutGroups = contextKey.replaceAll(GROUP, '') || '/';
/**
* When getting the static routes, they include a urlParams string at the end.
* If we have a route like `/(group)/(group2)`, this would normally be collapsed to `/`.
* But because of the urlParams, it becomes `${urlParams}` and we need to add a `/` to the start.
*/
if (typeWithoutGroups.startsWith(urlParams)) {
typeWithoutGroups = `/${typeWithoutGroups}`;
}
return `\`${typeWithGroups}\` | \`${typeWithoutGroups}\``;
}
//# sourceMappingURL=generate.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,35 @@
import { type RequireContextPonyFill } from 'expo-router/internal/testing';
export type { RequireContextPonyFill } from 'expo-router/internal/testing';
/**
* This file is imported via `@expo/cli`. While users should be using the same SDK version of `expo-router` as `@expo/cli`,
* this export allows us to ensure that the version of the `expo-router` package is compatible with the version of `@expo/cli`.
*/
export declare const version = 52;
/**
* Generate a Metro watch handler that regenerates the typed routes declaration file
*/
export declare function getWatchHandler(outputDir: string, { ctx, regenerateFn }?: {
ctx?: RequireContextPonyFill | undefined;
regenerateFn?: ((outputDir: string, options?: {
partialTypedGroups?: boolean;
} | undefined, ctx?: RequireContextPonyFill | undefined) => void) | undefined;
}): ({ filePath, type }: {
filePath: string;
type: string;
}) => Promise<void>;
/**
* Regenerate the declaration file.
*
* This function needs to be debounced due to Metro's handling of renaming folders.
* For example, if you have the file /(tabs)/route.tsx and you rename the folder to /(tabs,test)/route.tsx
*
* Metro will fire 2 filesystem events:
* - ADD /(tabs,test)/router.tsx
* - DELETE /(tabs)/router.tsx
*
* If you process the types after the ADD, then they will crash as you will have conflicting routes
*/
export declare const regenerateDeclarations: (outputDir: string, options?: {
partialTypedGroups?: boolean;
} | undefined, ctx?: RequireContextPonyFill | undefined) => void;
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/typed-routes/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAQ3F,YAAY,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAE3E;;;GAGG;AACH,eAAO,MAAM,OAAO,KAAK,CAAC;AAE1B;;GAEG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,EAAE,GAAgB,EAAE,YAAqC,EAAE;;;6BAyDzB,OAAO;gEAqBZ,IAAI;CA9E+B,IAIjC,oBAAoB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,mBAoCtF;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB;yBAGC,OAAO;4DAqBZ,IAAI,AATlC,CAAC"}

View File

@@ -0,0 +1,99 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.regenerateDeclarations = exports.version = void 0;
exports.getWatchHandler = getWatchHandler;
const _ctx_shared_1 = require("expo-router/_ctx-shared");
const routing_1 = require("expo-router/internal/routing");
const testing_1 = require("expo-router/internal/testing");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const generate_1 = require("./generate");
const defaultCtx = (0, testing_1.requireContext)(process.env.EXPO_ROUTER_APP_ROOT, true, _ctx_shared_1.EXPO_ROUTER_CTX_IGNORE);
/**
* This file is imported via `@expo/cli`. While users should be using the same SDK version of `expo-router` as `@expo/cli`,
* this export allows us to ensure that the version of the `expo-router` package is compatible with the version of `@expo/cli`.
*/
exports.version = 52;
/**
* Generate a Metro watch handler that regenerates the typed routes declaration file
*/
function getWatchHandler(outputDir, { ctx = defaultCtx, regenerateFn = exports.regenerateDeclarations } = {} // Exposed for testing
) {
const routeFiles = new Set(ctx.keys().filter((key) => (0, routing_1.isTypedRoute)(key)));
return async function callback({ filePath, type }) {
// Sanity check that we are in an Expo Router project
if (!process.env.EXPO_ROUTER_APP_ROOT)
return;
let shouldRegenerate = false;
let relativePath = node_path_1.default.relative(process.env.EXPO_ROUTER_APP_ROOT, filePath);
const isInsideAppRoot = !relativePath.startsWith('../');
const basename = node_path_1.default.basename(relativePath);
if (!isInsideAppRoot)
return;
// require.context paths always start with './' when relative to the root
relativePath = `./${relativePath}`;
if (type === 'delete') {
ctx.__delete(relativePath);
if (routeFiles.has(relativePath)) {
routeFiles.delete(relativePath);
shouldRegenerate = true;
}
}
else if (type === 'add') {
ctx.__add(relativePath);
if ((0, routing_1.isTypedRoute)(basename)) {
routeFiles.add(relativePath);
shouldRegenerate = true;
}
}
else {
shouldRegenerate = routeFiles.has(relativePath);
}
if (shouldRegenerate) {
// TODO(@kitten): This was altered from `regenerateFn(outputDir, ctx)` which, as per the types, is incorrect
// It's unclear whether fixing this will have other unintended consequences!
regenerateFn(outputDir, {}, ctx);
}
};
}
/**
* Regenerate the declaration file.
*
* This function needs to be debounced due to Metro's handling of renaming folders.
* For example, if you have the file /(tabs)/route.tsx and you rename the folder to /(tabs,test)/route.tsx
*
* Metro will fire 2 filesystem events:
* - ADD /(tabs,test)/router.tsx
* - DELETE /(tabs)/router.tsx
*
* If you process the types after the ADD, then they will crash as you will have conflicting routes
*/
exports.regenerateDeclarations = debounce((outputDir, options = {}, ctx = defaultCtx) => {
// Don't crash the process, just log the error. The user will most likely fix it and continue
try {
const file = (0, generate_1.getTypedRoutesDeclarationFile)(ctx, options);
if (!file)
return;
node_fs_1.default.writeFileSync(node_path_1.default.resolve(outputDir, './router.d.ts'), file);
}
catch (error) {
console.error(error);
}
});
/**
* Debounce a function to only run once after a period of inactivity
* If called while waiting, it will reset the timer
*/
function debounce(fn, timeout = 1000) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn(...args);
}, timeout);
};
}
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=testSetup.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"testSetup.d.ts","sourceRoot":"","sources":["../../src/typed-routes/testSetup.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const testing_1 = require("expo-router/internal/testing");
const promises_1 = require("node:fs/promises");
const node_path_1 = require("node:path");
const generate_1 = require("./generate");
const fixtures = {
default: {
context: {
'/apple': () => null,
'/banana': () => null,
'/colors/[color]': () => null,
'/animals/[...animal]': () => null,
'/mix/[fruit]/[color]/[...animals]': () => null,
'/(group)/static': () => null,
'/(group)/(a,b)/folder/index': () => null,
'/(group)/(a,b)/folder/[slug]': () => null,
'/(group)/(a,b)/folder/[...slug]': () => null,
'/(c)/folder/[slug]': () => null,
'/(group)/index': () => null,
},
},
partialGroups: {
options: { partialTypedGroups: true },
context: {
'/(group)/static': () => null,
'/(group)/(a,b)/folder/index': () => null,
'/(group)/(a,b)/folder/[slug]': () => null,
'/(group)/(a,b)/folder/[...slug]': () => null,
},
},
};
module.exports = function () {
return Promise.all(Object.entries(fixtures).map(async ([key, value]) => {
const template = (0, generate_1.getTypedRoutesDeclarationFile)((0, testing_1.inMemoryContext)(value.context), {
...value.options,
testIgnoreComments: true,
});
return (0, promises_1.writeFile)((0, node_path_1.join)(__dirname, '/__tests__/fixtures/', key + '.d.ts'), template);
}));
};
//# sourceMappingURL=testSetup.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"testSetup.js","sourceRoot":"","sources":["../../src/typed-routes/testSetup.ts"],"names":[],"mappings":";;AAAA,0DAA8E;AAC9E,+CAA6C;AAC7C,yCAAiC;AAEjC,yCAAiG;AAEjG,MAAM,QAAQ,GAGV;IACF,OAAO,EAAE;QACP,OAAO,EAAE;YACP,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI;YACpB,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI;YACrB,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI;YAC7B,sBAAsB,EAAE,GAAG,EAAE,CAAC,IAAI;YAClC,mCAAmC,EAAE,GAAG,EAAE,CAAC,IAAI;YAC/C,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI;YAC7B,6BAA6B,EAAE,GAAG,EAAE,CAAC,IAAI;YACzC,8BAA8B,EAAE,GAAG,EAAE,CAAC,IAAI;YAC1C,iCAAiC,EAAE,GAAG,EAAE,CAAC,IAAI;YAC7C,oBAAoB,EAAE,GAAG,EAAE,CAAC,IAAI;YAChC,gBAAgB,EAAE,GAAG,EAAE,CAAC,IAAI;SAC7B;KACF;IACD,aAAa,EAAE;QACb,OAAO,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE;QACrC,OAAO,EAAE;YACP,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI;YAC7B,6BAA6B,EAAE,GAAG,EAAE,CAAC,IAAI;YACzC,8BAA8B,EAAE,GAAG,EAAE,CAAC,IAAI;YAC1C,iCAAiC,EAAE,GAAG,EAAE,CAAC,IAAI;SAC9C;KACF;CACF,CAAC;AAEF,MAAM,CAAC,OAAO,GAAG;IACf,OAAO,OAAO,CAAC,GAAG,CAChB,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QAClD,MAAM,QAAQ,GAAG,IAAA,wCAA6B,EAAC,IAAA,yBAAe,EAAC,KAAK,CAAC,OAAO,CAAC,EAAE;YAC7E,GAAG,KAAK,CAAC,OAAO;YAChB,kBAAkB,EAAE,IAAI;SACzB,CAAC,CAAC;QAEH,OAAO,IAAA,oBAAS,EAAC,IAAA,gBAAI,EAAC,SAAS,EAAE,sBAAsB,EAAE,GAAG,GAAG,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;IACrF,CAAC,CAAC,CACH,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { inMemoryContext, MemoryContext } from 'expo-router/internal/testing';\nimport { writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getTypedRoutesDeclarationFile, GetTypedRoutesDeclarationFileOptions } from './generate';\n\nconst fixtures: Record<\n string,\n { context: MemoryContext; options?: GetTypedRoutesDeclarationFileOptions }\n> = {\n default: {\n context: {\n '/apple': () => null,\n '/banana': () => null,\n '/colors/[color]': () => null,\n '/animals/[...animal]': () => null,\n '/mix/[fruit]/[color]/[...animals]': () => null,\n '/(group)/static': () => null,\n '/(group)/(a,b)/folder/index': () => null,\n '/(group)/(a,b)/folder/[slug]': () => null,\n '/(group)/(a,b)/folder/[...slug]': () => null,\n '/(c)/folder/[slug]': () => null,\n '/(group)/index': () => null,\n },\n },\n partialGroups: {\n options: { partialTypedGroups: true },\n context: {\n '/(group)/static': () => null,\n '/(group)/(a,b)/folder/index': () => null,\n '/(group)/(a,b)/folder/[slug]': () => null,\n '/(group)/(a,b)/folder/[...slug]': () => null,\n },\n },\n};\n\nmodule.exports = function () {\n return Promise.all(\n Object.entries(fixtures).map(async ([key, value]) => {\n const template = getTypedRoutesDeclarationFile(inMemoryContext(value.context), {\n ...value.options,\n testIgnoreComments: true,\n });\n\n return writeFile(join(__dirname, '/__tests__/fixtures/', key + '.d.ts'), template);\n })\n );\n};\n"]}

View File

@@ -0,0 +1,17 @@
/**
* Copyright © 2025 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Creates a debug logger that is excluded from production bundles.
*
* In development, it uses the `debug` package for namespaced logging.
*
* In production, it returns a no-op function to avoid bundling `debug`. This is useful for SSR
* when we bundle `@expo/router-server/node/render.js`, and RSC when we bundle
* `@expo/router-server/build/rsc/middleware.js`
*/
export declare function createDebug(namespace: string): (...args: unknown[]) => void;
//# sourceMappingURL=debug.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/utils/debug.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAK3E"}

25
node_modules/@expo/router-server/build/utils/debug.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
"use strict";
/**
* Copyright © 2025 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDebug = createDebug;
/**
* Creates a debug logger that is excluded from production bundles.
*
* In development, it uses the `debug` package for namespaced logging.
*
* In production, it returns a no-op function to avoid bundling `debug`. This is useful for SSR
* when we bundle `@expo/router-server/node/render.js`, and RSC when we bundle
* `@expo/router-server/build/rsc/middleware.js`
*/
function createDebug(namespace) {
if (__DEV__) {
return require('debug')(namespace);
}
return () => { };
}
//# sourceMappingURL=debug.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"debug.js","sourceRoot":"","sources":["../../src/utils/debug.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAWH,kCAKC;AAdD;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,SAAiB;IAC3C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;AAClB,CAAC","sourcesContent":["/**\n * Copyright © 2025 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/**\n * Creates a debug logger that is excluded from production bundles.\n *\n * In development, it uses the `debug` package for namespaced logging.\n *\n * In production, it returns a no-op function to avoid bundling `debug`. This is useful for SSR\n * when we bundle `@expo/router-server/node/render.js`, and RSC when we bundle\n * `@expo/router-server/build/rsc/middleware.js`\n */\nexport function createDebug(namespace: string): (...args: unknown[]) => void {\n if (__DEV__) {\n return require('debug')(namespace);\n }\n return () => {};\n}\n"]}

12
node_modules/@expo/router-server/build/utils/html.d.ts generated vendored Normal file
View File

@@ -0,0 +1,12 @@
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Replaces unsafe characters in a string with their escaped equivalents. This is to safely
* embed data in an HTML context to prevent XSS.
*/
export declare function escapeUnsafeCharacters(str: string): string;
//# sourceMappingURL=html.d.ts.map

View File

@@ -0,0 +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"}

29
node_modules/@expo/router-server/build/utils/html.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
"use strict";
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.escapeUnsafeCharacters = escapeUnsafeCharacters;
// See: https://github.com/urql-graphql/urql/blob/ad0276ae616b2b2f2cd01a527b4217ae35c3fa2d/packages/next-urql/src/htmlescape.ts#L10
// License: https://github.com/urql-graphql/urql/blob/ad0276ae616b2b2f2cd01a527b4217ae35c3fa2d/LICENSE
// This utility is based on https://github.com/zertosh/htmlescape
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
const UNSAFE_CHARACTERS_REGEX = /[&><\u2028\u2029]/g;
const ESCAPED_CHARACTERS = {
'&': '\\u0026',
'>': '\\u003e',
'<': '\\u003c',
'\u2028': '\\u2028',
'\u2029': '\\u2029',
};
/**
* Replaces unsafe characters in a string with their escaped equivalents. This is to safely
* embed data in an HTML context to prevent XSS.
*/
function escapeUnsafeCharacters(str) {
return str.replace(UNSAFE_CHARACTERS_REGEX, (match) => ESCAPED_CHARACTERS[match]);
}
//# sourceMappingURL=html.js.map

View File

@@ -0,0 +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"]}

3
node_modules/@expo/router-server/node/render.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
// Assumes Metro handles this import.
// NOTE(EvanBacon): No relative imports!
module.exports = require('@expo/router-server/build/static/renderStaticContent');

72
node_modules/@expo/router-server/package.json generated vendored Normal file
View File

@@ -0,0 +1,72 @@
{
"name": "@expo/router-server",
"version": "55.0.9",
"description": "Expo Router is a file-based router for React Native and web applications.",
"author": "650 Industries, Inc.",
"license": "MIT",
"main": "build/index",
"types": "build/index.d.ts",
"files": [
"build",
"node"
],
"repository": {
"url": "https://github.com/expo/expo.git",
"type": "git",
"directory": "packages/@expo/router-server"
},
"bugs": {
"url": "https://github.com/expo/expo/issues"
},
"homepage": "https://docs.expo.dev/routing/introduction/",
"scripts": {
"build": "expo-module build",
"clean": "expo-module clean",
"lint": "expo-module lint",
"test": "expo-module test",
"test:rsc": "jest --config jest-rsc.config.js",
"test:tsd": "EXPORT_ROUTER_JEST_TSD=true expo-module test",
"prepublishOnly": "expo-module prepublishOnly",
"expo-module": "expo-module"
},
"keywords": [
"react-native",
"expo"
],
"peerDependencies": {
"@expo/metro-runtime": "^55.0.6",
"react": "*",
"react-dom": "*",
"expo": "*",
"expo-constants": "^55.0.7",
"expo-font": "^55.0.4",
"expo-router": "*",
"expo-server": "^55.0.6",
"react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1"
},
"peerDependenciesMeta": {
"@expo/metro-runtime": {
"optional": true
},
"expo-router": {
"optional": true
},
"react-dom": {
"optional": true
},
"react-server-dom-webpack": {
"optional": true
}
},
"devDependencies": {
"react-server-dom-webpack": "~19.0.1",
"tsd": "^0.28.1"
},
"dependencies": {
"debug": "^4.3.4"
},
"publishConfig": {
"access": "public"
},
"gitHead": "ab5a7ba749a730d7a9f43b74baaeded9255f6313"
}