@gscdump/cloudflare 0.17.1 → 0.17.3

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/dist/index.d.mts CHANGED
@@ -56,6 +56,20 @@ interface AnalyticsEngineHooks {
56
56
  onR2Write?: (byteLength: number) => void;
57
57
  }
58
58
  declare function getAnalyticsEngine(env: AnalyticsEnv, db: any, hooks?: AnalyticsEngineHooks): ReturnType<typeof createStorageEngine> | null;
59
+ interface InflightDedupe<T> {
60
+ dedupe: (key: string, run: () => Promise<T>) => Promise<T>;
61
+ has: (key: string) => boolean;
62
+ clear: () => void;
63
+ }
64
+ declare function createInflightDedupe<T>(): InflightDedupe<T>;
65
+ interface HostedR2QueryKeyInput {
66
+ userId: string | number;
67
+ siteId: string;
68
+ state: unknown;
69
+ comparison?: unknown;
70
+ comparisonFilter?: string;
71
+ }
72
+ declare function getHostedR2QueryKey(input: HostedR2QueryKeyInput): string;
59
73
  interface PresignOptions {
60
74
  key: string;
61
75
  bucket: string;
@@ -70,4 +84,4 @@ declare function signSizeHint(env: AnalyticsEnv, key: string, bytes: number): Pr
70
84
  declare function verifySizeHint(env: AnalyticsEnv, key: string, bytes: number, providedHex: string): Promise<boolean>;
71
85
  declare function createDucklingsCodec(_env: AnalyticsEnv): ParquetCodec;
72
86
  declare function createDucklingsExecutor(env: AnalyticsEnv): QueryExecutor;
73
- export { type AnalyticsEngineHooks, type AnalyticsEnv, type PresignOptions, type Row, createDucklingsCodec, createDucklingsExecutor, createR2Presigner, getAnalyticsEngine, getWasmDuckDBFactory, resetWasmDuckDB, signSizeHint, useAnalyticsEnv, verifySizeHint };
87
+ export { type AnalyticsEngineHooks, type AnalyticsEnv, type HostedR2QueryKeyInput, type InflightDedupe, type PresignOptions, type Row, createDucklingsCodec, createDucklingsExecutor, createInflightDedupe, createR2Presigner, getAnalyticsEngine, getHostedR2QueryKey, getWasmDuckDBFactory, resetWasmDuckDB, signSizeHint, useAnalyticsEnv, verifySizeHint };
package/dist/index.mjs CHANGED
@@ -129,6 +129,50 @@ function useAnalyticsEnv(event) {
129
129
  statusMessage: "AnalyticsEnv not available — host must populate event.context.analyticsEnv or use the Cloudflare adapter"
130
130
  });
131
131
  }
132
+ function createInflightDedupe() {
133
+ const inflight = /* @__PURE__ */ new Map();
134
+ return {
135
+ dedupe(key, run) {
136
+ const existing = inflight.get(key);
137
+ if (existing) return existing;
138
+ const promise = run().finally(() => {
139
+ if (inflight.get(key) === promise) inflight.delete(key);
140
+ });
141
+ inflight.set(key, promise);
142
+ return promise;
143
+ },
144
+ has(key) {
145
+ return inflight.has(key);
146
+ },
147
+ clear() {
148
+ inflight.clear();
149
+ }
150
+ };
151
+ }
152
+ function stableStringify(value) {
153
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
154
+ if (value && typeof value === "object") return `{${Object.keys(value).sort().map((key) => {
155
+ return `${JSON.stringify(key)}:${stableStringify(value[key])}`;
156
+ }).join(",")}}`;
157
+ return JSON.stringify(value);
158
+ }
159
+ function hashString(value) {
160
+ let hash = 0;
161
+ for (let i = 0; i < value.length; i++) {
162
+ hash = (hash << 5) - hash + value.charCodeAt(i);
163
+ hash |= 0;
164
+ }
165
+ return Math.abs(hash).toString(36);
166
+ }
167
+ function getHostedR2QueryKey(input) {
168
+ return [
169
+ input.userId,
170
+ input.siteId,
171
+ hashString(stableStringify(input.state)),
172
+ input.comparison ? hashString(stableStringify(input.comparison)) : "",
173
+ input.comparisonFilter ?? ""
174
+ ].join(":");
175
+ }
132
176
  function createR2Presigner(env) {
133
177
  if (!env.R2_ACCESS_KEY_ID || !env.R2_SECRET_ACCESS_KEY) throw createError({
134
178
  statusCode: 500,
@@ -197,4 +241,4 @@ async function verifySizeHint(env, key, bytes, providedHex) {
197
241
  for (let i = 0; i < SIG_HEX_LEN; i++) diff |= expected.charCodeAt(i) ^ providedHex.charCodeAt(i);
198
242
  return diff === 0;
199
243
  }
200
- export { createDucklingsCodec, createDucklingsExecutor, createR2Presigner, getAnalyticsEngine, getWasmDuckDBFactory, resetWasmDuckDB, signSizeHint, useAnalyticsEnv, verifySizeHint };
244
+ export { createDucklingsCodec, createDucklingsExecutor, createInflightDedupe, createR2Presigner, getAnalyticsEngine, getHostedR2QueryKey, getWasmDuckDBFactory, resetWasmDuckDB, signSizeHint, useAnalyticsEnv, verifySizeHint };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gscdump/cloudflare",
3
3
  "type": "module",
4
- "version": "0.17.1",
4
+ "version": "0.17.3",
5
5
  "description": "Cloudflare-Workers-flavored helpers for the gscdump analytics stack: AnalyticsEnv binding contract, R2 SigV4 presigner, size-hint HMAC, DuckDB Workers shims, engine factory.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -40,8 +40,8 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "aws4fetch": "^1.0.20",
43
- "@gscdump/engine": "0.17.1",
44
- "@gscdump/engine-sqlite": "0.17.1"
43
+ "@gscdump/engine": "0.17.3",
44
+ "@gscdump/engine-sqlite": "0.17.3"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@cloudflare/workers-types": "^4.20260517.1",