@limrun/api 0.22.2 → 0.23.1

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 (61) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/exec-client.d.mts +5 -1
  3. package/exec-client.d.mts.map +1 -1
  4. package/exec-client.d.ts +5 -1
  5. package/exec-client.d.ts.map +1 -1
  6. package/exec-client.js +14 -7
  7. package/exec-client.js.map +1 -1
  8. package/exec-client.mjs +14 -7
  9. package/exec-client.mjs.map +1 -1
  10. package/folder-sync-ignore.d.mts +7 -0
  11. package/folder-sync-ignore.d.mts.map +1 -0
  12. package/folder-sync-ignore.d.ts +7 -0
  13. package/folder-sync-ignore.d.ts.map +1 -0
  14. package/folder-sync-ignore.js +56 -0
  15. package/folder-sync-ignore.js.map +1 -0
  16. package/folder-sync-ignore.mjs +52 -0
  17. package/folder-sync-ignore.mjs.map +1 -0
  18. package/folder-sync-watcher.d.mts +2 -0
  19. package/folder-sync-watcher.d.mts.map +1 -1
  20. package/folder-sync-watcher.d.ts +2 -0
  21. package/folder-sync-watcher.d.ts.map +1 -1
  22. package/folder-sync-watcher.js +10 -62
  23. package/folder-sync-watcher.js.map +1 -1
  24. package/folder-sync-watcher.mjs +10 -62
  25. package/folder-sync-watcher.mjs.map +1 -1
  26. package/folder-sync.d.mts +16 -16
  27. package/folder-sync.d.mts.map +1 -1
  28. package/folder-sync.d.ts +16 -16
  29. package/folder-sync.d.ts.map +1 -1
  30. package/folder-sync.js +22 -65
  31. package/folder-sync.js.map +1 -1
  32. package/folder-sync.mjs +21 -64
  33. package/folder-sync.mjs.map +1 -1
  34. package/ios-client.d.mts +24 -0
  35. package/ios-client.d.mts.map +1 -1
  36. package/ios-client.d.ts +24 -0
  37. package/ios-client.d.ts.map +1 -1
  38. package/ios-client.js +108 -8
  39. package/ios-client.js.map +1 -1
  40. package/ios-client.mjs +109 -9
  41. package/ios-client.mjs.map +1 -1
  42. package/package.json +11 -1
  43. package/sandbox-client.d.mts +20 -15
  44. package/sandbox-client.d.mts.map +1 -1
  45. package/sandbox-client.d.ts +20 -15
  46. package/sandbox-client.d.ts.map +1 -1
  47. package/sandbox-client.js +49 -40
  48. package/sandbox-client.js.map +1 -1
  49. package/sandbox-client.mjs +48 -40
  50. package/sandbox-client.mjs.map +1 -1
  51. package/src/exec-client.ts +14 -7
  52. package/src/folder-sync-ignore.ts +65 -0
  53. package/src/folder-sync-watcher.ts +11 -66
  54. package/src/folder-sync.ts +39 -89
  55. package/src/ios-client.ts +138 -9
  56. package/src/sandbox-client.ts +72 -62
  57. package/src/version.ts +1 -1
  58. package/version.d.mts +1 -1
  59. package/version.d.ts +1 -1
  60. package/version.js +1 -1
  61. package/version.mjs +1 -1
package/sandbox-client.js CHANGED
@@ -1,8 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createXCodeSandboxClient = createXCodeSandboxClient;
4
+ const tslib_1 = require("./internal/tslib.js");
5
+ const os_1 = tslib_1.__importDefault(require("os"));
6
+ const path_1 = tslib_1.__importDefault(require("path"));
4
7
  const folder_sync_1 = require("./folder-sync.js");
5
8
  const exec_client_1 = require("./exec-client.js");
9
+ const folder_sync_ignore_1 = require("./folder-sync-ignore.js");
10
+ const crypto_1 = tslib_1.__importDefault(require("crypto"));
6
11
  /**
7
12
  * Creates a client for interacting with a sandboxed Xcode build service.
8
13
  *
@@ -49,7 +54,7 @@ async function createXCodeSandboxClient(options) {
49
54
  console.error('[XCodeSandbox]', ...args);
50
55
  },
51
56
  };
52
- const logFn = (level, msg) => {
57
+ const log = (level, msg) => {
53
58
  switch (level) {
54
59
  case 'debug':
55
60
  logger.debug(msg);
@@ -89,49 +94,53 @@ async function createXCodeSandboxClient(options) {
89
94
  }
90
95
  return {
91
96
  async sync(localCodePath, opts) {
97
+ // Use folder name and hash of absolute path to scope basisCacheDir uniquely for each sync root
98
+ const resolvedPath = path_1.default.resolve(localCodePath);
99
+ const folderName = path_1.default.basename(resolvedPath);
100
+ const hash = crypto_1.default.createHash('sha1').update(resolvedPath).digest('hex').slice(0, 8);
101
+ const cacheKey = `limsync-cache-${folderName}-${hash}`;
102
+ const basisCacheDir = opts?.basisCacheDir ?? path_1.default.join(os_1.default.tmpdir(), cacheKey);
92
103
  const codeSyncOpts = {
93
104
  apiUrl: options.apiUrl,
94
105
  token: options.token,
95
- udid: opts?.cacheKey ?? 'xcode-sandbox',
96
- install: false,
97
- filter: (relativePath) => {
98
- if (relativePath.startsWith('build/') ||
99
- relativePath.startsWith('.build/') ||
100
- relativePath.startsWith('DerivedData/') ||
101
- relativePath.startsWith('Index.noindex/') ||
102
- relativePath.startsWith('ModuleCache.noindex/') ||
103
- relativePath.startsWith('.index-build/')) {
106
+ udid: cacheKey,
107
+ install: opts?.install ?? true,
108
+ ignoreFn: await (0, folder_sync_ignore_1.createIgnoreFn)(localCodePath, {
109
+ basisCacheDir,
110
+ additional: (relativePath) => {
111
+ if (relativePath.startsWith('build/') ||
112
+ relativePath.startsWith('.build/') ||
113
+ relativePath.startsWith('DerivedData/') ||
114
+ relativePath.startsWith('Index.noindex/') ||
115
+ relativePath.startsWith('ModuleCache.noindex/') ||
116
+ relativePath.startsWith('.index-build/')) {
117
+ return true;
118
+ }
119
+ if (relativePath.startsWith('.swiftpm/') ||
120
+ relativePath.startsWith('Pods/') ||
121
+ relativePath.startsWith('Carthage/Build/')) {
122
+ return true;
123
+ }
124
+ if (relativePath.includes('/xcuserdata/')) {
125
+ return true;
126
+ }
127
+ if (relativePath.includes('.dSYM/')) {
128
+ return true;
129
+ }
130
+ // User-provided ignores
131
+ if (opts?.ignore?.(relativePath)) {
132
+ return true;
133
+ }
104
134
  return false;
105
- }
106
- if (relativePath.startsWith('.swiftpm/') ||
107
- relativePath.startsWith('Pods/') ||
108
- relativePath.startsWith('Carthage/Build/')) {
109
- return false;
110
- }
111
- if (relativePath.startsWith('.git/') ||
112
- relativePath.startsWith('.limsync-cache/') ||
113
- relativePath === '.DS_Store' ||
114
- relativePath.endsWith('/.DS_Store')) {
115
- return false;
116
- }
117
- if (relativePath.includes('/xcuserdata/')) {
118
- return false;
119
- }
120
- if (relativePath.includes('.dSYM/')) {
121
- return false;
122
- }
123
- // User-provided filter
124
- if (opts?.filter && !opts.filter(relativePath)) {
125
- return false;
126
- }
127
- return true;
128
- },
129
- ...(opts?.basisCacheDir ? { basisCacheDir: opts.basisCacheDir } : {}),
130
- ...(opts?.maxPatchBytes !== undefined ? { maxPatchBytes: opts.maxPatchBytes } : {}),
131
- ...(opts?.watch !== undefined ? { watch: opts.watch } : {}),
132
- log: opts?.log ?? logFn,
135
+ },
136
+ }),
137
+ basisCacheDir,
138
+ watch: opts?.watch ?? true,
139
+ maxPatchBytes: opts?.maxPatchBytes ?? 4 * 1024 * 1024,
140
+ launchMode: 'ForegroundIfRunning',
141
+ log,
133
142
  };
134
- const result = await (0, folder_sync_1.syncApp)(localCodePath, codeSyncOpts);
143
+ const result = await (0, folder_sync_1.syncFolder)(localCodePath, codeSyncOpts);
135
144
  if (result.stopWatching) {
136
145
  return { stopWatching: result.stopWatching };
137
146
  }
@@ -141,7 +150,7 @@ async function createXCodeSandboxClient(options) {
141
150
  return (0, exec_client_1.exec)({ command: 'xcodebuild', ...(opts && { xcodebuild: opts }) }, {
142
151
  apiUrl: options.apiUrl,
143
152
  token: options.token,
144
- log: logFn,
153
+ log,
145
154
  });
146
155
  },
147
156
  };
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox-client.js","sourceRoot":"","sources":["src/sandbox-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sandbox-client.js","sourceRoot":"","sources":["src/sandbox-client.ts"],"names":[],"mappings":";;AA6IA,4DAuIC;;AApRD,oDAAoB;AACpB,wDAAwB;AACxB,kDAAqF;AACrF,kDAAuD;AACvD,gEAAsD;AACtD,4DAA4B;AA8G5B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACI,KAAK,UAAU,wBAAwB,CAC5C,OAAwC;IAExC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC;IAC5C,MAAM,MAAM,GAAG;QACb,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE;YAC5B,IAAI,QAAQ,KAAK,OAAO;gBAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE;YAC3B,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,OAAO;gBAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1F,CAAC;QACD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE;YAC3B,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,OAAO;gBACpE,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE;YAC5B,IAAI,QAAQ,KAAK,MAAM;gBAAE,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,CAAC;QACpE,CAAC;KACF,CAAC;IAEF,MAAM,GAAG,GAAG,CAAC,KAA0C,EAAE,GAAW,EAAE,EAAE;QACtE,QAAQ,KAAK,EAAE,CAAC;YACd,KAAK,OAAO;gBACV,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAClB,MAAM;YACR,KAAK,MAAM;gBACT,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjB,MAAM;YACR,KAAK,MAAM;gBACT,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjB,MAAM;YACR,KAAK,OAAO;gBACV,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAClB,MAAM;YACR;gBACE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjB,MAAM;QACV,CAAC;IACH,CAAC,CAAC;IAEF,iDAAiD;IACjD,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,GAAG,GAGL;YACF,eAAe,EAAE,OAAO,CAAC,SAAS,CAAC,MAAM;YACzC,cAAc,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK;SACzD,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,YAAY,EAAE;YACrD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;aACzC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;SAC1B,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,aAAqB,EAAE,IAAkB;YAClD,+FAA+F;YAC/F,MAAM,YAAY,GAAG,cAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACjD,MAAM,UAAU,GAAG,cAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,gBAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtF,MAAM,QAAQ,GAAG,iBAAiB,UAAU,IAAI,IAAI,EAAE,CAAC;YACvD,MAAM,aAAa,GAAG,IAAI,EAAE,aAAa,IAAI,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC9E,MAAM,YAAY,GAAsB;gBACtC,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,IAAI;gBAC9B,QAAQ,EAAE,MAAM,IAAA,mCAAc,EAAC,aAAa,EAAE;oBAC5C,aAAa;oBACb,UAAU,EAAE,CAAC,YAAoB,EAAE,EAAE;wBACnC,IACE,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC;4BACjC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC;4BAClC,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC;4BACvC,YAAY,CAAC,UAAU,CAAC,gBAAgB,CAAC;4BACzC,YAAY,CAAC,UAAU,CAAC,sBAAsB,CAAC;4BAC/C,YAAY,CAAC,UAAU,CAAC,eAAe,CAAC,EACxC,CAAC;4BACD,OAAO,IAAI,CAAC;wBACd,CAAC;wBACD,IACE,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC;4BACpC,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC;4BAChC,YAAY,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAC1C,CAAC;4BACD,OAAO,IAAI,CAAC;wBACd,CAAC;wBACD,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;4BAC1C,OAAO,IAAI,CAAC;wBACd,CAAC;wBACD,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;4BACpC,OAAO,IAAI,CAAC;wBACd,CAAC;wBACD,wBAAwB;wBACxB,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC;4BACjC,OAAO,IAAI,CAAC;wBACd,CAAC;wBACD,OAAO,KAAK,CAAC;oBACf,CAAC;iBACF,CAAC;gBACF,aAAa;gBACb,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI;gBAC1B,aAAa,EAAE,IAAI,EAAE,aAAa,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;gBACrD,UAAU,EAAE,qBAAqB;gBACjC,GAAG;aACJ,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAc,EAAC,aAAa,EAAE,YAAY,CAAC,CAAC;YACjE,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;gBACxB,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;YAC/C,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,UAAU,CAAC,IAAuB;YAChC,OAAO,IAAA,kBAAI,EACT,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,EAC5D;gBACE,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,GAAG;aACJ,CACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,5 +1,9 @@
1
- import { syncApp as syncFolderImpl } from "./folder-sync.mjs";
1
+ import os from 'os';
2
+ import path from 'path';
3
+ import { syncFolder as syncFolderImpl } from "./folder-sync.mjs";
2
4
  import { exec } from "./exec-client.mjs";
5
+ import { createIgnoreFn } from "./folder-sync-ignore.mjs";
6
+ import crypto from 'crypto';
3
7
  /**
4
8
  * Creates a client for interacting with a sandboxed Xcode build service.
5
9
  *
@@ -46,7 +50,7 @@ export async function createXCodeSandboxClient(options) {
46
50
  console.error('[XCodeSandbox]', ...args);
47
51
  },
48
52
  };
49
- const logFn = (level, msg) => {
53
+ const log = (level, msg) => {
50
54
  switch (level) {
51
55
  case 'debug':
52
56
  logger.debug(msg);
@@ -86,47 +90,51 @@ export async function createXCodeSandboxClient(options) {
86
90
  }
87
91
  return {
88
92
  async sync(localCodePath, opts) {
93
+ // Use folder name and hash of absolute path to scope basisCacheDir uniquely for each sync root
94
+ const resolvedPath = path.resolve(localCodePath);
95
+ const folderName = path.basename(resolvedPath);
96
+ const hash = crypto.createHash('sha1').update(resolvedPath).digest('hex').slice(0, 8);
97
+ const cacheKey = `limsync-cache-${folderName}-${hash}`;
98
+ const basisCacheDir = opts?.basisCacheDir ?? path.join(os.tmpdir(), cacheKey);
89
99
  const codeSyncOpts = {
90
100
  apiUrl: options.apiUrl,
91
101
  token: options.token,
92
- udid: opts?.cacheKey ?? 'xcode-sandbox',
93
- install: false,
94
- filter: (relativePath) => {
95
- if (relativePath.startsWith('build/') ||
96
- relativePath.startsWith('.build/') ||
97
- relativePath.startsWith('DerivedData/') ||
98
- relativePath.startsWith('Index.noindex/') ||
99
- relativePath.startsWith('ModuleCache.noindex/') ||
100
- relativePath.startsWith('.index-build/')) {
102
+ udid: cacheKey,
103
+ install: opts?.install ?? true,
104
+ ignoreFn: await createIgnoreFn(localCodePath, {
105
+ basisCacheDir,
106
+ additional: (relativePath) => {
107
+ if (relativePath.startsWith('build/') ||
108
+ relativePath.startsWith('.build/') ||
109
+ relativePath.startsWith('DerivedData/') ||
110
+ relativePath.startsWith('Index.noindex/') ||
111
+ relativePath.startsWith('ModuleCache.noindex/') ||
112
+ relativePath.startsWith('.index-build/')) {
113
+ return true;
114
+ }
115
+ if (relativePath.startsWith('.swiftpm/') ||
116
+ relativePath.startsWith('Pods/') ||
117
+ relativePath.startsWith('Carthage/Build/')) {
118
+ return true;
119
+ }
120
+ if (relativePath.includes('/xcuserdata/')) {
121
+ return true;
122
+ }
123
+ if (relativePath.includes('.dSYM/')) {
124
+ return true;
125
+ }
126
+ // User-provided ignores
127
+ if (opts?.ignore?.(relativePath)) {
128
+ return true;
129
+ }
101
130
  return false;
102
- }
103
- if (relativePath.startsWith('.swiftpm/') ||
104
- relativePath.startsWith('Pods/') ||
105
- relativePath.startsWith('Carthage/Build/')) {
106
- return false;
107
- }
108
- if (relativePath.startsWith('.git/') ||
109
- relativePath.startsWith('.limsync-cache/') ||
110
- relativePath === '.DS_Store' ||
111
- relativePath.endsWith('/.DS_Store')) {
112
- return false;
113
- }
114
- if (relativePath.includes('/xcuserdata/')) {
115
- return false;
116
- }
117
- if (relativePath.includes('.dSYM/')) {
118
- return false;
119
- }
120
- // User-provided filter
121
- if (opts?.filter && !opts.filter(relativePath)) {
122
- return false;
123
- }
124
- return true;
125
- },
126
- ...(opts?.basisCacheDir ? { basisCacheDir: opts.basisCacheDir } : {}),
127
- ...(opts?.maxPatchBytes !== undefined ? { maxPatchBytes: opts.maxPatchBytes } : {}),
128
- ...(opts?.watch !== undefined ? { watch: opts.watch } : {}),
129
- log: opts?.log ?? logFn,
131
+ },
132
+ }),
133
+ basisCacheDir,
134
+ watch: opts?.watch ?? true,
135
+ maxPatchBytes: opts?.maxPatchBytes ?? 4 * 1024 * 1024,
136
+ launchMode: 'ForegroundIfRunning',
137
+ log,
130
138
  };
131
139
  const result = await syncFolderImpl(localCodePath, codeSyncOpts);
132
140
  if (result.stopWatching) {
@@ -138,7 +146,7 @@ export async function createXCodeSandboxClient(options) {
138
146
  return exec({ command: 'xcodebuild', ...(opts && { xcodebuild: opts }) }, {
139
147
  apiUrl: options.apiUrl,
140
148
  token: options.token,
141
- log: logFn,
149
+ log,
142
150
  });
143
151
  },
144
152
  };
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox-client.mjs","sourceRoot":"","sources":["src/sandbox-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sandbox-client.mjs","sourceRoot":"","sources":["src/sandbox-client.ts"],"names":[],"mappings":"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"}
@@ -77,6 +77,7 @@ export class ReadableStream {
77
77
  * @example
78
78
  * // Stream-based (like Node.js spawn)
79
79
  * const proc = exec({ command: 'xcodebuild' }, options);
80
+ * proc.command.on('data', (chunk) => console.log('[command]', chunk));
80
81
  * proc.stdout.on('data', (chunk) => process.stdout.write(chunk));
81
82
  * proc.stderr.on('data', (chunk) => process.stderr.write(chunk));
82
83
  * proc.on('exit', (code) => console.log(`Exited with code ${code}`));
@@ -85,6 +86,9 @@ export class ReadableStream {
85
86
  * const { exitCode, status } = await proc;
86
87
  */
87
88
  export class ExecChildProcess implements PromiseLike<ExecResult> {
89
+ /** Command stream - emits the executed command and then closes */
90
+ readonly command = new ReadableStream();
91
+
88
92
  /** Stdout stream - emits 'data' and 'close' events */
89
93
  readonly stdout = new ReadableStream();
90
94
 
@@ -166,7 +170,6 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
166
170
  const { apiUrl, token } = this.options;
167
171
 
168
172
  // 1. Trigger the build via POST /exec
169
- log('debug', `POST ${apiUrl}/exec`);
170
173
  let execRes: Response;
171
174
  try {
172
175
  execRes = await fetch(`${apiUrl}/exec`, {
@@ -180,6 +183,7 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
180
183
  });
181
184
  } catch (err) {
182
185
  if (this.killed) {
186
+ this.command.emit('close');
183
187
  this.stdout.emit('close');
184
188
  this.stderr.emit('close');
185
189
  for (const listener of this.exitListeners) {
@@ -197,11 +201,10 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
197
201
 
198
202
  const execData = (await execRes.json()) as { execId: string };
199
203
  this.execId = execData.execId;
200
- log('info', `Build started: ${this.execId}`);
204
+ log('debug', `Build started: ${this.execId}`);
201
205
 
202
206
  // 2. Stream logs via SSE and wait for exit code
203
207
  const eventsUrl = `${apiUrl}/exec/${this.execId}/events`;
204
- log('debug', `GET ${eventsUrl} (SSE)`);
205
208
 
206
209
  const timeoutMs = 3600 * 1000; // 1 hour max
207
210
  let exitCode: number;
@@ -215,7 +218,7 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
215
218
  ]);
216
219
  } catch {
217
220
  if (this.killed) {
218
- log('info', 'Build killed');
221
+ log('debug', 'Build killed');
219
222
  exitCode = -1;
220
223
  } else {
221
224
  log('warn', 'SSE completion timeout');
@@ -230,6 +233,7 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
230
233
  }
231
234
 
232
235
  // Emit close events on streams
236
+ this.command.emit('close');
233
237
  this.stdout.emit('close');
234
238
  this.stderr.emit('close');
235
239
 
@@ -250,12 +254,12 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
250
254
  status,
251
255
  };
252
256
 
253
- this.log('info', `Build finished: ${result.status} (exit ${result.exitCode})`);
257
+ this.log('debug', `Build finished: ${result.status} (exit ${result.exitCode})`);
254
258
  return result;
255
259
  }
256
260
 
257
261
  /**
258
- * Opens an SSE connection and routes events to stdout/stderr streams.
262
+ * Opens an SSE connection and routes streamed events to the exposed command/stdout/stderr streams.
259
263
  * Resolves with the exit code when an 'exitCode' event arrives.
260
264
  * Rejects when the abort signal fires (kill or cleanup).
261
265
  */
@@ -273,7 +277,9 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
273
277
  onMessage: (message: EventSourceMessage) => {
274
278
  const data = typeof message.data === 'string' ? message.data : String(message.data ?? '');
275
279
  const eventType = message.event;
276
- if (eventType === 'stdout') {
280
+ if (eventType === 'command') {
281
+ this.command.emit('data', data);
282
+ } else if (eventType === 'stdout') {
277
283
  this.stdout.emit('data', data);
278
284
  } else if (eventType === 'stderr') {
279
285
  this.stderr.emit('data', data);
@@ -316,6 +322,7 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
316
322
  * const proc = exec({ command: 'xcodebuild' }, { apiUrl: '...', token: '...' });
317
323
  *
318
324
  * // Stream output
325
+ * proc.command.on('data', (chunk) => console.log('[command]', chunk));
319
326
  * proc.stdout.on('data', (chunk) => console.log('[stdout]', chunk));
320
327
  * proc.stderr.on('data', (chunk) => console.error('[stderr]', chunk));
321
328
  *
@@ -0,0 +1,65 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import ignorePkg from 'ignore';
4
+
5
+ export type IgnoreFn = (relativePath: string) => boolean;
6
+
7
+ export type IgnoreFnOptions = {
8
+ additional?: IgnoreFn;
9
+ basisCacheDir: string;
10
+ };
11
+
12
+ function normalizeRelativePath(relativePath: string): string {
13
+ return relativePath
14
+ .split(path.sep)
15
+ .join('/')
16
+ .replace(/^\.\/+/, '')
17
+ .replace(/\/+/g, '/');
18
+ }
19
+
20
+ export async function createIgnoreFn(rootDir: string, options: IgnoreFnOptions): Promise<IgnoreFn> {
21
+ const rootResolved = path.resolve(rootDir);
22
+ const ig = ignorePkg();
23
+ const gitignorePath = path.join(rootResolved, '.gitignore');
24
+ try {
25
+ const content = await fs.promises.readFile(gitignorePath, 'utf-8');
26
+ ig.add(content);
27
+ } catch {
28
+ // No .gitignore file, return empty ignore instance
29
+ }
30
+ const basisCacheRelative = normalizeRelativePath(
31
+ path.relative(rootResolved, options.basisCacheDir),
32
+ ).replace(/\/+$/, '');
33
+ const shouldIgnoreBasisCache =
34
+ basisCacheRelative &&
35
+ basisCacheRelative !== '.' &&
36
+ basisCacheRelative !== '..' &&
37
+ !basisCacheRelative.startsWith('../');
38
+
39
+ return (relativePath: string) => {
40
+ const normalized = normalizeRelativePath(relativePath);
41
+ if (!normalized) return false;
42
+ const withoutTrailingSlash = normalized.replace(/\/+$/, '');
43
+
44
+ if (
45
+ withoutTrailingSlash === '.git' ||
46
+ withoutTrailingSlash.startsWith('.git/') ||
47
+ withoutTrailingSlash.endsWith('/.git') ||
48
+ withoutTrailingSlash.includes('/.git/') ||
49
+ withoutTrailingSlash === '.DS_Store' ||
50
+ withoutTrailingSlash.endsWith('/.DS_Store')
51
+ ) {
52
+ return true;
53
+ }
54
+ if (
55
+ shouldIgnoreBasisCache &&
56
+ (withoutTrailingSlash === basisCacheRelative ||
57
+ withoutTrailingSlash.startsWith(`${basisCacheRelative}/`))
58
+ ) {
59
+ return true;
60
+ }
61
+ if (ig.ignores(normalized)) return true;
62
+ if (options.additional?.(normalized)) return true;
63
+ return false;
64
+ };
65
+ }
@@ -1,9 +1,11 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
+ import { IgnoreFn } from './folder-sync-ignore';
3
4
 
4
5
  export type FolderSyncWatcherOptions = {
5
6
  rootPath: string;
6
7
  log?: (level: 'debug' | 'info' | 'warn' | 'error', msg: string) => void;
8
+ ignoreFn: IgnoreFn;
7
9
  onChange: (reason: string) => void;
8
10
  };
9
11
 
@@ -11,27 +13,6 @@ type WatcherHandle = { close: () => void };
11
13
 
12
14
  const noopLogger = (_level: 'debug' | 'info' | 'warn' | 'error', _msg: string) => {};
13
15
 
14
- async function listDirsRecursive(root: string): Promise<string[]> {
15
- const dirs: string[] = [root];
16
- const queue: string[] = [root];
17
- while (queue.length) {
18
- const dir = queue.pop()!;
19
- let entries: fs.Dirent[];
20
- try {
21
- entries = await fs.promises.readdir(dir, { withFileTypes: true });
22
- } catch {
23
- continue;
24
- }
25
- for (const ent of entries) {
26
- if (!ent.isDirectory()) continue;
27
- const full = path.join(dir, ent.name);
28
- dirs.push(full);
29
- queue.push(full);
30
- }
31
- }
32
- return dirs;
33
- }
34
-
35
16
  /**
36
17
  * Watch a folder tree for changes. Uses recursive watch when supported (macOS),
37
18
  * otherwise falls back to watching each directory. Debounced.
@@ -42,58 +23,22 @@ export async function watchFolderTree(opts: FolderSyncWatcherOptions): Promise<W
42
23
  const log = opts.log ?? noopLogger;
43
24
  const debounceMs = 500;
44
25
  const rootPath = opts.rootPath;
45
-
46
26
  if (!fs.existsSync(rootPath)) {
47
27
  throw new Error(`watchFolderTree root does not exist: ${rootPath}`);
48
28
  }
49
-
50
29
  let timer: NodeJS.Timeout | undefined;
51
30
  const schedule = (reason: string) => {
52
31
  if (timer) clearTimeout(timer);
53
32
  timer = setTimeout(() => opts.onChange(reason), debounceMs);
54
33
  };
55
-
56
- // Preferred: recursive watch
57
- try {
58
- const watcher = fs.watch(rootPath, { recursive: true }, (_eventType, filename) => {
59
- schedule(filename ? `change:${filename.toString()}` : 'change');
60
- });
61
- log('info', `watchFolderTree(recursive): ${rootPath}`);
62
- return { close: () => watcher.close() };
63
- } catch (err) {
64
- log(
65
- 'warn',
66
- `watchFolderTree: recursive unsupported, using per-directory watches: ${(err as Error).message}`,
67
- );
68
- }
69
-
70
- // Fallback: watch every directory. Also re-scan on any event to pick up newly-created dirs.
71
- const watchers = new Map<string, fs.FSWatcher>();
72
-
73
- const ensureWatched = async () => {
74
- const dirs = await listDirsRecursive(rootPath);
75
- for (const d of dirs) {
76
- if (watchers.has(d)) continue;
77
- try {
78
- const w = fs.watch(d, (_eventType, filename) => {
79
- schedule(filename ? `change:${filename.toString()}` : 'change');
80
- void ensureWatched();
81
- });
82
- watchers.set(d, w);
83
- } catch {
84
- // ignore dirs we can't watch
85
- }
34
+ const watcher = fs.watch(rootPath, { recursive: true }, (_eventType, filename) => {
35
+ if (!filename) return;
36
+ const relativePath = filename.split(path.sep).join('/');
37
+ if (opts.ignoreFn(relativePath)) {
38
+ return;
86
39
  }
87
- };
88
-
89
- await ensureWatched();
90
- log('info', `watchFolderTree(per-dir): ${rootPath} dirs=${watchers.size}`);
91
-
92
- return {
93
- close: () => {
94
- if (timer) clearTimeout(timer);
95
- for (const w of watchers.values()) w.close();
96
- watchers.clear();
97
- },
98
- };
40
+ schedule(relativePath ? `change:${relativePath}` : 'change');
41
+ });
42
+ log('debug', `watchFolderTree(recursive): ${rootPath}`);
43
+ return { close: () => watcher.close() };
99
44
  }