@expo/cli 1.0.0-canary-20250207-8bc5146 → 1.0.0-canary-20250219-4a5dade

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/bin/cli CHANGED
@@ -121,7 +121,7 @@ const args = (0, _arg().default)({
121
121
  });
122
122
  if (args["--version"]) {
123
123
  // Version is added in the build script.
124
- console.log("1.0.0-canary-20250207-8bc5146");
124
+ console.log("1.0.0-canary-20250219-4a5dade");
125
125
  process.exit(0);
126
126
  }
127
127
  if (args["--non-interactive"]) {
@@ -12,7 +12,7 @@ async function getNativeModuleVersionsAsync(sdkVersion) {
12
12
  const fetchAsync = (0, _client.createCachedFetch)({
13
13
  cacheDirectory: "native-modules-cache",
14
14
  // 1 minute cache
15
- ttl: 1000 * 60 * 1
15
+ ttl: 1000 * 60
16
16
  });
17
17
  const response = await fetchAsync(`sdks/${sdkVersion}/native-modules`);
18
18
  if (!response.ok) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/api/getNativeModuleVersions.ts"],"sourcesContent":["import { createCachedFetch, getResponseDataOrThrow } from './rest/client';\nimport { CommandError } from '../utils/errors';\n\ninterface NativeModule {\n npmPackage: string;\n versionRange: string;\n}\ntype BundledNativeModuleList = NativeModule[];\n\nexport type BundledNativeModules = Record<string, string>;\n\n/**\n * The endpoint returns the list of bundled native modules for a given SDK version.\n * The data is populated by the `et sync-bundled-native-modules` script from expo/expo repo.\n * See the code for more details:\n * https://github.com/expo/expo/blob/main/tools/src/commands/SyncBundledNativeModules.ts\n *\n * Example result:\n * [\n * {\n * id: \"79285187-e5c4-47f7-b6a9-664f5d16f0db\",\n * sdkVersion: \"41.0.0\",\n * npmPackage: \"expo-camera\",\n * versionRange: \"~10.1.0\",\n * createdAt: \"2021-04-29T09:34:32.825Z\",\n * updatedAt: \"2021-04-29T09:34:32.825Z\"\n * },\n * ...\n * ]\n */\nexport async function getNativeModuleVersionsAsync(\n sdkVersion: string\n): Promise<BundledNativeModules> {\n const fetchAsync = createCachedFetch({\n cacheDirectory: 'native-modules-cache',\n // 1 minute cache\n ttl: 1000 * 60 * 1,\n });\n const response = await fetchAsync(`sdks/${sdkVersion}/native-modules`);\n if (!response.ok) {\n throw new CommandError(\n 'API',\n `Unexpected response when fetching version info from Expo servers: ${response.statusText}.`\n );\n }\n\n const json = await response.json();\n const data = getResponseDataOrThrow<BundledNativeModuleList>(json);\n if (!data.length) {\n throw new CommandError('VERSIONS', 'The bundled native module list from the Expo API is empty');\n }\n return fromBundledNativeModuleList(data);\n}\n\nfunction fromBundledNativeModuleList(list: BundledNativeModuleList): BundledNativeModules {\n return list.reduce((acc, i) => {\n acc[i.npmPackage] = i.versionRange;\n return acc;\n }, {} as BundledNativeModules);\n}\n"],"names":["getNativeModuleVersionsAsync","sdkVersion","fetchAsync","createCachedFetch","cacheDirectory","ttl","response","ok","CommandError","statusText","json","data","getResponseDataOrThrow","length","fromBundledNativeModuleList","list","reduce","acc","i","npmPackage","versionRange"],"mappings":"AAAA;;;;+BA8BsBA,8BAA4B;;aAA5BA,4BAA4B;;wBA9BQ,eAAe;wBAC5C,iBAAiB;AA6BvC,eAAeA,4BAA4B,CAChDC,UAAkB,EACa;IAC/B,MAAMC,UAAU,GAAGC,IAAAA,OAAiB,kBAAA,EAAC;QACnCC,cAAc,EAAE,sBAAsB;QACtC,iBAAiB;QACjBC,GAAG,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC;KACnB,CAAC,AAAC;IACH,MAAMC,QAAQ,GAAG,MAAMJ,UAAU,CAAC,CAAC,KAAK,EAAED,UAAU,CAAC,eAAe,CAAC,CAAC,AAAC;IACvE,IAAI,CAACK,QAAQ,CAACC,EAAE,EAAE;QAChB,MAAM,IAAIC,OAAY,aAAA,CACpB,KAAK,EACL,CAAC,kEAAkE,EAAEF,QAAQ,CAACG,UAAU,CAAC,CAAC,CAAC,CAC5F,CAAC;IACJ,CAAC;IAED,MAAMC,IAAI,GAAG,MAAMJ,QAAQ,CAACI,IAAI,EAAE,AAAC;IACnC,MAAMC,IAAI,GAAGC,IAAAA,OAAsB,uBAAA,EAA0BF,IAAI,CAAC,AAAC;IACnE,IAAI,CAACC,IAAI,CAACE,MAAM,EAAE;QAChB,MAAM,IAAIL,OAAY,aAAA,CAAC,UAAU,EAAE,2DAA2D,CAAC,CAAC;IAClG,CAAC;IACD,OAAOM,2BAA2B,CAACH,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED,SAASG,2BAA2B,CAACC,IAA6B,EAAwB;IACxF,OAAOA,IAAI,CAACC,MAAM,CAAC,CAACC,GAAG,EAAEC,CAAC,GAAK;QAC7BD,GAAG,CAACC,CAAC,CAACC,UAAU,CAAC,GAAGD,CAAC,CAACE,YAAY,CAAC;QACnC,OAAOH,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAyB,CAAC;AACjC,CAAC"}
1
+ {"version":3,"sources":["../../../src/api/getNativeModuleVersions.ts"],"sourcesContent":["import { createCachedFetch, getResponseDataOrThrow } from './rest/client';\nimport { CommandError } from '../utils/errors';\n\ninterface NativeModule {\n npmPackage: string;\n versionRange: string;\n}\ntype BundledNativeModuleList = NativeModule[];\n\nexport type BundledNativeModules = Record<string, string>;\n\n/**\n * The endpoint returns the list of bundled native modules for a given SDK version.\n * The data is populated by the `et sync-bundled-native-modules` script from expo/expo repo.\n * See the code for more details:\n * https://github.com/expo/expo/blob/main/tools/src/commands/SyncBundledNativeModules.ts\n *\n * Example result:\n * [\n * {\n * id: \"79285187-e5c4-47f7-b6a9-664f5d16f0db\",\n * sdkVersion: \"41.0.0\",\n * npmPackage: \"expo-camera\",\n * versionRange: \"~10.1.0\",\n * createdAt: \"2021-04-29T09:34:32.825Z\",\n * updatedAt: \"2021-04-29T09:34:32.825Z\"\n * },\n * ...\n * ]\n */\nexport async function getNativeModuleVersionsAsync(\n sdkVersion: string\n): Promise<BundledNativeModules> {\n const fetchAsync = createCachedFetch({\n cacheDirectory: 'native-modules-cache',\n // 1 minute cache\n ttl: 1000 * 60,\n });\n const response = await fetchAsync(`sdks/${sdkVersion}/native-modules`);\n if (!response.ok) {\n throw new CommandError(\n 'API',\n `Unexpected response when fetching version info from Expo servers: ${response.statusText}.`\n );\n }\n\n const json = await response.json();\n const data = getResponseDataOrThrow<BundledNativeModuleList>(json);\n if (!data.length) {\n throw new CommandError('VERSIONS', 'The bundled native module list from the Expo API is empty');\n }\n return fromBundledNativeModuleList(data);\n}\n\nfunction fromBundledNativeModuleList(list: BundledNativeModuleList): BundledNativeModules {\n return list.reduce((acc, i) => {\n acc[i.npmPackage] = i.versionRange;\n return acc;\n }, {} as BundledNativeModules);\n}\n"],"names":["getNativeModuleVersionsAsync","sdkVersion","fetchAsync","createCachedFetch","cacheDirectory","ttl","response","ok","CommandError","statusText","json","data","getResponseDataOrThrow","length","fromBundledNativeModuleList","list","reduce","acc","i","npmPackage","versionRange"],"mappings":"AAAA;;;;+BA8BsBA,8BAA4B;;aAA5BA,4BAA4B;;wBA9BQ,eAAe;wBAC5C,iBAAiB;AA6BvC,eAAeA,4BAA4B,CAChDC,UAAkB,EACa;IAC/B,MAAMC,UAAU,GAAGC,IAAAA,OAAiB,kBAAA,EAAC;QACnCC,cAAc,EAAE,sBAAsB;QACtC,iBAAiB;QACjBC,GAAG,EAAE,IAAI,GAAG,EAAE;KACf,CAAC,AAAC;IACH,MAAMC,QAAQ,GAAG,MAAMJ,UAAU,CAAC,CAAC,KAAK,EAAED,UAAU,CAAC,eAAe,CAAC,CAAC,AAAC;IACvE,IAAI,CAACK,QAAQ,CAACC,EAAE,EAAE;QAChB,MAAM,IAAIC,OAAY,aAAA,CACpB,KAAK,EACL,CAAC,kEAAkE,EAAEF,QAAQ,CAACG,UAAU,CAAC,CAAC,CAAC,CAC5F,CAAC;IACJ,CAAC;IAED,MAAMC,IAAI,GAAG,MAAMJ,QAAQ,CAACI,IAAI,EAAE,AAAC;IACnC,MAAMC,IAAI,GAAGC,IAAAA,OAAsB,uBAAA,EAA0BF,IAAI,CAAC,AAAC;IACnE,IAAI,CAACC,IAAI,CAACE,MAAM,EAAE;QAChB,MAAM,IAAIL,OAAY,aAAA,CAAC,UAAU,EAAE,2DAA2D,CAAC,CAAC;IAClG,CAAC;IACD,OAAOM,2BAA2B,CAACH,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED,SAASG,2BAA2B,CAACC,IAA6B,EAAwB;IACxF,OAAOA,IAAI,CAACC,MAAM,CAAC,CAACC,GAAG,EAAEC,CAAC,GAAK;QAC7BD,GAAG,CAACC,CAAC,CAACC,UAAU,CAAC,GAAGD,CAAC,CAACE,YAAY,CAAC;QACnC,OAAOH,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAyB,CAAC;AACjC,CAAC"}
@@ -6,58 +6,130 @@ Object.defineProperty(exports, "FileSystemResponseCache", {
6
6
  enumerable: true,
7
7
  get: ()=>FileSystemResponseCache
8
8
  });
9
- function _cacache() {
10
- const data = /*#__PURE__*/ _interopRequireDefault(require("cacache"));
11
- _cacache = function() {
9
+ function _nodeCrypto() {
10
+ const data = /*#__PURE__*/ _interopRequireDefault(require("node:crypto"));
11
+ _nodeCrypto = function() {
12
12
  return data;
13
13
  };
14
14
  return data;
15
15
  }
16
- function _stream() {
17
- const data = require("stream");
18
- _stream = function() {
16
+ function _nodeFs() {
17
+ const data = /*#__PURE__*/ _interopRequireDefault(require("node:fs"));
18
+ _nodeFs = function() {
19
19
  return data;
20
20
  };
21
21
  return data;
22
22
  }
23
+ function _nodePath() {
24
+ const data = /*#__PURE__*/ _interopRequireDefault(require("node:path"));
25
+ _nodePath = function() {
26
+ return data;
27
+ };
28
+ return data;
29
+ }
30
+ function _nodeStream() {
31
+ const data = /*#__PURE__*/ _interopRequireWildcard(require("node:stream"));
32
+ _nodeStream = function() {
33
+ return data;
34
+ };
35
+ return data;
36
+ }
37
+ const _dir = require("../../../utils/dir");
23
38
  function _interopRequireDefault(obj) {
24
39
  return obj && obj.__esModule ? obj : {
25
40
  default: obj
26
41
  };
27
42
  }
43
+ function _getRequireWildcardCache(nodeInterop) {
44
+ if (typeof WeakMap !== "function") return null;
45
+ var cacheBabelInterop = new WeakMap();
46
+ var cacheNodeInterop = new WeakMap();
47
+ return (_getRequireWildcardCache = function(nodeInterop) {
48
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
49
+ })(nodeInterop);
50
+ }
51
+ function _interopRequireWildcard(obj, nodeInterop) {
52
+ if (!nodeInterop && obj && obj.__esModule) {
53
+ return obj;
54
+ }
55
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
56
+ return {
57
+ default: obj
58
+ };
59
+ }
60
+ var cache = _getRequireWildcardCache(nodeInterop);
61
+ if (cache && cache.has(obj)) {
62
+ return cache.get(obj);
63
+ }
64
+ var newObj = {};
65
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
66
+ for(var key in obj){
67
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
68
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
69
+ if (desc && (desc.get || desc.set)) {
70
+ Object.defineProperty(newObj, key, desc);
71
+ } else {
72
+ newObj[key] = obj[key];
73
+ }
74
+ }
75
+ }
76
+ newObj.default = obj;
77
+ if (cache) {
78
+ cache.set(obj, newObj);
79
+ }
80
+ return newObj;
81
+ }
28
82
  class FileSystemResponseCache {
29
83
  constructor(options){
30
84
  this.cacheDirectory = options.cacheDirectory;
31
85
  this.timeToLive = options.ttl;
32
86
  }
87
+ getFilePaths(cacheKey) {
88
+ // Create a hash of the cache key to use as filename
89
+ const hash = _nodeCrypto().default.createHash("sha256").update(cacheKey).digest("hex");
90
+ return {
91
+ info: _nodePath().default.join(this.cacheDirectory, `${hash}-info.json`),
92
+ body: _nodePath().default.join(this.cacheDirectory, `${hash}-body.bin`)
93
+ };
94
+ }
33
95
  /** Retrieve the cache response, if any */ async get(cacheKey) {
34
- const responseInfoKey = getResponseInfoKey(cacheKey);
35
- const responseInfoMeta = await _cacache().default.get.info(this.cacheDirectory, responseInfoKey);
36
- // Abort if the response info is not found
37
- if (!responseInfoMeta) {
96
+ const paths = this.getFilePaths(cacheKey);
97
+ if (!await (0, _dir.fileExistsAsync)(paths.info)) {
38
98
  return undefined;
39
99
  }
40
- const responseInfoBuffer = await _cacache().default.get.byDigest(this.cacheDirectory, responseInfoMeta.integrity);
41
- const responseInfo = JSON.parse(responseInfoBuffer.toString());
42
- // Remove cache-specific data from the response info
43
- const { empty , expiration , bodyIntegrity } = responseInfo;
44
- delete responseInfo.empty;
45
- delete responseInfo.expiration;
46
- delete responseInfo.bodyIntegrity;
47
- // Invalidate the response if it has expired, or there is no known body integrity
48
- if (!bodyIntegrity || expiration && expiration < Date.now()) {
100
+ // Read and parse the info file
101
+ const infoBuffer = await _nodeFs().default.promises.readFile(paths.info);
102
+ try {
103
+ const responseInfo = JSON.parse(infoBuffer.toString());
104
+ // Check if the response has expired
105
+ if (responseInfo.expiration && responseInfo.expiration < Date.now()) {
106
+ await this.remove(cacheKey);
107
+ return undefined;
108
+ }
109
+ // Remove cache-specific data from the response info
110
+ const { empty , expiration , bodyPath , ...cleanInfo } = responseInfo;
111
+ // Create response body stream
112
+ let responseBody;
113
+ if (empty) {
114
+ responseBody = _nodeStream().Readable.toWeb(_nodeStream().Readable.from(Buffer.alloc(0)));
115
+ } else {
116
+ const bodyBuffer = await _nodeFs().default.promises.readFile(paths.body);
117
+ responseBody = _nodeStream().Readable.toWeb(_nodeStream().Readable.from(bodyBuffer));
118
+ }
119
+ return {
120
+ body: responseBody,
121
+ info: cleanInfo
122
+ };
123
+ } catch {
124
+ // If file doesn't exist or other errors, return undefined
49
125
  return undefined;
50
126
  }
51
- // Create a read-stream for the response body
52
- const responseBody = empty ? _stream().Readable.from(Buffer.alloc(0)) : _stream().Readable.from(_cacache().default.get.stream.byDigest(this.cacheDirectory, bodyIntegrity));
53
- return {
54
- body: _stream().Readable.toWeb(responseBody),
55
- info: responseInfo
56
- };
57
127
  }
58
128
  /** Store the response for caching */ async set(cacheKey, response) {
59
- const responseBodyKey = getResponseBodyKey(cacheKey);
60
- const responseInfoKey = getResponseInfoKey(cacheKey);
129
+ await _nodeFs().default.promises.mkdir(this.cacheDirectory, {
130
+ recursive: true
131
+ });
132
+ const paths = this.getFilePaths(cacheKey);
61
133
  // Create a copy of the response info, to add cache-specific data
62
134
  const responseInfo = {
63
135
  ...response.info
@@ -67,35 +139,42 @@ class FileSystemResponseCache {
67
139
  responseInfo.expiration = Date.now() + this.timeToLive;
68
140
  }
69
141
  try {
70
- // Store the response body as stream, and calculate the stream integrity
71
- responseInfo.bodyIntegrity = await new Promise((fulfill, reject)=>{
72
- _stream().Readable.fromWeb(response.body).pipe(_cacache().default.put.stream(this.cacheDirectory, responseBodyKey)).on("integrity", (integrity)=>fulfill(integrity)).once("error", reject);
73
- });
74
- } catch (error) {
75
- if (error.code !== "ENODATA") {
76
- throw error;
142
+ // Clone the response body stream since we need to read it twice
143
+ const [forSize, forWrite] = response.body.tee();
144
+ // Check if the body is empty by reading the first stream
145
+ const reader = forSize.getReader();
146
+ const { value } = await reader.read();
147
+ reader.releaseLock();
148
+ if (!value || value.length === 0) {
149
+ responseInfo.empty = true;
150
+ } else {
151
+ // Create write stream and pipe response body to file
152
+ const writeStream = _nodeFs().default.createWriteStream(paths.body);
153
+ const nodeStream = _nodeStream().Readable.fromWeb(forWrite);
154
+ nodeStream.pipe(writeStream);
155
+ // Wait for the stream to finish
156
+ await _nodeStream().default.promises.finished(writeStream);
157
+ responseInfo.bodyPath = paths.body;
77
158
  }
78
- // Mark the response as empty
79
- responseInfo.empty = true;
80
- responseInfo.bodyIntegrity = undefined;
159
+ // Write info to file
160
+ await _nodeFs().default.promises.writeFile(paths.info, JSON.stringify(responseInfo));
161
+ return await this.get(cacheKey);
162
+ } catch (error) {
163
+ // Clean up any partially written files
164
+ await this.remove(cacheKey);
165
+ throw error;
81
166
  }
82
- // Store the response info
83
- const responseInfoBuffer = Buffer.from(JSON.stringify(responseInfo));
84
- await _cacache().default.put(this.cacheDirectory, responseInfoKey, responseInfoBuffer);
85
- return await this.get(cacheKey);
86
167
  }
87
168
  /** Remove the response from caching */ async remove(cacheKey) {
88
- await Promise.all([
89
- _cacache().default.rm.entry(this.cacheDirectory, getResponseBodyKey(cacheKey)),
90
- _cacache().default.rm.entry(this.cacheDirectory, getResponseBodyKey(cacheKey)),
91
- ]);
169
+ const paths = this.getFilePaths(cacheKey);
170
+ await removeAllAsync(paths.info, paths.body);
92
171
  }
93
172
  }
94
- function getResponseBodyKey(cacheKey) {
95
- return `${cacheKey}UndiciBody`;
96
- }
97
- function getResponseInfoKey(cacheKey) {
98
- return `${cacheKey}UndiciInfo`;
173
+ function removeAllAsync(...paths) {
174
+ return Promise.all(paths.map((path)=>_nodeFs().default.promises.rm(path, {
175
+ recursive: true,
176
+ force: true
177
+ }).catch(()=>{})));
99
178
  }
100
179
 
101
180
  //# sourceMappingURL=FileSystemResponseCache.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/api/rest/cache/FileSystemResponseCache.ts"],"sourcesContent":["import cacache from 'cacache';\nimport { Readable } from 'stream';\n\nimport type { ResponseCache, ResponseCacheEntry } from './ResponseCache';\n\ntype FileSystemResponseCacheInfo = ResponseCacheEntry['info'] & {\n /** Stream integrity used to validate the local body response */\n bodyIntegrity?: string;\n /** If there is no response body */\n empty?: boolean;\n /** The expiration time, in seconds, when the response should be invalidated */\n expiration?: number;\n};\n\nexport class FileSystemResponseCache implements ResponseCache {\n /** The absolute path to the directory used to store responses */\n private cacheDirectory: string;\n /** Optional auto-expiration for all stored response */\n private timeToLive?: number;\n\n constructor(options: { cacheDirectory: string; ttl?: number }) {\n this.cacheDirectory = options.cacheDirectory;\n this.timeToLive = options.ttl;\n }\n\n /** Retrieve the cache response, if any */\n async get(cacheKey: string): Promise<ResponseCacheEntry | undefined> {\n const responseInfoKey = getResponseInfoKey(cacheKey);\n const responseInfoMeta = await cacache.get.info(this.cacheDirectory, responseInfoKey);\n\n // Abort if the response info is not found\n if (!responseInfoMeta) {\n return undefined;\n }\n\n const responseInfoBuffer = await cacache.get.byDigest(\n this.cacheDirectory,\n responseInfoMeta.integrity\n );\n const responseInfo: FileSystemResponseCacheInfo = JSON.parse(responseInfoBuffer.toString());\n\n // Remove cache-specific data from the response info\n const { empty, expiration, bodyIntegrity } = responseInfo;\n delete responseInfo.empty;\n delete responseInfo.expiration;\n delete responseInfo.bodyIntegrity;\n\n // Invalidate the response if it has expired, or there is no known body integrity\n if (!bodyIntegrity || (expiration && expiration < Date.now())) {\n return undefined;\n }\n\n // Create a read-stream for the response body\n const responseBody = empty\n ? Readable.from(Buffer.alloc(0))\n : Readable.from(cacache.get.stream.byDigest(this.cacheDirectory, bodyIntegrity));\n\n return {\n body: Readable.toWeb(responseBody),\n info: responseInfo,\n };\n }\n\n /** Store the response for caching */\n async set(\n cacheKey: string,\n response: ResponseCacheEntry\n ): Promise<ResponseCacheEntry | undefined> {\n const responseBodyKey = getResponseBodyKey(cacheKey);\n const responseInfoKey = getResponseInfoKey(cacheKey);\n\n // Create a copy of the response info, to add cache-specific data\n const responseInfo: FileSystemResponseCacheInfo = { ...response.info };\n\n // Add expiration time if the \"time to live\" is set\n if (typeof this.timeToLive === 'number') {\n responseInfo.expiration = Date.now() + this.timeToLive;\n }\n\n try {\n // Store the response body as stream, and calculate the stream integrity\n responseInfo.bodyIntegrity = await new Promise((fulfill, reject) => {\n Readable.fromWeb(response.body)\n .pipe(cacache.put.stream(this.cacheDirectory, responseBodyKey))\n .on('integrity', (integrity) => fulfill(integrity))\n .once('error', reject);\n });\n } catch (error: any) {\n if (error.code !== 'ENODATA') {\n throw error;\n }\n\n // Mark the response as empty\n responseInfo.empty = true;\n responseInfo.bodyIntegrity = undefined;\n }\n\n // Store the response info\n const responseInfoBuffer = Buffer.from(JSON.stringify(responseInfo));\n await cacache.put(this.cacheDirectory, responseInfoKey, responseInfoBuffer);\n\n return await this.get(cacheKey);\n }\n\n /** Remove the response from caching */\n async remove(cacheKey: string): Promise<void> {\n await Promise.all([\n cacache.rm.entry(this.cacheDirectory, getResponseBodyKey(cacheKey)),\n cacache.rm.entry(this.cacheDirectory, getResponseBodyKey(cacheKey)),\n ]);\n }\n}\n\nfunction getResponseBodyKey(cacheKey: string) {\n return `${cacheKey}UndiciBody`;\n}\n\nfunction getResponseInfoKey(cacheKey: string) {\n return `${cacheKey}UndiciInfo`;\n}\n"],"names":["FileSystemResponseCache","constructor","options","cacheDirectory","timeToLive","ttl","get","cacheKey","responseInfoKey","getResponseInfoKey","responseInfoMeta","cacache","info","undefined","responseInfoBuffer","byDigest","integrity","responseInfo","JSON","parse","toString","empty","expiration","bodyIntegrity","Date","now","responseBody","Readable","from","Buffer","alloc","stream","body","toWeb","set","response","responseBodyKey","getResponseBodyKey","Promise","fulfill","reject","fromWeb","pipe","put","on","once","error","code","stringify","remove","all","rm","entry"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/api/rest/cache/FileSystemResponseCache.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport stream, { Readable } from 'node:stream';\nimport { ReadableStream } from 'node:stream/web';\n\nimport type { ResponseCache, ResponseCacheEntry } from './ResponseCache';\nimport { fileExistsAsync } from '../../../utils/dir';\n\ntype FileSystemResponseCacheInfo = ResponseCacheEntry['info'] & {\n /** The path to the cached body file */\n bodyPath?: string;\n /** If there is no response body */\n empty?: boolean;\n /** The expiration time, in milliseconds, when the response should be invalidated */\n expiration?: number;\n};\n\nexport class FileSystemResponseCache implements ResponseCache {\n /** The absolute path to the directory used to store responses */\n private cacheDirectory: string;\n /** Optional auto-expiration for all stored responses */\n private timeToLive?: number;\n\n constructor(options: { cacheDirectory: string; ttl?: number }) {\n this.cacheDirectory = options.cacheDirectory;\n this.timeToLive = options.ttl;\n }\n\n private getFilePaths(cacheKey: string) {\n // Create a hash of the cache key to use as filename\n const hash = crypto.createHash('sha256').update(cacheKey).digest('hex');\n return {\n info: path.join(this.cacheDirectory, `${hash}-info.json`),\n body: path.join(this.cacheDirectory, `${hash}-body.bin`),\n };\n }\n\n /** Retrieve the cache response, if any */\n async get(cacheKey: string): Promise<ResponseCacheEntry | undefined> {\n const paths = this.getFilePaths(cacheKey);\n\n if (!(await fileExistsAsync(paths.info))) {\n return undefined;\n }\n\n // Read and parse the info file\n const infoBuffer = await fs.promises.readFile(paths.info);\n\n try {\n const responseInfo: FileSystemResponseCacheInfo = JSON.parse(infoBuffer.toString());\n\n // Check if the response has expired\n if (responseInfo.expiration && responseInfo.expiration < Date.now()) {\n await this.remove(cacheKey);\n return undefined;\n }\n\n // Remove cache-specific data from the response info\n const { empty, expiration, bodyPath, ...cleanInfo } = responseInfo;\n\n // Create response body stream\n let responseBody: ReadableStream;\n if (empty) {\n responseBody = Readable.toWeb(Readable.from(Buffer.alloc(0)));\n } else {\n const bodyBuffer = await fs.promises.readFile(paths.body);\n responseBody = Readable.toWeb(Readable.from(bodyBuffer));\n }\n\n return {\n body: responseBody,\n info: cleanInfo,\n };\n } catch {\n // If file doesn't exist or other errors, return undefined\n return undefined;\n }\n }\n\n /** Store the response for caching */\n async set(\n cacheKey: string,\n response: ResponseCacheEntry\n ): Promise<ResponseCacheEntry | undefined> {\n await fs.promises.mkdir(this.cacheDirectory, { recursive: true });\n const paths = this.getFilePaths(cacheKey);\n\n // Create a copy of the response info, to add cache-specific data\n const responseInfo: FileSystemResponseCacheInfo = { ...response.info };\n\n // Add expiration time if the \"time to live\" is set\n if (typeof this.timeToLive === 'number') {\n responseInfo.expiration = Date.now() + this.timeToLive;\n }\n\n try {\n // Clone the response body stream since we need to read it twice\n const [forSize, forWrite] = response.body.tee();\n\n // Check if the body is empty by reading the first stream\n const reader = forSize.getReader();\n const { value } = await reader.read();\n reader.releaseLock();\n\n if (!value || value.length === 0) {\n responseInfo.empty = true;\n } else {\n // Create write stream and pipe response body to file\n const writeStream = fs.createWriteStream(paths.body);\n const nodeStream = Readable.fromWeb(forWrite);\n nodeStream.pipe(writeStream);\n\n // Wait for the stream to finish\n await stream.promises.finished(writeStream);\n\n responseInfo.bodyPath = paths.body;\n }\n\n // Write info to file\n await fs.promises.writeFile(paths.info, JSON.stringify(responseInfo));\n\n return await this.get(cacheKey);\n } catch (error) {\n // Clean up any partially written files\n await this.remove(cacheKey);\n throw error;\n }\n }\n\n /** Remove the response from caching */\n async remove(cacheKey: string): Promise<void> {\n const paths = this.getFilePaths(cacheKey);\n await removeAllAsync(paths.info, paths.body);\n }\n}\n\nfunction removeAllAsync(...paths: string[]) {\n return Promise.all(\n paths.map((path) => fs.promises.rm(path, { recursive: true, force: true }).catch(() => {}))\n );\n}\n"],"names":["FileSystemResponseCache","constructor","options","cacheDirectory","timeToLive","ttl","getFilePaths","cacheKey","hash","crypto","createHash","update","digest","info","path","join","body","get","paths","fileExistsAsync","undefined","infoBuffer","fs","promises","readFile","responseInfo","JSON","parse","toString","expiration","Date","now","remove","empty","bodyPath","cleanInfo","responseBody","Readable","toWeb","from","Buffer","alloc","bodyBuffer","set","response","mkdir","recursive","forSize","forWrite","tee","reader","getReader","value","read","releaseLock","length","writeStream","createWriteStream","nodeStream","fromWeb","pipe","stream","finished","writeFile","stringify","error","removeAllAsync","Promise","all","map","rm","force","catch"],"mappings":"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"}
@@ -20,9 +20,30 @@ function _chalk() {
20
20
  };
21
21
  return data;
22
22
  }
23
- function _nodeCrypto() {
24
- const data = require("node:crypto");
25
- _nodeCrypto = function() {
23
+ function _nodeFs() {
24
+ const data = /*#__PURE__*/ _interopRequireWildcard(require("node:fs"));
25
+ _nodeFs = function() {
26
+ return data;
27
+ };
28
+ return data;
29
+ }
30
+ function _nodeOs() {
31
+ const data = require("node:os");
32
+ _nodeOs = function() {
33
+ return data;
34
+ };
35
+ return data;
36
+ }
37
+ function _nodePath() {
38
+ const data = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
39
+ _nodePath = function() {
40
+ return data;
41
+ };
42
+ return data;
43
+ }
44
+ function _tempDir() {
45
+ const data = /*#__PURE__*/ _interopRequireDefault(require("temp-dir"));
46
+ _tempDir = function() {
26
47
  return data;
27
48
  };
28
49
  return data;
@@ -102,6 +123,24 @@ class AsyncWsTunnel {
102
123
  this.serverUrl = null;
103
124
  }
104
125
  }
126
+ // Generate a base-36 string of 5 characters (from 32 bits of randomness)
127
+ function randomStr() {
128
+ return (Math.random().toString(36) + "00000").slice(2, 7);
129
+ }
130
+ function getTunnelSession() {
131
+ let session = randomStr() + randomStr() + randomStr();
132
+ if ((0, _env.envIsWebcontainer)()) {
133
+ const leaseId = Buffer.from((0, _nodeOs().hostname)()).toString("base64url");
134
+ const leaseFile = _nodePath().join(_tempDir().default, `_ws_tunnel_lease_${leaseId}`);
135
+ try {
136
+ session = _nodeFs().readFileSync(leaseFile, "utf8").trim() || session;
137
+ } catch {}
138
+ try {
139
+ _nodeFs().writeFileSync(leaseFile, session, "utf8");
140
+ } catch {}
141
+ }
142
+ return session;
143
+ }
105
144
  function getTunnelOptions() {
106
145
  const userDefinedSubdomain = _env.env.EXPO_TUNNEL_SUBDOMAIN;
107
146
  if (userDefinedSubdomain && typeof userDefinedSubdomain === "string") {
@@ -109,16 +148,12 @@ function getTunnelOptions() {
109
148
  return {
110
149
  session: userDefinedSubdomain
111
150
  };
151
+ } else {
152
+ const session = getTunnelSession();
153
+ return {
154
+ session
155
+ };
112
156
  }
113
- let session;
114
- do {
115
- // TODO(cedric): replace this with non-random data generated from server to manage and prevent overlapping sessions
116
- session = (0, _nodeCrypto().randomBytes)(12).toString("base64url");
117
- }while (!/^[A-Za-z0-9]/.test(session));
118
- debug("Session:", session);
119
- return {
120
- session
121
- };
122
157
  }
123
158
 
124
159
  //# sourceMappingURL=AsyncWsTunnel.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/start/server/AsyncWsTunnel.ts"],"sourcesContent":["import * as tunnel from '@expo/ws-tunnel';\nimport chalk from 'chalk';\nimport { randomBytes } from 'node:crypto';\n\nimport * as Log from '../../log';\nimport { env } from '../../utils/env';\nimport { CommandError } from '../../utils/errors';\n\nconst debug = require('debug')('expo:start:server:ws-tunnel') as typeof console.log;\n\nexport class AsyncWsTunnel {\n /** Info about the currently running instance of tunnel. */\n private serverUrl: string | null = null;\n\n constructor(_projectRoot: string, port: number) {\n if (port !== 8081) {\n throw new CommandError(\n 'WS_TUNNEL_PORT',\n `WS-tunnel only supports tunneling over port 8081, attempted to use port ${port}`\n );\n }\n }\n\n public getActiveUrl(): string | null {\n return this.serverUrl;\n }\n\n async startAsync(): Promise<void> {\n this.serverUrl = await tunnel.startAsync({\n ...getTunnelOptions(),\n onStatusChange(status) {\n if (status === 'disconnected') {\n Log.error(\n chalk.red(\n 'Tunnel connection has been closed. This is often related to intermittent connection problems with the ws proxy servers. Restart the dev server to try connecting again.'\n ) + chalk.gray('\\nCheck the Expo status page for outages: https://status.expo.dev/')\n );\n }\n },\n });\n\n debug('Tunnel URL:', this.serverUrl);\n }\n\n async stopAsync(): Promise<void> {\n debug('Stopping Tunnel');\n await tunnel.stopAsync();\n this.serverUrl = null;\n }\n}\n\nfunction getTunnelOptions() {\n const userDefinedSubdomain = env.EXPO_TUNNEL_SUBDOMAIN;\n if (userDefinedSubdomain && typeof userDefinedSubdomain === 'string') {\n debug('Session:', userDefinedSubdomain);\n return { session: userDefinedSubdomain };\n }\n\n let session: string;\n do {\n // TODO(cedric): replace this with non-random data generated from server to manage and prevent overlapping sessions\n session = randomBytes(12).toString('base64url');\n } while (!/^[A-Za-z0-9]/.test(session));\n debug('Session:', session);\n return { session };\n}\n"],"names":["AsyncWsTunnel","debug","require","serverUrl","constructor","_projectRoot","port","CommandError","getActiveUrl","startAsync","tunnel","getTunnelOptions","onStatusChange","status","Log","error","chalk","red","gray","stopAsync","userDefinedSubdomain","env","EXPO_TUNNEL_SUBDOMAIN","session","randomBytes","toString","test"],"mappings":"AAAA;;;;+BAUaA,eAAa;;aAAbA,aAAa;;;+DAVF,iBAAiB;;;;;;;8DACvB,OAAO;;;;;;;yBACG,aAAa;;;;;;2DAEpB,WAAW;qBACZ,iBAAiB;wBACR,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEjD,MAAMC,KAAK,GAAGC,OAAO,CAAC,OAAO,CAAC,CAAC,6BAA6B,CAAC,AAAsB,AAAC;AAE7E,MAAMF,aAAa;IACxB,yDAAyD,GACzD,AAAQG,SAAS,GAAkB,IAAI,CAAC;IAExCC,YAAYC,YAAoB,EAAEC,IAAY,CAAE;QAC9C,IAAIA,IAAI,KAAK,IAAI,EAAE;YACjB,MAAM,IAAIC,OAAY,aAAA,CACpB,gBAAgB,EAChB,CAAC,wEAAwE,EAAED,IAAI,CAAC,CAAC,CAClF,CAAC;QACJ,CAAC;IACH;IAEOE,YAAY,GAAkB;QACnC,OAAO,IAAI,CAACL,SAAS,CAAC;IACxB;UAEMM,UAAU,GAAkB;QAChC,IAAI,CAACN,SAAS,GAAG,MAAMO,SAAM,EAAA,CAACD,UAAU,CAAC;YACvC,GAAGE,gBAAgB,EAAE;YACrBC,cAAc,EAACC,MAAM,EAAE;gBACrB,IAAIA,MAAM,KAAK,cAAc,EAAE;oBAC7BC,IAAG,CAACC,KAAK,CACPC,MAAK,EAAA,QAAA,CAACC,GAAG,CACP,yKAAyK,CAC1K,GAAGD,MAAK,EAAA,QAAA,CAACE,IAAI,CAAC,oEAAoE,CAAC,CACrF,CAAC;gBACJ,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEHjB,KAAK,CAAC,aAAa,EAAE,IAAI,CAACE,SAAS,CAAC,CAAC;IACvC;UAEMgB,SAAS,GAAkB;QAC/BlB,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACzB,MAAMS,SAAM,EAAA,CAACS,SAAS,EAAE,CAAC;QACzB,IAAI,CAAChB,SAAS,GAAG,IAAI,CAAC;IACxB;CACD;AAED,SAASQ,gBAAgB,GAAG;IAC1B,MAAMS,oBAAoB,GAAGC,IAAG,IAAA,CAACC,qBAAqB,AAAC;IACvD,IAAIF,oBAAoB,IAAI,OAAOA,oBAAoB,KAAK,QAAQ,EAAE;QACpEnB,KAAK,CAAC,UAAU,EAAEmB,oBAAoB,CAAC,CAAC;QACxC,OAAO;YAAEG,OAAO,EAAEH,oBAAoB;SAAE,CAAC;IAC3C,CAAC;IAED,IAAIG,OAAO,AAAQ,AAAC;IACpB,GAAG;QACD,mHAAmH;QACnHA,OAAO,GAAGC,IAAAA,WAAW,EAAA,YAAA,EAAC,EAAE,CAAC,CAACC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAClD,QAAS,CAAC,eAAeC,IAAI,CAACH,OAAO,CAAC,EAAE;IACxCtB,KAAK,CAAC,UAAU,EAAEsB,OAAO,CAAC,CAAC;IAC3B,OAAO;QAAEA,OAAO;KAAE,CAAC;AACrB,CAAC"}
1
+ {"version":3,"sources":["../../../../src/start/server/AsyncWsTunnel.ts"],"sourcesContent":["import * as tunnel from '@expo/ws-tunnel';\nimport chalk from 'chalk';\nimport * as fs from 'node:fs';\nimport { hostname } from 'node:os';\nimport * as path from 'node:path';\nimport tempDir from 'temp-dir';\n\nimport * as Log from '../../log';\nimport { env, envIsWebcontainer } from '../../utils/env';\nimport { CommandError } from '../../utils/errors';\n\nconst debug = require('debug')('expo:start:server:ws-tunnel') as typeof console.log;\n\nexport class AsyncWsTunnel {\n /** Info about the currently running instance of tunnel. */\n private serverUrl: string | null = null;\n\n constructor(_projectRoot: string, port: number) {\n if (port !== 8081) {\n throw new CommandError(\n 'WS_TUNNEL_PORT',\n `WS-tunnel only supports tunneling over port 8081, attempted to use port ${port}`\n );\n }\n }\n\n public getActiveUrl(): string | null {\n return this.serverUrl;\n }\n\n async startAsync(): Promise<void> {\n this.serverUrl = await tunnel.startAsync({\n ...getTunnelOptions(),\n onStatusChange(status) {\n if (status === 'disconnected') {\n Log.error(\n chalk.red(\n 'Tunnel connection has been closed. This is often related to intermittent connection problems with the ws proxy servers. Restart the dev server to try connecting again.'\n ) + chalk.gray('\\nCheck the Expo status page for outages: https://status.expo.dev/')\n );\n }\n },\n });\n\n debug('Tunnel URL:', this.serverUrl);\n }\n\n async stopAsync(): Promise<void> {\n debug('Stopping Tunnel');\n await tunnel.stopAsync();\n this.serverUrl = null;\n }\n}\n\n// Generate a base-36 string of 5 characters (from 32 bits of randomness)\nfunction randomStr() {\n return (Math.random().toString(36) + '00000').slice(2, 7);\n}\n\nfunction getTunnelSession(): string {\n let session = randomStr() + randomStr() + randomStr();\n if (envIsWebcontainer()) {\n const leaseId = Buffer.from(hostname()).toString('base64url');\n const leaseFile = path.join(tempDir, `_ws_tunnel_lease_${leaseId}`);\n try {\n session = fs.readFileSync(leaseFile, 'utf8').trim() || session;\n } catch {}\n try {\n fs.writeFileSync(leaseFile, session, 'utf8');\n } catch {}\n }\n return session;\n}\n\nfunction getTunnelOptions() {\n const userDefinedSubdomain = env.EXPO_TUNNEL_SUBDOMAIN;\n if (userDefinedSubdomain && typeof userDefinedSubdomain === 'string') {\n debug('Session:', userDefinedSubdomain);\n return { session: userDefinedSubdomain };\n } else {\n const session = getTunnelSession();\n return { session };\n }\n}\n"],"names":["AsyncWsTunnel","debug","require","serverUrl","constructor","_projectRoot","port","CommandError","getActiveUrl","startAsync","tunnel","getTunnelOptions","onStatusChange","status","Log","error","chalk","red","gray","stopAsync","randomStr","Math","random","toString","slice","getTunnelSession","session","envIsWebcontainer","leaseId","Buffer","from","hostname","leaseFile","path","join","tempDir","fs","readFileSync","trim","writeFileSync","userDefinedSubdomain","env","EXPO_TUNNEL_SUBDOMAIN"],"mappings":"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"}
@@ -525,7 +525,7 @@ function withExtendedResolver(config, { tsconfig , isTsconfigPathsEnabled , isFa
525
525
  // Shim out React Native native runtime globals in server mode for native.
526
526
  if (isServer) {
527
527
  if (normal.endsWith("react-native/Libraries/Core/InitializeCore.js")) {
528
- console.log("Shimming out InitializeCore for React Native in native SSR bundle");
528
+ debug("Shimming out InitializeCore for React Native in native SSR bundle");
529
529
  return {
530
530
  type: "empty"
531
531
  };