@expo/cli 55.0.32 → 55.0.34

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 (47) hide show
  1. package/build/bin/cli +1 -1
  2. package/build/src/events/index.js +1 -1
  3. package/build/src/export/createMetadataJson.js.map +1 -1
  4. package/build/src/export/embed/exportEmbedAsync.js +6 -3
  5. package/build/src/export/embed/exportEmbedAsync.js.map +1 -1
  6. package/build/src/export/embed/resolveOptions.js +2 -1
  7. package/build/src/export/embed/resolveOptions.js.map +1 -1
  8. package/build/src/export/exportApp.js +1 -1
  9. package/build/src/export/exportApp.js.map +1 -1
  10. package/build/src/export/exportHermes.js +10 -1
  11. package/build/src/export/exportHermes.js.map +1 -1
  12. package/build/src/export/resolveOptions.js +9 -10
  13. package/build/src/export/resolveOptions.js.map +1 -1
  14. package/build/src/export/saveAssets.js.map +1 -1
  15. package/build/src/export/static.js +6 -0
  16. package/build/src/export/static.js.map +1 -0
  17. package/build/src/run/android/resolveInstallApkName.js +48 -1
  18. package/build/src/run/android/resolveInstallApkName.js.map +1 -1
  19. package/build/src/run/ios/XcodeBuild.js +23 -0
  20. package/build/src/run/ios/XcodeBuild.js.map +1 -1
  21. package/build/src/run/ios/appleDevice/client/LockdowndClient.js +1 -1
  22. package/build/src/run/ios/appleDevice/client/LockdowndClient.js.map +1 -1
  23. package/build/src/serve/serveAsync.js +23 -11
  24. package/build/src/serve/serveAsync.js.map +1 -1
  25. package/build/src/serve/static.js +69 -0
  26. package/build/src/serve/static.js.map +1 -0
  27. package/build/src/start/server/metro/createExpoAutolinkingResolver.js +21 -8
  28. package/build/src/start/server/metro/createExpoAutolinkingResolver.js.map +1 -1
  29. package/build/src/start/server/metro/instantiateMetro.js +5 -2
  30. package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
  31. package/build/src/start/server/metro/withMetroMultiPlatform.js +89 -28
  32. package/build/src/start/server/metro/withMetroMultiPlatform.js.map +1 -1
  33. package/build/src/start/server/middleware/ExpoGoManifestHandlerMiddleware.js +3 -1
  34. package/build/src/start/server/middleware/ExpoGoManifestHandlerMiddleware.js.map +1 -1
  35. package/build/src/start/server/middleware/InterstitialPageMiddleware.js +3 -1
  36. package/build/src/start/server/middleware/InterstitialPageMiddleware.js.map +1 -1
  37. package/build/src/start/server/middleware/resolvePlatform.js +4 -2
  38. package/build/src/start/server/middleware/resolvePlatform.js.map +1 -1
  39. package/build/src/start/server/platformBundlers.js +3 -1
  40. package/build/src/start/server/platformBundlers.js.map +1 -1
  41. package/build/src/utils/findUp.js +17 -19
  42. package/build/src/utils/findUp.js.map +1 -1
  43. package/build/src/utils/qr.js +5 -4
  44. package/build/src/utils/qr.js.map +1 -1
  45. package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
  46. package/build/src/utils/telemetry/utils/context.js +1 -1
  47. package/package.json +14 -14
@@ -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 {\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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"}
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 // TODO(@kitten): Runtime-version resolution only reads ios/android config\n // tvos/macos fall back to the shared `runtimeVersion` until they get explicit support\n requestOptions.platform as 'android' | 'ios'\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":";;;;;;;;;;;IAiDaA,+BAA+B;eAA/BA;;IAZDC,mBAAmB;eAAnBA;;;;yBApCY;;;;;;;gEACJ;;;;;;;gEACD;;;;;;;yBAOZ;;;;;;;yBACyC;;;;;;oCAEQ;iCACG;2DACD;8BAEtB;sBACD;6BAK5B;wBACsB;qBACH;;;;;;AAE1B,MAAMC,iBAAiB;AAEvB,MAAMC,QAAQC,QAAQ,SAAS;AAE/B,IAAIC,4BAA4BC,iCAAoB;AACpD,IAAID,0BAA0BE,UAAU,CAACL,iBAAiB;IACxDG,4BACE,oBAAoBA,0BAA0BG,KAAK,CAACN,eAAeO,MAAM;AAC7E;AAEO,IAAA,AAAKR,6CAAAA;;;;;WAAAA;;AAYL,MAAMD,wCAAwCU,sCAAkB;IAC9DC,iBAAiBC,GAAkB,EAA6B;QACrE,IAAIC,WAAWC,IAAAA,oCAAmB,EAACF;QAEnC,IAAI,CAACC,UAAU;YACbV,MACE,CAAC,yFAAyF,CAAC;YAE7FU,WAAW;QACb;QAEAE,IAAAA,sCAAqB,EAACF;QAEtB,+FAA+F;QAC/F,kGAAkG;QAClG,gGAAgG;QAChG,0BAA0B;QAC1B,MAAMG,SAASC,IAAAA,kBAAO,EAACL;QACvB,MAAMM,eAAeF,OAAOG,KAAK,CAAC;YAChC;YACA;YACA;YACA;YACA;SACD;QAED,IAAIC;QACJ,OAAQF;YACN,KAAK;gBACHE;gBACA;YACF,KAAK;gBACHA;gBACA;YACF,KAAK;gBACHA;gBACA;YACF;gBACEA;gBACA;QACJ;QAEA,MAAMC,kBAAkBT,IAAIU,OAAO,CAAC,wBAAwB;QAE5D,OAAO;YACLF;YACAP;YACAQ,iBAAiBA,kBAAkBE,OAAOF,mBAAmB;YAC7DG,UAAUC,IAAAA,cAAS,EAACb,IAAIU,OAAO,CAAC,OAAO;YACvCI,UAAUd,IAAIU,OAAO,CAAC,oBAAoB;QAC5C;IACF;IAEQK,4BAAqC;QAC3C,MAAML,UAAU,IAAIM;QACpB,+DAA+D;QAC/DN,QAAQO,GAAG,CAAC,yBAAyB;QACrCP,QAAQO,GAAG,CAAC,oBAAoB;QAChCP,QAAQO,GAAG,CAAC,iBAAiB;QAC7B,OAAOP;IACT;IAEA,MAAaQ,0BACXC,cAAyC,EACtB;YAgCEC,gBAAAA;QA/BrB,MAAM,EAAEA,GAAG,EAAEC,OAAO,EAAEC,YAAY,EAAEC,SAAS,EAAE,GAC7C,MAAM,IAAI,CAACC,4BAA4B,CAACL;QAE1C,MAAMM,iBACJ,AAAC,MAAMC,IAAAA,oFAAyC,EAAC;YAC/CC,aAAa,IAAI,CAACA,WAAW;YAC7B1B,UAAUkB,eAAelB,QAAQ;QACnC,MACA,gGAAgG;QAChG,oGAAoG;QACpG,iCAAiC;QAChC,MAAM2B,wBAAO,CAACC,sBAAsB,CACnC,IAAI,CAACF,WAAW,EAChB;YAAE,GAAGP,GAAG;YAAEK,gBAAgBL,IAAIK,cAAc,IAAI;gBAAEK,QAAQ;YAAa;QAAE,GACzE,0EAA0E;QAC1E,sFAAsF;QACtFX,eAAelB,QAAQ;QAE3B,IAAI,CAACwB,gBAAgB;YACnB,MAAM,IAAIM,oBAAY,CACpB,uBACA,CAAC,kDAAkD,EAAEZ,eAAelB,QAAQ,CAAC,CAAC,CAAC;QAEnF;QAEA,MAAM+B,kBAAkB,MAAMC,IAAAA,oCAAuB,EACnDb,KACAD,eAAeV,eAAe,EAC9B,IAAI,CAACyB,OAAO,CAACC,cAAc;QAG7B,MAAMC,gBAAehB,aAAAA,IAAIiB,KAAK,sBAATjB,iBAAAA,WAAWkB,GAAG,qBAAdlB,eAAgBmB,SAAS;QAC9C,MAAMC,WAAW,MAAMpD,gCAAgCqD,gBAAgB,CAAC;YACtEC,MAAMtB,IAAIsB,IAAI;YACdV;QACF;QAEA,MAAMW,sBAA2C;YAC/CC,IAAIC,iBAAM,CAACC,UAAU;YACrBC,WAAW,IAAIC,OAAOC,WAAW;YACjCxB;YACAyB,aAAa;gBACXC,KAAK;gBACLC,aAAa;gBACbC,KAAK9B;YACP;YACA+B,QAAQ,EAAE;YACVC,UAAU,CAAC;YACXlB,OAAO;gBACLC,KAAK;oBACHC,WAAWH,gBAAgBoB;gBAC7B;gBACAC,YAAY;oBACV,GAAGrC,GAAG;oBACNC;gBACF;gBACAqC,QAAQpC;gBACRkB;YACF;QACF;QAEA,MAAMmB,sBAAsBC,KAAKC,SAAS,CAAClB;QAE3C,IAAImB;QACJ,IAAIC,uBAAsC;QAC1C,IAAI/B,iBAAiB;YACnB,MAAMgC,YAAYC,IAAAA,+BAAkB,EAACN,qBAAqB3B;YAC1D8B,sBAAsB;gBACpB,kBAAkBI,IAAAA,wCAAmB,EACnCC,uCAAuC;oBACrCC,OAAOpC,gBAAgBqC,KAAK;oBAC5BC,KAAKN;oBACLO,KAAK;gBACP;YAEJ;YACAR,uBAAuB/B,gBAAgBwC,2BAA2B,CAACC,IAAI,CAAC;QAC1E;QAEA,OAAQtD,eAAeX,mBAAmB;YACxC;gBAA0C;oBACxC,OAAO,IAAI,CAACkE,mBAAmB,CAAC;wBAC9Bf;wBACAG;wBACAC;oBACF;gBACF;YACA;YACA;YACA;gBAAqC;oBACnC,MAAMrD,UAAU,IAAI,CAACK,yBAAyB;oBAC9CL,QAAQO,GAAG,CACT,gBACA7B,gCAAgCuF,oCAAoC,CAClExD,eAAeX,mBAAmB;oBAGtC,IAAIsD,uCAAAA,mBAAqB,CAAC,iBAAiB,EAAE;wBAC3CpD,QAAQO,GAAG,CAAC,kBAAkB6C,mBAAmB,CAAC,iBAAiB;oBACrE;oBACA,OAAO,IAAIc,SAASjB,qBAAqB;wBAAEkB,QAAQ;wBAAKnE;oBAAQ;gBAClE;QACF;IACF;IAEA,OAAeiE,qCACbnE,mBAAwC,EAChC;QACR,OAAQA;YACN;gBACE,OAAO;YACT;gBACE,OAAO;YACT;gBACE,OAAO;YACT;gBACE,OAAO;QACX;IACF;IAEQkE,oBAAoB,EAC1Bf,mBAAmB,EACnBG,mBAAmB,EACnBC,oBAAoB,EAKrB,EAAY;QACX,MAAMe,QAAqB;YACzB;gBACE;gBACA,IAAIC,CAAAA,YAAY,eAAC,CAAC;oBAACpB;iBAAoB,EAAE,YAAY;oBACnDqB,MAAM;oBACNtE,SAASoD;gBACX;aACD;SACF;QACD,IAAIC,wBAAwBA,qBAAqBlE,MAAM,GAAG,GAAG;YAC3DiF,MAAMG,IAAI,CAAC;gBACT;gBACA,IAAIF,CAAAA,YAAY,eAAC,CAAC;oBAAChB;iBAAqB,EAAE,qBAAqB;oBAC7DiB,MAAM;gBACR;aACD;QACH;QACA,MAAMtE,UAAU,IAAI,CAACK,yBAAyB;QAC9CL,QAAQO,GAAG,CAAC,gBAAgBxB;QAC5B,OAAO,IAAImF,SAASM,IAAAA,6BAAgB,EAACC,IAAAA,4BAAe,EAACL,SAAS;YAAED,QAAQ;YAAKnE;QAAQ;IACvF;IAEA,aAAqB+B,iBAAiB,EACpCC,IAAI,EACJV,eAAe,EAIhB,EAAmB;QAClB,MAAMoD,8BAA8BpD,mCAAAA,gBAAiBQ,QAAQ;QAC7D,IAAI4C,6BAA6B;YAC/B,OAAOA;QACT;QAEA,YAAY;QACZ,qBAAqB;QACrB,kEAAkE;QAClE,iDAAiD;QACjD,KAAK;QACL,OAAO,MAAMC,0BAA0B3C;IACzC;AACF;AAEA,eAAe2C,0BAA0B3C,IAAY;IACnD,MAAM4C,0BAA0B,MAAMC,IAAAA,iCAAmB;IACzD,OAAO,CAAC,CAAC,EAAEC,wBAAkB,CAAC,CAAC,EAAE9C,KAAK,CAAC,EAAE4C,yBAAyB;AACpE;AAEA,SAASnB,uCAAuCsB,GAA8B;IAC5E,OAAO,IAAIC,IACTC,OAAOC,OAAO,CAACH,KAAKI,GAAG,CAAC,CAAC,CAACC,GAAGC,EAAE;QAC7B,OAAO;YAACD;YAAG;gBAACC;gBAAG,IAAIL;aAAM;SAAC;IAC5B;AAEJ"}
@@ -87,7 +87,9 @@ class InterstitialPageMiddleware extends _ExpoMiddleware.ExpoMiddleware {
87
87
  (0, _resolvePlatform.assertRuntimePlatform)(platform);
88
88
  const { exp } = (0, _config().getConfig)(this.projectRoot);
89
89
  const { appName } = (0, _config().getNameFromConfig)(exp);
90
- const runtimeVersion = await (0, _Updates().getRuntimeVersionNullableAsync)(this.projectRoot, exp, platform);
90
+ const runtimeVersion = await (0, _Updates().getRuntimeVersionNullableAsync)(this.projectRoot, exp, // TODO(@kitten): Runtime-version resolution only reads ios/android config
91
+ // tvos/macos fall back to the shared `runtimeVersion` until they get explicit support
92
+ platform);
91
93
  const sdkVersion = exp.sdkVersion ?? null;
92
94
  return {
93
95
  appName: appName ?? 'App',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/start/server/middleware/InterstitialPageMiddleware.ts"],"sourcesContent":["import { getConfig, getNameFromConfig } from '@expo/config';\nimport { getRuntimeVersionNullableAsync } from '@expo/config-plugins/build/utils/Updates';\nimport { readFile } from 'fs/promises';\nimport path from 'path';\nimport resolveFrom from 'resolve-from';\n\nimport { disableResponseCache, ExpoMiddleware } from './ExpoMiddleware';\nimport {\n assertMissingRuntimePlatform,\n assertRuntimePlatform,\n parsePlatformHeader,\n resolvePlatformFromUserAgentHeader,\n RuntimePlatform,\n} from './resolvePlatform';\nimport { ServerRequest, ServerResponse } from './server.types';\n\ntype ProjectVersion = {\n type: 'sdk' | 'runtime';\n version: string | null;\n};\n\nconst debug = require('debug')(\n 'expo:start:server:middleware:interstitialPage'\n) as typeof console.log;\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nexport const LoadingEndpoint = '/_expo/loading';\n\nexport class InterstitialPageMiddleware extends ExpoMiddleware {\n constructor(\n projectRoot: string,\n protected options: { scheme: string | null } = { scheme: null }\n ) {\n super(projectRoot, [LoadingEndpoint]);\n }\n\n /** Get the template HTML page and inject values. */\n async _getPageAsync({\n appName,\n projectVersion,\n }: {\n appName: string;\n projectVersion: ProjectVersion;\n }): Promise<string> {\n const templatePath =\n // Production: This will resolve when installed in the project.\n resolveFrom.silent(this.projectRoot, 'expo/static/loading-page/index.html') ??\n // Development: This will resolve when testing locally.\n path.resolve(__dirname, '../../../../../static/loading-page/index.html');\n let content = (await readFile(templatePath)).toString('utf-8');\n\n content = content.replace(/{{\\s*AppName\\s*}}/, escapeHtml(appName));\n content = content.replace(/{{\\s*Path\\s*}}/, escapeHtml(this.projectRoot));\n content = content.replace(/{{\\s*Scheme\\s*}}/, escapeHtml(this.options.scheme ?? 'Unknown'));\n content = content.replace(\n /{{\\s*ProjectVersionType\\s*}}/,\n `${projectVersion.type === 'sdk' ? 'SDK' : 'Runtime'} version`\n );\n content = content.replace(\n /{{\\s*ProjectVersion\\s*}}/,\n escapeHtml(projectVersion.version ?? 'Undetected')\n );\n\n return content;\n }\n\n /** Get settings for the page from the project config. */\n async _getProjectOptionsAsync(platform: RuntimePlatform): Promise<{\n appName: string;\n projectVersion: ProjectVersion;\n }> {\n assertRuntimePlatform(platform);\n\n const { exp } = getConfig(this.projectRoot);\n const { appName } = getNameFromConfig(exp);\n const runtimeVersion = await getRuntimeVersionNullableAsync(this.projectRoot, exp, platform);\n const sdkVersion = exp.sdkVersion ?? null;\n\n return {\n appName: appName ?? 'App',\n projectVersion:\n sdkVersion && !runtimeVersion\n ? { type: 'sdk', version: sdkVersion }\n : { type: 'runtime', version: runtimeVersion },\n };\n }\n\n async handleRequestAsync(req: ServerRequest, res: ServerResponse): Promise<void> {\n res = disableResponseCache(res);\n res.setHeader('Content-Type', 'text/html');\n\n const platform = parsePlatformHeader(req) ?? resolvePlatformFromUserAgentHeader(req);\n assertMissingRuntimePlatform(platform);\n assertRuntimePlatform(platform);\n\n const { appName, projectVersion } = await this._getProjectOptionsAsync(platform);\n debug(\n `Create loading page. (platform: ${platform}, appName: ${appName}, projectVersion: ${projectVersion.version}, type: ${projectVersion.type})`\n );\n const content = await this._getPageAsync({ appName, projectVersion });\n res.end(content);\n }\n}\n"],"names":["InterstitialPageMiddleware","LoadingEndpoint","debug","require","escapeHtml","value","replace","ExpoMiddleware","constructor","projectRoot","options","scheme","_getPageAsync","appName","projectVersion","templatePath","resolveFrom","silent","path","resolve","__dirname","content","readFile","toString","type","version","_getProjectOptionsAsync","platform","assertRuntimePlatform","exp","getConfig","getNameFromConfig","runtimeVersion","getRuntimeVersionNullableAsync","sdkVersion","handleRequestAsync","req","res","disableResponseCache","setHeader","parsePlatformHeader","resolvePlatformFromUserAgentHeader","assertMissingRuntimePlatform","end"],"mappings":";;;;;;;;;;;IAoCaA,0BAA0B;eAA1BA;;IAFAC,eAAe;eAAfA;;;;yBAlCgC;;;;;;;yBACE;;;;;;;yBACtB;;;;;;;gEACR;;;;;;;gEACO;;;;;;gCAE6B;iCAO9C;;;;;;AAQP,MAAMC,QAAQC,QAAQ,SACpB;AAGF,SAASC,WAAWC,KAAa;IAC/B,OAAOA,MACJC,OAAO,CAAC,MAAM,SACdA,OAAO,CAAC,MAAM,QACdA,OAAO,CAAC,MAAM,QACdA,OAAO,CAAC,MAAM,UACdA,OAAO,CAAC,MAAM;AACnB;AAEO,MAAML,kBAAkB;AAExB,MAAMD,mCAAmCO,8BAAc;IAC5DC,YACEC,WAAmB,EACnB,AAAUC,UAAqC;QAAEC,QAAQ;IAAK,CAAC,CAC/D;QACA,KAAK,CAACF,aAAa;YAACR;SAAgB,QAF1BS,UAAAA;IAGZ;IAEA,kDAAkD,GAClD,MAAME,cAAc,EAClBC,OAAO,EACPC,cAAc,EAIf,EAAmB;QAClB,MAAMC,eACJ,+DAA+D;QAC/DC,sBAAW,CAACC,MAAM,CAAC,IAAI,CAACR,WAAW,EAAE,0CACrC,uDAAuD;QACvDS,eAAI,CAACC,OAAO,CAACC,WAAW;QAC1B,IAAIC,UAAU,AAAC,CAAA,MAAMC,IAAAA,oBAAQ,EAACP,aAAY,EAAGQ,QAAQ,CAAC;QAEtDF,UAAUA,QAAQf,OAAO,CAAC,qBAAqBF,WAAWS;QAC1DQ,UAAUA,QAAQf,OAAO,CAAC,kBAAkBF,WAAW,IAAI,CAACK,WAAW;QACvEY,UAAUA,QAAQf,OAAO,CAAC,oBAAoBF,WAAW,IAAI,CAACM,OAAO,CAACC,MAAM,IAAI;QAChFU,UAAUA,QAAQf,OAAO,CACvB,gCACA,GAAGQ,eAAeU,IAAI,KAAK,QAAQ,QAAQ,UAAU,QAAQ,CAAC;QAEhEH,UAAUA,QAAQf,OAAO,CACvB,4BACAF,WAAWU,eAAeW,OAAO,IAAI;QAGvC,OAAOJ;IACT;IAEA,uDAAuD,GACvD,MAAMK,wBAAwBC,QAAyB,EAGpD;QACDC,IAAAA,sCAAqB,EAACD;QAEtB,MAAM,EAAEE,GAAG,EAAE,GAAGC,IAAAA,mBAAS,EAAC,IAAI,CAACrB,WAAW;QAC1C,MAAM,EAAEI,OAAO,EAAE,GAAGkB,IAAAA,2BAAiB,EAACF;QACtC,MAAMG,iBAAiB,MAAMC,IAAAA,yCAA8B,EAAC,IAAI,CAACxB,WAAW,EAAEoB,KAAKF;QACnF,MAAMO,aAAaL,IAAIK,UAAU,IAAI;QAErC,OAAO;YACLrB,SAASA,WAAW;YACpBC,gBACEoB,cAAc,CAACF,iBACX;gBAAER,MAAM;gBAAOC,SAASS;YAAW,IACnC;gBAAEV,MAAM;gBAAWC,SAASO;YAAe;QACnD;IACF;IAEA,MAAMG,mBAAmBC,GAAkB,EAAEC,GAAmB,EAAiB;QAC/EA,MAAMC,IAAAA,oCAAoB,EAACD;QAC3BA,IAAIE,SAAS,CAAC,gBAAgB;QAE9B,MAAMZ,WAAWa,IAAAA,oCAAmB,EAACJ,QAAQK,IAAAA,mDAAkC,EAACL;QAChFM,IAAAA,6CAA4B,EAACf;QAC7BC,IAAAA,sCAAqB,EAACD;QAEtB,MAAM,EAAEd,OAAO,EAAEC,cAAc,EAAE,GAAG,MAAM,IAAI,CAACY,uBAAuB,CAACC;QACvEzB,MACE,CAAC,gCAAgC,EAAEyB,SAAS,WAAW,EAAEd,QAAQ,kBAAkB,EAAEC,eAAeW,OAAO,CAAC,QAAQ,EAAEX,eAAeU,IAAI,CAAC,CAAC,CAAC;QAE9I,MAAMH,UAAU,MAAM,IAAI,CAACT,aAAa,CAAC;YAAEC;YAASC;QAAe;QACnEuB,IAAIM,GAAG,CAACtB;IACV;AACF"}
1
+ {"version":3,"sources":["../../../../../src/start/server/middleware/InterstitialPageMiddleware.ts"],"sourcesContent":["import { getConfig, getNameFromConfig } from '@expo/config';\nimport { getRuntimeVersionNullableAsync } from '@expo/config-plugins/build/utils/Updates';\nimport { readFile } from 'fs/promises';\nimport path from 'path';\nimport resolveFrom from 'resolve-from';\n\nimport { disableResponseCache, ExpoMiddleware } from './ExpoMiddleware';\nimport {\n assertMissingRuntimePlatform,\n assertRuntimePlatform,\n parsePlatformHeader,\n resolvePlatformFromUserAgentHeader,\n RuntimePlatform,\n} from './resolvePlatform';\nimport { ServerRequest, ServerResponse } from './server.types';\n\ntype ProjectVersion = {\n type: 'sdk' | 'runtime';\n version: string | null;\n};\n\nconst debug = require('debug')(\n 'expo:start:server:middleware:interstitialPage'\n) as typeof console.log;\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nexport const LoadingEndpoint = '/_expo/loading';\n\nexport class InterstitialPageMiddleware extends ExpoMiddleware {\n constructor(\n projectRoot: string,\n protected options: { scheme: string | null } = { scheme: null }\n ) {\n super(projectRoot, [LoadingEndpoint]);\n }\n\n /** Get the template HTML page and inject values. */\n async _getPageAsync({\n appName,\n projectVersion,\n }: {\n appName: string;\n projectVersion: ProjectVersion;\n }): Promise<string> {\n const templatePath =\n // Production: This will resolve when installed in the project.\n resolveFrom.silent(this.projectRoot, 'expo/static/loading-page/index.html') ??\n // Development: This will resolve when testing locally.\n path.resolve(__dirname, '../../../../../static/loading-page/index.html');\n let content = (await readFile(templatePath)).toString('utf-8');\n\n content = content.replace(/{{\\s*AppName\\s*}}/, escapeHtml(appName));\n content = content.replace(/{{\\s*Path\\s*}}/, escapeHtml(this.projectRoot));\n content = content.replace(/{{\\s*Scheme\\s*}}/, escapeHtml(this.options.scheme ?? 'Unknown'));\n content = content.replace(\n /{{\\s*ProjectVersionType\\s*}}/,\n `${projectVersion.type === 'sdk' ? 'SDK' : 'Runtime'} version`\n );\n content = content.replace(\n /{{\\s*ProjectVersion\\s*}}/,\n escapeHtml(projectVersion.version ?? 'Undetected')\n );\n\n return content;\n }\n\n /** Get settings for the page from the project config. */\n async _getProjectOptionsAsync(platform: RuntimePlatform): Promise<{\n appName: string;\n projectVersion: ProjectVersion;\n }> {\n assertRuntimePlatform(platform);\n\n const { exp } = getConfig(this.projectRoot);\n const { appName } = getNameFromConfig(exp);\n const runtimeVersion = await getRuntimeVersionNullableAsync(\n this.projectRoot,\n exp,\n // TODO(@kitten): Runtime-version resolution only reads ios/android config\n // tvos/macos fall back to the shared `runtimeVersion` until they get explicit support\n platform as 'android' | 'ios'\n );\n const sdkVersion = exp.sdkVersion ?? null;\n\n return {\n appName: appName ?? 'App',\n projectVersion:\n sdkVersion && !runtimeVersion\n ? { type: 'sdk', version: sdkVersion }\n : { type: 'runtime', version: runtimeVersion },\n };\n }\n\n async handleRequestAsync(req: ServerRequest, res: ServerResponse): Promise<void> {\n res = disableResponseCache(res);\n res.setHeader('Content-Type', 'text/html');\n\n const platform = parsePlatformHeader(req) ?? resolvePlatformFromUserAgentHeader(req);\n assertMissingRuntimePlatform(platform);\n assertRuntimePlatform(platform);\n\n const { appName, projectVersion } = await this._getProjectOptionsAsync(platform);\n debug(\n `Create loading page. (platform: ${platform}, appName: ${appName}, projectVersion: ${projectVersion.version}, type: ${projectVersion.type})`\n );\n const content = await this._getPageAsync({ appName, projectVersion });\n res.end(content);\n }\n}\n"],"names":["InterstitialPageMiddleware","LoadingEndpoint","debug","require","escapeHtml","value","replace","ExpoMiddleware","constructor","projectRoot","options","scheme","_getPageAsync","appName","projectVersion","templatePath","resolveFrom","silent","path","resolve","__dirname","content","readFile","toString","type","version","_getProjectOptionsAsync","platform","assertRuntimePlatform","exp","getConfig","getNameFromConfig","runtimeVersion","getRuntimeVersionNullableAsync","sdkVersion","handleRequestAsync","req","res","disableResponseCache","setHeader","parsePlatformHeader","resolvePlatformFromUserAgentHeader","assertMissingRuntimePlatform","end"],"mappings":"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"}
@@ -62,9 +62,11 @@ function assertRuntimePlatform(platform) {
62
62
  if (![
63
63
  'android',
64
64
  'ios',
65
- 'web'
65
+ 'web',
66
+ 'tvos',
67
+ 'macos'
66
68
  ].includes(stringifiedPlatform)) {
67
- throw new _errors.CommandError('PLATFORM_HEADER', `platform must be "android", "ios", or "web". Received: "${platform}"`);
69
+ throw new _errors.CommandError('PLATFORM_HEADER', `platform must be "android", "ios", "web", "tvos", or "macos". Received: "${platform}"`);
68
70
  }
69
71
  }
70
72
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/start/server/middleware/resolvePlatform.ts"],"sourcesContent":["import { parse } from 'url';\n\nimport { ServerRequest } from './server.types';\nimport { CommandError } from '../../../utils/errors';\n\nconst debug = require('debug')(\n 'expo:start:server:middleware:resolvePlatform'\n) as typeof console.log;\n\n/** Supported platforms */\nexport type RuntimePlatform = 'ios' | 'android';\n\n/**\n * Extract the runtime platform from the server request.\n * 1. Query param `platform`: `?platform=ios`\n * 2. Header `expo-platform`: `'expo-platform': ios`\n * 3. Legacy header `exponent-platform`: `'exponent-platform': ios`\n *\n * Returns first item in the case of an array.\n */\nexport function parsePlatformHeader(req: ServerRequest): string | null {\n const url = parse(req.url!, /* parseQueryString */ true);\n const platform =\n url.query?.platform || req.headers['expo-platform'] || req.headers['exponent-platform'];\n return (Array.isArray(platform) ? platform[0] : platform) ?? null;\n}\n\n/** Guess the platform from the user-agent header. */\nexport function resolvePlatformFromUserAgentHeader(req: ServerRequest): string | null {\n let platform = null;\n const userAgent = req.headers['user-agent'];\n if (userAgent?.match(/Android/i)) {\n platform = 'android';\n }\n if (userAgent?.match(/OculusBrowser|Quest/i)) {\n platform = 'android';\n }\n if (userAgent?.match(/iPhone|iPad/i)) {\n platform = 'ios';\n }\n debug(`Resolved platform ${platform} from user-agent header: ${userAgent}`);\n return platform;\n}\n\n/** Assert if the runtime platform is not included. */\nexport function assertMissingRuntimePlatform(platform?: any): asserts platform {\n if (!platform) {\n throw new CommandError(\n 'PLATFORM_HEADER',\n `Must specify \"expo-platform\" header or \"platform\" query parameter`\n );\n }\n}\n\n/** Assert if the runtime platform is not correct. */\nexport function assertRuntimePlatform(platform: string): asserts platform is RuntimePlatform {\n const stringifiedPlatform = String(platform);\n if (!['android', 'ios', 'web'].includes(stringifiedPlatform)) {\n throw new CommandError(\n 'PLATFORM_HEADER',\n `platform must be \"android\", \"ios\", or \"web\". Received: \"${platform}\"`\n );\n }\n}\n"],"names":["assertMissingRuntimePlatform","assertRuntimePlatform","parsePlatformHeader","resolvePlatformFromUserAgentHeader","debug","require","req","url","parse","platform","query","headers","Array","isArray","userAgent","match","CommandError","stringifiedPlatform","String","includes"],"mappings":";;;;;;;;;;;IA6CgBA,4BAA4B;eAA5BA;;IAUAC,qBAAqB;eAArBA;;IAnCAC,mBAAmB;eAAnBA;;IAQAC,kCAAkC;eAAlCA;;;;yBA5BM;;;;;;wBAGO;AAE7B,MAAMC,QAAQC,QAAQ,SACpB;AAcK,SAASH,oBAAoBI,GAAkB;QAGlDC;IAFF,MAAMA,MAAMC,IAAAA,YAAK,EAACF,IAAIC,GAAG,EAAG,oBAAoB,GAAG;IACnD,MAAME,WACJF,EAAAA,aAAAA,IAAIG,KAAK,qBAATH,WAAWE,QAAQ,KAAIH,IAAIK,OAAO,CAAC,gBAAgB,IAAIL,IAAIK,OAAO,CAAC,oBAAoB;IACzF,OAAO,AAACC,CAAAA,MAAMC,OAAO,CAACJ,YAAYA,QAAQ,CAAC,EAAE,GAAGA,QAAO,KAAM;AAC/D;AAGO,SAASN,mCAAmCG,GAAkB;IACnE,IAAIG,WAAW;IACf,MAAMK,YAAYR,IAAIK,OAAO,CAAC,aAAa;IAC3C,IAAIG,6BAAAA,UAAWC,KAAK,CAAC,aAAa;QAChCN,WAAW;IACb;IACA,IAAIK,6BAAAA,UAAWC,KAAK,CAAC,yBAAyB;QAC5CN,WAAW;IACb;IACA,IAAIK,6BAAAA,UAAWC,KAAK,CAAC,iBAAiB;QACpCN,WAAW;IACb;IACAL,MAAM,CAAC,kBAAkB,EAAEK,SAAS,yBAAyB,EAAEK,WAAW;IAC1E,OAAOL;AACT;AAGO,SAAST,6BAA6BS,QAAc;IACzD,IAAI,CAACA,UAAU;QACb,MAAM,IAAIO,oBAAY,CACpB,mBACA,CAAC,iEAAiE,CAAC;IAEvE;AACF;AAGO,SAASf,sBAAsBQ,QAAgB;IACpD,MAAMQ,sBAAsBC,OAAOT;IACnC,IAAI,CAAC;QAAC;QAAW;QAAO;KAAM,CAACU,QAAQ,CAACF,sBAAsB;QAC5D,MAAM,IAAID,oBAAY,CACpB,mBACA,CAAC,wDAAwD,EAAEP,SAAS,CAAC,CAAC;IAE1E;AACF"}
1
+ {"version":3,"sources":["../../../../../src/start/server/middleware/resolvePlatform.ts"],"sourcesContent":["import type { NativePlatform } from '@expo/config';\nimport { parse } from 'url';\n\nimport { ServerRequest } from './server.types';\nimport { CommandError } from '../../../utils/errors';\n\nconst debug = require('debug')(\n 'expo:start:server:middleware:resolvePlatform'\n) as typeof console.log;\n\n/** Supported native runtime platforms. */\nexport type RuntimePlatform = NativePlatform;\n\n/**\n * Extract the runtime platform from the server request.\n * 1. Query param `platform`: `?platform=ios`\n * 2. Header `expo-platform`: `'expo-platform': ios`\n * 3. Legacy header `exponent-platform`: `'exponent-platform': ios`\n *\n * Returns first item in the case of an array.\n */\nexport function parsePlatformHeader(req: ServerRequest): string | null {\n const url = parse(req.url!, /* parseQueryString */ true);\n const platform =\n url.query?.platform || req.headers['expo-platform'] || req.headers['exponent-platform'];\n return (Array.isArray(platform) ? platform[0] : platform) ?? null;\n}\n\n/** Guess the platform from the user-agent header. */\nexport function resolvePlatformFromUserAgentHeader(req: ServerRequest): string | null {\n let platform = null;\n const userAgent = req.headers['user-agent'];\n if (userAgent?.match(/Android/i)) {\n platform = 'android';\n }\n if (userAgent?.match(/OculusBrowser|Quest/i)) {\n platform = 'android';\n }\n if (userAgent?.match(/iPhone|iPad/i)) {\n platform = 'ios';\n }\n debug(`Resolved platform ${platform} from user-agent header: ${userAgent}`);\n return platform;\n}\n\n/** Assert if the runtime platform is not included. */\nexport function assertMissingRuntimePlatform(platform?: any): asserts platform {\n if (!platform) {\n throw new CommandError(\n 'PLATFORM_HEADER',\n `Must specify \"expo-platform\" header or \"platform\" query parameter`\n );\n }\n}\n\n/** Assert if the runtime platform is not correct. */\nexport function assertRuntimePlatform(platform: string): asserts platform is RuntimePlatform {\n const stringifiedPlatform = String(platform);\n if (!['android', 'ios', 'web', 'tvos', 'macos'].includes(stringifiedPlatform)) {\n throw new CommandError(\n 'PLATFORM_HEADER',\n `platform must be \"android\", \"ios\", \"web\", \"tvos\", or \"macos\". Received: \"${platform}\"`\n );\n }\n}\n"],"names":["assertMissingRuntimePlatform","assertRuntimePlatform","parsePlatformHeader","resolvePlatformFromUserAgentHeader","debug","require","req","url","parse","platform","query","headers","Array","isArray","userAgent","match","CommandError","stringifiedPlatform","String","includes"],"mappings":";;;;;;;;;;;IA8CgBA,4BAA4B;eAA5BA;;IAUAC,qBAAqB;eAArBA;;IAnCAC,mBAAmB;eAAnBA;;IAQAC,kCAAkC;eAAlCA;;;;yBA5BM;;;;;;wBAGO;AAE7B,MAAMC,QAAQC,QAAQ,SACpB;AAcK,SAASH,oBAAoBI,GAAkB;QAGlDC;IAFF,MAAMA,MAAMC,IAAAA,YAAK,EAACF,IAAIC,GAAG,EAAG,oBAAoB,GAAG;IACnD,MAAME,WACJF,EAAAA,aAAAA,IAAIG,KAAK,qBAATH,WAAWE,QAAQ,KAAIH,IAAIK,OAAO,CAAC,gBAAgB,IAAIL,IAAIK,OAAO,CAAC,oBAAoB;IACzF,OAAO,AAACC,CAAAA,MAAMC,OAAO,CAACJ,YAAYA,QAAQ,CAAC,EAAE,GAAGA,QAAO,KAAM;AAC/D;AAGO,SAASN,mCAAmCG,GAAkB;IACnE,IAAIG,WAAW;IACf,MAAMK,YAAYR,IAAIK,OAAO,CAAC,aAAa;IAC3C,IAAIG,6BAAAA,UAAWC,KAAK,CAAC,aAAa;QAChCN,WAAW;IACb;IACA,IAAIK,6BAAAA,UAAWC,KAAK,CAAC,yBAAyB;QAC5CN,WAAW;IACb;IACA,IAAIK,6BAAAA,UAAWC,KAAK,CAAC,iBAAiB;QACpCN,WAAW;IACb;IACAL,MAAM,CAAC,kBAAkB,EAAEK,SAAS,yBAAyB,EAAEK,WAAW;IAC1E,OAAOL;AACT;AAGO,SAAST,6BAA6BS,QAAc;IACzD,IAAI,CAACA,UAAU;QACb,MAAM,IAAIO,oBAAY,CACpB,mBACA,CAAC,iEAAiE,CAAC;IAEvE;AACF;AAGO,SAASf,sBAAsBQ,QAAgB;IACpD,MAAMQ,sBAAsBC,OAAOT;IACnC,IAAI,CAAC;QAAC;QAAW;QAAO;QAAO;QAAQ;KAAQ,CAACU,QAAQ,CAACF,sBAAsB;QAC7E,MAAM,IAAID,oBAAY,CACpB,mBACA,CAAC,yEAAyE,EAAEP,SAAS,CAAC,CAAC;IAE3F;AACF"}
@@ -32,7 +32,9 @@ function getPlatformBundlers(projectRoot, exp) {
32
32
  return {
33
33
  ios: ((_exp_ios = exp.ios) == null ? void 0 : _exp_ios.bundler) ?? 'metro',
34
34
  android: ((_exp_android = exp.android) == null ? void 0 : _exp_android.bundler) ?? 'metro',
35
- web
35
+ web,
36
+ tvos: 'metro',
37
+ macos: 'metro'
36
38
  };
37
39
  }
38
40
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/start/server/platformBundlers.ts"],"sourcesContent":["import type { ExpoConfig, ExpoConfigWeb, Platform } from '@expo/config';\nimport resolveFrom from 'resolve-from';\n\n/** Which bundler each platform should use. */\nexport type PlatformBundlers = Record<Platform, 'metro' | 'webpack'>;\n\n/** XDL-schema doesn't have `ios.bundler` and `android.bundler`, since this is technically deprecated */\ntype WithBundlerConfig = Pick<ExpoConfigWeb, 'bundler'> | undefined | null;\n\n/** Get the platform bundlers mapping. */\nexport function getPlatformBundlers(\n projectRoot: string,\n exp: Partial<ExpoConfig>\n): PlatformBundlers {\n /**\n * SDK 50+: The web bundler is dynamic based upon the presence of the `@expo/webpack-config` package.\n */\n let web = exp.web?.bundler;\n if (!web) {\n const resolved = resolveFrom.silent(projectRoot, '@expo/webpack-config/package.json');\n web = resolved ? 'webpack' : 'metro';\n }\n\n return {\n ios: (exp.ios as WithBundlerConfig)?.bundler ?? 'metro',\n android: (exp.android as WithBundlerConfig)?.bundler ?? 'metro',\n web,\n };\n}\n"],"names":["getPlatformBundlers","projectRoot","exp","web","bundler","resolved","resolveFrom","silent","ios","android"],"mappings":";;;;+BAUgBA;;;eAAAA;;;;gEATQ;;;;;;;;;;;AASjB,SAASA,oBACdC,WAAmB,EACnBC,GAAwB;QAKdA,UAOFA,UACIA;IAXZ;;GAEC,GACD,IAAIC,OAAMD,WAAAA,IAAIC,GAAG,qBAAPD,SAASE,OAAO;IAC1B,IAAI,CAACD,KAAK;QACR,MAAME,WAAWC,sBAAW,CAACC,MAAM,CAACN,aAAa;QACjDE,MAAME,WAAW,YAAY;IAC/B;IAEA,OAAO;QACLG,KAAK,EAACN,WAAAA,IAAIM,GAAG,qBAAR,AAACN,SAA+BE,OAAO,KAAI;QAChDK,SAAS,EAACP,eAAAA,IAAIO,OAAO,qBAAZ,AAACP,aAAmCE,OAAO,KAAI;QACxDD;IACF;AACF"}
1
+ {"version":3,"sources":["../../../../src/start/server/platformBundlers.ts"],"sourcesContent":["import type { ExpoConfig, ExpoConfigWeb, Platform } from '@expo/config';\nimport resolveFrom from 'resolve-from';\n\n/** Which bundler each platform should use. */\nexport type PlatformBundlers = Record<Platform, 'metro' | 'webpack'>;\n\n/** XDL-schema doesn't have `ios.bundler` and `android.bundler`, since this is technically deprecated */\ntype WithBundlerConfig = Pick<ExpoConfigWeb, 'bundler'> | undefined | null;\n\n/** Get the platform bundlers mapping. */\nexport function getPlatformBundlers(\n projectRoot: string,\n exp: Partial<ExpoConfig>\n): PlatformBundlers {\n /**\n * SDK 50+: The web bundler is dynamic based upon the presence of the `@expo/webpack-config` package.\n */\n let web = exp.web?.bundler;\n if (!web) {\n const resolved = resolveFrom.silent(projectRoot, '@expo/webpack-config/package.json');\n web = resolved ? 'webpack' : 'metro';\n }\n\n return {\n ios: (exp.ios as WithBundlerConfig)?.bundler ?? 'metro',\n android: (exp.android as WithBundlerConfig)?.bundler ?? 'metro',\n web,\n tvos: 'metro',\n macos: 'metro',\n };\n}\n"],"names":["getPlatformBundlers","projectRoot","exp","web","bundler","resolved","resolveFrom","silent","ios","android","tvos","macos"],"mappings":";;;;+BAUgBA;;;eAAAA;;;;gEATQ;;;;;;;;;;;AASjB,SAASA,oBACdC,WAAmB,EACnBC,GAAwB;QAKdA,UAOFA,UACIA;IAXZ;;GAEC,GACD,IAAIC,OAAMD,WAAAA,IAAIC,GAAG,qBAAPD,SAASE,OAAO;IAC1B,IAAI,CAACD,KAAK;QACR,MAAME,WAAWC,sBAAW,CAACC,MAAM,CAACN,aAAa;QACjDE,MAAME,WAAW,YAAY;IAC/B;IAEA,OAAO;QACLG,KAAK,EAACN,WAAAA,IAAIM,GAAG,qBAAR,AAACN,SAA+BE,OAAO,KAAI;QAChDK,SAAS,EAACP,eAAAA,IAAIO,OAAO,qBAAZ,AAACP,aAAmCE,OAAO,KAAI;QACxDD;QACAO,MAAM;QACNC,OAAO;IACT;AACF"}
@@ -16,16 +16,16 @@ _export(exports, {
16
16
  return findUpProjectRootOrAssert;
17
17
  }
18
18
  });
19
- function _path() {
20
- const data = /*#__PURE__*/ _interop_require_default(require("path"));
21
- _path = function() {
19
+ function _fs() {
20
+ const data = /*#__PURE__*/ _interop_require_default(require("fs"));
21
+ _fs = function() {
22
22
  return data;
23
23
  };
24
24
  return data;
25
25
  }
26
- function _resolvefrom() {
27
- const data = /*#__PURE__*/ _interop_require_default(require("resolve-from"));
28
- _resolvefrom = function() {
26
+ function _path() {
27
+ const data = /*#__PURE__*/ _interop_require_default(require("path"));
28
+ _path = function() {
29
29
  return data;
30
30
  };
31
31
  return data;
@@ -41,21 +41,19 @@ function findUpProjectRootOrAssert(cwd) {
41
41
  if (!projectRoot) {
42
42
  throw new _errors.CommandError(`Project root directory not found (working directory: ${cwd})`);
43
43
  }
44
- return projectRoot;
44
+ return _path().default.dirname(projectRoot);
45
45
  }
46
- function findUpProjectRoot(cwd) {
47
- const found = _resolvefrom().default.silent(cwd, './package.json');
48
- if (found) return _path().default.dirname(found);
49
- const parent = _path().default.dirname(cwd);
50
- if (parent === cwd) return null;
51
- return findUpProjectRoot(parent);
46
+ function findUpProjectRoot(root) {
47
+ return findFileInParents(root, 'package.json');
52
48
  }
53
- function findFileInParents(cwd, fileName) {
54
- const found = _resolvefrom().default.silent(cwd, `./${fileName}`);
55
- if (found) return found;
56
- const parent = _path().default.dirname(cwd);
57
- if (parent === cwd) return null;
58
- return findFileInParents(parent, fileName);
49
+ function findFileInParents(root, fileName) {
50
+ for(let dir = root; _path().default.dirname(dir) !== dir; dir = _path().default.dirname(dir)){
51
+ const file = _path().default.resolve(dir, fileName);
52
+ if (_fs().default.existsSync(file)) {
53
+ return file;
54
+ }
55
+ }
56
+ return null;
59
57
  }
60
58
 
61
59
  //# sourceMappingURL=findUp.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/findUp.ts"],"sourcesContent":["import path from 'path';\nimport resolveFrom from 'resolve-from';\n\nimport { CommandError } from '../utils/errors';\n\n/** Look up directories until one with a `package.json` can be found, assert if none can be found. */\nexport function findUpProjectRootOrAssert(cwd: string): string {\n const projectRoot = findUpProjectRoot(cwd);\n if (!projectRoot) {\n throw new CommandError(`Project root directory not found (working directory: ${cwd})`);\n }\n return projectRoot;\n}\n\nfunction findUpProjectRoot(cwd: string): string | null {\n const found = resolveFrom.silent(cwd, './package.json');\n if (found) return path.dirname(found);\n\n const parent = path.dirname(cwd);\n if (parent === cwd) return null;\n\n return findUpProjectRoot(parent);\n}\n\n/**\n * Find a file in the (closest) parent directories.\n * This will recursively look for the file, until the root directory is reached.\n */\nexport function findFileInParents(cwd: string, fileName: string): string | null {\n const found = resolveFrom.silent(cwd, `./${fileName}`);\n if (found) return found;\n\n const parent = path.dirname(cwd);\n if (parent === cwd) return null;\n\n return findFileInParents(parent, fileName);\n}\n"],"names":["findFileInParents","findUpProjectRootOrAssert","cwd","projectRoot","findUpProjectRoot","CommandError","found","resolveFrom","silent","path","dirname","parent","fileName"],"mappings":";;;;;;;;;;;IA4BgBA,iBAAiB;eAAjBA;;IAtBAC,yBAAyB;eAAzBA;;;;gEANC;;;;;;;gEACO;;;;;;wBAEK;;;;;;AAGtB,SAASA,0BAA0BC,GAAW;IACnD,MAAMC,cAAcC,kBAAkBF;IACtC,IAAI,CAACC,aAAa;QAChB,MAAM,IAAIE,oBAAY,CAAC,CAAC,qDAAqD,EAAEH,IAAI,CAAC,CAAC;IACvF;IACA,OAAOC;AACT;AAEA,SAASC,kBAAkBF,GAAW;IACpC,MAAMI,QAAQC,sBAAW,CAACC,MAAM,CAACN,KAAK;IACtC,IAAII,OAAO,OAAOG,eAAI,CAACC,OAAO,CAACJ;IAE/B,MAAMK,SAASF,eAAI,CAACC,OAAO,CAACR;IAC5B,IAAIS,WAAWT,KAAK,OAAO;IAE3B,OAAOE,kBAAkBO;AAC3B;AAMO,SAASX,kBAAkBE,GAAW,EAAEU,QAAgB;IAC7D,MAAMN,QAAQC,sBAAW,CAACC,MAAM,CAACN,KAAK,CAAC,EAAE,EAAEU,UAAU;IACrD,IAAIN,OAAO,OAAOA;IAElB,MAAMK,SAASF,eAAI,CAACC,OAAO,CAACR;IAC5B,IAAIS,WAAWT,KAAK,OAAO;IAE3B,OAAOF,kBAAkBW,QAAQC;AACnC"}
1
+ {"version":3,"sources":["../../../src/utils/findUp.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { CommandError } from '../utils/errors';\n\n/** Look up directories until one with a `package.json` can be found, assert if none can be found. */\nexport function findUpProjectRootOrAssert(cwd: string): string {\n const projectRoot = findUpProjectRoot(cwd);\n if (!projectRoot) {\n throw new CommandError(`Project root directory not found (working directory: ${cwd})`);\n }\n return path.dirname(projectRoot);\n}\n\nfunction findUpProjectRoot(root: string): string | null {\n return findFileInParents(root, 'package.json');\n}\n\n/**\n * Find a file in the (closest) parent directories.\n * This will recursively look for the file, until the root directory is reached.\n */\nexport function findFileInParents(root: string, fileName: string): string | null {\n for (let dir = root; path.dirname(dir) !== dir; dir = path.dirname(dir)) {\n const file = path.resolve(dir, fileName);\n if (fs.existsSync(file)) {\n return file;\n }\n }\n return null;\n}\n"],"names":["findFileInParents","findUpProjectRootOrAssert","cwd","projectRoot","findUpProjectRoot","CommandError","path","dirname","root","fileName","dir","file","resolve","fs","existsSync"],"mappings":";;;;;;;;;;;IAsBgBA,iBAAiB;eAAjBA;;IAhBAC,yBAAyB;eAAzBA;;;;gEAND;;;;;;;gEACE;;;;;;wBAEY;;;;;;AAGtB,SAASA,0BAA0BC,GAAW;IACnD,MAAMC,cAAcC,kBAAkBF;IACtC,IAAI,CAACC,aAAa;QAChB,MAAM,IAAIE,oBAAY,CAAC,CAAC,qDAAqD,EAAEH,IAAI,CAAC,CAAC;IACvF;IACA,OAAOI,eAAI,CAACC,OAAO,CAACJ;AACtB;AAEA,SAASC,kBAAkBI,IAAY;IACrC,OAAOR,kBAAkBQ,MAAM;AACjC;AAMO,SAASR,kBAAkBQ,IAAY,EAAEC,QAAgB;IAC9D,IAAK,IAAIC,MAAMF,MAAMF,eAAI,CAACC,OAAO,CAACG,SAASA,KAAKA,MAAMJ,eAAI,CAACC,OAAO,CAACG,KAAM;QACvE,MAAMC,OAAOL,eAAI,CAACM,OAAO,CAACF,KAAKD;QAC/B,IAAII,aAAE,CAACC,UAAU,CAACH,OAAO;YACvB,OAAOA;QACT;IACF;IACA,OAAO;AACT"}
@@ -81,18 +81,19 @@ function printQRCode(url) {
81
81
  };
82
82
  }
83
83
  /** On specific terminals we can print a smaller QR code */ function supportsSextants() {
84
- var _process_env_WT_SESSION, _process_env_KITTY_WINDOW_ID, _process_env_ALACRITTY_WINDOW_ID;
84
+ var _process_env_KITTY_WINDOW_ID, _process_env_ALACRITTY_WINDOW_ID;
85
85
  if (_env.env.CI || !_nodetty().default.isatty(1) || !_nodetty().default.isatty(2)) {
86
86
  return false;
87
87
  } else if (process.env.COLOR === '0' || process.env.COLOR === 'false') {
88
88
  return false;
89
89
  }
90
- const isWindowsTerminal = process.platform === 'win32' && !!((_process_env_WT_SESSION = process.env.WT_SESSION) == null ? void 0 : _process_env_WT_SESSION.length);
91
90
  const isGhostty = process.env.TERM_PROGRAM === 'ghostty';
92
91
  const isWezterm = process.env.TERM_PROGRAM === 'WezTerm';
92
+ // NOTE(@kitten): Zed regressed on rendering sextants
93
+ const isZed = process.env.TERM_PROGRAM === 'zed';
93
94
  const isKitty = !!((_process_env_KITTY_WINDOW_ID = process.env.KITTY_WINDOW_ID) == null ? void 0 : _process_env_KITTY_WINDOW_ID.length);
94
- const isAlacritty = !!((_process_env_ALACRITTY_WINDOW_ID = process.env.ALACRITTY_WINDOW_ID) == null ? void 0 : _process_env_ALACRITTY_WINDOW_ID.length);
95
- return isWindowsTerminal || isGhostty || isWezterm || isKitty || isAlacritty;
95
+ const isAlacritty = !!((_process_env_ALACRITTY_WINDOW_ID = process.env.ALACRITTY_WINDOW_ID) == null ? void 0 : _process_env_ALACRITTY_WINDOW_ID.length) && !isZed;
96
+ return isGhostty || isWezterm || isKitty || isAlacritty;
96
97
  }
97
98
  /** ANSI QR code output by using half-blocks (1x2-sized unicode blocks) */ function createHalfblockOutput(data) {
98
99
  const extent = Math.sqrt(data.byteLength) | 0;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/qr.ts"],"sourcesContent":["import tty from 'node:tty';\nimport { toQR } from 'toqr';\n\nimport { env } from './env';\nimport * as Log from '../log';\n\nexport interface QROutput {\n lines: number;\n print(): void;\n}\n\n/** Print the world famous 'Expo QR Code'. */\nexport function printQRCode(url: string): QROutput {\n const qr = toQR(url);\n const output = supportsSextants() ? createSextantOutput(qr) : createHalfblockOutput(qr);\n return {\n lines: output.split('\\n').length,\n print() {\n Log.log(output);\n },\n };\n}\n\n/** On specific terminals we can print a smaller QR code */\nfunction supportsSextants() {\n if (env.CI || !tty.isatty(1) || !tty.isatty(2)) {\n return false;\n } else if (process.env.COLOR === '0' || process.env.COLOR === 'false') {\n return false;\n }\n const isWindowsTerminal = process.platform === 'win32' && !!process.env.WT_SESSION?.length;\n const isGhostty = process.env.TERM_PROGRAM === 'ghostty';\n const isWezterm = process.env.TERM_PROGRAM === 'WezTerm';\n const isKitty = !!process.env.KITTY_WINDOW_ID?.length;\n const isAlacritty = !!process.env.ALACRITTY_WINDOW_ID?.length;\n return isWindowsTerminal || isGhostty || isWezterm || isKitty || isAlacritty;\n}\n\n/** ANSI QR code output by using half-blocks (1x2-sized unicode blocks) */\nfunction createHalfblockOutput(data: Uint8Array): string {\n const extent = Math.sqrt(data.byteLength) | 0;\n const CHAR_00 = '\\u2588';\n const CHAR_10 = '\\u2584';\n const CHAR_01 = '\\u2580';\n const CHAR_11 = ' ';\n let output = '';\n output += CHAR_10.repeat(extent + 2);\n for (let row = 0; row < extent; row += 2) {\n output += '\\n' + CHAR_00;\n for (let col = 0; col < extent; col++) {\n const value = (data[row * extent + col] << 1) | data[(row + 1) * extent + col];\n switch (value) {\n case 0b00:\n output += CHAR_00;\n break;\n case 0b01:\n output += CHAR_01;\n break;\n case 0b10:\n output += CHAR_10;\n break;\n case 0b11:\n output += CHAR_11;\n break;\n }\n }\n output += CHAR_00;\n }\n if (extent % 2 === 0) {\n output += '\\n' + CHAR_01.repeat(extent + 2);\n }\n output += '\\n';\n return output;\n}\n\n/** ANSI QR code output by using sextant-blocks (2x3-sized unicode blocks) */\nfunction createSextantOutput(data: Uint8Array): string {\n const getChar = (p: number): string => {\n // Invert then reverse\n let char = p ^ 0b111111;\n char = ((char & 0xaa) >> 1) | ((char & 0x55) << 1);\n char = ((char & 0xcc) >> 2) | ((char & 0x33) << 2);\n char = (char >> 4) | (char << 4);\n char = (char >> 2) & 63;\n switch (char) {\n case 0:\n return ' ';\n case 63:\n return '\\u2588';\n case 21:\n return '\\u258C';\n case 42:\n return '\\u2590';\n default:\n return String.fromCodePoint(0x1fb00 + char - 1 - (char > 21 ? 1 : 0) - (char > 42 ? 1 : 0));\n }\n };\n const extent = Math.sqrt(data.byteLength) | 0;\n const padded = extent + 2;\n let output = '';\n for (let baseRow = 0; baseRow < padded; baseRow += 3) {\n if (baseRow) output += '\\n';\n for (let baseCol = 0; baseCol < padded; baseCol += 2) {\n let p = 0;\n for (let dr = 0; dr < 3; dr++) {\n for (let dc = 0; dc < 2; dc++) {\n const r = baseRow + dr;\n const c = baseCol + dc;\n const bit = 5 - (dr * 2 + dc);\n let cell = 1; // default empty (out of bounds)\n if (r < padded && c < padded) {\n if (r === 0 || c === 0 || r === padded - 1 || c === padded - 1) {\n cell = 0; // border is filled\n } else if (r <= extent && c <= extent) {\n cell = data[(r - 1) * extent + (c - 1)];\n }\n }\n p |= (cell & 1) << bit;\n }\n }\n output += getChar(p);\n }\n }\n if (padded % 3 === 0) {\n // Only add newline if the padded output lines up with a newline exactly\n output += '\\n';\n }\n return output;\n}\n"],"names":["printQRCode","url","qr","toQR","output","supportsSextants","createSextantOutput","createHalfblockOutput","lines","split","length","print","Log","log","process","env","CI","tty","isatty","COLOR","isWindowsTerminal","platform","WT_SESSION","isGhostty","TERM_PROGRAM","isWezterm","isKitty","KITTY_WINDOW_ID","isAlacritty","ALACRITTY_WINDOW_ID","data","extent","Math","sqrt","byteLength","CHAR_00","CHAR_10","CHAR_01","CHAR_11","repeat","row","col","value","getChar","p","char","String","fromCodePoint","padded","baseRow","baseCol","dr","dc","r","c","bit","cell"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/utils/qr.ts"],"sourcesContent":["import tty from 'node:tty';\nimport { toQR } from 'toqr';\n\nimport { env } from './env';\nimport * as Log from '../log';\n\nexport interface QROutput {\n lines: number;\n print(): void;\n}\n\n/** Print the world famous 'Expo QR Code'. */\nexport function printQRCode(url: string): QROutput {\n const qr = toQR(url);\n const output = supportsSextants() ? createSextantOutput(qr) : createHalfblockOutput(qr);\n return {\n lines: output.split('\\n').length,\n print() {\n Log.log(output);\n },\n };\n}\n\n/** On specific terminals we can print a smaller QR code */\nfunction supportsSextants() {\n if (env.CI || !tty.isatty(1) || !tty.isatty(2)) {\n return false;\n } else if (process.env.COLOR === '0' || process.env.COLOR === 'false') {\n return false;\n }\n const isGhostty = process.env.TERM_PROGRAM === 'ghostty';\n const isWezterm = process.env.TERM_PROGRAM === 'WezTerm';\n // NOTE(@kitten): Zed regressed on rendering sextants\n const isZed = process.env.TERM_PROGRAM === 'zed';\n const isKitty = !!process.env.KITTY_WINDOW_ID?.length;\n const isAlacritty = !!process.env.ALACRITTY_WINDOW_ID?.length && !isZed;\n return isGhostty || isWezterm || isKitty || isAlacritty;\n}\n\n/** ANSI QR code output by using half-blocks (1x2-sized unicode blocks) */\nfunction createHalfblockOutput(data: Uint8Array): string {\n const extent = Math.sqrt(data.byteLength) | 0;\n const CHAR_00 = '\\u2588';\n const CHAR_10 = '\\u2584';\n const CHAR_01 = '\\u2580';\n const CHAR_11 = ' ';\n let output = '';\n output += CHAR_10.repeat(extent + 2);\n for (let row = 0; row < extent; row += 2) {\n output += '\\n' + CHAR_00;\n for (let col = 0; col < extent; col++) {\n const value = (data[row * extent + col] << 1) | data[(row + 1) * extent + col];\n switch (value) {\n case 0b00:\n output += CHAR_00;\n break;\n case 0b01:\n output += CHAR_01;\n break;\n case 0b10:\n output += CHAR_10;\n break;\n case 0b11:\n output += CHAR_11;\n break;\n }\n }\n output += CHAR_00;\n }\n if (extent % 2 === 0) {\n output += '\\n' + CHAR_01.repeat(extent + 2);\n }\n output += '\\n';\n return output;\n}\n\n/** ANSI QR code output by using sextant-blocks (2x3-sized unicode blocks) */\nfunction createSextantOutput(data: Uint8Array): string {\n const getChar = (p: number): string => {\n // Invert then reverse\n let char = p ^ 0b111111;\n char = ((char & 0xaa) >> 1) | ((char & 0x55) << 1);\n char = ((char & 0xcc) >> 2) | ((char & 0x33) << 2);\n char = (char >> 4) | (char << 4);\n char = (char >> 2) & 63;\n switch (char) {\n case 0:\n return ' ';\n case 63:\n return '\\u2588';\n case 21:\n return '\\u258C';\n case 42:\n return '\\u2590';\n default:\n return String.fromCodePoint(0x1fb00 + char - 1 - (char > 21 ? 1 : 0) - (char > 42 ? 1 : 0));\n }\n };\n const extent = Math.sqrt(data.byteLength) | 0;\n const padded = extent + 2;\n let output = '';\n for (let baseRow = 0; baseRow < padded; baseRow += 3) {\n if (baseRow) output += '\\n';\n for (let baseCol = 0; baseCol < padded; baseCol += 2) {\n let p = 0;\n for (let dr = 0; dr < 3; dr++) {\n for (let dc = 0; dc < 2; dc++) {\n const r = baseRow + dr;\n const c = baseCol + dc;\n const bit = 5 - (dr * 2 + dc);\n let cell = 1; // default empty (out of bounds)\n if (r < padded && c < padded) {\n if (r === 0 || c === 0 || r === padded - 1 || c === padded - 1) {\n cell = 0; // border is filled\n } else if (r <= extent && c <= extent) {\n cell = data[(r - 1) * extent + (c - 1)];\n }\n }\n p |= (cell & 1) << bit;\n }\n }\n output += getChar(p);\n }\n }\n if (padded % 3 === 0) {\n // Only add newline if the padded output lines up with a newline exactly\n output += '\\n';\n }\n return output;\n}\n"],"names":["printQRCode","url","qr","toQR","output","supportsSextants","createSextantOutput","createHalfblockOutput","lines","split","length","print","Log","log","process","env","CI","tty","isatty","COLOR","isGhostty","TERM_PROGRAM","isWezterm","isZed","isKitty","KITTY_WINDOW_ID","isAlacritty","ALACRITTY_WINDOW_ID","data","extent","Math","sqrt","byteLength","CHAR_00","CHAR_10","CHAR_01","CHAR_11","repeat","row","col","value","getChar","p","char","String","fromCodePoint","padded","baseRow","baseCol","dr","dc","r","c","bit","cell"],"mappings":"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"}
@@ -26,7 +26,7 @@ class FetchClient {
26
26
  this.headers = {
27
27
  accept: 'application/json',
28
28
  'content-type': 'application/json',
29
- 'user-agent': `expo-cli/${"55.0.32"}`,
29
+ 'user-agent': `expo-cli/${"55.0.34"}`,
30
30
  authorization: 'Basic ' + _nodebuffer().Buffer.from(`${target}:`).toString('base64')
31
31
  };
32
32
  }
@@ -83,7 +83,7 @@ function createContext() {
83
83
  cpu: summarizeCpuInfo(),
84
84
  app: {
85
85
  name: 'expo/cli',
86
- version: "55.0.32"
86
+ version: "55.0.34"
87
87
  },
88
88
  ci: _ciinfo().isCI ? {
89
89
  name: _ciinfo().name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/cli",
3
- "version": "55.0.32",
3
+ "version": "55.0.34",
4
4
  "description": "The Expo CLI",
5
5
  "main": "build/bin/cli",
6
6
  "bin": {
@@ -41,26 +41,26 @@
41
41
  "homepage": "https://github.com/expo/expo/tree/main/packages/@expo/cli",
42
42
  "dependencies": {
43
43
  "@expo/code-signing-certificates": "^0.0.6",
44
- "@expo/config": "~55.0.17",
45
- "@expo/config-plugins": "~55.0.10",
44
+ "@expo/config": "~55.0.19",
45
+ "@expo/config-plugins": "~55.0.11",
46
46
  "@expo/devcert": "^1.2.1",
47
- "@expo/env": "~2.1.2",
48
- "@expo/image-utils": "^0.8.14",
47
+ "@expo/env": "~2.1.3",
48
+ "@expo/image-utils": "^0.8.15",
49
49
  "@expo/json-file": "^10.0.15",
50
- "@expo/log-box": "55.0.12",
50
+ "@expo/log-box": "55.0.13",
51
51
  "@expo/metro": "~55.1.1",
52
- "@expo/metro-config": "~55.0.23",
52
+ "@expo/metro-config": "~55.0.25",
53
53
  "@expo/osascript": "^2.4.4",
54
- "@expo/package-manager": "^1.10.5",
54
+ "@expo/package-manager": "^1.10.6",
55
55
  "@expo/plist": "^0.5.4",
56
- "@expo/prebuild-config": "^55.0.18",
57
- "@expo/require-utils": "^55.0.5",
56
+ "@expo/prebuild-config": "^55.0.20",
57
+ "@expo/require-utils": "^55.0.6",
58
58
  "@expo/router-server": "^55.0.18",
59
- "@expo/schema-utils": "^55.0.4",
59
+ "@expo/schema-utils": "^55.0.5",
60
60
  "@expo/spawn-async": "^1.7.2",
61
61
  "@expo/ws-tunnel": "^1.0.1",
62
62
  "@expo/xcpretty": "^4.4.0",
63
- "@react-native/dev-middleware": "0.83.6",
63
+ "@react-native/dev-middleware": "0.83.10",
64
64
  "accepts": "^1.3.8",
65
65
  "arg": "^5.0.2",
66
66
  "better-opn": "~3.0.2",
@@ -71,7 +71,7 @@
71
71
  "compression": "^1.7.4",
72
72
  "connect": "^3.7.0",
73
73
  "debug": "^4.3.4",
74
- "dnssd-advertise": "^1.1.4",
74
+ "dnssd-advertise": "^1.1.6",
75
75
  "expo-server": "^55.0.11",
76
76
  "fetch-nodeshim": "^0.4.10",
77
77
  "getenv": "^2.0.0",
@@ -158,5 +158,5 @@
158
158
  "tree-kill": "^1.2.2",
159
159
  "tsd": "^0.28.1"
160
160
  },
161
- "gitHead": "bb1d4bd298e5bcaff86b04aabca7c56659e57138"
161
+ "gitHead": "c8f16914a2713c37fe446c46d613004626b3e6b3"
162
162
  }