@limrun/api 0.19.3 → 0.20.0

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 (68) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/client.d.mts +1 -0
  3. package/client.d.mts.map +1 -1
  4. package/client.d.ts +1 -0
  5. package/client.d.ts.map +1 -1
  6. package/client.js +10 -2
  7. package/client.js.map +1 -1
  8. package/client.mjs +10 -2
  9. package/client.mjs.map +1 -1
  10. package/exec-client.d.mts +101 -0
  11. package/exec-client.d.mts.map +1 -0
  12. package/exec-client.d.ts +101 -0
  13. package/exec-client.d.ts.map +1 -0
  14. package/exec-client.js +265 -0
  15. package/exec-client.js.map +1 -0
  16. package/exec-client.mjs +259 -0
  17. package/exec-client.mjs.map +1 -0
  18. package/folder-sync.d.mts +16 -2
  19. package/folder-sync.d.mts.map +1 -1
  20. package/folder-sync.d.ts +16 -2
  21. package/folder-sync.d.ts.map +1 -1
  22. package/folder-sync.js +43 -14
  23. package/folder-sync.js.map +1 -1
  24. package/folder-sync.mjs +43 -13
  25. package/folder-sync.mjs.map +1 -1
  26. package/index.d.mts +2 -0
  27. package/index.d.mts.map +1 -1
  28. package/index.d.ts +2 -0
  29. package/index.d.ts.map +1 -1
  30. package/index.js +5 -1
  31. package/index.js.map +1 -1
  32. package/index.mjs +2 -0
  33. package/index.mjs.map +1 -1
  34. package/internal/parse.d.mts.map +1 -1
  35. package/internal/parse.d.ts.map +1 -1
  36. package/internal/parse.js +5 -0
  37. package/internal/parse.js.map +1 -1
  38. package/internal/parse.mjs +5 -0
  39. package/internal/parse.mjs.map +1 -1
  40. package/ios-client.d.mts +10 -3
  41. package/ios-client.d.mts.map +1 -1
  42. package/ios-client.d.ts +10 -3
  43. package/ios-client.d.ts.map +1 -1
  44. package/ios-client.js +19 -4
  45. package/ios-client.js.map +1 -1
  46. package/ios-client.mjs +18 -3
  47. package/ios-client.mjs.map +1 -1
  48. package/package.json +23 -1
  49. package/sandbox-client.d.mts +124 -0
  50. package/sandbox-client.d.mts.map +1 -0
  51. package/sandbox-client.d.ts +124 -0
  52. package/sandbox-client.d.ts.map +1 -0
  53. package/sandbox-client.js +149 -0
  54. package/sandbox-client.js.map +1 -0
  55. package/sandbox-client.mjs +146 -0
  56. package/sandbox-client.mjs.map +1 -0
  57. package/src/client.ts +10 -2
  58. package/src/exec-client.ts +333 -0
  59. package/src/folder-sync.ts +66 -18
  60. package/src/index.ts +16 -0
  61. package/src/internal/parse.ts +6 -0
  62. package/src/ios-client.ts +35 -5
  63. package/src/sandbox-client.ts +267 -0
  64. package/src/version.ts +1 -1
  65. package/version.d.mts +1 -1
  66. package/version.d.ts +1 -1
  67. package/version.js +1 -1
  68. package/version.mjs +1 -1
package/exec-client.js ADDED
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ /**
3
+ * Client for executing commands on limbuild server with streaming output.
4
+ *
5
+ * The interface is designed to be similar to Node.js's child_process.spawn()
6
+ * for familiarity and ease of extension.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ExecChildProcess = exports.ReadableStream = void 0;
10
+ exports.exec = exec;
11
+ const eventsource_client_1 = require("eventsource-client");
12
+ /**
13
+ * A Readable-like stream interface, similar to Node.js stream.Readable.
14
+ * Emits 'data' for each chunk and 'close' when the stream ends.
15
+ */
16
+ class ReadableStream {
17
+ constructor() {
18
+ this.dataListeners = [];
19
+ this.closeListeners = [];
20
+ this.closed = false;
21
+ }
22
+ on(event, listener) {
23
+ if (event === 'data') {
24
+ this.dataListeners.push(listener);
25
+ }
26
+ else if (event === 'close') {
27
+ this.closeListeners.push(listener);
28
+ }
29
+ return this;
30
+ }
31
+ emit(event, arg) {
32
+ if (event === 'data' && typeof arg === 'string') {
33
+ for (const l of this.dataListeners)
34
+ l(arg);
35
+ }
36
+ else if (event === 'close' && !this.closed) {
37
+ this.closed = true;
38
+ for (const l of this.closeListeners)
39
+ l();
40
+ }
41
+ }
42
+ }
43
+ exports.ReadableStream = ReadableStream;
44
+ /**
45
+ * A ChildProcess-like object similar to Node.js's ChildProcess.
46
+ *
47
+ * Implements PromiseLike so it can be awaited directly.
48
+ *
49
+ * @example
50
+ * // Stream-based (like Node.js spawn)
51
+ * const proc = exec({ command: 'xcodebuild' }, options);
52
+ * proc.stdout.on('data', (chunk) => process.stdout.write(chunk));
53
+ * proc.stderr.on('data', (chunk) => process.stderr.write(chunk));
54
+ * proc.on('exit', (code) => console.log(`Exited with code ${code}`));
55
+ *
56
+ * // Promise-based (can be awaited)
57
+ * const { exitCode, status } = await proc;
58
+ */
59
+ class ExecChildProcess {
60
+ constructor(request, options) {
61
+ /** Stdout stream - emits 'data' and 'close' events */
62
+ this.stdout = new ReadableStream();
63
+ /** Stderr stream - emits 'data' and 'close' events */
64
+ this.stderr = new ReadableStream();
65
+ this.exitListeners = [];
66
+ this.abortController = null;
67
+ this.sseConnection = null;
68
+ this.killed = false;
69
+ this.options = options;
70
+ this.log = options.log ?? (() => { });
71
+ this.resultPromise = this.run(request);
72
+ }
73
+ /** Implement PromiseLike so this object can be awaited */
74
+ then(onfulfilled, onrejected) {
75
+ return this.resultPromise.then(onfulfilled, onrejected);
76
+ }
77
+ /** Catch errors */
78
+ catch(onrejected) {
79
+ return this.resultPromise.catch(onrejected);
80
+ }
81
+ /** Finally handler */
82
+ finally(onfinally) {
83
+ return this.resultPromise.finally(onfinally);
84
+ }
85
+ /** Listen for process events */
86
+ on(event, listener) {
87
+ if (event === 'exit') {
88
+ this.exitListeners.push(listener);
89
+ }
90
+ return this;
91
+ }
92
+ /** Send a signal to terminate the process */
93
+ async kill() {
94
+ this.killed = true;
95
+ if (this.abortController) {
96
+ this.abortController.abort();
97
+ }
98
+ if (this.sseConnection) {
99
+ this.sseConnection.close();
100
+ this.sseConnection = null;
101
+ }
102
+ if (!this.execId) {
103
+ this.log('warn', 'Failed to cancel build: execId is not set');
104
+ return;
105
+ }
106
+ try {
107
+ await fetch(`${this.options.apiUrl}/exec/${this.execId}/cancel`, {
108
+ method: 'POST',
109
+ headers: {
110
+ Authorization: `Bearer ${this.options.token}`,
111
+ },
112
+ });
113
+ this.log('info', 'Build cancelled');
114
+ }
115
+ catch (err) {
116
+ this.log('warn', `Failed to cancel build: ${err}`);
117
+ }
118
+ }
119
+ async run(request) {
120
+ const { log } = this;
121
+ const { apiUrl, token } = this.options;
122
+ // 1. Trigger the build via POST /exec
123
+ log('debug', `POST ${apiUrl}/exec`);
124
+ const execRes = await fetch(`${apiUrl}/exec`, {
125
+ method: 'POST',
126
+ headers: {
127
+ 'Content-Type': 'application/json',
128
+ Authorization: `Bearer ${token}`,
129
+ },
130
+ body: JSON.stringify(request),
131
+ });
132
+ if (!execRes.ok) {
133
+ const text = await execRes.text();
134
+ throw new Error(`exec failed: ${execRes.status} ${text}`);
135
+ }
136
+ const execData = (await execRes.json());
137
+ this.execId = execData.execId;
138
+ log('info', `Build started: ${this.execId}`);
139
+ // 2. Connect to SSE for log streaming and completion detection
140
+ this.abortController = new AbortController();
141
+ const eventsUrl = `${apiUrl}/exec/${this.execId}/events`;
142
+ log('debug', `GET ${eventsUrl} (SSE)`);
143
+ // Promise that resolves when build completes (via exitCode event)
144
+ let sseCompletionResolve = null;
145
+ const sseCompletionPromise = new Promise((resolve) => {
146
+ sseCompletionResolve = resolve;
147
+ });
148
+ const ssePromise = this.connectSSE(eventsUrl, sseCompletionResolve);
149
+ // Wait for SSE to signal completion (with timeout fallback)
150
+ const timeoutMs = 3600 * 1000; // 1 hour max
151
+ let exitCode;
152
+ try {
153
+ exitCode = await Promise.race([
154
+ sseCompletionPromise,
155
+ new Promise((_, reject) => setTimeout(() => reject(new Error('SSE timeout')), timeoutMs)),
156
+ ]);
157
+ }
158
+ catch {
159
+ log('warn', 'SSE completion timeout');
160
+ exitCode = 1;
161
+ }
162
+ // Cleanup SSE connection
163
+ if (this.abortController) {
164
+ this.abortController.abort();
165
+ }
166
+ await ssePromise.catch(() => { });
167
+ // Emit close events on streams
168
+ this.stdout.emit('close');
169
+ this.stderr.emit('close');
170
+ // Emit exit event
171
+ for (const listener of this.exitListeners) {
172
+ listener(exitCode);
173
+ }
174
+ // Determine status from exit code
175
+ const status = exitCode === 0 ? 'SUCCEEDED'
176
+ : exitCode === -1 ? 'CANCELLED'
177
+ : 'FAILED';
178
+ const result = {
179
+ exitCode,
180
+ execId: this.execId,
181
+ status,
182
+ };
183
+ this.log('info', `Build finished: ${result.status} (exit ${result.exitCode})`);
184
+ return result;
185
+ }
186
+ async connectSSE(eventsUrl, onComplete) {
187
+ return new Promise((resolve) => {
188
+ const authHeader = `Bearer ${this.options.token}`;
189
+ let resolved = false;
190
+ const resolveOnce = () => {
191
+ if (resolved)
192
+ return;
193
+ resolved = true;
194
+ this.sseConnection?.close();
195
+ this.sseConnection = null;
196
+ resolve();
197
+ };
198
+ try {
199
+ const eventSource = (0, eventsource_client_1.createEventSource)({
200
+ url: eventsUrl,
201
+ headers: { Authorization: authHeader },
202
+ onMessage: (message) => {
203
+ const data = typeof message.data === 'string' ? message.data : String(message.data ?? '');
204
+ const eventType = message.event;
205
+ if (eventType === 'stdout') {
206
+ this.stdout.emit('data', data);
207
+ return;
208
+ }
209
+ if (eventType === 'stderr') {
210
+ this.stderr.emit('data', data);
211
+ return;
212
+ }
213
+ if (eventType === 'exitCode') {
214
+ const exitCode = parseInt(data, 10);
215
+ if (Number.isNaN(exitCode)) {
216
+ this.log('warn', `SSE exitCode event has invalid data: ${data}`);
217
+ return;
218
+ }
219
+ this.log('debug', `Build completed via SSE: exitCode=${exitCode}`);
220
+ onComplete?.(exitCode);
221
+ resolveOnce();
222
+ }
223
+ },
224
+ onDisconnect: () => {
225
+ if (!this.killed) {
226
+ this.log('warn', 'SSE disconnected');
227
+ }
228
+ },
229
+ });
230
+ this.sseConnection = eventSource;
231
+ const abortSignal = this.abortController?.signal;
232
+ if (abortSignal) {
233
+ abortSignal.addEventListener('abort', () => {
234
+ resolveOnce();
235
+ }, { once: true });
236
+ }
237
+ }
238
+ catch (err) {
239
+ if (!this.killed) {
240
+ this.log('warn', `SSE setup failed: ${err}`);
241
+ }
242
+ resolveOnce();
243
+ }
244
+ });
245
+ }
246
+ }
247
+ exports.ExecChildProcess = ExecChildProcess;
248
+ /**
249
+ * Execute a command on the limbuild server.
250
+ * Returns a ChildProcess-like object with stdout/stderr streams.
251
+ *
252
+ * @example
253
+ * const proc = exec({ command: 'xcodebuild' }, { apiUrl: '...', token: '...' });
254
+ *
255
+ * // Stream output
256
+ * proc.stdout.on('data', (chunk) => console.log('[stdout]', chunk));
257
+ * proc.stderr.on('data', (chunk) => console.error('[stderr]', chunk));
258
+ *
259
+ * // Wait for completion
260
+ * const { exitCode, status } = await proc;
261
+ */
262
+ function exec(request, options) {
263
+ return new ExecChildProcess(request, options);
264
+ }
265
+ //# sourceMappingURL=exec-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec-client.js","sourceRoot":"","sources":["src/exec-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Client for executing commands on limbuild server with streaming output.
3
+ *
4
+ * The interface is designed to be similar to Node.js's child_process.spawn()
5
+ * for familiarity and ease of extension.
6
+ */
7
+ import { createEventSource } from 'eventsource-client';
8
+ /**
9
+ * A Readable-like stream interface, similar to Node.js stream.Readable.
10
+ * Emits 'data' for each chunk and 'close' when the stream ends.
11
+ */
12
+ export class ReadableStream {
13
+ constructor() {
14
+ this.dataListeners = [];
15
+ this.closeListeners = [];
16
+ this.closed = false;
17
+ }
18
+ on(event, listener) {
19
+ if (event === 'data') {
20
+ this.dataListeners.push(listener);
21
+ }
22
+ else if (event === 'close') {
23
+ this.closeListeners.push(listener);
24
+ }
25
+ return this;
26
+ }
27
+ emit(event, arg) {
28
+ if (event === 'data' && typeof arg === 'string') {
29
+ for (const l of this.dataListeners)
30
+ l(arg);
31
+ }
32
+ else if (event === 'close' && !this.closed) {
33
+ this.closed = true;
34
+ for (const l of this.closeListeners)
35
+ l();
36
+ }
37
+ }
38
+ }
39
+ /**
40
+ * A ChildProcess-like object similar to Node.js's ChildProcess.
41
+ *
42
+ * Implements PromiseLike so it can be awaited directly.
43
+ *
44
+ * @example
45
+ * // Stream-based (like Node.js spawn)
46
+ * const proc = exec({ command: 'xcodebuild' }, options);
47
+ * proc.stdout.on('data', (chunk) => process.stdout.write(chunk));
48
+ * proc.stderr.on('data', (chunk) => process.stderr.write(chunk));
49
+ * proc.on('exit', (code) => console.log(`Exited with code ${code}`));
50
+ *
51
+ * // Promise-based (can be awaited)
52
+ * const { exitCode, status } = await proc;
53
+ */
54
+ export class ExecChildProcess {
55
+ constructor(request, options) {
56
+ /** Stdout stream - emits 'data' and 'close' events */
57
+ this.stdout = new ReadableStream();
58
+ /** Stderr stream - emits 'data' and 'close' events */
59
+ this.stderr = new ReadableStream();
60
+ this.exitListeners = [];
61
+ this.abortController = null;
62
+ this.sseConnection = null;
63
+ this.killed = false;
64
+ this.options = options;
65
+ this.log = options.log ?? (() => { });
66
+ this.resultPromise = this.run(request);
67
+ }
68
+ /** Implement PromiseLike so this object can be awaited */
69
+ then(onfulfilled, onrejected) {
70
+ return this.resultPromise.then(onfulfilled, onrejected);
71
+ }
72
+ /** Catch errors */
73
+ catch(onrejected) {
74
+ return this.resultPromise.catch(onrejected);
75
+ }
76
+ /** Finally handler */
77
+ finally(onfinally) {
78
+ return this.resultPromise.finally(onfinally);
79
+ }
80
+ /** Listen for process events */
81
+ on(event, listener) {
82
+ if (event === 'exit') {
83
+ this.exitListeners.push(listener);
84
+ }
85
+ return this;
86
+ }
87
+ /** Send a signal to terminate the process */
88
+ async kill() {
89
+ this.killed = true;
90
+ if (this.abortController) {
91
+ this.abortController.abort();
92
+ }
93
+ if (this.sseConnection) {
94
+ this.sseConnection.close();
95
+ this.sseConnection = null;
96
+ }
97
+ if (!this.execId) {
98
+ this.log('warn', 'Failed to cancel build: execId is not set');
99
+ return;
100
+ }
101
+ try {
102
+ await fetch(`${this.options.apiUrl}/exec/${this.execId}/cancel`, {
103
+ method: 'POST',
104
+ headers: {
105
+ Authorization: `Bearer ${this.options.token}`,
106
+ },
107
+ });
108
+ this.log('info', 'Build cancelled');
109
+ }
110
+ catch (err) {
111
+ this.log('warn', `Failed to cancel build: ${err}`);
112
+ }
113
+ }
114
+ async run(request) {
115
+ const { log } = this;
116
+ const { apiUrl, token } = this.options;
117
+ // 1. Trigger the build via POST /exec
118
+ log('debug', `POST ${apiUrl}/exec`);
119
+ const execRes = await fetch(`${apiUrl}/exec`, {
120
+ method: 'POST',
121
+ headers: {
122
+ 'Content-Type': 'application/json',
123
+ Authorization: `Bearer ${token}`,
124
+ },
125
+ body: JSON.stringify(request),
126
+ });
127
+ if (!execRes.ok) {
128
+ const text = await execRes.text();
129
+ throw new Error(`exec failed: ${execRes.status} ${text}`);
130
+ }
131
+ const execData = (await execRes.json());
132
+ this.execId = execData.execId;
133
+ log('info', `Build started: ${this.execId}`);
134
+ // 2. Connect to SSE for log streaming and completion detection
135
+ this.abortController = new AbortController();
136
+ const eventsUrl = `${apiUrl}/exec/${this.execId}/events`;
137
+ log('debug', `GET ${eventsUrl} (SSE)`);
138
+ // Promise that resolves when build completes (via exitCode event)
139
+ let sseCompletionResolve = null;
140
+ const sseCompletionPromise = new Promise((resolve) => {
141
+ sseCompletionResolve = resolve;
142
+ });
143
+ const ssePromise = this.connectSSE(eventsUrl, sseCompletionResolve);
144
+ // Wait for SSE to signal completion (with timeout fallback)
145
+ const timeoutMs = 3600 * 1000; // 1 hour max
146
+ let exitCode;
147
+ try {
148
+ exitCode = await Promise.race([
149
+ sseCompletionPromise,
150
+ new Promise((_, reject) => setTimeout(() => reject(new Error('SSE timeout')), timeoutMs)),
151
+ ]);
152
+ }
153
+ catch {
154
+ log('warn', 'SSE completion timeout');
155
+ exitCode = 1;
156
+ }
157
+ // Cleanup SSE connection
158
+ if (this.abortController) {
159
+ this.abortController.abort();
160
+ }
161
+ await ssePromise.catch(() => { });
162
+ // Emit close events on streams
163
+ this.stdout.emit('close');
164
+ this.stderr.emit('close');
165
+ // Emit exit event
166
+ for (const listener of this.exitListeners) {
167
+ listener(exitCode);
168
+ }
169
+ // Determine status from exit code
170
+ const status = exitCode === 0 ? 'SUCCEEDED'
171
+ : exitCode === -1 ? 'CANCELLED'
172
+ : 'FAILED';
173
+ const result = {
174
+ exitCode,
175
+ execId: this.execId,
176
+ status,
177
+ };
178
+ this.log('info', `Build finished: ${result.status} (exit ${result.exitCode})`);
179
+ return result;
180
+ }
181
+ async connectSSE(eventsUrl, onComplete) {
182
+ return new Promise((resolve) => {
183
+ const authHeader = `Bearer ${this.options.token}`;
184
+ let resolved = false;
185
+ const resolveOnce = () => {
186
+ if (resolved)
187
+ return;
188
+ resolved = true;
189
+ this.sseConnection?.close();
190
+ this.sseConnection = null;
191
+ resolve();
192
+ };
193
+ try {
194
+ const eventSource = createEventSource({
195
+ url: eventsUrl,
196
+ headers: { Authorization: authHeader },
197
+ onMessage: (message) => {
198
+ const data = typeof message.data === 'string' ? message.data : String(message.data ?? '');
199
+ const eventType = message.event;
200
+ if (eventType === 'stdout') {
201
+ this.stdout.emit('data', data);
202
+ return;
203
+ }
204
+ if (eventType === 'stderr') {
205
+ this.stderr.emit('data', data);
206
+ return;
207
+ }
208
+ if (eventType === 'exitCode') {
209
+ const exitCode = parseInt(data, 10);
210
+ if (Number.isNaN(exitCode)) {
211
+ this.log('warn', `SSE exitCode event has invalid data: ${data}`);
212
+ return;
213
+ }
214
+ this.log('debug', `Build completed via SSE: exitCode=${exitCode}`);
215
+ onComplete?.(exitCode);
216
+ resolveOnce();
217
+ }
218
+ },
219
+ onDisconnect: () => {
220
+ if (!this.killed) {
221
+ this.log('warn', 'SSE disconnected');
222
+ }
223
+ },
224
+ });
225
+ this.sseConnection = eventSource;
226
+ const abortSignal = this.abortController?.signal;
227
+ if (abortSignal) {
228
+ abortSignal.addEventListener('abort', () => {
229
+ resolveOnce();
230
+ }, { once: true });
231
+ }
232
+ }
233
+ catch (err) {
234
+ if (!this.killed) {
235
+ this.log('warn', `SSE setup failed: ${err}`);
236
+ }
237
+ resolveOnce();
238
+ }
239
+ });
240
+ }
241
+ }
242
+ /**
243
+ * Execute a command on the limbuild server.
244
+ * Returns a ChildProcess-like object with stdout/stderr streams.
245
+ *
246
+ * @example
247
+ * const proc = exec({ command: 'xcodebuild' }, { apiUrl: '...', token: '...' });
248
+ *
249
+ * // Stream output
250
+ * proc.stdout.on('data', (chunk) => console.log('[stdout]', chunk));
251
+ * proc.stderr.on('data', (chunk) => console.error('[stderr]', chunk));
252
+ *
253
+ * // Wait for completion
254
+ * const { exitCode, status } = await proc;
255
+ */
256
+ export function exec(request, options) {
257
+ return new ExecChildProcess(request, options);
258
+ }
259
+ //# sourceMappingURL=exec-client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec-client.mjs","sourceRoot":"","sources":["src/exec-client.ts"],"names":[],"mappings":"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"}
package/folder-sync.d.mts CHANGED
@@ -7,7 +7,7 @@ export type FolderSyncOptions = {
7
7
  * Used to store the last-synced “basis” copies of files (and related sync metadata) so we can compute xdelta patches
8
8
  * on subsequent syncs without re-downloading server state.
9
9
  *
10
- * Can be absolute or relative to process.cwd(). Defaults to `.lim-metadata-cache/`.
10
+ * Can be absolute or relative to process.cwd(). Defaults to `.limsync-cache/`.
11
11
  */
12
12
  basisCacheDir?: string;
13
13
  install?: boolean;
@@ -18,6 +18,21 @@ export type FolderSyncOptions = {
18
18
  maxPatchBytes?: number;
19
19
  /** Controls logging verbosity */
20
20
  log?: (level: 'debug' | 'info' | 'warn' | 'error', msg: string) => void;
21
+ /**
22
+ * Optional filter function to include/exclude files and directories.
23
+ * Called with the relative path from localFolderPath (using forward slashes).
24
+ * For directories, the path ends with '/'.
25
+ * Return true to include, false to exclude.
26
+ *
27
+ * @example
28
+ * // Exclude build folder
29
+ * filter: (path) => !path.startsWith('build/')
30
+ *
31
+ * @example
32
+ * // Only include source files
33
+ * filter: (path) => path.startsWith('src/') || path.endsWith('.json')
34
+ */
35
+ filter?: (relativePath: string) => boolean;
21
36
  };
22
37
  export type SyncFolderResult = {
23
38
  installedAppPath?: string;
@@ -27,5 +42,4 @@ export type SyncFolderResult = {
27
42
  };
28
43
  export type SyncAppResult = SyncFolderResult;
29
44
  export declare function syncApp(localFolderPath: string, opts: FolderSyncOptions): Promise<SyncFolderResult>;
30
- export declare function syncFolder(localFolderPath: string, opts: FolderSyncOptions): Promise<SyncFolderResult>;
31
45
  //# sourceMappingURL=folder-sync.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"folder-sync.d.mts","sourceRoot":"","sources":["src/folder-sync.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,qBAAqB,GAAG,mBAAmB,GAAG,eAAe,CAAC;IAC3E,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AA4QF,MAAM,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAE7C,wBAAsB,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2CzG;AAGD,wBAAsB,UAAU,CAC9B,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CAE3B"}
1
+ {"version":3,"file":"folder-sync.d.mts","sourceRoot":"","sources":["src/folder-sync.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,qBAAqB,GAAG,mBAAmB,GAAG,eAAe,CAAC;IAC3E,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAmTF,MAAM,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAE7C,wBAAsB,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4CzG"}
package/folder-sync.d.ts CHANGED
@@ -7,7 +7,7 @@ export type FolderSyncOptions = {
7
7
  * Used to store the last-synced “basis” copies of files (and related sync metadata) so we can compute xdelta patches
8
8
  * on subsequent syncs without re-downloading server state.
9
9
  *
10
- * Can be absolute or relative to process.cwd(). Defaults to `.lim-metadata-cache/`.
10
+ * Can be absolute or relative to process.cwd(). Defaults to `.limsync-cache/`.
11
11
  */
12
12
  basisCacheDir?: string;
13
13
  install?: boolean;
@@ -18,6 +18,21 @@ export type FolderSyncOptions = {
18
18
  maxPatchBytes?: number;
19
19
  /** Controls logging verbosity */
20
20
  log?: (level: 'debug' | 'info' | 'warn' | 'error', msg: string) => void;
21
+ /**
22
+ * Optional filter function to include/exclude files and directories.
23
+ * Called with the relative path from localFolderPath (using forward slashes).
24
+ * For directories, the path ends with '/'.
25
+ * Return true to include, false to exclude.
26
+ *
27
+ * @example
28
+ * // Exclude build folder
29
+ * filter: (path) => !path.startsWith('build/')
30
+ *
31
+ * @example
32
+ * // Only include source files
33
+ * filter: (path) => path.startsWith('src/') || path.endsWith('.json')
34
+ */
35
+ filter?: (relativePath: string) => boolean;
21
36
  };
22
37
  export type SyncFolderResult = {
23
38
  installedAppPath?: string;
@@ -27,5 +42,4 @@ export type SyncFolderResult = {
27
42
  };
28
43
  export type SyncAppResult = SyncFolderResult;
29
44
  export declare function syncApp(localFolderPath: string, opts: FolderSyncOptions): Promise<SyncFolderResult>;
30
- export declare function syncFolder(localFolderPath: string, opts: FolderSyncOptions): Promise<SyncFolderResult>;
31
45
  //# sourceMappingURL=folder-sync.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"folder-sync.d.ts","sourceRoot":"","sources":["src/folder-sync.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,qBAAqB,GAAG,mBAAmB,GAAG,eAAe,CAAC;IAC3E,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AA4QF,MAAM,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAE7C,wBAAsB,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2CzG;AAGD,wBAAsB,UAAU,CAC9B,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CAE3B"}
1
+ {"version":3,"file":"folder-sync.d.ts","sourceRoot":"","sources":["src/folder-sync.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,qBAAqB,GAAG,mBAAmB,GAAG,eAAe,CAAC;IAC3E,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAmTF,MAAM,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAE7C,wBAAsB,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4CzG"}