hazo_collect 0.2.2 → 0.2.4
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/CHANGE_LOG.md +47 -0
- package/dist/server/index.js +11 -12
- package/package.json +3 -3
package/CHANGE_LOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# hazo_collect — Change Log
|
|
2
2
|
|
|
3
|
+
## 0.2.4 — 2026-06-14
|
|
4
|
+
|
|
5
|
+
### Fixes — `discover()` read-back of the now-`jsonb` manifest (0.2.3 follow-up)
|
|
6
|
+
|
|
7
|
+
0.2.3 fixed the **write** side (manifest/payload stored as real `jsonb` objects) but missed the
|
|
8
|
+
matching **read** site. `discover()` still did `JSON.parse(row.manifest)`, and now that the column
|
|
9
|
+
holds real `jsonb` the PostgREST adapter returns `row.manifest` as an already-parsed **object** —
|
|
10
|
+
`JSON.parse(object)` coerces to the string `"[object Object]"` and throws. The worker could not
|
|
11
|
+
boot: `engine.discover_failed` (`"[object Object]" is not valid JSON`) retried forever.
|
|
12
|
+
|
|
13
|
+
Fix: `src/registry/discovery.ts` reads the manifest via `parseJsonbField()` (from
|
|
14
|
+
`hazo_connect/server`), which normalises both shapes — an already-parsed object (PostgREST/pg
|
|
15
|
+
`jsonb`) and a JSON string (text/SQLite read) — instead of blindly `JSON.parse`-ing.
|
|
16
|
+
|
|
17
|
+
Regression test (`src/__tests__/discovery.test.ts`): a PostgREST-shaped adapter wrapper returns
|
|
18
|
+
the registry `manifest` column as an object; `discover()` must boot the worker without re-parsing.
|
|
19
|
+
|
|
20
|
+
**Requires:** `hazo_connect ^3.8.0`.
|
|
21
|
+
|
|
22
|
+
## 0.2.3 — 2026-06-14
|
|
23
|
+
|
|
24
|
+
### Fixes — stop double-encoding JSON columns for PostgREST/JSONB adapters
|
|
25
|
+
|
|
26
|
+
Previously, `write-adapter.ts`, `registry/index.ts`, and `manager/index.ts` all called
|
|
27
|
+
`JSON.stringify()` on JSON-valued fields before handing them to the adapter. This was correct for
|
|
28
|
+
SQLite (which stores JSON as TEXT), but caused **double-encoding** for PostgREST/pg adapters whose
|
|
29
|
+
JSONB columns serialize objects natively — making `manifest->>'name'` and `payload->>'seq'`
|
|
30
|
+
return null on ocdata.
|
|
31
|
+
|
|
32
|
+
Fix: pass objects/arrays through directly and declare the JSON columns via the new
|
|
33
|
+
`QueryBuilder.jsonColumns([...])` API (introduced in `hazo_connect@3.8.0`). The SQLite adapter
|
|
34
|
+
reads the declared columns and serializes them itself; the PostgREST adapter passes the object
|
|
35
|
+
through as-is.
|
|
36
|
+
|
|
37
|
+
**Changed write sites:**
|
|
38
|
+
- `src/server/write-adapter.ts` — `payload` no longer pre-stringified; `QueryBuilder` chain adds
|
|
39
|
+
`.jsonColumns(['payload'])`.
|
|
40
|
+
- `src/registry/index.ts` — `manifest` no longer pre-stringified; `RegistryRow.manifest` type
|
|
41
|
+
widened from `string` to `ManifestInput`; both `doUpdate` and `doNothing` QueryBuilders get
|
|
42
|
+
`.jsonColumns(['manifest'])`.
|
|
43
|
+
- `src/manager/index.ts` `insertRunRow` — `errors` changed from `'[]'` string to `[]` array;
|
|
44
|
+
QueryBuilder gets `.jsonColumns(['errors'])`.
|
|
45
|
+
- `src/manager/index.ts` `updateRunRow` — `errors` and `metrics` no longer pre-stringified;
|
|
46
|
+
QueryBuilder gets `.jsonColumns(['errors', 'metrics'])`.
|
|
47
|
+
|
|
48
|
+
**Requires:** `hazo_connect ^3.8.0`.
|
|
49
|
+
|
|
3
50
|
## 0.2.2 — 2026-06-14
|
|
4
51
|
|
|
5
52
|
### Fixes — CJS-host plugin discovery (empty-registry bug)
|
package/dist/server/index.js
CHANGED
|
@@ -22,17 +22,16 @@ function createWriteAdapter(adapter) {
|
|
|
22
22
|
let landingWritten = 0;
|
|
23
23
|
let canonicalWritten = 0;
|
|
24
24
|
for (const row of landing) {
|
|
25
|
-
const payload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload);
|
|
26
25
|
const record = {
|
|
27
26
|
id: generateRequestId().slice(4),
|
|
28
27
|
plugin,
|
|
29
28
|
run_id: row.run_id,
|
|
30
29
|
idempotency_key: row.idempotency_key,
|
|
31
|
-
payload,
|
|
30
|
+
payload: row.payload,
|
|
32
31
|
...row.window?.since != null ? { window_since: row.window.since } : {},
|
|
33
32
|
...row.window?.until != null ? { window_until: row.window.until } : {}
|
|
34
33
|
};
|
|
35
|
-
const qb = new QueryBuilder().from("hazo_collect_landing").onConflict(["plugin", "idempotency_key"]).doUpdate();
|
|
34
|
+
const qb = new QueryBuilder().from("hazo_collect_landing").onConflict(["plugin", "idempotency_key"]).doUpdate().jsonColumns(["payload"]);
|
|
36
35
|
await tx.query(qb, "POST", record);
|
|
37
36
|
landingWritten++;
|
|
38
37
|
}
|
|
@@ -167,22 +166,22 @@ async function insertRunRow(adapter, params) {
|
|
|
167
166
|
correlation_id: params.correlation_id,
|
|
168
167
|
records_fetched: 0,
|
|
169
168
|
records_written: 0,
|
|
170
|
-
errors:
|
|
169
|
+
errors: [],
|
|
171
170
|
contract_version: CONTRACT_VERSION
|
|
172
171
|
};
|
|
173
|
-
const qb = new QueryBuilder2().from("hazo_collect_plugin_runs");
|
|
172
|
+
const qb = new QueryBuilder2().from("hazo_collect_plugin_runs").jsonColumns(["errors"]);
|
|
174
173
|
await adapter.query(qb, "POST", row);
|
|
175
174
|
}
|
|
176
175
|
async function updateRunRow(adapter, run_id, result) {
|
|
177
|
-
const qb = new QueryBuilder2().from("hazo_collect_plugin_runs").where("run_id", "eq", run_id);
|
|
176
|
+
const qb = new QueryBuilder2().from("hazo_collect_plugin_runs").where("run_id", "eq", run_id).jsonColumns(["errors", "metrics"]);
|
|
178
177
|
await adapter.query(qb, "PATCH", {
|
|
179
178
|
status: result.status,
|
|
180
179
|
completed_at: result.completed_at,
|
|
181
180
|
records_fetched: result.records_fetched,
|
|
182
181
|
records_written: result.records_written,
|
|
183
182
|
watermark: result.watermark ?? null,
|
|
184
|
-
errors:
|
|
185
|
-
metrics: result.metrics
|
|
183
|
+
errors: result.errors,
|
|
184
|
+
metrics: result.metrics ?? null,
|
|
186
185
|
contract_version: result.contract_version ?? null
|
|
187
186
|
});
|
|
188
187
|
}
|
|
@@ -373,7 +372,7 @@ import { QueryBuilder as QueryBuilder4, wrapResult as wrapResult3 } from "hazo_c
|
|
|
373
372
|
import { readFileSync, readdirSync } from "fs";
|
|
374
373
|
import { resolve } from "path";
|
|
375
374
|
import { pathToFileURL } from "url";
|
|
376
|
-
import { QueryBuilder as QueryBuilder3 } from "hazo_connect/server";
|
|
375
|
+
import { QueryBuilder as QueryBuilder3, parseJsonbField } from "hazo_connect/server";
|
|
377
376
|
async function scanFolder(pluginsDir) {
|
|
378
377
|
const entries = readdirSync(pluginsDir, { withFileTypes: true });
|
|
379
378
|
const subdirs = entries.filter((e) => e.isDirectory());
|
|
@@ -402,7 +401,7 @@ async function discover(opts) {
|
|
|
402
401
|
const rows = await opts.adapter.query(qb);
|
|
403
402
|
const snapshotEntries = [];
|
|
404
403
|
for (const row of rows) {
|
|
405
|
-
const parsedManifest = parseManifest(
|
|
404
|
+
const parsedManifest = parseManifest(parseJsonbField(row.manifest));
|
|
406
405
|
const worker = getCollector(parsedManifest.name);
|
|
407
406
|
if (!worker) {
|
|
408
407
|
continue;
|
|
@@ -460,12 +459,12 @@ async function persistRegistry(adapter, entries, opts) {
|
|
|
460
459
|
kind: entry.manifest.kind,
|
|
461
460
|
version: entry.manifest.version,
|
|
462
461
|
runtime: entry.manifest.runtime,
|
|
463
|
-
manifest:
|
|
462
|
+
manifest: entry.manifest,
|
|
464
463
|
source: entry.source ?? "folder",
|
|
465
464
|
valid,
|
|
466
465
|
quarantine_reason: quarantineReason
|
|
467
466
|
};
|
|
468
|
-
const qb = opts?.reseed ? new QueryBuilder4().from("hazo_collect_plugin_registry").onConflict(["name"]).doUpdate() : new QueryBuilder4().from("hazo_collect_plugin_registry").onConflict(["name"]).doNothing();
|
|
467
|
+
const qb = opts?.reseed ? new QueryBuilder4().from("hazo_collect_plugin_registry").onConflict(["name"]).doUpdate().jsonColumns(["manifest"]) : new QueryBuilder4().from("hazo_collect_plugin_registry").onConflict(["name"]).doNothing().jsonColumns(["manifest"]);
|
|
469
468
|
await adapter.query(qb, "POST", row);
|
|
470
469
|
}
|
|
471
470
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_collect",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Collector-manager engine for the Ocdata platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"hazo_core": "^1.2.0",
|
|
47
|
-
"hazo_connect": "^3.
|
|
47
|
+
"hazo_connect": "^3.8.0",
|
|
48
48
|
"hazo_secure": "^1.3.0",
|
|
49
49
|
"react": "^18.0.0 || ^19.0.0",
|
|
50
50
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"@types/react": "^19.0.0",
|
|
76
76
|
"@types/react-dom": "^19.0.0",
|
|
77
77
|
"hazo_core": "^1.2.0",
|
|
78
|
-
"hazo_connect": "^3.
|
|
78
|
+
"hazo_connect": "^3.8.0",
|
|
79
79
|
"hazo_secure": "^1.3.0"
|
|
80
80
|
},
|
|
81
81
|
"keywords": [],
|