vargai 0.4.0-alpha51 → 0.4.0-alpha53

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/CLAUDE.md CHANGED
@@ -123,3 +123,13 @@ bun --hot ./index.ts
123
123
  ```
124
124
 
125
125
  For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`.
126
+
127
+ ## Cache Policy
128
+
129
+ **NEVER clear or delete the user's cache**, even when debugging.
130
+
131
+ - Video/image generation costs real money ($0.05–$0.50+ per generation) and takes 60–180 seconds
132
+ - The cache is the user's asset — treat it as production data, not disposable debug state
133
+ - If you need to regenerate, modify the prompt slightly or use a different cache key
134
+ - If cache must be cleared, always ask the user explicitly first
135
+ - Suggest `--no-cache` flag for one-off re-renders instead of deleting cached files
package/package.json CHANGED
@@ -69,7 +69,8 @@
69
69
  "sharp": "^0.34.5",
70
70
  "zod": "^4.2.1"
71
71
  },
72
- "version": "0.4.0-alpha51",
72
+ "sideEffects": false,
73
+ "version": "0.4.0-alpha53",
73
74
  "exports": {
74
75
  ".": "./src/index.ts",
75
76
  "./ai": "./src/ai-sdk/index.ts",
@@ -80,6 +81,7 @@
80
81
  "./studio": "./src/studio/index.ts",
81
82
  "./jsx-runtime": "./src/react/runtime/jsx-runtime.ts",
82
83
  "./jsx-dev-runtime": "./src/react/runtime/jsx-dev-runtime.ts",
83
- "./editly": "./src/ai-sdk/providers/editly/index.ts"
84
+ "./editly": "./src/ai-sdk/providers/editly/index.ts",
85
+ "./file": "./src/ai-sdk/file.ts"
84
86
  }
85
87
  }
@@ -11,7 +11,10 @@ export interface WithCacheOptions {
11
11
 
12
12
  type CacheKeyDeps = (string | number | boolean | null | undefined)[];
13
13
 
14
- type WithCacheKey<T> = Omit<T, "cacheKey"> & { cacheKey?: CacheKeyDeps };
14
+ type WithCacheKey<T> = Omit<T, "cacheKey" | "skipCacheWrite"> & {
15
+ cacheKey?: CacheKeyDeps;
16
+ skipCacheWrite?: boolean;
17
+ };
15
18
 
16
19
  type CachedFn<T, R> = (options: WithCacheKey<T>) => Promise<R>;
17
20
 
@@ -60,7 +63,8 @@ function parseTTL(ttl: number | string | undefined): number | undefined {
60
63
  }
61
64
  }
62
65
 
63
- function depsToKey(prefix: string, deps: CacheKeyDeps): string {
66
+ /** Build a cache key string from a prefix and an array of dependencies. */
67
+ export function depsToKey(prefix: string, deps: CacheKeyDeps): string {
64
68
  const depsStr = deps.map((d) => String(d ?? "")).join(":");
65
69
  return prefix ? `${prefix}:${depsStr}` : depsStr;
66
70
  }
@@ -116,7 +120,7 @@ export function withCache<T extends object, R>(
116
120
  const ttl = parseTTL(options.ttl ?? DEFAULT_TTL);
117
121
  const prefix = fn.name || "anonymous";
118
122
  return async (opts: WithCacheKey<T>): Promise<R> => {
119
- const { cacheKey, ...rest } = opts;
123
+ const { cacheKey, skipCacheWrite, ...rest } = opts;
120
124
 
121
125
  if (!cacheKey) {
122
126
  return fn(rest as T);
@@ -128,8 +132,10 @@ export function withCache<T extends object, R>(
128
132
  return cached as R;
129
133
  }
130
134
  const result = await fn(rest as T);
131
- const flattened = flatten(result);
132
- await storage.set(key, flattened, ttl);
135
+ if (!skipCacheWrite) {
136
+ const flattened = flatten(result);
137
+ await storage.set(key, flattened, ttl);
138
+ }
133
139
 
134
140
  return result;
135
141
  };
@@ -1,7 +1,6 @@
1
1
  import { unlink } from "node:fs/promises";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
- import { $ } from "bun";
5
4
 
6
5
  export interface PlaceholderOptions {
7
6
  type: "image" | "video" | "audio";
@@ -82,6 +81,8 @@ export async function generatePlaceholder(
82
81
  `placeholder_${Date.now()}_${Math.random().toString(36).slice(2)}.${ext}`,
83
82
  );
84
83
 
84
+ const { $ } = await import("bun");
85
+
85
86
  try {
86
87
  if (type === "audio") {
87
88
  await $`ffmpeg -y -f lavfi -i anullsrc=r=44100:cl=stereo -t ${duration} -c:a libmp3lame ${outputPath}`.quiet();
@@ -1,3 +1,4 @@
1
+ import type { ImageModelV3 } from "@ai-sdk/provider";
1
2
  import { generateImage, wrapImageModel } from "ai";
2
3
  import { type CacheStorage, withCache } from "../../ai-sdk/cache";
3
4
  import type { File, File as VargFile } from "../../ai-sdk/file";
@@ -8,6 +9,7 @@ import {
8
9
  placeholderFallbackMiddleware,
9
10
  wrapVideoModel,
10
11
  } from "../../ai-sdk/middleware";
12
+
11
13
  import { editly, localBackend } from "../../ai-sdk/providers/editly";
12
14
  import type {
13
15
  AudioTrack,
@@ -58,6 +60,28 @@ function resolveCacheStorage(
58
60
  return cache;
59
61
  }
60
62
 
63
+ function toImageModelV3(
64
+ model: Parameters<typeof generateImage>[0]["model"],
65
+ ): ImageModelV3 {
66
+ if (typeof model === "object" && model.specificationVersion === "v3") {
67
+ return model;
68
+ }
69
+ // for string IDs and v2 models, create a shell that satisfies the type.
70
+ // in preview mode the middleware intercepts before doGenerate is called.
71
+ const modelId = typeof model === "string" ? model : model.modelId;
72
+ return {
73
+ specificationVersion: "v3",
74
+ provider: "placeholder",
75
+ modelId,
76
+ maxImagesPerCall: 1,
77
+ doGenerate: async () => {
78
+ throw new Error(
79
+ `toImageModelV3 shell: doGenerate should not be called in preview mode (model: ${modelId})`,
80
+ );
81
+ },
82
+ };
83
+ }
84
+
61
85
  export async function renderRoot(
62
86
  element: VargElement<"render">,
63
87
  options: RenderOptions,
@@ -84,23 +108,19 @@ export async function renderRoot(
84
108
  : generateVideo;
85
109
 
86
110
  const wrapGenerateImage: typeof generateImage = async (opts) => {
87
- if (
88
- typeof opts.model === "string" ||
89
- opts.model.specificationVersion !== "v3"
90
- ) {
91
- return cachedGenerateImage(opts);
92
- }
93
-
94
111
  if (mode === "preview") {
95
112
  trackPlaceholder("image");
96
- const wrappedModel = wrapImageModel({
97
- model: opts.model,
98
- middleware: imagePlaceholderFallbackMiddleware({
99
- mode: "preview",
100
- onFallback: () => {},
113
+ return cachedGenerateImage({
114
+ ...opts,
115
+ model: wrapImageModel({
116
+ model: toImageModelV3(opts.model),
117
+ middleware: imagePlaceholderFallbackMiddleware({
118
+ mode: "preview",
119
+ onFallback: () => {},
120
+ }),
101
121
  }),
102
- });
103
- return generateImage({ ...opts, model: wrappedModel });
122
+ skipCacheWrite: true,
123
+ } as Parameters<typeof cachedGenerateImage>[0]);
104
124
  }
105
125
 
106
126
  return cachedGenerateImage(opts);
@@ -109,14 +129,17 @@ export async function renderRoot(
109
129
  const wrapGenerateVideo: typeof generateVideo = async (opts) => {
110
130
  if (mode === "preview") {
111
131
  trackPlaceholder("video");
112
- const wrappedModel = wrapVideoModel({
113
- model: opts.model,
114
- middleware: placeholderFallbackMiddleware({
115
- mode: "preview",
116
- onFallback: () => {},
132
+ return cachedGenerateVideo({
133
+ ...opts,
134
+ model: wrapVideoModel({
135
+ model: opts.model,
136
+ middleware: placeholderFallbackMiddleware({
137
+ mode: "preview",
138
+ onFallback: () => {},
139
+ }),
117
140
  }),
118
- });
119
- return generateVideo({ ...opts, model: wrappedModel });
141
+ skipCacheWrite: true,
142
+ } as Parameters<typeof cachedGenerateVideo>[0]);
120
143
  }
121
144
 
122
145
  return cachedGenerateVideo(opts);