@gscdump/engine 0.4.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 +21 -0
- package/README.md +53 -0
- package/dist/adapters/duckdb-node.d.mts +19 -0
- package/dist/adapters/duckdb-node.mjs +78 -0
- package/dist/adapters/filesystem.d.mts +206 -0
- package/dist/adapters/filesystem.mjs +320 -0
- package/dist/adapters/http.d.mts +227 -0
- package/dist/adapters/http.mjs +119 -0
- package/dist/adapters/hyparquet.d.mts +107 -0
- package/dist/adapters/hyparquet.mjs +250 -0
- package/dist/adapters/inspection-sqlite-browser.d.mts +9 -0
- package/dist/adapters/inspection-sqlite-browser.mjs +42 -0
- package/dist/adapters/inspection-sqlite-node.d.mts +9 -0
- package/dist/adapters/inspection-sqlite-node.mjs +32 -0
- package/dist/adapters/node-harness.d.mts +334 -0
- package/dist/adapters/node-harness.mjs +1907 -0
- package/dist/adapters/r2-manifest.d.mts +227 -0
- package/dist/adapters/r2-manifest.mjs +355 -0
- package/dist/adapters/r2.d.mts +93 -0
- package/dist/adapters/r2.mjs +65 -0
- package/dist/arrow-utils.d.mts +14 -0
- package/dist/arrow-utils.mjs +8 -0
- package/dist/contracts.d.mts +436 -0
- package/dist/contracts.mjs +1 -0
- package/dist/entities.d.mts +238 -0
- package/dist/entities.mjs +359 -0
- package/dist/index.d.mts +1849 -0
- package/dist/index.mjs +1976 -0
- package/dist/ingest.d.mts +96 -0
- package/dist/ingest.mjs +187 -0
- package/dist/planner.d.mts +16 -0
- package/dist/planner.mjs +321 -0
- package/dist/resolver/index.d.mts +207 -0
- package/dist/resolver/index.mjs +869 -0
- package/dist/rollups.d.mts +207 -0
- package/dist/rollups.mjs +553 -0
- package/dist/schema.d.mts +1258 -0
- package/dist/schema.mjs +139 -0
- package/dist/scope.d.mts +38 -0
- package/dist/scope.mjs +28 -0
- package/dist/snapshot.d.mts +14 -0
- package/dist/snapshot.mjs +1 -0
- package/dist/sql-bind.d.mts +19 -0
- package/dist/sql-bind.mjs +92 -0
- package/dist/sql-fragments.d.mts +21 -0
- package/dist/sql-fragments.mjs +13 -0
- package/package.json +168 -0
package/dist/schema.mjs
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { date, doublePrecision, getTableConfig, integer, pgTable, varchar } from "drizzle-orm/pg-core";
|
|
2
|
+
function metricCols() {
|
|
3
|
+
return {
|
|
4
|
+
clicks: integer("clicks").notNull(),
|
|
5
|
+
impressions: integer("impressions").notNull(),
|
|
6
|
+
sum_position: doublePrecision("sum_position").notNull()
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
const dateCol = () => date("date").notNull();
|
|
10
|
+
const pages = pgTable("pages", {
|
|
11
|
+
url: varchar("url").notNull(),
|
|
12
|
+
date: dateCol(),
|
|
13
|
+
...metricCols()
|
|
14
|
+
});
|
|
15
|
+
const keywords = pgTable("keywords", {
|
|
16
|
+
query: varchar("query").notNull(),
|
|
17
|
+
query_canonical: varchar("query_canonical"),
|
|
18
|
+
date: dateCol(),
|
|
19
|
+
...metricCols()
|
|
20
|
+
});
|
|
21
|
+
const countries = pgTable("countries", {
|
|
22
|
+
country: varchar("country").notNull(),
|
|
23
|
+
date: dateCol(),
|
|
24
|
+
...metricCols()
|
|
25
|
+
});
|
|
26
|
+
const devices = pgTable("devices", {
|
|
27
|
+
device: varchar("device").notNull(),
|
|
28
|
+
date: dateCol(),
|
|
29
|
+
...metricCols()
|
|
30
|
+
});
|
|
31
|
+
const page_keywords = pgTable("page_keywords", {
|
|
32
|
+
url: varchar("url").notNull(),
|
|
33
|
+
query: varchar("query").notNull(),
|
|
34
|
+
query_canonical: varchar("query_canonical"),
|
|
35
|
+
date: dateCol(),
|
|
36
|
+
...metricCols()
|
|
37
|
+
});
|
|
38
|
+
const search_appearance = pgTable("search_appearance", {
|
|
39
|
+
searchAppearance: varchar("searchAppearance").notNull(),
|
|
40
|
+
date: dateCol(),
|
|
41
|
+
...metricCols()
|
|
42
|
+
});
|
|
43
|
+
const drizzleSchema = {
|
|
44
|
+
pages,
|
|
45
|
+
keywords,
|
|
46
|
+
countries,
|
|
47
|
+
devices,
|
|
48
|
+
page_keywords,
|
|
49
|
+
search_appearance
|
|
50
|
+
};
|
|
51
|
+
const TABLE_METADATA = {
|
|
52
|
+
pages: {
|
|
53
|
+
sortKey: ["date", "url"],
|
|
54
|
+
version: 1
|
|
55
|
+
},
|
|
56
|
+
keywords: {
|
|
57
|
+
sortKey: ["date", "query"],
|
|
58
|
+
version: 2
|
|
59
|
+
},
|
|
60
|
+
countries: {
|
|
61
|
+
sortKey: ["date", "country"],
|
|
62
|
+
version: 1
|
|
63
|
+
},
|
|
64
|
+
devices: {
|
|
65
|
+
sortKey: ["date", "device"],
|
|
66
|
+
version: 1
|
|
67
|
+
},
|
|
68
|
+
page_keywords: {
|
|
69
|
+
sortKey: [
|
|
70
|
+
"date",
|
|
71
|
+
"url",
|
|
72
|
+
"query"
|
|
73
|
+
],
|
|
74
|
+
version: 2
|
|
75
|
+
},
|
|
76
|
+
search_appearance: {
|
|
77
|
+
sortKey: ["date", "searchAppearance"],
|
|
78
|
+
version: 1
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
function pgSqlTypeToColumnType(sqlType) {
|
|
82
|
+
const t = sqlType.toLowerCase();
|
|
83
|
+
if (t.startsWith("varchar") || t === "text" || t.startsWith("char")) return "VARCHAR";
|
|
84
|
+
if (t === "date" || t.startsWith("timestamp")) return "DATE";
|
|
85
|
+
if (t.startsWith("double") || t === "real" || t.startsWith("numeric") || t.startsWith("decimal")) return "DOUBLE";
|
|
86
|
+
if (t === "bigint" || t === "int8") return "BIGINT";
|
|
87
|
+
if (t === "integer" || t === "int" || t === "int4" || t === "smallint" || t === "int2") return "INTEGER";
|
|
88
|
+
throw new Error(`unmapped pg type '${sqlType}' — extend pgSqlTypeToColumnType in @gscdump/engine/schema`);
|
|
89
|
+
}
|
|
90
|
+
function tableSchemaFrom(tableName) {
|
|
91
|
+
const columns = getTableConfig(drizzleSchema[tableName]).columns.map((col) => ({
|
|
92
|
+
name: col.name,
|
|
93
|
+
type: pgSqlTypeToColumnType(col.getSQLType()),
|
|
94
|
+
nullable: !col.notNull
|
|
95
|
+
}));
|
|
96
|
+
const meta = TABLE_METADATA[tableName];
|
|
97
|
+
return {
|
|
98
|
+
name: tableName,
|
|
99
|
+
columns,
|
|
100
|
+
sortKey: meta.sortKey,
|
|
101
|
+
version: meta.version
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const METRIC_TABLES = [
|
|
105
|
+
"pages",
|
|
106
|
+
"keywords",
|
|
107
|
+
"countries",
|
|
108
|
+
"devices",
|
|
109
|
+
"page_keywords",
|
|
110
|
+
"search_appearance"
|
|
111
|
+
];
|
|
112
|
+
const SCHEMAS = Object.fromEntries(METRIC_TABLES.map((t) => [t, tableSchemaFrom(t)]));
|
|
113
|
+
function currentSchemaVersion(table) {
|
|
114
|
+
return SCHEMAS[table].version;
|
|
115
|
+
}
|
|
116
|
+
function schemaFor(table) {
|
|
117
|
+
return SCHEMAS[table];
|
|
118
|
+
}
|
|
119
|
+
function allTables() {
|
|
120
|
+
return METRIC_TABLES;
|
|
121
|
+
}
|
|
122
|
+
function inferTable(dimensions) {
|
|
123
|
+
const dims = new Set(dimensions);
|
|
124
|
+
const hasPage = dims.has("page");
|
|
125
|
+
const hasQuery = dims.has("query");
|
|
126
|
+
if (hasPage && hasQuery) return "page_keywords";
|
|
127
|
+
if (hasQuery) return "keywords";
|
|
128
|
+
if (hasPage) return "pages";
|
|
129
|
+
if (dims.has("country")) return "countries";
|
|
130
|
+
if (dims.has("device")) return "devices";
|
|
131
|
+
if (dims.has("searchAppearance")) return "search_appearance";
|
|
132
|
+
return "keywords";
|
|
133
|
+
}
|
|
134
|
+
function dimensionToColumn(dim, _table) {
|
|
135
|
+
if (dim === "page") return "url";
|
|
136
|
+
if (dim === "queryCanonical") return "query_canonical";
|
|
137
|
+
return dim;
|
|
138
|
+
}
|
|
139
|
+
export { SCHEMAS, TABLE_METADATA, allTables, countries, currentSchemaVersion, devices, dimensionToColumn, drizzleSchema, inferTable, keywords, page_keywords, pages, schemaFor, search_appearance };
|
package/dist/scope.d.mts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SQL } from "drizzle-orm";
|
|
2
|
+
/**
|
|
3
|
+
* Structural subset of `ResolvedWindow` from `@gscdump/analysis/period`.
|
|
4
|
+
* Inlined here so engine doesn't take a downstream dependency on analysis;
|
|
5
|
+
* any object with `start`/`end` strings (and optional `days`) satisfies it.
|
|
6
|
+
*/
|
|
7
|
+
interface ResolvedWindow {
|
|
8
|
+
start: string;
|
|
9
|
+
end: string;
|
|
10
|
+
days?: number;
|
|
11
|
+
}
|
|
12
|
+
interface ScopedRunnerOptions {
|
|
13
|
+
siteId?: string;
|
|
14
|
+
window?: ResolvedWindow;
|
|
15
|
+
/** Inclusive lower bound for `date`. Ignored if `window` is supplied. */
|
|
16
|
+
startDate?: string;
|
|
17
|
+
/** Inclusive upper bound for `date`. Ignored if `window` is supplied. */
|
|
18
|
+
endDate?: string;
|
|
19
|
+
}
|
|
20
|
+
interface TableScope {
|
|
21
|
+
wherePredicates: SQL[];
|
|
22
|
+
window?: ResolvedWindow;
|
|
23
|
+
siteId?: string;
|
|
24
|
+
}
|
|
25
|
+
declare function buildTableScope(table: Record<string, any>, opts: ScopedRunnerOptions): TableScope;
|
|
26
|
+
declare function mergeScope(scope: TableScope, ...extra: SQL[]): SQL | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Bind `buildTableScope` + `mergeScope` to a specific drizzle schema. Engine
|
|
29
|
+
* adapters (`engine-sqlite`, `engine-wasm`) call this once at module load and
|
|
30
|
+
* re-export the returned `scopeFor` / `mergeScope` so consumers get a typed
|
|
31
|
+
* `keyof Schema` table parameter without each adapter re-implementing the
|
|
32
|
+
* pass-through wrapper.
|
|
33
|
+
*/
|
|
34
|
+
declare function createScopedHelpers<S extends Record<string, Record<string, any>>>(schema: S): {
|
|
35
|
+
scopeFor: (table: keyof S, opts: ScopedRunnerOptions) => TableScope;
|
|
36
|
+
mergeScope: typeof mergeScope;
|
|
37
|
+
};
|
|
38
|
+
export { ResolvedWindow, ScopedRunnerOptions, TableScope, buildTableScope, createScopedHelpers, mergeScope };
|
package/dist/scope.mjs
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { and, eq, gte, lte } from "drizzle-orm";
|
|
2
|
+
function buildTableScope(table, opts) {
|
|
3
|
+
const predicates = [];
|
|
4
|
+
if (opts.siteId && "site_id" in table) predicates.push(eq(table.site_id, opts.siteId));
|
|
5
|
+
if ("date" in table) {
|
|
6
|
+
const start = opts.window?.start ?? opts.startDate;
|
|
7
|
+
const end = opts.window?.end ?? opts.endDate;
|
|
8
|
+
if (start) predicates.push(gte(table.date, start));
|
|
9
|
+
if (end) predicates.push(lte(table.date, end));
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
wherePredicates: predicates,
|
|
13
|
+
window: opts.window,
|
|
14
|
+
siteId: opts.siteId
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function mergeScope(scope, ...extra) {
|
|
18
|
+
const all = [...scope.wherePredicates, ...extra].filter(Boolean);
|
|
19
|
+
if (all.length === 0) return void 0;
|
|
20
|
+
return and(...all);
|
|
21
|
+
}
|
|
22
|
+
function createScopedHelpers(schema) {
|
|
23
|
+
return {
|
|
24
|
+
scopeFor: (table, opts) => buildTableScope(schema[table], opts),
|
|
25
|
+
mergeScope
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export { buildTableScope, createScopedHelpers, mergeScope };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describes a hot/cold snapshot set. Produced by the snapshot builder,
|
|
3
|
+
* consumed by `attachSnapshotIndex`. Filenames are derived from `cold`
|
|
4
|
+
* via `cold-${yearMonth}.duckdb`; hot is always `hot.duckdb` when
|
|
5
|
+
* `hot: true`.
|
|
6
|
+
*/
|
|
7
|
+
interface SnapshotIndex {
|
|
8
|
+
version: 1;
|
|
9
|
+
builtAt: string;
|
|
10
|
+
cold: string[];
|
|
11
|
+
hot: boolean;
|
|
12
|
+
hotDays: number;
|
|
13
|
+
}
|
|
14
|
+
export { SnapshotIndex };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Escape single quotes for inlining inside a SQL string literal (SQL-standard `''` escaping). */
|
|
2
|
+
declare function sqlEscape(s: string): string;
|
|
3
|
+
declare function formatLiteral(value: unknown): string;
|
|
4
|
+
/**
|
|
5
|
+
* Replace `?` and `$N` placeholders with inline SQL literals. Single-quoted
|
|
6
|
+
* string regions and SQL comments (`-- line`, `/* block *\/`) are left
|
|
7
|
+
* untouched — a `?` or `$1` inside `'foo?bar'` or a comment is not a
|
|
8
|
+
* placeholder. SQL-standard `''` escape handling; no `\`-escape or
|
|
9
|
+
* dialect-specific identifier quoting.
|
|
10
|
+
*
|
|
11
|
+
* `?` placeholders bind sequentially against `params`. `$N` (Postgres-style)
|
|
12
|
+
* binds explicitly to `params[N-1]`. The two styles must not be mixed in the
|
|
13
|
+
* same query.
|
|
14
|
+
*
|
|
15
|
+
* Throws when placeholder count and params length disagree, or when a `$N`
|
|
16
|
+
* index is out of range.
|
|
17
|
+
*/
|
|
18
|
+
declare function bindLiterals(sql: string, params: readonly unknown[]): string;
|
|
19
|
+
export { bindLiterals, formatLiteral, sqlEscape };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
function containsDisallowedControlChars(value) {
|
|
2
|
+
for (let i = 0; i < value.length; i++) {
|
|
3
|
+
const code = value.charCodeAt(i);
|
|
4
|
+
if (code >= 0 && code <= 8 || code === 11 || code === 12 || code >= 14 && code <= 31) return true;
|
|
5
|
+
}
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
function sqlEscape(s) {
|
|
9
|
+
return s.replace(/'/g, "''");
|
|
10
|
+
}
|
|
11
|
+
function formatLiteral(value) {
|
|
12
|
+
if (value == null) return "NULL";
|
|
13
|
+
if (typeof value === "number") {
|
|
14
|
+
if (!Number.isFinite(value)) throw new Error(`cannot inline non-finite number: ${value}`);
|
|
15
|
+
return String(value);
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
|
|
18
|
+
if (typeof value === "bigint") return value.toString();
|
|
19
|
+
if (value instanceof Date) return `'${value.toISOString()}'`;
|
|
20
|
+
if (typeof value === "string") {
|
|
21
|
+
if (containsDisallowedControlChars(value)) throw new Error("string literal contains disallowed control characters");
|
|
22
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`cannot inline value of type ${typeof value}`);
|
|
25
|
+
}
|
|
26
|
+
function bindLiterals(sql, params) {
|
|
27
|
+
if (params.length === 0) return sql;
|
|
28
|
+
let out = "";
|
|
29
|
+
let i = 0;
|
|
30
|
+
let qmarkIdx = 0;
|
|
31
|
+
const usedDollar = /* @__PURE__ */ new Set();
|
|
32
|
+
let inString = false;
|
|
33
|
+
while (i < sql.length) {
|
|
34
|
+
const c = sql[i];
|
|
35
|
+
if (inString) {
|
|
36
|
+
out += c;
|
|
37
|
+
if (c === "'") {
|
|
38
|
+
if (sql[i + 1] === "'") {
|
|
39
|
+
out += "'";
|
|
40
|
+
i += 2;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
inString = false;
|
|
44
|
+
}
|
|
45
|
+
i++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (c === "-" && sql[i + 1] === "-") {
|
|
49
|
+
const nl = sql.indexOf("\n", i + 2);
|
|
50
|
+
const end = nl === -1 ? sql.length : nl;
|
|
51
|
+
out += sql.slice(i, end);
|
|
52
|
+
i = end;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (c === "/" && sql[i + 1] === "*") {
|
|
56
|
+
const close = sql.indexOf("*/", i + 2);
|
|
57
|
+
const end = close === -1 ? sql.length : close + 2;
|
|
58
|
+
out += sql.slice(i, end);
|
|
59
|
+
i = end;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (c === "'") {
|
|
63
|
+
inString = true;
|
|
64
|
+
out += c;
|
|
65
|
+
i++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (c === "?") {
|
|
69
|
+
if (qmarkIdx >= params.length) throw new Error(`bindLiterals: more '?' placeholders than params (have ${params.length})`);
|
|
70
|
+
out += formatLiteral(params[qmarkIdx++]);
|
|
71
|
+
i++;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (c === "$" && sql[i + 1] && sql[i + 1] >= "0" && sql[i + 1] <= "9") {
|
|
75
|
+
let j = i + 1;
|
|
76
|
+
while (j < sql.length && sql[j] >= "0" && sql[j] <= "9") j++;
|
|
77
|
+
const n = Number(sql.slice(i + 1, j));
|
|
78
|
+
if (n < 1 || n > params.length) throw new Error(`bindLiterals: $${n} out of range (have ${params.length} params)`);
|
|
79
|
+
usedDollar.add(n - 1);
|
|
80
|
+
out += formatLiteral(params[n - 1]);
|
|
81
|
+
i = j;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
out += c;
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
if (qmarkIdx > 0 && usedDollar.size > 0) throw new Error("bindLiterals: cannot mix '?' and '$N' placeholders in the same query");
|
|
88
|
+
const used = qmarkIdx > 0 ? qmarkIdx : usedDollar.size;
|
|
89
|
+
if (used !== params.length) throw new Error(`bindLiterals: ${params.length - used} params unused`);
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
export { bindLiterals, formatLiteral, sqlEscape };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Metric } from "gscdump/query";
|
|
2
|
+
/**
|
|
3
|
+
* Standard SQL `LIKE` escape. Backslash is the explicit ESCAPE char so
|
|
4
|
+
* literal `%`, `_`, and `\` survive a `contains` predicate unchanged.
|
|
5
|
+
*/
|
|
6
|
+
declare function escapeLike(value: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Per-metric raw SQL aggregate expression.
|
|
9
|
+
*
|
|
10
|
+
* - `clicks` / `impressions` cast to DOUBLE so DuckDB SUM doesn't return
|
|
11
|
+
* BIGINT (which loses through JSON / Workers RPC).
|
|
12
|
+
* - `position` reverses the ingestion offset (`sum_position = position - 1`
|
|
13
|
+
* summed; divide by impressions and add 1 back).
|
|
14
|
+
*/
|
|
15
|
+
declare const METRIC_EXPR: Record<Metric, string>;
|
|
16
|
+
/**
|
|
17
|
+
* Top-level page predicate: matches paths with at most one `/`. Parameterized
|
|
18
|
+
* on the resolved column expression so drizzle can pass a column ref.
|
|
19
|
+
*/
|
|
20
|
+
declare function topLevelPagePredicateSql(pathExpr: string): string;
|
|
21
|
+
export { METRIC_EXPR, escapeLike, topLevelPagePredicateSql };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function escapeLike(value) {
|
|
2
|
+
return value.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
3
|
+
}
|
|
4
|
+
const METRIC_EXPR = {
|
|
5
|
+
clicks: "CAST(SUM(clicks) AS DOUBLE)",
|
|
6
|
+
impressions: "CAST(SUM(impressions) AS DOUBLE)",
|
|
7
|
+
ctr: "CAST(SUM(clicks) AS DOUBLE) / NULLIF(SUM(impressions), 0)",
|
|
8
|
+
position: "SUM(sum_position) / NULLIF(SUM(impressions), 0) + 1"
|
|
9
|
+
};
|
|
10
|
+
function topLevelPagePredicateSql(pathExpr) {
|
|
11
|
+
return `LENGTH(${pathExpr}) - LENGTH(REPLACE(${pathExpr}, '/', '')) <= 1`;
|
|
12
|
+
}
|
|
13
|
+
export { METRIC_EXPR, escapeLike, topLevelPagePredicateSql };
|
package/package.json
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gscdump/engine",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.4.0",
|
|
5
|
+
"description": "Append-only Parquet/DuckDB storage engine + planner + adapters for the gscdump pipeline. Node + edge runtimes; opt-in heavy peers.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Harlan Wilton",
|
|
8
|
+
"email": "harlan@harlanzw.com",
|
|
9
|
+
"url": "https://harlanzw.com/"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"funding": "https://github.com/sponsors/harlan-zw",
|
|
13
|
+
"homepage": "https://github.com/harlan-zw/gscdump/tree/main/packages/engine#readme",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/harlan-zw/gscdump.git",
|
|
17
|
+
"directory": "packages/engine"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/harlan-zw/gscdump/issues"
|
|
21
|
+
},
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.mts",
|
|
26
|
+
"import": "./dist/index.mjs"
|
|
27
|
+
},
|
|
28
|
+
"./contracts": {
|
|
29
|
+
"types": "./dist/contracts.d.mts",
|
|
30
|
+
"import": "./dist/contracts.mjs"
|
|
31
|
+
},
|
|
32
|
+
"./snapshot": {
|
|
33
|
+
"types": "./dist/snapshot.d.mts",
|
|
34
|
+
"import": "./dist/snapshot.mjs"
|
|
35
|
+
},
|
|
36
|
+
"./planner": {
|
|
37
|
+
"types": "./dist/planner.d.mts",
|
|
38
|
+
"import": "./dist/planner.mjs"
|
|
39
|
+
},
|
|
40
|
+
"./schema": {
|
|
41
|
+
"types": "./dist/schema.d.mts",
|
|
42
|
+
"import": "./dist/schema.mjs"
|
|
43
|
+
},
|
|
44
|
+
"./ingest": {
|
|
45
|
+
"types": "./dist/ingest.d.mts",
|
|
46
|
+
"import": "./dist/ingest.mjs"
|
|
47
|
+
},
|
|
48
|
+
"./sql": {
|
|
49
|
+
"types": "./dist/sql-bind.d.mts",
|
|
50
|
+
"import": "./dist/sql-bind.mjs"
|
|
51
|
+
},
|
|
52
|
+
"./sql-fragments": {
|
|
53
|
+
"types": "./dist/sql-fragments.d.mts",
|
|
54
|
+
"import": "./dist/sql-fragments.mjs"
|
|
55
|
+
},
|
|
56
|
+
"./rollups": {
|
|
57
|
+
"types": "./dist/rollups.d.mts",
|
|
58
|
+
"import": "./dist/rollups.mjs"
|
|
59
|
+
},
|
|
60
|
+
"./entities": {
|
|
61
|
+
"types": "./dist/entities.d.mts",
|
|
62
|
+
"import": "./dist/entities.mjs"
|
|
63
|
+
},
|
|
64
|
+
"./node": {
|
|
65
|
+
"types": "./dist/adapters/duckdb-node.d.mts",
|
|
66
|
+
"import": "./dist/adapters/duckdb-node.mjs"
|
|
67
|
+
},
|
|
68
|
+
"./node-harness": {
|
|
69
|
+
"types": "./dist/adapters/node-harness.d.mts",
|
|
70
|
+
"import": "./dist/adapters/node-harness.mjs"
|
|
71
|
+
},
|
|
72
|
+
"./filesystem": {
|
|
73
|
+
"types": "./dist/adapters/filesystem.d.mts",
|
|
74
|
+
"import": "./dist/adapters/filesystem.mjs"
|
|
75
|
+
},
|
|
76
|
+
"./http": {
|
|
77
|
+
"types": "./dist/adapters/http.d.mts",
|
|
78
|
+
"import": "./dist/adapters/http.mjs"
|
|
79
|
+
},
|
|
80
|
+
"./hyparquet": {
|
|
81
|
+
"types": "./dist/adapters/hyparquet.d.mts",
|
|
82
|
+
"import": "./dist/adapters/hyparquet.mjs"
|
|
83
|
+
},
|
|
84
|
+
"./r2": {
|
|
85
|
+
"types": "./dist/adapters/r2.d.mts",
|
|
86
|
+
"import": "./dist/adapters/r2.mjs"
|
|
87
|
+
},
|
|
88
|
+
"./r2-manifest": {
|
|
89
|
+
"types": "./dist/adapters/r2-manifest.d.mts",
|
|
90
|
+
"import": "./dist/adapters/r2-manifest.mjs"
|
|
91
|
+
},
|
|
92
|
+
"./resolver": {
|
|
93
|
+
"types": "./dist/resolver/index.d.mts",
|
|
94
|
+
"import": "./dist/resolver/index.mjs"
|
|
95
|
+
},
|
|
96
|
+
"./scope": {
|
|
97
|
+
"types": "./dist/scope.d.mts",
|
|
98
|
+
"import": "./dist/scope.mjs"
|
|
99
|
+
},
|
|
100
|
+
"./arrow": {
|
|
101
|
+
"types": "./dist/arrow-utils.d.mts",
|
|
102
|
+
"import": "./dist/arrow-utils.mjs"
|
|
103
|
+
},
|
|
104
|
+
"./inspection-sqlite-node": {
|
|
105
|
+
"types": "./dist/adapters/inspection-sqlite-node.d.mts",
|
|
106
|
+
"import": "./dist/adapters/inspection-sqlite-node.mjs"
|
|
107
|
+
},
|
|
108
|
+
"./inspection-sqlite-browser": {
|
|
109
|
+
"types": "./dist/adapters/inspection-sqlite-browser.d.mts",
|
|
110
|
+
"import": "./dist/adapters/inspection-sqlite-browser.mjs"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"main": "./dist/index.mjs",
|
|
114
|
+
"types": "./dist/index.d.mts",
|
|
115
|
+
"files": [
|
|
116
|
+
"dist"
|
|
117
|
+
],
|
|
118
|
+
"engines": {
|
|
119
|
+
"node": ">=18"
|
|
120
|
+
},
|
|
121
|
+
"peerDependencies": {
|
|
122
|
+
"@duckdb/duckdb-wasm": "^1.32.0",
|
|
123
|
+
"better-sqlite3": "^12.9.0",
|
|
124
|
+
"hyparquet": "^1.25.1",
|
|
125
|
+
"hyparquet-writer": "^0.13.0",
|
|
126
|
+
"wa-sqlite": "^1.0.0"
|
|
127
|
+
},
|
|
128
|
+
"peerDependenciesMeta": {
|
|
129
|
+
"@duckdb/duckdb-wasm": {
|
|
130
|
+
"optional": true
|
|
131
|
+
},
|
|
132
|
+
"better-sqlite3": {
|
|
133
|
+
"optional": true
|
|
134
|
+
},
|
|
135
|
+
"hyparquet": {
|
|
136
|
+
"optional": true
|
|
137
|
+
},
|
|
138
|
+
"hyparquet-writer": {
|
|
139
|
+
"optional": true
|
|
140
|
+
},
|
|
141
|
+
"wa-sqlite": {
|
|
142
|
+
"optional": true
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"dependencies": {
|
|
146
|
+
"drizzle-orm": "^0.45.2",
|
|
147
|
+
"proper-lockfile": "^4.1.2",
|
|
148
|
+
"gscdump": "0.4.0"
|
|
149
|
+
},
|
|
150
|
+
"devDependencies": {
|
|
151
|
+
"@duckdb/duckdb-wasm": "^1.32.0",
|
|
152
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
153
|
+
"aws4fetch": "^1.0.20",
|
|
154
|
+
"better-sqlite3": "^12.9.0",
|
|
155
|
+
"hyparquet": "^1.25.1",
|
|
156
|
+
"hyparquet-writer": "^0.13.0",
|
|
157
|
+
"tsx": "^4.19.2",
|
|
158
|
+
"vitest": "^4.1.5"
|
|
159
|
+
},
|
|
160
|
+
"scripts": {
|
|
161
|
+
"dev": "obuild --stub",
|
|
162
|
+
"build": "obuild",
|
|
163
|
+
"typecheck": "tsc --noEmit",
|
|
164
|
+
"test": "vitest",
|
|
165
|
+
"r2-harness": "tsx scripts/r2-contention-harness.ts",
|
|
166
|
+
"backfill-audit": "tsx scripts/backfill-audit.ts"
|
|
167
|
+
}
|
|
168
|
+
}
|