@expo/cli 55.0.24 → 55.0.26

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 (26) hide show
  1. package/build/bin/cli +1 -1
  2. package/build/src/events/index.js +2 -9
  3. package/build/src/events/index.js.map +1 -1
  4. package/build/src/events/stream.js +94 -24
  5. package/build/src/events/stream.js.map +1 -1
  6. package/build/src/prebuild/clearNativeFolder.js +38 -0
  7. package/build/src/prebuild/clearNativeFolder.js.map +1 -1
  8. package/build/src/prebuild/prebuildAsync.js +4 -0
  9. package/build/src/prebuild/prebuildAsync.js.map +1 -1
  10. package/build/src/start/server/metro/MetroBundlerDevServer.js +9 -11
  11. package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
  12. package/build/src/start/server/metro/metroWatchTypeScriptFiles.js +48 -16
  13. package/build/src/start/server/metro/metroWatchTypeScriptFiles.js.map +1 -1
  14. package/build/src/start/server/metro/waitForMetroToObserveTypeScriptFile.js +32 -30
  15. package/build/src/start/server/metro/waitForMetroToObserveTypeScriptFile.js.map +1 -1
  16. package/build/src/start/server/metro/withMetroMultiPlatform.js +2 -0
  17. package/build/src/start/server/metro/withMetroMultiPlatform.js.map +1 -1
  18. package/build/src/start/server/middleware/ManifestMiddleware.js +12 -3
  19. package/build/src/start/server/middleware/ManifestMiddleware.js.map +1 -1
  20. package/build/src/start/server/type-generation/routes.js +1 -0
  21. package/build/src/start/server/type-generation/routes.js.map +1 -1
  22. package/build/src/utils/tar.js +3 -2
  23. package/build/src/utils/tar.js.map +1 -1
  24. package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
  25. package/build/src/utils/telemetry/utils/context.js +1 -1
  26. package/package.json +10 -10
package/build/bin/cli CHANGED
@@ -139,7 +139,7 @@ const args = (0, _arg().default)({
139
139
  });
140
140
  if (args['--version']) {
141
141
  // Version is added in the build script.
142
- console.log("55.0.24");
142
+ console.log("55.0.26");
143
143
  process.exit(0);
144
144
  }
145
145
  if (args['--non-interactive']) {
@@ -70,7 +70,7 @@ function getInitMetadata() {
70
70
  return {
71
71
  format: 'v0-jsonl',
72
72
  // Version is added in the build script.
73
- version: "55.0.24" ?? 'UNVERSIONED'
73
+ version: "55.0.26" ?? 'UNVERSIONED'
74
74
  };
75
75
  }
76
76
  function installEventLogger(env = process.env.LOG_EVENTS) {
@@ -100,14 +100,7 @@ const shouldReduceLogs = ()=>!!logStream && _env.env.EXPO_UNSTABLE_HEADLESS;
100
100
  const events = (category, _fn)=>{
101
101
  function log(event, data) {
102
102
  if (logStream) {
103
- const _e = `${category}:${String(event)}`;
104
- const _t = Date.now();
105
- const payload = JSON.stringify({
106
- _e,
107
- _t,
108
- ...data
109
- });
110
- logStream._write(payload + '\n');
103
+ (0, _stream.writeEvent)(logStream, category, event, data);
111
104
  }
112
105
  }
113
106
  log.category = category;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/events/index.ts"],"sourcesContent":["import { Console } from 'node:console';\nimport path from 'node:path';\n\nimport type { EventBuilder, EventLoggerBuilder, EventShape } from './builder';\nimport { LogStream } from './stream';\nimport { env } from '../utils/env';\n\ninterface InitMetadata {\n format: 'v0-jsonl' | (string & {});\n version: string;\n}\n\nlet logPath = process.cwd();\nlet logStream: LogStream | undefined;\n\nfunction parseLogTarget(env: string | undefined) {\n let logDestination: string | number | undefined;\n if (env) {\n const fd = parseInt(env, 10);\n if (fd > 0 && Number.isSafeInteger(fd)) {\n logDestination = fd;\n } else {\n try {\n const parsedPath = path.parse(env);\n logDestination = path.format(parsedPath);\n logPath = parsedPath.dir;\n } catch {\n logDestination = undefined;\n }\n }\n }\n return logDestination;\n}\n\nfunction getInitMetadata(): InitMetadata {\n return {\n format: 'v0-jsonl',\n // Version is added in the build script.\n version: process.env.__EXPO_VERSION ?? 'UNVERSIONED',\n };\n}\n\n/** Activates the event logger based on the input env var\n * @param env - The target to write the logs to; defaults to `$LOG_EVENTS`\n */\nexport function installEventLogger(env = process.env.LOG_EVENTS) {\n const eventLogDestination = parseLogTarget(env);\n if (eventLogDestination) {\n if (eventLogDestination === 1) {\n // Reuse Node's existing stdio streams so redirected or piped terminals don't\n // attempt TTY-only initialization when LOG_EVENTS swaps console output.\n const output = process.stderr;\n Object.defineProperty(process, 'stdout', { get: () => output });\n globalThis.console = new Console(output, output);\n } else if (eventLogDestination === 2) {\n const output = process.stdout;\n Object.defineProperty(process, 'stderr', { get: () => output });\n globalThis.console = new Console(output, output);\n }\n logStream = new LogStream(eventLogDestination);\n rootEvent('init', getInitMetadata());\n }\n}\n\n/** Returns whether the event logger is active */\nexport const isEventLoggerActive = () => !!logStream?.writable;\n\n/** Whether logs shown in the terminal should be reduced.\n * @remarks\n * We indicate that we're in an automated tool (e.g. E2E tests) with `EXPO_UNSTABLE_HEADLESS`.\n * If the event logger is activate and we're running in a headless tool, we should reduce\n * interactive or noisy logs, in favour of the event logger.\n */\nexport const shouldReduceLogs = () => !!logStream && env.EXPO_UNSTABLE_HEADLESS;\n\n/** Used to create an event logger for structured JSONL logs activated with the `LOG_EVENTS` environment variable.\n *\n * @remarks\n * Structured logs are streamed to a JSONL output file or file descriptor, and are meant for automated tooling\n * or normal usage to document what happened during a user session. When creating a module that outputs errors,\n * events, or captures what the user was doing, create a new event logger category for them and add structured\n * log events.\n * For example, `../start/server/metro/MetroTerminalReporter` captures most of Metro's logged events.\n * Structured JSONL logs don't have a large performance impact, unlike `DEBUG` logs, and are easily parseable\n * and filterable, including by wrapper processes.\n *\n * After adding a new event category, don't forget to add it to `./types.ts` to collect all event shape types\n * in one place.\n *\n * @example\n * ```ts\n * export const event = events('test', (t) => [\n * t.event<'my_event', {\n * myValue: string | null;\n * }>(),\n * ]);\n *\n * event('my_event', { myValue: 'test' });\n * ```\n *\n * This will log a `{ _e: 'test:my_event', _t: 0, myValue: 'test' }` entry in the event log.\n */\nexport const events: EventLoggerBuilder = ((\n category: string,\n _fn: (builder: EventBuilder) => readonly EventShape<string>[]\n) => {\n function log(event: string, data: any) {\n if (logStream) {\n const _e = `${category}:${String(event)}`;\n const _t = Date.now();\n const payload = JSON.stringify({ _e, _t, ...data });\n logStream._write(payload + '\\n');\n }\n }\n log.category = category;\n\n log.path = function relativePath(target: string | undefined | null): string | null {\n try {\n return target != null && path.isAbsolute(target)\n ? path.relative(logPath, target).replace(/\\\\/, '/') || '.'\n : (target ?? null);\n } catch {\n return target || null;\n }\n };\n\n return log;\n}) as EventLoggerBuilder;\n\n// These are built-in events: We choose an ambiguous name on purpose,\n// since we don't assume this implementation will necessarily only be in `@expo/cli`\nexport const rootEvent = events('root', (t) => [t.event<'init', InitMetadata>()]);\n\nexport type { EventLogger } from './builder';\n"],"names":["events","installEventLogger","isEventLoggerActive","rootEvent","shouldReduceLogs","logPath","process","cwd","logStream","parseLogTarget","env","logDestination","fd","parseInt","Number","isSafeInteger","parsedPath","path","parse","format","dir","undefined","getInitMetadata","version","__EXPO_VERSION","LOG_EVENTS","eventLogDestination","output","stderr","Object","defineProperty","get","globalThis","console","Console","stdout","LogStream","writable","EXPO_UNSTABLE_HEADLESS","category","_fn","log","event","data","_e","String","_t","Date","now","payload","JSON","stringify","_write","relativePath","target","isAbsolute","relative","replace","t"],"mappings":";;;;;;;;;;;IAsGaA,MAAM;eAANA;;IAzDGC,kBAAkB;eAAlBA;;IAoBHC,mBAAmB;eAAnBA;;IAkEAC,SAAS;eAATA;;IA1DAC,gBAAgB;eAAhBA;;;;yBAzEW;;;;;;;gEACP;;;;;;wBAGS;qBACN;;;;;;AAOpB,IAAIC,UAAUC,QAAQC,GAAG;AACzB,IAAIC;AAEJ,SAASC,eAAeC,GAAuB;IAC7C,IAAIC;IACJ,IAAID,KAAK;QACP,MAAME,KAAKC,SAASH,KAAK;QACzB,IAAIE,KAAK,KAAKE,OAAOC,aAAa,CAACH,KAAK;YACtCD,iBAAiBC;QACnB,OAAO;YACL,IAAI;gBACF,MAAMI,aAAaC,mBAAI,CAACC,KAAK,CAACR;gBAC9BC,iBAAiBM,mBAAI,CAACE,MAAM,CAACH;gBAC7BX,UAAUW,WAAWI,GAAG;YAC1B,EAAE,OAAM;gBACNT,iBAAiBU;YACnB;QACF;IACF;IACA,OAAOV;AACT;AAEA,SAASW;IACP,OAAO;QACLH,QAAQ;QACR,wCAAwC;QACxCI,SAASjB,QAAQI,GAAG,CAACc,cAAc,IAAI;IACzC;AACF;AAKO,SAASvB,mBAAmBS,MAAMJ,QAAQI,GAAG,CAACe,UAAU;IAC7D,MAAMC,sBAAsBjB,eAAeC;IAC3C,IAAIgB,qBAAqB;QACvB,IAAIA,wBAAwB,GAAG;YAC7B,6EAA6E;YAC7E,wEAAwE;YACxE,MAAMC,SAASrB,QAAQsB,MAAM;YAC7BC,OAAOC,cAAc,CAACxB,SAAS,UAAU;gBAAEyB,KAAK,IAAMJ;YAAO;YAC7DK,WAAWC,OAAO,GAAG,IAAIC,CAAAA,cAAM,SAAC,CAACP,QAAQA;QAC3C,OAAO,IAAID,wBAAwB,GAAG;YACpC,MAAMC,SAASrB,QAAQ6B,MAAM;YAC7BN,OAAOC,cAAc,CAACxB,SAAS,UAAU;gBAAEyB,KAAK,IAAMJ;YAAO;YAC7DK,WAAWC,OAAO,GAAG,IAAIC,CAAAA,cAAM,SAAC,CAACP,QAAQA;QAC3C;QACAnB,YAAY,IAAI4B,iBAAS,CAACV;QAC1BvB,UAAU,QAAQmB;IACpB;AACF;AAGO,MAAMpB,sBAAsB,IAAM,CAAC,EAACM,6BAAAA,UAAW6B,QAAQ;AAQvD,MAAMjC,mBAAmB,IAAM,CAAC,CAACI,aAAaE,QAAG,CAAC4B,sBAAsB;AA6BxE,MAAMtC,SAA8B,CACzCuC,UACAC;IAEA,SAASC,IAAIC,KAAa,EAAEC,IAAS;QACnC,IAAInC,WAAW;YACb,MAAMoC,KAAK,GAAGL,SAAS,CAAC,EAAEM,OAAOH,QAAQ;YACzC,MAAMI,KAAKC,KAAKC,GAAG;YACnB,MAAMC,UAAUC,KAAKC,SAAS,CAAC;gBAAEP;gBAAIE;gBAAI,GAAGH,IAAI;YAAC;YACjDnC,UAAU4C,MAAM,CAACH,UAAU;QAC7B;IACF;IACAR,IAAIF,QAAQ,GAAGA;IAEfE,IAAIxB,IAAI,GAAG,SAASoC,aAAaC,MAAiC;QAChE,IAAI;YACF,OAAOA,UAAU,QAAQrC,mBAAI,CAACsC,UAAU,CAACD,UACrCrC,mBAAI,CAACuC,QAAQ,CAACnD,SAASiD,QAAQG,OAAO,CAAC,MAAM,QAAQ,MACpDH,UAAU;QACjB,EAAE,OAAM;YACN,OAAOA,UAAU;QACnB;IACF;IAEA,OAAOb;AACT;AAIO,MAAMtC,YAAYH,OAAO,QAAQ,CAAC0D,IAAM;QAACA,EAAEhB,KAAK;KAAyB"}
1
+ {"version":3,"sources":["../../../src/events/index.ts"],"sourcesContent":["import { Console } from 'node:console';\nimport path from 'node:path';\n\nimport type { EventBuilder, EventLoggerBuilder, EventShape } from './builder';\nimport { LogStream, writeEvent } from './stream';\nimport { env } from '../utils/env';\n\ninterface InitMetadata {\n format: 'v0-jsonl' | (string & {});\n version: string;\n}\n\nlet logPath = process.cwd();\nlet logStream: LogStream | undefined;\n\nfunction parseLogTarget(env: string | undefined) {\n let logDestination: string | number | undefined;\n if (env) {\n const fd = parseInt(env, 10);\n if (fd > 0 && Number.isSafeInteger(fd)) {\n logDestination = fd;\n } else {\n try {\n const parsedPath = path.parse(env);\n logDestination = path.format(parsedPath);\n logPath = parsedPath.dir;\n } catch {\n logDestination = undefined;\n }\n }\n }\n return logDestination;\n}\n\nfunction getInitMetadata(): InitMetadata {\n return {\n format: 'v0-jsonl',\n // Version is added in the build script.\n version: process.env.__EXPO_VERSION ?? 'UNVERSIONED',\n };\n}\n\n/** Activates the event logger based on the input env var\n * @param env - The target to write the logs to; defaults to `$LOG_EVENTS`\n */\nexport function installEventLogger(env = process.env.LOG_EVENTS) {\n const eventLogDestination = parseLogTarget(env);\n if (eventLogDestination) {\n if (eventLogDestination === 1) {\n // Reuse Node's existing stdio streams so redirected or piped terminals don't\n // attempt TTY-only initialization when LOG_EVENTS swaps console output.\n const output = process.stderr;\n Object.defineProperty(process, 'stdout', { get: () => output });\n globalThis.console = new Console(output, output);\n } else if (eventLogDestination === 2) {\n const output = process.stdout;\n Object.defineProperty(process, 'stderr', { get: () => output });\n globalThis.console = new Console(output, output);\n }\n logStream = new LogStream(eventLogDestination);\n rootEvent('init', getInitMetadata());\n }\n}\n\n/** Returns whether the event logger is active */\nexport const isEventLoggerActive = () => !!logStream?.writable;\n\n/** Whether logs shown in the terminal should be reduced.\n * @remarks\n * We indicate that we're in an automated tool (e.g. E2E tests) with `EXPO_UNSTABLE_HEADLESS`.\n * If the event logger is activate and we're running in a headless tool, we should reduce\n * interactive or noisy logs, in favour of the event logger.\n */\nexport const shouldReduceLogs = () => !!logStream && env.EXPO_UNSTABLE_HEADLESS;\n\n/** Used to create an event logger for structured JSONL logs activated with the `LOG_EVENTS` environment variable.\n *\n * @remarks\n * Structured logs are streamed to a JSONL output file or file descriptor, and are meant for automated tooling\n * or normal usage to document what happened during a user session. When creating a module that outputs errors,\n * events, or captures what the user was doing, create a new event logger category for them and add structured\n * log events.\n * For example, `../start/server/metro/MetroTerminalReporter` captures most of Metro's logged events.\n * Structured JSONL logs don't have a large performance impact, unlike `DEBUG` logs, and are easily parseable\n * and filterable, including by wrapper processes.\n *\n * After adding a new event category, don't forget to add it to `./types.ts` to collect all event shape types\n * in one place.\n *\n * @example\n * ```ts\n * export const event = events('test', (t) => [\n * t.event<'my_event', {\n * myValue: string | null;\n * }>(),\n * ]);\n *\n * event('my_event', { myValue: 'test' });\n * ```\n *\n * This will log a `{ _e: 'test:my_event', _t: 0, myValue: 'test' }` entry in the event log.\n */\nexport const events: EventLoggerBuilder = ((\n category: string,\n _fn: (builder: EventBuilder) => readonly EventShape<string>[]\n) => {\n function log(event: string, data: any) {\n if (logStream) {\n writeEvent(logStream, category, event, data);\n }\n }\n log.category = category;\n\n log.path = function relativePath(target: string | undefined | null): string | null {\n try {\n return target != null && path.isAbsolute(target)\n ? path.relative(logPath, target).replace(/\\\\/, '/') || '.'\n : (target ?? null);\n } catch {\n return target || null;\n }\n };\n\n return log;\n}) as EventLoggerBuilder;\n\n// These are built-in events: We choose an ambiguous name on purpose,\n// since we don't assume this implementation will necessarily only be in `@expo/cli`\nexport const rootEvent = events('root', (t) => [t.event<'init', InitMetadata>()]);\n\nexport type { EventLogger } from './builder';\n"],"names":["events","installEventLogger","isEventLoggerActive","rootEvent","shouldReduceLogs","logPath","process","cwd","logStream","parseLogTarget","env","logDestination","fd","parseInt","Number","isSafeInteger","parsedPath","path","parse","format","dir","undefined","getInitMetadata","version","__EXPO_VERSION","LOG_EVENTS","eventLogDestination","output","stderr","Object","defineProperty","get","globalThis","console","Console","stdout","LogStream","writable","EXPO_UNSTABLE_HEADLESS","category","_fn","log","event","data","writeEvent","relativePath","target","isAbsolute","relative","replace","t"],"mappings":";;;;;;;;;;;IAsGaA,MAAM;eAANA;;IAzDGC,kBAAkB;eAAlBA;;IAoBHC,mBAAmB;eAAnBA;;IA+DAC,SAAS;eAATA;;IAvDAC,gBAAgB;eAAhBA;;;;yBAzEW;;;;;;;gEACP;;;;;;wBAGqB;qBAClB;;;;;;AAOpB,IAAIC,UAAUC,QAAQC,GAAG;AACzB,IAAIC;AAEJ,SAASC,eAAeC,GAAuB;IAC7C,IAAIC;IACJ,IAAID,KAAK;QACP,MAAME,KAAKC,SAASH,KAAK;QACzB,IAAIE,KAAK,KAAKE,OAAOC,aAAa,CAACH,KAAK;YACtCD,iBAAiBC;QACnB,OAAO;YACL,IAAI;gBACF,MAAMI,aAAaC,mBAAI,CAACC,KAAK,CAACR;gBAC9BC,iBAAiBM,mBAAI,CAACE,MAAM,CAACH;gBAC7BX,UAAUW,WAAWI,GAAG;YAC1B,EAAE,OAAM;gBACNT,iBAAiBU;YACnB;QACF;IACF;IACA,OAAOV;AACT;AAEA,SAASW;IACP,OAAO;QACLH,QAAQ;QACR,wCAAwC;QACxCI,SAASjB,QAAQI,GAAG,CAACc,cAAc,IAAI;IACzC;AACF;AAKO,SAASvB,mBAAmBS,MAAMJ,QAAQI,GAAG,CAACe,UAAU;IAC7D,MAAMC,sBAAsBjB,eAAeC;IAC3C,IAAIgB,qBAAqB;QACvB,IAAIA,wBAAwB,GAAG;YAC7B,6EAA6E;YAC7E,wEAAwE;YACxE,MAAMC,SAASrB,QAAQsB,MAAM;YAC7BC,OAAOC,cAAc,CAACxB,SAAS,UAAU;gBAAEyB,KAAK,IAAMJ;YAAO;YAC7DK,WAAWC,OAAO,GAAG,IAAIC,CAAAA,cAAM,SAAC,CAACP,QAAQA;QAC3C,OAAO,IAAID,wBAAwB,GAAG;YACpC,MAAMC,SAASrB,QAAQ6B,MAAM;YAC7BN,OAAOC,cAAc,CAACxB,SAAS,UAAU;gBAAEyB,KAAK,IAAMJ;YAAO;YAC7DK,WAAWC,OAAO,GAAG,IAAIC,CAAAA,cAAM,SAAC,CAACP,QAAQA;QAC3C;QACAnB,YAAY,IAAI4B,iBAAS,CAACV;QAC1BvB,UAAU,QAAQmB;IACpB;AACF;AAGO,MAAMpB,sBAAsB,IAAM,CAAC,EAACM,6BAAAA,UAAW6B,QAAQ;AAQvD,MAAMjC,mBAAmB,IAAM,CAAC,CAACI,aAAaE,QAAG,CAAC4B,sBAAsB;AA6BxE,MAAMtC,SAA8B,CACzCuC,UACAC;IAEA,SAASC,IAAIC,KAAa,EAAEC,IAAS;QACnC,IAAInC,WAAW;YACboC,IAAAA,kBAAU,EAACpC,WAAW+B,UAAUG,OAAOC;QACzC;IACF;IACAF,IAAIF,QAAQ,GAAGA;IAEfE,IAAIxB,IAAI,GAAG,SAAS4B,aAAaC,MAAiC;QAChE,IAAI;YACF,OAAOA,UAAU,QAAQ7B,mBAAI,CAAC8B,UAAU,CAACD,UACrC7B,mBAAI,CAAC+B,QAAQ,CAAC3C,SAASyC,QAAQG,OAAO,CAAC,MAAM,QAAQ,MACpDH,UAAU;QACjB,EAAE,OAAM;YACN,OAAOA,UAAU;QACnB;IACF;IAEA,OAAOL;AACT;AAIO,MAAMtC,YAAYH,OAAO,QAAQ,CAACkD,IAAM;QAACA,EAAER,KAAK;KAAyB"}
@@ -2,10 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "LogStream", {
6
- enumerable: true,
7
- get: function() {
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ LogStream: function() {
8
13
  return LogStream;
14
+ },
15
+ writeEvent: function() {
16
+ return writeEvent;
9
17
  }
10
18
  });
11
19
  function _nodebuffer() {
@@ -43,6 +51,12 @@ function _interop_require_default(obj) {
43
51
  }
44
52
  const BUSY_WRITE_TIMEOUT = 100;
45
53
  const HIGH_WATER_MARK = 16387; /*16KB*/
54
+ function writeEvent(dest, category, kind, payload) {
55
+ const timestamp = Date.now();
56
+ const rest = JSON.stringify(payload).slice(1);
57
+ const line = rest.length > 1 ? `{"_e":"${category}:${kind}","_t":${timestamp},${rest}\n` : `{"_e":"${category}:${kind}","_t":${timestamp}}\n`;
58
+ dest._writeln(line);
59
+ }
46
60
  class LogStream extends _nodeevents().EventEmitter {
47
61
  #fd;
48
62
  #file;
@@ -54,9 +68,11 @@ class LogStream extends _nodeevents().EventEmitter {
54
68
  #output;
55
69
  #len;
56
70
  #lines;
71
+ #head;
57
72
  #partialLine;
73
+ #onRelease;
58
74
  constructor(dest){
59
- super(), this.#fd = -1, this.#file = null, this.#writing = false, this.#ending = false, this.#flushPending = false, this.#destroyed = false, this.#opening = false, this.#output = '', this.#len = 0, this.#lines = [], this.#partialLine = 0;
75
+ super(), this.#fd = -1, this.#file = null, this.#writing = false, this.#ending = false, this.#flushPending = false, this.#destroyed = false, this.#opening = false, this.#output = '', this.#len = 0, this.#lines = [], this.#head = 0, this.#partialLine = 0, this.#onRelease = (err, written)=>this.#release(err, written);
60
76
  if (typeof dest === 'number') {
61
77
  _nodefs().default.fsyncSync(dest);
62
78
  this.#fd = dest;
@@ -87,23 +103,43 @@ class LogStream extends _nodeevents().EventEmitter {
87
103
  }
88
104
  } else {
89
105
  this.emit('write', written);
90
- const outputLength = _nodebuffer().Buffer.byteLength(this.#output);
91
- if (outputLength > written) {
92
- const output = _nodebuffer().Buffer.from(this.#output).subarray(written).toString();
93
- this.#len -= this.#output.length - output.length;
94
- this.#output = output;
95
- } else {
106
+ if (written === this.#output.length) {
107
+ // Fast path: complete write (exact for ASCII, the common case for JSONL)
96
108
  this.#len -= this.#output.length;
97
109
  this.#output = '';
98
- }
99
- if (this.#output || this.#lines.length > this.#partialLine) {
100
- this.#writeLine();
101
- } else if (this.#ending) {
102
- this.#writing = false;
103
- this.#close();
110
+ if (this.#lines.length - this.#head > this.#partialLine) {
111
+ this.#writeLine();
112
+ } else if (this.#ending) {
113
+ this.#writing = false;
114
+ this.#close();
115
+ } else {
116
+ this.#writing = false;
117
+ if (this.#flushPending) {
118
+ this.emit('drain');
119
+ }
120
+ }
104
121
  } else {
105
- this.#writing = false;
106
- this.emit('drain');
122
+ // Multi-byte complete write (written > length) or partial write (written < length)
123
+ const outputLength = _nodebuffer().Buffer.byteLength(this.#output);
124
+ if (outputLength > written) {
125
+ const output = _nodebuffer().Buffer.from(this.#output).toString('utf8', written);
126
+ this.#len -= this.#output.length - output.length;
127
+ this.#output = output;
128
+ } else {
129
+ this.#len -= this.#output.length;
130
+ this.#output = '';
131
+ }
132
+ if (this.#output || this.#lines.length - this.#head > this.#partialLine) {
133
+ this.#writeLine();
134
+ } else if (this.#ending) {
135
+ this.#writing = false;
136
+ this.#close();
137
+ } else {
138
+ this.#writing = false;
139
+ if (this.#flushPending) {
140
+ this.emit('drain');
141
+ }
142
+ }
107
143
  }
108
144
  }
109
145
  }
@@ -123,7 +159,7 @@ class LogStream extends _nodeevents().EventEmitter {
123
159
  this.emit('ready');
124
160
  if (this.#destroyed) {
125
161
  // do nothing when we're already closing the file
126
- } else if (!this.writing && this.#lines.length > this.#partialLine || this.#flushPending) {
162
+ } else if (!this.writing && this.#lines.length - this.#head > this.#partialLine || this.#flushPending) {
127
163
  this.#writeLine();
128
164
  }
129
165
  }
@@ -143,6 +179,7 @@ class LogStream extends _nodeevents().EventEmitter {
143
179
  this.#destroyed = true;
144
180
  this.#partialLine = 0;
145
181
  this.#lines.length = 0;
182
+ this.#head = 0;
146
183
  const onClose = (error)=>{
147
184
  if (error) {
148
185
  this.emit('error', error);
@@ -162,8 +199,22 @@ class LogStream extends _nodeevents().EventEmitter {
162
199
  }
163
200
  #writeLine() {
164
201
  this.#writing = true;
165
- this.#output ||= this.#lines.length > this.#partialLine ? this.#lines.shift() || '' : '';
166
- _nodefs().default.write(this.#fd, this.#output, (err, written)=>this.#release(err, written));
202
+ if (!this.#output) {
203
+ const end = this.#lines.length - this.#partialLine;
204
+ if (end > this.#head) {
205
+ this.#output = this.#lines[this.#head++] || '';
206
+ // Batch multiple lines into one write call below HWM, to avoid
207
+ // excessive syscalls after when lines accumulated during a previous write
208
+ while(this.#head < end && this.#output.length < HIGH_WATER_MARK){
209
+ this.#output += this.#lines[this.#head++];
210
+ }
211
+ if (this.#head === this.#lines.length) {
212
+ this.#lines.length = 0;
213
+ this.#head = 0;
214
+ }
215
+ }
216
+ }
217
+ _nodefs().default.write(this.#fd, this.#output, this.#onRelease);
167
218
  }
168
219
  _end() {
169
220
  if (!this.#destroyed && !this.#ending) {
@@ -171,7 +222,7 @@ class LogStream extends _nodeevents().EventEmitter {
171
222
  if (this.#opening) {
172
223
  this.once('ready', ()=>this._end());
173
224
  } else if (!this.#writing && this.#fd >= 0) {
174
- if (this.#lines.length > this.#partialLine) {
225
+ if (this.#lines.length - this.#head > this.#partialLine) {
175
226
  this.#writeLine();
176
227
  } else {
177
228
  this.#close();
@@ -225,7 +276,7 @@ class LogStream extends _nodeevents().EventEmitter {
225
276
  this.once('drain', onDrain);
226
277
  this.once('error', onError);
227
278
  if (!this.#writing) {
228
- if (this.#lines.length > this.#partialLine || this.#output) {
279
+ if (this.#lines.length - this.#head > this.#partialLine || this.#output) {
229
280
  // There are complete lines or remaining output to write
230
281
  this.#writeLine();
231
282
  } else {
@@ -235,11 +286,30 @@ class LogStream extends _nodeevents().EventEmitter {
235
286
  }
236
287
  }
237
288
  }
289
+ _writeln(data) {
290
+ this.#len += data.length;
291
+ if (!this.#writing && this.#lines.length === this.#head && !this.#output) {
292
+ // Fast path: When no write is pending, directly write the line
293
+ this.#writing = true;
294
+ this.#output = data;
295
+ _nodefs().default.write(this.#fd, data, this.#onRelease);
296
+ } else {
297
+ this.#lines.push(data);
298
+ if (!this.#writing) {
299
+ this.#writeLine();
300
+ }
301
+ }
302
+ return this.#len < HIGH_WATER_MARK;
303
+ }
238
304
  _write(data) {
239
305
  if (this.#destroyed) {
240
306
  return false;
241
307
  }
242
308
  this.#len += data.length;
309
+ // Fast path: For complete lines with no pending partial we can skip the work below
310
+ if (this.#partialLine === 0 && data.charCodeAt(data.length - 1) === 10 /*'\n'*/ ) {
311
+ return this._writeln(data);
312
+ }
243
313
  let startIdx = 0;
244
314
  let endIdx = -1;
245
315
  while((endIdx = data.indexOf('\n', startIdx)) > -1){
@@ -261,7 +331,7 @@ class LogStream extends _nodeevents().EventEmitter {
261
331
  }
262
332
  this.#partialLine = 1;
263
333
  }
264
- if (!this.#writing && this.#lines.length > this.#partialLine) {
334
+ if (!this.#writing && this.#lines.length - this.#head > this.#partialLine) {
265
335
  this.#writeLine();
266
336
  }
267
337
  return this.#len < HIGH_WATER_MARK;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/events/stream.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport { EventEmitter } from 'node:events';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nconst BUSY_WRITE_TIMEOUT = 100;\nconst HIGH_WATER_MARK = 16_387; /*16KB*/\n\nexport class LogStream extends EventEmitter implements NodeJS.WritableStream {\n #fd = -1;\n #file: string | null = null;\n\n #writing = false;\n #ending = false;\n #flushPending = false;\n #destroyed = false;\n #opening = false;\n\n #output = '';\n #len = 0;\n #lines: string[] = [];\n #partialLine = 0;\n\n constructor(dest: string | number) {\n super();\n if (typeof dest === 'number') {\n fs.fsyncSync(dest);\n this.#fd = dest;\n process.nextTick(() => this.emit('ready'));\n } else if (typeof dest === 'string') {\n this.#openFile(dest);\n }\n }\n\n get file(): string | null {\n return this.#file;\n }\n\n get fd(): number {\n return this.#fd;\n }\n\n get writing(): boolean {\n return this.#writing;\n }\n\n get writable(): boolean {\n return !this.#destroyed && !this.#ending;\n }\n\n #release(error: NodeJS.ErrnoException | null, written: number) {\n if (error) {\n if (error.code === 'EAGAIN' || error.code === 'EBUSY') {\n setTimeout(() => this.#writeLine(), BUSY_WRITE_TIMEOUT);\n } else {\n this.#writing = false;\n this.emit('error', error);\n }\n } else {\n this.emit('write', written);\n\n const outputLength = Buffer.byteLength(this.#output);\n if (outputLength > written) {\n const output = Buffer.from(this.#output).subarray(written).toString();\n this.#len -= this.#output.length - output.length;\n this.#output = output;\n } else {\n this.#len -= this.#output.length;\n this.#output = '';\n }\n\n if (this.#output || this.#lines.length > this.#partialLine) {\n this.#writeLine();\n } else if (this.#ending) {\n this.#writing = false;\n this.#close();\n } else {\n this.#writing = false;\n this.emit('drain');\n }\n }\n }\n\n #openFile(file: string) {\n this.#opening = true;\n this.#writing = true;\n\n const onOpened = (error: Error | null, fd?: number | null) => {\n if (error) {\n this.#writing = false;\n this.#opening = false;\n this.emit('error', error);\n } else {\n this.#fd = fd!;\n this.#file = file;\n this.#opening = false;\n this.#writing = false;\n this.emit('ready');\n if (this.#destroyed) {\n // do nothing when we're already closing the file\n } else if (\n (!this.writing && this.#lines.length > this.#partialLine) ||\n this.#flushPending\n ) {\n this.#writeLine();\n }\n }\n };\n\n fs.mkdir(path.dirname(file), { recursive: true }, (err) => {\n if (err) return onOpened(err);\n fs.open(file, 'a', 0o666, onOpened);\n });\n }\n\n #close() {\n if (this.#fd === -1) {\n this.once('ready', () => this.#close());\n return;\n }\n\n this.#destroyed = true;\n this.#partialLine = 0;\n this.#lines.length = 0;\n\n const onClose = (error?: NodeJS.ErrnoException | null) => {\n if (error) {\n this.emit('error', error);\n this.emit('close', error);\n } else {\n if (this.#ending && !this.#writing) this.emit('finish');\n this.emit('close');\n }\n };\n\n fsFsync(this.#fd, (error) => {\n if (!error && !isStdFd(this.#fd)) {\n fs.close(this.#fd, onClose);\n } else {\n onClose(); // Error intentionally ignored, assume closed\n }\n });\n }\n\n #writeLine() {\n this.#writing = true;\n this.#output ||= this.#lines.length > this.#partialLine ? this.#lines.shift() || '' : '';\n fs.write(this.#fd, this.#output, (err, written) => this.#release(err, written));\n }\n\n _end() {\n if (!this.#destroyed && !this.#ending) {\n this.#ending = true;\n if (this.#opening) {\n this.once('ready', () => this._end());\n } else if (!this.#writing && this.#fd >= 0) {\n if (this.#lines.length > this.#partialLine) {\n this.#writeLine();\n } else {\n this.#close();\n }\n }\n }\n return this;\n }\n\n end(cb?: () => void): this;\n end(data: string | Uint8Array, cb?: () => void): this;\n end(str: string, encoding?: BufferEncoding, cb?: () => void): this;\n\n end(\n arg1?: Uint8Array | string | (() => void),\n arg2?: BufferEncoding | (() => void),\n arg3?: () => void\n ) {\n const maybeCb = arg3 || arg2 || arg1;\n const input = typeof arg1 !== 'function' ? arg1 : undefined;\n const encoding = typeof arg2 === 'string' ? arg2 : 'utf8';\n const cb = typeof maybeCb === 'function' ? maybeCb : undefined;\n if (typeof input === 'string') {\n this.write(input, encoding);\n } else if (input != null) {\n this.write(input);\n }\n if (cb) this.once('close', cb);\n return this._end();\n }\n\n destroy() {\n if (!this.#destroyed) this.#close();\n }\n\n flush(cb?: (error?: Error | null) => void) {\n if (this.#destroyed) {\n cb?.();\n } else {\n const onDrain = () => {\n if (!this.#destroyed) {\n fsFsync(this.#fd, (error) => {\n this.#flushPending = false;\n if (error?.code === 'EBADF') {\n cb?.(); // If fd is closed, ignore the error\n } else {\n cb?.(error);\n }\n });\n } else {\n this.#flushPending = false;\n cb?.();\n }\n this.off('error', onError);\n };\n\n const onError = (err: Error) => {\n this.#flushPending = false;\n this.off('drain', onDrain);\n cb?.(err);\n };\n\n this.#flushPending = true;\n this.once('drain', onDrain);\n this.once('error', onError);\n\n if (!this.#writing) {\n if (this.#lines.length > this.#partialLine || this.#output) {\n // There are complete lines or remaining output to write\n this.#writeLine();\n } else {\n // Nothing complete to write, emit drain immediately\n process.nextTick(() => this.emit('drain'));\n }\n }\n }\n }\n\n _write(data: string): boolean {\n if (this.#destroyed) {\n return false;\n }\n\n this.#len += data.length;\n\n let startIdx = 0;\n let endIdx = -1;\n while ((endIdx = data.indexOf('\\n', startIdx)) > -1) {\n const line = data.slice(startIdx, endIdx + 1);\n if (this.#partialLine > 0) {\n this.#lines[this.#lines.length - 1] += line;\n } else {\n this.#lines.push(line);\n }\n this.#partialLine = 0;\n startIdx = ++endIdx;\n }\n\n if (startIdx < data.length) {\n const line = data.slice(startIdx);\n if (this.#partialLine > 0) {\n this.#lines[this.#lines.length - 1] += line;\n } else {\n this.#lines.push(data.slice(startIdx));\n }\n this.#partialLine = 1;\n }\n\n if (!this.#writing && this.#lines.length > this.#partialLine) {\n this.#writeLine();\n }\n\n return this.#len < HIGH_WATER_MARK;\n }\n\n write(buffer: Uint8Array | string, cb?: (err?: Error | null) => void): boolean;\n write(str: string, encoding?: BufferEncoding, cb?: (err?: Error | null) => void): boolean;\n\n write(\n input: Uint8Array | string,\n arg2?: BufferEncoding | ((err?: Error | null) => void),\n arg3?: (err?: Error | null) => void\n ): boolean {\n const maybeCb = arg3 || arg2;\n const encoding = typeof arg2 === 'string' ? arg2 : 'utf8';\n const data = typeof input === 'string' ? input : Buffer.from(input).toString(encoding);\n const cb = typeof maybeCb === 'function' ? maybeCb : undefined;\n try {\n return this._write(data);\n } finally {\n cb?.();\n }\n }\n\n [Symbol.dispose]() {\n this.destroy();\n }\n}\n\nconst isStdFd = (fd: number) => {\n switch (fd) {\n case 1:\n case 2:\n case process.stdout.fd:\n case process.stderr.fd:\n return true;\n default:\n return false;\n }\n};\n\nconst fsFsync = (fd: number, cb: (error?: NodeJS.ErrnoException | null) => void) => {\n try {\n fs.fsync(fd, cb);\n } catch (error: any) {\n cb(error);\n }\n};\n"],"names":["LogStream","BUSY_WRITE_TIMEOUT","HIGH_WATER_MARK","EventEmitter","constructor","dest","fs","fsyncSync","process","nextTick","emit","file","fd","writing","writable","error","written","code","setTimeout","outputLength","Buffer","byteLength","output","from","subarray","toString","length","onOpened","mkdir","path","dirname","recursive","err","open","once","onClose","fsFsync","isStdFd","close","shift","write","_end","end","arg1","arg2","arg3","maybeCb","input","undefined","encoding","cb","destroy","flush","onDrain","off","onError","_write","data","startIdx","endIdx","indexOf","line","slice","push","Symbol","dispose","stdout","stderr","fsync"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/events/stream.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport { EventEmitter } from 'node:events';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nconst BUSY_WRITE_TIMEOUT = 100;\nconst HIGH_WATER_MARK = 16_387; /*16KB*/\n\nexport function writeEvent(dest: LogStream, category: string, kind: string, payload: any) {\n const timestamp = Date.now();\n const rest = JSON.stringify(payload).slice(1);\n const line =\n rest.length > 1\n ? `{\"_e\":\"${category}:${kind}\",\"_t\":${timestamp},${rest}\\n`\n : `{\"_e\":\"${category}:${kind}\",\"_t\":${timestamp}}\\n`;\n dest._writeln(line);\n}\n\nexport class LogStream extends EventEmitter implements NodeJS.WritableStream {\n #fd = -1;\n #file: string | null = null;\n\n #writing = false;\n #ending = false;\n #flushPending = false;\n #destroyed = false;\n #opening = false;\n\n #output = '';\n #len = 0;\n #lines: string[] = [];\n #head = 0;\n #partialLine = 0;\n #onRelease = (err: NodeJS.ErrnoException | null, written: number) => this.#release(err, written);\n\n constructor(dest: string | number) {\n super();\n if (typeof dest === 'number') {\n fs.fsyncSync(dest);\n this.#fd = dest;\n process.nextTick(() => this.emit('ready'));\n } else if (typeof dest === 'string') {\n this.#openFile(dest);\n }\n }\n\n get file(): string | null {\n return this.#file;\n }\n\n get fd(): number {\n return this.#fd;\n }\n\n get writing(): boolean {\n return this.#writing;\n }\n\n get writable(): boolean {\n return !this.#destroyed && !this.#ending;\n }\n\n #release(error: NodeJS.ErrnoException | null, written: number) {\n if (error) {\n if (error.code === 'EAGAIN' || error.code === 'EBUSY') {\n setTimeout(() => this.#writeLine(), BUSY_WRITE_TIMEOUT);\n } else {\n this.#writing = false;\n this.emit('error', error);\n }\n } else {\n this.emit('write', written);\n\n if (written === this.#output.length) {\n // Fast path: complete write (exact for ASCII, the common case for JSONL)\n this.#len -= this.#output.length;\n this.#output = '';\n\n if (this.#lines.length - this.#head > this.#partialLine) {\n this.#writeLine();\n } else if (this.#ending) {\n this.#writing = false;\n this.#close();\n } else {\n this.#writing = false;\n if (this.#flushPending) {\n this.emit('drain');\n }\n }\n } else {\n // Multi-byte complete write (written > length) or partial write (written < length)\n const outputLength = Buffer.byteLength(this.#output);\n if (outputLength > written) {\n const output = Buffer.from(this.#output).toString('utf8', written);\n this.#len -= this.#output.length - output.length;\n this.#output = output;\n } else {\n this.#len -= this.#output.length;\n this.#output = '';\n }\n\n if (this.#output || this.#lines.length - this.#head > this.#partialLine) {\n this.#writeLine();\n } else if (this.#ending) {\n this.#writing = false;\n this.#close();\n } else {\n this.#writing = false;\n if (this.#flushPending) {\n this.emit('drain');\n }\n }\n }\n }\n }\n\n #openFile(file: string) {\n this.#opening = true;\n this.#writing = true;\n\n const onOpened = (error: Error | null, fd?: number | null) => {\n if (error) {\n this.#writing = false;\n this.#opening = false;\n this.emit('error', error);\n } else {\n this.#fd = fd!;\n this.#file = file;\n this.#opening = false;\n this.#writing = false;\n this.emit('ready');\n if (this.#destroyed) {\n // do nothing when we're already closing the file\n } else if (\n (!this.writing && this.#lines.length - this.#head > this.#partialLine) ||\n this.#flushPending\n ) {\n this.#writeLine();\n }\n }\n };\n\n fs.mkdir(path.dirname(file), { recursive: true }, (err) => {\n if (err) return onOpened(err);\n fs.open(file, 'a', 0o666, onOpened);\n });\n }\n\n #close() {\n if (this.#fd === -1) {\n this.once('ready', () => this.#close());\n return;\n }\n\n this.#destroyed = true;\n this.#partialLine = 0;\n this.#lines.length = 0;\n this.#head = 0;\n\n const onClose = (error?: NodeJS.ErrnoException | null) => {\n if (error) {\n this.emit('error', error);\n this.emit('close', error);\n } else {\n if (this.#ending && !this.#writing) this.emit('finish');\n this.emit('close');\n }\n };\n\n fsFsync(this.#fd, (error) => {\n if (!error && !isStdFd(this.#fd)) {\n fs.close(this.#fd, onClose);\n } else {\n onClose(); // Error intentionally ignored, assume closed\n }\n });\n }\n\n #writeLine() {\n this.#writing = true;\n if (!this.#output) {\n const end = this.#lines.length - this.#partialLine;\n if (end > this.#head) {\n this.#output = this.#lines[this.#head++] || '';\n // Batch multiple lines into one write call below HWM, to avoid\n // excessive syscalls after when lines accumulated during a previous write\n while (this.#head < end && this.#output.length < HIGH_WATER_MARK) {\n this.#output += this.#lines[this.#head++];\n }\n if (this.#head === this.#lines.length) {\n this.#lines.length = 0;\n this.#head = 0;\n }\n }\n }\n fs.write(this.#fd, this.#output, this.#onRelease);\n }\n\n _end() {\n if (!this.#destroyed && !this.#ending) {\n this.#ending = true;\n if (this.#opening) {\n this.once('ready', () => this._end());\n } else if (!this.#writing && this.#fd >= 0) {\n if (this.#lines.length - this.#head > this.#partialLine) {\n this.#writeLine();\n } else {\n this.#close();\n }\n }\n }\n return this;\n }\n\n end(cb?: () => void): this;\n end(data: string | Uint8Array, cb?: () => void): this;\n end(str: string, encoding?: BufferEncoding, cb?: () => void): this;\n\n end(\n arg1?: Uint8Array | string | (() => void),\n arg2?: BufferEncoding | (() => void),\n arg3?: () => void\n ) {\n const maybeCb = arg3 || arg2 || arg1;\n const input = typeof arg1 !== 'function' ? arg1 : undefined;\n const encoding = typeof arg2 === 'string' ? arg2 : 'utf8';\n const cb = typeof maybeCb === 'function' ? maybeCb : undefined;\n if (typeof input === 'string') {\n this.write(input, encoding);\n } else if (input != null) {\n this.write(input);\n }\n if (cb) this.once('close', cb);\n return this._end();\n }\n\n destroy() {\n if (!this.#destroyed) this.#close();\n }\n\n flush(cb?: (error?: Error | null) => void) {\n if (this.#destroyed) {\n cb?.();\n } else {\n const onDrain = () => {\n if (!this.#destroyed) {\n fsFsync(this.#fd, (error) => {\n this.#flushPending = false;\n if (error?.code === 'EBADF') {\n cb?.(); // If fd is closed, ignore the error\n } else {\n cb?.(error);\n }\n });\n } else {\n this.#flushPending = false;\n cb?.();\n }\n this.off('error', onError);\n };\n\n const onError = (err: Error) => {\n this.#flushPending = false;\n this.off('drain', onDrain);\n cb?.(err);\n };\n\n this.#flushPending = true;\n this.once('drain', onDrain);\n this.once('error', onError);\n\n if (!this.#writing) {\n if (this.#lines.length - this.#head > this.#partialLine || this.#output) {\n // There are complete lines or remaining output to write\n this.#writeLine();\n } else {\n // Nothing complete to write, emit drain immediately\n process.nextTick(() => this.emit('drain'));\n }\n }\n }\n }\n\n _writeln(data: string): boolean {\n this.#len += data.length;\n if (!this.#writing && this.#lines.length === this.#head && !this.#output) {\n // Fast path: When no write is pending, directly write the line\n this.#writing = true;\n this.#output = data;\n fs.write(this.#fd, data, this.#onRelease);\n } else {\n this.#lines.push(data);\n if (!this.#writing) {\n this.#writeLine();\n }\n }\n return this.#len < HIGH_WATER_MARK;\n }\n\n _write(data: string): boolean {\n if (this.#destroyed) {\n return false;\n }\n\n this.#len += data.length;\n\n // Fast path: For complete lines with no pending partial we can skip the work below\n if (this.#partialLine === 0 && data.charCodeAt(data.length - 1) === 10 /*'\\n'*/) {\n return this._writeln(data);\n }\n\n let startIdx = 0;\n let endIdx = -1;\n while ((endIdx = data.indexOf('\\n', startIdx)) > -1) {\n const line = data.slice(startIdx, endIdx + 1);\n if (this.#partialLine > 0) {\n this.#lines[this.#lines.length - 1] += line;\n } else {\n this.#lines.push(line);\n }\n this.#partialLine = 0;\n startIdx = ++endIdx;\n }\n\n if (startIdx < data.length) {\n const line = data.slice(startIdx);\n if (this.#partialLine > 0) {\n this.#lines[this.#lines.length - 1] += line;\n } else {\n this.#lines.push(data.slice(startIdx));\n }\n this.#partialLine = 1;\n }\n\n if (!this.#writing && this.#lines.length - this.#head > this.#partialLine) {\n this.#writeLine();\n }\n\n return this.#len < HIGH_WATER_MARK;\n }\n\n write(buffer: Uint8Array | string, cb?: (err?: Error | null) => void): boolean;\n write(str: string, encoding?: BufferEncoding, cb?: (err?: Error | null) => void): boolean;\n\n write(\n input: Uint8Array | string,\n arg2?: BufferEncoding | ((err?: Error | null) => void),\n arg3?: (err?: Error | null) => void\n ): boolean {\n const maybeCb = arg3 || arg2;\n const encoding = typeof arg2 === 'string' ? arg2 : 'utf8';\n const data = typeof input === 'string' ? input : Buffer.from(input).toString(encoding);\n const cb = typeof maybeCb === 'function' ? maybeCb : undefined;\n try {\n return this._write(data);\n } finally {\n cb?.();\n }\n }\n\n [Symbol.dispose]() {\n this.destroy();\n }\n}\n\nconst isStdFd = (fd: number) => {\n switch (fd) {\n case 1:\n case 2:\n case process.stdout.fd:\n case process.stderr.fd:\n return true;\n default:\n return false;\n }\n};\n\nconst fsFsync = (fd: number, cb: (error?: NodeJS.ErrnoException | null) => void) => {\n try {\n fs.fsync(fd, cb);\n } catch (error: any) {\n cb(error);\n }\n};\n"],"names":["LogStream","writeEvent","BUSY_WRITE_TIMEOUT","HIGH_WATER_MARK","dest","category","kind","payload","timestamp","Date","now","rest","JSON","stringify","slice","line","length","_writeln","EventEmitter","constructor","err","written","fs","fsyncSync","process","nextTick","emit","file","fd","writing","writable","error","code","setTimeout","outputLength","Buffer","byteLength","output","from","toString","onOpened","mkdir","path","dirname","recursive","open","once","onClose","fsFsync","isStdFd","close","end","write","_end","arg1","arg2","arg3","maybeCb","input","undefined","encoding","cb","destroy","flush","onDrain","off","onError","data","push","_write","charCodeAt","startIdx","endIdx","indexOf","Symbol","dispose","stdout","stderr","fsync"],"mappings":"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"}
@@ -21,6 +21,9 @@ _export(exports, {
21
21
  hasRequiredIOSFilesAsync: function() {
22
22
  return hasRequiredIOSFilesAsync;
23
23
  },
24
+ maybeBailOnNativeModuleAsync: function() {
25
+ return maybeBailOnNativeModuleAsync;
26
+ },
24
27
  promptToClearMalformedNativeProjectsAsync: function() {
25
28
  return promptToClearMalformedNativeProjectsAsync;
26
29
  }
@@ -39,6 +42,13 @@ function _chalk() {
39
42
  };
40
43
  return data;
41
44
  }
45
+ function _unstableautolinkingexports() {
46
+ const data = require("expo/internal/unstable-autolinking-exports");
47
+ _unstableautolinkingexports = function() {
48
+ return data;
49
+ };
50
+ return data;
51
+ }
42
52
  function _fs() {
43
53
  const data = /*#__PURE__*/ _interop_require_default(require("fs"));
44
54
  _fs = function() {
@@ -178,6 +188,8 @@ async function promptToClearMalformedNativeProjectsAsync(projectRoot, checkPlatf
178
188
  const platforms = await getMalformedNativeProjectsAsync(projectRoot, checkPlatforms);
179
189
  if (!platforms.length) {
180
190
  return;
191
+ } else if (await maybeBailOnNativeModuleAsync(projectRoot)) {
192
+ return;
181
193
  }
182
194
  const displayPlatforms = platforms.map((platform)=>_chalk().default.cyan(platform));
183
195
  // Prompt which platforms to reset.
@@ -198,5 +210,31 @@ async function promptToClearMalformedNativeProjectsAsync(projectRoot, checkPlatf
198
210
  _log.warn('Continuing with malformed native projects');
199
211
  }
200
212
  }
213
+ async function maybeBailOnNativeModuleAsync(projectRoot) {
214
+ let isNativeModule = false;
215
+ try {
216
+ isNativeModule = await (0, _unstableautolinkingexports().isNativeModuleAsync)(projectRoot);
217
+ } catch {
218
+ // We don't care too much about a failure here
219
+ // TODO(@kitten): Remove try/catch; this is only to protect against version misalignment
220
+ // Remove this when we're bumping to SDK 56
221
+ }
222
+ if (isNativeModule) {
223
+ if (!(0, _interactive.isInteractive)()) {
224
+ _log.warn(`Current project was detected as a native module, but the command will continue because the terminal is not interactive.`);
225
+ return false;
226
+ } else {
227
+ _log.warn('Current project was detected as a native module and not an Expo app.');
228
+ }
229
+ const answer = await (0, _prompts.confirmAsync)({
230
+ message: `Continue anyway?`
231
+ });
232
+ if (!answer) {
233
+ return true;
234
+ }
235
+ _log.log();
236
+ }
237
+ return false;
238
+ }
201
239
 
202
240
  //# sourceMappingURL=clearNativeFolder.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/prebuild/clearNativeFolder.ts"],"sourcesContent":["import { AndroidConfig, IOSConfig, ModPlatform } from '@expo/config-plugins';\nimport chalk from 'chalk';\nimport fs from 'fs';\nimport path from 'path';\n\nimport * as Log from '../log';\nimport { directoryExistsAsync } from '../utils/dir';\nimport { isInteractive } from '../utils/interactive';\nimport { logNewSection } from '../utils/ora';\nimport { confirmAsync } from '../utils/prompts';\n\ntype ArbitraryPlatform = ModPlatform | string;\n\n/** Delete the input native folders and print a loading step. */\nexport async function clearNativeFolder(projectRoot: string, folders: string[]) {\n const step = logNewSection(`Clearing ${folders.join(', ')}`);\n try {\n await Promise.all(\n folders.map((folderName) =>\n fs.promises.rm(path.join(projectRoot, folderName), {\n recursive: true,\n force: true,\n })\n )\n );\n step.succeed(`Cleared ${folders.join(', ')} code`);\n } catch (error: any) {\n step.fail(`Failed to delete ${folders.join(', ')} code: ${error.message}`);\n throw error;\n }\n}\n\n/**\n * Returns `true` if a certain subset of required Android project files are intact.\n *\n * This isn't perfect but it serves the purpose of indicating that the user should\n * be warned to nuke the project files, most commonly when git is cleared and the root folder\n * remains in memory.\n */\nexport async function hasRequiredAndroidFilesAsync(projectRoot: string): Promise<boolean> {\n try {\n await Promise.all([\n AndroidConfig.Paths.getAppBuildGradleAsync(projectRoot),\n AndroidConfig.Paths.getProjectBuildGradleAsync(projectRoot),\n AndroidConfig.Paths.getAndroidManifestAsync(projectRoot),\n AndroidConfig.Paths.getMainApplicationAsync(projectRoot),\n ]);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Returns `true` if a certain subset of required iOS project files are intact. */\nexport async function hasRequiredIOSFilesAsync(projectRoot: string) {\n try {\n // If any of the following required files are missing, then the project is malformed.\n await Promise.all([\n IOSConfig.Paths.getAllXcodeProjectPaths(projectRoot),\n IOSConfig.Paths.getAllPBXProjectPaths(projectRoot),\n ]);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Filter out platforms that do not have an existing platform folder.\n * If the user wants to validate that neither of ['ios', 'android'] are malformed then we should\n * first check that both `ios` and `android` folders exist.\n *\n * This optimization prevents us from prompting to clear a \"malformed\" project that doesn't exist yet.\n */\nasync function filterPlatformsThatDoNotExistAsync(\n projectRoot: string,\n platforms: ArbitraryPlatform[]\n): Promise<ArbitraryPlatform[]> {\n const valid = await Promise.all(\n platforms.map(async (platform) => {\n if (await directoryExistsAsync(path.join(projectRoot, platform))) {\n return platform;\n }\n return null;\n })\n );\n return valid.filter(Boolean) as ArbitraryPlatform[];\n}\n\n/** Get a list of native platforms that have existing directories which contain malformed projects. */\nexport async function getMalformedNativeProjectsAsync(\n projectRoot: string,\n platforms: ArbitraryPlatform[]\n): Promise<ArbitraryPlatform[]> {\n const VERIFIERS: Record<ArbitraryPlatform, (root: string) => Promise<boolean>> = {\n android: hasRequiredAndroidFilesAsync,\n ios: hasRequiredIOSFilesAsync,\n };\n\n const checkablePlatforms = platforms.filter((platform) => platform in VERIFIERS);\n const checkPlatforms = await filterPlatformsThatDoNotExistAsync(projectRoot, checkablePlatforms);\n return (\n await Promise.all(\n checkPlatforms.map(async (platform) => {\n if (!VERIFIERS[platform]) {\n return false;\n }\n if (await VERIFIERS[platform](projectRoot)) {\n return false;\n }\n return platform;\n })\n )\n ).filter(Boolean) as ArbitraryPlatform[];\n}\n\nexport async function promptToClearMalformedNativeProjectsAsync(\n projectRoot: string,\n checkPlatforms: ArbitraryPlatform[]\n) {\n const platforms = await getMalformedNativeProjectsAsync(projectRoot, checkPlatforms);\n\n if (!platforms.length) {\n return;\n }\n\n const displayPlatforms = platforms.map((platform) => chalk.cyan(platform));\n // Prompt which platforms to reset.\n const message =\n platforms.length > 1\n ? `The ${displayPlatforms[0]} and ${displayPlatforms[1]} projects are malformed`\n : `The ${displayPlatforms[0]} project is malformed`;\n\n if (\n // If the process is non-interactive, default to clearing the malformed native project.\n // This would only happen on re-running prebuild.\n !isInteractive() ||\n // Prompt to clear the native folders.\n (await confirmAsync({\n message: `${message}, would you like to clear the project files and reinitialize them?`,\n initial: true,\n }))\n ) {\n if (!isInteractive()) {\n Log.warn(`${message}, project files will be cleared and reinitialized.`);\n }\n await clearNativeFolder(projectRoot, platforms);\n } else {\n // Warn the user that the process may fail.\n Log.warn('Continuing with malformed native projects');\n }\n}\n"],"names":["clearNativeFolder","getMalformedNativeProjectsAsync","hasRequiredAndroidFilesAsync","hasRequiredIOSFilesAsync","promptToClearMalformedNativeProjectsAsync","projectRoot","folders","step","logNewSection","join","Promise","all","map","folderName","fs","promises","rm","path","recursive","force","succeed","error","fail","message","AndroidConfig","Paths","getAppBuildGradleAsync","getProjectBuildGradleAsync","getAndroidManifestAsync","getMainApplicationAsync","IOSConfig","getAllXcodeProjectPaths","getAllPBXProjectPaths","filterPlatformsThatDoNotExistAsync","platforms","valid","platform","directoryExistsAsync","filter","Boolean","VERIFIERS","android","ios","checkablePlatforms","checkPlatforms","length","displayPlatforms","chalk","cyan","isInteractive","confirmAsync","initial","Log","warn"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/prebuild/clearNativeFolder.ts"],"sourcesContent":["import { AndroidConfig, IOSConfig, ModPlatform } from '@expo/config-plugins';\nimport chalk from 'chalk';\nimport { isNativeModuleAsync } from 'expo/internal/unstable-autolinking-exports';\nimport fs from 'fs';\nimport path from 'path';\n\nimport * as Log from '../log';\nimport { directoryExistsAsync } from '../utils/dir';\nimport { isInteractive } from '../utils/interactive';\nimport { logNewSection } from '../utils/ora';\nimport { confirmAsync } from '../utils/prompts';\n\ntype ArbitraryPlatform = ModPlatform | string;\n\n/** Delete the input native folders and print a loading step. */\nexport async function clearNativeFolder(projectRoot: string, folders: string[]) {\n const step = logNewSection(`Clearing ${folders.join(', ')}`);\n try {\n await Promise.all(\n folders.map((folderName) =>\n fs.promises.rm(path.join(projectRoot, folderName), {\n recursive: true,\n force: true,\n })\n )\n );\n step.succeed(`Cleared ${folders.join(', ')} code`);\n } catch (error: any) {\n step.fail(`Failed to delete ${folders.join(', ')} code: ${error.message}`);\n throw error;\n }\n}\n\n/**\n * Returns `true` if a certain subset of required Android project files are intact.\n *\n * This isn't perfect but it serves the purpose of indicating that the user should\n * be warned to nuke the project files, most commonly when git is cleared and the root folder\n * remains in memory.\n */\nexport async function hasRequiredAndroidFilesAsync(projectRoot: string): Promise<boolean> {\n try {\n await Promise.all([\n AndroidConfig.Paths.getAppBuildGradleAsync(projectRoot),\n AndroidConfig.Paths.getProjectBuildGradleAsync(projectRoot),\n AndroidConfig.Paths.getAndroidManifestAsync(projectRoot),\n AndroidConfig.Paths.getMainApplicationAsync(projectRoot),\n ]);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Returns `true` if a certain subset of required iOS project files are intact. */\nexport async function hasRequiredIOSFilesAsync(projectRoot: string) {\n try {\n // If any of the following required files are missing, then the project is malformed.\n await Promise.all([\n IOSConfig.Paths.getAllXcodeProjectPaths(projectRoot),\n IOSConfig.Paths.getAllPBXProjectPaths(projectRoot),\n ]);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Filter out platforms that do not have an existing platform folder.\n * If the user wants to validate that neither of ['ios', 'android'] are malformed then we should\n * first check that both `ios` and `android` folders exist.\n *\n * This optimization prevents us from prompting to clear a \"malformed\" project that doesn't exist yet.\n */\nasync function filterPlatformsThatDoNotExistAsync(\n projectRoot: string,\n platforms: ArbitraryPlatform[]\n): Promise<ArbitraryPlatform[]> {\n const valid = await Promise.all(\n platforms.map(async (platform) => {\n if (await directoryExistsAsync(path.join(projectRoot, platform))) {\n return platform;\n }\n return null;\n })\n );\n return valid.filter(Boolean) as ArbitraryPlatform[];\n}\n\n/** Get a list of native platforms that have existing directories which contain malformed projects. */\nexport async function getMalformedNativeProjectsAsync(\n projectRoot: string,\n platforms: ArbitraryPlatform[]\n): Promise<ArbitraryPlatform[]> {\n const VERIFIERS: Record<ArbitraryPlatform, (root: string) => Promise<boolean>> = {\n android: hasRequiredAndroidFilesAsync,\n ios: hasRequiredIOSFilesAsync,\n };\n\n const checkablePlatforms = platforms.filter((platform) => platform in VERIFIERS);\n const checkPlatforms = await filterPlatformsThatDoNotExistAsync(projectRoot, checkablePlatforms);\n return (\n await Promise.all(\n checkPlatforms.map(async (platform) => {\n if (!VERIFIERS[platform]) {\n return false;\n }\n if (await VERIFIERS[platform](projectRoot)) {\n return false;\n }\n return platform;\n })\n )\n ).filter(Boolean) as ArbitraryPlatform[];\n}\n\nexport async function promptToClearMalformedNativeProjectsAsync(\n projectRoot: string,\n checkPlatforms: ArbitraryPlatform[]\n) {\n const platforms = await getMalformedNativeProjectsAsync(projectRoot, checkPlatforms);\n\n if (!platforms.length) {\n return;\n } else if (await maybeBailOnNativeModuleAsync(projectRoot)) {\n return;\n }\n\n const displayPlatforms = platforms.map((platform) => chalk.cyan(platform));\n // Prompt which platforms to reset.\n const message =\n platforms.length > 1\n ? `The ${displayPlatforms[0]} and ${displayPlatforms[1]} projects are malformed`\n : `The ${displayPlatforms[0]} project is malformed`;\n\n if (\n // If the process is non-interactive, default to clearing the malformed native project.\n // This would only happen on re-running prebuild.\n !isInteractive() ||\n // Prompt to clear the native folders.\n (await confirmAsync({\n message: `${message}, would you like to clear the project files and reinitialize them?`,\n initial: true,\n }))\n ) {\n if (!isInteractive()) {\n Log.warn(`${message}, project files will be cleared and reinitialized.`);\n }\n await clearNativeFolder(projectRoot, platforms);\n } else {\n // Warn the user that the process may fail.\n Log.warn('Continuing with malformed native projects');\n }\n}\n\nexport async function maybeBailOnNativeModuleAsync(projectRoot: string) {\n let isNativeModule = false;\n try {\n isNativeModule = await isNativeModuleAsync(projectRoot);\n } catch {\n // We don't care too much about a failure here\n // TODO(@kitten): Remove try/catch; this is only to protect against version misalignment\n // Remove this when we're bumping to SDK 56\n }\n if (isNativeModule) {\n if (!isInteractive()) {\n Log.warn(\n `Current project was detected as a native module, but the command will continue because the terminal is not interactive.`\n );\n return false;\n } else {\n Log.warn('Current project was detected as a native module and not an Expo app.');\n }\n\n const answer = await confirmAsync({\n message: `Continue anyway?`,\n });\n if (!answer) {\n return true;\n }\n\n Log.log();\n }\n\n return false;\n}\n"],"names":["clearNativeFolder","getMalformedNativeProjectsAsync","hasRequiredAndroidFilesAsync","hasRequiredIOSFilesAsync","maybeBailOnNativeModuleAsync","promptToClearMalformedNativeProjectsAsync","projectRoot","folders","step","logNewSection","join","Promise","all","map","folderName","fs","promises","rm","path","recursive","force","succeed","error","fail","message","AndroidConfig","Paths","getAppBuildGradleAsync","getProjectBuildGradleAsync","getAndroidManifestAsync","getMainApplicationAsync","IOSConfig","getAllXcodeProjectPaths","getAllPBXProjectPaths","filterPlatformsThatDoNotExistAsync","platforms","valid","platform","directoryExistsAsync","filter","Boolean","VERIFIERS","android","ios","checkablePlatforms","checkPlatforms","length","displayPlatforms","chalk","cyan","isInteractive","confirmAsync","initial","Log","warn","isNativeModule","isNativeModuleAsync","answer","log"],"mappings":"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"}
@@ -102,6 +102,10 @@ async function prebuildAsync(projectRoot, options) {
102
102
  if (await maybeBailOnGitStatusAsync()) {
103
103
  return null;
104
104
  }
105
+ // Check if the target project is actually a native module, which we don't want to erase
106
+ if (await (0, _clearNativeFolder.maybeBailOnNativeModuleAsync)(projectRoot)) {
107
+ return null;
108
+ }
105
109
  // Clear the native folders before syncing
106
110
  await (0, _clearNativeFolder.clearNativeFolder)(projectRoot, options.platforms);
107
111
  } else {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/prebuild/prebuildAsync.ts"],"sourcesContent":["import { ExpoConfig, getConfig } from '@expo/config';\nimport { ModPlatform } from '@expo/config-plugins';\nimport chalk from 'chalk';\n\nimport { clearNativeFolder, promptToClearMalformedNativeProjectsAsync } from './clearNativeFolder';\nimport { configureProjectAsync } from './configureProjectAsync';\nimport { ensureConfigAsync } from './ensureConfigAsync';\nimport { assertPlatforms, ensureValidPlatforms, resolveTemplateOption } from './resolveOptions';\nimport { updateFromTemplateAsync } from './updateFromTemplate';\nimport { installAsync } from '../install/installAsync';\nimport { Log } from '../log';\nimport { env } from '../utils/env';\nimport { setNodeEnv, loadEnvFiles } from '../utils/nodeEnv';\nimport { clearNodeModulesAsync } from '../utils/nodeModules';\nimport { logNewSection } from '../utils/ora';\nimport { profile } from '../utils/profile';\nimport { confirmAsync } from '../utils/prompts';\n\nconst debug = require('debug')('expo:prebuild') as typeof console.log;\n\nexport type PrebuildResults = {\n /** Expo config. */\n exp: ExpoConfig;\n /** Indicates if the process created new files. */\n hasNewProjectFiles: boolean;\n /** The platforms that were prebuilt. */\n platforms: ModPlatform[];\n /** Indicates if pod install was run. */\n podInstall: boolean;\n /** Indicates if node modules were installed. */\n nodeInstall: boolean;\n};\n\n/**\n * Entry point into the prebuild process, delegates to other helpers to perform various steps.\n *\n * 0. Attempt to clean the project folders.\n * 1. Create native projects (ios, android).\n * 2. Install node modules.\n * 3. Apply config to native projects.\n * 4. Install CocoaPods.\n */\nexport async function prebuildAsync(\n projectRoot: string,\n options: {\n /** Should install node modules and cocoapods. */\n install?: boolean;\n /** List of platforms to prebuild. */\n platforms: ModPlatform[];\n /** Should delete the native folders before attempting to prebuild. */\n clean?: boolean;\n /** URL or file path to the prebuild template. */\n template?: string;\n /** Name of the node package manager to install with. */\n packageManager?: {\n npm?: boolean;\n yarn?: boolean;\n pnpm?: boolean;\n bun?: boolean;\n };\n /** List of node modules to skip updating. */\n skipDependencyUpdate?: string[];\n }\n): Promise<PrebuildResults | null> {\n setNodeEnv('development');\n loadEnvFiles(projectRoot);\n\n const { platforms } = getConfig(projectRoot).exp;\n if (platforms?.length) {\n // Filter out platforms that aren't in the app.json.\n const finalPlatforms = options.platforms.filter((platform) => platforms.includes(platform));\n if (finalPlatforms.length > 0) {\n options.platforms = finalPlatforms;\n } else {\n const requestedPlatforms = options.platforms.join(', ');\n Log.warn(\n chalk`⚠️ Requested prebuild for \"${requestedPlatforms}\", but only \"${platforms.join(', ')}\" is present in app config (\"expo.platforms\" entry). Continuing with \"${requestedPlatforms}\".`\n );\n }\n }\n if (options.clean) {\n const { maybeBailOnGitStatusAsync } = await import('../utils/git.js');\n // Clean the project folders...\n if (await maybeBailOnGitStatusAsync()) {\n return null;\n }\n // Clear the native folders before syncing\n await clearNativeFolder(projectRoot, options.platforms);\n } else {\n // Check if the existing project folders are malformed.\n await promptToClearMalformedNativeProjectsAsync(projectRoot, options.platforms);\n }\n\n // Warn if the project is attempting to prebuild an unsupported platform (iOS on Windows).\n options.platforms = ensureValidPlatforms(options.platforms);\n // Assert if no platforms are left over after filtering.\n assertPlatforms(options.platforms);\n\n // Get the Expo config, create it if missing.\n const { exp, pkg } = await ensureConfigAsync(projectRoot, { platforms: options.platforms });\n\n // Create native projects from template.\n const { hasNewProjectFiles, needsPodInstall, templateChecksum, changedDependencies } =\n await updateFromTemplateAsync(projectRoot, {\n exp,\n pkg,\n template: options.template != null ? resolveTemplateOption(options.template) : undefined,\n platforms: options.platforms,\n skipDependencyUpdate: options.skipDependencyUpdate,\n });\n\n // Install node modules\n if (options.install) {\n if (changedDependencies.length) {\n if (options.packageManager?.npm) {\n await clearNodeModulesAsync(projectRoot);\n }\n\n Log.log(chalk.gray(chalk`Dependencies in the {bold package.json} changed:`));\n Log.log(chalk.gray(' ' + changedDependencies.join(', ')));\n\n // Installing dependencies is a legacy feature from the unversioned\n // command. We know opt to not change dependencies unless a template\n // indicates a new dependency is required, or if the core dependencies are wrong.\n if (\n await confirmAsync({\n message: `Install the updated dependencies?`,\n initial: true,\n })\n ) {\n await installAsync([], {\n npm: !!options.packageManager?.npm,\n yarn: !!options.packageManager?.yarn,\n pnpm: !!options.packageManager?.pnpm,\n bun: !!options.packageManager?.bun,\n silent: !(env.EXPO_DEBUG || env.CI),\n });\n }\n }\n }\n\n // Apply Expo config to native projects. Prevent log-spew from ora when running in debug mode.\n const configSyncingStep: { succeed(text?: string): unknown; fail(text?: string): unknown } =\n env.EXPO_DEBUG\n ? {\n succeed(text) {\n Log.log(text!);\n },\n fail(text) {\n Log.error(text!);\n },\n }\n : logNewSection('Running prebuild');\n try {\n await profile(configureProjectAsync)(projectRoot, {\n platforms: options.platforms,\n exp,\n templateChecksum,\n });\n configSyncingStep.succeed('Finished prebuild');\n } catch (error) {\n configSyncingStep.fail('Prebuild failed');\n throw error;\n }\n\n // Install CocoaPods\n let podsInstalled: boolean = false;\n // err towards running pod install less because it's slow and users can easily run npx pod-install afterwards.\n if (options.platforms.includes('ios') && options.install && needsPodInstall) {\n const { installCocoaPodsAsync } = await import('../utils/cocoapods.js');\n\n podsInstalled = await installCocoaPodsAsync(projectRoot);\n } else {\n debug('Skipped pod install');\n }\n\n return {\n nodeInstall: !!options.install,\n podInstall: !podsInstalled,\n platforms: options.platforms,\n hasNewProjectFiles,\n exp,\n };\n}\n"],"names":["prebuildAsync","debug","require","projectRoot","options","setNodeEnv","loadEnvFiles","platforms","getConfig","exp","length","finalPlatforms","filter","platform","includes","requestedPlatforms","join","Log","warn","chalk","clean","maybeBailOnGitStatusAsync","clearNativeFolder","promptToClearMalformedNativeProjectsAsync","ensureValidPlatforms","assertPlatforms","pkg","ensureConfigAsync","hasNewProjectFiles","needsPodInstall","templateChecksum","changedDependencies","updateFromTemplateAsync","template","resolveTemplateOption","undefined","skipDependencyUpdate","install","packageManager","npm","clearNodeModulesAsync","log","gray","confirmAsync","message","initial","installAsync","yarn","pnpm","bun","silent","env","EXPO_DEBUG","CI","configSyncingStep","succeed","text","fail","error","logNewSection","profile","configureProjectAsync","podsInstalled","installCocoaPodsAsync","nodeInstall","podInstall"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/prebuild/prebuildAsync.ts"],"sourcesContent":["import { ExpoConfig, getConfig } from '@expo/config';\nimport { ModPlatform } from '@expo/config-plugins';\nimport chalk from 'chalk';\n\nimport {\n clearNativeFolder,\n promptToClearMalformedNativeProjectsAsync,\n maybeBailOnNativeModuleAsync,\n} from './clearNativeFolder';\nimport { configureProjectAsync } from './configureProjectAsync';\nimport { ensureConfigAsync } from './ensureConfigAsync';\nimport { assertPlatforms, ensureValidPlatforms, resolveTemplateOption } from './resolveOptions';\nimport { updateFromTemplateAsync } from './updateFromTemplate';\nimport { installAsync } from '../install/installAsync';\nimport { Log } from '../log';\nimport { env } from '../utils/env';\nimport { setNodeEnv, loadEnvFiles } from '../utils/nodeEnv';\nimport { clearNodeModulesAsync } from '../utils/nodeModules';\nimport { logNewSection } from '../utils/ora';\nimport { profile } from '../utils/profile';\nimport { confirmAsync } from '../utils/prompts';\n\nconst debug = require('debug')('expo:prebuild') as typeof console.log;\n\nexport type PrebuildResults = {\n /** Expo config. */\n exp: ExpoConfig;\n /** Indicates if the process created new files. */\n hasNewProjectFiles: boolean;\n /** The platforms that were prebuilt. */\n platforms: ModPlatform[];\n /** Indicates if pod install was run. */\n podInstall: boolean;\n /** Indicates if node modules were installed. */\n nodeInstall: boolean;\n};\n\n/**\n * Entry point into the prebuild process, delegates to other helpers to perform various steps.\n *\n * 0. Attempt to clean the project folders.\n * 1. Create native projects (ios, android).\n * 2. Install node modules.\n * 3. Apply config to native projects.\n * 4. Install CocoaPods.\n */\nexport async function prebuildAsync(\n projectRoot: string,\n options: {\n /** Should install node modules and cocoapods. */\n install?: boolean;\n /** List of platforms to prebuild. */\n platforms: ModPlatform[];\n /** Should delete the native folders before attempting to prebuild. */\n clean?: boolean;\n /** URL or file path to the prebuild template. */\n template?: string;\n /** Name of the node package manager to install with. */\n packageManager?: {\n npm?: boolean;\n yarn?: boolean;\n pnpm?: boolean;\n bun?: boolean;\n };\n /** List of node modules to skip updating. */\n skipDependencyUpdate?: string[];\n }\n): Promise<PrebuildResults | null> {\n setNodeEnv('development');\n loadEnvFiles(projectRoot);\n\n const { platforms } = getConfig(projectRoot).exp;\n if (platforms?.length) {\n // Filter out platforms that aren't in the app.json.\n const finalPlatforms = options.platforms.filter((platform) => platforms.includes(platform));\n if (finalPlatforms.length > 0) {\n options.platforms = finalPlatforms;\n } else {\n const requestedPlatforms = options.platforms.join(', ');\n Log.warn(\n chalk`⚠️ Requested prebuild for \"${requestedPlatforms}\", but only \"${platforms.join(', ')}\" is present in app config (\"expo.platforms\" entry). Continuing with \"${requestedPlatforms}\".`\n );\n }\n }\n if (options.clean) {\n const { maybeBailOnGitStatusAsync } = await import('../utils/git.js');\n // Clean the project folders...\n if (await maybeBailOnGitStatusAsync()) {\n return null;\n }\n // Check if the target project is actually a native module, which we don't want to erase\n if (await maybeBailOnNativeModuleAsync(projectRoot)) {\n return null;\n }\n // Clear the native folders before syncing\n await clearNativeFolder(projectRoot, options.platforms);\n } else {\n // Check if the existing project folders are malformed.\n await promptToClearMalformedNativeProjectsAsync(projectRoot, options.platforms);\n }\n\n // Warn if the project is attempting to prebuild an unsupported platform (iOS on Windows).\n options.platforms = ensureValidPlatforms(options.platforms);\n // Assert if no platforms are left over after filtering.\n assertPlatforms(options.platforms);\n\n // Get the Expo config, create it if missing.\n const { exp, pkg } = await ensureConfigAsync(projectRoot, { platforms: options.platforms });\n\n // Create native projects from template.\n const { hasNewProjectFiles, needsPodInstall, templateChecksum, changedDependencies } =\n await updateFromTemplateAsync(projectRoot, {\n exp,\n pkg,\n template: options.template != null ? resolveTemplateOption(options.template) : undefined,\n platforms: options.platforms,\n skipDependencyUpdate: options.skipDependencyUpdate,\n });\n\n // Install node modules\n if (options.install) {\n if (changedDependencies.length) {\n if (options.packageManager?.npm) {\n await clearNodeModulesAsync(projectRoot);\n }\n\n Log.log(chalk.gray(chalk`Dependencies in the {bold package.json} changed:`));\n Log.log(chalk.gray(' ' + changedDependencies.join(', ')));\n\n // Installing dependencies is a legacy feature from the unversioned\n // command. We know opt to not change dependencies unless a template\n // indicates a new dependency is required, or if the core dependencies are wrong.\n if (\n await confirmAsync({\n message: `Install the updated dependencies?`,\n initial: true,\n })\n ) {\n await installAsync([], {\n npm: !!options.packageManager?.npm,\n yarn: !!options.packageManager?.yarn,\n pnpm: !!options.packageManager?.pnpm,\n bun: !!options.packageManager?.bun,\n silent: !(env.EXPO_DEBUG || env.CI),\n });\n }\n }\n }\n\n // Apply Expo config to native projects. Prevent log-spew from ora when running in debug mode.\n const configSyncingStep: { succeed(text?: string): unknown; fail(text?: string): unknown } =\n env.EXPO_DEBUG\n ? {\n succeed(text) {\n Log.log(text!);\n },\n fail(text) {\n Log.error(text!);\n },\n }\n : logNewSection('Running prebuild');\n try {\n await profile(configureProjectAsync)(projectRoot, {\n platforms: options.platforms,\n exp,\n templateChecksum,\n });\n configSyncingStep.succeed('Finished prebuild');\n } catch (error) {\n configSyncingStep.fail('Prebuild failed');\n throw error;\n }\n\n // Install CocoaPods\n let podsInstalled: boolean = false;\n // err towards running pod install less because it's slow and users can easily run npx pod-install afterwards.\n if (options.platforms.includes('ios') && options.install && needsPodInstall) {\n const { installCocoaPodsAsync } = await import('../utils/cocoapods.js');\n\n podsInstalled = await installCocoaPodsAsync(projectRoot);\n } else {\n debug('Skipped pod install');\n }\n\n return {\n nodeInstall: !!options.install,\n podInstall: !podsInstalled,\n platforms: options.platforms,\n hasNewProjectFiles,\n exp,\n };\n}\n"],"names":["prebuildAsync","debug","require","projectRoot","options","setNodeEnv","loadEnvFiles","platforms","getConfig","exp","length","finalPlatforms","filter","platform","includes","requestedPlatforms","join","Log","warn","chalk","clean","maybeBailOnGitStatusAsync","maybeBailOnNativeModuleAsync","clearNativeFolder","promptToClearMalformedNativeProjectsAsync","ensureValidPlatforms","assertPlatforms","pkg","ensureConfigAsync","hasNewProjectFiles","needsPodInstall","templateChecksum","changedDependencies","updateFromTemplateAsync","template","resolveTemplateOption","undefined","skipDependencyUpdate","install","packageManager","npm","clearNodeModulesAsync","log","gray","confirmAsync","message","initial","installAsync","yarn","pnpm","bun","silent","env","EXPO_DEBUG","CI","configSyncingStep","succeed","text","fail","error","logNewSection","profile","configureProjectAsync","podsInstalled","installCocoaPodsAsync","nodeInstall","podInstall"],"mappings":"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"}
@@ -950,7 +950,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
950
950
  (0, _waitForMetroToObserveTypeScriptFile.observeAnyFileChanges)({
951
951
  metro,
952
952
  server
953
- }, (events)=>{
953
+ }, ({ changes })=>{
954
954
  var _exp_extra_router, _exp_extra;
955
955
  if (hasApiRoutes) {
956
956
  // NOTE(EvanBacon): We aren't sure what files the API routes are using so we'll just invalidate
@@ -960,23 +960,19 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
960
960
  // up for a lot of the overhead.
961
961
  this.invalidateApiRouteCache();
962
962
  } else if (!(0, _router.hasWarnedAboutApiRoutes)()) {
963
- for (const event of events){
964
- var // If the user did not delete a file that matches the Expo Router API Route convention, then we should warn that
963
+ for (const change of changes.addedFiles){
964
+ if (// If the user did not delete a file that matches the Expo Router API Route convention, then we should warn that
965
965
  // API Routes are not enabled in the project.
966
- _event_metadata;
967
- if (((_event_metadata = event.metadata) == null ? void 0 : _event_metadata.type) !== 'd' && // Ensure the file is in the project's routes directory to prevent false positives in monorepos.
968
- event.filePath.startsWith(appDir) && (0, _router.isApiRouteConvention)(event.filePath)) {
966
+ // Ensure the file is in the project's routes directory to prevent false positives in monorepos.
967
+ change[0].startsWith(appDir) && (0, _router.isApiRouteConvention)(change[0])) {
969
968
  (0, _router.warnInvalidWebOutput)();
970
969
  }
971
970
  }
972
971
  }
973
972
  // Handle loader file changes for HMR
974
973
  if ((_exp_extra = exp.extra) == null ? void 0 : (_exp_extra_router = _exp_extra.router) == null ? void 0 : _exp_extra_router.unstable_useServerDataLoaders) {
975
- for (const event of events){
976
- var _event_metadata1;
977
- if (((_event_metadata1 = event.metadata) == null ? void 0 : _event_metadata1.type) !== 'd') {
978
- this.handleLoaderFileChange(event.filePath);
979
- }
974
+ for (const change of changes.modifiedFiles){
975
+ this.handleLoaderFileChange(change[0]);
980
976
  }
981
977
  }
982
978
  });
@@ -1157,6 +1153,8 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
1157
1153
  debug('Skipping TypeScript check because Metro is not running (headless).');
1158
1154
  return resolve(false);
1159
1155
  }
1156
+ // TODO(@kitten): This is highly inefficient. We shouldn't watch all changes to determine this
1157
+ // and instead use startup heuristic and do a pre-bundling check
1160
1158
  const off = (0, _metroWatchTypeScriptFiles.metroWatchTypeScriptFiles)({
1161
1159
  projectRoot: this.projectRoot,
1162
1160
  server: this.instance.server,