@declaw/sdk 1.4.0 → 1.5.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.
- package/CHANGELOG.md +36 -0
- package/dist/index.cjs +174 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -10
- package/dist/index.d.ts +45 -10
- package/dist/index.js +174 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1639,9 +1639,15 @@ declare class TemplateError extends SandboxError {
|
|
|
1639
1639
|
}
|
|
1640
1640
|
/** Thrown when a template build fails. */
|
|
1641
1641
|
declare class BuildError extends TemplateError {
|
|
1642
|
+
/** The failed build's ID, when the error comes from a build that ran (`Template.build`). */
|
|
1643
|
+
buildId?: string;
|
|
1644
|
+
/** The failed build's full output, when the error comes from a build that ran. */
|
|
1645
|
+
logs: string[];
|
|
1642
1646
|
constructor(message: string, opts?: {
|
|
1643
1647
|
sandboxId?: string;
|
|
1644
1648
|
code?: string;
|
|
1649
|
+
buildId?: string;
|
|
1650
|
+
logs?: string[];
|
|
1645
1651
|
});
|
|
1646
1652
|
}
|
|
1647
1653
|
/** Thrown when a file upload fails. */
|
|
@@ -1769,7 +1775,13 @@ declare class TemplateBase {
|
|
|
1769
1775
|
fromDockerfile(content: string): this;
|
|
1770
1776
|
/** Add a run command (as array of command + args). */
|
|
1771
1777
|
runCmd(cmds: string[]): this;
|
|
1772
|
-
/**
|
|
1778
|
+
/**
|
|
1779
|
+
* Copy a local file into the template.
|
|
1780
|
+
*
|
|
1781
|
+
* Not supported yet: a template build cannot upload local files, so
|
|
1782
|
+
* building a template that uses `copy()` throws `InvalidArgumentError`.
|
|
1783
|
+
* Fetch the file in a `runCmd` step, or use `fromDockerfile`.
|
|
1784
|
+
*/
|
|
1773
1785
|
copy(src: string, dst: string, mode?: number): this;
|
|
1774
1786
|
/** Set environment variables. */
|
|
1775
1787
|
setEnvs(envs: Record<string, string>): this;
|
|
@@ -1777,22 +1789,37 @@ declare class TemplateBase {
|
|
|
1777
1789
|
aptInstall(...packages: string[]): this;
|
|
1778
1790
|
/** Set the start command. */
|
|
1779
1791
|
setStartCmd(cmd: string): this;
|
|
1792
|
+
/**
|
|
1793
|
+
* Whether `copy()` was used. Builds reject such a template until builds can
|
|
1794
|
+
* upload local files.
|
|
1795
|
+
* @internal
|
|
1796
|
+
*/
|
|
1797
|
+
hasCopies(): boolean;
|
|
1780
1798
|
/** Serialize the template to a JSON-friendly object. */
|
|
1781
1799
|
toJSON(): Record<string, any>;
|
|
1782
1800
|
}
|
|
1783
1801
|
/** Information about a template build. */
|
|
1784
1802
|
interface BuildInfo {
|
|
1785
1803
|
buildId: string;
|
|
1804
|
+
/** `building`, then `completed` or `failed`. */
|
|
1786
1805
|
status: string;
|
|
1787
1806
|
templateId?: string;
|
|
1807
|
+
/**
|
|
1808
|
+
* Build output. Empty in the response to starting a build; filled when
|
|
1809
|
+
* `Template.build()` returns a finished build.
|
|
1810
|
+
*/
|
|
1811
|
+
logs: string[];
|
|
1788
1812
|
}
|
|
1789
1813
|
/** Parse raw JSON data into BuildInfo. */
|
|
1790
1814
|
declare function parseBuildInfo(data: Record<string, any>): BuildInfo;
|
|
1791
1815
|
/** Status of a template build. */
|
|
1792
1816
|
interface TemplateBuildStatus {
|
|
1793
1817
|
buildId: string;
|
|
1818
|
+
/** `building`, then `completed` or `failed`. */
|
|
1794
1819
|
status: string;
|
|
1820
|
+
/** Build output so far. */
|
|
1795
1821
|
logs: string[];
|
|
1822
|
+
templateId?: string;
|
|
1796
1823
|
}
|
|
1797
1824
|
/** Parse raw JSON data into TemplateBuildStatus. */
|
|
1798
1825
|
declare function parseTemplateBuildStatus(data: Record<string, any>): TemplateBuildStatus;
|
|
@@ -1805,8 +1832,10 @@ interface TemplateBuildOpts {
|
|
|
1805
1832
|
memoryMb?: number;
|
|
1806
1833
|
/** Disk size in MB for the build (128–102400). */
|
|
1807
1834
|
diskMb?: number;
|
|
1808
|
-
/**
|
|
1835
|
+
/** Called with each new line of build output while `build()` waits. */
|
|
1809
1836
|
onBuildLogs?: (log: string) => void;
|
|
1837
|
+
/** How long `build()` waits for the build to finish, in milliseconds. Defaults to one hour. */
|
|
1838
|
+
buildTimeout?: number;
|
|
1810
1839
|
/** API key override. */
|
|
1811
1840
|
apiKey?: string;
|
|
1812
1841
|
/** Domain override. */
|
|
@@ -1831,20 +1860,26 @@ interface GetBuildStatusOpts {
|
|
|
1831
1860
|
*/
|
|
1832
1861
|
declare class Template {
|
|
1833
1862
|
/**
|
|
1834
|
-
* Build a template and wait for
|
|
1863
|
+
* Build a template and wait for the build to finish.
|
|
1864
|
+
*
|
|
1865
|
+
* Builds usually take several minutes. While waiting, each new line of build
|
|
1866
|
+
* output is passed to `onBuildLogs`. Sandboxes are created from the finished
|
|
1867
|
+
* template by its alias: `Sandbox.create({ template: alias })`.
|
|
1835
1868
|
*
|
|
1836
|
-
*
|
|
1837
|
-
*
|
|
1869
|
+
* @throws {BuildError} The build failed; the error carries its logs.
|
|
1870
|
+
* @throws {TimeoutError} The build was still running after `buildTimeout`.
|
|
1871
|
+
* It keeps running; follow it with `getBuildStatus()`.
|
|
1872
|
+
* @throws {InvalidArgumentError} The template uses `copy()`, which is not
|
|
1873
|
+
* supported yet.
|
|
1838
1874
|
*/
|
|
1839
1875
|
static build(template: TemplateBase, alias: string, opts?: TemplateBuildOpts): Promise<BuildInfo>;
|
|
1840
1876
|
/**
|
|
1841
|
-
* Start a template build
|
|
1842
|
-
*
|
|
1843
|
-
* Sends POST /templates/build with `background: true`.
|
|
1877
|
+
* Start a template build and return as soon as the server has accepted it,
|
|
1878
|
+
* with status `building`. Follow the build with `getBuildStatus()`.
|
|
1844
1879
|
*/
|
|
1845
|
-
static buildInBackground(template: TemplateBase, alias: string, opts?: Omit<TemplateBuildOpts, 'onBuildLogs'>): Promise<BuildInfo>;
|
|
1880
|
+
static buildInBackground(template: TemplateBase, alias: string, opts?: Omit<TemplateBuildOpts, 'onBuildLogs' | 'buildTimeout'>): Promise<BuildInfo>;
|
|
1846
1881
|
/**
|
|
1847
|
-
* Get the status of a template build.
|
|
1882
|
+
* Get the status of a template build, including its logs so far.
|
|
1848
1883
|
*
|
|
1849
1884
|
* Sends GET /templates/builds/:buildId.
|
|
1850
1885
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1639,9 +1639,15 @@ declare class TemplateError extends SandboxError {
|
|
|
1639
1639
|
}
|
|
1640
1640
|
/** Thrown when a template build fails. */
|
|
1641
1641
|
declare class BuildError extends TemplateError {
|
|
1642
|
+
/** The failed build's ID, when the error comes from a build that ran (`Template.build`). */
|
|
1643
|
+
buildId?: string;
|
|
1644
|
+
/** The failed build's full output, when the error comes from a build that ran. */
|
|
1645
|
+
logs: string[];
|
|
1642
1646
|
constructor(message: string, opts?: {
|
|
1643
1647
|
sandboxId?: string;
|
|
1644
1648
|
code?: string;
|
|
1649
|
+
buildId?: string;
|
|
1650
|
+
logs?: string[];
|
|
1645
1651
|
});
|
|
1646
1652
|
}
|
|
1647
1653
|
/** Thrown when a file upload fails. */
|
|
@@ -1769,7 +1775,13 @@ declare class TemplateBase {
|
|
|
1769
1775
|
fromDockerfile(content: string): this;
|
|
1770
1776
|
/** Add a run command (as array of command + args). */
|
|
1771
1777
|
runCmd(cmds: string[]): this;
|
|
1772
|
-
/**
|
|
1778
|
+
/**
|
|
1779
|
+
* Copy a local file into the template.
|
|
1780
|
+
*
|
|
1781
|
+
* Not supported yet: a template build cannot upload local files, so
|
|
1782
|
+
* building a template that uses `copy()` throws `InvalidArgumentError`.
|
|
1783
|
+
* Fetch the file in a `runCmd` step, or use `fromDockerfile`.
|
|
1784
|
+
*/
|
|
1773
1785
|
copy(src: string, dst: string, mode?: number): this;
|
|
1774
1786
|
/** Set environment variables. */
|
|
1775
1787
|
setEnvs(envs: Record<string, string>): this;
|
|
@@ -1777,22 +1789,37 @@ declare class TemplateBase {
|
|
|
1777
1789
|
aptInstall(...packages: string[]): this;
|
|
1778
1790
|
/** Set the start command. */
|
|
1779
1791
|
setStartCmd(cmd: string): this;
|
|
1792
|
+
/**
|
|
1793
|
+
* Whether `copy()` was used. Builds reject such a template until builds can
|
|
1794
|
+
* upload local files.
|
|
1795
|
+
* @internal
|
|
1796
|
+
*/
|
|
1797
|
+
hasCopies(): boolean;
|
|
1780
1798
|
/** Serialize the template to a JSON-friendly object. */
|
|
1781
1799
|
toJSON(): Record<string, any>;
|
|
1782
1800
|
}
|
|
1783
1801
|
/** Information about a template build. */
|
|
1784
1802
|
interface BuildInfo {
|
|
1785
1803
|
buildId: string;
|
|
1804
|
+
/** `building`, then `completed` or `failed`. */
|
|
1786
1805
|
status: string;
|
|
1787
1806
|
templateId?: string;
|
|
1807
|
+
/**
|
|
1808
|
+
* Build output. Empty in the response to starting a build; filled when
|
|
1809
|
+
* `Template.build()` returns a finished build.
|
|
1810
|
+
*/
|
|
1811
|
+
logs: string[];
|
|
1788
1812
|
}
|
|
1789
1813
|
/** Parse raw JSON data into BuildInfo. */
|
|
1790
1814
|
declare function parseBuildInfo(data: Record<string, any>): BuildInfo;
|
|
1791
1815
|
/** Status of a template build. */
|
|
1792
1816
|
interface TemplateBuildStatus {
|
|
1793
1817
|
buildId: string;
|
|
1818
|
+
/** `building`, then `completed` or `failed`. */
|
|
1794
1819
|
status: string;
|
|
1820
|
+
/** Build output so far. */
|
|
1795
1821
|
logs: string[];
|
|
1822
|
+
templateId?: string;
|
|
1796
1823
|
}
|
|
1797
1824
|
/** Parse raw JSON data into TemplateBuildStatus. */
|
|
1798
1825
|
declare function parseTemplateBuildStatus(data: Record<string, any>): TemplateBuildStatus;
|
|
@@ -1805,8 +1832,10 @@ interface TemplateBuildOpts {
|
|
|
1805
1832
|
memoryMb?: number;
|
|
1806
1833
|
/** Disk size in MB for the build (128–102400). */
|
|
1807
1834
|
diskMb?: number;
|
|
1808
|
-
/**
|
|
1835
|
+
/** Called with each new line of build output while `build()` waits. */
|
|
1809
1836
|
onBuildLogs?: (log: string) => void;
|
|
1837
|
+
/** How long `build()` waits for the build to finish, in milliseconds. Defaults to one hour. */
|
|
1838
|
+
buildTimeout?: number;
|
|
1810
1839
|
/** API key override. */
|
|
1811
1840
|
apiKey?: string;
|
|
1812
1841
|
/** Domain override. */
|
|
@@ -1831,20 +1860,26 @@ interface GetBuildStatusOpts {
|
|
|
1831
1860
|
*/
|
|
1832
1861
|
declare class Template {
|
|
1833
1862
|
/**
|
|
1834
|
-
* Build a template and wait for
|
|
1863
|
+
* Build a template and wait for the build to finish.
|
|
1864
|
+
*
|
|
1865
|
+
* Builds usually take several minutes. While waiting, each new line of build
|
|
1866
|
+
* output is passed to `onBuildLogs`. Sandboxes are created from the finished
|
|
1867
|
+
* template by its alias: `Sandbox.create({ template: alias })`.
|
|
1835
1868
|
*
|
|
1836
|
-
*
|
|
1837
|
-
*
|
|
1869
|
+
* @throws {BuildError} The build failed; the error carries its logs.
|
|
1870
|
+
* @throws {TimeoutError} The build was still running after `buildTimeout`.
|
|
1871
|
+
* It keeps running; follow it with `getBuildStatus()`.
|
|
1872
|
+
* @throws {InvalidArgumentError} The template uses `copy()`, which is not
|
|
1873
|
+
* supported yet.
|
|
1838
1874
|
*/
|
|
1839
1875
|
static build(template: TemplateBase, alias: string, opts?: TemplateBuildOpts): Promise<BuildInfo>;
|
|
1840
1876
|
/**
|
|
1841
|
-
* Start a template build
|
|
1842
|
-
*
|
|
1843
|
-
* Sends POST /templates/build with `background: true`.
|
|
1877
|
+
* Start a template build and return as soon as the server has accepted it,
|
|
1878
|
+
* with status `building`. Follow the build with `getBuildStatus()`.
|
|
1844
1879
|
*/
|
|
1845
|
-
static buildInBackground(template: TemplateBase, alias: string, opts?: Omit<TemplateBuildOpts, 'onBuildLogs'>): Promise<BuildInfo>;
|
|
1880
|
+
static buildInBackground(template: TemplateBase, alias: string, opts?: Omit<TemplateBuildOpts, 'onBuildLogs' | 'buildTimeout'>): Promise<BuildInfo>;
|
|
1846
1881
|
/**
|
|
1847
|
-
* Get the status of a template build.
|
|
1882
|
+
* Get the status of a template build, including its logs so far.
|
|
1848
1883
|
*
|
|
1849
1884
|
* Sends GET /templates/builds/:buildId.
|
|
1850
1885
|
*/
|
package/dist/index.js
CHANGED
|
@@ -123,9 +123,15 @@ var TemplateError = class extends SandboxError {
|
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
125
|
var BuildError = class extends TemplateError {
|
|
126
|
+
/** The failed build's ID, when the error comes from a build that ran (`Template.build`). */
|
|
127
|
+
buildId;
|
|
128
|
+
/** The failed build's full output, when the error comes from a build that ran. */
|
|
129
|
+
logs;
|
|
126
130
|
constructor(message, opts) {
|
|
127
131
|
super(message, opts);
|
|
128
132
|
this.name = "BuildError";
|
|
133
|
+
this.buildId = opts?.buildId;
|
|
134
|
+
this.logs = opts?.logs ?? [];
|
|
129
135
|
}
|
|
130
136
|
};
|
|
131
137
|
var FileUploadError = class extends SandboxError {
|
|
@@ -3108,7 +3114,13 @@ var TemplateBase = class {
|
|
|
3108
3114
|
this._runCmds.push(cmds);
|
|
3109
3115
|
return this;
|
|
3110
3116
|
}
|
|
3111
|
-
/**
|
|
3117
|
+
/**
|
|
3118
|
+
* Copy a local file into the template.
|
|
3119
|
+
*
|
|
3120
|
+
* Not supported yet: a template build cannot upload local files, so
|
|
3121
|
+
* building a template that uses `copy()` throws `InvalidArgumentError`.
|
|
3122
|
+
* Fetch the file in a `runCmd` step, or use `fromDockerfile`.
|
|
3123
|
+
*/
|
|
3112
3124
|
copy(src, dst, mode) {
|
|
3113
3125
|
this._copies.push({ src, dst, mode });
|
|
3114
3126
|
return this;
|
|
@@ -3128,6 +3140,14 @@ var TemplateBase = class {
|
|
|
3128
3140
|
this._startCmd = cmd;
|
|
3129
3141
|
return this;
|
|
3130
3142
|
}
|
|
3143
|
+
/**
|
|
3144
|
+
* Whether `copy()` was used. Builds reject such a template until builds can
|
|
3145
|
+
* upload local files.
|
|
3146
|
+
* @internal
|
|
3147
|
+
*/
|
|
3148
|
+
hasCopies() {
|
|
3149
|
+
return this._copies.length > 0;
|
|
3150
|
+
}
|
|
3131
3151
|
/** Serialize the template to a JSON-friendly object. */
|
|
3132
3152
|
toJSON() {
|
|
3133
3153
|
if (this._dockerfile !== void 0) {
|
|
@@ -3139,14 +3159,11 @@ var TemplateBase = class {
|
|
|
3139
3159
|
if (this._runCmds.length > 0) {
|
|
3140
3160
|
result.run_cmds = this._runCmds.map((c) => c.join(" "));
|
|
3141
3161
|
}
|
|
3142
|
-
if (this._copies.length > 0) {
|
|
3143
|
-
result.copies = this._copies;
|
|
3144
|
-
}
|
|
3145
3162
|
if (Object.keys(this._envs).length > 0) {
|
|
3146
3163
|
result.envs = this._envs;
|
|
3147
3164
|
}
|
|
3148
3165
|
if (this._aptPackages.length > 0) {
|
|
3149
|
-
result.
|
|
3166
|
+
result.packages = this._aptPackages;
|
|
3150
3167
|
}
|
|
3151
3168
|
if (this._startCmd !== void 0) {
|
|
3152
3169
|
result.start_cmd = this._startCmd;
|
|
@@ -3158,19 +3175,70 @@ function parseBuildInfo(data) {
|
|
|
3158
3175
|
return {
|
|
3159
3176
|
buildId: data.build_id ?? data.buildId ?? "",
|
|
3160
3177
|
status: data.status ?? "",
|
|
3161
|
-
templateId: data.template_id ?? data.templateId ?? void 0
|
|
3178
|
+
templateId: data.template_id ?? data.templateId ?? void 0,
|
|
3179
|
+
logs: data.logs ?? []
|
|
3162
3180
|
};
|
|
3163
3181
|
}
|
|
3164
3182
|
function parseTemplateBuildStatus(data) {
|
|
3165
3183
|
return {
|
|
3166
3184
|
buildId: data.build_id ?? data.buildId ?? "",
|
|
3167
3185
|
status: data.status ?? "",
|
|
3168
|
-
|
|
3186
|
+
// A build with no output yet serializes its logs as null.
|
|
3187
|
+
logs: data.logs ?? [],
|
|
3188
|
+
templateId: data.template_id ?? data.templateId ?? void 0
|
|
3169
3189
|
};
|
|
3170
3190
|
}
|
|
3171
3191
|
|
|
3172
3192
|
// src/template/template.ts
|
|
3173
3193
|
var VALID_BUILD_ID_RE = /^[a-zA-Z0-9_-]+$/;
|
|
3194
|
+
var BUILD_STATUS_COMPLETED = "completed";
|
|
3195
|
+
var BUILD_STATUS_FAILED = "failed";
|
|
3196
|
+
var DEFAULT_BUILD_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
3197
|
+
var FAILURE_LOG_LINES = 20;
|
|
3198
|
+
var buildPolling = {
|
|
3199
|
+
/** How often a waiting build is re-read. */
|
|
3200
|
+
intervalMs: 3e3,
|
|
3201
|
+
/**
|
|
3202
|
+
* How long status checks may keep failing temporarily (5xx, 408, 429, or no
|
|
3203
|
+
* response) before the wait gives up. It rides out a sandbox-manager
|
|
3204
|
+
* restart; the build itself keeps running.
|
|
3205
|
+
*/
|
|
3206
|
+
errorWindowMs: 2 * 60 * 1e3
|
|
3207
|
+
};
|
|
3208
|
+
var BUILD_LOG_TRUNCATION_NOTICE = "... [earlier build output truncated]";
|
|
3209
|
+
var LOG_ANCHOR_LINES = 64;
|
|
3210
|
+
var REJECTIONS = [
|
|
3211
|
+
AuthenticationError,
|
|
3212
|
+
ConflictError,
|
|
3213
|
+
InvalidArgumentError,
|
|
3214
|
+
NotEnoughSpaceError,
|
|
3215
|
+
NotFoundError
|
|
3216
|
+
];
|
|
3217
|
+
var LogCursor = class {
|
|
3218
|
+
seen = 0;
|
|
3219
|
+
tail = [];
|
|
3220
|
+
newLines(logs) {
|
|
3221
|
+
const fresh = logs.length === 0 || logs[0] !== BUILD_LOG_TRUNCATION_NOTICE ? logs.slice(this.seen) : this.afterTail(logs);
|
|
3222
|
+
this.seen = logs.length;
|
|
3223
|
+
this.tail = [...this.tail, ...fresh].slice(-LOG_ANCHOR_LINES);
|
|
3224
|
+
return fresh;
|
|
3225
|
+
}
|
|
3226
|
+
afterTail(logs) {
|
|
3227
|
+
const window = logs.slice(1);
|
|
3228
|
+
const n = this.tail.length;
|
|
3229
|
+
if (n > 0) {
|
|
3230
|
+
for (let end = window.length; end >= n; end--) {
|
|
3231
|
+
if (window[end - 1] === this.tail[n - 1] && this.tail.every((line, i) => window[end - n + i] === line)) {
|
|
3232
|
+
return window.slice(end);
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
return logs;
|
|
3237
|
+
}
|
|
3238
|
+
};
|
|
3239
|
+
function isTemporaryPollError(err) {
|
|
3240
|
+
return err instanceof SandboxError && !REJECTIONS.some((Rejection) => err instanceof Rejection);
|
|
3241
|
+
}
|
|
3174
3242
|
function assertValidBuildId(buildId) {
|
|
3175
3243
|
if (!buildId || !VALID_BUILD_ID_RE.test(buildId)) {
|
|
3176
3244
|
throw new InvalidArgumentError(
|
|
@@ -3178,72 +3246,131 @@ function assertValidBuildId(buildId) {
|
|
|
3178
3246
|
);
|
|
3179
3247
|
}
|
|
3180
3248
|
}
|
|
3249
|
+
function buildRequestBody(template, alias, opts) {
|
|
3250
|
+
if (template.hasCopies()) {
|
|
3251
|
+
throw new InvalidArgumentError(
|
|
3252
|
+
"TemplateBase.copy() is not supported yet: a template build cannot upload local files. Fetch them in a runCmd step, or use fromDockerfile()."
|
|
3253
|
+
);
|
|
3254
|
+
}
|
|
3255
|
+
const body = {
|
|
3256
|
+
template: template.toJSON(),
|
|
3257
|
+
alias
|
|
3258
|
+
};
|
|
3259
|
+
if (opts?.cpuCount !== void 0) {
|
|
3260
|
+
body.cpu_count = opts.cpuCount;
|
|
3261
|
+
}
|
|
3262
|
+
if (opts?.memoryMb !== void 0) {
|
|
3263
|
+
body.memory_mb = opts.memoryMb;
|
|
3264
|
+
}
|
|
3265
|
+
if (opts?.diskMb !== void 0) {
|
|
3266
|
+
body.disk_mb = opts.diskMb;
|
|
3267
|
+
}
|
|
3268
|
+
return body;
|
|
3269
|
+
}
|
|
3270
|
+
function buildFailedError(status) {
|
|
3271
|
+
let message = `template build ${status.buildId} failed`;
|
|
3272
|
+
const tail = status.logs.slice(-FAILURE_LOG_LINES);
|
|
3273
|
+
if (tail.length > 0) {
|
|
3274
|
+
message += ":\n" + tail.join("\n");
|
|
3275
|
+
}
|
|
3276
|
+
return new BuildError(message, { buildId: status.buildId, logs: status.logs });
|
|
3277
|
+
}
|
|
3181
3278
|
var Template = class {
|
|
3182
3279
|
/**
|
|
3183
|
-
* Build a template and wait for
|
|
3280
|
+
* Build a template and wait for the build to finish.
|
|
3184
3281
|
*
|
|
3185
|
-
*
|
|
3186
|
-
*
|
|
3282
|
+
* Builds usually take several minutes. While waiting, each new line of build
|
|
3283
|
+
* output is passed to `onBuildLogs`. Sandboxes are created from the finished
|
|
3284
|
+
* template by its alias: `Sandbox.create({ template: alias })`.
|
|
3285
|
+
*
|
|
3286
|
+
* @throws {BuildError} The build failed; the error carries its logs.
|
|
3287
|
+
* @throws {TimeoutError} The build was still running after `buildTimeout`.
|
|
3288
|
+
* It keeps running; follow it with `getBuildStatus()`.
|
|
3289
|
+
* @throws {InvalidArgumentError} The template uses `copy()`, which is not
|
|
3290
|
+
* supported yet.
|
|
3187
3291
|
*/
|
|
3188
3292
|
static async build(template, alias, opts) {
|
|
3293
|
+
const body = buildRequestBody(template, alias, opts);
|
|
3189
3294
|
const config = new ConnectionConfig({
|
|
3190
3295
|
apiKey: opts?.apiKey,
|
|
3191
3296
|
domain: opts?.domain,
|
|
3192
3297
|
requestTimeout: opts?.requestTimeout
|
|
3193
3298
|
});
|
|
3194
3299
|
const client = getSharedClient(config);
|
|
3195
|
-
const body = {
|
|
3196
|
-
template: template.toJSON(),
|
|
3197
|
-
alias
|
|
3198
|
-
};
|
|
3199
|
-
if (opts?.cpuCount !== void 0) {
|
|
3200
|
-
body.cpu_count = opts.cpuCount;
|
|
3201
|
-
}
|
|
3202
|
-
if (opts?.memoryMb !== void 0) {
|
|
3203
|
-
body.memory_mb = opts.memoryMb;
|
|
3204
|
-
}
|
|
3205
|
-
if (opts?.diskMb !== void 0) {
|
|
3206
|
-
body.disk_mb = opts.diskMb;
|
|
3207
|
-
}
|
|
3208
3300
|
const data = await client.post("/templates/build", {
|
|
3209
3301
|
json: body,
|
|
3210
3302
|
timeout: opts?.requestTimeout
|
|
3211
3303
|
});
|
|
3212
|
-
const
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3304
|
+
const info = parseBuildInfo(data);
|
|
3305
|
+
assertValidBuildId(info.buildId);
|
|
3306
|
+
let status = {
|
|
3307
|
+
buildId: info.buildId,
|
|
3308
|
+
status: info.status,
|
|
3309
|
+
logs: info.logs,
|
|
3310
|
+
templateId: info.templateId
|
|
3311
|
+
};
|
|
3312
|
+
const buildTimeout = opts?.buildTimeout ?? DEFAULT_BUILD_TIMEOUT_MS;
|
|
3313
|
+
const deadline = Date.now() + buildTimeout;
|
|
3314
|
+
const timedOut = (cause) => new TimeoutError(
|
|
3315
|
+
`template build ${info.buildId} was still running after ${buildTimeout}ms. It keeps running; follow it with Template.getBuildStatus('${info.buildId}').` + (cause instanceof Error ? ` Last status check: ${cause.message}` : "")
|
|
3316
|
+
);
|
|
3317
|
+
const cursor = new LogCursor();
|
|
3318
|
+
for (; ; ) {
|
|
3319
|
+
if (opts?.onBuildLogs) {
|
|
3320
|
+
for (const line of cursor.newLines(status.logs)) {
|
|
3321
|
+
opts.onBuildLogs(line);
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
if (status.status === BUILD_STATUS_COMPLETED) {
|
|
3325
|
+
return {
|
|
3326
|
+
buildId: status.buildId,
|
|
3327
|
+
status: status.status,
|
|
3328
|
+
templateId: status.templateId ?? info.templateId,
|
|
3329
|
+
logs: status.logs
|
|
3330
|
+
};
|
|
3331
|
+
}
|
|
3332
|
+
if (status.status === BUILD_STATUS_FAILED) {
|
|
3333
|
+
throw buildFailedError(status);
|
|
3334
|
+
}
|
|
3335
|
+
if (Date.now() >= deadline) {
|
|
3336
|
+
throw timedOut();
|
|
3337
|
+
}
|
|
3338
|
+
let failingSince;
|
|
3339
|
+
for (; ; ) {
|
|
3340
|
+
await new Promise((resolve) => setTimeout(resolve, buildPolling.intervalMs));
|
|
3341
|
+
try {
|
|
3342
|
+
const next = await client.get(`/templates/builds/${info.buildId}`, {
|
|
3343
|
+
timeout: opts?.requestTimeout
|
|
3344
|
+
});
|
|
3345
|
+
status = parseTemplateBuildStatus(next);
|
|
3346
|
+
break;
|
|
3347
|
+
} catch (err) {
|
|
3348
|
+
if (!isTemporaryPollError(err)) {
|
|
3349
|
+
throw err;
|
|
3350
|
+
}
|
|
3351
|
+
failingSince ??= Date.now();
|
|
3352
|
+
if (Date.now() - failingSince >= buildPolling.errorWindowMs) {
|
|
3353
|
+
throw err;
|
|
3354
|
+
}
|
|
3355
|
+
if (Date.now() >= deadline) {
|
|
3356
|
+
throw timedOut(err);
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3217
3359
|
}
|
|
3218
3360
|
}
|
|
3219
|
-
return result;
|
|
3220
3361
|
}
|
|
3221
3362
|
/**
|
|
3222
|
-
* Start a template build
|
|
3223
|
-
*
|
|
3224
|
-
* Sends POST /templates/build with `background: true`.
|
|
3363
|
+
* Start a template build and return as soon as the server has accepted it,
|
|
3364
|
+
* with status `building`. Follow the build with `getBuildStatus()`.
|
|
3225
3365
|
*/
|
|
3226
3366
|
static async buildInBackground(template, alias, opts) {
|
|
3367
|
+
const body = buildRequestBody(template, alias, opts);
|
|
3227
3368
|
const config = new ConnectionConfig({
|
|
3228
3369
|
apiKey: opts?.apiKey,
|
|
3229
3370
|
domain: opts?.domain,
|
|
3230
3371
|
requestTimeout: opts?.requestTimeout
|
|
3231
3372
|
});
|
|
3232
3373
|
const client = getSharedClient(config);
|
|
3233
|
-
const body = {
|
|
3234
|
-
template: template.toJSON(),
|
|
3235
|
-
alias,
|
|
3236
|
-
background: true
|
|
3237
|
-
};
|
|
3238
|
-
if (opts?.cpuCount !== void 0) {
|
|
3239
|
-
body.cpu_count = opts.cpuCount;
|
|
3240
|
-
}
|
|
3241
|
-
if (opts?.memoryMb !== void 0) {
|
|
3242
|
-
body.memory_mb = opts.memoryMb;
|
|
3243
|
-
}
|
|
3244
|
-
if (opts?.diskMb !== void 0) {
|
|
3245
|
-
body.disk_mb = opts.diskMb;
|
|
3246
|
-
}
|
|
3247
3374
|
const data = await client.post("/templates/build", {
|
|
3248
3375
|
json: body,
|
|
3249
3376
|
timeout: opts?.requestTimeout
|
|
@@ -3251,7 +3378,7 @@ var Template = class {
|
|
|
3251
3378
|
return parseBuildInfo(data);
|
|
3252
3379
|
}
|
|
3253
3380
|
/**
|
|
3254
|
-
* Get the status of a template build.
|
|
3381
|
+
* Get the status of a template build, including its logs so far.
|
|
3255
3382
|
*
|
|
3256
3383
|
* Sends GET /templates/builds/:buildId.
|
|
3257
3384
|
*/
|