freestyle-sandboxes 0.1.42 → 0.1.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs +166 -48
- package/index.d.cts +21 -9
- package/index.d.mts +21 -9
- package/index.mjs +166 -48
- package/package.json +1 -1
package/index.cjs
CHANGED
|
@@ -3763,6 +3763,9 @@ class ApiClient {
|
|
|
3763
3763
|
};
|
|
3764
3764
|
return this.fetchFn(url, finalOptions);
|
|
3765
3765
|
}
|
|
3766
|
+
resolveUrl(path, params, query) {
|
|
3767
|
+
return this.buildUrl(path, params, query);
|
|
3768
|
+
}
|
|
3766
3769
|
getRaw(path, options) {
|
|
3767
3770
|
const url = this.buildUrl(path, options?.params, options?.query);
|
|
3768
3771
|
return this.requestRaw("GET", url, void 0, options?.headers);
|
|
@@ -3777,6 +3780,11 @@ class ApiClient {
|
|
|
3777
3780
|
const url = this.buildUrl(path, options?.params, options?.query);
|
|
3778
3781
|
return this.request("POST", url, options?.body, options?.headers);
|
|
3779
3782
|
}
|
|
3783
|
+
postRaw(path, ...args) {
|
|
3784
|
+
const options = args[0];
|
|
3785
|
+
const url = this.buildUrl(path, options?.params, options?.query);
|
|
3786
|
+
return this.requestRaw("POST", url, options?.body, options?.headers);
|
|
3787
|
+
}
|
|
3780
3788
|
put(path, ...args) {
|
|
3781
3789
|
const options = args[0];
|
|
3782
3790
|
const url = this.buildUrl(path, options?.params, options?.query);
|
|
@@ -6013,6 +6021,94 @@ function composeVmSpecs(specs) {
|
|
|
6013
6021
|
const DEFAULT_CONFIGURE_BASE_IMAGE = "FROM debian:trixie-slim";
|
|
6014
6022
|
const RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX = "freestyle-run-command";
|
|
6015
6023
|
const WAIT_FOR_SYSTEMD_SERVICE_PREFIX = "freestyle-wait-for";
|
|
6024
|
+
const BACKGROUND_AFTER_SECS_HEADER = "x-freestyle-background-after-secs";
|
|
6025
|
+
const BACKGROUND_REQUEST_ID_HEADER = "x-freestyle-background-request-id";
|
|
6026
|
+
const DEFAULT_BACKGROUND_AFTER_SECS = 5;
|
|
6027
|
+
const DEFAULT_BACKGROUND_POLL_INTERVAL_MS = 2e3;
|
|
6028
|
+
function delay(ms) {
|
|
6029
|
+
const timerApi = globalThis;
|
|
6030
|
+
return new Promise((resolve) => timerApi.setTimeout(resolve, ms));
|
|
6031
|
+
}
|
|
6032
|
+
function extractBackgroundRequestId(response, body) {
|
|
6033
|
+
return response.headers.get(BACKGROUND_REQUEST_ID_HEADER) ?? body?.requestId ?? body?.request_id;
|
|
6034
|
+
}
|
|
6035
|
+
async function parseJsonResponse(response) {
|
|
6036
|
+
return await response.json();
|
|
6037
|
+
}
|
|
6038
|
+
async function readResponseError(response, fallbackMessage) {
|
|
6039
|
+
const responseText = await response.text();
|
|
6040
|
+
if (!responseText) {
|
|
6041
|
+
return fallbackMessage;
|
|
6042
|
+
}
|
|
6043
|
+
try {
|
|
6044
|
+
const errorBody = JSON.parse(responseText);
|
|
6045
|
+
return errorBody.message ?? errorBody.error ?? responseText;
|
|
6046
|
+
} catch {
|
|
6047
|
+
return responseText;
|
|
6048
|
+
}
|
|
6049
|
+
}
|
|
6050
|
+
async function emitBackgroundLogs(apiClient, requestId, logger, seenLogs) {
|
|
6051
|
+
const response = await apiClient.fetch(
|
|
6052
|
+
apiClient.resolveUrl("/observability/v1/logs", void 0, { requestId }),
|
|
6053
|
+
{ method: "GET" }
|
|
6054
|
+
);
|
|
6055
|
+
if (!response.ok) {
|
|
6056
|
+
return;
|
|
6057
|
+
}
|
|
6058
|
+
const payload = await response.json();
|
|
6059
|
+
for (const entry of payload.logs ?? []) {
|
|
6060
|
+
const key = `${entry.timestamp} ${entry.message}`;
|
|
6061
|
+
if (seenLogs.has(key)) {
|
|
6062
|
+
continue;
|
|
6063
|
+
}
|
|
6064
|
+
seenLogs.add(key);
|
|
6065
|
+
logger(`[${entry.timestamp}] ${entry.message}`);
|
|
6066
|
+
}
|
|
6067
|
+
}
|
|
6068
|
+
async function waitForBackgroundRequest(apiClient, requestId, logger) {
|
|
6069
|
+
const seenLogs = /* @__PURE__ */ new Set();
|
|
6070
|
+
const resultUrl = apiClient.resolveUrl(
|
|
6071
|
+
`/auth/v1/background-requests/${encodeURIComponent(requestId)}`
|
|
6072
|
+
);
|
|
6073
|
+
while (true) {
|
|
6074
|
+
await emitBackgroundLogs(apiClient, requestId, logger, seenLogs);
|
|
6075
|
+
const response = await apiClient.fetch(resultUrl, { method: "GET" });
|
|
6076
|
+
if (response.status === 202) {
|
|
6077
|
+
await delay(DEFAULT_BACKGROUND_POLL_INTERVAL_MS);
|
|
6078
|
+
continue;
|
|
6079
|
+
}
|
|
6080
|
+
if (!response.ok) {
|
|
6081
|
+
const message = await readResponseError(
|
|
6082
|
+
response,
|
|
6083
|
+
`Background request ${requestId} failed`
|
|
6084
|
+
);
|
|
6085
|
+
throw new Error(message);
|
|
6086
|
+
}
|
|
6087
|
+
return parseJsonResponse(response);
|
|
6088
|
+
}
|
|
6089
|
+
}
|
|
6090
|
+
async function postWithBackgroundLogger(apiClient, path, options, logger) {
|
|
6091
|
+
const response = await apiClient.postRaw(path, {
|
|
6092
|
+
...options,
|
|
6093
|
+
headers: logger ? {
|
|
6094
|
+
...options.headers ?? {},
|
|
6095
|
+
[BACKGROUND_AFTER_SECS_HEADER]: String(DEFAULT_BACKGROUND_AFTER_SECS)
|
|
6096
|
+
} : options.headers
|
|
6097
|
+
});
|
|
6098
|
+
if (response.status !== 202 || !logger) {
|
|
6099
|
+
return parseJsonResponse(response);
|
|
6100
|
+
}
|
|
6101
|
+
const accepted = await parseJsonResponse(
|
|
6102
|
+
response
|
|
6103
|
+
);
|
|
6104
|
+
const requestId = extractBackgroundRequestId(response, accepted);
|
|
6105
|
+
if (!requestId) {
|
|
6106
|
+
throw new Error(
|
|
6107
|
+
`Background request response for ${path} did not include a request ID`
|
|
6108
|
+
);
|
|
6109
|
+
}
|
|
6110
|
+
return waitForBackgroundRequest(apiClient, requestId, logger);
|
|
6111
|
+
}
|
|
6016
6112
|
function escapeRegExp(value) {
|
|
6017
6113
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6018
6114
|
}
|
|
@@ -6394,9 +6490,9 @@ class Vm {
|
|
|
6394
6490
|
ref({ vmId }) {
|
|
6395
6491
|
return new Vm({ vmId, freestyle: this._freestyle });
|
|
6396
6492
|
}
|
|
6397
|
-
async delete(
|
|
6493
|
+
async delete() {
|
|
6398
6494
|
return this.apiClient.delete("/v1/vms/{vm_id}", {
|
|
6399
|
-
params: { vm_id: vmId }
|
|
6495
|
+
params: { vm_id: this.vmId }
|
|
6400
6496
|
});
|
|
6401
6497
|
}
|
|
6402
6498
|
}
|
|
@@ -6886,9 +6982,15 @@ class VmsNamespace {
|
|
|
6886
6982
|
}
|
|
6887
6983
|
snapshots;
|
|
6888
6984
|
async create(options = {}) {
|
|
6985
|
+
let logger;
|
|
6889
6986
|
if (isVmSpecLike$1(options)) {
|
|
6890
6987
|
options = { spec: cloneVmSpecTree(options) };
|
|
6891
6988
|
} else {
|
|
6989
|
+
logger = options.logger;
|
|
6990
|
+
if ("logger" in options) {
|
|
6991
|
+
const { logger: _logger, ...rest } = options;
|
|
6992
|
+
options = rest;
|
|
6993
|
+
}
|
|
6892
6994
|
if (isVmSpecLike$1(options.spec)) {
|
|
6893
6995
|
options.spec = cloneVmSpecTree(options.spec);
|
|
6894
6996
|
}
|
|
@@ -6968,7 +7070,8 @@ class VmsNamespace {
|
|
|
6968
7070
|
if (isVmTemplateLike$1(config.template)) {
|
|
6969
7071
|
config.template = await ensureNestedTemplates(
|
|
6970
7072
|
config.template,
|
|
6971
|
-
this.snapshots
|
|
7073
|
+
this.snapshots,
|
|
7074
|
+
logger
|
|
6972
7075
|
);
|
|
6973
7076
|
}
|
|
6974
7077
|
const keys = Object.keys(builders);
|
|
@@ -7009,27 +7112,24 @@ class VmsNamespace {
|
|
|
7009
7112
|
template: _template,
|
|
7010
7113
|
...requestConfig
|
|
7011
7114
|
} = config;
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
}).catch((e) => {
|
|
7028
|
-
if (slowPathTimeout) clearTimeout(slowPathTimeout);
|
|
7115
|
+
const response = await postWithBackgroundLogger(
|
|
7116
|
+
this.freestyle._apiClient,
|
|
7117
|
+
"/v1/vms",
|
|
7118
|
+
{
|
|
7119
|
+
body: {
|
|
7120
|
+
...requestConfig,
|
|
7121
|
+
template: normalizedRequestTemplate,
|
|
7122
|
+
// Cast systemd since we've processed SystemdServiceInput[] to RawSystemdService[]
|
|
7123
|
+
systemd: config.systemd,
|
|
7124
|
+
// Normalize git options - default config to {}
|
|
7125
|
+
git: normalizeGitOptions(config.git)
|
|
7126
|
+
}
|
|
7127
|
+
},
|
|
7128
|
+
logger
|
|
7129
|
+
).catch((e) => {
|
|
7029
7130
|
enhanceError(e);
|
|
7030
7131
|
throw e;
|
|
7031
7132
|
});
|
|
7032
|
-
if (slowPathTimeout) clearTimeout(slowPathTimeout);
|
|
7033
7133
|
const vmId = response.id;
|
|
7034
7134
|
const vm = new Vm({ vmId, freestyle: this.freestyle });
|
|
7035
7135
|
for (const key in builders) {
|
|
@@ -7182,11 +7282,12 @@ class VmSnapshotsNamespace {
|
|
|
7182
7282
|
this.apiClient = apiClient;
|
|
7183
7283
|
}
|
|
7184
7284
|
async ensure(options) {
|
|
7285
|
+
const { logger, ...restOptions } = options;
|
|
7185
7286
|
let requestOptions = {
|
|
7186
|
-
...
|
|
7187
|
-
spec: isVmSpecLike$1(
|
|
7188
|
-
snapshot: isVmSpecLike$1(
|
|
7189
|
-
template: isVmTemplateLike$1(
|
|
7287
|
+
...restOptions,
|
|
7288
|
+
spec: isVmSpecLike$1(restOptions.spec) ? cloneVmSpecTree(restOptions.spec) : void 0,
|
|
7289
|
+
snapshot: isVmSpecLike$1(restOptions.snapshot) ? cloneVmSpecTree(restOptions.snapshot) : void 0,
|
|
7290
|
+
template: isVmTemplateLike$1(restOptions.template) ? cloneVmTemplateTree(restOptions.template) : restOptions.template
|
|
7190
7291
|
};
|
|
7191
7292
|
if (isVmSpecLike$1(requestOptions.snapshot)) {
|
|
7192
7293
|
if (isVmSpecLike$1(requestOptions.spec)) {
|
|
@@ -7224,7 +7325,8 @@ class VmSnapshotsNamespace {
|
|
|
7224
7325
|
if (isVmTemplateLike$1(processedTemplate.raw.template)) {
|
|
7225
7326
|
requestOptions.template = await ensureNestedTemplates(
|
|
7226
7327
|
processedTemplate,
|
|
7227
|
-
this
|
|
7328
|
+
this,
|
|
7329
|
+
logger
|
|
7228
7330
|
);
|
|
7229
7331
|
}
|
|
7230
7332
|
}
|
|
@@ -7233,27 +7335,43 @@ class VmSnapshotsNamespace {
|
|
|
7233
7335
|
"snapshots.ensure requires a template or spec to build a snapshot"
|
|
7234
7336
|
);
|
|
7235
7337
|
}
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
);
|
|
7250
|
-
}
|
|
7251
|
-
return response;
|
|
7252
|
-
}).catch((e) => {
|
|
7338
|
+
return postWithBackgroundLogger(
|
|
7339
|
+
this.apiClient,
|
|
7340
|
+
"/v1/vms/snapshots",
|
|
7341
|
+
{
|
|
7342
|
+
body: {
|
|
7343
|
+
...requestOptions,
|
|
7344
|
+
template: normalizeTemplateForRequest(
|
|
7345
|
+
isVmTemplateLike$1(requestOptions.template) ? requestOptions.template.raw : requestOptions.template
|
|
7346
|
+
)
|
|
7347
|
+
}
|
|
7348
|
+
},
|
|
7349
|
+
logger
|
|
7350
|
+
).catch((e) => {
|
|
7253
7351
|
enhanceError(e);
|
|
7254
7352
|
throw e;
|
|
7255
7353
|
});
|
|
7256
7354
|
}
|
|
7355
|
+
async create(options) {
|
|
7356
|
+
return this.ensure(options);
|
|
7357
|
+
}
|
|
7358
|
+
async delete({ snapshotId }) {
|
|
7359
|
+
const path = "/v1/vms/snapshots/{snapshot_id}";
|
|
7360
|
+
const response = await this.apiClient.fetch(
|
|
7361
|
+
this.apiClient.resolveUrl(path, { snapshot_id: snapshotId }),
|
|
7362
|
+
{ method: "DELETE" }
|
|
7363
|
+
);
|
|
7364
|
+
if (!response.ok) {
|
|
7365
|
+
const errorBody = await response.json().catch(() => null);
|
|
7366
|
+
if (errorBody?.code) {
|
|
7367
|
+
throw errorFromJSON(errorBody);
|
|
7368
|
+
}
|
|
7369
|
+
throw new Error(
|
|
7370
|
+
`Failed to delete snapshot: ${response.status} ${response.statusText}`
|
|
7371
|
+
);
|
|
7372
|
+
}
|
|
7373
|
+
return await response.json();
|
|
7374
|
+
}
|
|
7257
7375
|
}
|
|
7258
7376
|
async function processTemplateTree(template) {
|
|
7259
7377
|
if (template.raw.baseImage) {
|
|
@@ -7325,24 +7443,24 @@ async function processTemplateTree(template) {
|
|
|
7325
7443
|
}
|
|
7326
7444
|
return template;
|
|
7327
7445
|
}
|
|
7328
|
-
async function ensureNestedTemplates(template, snapshots) {
|
|
7446
|
+
async function ensureNestedTemplates(template, snapshots, logger) {
|
|
7329
7447
|
const templates = [template];
|
|
7330
7448
|
while (isVmTemplateLike$1(templates.at(-1)?.raw.template)) {
|
|
7331
7449
|
const innerTemplate = templates.at(-1).raw.template;
|
|
7332
7450
|
templates.at(-1).raw.template = void 0;
|
|
7333
7451
|
templates.push(innerTemplate);
|
|
7334
7452
|
}
|
|
7335
|
-
return await layerTemplates(templates, snapshots);
|
|
7453
|
+
return await layerTemplates(templates, snapshots, logger);
|
|
7336
7454
|
}
|
|
7337
|
-
async function layerTemplates(templates, snapshots) {
|
|
7455
|
+
async function layerTemplates(templates, snapshots, logger) {
|
|
7338
7456
|
if (templates.length === 1) {
|
|
7339
7457
|
return templates[0];
|
|
7340
7458
|
}
|
|
7341
|
-
let lastSnapshotId = (await snapshots.ensure({ template: templates.pop() })).snapshotId;
|
|
7459
|
+
let lastSnapshotId = (await snapshots.ensure({ template: templates.pop(), logger })).snapshotId;
|
|
7342
7460
|
while (templates.length > 1) {
|
|
7343
7461
|
const template = templates.pop();
|
|
7344
7462
|
template.raw.snapshotId = lastSnapshotId;
|
|
7345
|
-
lastSnapshotId = (await snapshots.ensure({ template })).snapshotId;
|
|
7463
|
+
lastSnapshotId = (await snapshots.ensure({ template, logger })).snapshotId;
|
|
7346
7464
|
}
|
|
7347
7465
|
const outermost = templates.pop();
|
|
7348
7466
|
outermost.raw.snapshotId = lastSnapshotId;
|
package/index.d.cts
CHANGED
|
@@ -6707,9 +6707,11 @@ declare class ApiClient {
|
|
|
6707
6707
|
private requestRaw;
|
|
6708
6708
|
private request;
|
|
6709
6709
|
fetch(url: string, options?: RequestInit): Promise<Response>;
|
|
6710
|
+
resolveUrl(path: string, params?: Record<string, string>, query?: Record<string, any>): string;
|
|
6710
6711
|
getRaw<P extends keyof GetPathMap>(path: P, options?: GetPathMap[P]["options"]): Promise<Response>;
|
|
6711
6712
|
get<P extends keyof GetPathMap>(path: P, ...args: GetPathMap[P]["options"] extends undefined ? [options?: GetPathMap[P]["options"]] : [options: GetPathMap[P]["options"]]): Promise<GetPathMap[P]["response"]>;
|
|
6712
6713
|
post<P extends keyof PostPathMap>(path: P, ...args: PostPathMap[P]["options"] extends undefined ? [options?: PostPathMap[P]["options"]] : [options: PostPathMap[P]["options"]]): Promise<PostPathMap[P]["response"]>;
|
|
6714
|
+
postRaw<P extends keyof PostPathMap>(path: P, ...args: PostPathMap[P]["options"] extends undefined ? [options?: PostPathMap[P]["options"]] : [options: PostPathMap[P]["options"]]): Promise<Response>;
|
|
6713
6715
|
put<P extends keyof PutPathMap>(path: P, ...args: PutPathMap[P]["options"] extends undefined ? [options?: PutPathMap[P]["options"]] : [options: PutPathMap[P]["options"]]): Promise<PutPathMap[P]["response"]>;
|
|
6714
6716
|
delete<P extends keyof DeletePathMap>(path: P, ...args: DeletePathMap[P]["options"] extends undefined ? [options?: DeletePathMap[P]["options"]] : [options: DeletePathMap[P]["options"]]): Promise<DeletePathMap[P]["response"]>;
|
|
6715
6717
|
patch<P extends keyof PatchPathMap>(path: P, ...args: PatchPathMap[P]["options"] extends undefined ? [options?: PatchPathMap[P]["options"]] : [options: PatchPathMap[P]["options"]]): Promise<PatchPathMap[P]["response"]>;
|
|
@@ -12313,6 +12315,16 @@ type SystemdServiceInput = Omit<RawSystemdService, "mode" | "exec"> & {
|
|
|
12313
12315
|
type VmWaitForConfig = Omit<SystemdServiceInput, "mode" | "exec" | "bash" | "deleteAfterSuccess"> & {
|
|
12314
12316
|
intervalSeconds?: number;
|
|
12315
12317
|
};
|
|
12318
|
+
type BackgroundRequestLogger = (message: string) => void;
|
|
12319
|
+
type SnapshotCreateOptions<T extends Record<string, VmWithLike> = {}> = Omit<PostV1VmsSnapshotsRequestBody, "template"> & {
|
|
12320
|
+
template?: VmTemplate<T> | PostV1VmsSnapshotsRequestBody["template"];
|
|
12321
|
+
spec?: VmSpec<T>;
|
|
12322
|
+
snapshot?: VmSpec<T>;
|
|
12323
|
+
logger?: BackgroundRequestLogger;
|
|
12324
|
+
};
|
|
12325
|
+
type SnapshotDeleteResponse = {
|
|
12326
|
+
snapshotId: string;
|
|
12327
|
+
};
|
|
12316
12328
|
/**
|
|
12317
12329
|
* Terminal management operations for a VM.
|
|
12318
12330
|
*/
|
|
@@ -12446,9 +12458,7 @@ declare class Vm {
|
|
|
12446
12458
|
ref({ vmId }: {
|
|
12447
12459
|
vmId: string;
|
|
12448
12460
|
}): Vm;
|
|
12449
|
-
delete(
|
|
12450
|
-
vmId: string;
|
|
12451
|
-
}): Promise<ResponseDeleteV1VmsVmId200>;
|
|
12461
|
+
delete(): Promise<ResponseDeleteV1VmsVmId200>;
|
|
12452
12462
|
}
|
|
12453
12463
|
/**
|
|
12454
12464
|
* Git configuration with optional config (defaults to {})
|
|
@@ -12551,6 +12561,7 @@ declare class VmsNamespace {
|
|
|
12551
12561
|
template?: VmTemplate<T>;
|
|
12552
12562
|
spec?: VmSpec<T>;
|
|
12553
12563
|
snapshot?: VmSpec<T>;
|
|
12564
|
+
logger?: BackgroundRequestLogger;
|
|
12554
12565
|
}): Promise<Omit<ResponsePostV1Vms200, "consoleUrl"> & {
|
|
12555
12566
|
vmId: string;
|
|
12556
12567
|
vm: Vm & {
|
|
@@ -12594,11 +12605,11 @@ declare class VmsNamespace {
|
|
|
12594
12605
|
declare class VmSnapshotsNamespace {
|
|
12595
12606
|
private apiClient;
|
|
12596
12607
|
constructor(apiClient: ApiClient);
|
|
12597
|
-
ensure<T extends Record<string, VmWithLike>>(options:
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
|
|
12601
|
-
}): Promise<
|
|
12608
|
+
ensure<T extends Record<string, VmWithLike>>(options: SnapshotCreateOptions<T>): Promise<ResponsePostV1VmsSnapshots200>;
|
|
12609
|
+
create<T extends Record<string, VmWithLike>>(options: SnapshotCreateOptions<T>): Promise<ResponsePostV1VmsSnapshots200>;
|
|
12610
|
+
delete({ snapshotId }: {
|
|
12611
|
+
snapshotId: string;
|
|
12612
|
+
}): Promise<SnapshotDeleteResponse>;
|
|
12602
12613
|
}
|
|
12603
12614
|
type CreateVmOptions = Omit<PostV1VmsRequestBody, "template" | "systemd" | "git"> & {
|
|
12604
12615
|
rootfsSizeGb?: number | null;
|
|
@@ -12615,6 +12626,7 @@ type CreateVmOptions = Omit<PostV1VmsRequestBody, "template" | "systemd" | "git"
|
|
|
12615
12626
|
git?: null | GitOptions;
|
|
12616
12627
|
discriminator?: CreateSnapshotRequest["template"]["discriminator"];
|
|
12617
12628
|
skipCache?: CreateSnapshotRequest["template"]["skipCache"];
|
|
12629
|
+
logger?: BackgroundRequestLogger;
|
|
12618
12630
|
};
|
|
12619
12631
|
|
|
12620
12632
|
type CronSchedule = {
|
|
@@ -12763,4 +12775,4 @@ declare class Freestyle {
|
|
|
12763
12775
|
declare const freestyle: Freestyle;
|
|
12764
12776
|
|
|
12765
12777
|
export { CronNamespace, Deployment, errors as Errors, FileSystem, Freestyle, GitRepo, Identity, requests as Requests, responses as Responses, Systemd, SystemdService, Vm, VmBaseImage, VmBuilder, VmService, VmSpec, VmTemplate, VmWith, VmWithInstance, debugCreateRequests, freestyle, readFiles };
|
|
12766
|
-
export type { CreateVmOptions, CronSchedule, FreestyleOptions, SystemdServiceInput, VmWaitForConfig, VmWithDefaultFieldRecord };
|
|
12778
|
+
export type { BackgroundRequestLogger, CreateVmOptions, CronSchedule, FreestyleOptions, SystemdServiceInput, VmWaitForConfig, VmWithDefaultFieldRecord };
|
package/index.d.mts
CHANGED
|
@@ -6707,9 +6707,11 @@ declare class ApiClient {
|
|
|
6707
6707
|
private requestRaw;
|
|
6708
6708
|
private request;
|
|
6709
6709
|
fetch(url: string, options?: RequestInit): Promise<Response>;
|
|
6710
|
+
resolveUrl(path: string, params?: Record<string, string>, query?: Record<string, any>): string;
|
|
6710
6711
|
getRaw<P extends keyof GetPathMap>(path: P, options?: GetPathMap[P]["options"]): Promise<Response>;
|
|
6711
6712
|
get<P extends keyof GetPathMap>(path: P, ...args: GetPathMap[P]["options"] extends undefined ? [options?: GetPathMap[P]["options"]] : [options: GetPathMap[P]["options"]]): Promise<GetPathMap[P]["response"]>;
|
|
6712
6713
|
post<P extends keyof PostPathMap>(path: P, ...args: PostPathMap[P]["options"] extends undefined ? [options?: PostPathMap[P]["options"]] : [options: PostPathMap[P]["options"]]): Promise<PostPathMap[P]["response"]>;
|
|
6714
|
+
postRaw<P extends keyof PostPathMap>(path: P, ...args: PostPathMap[P]["options"] extends undefined ? [options?: PostPathMap[P]["options"]] : [options: PostPathMap[P]["options"]]): Promise<Response>;
|
|
6713
6715
|
put<P extends keyof PutPathMap>(path: P, ...args: PutPathMap[P]["options"] extends undefined ? [options?: PutPathMap[P]["options"]] : [options: PutPathMap[P]["options"]]): Promise<PutPathMap[P]["response"]>;
|
|
6714
6716
|
delete<P extends keyof DeletePathMap>(path: P, ...args: DeletePathMap[P]["options"] extends undefined ? [options?: DeletePathMap[P]["options"]] : [options: DeletePathMap[P]["options"]]): Promise<DeletePathMap[P]["response"]>;
|
|
6715
6717
|
patch<P extends keyof PatchPathMap>(path: P, ...args: PatchPathMap[P]["options"] extends undefined ? [options?: PatchPathMap[P]["options"]] : [options: PatchPathMap[P]["options"]]): Promise<PatchPathMap[P]["response"]>;
|
|
@@ -12313,6 +12315,16 @@ type SystemdServiceInput = Omit<RawSystemdService, "mode" | "exec"> & {
|
|
|
12313
12315
|
type VmWaitForConfig = Omit<SystemdServiceInput, "mode" | "exec" | "bash" | "deleteAfterSuccess"> & {
|
|
12314
12316
|
intervalSeconds?: number;
|
|
12315
12317
|
};
|
|
12318
|
+
type BackgroundRequestLogger = (message: string) => void;
|
|
12319
|
+
type SnapshotCreateOptions<T extends Record<string, VmWithLike> = {}> = Omit<PostV1VmsSnapshotsRequestBody, "template"> & {
|
|
12320
|
+
template?: VmTemplate<T> | PostV1VmsSnapshotsRequestBody["template"];
|
|
12321
|
+
spec?: VmSpec<T>;
|
|
12322
|
+
snapshot?: VmSpec<T>;
|
|
12323
|
+
logger?: BackgroundRequestLogger;
|
|
12324
|
+
};
|
|
12325
|
+
type SnapshotDeleteResponse = {
|
|
12326
|
+
snapshotId: string;
|
|
12327
|
+
};
|
|
12316
12328
|
/**
|
|
12317
12329
|
* Terminal management operations for a VM.
|
|
12318
12330
|
*/
|
|
@@ -12446,9 +12458,7 @@ declare class Vm {
|
|
|
12446
12458
|
ref({ vmId }: {
|
|
12447
12459
|
vmId: string;
|
|
12448
12460
|
}): Vm;
|
|
12449
|
-
delete(
|
|
12450
|
-
vmId: string;
|
|
12451
|
-
}): Promise<ResponseDeleteV1VmsVmId200>;
|
|
12461
|
+
delete(): Promise<ResponseDeleteV1VmsVmId200>;
|
|
12452
12462
|
}
|
|
12453
12463
|
/**
|
|
12454
12464
|
* Git configuration with optional config (defaults to {})
|
|
@@ -12551,6 +12561,7 @@ declare class VmsNamespace {
|
|
|
12551
12561
|
template?: VmTemplate<T>;
|
|
12552
12562
|
spec?: VmSpec<T>;
|
|
12553
12563
|
snapshot?: VmSpec<T>;
|
|
12564
|
+
logger?: BackgroundRequestLogger;
|
|
12554
12565
|
}): Promise<Omit<ResponsePostV1Vms200, "consoleUrl"> & {
|
|
12555
12566
|
vmId: string;
|
|
12556
12567
|
vm: Vm & {
|
|
@@ -12594,11 +12605,11 @@ declare class VmsNamespace {
|
|
|
12594
12605
|
declare class VmSnapshotsNamespace {
|
|
12595
12606
|
private apiClient;
|
|
12596
12607
|
constructor(apiClient: ApiClient);
|
|
12597
|
-
ensure<T extends Record<string, VmWithLike>>(options:
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
|
|
12601
|
-
}): Promise<
|
|
12608
|
+
ensure<T extends Record<string, VmWithLike>>(options: SnapshotCreateOptions<T>): Promise<ResponsePostV1VmsSnapshots200>;
|
|
12609
|
+
create<T extends Record<string, VmWithLike>>(options: SnapshotCreateOptions<T>): Promise<ResponsePostV1VmsSnapshots200>;
|
|
12610
|
+
delete({ snapshotId }: {
|
|
12611
|
+
snapshotId: string;
|
|
12612
|
+
}): Promise<SnapshotDeleteResponse>;
|
|
12602
12613
|
}
|
|
12603
12614
|
type CreateVmOptions = Omit<PostV1VmsRequestBody, "template" | "systemd" | "git"> & {
|
|
12604
12615
|
rootfsSizeGb?: number | null;
|
|
@@ -12615,6 +12626,7 @@ type CreateVmOptions = Omit<PostV1VmsRequestBody, "template" | "systemd" | "git"
|
|
|
12615
12626
|
git?: null | GitOptions;
|
|
12616
12627
|
discriminator?: CreateSnapshotRequest["template"]["discriminator"];
|
|
12617
12628
|
skipCache?: CreateSnapshotRequest["template"]["skipCache"];
|
|
12629
|
+
logger?: BackgroundRequestLogger;
|
|
12618
12630
|
};
|
|
12619
12631
|
|
|
12620
12632
|
type CronSchedule = {
|
|
@@ -12763,4 +12775,4 @@ declare class Freestyle {
|
|
|
12763
12775
|
declare const freestyle: Freestyle;
|
|
12764
12776
|
|
|
12765
12777
|
export { CronNamespace, Deployment, errors as Errors, FileSystem, Freestyle, GitRepo, Identity, requests as Requests, responses as Responses, Systemd, SystemdService, Vm, VmBaseImage, VmBuilder, VmService, VmSpec, VmTemplate, VmWith, VmWithInstance, debugCreateRequests, freestyle, readFiles };
|
|
12766
|
-
export type { CreateVmOptions, CronSchedule, FreestyleOptions, SystemdServiceInput, VmWaitForConfig, VmWithDefaultFieldRecord };
|
|
12778
|
+
export type { BackgroundRequestLogger, CreateVmOptions, CronSchedule, FreestyleOptions, SystemdServiceInput, VmWaitForConfig, VmWithDefaultFieldRecord };
|
package/index.mjs
CHANGED
|
@@ -3761,6 +3761,9 @@ class ApiClient {
|
|
|
3761
3761
|
};
|
|
3762
3762
|
return this.fetchFn(url, finalOptions);
|
|
3763
3763
|
}
|
|
3764
|
+
resolveUrl(path, params, query) {
|
|
3765
|
+
return this.buildUrl(path, params, query);
|
|
3766
|
+
}
|
|
3764
3767
|
getRaw(path, options) {
|
|
3765
3768
|
const url = this.buildUrl(path, options?.params, options?.query);
|
|
3766
3769
|
return this.requestRaw("GET", url, void 0, options?.headers);
|
|
@@ -3775,6 +3778,11 @@ class ApiClient {
|
|
|
3775
3778
|
const url = this.buildUrl(path, options?.params, options?.query);
|
|
3776
3779
|
return this.request("POST", url, options?.body, options?.headers);
|
|
3777
3780
|
}
|
|
3781
|
+
postRaw(path, ...args) {
|
|
3782
|
+
const options = args[0];
|
|
3783
|
+
const url = this.buildUrl(path, options?.params, options?.query);
|
|
3784
|
+
return this.requestRaw("POST", url, options?.body, options?.headers);
|
|
3785
|
+
}
|
|
3778
3786
|
put(path, ...args) {
|
|
3779
3787
|
const options = args[0];
|
|
3780
3788
|
const url = this.buildUrl(path, options?.params, options?.query);
|
|
@@ -6011,6 +6019,94 @@ function composeVmSpecs(specs) {
|
|
|
6011
6019
|
const DEFAULT_CONFIGURE_BASE_IMAGE = "FROM debian:trixie-slim";
|
|
6012
6020
|
const RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX = "freestyle-run-command";
|
|
6013
6021
|
const WAIT_FOR_SYSTEMD_SERVICE_PREFIX = "freestyle-wait-for";
|
|
6022
|
+
const BACKGROUND_AFTER_SECS_HEADER = "x-freestyle-background-after-secs";
|
|
6023
|
+
const BACKGROUND_REQUEST_ID_HEADER = "x-freestyle-background-request-id";
|
|
6024
|
+
const DEFAULT_BACKGROUND_AFTER_SECS = 5;
|
|
6025
|
+
const DEFAULT_BACKGROUND_POLL_INTERVAL_MS = 2e3;
|
|
6026
|
+
function delay(ms) {
|
|
6027
|
+
const timerApi = globalThis;
|
|
6028
|
+
return new Promise((resolve) => timerApi.setTimeout(resolve, ms));
|
|
6029
|
+
}
|
|
6030
|
+
function extractBackgroundRequestId(response, body) {
|
|
6031
|
+
return response.headers.get(BACKGROUND_REQUEST_ID_HEADER) ?? body?.requestId ?? body?.request_id;
|
|
6032
|
+
}
|
|
6033
|
+
async function parseJsonResponse(response) {
|
|
6034
|
+
return await response.json();
|
|
6035
|
+
}
|
|
6036
|
+
async function readResponseError(response, fallbackMessage) {
|
|
6037
|
+
const responseText = await response.text();
|
|
6038
|
+
if (!responseText) {
|
|
6039
|
+
return fallbackMessage;
|
|
6040
|
+
}
|
|
6041
|
+
try {
|
|
6042
|
+
const errorBody = JSON.parse(responseText);
|
|
6043
|
+
return errorBody.message ?? errorBody.error ?? responseText;
|
|
6044
|
+
} catch {
|
|
6045
|
+
return responseText;
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
6048
|
+
async function emitBackgroundLogs(apiClient, requestId, logger, seenLogs) {
|
|
6049
|
+
const response = await apiClient.fetch(
|
|
6050
|
+
apiClient.resolveUrl("/observability/v1/logs", void 0, { requestId }),
|
|
6051
|
+
{ method: "GET" }
|
|
6052
|
+
);
|
|
6053
|
+
if (!response.ok) {
|
|
6054
|
+
return;
|
|
6055
|
+
}
|
|
6056
|
+
const payload = await response.json();
|
|
6057
|
+
for (const entry of payload.logs ?? []) {
|
|
6058
|
+
const key = `${entry.timestamp} ${entry.message}`;
|
|
6059
|
+
if (seenLogs.has(key)) {
|
|
6060
|
+
continue;
|
|
6061
|
+
}
|
|
6062
|
+
seenLogs.add(key);
|
|
6063
|
+
logger(`[${entry.timestamp}] ${entry.message}`);
|
|
6064
|
+
}
|
|
6065
|
+
}
|
|
6066
|
+
async function waitForBackgroundRequest(apiClient, requestId, logger) {
|
|
6067
|
+
const seenLogs = /* @__PURE__ */ new Set();
|
|
6068
|
+
const resultUrl = apiClient.resolveUrl(
|
|
6069
|
+
`/auth/v1/background-requests/${encodeURIComponent(requestId)}`
|
|
6070
|
+
);
|
|
6071
|
+
while (true) {
|
|
6072
|
+
await emitBackgroundLogs(apiClient, requestId, logger, seenLogs);
|
|
6073
|
+
const response = await apiClient.fetch(resultUrl, { method: "GET" });
|
|
6074
|
+
if (response.status === 202) {
|
|
6075
|
+
await delay(DEFAULT_BACKGROUND_POLL_INTERVAL_MS);
|
|
6076
|
+
continue;
|
|
6077
|
+
}
|
|
6078
|
+
if (!response.ok) {
|
|
6079
|
+
const message = await readResponseError(
|
|
6080
|
+
response,
|
|
6081
|
+
`Background request ${requestId} failed`
|
|
6082
|
+
);
|
|
6083
|
+
throw new Error(message);
|
|
6084
|
+
}
|
|
6085
|
+
return parseJsonResponse(response);
|
|
6086
|
+
}
|
|
6087
|
+
}
|
|
6088
|
+
async function postWithBackgroundLogger(apiClient, path, options, logger) {
|
|
6089
|
+
const response = await apiClient.postRaw(path, {
|
|
6090
|
+
...options,
|
|
6091
|
+
headers: logger ? {
|
|
6092
|
+
...options.headers ?? {},
|
|
6093
|
+
[BACKGROUND_AFTER_SECS_HEADER]: String(DEFAULT_BACKGROUND_AFTER_SECS)
|
|
6094
|
+
} : options.headers
|
|
6095
|
+
});
|
|
6096
|
+
if (response.status !== 202 || !logger) {
|
|
6097
|
+
return parseJsonResponse(response);
|
|
6098
|
+
}
|
|
6099
|
+
const accepted = await parseJsonResponse(
|
|
6100
|
+
response
|
|
6101
|
+
);
|
|
6102
|
+
const requestId = extractBackgroundRequestId(response, accepted);
|
|
6103
|
+
if (!requestId) {
|
|
6104
|
+
throw new Error(
|
|
6105
|
+
`Background request response for ${path} did not include a request ID`
|
|
6106
|
+
);
|
|
6107
|
+
}
|
|
6108
|
+
return waitForBackgroundRequest(apiClient, requestId, logger);
|
|
6109
|
+
}
|
|
6014
6110
|
function escapeRegExp(value) {
|
|
6015
6111
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6016
6112
|
}
|
|
@@ -6392,9 +6488,9 @@ class Vm {
|
|
|
6392
6488
|
ref({ vmId }) {
|
|
6393
6489
|
return new Vm({ vmId, freestyle: this._freestyle });
|
|
6394
6490
|
}
|
|
6395
|
-
async delete(
|
|
6491
|
+
async delete() {
|
|
6396
6492
|
return this.apiClient.delete("/v1/vms/{vm_id}", {
|
|
6397
|
-
params: { vm_id: vmId }
|
|
6493
|
+
params: { vm_id: this.vmId }
|
|
6398
6494
|
});
|
|
6399
6495
|
}
|
|
6400
6496
|
}
|
|
@@ -6884,9 +6980,15 @@ class VmsNamespace {
|
|
|
6884
6980
|
}
|
|
6885
6981
|
snapshots;
|
|
6886
6982
|
async create(options = {}) {
|
|
6983
|
+
let logger;
|
|
6887
6984
|
if (isVmSpecLike$1(options)) {
|
|
6888
6985
|
options = { spec: cloneVmSpecTree(options) };
|
|
6889
6986
|
} else {
|
|
6987
|
+
logger = options.logger;
|
|
6988
|
+
if ("logger" in options) {
|
|
6989
|
+
const { logger: _logger, ...rest } = options;
|
|
6990
|
+
options = rest;
|
|
6991
|
+
}
|
|
6890
6992
|
if (isVmSpecLike$1(options.spec)) {
|
|
6891
6993
|
options.spec = cloneVmSpecTree(options.spec);
|
|
6892
6994
|
}
|
|
@@ -6966,7 +7068,8 @@ class VmsNamespace {
|
|
|
6966
7068
|
if (isVmTemplateLike$1(config.template)) {
|
|
6967
7069
|
config.template = await ensureNestedTemplates(
|
|
6968
7070
|
config.template,
|
|
6969
|
-
this.snapshots
|
|
7071
|
+
this.snapshots,
|
|
7072
|
+
logger
|
|
6970
7073
|
);
|
|
6971
7074
|
}
|
|
6972
7075
|
const keys = Object.keys(builders);
|
|
@@ -7007,27 +7110,24 @@ class VmsNamespace {
|
|
|
7007
7110
|
template: _template,
|
|
7008
7111
|
...requestConfig
|
|
7009
7112
|
} = config;
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
}).catch((e) => {
|
|
7026
|
-
if (slowPathTimeout) clearTimeout(slowPathTimeout);
|
|
7113
|
+
const response = await postWithBackgroundLogger(
|
|
7114
|
+
this.freestyle._apiClient,
|
|
7115
|
+
"/v1/vms",
|
|
7116
|
+
{
|
|
7117
|
+
body: {
|
|
7118
|
+
...requestConfig,
|
|
7119
|
+
template: normalizedRequestTemplate,
|
|
7120
|
+
// Cast systemd since we've processed SystemdServiceInput[] to RawSystemdService[]
|
|
7121
|
+
systemd: config.systemd,
|
|
7122
|
+
// Normalize git options - default config to {}
|
|
7123
|
+
git: normalizeGitOptions(config.git)
|
|
7124
|
+
}
|
|
7125
|
+
},
|
|
7126
|
+
logger
|
|
7127
|
+
).catch((e) => {
|
|
7027
7128
|
enhanceError(e);
|
|
7028
7129
|
throw e;
|
|
7029
7130
|
});
|
|
7030
|
-
if (slowPathTimeout) clearTimeout(slowPathTimeout);
|
|
7031
7131
|
const vmId = response.id;
|
|
7032
7132
|
const vm = new Vm({ vmId, freestyle: this.freestyle });
|
|
7033
7133
|
for (const key in builders) {
|
|
@@ -7180,11 +7280,12 @@ class VmSnapshotsNamespace {
|
|
|
7180
7280
|
this.apiClient = apiClient;
|
|
7181
7281
|
}
|
|
7182
7282
|
async ensure(options) {
|
|
7283
|
+
const { logger, ...restOptions } = options;
|
|
7183
7284
|
let requestOptions = {
|
|
7184
|
-
...
|
|
7185
|
-
spec: isVmSpecLike$1(
|
|
7186
|
-
snapshot: isVmSpecLike$1(
|
|
7187
|
-
template: isVmTemplateLike$1(
|
|
7285
|
+
...restOptions,
|
|
7286
|
+
spec: isVmSpecLike$1(restOptions.spec) ? cloneVmSpecTree(restOptions.spec) : void 0,
|
|
7287
|
+
snapshot: isVmSpecLike$1(restOptions.snapshot) ? cloneVmSpecTree(restOptions.snapshot) : void 0,
|
|
7288
|
+
template: isVmTemplateLike$1(restOptions.template) ? cloneVmTemplateTree(restOptions.template) : restOptions.template
|
|
7188
7289
|
};
|
|
7189
7290
|
if (isVmSpecLike$1(requestOptions.snapshot)) {
|
|
7190
7291
|
if (isVmSpecLike$1(requestOptions.spec)) {
|
|
@@ -7222,7 +7323,8 @@ class VmSnapshotsNamespace {
|
|
|
7222
7323
|
if (isVmTemplateLike$1(processedTemplate.raw.template)) {
|
|
7223
7324
|
requestOptions.template = await ensureNestedTemplates(
|
|
7224
7325
|
processedTemplate,
|
|
7225
|
-
this
|
|
7326
|
+
this,
|
|
7327
|
+
logger
|
|
7226
7328
|
);
|
|
7227
7329
|
}
|
|
7228
7330
|
}
|
|
@@ -7231,27 +7333,43 @@ class VmSnapshotsNamespace {
|
|
|
7231
7333
|
"snapshots.ensure requires a template or spec to build a snapshot"
|
|
7232
7334
|
);
|
|
7233
7335
|
}
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
);
|
|
7248
|
-
}
|
|
7249
|
-
return response;
|
|
7250
|
-
}).catch((e) => {
|
|
7336
|
+
return postWithBackgroundLogger(
|
|
7337
|
+
this.apiClient,
|
|
7338
|
+
"/v1/vms/snapshots",
|
|
7339
|
+
{
|
|
7340
|
+
body: {
|
|
7341
|
+
...requestOptions,
|
|
7342
|
+
template: normalizeTemplateForRequest(
|
|
7343
|
+
isVmTemplateLike$1(requestOptions.template) ? requestOptions.template.raw : requestOptions.template
|
|
7344
|
+
)
|
|
7345
|
+
}
|
|
7346
|
+
},
|
|
7347
|
+
logger
|
|
7348
|
+
).catch((e) => {
|
|
7251
7349
|
enhanceError(e);
|
|
7252
7350
|
throw e;
|
|
7253
7351
|
});
|
|
7254
7352
|
}
|
|
7353
|
+
async create(options) {
|
|
7354
|
+
return this.ensure(options);
|
|
7355
|
+
}
|
|
7356
|
+
async delete({ snapshotId }) {
|
|
7357
|
+
const path = "/v1/vms/snapshots/{snapshot_id}";
|
|
7358
|
+
const response = await this.apiClient.fetch(
|
|
7359
|
+
this.apiClient.resolveUrl(path, { snapshot_id: snapshotId }),
|
|
7360
|
+
{ method: "DELETE" }
|
|
7361
|
+
);
|
|
7362
|
+
if (!response.ok) {
|
|
7363
|
+
const errorBody = await response.json().catch(() => null);
|
|
7364
|
+
if (errorBody?.code) {
|
|
7365
|
+
throw errorFromJSON(errorBody);
|
|
7366
|
+
}
|
|
7367
|
+
throw new Error(
|
|
7368
|
+
`Failed to delete snapshot: ${response.status} ${response.statusText}`
|
|
7369
|
+
);
|
|
7370
|
+
}
|
|
7371
|
+
return await response.json();
|
|
7372
|
+
}
|
|
7255
7373
|
}
|
|
7256
7374
|
async function processTemplateTree(template) {
|
|
7257
7375
|
if (template.raw.baseImage) {
|
|
@@ -7323,24 +7441,24 @@ async function processTemplateTree(template) {
|
|
|
7323
7441
|
}
|
|
7324
7442
|
return template;
|
|
7325
7443
|
}
|
|
7326
|
-
async function ensureNestedTemplates(template, snapshots) {
|
|
7444
|
+
async function ensureNestedTemplates(template, snapshots, logger) {
|
|
7327
7445
|
const templates = [template];
|
|
7328
7446
|
while (isVmTemplateLike$1(templates.at(-1)?.raw.template)) {
|
|
7329
7447
|
const innerTemplate = templates.at(-1).raw.template;
|
|
7330
7448
|
templates.at(-1).raw.template = void 0;
|
|
7331
7449
|
templates.push(innerTemplate);
|
|
7332
7450
|
}
|
|
7333
|
-
return await layerTemplates(templates, snapshots);
|
|
7451
|
+
return await layerTemplates(templates, snapshots, logger);
|
|
7334
7452
|
}
|
|
7335
|
-
async function layerTemplates(templates, snapshots) {
|
|
7453
|
+
async function layerTemplates(templates, snapshots, logger) {
|
|
7336
7454
|
if (templates.length === 1) {
|
|
7337
7455
|
return templates[0];
|
|
7338
7456
|
}
|
|
7339
|
-
let lastSnapshotId = (await snapshots.ensure({ template: templates.pop() })).snapshotId;
|
|
7457
|
+
let lastSnapshotId = (await snapshots.ensure({ template: templates.pop(), logger })).snapshotId;
|
|
7340
7458
|
while (templates.length > 1) {
|
|
7341
7459
|
const template = templates.pop();
|
|
7342
7460
|
template.raw.snapshotId = lastSnapshotId;
|
|
7343
|
-
lastSnapshotId = (await snapshots.ensure({ template })).snapshotId;
|
|
7461
|
+
lastSnapshotId = (await snapshots.ensure({ template, logger })).snapshotId;
|
|
7344
7462
|
}
|
|
7345
7463
|
const outermost = templates.pop();
|
|
7346
7464
|
outermost.raw.snapshotId = lastSnapshotId;
|