@saga-sync/producer 0.1.3 → 0.2.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/LICENSE +674 -0
- package/README.md +473 -0
- package/dist/chunk-builder/accumulator.d.ts +4 -4
- package/dist/chunk-builder/accumulator.d.ts.map +1 -1
- package/dist/chunk-builder/accumulator.js.map +1 -1
- package/dist/chunk-builder/archive.d.ts +5 -5
- package/dist/chunk-builder/archive.d.ts.map +1 -1
- package/dist/chunk-builder/archive.js +1 -1
- package/dist/chunk-builder/archive.js.map +1 -1
- package/dist/chunk-builder/cli.d.ts +4 -3
- package/dist/chunk-builder/cli.d.ts.map +1 -1
- package/dist/chunk-builder/cli.js +7 -3
- package/dist/chunk-builder/cli.js.map +1 -1
- package/dist/keygen.d.ts +1 -1
- package/dist/keygen.d.ts.map +1 -1
- package/dist/keygen.js +38 -6
- package/dist/keygen.js.map +1 -1
- package/dist/orchestrator/cli.d.ts +6 -4
- package/dist/orchestrator/cli.d.ts.map +1 -1
- package/dist/orchestrator/cli.js +96 -32
- package/dist/orchestrator/cli.js.map +1 -1
- package/dist/orchestrator/pipeline.d.ts +5 -8
- package/dist/orchestrator/pipeline.d.ts.map +1 -1
- package/dist/orchestrator/pipeline.js +5 -12
- package/dist/orchestrator/pipeline.js.map +1 -1
- package/dist/scraper/cli.d.ts +1 -0
- package/dist/scraper/cli.d.ts.map +1 -1
- package/dist/scraper/cli.js +20 -2
- package/dist/scraper/cli.js.map +1 -1
- package/dist/scraper/config.d.ts +13 -1
- package/dist/scraper/config.d.ts.map +1 -1
- package/dist/scraper/config.js +58 -2
- package/dist/scraper/config.js.map +1 -1
- package/dist/scraper/scrape.d.ts.map +1 -1
- package/dist/scraper/scrape.js +39 -6
- package/dist/scraper/scrape.js.map +1 -1
- package/dist/sources/index.d.ts +14 -0
- package/dist/sources/index.d.ts.map +1 -0
- package/dist/sources/index.js +25 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/rpc-log-source.d.ts +17 -0
- package/dist/sources/rpc-log-source.d.ts.map +1 -0
- package/dist/sources/rpc-log-source.js +43 -0
- package/dist/sources/rpc-log-source.js.map +1 -0
- package/dist/sources/subsquid-source.d.ts +38 -0
- package/dist/sources/subsquid-source.d.ts.map +1 -0
- package/dist/sources/subsquid-source.js +191 -0
- package/dist/sources/subsquid-source.js.map +1 -0
- package/dist/sources/types.d.ts +7 -0
- package/dist/sources/types.d.ts.map +1 -0
- package/dist/sources/types.js +2 -0
- package/dist/sources/types.js.map +1 -0
- package/dist/storage/gcs-store.d.ts +1 -0
- package/dist/storage/gcs-store.d.ts.map +1 -1
- package/dist/storage/gcs-store.js +34 -3
- package/dist/storage/gcs-store.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcs-store.d.ts","sourceRoot":"","sources":["../../src/storage/gcs-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAO7C,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AACF,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,QAAQ,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAClC,MAAM,CAAC,IAAI,EAAE;QAAE,cAAc,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7D;AACD,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC,CAAC;CACxE;AACD,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAUpE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"gcs-store.d.ts","sourceRoot":"","sources":["../../src/storage/gcs-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAO7C,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AACF,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,QAAQ,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAClC,MAAM,CAAC,IAAI,EAAE;QAAE,cAAc,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7D;AACD,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC,CAAC;CACxE;AACD,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAUpE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOlD;AAkBD,MAAM,MAAM,eAAe,GAAG;IAG5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,CAAC;AAKF,qBAAa,QAAS,YAAW,KAAK;IAMlC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAL7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,YAAY,CAAC,CAAqB;gBAGvB,UAAU,EAAE,MAAM,EACnC,IAAI,GAAE,eAAoB;IAM5B,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,GAAG;IAIL,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAcjD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAW5C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAI9C;AAkBD,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAUnE"}
|
|
@@ -13,7 +13,10 @@ export function cacheControlFor(key) {
|
|
|
13
13
|
export function contentTypeFor(key) {
|
|
14
14
|
if (key.endsWith(".gz"))
|
|
15
15
|
return "application/gzip";
|
|
16
|
-
|
|
16
|
+
// `.sigs` is the JSON signature envelope; `.sig` stays opaque — it is a bare
|
|
17
|
+
// hex string, not JSON. (Neither is cached long: only *.jsonl.gz is immutable,
|
|
18
|
+
// so both re-validate on the short TTL above.)
|
|
19
|
+
if (key.endsWith(".json") || key.endsWith(".sigs"))
|
|
17
20
|
return "application/json";
|
|
18
21
|
return "application/octet-stream";
|
|
19
22
|
}
|
|
@@ -52,11 +55,14 @@ export class GcsStore {
|
|
|
52
55
|
}
|
|
53
56
|
async put(key, data) {
|
|
54
57
|
const file = (await this.bucket()).file(this.obj(key));
|
|
55
|
-
|
|
58
|
+
// GCS caps mutations to a single object at ~1/sec; the manifest coalesces
|
|
59
|
+
// writes to stay under it, but retry 429s with backoff as a safety net so a
|
|
60
|
+
// transient burst never fails a run.
|
|
61
|
+
await withRetry(() => file.save(data, {
|
|
56
62
|
contentType: contentTypeFor(key),
|
|
57
63
|
metadata: { cacheControl: cacheControlFor(key) },
|
|
58
64
|
resumable: false,
|
|
59
|
-
});
|
|
65
|
+
}));
|
|
60
66
|
}
|
|
61
67
|
async get(key) {
|
|
62
68
|
const file = (await this.bucket()).file(this.obj(key));
|
|
@@ -82,4 +88,29 @@ export class GcsStore {
|
|
|
82
88
|
function isNotFound(err) {
|
|
83
89
|
return typeof err === "object" && err !== null && err.code === 404;
|
|
84
90
|
}
|
|
91
|
+
function isRateLimit(err) {
|
|
92
|
+
if (typeof err !== "object" || err === null)
|
|
93
|
+
return false;
|
|
94
|
+
if (err.code === 429)
|
|
95
|
+
return true;
|
|
96
|
+
const msg = String(err.message ?? "").toLowerCase();
|
|
97
|
+
return msg.includes("429") || msg.includes("rate limit");
|
|
98
|
+
}
|
|
99
|
+
const RETRY_ATTEMPTS = 6;
|
|
100
|
+
const RETRY_BASE_MS = 500;
|
|
101
|
+
// Retry a put on GCS 429 (object mutation rate limit) with exponential backoff +
|
|
102
|
+
// full jitter; other errors propagate immediately. Exported for tests.
|
|
103
|
+
export async function withRetry(fn) {
|
|
104
|
+
for (let attempt = 0;; attempt++) {
|
|
105
|
+
try {
|
|
106
|
+
return await fn();
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
if (!isRateLimit(err) || attempt >= RETRY_ATTEMPTS)
|
|
110
|
+
throw err;
|
|
111
|
+
const cap = Math.min(15_000, RETRY_BASE_MS * 2 ** attempt);
|
|
112
|
+
await new Promise((r) => setTimeout(r, Math.round(Math.random() * cap)));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
85
116
|
//# sourceMappingURL=gcs-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcs-store.js","sourceRoot":"","sources":["../../src/storage/gcs-store.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,GAAG,cAAc,CAAC;AAC9B,MAAM,GAAG,GAAG,mBAAmB,CAAC;AAEhC,iFAAiF;AACjF,iFAAiF;AACjF,kFAAkF;AAClF,kFAAkF;AAClF,sEAAsE;AACtE,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,qCAAqC,CAAC;IACrF,OAAO,oBAAoB,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,kBAAkB,CAAC;IACnD,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"gcs-store.js","sourceRoot":"","sources":["../../src/storage/gcs-store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saga-sync/producer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Producer side of saga-sync: scraper, chunk-builder, orchestrator, and cloud stores",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "GPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/fatlabsxyz/saga-sync.git",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"viem": "^2.21.0",
|
|
37
37
|
"zod": "^3.23.8",
|
|
38
|
-
"@saga-sync/core": "0.
|
|
38
|
+
"@saga-sync/core": "0.2.0"
|
|
39
39
|
},
|
|
40
40
|
"optionalDependencies": {
|
|
41
41
|
"@google-cloud/storage": "^7.19.0"
|