buildonce 0.32.0 → 0.34.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # Once JavaScript SDK
1
+ # Once JavaScript Software Development Kit
2
2
 
3
3
  `buildonce` exposes Once primitives to Node.js. It loads the same
4
- native Once library used by the other SDKs and does not expose script
4
+ native Once library used by the other language libraries and does not expose script
5
5
  execution.
6
6
 
7
7
  ```js
@@ -19,6 +19,8 @@ async function example() {
19
19
  The package looks for a bundled native library under `prebuilds/`. Set
20
20
  `ONCE_LIBRARY_PATH` to load a custom `libonce` build.
21
21
 
22
- `putBlob` sends bytes to the native library through the JSON SDK ABI. This
23
- keeps the package portable across platforms, but it means very large blobs are
24
- materialized as JSON byte arrays before crossing into Rust.
22
+ Use `new Cache({ workspaceRoot })` to share the effective provider configured
23
+ for a repository, or `new Cache({ localCacheRoot })` for isolation. Use
24
+ `putFile` and `getBlobToFile` for large payloads so the host does not need to
25
+ hold their complete contents in JavaScript memory. `ActionKey` builds a stable
26
+ digest from ordered, labeled inputs.
package/lib/index.d.ts CHANGED
@@ -14,21 +14,28 @@ export interface CacheStats {
14
14
 
15
15
  export class OnceError extends Error {}
16
16
 
17
+ export interface CacheOptions {
18
+ localCacheRoot?: string;
19
+ workspaceRoot?: string;
20
+ }
21
+
17
22
  export class Cache {
23
+ constructor(options?: CacheOptions);
18
24
  version(): string;
19
25
  /**
20
- * Strings are encoded as UTF-8 before hashing.
26
+ * Strings use Unicode Transformation Format, 8-bit before hashing.
21
27
  */
22
28
  digest(bytes: Buffer | Uint8Array | string): string;
23
29
  /**
24
- * Strings are encoded as UTF-8 before being stored.
30
+ * Strings use Unicode Transformation Format, 8-bit before being stored.
25
31
  *
26
- * Blob bytes currently cross the native boundary as JSON arrays, so very
27
- * large blobs should use the Rust SDK or CLI until the JavaScript SDK has a
28
- * streaming native ABI.
32
+ * Use putFile for large blobs to avoid loading the complete payload into
33
+ * JavaScript memory.
29
34
  */
30
35
  putBlob(bytes: Buffer | Uint8Array | string): Promise<string>;
36
+ putFile(path: string): Promise<string>;
31
37
  getBlob(digest: string): Promise<Buffer>;
38
+ getBlobToFile(digest: string, path: string): Promise<number>;
32
39
  hasBlob(digest: string): Promise<boolean>;
33
40
  putActionResult(result: ActionResult, actionDigest: string): Promise<boolean>;
34
41
  getActionResult(actionDigest: string): Promise<ActionResult | null>;
@@ -36,7 +43,14 @@ export class Cache {
36
43
  stats(): Promise<CacheStats>;
37
44
  }
38
45
 
46
+ export class ActionKey {
47
+ constructor(namespace: string);
48
+ addBytes(label: string, bytes: Buffer | Uint8Array | string): this;
49
+ addDigest(label: string, digest: string): this;
50
+ digest(): string;
51
+ }
52
+
39
53
  /**
40
- * Strings are encoded as UTF-8 before hashing.
54
+ * Strings use Unicode Transformation Format, 8-bit before hashing.
41
55
  */
42
56
  export function digest(bytes: Buffer | Uint8Array | string): string;
package/lib/index.js CHANGED
@@ -15,6 +15,26 @@ const native = loadNative();
15
15
  const DIGEST_PATTERN = /^[0-9a-f]{64}$/;
16
16
 
17
17
  class Cache {
18
+ constructor(options = {}) {
19
+ if (options == null || typeof options !== "object" || Array.isArray(options)) {
20
+ throw new TypeError("Cache options must be an object");
21
+ }
22
+ const { localCacheRoot, workspaceRoot } = options;
23
+ if (localCacheRoot != null && workspaceRoot != null) {
24
+ throw new TypeError("localCacheRoot and workspaceRoot cannot be used together");
25
+ }
26
+ if (localCacheRoot != null && typeof localCacheRoot !== "string") {
27
+ throw new TypeError("localCacheRoot must be a string");
28
+ }
29
+ if (workspaceRoot != null && typeof workspaceRoot !== "string") {
30
+ throw new TypeError("workspaceRoot must be a string");
31
+ }
32
+ this.selection = {
33
+ ...(localCacheRoot == null ? {} : { local_cache_root: localCacheRoot }),
34
+ ...(workspaceRoot == null ? {} : { workspace_root: workspaceRoot }),
35
+ };
36
+ }
37
+
18
38
  version() {
19
39
  return native.once_version() || "";
20
40
  }
@@ -28,19 +48,43 @@ class Cache {
28
48
  const buffer = toBuffer(bytes, "Cache#putBlob bytes");
29
49
  return decodeRequest(
30
50
  native.once_cache_put_blob_json,
31
- { bytes: Array.from(buffer) },
51
+ { ...this.selection, bytes: Array.from(buffer) },
32
52
  );
33
53
  }
34
54
 
55
+ async putFile(filePath) {
56
+ validatePath(filePath, "filePath");
57
+ return decodeRequest(native.once_cache_put_file_json, {
58
+ ...this.selection,
59
+ path: filePath,
60
+ });
61
+ }
62
+
35
63
  async getBlob(digest) {
36
64
  validateDigest(digest, "digest");
37
- const response = decodeRequest(native.once_cache_get_blob_json, { digest });
65
+ const response = decodeRequest(native.once_cache_get_blob_json, {
66
+ ...this.selection,
67
+ digest,
68
+ });
38
69
  return Buffer.from(response.bytes);
39
70
  }
40
71
 
72
+ async getBlobToFile(digest, filePath) {
73
+ validateDigest(digest, "digest");
74
+ validatePath(filePath, "filePath");
75
+ return decodeRequest(native.once_cache_get_blob_to_file_json, {
76
+ ...this.selection,
77
+ digest,
78
+ path: filePath,
79
+ });
80
+ }
81
+
41
82
  async hasBlob(digest) {
42
83
  validateDigest(digest, "digest");
43
- return decodeRequest(native.once_cache_has_blob_json, { digest });
84
+ return decodeRequest(native.once_cache_has_blob_json, {
85
+ ...this.selection,
86
+ digest,
87
+ });
44
88
  }
45
89
 
46
90
  async putActionResult(result, actionDigest) {
@@ -48,6 +92,7 @@ class Cache {
48
92
  return decodeRequest(
49
93
  native.once_cache_put_action_result_json,
50
94
  {
95
+ ...this.selection,
51
96
  action_digest: actionDigest,
52
97
  result: actionResultToNative(result),
53
98
  },
@@ -58,7 +103,7 @@ class Cache {
58
103
  validateDigest(actionDigest, "actionDigest");
59
104
  const result = decodeRequest(
60
105
  native.once_cache_get_action_result_json,
61
- { action_digest: actionDigest },
106
+ { ...this.selection, action_digest: actionDigest },
62
107
  );
63
108
  return result === null ? null : actionResultFromNative(result);
64
109
  }
@@ -67,12 +112,12 @@ class Cache {
67
112
  validateDigest(actionDigest, "actionDigest");
68
113
  return decodeRequest(
69
114
  native.once_cache_forget_action_json,
70
- { action_digest: actionDigest },
115
+ { ...this.selection, action_digest: actionDigest },
71
116
  );
72
117
  }
73
118
 
74
119
  async stats() {
75
- const stats = decodeRequest(native.once_cache_stats_json, {});
120
+ const stats = decodeRequest(native.once_cache_stats_json, this.selection);
76
121
  return {
77
122
  blobCount: stats.blob_count,
78
123
  blobBytes: stats.blob_bytes,
@@ -82,6 +127,37 @@ class Cache {
82
127
  }
83
128
  }
84
129
 
130
+ class ActionKey {
131
+ constructor(namespace) {
132
+ if (typeof namespace !== "string") {
133
+ throw new TypeError("ActionKey namespace must be a string");
134
+ }
135
+ this.namespace = namespace;
136
+ this.inputs = [];
137
+ }
138
+
139
+ addBytes(label, bytes) {
140
+ validateLabel(label);
141
+ const buffer = toBuffer(bytes, "ActionKey#addBytes bytes");
142
+ this.inputs.push({ kind: "bytes", label, bytes: Array.from(buffer) });
143
+ return this;
144
+ }
145
+
146
+ addDigest(label, digest) {
147
+ validateLabel(label);
148
+ validateDigest(digest, "digest");
149
+ this.inputs.push({ kind: "digest", label, digest });
150
+ return this;
151
+ }
152
+
153
+ digest() {
154
+ return decodeRequest(native.once_action_key_json, {
155
+ namespace: this.namespace,
156
+ inputs: this.inputs,
157
+ });
158
+ }
159
+ }
160
+
85
161
  function digest(bytes) {
86
162
  return new Cache().digest(bytes);
87
163
  }
@@ -103,7 +179,9 @@ function decodeResponse(pointer) {
103
179
  try {
104
180
  response = JSON.parse(pointer);
105
181
  } catch (error) {
106
- throw new OnceError(`native Once response must be valid JSON: ${error.message}`);
182
+ throw new OnceError(
183
+ `native Once response must be valid JavaScript Object Notation: ${error.message}`,
184
+ );
107
185
  }
108
186
  if (response.status === "ok") {
109
187
  return response.value;
@@ -135,6 +213,18 @@ function validateDigest(value, name) {
135
213
  }
136
214
  }
137
215
 
216
+ function validateLabel(value) {
217
+ if (typeof value !== "string") {
218
+ throw new TypeError("ActionKey input label must be a string");
219
+ }
220
+ }
221
+
222
+ function validatePath(value, name) {
223
+ if (typeof value !== "string" || value.length === 0) {
224
+ throw new TypeError(`${name} must be a non-empty string`);
225
+ }
226
+ }
227
+
138
228
  function toBuffer(bytes, name) {
139
229
  if (Buffer.isBuffer(bytes)) {
140
230
  return bytes;
@@ -159,16 +249,29 @@ function loadNative() {
159
249
  "const void *",
160
250
  "size_t",
161
251
  ]),
252
+ once_action_key_json: library.func("once_action_key_json", onceString, [
253
+ "str",
254
+ ]),
162
255
  once_cache_put_blob_json: library.func(
163
256
  "once_cache_put_blob_json",
164
257
  onceString,
165
258
  ["str"],
166
259
  ),
260
+ once_cache_put_file_json: library.func(
261
+ "once_cache_put_file_json",
262
+ onceString,
263
+ ["str"],
264
+ ),
167
265
  once_cache_get_blob_json: library.func(
168
266
  "once_cache_get_blob_json",
169
267
  onceString,
170
268
  ["str"],
171
269
  ),
270
+ once_cache_get_blob_to_file_json: library.func(
271
+ "once_cache_get_blob_to_file_json",
272
+ onceString,
273
+ ["str"],
274
+ ),
172
275
  once_cache_has_blob_json: library.func(
173
276
  "once_cache_has_blob_json",
174
277
  onceString,
@@ -229,6 +332,7 @@ function libraryName() {
229
332
  }
230
333
 
231
334
  module.exports = {
335
+ ActionKey,
232
336
  Cache,
233
337
  OnceError,
234
338
  digest,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "buildonce",
3
- "version": "0.32.0",
4
- "description": "JavaScript SDK for Once cache access",
3
+ "version": "0.34.0",
4
+ "description": "JavaScript software development kit for Once cache access",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
Binary file
Binary file
Binary file
Binary file