@declaw/sdk 1.0.3 → 1.1.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 +38 -0
- package/dist/index.cjs +121 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -2
- package/dist/index.d.ts +58 -2
- package/dist/index.js +117 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,44 @@ All notable changes to the Declaw TypeScript / JavaScript SDK are documented in
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.1.0]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Volumes API.** Upload a tarball once, attach it to one or many
|
|
13
|
+
sandboxes at create time. The server streams the blob from object
|
|
14
|
+
storage into each sandbox's overlay filesystem at boot — so N
|
|
15
|
+
parallel sandboxes share a dataset without N uploads.
|
|
16
|
+
- New `Volumes` class with static `create` / `get` / `list` /
|
|
17
|
+
`delete` methods. Body is a `Uint8Array` or `ArrayBuffer`;
|
|
18
|
+
streams end-to-end with no in-memory buffering on the server.
|
|
19
|
+
- New types: `VolumeInfo`, `VolumeAttachment`, `VolumeCreateOpts`,
|
|
20
|
+
`VolumeRequestOpts` — exported from the package root.
|
|
21
|
+
- `SandboxOpts.volumes?: VolumeAttachment[]` on `Sandbox.create` —
|
|
22
|
+
each attachment is `{ volumeId, mountPath }`. Multiple sandboxes
|
|
23
|
+
can attach the same `volumeId` in parallel.
|
|
24
|
+
- Helper functions `parseVolumeInfo` (wire → shape) and
|
|
25
|
+
`volumeAttachmentToJSON` (shape → wire).
|
|
26
|
+
- Phase 1 limits: upload body capped at 4 GiB; format must be
|
|
27
|
+
`application/gzip` (tar.gz); volumes are read-at-boot (sandbox
|
|
28
|
+
writes do not flow back). Symlinks, hardlinks, device nodes, and
|
|
29
|
+
entries containing `..` are dropped server-side for safety.
|
|
30
|
+
|
|
31
|
+
## [1.0.4]
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- `InjectionAction` — dropped the `"sanitize"` value. The server
|
|
36
|
+
never implemented request-body sanitization for detected injections
|
|
37
|
+
(the classifier returns a whole-request verdict, not span offsets),
|
|
38
|
+
so the value was accepted client-side but silently behaved like
|
|
39
|
+
`log_only` at the edge proxy. Valid values are now `"block"` and
|
|
40
|
+
`"log_only"`. Default action changes from `"sanitize"` to
|
|
41
|
+
`"log_only"` so existing enforcement behaviour is preserved.
|
|
42
|
+
Callers passing `action: "sanitize"` will now raise at construction
|
|
43
|
+
time; migrate to `"log_only"` (same behaviour) or `"block"`
|
|
44
|
+
(hard-reject on detection).
|
|
45
|
+
|
|
8
46
|
## [1.0.3]
|
|
9
47
|
|
|
10
48
|
### Added
|
package/dist/index.cjs
CHANGED
|
@@ -54,6 +54,7 @@ __export(index_exports, {
|
|
|
54
54
|
TemplateError: () => TemplateError,
|
|
55
55
|
TimeoutError: () => TimeoutError,
|
|
56
56
|
TransformDirection: () => TransformDirection,
|
|
57
|
+
Volumes: () => Volumes,
|
|
57
58
|
WatchHandle: () => WatchHandle,
|
|
58
59
|
applyTransformation: () => applyTransformation,
|
|
59
60
|
codeSecurityConfigToJSON: () => codeSecurityConfigToJSON,
|
|
@@ -92,11 +93,13 @@ __export(index_exports, {
|
|
|
92
93
|
parseSnapshotInfo: () => parseSnapshotInfo,
|
|
93
94
|
parseTemplateBuildStatus: () => parseTemplateBuildStatus,
|
|
94
95
|
parseToxicityConfig: () => parseToxicityConfig,
|
|
96
|
+
parseVolumeInfo: () => parseVolumeInfo,
|
|
95
97
|
parseWriteInfo: () => parseWriteInfo,
|
|
96
98
|
requiresTlsInterception: () => requiresTlsInterception,
|
|
97
99
|
securityPolicyToJSON: () => securityPolicyToJSON,
|
|
98
100
|
toxicityConfigToJSON: () => toxicityConfigToJSON,
|
|
99
|
-
validateNetworkEntry: () => validateNetworkEntry
|
|
101
|
+
validateNetworkEntry: () => validateNetworkEntry,
|
|
102
|
+
volumeAttachmentToJSON: () => volumeAttachmentToJSON
|
|
100
103
|
});
|
|
101
104
|
module.exports = __toCommonJS(index_exports);
|
|
102
105
|
|
|
@@ -506,7 +509,6 @@ var InjectionSensitivity = /* @__PURE__ */ ((InjectionSensitivity2) => {
|
|
|
506
509
|
})(InjectionSensitivity || {});
|
|
507
510
|
var InjectionAction = /* @__PURE__ */ ((InjectionAction2) => {
|
|
508
511
|
InjectionAction2["Block"] = "block";
|
|
509
|
-
InjectionAction2["Sanitize"] = "sanitize";
|
|
510
512
|
InjectionAction2["LogOnly"] = "log_only";
|
|
511
513
|
return InjectionAction2;
|
|
512
514
|
})(InjectionAction || {});
|
|
@@ -516,7 +518,7 @@ function createInjectionDefenseConfig(opts) {
|
|
|
516
518
|
const config = {
|
|
517
519
|
enabled: opts?.enabled ?? false,
|
|
518
520
|
sensitivity: opts?.sensitivity ?? "medium" /* Medium */,
|
|
519
|
-
action: opts?.action ?? "
|
|
521
|
+
action: opts?.action ?? "log_only" /* LogOnly */,
|
|
520
522
|
threshold: opts?.threshold ?? 0.8,
|
|
521
523
|
domains: opts?.domains
|
|
522
524
|
};
|
|
@@ -541,7 +543,7 @@ function parseInjectionDefenseConfig(data) {
|
|
|
541
543
|
return {
|
|
542
544
|
enabled: data.enabled ?? false,
|
|
543
545
|
sensitivity: data.sensitivity ?? "medium" /* Medium */,
|
|
544
|
-
action: data.action ?? "
|
|
546
|
+
action: data.action ?? "log_only" /* LogOnly */,
|
|
545
547
|
threshold: data.threshold ?? 0.8,
|
|
546
548
|
domains: data.domains
|
|
547
549
|
};
|
|
@@ -1796,6 +1798,23 @@ var Pty = class {
|
|
|
1796
1798
|
}
|
|
1797
1799
|
};
|
|
1798
1800
|
|
|
1801
|
+
// src/volumes/models.ts
|
|
1802
|
+
function parseVolumeInfo(data) {
|
|
1803
|
+
return {
|
|
1804
|
+
volumeId: String(data.volume_id ?? ""),
|
|
1805
|
+
ownerId: String(data.owner_id ?? ""),
|
|
1806
|
+
name: String(data.name ?? ""),
|
|
1807
|
+
blobKey: String(data.blob_key ?? ""),
|
|
1808
|
+
sizeBytes: Number(data.size_bytes ?? 0),
|
|
1809
|
+
contentType: String(data.content_type ?? ""),
|
|
1810
|
+
metadata: data.metadata ?? {},
|
|
1811
|
+
createdAt: String(data.created_at ?? "")
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
function volumeAttachmentToJSON(att) {
|
|
1815
|
+
return { volume_id: att.volumeId, mount_path: att.mountPath };
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1799
1818
|
// src/sandbox/sandbox.ts
|
|
1800
1819
|
var DEFAULT_TEMPLATE = "base";
|
|
1801
1820
|
var DEFAULT_TIMEOUT = 300;
|
|
@@ -1952,6 +1971,9 @@ var Sandbox = class _Sandbox {
|
|
|
1952
1971
|
if (opts?.lifecycle) {
|
|
1953
1972
|
body.lifecycle = lifecycleToJSON(opts.lifecycle);
|
|
1954
1973
|
}
|
|
1974
|
+
if (opts?.volumes && opts.volumes.length > 0) {
|
|
1975
|
+
body.volumes = opts.volumes.map(volumeAttachmentToJSON);
|
|
1976
|
+
}
|
|
1955
1977
|
const data = await client.post("/sandboxes", {
|
|
1956
1978
|
json: body,
|
|
1957
1979
|
timeout: opts?.requestTimeout
|
|
@@ -2545,6 +2567,97 @@ var Template = class {
|
|
|
2545
2567
|
}
|
|
2546
2568
|
}
|
|
2547
2569
|
};
|
|
2570
|
+
|
|
2571
|
+
// src/volumes/volumes.ts
|
|
2572
|
+
var VALID_VOLUME_ID_RE = /^[a-zA-Z0-9_-]+$/;
|
|
2573
|
+
function assertValidVolumeId(id) {
|
|
2574
|
+
if (!id || !VALID_VOLUME_ID_RE.test(id)) {
|
|
2575
|
+
throw new InvalidArgumentError(
|
|
2576
|
+
`Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
|
|
2577
|
+
);
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
var Volumes = class {
|
|
2581
|
+
/** Create a volume by streaming a tarball to the server. */
|
|
2582
|
+
static async create(name, data, opts) {
|
|
2583
|
+
if (!name) {
|
|
2584
|
+
throw new InvalidArgumentError("volume name is required");
|
|
2585
|
+
}
|
|
2586
|
+
const config = new ConnectionConfig({
|
|
2587
|
+
apiKey: opts?.apiKey,
|
|
2588
|
+
domain: opts?.domain,
|
|
2589
|
+
apiUrl: opts?.apiUrl,
|
|
2590
|
+
requestTimeout: opts?.requestTimeout
|
|
2591
|
+
});
|
|
2592
|
+
const client = new ApiClient(config);
|
|
2593
|
+
try {
|
|
2594
|
+
const body = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
2595
|
+
const resp = await client.post("/volumes", {
|
|
2596
|
+
params: { name },
|
|
2597
|
+
body,
|
|
2598
|
+
headers: { "Content-Type": opts?.contentType ?? "application/gzip" },
|
|
2599
|
+
timeout: opts?.requestTimeout
|
|
2600
|
+
});
|
|
2601
|
+
return parseVolumeInfo(resp);
|
|
2602
|
+
} finally {
|
|
2603
|
+
client.close();
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
/** Fetch metadata for a single volume. */
|
|
2607
|
+
static async get(volumeId, opts) {
|
|
2608
|
+
assertValidVolumeId(volumeId);
|
|
2609
|
+
const config = new ConnectionConfig({
|
|
2610
|
+
apiKey: opts?.apiKey,
|
|
2611
|
+
domain: opts?.domain,
|
|
2612
|
+
apiUrl: opts?.apiUrl,
|
|
2613
|
+
requestTimeout: opts?.requestTimeout
|
|
2614
|
+
});
|
|
2615
|
+
const client = new ApiClient(config);
|
|
2616
|
+
try {
|
|
2617
|
+
const resp = await client.get(`/volumes/${volumeId}`, {
|
|
2618
|
+
timeout: opts?.requestTimeout
|
|
2619
|
+
});
|
|
2620
|
+
return parseVolumeInfo(resp);
|
|
2621
|
+
} finally {
|
|
2622
|
+
client.close();
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
/** List all volumes owned by the caller, newest first. */
|
|
2626
|
+
static async list(opts) {
|
|
2627
|
+
const config = new ConnectionConfig({
|
|
2628
|
+
apiKey: opts?.apiKey,
|
|
2629
|
+
domain: opts?.domain,
|
|
2630
|
+
apiUrl: opts?.apiUrl,
|
|
2631
|
+
requestTimeout: opts?.requestTimeout
|
|
2632
|
+
});
|
|
2633
|
+
const client = new ApiClient(config);
|
|
2634
|
+
try {
|
|
2635
|
+
const resp = await client.get("/volumes", {
|
|
2636
|
+
timeout: opts?.requestTimeout
|
|
2637
|
+
});
|
|
2638
|
+
const rows = resp.volumes ?? [];
|
|
2639
|
+
return rows.map(parseVolumeInfo);
|
|
2640
|
+
} finally {
|
|
2641
|
+
client.close();
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
/** Delete a volume and its blob. Idempotent on the wire. */
|
|
2645
|
+
static async delete(volumeId, opts) {
|
|
2646
|
+
assertValidVolumeId(volumeId);
|
|
2647
|
+
const config = new ConnectionConfig({
|
|
2648
|
+
apiKey: opts?.apiKey,
|
|
2649
|
+
domain: opts?.domain,
|
|
2650
|
+
apiUrl: opts?.apiUrl,
|
|
2651
|
+
requestTimeout: opts?.requestTimeout
|
|
2652
|
+
});
|
|
2653
|
+
const client = new ApiClient(config);
|
|
2654
|
+
try {
|
|
2655
|
+
await client.delete(`/volumes/${volumeId}`, { timeout: opts?.requestTimeout });
|
|
2656
|
+
} finally {
|
|
2657
|
+
client.close();
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
};
|
|
2548
2661
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2549
2662
|
0 && (module.exports = {
|
|
2550
2663
|
ALL_TRAFFIC,
|
|
@@ -2581,6 +2694,7 @@ var Template = class {
|
|
|
2581
2694
|
TemplateError,
|
|
2582
2695
|
TimeoutError,
|
|
2583
2696
|
TransformDirection,
|
|
2697
|
+
Volumes,
|
|
2584
2698
|
WatchHandle,
|
|
2585
2699
|
applyTransformation,
|
|
2586
2700
|
codeSecurityConfigToJSON,
|
|
@@ -2619,10 +2733,12 @@ var Template = class {
|
|
|
2619
2733
|
parseSnapshotInfo,
|
|
2620
2734
|
parseTemplateBuildStatus,
|
|
2621
2735
|
parseToxicityConfig,
|
|
2736
|
+
parseVolumeInfo,
|
|
2622
2737
|
parseWriteInfo,
|
|
2623
2738
|
requiresTlsInterception,
|
|
2624
2739
|
securityPolicyToJSON,
|
|
2625
2740
|
toxicityConfigToJSON,
|
|
2626
|
-
validateNetworkEntry
|
|
2741
|
+
validateNetworkEntry,
|
|
2742
|
+
volumeAttachmentToJSON
|
|
2627
2743
|
});
|
|
2628
2744
|
//# sourceMappingURL=index.cjs.map
|