@expo/cli 55.0.3 → 55.0.5

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 (81) hide show
  1. package/build/bin/cli +1 -1
  2. package/build/src/api/graphql/client.js +133 -68
  3. package/build/src/api/graphql/client.js.map +1 -1
  4. package/build/src/api/graphql/queries/AppQuery.js +21 -25
  5. package/build/src/api/graphql/queries/AppQuery.js.map +1 -1
  6. package/build/src/api/graphql/queries/UserQuery.js +45 -38
  7. package/build/src/api/graphql/queries/UserQuery.js.map +1 -1
  8. package/build/src/api/rest/cache/FileSystemResponseCache.js.map +1 -1
  9. package/build/src/api/rest/cache/ResponseCache.js.map +1 -1
  10. package/build/src/api/rest/cache/wrapFetchWithCache.js +7 -7
  11. package/build/src/api/rest/cache/wrapFetchWithCache.js.map +1 -1
  12. package/build/src/api/rest/client.js +3 -7
  13. package/build/src/api/rest/client.js.map +1 -1
  14. package/build/src/api/rest/wrapFetchWithProgress.js +1 -8
  15. package/build/src/api/rest/wrapFetchWithProgress.js.map +1 -1
  16. package/build/src/api/user/user.js +6 -36
  17. package/build/src/api/user/user.js.map +1 -1
  18. package/build/src/prebuild/renameTemplateAppName.js +2 -6
  19. package/build/src/prebuild/renameTemplateAppName.js.map +1 -1
  20. package/build/src/prebuild/resolveLocalTemplate.js +2 -4
  21. package/build/src/prebuild/resolveLocalTemplate.js.map +1 -1
  22. package/build/src/prebuild/resolveTemplate.js +13 -17
  23. package/build/src/prebuild/resolveTemplate.js.map +1 -1
  24. package/build/src/prebuild/updateFromTemplate.js +4 -6
  25. package/build/src/prebuild/updateFromTemplate.js.map +1 -1
  26. package/build/src/start/doctor/ngrok/ExternalModule.js +2 -8
  27. package/build/src/start/doctor/ngrok/ExternalModule.js.map +1 -1
  28. package/build/src/start/server/metro/DevToolsPluginWebsocketEndpoint.js +1 -9
  29. package/build/src/start/server/metro/DevToolsPluginWebsocketEndpoint.js.map +1 -1
  30. package/build/src/start/server/metro/MetroBundlerDevServer.js +13 -8
  31. package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
  32. package/build/src/start/server/metro/createServerComponentsMiddleware.js +4 -14
  33. package/build/src/start/server/metro/createServerComponentsMiddleware.js.map +1 -1
  34. package/build/src/start/server/metro/createServerRouteMiddleware.js +17 -0
  35. package/build/src/start/server/metro/createServerRouteMiddleware.js.map +1 -1
  36. package/build/src/start/server/metro/fetchRouterManifest.js +1 -13
  37. package/build/src/start/server/metro/fetchRouterManifest.js.map +1 -1
  38. package/build/src/start/server/metro/instantiateMetro.js +1 -3
  39. package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
  40. package/build/src/start/server/middleware/ExpoGoManifestHandlerMiddleware.js +47 -34
  41. package/build/src/start/server/middleware/ExpoGoManifestHandlerMiddleware.js.map +1 -1
  42. package/build/src/start/server/middleware/ManifestMiddleware.js +27 -4
  43. package/build/src/start/server/middleware/ManifestMiddleware.js.map +1 -1
  44. package/build/src/start/server/type-generation/routes.js +2 -62
  45. package/build/src/start/server/type-generation/routes.js.map +1 -1
  46. package/build/src/utils/build-cache-providers/index.js +1 -1
  47. package/build/src/utils/build-cache-providers/index.js.map +1 -1
  48. package/build/src/utils/codesigning.js +3 -17
  49. package/build/src/utils/codesigning.js.map +1 -1
  50. package/build/src/utils/createFileTransform.js +3 -38
  51. package/build/src/utils/createFileTransform.js.map +1 -1
  52. package/build/src/utils/downloadAppAsync.js +1 -12
  53. package/build/src/utils/downloadAppAsync.js.map +1 -1
  54. package/build/src/utils/fetch.js +23 -4
  55. package/build/src/utils/fetch.js.map +1 -1
  56. package/build/src/utils/freeport.js +21 -5
  57. package/build/src/utils/freeport.js.map +1 -1
  58. package/build/src/utils/getOrPromptApplicationId.js +2 -15
  59. package/build/src/utils/getOrPromptApplicationId.js.map +1 -1
  60. package/build/src/utils/npm.js +60 -65
  61. package/build/src/utils/npm.js.map +1 -1
  62. package/build/src/utils/port.js +4 -4
  63. package/build/src/utils/port.js.map +1 -1
  64. package/build/src/utils/resolveGlobal.js +195 -0
  65. package/build/src/utils/resolveGlobal.js.map +1 -0
  66. package/build/src/utils/tar.js +138 -69
  67. package/build/src/utils/tar.js.map +1 -1
  68. package/build/src/utils/telemetry/clients/FetchClient.js +12 -24
  69. package/build/src/utils/telemetry/clients/FetchClient.js.map +1 -1
  70. package/build/src/utils/telemetry/utils/context.js +1 -1
  71. package/package.json +18 -28
  72. package/build/src/api/graphql/types/App.js +0 -29
  73. package/build/src/api/graphql/types/App.js.map +0 -1
  74. package/build/src/api/rest/wrapFetchWithProxy.js +0 -31
  75. package/build/src/api/rest/wrapFetchWithProxy.js.map +0 -1
  76. package/build/src/graphql/generated.js +0 -1196
  77. package/build/src/graphql/generated.js.map +0 -1
  78. package/build/src/start/server/middleware/createBuiltinAPIRequestHandler.js +0 -85
  79. package/build/src/start/server/middleware/createBuiltinAPIRequestHandler.js.map +0 -1
  80. package/build/src/utils/multipartMixed.js +0 -56
  81. package/build/src/utils/multipartMixed.js.map +0 -1
@@ -37,6 +37,13 @@ function _crypto() {
37
37
  };
38
38
  return data;
39
39
  }
40
+ function _multitars() {
41
+ const data = require("multitars");
42
+ _multitars = function() {
43
+ return data;
44
+ };
45
+ return data;
46
+ }
40
47
  function _structuredheaders() {
41
48
  const data = require("structured-headers");
42
49
  _structuredheaders = function() {
@@ -51,14 +58,18 @@ const _UserSettings = require("../../../api/user/UserSettings");
51
58
  const _user = require("../../../api/user/user");
52
59
  const _codesigning = require("../../../utils/codesigning");
53
60
  const _errors = require("../../../utils/errors");
54
- const _multipartMixed = require("../../../utils/multipartMixed");
55
61
  const _url = require("../../../utils/url");
56
62
  function _interop_require_default(obj) {
57
63
  return obj && obj.__esModule ? obj : {
58
64
  default: obj
59
65
  };
60
66
  }
67
+ const MULTIPART_TYPE = 'multipart/form-data';
61
68
  const debug = require('debug')('expo:start:server:middleware:ExpoGoManifestHandlerMiddleware');
69
+ let multipartMixedContentType = _multitars().multipartContentType;
70
+ if (multipartMixedContentType.startsWith(MULTIPART_TYPE)) {
71
+ multipartMixedContentType = 'multipart/mixed' + multipartMixedContentType.slice(MULTIPART_TYPE.length);
72
+ }
62
73
  var ResponseContentType = /*#__PURE__*/ function(ResponseContentType) {
63
74
  ResponseContentType[ResponseContentType["TEXT_PLAIN"] = 0] = "TEXT_PLAIN";
64
75
  ResponseContentType[ResponseContentType["APPLICATION_JSON"] = 1] = "APPLICATION_JSON";
@@ -111,10 +122,10 @@ class ExpoGoManifestHandlerMiddleware extends _ManifestMiddleware.ManifestMiddle
111
122
  };
112
123
  }
113
124
  getDefaultResponseHeaders() {
114
- const headers = new Map();
125
+ const headers = new Headers();
115
126
  // set required headers for Expo Updates manifest specification
116
- headers.set('expo-protocol-version', 0);
117
- headers.set('expo-sfv-version', 0);
127
+ headers.set('expo-protocol-version', '0');
128
+ headers.set('expo-sfv-version', '0');
118
129
  headers.set('cache-control', 'private, max-age=0');
119
130
  return headers;
120
131
  }
@@ -166,7 +177,7 @@ class ExpoGoManifestHandlerMiddleware extends _ManifestMiddleware.ManifestMiddle
166
177
  }
167
178
  };
168
179
  const stringifiedManifest = JSON.stringify(expoUpdatesManifest);
169
- let manifestPartHeaders = null;
180
+ let manifestPartHeaders;
170
181
  let certificateChainBody = null;
171
182
  if (codeSigningInfo) {
172
183
  const signature = (0, _codesigning.signManifestString)(stringifiedManifest, codeSigningInfo);
@@ -179,37 +190,28 @@ class ExpoGoManifestHandlerMiddleware extends _ManifestMiddleware.ManifestMiddle
179
190
  };
180
191
  certificateChainBody = codeSigningInfo.certificateChainForResponse.join('\n');
181
192
  }
182
- const headers = this.getDefaultResponseHeaders();
183
193
  switch(requestOptions.responseContentType){
184
194
  case 3:
185
195
  {
186
- const encoded = await this.encodeFormDataAsync({
196
+ return this.encodeFormDataAsync({
187
197
  stringifiedManifest,
188
198
  manifestPartHeaders,
189
199
  certificateChainBody
190
200
  });
191
- headers.set('content-type', `multipart/mixed; boundary=${encoded.boundary}`);
192
- return {
193
- body: encoded.body,
194
- version: runtimeVersion,
195
- headers
196
- };
197
201
  }
198
202
  case 2:
199
203
  case 1:
200
204
  case 0:
201
205
  {
206
+ const headers = this.getDefaultResponseHeaders();
202
207
  headers.set('content-type', ExpoGoManifestHandlerMiddleware.getContentTypeForResponseContentType(requestOptions.responseContentType));
203
- if (manifestPartHeaders) {
204
- Object.entries(manifestPartHeaders).forEach(([key, value])=>{
205
- headers.set(key, value);
206
- });
208
+ if (manifestPartHeaders == null ? void 0 : manifestPartHeaders['expo-signature']) {
209
+ headers.set('expo-signature', manifestPartHeaders['expo-signature']);
207
210
  }
208
- return {
209
- body: stringifiedManifest,
210
- version: runtimeVersion,
211
+ return new Response(stringifiedManifest, {
212
+ status: 200,
211
213
  headers
212
- };
214
+ });
213
215
  }
214
216
  }
215
217
  }
@@ -226,22 +228,33 @@ class ExpoGoManifestHandlerMiddleware extends _ManifestMiddleware.ManifestMiddle
226
228
  }
227
229
  }
228
230
  encodeFormDataAsync({ stringifiedManifest, manifestPartHeaders, certificateChainBody }) {
229
- const fields = [
230
- {
231
- name: 'manifest',
232
- value: stringifiedManifest,
233
- contentType: 'application/json',
234
- partHeaders: manifestPartHeaders
235
- }
231
+ const parts = [
232
+ [
233
+ 'manifest',
234
+ new (_multitars()).MultipartPart([
235
+ stringifiedManifest
236
+ ], 'manifest', {
237
+ type: 'application/json',
238
+ headers: manifestPartHeaders
239
+ })
240
+ ]
236
241
  ];
237
242
  if (certificateChainBody && certificateChainBody.length > 0) {
238
- fields.push({
239
- name: 'certificate_chain',
240
- value: certificateChainBody,
241
- contentType: 'application/x-pem-file'
242
- });
243
+ parts.push([
244
+ 'certificate_chain',
245
+ new (_multitars()).MultipartPart([
246
+ certificateChainBody
247
+ ], 'certificate_chain', {
248
+ type: 'application/x-pem-file'
249
+ })
250
+ ]);
243
251
  }
244
- return (0, _multipartMixed.encodeMultipartMixed)(fields);
252
+ const headers = this.getDefaultResponseHeaders();
253
+ headers.set('Content-Type', multipartMixedContentType);
254
+ return new Response((0, _multitars().iterableToStream)((0, _multitars().streamMultipart)(parts)), {
255
+ status: 200,
256
+ headers
257
+ });
245
258
  }
246
259
  static async getScopeKeyAsync({ slug, codeSigningInfo }) {
247
260
  const scopeKeyFromCodeSigningInfo = codeSigningInfo == null ? void 0 : codeSigningInfo.scopeKey;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/start/server/middleware/ExpoGoManifestHandlerMiddleware.ts"],"sourcesContent":["import { ExpoUpdatesManifest } from '@expo/config';\nimport { Updates } from '@expo/config-plugins';\nimport accepts from 'accepts';\nimport crypto from 'crypto';\nimport { serializeDictionary, Dictionary } from 'structured-headers';\n\nimport { ManifestMiddleware, ManifestRequestInfo } from './ManifestMiddleware';\nimport { assertRuntimePlatform, parsePlatformHeader } from './resolvePlatform';\nimport { resolveRuntimeVersionWithExpoUpdatesAsync } from './resolveRuntimeVersionWithExpoUpdatesAsync';\nimport { ServerHeaders, ServerRequest } from './server.types';\nimport { getAnonymousIdAsync } from '../../../api/user/UserSettings';\nimport { ANONYMOUS_USERNAME } from '../../../api/user/user';\nimport {\n CodeSigningInfo,\n getCodeSigningInfoAsync,\n signManifestString,\n} from '../../../utils/codesigning';\nimport { CommandError } from '../../../utils/errors';\nimport {\n encodeMultipartMixed,\n FormDataField,\n EncodedFormData,\n} from '../../../utils/multipartMixed';\nimport { stripPort } from '../../../utils/url';\n\nconst debug = require('debug')('expo:start:server:middleware:ExpoGoManifestHandlerMiddleware');\n\nexport enum ResponseContentType {\n TEXT_PLAIN,\n APPLICATION_JSON,\n APPLICATION_EXPO_JSON,\n MULTIPART_MIXED,\n}\n\ninterface ExpoGoManifestRequestInfo extends ManifestRequestInfo {\n responseContentType: ResponseContentType;\n expectSignature: string | null;\n}\n\nexport class ExpoGoManifestHandlerMiddleware extends ManifestMiddleware<ExpoGoManifestRequestInfo> {\n public getParsedHeaders(req: ServerRequest): ExpoGoManifestRequestInfo {\n let platform = parsePlatformHeader(req);\n\n if (!platform) {\n debug(\n `No \"expo-platform\" header or \"platform\" query parameter specified. Falling back to \"ios\".`\n );\n platform = 'ios';\n }\n\n assertRuntimePlatform(platform);\n\n // Expo Updates clients explicitly accept \"multipart/mixed\" responses while browsers implicitly\n // accept them with \"accept: */*\". To make it easier to debug manifest responses by visiting their\n // URLs in a browser, we denote the response as \"text/plain\" if the user agent appears not to be\n // an Expo Updates client.\n const accept = accepts(req);\n const acceptedType = accept.types([\n 'unknown/unknown',\n 'multipart/mixed',\n 'application/json',\n 'application/expo+json',\n 'text/plain',\n ]);\n\n let responseContentType;\n switch (acceptedType) {\n case 'multipart/mixed':\n responseContentType = ResponseContentType.MULTIPART_MIXED;\n break;\n case 'application/json':\n responseContentType = ResponseContentType.APPLICATION_JSON;\n break;\n case 'application/expo+json':\n responseContentType = ResponseContentType.APPLICATION_EXPO_JSON;\n break;\n default:\n responseContentType = ResponseContentType.TEXT_PLAIN;\n break;\n }\n\n const expectSignature = req.headers['expo-expect-signature'];\n\n return {\n responseContentType,\n platform,\n expectSignature: expectSignature ? String(expectSignature) : null,\n hostname: stripPort(req.headers['host']),\n protocol: req.headers['x-forwarded-proto'] as 'http' | 'https' | undefined,\n };\n }\n\n private getDefaultResponseHeaders(): ServerHeaders {\n const headers = new Map<string, number | string | readonly string[]>();\n // set required headers for Expo Updates manifest specification\n headers.set('expo-protocol-version', 0);\n headers.set('expo-sfv-version', 0);\n headers.set('cache-control', 'private, max-age=0');\n return headers;\n }\n\n public async _getManifestResponseAsync(requestOptions: ExpoGoManifestRequestInfo): Promise<{\n body: string;\n version: string;\n headers: ServerHeaders;\n }> {\n const { exp, hostUri, expoGoConfig, bundleUrl } =\n await this._resolveProjectSettingsAsync(requestOptions);\n\n const runtimeVersion =\n (await resolveRuntimeVersionWithExpoUpdatesAsync({\n projectRoot: this.projectRoot,\n platform: requestOptions.platform,\n })) ??\n // if expo-updates can't determine runtime version, fall back to calculation from config-plugin.\n // this happens when expo-updates is installed but runtimeVersion hasn't yet been configured or when\n // expo-updates is not installed.\n (await Updates.getRuntimeVersionAsync(\n this.projectRoot,\n { ...exp, runtimeVersion: exp.runtimeVersion ?? { policy: 'sdkVersion' } },\n requestOptions.platform\n ));\n if (!runtimeVersion) {\n throw new CommandError(\n 'MANIFEST_MIDDLEWARE',\n `Unable to determine runtime version for platform '${requestOptions.platform}'`\n );\n }\n\n const codeSigningInfo = await getCodeSigningInfoAsync(\n exp,\n requestOptions.expectSignature,\n this.options.privateKeyPath\n );\n\n const easProjectId = exp.extra?.eas?.projectId as string | undefined | null;\n const scopeKey = await ExpoGoManifestHandlerMiddleware.getScopeKeyAsync({\n slug: exp.slug,\n codeSigningInfo,\n });\n\n const expoUpdatesManifest: ExpoUpdatesManifest = {\n id: crypto.randomUUID(),\n createdAt: new Date().toISOString(),\n runtimeVersion,\n launchAsset: {\n key: 'bundle',\n contentType: 'application/javascript',\n url: bundleUrl,\n },\n assets: [], // assets are not used in development\n metadata: {}, // required for the client to detect that this is an expo-updates manifest\n extra: {\n eas: {\n projectId: easProjectId ?? undefined,\n },\n expoClient: {\n ...exp,\n hostUri,\n },\n expoGo: expoGoConfig,\n scopeKey,\n },\n };\n\n const stringifiedManifest = JSON.stringify(expoUpdatesManifest);\n\n let manifestPartHeaders: { 'expo-signature': string } | null = null;\n let certificateChainBody: string | null = null;\n if (codeSigningInfo) {\n const signature = signManifestString(stringifiedManifest, codeSigningInfo);\n manifestPartHeaders = {\n 'expo-signature': serializeDictionary(\n convertToDictionaryItemsRepresentation({\n keyid: codeSigningInfo.keyId,\n sig: signature,\n alg: 'rsa-v1_5-sha256',\n })\n ),\n };\n certificateChainBody = codeSigningInfo.certificateChainForResponse.join('\\n');\n }\n\n const headers = this.getDefaultResponseHeaders();\n\n switch (requestOptions.responseContentType) {\n case ResponseContentType.MULTIPART_MIXED: {\n const encoded = await this.encodeFormDataAsync({\n stringifiedManifest,\n manifestPartHeaders,\n certificateChainBody,\n });\n headers.set('content-type', `multipart/mixed; boundary=${encoded.boundary}`);\n return {\n body: encoded.body,\n version: runtimeVersion,\n headers,\n };\n }\n case ResponseContentType.APPLICATION_EXPO_JSON:\n case ResponseContentType.APPLICATION_JSON:\n case ResponseContentType.TEXT_PLAIN: {\n headers.set(\n 'content-type',\n ExpoGoManifestHandlerMiddleware.getContentTypeForResponseContentType(\n requestOptions.responseContentType\n )\n );\n if (manifestPartHeaders) {\n Object.entries(manifestPartHeaders).forEach(([key, value]) => {\n headers.set(key, value);\n });\n }\n\n return {\n body: stringifiedManifest,\n version: runtimeVersion,\n headers,\n };\n }\n }\n }\n\n private static getContentTypeForResponseContentType(\n responseContentType: ResponseContentType\n ): string {\n switch (responseContentType) {\n case ResponseContentType.MULTIPART_MIXED:\n return 'multipart/mixed';\n case ResponseContentType.APPLICATION_EXPO_JSON:\n return 'application/expo+json';\n case ResponseContentType.APPLICATION_JSON:\n return 'application/json';\n case ResponseContentType.TEXT_PLAIN:\n return 'text/plain';\n }\n }\n\n private encodeFormDataAsync({\n stringifiedManifest,\n manifestPartHeaders,\n certificateChainBody,\n }: {\n stringifiedManifest: string;\n manifestPartHeaders: { 'expo-signature': string } | null;\n certificateChainBody: string | null;\n }): Promise<EncodedFormData> {\n const fields: FormDataField[] = [\n {\n name: 'manifest',\n value: stringifiedManifest,\n contentType: 'application/json',\n partHeaders: manifestPartHeaders,\n },\n ];\n if (certificateChainBody && certificateChainBody.length > 0) {\n fields.push({\n name: 'certificate_chain',\n value: certificateChainBody,\n contentType: 'application/x-pem-file',\n });\n }\n return encodeMultipartMixed(fields);\n }\n\n private static async getScopeKeyAsync({\n slug,\n codeSigningInfo,\n }: {\n slug: string;\n codeSigningInfo: CodeSigningInfo | null;\n }): Promise<string> {\n const scopeKeyFromCodeSigningInfo = codeSigningInfo?.scopeKey;\n if (scopeKeyFromCodeSigningInfo) {\n return scopeKeyFromCodeSigningInfo;\n }\n\n // Log.warn(\n // env.EXPO_OFFLINE\n // ? 'Using anonymous scope key in manifest for offline mode.'\n // : 'Using anonymous scope key in manifest.'\n // );\n return await getAnonymousScopeKeyAsync(slug);\n }\n}\n\nasync function getAnonymousScopeKeyAsync(slug: string): Promise<string> {\n const userAnonymousIdentifier = await getAnonymousIdAsync();\n return `@${ANONYMOUS_USERNAME}/${slug}-${userAnonymousIdentifier}`;\n}\n\nfunction convertToDictionaryItemsRepresentation(obj: { [key: string]: string }): Dictionary {\n return new Map(\n Object.entries(obj).map(([k, v]) => {\n return [k, [v, new Map()]];\n })\n );\n}\n"],"names":["ExpoGoManifestHandlerMiddleware","ResponseContentType","debug","require","ManifestMiddleware","getParsedHeaders","req","platform","parsePlatformHeader","assertRuntimePlatform","accept","accepts","acceptedType","types","responseContentType","expectSignature","headers","String","hostname","stripPort","protocol","getDefaultResponseHeaders","Map","set","_getManifestResponseAsync","requestOptions","exp","hostUri","expoGoConfig","bundleUrl","_resolveProjectSettingsAsync","runtimeVersion","resolveRuntimeVersionWithExpoUpdatesAsync","projectRoot","Updates","getRuntimeVersionAsync","policy","CommandError","codeSigningInfo","getCodeSigningInfoAsync","options","privateKeyPath","easProjectId","extra","eas","projectId","scopeKey","getScopeKeyAsync","slug","expoUpdatesManifest","id","crypto","randomUUID","createdAt","Date","toISOString","launchAsset","key","contentType","url","assets","metadata","undefined","expoClient","expoGo","stringifiedManifest","JSON","stringify","manifestPartHeaders","certificateChainBody","signature","signManifestString","serializeDictionary","convertToDictionaryItemsRepresentation","keyid","keyId","sig","alg","certificateChainForResponse","join","encoded","encodeFormDataAsync","boundary","body","version","getContentTypeForResponseContentType","Object","entries","forEach","value","fields","name","partHeaders","length","push","encodeMultipartMixed","scopeKeyFromCodeSigningInfo","getAnonymousScopeKeyAsync","userAnonymousIdentifier","getAnonymousIdAsync","ANONYMOUS_USERNAME","obj","map","k","v"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/start/server/middleware/ExpoGoManifestHandlerMiddleware.ts"],"sourcesContent":["import { ExpoUpdatesManifest } from '@expo/config';\nimport { Updates } from '@expo/config-plugins';\nimport accepts from 'accepts';\nimport crypto from 'crypto';\nimport {\n iterableToStream,\n streamMultipart,\n multipartContentType,\n FormEntry,\n MultipartPart,\n} from 'multitars';\nimport { serializeDictionary, Dictionary } from 'structured-headers';\n\nimport { ManifestMiddleware, ManifestRequestInfo } from './ManifestMiddleware';\nimport { assertRuntimePlatform, parsePlatformHeader } from './resolvePlatform';\nimport { resolveRuntimeVersionWithExpoUpdatesAsync } from './resolveRuntimeVersionWithExpoUpdatesAsync';\nimport { ServerRequest } from './server.types';\nimport { getAnonymousIdAsync } from '../../../api/user/UserSettings';\nimport { ANONYMOUS_USERNAME } from '../../../api/user/user';\nimport {\n CodeSigningInfo,\n getCodeSigningInfoAsync,\n signManifestString,\n} from '../../../utils/codesigning';\nimport { CommandError } from '../../../utils/errors';\nimport { stripPort } from '../../../utils/url';\n\nconst MULTIPART_TYPE = 'multipart/form-data';\n\nconst debug = require('debug')('expo:start:server:middleware:ExpoGoManifestHandlerMiddleware');\n\nlet multipartMixedContentType = multipartContentType;\nif (multipartMixedContentType.startsWith(MULTIPART_TYPE)) {\n multipartMixedContentType =\n 'multipart/mixed' + multipartMixedContentType.slice(MULTIPART_TYPE.length);\n}\n\nexport enum ResponseContentType {\n TEXT_PLAIN,\n APPLICATION_JSON,\n APPLICATION_EXPO_JSON,\n MULTIPART_MIXED,\n}\n\ninterface ExpoGoManifestRequestInfo extends ManifestRequestInfo {\n responseContentType: ResponseContentType;\n expectSignature: string | null;\n}\n\nexport class ExpoGoManifestHandlerMiddleware extends ManifestMiddleware<ExpoGoManifestRequestInfo> {\n public getParsedHeaders(req: ServerRequest): ExpoGoManifestRequestInfo {\n let platform = parsePlatformHeader(req);\n\n if (!platform) {\n debug(\n `No \"expo-platform\" header or \"platform\" query parameter specified. Falling back to \"ios\".`\n );\n platform = 'ios';\n }\n\n assertRuntimePlatform(platform);\n\n // Expo Updates clients explicitly accept \"multipart/mixed\" responses while browsers implicitly\n // accept them with \"accept: */*\". To make it easier to debug manifest responses by visiting their\n // URLs in a browser, we denote the response as \"text/plain\" if the user agent appears not to be\n // an Expo Updates client.\n const accept = accepts(req);\n const acceptedType = accept.types([\n 'unknown/unknown',\n 'multipart/mixed',\n 'application/json',\n 'application/expo+json',\n 'text/plain',\n ]);\n\n let responseContentType;\n switch (acceptedType) {\n case 'multipart/mixed':\n responseContentType = ResponseContentType.MULTIPART_MIXED;\n break;\n case 'application/json':\n responseContentType = ResponseContentType.APPLICATION_JSON;\n break;\n case 'application/expo+json':\n responseContentType = ResponseContentType.APPLICATION_EXPO_JSON;\n break;\n default:\n responseContentType = ResponseContentType.TEXT_PLAIN;\n break;\n }\n\n const expectSignature = req.headers['expo-expect-signature'];\n\n return {\n responseContentType,\n platform,\n expectSignature: expectSignature ? String(expectSignature) : null,\n hostname: stripPort(req.headers['host']),\n protocol: req.headers['x-forwarded-proto'] as 'http' | 'https' | undefined,\n };\n }\n\n private getDefaultResponseHeaders(): Headers {\n const headers = new Headers();\n // set required headers for Expo Updates manifest specification\n headers.set('expo-protocol-version', '0');\n headers.set('expo-sfv-version', '0');\n headers.set('cache-control', 'private, max-age=0');\n return headers;\n }\n\n public async _getManifestResponseAsync(\n requestOptions: ExpoGoManifestRequestInfo\n ): Promise<Response> {\n const { exp, hostUri, expoGoConfig, bundleUrl } =\n await this._resolveProjectSettingsAsync(requestOptions);\n\n const runtimeVersion =\n (await resolveRuntimeVersionWithExpoUpdatesAsync({\n projectRoot: this.projectRoot,\n platform: requestOptions.platform,\n })) ??\n // if expo-updates can't determine runtime version, fall back to calculation from config-plugin.\n // this happens when expo-updates is installed but runtimeVersion hasn't yet been configured or when\n // expo-updates is not installed.\n (await Updates.getRuntimeVersionAsync(\n this.projectRoot,\n { ...exp, runtimeVersion: exp.runtimeVersion ?? { policy: 'sdkVersion' } },\n requestOptions.platform\n ));\n if (!runtimeVersion) {\n throw new CommandError(\n 'MANIFEST_MIDDLEWARE',\n `Unable to determine runtime version for platform '${requestOptions.platform}'`\n );\n }\n\n const codeSigningInfo = await getCodeSigningInfoAsync(\n exp,\n requestOptions.expectSignature,\n this.options.privateKeyPath\n );\n\n const easProjectId = exp.extra?.eas?.projectId as string | undefined | null;\n const scopeKey = await ExpoGoManifestHandlerMiddleware.getScopeKeyAsync({\n slug: exp.slug,\n codeSigningInfo,\n });\n\n const expoUpdatesManifest: ExpoUpdatesManifest = {\n id: crypto.randomUUID(),\n createdAt: new Date().toISOString(),\n runtimeVersion,\n launchAsset: {\n key: 'bundle',\n contentType: 'application/javascript',\n url: bundleUrl,\n },\n assets: [], // assets are not used in development\n metadata: {}, // required for the client to detect that this is an expo-updates manifest\n extra: {\n eas: {\n projectId: easProjectId ?? undefined,\n },\n expoClient: {\n ...exp,\n hostUri,\n },\n expoGo: expoGoConfig,\n scopeKey,\n },\n };\n\n const stringifiedManifest = JSON.stringify(expoUpdatesManifest);\n\n let manifestPartHeaders: { 'expo-signature': string } | undefined;\n let certificateChainBody: string | null = null;\n if (codeSigningInfo) {\n const signature = signManifestString(stringifiedManifest, codeSigningInfo);\n manifestPartHeaders = {\n 'expo-signature': serializeDictionary(\n convertToDictionaryItemsRepresentation({\n keyid: codeSigningInfo.keyId,\n sig: signature,\n alg: 'rsa-v1_5-sha256',\n })\n ),\n };\n certificateChainBody = codeSigningInfo.certificateChainForResponse.join('\\n');\n }\n\n switch (requestOptions.responseContentType) {\n case ResponseContentType.MULTIPART_MIXED: {\n return this.encodeFormDataAsync({\n stringifiedManifest,\n manifestPartHeaders,\n certificateChainBody,\n });\n }\n case ResponseContentType.APPLICATION_EXPO_JSON:\n case ResponseContentType.APPLICATION_JSON:\n case ResponseContentType.TEXT_PLAIN: {\n const headers = this.getDefaultResponseHeaders();\n headers.set(\n 'content-type',\n ExpoGoManifestHandlerMiddleware.getContentTypeForResponseContentType(\n requestOptions.responseContentType\n )\n );\n if (manifestPartHeaders?.['expo-signature']) {\n headers.set('expo-signature', manifestPartHeaders['expo-signature']);\n }\n return new Response(stringifiedManifest, { status: 200, headers });\n }\n }\n }\n\n private static getContentTypeForResponseContentType(\n responseContentType: ResponseContentType\n ): string {\n switch (responseContentType) {\n case ResponseContentType.MULTIPART_MIXED:\n return 'multipart/mixed';\n case ResponseContentType.APPLICATION_EXPO_JSON:\n return 'application/expo+json';\n case ResponseContentType.APPLICATION_JSON:\n return 'application/json';\n case ResponseContentType.TEXT_PLAIN:\n return 'text/plain';\n }\n }\n\n private encodeFormDataAsync({\n stringifiedManifest,\n manifestPartHeaders,\n certificateChainBody,\n }: {\n stringifiedManifest: string;\n manifestPartHeaders: { 'expo-signature': string } | undefined;\n certificateChainBody: string | null;\n }): Response {\n const parts: FormEntry[] = [\n [\n 'manifest',\n new MultipartPart([stringifiedManifest], 'manifest', {\n type: 'application/json',\n headers: manifestPartHeaders,\n }),\n ],\n ];\n if (certificateChainBody && certificateChainBody.length > 0) {\n parts.push([\n 'certificate_chain',\n new MultipartPart([certificateChainBody], 'certificate_chain', {\n type: 'application/x-pem-file',\n }),\n ]);\n }\n const headers = this.getDefaultResponseHeaders();\n headers.set('Content-Type', multipartMixedContentType);\n return new Response(iterableToStream(streamMultipart(parts)), { status: 200, headers });\n }\n\n private static async getScopeKeyAsync({\n slug,\n codeSigningInfo,\n }: {\n slug: string;\n codeSigningInfo: CodeSigningInfo | null;\n }): Promise<string> {\n const scopeKeyFromCodeSigningInfo = codeSigningInfo?.scopeKey;\n if (scopeKeyFromCodeSigningInfo) {\n return scopeKeyFromCodeSigningInfo;\n }\n\n // Log.warn(\n // env.EXPO_OFFLINE\n // ? 'Using anonymous scope key in manifest for offline mode.'\n // : 'Using anonymous scope key in manifest.'\n // );\n return await getAnonymousScopeKeyAsync(slug);\n }\n}\n\nasync function getAnonymousScopeKeyAsync(slug: string): Promise<string> {\n const userAnonymousIdentifier = await getAnonymousIdAsync();\n return `@${ANONYMOUS_USERNAME}/${slug}-${userAnonymousIdentifier}`;\n}\n\nfunction convertToDictionaryItemsRepresentation(obj: { [key: string]: string }): Dictionary {\n return new Map(\n Object.entries(obj).map(([k, v]) => {\n return [k, [v, new Map()]];\n })\n );\n}\n"],"names":["ExpoGoManifestHandlerMiddleware","ResponseContentType","MULTIPART_TYPE","debug","require","multipartMixedContentType","multipartContentType","startsWith","slice","length","ManifestMiddleware","getParsedHeaders","req","platform","parsePlatformHeader","assertRuntimePlatform","accept","accepts","acceptedType","types","responseContentType","expectSignature","headers","String","hostname","stripPort","protocol","getDefaultResponseHeaders","Headers","set","_getManifestResponseAsync","requestOptions","exp","hostUri","expoGoConfig","bundleUrl","_resolveProjectSettingsAsync","runtimeVersion","resolveRuntimeVersionWithExpoUpdatesAsync","projectRoot","Updates","getRuntimeVersionAsync","policy","CommandError","codeSigningInfo","getCodeSigningInfoAsync","options","privateKeyPath","easProjectId","extra","eas","projectId","scopeKey","getScopeKeyAsync","slug","expoUpdatesManifest","id","crypto","randomUUID","createdAt","Date","toISOString","launchAsset","key","contentType","url","assets","metadata","undefined","expoClient","expoGo","stringifiedManifest","JSON","stringify","manifestPartHeaders","certificateChainBody","signature","signManifestString","serializeDictionary","convertToDictionaryItemsRepresentation","keyid","keyId","sig","alg","certificateChainForResponse","join","encodeFormDataAsync","getContentTypeForResponseContentType","Response","status","parts","MultipartPart","type","push","iterableToStream","streamMultipart","scopeKeyFromCodeSigningInfo","getAnonymousScopeKeyAsync","userAnonymousIdentifier","getAnonymousIdAsync","ANONYMOUS_USERNAME","obj","Map","Object","entries","map","k","v"],"mappings":"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"}
@@ -36,6 +36,20 @@ function _paths() {
36
36
  };
37
37
  return data;
38
38
  }
39
+ function _nodestream() {
40
+ const data = require("node:stream");
41
+ _nodestream = function() {
42
+ return data;
43
+ };
44
+ return data;
45
+ }
46
+ function _promises() {
47
+ const data = require("node:stream/promises");
48
+ _promises = function() {
49
+ return data;
50
+ };
51
+ return data;
52
+ }
39
53
  function _path() {
40
54
  const data = /*#__PURE__*/ _interop_require_default(require("path"));
41
55
  _path = function() {
@@ -328,11 +342,20 @@ class ManifestMiddleware extends _ExpoMiddleware.ExpoMiddleware {
328
342
  await this.saveDevicesAsync(req);
329
343
  // Read from headers
330
344
  const options = this.getParsedHeaders(req);
331
- const { body, headers } = await this._getManifestResponseAsync(options);
332
- for (const [headerName, headerValue] of headers){
333
- res.setHeader(headerName, headerValue);
345
+ const response = await this._getManifestResponseAsync(options);
346
+ // Convert `Response` to node:http response
347
+ if (typeof res.setHeaders === 'function') {
348
+ res.setHeaders(response.headers);
349
+ } else {
350
+ for (const [key, value] of response.headers.entries()){
351
+ res.appendHeader(key, value);
352
+ }
353
+ }
354
+ if (response.body) {
355
+ await (0, _promises().pipeline)(_nodestream().Readable.fromWeb(response.body), res);
356
+ } else {
357
+ res.end();
334
358
  }
335
- res.end(body);
336
359
  }
337
360
  }
338
361
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/start/server/middleware/ManifestMiddleware.ts"],"sourcesContent":["import {\n ExpoConfig,\n ExpoGoConfig,\n getConfig,\n PackageJSONConfig,\n ProjectConfig,\n} from '@expo/config';\nimport { resolveEntryPoint, getMetroServerRoot } from '@expo/config/paths';\nimport path from 'path';\nimport { resolve } from 'url';\n\nimport { ExpoMiddleware } from './ExpoMiddleware';\nimport {\n createBundleUrlPath,\n getBaseUrlFromExpoConfig,\n getAsyncRoutesFromExpoConfig,\n createBundleUrlPathFromExpoConfig,\n convertPathToModuleSpecifier,\n} from './metroOptions';\nimport { resolveGoogleServicesFile, resolveManifestAssets } from './resolveAssets';\nimport { parsePlatformHeader, RuntimePlatform } from './resolvePlatform';\nimport { ServerHeaders, ServerNext, ServerRequest, ServerResponse } from './server.types';\nimport { isEnableHermesManaged } from '../../../export/exportHermes';\nimport * as Log from '../../../log';\nimport { env } from '../../../utils/env';\nimport { CommandError } from '../../../utils/errors';\nimport { stripExtension } from '../../../utils/url';\nimport * as ProjectDevices from '../../project/devices';\nimport { UrlCreator } from '../UrlCreator';\nimport { getRouterDirectoryModuleIdWithManifest } from '../metro/router';\nimport { getPlatformBundlers, PlatformBundlers } from '../platformBundlers';\nimport { createTemplateHtmlFromExpoConfigAsync } from '../webTemplate';\n\nconst debug = require('debug')('expo:start:server:middleware:manifest') as typeof console.log;\n\nconst supportedPlatforms = ['ios', 'android', 'web', 'none'];\n\nexport function getEntryWithServerRoot(\n projectRoot: string,\n props: { platform: string; pkg?: PackageJSONConfig }\n) {\n if (!supportedPlatforms.includes(props.platform)) {\n throw new CommandError(\n `Failed to resolve the project's entry file: The platform \"${props.platform}\" is not supported.`\n );\n }\n return convertPathToModuleSpecifier(\n path.relative(getMetroServerRoot(projectRoot), resolveEntryPoint(projectRoot, props))\n );\n}\n\n/** Get the main entry module ID (file) relative to the project root. */\nexport function resolveMainModuleName(\n projectRoot: string,\n props: { platform: string; pkg?: PackageJSONConfig }\n): string {\n const entryPoint = getEntryWithServerRoot(projectRoot, props);\n\n debug(`Resolved entry point: ${entryPoint} (project root: ${projectRoot})`);\n\n return convertPathToModuleSpecifier(stripExtension(entryPoint, 'js'));\n}\n\n/** Info about the computer hosting the dev server. */\nexport interface HostInfo {\n host: string;\n server: 'expo';\n serverVersion: string;\n serverDriver: string | null;\n serverOS: NodeJS.Platform;\n serverOSVersion: string;\n}\n\n/** Parsed values from the supported request headers. */\nexport interface ManifestRequestInfo {\n /** Platform to serve. */\n platform: RuntimePlatform;\n /** Requested host name. */\n hostname?: string | null;\n /** The protocol used to request the manifest */\n protocol?: 'http' | 'https';\n}\n\n/** Project related info. */\nexport type ResponseProjectSettings = {\n expoGoConfig: ExpoGoConfig;\n hostUri: string;\n bundleUrl: string;\n exp: ExpoConfig;\n};\n\nexport const DEVELOPER_TOOL = 'expo-cli';\n\nexport type ManifestMiddlewareOptions = {\n /** Should start the dev servers in development mode (minify). */\n mode?: 'development' | 'production';\n /** Should instruct the bundler to create minified bundles. */\n minify?: boolean;\n constructUrl: UrlCreator['constructUrl'];\n isNativeWebpack?: boolean;\n privateKeyPath?: string;\n};\n\n/** Base middleware creator for serving the Expo manifest (like the index.html but for native runtimes). */\nexport abstract class ManifestMiddleware<\n TManifestRequestInfo extends ManifestRequestInfo,\n> extends ExpoMiddleware {\n private initialProjectConfig: ProjectConfig;\n private platformBundlers: PlatformBundlers;\n\n constructor(\n protected projectRoot: string,\n protected options: ManifestMiddlewareOptions\n ) {\n super(\n projectRoot,\n /**\n * Only support `/`, `/manifest`, `/index.exp` for the manifest middleware.\n */\n ['/', '/manifest', '/index.exp']\n );\n this.initialProjectConfig = getConfig(projectRoot);\n this.platformBundlers = getPlatformBundlers(projectRoot, this.initialProjectConfig.exp);\n }\n\n /** Exposed for testing. */\n public async _resolveProjectSettingsAsync({\n platform,\n hostname,\n protocol,\n }: Pick<\n TManifestRequestInfo,\n 'hostname' | 'platform' | 'protocol'\n >): Promise<ResponseProjectSettings> {\n // Read the config\n const projectConfig = getConfig(this.projectRoot);\n\n // Read from headers\n const mainModuleName = this.resolveMainModuleName({\n pkg: projectConfig.pkg,\n platform,\n });\n\n const isHermesEnabled = isEnableHermesManaged(projectConfig.exp, platform);\n\n // Create the manifest and set fields within it\n const expoGoConfig = this.getExpoGoConfig({\n mainModuleName,\n hostname,\n });\n\n const hostUri = this.options.constructUrl({ scheme: '', hostname });\n\n const bundleUrl = this._getBundleUrl({\n platform,\n mainModuleName,\n hostname,\n engine: isHermesEnabled ? 'hermes' : undefined,\n baseUrl: getBaseUrlFromExpoConfig(projectConfig.exp),\n asyncRoutes: getAsyncRoutesFromExpoConfig(\n projectConfig.exp,\n this.options.mode ?? 'development',\n platform\n ),\n routerRoot: getRouterDirectoryModuleIdWithManifest(this.projectRoot, projectConfig.exp),\n protocol,\n reactCompiler: !!projectConfig.exp.experiments?.reactCompiler,\n });\n\n // Resolve all assets and set them on the manifest as URLs\n await this.mutateManifestWithAssetsAsync(projectConfig.exp, bundleUrl);\n\n return {\n expoGoConfig,\n hostUri,\n bundleUrl,\n exp: projectConfig.exp,\n };\n }\n\n /** Get the main entry module ID (file) relative to the project root. */\n private resolveMainModuleName(props: { pkg: PackageJSONConfig; platform: string }): string {\n let entryPoint = getEntryWithServerRoot(this.projectRoot, props);\n\n debug(`Resolved entry point: ${entryPoint} (project root: ${this.projectRoot})`);\n\n // NOTE(Bacon): Webpack is currently hardcoded to index.bundle on native\n // in the future (TODO) we should move this logic into a Webpack plugin and use\n // a generated file name like we do on web.\n // const server = getDefaultDevServer();\n // // TODO: Move this into BundlerDevServer and read this info from self.\n // const isNativeWebpack = server instanceof WebpackBundlerDevServer && server.isTargetingNative();\n if (this.options.isNativeWebpack) {\n entryPoint = 'index.js';\n }\n\n return stripExtension(entryPoint, 'js');\n }\n\n /** Parse request headers into options. */\n public abstract getParsedHeaders(req: ServerRequest): TManifestRequestInfo;\n\n /** Store device IDs that were sent in the request headers. */\n private async saveDevicesAsync(req: ServerRequest) {\n const deviceIds = req.headers?.['expo-dev-client-id'];\n if (deviceIds) {\n await ProjectDevices.saveDevicesAsync(this.projectRoot, deviceIds).catch((e) =>\n Log.exception(e)\n );\n }\n }\n\n /** Create the bundle URL (points to the single JS entry file). Exposed for testing. */\n public _getBundleUrl({\n platform,\n mainModuleName,\n hostname,\n engine,\n baseUrl,\n isExporting,\n asyncRoutes,\n routerRoot,\n protocol,\n reactCompiler,\n }: {\n platform: string;\n hostname?: string | null;\n mainModuleName: string;\n engine?: 'hermes';\n baseUrl?: string;\n asyncRoutes: boolean;\n isExporting?: boolean;\n routerRoot: string;\n protocol?: 'http' | 'https';\n reactCompiler: boolean;\n }): string {\n const path = createBundleUrlPath({\n mode: this.options.mode ?? 'development',\n minify: this.options.minify,\n platform,\n mainModuleName,\n lazy: !env.EXPO_NO_METRO_LAZY,\n engine,\n bytecode: engine === 'hermes',\n baseUrl,\n isExporting: !!isExporting,\n asyncRoutes,\n routerRoot,\n reactCompiler,\n });\n\n return (\n this.options.constructUrl({\n scheme: protocol ?? 'http',\n // hostType: this.options.location.hostType,\n hostname,\n }) + path\n );\n }\n\n /** Get the manifest response to return to the runtime. This file contains info regarding where the assets can be loaded from. Exposed for testing. */\n public abstract _getManifestResponseAsync(options: TManifestRequestInfo): Promise<{\n body: string;\n version: string;\n headers: ServerHeaders;\n }>;\n\n private getExpoGoConfig({\n mainModuleName,\n hostname,\n }: {\n mainModuleName: string;\n hostname?: string | null;\n }): ExpoGoConfig {\n return {\n // localhost:8081\n debuggerHost: this.options.constructUrl({ scheme: '', hostname }),\n // Required for Expo Go to function.\n developer: {\n tool: DEVELOPER_TOOL,\n projectRoot: this.projectRoot,\n },\n packagerOpts: {\n // Required for dev client.\n dev: this.options.mode !== 'production',\n },\n // Indicates the name of the main bundle.\n mainModuleName,\n };\n }\n\n /** Resolve all assets and set them on the manifest as URLs */\n private async mutateManifestWithAssetsAsync(manifest: ExpoConfig, bundleUrl: string) {\n await resolveManifestAssets(this.projectRoot, {\n manifest,\n resolver: async (path) => {\n if (this.options.isNativeWebpack) {\n // When using our custom dev server, just do assets normally\n // without the `assets/` subpath redirect.\n return resolve(bundleUrl!.match(/^https?:\\/\\/.*?\\//)![0], path);\n }\n return bundleUrl!.match(/^https?:\\/\\/.*?\\//)![0] + 'assets/' + path;\n },\n });\n // The server normally inserts this but if we're offline we'll do it here\n await resolveGoogleServicesFile(this.projectRoot, manifest);\n }\n\n public getWebBundleUrl() {\n const platform = 'web';\n // Read from headers\n const mainModuleName = this.resolveMainModuleName({\n pkg: this.initialProjectConfig.pkg,\n platform,\n });\n\n return createBundleUrlPathFromExpoConfig(this.projectRoot, this.initialProjectConfig.exp, {\n platform,\n mainModuleName,\n minify: this.options.minify,\n lazy: !env.EXPO_NO_METRO_LAZY,\n mode: this.options.mode ?? 'development',\n // Hermes doesn't support more modern JS features than most, if not all, modern browser.\n engine: 'hermes',\n isExporting: false,\n bytecode: false,\n });\n }\n\n /**\n * Web platforms should create an index.html response using the same script resolution as native.\n *\n * Instead of adding a `bundleUrl` to a `manifest.json` (native) we'll add a `<script src=\"\">`\n * to an `index.html`, this enables the web platform to load JavaScript from the server.\n */\n private async handleWebRequestAsync(req: ServerRequest, res: ServerResponse) {\n res.setHeader('Content-Type', 'text/html');\n\n res.end(await this.getSingleHtmlTemplateAsync());\n }\n\n getSingleHtmlTemplateAsync() {\n // Read from headers\n const bundleUrl = this.getWebBundleUrl();\n\n return createTemplateHtmlFromExpoConfigAsync(this.projectRoot, {\n exp: this.initialProjectConfig.exp,\n scripts: [bundleUrl],\n });\n }\n\n /** Exposed for testing. */\n async checkBrowserRequestAsync(req: ServerRequest, res: ServerResponse, next: ServerNext) {\n if (\n this.platformBundlers.web === 'metro' &&\n this.initialProjectConfig.exp.platforms?.includes('web')\n ) {\n // NOTE(EvanBacon): This effectively disables the safety check we do on custom runtimes to ensure\n // the `expo-platform` header is included. When `web.bundler=web`, if the user has non-standard Expo\n // code loading then they'll get a web bundle without a clear assertion of platform support.\n const platform = parsePlatformHeader(req);\n // On web, serve the public folder\n if (!platform || platform === 'web') {\n if (['static', 'server'].includes(this.initialProjectConfig.exp.web?.output ?? '')) {\n // Skip the spa-styled index.html when static generation is enabled.\n next();\n return true;\n } else {\n await this.handleWebRequestAsync(req, res);\n return true;\n }\n }\n }\n return false;\n }\n\n async handleRequestAsync(\n req: ServerRequest,\n res: ServerResponse,\n next: ServerNext\n ): Promise<void> {\n // First check for standard JavaScript runtimes (aka legacy browsers like Chrome).\n if (await this.checkBrowserRequestAsync(req, res, next)) {\n return;\n }\n\n // Save device IDs for dev client.\n await this.saveDevicesAsync(req);\n\n // Read from headers\n const options = this.getParsedHeaders(req);\n const { body, headers } = await this._getManifestResponseAsync(options);\n for (const [headerName, headerValue] of headers) {\n res.setHeader(headerName, headerValue);\n }\n res.end(body);\n }\n}\n"],"names":["DEVELOPER_TOOL","ManifestMiddleware","getEntryWithServerRoot","resolveMainModuleName","debug","require","supportedPlatforms","projectRoot","props","includes","platform","CommandError","convertPathToModuleSpecifier","path","relative","getMetroServerRoot","resolveEntryPoint","entryPoint","stripExtension","ExpoMiddleware","constructor","options","initialProjectConfig","getConfig","platformBundlers","getPlatformBundlers","exp","_resolveProjectSettingsAsync","hostname","protocol","projectConfig","mainModuleName","pkg","isHermesEnabled","isEnableHermesManaged","expoGoConfig","getExpoGoConfig","hostUri","constructUrl","scheme","bundleUrl","_getBundleUrl","engine","undefined","baseUrl","getBaseUrlFromExpoConfig","asyncRoutes","getAsyncRoutesFromExpoConfig","mode","routerRoot","getRouterDirectoryModuleIdWithManifest","reactCompiler","experiments","mutateManifestWithAssetsAsync","isNativeWebpack","saveDevicesAsync","req","deviceIds","headers","ProjectDevices","catch","e","Log","exception","isExporting","createBundleUrlPath","minify","lazy","env","EXPO_NO_METRO_LAZY","bytecode","debuggerHost","developer","tool","packagerOpts","dev","manifest","resolveManifestAssets","resolver","resolve","match","resolveGoogleServicesFile","getWebBundleUrl","createBundleUrlPathFromExpoConfig","handleWebRequestAsync","res","setHeader","end","getSingleHtmlTemplateAsync","createTemplateHtmlFromExpoConfigAsync","scripts","checkBrowserRequestAsync","next","web","platforms","parsePlatformHeader","output","handleRequestAsync","getParsedHeaders","body","_getManifestResponseAsync","headerName","headerValue"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/start/server/middleware/ManifestMiddleware.ts"],"sourcesContent":["import {\n ExpoConfig,\n ExpoGoConfig,\n getConfig,\n PackageJSONConfig,\n ProjectConfig,\n} from '@expo/config';\nimport { resolveEntryPoint, getMetroServerRoot } from '@expo/config/paths';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport path from 'path';\nimport { resolve } from 'url';\n\nimport { ExpoMiddleware } from './ExpoMiddleware';\nimport {\n createBundleUrlPath,\n getBaseUrlFromExpoConfig,\n getAsyncRoutesFromExpoConfig,\n createBundleUrlPathFromExpoConfig,\n convertPathToModuleSpecifier,\n} from './metroOptions';\nimport { resolveGoogleServicesFile, resolveManifestAssets } from './resolveAssets';\nimport { parsePlatformHeader, RuntimePlatform } from './resolvePlatform';\nimport { ServerNext, ServerRequest, ServerResponse } from './server.types';\nimport { isEnableHermesManaged } from '../../../export/exportHermes';\nimport * as Log from '../../../log';\nimport { env } from '../../../utils/env';\nimport { CommandError } from '../../../utils/errors';\nimport { stripExtension } from '../../../utils/url';\nimport * as ProjectDevices from '../../project/devices';\nimport { UrlCreator } from '../UrlCreator';\nimport { getRouterDirectoryModuleIdWithManifest } from '../metro/router';\nimport { getPlatformBundlers, PlatformBundlers } from '../platformBundlers';\nimport { createTemplateHtmlFromExpoConfigAsync } from '../webTemplate';\n\nconst debug = require('debug')('expo:start:server:middleware:manifest') as typeof console.log;\n\nconst supportedPlatforms = ['ios', 'android', 'web', 'none'];\n\nexport function getEntryWithServerRoot(\n projectRoot: string,\n props: { platform: string; pkg?: PackageJSONConfig }\n) {\n if (!supportedPlatforms.includes(props.platform)) {\n throw new CommandError(\n `Failed to resolve the project's entry file: The platform \"${props.platform}\" is not supported.`\n );\n }\n return convertPathToModuleSpecifier(\n path.relative(getMetroServerRoot(projectRoot), resolveEntryPoint(projectRoot, props))\n );\n}\n\n/** Get the main entry module ID (file) relative to the project root. */\nexport function resolveMainModuleName(\n projectRoot: string,\n props: { platform: string; pkg?: PackageJSONConfig }\n): string {\n const entryPoint = getEntryWithServerRoot(projectRoot, props);\n\n debug(`Resolved entry point: ${entryPoint} (project root: ${projectRoot})`);\n\n return convertPathToModuleSpecifier(stripExtension(entryPoint, 'js'));\n}\n\n/** Info about the computer hosting the dev server. */\nexport interface HostInfo {\n host: string;\n server: 'expo';\n serverVersion: string;\n serverDriver: string | null;\n serverOS: NodeJS.Platform;\n serverOSVersion: string;\n}\n\n/** Parsed values from the supported request headers. */\nexport interface ManifestRequestInfo {\n /** Platform to serve. */\n platform: RuntimePlatform;\n /** Requested host name. */\n hostname?: string | null;\n /** The protocol used to request the manifest */\n protocol?: 'http' | 'https';\n}\n\n/** Project related info. */\nexport type ResponseProjectSettings = {\n expoGoConfig: ExpoGoConfig;\n hostUri: string;\n bundleUrl: string;\n exp: ExpoConfig;\n};\n\nexport const DEVELOPER_TOOL = 'expo-cli';\n\nexport type ManifestMiddlewareOptions = {\n /** Should start the dev servers in development mode (minify). */\n mode?: 'development' | 'production';\n /** Should instruct the bundler to create minified bundles. */\n minify?: boolean;\n constructUrl: UrlCreator['constructUrl'];\n isNativeWebpack?: boolean;\n privateKeyPath?: string;\n};\n\n/** Base middleware creator for serving the Expo manifest (like the index.html but for native runtimes). */\nexport abstract class ManifestMiddleware<\n TManifestRequestInfo extends ManifestRequestInfo,\n> extends ExpoMiddleware {\n private initialProjectConfig: ProjectConfig;\n private platformBundlers: PlatformBundlers;\n\n constructor(\n protected projectRoot: string,\n protected options: ManifestMiddlewareOptions\n ) {\n super(\n projectRoot,\n /**\n * Only support `/`, `/manifest`, `/index.exp` for the manifest middleware.\n */\n ['/', '/manifest', '/index.exp']\n );\n this.initialProjectConfig = getConfig(projectRoot);\n this.platformBundlers = getPlatformBundlers(projectRoot, this.initialProjectConfig.exp);\n }\n\n /** Exposed for testing. */\n public async _resolveProjectSettingsAsync({\n platform,\n hostname,\n protocol,\n }: Pick<\n TManifestRequestInfo,\n 'hostname' | 'platform' | 'protocol'\n >): Promise<ResponseProjectSettings> {\n // Read the config\n const projectConfig = getConfig(this.projectRoot);\n\n // Read from headers\n const mainModuleName = this.resolveMainModuleName({\n pkg: projectConfig.pkg,\n platform,\n });\n\n const isHermesEnabled = isEnableHermesManaged(projectConfig.exp, platform);\n\n // Create the manifest and set fields within it\n const expoGoConfig = this.getExpoGoConfig({\n mainModuleName,\n hostname,\n });\n\n const hostUri = this.options.constructUrl({ scheme: '', hostname });\n\n const bundleUrl = this._getBundleUrl({\n platform,\n mainModuleName,\n hostname,\n engine: isHermesEnabled ? 'hermes' : undefined,\n baseUrl: getBaseUrlFromExpoConfig(projectConfig.exp),\n asyncRoutes: getAsyncRoutesFromExpoConfig(\n projectConfig.exp,\n this.options.mode ?? 'development',\n platform\n ),\n routerRoot: getRouterDirectoryModuleIdWithManifest(this.projectRoot, projectConfig.exp),\n protocol,\n reactCompiler: !!projectConfig.exp.experiments?.reactCompiler,\n });\n\n // Resolve all assets and set them on the manifest as URLs\n await this.mutateManifestWithAssetsAsync(projectConfig.exp, bundleUrl);\n\n return {\n expoGoConfig,\n hostUri,\n bundleUrl,\n exp: projectConfig.exp,\n };\n }\n\n /** Get the main entry module ID (file) relative to the project root. */\n private resolveMainModuleName(props: { pkg: PackageJSONConfig; platform: string }): string {\n let entryPoint = getEntryWithServerRoot(this.projectRoot, props);\n\n debug(`Resolved entry point: ${entryPoint} (project root: ${this.projectRoot})`);\n\n // NOTE(Bacon): Webpack is currently hardcoded to index.bundle on native\n // in the future (TODO) we should move this logic into a Webpack plugin and use\n // a generated file name like we do on web.\n // const server = getDefaultDevServer();\n // // TODO: Move this into BundlerDevServer and read this info from self.\n // const isNativeWebpack = server instanceof WebpackBundlerDevServer && server.isTargetingNative();\n if (this.options.isNativeWebpack) {\n entryPoint = 'index.js';\n }\n\n return stripExtension(entryPoint, 'js');\n }\n\n /** Parse request headers into options. */\n public abstract getParsedHeaders(req: ServerRequest): TManifestRequestInfo;\n\n /** Store device IDs that were sent in the request headers. */\n private async saveDevicesAsync(req: ServerRequest) {\n const deviceIds = req.headers?.['expo-dev-client-id'];\n if (deviceIds) {\n await ProjectDevices.saveDevicesAsync(this.projectRoot, deviceIds).catch((e) =>\n Log.exception(e)\n );\n }\n }\n\n /** Create the bundle URL (points to the single JS entry file). Exposed for testing. */\n public _getBundleUrl({\n platform,\n mainModuleName,\n hostname,\n engine,\n baseUrl,\n isExporting,\n asyncRoutes,\n routerRoot,\n protocol,\n reactCompiler,\n }: {\n platform: string;\n hostname?: string | null;\n mainModuleName: string;\n engine?: 'hermes';\n baseUrl?: string;\n asyncRoutes: boolean;\n isExporting?: boolean;\n routerRoot: string;\n protocol?: 'http' | 'https';\n reactCompiler: boolean;\n }): string {\n const path = createBundleUrlPath({\n mode: this.options.mode ?? 'development',\n minify: this.options.minify,\n platform,\n mainModuleName,\n lazy: !env.EXPO_NO_METRO_LAZY,\n engine,\n bytecode: engine === 'hermes',\n baseUrl,\n isExporting: !!isExporting,\n asyncRoutes,\n routerRoot,\n reactCompiler,\n });\n\n return (\n this.options.constructUrl({\n scheme: protocol ?? 'http',\n // hostType: this.options.location.hostType,\n hostname,\n }) + path\n );\n }\n\n /** Get the manifest response to return to the runtime. This file contains info regarding where the assets can be loaded from. Exposed for testing. */\n public abstract _getManifestResponseAsync(options: TManifestRequestInfo): Promise<Response>;\n\n private getExpoGoConfig({\n mainModuleName,\n hostname,\n }: {\n mainModuleName: string;\n hostname?: string | null;\n }): ExpoGoConfig {\n return {\n // localhost:8081\n debuggerHost: this.options.constructUrl({ scheme: '', hostname }),\n // Required for Expo Go to function.\n developer: {\n tool: DEVELOPER_TOOL,\n projectRoot: this.projectRoot,\n },\n packagerOpts: {\n // Required for dev client.\n dev: this.options.mode !== 'production',\n },\n // Indicates the name of the main bundle.\n mainModuleName,\n };\n }\n\n /** Resolve all assets and set them on the manifest as URLs */\n private async mutateManifestWithAssetsAsync(manifest: ExpoConfig, bundleUrl: string) {\n await resolveManifestAssets(this.projectRoot, {\n manifest,\n resolver: async (path) => {\n if (this.options.isNativeWebpack) {\n // When using our custom dev server, just do assets normally\n // without the `assets/` subpath redirect.\n return resolve(bundleUrl!.match(/^https?:\\/\\/.*?\\//)![0], path);\n }\n return bundleUrl!.match(/^https?:\\/\\/.*?\\//)![0] + 'assets/' + path;\n },\n });\n // The server normally inserts this but if we're offline we'll do it here\n await resolveGoogleServicesFile(this.projectRoot, manifest);\n }\n\n public getWebBundleUrl() {\n const platform = 'web';\n // Read from headers\n const mainModuleName = this.resolveMainModuleName({\n pkg: this.initialProjectConfig.pkg,\n platform,\n });\n\n return createBundleUrlPathFromExpoConfig(this.projectRoot, this.initialProjectConfig.exp, {\n platform,\n mainModuleName,\n minify: this.options.minify,\n lazy: !env.EXPO_NO_METRO_LAZY,\n mode: this.options.mode ?? 'development',\n // Hermes doesn't support more modern JS features than most, if not all, modern browser.\n engine: 'hermes',\n isExporting: false,\n bytecode: false,\n });\n }\n\n /**\n * Web platforms should create an index.html response using the same script resolution as native.\n *\n * Instead of adding a `bundleUrl` to a `manifest.json` (native) we'll add a `<script src=\"\">`\n * to an `index.html`, this enables the web platform to load JavaScript from the server.\n */\n private async handleWebRequestAsync(req: ServerRequest, res: ServerResponse) {\n res.setHeader('Content-Type', 'text/html');\n\n res.end(await this.getSingleHtmlTemplateAsync());\n }\n\n getSingleHtmlTemplateAsync() {\n // Read from headers\n const bundleUrl = this.getWebBundleUrl();\n\n return createTemplateHtmlFromExpoConfigAsync(this.projectRoot, {\n exp: this.initialProjectConfig.exp,\n scripts: [bundleUrl],\n });\n }\n\n /** Exposed for testing. */\n async checkBrowserRequestAsync(req: ServerRequest, res: ServerResponse, next: ServerNext) {\n if (\n this.platformBundlers.web === 'metro' &&\n this.initialProjectConfig.exp.platforms?.includes('web')\n ) {\n // NOTE(EvanBacon): This effectively disables the safety check we do on custom runtimes to ensure\n // the `expo-platform` header is included. When `web.bundler=web`, if the user has non-standard Expo\n // code loading then they'll get a web bundle without a clear assertion of platform support.\n const platform = parsePlatformHeader(req);\n // On web, serve the public folder\n if (!platform || platform === 'web') {\n if (['static', 'server'].includes(this.initialProjectConfig.exp.web?.output ?? '')) {\n // Skip the spa-styled index.html when static generation is enabled.\n next();\n return true;\n } else {\n await this.handleWebRequestAsync(req, res);\n return true;\n }\n }\n }\n return false;\n }\n\n async handleRequestAsync(\n req: ServerRequest,\n res: ServerResponse,\n next: ServerNext\n ): Promise<void> {\n // First check for standard JavaScript runtimes (aka legacy browsers like Chrome).\n if (await this.checkBrowserRequestAsync(req, res, next)) {\n return;\n }\n\n // Save device IDs for dev client.\n await this.saveDevicesAsync(req);\n\n // Read from headers\n const options = this.getParsedHeaders(req);\n\n const response = await this._getManifestResponseAsync(options);\n // Convert `Response` to node:http response\n if (typeof res.setHeaders === 'function') {\n res.setHeaders(response.headers);\n } else {\n for (const [key, value] of response.headers.entries()) {\n res.appendHeader(key, value);\n }\n }\n if (response.body) {\n await pipeline(Readable.fromWeb(response.body as any), res);\n } else {\n res.end();\n }\n }\n}\n"],"names":["DEVELOPER_TOOL","ManifestMiddleware","getEntryWithServerRoot","resolveMainModuleName","debug","require","supportedPlatforms","projectRoot","props","includes","platform","CommandError","convertPathToModuleSpecifier","path","relative","getMetroServerRoot","resolveEntryPoint","entryPoint","stripExtension","ExpoMiddleware","constructor","options","initialProjectConfig","getConfig","platformBundlers","getPlatformBundlers","exp","_resolveProjectSettingsAsync","hostname","protocol","projectConfig","mainModuleName","pkg","isHermesEnabled","isEnableHermesManaged","expoGoConfig","getExpoGoConfig","hostUri","constructUrl","scheme","bundleUrl","_getBundleUrl","engine","undefined","baseUrl","getBaseUrlFromExpoConfig","asyncRoutes","getAsyncRoutesFromExpoConfig","mode","routerRoot","getRouterDirectoryModuleIdWithManifest","reactCompiler","experiments","mutateManifestWithAssetsAsync","isNativeWebpack","saveDevicesAsync","req","deviceIds","headers","ProjectDevices","catch","e","Log","exception","isExporting","createBundleUrlPath","minify","lazy","env","EXPO_NO_METRO_LAZY","bytecode","debuggerHost","developer","tool","packagerOpts","dev","manifest","resolveManifestAssets","resolver","resolve","match","resolveGoogleServicesFile","getWebBundleUrl","createBundleUrlPathFromExpoConfig","handleWebRequestAsync","res","setHeader","end","getSingleHtmlTemplateAsync","createTemplateHtmlFromExpoConfigAsync","scripts","checkBrowserRequestAsync","next","web","platforms","parsePlatformHeader","output","handleRequestAsync","getParsedHeaders","response","_getManifestResponseAsync","setHeaders","key","value","entries","appendHeader","body","pipeline","Readable","fromWeb"],"mappings":";;;;;;;;;;;IA6FaA,cAAc;eAAdA;;IAaSC,kBAAkB;eAAlBA;;IAnENC,sBAAsB;eAAtBA;;IAeAC,qBAAqB;eAArBA;;;;yBAhDT;;;;;;;yBAC+C;;;;;;;yBAC7B;;;;;;;yBACA;;;;;;;gEACR;;;;;;;yBACO;;;;;;gCAEO;8BAOxB;+BAC0D;iCACZ;8BAEf;6DACjB;qBACD;wBACS;sBACE;iEACC;wBAEuB;kCACD;6BACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEtD,MAAMC,QAAQC,QAAQ,SAAS;AAE/B,MAAMC,qBAAqB;IAAC;IAAO;IAAW;IAAO;CAAO;AAErD,SAASJ,uBACdK,WAAmB,EACnBC,KAAoD;IAEpD,IAAI,CAACF,mBAAmBG,QAAQ,CAACD,MAAME,QAAQ,GAAG;QAChD,MAAM,IAAIC,oBAAY,CACpB,CAAC,0DAA0D,EAAEH,MAAME,QAAQ,CAAC,mBAAmB,CAAC;IAEpG;IACA,OAAOE,IAAAA,0CAA4B,EACjCC,eAAI,CAACC,QAAQ,CAACC,IAAAA,2BAAkB,EAACR,cAAcS,IAAAA,0BAAiB,EAACT,aAAaC;AAElF;AAGO,SAASL,sBACdI,WAAmB,EACnBC,KAAoD;IAEpD,MAAMS,aAAaf,uBAAuBK,aAAaC;IAEvDJ,MAAM,CAAC,sBAAsB,EAAEa,WAAW,gBAAgB,EAAEV,YAAY,CAAC,CAAC;IAE1E,OAAOK,IAAAA,0CAA4B,EAACM,IAAAA,oBAAc,EAACD,YAAY;AACjE;AA8BO,MAAMjB,iBAAiB;AAavB,MAAeC,2BAEZkB,8BAAc;IAItBC,YACE,AAAUb,WAAmB,EAC7B,AAAUc,OAAkC,CAC5C;QACA,KAAK,CACHd,aACA;;OAEC,GACD;YAAC;YAAK;YAAa;SAAa,QARxBA,cAAAA,kBACAc,UAAAA;QASV,IAAI,CAACC,oBAAoB,GAAGC,IAAAA,mBAAS,EAAChB;QACtC,IAAI,CAACiB,gBAAgB,GAAGC,IAAAA,qCAAmB,EAAClB,aAAa,IAAI,CAACe,oBAAoB,CAACI,GAAG;IACxF;IAEA,yBAAyB,GACzB,MAAaC,6BAA6B,EACxCjB,QAAQ,EACRkB,QAAQ,EACRC,QAAQ,EAIT,EAAoC;YAiChBC;QAhCnB,kBAAkB;QAClB,MAAMA,gBAAgBP,IAAAA,mBAAS,EAAC,IAAI,CAAChB,WAAW;QAEhD,oBAAoB;QACpB,MAAMwB,iBAAiB,IAAI,CAAC5B,qBAAqB,CAAC;YAChD6B,KAAKF,cAAcE,GAAG;YACtBtB;QACF;QAEA,MAAMuB,kBAAkBC,IAAAA,mCAAqB,EAACJ,cAAcJ,GAAG,EAAEhB;QAEjE,+CAA+C;QAC/C,MAAMyB,eAAe,IAAI,CAACC,eAAe,CAAC;YACxCL;YACAH;QACF;QAEA,MAAMS,UAAU,IAAI,CAAChB,OAAO,CAACiB,YAAY,CAAC;YAAEC,QAAQ;YAAIX;QAAS;QAEjE,MAAMY,YAAY,IAAI,CAACC,aAAa,CAAC;YACnC/B;YACAqB;YACAH;YACAc,QAAQT,kBAAkB,WAAWU;YACrCC,SAASC,IAAAA,sCAAwB,EAACf,cAAcJ,GAAG;YACnDoB,aAAaC,IAAAA,0CAA4B,EACvCjB,cAAcJ,GAAG,EACjB,IAAI,CAACL,OAAO,CAAC2B,IAAI,IAAI,eACrBtC;YAEFuC,YAAYC,IAAAA,8CAAsC,EAAC,IAAI,CAAC3C,WAAW,EAAEuB,cAAcJ,GAAG;YACtFG;YACAsB,eAAe,CAAC,GAACrB,iCAAAA,cAAcJ,GAAG,CAAC0B,WAAW,qBAA7BtB,+BAA+BqB,aAAa;QAC/D;QAEA,0DAA0D;QAC1D,MAAM,IAAI,CAACE,6BAA6B,CAACvB,cAAcJ,GAAG,EAAEc;QAE5D,OAAO;YACLL;YACAE;YACAG;YACAd,KAAKI,cAAcJ,GAAG;QACxB;IACF;IAEA,sEAAsE,GACtE,AAAQvB,sBAAsBK,KAAmD,EAAU;QACzF,IAAIS,aAAaf,uBAAuB,IAAI,CAACK,WAAW,EAAEC;QAE1DJ,MAAM,CAAC,sBAAsB,EAAEa,WAAW,gBAAgB,EAAE,IAAI,CAACV,WAAW,CAAC,CAAC,CAAC;QAE/E,wEAAwE;QACxE,+EAA+E;QAC/E,2CAA2C;QAC3C,wCAAwC;QACxC,yEAAyE;QACzE,mGAAmG;QACnG,IAAI,IAAI,CAACc,OAAO,CAACiC,eAAe,EAAE;YAChCrC,aAAa;QACf;QAEA,OAAOC,IAAAA,oBAAc,EAACD,YAAY;IACpC;IAKA,4DAA4D,GAC5D,MAAcsC,iBAAiBC,GAAkB,EAAE;YAC/BA;QAAlB,MAAMC,aAAYD,eAAAA,IAAIE,OAAO,qBAAXF,YAAa,CAAC,qBAAqB;QACrD,IAAIC,WAAW;YACb,MAAME,SAAeJ,gBAAgB,CAAC,IAAI,CAAChD,WAAW,EAAEkD,WAAWG,KAAK,CAAC,CAACC,IACxEC,KAAIC,SAAS,CAACF;QAElB;IACF;IAEA,qFAAqF,GACrF,AAAOpB,cAAc,EACnB/B,QAAQ,EACRqB,cAAc,EACdH,QAAQ,EACRc,MAAM,EACNE,OAAO,EACPoB,WAAW,EACXlB,WAAW,EACXG,UAAU,EACVpB,QAAQ,EACRsB,aAAa,EAYd,EAAU;QACT,MAAMtC,OAAOoD,IAAAA,iCAAmB,EAAC;YAC/BjB,MAAM,IAAI,CAAC3B,OAAO,CAAC2B,IAAI,IAAI;YAC3BkB,QAAQ,IAAI,CAAC7C,OAAO,CAAC6C,MAAM;YAC3BxD;YACAqB;YACAoC,MAAM,CAACC,QAAG,CAACC,kBAAkB;YAC7B3B;YACA4B,UAAU5B,WAAW;YACrBE;YACAoB,aAAa,CAAC,CAACA;YACflB;YACAG;YACAE;QACF;QAEA,OACE,IAAI,CAAC9B,OAAO,CAACiB,YAAY,CAAC;YACxBC,QAAQV,YAAY;YACpB,4CAA4C;YAC5CD;QACF,KAAKf;IAET;IAKQuB,gBAAgB,EACtBL,cAAc,EACdH,QAAQ,EAIT,EAAgB;QACf,OAAO;YACL,iBAAiB;YACjB2C,cAAc,IAAI,CAAClD,OAAO,CAACiB,YAAY,CAAC;gBAAEC,QAAQ;gBAAIX;YAAS;YAC/D,oCAAoC;YACpC4C,WAAW;gBACTC,MAAMzE;gBACNO,aAAa,IAAI,CAACA,WAAW;YAC/B;YACAmE,cAAc;gBACZ,2BAA2B;gBAC3BC,KAAK,IAAI,CAACtD,OAAO,CAAC2B,IAAI,KAAK;YAC7B;YACA,yCAAyC;YACzCjB;QACF;IACF;IAEA,4DAA4D,GAC5D,MAAcsB,8BAA8BuB,QAAoB,EAAEpC,SAAiB,EAAE;QACnF,MAAMqC,IAAAA,oCAAqB,EAAC,IAAI,CAACtE,WAAW,EAAE;YAC5CqE;YACAE,UAAU,OAAOjE;gBACf,IAAI,IAAI,CAACQ,OAAO,CAACiC,eAAe,EAAE;oBAChC,4DAA4D;oBAC5D,0CAA0C;oBAC1C,OAAOyB,IAAAA,cAAO,EAACvC,UAAWwC,KAAK,CAAC,oBAAqB,CAAC,EAAE,EAAEnE;gBAC5D;gBACA,OAAO2B,UAAWwC,KAAK,CAAC,oBAAqB,CAAC,EAAE,GAAG,YAAYnE;YACjE;QACF;QACA,yEAAyE;QACzE,MAAMoE,IAAAA,wCAAyB,EAAC,IAAI,CAAC1E,WAAW,EAAEqE;IACpD;IAEOM,kBAAkB;QACvB,MAAMxE,WAAW;QACjB,oBAAoB;QACpB,MAAMqB,iBAAiB,IAAI,CAAC5B,qBAAqB,CAAC;YAChD6B,KAAK,IAAI,CAACV,oBAAoB,CAACU,GAAG;YAClCtB;QACF;QAEA,OAAOyE,IAAAA,+CAAiC,EAAC,IAAI,CAAC5E,WAAW,EAAE,IAAI,CAACe,oBAAoB,CAACI,GAAG,EAAE;YACxFhB;YACAqB;YACAmC,QAAQ,IAAI,CAAC7C,OAAO,CAAC6C,MAAM;YAC3BC,MAAM,CAACC,QAAG,CAACC,kBAAkB;YAC7BrB,MAAM,IAAI,CAAC3B,OAAO,CAAC2B,IAAI,IAAI;YAC3B,wFAAwF;YACxFN,QAAQ;YACRsB,aAAa;YACbM,UAAU;QACZ;IACF;IAEA;;;;;GAKC,GACD,MAAcc,sBAAsB5B,GAAkB,EAAE6B,GAAmB,EAAE;QAC3EA,IAAIC,SAAS,CAAC,gBAAgB;QAE9BD,IAAIE,GAAG,CAAC,MAAM,IAAI,CAACC,0BAA0B;IAC/C;IAEAA,6BAA6B;QAC3B,oBAAoB;QACpB,MAAMhD,YAAY,IAAI,CAAC0C,eAAe;QAEtC,OAAOO,IAAAA,kDAAqC,EAAC,IAAI,CAAClF,WAAW,EAAE;YAC7DmB,KAAK,IAAI,CAACJ,oBAAoB,CAACI,GAAG;YAClCgE,SAAS;gBAAClD;aAAU;QACtB;IACF;IAEA,yBAAyB,GACzB,MAAMmD,yBAAyBnC,GAAkB,EAAE6B,GAAmB,EAAEO,IAAgB,EAAE;YAGtF;QAFF,IACE,IAAI,CAACpE,gBAAgB,CAACqE,GAAG,KAAK,aAC9B,2CAAA,IAAI,CAACvE,oBAAoB,CAACI,GAAG,CAACoE,SAAS,qBAAvC,yCAAyCrF,QAAQ,CAAC,SAClD;YACA,iGAAiG;YACjG,oGAAoG;YACpG,4FAA4F;YAC5F,MAAMC,WAAWqF,IAAAA,oCAAmB,EAACvC;YACrC,kCAAkC;YAClC,IAAI,CAAC9C,YAAYA,aAAa,OAAO;oBACD;gBAAlC,IAAI;oBAAC;oBAAU;iBAAS,CAACD,QAAQ,CAAC,EAAA,qCAAA,IAAI,CAACa,oBAAoB,CAACI,GAAG,CAACmE,GAAG,qBAAjC,mCAAmCG,MAAM,KAAI,KAAK;oBAClF,oEAAoE;oBACpEJ;oBACA,OAAO;gBACT,OAAO;oBACL,MAAM,IAAI,CAACR,qBAAqB,CAAC5B,KAAK6B;oBACtC,OAAO;gBACT;YACF;QACF;QACA,OAAO;IACT;IAEA,MAAMY,mBACJzC,GAAkB,EAClB6B,GAAmB,EACnBO,IAAgB,EACD;QACf,kFAAkF;QAClF,IAAI,MAAM,IAAI,CAACD,wBAAwB,CAACnC,KAAK6B,KAAKO,OAAO;YACvD;QACF;QAEA,kCAAkC;QAClC,MAAM,IAAI,CAACrC,gBAAgB,CAACC;QAE5B,oBAAoB;QACpB,MAAMnC,UAAU,IAAI,CAAC6E,gBAAgB,CAAC1C;QAEtC,MAAM2C,WAAW,MAAM,IAAI,CAACC,yBAAyB,CAAC/E;QACtD,2CAA2C;QAC3C,IAAI,OAAOgE,IAAIgB,UAAU,KAAK,YAAY;YACxChB,IAAIgB,UAAU,CAACF,SAASzC,OAAO;QACjC,OAAO;YACL,KAAK,MAAM,CAAC4C,KAAKC,MAAM,IAAIJ,SAASzC,OAAO,CAAC8C,OAAO,GAAI;gBACrDnB,IAAIoB,YAAY,CAACH,KAAKC;YACxB;QACF;QACA,IAAIJ,SAASO,IAAI,EAAE;YACjB,MAAMC,IAAAA,oBAAQ,EAACC,sBAAQ,CAACC,OAAO,CAACV,SAASO,IAAI,GAAUrB;QACzD,OAAO;YACLA,IAAIE,GAAG;QACT;IACF;AACF"}
@@ -57,14 +57,6 @@ function _path() {
57
57
  };
58
58
  return data;
59
59
  }
60
- function _resolvefrom() {
61
- const data = /*#__PURE__*/ _interop_require_default(require("resolve-from"));
62
- _resolvefrom = function() {
63
- return data;
64
- };
65
- return data;
66
- }
67
- const _dir = require("../../../utils/dir");
68
60
  const _template = require("../../../utils/template");
69
61
  const _metroWatchTypeScriptFiles = require("../metro/metroWatchTypeScriptFiles");
70
62
  function _interop_require_default(obj) {
@@ -79,13 +71,8 @@ const ARRAY_GROUP_REGEX = /\(\s*\w[\w\s]*?,.*?\)/g;
79
71
  const CAPTURE_GROUP_REGEX = /[\\(,]\s*(\w[\w\s]*?)\s*(?=[,\\)])/g;
80
72
  const TYPED_ROUTES_EXCLUSION_REGEX = /(_layout|[^/]*?\+[^/]*?)\.[tj]sx?$/;
81
73
  async function setupTypedRoutes(options) {
82
- /*
83
- * In SDK 51, TypedRoutes was moved out of cli and into expo-router. For now we need to support both
84
- * the legacy and new versions of TypedRoutes.
85
- *
86
- * TODO (@marklawlor): Remove this check in SDK 53, only support Expo Router v4 and above.
87
- */ const typedRoutesModule = _resolvefrom().default.silent(options.projectRoot, '@expo/router-server/build/typed-routes');
88
- return typedRoutesModule ? typedRoutes(typedRoutesModule, options) : legacyTypedRoutes(options);
74
+ const typedRoutesModule = require.resolve('@expo/router-server/build/typed-routes');
75
+ return typedRoutes(typedRoutesModule, options);
89
76
  }
90
77
  async function typedRoutes(typedRoutesModulePath, { server, metro, typesDirectory, projectRoot, routerDirectory, plugin }) {
91
78
  /*
@@ -122,53 +109,6 @@ async function typedRoutes(typedRoutesModulePath, { server, metro, typesDirector
122
109
  typedRoutesModule.regenerateDeclarations(typesDirectory);
123
110
  }
124
111
  }
125
- async function legacyTypedRoutes({ server, metro, typesDirectory, projectRoot, routerDirectory }) {
126
- const { filePathToRoute, staticRoutes, dynamicRoutes, addFilePath, isRouteFile } = getTypedRoutesUtils(routerDirectory);
127
- // Typed Routes can be run with out Metro or a Server, e.g. `expo customize tsconfig.json`
128
- if (metro && server) {
129
- (0, _metroWatchTypeScriptFiles.metroWatchTypeScriptFiles)({
130
- projectRoot,
131
- server,
132
- metro,
133
- eventTypes: [
134
- 'add',
135
- 'delete',
136
- 'change'
137
- ],
138
- async callback ({ filePath, type }) {
139
- if (!isRouteFile(filePath)) {
140
- return;
141
- }
142
- let shouldRegenerate = false;
143
- if (type === 'delete') {
144
- const route = filePathToRoute(filePath);
145
- staticRoutes.delete(route);
146
- dynamicRoutes.delete(route);
147
- shouldRegenerate = true;
148
- } else {
149
- shouldRegenerate = addFilePath(filePath);
150
- }
151
- if (shouldRegenerate) {
152
- regenerateRouterDotTS(typesDirectory, new Set([
153
- ...staticRoutes.values()
154
- ].flatMap((v)=>Array.from(v))), new Set([
155
- ...dynamicRoutes.values()
156
- ].flatMap((v)=>Array.from(v))), new Set(dynamicRoutes.keys()));
157
- }
158
- }
159
- });
160
- }
161
- if (await (0, _dir.directoryExistsAsync)(routerDirectory)) {
162
- // Do we need to walk the entire tree on startup?
163
- // Idea: Store the list of files in the last write, then simply check Git for what files have changed
164
- await walk(routerDirectory, addFilePath);
165
- }
166
- regenerateRouterDotTS(typesDirectory, new Set([
167
- ...staticRoutes.values()
168
- ].flatMap((v)=>Array.from(v))), new Set([
169
- ...dynamicRoutes.values()
170
- ].flatMap((v)=>Array.from(v))), new Set(dynamicRoutes.keys()));
171
- }
172
112
  function debounce(fn, delay) {
173
113
  let timeoutId;
174
114
  return function(...args) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/start/server/type-generation/routes.ts"],"sourcesContent":["import type Server from '@expo/metro/metro/Server';\nimport fs from 'fs/promises';\nimport path from 'path';\nimport resolveFrom from 'resolve-from';\n\nimport { directoryExistsAsync } from '../../../utils/dir';\nimport { unsafeTemplate } from '../../../utils/template';\nimport { 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 /*\n * In SDK 51, TypedRoutes was moved out of cli and into expo-router. For now we need to support both\n * the legacy and new versions of TypedRoutes.\n *\n * TODO (@marklawlor): Remove this check in SDK 53, only support Expo Router v4 and above.\n */\n const typedRoutesModule = resolveFrom.silent(\n options.projectRoot,\n '@expo/router-server/build/typed-routes'\n );\n return typedRoutesModule ? typedRoutes(typedRoutesModule, options) : legacyTypedRoutes(options);\n}\n\nasync function typedRoutes(\n typedRoutesModulePath: any,\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 = require(typedRoutesModulePath);\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\nasync function legacyTypedRoutes({\n server,\n metro,\n typesDirectory,\n projectRoot,\n routerDirectory,\n}: SetupTypedRoutesOptions) {\n const { filePathToRoute, staticRoutes, dynamicRoutes, addFilePath, isRouteFile } =\n getTypedRoutesUtils(routerDirectory);\n\n // Typed Routes can be run with out Metro or a Server, e.g. `expo customize tsconfig.json`\n if (metro && server) {\n metroWatchTypeScriptFiles({\n projectRoot,\n server,\n metro,\n eventTypes: ['add', 'delete', 'change'],\n async callback({ filePath, type }) {\n if (!isRouteFile(filePath)) {\n return;\n }\n\n let shouldRegenerate = false;\n\n if (type === 'delete') {\n const route = filePathToRoute(filePath);\n staticRoutes.delete(route);\n dynamicRoutes.delete(route);\n shouldRegenerate = true;\n } else {\n shouldRegenerate = addFilePath(filePath);\n }\n\n if (shouldRegenerate) {\n regenerateRouterDotTS(\n typesDirectory,\n new Set([...staticRoutes.values()].flatMap((v) => Array.from(v))),\n new Set([...dynamicRoutes.values()].flatMap((v) => Array.from(v))),\n new Set(dynamicRoutes.keys())\n );\n }\n },\n });\n }\n\n if (await directoryExistsAsync(routerDirectory)) {\n // Do we need to walk the entire tree on startup?\n // Idea: Store the list of files in the last write, then simply check Git for what files have changed\n await walk(routerDirectory, addFilePath);\n }\n\n regenerateRouterDotTS(\n typesDirectory,\n new Set([...staticRoutes.values()].flatMap((v) => Array.from(v))),\n new Set([...dynamicRoutes.values()].flatMap((v) => Array.from(v))),\n new Set(dynamicRoutes.keys())\n );\n}\n\nfunction debounce<U, T extends (this: U, ...args: any[]) => void>(fn: T, delay: number): T {\n let timeoutId: NodeJS.Timeout | undefined;\n return function (this: U, ...args: any[]) {\n clearTimeout(timeoutId);\n // NOTE(@hassankhan): The cast to `NodeJS.Timeout` below is a hack to work around an issue\n // with TypeScript where React Native's types are being imported before Node types\n timeoutId = setTimeout(() => fn.apply(this, args), delay) as unknown as NodeJS.Timeout;\n } as T;\n}\n\n/**\n * Generate a router.d.ts file that contains all of the routes in the project.\n * Should be debounced as its very common for developers to make changes to multiple files at once (eg Save All)\n */\nconst regenerateRouterDotTS = debounce(\n async (\n typesDir: string,\n staticRoutes: Set<string>,\n dynamicRoutes: Set<string>,\n dynamicRouteTemplates: Set<string>\n ) => {\n await fs.mkdir(typesDir, { recursive: true });\n await fs.writeFile(\n path.resolve(typesDir, './router.d.ts'),\n getTemplateString(staticRoutes, dynamicRoutes, dynamicRouteTemplates)\n );\n },\n 100\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 * Recursively walk a directory and call the callback with the file path.\n */\nasync function walk(directory: string, callback: (filePath: string) => void) {\n const files = await fs.readdir(directory);\n for (const file of files) {\n const p = path.join(directory, file);\n if ((await fs.stat(p)).isDirectory()) {\n await walk(p, callback);\n } else {\n // Normalise the paths so they are easier to convert to URLs\n const normalizedPath = p.replaceAll(path.sep, '/');\n callback(normalizedPath);\n }\n }\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","resolveFrom","silent","projectRoot","typedRoutes","legacyTypedRoutes","typedRoutesModulePath","server","metro","typesDirectory","routerDirectory","plugin","process","env","EXPO_ROUTER_APP_ROOT","require","metroWatchTypeScriptFiles","eventTypes","callback","getWatchHandler","version","regenerateDeclarations","filePathToRoute","staticRoutes","dynamicRoutes","addFilePath","isRouteFile","filePath","type","shouldRegenerate","route","delete","regenerateRouterDotTS","Set","values","flatMap","v","Array","from","keys","directoryExistsAsync","walk","debounce","fn","delay","timeoutId","args","clearTimeout","setTimeout","apply","typesDir","dynamicRouteTemplates","fs","mkdir","recursive","writeFile","path","resolve","routerDotTSTemplate","dynamicRouteParams","appRoot","filePathSeperator","sep","Map","normalizedFilePath","replaceAll","normalizedAppRoot","replace","match","relative","startsWith","isAbsolute","has","dynamicParams","matchAll","map","isDynamic","size","addRoute","originalRoute","set","get","add","includes","routeWithoutGroups","routeWithSingleGroup","s","join","directory","files","readdir","file","p","stat","isDirectory","normalizedPath","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 fs from 'fs/promises';\nimport path from 'path';\n\nimport { directoryExistsAsync } from '../../../utils/dir';\nimport { unsafeTemplate } from '../../../utils/template';\nimport { 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 const typedRoutesModule = require.resolve('@expo/router-server/build/typed-routes');\n return typedRoutes(typedRoutesModule, options);\n}\n\nasync function typedRoutes(\n typedRoutesModulePath: any,\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 = require(typedRoutesModulePath);\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\nfunction debounce<U, T extends (this: U, ...args: any[]) => void>(fn: T, delay: number): T {\n let timeoutId: NodeJS.Timeout | undefined;\n return function (this: U, ...args: any[]) {\n clearTimeout(timeoutId);\n // NOTE(@hassankhan): The cast to `NodeJS.Timeout` below is a hack to work around an issue\n // with TypeScript where React Native's types are being imported before Node types\n timeoutId = setTimeout(() => fn.apply(this, args), delay) as unknown as NodeJS.Timeout;\n } as T;\n}\n\n/**\n * Generate a router.d.ts file that contains all of the routes in the project.\n * Should be debounced as its very common for developers to make changes to multiple files at once (eg Save All)\n */\nconst regenerateRouterDotTS = debounce(\n async (\n typesDir: string,\n staticRoutes: Set<string>,\n dynamicRoutes: Set<string>,\n dynamicRouteTemplates: Set<string>\n ) => {\n await fs.mkdir(typesDir, { recursive: true });\n await fs.writeFile(\n path.resolve(typesDir, './router.d.ts'),\n getTemplateString(staticRoutes, dynamicRoutes, dynamicRouteTemplates)\n );\n },\n 100\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 * Recursively walk a directory and call the callback with the file path.\n */\nasync function walk(directory: string, callback: (filePath: string) => void) {\n const files = await fs.readdir(directory);\n for (const file of files) {\n const p = path.join(directory, file);\n if ((await fs.stat(p)).isDirectory()) {\n await walk(p, callback);\n } else {\n // Normalise the paths so they are easier to convert to URLs\n const normalizedPath = p.replaceAll(path.sep, '/');\n callback(normalizedPath);\n }\n }\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","debounce","fn","delay","timeoutId","args","clearTimeout","setTimeout","apply","regenerateRouterDotTS","typesDir","staticRoutes","dynamicRoutes","dynamicRouteTemplates","fs","mkdir","recursive","writeFile","path","routerDotTSTemplate","dynamicRouteParams","appRoot","filePathSeperator","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","walk","directory","files","readdir","file","p","stat","isDirectory","normalizedPath","routes","groupsMatch","group","trim","unsafeTemplate"],"mappings":"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"}