gencow 0.1.144 → 0.1.146

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.
Files changed (40) hide show
  1. package/core/index.js +101 -78
  2. package/dashboard/assets/{index-DX9dDxtT.js → index-7pP-gCcL.js} +3 -3
  3. package/dashboard/index.html +1 -1
  4. package/lib/add-command.mjs +9 -3
  5. package/lib/backup-command.mjs +27 -12
  6. package/lib/cli-dev-runtime.mjs +76 -4
  7. package/lib/cli-project-runtime.mjs +37 -30
  8. package/lib/codegen/index.mjs +10110 -217
  9. package/lib/codegen-command.mjs +29 -4
  10. package/lib/coding-guardrails.mjs +9 -2
  11. package/lib/config-command.mjs +5 -2
  12. package/lib/cors-command.mjs +6 -2
  13. package/lib/db-command.mjs +8 -9
  14. package/lib/deploy-auditor.mjs +229 -9
  15. package/lib/deploy-command.mjs +1 -7
  16. package/lib/deploy-package-runtime.mjs +30 -17
  17. package/lib/deploy-runtime.mjs +7 -4
  18. package/lib/deploy-static-fullstack-runtime.mjs +3 -1
  19. package/lib/dev-cloud-bundle.mjs +128 -0
  20. package/lib/dev-cloud-command.mjs +18 -12
  21. package/lib/env-command.mjs +10 -3
  22. package/lib/files-command.mjs +6 -7
  23. package/lib/init-command.mjs +15 -8
  24. package/lib/jobs-command.mjs +12 -0
  25. package/lib/readme-codegen.mjs +2 -0
  26. package/lib/static-command.mjs +14 -4
  27. package/lib/static-deploy-command.mjs +33 -11
  28. package/package.json +3 -2
  29. package/scripts/pre-publish-check.mjs +26 -1
  30. package/server/index.js +7115 -48330
  31. package/server/index.js.map +4 -4
  32. package/templates/SECURITY.md +8 -1
  33. package/templates/ai-chat/ai.ts +5 -3
  34. package/templates/ai.ts +5 -3
  35. package/templates/auth-schema.ts +2 -2
  36. package/templates/auth.ts +20 -1
  37. package/templates/fullstack/ai.ts +5 -3
  38. package/templates/rag.ts +6 -16
  39. package/templates/reranker.ts +3 -1
  40. package/templates/search.ts +9 -12
package/core/index.js CHANGED
@@ -1502,7 +1502,17 @@ var DEFAULT_GROUNDING_BUDGET = {
1502
1502
  };
1503
1503
 
1504
1504
  // ../core/src/rag-schema.ts
1505
- import { bigint, boolean, doublePrecision, integer, jsonb, pgTable, text, timestamp, vector } from "drizzle-orm/pg-core";
1505
+ import {
1506
+ bigint,
1507
+ boolean,
1508
+ doublePrecision,
1509
+ integer,
1510
+ jsonb,
1511
+ pgTable,
1512
+ text,
1513
+ timestamp,
1514
+ vector
1515
+ } from "drizzle-orm/pg-core";
1506
1516
  function buildScopeColumns() {
1507
1517
  return {
1508
1518
  id: text("id").primaryKey(),
@@ -2105,7 +2115,7 @@ function createScheduler(options) {
2105
2115
  }
2106
2116
  return {
2107
2117
  runAfter(ms, action, args, scheduleOpts) {
2108
- const id = generateId();
2118
+ const id = scheduleOpts?.id ?? generateId();
2109
2119
  const jobEntry = {
2110
2120
  id,
2111
2121
  action,
@@ -2207,10 +2217,17 @@ function createScheduler(options) {
2207
2217
  }
2208
2218
 
2209
2219
  // ../core/src/workflow.ts
2210
- import { sql as sql2 } from "drizzle-orm";
2220
+ import { sql as sql3 } from "drizzle-orm";
2211
2221
 
2212
- // ../core/src/workflows-api.ts
2222
+ // ../core/src/workflow-json.ts
2213
2223
  import { sql } from "drizzle-orm";
2224
+ function workflowJsonb(value) {
2225
+ const json = JSON.stringify(value ?? {});
2226
+ return sql`${json}::text::jsonb`;
2227
+ }
2228
+
2229
+ // ../core/src/workflows-api.ts
2230
+ import { sql as sql2 } from "drizzle-orm";
2214
2231
 
2215
2232
  // ../core/src/v.ts
2216
2233
  var GencowValidationError = class extends Error {
@@ -2419,7 +2436,7 @@ function toWorkflowStatusFilter(status) {
2419
2436
  async function ensureWorkflowRealtimeToken(db, workflowId, currentToken) {
2420
2437
  if (currentToken && currentToken.trim() !== "") return currentToken;
2421
2438
  const nextToken = createWorkflowRealtimeToken();
2422
- const updateResult = await db.execute(sql`
2439
+ const updateResult = await db.execute(sql2`
2423
2440
  UPDATE _gencow_workflows
2424
2441
  SET realtime_token = ${nextToken}
2425
2442
  WHERE id = ${workflowId}
@@ -2428,7 +2445,7 @@ async function ensureWorkflowRealtimeToken(db, workflowId, currentToken) {
2428
2445
  `);
2429
2446
  const updatedToken = rowsFromResult(updateResult)[0]?.realtime_token ?? null;
2430
2447
  if (updatedToken && updatedToken.trim() !== "") return updatedToken;
2431
- const rereadResult = await db.execute(sql`
2448
+ const rereadResult = await db.execute(sql2`
2432
2449
  SELECT realtime_token
2433
2450
  FROM _gencow_workflows
2434
2451
  WHERE id = ${workflowId}
@@ -2438,7 +2455,7 @@ async function ensureWorkflowRealtimeToken(db, workflowId, currentToken) {
2438
2455
  return rereadToken && rereadToken.trim() !== "" ? rereadToken : null;
2439
2456
  }
2440
2457
  async function loadWorkflowSignalTarget(db, workflowId) {
2441
- const result = await db.execute(sql`
2458
+ const result = await db.execute(sql2`
2442
2459
  SELECT
2443
2460
  id,
2444
2461
  name,
@@ -2460,7 +2477,7 @@ function isMissingWorkflowV2SignalSchemaError(error) {
2460
2477
  }
2461
2478
  async function tryRecordWorkflowV2Signal(options) {
2462
2479
  try {
2463
- await options.db.execute(sql`
2480
+ await options.db.execute(sql2`
2464
2481
  WITH inserted AS (
2465
2482
  INSERT INTO _gencow_workflow_signals_v2 (
2466
2483
  id,
@@ -2473,7 +2490,7 @@ async function tryRecordWorkflowV2Signal(options) {
2473
2490
  ${crypto.randomUUID()},
2474
2491
  ${options.workflowId},
2475
2492
  ${options.event},
2476
- ${JSON.stringify(options.payload)}::jsonb,
2493
+ ${workflowJsonb(options.payload)},
2477
2494
  ${crypto.randomUUID()}
2478
2495
  )
2479
2496
  RETURNING run_id
@@ -2499,7 +2516,7 @@ async function tryRecordWorkflowV2Signal(options) {
2499
2516
  }
2500
2517
  }
2501
2518
  async function loadWorkflowSnapshot(db, workflowId, options) {
2502
- const workflowResult = await db.execute(sql`
2519
+ const workflowResult = await db.execute(sql2`
2503
2520
  SELECT
2504
2521
  id,
2505
2522
  name,
@@ -2529,7 +2546,7 @@ async function loadWorkflowSnapshot(db, workflowId, options) {
2529
2546
  }
2530
2547
  const realtimeToken = await ensureWorkflowRealtimeToken(db, workflowId, row.realtime_token);
2531
2548
  if (!realtimeToken) return null;
2532
- const stepsResult = await db.execute(sql`
2549
+ const stepsResult = await db.execute(sql2`
2533
2550
  SELECT
2534
2551
  step_name,
2535
2552
  status,
@@ -2594,7 +2611,7 @@ function registerWorkflowsApi() {
2594
2611
  };
2595
2612
  }
2596
2613
  const persistedPayload = serializeWorkflowValue(args.payload);
2597
- await ctx.unsafeDb.execute(sql`
2614
+ await ctx.unsafeDb.execute(sql2`
2598
2615
  INSERT INTO _gencow_workflow_events (
2599
2616
  id,
2600
2617
  workflow_id,
@@ -2605,7 +2622,7 @@ function registerWorkflowsApi() {
2605
2622
  ${crypto.randomUUID()},
2606
2623
  ${workflow2.id},
2607
2624
  ${normalizedEvent},
2608
- ${JSON.stringify(persistedPayload)}::jsonb
2625
+ ${workflowJsonb(persistedPayload)}
2609
2626
  )
2610
2627
  `);
2611
2628
  await tryRecordWorkflowV2Signal({
@@ -2642,7 +2659,7 @@ function registerWorkflowsApi() {
2642
2659
  const limit = normalizeListLimit(args.limit);
2643
2660
  const requestedStatus = normalizeDerivedStatus(args.status);
2644
2661
  const status = toWorkflowStatusFilter(requestedStatus);
2645
- const result = status == null ? await ctx.unsafeDb.execute(sql`
2662
+ const result = status == null ? await ctx.unsafeDb.execute(sql2`
2646
2663
  SELECT
2647
2664
  id,
2648
2665
  name,
@@ -2663,7 +2680,7 @@ function registerWorkflowsApi() {
2663
2680
  WHERE user_id = ${userId}
2664
2681
  ORDER BY started_at DESC
2665
2682
  LIMIT ${limit}
2666
- `) : await ctx.unsafeDb.execute(sql`
2683
+ `) : await ctx.unsafeDb.execute(sql2`
2667
2684
  SELECT
2668
2685
  id,
2669
2686
  name,
@@ -2769,61 +2786,60 @@ function isMissingWorkflowV2SchemaError(error) {
2769
2786
  const message = error instanceof Error ? error.message : String(error);
2770
2787
  return code === "42P01" || code === "42703" || causeCode === "42P01" || causeCode === "42703" || message.includes('relation "_gencow_workflow_runs_v2" does not exist') || message.includes("relation _gencow_workflow_runs_v2 does not exist") || message.includes('relation "_gencow_workflow_outbox_v2" does not exist') || message.includes("relation _gencow_workflow_outbox_v2 does not exist") || message.includes('column "max_active_duration_ms"') || message.includes('column "retry_count"') || message.includes('column "user_id"');
2771
2788
  }
2772
- async function tryInsertWorkflowV2WakeOutbox(db, workflowId) {
2773
- try {
2774
- await db.execute(sql2`
2775
- INSERT INTO _gencow_workflow_outbox_v2 (
2776
- id,
2777
- run_id,
2778
- kind,
2779
- available_at,
2780
- status
2781
- )
2782
- VALUES (
2783
- ${`start:${workflowId}`},
2784
- ${workflowId},
2785
- 'wake_run',
2786
- NOW(),
2787
- 'pending'
2788
- )
2789
- ON CONFLICT (id) DO NOTHING
2790
- `);
2791
- } catch (error) {
2792
- if (!isMissingWorkflowV2SchemaError(error)) throw error;
2793
- }
2794
- }
2795
2789
  async function tryInsertWorkflowV2Run(options) {
2796
2790
  try {
2797
- await options.db.execute(sql2`
2798
- INSERT INTO _gencow_workflow_runs_v2 (
2799
- id,
2800
- workflow_name,
2801
- workflow_version,
2802
- args_json,
2803
- user_id,
2804
- max_active_duration_ms,
2805
- lifecycle_deadline_at,
2806
- retry_count,
2807
- max_retries,
2808
- max_attempts
2809
- )
2810
- VALUES (
2811
- ${options.workflowId},
2812
- ${options.workflowName},
2813
- ${options.workflowVersion ?? null},
2814
- ${JSON.stringify(options.args)}::jsonb,
2815
- ${options.userId},
2816
- ${options.maxActiveDurationMs},
2817
- CASE
2818
- WHEN ${options.lifecycleTimeoutMs}::bigint IS NULL THEN NULL
2819
- ELSE NOW() + (${options.lifecycleTimeoutMs}::bigint * INTERVAL '1 millisecond')
2820
- END,
2821
- 0,
2822
- ${options.maxRetries},
2823
- ${options.maxRetries + 1}
2791
+ await options.db.execute(sql3`
2792
+ WITH inserted_run AS (
2793
+ INSERT INTO _gencow_workflow_runs_v2 (
2794
+ id,
2795
+ workflow_name,
2796
+ workflow_version,
2797
+ args_json,
2798
+ user_id,
2799
+ max_active_duration_ms,
2800
+ lifecycle_deadline_at,
2801
+ retry_count,
2802
+ max_retries,
2803
+ max_attempts
2804
+ )
2805
+ VALUES (
2806
+ ${options.workflowId},
2807
+ ${options.workflowName},
2808
+ ${options.workflowVersion ?? null},
2809
+ ${workflowJsonb(options.args)},
2810
+ ${options.userId},
2811
+ ${options.maxActiveDurationMs},
2812
+ CASE
2813
+ WHEN ${options.lifecycleTimeoutMs}::bigint IS NULL THEN NULL
2814
+ ELSE NOW() + (${options.lifecycleTimeoutMs}::bigint * INTERVAL '1 millisecond')
2815
+ END,
2816
+ 0,
2817
+ ${options.maxRetries},
2818
+ ${options.maxRetries + 1}
2819
+ )
2820
+ RETURNING id
2821
+ ),
2822
+ inserted_outbox AS (
2823
+ INSERT INTO _gencow_workflow_outbox_v2 (
2824
+ id,
2825
+ run_id,
2826
+ kind,
2827
+ available_at,
2828
+ status
2829
+ )
2830
+ SELECT
2831
+ 'start:' || inserted_run.id,
2832
+ inserted_run.id,
2833
+ 'wake_run',
2834
+ NOW(),
2835
+ 'pending'
2836
+ FROM inserted_run
2837
+ ON CONFLICT (id) DO NOTHING
2838
+ RETURNING id
2824
2839
  )
2840
+ SELECT id
2841
+ FROM inserted_run
2825
2842
  `);
2826
- await tryInsertWorkflowV2WakeOutbox(options.db, options.workflowId);
2827
2843
  return true;
2828
2844
  } catch (error) {
2829
2845
  if (isMissingWorkflowV2SchemaError(error)) return false;
@@ -2832,7 +2848,7 @@ async function tryInsertWorkflowV2Run(options) {
2832
2848
  }
2833
2849
  async function tryDeleteWorkflowV2Run(db, workflowId) {
2834
2850
  try {
2835
- await db.execute(sql2`
2851
+ await db.execute(sql3`
2836
2852
  DELETE FROM _gencow_workflow_runs_v2
2837
2853
  WHERE id = ${workflowId}
2838
2854
  `);
@@ -2888,7 +2904,7 @@ function workflow(name, options) {
2888
2904
  const ownerId = ctx.auth.getUserIdentity()?.id ?? null;
2889
2905
  const persistedArgs = serializeWorkflowValue(args ?? {});
2890
2906
  const realtimeToken = createWorkflowRealtimeToken();
2891
- await ctx.unsafeDb.execute(sql2`
2907
+ await ctx.unsafeDb.execute(sql3`
2892
2908
  INSERT INTO _gencow_workflows (
2893
2909
  id,
2894
2910
  name,
@@ -2903,7 +2919,7 @@ function workflow(name, options) {
2903
2919
  VALUES (
2904
2920
  ${workflowId},
2905
2921
  ${name},
2906
- ${JSON.stringify(persistedArgs)}::jsonb,
2922
+ ${workflowJsonb(persistedArgs)},
2907
2923
  ${realtimeToken},
2908
2924
  'pending',
2909
2925
  0,
@@ -2925,7 +2941,7 @@ function workflow(name, options) {
2925
2941
  lifecycleTimeoutMs,
2926
2942
  maxRetries
2927
2943
  });
2928
- const scheduledJobId = ctx.scheduler.runAfter(0, resumeAction, { workflowId });
2944
+ const scheduledJobId = insertedWorkflowV2 ? `start:${workflowId}` : ctx.scheduler.runAfter(0, resumeAction, { workflowId });
2929
2945
  return {
2930
2946
  id: workflowId,
2931
2947
  name,
@@ -2933,7 +2949,7 @@ function workflow(name, options) {
2933
2949
  scheduledJobId
2934
2950
  };
2935
2951
  } catch (error) {
2936
- await ctx.unsafeDb.execute(sql2`
2952
+ await ctx.unsafeDb.execute(sql3`
2937
2953
  DELETE FROM _gencow_workflows
2938
2954
  WHERE id = ${workflowId}
2939
2955
  `);
@@ -3019,12 +3035,19 @@ var RESERVED_TENANT_RUNTIME_ENV_KEYS = /* @__PURE__ */ new Set([
3019
3035
  "GENCOW_SHUTDOWN_MARKER_PATH",
3020
3036
  "GENCOW_SKIP_MIGRATION",
3021
3037
  "GENCOW_DB_MAX_CONNECTIONS",
3038
+ "GENCOW_DB_IDLE_TIMEOUT_SECONDS",
3039
+ "GENCOW_DB_CONNECTION_TIMEOUT_SECONDS",
3022
3040
  "GENCOW_MEMORY_MB",
3023
3041
  "BUN_JSC_forceRAMSize",
3024
3042
  "MIMALLOC_PURGE_DELAY",
3025
3043
  "NODE_PATH"
3026
3044
  ]);
3027
- var RESERVED_TENANT_RUNTIME_ENV_PREFIXES = ["__GENCOW_", "GENCOW_DOCUMENT_", "GENCOW_TEMPLATE_", "GENCOW_WARM_"];
3045
+ var RESERVED_TENANT_RUNTIME_ENV_PREFIXES = [
3046
+ "__GENCOW_",
3047
+ "GENCOW_DOCUMENT_",
3048
+ "GENCOW_TEMPLATE_",
3049
+ "GENCOW_WARM_"
3050
+ ];
3028
3051
  function isReservedTenantRuntimeEnvKey(key) {
3029
3052
  const normalized = key.trim();
3030
3053
  return RESERVED_TENANT_RUNTIME_ENV_KEYS.has(normalized) || RESERVED_TENANT_RUNTIME_ENV_PREFIXES.some((prefix) => normalized.startsWith(prefix));
@@ -3088,7 +3111,7 @@ function intervalToPattern(options) {
3088
3111
 
3089
3112
  // ../core/src/auth-config.ts
3090
3113
  function defineAuth(config) {
3091
- return config;
3114
+ return { ...config, provider: config.provider ?? "better-auth" };
3092
3115
  }
3093
3116
 
3094
3117
  // ../core/src/config.ts
@@ -3097,7 +3120,7 @@ function defineConfig(config) {
3097
3120
  }
3098
3121
 
3099
3122
  // ../core/src/rls.ts
3100
- import { sql as sql3 } from "drizzle-orm";
3123
+ import { sql as sql4 } from "drizzle-orm";
3101
3124
  import { pgPolicy } from "drizzle-orm/pg-core";
3102
3125
  var _ownerRlsRegistry = /* @__PURE__ */ new WeakMap();
3103
3126
  function getOwnerRlsMeta(table) {
@@ -3113,13 +3136,13 @@ function ownerRls(userIdColumn, options) {
3113
3136
  "[ownerRls] userIdColumn must have a .name property. Ensure you pass a valid Drizzle column reference (e.g. t.userId)."
3114
3137
  );
3115
3138
  }
3116
- const isOwner = sql3`${userIdColumn} = current_setting('app.current_user_id', true)`;
3139
+ const isOwner = sql4`${userIdColumn} = current_setting('app.current_user_id', true)`;
3117
3140
  const meta = {
3118
3141
  columnName: colName,
3119
3142
  readPublic: options?.read === "public"
3120
3143
  };
3121
3144
  const policies = [
3122
- pgPolicy("rls-select", { for: "select", using: options?.read === "public" ? sql3`true` : isOwner }),
3145
+ pgPolicy("rls-select", { for: "select", using: options?.read === "public" ? sql4`true` : isOwner }),
3123
3146
  pgPolicy("rls-insert", { for: "insert", withCheck: isOwner }),
3124
3147
  pgPolicy("rls-update", { for: "update", using: isOwner, withCheck: isOwner }),
3125
3148
  pgPolicy("rls-delete", { for: "delete", using: isOwner })
@@ -3129,7 +3152,7 @@ function ownerRls(userIdColumn, options) {
3129
3152
 
3130
3153
  // ../core/src/rls-db.ts
3131
3154
  import { AsyncLocalStorage } from "node:async_hooks";
3132
- import { sql as sql4 } from "drizzle-orm";
3155
+ import { sql as sql5 } from "drizzle-orm";
3133
3156
  var gucNameRe = /^app\.[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)*$/;
3134
3157
  var RESERVED_VARS_KEYS = /* @__PURE__ */ new Set(["app.current_user_id", "app.current_user_role", "app.tenant_id"]);
3135
3158
  function assertSafeGucName(key) {
@@ -3189,7 +3212,7 @@ async function applyRlsSessionVars(client, rls) {
3189
3212
  await forEachSetConfig(rls, (name, value) => execSetConfig(client, name, value));
3190
3213
  }
3191
3214
  async function injectRlsVarsOnTx(tx, rls) {
3192
- await forEachSetConfig(rls, (name, value) => tx.execute(sql4`SELECT set_config(${name}, ${value}, true)`));
3215
+ await forEachSetConfig(rls, (name, value) => tx.execute(sql5`SELECT set_config(${name}, ${value}, true)`));
3193
3216
  }
3194
3217
  async function withRlsLeasedConnection(leased, rls, fn) {
3195
3218
  try {