@aztec/blob-client 0.0.1-commit.03f7ef2 → 0.0.1-commit.04852196a
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 +10 -1
- package/dest/archive/config.js +1 -1
- package/dest/archive/instrumentation.d.ts +1 -1
- package/dest/archive/instrumentation.d.ts.map +1 -1
- package/dest/archive/instrumentation.js +13 -13
- package/dest/blobstore/blob_store_test_suite.js +9 -9
- package/dest/client/config.d.ts +5 -1
- package/dest/client/config.d.ts.map +1 -1
- package/dest/client/config.js +5 -0
- package/dest/client/factory.d.ts +3 -2
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +5 -2
- package/dest/client/http.d.ts +24 -2
- package/dest/client/http.d.ts.map +1 -1
- package/dest/client/http.js +133 -47
- package/dest/client/interface.d.ts +18 -1
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/local.d.ts +3 -1
- package/dest/client/local.d.ts.map +1 -1
- package/dest/client/local.js +3 -0
- package/dest/client/tests.js +3 -3
- package/dest/filestore/filestore_blob_client.d.ts +14 -2
- package/dest/filestore/filestore_blob_client.d.ts.map +1 -1
- package/dest/filestore/filestore_blob_client.js +29 -5
- package/dest/filestore/healthcheck.d.ts +5 -0
- package/dest/filestore/healthcheck.d.ts.map +1 -0
- package/dest/filestore/healthcheck.js +3 -0
- package/package.json +8 -8
- package/src/archive/config.ts +1 -1
- package/src/archive/instrumentation.ts +22 -13
- package/src/blobstore/blob_store_test_suite.ts +9 -9
- package/src/client/config.ts +10 -0
- package/src/client/factory.ts +7 -2
- package/src/client/http.ts +175 -41
- package/src/client/interface.ts +17 -0
- package/src/client/local.ts +5 -0
- package/src/client/tests.ts +2 -2
- package/src/filestore/filestore_blob_client.ts +33 -5
- package/src/filestore/healthcheck.ts +5 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/client/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/client/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,qEAAqE;IACrE,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACtG,6EAA6E;IAC7E,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,oFAAoF;IACpF,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,0DAA0D;IAC1D,IAAI,CAAC,IAAI,IAAI,CAAC;IACd,iEAAiE;IACjE,SAAS,IAAI,OAAO,CAAC;CACtB"}
|
package/dest/client/local.d.ts
CHANGED
|
@@ -7,5 +7,7 @@ export declare class LocalBlobClient implements BlobClientInterface {
|
|
|
7
7
|
testSources(): Promise<void>;
|
|
8
8
|
sendBlobsToFilestore(blobs: Blob[]): Promise<boolean>;
|
|
9
9
|
getBlobSidecar(_blockId: string, blobHashes: Buffer[], _opts?: GetBlobSidecarOptions): Promise<Blob[]>;
|
|
10
|
+
/** Returns true if this client can upload blobs. Always true for local client. */
|
|
11
|
+
canUpload(): boolean;
|
|
10
12
|
}
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWwuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jbGllbnQvbG9jYWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsSUFBSSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFNUMsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDdkQsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVqRixxQkFBYSxlQUFnQixZQUFXLG1CQUFtQjtJQUN6RCxPQUFPLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBWTtJQUV0QyxZQUFZLFNBQVMsRUFBRSxTQUFTLEVBRS9CO0lBRU0sV0FBVyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFbEM7SUFFWSxvQkFBb0IsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUdqRTtJQUVNLGNBQWMsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxxQkFBcUIsR0FBRyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FFNUc7SUFFRCxrRkFBa0Y7SUFDM0UsU0FBUyxJQUFJLE9BQU8sQ0FFMUI7Q0FDRiJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/client/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEjF,qBAAa,eAAgB,YAAW,mBAAmB;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC,YAAY,SAAS,EAAE,SAAS,EAE/B;IAEM,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAElC;IAEY,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAGjE;IAEM,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAE5G;CACF"}
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/client/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEjF,qBAAa,eAAgB,YAAW,mBAAmB;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC,YAAY,SAAS,EAAE,SAAS,EAE/B;IAEM,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAElC;IAEY,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAGjE;IAEM,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAE5G;IAED,kFAAkF;IAC3E,SAAS,IAAI,OAAO,CAE1B;CACF"}
|
package/dest/client/local.js
CHANGED
|
@@ -13,4 +13,7 @@ export class LocalBlobClient {
|
|
|
13
13
|
getBlobSidecar(_blockId, blobHashes, _opts) {
|
|
14
14
|
return this.blobStore.getBlobsByHashes(blobHashes);
|
|
15
15
|
}
|
|
16
|
+
/** Returns true if this client can upload blobs. Always true for local client. */ canUpload() {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
16
19
|
}
|
package/dest/client/tests.js
CHANGED
|
@@ -17,7 +17,7 @@ import { makeRandomBlob } from '@aztec/blob-lib/testing';
|
|
|
17
17
|
await cleanup();
|
|
18
18
|
});
|
|
19
19
|
it('should send and retrieve blobs by hash', async ()=>{
|
|
20
|
-
const blob = makeRandomBlob(5);
|
|
20
|
+
const blob = await makeRandomBlob(5);
|
|
21
21
|
const blobHash = blob.getEthVersionedBlobHash();
|
|
22
22
|
await client.sendBlobsToFilestore([
|
|
23
23
|
blob
|
|
@@ -29,9 +29,9 @@ import { makeRandomBlob } from '@aztec/blob-lib/testing';
|
|
|
29
29
|
expect(retrievedBlobs[0]).toEqual(blob);
|
|
30
30
|
});
|
|
31
31
|
it('should handle multiple blobs', async ()=>{
|
|
32
|
-
const blobs = Array.from({
|
|
32
|
+
const blobs = await Promise.all(Array.from({
|
|
33
33
|
length: 3
|
|
34
|
-
}, ()=>makeRandomBlob(7));
|
|
34
|
+
}, ()=>makeRandomBlob(7)));
|
|
35
35
|
const blobHashes = blobs.map((blob)=>blob.getEthVersionedBlobHash());
|
|
36
36
|
await client.sendBlobsToFilestore(blobs);
|
|
37
37
|
const retrievedBlobs = await client.getBlobSidecar(blockId, blobHashes);
|
|
@@ -15,6 +15,11 @@ export declare class FileStoreBlobClient {
|
|
|
15
15
|
* Format: basePath/blobs/{versionedBlobHash}.data
|
|
16
16
|
*/
|
|
17
17
|
private blobPath;
|
|
18
|
+
/**
|
|
19
|
+
* Get the path for the healthcheck file.
|
|
20
|
+
* Format: basePath/.healthcheck
|
|
21
|
+
*/
|
|
22
|
+
private healthcheckPath;
|
|
18
23
|
/**
|
|
19
24
|
* Fetch blobs by their versioned hashes.
|
|
20
25
|
* @param blobHashes - Array of versioned blob hashes (0x-prefixed hex strings)
|
|
@@ -44,12 +49,19 @@ export declare class FileStoreBlobClient {
|
|
|
44
49
|
*/
|
|
45
50
|
getBaseUrl(): string;
|
|
46
51
|
/**
|
|
47
|
-
* Test if the filestore connection is working.
|
|
52
|
+
* Test if the filestore connection is working by checking for healthcheck file.
|
|
53
|
+
* The healthcheck file is uploaded periodically by writable clients via HttpBlobClient.start().
|
|
54
|
+
* This provides a uniform connection test across all store types (S3/GCS/Local/HTTP).
|
|
48
55
|
*/
|
|
49
56
|
testConnection(): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Upload the healthcheck file if it doesn't already exist.
|
|
59
|
+
* This enables read-only clients (HTTP) to verify connectivity.
|
|
60
|
+
*/
|
|
61
|
+
uploadHealthcheck(): Promise<void>;
|
|
50
62
|
/**
|
|
51
63
|
* Check if the store supports write operations.
|
|
52
64
|
*/
|
|
53
65
|
private isWritable;
|
|
54
66
|
}
|
|
55
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
67
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZXN0b3JlX2Jsb2JfY2xpZW50LmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmlsZXN0b3JlL2ZpbGVzdG9yZV9ibG9iX2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssUUFBUSxFQUErQixNQUFNLGlCQUFpQixDQUFDO0FBQ25GLE9BQU8sRUFBRSxLQUFLLE1BQU0sRUFBZ0IsTUFBTSx1QkFBdUIsQ0FBQztBQUNsRSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUs3RTs7O0dBR0c7QUFDSCxxQkFBYSxtQkFBbUI7SUFJNUIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLO0lBQ3RCLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUTtJQUozQixPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBUztJQUU3QixZQUNtQixLQUFLLEVBQUUsaUJBQWlCLEdBQUcsU0FBUyxFQUNwQyxRQUFRLEVBQUUsTUFBTSxFQUNqQyxNQUFNLENBQUMsRUFBRSxNQUFNLEVBR2hCO0lBRUQ7OztPQUdHO0lBQ0gsT0FBTyxDQUFDLFFBQVE7SUFJaEI7OztPQUdHO0lBQ0gsT0FBTyxDQUFDLGVBQWU7SUFJdkI7Ozs7T0FJRztJQUNHLGdCQUFnQixDQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FtQmhFO0lBRUQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLGlCQUFpQixFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBRWxEO0lBRUQ7Ozs7O09BS0c7SUFDRyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxZQUFZLFVBQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBa0I3RDtJQUVEOzs7O09BSUc7SUFDRyxTQUFTLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLFlBQVksVUFBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFakU7SUFFRDs7T0FFRztJQUNILFVBQVUsSUFBSSxNQUFNLENBRW5CO0lBRUQ7Ozs7T0FJRztJQUNHLGNBQWMsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLENBT3ZDO0lBRUQ7OztPQUdHO0lBQ0csaUJBQWlCLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQVF2QztJQUVEOztPQUVHO0lBQ0gsT0FBTyxDQUFDLFVBQVU7Q0FHbkIifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filestore_blob_client.d.ts","sourceRoot":"","sources":["../../src/filestore/filestore_blob_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,QAAQ,EAA+B,MAAM,iBAAiB,CAAC;AACnF,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"filestore_blob_client.d.ts","sourceRoot":"","sources":["../../src/filestore/filestore_blob_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,QAAQ,EAA+B,MAAM,iBAAiB,CAAC;AACnF,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAK7E;;;GAGG;AACH,qBAAa,mBAAmB;IAI5B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJ3B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B,YACmB,KAAK,EAAE,iBAAiB,GAAG,SAAS,EACpC,QAAQ,EAAE,MAAM,EACjC,MAAM,CAAC,EAAE,MAAM,EAGhB;IAED;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAIhB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAIvB;;;;OAIG;IACG,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAmBhE;IAED;;;OAGG;IACH,MAAM,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElD;IAED;;;;;OAKG;IACG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB7D;IAED;;;;OAIG;IACG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,YAAY,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjE;IAED;;OAEG;IACH,UAAU,IAAI,MAAM,CAEnB;IAED;;;;OAIG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAOvC;IAED;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQvC;IAED;;OAEG;IACH,OAAO,CAAC,UAAU;CAGnB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { computeEthVersionedBlobHash } from '@aztec/blob-lib';
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import { inboundTransform, outboundTransform } from '../encoding/index.js';
|
|
4
|
+
import { HEALTHCHECK_CONTENT, HEALTHCHECK_FILENAME } from './healthcheck.js';
|
|
4
5
|
/**
|
|
5
6
|
* A blob client that uses a FileStore (S3/GCS/local) as the data source.
|
|
6
7
|
* Blobs are stored as JSON files keyed by their versioned blob hash.
|
|
@@ -20,6 +21,12 @@ import { inboundTransform, outboundTransform } from '../encoding/index.js';
|
|
|
20
21
|
return `${this.basePath}/blobs/${versionedBlobHash}.data`;
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
24
|
+
* Get the path for the healthcheck file.
|
|
25
|
+
* Format: basePath/.healthcheck
|
|
26
|
+
*/ healthcheckPath() {
|
|
27
|
+
return `${this.basePath}/${HEALTHCHECK_FILENAME}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
23
30
|
* Fetch blobs by their versioned hashes.
|
|
24
31
|
* @param blobHashes - Array of versioned blob hashes (0x-prefixed hex strings)
|
|
25
32
|
* @returns Array of BlobJson objects for found blobs
|
|
@@ -77,11 +84,28 @@ import { inboundTransform, outboundTransform } from '../encoding/index.js';
|
|
|
77
84
|
return this.basePath;
|
|
78
85
|
}
|
|
79
86
|
/**
|
|
80
|
-
* Test if the filestore connection is working.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
* Test if the filestore connection is working by checking for healthcheck file.
|
|
88
|
+
* The healthcheck file is uploaded periodically by writable clients via HttpBlobClient.start().
|
|
89
|
+
* This provides a uniform connection test across all store types (S3/GCS/Local/HTTP).
|
|
90
|
+
*/ async testConnection() {
|
|
91
|
+
try {
|
|
92
|
+
return await this.store.exists(this.healthcheckPath());
|
|
93
|
+
} catch (err) {
|
|
94
|
+
this.log.warn(`Connection test failed: ${err?.message ?? String(err)}`);
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Upload the healthcheck file if it doesn't already exist.
|
|
100
|
+
* This enables read-only clients (HTTP) to verify connectivity.
|
|
101
|
+
*/ async uploadHealthcheck() {
|
|
102
|
+
if (!this.isWritable()) {
|
|
103
|
+
this.log.trace('Cannot upload healthcheck: store is read-only');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const path = this.healthcheckPath();
|
|
107
|
+
await this.store.save(path, Buffer.from(HEALTHCHECK_CONTENT));
|
|
108
|
+
this.log.debug(`Uploaded healthcheck file to ${path}`);
|
|
85
109
|
}
|
|
86
110
|
/**
|
|
87
111
|
* Check if the store supports write operations.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Constants for healthcheck file used to test file store connectivity. */
|
|
2
|
+
export declare const HEALTHCHECK_FILENAME = ".healthcheck";
|
|
3
|
+
export declare const HEALTHCHECK_CONTENT = "ok";
|
|
4
|
+
export declare const DEFAULT_HEALTHCHECK_UPLOAD_INTERVAL_MINUTES = 60;
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVhbHRoY2hlY2suZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9maWxlc3RvcmUvaGVhbHRoY2hlY2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsMkVBQTJFO0FBRTNFLGVBQU8sTUFBTSxvQkFBb0IsaUJBQWlCLENBQUM7QUFDbkQsZUFBTyxNQUFNLG1CQUFtQixPQUFPLENBQUM7QUFDeEMsZUFBTyxNQUFNLDJDQUEyQyxLQUFLLENBQUMifQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"healthcheck.d.ts","sourceRoot":"","sources":["../../src/filestore/healthcheck.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AACnD,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,2CAA2C,KAAK,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/blob-client",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.04852196a",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": "./dest/client/bin/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
]
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
60
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
61
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
62
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
63
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
64
|
-
"@aztec/telemetry-client": "0.0.1-commit.
|
|
59
|
+
"@aztec/blob-lib": "0.0.1-commit.04852196a",
|
|
60
|
+
"@aztec/ethereum": "0.0.1-commit.04852196a",
|
|
61
|
+
"@aztec/foundation": "0.0.1-commit.04852196a",
|
|
62
|
+
"@aztec/kv-store": "0.0.1-commit.04852196a",
|
|
63
|
+
"@aztec/stdlib": "0.0.1-commit.04852196a",
|
|
64
|
+
"@aztec/telemetry-client": "0.0.1-commit.04852196a",
|
|
65
65
|
"express": "^4.21.2",
|
|
66
66
|
"snappy": "^7.2.2",
|
|
67
67
|
"source-map-support": "^0.5.21",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"@types/node": "^22.15.17",
|
|
76
76
|
"@types/source-map-support": "^0.5.10",
|
|
77
77
|
"@types/supertest": "^6.0.2",
|
|
78
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
78
|
+
"@typescript/native-preview": "7.0.0-dev.20260113.1",
|
|
79
79
|
"jest": "^30.0.0",
|
|
80
80
|
"jest-mock-extended": "^4.0.0",
|
|
81
81
|
"supertest": "^7.0.0",
|
package/src/archive/config.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type BlobArchiveApiConfig = {
|
|
|
7
7
|
|
|
8
8
|
export const blobArchiveApiConfigMappings: ConfigMappingsType<BlobArchiveApiConfig> = {
|
|
9
9
|
archiveApiUrl: {
|
|
10
|
-
env: '
|
|
10
|
+
env: 'BLOB_ARCHIVE_API_URL',
|
|
11
11
|
description: 'The URL of the archive API',
|
|
12
12
|
},
|
|
13
13
|
...pickConfigMappings(l1ReaderConfigMappings, ['l1ChainId']),
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Attributes,
|
|
3
|
+
Metrics,
|
|
4
|
+
type TelemetryClient,
|
|
5
|
+
type UpDownCounter,
|
|
6
|
+
createUpDownCounterWithDefault,
|
|
7
|
+
} from '@aztec/telemetry-client';
|
|
2
8
|
|
|
3
9
|
export class BlobArchiveClientInstrumentation {
|
|
4
10
|
private blockRequestCounter: UpDownCounter;
|
|
@@ -11,20 +17,23 @@ export class BlobArchiveClientInstrumentation {
|
|
|
11
17
|
name: string,
|
|
12
18
|
) {
|
|
13
19
|
const meter = client.getMeter(name);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
20
|
+
const requestAttrs = {
|
|
21
|
+
[Attributes.HTTP_RESPONSE_STATUS_CODE]: [200, 404],
|
|
22
|
+
[Attributes.HTTP_REQUEST_HOST]: [httpHost],
|
|
23
|
+
};
|
|
24
|
+
this.blockRequestCounter = createUpDownCounterWithDefault(
|
|
25
|
+
meter,
|
|
26
|
+
Metrics.BLOB_SINK_ARCHIVE_BLOCK_REQUEST_COUNT,
|
|
27
|
+
requestAttrs,
|
|
28
|
+
);
|
|
18
29
|
|
|
19
|
-
this.blobRequestCounter =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
this.blobRequestCounter = createUpDownCounterWithDefault(
|
|
31
|
+
meter,
|
|
32
|
+
Metrics.BLOB_SINK_ARCHIVE_BLOB_REQUEST_COUNT,
|
|
33
|
+
requestAttrs,
|
|
34
|
+
);
|
|
23
35
|
|
|
24
|
-
this.retrievedBlobs = meter
|
|
25
|
-
description: 'Number of blobs retrieved from the blob archive',
|
|
26
|
-
valueType: ValueType.INT,
|
|
27
|
-
});
|
|
36
|
+
this.retrievedBlobs = createUpDownCounterWithDefault(meter, Metrics.BLOB_SINK_ARCHIVE_BLOB_COUNT);
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
incRequest(type: 'blocks' | 'blobs', status: number) {
|
|
@@ -13,7 +13,7 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
|
|
|
13
13
|
it('should store and retrieve a blob by hash', async () => {
|
|
14
14
|
// Create a test blob with random fields
|
|
15
15
|
const testFields = [Fr.random(), Fr.random(), Fr.random()];
|
|
16
|
-
const blob = Blob.fromFields(testFields);
|
|
16
|
+
const blob = await Blob.fromFields(testFields);
|
|
17
17
|
const blobHash = blob.getEthVersionedBlobHash();
|
|
18
18
|
|
|
19
19
|
// Store the blob
|
|
@@ -29,8 +29,8 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
|
|
|
29
29
|
|
|
30
30
|
it('should handle multiple blobs stored and retrieved by their hashes', async () => {
|
|
31
31
|
// Create two different blobs
|
|
32
|
-
const blob1 = Blob.fromFields([Fr.random(), Fr.random()]);
|
|
33
|
-
const blob2 = Blob.fromFields([Fr.random(), Fr.random(), Fr.random()]);
|
|
32
|
+
const blob1 = await Blob.fromFields([Fr.random(), Fr.random()]);
|
|
33
|
+
const blob2 = await Blob.fromFields([Fr.random(), Fr.random(), Fr.random()]);
|
|
34
34
|
|
|
35
35
|
const blobHash1 = blob1.getEthVersionedBlobHash();
|
|
36
36
|
const blobHash2 = blob2.getEthVersionedBlobHash();
|
|
@@ -57,9 +57,9 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
|
|
|
57
57
|
|
|
58
58
|
it('should handle retrieving subset of stored blobs', async () => {
|
|
59
59
|
// Store multiple blobs
|
|
60
|
-
const blob1 = Blob.fromFields([Fr.random()]);
|
|
61
|
-
const blob2 = Blob.fromFields([Fr.random()]);
|
|
62
|
-
const blob3 = Blob.fromFields([Fr.random()]);
|
|
60
|
+
const blob1 = await Blob.fromFields([Fr.random()]);
|
|
61
|
+
const blob2 = await Blob.fromFields([Fr.random()]);
|
|
62
|
+
const blob3 = await Blob.fromFields([Fr.random()]);
|
|
63
63
|
|
|
64
64
|
await blobStore.addBlobs([blob1, blob2, blob3]);
|
|
65
65
|
|
|
@@ -75,7 +75,7 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
|
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
it('should handle duplicate blob hashes in request', async () => {
|
|
78
|
-
const blob = Blob.fromFields([Fr.random()]);
|
|
78
|
+
const blob = await Blob.fromFields([Fr.random()]);
|
|
79
79
|
const blobHash = blob.getEthVersionedBlobHash();
|
|
80
80
|
|
|
81
81
|
await blobStore.addBlobs([blob]);
|
|
@@ -91,8 +91,8 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
|
|
|
91
91
|
it('should overwrite blob when storing with same hash', async () => {
|
|
92
92
|
// Create two blobs that will have the same hash (same content)
|
|
93
93
|
const fields = [Fr.random(), Fr.random()];
|
|
94
|
-
const blob1 = Blob.fromFields(fields);
|
|
95
|
-
const blob2 = Blob.fromFields(fields);
|
|
94
|
+
const blob1 = await Blob.fromFields(fields);
|
|
95
|
+
const blob2 = await Blob.fromFields(fields);
|
|
96
96
|
|
|
97
97
|
const blobHash = blob1.getEthVersionedBlobHash();
|
|
98
98
|
|
package/src/client/config.ts
CHANGED
|
@@ -50,6 +50,11 @@ export interface BlobClientConfig extends BlobArchiveApiConfig {
|
|
|
50
50
|
* URL for uploading blobs to filestore (s3://, gs://, file://)
|
|
51
51
|
*/
|
|
52
52
|
blobFileStoreUploadUrl?: string;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Interval in minutes for uploading healthcheck file to file store (default: 60 = 1 hour)
|
|
56
|
+
*/
|
|
57
|
+
blobHealthcheckUploadIntervalMinutes?: number;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
export const blobClientConfigMapping: ConfigMappingsType<BlobClientConfig> = {
|
|
@@ -98,6 +103,11 @@ export const blobClientConfigMapping: ConfigMappingsType<BlobClientConfig> = {
|
|
|
98
103
|
env: 'BLOB_FILE_STORE_UPLOAD_URL',
|
|
99
104
|
description: 'URL for uploading blobs to filestore (s3://, gs://, file://)',
|
|
100
105
|
},
|
|
106
|
+
blobHealthcheckUploadIntervalMinutes: {
|
|
107
|
+
env: 'BLOB_HEALTHCHECK_UPLOAD_INTERVAL_MINUTES',
|
|
108
|
+
description: 'Interval in minutes for uploading healthcheck file to file store (default: 60 = 1 hour)',
|
|
109
|
+
parseEnv: (val: string | undefined) => (val ? +val : undefined),
|
|
110
|
+
},
|
|
101
111
|
...blobArchiveApiConfigMappings,
|
|
102
112
|
};
|
|
103
113
|
|
package/src/client/factory.ts
CHANGED
|
@@ -58,10 +58,11 @@ export interface BlobClientWithFileStoresConfig extends BlobClientConfig {
|
|
|
58
58
|
* 2. Creating read-only FileStore clients
|
|
59
59
|
* 3. Creating a writable FileStore client for uploads
|
|
60
60
|
* 4. Creating the BlobClient with these dependencies
|
|
61
|
+
* 5. Starting the client (uploads initial healthcheck file if upload client is configured)
|
|
61
62
|
*
|
|
62
63
|
* @param config - Configuration containing blob client settings and chain metadata
|
|
63
64
|
* @param logger - Optional logger for the blob client
|
|
64
|
-
* @returns A BlobClientInterface configured with file store support
|
|
65
|
+
* @returns A BlobClientInterface configured with file store support, already started
|
|
65
66
|
*/
|
|
66
67
|
export async function createBlobClientWithFileStores(
|
|
67
68
|
config: BlobClientWithFileStoresConfig,
|
|
@@ -80,9 +81,13 @@ export async function createBlobClientWithFileStores(
|
|
|
80
81
|
createWritableFileStoreBlobClient(config.blobFileStoreUploadUrl, fileStoreMetadata, log),
|
|
81
82
|
]);
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
const client = createBlobClient(config, {
|
|
84
85
|
logger: log,
|
|
85
86
|
fileStoreClients,
|
|
86
87
|
fileStoreUploadClient,
|
|
87
88
|
});
|
|
89
|
+
|
|
90
|
+
await client.start?.();
|
|
91
|
+
|
|
92
|
+
return client;
|
|
88
93
|
}
|