@expo/cli 56.1.4 → 56.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/build/bin/cli +1 -1
  2. package/build/src/api/user/actions.js +7 -0
  3. package/build/src/api/user/actions.js.map +1 -1
  4. package/build/src/api/user/expoSsoLauncher.js +2 -8
  5. package/build/src/api/user/expoSsoLauncher.js.map +1 -1
  6. package/build/src/api/user/user.js +12 -0
  7. package/build/src/api/user/user.js.map +1 -1
  8. package/build/src/events/index.js +1 -1
  9. package/build/src/export/embed/exportEmbedAsync.js +1 -1
  10. package/build/src/export/embed/exportEmbedAsync.js.map +1 -1
  11. package/build/src/export/embed/exportServer.js +1 -1
  12. package/build/src/export/embed/exportServer.js.map +1 -1
  13. package/build/src/export/exportApp.js +1 -1
  14. package/build/src/export/exportApp.js.map +1 -1
  15. package/build/src/export/publicFolder.js +19 -1
  16. package/build/src/export/publicFolder.js.map +1 -1
  17. package/build/src/login/index.js +25 -5
  18. package/build/src/login/index.js.map +1 -1
  19. package/build/src/run/android/resolveLaunchProps.js +4 -1
  20. package/build/src/run/android/resolveLaunchProps.js.map +1 -1
  21. package/build/src/start/doctor/dependencies/reactNativeTv.js +149 -0
  22. package/build/src/start/doctor/dependencies/reactNativeTv.js.map +1 -0
  23. package/build/src/start/doctor/dependencies/validateDependenciesVersions.js +28 -3
  24. package/build/src/start/doctor/dependencies/validateDependenciesVersions.js.map +1 -1
  25. package/build/src/start/platforms/ios/simctl.js +4 -0
  26. package/build/src/start/platforms/ios/simctl.js.map +1 -1
  27. package/build/src/start/server/DevToolsPlugin.js +26 -1
  28. package/build/src/start/server/DevToolsPlugin.js.map +1 -1
  29. package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js +57 -22
  30. package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js.map +1 -1
  31. package/build/src/start/server/DevToolsPluginCliExtensionResults.js +29 -0
  32. package/build/src/start/server/DevToolsPluginCliExtensionResults.js.map +1 -1
  33. package/build/src/start/server/MCPDevToolsPluginCLIExtensions.js +15 -5
  34. package/build/src/start/server/MCPDevToolsPluginCLIExtensions.js.map +1 -1
  35. package/build/src/start/server/UrlCreator.js +4 -0
  36. package/build/src/start/server/UrlCreator.js.map +1 -1
  37. package/build/src/start/server/createMCPDevToolsExtensionSchema.js +13 -1
  38. package/build/src/start/server/createMCPDevToolsExtensionSchema.js.map +1 -1
  39. package/build/src/start/server/metro/MetroBundlerDevServer.js +95 -32
  40. package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
  41. package/build/src/start/server/metro/createServerComponentsMiddleware.js +13 -13
  42. package/build/src/start/server/metro/createServerComponentsMiddleware.js.map +1 -1
  43. package/build/src/start/server/metro/dev-server/createMessageSocket.js +13 -2
  44. package/build/src/start/server/metro/dev-server/createMessageSocket.js.map +1 -1
  45. package/build/src/start/server/metro/dev-server/createMetroMiddleware.js +2 -1
  46. package/build/src/start/server/metro/dev-server/createMetroMiddleware.js.map +1 -1
  47. package/build/src/start/server/metro/instantiateMetro.js +5 -4
  48. package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
  49. package/build/src/start/server/metro/router.js +10 -1
  50. package/build/src/start/server/metro/router.js.map +1 -1
  51. package/build/src/start/server/metro/withMetroMultiPlatform.js +8 -4
  52. package/build/src/start/server/metro/withMetroMultiPlatform.js.map +1 -1
  53. package/build/src/start/server/middleware/OpenMiddleware.js +150 -0
  54. package/build/src/start/server/middleware/OpenMiddleware.js.map +1 -0
  55. package/build/src/start/server/middleware/RuntimeRedirectMiddleware.js +13 -4
  56. package/build/src/start/server/middleware/RuntimeRedirectMiddleware.js.map +1 -1
  57. package/build/src/start/server/middleware/ServeStaticMiddleware.js +2 -9
  58. package/build/src/start/server/middleware/ServeStaticMiddleware.js.map +1 -1
  59. package/build/src/start/server/middleware/openHandlers.js +157 -0
  60. package/build/src/start/server/middleware/openHandlers.js.map +1 -0
  61. package/build/src/start/server/type-generation/routes.js +1 -3
  62. package/build/src/start/server/type-generation/routes.js.map +1 -1
  63. package/build/src/start/server/webTemplate.js +3 -5
  64. package/build/src/start/server/webTemplate.js.map +1 -1
  65. package/build/src/utils/net.js +7 -1
  66. package/build/src/utils/net.js.map +1 -1
  67. package/build/src/utils/open.js +243 -11
  68. package/build/src/utils/open.js.map +1 -1
  69. package/build/src/utils/tar.js +2 -2
  70. package/build/src/utils/tar.js.map +1 -1
  71. package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
  72. package/build/src/utils/telemetry/utils/context.js +1 -1
  73. package/package.json +17 -18
  74. package/static/loading-page/index.html +35 -1
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get createInfoHandler () {
13
+ return createInfoHandler;
14
+ },
15
+ get createOpen () {
16
+ return createOpen;
17
+ },
18
+ get resolveOpenInfo () {
19
+ return resolveOpenInfo;
20
+ }
21
+ });
22
+ function createInfoHandler(deps) {
23
+ return ({ platform, runtime })=>resolveOpenInfo({
24
+ platform,
25
+ runtime
26
+ }, deps);
27
+ }
28
+ async function resolveOpenInfo({ platform, runtime }, deps) {
29
+ // Snapshot the live state once per request so the response is internally consistent even if a
30
+ // toggle happens between sub-resolutions.
31
+ const scheme = deps.urlCreator.getScheme();
32
+ const isDevClient = deps.getIsDevClient();
33
+ const isRedirectPageEnabled = deps.getIsRedirectPageEnabled();
34
+ const availableRuntimes = isDevClient ? [
35
+ 'custom'
36
+ ] : isRedirectPageEnabled ? [
37
+ 'expo',
38
+ 'custom'
39
+ ] : [
40
+ 'expo'
41
+ ];
42
+ if (platform) {
43
+ return {
44
+ scheme,
45
+ availableRuntimes,
46
+ ...await resolvePlatformInfo(platform, runtime, deps, {
47
+ isDevClient,
48
+ isRedirectPageEnabled
49
+ })
50
+ };
51
+ }
52
+ const [ios, android, web] = await Promise.all([
53
+ resolvePlatformInfo('ios', runtime, deps, {
54
+ isDevClient,
55
+ isRedirectPageEnabled
56
+ }),
57
+ resolvePlatformInfo('android', runtime, deps, {
58
+ isDevClient,
59
+ isRedirectPageEnabled
60
+ }),
61
+ resolvePlatformInfo('web', runtime, deps, {
62
+ isDevClient,
63
+ isRedirectPageEnabled
64
+ })
65
+ ]);
66
+ return {
67
+ scheme,
68
+ availableRuntimes,
69
+ platforms: {
70
+ ios,
71
+ android,
72
+ web
73
+ }
74
+ };
75
+ }
76
+ async function resolvePlatformInfo(platform, runtime, deps, state) {
77
+ const { urlCreator, getAppId } = deps;
78
+ const { isDevClient, isRedirectPageEnabled } = state;
79
+ const appId = await getAppId(platform);
80
+ if (platform === 'web') {
81
+ // constructUrl inherits the tunnel host from `defaults.hostType` when --tunnel is active,
82
+ // so this returns the ngrok URL instead of localhost in that case.
83
+ return {
84
+ runtime: 'web',
85
+ url: urlCreator.constructUrl({
86
+ scheme: 'http'
87
+ }),
88
+ appId
89
+ };
90
+ }
91
+ // Caller explicitly wants the disambiguation page — useful when they want the device (not the
92
+ // dev server) to pick between Expo Go and the dev build. No `runtime` field on the response
93
+ // since the actual runtime depends on the device's choice.
94
+ if (runtime === 'unknown') {
95
+ return {
96
+ url: urlCreator.constructLoadingUrl({}, platform),
97
+ appId
98
+ };
99
+ }
100
+ // `runtime: 'default'` mirrors what pressing `i` / `a` does in the terminal:
101
+ // --dev-client server → open the dev client directly.
102
+ // project has both → hand off to the disambiguation interstitial so the
103
+ // device resolves between Expo Go and the dev build.
104
+ // else → open Expo Go directly.
105
+ if (runtime === 'default') {
106
+ if (isDevClient) {
107
+ return {
108
+ runtime: 'custom',
109
+ url: urlCreator.constructDevClientUrl(),
110
+ appId
111
+ };
112
+ }
113
+ if (isRedirectPageEnabled) {
114
+ return {
115
+ url: urlCreator.constructLoadingUrl({}, platform),
116
+ appId
117
+ };
118
+ }
119
+ return {
120
+ runtime: 'expo',
121
+ url: urlCreator.constructUrl({
122
+ scheme: 'exp'
123
+ }),
124
+ appId
125
+ };
126
+ }
127
+ return {
128
+ runtime,
129
+ url: runtime === 'custom' ? urlCreator.constructDevClientUrl() : urlCreator.constructUrl({
130
+ scheme: 'exp'
131
+ }),
132
+ appId
133
+ };
134
+ }
135
+ function createOpen(deps) {
136
+ return async ({ platform })=>{
137
+ if (platform === 'web') {
138
+ const result = await deps.openPlatformAsync('desktop');
139
+ return {
140
+ platform,
141
+ runtime: 'web',
142
+ url: result.url ?? ''
143
+ };
144
+ }
145
+ const launchTarget = platform === 'ios' ? 'simulator' : 'emulator';
146
+ const result = await deps.openPlatformAsync(launchTarget, {
147
+ shouldPrompt: false
148
+ });
149
+ return {
150
+ platform,
151
+ runtime: deps.getIsDevClient() ? 'custom' : 'expo',
152
+ url: result.url ?? ''
153
+ };
154
+ };
155
+ }
156
+
157
+ //# sourceMappingURL=openHandlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/start/server/middleware/openHandlers.ts"],"sourcesContent":["import type {\n OpenActionResult,\n OpenInfoResult,\n OpenMiddlewareOptions,\n OpenNativeRuntime,\n OpenPlatform,\n OpenPlatformInfo,\n OpenRequestedRuntime,\n} from './OpenMiddleware';\nimport type { UrlCreator } from '../UrlCreator';\n\ninterface InfoHandlerDeps {\n /** Stable UrlCreator instance — its `defaults` mutate when `toggleRuntimeMode` runs, so the same instance keeps producing fresh URLs and reflects the current scheme. */\n urlCreator: UrlCreator;\n /**\n * Read live values every call. The dev server's runtime mode can flip mid-run via the `s` key\n * in the terminal, and `expo-dev-client` can be installed while the server is running — both\n * change `isDevClient` and `isRedirectPageEnabled`, and the endpoint should reflect the\n * current state on every request.\n */\n getIsDevClient: () => boolean;\n /** Live mirror of `BundlerDevServer.isRedirectPageEnabled()`. */\n getIsRedirectPageEnabled: () => boolean;\n /**\n * Resolve the native application identifier for a platform (iOS bundle id / Android package\n * name). Implementations should return `null` instead of throwing when the project has no\n * configured identifier; the endpoint surfaces `null` so distributed preview systems can detect\n * that the build can't be matched by app id and either bail out or prompt the user.\n */\n getAppId: (platform: OpenPlatform) => Promise<string | null>;\n}\n\n/**\n * Build the GET handler for `/_expo/open`. Resolves dry-run info for a single platform, or for\n * every platform in discovery mode. Extracted so it can be exercised with a real\n * {@link UrlCreator} in tests (covers tunnel routing in particular).\n */\nexport function createInfoHandler(deps: InfoHandlerDeps): OpenMiddlewareOptions['getInfo'] {\n return ({ platform, runtime }) => resolveOpenInfo({ platform, runtime }, deps);\n}\n\nexport async function resolveOpenInfo(\n { platform, runtime }: { platform: OpenPlatform | null; runtime: OpenRequestedRuntime },\n deps: InfoHandlerDeps\n): Promise<OpenInfoResult> {\n // Snapshot the live state once per request so the response is internally consistent even if a\n // toggle happens between sub-resolutions.\n const scheme = deps.urlCreator.getScheme();\n const isDevClient = deps.getIsDevClient();\n const isRedirectPageEnabled = deps.getIsRedirectPageEnabled();\n const availableRuntimes: OpenNativeRuntime[] = isDevClient\n ? ['custom']\n : isRedirectPageEnabled\n ? ['expo', 'custom']\n : ['expo'];\n\n if (platform) {\n return {\n scheme,\n availableRuntimes,\n ...(await resolvePlatformInfo(platform, runtime, deps, {\n isDevClient,\n isRedirectPageEnabled,\n })),\n };\n }\n\n const [ios, android, web] = await Promise.all([\n resolvePlatformInfo('ios', runtime, deps, { isDevClient, isRedirectPageEnabled }),\n resolvePlatformInfo('android', runtime, deps, { isDevClient, isRedirectPageEnabled }),\n resolvePlatformInfo('web', runtime, deps, { isDevClient, isRedirectPageEnabled }),\n ]);\n return { scheme, availableRuntimes, platforms: { ios, android, web } };\n}\n\nasync function resolvePlatformInfo(\n platform: OpenPlatform,\n runtime: OpenRequestedRuntime,\n deps: InfoHandlerDeps,\n state: { isDevClient: boolean; isRedirectPageEnabled: boolean }\n): Promise<OpenPlatformInfo> {\n const { urlCreator, getAppId } = deps;\n const { isDevClient, isRedirectPageEnabled } = state;\n const appId = await getAppId(platform);\n\n if (platform === 'web') {\n // constructUrl inherits the tunnel host from `defaults.hostType` when --tunnel is active,\n // so this returns the ngrok URL instead of localhost in that case.\n return { runtime: 'web', url: urlCreator.constructUrl({ scheme: 'http' }), appId };\n }\n\n // Caller explicitly wants the disambiguation page — useful when they want the device (not the\n // dev server) to pick between Expo Go and the dev build. No `runtime` field on the response\n // since the actual runtime depends on the device's choice.\n if (runtime === 'unknown') {\n return { url: urlCreator.constructLoadingUrl({}, platform), appId };\n }\n\n // `runtime: 'default'` mirrors what pressing `i` / `a` does in the terminal:\n // --dev-client server → open the dev client directly.\n // project has both → hand off to the disambiguation interstitial so the\n // device resolves between Expo Go and the dev build.\n // else → open Expo Go directly.\n if (runtime === 'default') {\n if (isDevClient) {\n return { runtime: 'custom', url: urlCreator.constructDevClientUrl(), appId };\n }\n if (isRedirectPageEnabled) {\n return { url: urlCreator.constructLoadingUrl({}, platform), appId };\n }\n return { runtime: 'expo', url: urlCreator.constructUrl({ scheme: 'exp' }), appId };\n }\n\n return {\n runtime,\n url:\n runtime === 'custom'\n ? urlCreator.constructDevClientUrl()\n : urlCreator.constructUrl({ scheme: 'exp' }),\n appId,\n };\n}\n\ninterface OpenHandlerDeps {\n /** Live `BundlerDevServer.isDevClient` — `s` in the terminal can flip this between dispatch and response. */\n getIsDevClient: () => boolean;\n /** Same shape as `BundlerDevServer.openPlatformAsync`. */\n openPlatformAsync: (\n launchTarget: 'simulator' | 'emulator' | 'desktop',\n resolver?: { shouldPrompt?: boolean }\n ) => Promise<{ url: string | null }>;\n}\n\n/** Build the POST handler for `/_expo/open` — dispatches to the dev server's platform launcher. */\nexport function createOpen(deps: OpenHandlerDeps): OpenMiddlewareOptions['open'] {\n return async ({ platform }): Promise<OpenActionResult> => {\n if (platform === 'web') {\n const result = await deps.openPlatformAsync('desktop');\n return { platform, runtime: 'web', url: result.url ?? '' };\n }\n const launchTarget = platform === 'ios' ? 'simulator' : 'emulator';\n const result = await deps.openPlatformAsync(launchTarget, { shouldPrompt: false });\n return {\n platform,\n runtime: deps.getIsDevClient() ? 'custom' : 'expo',\n url: result.url ?? '',\n };\n };\n}\n"],"names":["createInfoHandler","createOpen","resolveOpenInfo","deps","platform","runtime","scheme","urlCreator","getScheme","isDevClient","getIsDevClient","isRedirectPageEnabled","getIsRedirectPageEnabled","availableRuntimes","resolvePlatformInfo","ios","android","web","Promise","all","platforms","state","getAppId","appId","url","constructUrl","constructLoadingUrl","constructDevClientUrl","result","openPlatformAsync","launchTarget","shouldPrompt"],"mappings":"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"}
@@ -224,9 +224,7 @@ function extrapolateGroupRoutes(route, routes = new Set()) {
224
224
  * NOTE: This code refers to a specific version of `expo-router` and is therefore unsafe to
225
225
  * mix with arbitrary versions.
226
226
  * TODO: Version this code with `expo-router` or version expo-router with `@expo/cli`.
227
- */ const routerDotTSTemplate = (0, _template.unsafeTemplate)`/* eslint-disable @typescript-eslint/no-unused-vars */
228
- /* eslint-disable import/export */
229
- /* eslint-disable @typescript-eslint/ban-types */
227
+ */ const routerDotTSTemplate = (0, _template.unsafeTemplate)`/* eslint-disable */
230
228
  declare module "expo-router" {
231
229
  import type { LinkProps as OriginalLinkProps } from 'expo-router/build/link/Link';
232
230
  import type { Router as OriginalRouter } from 'expo-router/build/types';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/start/server/type-generation/routes.ts"],"sourcesContent":["import type Server from '@expo/metro/metro/Server';\nimport path from 'path';\n\nimport { unsafeTemplate } from '../../../utils/template';\nimport type { ServerLike } from '../BundlerDevServer';\nimport { metroWatchTypeScriptFiles } from '../metro/metroWatchTypeScriptFiles';\n\n// /test/[...param1]/[param2]/[param3] - captures [\"param1\", \"param2\", \"param3\"]\nexport const CAPTURE_DYNAMIC_PARAMS = /\\[(?:\\.{3})?(\\w*?)[\\]$]/g;\n// /[...param1]/ - Match [...param1]\nexport const CATCH_ALL = /\\[\\.\\.\\..+?\\]/g;\n// /[param1] - Match [param1]\nexport const SLUG = /\\[.+?\\]/g;\n// /(group1,group2,group3)/test - match (group1,group2,group3)\nexport const ARRAY_GROUP_REGEX = /\\(\\s*\\w[\\w\\s]*?,.*?\\)/g;\n// /(group1,group2,group3)/test - captures [\"group1\", \"group2\", \"group3\"]\nexport const CAPTURE_GROUP_REGEX = /[\\\\(,]\\s*(\\w[\\w\\s]*?)\\s*(?=[,\\\\)])/g;\n/**\n * Match:\n * - _layout files, +html, +not-found, string+api, etc\n * - Routes can still use `+`, but it cannot be in the last segment.\n */\nexport const TYPED_ROUTES_EXCLUSION_REGEX = /(_layout|[^/]*?\\+[^/]*?)\\.[tj]sx?$/;\n\nexport interface SetupTypedRoutesOptions {\n server?: ServerLike;\n metro?: Server | null;\n typesDirectory: string;\n projectRoot: string;\n /** Absolute expo router routes directory. */\n routerDirectory: string;\n plugin?: Record<string, any>;\n}\n\nexport async function setupTypedRoutes(options: SetupTypedRoutesOptions) {\n // TODO(@kitten): Remove indirection here. Unclear why it's needed\n const typedRoutesModule = require.resolve('@expo/router-server/build/typed-routes');\n return typedRoutes(typedRoutesModule, options);\n}\n\nasync function typedRoutes(\n typedRoutesModulePath: string,\n { server, metro, typesDirectory, projectRoot, routerDirectory, plugin }: SetupTypedRoutesOptions\n) {\n /*\n * Expo Router uses EXPO_ROUTER_APP_ROOT in multiple places to determine the root of the project.\n * In apps compiled by Metro, this code is compiled away. But Typed Routes run in NodeJS with no compilation\n * so we need to explicitly set it.\n */\n process.env.EXPO_ROUTER_APP_ROOT = routerDirectory;\n\n const typedRoutesModule: typeof import('@expo/router-server/build/typed-routes') = require(\n typedRoutesModulePath\n );\n\n /*\n * Typed Routes can be run with out Metro or a Server, e.g. `expo customize tsconfig.json`\n */\n if (metro && server) {\n // Setup out watcher first\n metroWatchTypeScriptFiles({\n projectRoot,\n server,\n metro,\n eventTypes: ['add', 'delete', 'change'],\n callback: typedRoutesModule.getWatchHandler(typesDirectory),\n });\n }\n\n /*\n * In SDK 52, the `regenerateDeclarations` was changed to accept plugin options.\n * This function has an optional parameter that we cannot override, so we need to ensure the user\n * is using a compatible version of `expo-router`. Otherwise, we will fallback to the old method.\n *\n * TODO(@marklawlor): In SDK53+ we should remove this check and always use the new method.\n */\n if ('version' in typedRoutesModule && typedRoutesModule.version >= 52) {\n typedRoutesModule.regenerateDeclarations(typesDirectory, plugin);\n } else {\n typedRoutesModule.regenerateDeclarations(typesDirectory);\n }\n}\n\n/*\n * This is exported for testing purposes\n */\nexport function getTemplateString(\n staticRoutes: Set<string>,\n dynamicRoutes: Set<string>,\n dynamicRouteTemplates: Set<string>\n) {\n return routerDotTSTemplate({\n staticRoutes: setToUnionType(staticRoutes),\n dynamicRoutes: setToUnionType(dynamicRoutes),\n dynamicRouteParams: setToUnionType(dynamicRouteTemplates),\n });\n}\n\n/**\n * Utility functions for typed routes\n *\n * These are extracted for easier testing\n */\nexport function getTypedRoutesUtils(appRoot: string, filePathSeperator = path.sep) {\n /*\n * staticRoutes are a map where the key if the route without groups and the value\n * is another set of all group versions of the route. e.g,\n * Map([\n * [\"/\", [\"/(app)/(notes)\", \"/(app)/(profile)\"]\n * ])\n */\n const staticRoutes = new Map<string, Set<string>>([['/', new Set('/')]]);\n /*\n * dynamicRoutes are the same as staticRoutes (key if the resolved route,\n * and the value is a set of possible routes). e.g:\n *\n * /[...fruits] -> /${CatchAllRoutePart<T>}\n * /color/[color] -> /color/${SingleRoutePart<T>}\n *\n * The keys of this map are also important, as they can be used as \"static\" types\n * <Link href={{ pathname: \"/[...fruits]\",params: { fruits: [\"apple\"] } }} />\n */\n const dynamicRoutes = new Map<string, Set<string>>();\n\n function normalizedFilePath(filePath: string) {\n return filePath.replaceAll(filePathSeperator, '/');\n }\n\n const normalizedAppRoot = normalizedFilePath(appRoot);\n\n const filePathToRoute = (filePath: string) => {\n return normalizedFilePath(filePath)\n .replace(normalizedAppRoot, '')\n .replace(/index\\.[jt]sx?/, '')\n .replace(/\\.[jt]sx?$/, '');\n };\n\n const isRouteFile = (filePath: string) => {\n if (filePath.match(TYPED_ROUTES_EXCLUSION_REGEX)) {\n return false;\n }\n\n // Route files must be nested with in the appRoot\n const relative = path.relative(appRoot, filePath);\n return relative && !relative.startsWith('..') && !path.isAbsolute(relative);\n };\n\n const addFilePath = (filePath: string): boolean => {\n if (!isRouteFile(filePath)) {\n return false;\n }\n\n const route = filePathToRoute(filePath);\n\n // We have already processed this file\n if (staticRoutes.has(route) || dynamicRoutes.has(route)) {\n return false;\n }\n\n const dynamicParams = new Set(\n [...route.matchAll(CAPTURE_DYNAMIC_PARAMS)].map((match) => match[1])\n );\n const isDynamic = dynamicParams.size > 0;\n\n const addRoute = (originalRoute: string, route: string) => {\n if (isDynamic) {\n let set = dynamicRoutes.get(originalRoute);\n\n if (!set) {\n set = new Set();\n dynamicRoutes.set(originalRoute, set);\n }\n\n set.add(\n route\n .replaceAll(CATCH_ALL, '${CatchAllRoutePart<T>}')\n .replaceAll(SLUG, '${SingleRoutePart<T>}')\n );\n } else {\n let set = staticRoutes.get(originalRoute);\n\n if (!set) {\n set = new Set();\n staticRoutes.set(originalRoute, set);\n }\n\n set.add(route);\n }\n };\n\n if (!route.match(ARRAY_GROUP_REGEX)) {\n addRoute(route, route);\n }\n\n // Does this route have a group? eg /(group)\n if (route.includes('/(')) {\n const routeWithoutGroups = route.replace(/\\/\\(.+?\\)/g, '');\n addRoute(route, routeWithoutGroups);\n\n // If there are multiple groups, we need to expand them\n // eg /(test1,test2)/page => /test1/page & /test2/page\n for (const routeWithSingleGroup of extrapolateGroupRoutes(route)) {\n addRoute(route, routeWithSingleGroup);\n }\n }\n\n return true;\n };\n\n return {\n staticRoutes,\n dynamicRoutes,\n filePathToRoute,\n addFilePath,\n isRouteFile,\n };\n}\n\nexport const setToUnionType = <T>(set: Set<T>) => {\n return set.size > 0 ? [...set].map((s) => `\\`${s}\\``).join(' | ') : 'never';\n};\n\n/**\n * Given a route, return all possible routes that could be generated from it.\n */\nexport function extrapolateGroupRoutes(\n route: string,\n routes: Set<string> = new Set()\n): Set<string> {\n // Create a version with no groups. We will then need to cleanup double and/or trailing slashes\n routes.add(route.replaceAll(ARRAY_GROUP_REGEX, '').replaceAll(/\\/+/g, '/').replace(/\\/$/, ''));\n\n const match = route.match(ARRAY_GROUP_REGEX);\n\n if (!match) {\n routes.add(route);\n return routes;\n }\n\n const groupsMatch = match[0];\n\n for (const group of groupsMatch.matchAll(CAPTURE_GROUP_REGEX)) {\n extrapolateGroupRoutes(route.replace(groupsMatch, `(${group[1]!.trim()})`), routes);\n }\n\n return routes;\n}\n\n/**\n * NOTE: This code refers to a specific version of `expo-router` and is therefore unsafe to\n * mix with arbitrary versions.\n * TODO: Version this code with `expo-router` or version expo-router with `@expo/cli`.\n */\nconst routerDotTSTemplate = unsafeTemplate`/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable import/export */\n/* eslint-disable @typescript-eslint/ban-types */\ndeclare module \"expo-router\" {\n import type { LinkProps as OriginalLinkProps } from 'expo-router/build/link/Link';\n import type { Router as OriginalRouter } from 'expo-router/build/types';\n export * from 'expo-router/build';\n\n // prettier-ignore\n type StaticRoutes = ${'staticRoutes'};\n // prettier-ignore\n type DynamicRoutes<T extends string> = ${'dynamicRoutes'};\n // prettier-ignore\n type DynamicRouteTemplate = ${'dynamicRouteParams'};\n\n type RelativePathString = \\`./\\${string}\\` | \\`../\\${string}\\` | '..';\n type AbsoluteRoute = DynamicRouteTemplate | StaticRoutes;\n type ExternalPathString = \\`\\${string}:\\${string}\\`;\n\n type ExpoRouterRoutes = DynamicRouteTemplate | StaticRoutes | RelativePathString;\n export type AllRoutes = ExpoRouterRoutes | ExternalPathString;\n\n /****************\n * Route Utils *\n ****************/\n\n type SearchOrHash = \\`?\\${string}\\` | \\`#\\${string}\\`;\n type UnknownInputParams = Record<string, string | number | (string | number)[]>;\n type UnknownOutputParams = Record<string, string | string[]>;\n\n /**\n * Return only the RoutePart of a string. If the string has multiple parts return never\n *\n * string | type\n * ---------|------\n * 123 | 123\n * /123/abc | never\n * 123?abc | never\n * ./123 | never\n * /123 | never\n * 123/../ | never\n */\n type SingleRoutePart<S extends string> = S extends \\`\\${string}/\\${string}\\`\n ? never\n : S extends \\`\\${string}\\${SearchOrHash}\\`\n ? never\n : S extends ''\n ? never\n : S extends \\`(\\${string})\\`\n ? never\n : S extends \\`[\\${string}]\\`\n ? never\n : S;\n\n /**\n * Return only the CatchAll router part. If the string has search parameters or a hash return never\n */\n type CatchAllRoutePart<S extends string> = S extends \\`\\${string}\\${SearchOrHash}\\`\n ? never\n : S extends ''\n ? never\n : S extends \\`\\${string}(\\${string})\\${string}\\`\n ? never\n : S extends \\`\\${string}[\\${string}]\\${string}\\`\n ? never\n : S;\n\n // type OptionalCatchAllRoutePart<S extends string> = S extends \\`\\${string}\\${SearchOrHash}\\` ? never : S\n\n /**\n * Return the name of a route parameter\n * '[test]' -> 'test'\n * 'test' -> never\n * '[...test]' -> '...test'\n */\n type IsParameter<Part> = Part extends \\`[\\${infer ParamName}]\\` ? ParamName : never;\n\n /**\n * Return a union of all parameter names. If there are no names return never\n *\n * /[test] -> 'test'\n * /[abc]/[...def] -> 'abc'|'...def'\n */\n type ParameterNames<Path> = Path extends \\`\\${infer PartA}/\\${infer PartB}\\`\n ? IsParameter<PartA> | ParameterNames<PartB>\n : IsParameter<Path>;\n\n /**\n * Returns all segements of a route.\n *\n * /(group)/123/abc/[id]/[...rest] -> ['(group)', '123', 'abc', '[id]', '[...rest]'\n */\n type RouteSegments<Path> = Path extends \\`\\${infer PartA}/\\${infer PartB}\\`\n ? PartA extends '' | '.'\n ? [...RouteSegments<PartB>]\n : [PartA, ...RouteSegments<PartB>]\n : Path extends ''\n ? []\n : [Path];\n\n /**\n * Returns a Record of the routes parameters as strings and CatchAll parameters\n *\n * There are two versions, input and output, as you can input 'string | number' but\n * the output will always be 'string'\n *\n * /[id]/[...rest] -> { id: string, rest: string[] }\n * /no-params -> {}\n */\n type InputRouteParams<Path> = {\n [Key in ParameterNames<Path> as Key extends \\`...\\${infer Name}\\`\n ? Name\n : Key]: Key extends \\`...\\${string}\\` ? (string | number)[] : string | number;\n } & UnknownInputParams;\n\n type OutputRouteParams<Path> = {\n [Key in ParameterNames<Path> as Key extends \\`...\\${infer Name}\\`\n ? Name\n : Key]: Key extends \\`...\\${string}\\` ? string[] : string;\n } & UnknownOutputParams;\n\n /**\n * Returns the search parameters for a route.\n */\n export type SearchParams<T extends AllRoutes> = T extends DynamicRouteTemplate\n ? OutputRouteParams<T>\n : T extends StaticRoutes\n ? never\n : UnknownOutputParams;\n\n /**\n * Route is mostly used as part of Href to ensure that a valid route is provided\n *\n * Given a dynamic route, this will return never. This is helpful for conditional logic\n *\n * /test -> /test, /test2, etc\n * /test/[abc] -> never\n * /test/resolve -> /test, /test2, etc\n *\n * Note that if we provide a value for [abc] then the route is allowed\n *\n * This is named Route to prevent confusion, as users they will often see it in tooltips\n */\n export type Route<T> = T extends string\n ? T extends DynamicRouteTemplate\n ? never\n :\n | StaticRoutes\n | RelativePathString\n | ExternalPathString\n | (T extends \\`\\${infer P}\\${SearchOrHash}\\`\n ? P extends DynamicRoutes<infer _>\n ? T\n : never\n : T extends DynamicRoutes<infer _>\n ? T\n : never)\n : never;\n\n /*********\n * Href *\n *********/\n\n export type Href<T> = T extends Record<'pathname', string> ? HrefObject<T> : Route<T>;\n\n export type HrefObject<\n R extends Record<'pathname', string>,\n P = R['pathname'],\n > = P extends DynamicRouteTemplate\n ? { pathname: P; params: InputRouteParams<P> }\n : P extends Route<P>\n ? { pathname: Route<P> | DynamicRouteTemplate; params?: never | InputRouteParams<never> }\n : never;\n\n /***********************\n * Expo Router Exports *\n ***********************/\n\n export type Router = Omit<OriginalRouter, 'push' | 'replace' | 'setParams'> & {\n /** Navigate to the provided href. */\n push: <T>(href: Href<T>) => void;\n /** Navigate to route without appending to the history. */\n replace: <T>(href: Href<T>) => void;\n /** Update the current route query params. */\n setParams: <T = ''>(params?: T extends '' ? Record<string, string> : InputRouteParams<T>) => void;\n };\n\n /** The imperative router. */\n export const router: Router;\n\n /************\n * <Link /> *\n ************/\n export interface LinkProps<T> extends OriginalLinkProps {\n href: Href<T>;\n }\n\n export interface LinkComponent {\n <T>(props: React.PropsWithChildren<LinkProps<T>>): JSX.Element;\n /** Helper method to resolve an Href object into a string. */\n resolveHref: <T>(href: Href<T>) => string;\n }\n\n /**\n * Component to render link to another route using a path.\n * Uses an anchor tag on the web.\n *\n * @param props.href Absolute path to route (e.g. \\`/feeds/hot\\`).\n * @param props.replace Should replace the current route without adding to the history.\n * @param props.asChild Forward props to child component. Useful for custom buttons.\n * @param props.children Child elements to render the content.\n * @param props.className On web, this sets the HTML \\`class\\` directly. On native, this can be used with CSS interop tools like Nativewind.\n */\n export const Link: LinkComponent;\n\n /** Redirects to the href as soon as the component is mounted. */\n export const Redirect: <T>(\n props: React.PropsWithChildren<{ href: Href<T> }>\n ) => JSX.Element;\n\n /************\n * Hooks *\n ************/\n export function useRouter(): Router;\n\n export function useLocalSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams,\n >(): T extends AllRoutes ? SearchParams<T> : T;\n\n /** @deprecated renamed to \\`useGlobalSearchParams\\` */\n export function useSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams,\n >(): T extends AllRoutes ? SearchParams<T> : T;\n\n export function useGlobalSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams,\n >(): T extends AllRoutes ? SearchParams<T> : T;\n\n export function useSegments<\n T extends AbsoluteRoute | RouteSegments<AbsoluteRoute> | RelativePathString,\n >(): T extends AbsoluteRoute ? RouteSegments<T> : T extends string ? string[] : T;\n}\n`;\n"],"names":["ARRAY_GROUP_REGEX","CAPTURE_DYNAMIC_PARAMS","CAPTURE_GROUP_REGEX","CATCH_ALL","SLUG","TYPED_ROUTES_EXCLUSION_REGEX","extrapolateGroupRoutes","getTemplateString","getTypedRoutesUtils","setToUnionType","setupTypedRoutes","options","typedRoutesModule","require","resolve","typedRoutes","typedRoutesModulePath","server","metro","typesDirectory","projectRoot","routerDirectory","plugin","process","env","EXPO_ROUTER_APP_ROOT","metroWatchTypeScriptFiles","eventTypes","callback","getWatchHandler","version","regenerateDeclarations","staticRoutes","dynamicRoutes","dynamicRouteTemplates","routerDotTSTemplate","dynamicRouteParams","appRoot","filePathSeperator","path","sep","Map","Set","normalizedFilePath","filePath","replaceAll","normalizedAppRoot","filePathToRoute","replace","isRouteFile","match","relative","startsWith","isAbsolute","addFilePath","route","has","dynamicParams","matchAll","map","isDynamic","size","addRoute","originalRoute","set","get","add","includes","routeWithoutGroups","routeWithSingleGroup","s","join","routes","groupsMatch","group","trim","unsafeTemplate"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/start/server/type-generation/routes.ts"],"sourcesContent":["import type Server from '@expo/metro/metro/Server';\nimport path from 'path';\n\nimport { unsafeTemplate } from '../../../utils/template';\nimport type { ServerLike } from '../BundlerDevServer';\nimport { metroWatchTypeScriptFiles } from '../metro/metroWatchTypeScriptFiles';\n\n// /test/[...param1]/[param2]/[param3] - captures [\"param1\", \"param2\", \"param3\"]\nexport const CAPTURE_DYNAMIC_PARAMS = /\\[(?:\\.{3})?(\\w*?)[\\]$]/g;\n// /[...param1]/ - Match [...param1]\nexport const CATCH_ALL = /\\[\\.\\.\\..+?\\]/g;\n// /[param1] - Match [param1]\nexport const SLUG = /\\[.+?\\]/g;\n// /(group1,group2,group3)/test - match (group1,group2,group3)\nexport const ARRAY_GROUP_REGEX = /\\(\\s*\\w[\\w\\s]*?,.*?\\)/g;\n// /(group1,group2,group3)/test - captures [\"group1\", \"group2\", \"group3\"]\nexport const CAPTURE_GROUP_REGEX = /[\\\\(,]\\s*(\\w[\\w\\s]*?)\\s*(?=[,\\\\)])/g;\n/**\n * Match:\n * - _layout files, +html, +not-found, string+api, etc\n * - Routes can still use `+`, but it cannot be in the last segment.\n */\nexport const TYPED_ROUTES_EXCLUSION_REGEX = /(_layout|[^/]*?\\+[^/]*?)\\.[tj]sx?$/;\n\nexport interface SetupTypedRoutesOptions {\n server?: ServerLike;\n metro?: Server | null;\n typesDirectory: string;\n projectRoot: string;\n /** Absolute expo router routes directory. */\n routerDirectory: string;\n plugin?: Record<string, any>;\n}\n\nexport async function setupTypedRoutes(options: SetupTypedRoutesOptions) {\n // TODO(@kitten): Remove indirection here. Unclear why it's needed\n const typedRoutesModule = require.resolve('@expo/router-server/build/typed-routes');\n return typedRoutes(typedRoutesModule, options);\n}\n\nasync function typedRoutes(\n typedRoutesModulePath: string,\n { server, metro, typesDirectory, projectRoot, routerDirectory, plugin }: SetupTypedRoutesOptions\n) {\n /*\n * Expo Router uses EXPO_ROUTER_APP_ROOT in multiple places to determine the root of the project.\n * In apps compiled by Metro, this code is compiled away. But Typed Routes run in NodeJS with no compilation\n * so we need to explicitly set it.\n */\n process.env.EXPO_ROUTER_APP_ROOT = routerDirectory;\n\n const typedRoutesModule: typeof import('@expo/router-server/build/typed-routes') = require(\n typedRoutesModulePath\n );\n\n /*\n * Typed Routes can be run with out Metro or a Server, e.g. `expo customize tsconfig.json`\n */\n if (metro && server) {\n // Setup out watcher first\n metroWatchTypeScriptFiles({\n projectRoot,\n server,\n metro,\n eventTypes: ['add', 'delete', 'change'],\n callback: typedRoutesModule.getWatchHandler(typesDirectory),\n });\n }\n\n /*\n * In SDK 52, the `regenerateDeclarations` was changed to accept plugin options.\n * This function has an optional parameter that we cannot override, so we need to ensure the user\n * is using a compatible version of `expo-router`. Otherwise, we will fallback to the old method.\n *\n * TODO(@marklawlor): In SDK53+ we should remove this check and always use the new method.\n */\n if ('version' in typedRoutesModule && typedRoutesModule.version >= 52) {\n typedRoutesModule.regenerateDeclarations(typesDirectory, plugin);\n } else {\n typedRoutesModule.regenerateDeclarations(typesDirectory);\n }\n}\n\n/*\n * This is exported for testing purposes\n */\nexport function getTemplateString(\n staticRoutes: Set<string>,\n dynamicRoutes: Set<string>,\n dynamicRouteTemplates: Set<string>\n) {\n return routerDotTSTemplate({\n staticRoutes: setToUnionType(staticRoutes),\n dynamicRoutes: setToUnionType(dynamicRoutes),\n dynamicRouteParams: setToUnionType(dynamicRouteTemplates),\n });\n}\n\n/**\n * Utility functions for typed routes\n *\n * These are extracted for easier testing\n */\nexport function getTypedRoutesUtils(appRoot: string, filePathSeperator = path.sep) {\n /*\n * staticRoutes are a map where the key if the route without groups and the value\n * is another set of all group versions of the route. e.g,\n * Map([\n * [\"/\", [\"/(app)/(notes)\", \"/(app)/(profile)\"]\n * ])\n */\n const staticRoutes = new Map<string, Set<string>>([['/', new Set('/')]]);\n /*\n * dynamicRoutes are the same as staticRoutes (key if the resolved route,\n * and the value is a set of possible routes). e.g:\n *\n * /[...fruits] -> /${CatchAllRoutePart<T>}\n * /color/[color] -> /color/${SingleRoutePart<T>}\n *\n * The keys of this map are also important, as they can be used as \"static\" types\n * <Link href={{ pathname: \"/[...fruits]\",params: { fruits: [\"apple\"] } }} />\n */\n const dynamicRoutes = new Map<string, Set<string>>();\n\n function normalizedFilePath(filePath: string) {\n return filePath.replaceAll(filePathSeperator, '/');\n }\n\n const normalizedAppRoot = normalizedFilePath(appRoot);\n\n const filePathToRoute = (filePath: string) => {\n return normalizedFilePath(filePath)\n .replace(normalizedAppRoot, '')\n .replace(/index\\.[jt]sx?/, '')\n .replace(/\\.[jt]sx?$/, '');\n };\n\n const isRouteFile = (filePath: string) => {\n if (filePath.match(TYPED_ROUTES_EXCLUSION_REGEX)) {\n return false;\n }\n\n // Route files must be nested with in the appRoot\n const relative = path.relative(appRoot, filePath);\n return relative && !relative.startsWith('..') && !path.isAbsolute(relative);\n };\n\n const addFilePath = (filePath: string): boolean => {\n if (!isRouteFile(filePath)) {\n return false;\n }\n\n const route = filePathToRoute(filePath);\n\n // We have already processed this file\n if (staticRoutes.has(route) || dynamicRoutes.has(route)) {\n return false;\n }\n\n const dynamicParams = new Set(\n [...route.matchAll(CAPTURE_DYNAMIC_PARAMS)].map((match) => match[1])\n );\n const isDynamic = dynamicParams.size > 0;\n\n const addRoute = (originalRoute: string, route: string) => {\n if (isDynamic) {\n let set = dynamicRoutes.get(originalRoute);\n\n if (!set) {\n set = new Set();\n dynamicRoutes.set(originalRoute, set);\n }\n\n set.add(\n route\n .replaceAll(CATCH_ALL, '${CatchAllRoutePart<T>}')\n .replaceAll(SLUG, '${SingleRoutePart<T>}')\n );\n } else {\n let set = staticRoutes.get(originalRoute);\n\n if (!set) {\n set = new Set();\n staticRoutes.set(originalRoute, set);\n }\n\n set.add(route);\n }\n };\n\n if (!route.match(ARRAY_GROUP_REGEX)) {\n addRoute(route, route);\n }\n\n // Does this route have a group? eg /(group)\n if (route.includes('/(')) {\n const routeWithoutGroups = route.replace(/\\/\\(.+?\\)/g, '');\n addRoute(route, routeWithoutGroups);\n\n // If there are multiple groups, we need to expand them\n // eg /(test1,test2)/page => /test1/page & /test2/page\n for (const routeWithSingleGroup of extrapolateGroupRoutes(route)) {\n addRoute(route, routeWithSingleGroup);\n }\n }\n\n return true;\n };\n\n return {\n staticRoutes,\n dynamicRoutes,\n filePathToRoute,\n addFilePath,\n isRouteFile,\n };\n}\n\nexport const setToUnionType = <T>(set: Set<T>) => {\n return set.size > 0 ? [...set].map((s) => `\\`${s}\\``).join(' | ') : 'never';\n};\n\n/**\n * Given a route, return all possible routes that could be generated from it.\n */\nexport function extrapolateGroupRoutes(\n route: string,\n routes: Set<string> = new Set()\n): Set<string> {\n // Create a version with no groups. We will then need to cleanup double and/or trailing slashes\n routes.add(route.replaceAll(ARRAY_GROUP_REGEX, '').replaceAll(/\\/+/g, '/').replace(/\\/$/, ''));\n\n const match = route.match(ARRAY_GROUP_REGEX);\n\n if (!match) {\n routes.add(route);\n return routes;\n }\n\n const groupsMatch = match[0];\n\n for (const group of groupsMatch.matchAll(CAPTURE_GROUP_REGEX)) {\n extrapolateGroupRoutes(route.replace(groupsMatch, `(${group[1]!.trim()})`), routes);\n }\n\n return routes;\n}\n\n/**\n * NOTE: This code refers to a specific version of `expo-router` and is therefore unsafe to\n * mix with arbitrary versions.\n * TODO: Version this code with `expo-router` or version expo-router with `@expo/cli`.\n */\nconst routerDotTSTemplate = unsafeTemplate`/* eslint-disable */\ndeclare module \"expo-router\" {\n import type { LinkProps as OriginalLinkProps } from 'expo-router/build/link/Link';\n import type { Router as OriginalRouter } from 'expo-router/build/types';\n export * from 'expo-router/build';\n\n // prettier-ignore\n type StaticRoutes = ${'staticRoutes'};\n // prettier-ignore\n type DynamicRoutes<T extends string> = ${'dynamicRoutes'};\n // prettier-ignore\n type DynamicRouteTemplate = ${'dynamicRouteParams'};\n\n type RelativePathString = \\`./\\${string}\\` | \\`../\\${string}\\` | '..';\n type AbsoluteRoute = DynamicRouteTemplate | StaticRoutes;\n type ExternalPathString = \\`\\${string}:\\${string}\\`;\n\n type ExpoRouterRoutes = DynamicRouteTemplate | StaticRoutes | RelativePathString;\n export type AllRoutes = ExpoRouterRoutes | ExternalPathString;\n\n /****************\n * Route Utils *\n ****************/\n\n type SearchOrHash = \\`?\\${string}\\` | \\`#\\${string}\\`;\n type UnknownInputParams = Record<string, string | number | (string | number)[]>;\n type UnknownOutputParams = Record<string, string | string[]>;\n\n /**\n * Return only the RoutePart of a string. If the string has multiple parts return never\n *\n * string | type\n * ---------|------\n * 123 | 123\n * /123/abc | never\n * 123?abc | never\n * ./123 | never\n * /123 | never\n * 123/../ | never\n */\n type SingleRoutePart<S extends string> = S extends \\`\\${string}/\\${string}\\`\n ? never\n : S extends \\`\\${string}\\${SearchOrHash}\\`\n ? never\n : S extends ''\n ? never\n : S extends \\`(\\${string})\\`\n ? never\n : S extends \\`[\\${string}]\\`\n ? never\n : S;\n\n /**\n * Return only the CatchAll router part. If the string has search parameters or a hash return never\n */\n type CatchAllRoutePart<S extends string> = S extends \\`\\${string}\\${SearchOrHash}\\`\n ? never\n : S extends ''\n ? never\n : S extends \\`\\${string}(\\${string})\\${string}\\`\n ? never\n : S extends \\`\\${string}[\\${string}]\\${string}\\`\n ? never\n : S;\n\n // type OptionalCatchAllRoutePart<S extends string> = S extends \\`\\${string}\\${SearchOrHash}\\` ? never : S\n\n /**\n * Return the name of a route parameter\n * '[test]' -> 'test'\n * 'test' -> never\n * '[...test]' -> '...test'\n */\n type IsParameter<Part> = Part extends \\`[\\${infer ParamName}]\\` ? ParamName : never;\n\n /**\n * Return a union of all parameter names. If there are no names return never\n *\n * /[test] -> 'test'\n * /[abc]/[...def] -> 'abc'|'...def'\n */\n type ParameterNames<Path> = Path extends \\`\\${infer PartA}/\\${infer PartB}\\`\n ? IsParameter<PartA> | ParameterNames<PartB>\n : IsParameter<Path>;\n\n /**\n * Returns all segements of a route.\n *\n * /(group)/123/abc/[id]/[...rest] -> ['(group)', '123', 'abc', '[id]', '[...rest]'\n */\n type RouteSegments<Path> = Path extends \\`\\${infer PartA}/\\${infer PartB}\\`\n ? PartA extends '' | '.'\n ? [...RouteSegments<PartB>]\n : [PartA, ...RouteSegments<PartB>]\n : Path extends ''\n ? []\n : [Path];\n\n /**\n * Returns a Record of the routes parameters as strings and CatchAll parameters\n *\n * There are two versions, input and output, as you can input 'string | number' but\n * the output will always be 'string'\n *\n * /[id]/[...rest] -> { id: string, rest: string[] }\n * /no-params -> {}\n */\n type InputRouteParams<Path> = {\n [Key in ParameterNames<Path> as Key extends \\`...\\${infer Name}\\`\n ? Name\n : Key]: Key extends \\`...\\${string}\\` ? (string | number)[] : string | number;\n } & UnknownInputParams;\n\n type OutputRouteParams<Path> = {\n [Key in ParameterNames<Path> as Key extends \\`...\\${infer Name}\\`\n ? Name\n : Key]: Key extends \\`...\\${string}\\` ? string[] : string;\n } & UnknownOutputParams;\n\n /**\n * Returns the search parameters for a route.\n */\n export type SearchParams<T extends AllRoutes> = T extends DynamicRouteTemplate\n ? OutputRouteParams<T>\n : T extends StaticRoutes\n ? never\n : UnknownOutputParams;\n\n /**\n * Route is mostly used as part of Href to ensure that a valid route is provided\n *\n * Given a dynamic route, this will return never. This is helpful for conditional logic\n *\n * /test -> /test, /test2, etc\n * /test/[abc] -> never\n * /test/resolve -> /test, /test2, etc\n *\n * Note that if we provide a value for [abc] then the route is allowed\n *\n * This is named Route to prevent confusion, as users they will often see it in tooltips\n */\n export type Route<T> = T extends string\n ? T extends DynamicRouteTemplate\n ? never\n :\n | StaticRoutes\n | RelativePathString\n | ExternalPathString\n | (T extends \\`\\${infer P}\\${SearchOrHash}\\`\n ? P extends DynamicRoutes<infer _>\n ? T\n : never\n : T extends DynamicRoutes<infer _>\n ? T\n : never)\n : never;\n\n /*********\n * Href *\n *********/\n\n export type Href<T> = T extends Record<'pathname', string> ? HrefObject<T> : Route<T>;\n\n export type HrefObject<\n R extends Record<'pathname', string>,\n P = R['pathname'],\n > = P extends DynamicRouteTemplate\n ? { pathname: P; params: InputRouteParams<P> }\n : P extends Route<P>\n ? { pathname: Route<P> | DynamicRouteTemplate; params?: never | InputRouteParams<never> }\n : never;\n\n /***********************\n * Expo Router Exports *\n ***********************/\n\n export type Router = Omit<OriginalRouter, 'push' | 'replace' | 'setParams'> & {\n /** Navigate to the provided href. */\n push: <T>(href: Href<T>) => void;\n /** Navigate to route without appending to the history. */\n replace: <T>(href: Href<T>) => void;\n /** Update the current route query params. */\n setParams: <T = ''>(params?: T extends '' ? Record<string, string> : InputRouteParams<T>) => void;\n };\n\n /** The imperative router. */\n export const router: Router;\n\n /************\n * <Link /> *\n ************/\n export interface LinkProps<T> extends OriginalLinkProps {\n href: Href<T>;\n }\n\n export interface LinkComponent {\n <T>(props: React.PropsWithChildren<LinkProps<T>>): JSX.Element;\n /** Helper method to resolve an Href object into a string. */\n resolveHref: <T>(href: Href<T>) => string;\n }\n\n /**\n * Component to render link to another route using a path.\n * Uses an anchor tag on the web.\n *\n * @param props.href Absolute path to route (e.g. \\`/feeds/hot\\`).\n * @param props.replace Should replace the current route without adding to the history.\n * @param props.asChild Forward props to child component. Useful for custom buttons.\n * @param props.children Child elements to render the content.\n * @param props.className On web, this sets the HTML \\`class\\` directly. On native, this can be used with CSS interop tools like Nativewind.\n */\n export const Link: LinkComponent;\n\n /** Redirects to the href as soon as the component is mounted. */\n export const Redirect: <T>(\n props: React.PropsWithChildren<{ href: Href<T> }>\n ) => JSX.Element;\n\n /************\n * Hooks *\n ************/\n export function useRouter(): Router;\n\n export function useLocalSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams,\n >(): T extends AllRoutes ? SearchParams<T> : T;\n\n /** @deprecated renamed to \\`useGlobalSearchParams\\` */\n export function useSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams,\n >(): T extends AllRoutes ? SearchParams<T> : T;\n\n export function useGlobalSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams,\n >(): T extends AllRoutes ? SearchParams<T> : T;\n\n export function useSegments<\n T extends AbsoluteRoute | RouteSegments<AbsoluteRoute> | RelativePathString,\n >(): T extends AbsoluteRoute ? RouteSegments<T> : T extends string ? string[] : T;\n}\n`;\n"],"names":["ARRAY_GROUP_REGEX","CAPTURE_DYNAMIC_PARAMS","CAPTURE_GROUP_REGEX","CATCH_ALL","SLUG","TYPED_ROUTES_EXCLUSION_REGEX","extrapolateGroupRoutes","getTemplateString","getTypedRoutesUtils","setToUnionType","setupTypedRoutes","options","typedRoutesModule","require","resolve","typedRoutes","typedRoutesModulePath","server","metro","typesDirectory","projectRoot","routerDirectory","plugin","process","env","EXPO_ROUTER_APP_ROOT","metroWatchTypeScriptFiles","eventTypes","callback","getWatchHandler","version","regenerateDeclarations","staticRoutes","dynamicRoutes","dynamicRouteTemplates","routerDotTSTemplate","dynamicRouteParams","appRoot","filePathSeperator","path","sep","Map","Set","normalizedFilePath","filePath","replaceAll","normalizedAppRoot","filePathToRoute","replace","isRouteFile","match","relative","startsWith","isAbsolute","addFilePath","route","has","dynamicParams","matchAll","map","isDynamic","size","addRoute","originalRoute","set","get","add","includes","routeWithoutGroups","routeWithSingleGroup","s","join","routes","groupsMatch","group","trim","unsafeTemplate"],"mappings":"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"}
@@ -39,7 +39,7 @@ function _path() {
39
39
  }
40
40
  const _templates = require("../../customize/templates");
41
41
  const _html = require("../../export/html");
42
- const _env = require("../../utils/env");
42
+ const _publicFolder = require("../../export/publicFolder");
43
43
  function _interop_require_default(obj) {
44
44
  return obj && obj.__esModule ? obj : {
45
45
  default: obj
@@ -58,8 +58,8 @@ async function createTemplateHtmlFromExpoConfigAsync(projectRoot, { scripts, css
58
58
  themeColor: (_exp_web2 = exp.web) == null ? void 0 : _exp_web2.themeColor
59
59
  });
60
60
  }
61
- function getFileFromLocalPublicFolder(projectRoot, { publicFolder, filePath }) {
62
- const localFilePath = _path().default.resolve(projectRoot, publicFolder, filePath);
61
+ function getFileFromLocalPublicFolder(projectRoot, { filePath }) {
62
+ const localFilePath = _path().default.resolve((0, _publicFolder.getPublicFolderPath)(projectRoot), filePath);
63
63
  if (!_fs().default.existsSync(localFilePath)) {
64
64
  return null;
65
65
  }
@@ -67,8 +67,6 @@ function getFileFromLocalPublicFolder(projectRoot, { publicFolder, filePath }) {
67
67
  }
68
68
  /** Attempt to read the `index.html` from the local project before falling back on the template `index.html`. */ async function getTemplateIndexHtmlAsync(projectRoot) {
69
69
  let filePath = getFileFromLocalPublicFolder(projectRoot, {
70
- // TODO: Maybe use the app.json override.
71
- publicFolder: _env.env.EXPO_PUBLIC_FOLDER,
72
70
  filePath: 'index.html'
73
71
  });
74
72
  if (!filePath) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/start/server/webTemplate.ts"],"sourcesContent":["import type { ExpoConfig } from '@expo/config';\nimport { getConfig, getNameFromConfig } from '@expo/config';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { TEMPLATES } from '../../customize/templates';\nimport { appendLinkToHtml, appendScriptsToHtml } from '../../export/html';\nimport { env } from '../../utils/env';\n\n/**\n * Create a static HTML for SPA styled websites.\n * This method attempts to reuse the same patterns as `@expo/webpack-config`.\n */\nexport async function createTemplateHtmlFromExpoConfigAsync(\n projectRoot: string,\n {\n scripts,\n cssLinks,\n exp = getConfig(projectRoot, { skipSDKVersionRequirement: true }).exp,\n }: {\n scripts: string[];\n cssLinks?: string[];\n exp?: ExpoConfig;\n }\n) {\n return createTemplateHtmlAsync(projectRoot, {\n langIsoCode: exp.web?.lang ?? 'en',\n scripts,\n cssLinks,\n title: getNameFromConfig(exp).webName ?? 'Expo App',\n description: exp.web?.description,\n themeColor: exp.web?.themeColor,\n });\n}\n\nfunction getFileFromLocalPublicFolder(\n projectRoot: string,\n { publicFolder, filePath }: { publicFolder: string; filePath: string }\n): string | null {\n const localFilePath = path.resolve(projectRoot, publicFolder, filePath);\n if (!fs.existsSync(localFilePath)) {\n return null;\n }\n return localFilePath;\n}\n\n/** Attempt to read the `index.html` from the local project before falling back on the template `index.html`. */\nasync function getTemplateIndexHtmlAsync(projectRoot: string): Promise<string> {\n let filePath = getFileFromLocalPublicFolder(projectRoot, {\n // TODO: Maybe use the app.json override.\n publicFolder: env.EXPO_PUBLIC_FOLDER,\n filePath: 'index.html',\n });\n if (!filePath) {\n filePath = TEMPLATES.find((value) => value.id === 'index.html')!.file(projectRoot);\n }\n return fs.promises.readFile(filePath, 'utf8');\n}\n\n/** Return an `index.html` string with template values added. */\nexport async function createTemplateHtmlAsync(\n projectRoot: string,\n {\n scripts,\n cssLinks,\n description,\n langIsoCode,\n title,\n themeColor,\n }: {\n scripts: string[];\n cssLinks?: string[];\n description?: string;\n langIsoCode: string;\n title: string;\n themeColor?: string;\n }\n): Promise<string> {\n // Resolve the best possible index.html template file.\n let contents = await getTemplateIndexHtmlAsync(projectRoot);\n\n contents = contents.replace('%LANG_ISO_CODE%', langIsoCode);\n contents = contents.replace('%WEB_TITLE%', title);\n\n contents = appendScriptsToHtml(contents, scripts);\n\n if (cssLinks) {\n contents = appendLinkToHtml(\n contents,\n cssLinks\n .map((href) => [\n // NOTE: We probably don't have to preload the CSS files for SPA-styled websites.\n {\n as: 'style',\n rel: 'preload',\n href,\n },\n {\n rel: 'stylesheet',\n href,\n },\n ])\n .flat()\n );\n }\n\n if (themeColor) {\n contents = addMeta(contents, `name=\"theme-color\" content=\"${themeColor}\"`);\n }\n\n if (description) {\n contents = addMeta(contents, `name=\"description\" content=\"${description}\"`);\n }\n\n return contents;\n}\n\n/** Add a `<meta />` tag to the `<head />` element. */\nfunction addMeta(contents: string, meta: string): string {\n return contents.replace('</head>', `<meta ${meta}>\\n</head>`);\n}\n"],"names":["createTemplateHtmlAsync","createTemplateHtmlFromExpoConfigAsync","projectRoot","scripts","cssLinks","exp","getConfig","skipSDKVersionRequirement","langIsoCode","web","lang","title","getNameFromConfig","webName","description","themeColor","getFileFromLocalPublicFolder","publicFolder","filePath","localFilePath","path","resolve","fs","existsSync","getTemplateIndexHtmlAsync","env","EXPO_PUBLIC_FOLDER","TEMPLATES","find","value","id","file","promises","readFile","contents","replace","appendScriptsToHtml","appendLinkToHtml","map","href","as","rel","flat","addMeta","meta"],"mappings":";;;;;;;;;;;QA4DsBA;eAAAA;;QA/CAC;eAAAA;;;;yBAZuB;;;;;;;gEAC9B;;;;;;;gEACE;;;;;;2BAES;sBAC4B;qBAClC;;;;;;AAMb,eAAeA,sCACpBC,WAAmB,EACnB,EACEC,OAAO,EACPC,QAAQ,EACRC,MAAMC,IAAAA,mBAAS,EAACJ,aAAa;IAAEK,2BAA2B;AAAK,GAAGF,GAAG,EAKtE;QAGcA,UAIAA,WACDA;IANd,OAAOL,wBAAwBE,aAAa;QAC1CM,aAAaH,EAAAA,WAAAA,IAAII,GAAG,qBAAPJ,SAASK,IAAI,KAAI;QAC9BP;QACAC;QACAO,OAAOC,IAAAA,2BAAiB,EAACP,KAAKQ,OAAO,IAAI;QACzCC,WAAW,GAAET,YAAAA,IAAII,GAAG,qBAAPJ,UAASS,WAAW;QACjCC,UAAU,GAAEV,YAAAA,IAAII,GAAG,qBAAPJ,UAASU,UAAU;IACjC;AACF;AAEA,SAASC,6BACPd,WAAmB,EACnB,EAAEe,YAAY,EAAEC,QAAQ,EAA8C;IAEtE,MAAMC,gBAAgBC,eAAI,CAACC,OAAO,CAACnB,aAAae,cAAcC;IAC9D,IAAI,CAACI,aAAE,CAACC,UAAU,CAACJ,gBAAgB;QACjC,OAAO;IACT;IACA,OAAOA;AACT;AAEA,8GAA8G,GAC9G,eAAeK,0BAA0BtB,WAAmB;IAC1D,IAAIgB,WAAWF,6BAA6Bd,aAAa;QACvD,yCAAyC;QACzCe,cAAcQ,QAAG,CAACC,kBAAkB;QACpCR,UAAU;IACZ;IACA,IAAI,CAACA,UAAU;QACbA,WAAWS,oBAAS,CAACC,IAAI,CAAC,CAACC,QAAUA,MAAMC,EAAE,KAAK,cAAeC,IAAI,CAAC7B;IACxE;IACA,OAAOoB,aAAE,CAACU,QAAQ,CAACC,QAAQ,CAACf,UAAU;AACxC;AAGO,eAAelB,wBACpBE,WAAmB,EACnB,EACEC,OAAO,EACPC,QAAQ,EACRU,WAAW,EACXN,WAAW,EACXG,KAAK,EACLI,UAAU,EAQX;IAED,sDAAsD;IACtD,IAAImB,WAAW,MAAMV,0BAA0BtB;IAE/CgC,WAAWA,SAASC,OAAO,CAAC,mBAAmB3B;IAC/C0B,WAAWA,SAASC,OAAO,CAAC,eAAexB;IAE3CuB,WAAWE,IAAAA,yBAAmB,EAACF,UAAU/B;IAEzC,IAAIC,UAAU;QACZ8B,WAAWG,IAAAA,sBAAgB,EACzBH,UACA9B,SACGkC,GAAG,CAAC,CAACC,OAAS;gBACb,iFAAiF;gBACjF;oBACEC,IAAI;oBACJC,KAAK;oBACLF;gBACF;gBACA;oBACEE,KAAK;oBACLF;gBACF;aACD,EACAG,IAAI;IAEX;IAEA,IAAI3B,YAAY;QACdmB,WAAWS,QAAQT,UAAU,CAAC,4BAA4B,EAAEnB,WAAW,CAAC,CAAC;IAC3E;IAEA,IAAID,aAAa;QACfoB,WAAWS,QAAQT,UAAU,CAAC,4BAA4B,EAAEpB,YAAY,CAAC,CAAC;IAC5E;IAEA,OAAOoB;AACT;AAEA,oDAAoD,GACpD,SAASS,QAAQT,QAAgB,EAAEU,IAAY;IAC7C,OAAOV,SAASC,OAAO,CAAC,WAAW,CAAC,MAAM,EAAES,KAAK,UAAU,CAAC;AAC9D"}
1
+ {"version":3,"sources":["../../../../src/start/server/webTemplate.ts"],"sourcesContent":["import type { ExpoConfig } from '@expo/config';\nimport { getConfig, getNameFromConfig } from '@expo/config';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { TEMPLATES } from '../../customize/templates';\nimport { appendLinkToHtml, appendScriptsToHtml } from '../../export/html';\nimport { getPublicFolderPath } from '../../export/publicFolder';\n\n/**\n * Create a static HTML for SPA styled websites.\n * This method attempts to reuse the same patterns as `@expo/webpack-config`.\n */\nexport async function createTemplateHtmlFromExpoConfigAsync(\n projectRoot: string,\n {\n scripts,\n cssLinks,\n exp = getConfig(projectRoot, { skipSDKVersionRequirement: true }).exp,\n }: {\n scripts: string[];\n cssLinks?: string[];\n exp?: ExpoConfig;\n }\n) {\n return createTemplateHtmlAsync(projectRoot, {\n langIsoCode: exp.web?.lang ?? 'en',\n scripts,\n cssLinks,\n title: getNameFromConfig(exp).webName ?? 'Expo App',\n description: exp.web?.description,\n themeColor: exp.web?.themeColor,\n });\n}\n\nfunction getFileFromLocalPublicFolder(\n projectRoot: string,\n { filePath }: { filePath: string }\n): string | null {\n const localFilePath = path.resolve(getPublicFolderPath(projectRoot), filePath);\n if (!fs.existsSync(localFilePath)) {\n return null;\n }\n return localFilePath;\n}\n\n/** Attempt to read the `index.html` from the local project before falling back on the template `index.html`. */\nasync function getTemplateIndexHtmlAsync(projectRoot: string): Promise<string> {\n let filePath = getFileFromLocalPublicFolder(projectRoot, {\n filePath: 'index.html',\n });\n if (!filePath) {\n filePath = TEMPLATES.find((value) => value.id === 'index.html')!.file(projectRoot);\n }\n return fs.promises.readFile(filePath, 'utf8');\n}\n\n/** Return an `index.html` string with template values added. */\nexport async function createTemplateHtmlAsync(\n projectRoot: string,\n {\n scripts,\n cssLinks,\n description,\n langIsoCode,\n title,\n themeColor,\n }: {\n scripts: string[];\n cssLinks?: string[];\n description?: string;\n langIsoCode: string;\n title: string;\n themeColor?: string;\n }\n): Promise<string> {\n // Resolve the best possible index.html template file.\n let contents = await getTemplateIndexHtmlAsync(projectRoot);\n\n contents = contents.replace('%LANG_ISO_CODE%', langIsoCode);\n contents = contents.replace('%WEB_TITLE%', title);\n\n contents = appendScriptsToHtml(contents, scripts);\n\n if (cssLinks) {\n contents = appendLinkToHtml(\n contents,\n cssLinks\n .map((href) => [\n // NOTE: We probably don't have to preload the CSS files for SPA-styled websites.\n {\n as: 'style',\n rel: 'preload',\n href,\n },\n {\n rel: 'stylesheet',\n href,\n },\n ])\n .flat()\n );\n }\n\n if (themeColor) {\n contents = addMeta(contents, `name=\"theme-color\" content=\"${themeColor}\"`);\n }\n\n if (description) {\n contents = addMeta(contents, `name=\"description\" content=\"${description}\"`);\n }\n\n return contents;\n}\n\n/** Add a `<meta />` tag to the `<head />` element. */\nfunction addMeta(contents: string, meta: string): string {\n return contents.replace('</head>', `<meta ${meta}>\\n</head>`);\n}\n"],"names":["createTemplateHtmlAsync","createTemplateHtmlFromExpoConfigAsync","projectRoot","scripts","cssLinks","exp","getConfig","skipSDKVersionRequirement","langIsoCode","web","lang","title","getNameFromConfig","webName","description","themeColor","getFileFromLocalPublicFolder","filePath","localFilePath","path","resolve","getPublicFolderPath","fs","existsSync","getTemplateIndexHtmlAsync","TEMPLATES","find","value","id","file","promises","readFile","contents","replace","appendScriptsToHtml","appendLinkToHtml","map","href","as","rel","flat","addMeta","meta"],"mappings":";;;;;;;;;;;QA0DsBA;eAAAA;;QA7CAC;eAAAA;;;;yBAZuB;;;;;;;gEAC9B;;;;;;;gEACE;;;;;;2BAES;sBAC4B;8BAClB;;;;;;AAM7B,eAAeA,sCACpBC,WAAmB,EACnB,EACEC,OAAO,EACPC,QAAQ,EACRC,MAAMC,IAAAA,mBAAS,EAACJ,aAAa;IAAEK,2BAA2B;AAAK,GAAGF,GAAG,EAKtE;QAGcA,UAIAA,WACDA;IANd,OAAOL,wBAAwBE,aAAa;QAC1CM,aAAaH,EAAAA,WAAAA,IAAII,GAAG,qBAAPJ,SAASK,IAAI,KAAI;QAC9BP;QACAC;QACAO,OAAOC,IAAAA,2BAAiB,EAACP,KAAKQ,OAAO,IAAI;QACzCC,WAAW,GAAET,YAAAA,IAAII,GAAG,qBAAPJ,UAASS,WAAW;QACjCC,UAAU,GAAEV,YAAAA,IAAII,GAAG,qBAAPJ,UAASU,UAAU;IACjC;AACF;AAEA,SAASC,6BACPd,WAAmB,EACnB,EAAEe,QAAQ,EAAwB;IAElC,MAAMC,gBAAgBC,eAAI,CAACC,OAAO,CAACC,IAAAA,iCAAmB,EAACnB,cAAce;IACrE,IAAI,CAACK,aAAE,CAACC,UAAU,CAACL,gBAAgB;QACjC,OAAO;IACT;IACA,OAAOA;AACT;AAEA,8GAA8G,GAC9G,eAAeM,0BAA0BtB,WAAmB;IAC1D,IAAIe,WAAWD,6BAA6Bd,aAAa;QACvDe,UAAU;IACZ;IACA,IAAI,CAACA,UAAU;QACbA,WAAWQ,oBAAS,CAACC,IAAI,CAAC,CAACC,QAAUA,MAAMC,EAAE,KAAK,cAAeC,IAAI,CAAC3B;IACxE;IACA,OAAOoB,aAAE,CAACQ,QAAQ,CAACC,QAAQ,CAACd,UAAU;AACxC;AAGO,eAAejB,wBACpBE,WAAmB,EACnB,EACEC,OAAO,EACPC,QAAQ,EACRU,WAAW,EACXN,WAAW,EACXG,KAAK,EACLI,UAAU,EAQX;IAED,sDAAsD;IACtD,IAAIiB,WAAW,MAAMR,0BAA0BtB;IAE/C8B,WAAWA,SAASC,OAAO,CAAC,mBAAmBzB;IAC/CwB,WAAWA,SAASC,OAAO,CAAC,eAAetB;IAE3CqB,WAAWE,IAAAA,yBAAmB,EAACF,UAAU7B;IAEzC,IAAIC,UAAU;QACZ4B,WAAWG,IAAAA,sBAAgB,EACzBH,UACA5B,SACGgC,GAAG,CAAC,CAACC,OAAS;gBACb,iFAAiF;gBACjF;oBACEC,IAAI;oBACJC,KAAK;oBACLF;gBACF;gBACA;oBACEE,KAAK;oBACLF;gBACF;aACD,EACAG,IAAI;IAEX;IAEA,IAAIzB,YAAY;QACdiB,WAAWS,QAAQT,UAAU,CAAC,4BAA4B,EAAEjB,WAAW,CAAC,CAAC;IAC3E;IAEA,IAAID,aAAa;QACfkB,WAAWS,QAAQT,UAAU,CAAC,4BAA4B,EAAElB,YAAY,CAAC,CAAC;IAC5E;IAEA,OAAOkB;AACT;AAEA,oDAAoD,GACpD,SAASS,QAAQT,QAAgB,EAAEU,IAAY;IAC7C,OAAOV,SAASC,OAAO,CAAC,WAAW,CAAC,MAAM,EAAES,KAAK,UAAU,CAAC;AAC9D"}
@@ -35,7 +35,13 @@ const isMatchingOrigin = (request, serverBaseUrl)=>{
35
35
  if (!request.headers.origin) {
36
36
  return true;
37
37
  }
38
- const actualHost = new URL(`${request.headers.origin}`).host;
38
+ let actualHost;
39
+ try {
40
+ actualHost = new URL(`${request.headers.origin}`).host;
41
+ } catch {
42
+ // Malformed Origin — treat as untrusted.
43
+ return false;
44
+ }
39
45
  const expectedHost = new URL(serverBaseUrl).host;
40
46
  return actualHost === expectedHost;
41
47
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/net.ts"],"sourcesContent":["import type { IncomingHttpHeaders } from 'node:http';\nimport type { Socket } from 'node:net';\n\nconst ipv6To4Prefix = '::ffff:';\n\nexport const isLocalSocket = (socket: Socket): boolean => {\n let { localAddress, remoteAddress, remoteFamily } = socket;\n\n const isLoopbackRequest = localAddress && localAddress === remoteAddress;\n if (isLoopbackRequest) {\n return true;\n } else if (!remoteAddress || !remoteFamily) {\n return false;\n }\n\n if (remoteFamily === 'IPv6' && remoteAddress.startsWith(ipv6To4Prefix)) {\n remoteAddress = remoteAddress.slice(ipv6To4Prefix.length);\n }\n\n return remoteAddress === '::1' || remoteAddress.startsWith('127.');\n};\n\ninterface AbstractIncomingMessage {\n headers: IncomingHttpHeaders | Record<string, string | string[]>;\n}\n\nexport const isMatchingOrigin = (\n request: AbstractIncomingMessage,\n serverBaseUrl: string\n): boolean => {\n // NOTE(@kitten): The browser will always send an origin header for websocket upgrade connections\n if (!request.headers.origin) {\n return true;\n }\n const actualHost = new URL(`${request.headers.origin}`).host;\n const expectedHost = new URL(serverBaseUrl).host;\n return actualHost === expectedHost;\n};\n"],"names":["isLocalSocket","isMatchingOrigin","ipv6To4Prefix","socket","localAddress","remoteAddress","remoteFamily","isLoopbackRequest","startsWith","slice","length","request","serverBaseUrl","headers","origin","actualHost","URL","host","expectedHost"],"mappings":";;;;;;;;;;;QAKaA;eAAAA;;QAqBAC;eAAAA;;;AAvBb,MAAMC,gBAAgB;AAEf,MAAMF,gBAAgB,CAACG;IAC5B,IAAI,EAAEC,YAAY,EAAEC,aAAa,EAAEC,YAAY,EAAE,GAAGH;IAEpD,MAAMI,oBAAoBH,gBAAgBA,iBAAiBC;IAC3D,IAAIE,mBAAmB;QACrB,OAAO;IACT,OAAO,IAAI,CAACF,iBAAiB,CAACC,cAAc;QAC1C,OAAO;IACT;IAEA,IAAIA,iBAAiB,UAAUD,cAAcG,UAAU,CAACN,gBAAgB;QACtEG,gBAAgBA,cAAcI,KAAK,CAACP,cAAcQ,MAAM;IAC1D;IAEA,OAAOL,kBAAkB,SAASA,cAAcG,UAAU,CAAC;AAC7D;AAMO,MAAMP,mBAAmB,CAC9BU,SACAC;IAEA,iGAAiG;IACjG,IAAI,CAACD,QAAQE,OAAO,CAACC,MAAM,EAAE;QAC3B,OAAO;IACT;IACA,MAAMC,aAAa,IAAIC,IAAI,GAAGL,QAAQE,OAAO,CAACC,MAAM,EAAE,EAAEG,IAAI;IAC5D,MAAMC,eAAe,IAAIF,IAAIJ,eAAeK,IAAI;IAChD,OAAOF,eAAeG;AACxB"}
1
+ {"version":3,"sources":["../../../src/utils/net.ts"],"sourcesContent":["import type { IncomingHttpHeaders } from 'node:http';\nimport type { Socket } from 'node:net';\n\nconst ipv6To4Prefix = '::ffff:';\n\nexport const isLocalSocket = (socket: Socket): boolean => {\n let { localAddress, remoteAddress, remoteFamily } = socket;\n\n const isLoopbackRequest = localAddress && localAddress === remoteAddress;\n if (isLoopbackRequest) {\n return true;\n } else if (!remoteAddress || !remoteFamily) {\n return false;\n }\n\n if (remoteFamily === 'IPv6' && remoteAddress.startsWith(ipv6To4Prefix)) {\n remoteAddress = remoteAddress.slice(ipv6To4Prefix.length);\n }\n\n return remoteAddress === '::1' || remoteAddress.startsWith('127.');\n};\n\ninterface AbstractIncomingMessage {\n headers: IncomingHttpHeaders | Record<string, string | string[]>;\n}\n\nexport const isMatchingOrigin = (\n request: AbstractIncomingMessage,\n serverBaseUrl: string\n): boolean => {\n // NOTE(@kitten): The browser will always send an origin header for websocket upgrade connections\n if (!request.headers.origin) {\n return true;\n }\n let actualHost: string;\n try {\n actualHost = new URL(`${request.headers.origin}`).host;\n } catch {\n // Malformed Origin — treat as untrusted.\n return false;\n }\n const expectedHost = new URL(serverBaseUrl).host;\n return actualHost === expectedHost;\n};\n"],"names":["isLocalSocket","isMatchingOrigin","ipv6To4Prefix","socket","localAddress","remoteAddress","remoteFamily","isLoopbackRequest","startsWith","slice","length","request","serverBaseUrl","headers","origin","actualHost","URL","host","expectedHost"],"mappings":";;;;;;;;;;;QAKaA;eAAAA;;QAqBAC;eAAAA;;;AAvBb,MAAMC,gBAAgB;AAEf,MAAMF,gBAAgB,CAACG;IAC5B,IAAI,EAAEC,YAAY,EAAEC,aAAa,EAAEC,YAAY,EAAE,GAAGH;IAEpD,MAAMI,oBAAoBH,gBAAgBA,iBAAiBC;IAC3D,IAAIE,mBAAmB;QACrB,OAAO;IACT,OAAO,IAAI,CAACF,iBAAiB,CAACC,cAAc;QAC1C,OAAO;IACT;IAEA,IAAIA,iBAAiB,UAAUD,cAAcG,UAAU,CAACN,gBAAgB;QACtEG,gBAAgBA,cAAcI,KAAK,CAACP,cAAcQ,MAAM;IAC1D;IAEA,OAAOL,kBAAkB,SAASA,cAAcG,UAAU,CAAC;AAC7D;AAMO,MAAMP,mBAAmB,CAC9BU,SACAC;IAEA,iGAAiG;IACjG,IAAI,CAACD,QAAQE,OAAO,CAACC,MAAM,EAAE;QAC3B,OAAO;IACT;IACA,IAAIC;IACJ,IAAI;QACFA,aAAa,IAAIC,IAAI,GAAGL,QAAQE,OAAO,CAACC,MAAM,EAAE,EAAEG,IAAI;IACxD,EAAE,OAAM;QACN,yCAAyC;QACzC,OAAO;IACT;IACA,MAAMC,eAAe,IAAIF,IAAIJ,eAAeK,IAAI;IAChD,OAAOF,eAAeG;AACxB"}