@limrun/api 0.46.1 → 0.46.2

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 (46) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/index.d.mts +2 -1
  3. package/index.d.mts.map +1 -1
  4. package/index.d.ts +2 -1
  5. package/index.d.ts.map +1 -1
  6. package/index.js +10 -1
  7. package/index.js.map +1 -1
  8. package/index.mjs +1 -0
  9. package/index.mjs.map +1 -1
  10. package/package.json +11 -1
  11. package/resources/gradle-instances.d.mts +9 -0
  12. package/resources/gradle-instances.d.mts.map +1 -1
  13. package/resources/gradle-instances.d.ts +9 -0
  14. package/resources/gradle-instances.d.ts.map +1 -1
  15. package/resources/index.d.mts +1 -1
  16. package/resources/index.d.mts.map +1 -1
  17. package/resources/index.d.ts +1 -1
  18. package/resources/index.d.ts.map +1 -1
  19. package/resources/index.js.map +1 -1
  20. package/resources/index.mjs.map +1 -1
  21. package/resources/xcode-instances-helpers.d.mts +30 -1
  22. package/resources/xcode-instances-helpers.d.mts.map +1 -1
  23. package/resources/xcode-instances-helpers.d.ts +30 -1
  24. package/resources/xcode-instances-helpers.d.ts.map +1 -1
  25. package/resources/xcode-instances-helpers.js +38 -0
  26. package/resources/xcode-instances-helpers.js.map +1 -1
  27. package/resources/xcode-instances-helpers.mjs +39 -1
  28. package/resources/xcode-instances-helpers.mjs.map +1 -1
  29. package/src/index.ts +21 -0
  30. package/src/resources/gradle-instances.ts +10 -0
  31. package/src/resources/index.ts +1 -0
  32. package/src/resources/xcode-instances-helpers.ts +61 -1
  33. package/src/version.ts +1 -1
  34. package/src/xcode-cache.ts +327 -0
  35. package/version.d.mts +1 -1
  36. package/version.d.ts +1 -1
  37. package/version.js +1 -1
  38. package/version.mjs +1 -1
  39. package/xcode-cache.d.mts +142 -0
  40. package/xcode-cache.d.mts.map +1 -0
  41. package/xcode-cache.d.ts +142 -0
  42. package/xcode-cache.d.ts.map +1 -0
  43. package/xcode-cache.js +175 -0
  44. package/xcode-cache.js.map +1 -0
  45. package/xcode-cache.mjs +165 -0
  46. package/xcode-cache.mjs.map +1 -0
@@ -0,0 +1,327 @@
1
+ import { createEventSource, type EventSourceMessage } from 'eventsource-client';
2
+
3
+ import { nodeProxyTransport } from './internal/proxy-transport';
4
+
5
+ /**
6
+ * Build cache configuration for an Xcode instance. Omitted means an ordinary uncached
7
+ * instance, which resolves nothing, adopts no stable directory, and publishes nothing.
8
+ */
9
+ export type XcodeCacheConfig = {
10
+ /**
11
+ * Where this instance's workspace is published at termination. Organization-scoped and set
12
+ * once, either here or later through `bindCacheKey`. Reusing a key is normal operation:
13
+ * termination replaces its archive.
14
+ *
15
+ * With no restoreKeys, a key given here also serves as the single restore key.
16
+ */
17
+ key?: string;
18
+ /**
19
+ * Keys to restore from, tried in exactly this order: exact match first, then literal prefix,
20
+ * newest archive first within a prefix. Immutable after create.
21
+ */
22
+ restoreKeys?: string[];
23
+ /**
24
+ * Project-root-relative paths to store. Create-only, and it controls what is STORED: the
25
+ * first publication under a key fixes its path set and restores materialize that set.
26
+ * Omitted means the whole deterministic workspace.
27
+ */
28
+ paths?: string[];
29
+ };
30
+
31
+ /**
32
+ * How far a restore got. `disabled`, `unsupported` and `skipped` are not failures: they
33
+ * describe an ordinary cold instance, which is perfectly usable. Only `failed` means the
34
+ * workspace was supposed to be warm and something actually broke.
35
+ */
36
+ export type XcodeCacheRestorePhase =
37
+ | 'disabled'
38
+ | 'unsupported'
39
+ | 'placing'
40
+ | 'downloading'
41
+ | 'materializing'
42
+ | 'restored'
43
+ | 'skipped'
44
+ | 'failed';
45
+
46
+ /** How far publication got. */
47
+ export type XcodeCacheSavePhase =
48
+ | 'disabled'
49
+ | 'idle'
50
+ | 'quiescing'
51
+ | 'archiving'
52
+ | 'uploading'
53
+ | 'verifying'
54
+ | 'published'
55
+ | 'skipped'
56
+ | 'failed'
57
+ | 'timed_out';
58
+
59
+ /** A restore key resolution passed over, so a miss is explainable rather than just a miss. */
60
+ export type XcodeCacheSkippedKey = { key: string; reason: string };
61
+
62
+ export type XcodeCacheRestoreStatus = {
63
+ phase: XcodeCacheRestorePhase;
64
+ reason?: string;
65
+ message?: string;
66
+ /** Restore key whose archive was used. */
67
+ matchedKey?: string;
68
+ matchKind?: 'exact_hit' | 'prefix_hit';
69
+ skippedKeys?: XcodeCacheSkippedKey[];
70
+ /** Path set actually materialized, which is the set the archive stores. */
71
+ paths?: string[];
72
+ /** Whether the bytes came through the regional accelerator or direct from object storage. */
73
+ source?: 'tag' | 'tigris';
74
+ bytes?: number;
75
+ uncompressedBytes?: number;
76
+ startedAt?: string;
77
+ finishedAt?: string;
78
+ };
79
+
80
+ export type XcodeCacheSaveStatus = {
81
+ phase: XcodeCacheSavePhase;
82
+ reason?: string;
83
+ message?: string;
84
+ /** Destination key the archive is published under. */
85
+ cacheKey?: string;
86
+ paths?: string[];
87
+ bytes?: number;
88
+ uncompressedBytes?: number;
89
+ startedAt?: string;
90
+ finishedAt?: string;
91
+ };
92
+
93
+ export type XcodeInstanceCache = {
94
+ config?: XcodeCacheConfig;
95
+ restore: XcodeCacheRestoreStatus;
96
+ save: XcodeCacheSaveStatus;
97
+ };
98
+
99
+ /** Which half of the cache lifecycle a follower waits on. */
100
+ export type XcodeCacheSide = 'restore' | 'save';
101
+
102
+ export type XcodeCacheFollowOptions = {
103
+ /** Defaults to 'restore'. */
104
+ side?: XcodeCacheSide;
105
+ /**
106
+ * Called once per distinct state, including the snapshot the stream opens with. Phases that
107
+ * repeat, which a reconnect produces, are not reported again.
108
+ */
109
+ onUpdate?: (cache: XcodeInstanceCache) => void;
110
+ /**
111
+ * Called when the stream is open, and again after each reconnect. A caller that is about to
112
+ * cause the very transitions it wants to watch waits for this first, so it cannot race its
113
+ * own subscription.
114
+ */
115
+ onOpen?: () => void;
116
+ /**
117
+ * How long to wait for a terminal phase. Restores move multi-gigabyte archives and
118
+ * publication is capped server-side at ten minutes, so these are generous by design.
119
+ */
120
+ timeoutMs?: number;
121
+ signal?: AbortSignal;
122
+ };
123
+
124
+ export type XcodeCacheFollowResult = {
125
+ /** The last state seen, terminal unless the stream ended first. */
126
+ cache: XcodeInstanceCache;
127
+ /**
128
+ * True when the instance was collected before the phase went terminal. The last snapshot is
129
+ * still the summary: the control plane writes the terminal phase and deletes moments later.
130
+ */
131
+ gone: boolean;
132
+ };
133
+
134
+ /**
135
+ * The instance was gone before it said anything about its cache, so there is no last state to
136
+ * summarise. Distinct from a follow that ends with `gone: true`, which at least saw one.
137
+ */
138
+ export class XcodeCacheGoneError extends Error {
139
+ constructor(readonly instanceId: string) {
140
+ super(`Instance ${instanceId} was gone before it reported any cache status`);
141
+ this.name = 'XcodeCacheGoneError';
142
+ }
143
+ }
144
+
145
+ export class XcodeCacheTimeoutError extends Error {
146
+ constructor(
147
+ readonly side: XcodeCacheSide,
148
+ readonly timeoutMs: number,
149
+ readonly cache: XcodeInstanceCache | undefined,
150
+ ) {
151
+ super(
152
+ `Timed out after ${Math.round(timeoutMs / 1000)}s waiting for the cache ${side} to finish` +
153
+ (cache ? ` (last phase: ${cache[side].phase})` : ''),
154
+ );
155
+ this.name = 'XcodeCacheTimeoutError';
156
+ }
157
+ }
158
+
159
+ const DEFAULT_TIMEOUT_MS: Record<XcodeCacheSide, number> = {
160
+ restore: 20 * 60 * 1000,
161
+ save: 12 * 60 * 1000,
162
+ };
163
+
164
+ /** Phases past which nothing more will happen. */
165
+ export function isRestoreTerminal(phase: XcodeCacheRestorePhase): boolean {
166
+ return (
167
+ phase === 'disabled' ||
168
+ phase === 'unsupported' ||
169
+ phase === 'restored' ||
170
+ phase === 'skipped' ||
171
+ phase === 'failed'
172
+ );
173
+ }
174
+
175
+ /**
176
+ * Separates the one outcome worth reacting to from the terminal phases that just mean "cold,
177
+ * carry on". A caller that created an instance for a warm workspace deletes it on a failure,
178
+ * but a fallback to a cold build leaves a perfectly usable instance behind.
179
+ */
180
+ export function isRestoreFailure(phase: XcodeCacheRestorePhase): boolean {
181
+ return phase === 'failed';
182
+ }
183
+
184
+ export function isSaveTerminal(phase: XcodeCacheSavePhase): boolean {
185
+ return (
186
+ phase === 'disabled' ||
187
+ phase === 'published' ||
188
+ phase === 'skipped' ||
189
+ phase === 'failed' ||
190
+ phase === 'timed_out'
191
+ );
192
+ }
193
+
194
+ export function isCacheTerminal(cache: XcodeInstanceCache, side: XcodeCacheSide): boolean {
195
+ return side === 'restore' ? isRestoreTerminal(cache.restore.phase) : isSaveTerminal(cache.save.phase);
196
+ }
197
+
198
+ export type XcodeCacheFollowTarget = {
199
+ baseURL: string;
200
+ apiKey: string;
201
+ instanceId: string;
202
+ };
203
+
204
+ /**
205
+ * Follows an instance's cache status until the chosen side reaches a terminal phase, the
206
+ * instance is collected, or the wait times out.
207
+ *
208
+ * The transport is the same endpoint that serves a JSON snapshot, asked for as an event
209
+ * stream. The server emits on phase change only, so every callback is a real transition.
210
+ */
211
+ export function followXcodeCache(
212
+ target: XcodeCacheFollowTarget,
213
+ options: XcodeCacheFollowOptions = {},
214
+ ): Promise<XcodeCacheFollowResult> {
215
+ const side = options.side ?? 'restore';
216
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS[side];
217
+ let base = target.baseURL;
218
+ while (base.endsWith('/')) base = base.slice(0, -1);
219
+ const url = `${base}/v1/xcode_instances/${encodeURIComponent(target.instanceId)}/cache`;
220
+
221
+ return new Promise<XcodeCacheFollowResult>((resolve, reject) => {
222
+ let last: XcodeInstanceCache | undefined;
223
+ let lastKey = '';
224
+ let settled = false;
225
+
226
+ const finish = (fn: () => void) => {
227
+ if (settled) return;
228
+ settled = true;
229
+ clearTimeout(timer);
230
+ options.signal?.removeEventListener('abort', onAbort);
231
+ try {
232
+ source.close();
233
+ } catch {
234
+ // A stream that never opened has nothing to close.
235
+ }
236
+ fn();
237
+ };
238
+
239
+ const timer = setTimeout(
240
+ () => finish(() => reject(new XcodeCacheTimeoutError(side, timeoutMs, last))),
241
+ timeoutMs,
242
+ );
243
+ const onAbort = () => finish(() => reject(options.signal?.reason ?? new Error('aborted')));
244
+
245
+ let confirming = false;
246
+ const confirmGone = () => {
247
+ if (confirming || settled) return;
248
+ confirming = true;
249
+ nodeProxyTransport
250
+ .fetch(url, {
251
+ headers: { Authorization: `Bearer ${target.apiKey}`, Accept: 'application/json' },
252
+ })
253
+ .then(async (res) => {
254
+ confirming = false;
255
+ if (res.status !== 404) {
256
+ await res.text().catch(() => undefined);
257
+ return;
258
+ }
259
+ finish(() =>
260
+ last ? resolve({ cache: last, gone: true }) : reject(new XcodeCacheGoneError(target.instanceId)),
261
+ );
262
+ })
263
+ .catch(() => {
264
+ confirming = false;
265
+ });
266
+ };
267
+
268
+ // The endpoint answers from the region, which keeps the instance while it terminates and
269
+ // drops it once it is collected, so a 404 is the instance being over rather than a fault.
270
+ // Without this the client treats it as a connection to retry and follows a gone instance
271
+ // until the timeout, which is minutes of a command that looks hung and says nothing.
272
+ const fetchOrGone: typeof nodeProxyTransport.fetch = async (input, init) => {
273
+ const res = await nodeProxyTransport.fetch(input, init);
274
+ if (res.status === 404) {
275
+ finish(() =>
276
+ last ? resolve({ cache: last, gone: true }) : reject(new XcodeCacheGoneError(target.instanceId)),
277
+ );
278
+ }
279
+ return res;
280
+ };
281
+
282
+ const source = createEventSource({
283
+ url,
284
+ fetch: fetchOrGone,
285
+ onConnect: () => options.onOpen?.(),
286
+ headers: {
287
+ Authorization: `Bearer ${target.apiKey}`,
288
+ Accept: 'text/event-stream',
289
+ },
290
+ onMessage: (message: EventSourceMessage) => {
291
+ if (message.event !== 'cache' && message.event !== 'gone') return;
292
+ let cache: XcodeInstanceCache;
293
+ try {
294
+ cache = JSON.parse(typeof message.data === 'string' ? message.data : String(message.data));
295
+ } catch (err) {
296
+ finish(() => reject(new Error(`Cache stream sent unreadable data: ${err}`)));
297
+ return;
298
+ }
299
+ last = cache;
300
+ if (message.event === 'gone') {
301
+ // The server also ends the stream this way when its own watch is cut short, which
302
+ // Kubernetes does routinely on a long one, so a snapshot decides which it was. The
303
+ // client library reconnects on its own when the instance is in fact still there.
304
+ confirmGone();
305
+ return;
306
+ }
307
+ // A reconnect replays the current state, which is not a transition.
308
+ const key = `${cache.restore.phase}/${cache.restore.reason ?? ''}|${cache.save.phase}/${
309
+ cache.save.reason ?? ''
310
+ }`;
311
+ if (key !== lastKey) {
312
+ lastKey = key;
313
+ options.onUpdate?.(cache);
314
+ }
315
+ if (isCacheTerminal(cache, side)) {
316
+ finish(() => resolve({ cache, gone: false }));
317
+ }
318
+ },
319
+ });
320
+
321
+ if (options.signal?.aborted) {
322
+ onAbort();
323
+ return;
324
+ }
325
+ options.signal?.addEventListener('abort', onAbort, { once: true });
326
+ });
327
+ }
package/version.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.46.1";
1
+ export declare const VERSION = "0.46.2";
2
2
  //# sourceMappingURL=version.d.mts.map
package/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.46.1";
1
+ export declare const VERSION = "0.46.2";
2
2
  //# sourceMappingURL=version.d.ts.map
package/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = '0.46.1'; // x-release-please-version
4
+ exports.VERSION = '0.46.2'; // x-release-please-version
5
5
  //# sourceMappingURL=version.js.map
package/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = '0.46.1'; // x-release-please-version
1
+ export const VERSION = '0.46.2'; // x-release-please-version
2
2
  //# sourceMappingURL=version.mjs.map
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Build cache configuration for an Xcode instance. Omitted means an ordinary uncached
3
+ * instance, which resolves nothing, adopts no stable directory, and publishes nothing.
4
+ */
5
+ export type XcodeCacheConfig = {
6
+ /**
7
+ * Where this instance's workspace is published at termination. Organization-scoped and set
8
+ * once, either here or later through `bindCacheKey`. Reusing a key is normal operation:
9
+ * termination replaces its archive.
10
+ *
11
+ * With no restoreKeys, a key given here also serves as the single restore key.
12
+ */
13
+ key?: string;
14
+ /**
15
+ * Keys to restore from, tried in exactly this order: exact match first, then literal prefix,
16
+ * newest archive first within a prefix. Immutable after create.
17
+ */
18
+ restoreKeys?: string[];
19
+ /**
20
+ * Project-root-relative paths to store. Create-only, and it controls what is STORED: the
21
+ * first publication under a key fixes its path set and restores materialize that set.
22
+ * Omitted means the whole deterministic workspace.
23
+ */
24
+ paths?: string[];
25
+ };
26
+ /**
27
+ * How far a restore got. `disabled`, `unsupported` and `skipped` are not failures: they
28
+ * describe an ordinary cold instance, which is perfectly usable. Only `failed` means the
29
+ * workspace was supposed to be warm and something actually broke.
30
+ */
31
+ export type XcodeCacheRestorePhase = 'disabled' | 'unsupported' | 'placing' | 'downloading' | 'materializing' | 'restored' | 'skipped' | 'failed';
32
+ /** How far publication got. */
33
+ export type XcodeCacheSavePhase = 'disabled' | 'idle' | 'quiescing' | 'archiving' | 'uploading' | 'verifying' | 'published' | 'skipped' | 'failed' | 'timed_out';
34
+ /** A restore key resolution passed over, so a miss is explainable rather than just a miss. */
35
+ export type XcodeCacheSkippedKey = {
36
+ key: string;
37
+ reason: string;
38
+ };
39
+ export type XcodeCacheRestoreStatus = {
40
+ phase: XcodeCacheRestorePhase;
41
+ reason?: string;
42
+ message?: string;
43
+ /** Restore key whose archive was used. */
44
+ matchedKey?: string;
45
+ matchKind?: 'exact_hit' | 'prefix_hit';
46
+ skippedKeys?: XcodeCacheSkippedKey[];
47
+ /** Path set actually materialized, which is the set the archive stores. */
48
+ paths?: string[];
49
+ /** Whether the bytes came through the regional accelerator or direct from object storage. */
50
+ source?: 'tag' | 'tigris';
51
+ bytes?: number;
52
+ uncompressedBytes?: number;
53
+ startedAt?: string;
54
+ finishedAt?: string;
55
+ };
56
+ export type XcodeCacheSaveStatus = {
57
+ phase: XcodeCacheSavePhase;
58
+ reason?: string;
59
+ message?: string;
60
+ /** Destination key the archive is published under. */
61
+ cacheKey?: string;
62
+ paths?: string[];
63
+ bytes?: number;
64
+ uncompressedBytes?: number;
65
+ startedAt?: string;
66
+ finishedAt?: string;
67
+ };
68
+ export type XcodeInstanceCache = {
69
+ config?: XcodeCacheConfig;
70
+ restore: XcodeCacheRestoreStatus;
71
+ save: XcodeCacheSaveStatus;
72
+ };
73
+ /** Which half of the cache lifecycle a follower waits on. */
74
+ export type XcodeCacheSide = 'restore' | 'save';
75
+ export type XcodeCacheFollowOptions = {
76
+ /** Defaults to 'restore'. */
77
+ side?: XcodeCacheSide;
78
+ /**
79
+ * Called once per distinct state, including the snapshot the stream opens with. Phases that
80
+ * repeat, which a reconnect produces, are not reported again.
81
+ */
82
+ onUpdate?: (cache: XcodeInstanceCache) => void;
83
+ /**
84
+ * Called when the stream is open, and again after each reconnect. A caller that is about to
85
+ * cause the very transitions it wants to watch waits for this first, so it cannot race its
86
+ * own subscription.
87
+ */
88
+ onOpen?: () => void;
89
+ /**
90
+ * How long to wait for a terminal phase. Restores move multi-gigabyte archives and
91
+ * publication is capped server-side at ten minutes, so these are generous by design.
92
+ */
93
+ timeoutMs?: number;
94
+ signal?: AbortSignal;
95
+ };
96
+ export type XcodeCacheFollowResult = {
97
+ /** The last state seen, terminal unless the stream ended first. */
98
+ cache: XcodeInstanceCache;
99
+ /**
100
+ * True when the instance was collected before the phase went terminal. The last snapshot is
101
+ * still the summary: the control plane writes the terminal phase and deletes moments later.
102
+ */
103
+ gone: boolean;
104
+ };
105
+ /**
106
+ * The instance was gone before it said anything about its cache, so there is no last state to
107
+ * summarise. Distinct from a follow that ends with `gone: true`, which at least saw one.
108
+ */
109
+ export declare class XcodeCacheGoneError extends Error {
110
+ readonly instanceId: string;
111
+ constructor(instanceId: string);
112
+ }
113
+ export declare class XcodeCacheTimeoutError extends Error {
114
+ readonly side: XcodeCacheSide;
115
+ readonly timeoutMs: number;
116
+ readonly cache: XcodeInstanceCache | undefined;
117
+ constructor(side: XcodeCacheSide, timeoutMs: number, cache: XcodeInstanceCache | undefined);
118
+ }
119
+ /** Phases past which nothing more will happen. */
120
+ export declare function isRestoreTerminal(phase: XcodeCacheRestorePhase): boolean;
121
+ /**
122
+ * Separates the one outcome worth reacting to from the terminal phases that just mean "cold,
123
+ * carry on". A caller that created an instance for a warm workspace deletes it on a failure,
124
+ * but a fallback to a cold build leaves a perfectly usable instance behind.
125
+ */
126
+ export declare function isRestoreFailure(phase: XcodeCacheRestorePhase): boolean;
127
+ export declare function isSaveTerminal(phase: XcodeCacheSavePhase): boolean;
128
+ export declare function isCacheTerminal(cache: XcodeInstanceCache, side: XcodeCacheSide): boolean;
129
+ export type XcodeCacheFollowTarget = {
130
+ baseURL: string;
131
+ apiKey: string;
132
+ instanceId: string;
133
+ };
134
+ /**
135
+ * Follows an instance's cache status until the chosen side reaches a terminal phase, the
136
+ * instance is collected, or the wait times out.
137
+ *
138
+ * The transport is the same endpoint that serves a JSON snapshot, asked for as an event
139
+ * stream. The server emits on phase change only, so every callback is a real transition.
140
+ */
141
+ export declare function followXcodeCache(target: XcodeCacheFollowTarget, options?: XcodeCacheFollowOptions): Promise<XcodeCacheFollowResult>;
142
+ //# sourceMappingURL=xcode-cache.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xcode-cache.d.mts","sourceRoot":"","sources":["src/xcode-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Build cache configuration for an Xcode instance. Omitted means an ordinary uncached
3
+ * instance, which resolves nothing, adopts no stable directory, and publishes nothing.
4
+ */
5
+ export type XcodeCacheConfig = {
6
+ /**
7
+ * Where this instance's workspace is published at termination. Organization-scoped and set
8
+ * once, either here or later through `bindCacheKey`. Reusing a key is normal operation:
9
+ * termination replaces its archive.
10
+ *
11
+ * With no restoreKeys, a key given here also serves as the single restore key.
12
+ */
13
+ key?: string;
14
+ /**
15
+ * Keys to restore from, tried in exactly this order: exact match first, then literal prefix,
16
+ * newest archive first within a prefix. Immutable after create.
17
+ */
18
+ restoreKeys?: string[];
19
+ /**
20
+ * Project-root-relative paths to store. Create-only, and it controls what is STORED: the
21
+ * first publication under a key fixes its path set and restores materialize that set.
22
+ * Omitted means the whole deterministic workspace.
23
+ */
24
+ paths?: string[];
25
+ };
26
+ /**
27
+ * How far a restore got. `disabled`, `unsupported` and `skipped` are not failures: they
28
+ * describe an ordinary cold instance, which is perfectly usable. Only `failed` means the
29
+ * workspace was supposed to be warm and something actually broke.
30
+ */
31
+ export type XcodeCacheRestorePhase = 'disabled' | 'unsupported' | 'placing' | 'downloading' | 'materializing' | 'restored' | 'skipped' | 'failed';
32
+ /** How far publication got. */
33
+ export type XcodeCacheSavePhase = 'disabled' | 'idle' | 'quiescing' | 'archiving' | 'uploading' | 'verifying' | 'published' | 'skipped' | 'failed' | 'timed_out';
34
+ /** A restore key resolution passed over, so a miss is explainable rather than just a miss. */
35
+ export type XcodeCacheSkippedKey = {
36
+ key: string;
37
+ reason: string;
38
+ };
39
+ export type XcodeCacheRestoreStatus = {
40
+ phase: XcodeCacheRestorePhase;
41
+ reason?: string;
42
+ message?: string;
43
+ /** Restore key whose archive was used. */
44
+ matchedKey?: string;
45
+ matchKind?: 'exact_hit' | 'prefix_hit';
46
+ skippedKeys?: XcodeCacheSkippedKey[];
47
+ /** Path set actually materialized, which is the set the archive stores. */
48
+ paths?: string[];
49
+ /** Whether the bytes came through the regional accelerator or direct from object storage. */
50
+ source?: 'tag' | 'tigris';
51
+ bytes?: number;
52
+ uncompressedBytes?: number;
53
+ startedAt?: string;
54
+ finishedAt?: string;
55
+ };
56
+ export type XcodeCacheSaveStatus = {
57
+ phase: XcodeCacheSavePhase;
58
+ reason?: string;
59
+ message?: string;
60
+ /** Destination key the archive is published under. */
61
+ cacheKey?: string;
62
+ paths?: string[];
63
+ bytes?: number;
64
+ uncompressedBytes?: number;
65
+ startedAt?: string;
66
+ finishedAt?: string;
67
+ };
68
+ export type XcodeInstanceCache = {
69
+ config?: XcodeCacheConfig;
70
+ restore: XcodeCacheRestoreStatus;
71
+ save: XcodeCacheSaveStatus;
72
+ };
73
+ /** Which half of the cache lifecycle a follower waits on. */
74
+ export type XcodeCacheSide = 'restore' | 'save';
75
+ export type XcodeCacheFollowOptions = {
76
+ /** Defaults to 'restore'. */
77
+ side?: XcodeCacheSide;
78
+ /**
79
+ * Called once per distinct state, including the snapshot the stream opens with. Phases that
80
+ * repeat, which a reconnect produces, are not reported again.
81
+ */
82
+ onUpdate?: (cache: XcodeInstanceCache) => void;
83
+ /**
84
+ * Called when the stream is open, and again after each reconnect. A caller that is about to
85
+ * cause the very transitions it wants to watch waits for this first, so it cannot race its
86
+ * own subscription.
87
+ */
88
+ onOpen?: () => void;
89
+ /**
90
+ * How long to wait for a terminal phase. Restores move multi-gigabyte archives and
91
+ * publication is capped server-side at ten minutes, so these are generous by design.
92
+ */
93
+ timeoutMs?: number;
94
+ signal?: AbortSignal;
95
+ };
96
+ export type XcodeCacheFollowResult = {
97
+ /** The last state seen, terminal unless the stream ended first. */
98
+ cache: XcodeInstanceCache;
99
+ /**
100
+ * True when the instance was collected before the phase went terminal. The last snapshot is
101
+ * still the summary: the control plane writes the terminal phase and deletes moments later.
102
+ */
103
+ gone: boolean;
104
+ };
105
+ /**
106
+ * The instance was gone before it said anything about its cache, so there is no last state to
107
+ * summarise. Distinct from a follow that ends with `gone: true`, which at least saw one.
108
+ */
109
+ export declare class XcodeCacheGoneError extends Error {
110
+ readonly instanceId: string;
111
+ constructor(instanceId: string);
112
+ }
113
+ export declare class XcodeCacheTimeoutError extends Error {
114
+ readonly side: XcodeCacheSide;
115
+ readonly timeoutMs: number;
116
+ readonly cache: XcodeInstanceCache | undefined;
117
+ constructor(side: XcodeCacheSide, timeoutMs: number, cache: XcodeInstanceCache | undefined);
118
+ }
119
+ /** Phases past which nothing more will happen. */
120
+ export declare function isRestoreTerminal(phase: XcodeCacheRestorePhase): boolean;
121
+ /**
122
+ * Separates the one outcome worth reacting to from the terminal phases that just mean "cold,
123
+ * carry on". A caller that created an instance for a warm workspace deletes it on a failure,
124
+ * but a fallback to a cold build leaves a perfectly usable instance behind.
125
+ */
126
+ export declare function isRestoreFailure(phase: XcodeCacheRestorePhase): boolean;
127
+ export declare function isSaveTerminal(phase: XcodeCacheSavePhase): boolean;
128
+ export declare function isCacheTerminal(cache: XcodeInstanceCache, side: XcodeCacheSide): boolean;
129
+ export type XcodeCacheFollowTarget = {
130
+ baseURL: string;
131
+ apiKey: string;
132
+ instanceId: string;
133
+ };
134
+ /**
135
+ * Follows an instance's cache status until the chosen side reaches a terminal phase, the
136
+ * instance is collected, or the wait times out.
137
+ *
138
+ * The transport is the same endpoint that serves a JSON snapshot, asked for as an event
139
+ * stream. The server emits on phase change only, so every callback is a real transition.
140
+ */
141
+ export declare function followXcodeCache(target: XcodeCacheFollowTarget, options?: XcodeCacheFollowOptions): Promise<XcodeCacheFollowResult>;
142
+ //# sourceMappingURL=xcode-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xcode-cache.d.ts","sourceRoot":"","sources":["src/xcode-cache.ts"],"names":[],"mappings":"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"}