gencow 0.1.151 → 0.1.153

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gencow",
3
- "version": "0.1.151",
3
+ "version": "0.1.153",
4
4
  "description": "Gencow — AI Backend Engine",
5
5
  "type": "module",
6
6
  "bin": {
package/server/index.js CHANGED
@@ -20610,8 +20610,8 @@ var init_pdf = __esm({
20610
20610
  this._readCapability = Promise.withResolvers();
20611
20611
  this._headersCapability = Promise.withResolvers();
20612
20612
  const fs4 = process.getBuiltinModule("fs");
20613
- fs4.promises.lstat(this._url).then((stat4) => {
20614
- this._contentLength = stat4.size;
20613
+ fs4.promises.lstat(this._url).then((stat5) => {
20614
+ this._contentLength = stat5.size;
20615
20615
  this._setReadableStream(fs4.createReadStream(this._url));
20616
20616
  this._headersCapability.resolve();
20617
20617
  }, (error) => {
@@ -88535,14 +88535,20 @@ var DEFAULT_TIMEOUT_RESTART_THRESHOLD = 3;
88535
88535
  var DEFAULT_TIMEOUT_RESTART_WINDOW_MS = 6e4;
88536
88536
  var DEFAULT_TIMEOUT_RESTART_DELAY_MS = 250;
88537
88537
  var DEFAULT_TIMEOUT_RESTART_KINDS = ["query", "mutation"];
88538
+ var DEFAULT_FUNCTION_SLOW_LOG_MS = 1e4;
88538
88539
  var timeoutWindowStartMs = 0;
88539
88540
  var timeoutCountInWindow = 0;
88540
88541
  var timeoutRestartScheduled = false;
88541
88542
  var timeoutFunctionNames = [];
88543
+ var functionInvocationSequence = 0;
88542
88544
  function parsePositiveInteger(value, fallback) {
88543
88545
  const parsed = Number(value);
88544
88546
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
88545
88547
  }
88548
+ function parseNonNegativeInteger(value, fallback) {
88549
+ const parsed = Number(value);
88550
+ return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
88551
+ }
88546
88552
  function parseRestartKinds(value) {
88547
88553
  if (!value?.trim()) return [...DEFAULT_TIMEOUT_RESTART_KINDS];
88548
88554
  const allowed = /* @__PURE__ */ new Set(["query", "mutation", "httpAction", "cron"]);
@@ -88569,6 +88575,20 @@ function resolveFunctionTimeoutRestartPolicy(env2 = process.env) {
88569
88575
  kinds: parseRestartKinds(env2.GENCOW_FUNCTION_TIMEOUT_RESTART_KINDS)
88570
88576
  };
88571
88577
  }
88578
+ function resolveFunctionSlowLogMs(env2 = process.env) {
88579
+ return parseNonNegativeInteger(env2.GENCOW_FUNCTION_SLOW_LOG_MS, DEFAULT_FUNCTION_SLOW_LOG_MS);
88580
+ }
88581
+ function nextFunctionInvocationId() {
88582
+ functionInvocationSequence = functionInvocationSequence >= Number.MAX_SAFE_INTEGER ? 1 : functionInvocationSequence + 1;
88583
+ return `${Date.now().toString(36)}-${functionInvocationSequence}`;
88584
+ }
88585
+ function formatErrorForRuntimeLog(error) {
88586
+ const record = error;
88587
+ const name = typeof record?.name === "string" ? record.name : "Error";
88588
+ const code = typeof record?.code === "string" ? ` code=${record.code}` : "";
88589
+ const message = typeof record?.message === "string" ? record.message.replace(/\s+/g, " ").slice(0, 300) : String(error).replace(/\s+/g, " ").slice(0, 300);
88590
+ return `name=${name}${code} message="${message}"`;
88591
+ }
88572
88592
  function recordFunctionTimeout(event, runtime = {}) {
88573
88593
  const env2 = runtime.env ?? process.env;
88574
88594
  const policy = resolveFunctionTimeoutRestartPolicy(env2);
@@ -88600,13 +88620,40 @@ function recordFunctionTimeout(event, runtime = {}) {
88600
88620
  }
88601
88621
  async function executeWithTimeout(fn, type, functionName, timeouts = FUNCTION_TIMEOUTS, restartRuntime) {
88602
88622
  const timeoutMs = timeouts[type];
88623
+ const invocationId = nextFunctionInvocationId();
88624
+ const startedAt = Date.now();
88625
+ const logger2 = restartRuntime?.logger ?? console;
88626
+ const slowLogMs = resolveFunctionSlowLogMs(restartRuntime?.env);
88603
88627
  const controller = new AbortController();
88604
88628
  const timer = setTimeout(() => controller.abort(), timeoutMs);
88629
+ let timedOut = false;
88630
+ const work = Promise.resolve().then(fn);
88631
+ work.then(
88632
+ () => {
88633
+ if (!timedOut) return;
88634
+ const elapsedMs = Date.now() - startedAt;
88635
+ logger2.warn(
88636
+ `[runtime] function completed after timeout id=${invocationId} type=${type} name="${functionName}" elapsedMs=${elapsedMs} timeoutMs=${timeoutMs}`
88637
+ );
88638
+ },
88639
+ (error) => {
88640
+ if (!timedOut) return;
88641
+ const elapsedMs = Date.now() - startedAt;
88642
+ logger2.error(
88643
+ `[runtime] function failed after timeout id=${invocationId} type=${type} name="${functionName}" elapsedMs=${elapsedMs} timeoutMs=${timeoutMs} ${formatErrorForRuntimeLog(error)}`
88644
+ );
88645
+ }
88646
+ );
88605
88647
  try {
88606
- return await Promise.race([
88607
- fn(),
88648
+ const result2 = await Promise.race([
88649
+ work,
88608
88650
  new Promise((_3, reject2) => {
88609
88651
  controller.signal.addEventListener("abort", () => {
88652
+ timedOut = true;
88653
+ const elapsedMs2 = Date.now() - startedAt;
88654
+ logger2.error(
88655
+ `[runtime] function timeout id=${invocationId} type=${type} name="${functionName}" elapsedMs=${elapsedMs2} timeoutMs=${timeoutMs}`
88656
+ );
88610
88657
  recordFunctionTimeout({ type, functionName, timeoutMs }, restartRuntime);
88611
88658
  const error = new Error(
88612
88659
  `Function "${functionName}" exceeded ${timeoutMs / 1e3}s time limit. Split into smaller mutations and call them sequentially from the frontend. Limits: query 30s, mutation 30s, httpAction 5min, cron 10min.`
@@ -88616,6 +88663,22 @@ async function executeWithTimeout(fn, type, functionName, timeouts = FUNCTION_TI
88616
88663
  });
88617
88664
  })
88618
88665
  ]);
88666
+ const elapsedMs = Date.now() - startedAt;
88667
+ if (slowLogMs > 0 && elapsedMs >= slowLogMs) {
88668
+ logger2.warn(
88669
+ `[runtime] function slow id=${invocationId} type=${type} name="${functionName}" elapsedMs=${elapsedMs} thresholdMs=${slowLogMs}`
88670
+ );
88671
+ }
88672
+ return result2;
88673
+ } catch (error) {
88674
+ const elapsedMs = Date.now() - startedAt;
88675
+ const code = error?.code;
88676
+ if (code !== "FUNCTION_TIMEOUT" && slowLogMs > 0 && elapsedMs >= slowLogMs) {
88677
+ logger2.warn(
88678
+ `[runtime] function slow failed id=${invocationId} type=${type} name="${functionName}" elapsedMs=${elapsedMs} thresholdMs=${slowLogMs} ${formatErrorForRuntimeLog(error)}`
88679
+ );
88680
+ }
88681
+ throw error;
88619
88682
  } finally {
88620
88683
  clearTimeout(timer);
88621
88684
  }
@@ -92725,7 +92788,9 @@ var getNodeRouteMetricsSnapshot = mod2.getNodeRouteMetricsSnapshot;
92725
92788
  var resetNodeRouteMetricsForTests = mod2.resetNodeRouteMetricsForTests;
92726
92789
 
92727
92790
  // ../server/src/server-platform-static-file.ts
92728
- import { join as join2 } from "path";
92791
+ import { extname as extname2, join as join2 } from "path";
92792
+ import { brotliCompressSync, gzipSync } from "zlib";
92793
+ import { stat } from "fs/promises";
92729
92794
 
92730
92795
  // ../server/src/static-file-routing.ts
92731
92796
  import { extname, isAbsolute, relative as relative2, resolve as resolve7 } from "path";
@@ -92848,6 +92913,65 @@ async function resolveStaticFileRequest(params) {
92848
92913
  }
92849
92914
 
92850
92915
  // ../server/src/server-platform-static-file.ts
92916
+ var compressibleStaticExtensions = /* @__PURE__ */ new Set([
92917
+ ".css",
92918
+ ".csv",
92919
+ ".htm",
92920
+ ".html",
92921
+ ".js",
92922
+ ".json",
92923
+ ".mjs",
92924
+ ".svg",
92925
+ ".txt",
92926
+ ".wasm",
92927
+ ".webmanifest",
92928
+ ".xml"
92929
+ ]);
92930
+ var encodedFileCache = /* @__PURE__ */ new Map();
92931
+ var encodedFileCacheTtlMs = 10 * 60 * 1e3;
92932
+ var encodedFileCacheMaxEntries = 240;
92933
+ function acceptsEncoding(value, encoding) {
92934
+ const tokens = value.toLowerCase().split(",").map((part) => part.trim());
92935
+ return tokens.some((token) => {
92936
+ if (!token.startsWith(encoding)) return false;
92937
+ const q = token.match(/;\s*q=([0-9.]+)/)?.[1];
92938
+ return q === void 0 || Number(q) > 0;
92939
+ });
92940
+ }
92941
+ function requestHeader(c, name) {
92942
+ const direct = c?.req?.header?.(name);
92943
+ if (typeof direct === "string") return direct;
92944
+ const fromHeaders = c?.req?.headers?.get?.(name);
92945
+ return typeof fromHeaders === "string" ? fromHeaders : "";
92946
+ }
92947
+ function preferredStaticEncoding(acceptEncoding, filePath) {
92948
+ if (!compressibleStaticExtensions.has(extname2(filePath).toLowerCase())) return null;
92949
+ if (acceptsEncoding(acceptEncoding, "br")) return "br";
92950
+ if (acceptsEncoding(acceptEncoding, "gzip")) return "gzip";
92951
+ return null;
92952
+ }
92953
+ function pruneEncodedFileCache(now = Date.now()) {
92954
+ for (const [key, value] of encodedFileCache) {
92955
+ if (now - value.createdAt > encodedFileCacheTtlMs) encodedFileCache.delete(key);
92956
+ }
92957
+ while (encodedFileCache.size > encodedFileCacheMaxEntries) {
92958
+ const oldest = encodedFileCache.keys().next().value;
92959
+ if (!oldest) break;
92960
+ encodedFileCache.delete(oldest);
92961
+ }
92962
+ }
92963
+ async function encodedStaticFile(filePath, encoding, originalSize) {
92964
+ const stats = await stat(filePath).catch(() => null);
92965
+ const cacheKey = `${filePath}:${stats?.mtimeMs ?? 0}:${originalSize}:${encoding}`;
92966
+ pruneEncodedFileCache();
92967
+ const cached = encodedFileCache.get(cacheKey);
92968
+ if (cached) return cached.body;
92969
+ const input = Buffer.from(await Bun.file(filePath).arrayBuffer());
92970
+ const output = encoding === "br" ? brotliCompressSync(input) : gzipSync(input);
92971
+ if (output.byteLength >= input.byteLength) return null;
92972
+ encodedFileCache.set(cacheKey, { body: output, createdAt: Date.now() });
92973
+ return output;
92974
+ }
92851
92975
  async function serveStaticFile(params) {
92852
92976
  const staticDir = join2(params.dataDir, "static");
92853
92977
  const resolution = await resolveStaticFileRequest({
@@ -92862,14 +92986,23 @@ async function serveStaticFile(params) {
92862
92986
  const file = Bun.file(resolution.filePath);
92863
92987
  const fileSize = file.size;
92864
92988
  const requestMethod = String(params.c?.req?.method ?? "").toUpperCase();
92865
- if (requestMethod !== "HEAD" && Number.isSafeInteger(fileSize) && fileSize > 0) {
92866
- params.recordBytes?.(fileSize);
92989
+ const encoding = preferredStaticEncoding(requestHeader(params.c, "Accept-Encoding"), resolution.filePath);
92990
+ const encodedBody = encoding && Number.isSafeInteger(fileSize) && fileSize > 0 ? await encodedStaticFile(resolution.filePath, encoding, fileSize) : null;
92991
+ const responseBody = encodedBody ? new Uint8Array(encodedBody) : file;
92992
+ const responseBytes = encodedBody?.byteLength ?? fileSize;
92993
+ if (requestMethod !== "HEAD" && Number.isSafeInteger(responseBytes) && responseBytes > 0) {
92994
+ params.recordBytes?.(responseBytes);
92867
92995
  }
92868
92996
  const headers = new Headers({ "Cache-Control": resolution.cacheControl });
92869
- if (Number.isSafeInteger(fileSize) && fileSize >= 0) {
92870
- headers.set("Content-Length", String(fileSize));
92997
+ if (encodedBody && encoding) {
92998
+ headers.set("Content-Encoding", encoding);
92999
+ headers.set("Vary", "Accept-Encoding");
92871
93000
  }
92872
- return new Response(file, {
93001
+ if (file.type) headers.set("Content-Type", file.type);
93002
+ if (Number.isSafeInteger(responseBytes) && responseBytes >= 0) {
93003
+ headers.set("Content-Length", String(responseBytes));
93004
+ }
93005
+ return new Response(requestMethod === "HEAD" ? null : responseBody, {
92873
93006
  headers
92874
93007
  });
92875
93008
  }
@@ -97137,7 +97270,7 @@ import { existsSync as existsSync6 } from "fs";
97137
97270
  import { resolve as resolve20 } from "path";
97138
97271
 
97139
97272
  // ../../node_modules/.pnpm/hono@4.12.18/node_modules/hono/dist/adapter/bun/serve-static.js
97140
- import { stat } from "node:fs/promises";
97273
+ import { stat as stat2 } from "node:fs/promises";
97141
97274
  import { join as join3 } from "node:path";
97142
97275
 
97143
97276
  // ../../node_modules/.pnpm/hono@4.12.18/node_modules/hono/dist/utils/compress.js
@@ -97313,7 +97446,7 @@ var serveStatic2 = (options) => {
97313
97446
  const isDir = async (path3) => {
97314
97447
  let isDir2;
97315
97448
  try {
97316
- const stats = await stat(path3);
97449
+ const stats = await stat2(path3);
97317
97450
  isDir2 = stats.isDirectory();
97318
97451
  } catch {
97319
97452
  }
@@ -97761,11 +97894,11 @@ async function loadStorageMeta(params) {
97761
97894
  try {
97762
97895
  const raw2 = await fs.readFile(`${filePath}.meta`, "utf-8");
97763
97896
  const parsed = JSON.parse(raw2);
97764
- const stat4 = await fs.stat(filePath);
97897
+ const stat5 = await fs.stat(filePath);
97765
97898
  const meta = {
97766
97899
  id: params.storageId,
97767
97900
  name: typeof parsed.name === "string" ? parsed.name : params.storageId,
97768
- size: typeof parsed.size === "number" ? parsed.size : stat4.size,
97901
+ size: typeof parsed.size === "number" ? parsed.size : stat5.size,
97769
97902
  type: typeof parsed.type === "string" ? parsed.type : "application/octet-stream",
97770
97903
  visibility: normalizeStorageVisibility(parsed.visibility),
97771
97904
  path: filePath
@@ -99151,6 +99284,9 @@ function isAuthorizedCronToken(token, internalToken, cronToken) {
99151
99284
  if (!token) return false;
99152
99285
  return Boolean(internalToken) && token === internalToken || Boolean(cronToken) && token === cronToken;
99153
99286
  }
99287
+ function canFallbackToStableSchedulerAction(action) {
99288
+ return action.startsWith(`${WORKFLOW_RESUME_ACTION_PREFIX}.`);
99289
+ }
99154
99290
  function createInternalCronRouteHandler(params) {
99155
99291
  const logger2 = params.logger ?? console;
99156
99292
  return async (c) => {
@@ -99187,7 +99323,7 @@ function createInternalCronRouteHandler(params) {
99187
99323
  logger2.error(`[cron] /internal/cron/${action}: failed:`, message);
99188
99324
  return c.json({ ok: false, error: message }, 500);
99189
99325
  }
99190
- if (hasActionTokenMap) {
99326
+ if (hasActionTokenMap && !canFallbackToStableSchedulerAction(action)) {
99191
99327
  logger2.warn(`[cron] /internal/cron/${action}: action token not found`);
99192
99328
  return c.json({ ok: false, error: `Action "${action}" not found` }, 404);
99193
99329
  }
@@ -109535,13 +109671,21 @@ function sanitizePublicAuthResponsePayload(payload, fallback = "Authentication f
109535
109671
  return sanitized;
109536
109672
  }
109537
109673
 
109538
- // ../server/src/auth-session-cookies.ts
109674
+ // ../server/src/auth-session-resolution.ts
109539
109675
  function sessionTokenToCookieHeader(sessionToken) {
109540
109676
  return [
109541
109677
  `better-auth.session_token=${sessionToken}`,
109542
109678
  `__Secure-better-auth.session_token=${sessionToken}`
109543
109679
  ].join("; ");
109544
109680
  }
109681
+ function decodeCookieToken(value) {
109682
+ try {
109683
+ const decoded = decodeURIComponent(value);
109684
+ return decoded || null;
109685
+ } catch {
109686
+ return null;
109687
+ }
109688
+ }
109545
109689
  function extractSessionTokenFromCookieHeader(cookieHeader) {
109546
109690
  return extractSessionTokensFromCookieHeader(cookieHeader)[0] ?? null;
109547
109691
  }
@@ -109550,7 +109694,8 @@ function extractSessionTokensFromCookieHeader(cookieHeader) {
109550
109694
  const pattern = /(?:^|;\s*)(?:__Secure-)?better-auth\.session_token=([^;]+)/g;
109551
109695
  let match2;
109552
109696
  while ((match2 = pattern.exec(cookieHeader)) !== null) {
109553
- tokens.push(decodeURIComponent(match2[1]));
109697
+ const token = decodeCookieToken(match2[1]);
109698
+ if (token) tokens.push(token);
109554
109699
  }
109555
109700
  return tokens;
109556
109701
  }
@@ -109574,6 +109719,37 @@ function sessionCreatedAtMs(session2) {
109574
109719
  }
109575
109720
  return 0;
109576
109721
  }
109722
+ async function resolveRequestSession(input) {
109723
+ if (input.authorizationHeader?.startsWith("Bearer ")) {
109724
+ const sessionToken2 = input.authorizationHeader.substring(7);
109725
+ const session3 = await input.getSession(new Headers({ cookie: sessionTokenToCookieHeader(sessionToken2) }));
109726
+ return { session: session3, sessionToken: sessionToken2 };
109727
+ }
109728
+ const cookieHeader = input.cookieHeader ?? "";
109729
+ const sessionTokens = [...new Set(extractSessionTokensFromCookieHeader(cookieHeader))];
109730
+ if (sessionTokens.length <= 1) {
109731
+ const session3 = await input.getSession(buildSessionLookupHeaders(input.headers, cookieHeader));
109732
+ return { session: session3, sessionToken: sessionTokens[0] ?? null };
109733
+ }
109734
+ const resolved = await Promise.all(
109735
+ sessionTokens.map(async (sessionToken2, index) => {
109736
+ try {
109737
+ const session3 = await input.getSession(buildSessionLookupHeadersForToken(input.headers, sessionToken2));
109738
+ return session3 ? { session: session3, sessionToken: sessionToken2, index } : null;
109739
+ } catch {
109740
+ return null;
109741
+ }
109742
+ })
109743
+ );
109744
+ const valid = resolved.filter((candidate) => candidate !== null);
109745
+ if (valid.length === 0) return { session: null, sessionToken: null };
109746
+ valid.sort((a, b) => {
109747
+ const createdDelta = sessionCreatedAtMs(b.session) - sessionCreatedAtMs(a.session);
109748
+ return createdDelta || a.index - b.index;
109749
+ });
109750
+ const { session: session2, sessionToken } = valid[0];
109751
+ return { session: session2, sessionToken };
109752
+ }
109577
109753
 
109578
109754
  // ../server/src/auth-oauth-invite-reservation.ts
109579
109755
  import { createHash as createHash7, randomUUID as randomUUID2 } from "crypto";
@@ -110983,29 +111159,12 @@ async function issueJWT(user2) {
110983
111159
  return { token, expires_in: JWT_EXPIRES_IN_SEC };
110984
111160
  }
110985
111161
  async function resolveSessionFromRequest(c) {
110986
- const authHeader = c.req.header("Authorization");
110987
- if (authHeader?.startsWith("Bearer ")) {
110988
- const sessionToken = authHeader.substring(7);
110989
- const session2 = await authInstance.api.getSession({
110990
- headers: new Headers({ cookie: sessionTokenToCookieHeader(sessionToken) })
110991
- });
110992
- return { session: session2, sessionToken };
110993
- }
110994
- const cookieHeader = c.req.header("cookie") || "";
110995
- const sessionTokens = [...new Set(extractSessionTokensFromCookieHeader(cookieHeader))];
110996
- if (sessionTokens.length <= 1) {
110997
- const session2 = await authInstance.api.getSession({
110998
- headers: buildSessionLookupHeaders(c.req.raw.headers, cookieHeader)
110999
- });
111000
- return { session: session2, sessionToken: sessionTokens[0] ?? null };
111001
- }
111002
- const resolved = (await Promise.all(
111003
- sessionTokens.map(
111004
- (sessionToken) => authInstance.api.getSession({ headers: buildSessionLookupHeadersForToken(c.req.raw.headers, sessionToken) }).then((session2) => session2 ? { session: session2, sessionToken } : null).catch(() => null)
111005
- )
111006
- )).filter(Boolean);
111007
- if (resolved.length === 0) return { session: null, sessionToken: null };
111008
- return resolved.sort((a, b) => sessionCreatedAtMs(b.session) - sessionCreatedAtMs(a.session))[0];
111162
+ return resolveRequestSession({
111163
+ authorizationHeader: c.req.header("Authorization"),
111164
+ cookieHeader: c.req.header("cookie"),
111165
+ headers: c.req.raw.headers,
111166
+ getSession: (headers) => authInstance.api.getSession({ headers })
111167
+ });
111009
111168
  }
111010
111169
  async function getSessionFromRequest(c) {
111011
111170
  return (await resolveSessionFromRequest(c)).session;