egaki 0.6.0 → 0.7.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/CHANGELOG.md +140 -9
- package/dist/cli/cache-utils.d.ts +33 -0
- package/dist/cli/cache-utils.d.ts.map +1 -0
- package/dist/cli/cache-utils.js +157 -0
- package/dist/cli/cached-generate.d.ts +105 -0
- package/dist/cli/cached-generate.d.ts.map +1 -0
- package/dist/cli/cached-generate.js +208 -0
- package/dist/cli/cached-generate.test.d.ts +11 -0
- package/dist/cli/cached-generate.test.d.ts.map +1 -0
- package/dist/cli/cached-generate.test.js +431 -0
- package/dist/cli/cartesia-provider.d.ts +16 -0
- package/dist/cli/cartesia-provider.d.ts.map +1 -0
- package/dist/cli/cartesia-provider.js +184 -0
- package/dist/cli/chatgpt-auth.d.ts.map +1 -0
- package/dist/cli/cli.d.ts +4 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/{cli.js → cli/cli.js} +626 -600
- package/dist/cli/clone-generate.d.ts +26 -0
- package/dist/cli/clone-generate.d.ts.map +1 -0
- package/dist/cli/clone-generate.js +148 -0
- package/dist/cli/credentials.d.ts.map +1 -0
- package/dist/{credentials.js → cli/credentials.js} +20 -0
- package/dist/cli/elevenlabs-speech-provider.d.ts +26 -0
- package/dist/cli/elevenlabs-speech-provider.d.ts.map +1 -0
- package/dist/cli/elevenlabs-speech-provider.js +199 -0
- package/dist/cli/generate.d.ts +140 -0
- package/dist/cli/generate.d.ts.map +1 -0
- package/dist/cli/generate.js +604 -0
- package/dist/cli/generate.test.d.ts +2 -0
- package/dist/cli/generate.test.d.ts.map +1 -0
- package/dist/cli/generate.test.js +131 -0
- package/dist/cli/login.d.ts.map +1 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +7 -0
- package/dist/{model-catalog.d.ts → cli/model-catalog.d.ts} +6 -0
- package/dist/cli/model-catalog.d.ts.map +1 -0
- package/dist/{model-catalog.js → cli/model-catalog.js} +714 -4
- package/dist/{models.d.ts → cli/models.d.ts} +12 -5
- package/dist/cli/models.d.ts.map +1 -0
- package/dist/{models.js → cli/models.js} +58 -57
- package/dist/cli/open-browser.d.ts.map +1 -0
- package/dist/cli/openai-speech-provider.d.ts +3 -0
- package/dist/cli/openai-speech-provider.d.ts.map +1 -0
- package/dist/cli/openai-speech-provider.js +28 -0
- package/dist/cli/separation-generate.d.ts +34 -0
- package/dist/cli/separation-generate.d.ts.map +1 -0
- package/dist/cli/separation-generate.js +117 -0
- package/dist/cli/speech-catalog.d.ts +35 -0
- package/dist/cli/speech-catalog.d.ts.map +1 -0
- package/dist/cli/speech-catalog.js +195 -0
- package/dist/cli/speech-generate.d.ts +86 -0
- package/dist/cli/speech-generate.d.ts.map +1 -0
- package/dist/cli/speech-generate.js +156 -0
- package/dist/cli/speech-models.d.ts +8 -0
- package/dist/cli/speech-models.d.ts.map +1 -0
- package/dist/cli/speech-models.js +109 -0
- package/dist/cli/speech-provider.test.d.ts +2 -0
- package/dist/cli/speech-provider.test.d.ts.map +1 -0
- package/dist/cli/speech-provider.test.js +197 -0
- package/dist/cli/subscription.d.ts.map +1 -0
- package/dist/cli/transcription-catalog.d.ts +35 -0
- package/dist/cli/transcription-catalog.d.ts.map +1 -0
- package/dist/cli/transcription-catalog.js +192 -0
- package/dist/cli/transcription-generate.d.ts +62 -0
- package/dist/cli/transcription-generate.d.ts.map +1 -0
- package/dist/cli/transcription-generate.js +144 -0
- package/dist/cli/transcription-models.d.ts +9 -0
- package/dist/cli/transcription-models.d.ts.map +1 -0
- package/dist/cli/transcription-models.js +100 -0
- package/dist/cli/transcription-providers.d.ts +22 -0
- package/dist/cli/transcription-providers.d.ts.map +1 -0
- package/dist/cli/transcription-providers.js +290 -0
- package/dist/cli/video-model-catalog.d.ts.map +1 -0
- package/dist/cli/xai-auth.d.ts.map +1 -0
- package/dist/{xai-auth.js → cli/xai-auth.js} +1 -1
- package/dist/vite/angled-screen.d.ts +57 -0
- package/dist/vite/angled-screen.d.ts.map +1 -0
- package/dist/vite/angled-screen.js +115 -0
- package/dist/vite/app.d.ts +51 -0
- package/dist/vite/app.d.ts.map +1 -0
- package/dist/vite/app.js +150 -0
- package/dist/vite/bands-shader.d.ts +47 -0
- package/dist/vite/bands-shader.d.ts.map +1 -0
- package/dist/vite/bands-shader.js +267 -0
- package/dist/vite/code-block.d.ts +107 -0
- package/dist/vite/code-block.d.ts.map +1 -0
- package/dist/vite/code-block.js +641 -0
- package/dist/vite/components.d.ts +36 -0
- package/dist/vite/components.d.ts.map +1 -0
- package/dist/vite/components.js +113 -0
- package/dist/vite/dispersion-rings-shader.d.ts +44 -0
- package/dist/vite/dispersion-rings-shader.d.ts.map +1 -0
- package/dist/vite/dispersion-rings-shader.js +282 -0
- package/dist/vite/easing-curves.d.ts +129 -0
- package/dist/vite/easing-curves.d.ts.map +1 -0
- package/dist/vite/easing-curves.js +584 -0
- package/dist/vite/easing-curves.test.d.ts +2 -0
- package/dist/vite/easing-curves.test.d.ts.map +1 -0
- package/dist/vite/easing-curves.test.js +200 -0
- package/dist/vite/generated-media-client.d.ts +35 -0
- package/dist/vite/generated-media-client.d.ts.map +1 -0
- package/dist/vite/generated-media-client.js +76 -0
- package/dist/vite/keyframes.d.ts +129 -0
- package/dist/vite/keyframes.d.ts.map +1 -0
- package/dist/vite/keyframes.js +194 -0
- package/dist/vite/layout-editor.d.ts +45 -0
- package/dist/vite/layout-editor.d.ts.map +1 -0
- package/dist/vite/layout-editor.js +587 -0
- package/dist/vite/layout-transition.d.ts +136 -0
- package/dist/vite/layout-transition.d.ts.map +1 -0
- package/dist/vite/layout-transition.js +581 -0
- package/dist/vite/liquid-gradient-shader.d.ts +62 -0
- package/dist/vite/liquid-gradient-shader.d.ts.map +1 -0
- package/dist/vite/liquid-gradient-shader.js +413 -0
- package/dist/vite/mdx-client.d.ts +15 -0
- package/dist/vite/mdx-client.d.ts.map +1 -0
- package/dist/vite/mdx-client.js +265 -0
- package/dist/vite/mdx-parse.d.ts +102 -0
- package/dist/vite/mdx-parse.d.ts.map +1 -0
- package/dist/vite/mdx-parse.js +251 -0
- package/dist/vite/mdx-provided-components.d.ts +18 -0
- package/dist/vite/mdx-provided-components.d.ts.map +1 -0
- package/dist/vite/mdx-provided-components.js +14 -0
- package/dist/vite/mdx-video.d.ts +327 -0
- package/dist/vite/mdx-video.d.ts.map +1 -0
- package/dist/vite/mdx-video.js +596 -0
- package/dist/vite/mdx-video.test.d.ts +9 -0
- package/dist/vite/mdx-video.test.d.ts.map +1 -0
- package/dist/vite/mdx-video.test.js +1945 -0
- package/dist/vite/media-components.d.ts +45 -0
- package/dist/vite/media-components.d.ts.map +1 -0
- package/dist/vite/media-components.js +355 -0
- package/dist/vite/media-duration-store.d.ts +66 -0
- package/dist/vite/media-duration-store.d.ts.map +1 -0
- package/dist/vite/media-duration-store.js +204 -0
- package/dist/vite/player-page.d.ts +35 -0
- package/dist/vite/player-page.d.ts.map +1 -0
- package/dist/vite/player-page.js +720 -0
- package/dist/vite/render-client.d.ts +18 -0
- package/dist/vite/render-client.d.ts.map +1 -0
- package/dist/vite/render-client.js +67 -0
- package/dist/vite/sdk.d.ts +221 -0
- package/dist/vite/sdk.d.ts.map +1 -0
- package/dist/vite/sdk.js +355 -0
- package/dist/vite/server-components.d.ts +55 -0
- package/dist/vite/server-components.d.ts.map +1 -0
- package/dist/vite/server-components.js +156 -0
- package/dist/vite/server-mdx.d.ts +74 -0
- package/dist/vite/server-mdx.d.ts.map +1 -0
- package/dist/vite/server-mdx.js +259 -0
- package/dist/vite/shader-renderer.d.ts +48 -0
- package/dist/vite/shader-renderer.d.ts.map +1 -0
- package/dist/vite/shader-renderer.js +411 -0
- package/dist/vite/store-hooks.d.ts +12 -0
- package/dist/vite/store-hooks.d.ts.map +1 -0
- package/dist/vite/store-hooks.js +93 -0
- package/dist/vite/store.d.ts +75 -0
- package/dist/vite/store.d.ts.map +1 -0
- package/dist/vite/store.js +52 -0
- package/dist/vite/store.test.d.ts +6 -0
- package/dist/vite/store.test.d.ts.map +1 -0
- package/dist/vite/store.test.js +172 -0
- package/dist/vite/tweakpane-hook.d.ts +94 -0
- package/dist/vite/tweakpane-hook.d.ts.map +1 -0
- package/dist/vite/tweakpane-hook.js +450 -0
- package/dist/vite/vite-plugin.d.ts +28 -0
- package/dist/vite/vite-plugin.d.ts.map +1 -0
- package/dist/vite/vite-plugin.js +538 -0
- package/dist/vite/wave-gradient-shader.d.ts +41 -0
- package/dist/vite/wave-gradient-shader.d.ts.map +1 -0
- package/dist/vite/wave-gradient-shader.js +207 -0
- package/package.json +101 -24
- package/skills/egaki/SKILL.md +162 -1
- package/src/cli/cache-utils.ts +169 -0
- package/src/cli/cached-generate.test.ts +531 -0
- package/src/cli/cached-generate.ts +348 -0
- package/src/cli/cartesia-provider.ts +249 -0
- package/src/{cli.ts → cli/cli.ts} +836 -884
- package/src/cli/clone-generate.ts +202 -0
- package/src/{credentials.ts → cli/credentials.ts} +20 -0
- package/src/cli/elevenlabs-speech-provider.ts +243 -0
- package/src/cli/generate.test.ts +166 -0
- package/src/cli/generate.ts +912 -0
- package/src/cli/main.ts +8 -0
- package/src/{model-catalog.ts → cli/model-catalog.ts} +787 -58
- package/src/{models.ts → cli/models.ts} +65 -86
- package/src/cli/openai-speech-provider.ts +34 -0
- package/src/cli/separation-generate.ts +187 -0
- package/src/cli/speech-catalog.ts +253 -0
- package/src/cli/speech-generate.ts +275 -0
- package/src/cli/speech-models.ts +146 -0
- package/src/cli/speech-provider.test.ts +226 -0
- package/src/cli/transcription-catalog.ts +250 -0
- package/src/cli/transcription-generate.ts +214 -0
- package/src/cli/transcription-models.ts +136 -0
- package/src/cli/transcription-providers.ts +427 -0
- package/src/{xai-auth.ts → cli/xai-auth.ts} +1 -1
- package/src/vite/angled-screen.tsx +214 -0
- package/src/vite/app.tsx +197 -0
- package/src/vite/bands-shader.tsx +319 -0
- package/src/vite/code-block.tsx +939 -0
- package/src/vite/components.tsx +278 -0
- package/src/vite/dispersion-rings-shader.tsx +331 -0
- package/src/vite/easing-curves.test.ts +232 -0
- package/src/vite/easing-curves.ts +743 -0
- package/src/vite/generated-media-client.tsx +121 -0
- package/src/vite/keyframes.tsx +347 -0
- package/src/vite/layout-editor.tsx +709 -0
- package/src/vite/layout-transition.tsx +706 -0
- package/src/vite/liquid-gradient-shader.tsx +474 -0
- package/src/vite/mdx-client.tsx +420 -0
- package/src/vite/mdx-parse.ts +343 -0
- package/src/vite/mdx-provided-components.ts +19 -0
- package/src/vite/mdx-video.test.tsx +2219 -0
- package/src/vite/mdx-video.tsx +976 -0
- package/src/vite/media-components.tsx +473 -0
- package/src/vite/media-duration-store.ts +225 -0
- package/src/vite/motion-timing.ts +194 -0
- package/src/vite/player-page.tsx +1107 -0
- package/src/vite/render-client.ts +84 -0
- package/src/vite/sdk.ts +598 -0
- package/src/vite/server-components.tsx +241 -0
- package/src/vite/server-mdx.ts +285 -0
- package/src/vite/shader-renderer.tsx +535 -0
- package/src/vite/store-hooks.ts +117 -0
- package/src/vite/store.test.ts +202 -0
- package/src/vite/store.ts +115 -0
- package/src/vite/styles.css +21 -0
- package/src/vite/tweakpane-hook.tsx +593 -0
- package/src/vite/virtual-modules.d.ts +30 -0
- package/src/vite/vite-plugin.ts +584 -0
- package/src/vite/wave-gradient-shader.tsx +253 -0
- package/README.md +0 -370
- package/dist/antigravity-auth.d.ts +0 -15
- package/dist/antigravity-auth.d.ts.map +0 -1
- package/dist/antigravity-auth.js +0 -544
- package/dist/antigravity-image.d.ts +0 -11
- package/dist/antigravity-image.d.ts.map +0 -1
- package/dist/antigravity-image.js +0 -285
- package/dist/chatgpt-auth.d.ts.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/credentials.d.ts.map +0 -1
- package/dist/gateway-model-candidates.generated.d.ts +0 -11
- package/dist/gateway-model-candidates.generated.d.ts.map +0 -1
- package/dist/gateway-model-candidates.generated.js +0 -64
- package/dist/login.d.ts.map +0 -1
- package/dist/model-catalog.d.ts.map +0 -1
- package/dist/models.d.ts.map +0 -1
- package/dist/open-browser.d.ts.map +0 -1
- package/dist/subscription.d.ts.map +0 -1
- package/dist/video-model-catalog.d.ts.map +0 -1
- package/dist/xai-auth.d.ts.map +0 -1
- /package/dist/{chatgpt-auth.d.ts → cli/chatgpt-auth.d.ts} +0 -0
- /package/dist/{chatgpt-auth.js → cli/chatgpt-auth.js} +0 -0
- /package/dist/{credentials.d.ts → cli/credentials.d.ts} +0 -0
- /package/dist/{login.d.ts → cli/login.d.ts} +0 -0
- /package/dist/{login.js → cli/login.js} +0 -0
- /package/dist/{open-browser.d.ts → cli/open-browser.d.ts} +0 -0
- /package/dist/{open-browser.js → cli/open-browser.js} +0 -0
- /package/dist/{subscription.d.ts → cli/subscription.d.ts} +0 -0
- /package/dist/{subscription.js → cli/subscription.js} +0 -0
- /package/dist/{video-model-catalog.d.ts → cli/video-model-catalog.d.ts} +0 -0
- /package/dist/{video-model-catalog.js → cli/video-model-catalog.js} +0 -0
- /package/dist/{xai-auth.d.ts → cli/xai-auth.d.ts} +0 -0
- /package/src/{chatgpt-auth.ts → cli/chatgpt-auth.ts} +0 -0
- /package/src/{login.ts → cli/login.ts} +0 -0
- /package/src/{open-browser.ts → cli/open-browser.ts} +0 -0
- /package/src/{subscription.ts → cli/subscription.ts} +0 -0
- /package/src/{video-model-catalog.ts → cli/video-model-catalog.ts} +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server components for AI media generation in MDX <Server> blocks.
|
|
3
|
+
*
|
|
4
|
+
* No 'use client' directive: these execute in the RSC environment (async,
|
|
5
|
+
* filesystem access, API calls). They are auto-wrapped in <Server> by
|
|
6
|
+
* wrapGenerateNodes() in server-mdx.ts, so users write them bare in MDX.
|
|
7
|
+
*
|
|
8
|
+
* Each component delegates to the cached generate functions from egaki/generate
|
|
9
|
+
* (which handle caching, deduplication, stale management, and progress tracking
|
|
10
|
+
* via cachedGenerate) and passes the resolved URL to the client wrapper component.
|
|
11
|
+
*
|
|
12
|
+
* The server components add a thin layer on top for:
|
|
13
|
+
* - Composition-aware defaults (aspect ratio from dimensions)
|
|
14
|
+
* - Asset path resolution (string paths → Uint8Array)
|
|
15
|
+
* - Fallback lookup for RSC streaming (show stale while generating)
|
|
16
|
+
* - RSC flight streaming (pass promise to client wrapper)
|
|
17
|
+
*/
|
|
18
|
+
import type { ComponentProps } from 'react';
|
|
19
|
+
import type { GenerateImageOptions } from '../cli/generate.js';
|
|
20
|
+
import type { GenerateVideoOptions } from '../cli/generate.js';
|
|
21
|
+
import type { GenerateSpeechOptions } from '../cli/speech-generate.js';
|
|
22
|
+
import type { Img, Audio, Video } from './mdx-video.tsx';
|
|
23
|
+
export { getGenerationProgress, onProgressChange, type GenerationProgressEvent, type GenerationProgressSummary, type GenerationProgressEntry, type GenerationError, type GenerationEntry, } from '../cli/cached-generate.js';
|
|
24
|
+
export { stableJsonKey, hashKey, promptPrefix, findCachedFile, findFallbackFile } from '../cli/cache-utils.js';
|
|
25
|
+
/** Resolve a path prop to an absolute filesystem path.
|
|
26
|
+
* `/photo.png` → `{projectRoot}/public/photo.png` if the file exists.
|
|
27
|
+
* Relative paths resolve against projectRoot.
|
|
28
|
+
* Absolute paths and URLs pass through unchanged. */
|
|
29
|
+
export declare function resolveAssetPath(p: string): Promise<string>;
|
|
30
|
+
/** Resolve a path and read it as bytes. */
|
|
31
|
+
export declare function readAssetBytes(p: string): Promise<Uint8Array>;
|
|
32
|
+
type GeneratedImageGenProps = Omit<GenerateImageOptions, 'count' | 'inputImages' | 'maskImage'> & {
|
|
33
|
+
inputImages?: string[];
|
|
34
|
+
maskImage?: string;
|
|
35
|
+
};
|
|
36
|
+
export type GeneratedImageProps = GeneratedImageGenProps & Omit<ComponentProps<typeof Img>, 'src'>;
|
|
37
|
+
export declare function GeneratedImage({ inputImages: inputImagePaths, maskImage: maskImagePath, ...props }: GeneratedImageProps): Promise<import("react").JSX.Element>;
|
|
38
|
+
type GeneratedVideoGenProps = Omit<GenerateVideoOptions, 'count' | 'inputImage'> & {
|
|
39
|
+
inputImage?: string;
|
|
40
|
+
};
|
|
41
|
+
export type GeneratedVideoProps = GeneratedVideoGenProps & Omit<ComponentProps<typeof Video>, 'src'>;
|
|
42
|
+
export declare function GeneratedVideo({ inputImage: inputImagePath, ...props }: GeneratedVideoProps): Promise<import("react").JSX.Element>;
|
|
43
|
+
type GeneratedSpeechGenProps = GenerateSpeechOptions & {
|
|
44
|
+
seed?: number;
|
|
45
|
+
};
|
|
46
|
+
export type GeneratedSpeechProps = GeneratedSpeechGenProps & Omit<ComponentProps<typeof Audio>, 'src'>;
|
|
47
|
+
export declare function GeneratedSpeech(props: GeneratedSpeechProps): Promise<import("react").JSX.Element>;
|
|
48
|
+
interface TextToSpeechProps {
|
|
49
|
+
/** Text to synthesize. */
|
|
50
|
+
text: string;
|
|
51
|
+
/** Voice preset. */
|
|
52
|
+
voice?: string;
|
|
53
|
+
}
|
|
54
|
+
export declare function TextToSpeech({ text, voice }: TextToSpeechProps): Promise<import("react").JSX.Element>;
|
|
55
|
+
//# sourceMappingURL=server-components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-components.d.ts","sourceRoot":"","sources":["../../src/vite/server-components.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAStE,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAIxD,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAoC9G;;;sDAGsD;AACtD,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAcjE;AAED,2CAA2C;AAC3C,wBAAsB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAQnE;AAMD,KAAK,sBAAsB,GAAG,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,CAAC,GAAG;IAChG,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,sBAAsB,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,GAAG,CAAC,EAAE,KAAK,CAAC,CAAA;AAElG,wBAAsB,cAAc,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,KAAK,EAAE,EAAE,mBAAmB,wCA6B7H;AAMD,KAAK,sBAAsB,GAAG,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,YAAY,CAAC,GAAG;IACjF,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,sBAAsB,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,KAAK,CAAC,EAAE,KAAK,CAAC,CAAA;AAEpG,wBAAsB,cAAc,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,KAAK,EAAE,EAAE,mBAAmB,wCA0BjG;AAMD,KAAK,uBAAuB,GAAG,qBAAqB,GAAG;IACrD,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG,uBAAuB,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,KAAK,CAAC,EAAE,KAAK,CAAC,CAAA;AAEtG,wBAAsB,eAAe,CAAC,KAAK,EAAE,oBAAoB,wCAmBhE;AAMD,UAAU,iBAAiB;IACzB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,YAAY,CAAC,EAAE,IAAI,EAAE,KAAe,EAAE,EAAE,iBAAiB,wCAE9E"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Server components for AI media generation in MDX <Server> blocks.
|
|
4
|
+
*
|
|
5
|
+
* No 'use client' directive: these execute in the RSC environment (async,
|
|
6
|
+
* filesystem access, API calls). They are auto-wrapped in <Server> by
|
|
7
|
+
* wrapGenerateNodes() in server-mdx.ts, so users write them bare in MDX.
|
|
8
|
+
*
|
|
9
|
+
* Each component delegates to the cached generate functions from egaki/generate
|
|
10
|
+
* (which handle caching, deduplication, stale management, and progress tracking
|
|
11
|
+
* via cachedGenerate) and passes the resolved URL to the client wrapper component.
|
|
12
|
+
*
|
|
13
|
+
* The server components add a thin layer on top for:
|
|
14
|
+
* - Composition-aware defaults (aspect ratio from dimensions)
|
|
15
|
+
* - Asset path resolution (string paths → Uint8Array)
|
|
16
|
+
* - Fallback lookup for RSC streaming (show stale while generating)
|
|
17
|
+
* - RSC flight streaming (pass promise to client wrapper)
|
|
18
|
+
*/
|
|
19
|
+
import fs from 'node:fs';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import { CATALOG, VIDEO_CATALOG } from '../cli/model-catalog.js';
|
|
22
|
+
import { DEFAULT_MODEL, DEFAULT_VIDEO_MODEL } from '../cli/models.js';
|
|
23
|
+
import { aspectRatioFromDimensions } from "./mdx-parse.js";
|
|
24
|
+
import { GeneratedImageClient, GeneratedVideoClient, GeneratedSpeechClient, } from "./generated-media-client.js";
|
|
25
|
+
import { setProjectRoot } from '../cli/cache-utils.js';
|
|
26
|
+
// Re-export progress tracking from the centralized module
|
|
27
|
+
export { getGenerationProgress, onProgressChange, } from '../cli/cached-generate.js';
|
|
28
|
+
// Re-export caching utilities so existing imports from 'egaki/generate-media' still work
|
|
29
|
+
export { stableJsonKey, hashKey, promptPrefix, findCachedFile, findFallbackFile } from '../cli/cache-utils.js';
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Project root and composition dimensions from Vite virtual module.
|
|
32
|
+
// setProjectRoot() is called here so the cached generate functions
|
|
33
|
+
// in egaki/generate know where public/generated/ is.
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
let _initialized = false;
|
|
36
|
+
async function ensureInit() {
|
|
37
|
+
if (_initialized)
|
|
38
|
+
return;
|
|
39
|
+
const mod = await import('virtual:egaki-mdx');
|
|
40
|
+
setProjectRoot(mod.projectRoot);
|
|
41
|
+
_initialized = true;
|
|
42
|
+
}
|
|
43
|
+
async function getCompositionDimensions() {
|
|
44
|
+
const mod = await import('virtual:egaki-mdx');
|
|
45
|
+
return { width: mod.compositionWidth, height: mod.compositionHeight };
|
|
46
|
+
}
|
|
47
|
+
/** Look up a model's supported aspect ratios from the catalog. */
|
|
48
|
+
function getModelAspectRatios(modelId, type) {
|
|
49
|
+
if (type === 'image') {
|
|
50
|
+
const entry = CATALOG.find((m) => m.id === modelId);
|
|
51
|
+
return entry?.features.aspectRatios;
|
|
52
|
+
}
|
|
53
|
+
const entry = VIDEO_CATALOG.find((m) => m.id === modelId);
|
|
54
|
+
return entry?.features.aspectRatios ?? undefined;
|
|
55
|
+
}
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Asset path resolution — paths starting with `/` resolve to the project's
|
|
58
|
+
// public/ folder (Vite convention), then fall back to absolute/relative paths.
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
/** Resolve a path prop to an absolute filesystem path.
|
|
61
|
+
* `/photo.png` → `{projectRoot}/public/photo.png` if the file exists.
|
|
62
|
+
* Relative paths resolve against projectRoot.
|
|
63
|
+
* Absolute paths and URLs pass through unchanged. */
|
|
64
|
+
export async function resolveAssetPath(p) {
|
|
65
|
+
await ensureInit();
|
|
66
|
+
const { getProjectRoot } = await import('../cli/cache-utils.js');
|
|
67
|
+
const root = getProjectRoot();
|
|
68
|
+
if (p.startsWith('http://') || p.startsWith('https://'))
|
|
69
|
+
return p;
|
|
70
|
+
if (p.startsWith('/')) {
|
|
71
|
+
const publicDir = path.join(root, 'public');
|
|
72
|
+
const publicPath = path.resolve(publicDir, '.' + p);
|
|
73
|
+
if (publicPath.startsWith(publicDir + path.sep) && fs.existsSync(publicPath)) {
|
|
74
|
+
return publicPath;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (path.isAbsolute(p))
|
|
78
|
+
return p;
|
|
79
|
+
return path.resolve(root, p);
|
|
80
|
+
}
|
|
81
|
+
/** Resolve a path and read it as bytes. */
|
|
82
|
+
export async function readAssetBytes(p) {
|
|
83
|
+
const resolved = await resolveAssetPath(p);
|
|
84
|
+
if (resolved.startsWith('http://') || resolved.startsWith('https://')) {
|
|
85
|
+
const res = await fetch(resolved);
|
|
86
|
+
if (!res.ok)
|
|
87
|
+
throw new Error(`Failed to fetch ${resolved}: ${res.status}`);
|
|
88
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
89
|
+
}
|
|
90
|
+
return new Uint8Array(fs.readFileSync(resolved));
|
|
91
|
+
}
|
|
92
|
+
export async function GeneratedImage({ inputImages: inputImagePaths, maskImage: maskImagePath, ...props }) {
|
|
93
|
+
await ensureInit();
|
|
94
|
+
const { prompt, model, seed, aspectRatio: aspectRatioProp, quality, resolution, outputFormat, negativePrompt, allowPeople, imageSize, ...passthrough } = props;
|
|
95
|
+
const { width, height } = await getCompositionDimensions();
|
|
96
|
+
const allowedRatios = getModelAspectRatios(model ?? DEFAULT_MODEL, 'image');
|
|
97
|
+
const aspectRatio = aspectRatioProp ?? (allowedRatios?.length ? aspectRatioFromDimensions(width, height, allowedRatios) : undefined);
|
|
98
|
+
const inputImages = inputImagePaths ? await Promise.all(inputImagePaths.map(readAssetBytes)) : undefined;
|
|
99
|
+
const maskImage = maskImagePath ? await readAssetBytes(maskImagePath) : undefined;
|
|
100
|
+
const genParams = { prompt, model, seed, aspectRatio, quality, resolution, outputFormat, negativePrompt, allowPeople, imageSize, inputImages, maskImage };
|
|
101
|
+
// Sync cache check + fallback lookup for RSC streaming.
|
|
102
|
+
// Uses the wrapper's getCacheInfo() so the same cacheKey config is applied.
|
|
103
|
+
const { generateImage } = await import('../cli/generate.js');
|
|
104
|
+
const cacheInfo = generateImage.getCacheInfo(genParams);
|
|
105
|
+
if (cacheInfo.cached) {
|
|
106
|
+
return _jsx(GeneratedImageClient, { srcPromise: Promise.resolve(`/generated/image/${cacheInfo.cached}`), ...passthrough });
|
|
107
|
+
}
|
|
108
|
+
const srcPromise = generateImage(genParams)
|
|
109
|
+
.then((result) => {
|
|
110
|
+
if (result instanceof Error)
|
|
111
|
+
throw result;
|
|
112
|
+
return result.src;
|
|
113
|
+
});
|
|
114
|
+
return _jsx(GeneratedImageClient, { srcPromise: srcPromise, fallbackSrc: cacheInfo.fallbackSrc, ...passthrough });
|
|
115
|
+
}
|
|
116
|
+
export async function GeneratedVideo({ inputImage: inputImagePath, ...props }) {
|
|
117
|
+
await ensureInit();
|
|
118
|
+
const { prompt, model, seed, aspectRatio: aspectRatioProp, resolution, duration, fps, negativePrompt, mode, videoUrl, referenceImages, ...passthrough } = props;
|
|
119
|
+
const inputImage = inputImagePath ? await readAssetBytes(inputImagePath) : undefined;
|
|
120
|
+
const { width, height } = await getCompositionDimensions();
|
|
121
|
+
const allowedRatios = getModelAspectRatios(model ?? DEFAULT_VIDEO_MODEL, 'video');
|
|
122
|
+
const aspectRatio = aspectRatioProp ?? (allowedRatios?.length ? aspectRatioFromDimensions(width, height, allowedRatios) : undefined);
|
|
123
|
+
const genParams = { prompt, model, seed, aspectRatio, resolution, duration, fps, negativePrompt, inputImage, mode, videoUrl, referenceImages };
|
|
124
|
+
const { generateVideo } = await import('../cli/generate.js');
|
|
125
|
+
const cacheInfo = generateVideo.getCacheInfo(genParams);
|
|
126
|
+
if (cacheInfo.cached) {
|
|
127
|
+
return _jsx(GeneratedVideoClient, { srcPromise: Promise.resolve(`/generated/video/${cacheInfo.cached}`), ...passthrough });
|
|
128
|
+
}
|
|
129
|
+
const srcPromise = generateVideo(genParams)
|
|
130
|
+
.then((result) => {
|
|
131
|
+
if (result instanceof Error)
|
|
132
|
+
throw result;
|
|
133
|
+
return result.src;
|
|
134
|
+
});
|
|
135
|
+
return _jsx(GeneratedVideoClient, { srcPromise: srcPromise, fallbackSrc: cacheInfo.fallbackSrc, ...passthrough });
|
|
136
|
+
}
|
|
137
|
+
export async function GeneratedSpeech(props) {
|
|
138
|
+
await ensureInit();
|
|
139
|
+
const { text, model, voice, outputFormat, instructions, speed, language, seed, ...passthrough } = props;
|
|
140
|
+
const genParams = { text, model, voice, outputFormat, instructions, speed, language, seed };
|
|
141
|
+
const { generateSpeech } = await import('../cli/speech-generate.js');
|
|
142
|
+
const cacheInfo = generateSpeech.getCacheInfo(genParams);
|
|
143
|
+
if (cacheInfo.cached) {
|
|
144
|
+
return _jsx(GeneratedSpeechClient, { srcPromise: Promise.resolve(`/generated/audio/${cacheInfo.cached}`), ...passthrough });
|
|
145
|
+
}
|
|
146
|
+
const srcPromise = generateSpeech(genParams)
|
|
147
|
+
.then((result) => {
|
|
148
|
+
if (result instanceof Error)
|
|
149
|
+
throw result;
|
|
150
|
+
return result.src;
|
|
151
|
+
});
|
|
152
|
+
return _jsx(GeneratedSpeechClient, { srcPromise: srcPromise, fallbackSrc: cacheInfo.fallbackSrc, ...passthrough });
|
|
153
|
+
}
|
|
154
|
+
export async function TextToSpeech({ text, voice = 'alloy' }) {
|
|
155
|
+
return GeneratedSpeech({ text, voice });
|
|
156
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <Server> MDX parsing utilities.
|
|
3
|
+
*
|
|
4
|
+
* <Server> is a reserved MDX element marking a subtree as React Server
|
|
5
|
+
* Components. This module contains the pure parsing logic shared by the
|
|
6
|
+
* server (app.tsx), the client (mdx-client.tsx), and the vite plugin:
|
|
7
|
+
*
|
|
8
|
+
* - findServerNodes: locate <Server> elements, keyed by start line
|
|
9
|
+
* - blankServerContents: strip server content from the client-facing MDX
|
|
10
|
+
* string while preserving line positions
|
|
11
|
+
* - collectServerImportSources: detect which MDX imports <Server> blocks
|
|
12
|
+
* need (app.tsx dynamically imports them at request time)
|
|
13
|
+
* - filterImportNodesToModules: per-statement import filtering against an
|
|
14
|
+
* environment's modules map
|
|
15
|
+
*
|
|
16
|
+
* Environment-neutral: no remotion, react, or node-only imports.
|
|
17
|
+
*/
|
|
18
|
+
type RootContent = any;
|
|
19
|
+
export interface ServerNode {
|
|
20
|
+
/** Slot key: the node's start LINE as a string. Stable across server
|
|
21
|
+
* and client because both parse the same source string
|
|
22
|
+
* (blankServerContents preserves all line positions). Line-only (no
|
|
23
|
+
* column) because the client matches slots via the data-markdown-line
|
|
24
|
+
* prop that safe-mdx injects, which only carries the line. Two <Server>
|
|
25
|
+
* elements on the same line collide — app.tsx warns about duplicates. */
|
|
26
|
+
key: string;
|
|
27
|
+
node: RootContent;
|
|
28
|
+
}
|
|
29
|
+
/** Recursively find <Server> elements in the mdast. Server nodes nested
|
|
30
|
+
* inside another <Server> are skipped — the outer slot covers them. */
|
|
31
|
+
export declare function findServerNodes(mdast: {
|
|
32
|
+
children?: RootContent[];
|
|
33
|
+
}): ServerNode[];
|
|
34
|
+
/** Replace each <Server> element's source range with a self-closing
|
|
35
|
+
* `<Server />` marker, padded with newlines so the result has the EXACT
|
|
36
|
+
* same line count and all subsequent positions stay valid. This keeps
|
|
37
|
+
* slot keys, data-markdown-line attributes, and sourcemaps aligned with
|
|
38
|
+
* the original file, and prevents the client from parsing (and trying to
|
|
39
|
+
* resolve imports for) server-only content. */
|
|
40
|
+
export declare function blankServerContents(source: string, serverNodes: ServerNode[]): string;
|
|
41
|
+
/** Collect MDX import sources whose names are used inside <Server>
|
|
42
|
+
* subtrees. Includes bare specifiers (e.g. 'egaki/text-to-speech') —
|
|
43
|
+
* app.tsx imports them through vite's resolver, and the resolved file's
|
|
44
|
+
* 'use client' directive (or lack of it) decides whether the exports are
|
|
45
|
+
* client refs or server components. */
|
|
46
|
+
export declare function collectServerImportSources(mdast: {
|
|
47
|
+
children?: RootContent[];
|
|
48
|
+
}): string[];
|
|
49
|
+
/** Component names that should be auto-wrapped in <Server>. */
|
|
50
|
+
export declare const GENERATED_COMPONENT_NAMES: Set<string>;
|
|
51
|
+
/** Collect local names imported from *.server.* sources in the MDX.
|
|
52
|
+
* These components should be auto-wrapped in <Server> because the
|
|
53
|
+
* .server postfix signals they run in the RSC environment. */
|
|
54
|
+
export declare function collectServerFileImportNames(mdast: {
|
|
55
|
+
children?: RootContent[];
|
|
56
|
+
}): Set<string>;
|
|
57
|
+
/** Walk the mdast and wrap bare server components in <Server>.
|
|
58
|
+
* Targets two categories:
|
|
59
|
+
* 1. Built-in generated media components (GeneratedImage, etc.)
|
|
60
|
+
* 2. Components imported from *.server.* files
|
|
61
|
+
* Mutates the tree in place. Wrapping reuses the original node's position
|
|
62
|
+
* so slot keys and line numbers are unchanged. */
|
|
63
|
+
export declare function wrapGenerateNodes(mdast: {
|
|
64
|
+
children?: RootContent[];
|
|
65
|
+
}): void;
|
|
66
|
+
/** Filter mdxjsEsm import nodes to statements whose source is resolvable
|
|
67
|
+
* in the given modules map. Each environment's map only contains the
|
|
68
|
+
* modules that belong there, so this keeps exactly the imports that
|
|
69
|
+
* environment can satisfy — no naming rules. Filtering is per-STATEMENT:
|
|
70
|
+
* contiguous import lines parse as a single mdxjsEsm node, so dropping
|
|
71
|
+
* whole nodes would remove unrelated imports. */
|
|
72
|
+
export declare function filterImportNodesToModules(importNodes: RootContent[], moduleKeys: string[]): RootContent[];
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=server-mdx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-mdx.d.ts","sourceRoot":"","sources":["../../src/vite/server-mdx.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,KAAK,WAAW,GAAG,GAAG,CAAA;AAYtB,MAAM,WAAW,UAAU;IACzB;;;;;8EAK0E;IAC1E,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,WAAW,CAAA;CAClB;AAMD;wEACwE;AACxE,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,GAAG,UAAU,EAAE,CAcjF;AAED;;;;;gDAKgD;AAChD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAgBrF;AAsDD;;;;wCAIwC;AACxC,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,GAAG,MAAM,EAAE,CA+BxF;AAYD,+DAA+D;AAC/D,eAAO,MAAM,yBAAyB,aAIpC,CAAA;AAEF;;+DAE+D;AAC/D,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAe7F;AAED;;;;;mDAKmD;AACnD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,GAAG,IAAI,CAqC3E;AAED;;;;;kDAKkD;AAClD,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,WAAW,EAAE,EAC1B,UAAU,EAAE,MAAM,EAAE,GACnB,WAAW,EAAE,CAaf"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <Server> MDX parsing utilities.
|
|
3
|
+
*
|
|
4
|
+
* <Server> is a reserved MDX element marking a subtree as React Server
|
|
5
|
+
* Components. This module contains the pure parsing logic shared by the
|
|
6
|
+
* server (app.tsx), the client (mdx-client.tsx), and the vite plugin:
|
|
7
|
+
*
|
|
8
|
+
* - findServerNodes: locate <Server> elements, keyed by start line
|
|
9
|
+
* - blankServerContents: strip server content from the client-facing MDX
|
|
10
|
+
* string while preserving line positions
|
|
11
|
+
* - collectServerImportSources: detect which MDX imports <Server> blocks
|
|
12
|
+
* need (app.tsx dynamically imports them at request time)
|
|
13
|
+
* - filterImportNodesToModules: per-statement import filtering against an
|
|
14
|
+
* environment's modules map
|
|
15
|
+
*
|
|
16
|
+
* Environment-neutral: no remotion, react, or node-only imports.
|
|
17
|
+
*/
|
|
18
|
+
import { resolveModulePath } from 'safe-mdx/parse';
|
|
19
|
+
function serverNodeKey(node) {
|
|
20
|
+
return String(node.position?.start?.line);
|
|
21
|
+
}
|
|
22
|
+
/** Recursively find <Server> elements in the mdast. Server nodes nested
|
|
23
|
+
* inside another <Server> are skipped — the outer slot covers them. */
|
|
24
|
+
export function findServerNodes(mdast) {
|
|
25
|
+
const found = [];
|
|
26
|
+
const visit = (node) => {
|
|
27
|
+
const isServer = (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement')
|
|
28
|
+
&& node.name === 'Server';
|
|
29
|
+
if (isServer) {
|
|
30
|
+
found.push({ key: serverNodeKey(node), node });
|
|
31
|
+
return; // don't descend — nested Server is part of the outer slot
|
|
32
|
+
}
|
|
33
|
+
for (const child of node.children || [])
|
|
34
|
+
visit(child);
|
|
35
|
+
};
|
|
36
|
+
for (const child of mdast.children || [])
|
|
37
|
+
visit(child);
|
|
38
|
+
return found;
|
|
39
|
+
}
|
|
40
|
+
/** Replace each <Server> element's source range with a self-closing
|
|
41
|
+
* `<Server />` marker, padded with newlines so the result has the EXACT
|
|
42
|
+
* same line count and all subsequent positions stay valid. This keeps
|
|
43
|
+
* slot keys, data-markdown-line attributes, and sourcemaps aligned with
|
|
44
|
+
* the original file, and prevents the client from parsing (and trying to
|
|
45
|
+
* resolve imports for) server-only content. */
|
|
46
|
+
export function blankServerContents(source, serverNodes) {
|
|
47
|
+
// Process back-to-front so earlier offsets stay valid after each splice.
|
|
48
|
+
const sorted = [...serverNodes].sort((a, b) => (b.node.position?.start?.offset ?? 0) - (a.node.position?.start?.offset ?? 0));
|
|
49
|
+
let result = source;
|
|
50
|
+
for (const { node } of sorted) {
|
|
51
|
+
const start = node.position?.start?.offset;
|
|
52
|
+
const end = node.position?.end?.offset;
|
|
53
|
+
if (typeof start !== 'number' || typeof end !== 'number')
|
|
54
|
+
continue;
|
|
55
|
+
const span = result.slice(start, end);
|
|
56
|
+
const newlines = span.split('\n').length - 1;
|
|
57
|
+
const replacement = '<Server />' + '\n'.repeat(newlines);
|
|
58
|
+
result = result.slice(0, start) + replacement + result.slice(end);
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Server import detection
|
|
64
|
+
//
|
|
65
|
+
// Detects which MDX imports are needed by <Server> slot rendering by
|
|
66
|
+
// scanning identifier usage inside <Server> subtrees. app.tsx dynamically
|
|
67
|
+
// imports exactly these sources at request time — no filename convention
|
|
68
|
+
// required (though *.server.* remains supported as a hard "never bundle
|
|
69
|
+
// to the browser" override in the vite plugin).
|
|
70
|
+
//
|
|
71
|
+
// Detection is name-based and intentionally COARSE: it collects JSX
|
|
72
|
+
// element names (root identifier of <ns.Comp/>) plus every estree
|
|
73
|
+
// Identifier in expressions and attribute values. Over-collection just
|
|
74
|
+
// imports an extra file server-side; under-collection would break slot
|
|
75
|
+
// rendering, so coarse is the safe direction.
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
/** Collect every estree Identifier name reachable from a value. */
|
|
78
|
+
function collectEstreeIdentifiers(value, out) {
|
|
79
|
+
if (!value || typeof value !== 'object')
|
|
80
|
+
return;
|
|
81
|
+
if (Array.isArray(value)) {
|
|
82
|
+
for (const item of value)
|
|
83
|
+
collectEstreeIdentifiers(item, out);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (value.type === 'Identifier' && typeof value.name === 'string') {
|
|
87
|
+
out.add(value.name);
|
|
88
|
+
}
|
|
89
|
+
for (const key of Object.keys(value)) {
|
|
90
|
+
if (key === 'position' || key === 'loc' || key === 'range' || key === 'start' || key === 'end')
|
|
91
|
+
continue;
|
|
92
|
+
collectEstreeIdentifiers(value[key], out);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Collect identifier usage from a single mdast node into a bucket:
|
|
96
|
+
* JSX element names plus identifiers in expressions/attribute values. */
|
|
97
|
+
function collectNodeIdentifiers(node, out) {
|
|
98
|
+
if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
|
|
99
|
+
if (typeof node.name === 'string' && node.name) {
|
|
100
|
+
out.add(node.name.split('.')[0]);
|
|
101
|
+
}
|
|
102
|
+
for (const attr of node.attributes || []) {
|
|
103
|
+
if (attr.type === 'mdxJsxExpressionAttribute') {
|
|
104
|
+
collectEstreeIdentifiers(attr.data?.estree, out);
|
|
105
|
+
}
|
|
106
|
+
else if (attr.value && typeof attr.value === 'object') {
|
|
107
|
+
collectEstreeIdentifiers(attr.value.data?.estree, out);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression') {
|
|
112
|
+
collectEstreeIdentifiers(node.data?.estree, out);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Collect MDX import sources whose names are used inside <Server>
|
|
116
|
+
* subtrees. Includes bare specifiers (e.g. 'egaki/text-to-speech') —
|
|
117
|
+
* app.tsx imports them through vite's resolver, and the resolved file's
|
|
118
|
+
* 'use client' directive (or lack of it) decides whether the exports are
|
|
119
|
+
* client refs or server components. */
|
|
120
|
+
export function collectServerImportSources(mdast) {
|
|
121
|
+
const insideNames = new Set();
|
|
122
|
+
const visit = (node, insideServer) => {
|
|
123
|
+
const isServer = (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement')
|
|
124
|
+
&& node.name === 'Server';
|
|
125
|
+
const nowInside = insideServer || isServer;
|
|
126
|
+
if (nowInside && !isServer) {
|
|
127
|
+
// The <Server> element itself contributes no identifiers.
|
|
128
|
+
collectNodeIdentifiers(node, insideNames);
|
|
129
|
+
}
|
|
130
|
+
for (const child of node.children || [])
|
|
131
|
+
visit(child, nowInside);
|
|
132
|
+
};
|
|
133
|
+
for (const child of mdast.children || [])
|
|
134
|
+
visit(child, false);
|
|
135
|
+
const sources = new Set();
|
|
136
|
+
for (const node of mdast.children || []) {
|
|
137
|
+
if (node.type !== 'mdxjsEsm')
|
|
138
|
+
continue;
|
|
139
|
+
const body = node.data?.estree?.body || [];
|
|
140
|
+
for (const stmt of body) {
|
|
141
|
+
if (stmt.type !== 'ImportDeclaration')
|
|
142
|
+
continue;
|
|
143
|
+
const source = stmt.source?.value;
|
|
144
|
+
if (typeof source !== 'string')
|
|
145
|
+
continue;
|
|
146
|
+
const locals = (stmt.specifiers || [])
|
|
147
|
+
.map((s) => s.local?.name)
|
|
148
|
+
.filter(Boolean);
|
|
149
|
+
if (locals.some((name) => insideNames.has(name)))
|
|
150
|
+
sources.add(source);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return [...sources].sort();
|
|
154
|
+
}
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Auto-wrap generated media components in <Server>
|
|
157
|
+
//
|
|
158
|
+
// <GeneratedImage>, <GeneratedVideo>, <GeneratedSpeech> are server components
|
|
159
|
+
// that call egaki's generation APIs. When found bare in the mdast (not inside
|
|
160
|
+
// a <Server> block), this transform wraps them in a synthetic <Server> node
|
|
161
|
+
// so findServerNodes() picks them up. The wrapper reuses the original node's
|
|
162
|
+
// position so line numbers stay stable and no sourcemap fixup is needed.
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
/** Component names that should be auto-wrapped in <Server>. */
|
|
165
|
+
export const GENERATED_COMPONENT_NAMES = new Set([
|
|
166
|
+
'GeneratedImage',
|
|
167
|
+
'GeneratedVideo',
|
|
168
|
+
'GeneratedSpeech',
|
|
169
|
+
]);
|
|
170
|
+
/** Collect local names imported from *.server.* sources in the MDX.
|
|
171
|
+
* These components should be auto-wrapped in <Server> because the
|
|
172
|
+
* .server postfix signals they run in the RSC environment. */
|
|
173
|
+
export function collectServerFileImportNames(mdast) {
|
|
174
|
+
const names = new Set();
|
|
175
|
+
for (const node of mdast.children || []) {
|
|
176
|
+
if (node.type !== 'mdxjsEsm')
|
|
177
|
+
continue;
|
|
178
|
+
for (const stmt of node.data?.estree?.body || []) {
|
|
179
|
+
if (stmt.type !== 'ImportDeclaration')
|
|
180
|
+
continue;
|
|
181
|
+
const source = stmt.source?.value;
|
|
182
|
+
if (typeof source !== 'string')
|
|
183
|
+
continue;
|
|
184
|
+
if (!/\.server(\.[jt]sx?)?$/.test(source))
|
|
185
|
+
continue;
|
|
186
|
+
for (const spec of stmt.specifiers || []) {
|
|
187
|
+
if (spec.local?.name)
|
|
188
|
+
names.add(spec.local.name);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return names;
|
|
193
|
+
}
|
|
194
|
+
/** Walk the mdast and wrap bare server components in <Server>.
|
|
195
|
+
* Targets two categories:
|
|
196
|
+
* 1. Built-in generated media components (GeneratedImage, etc.)
|
|
197
|
+
* 2. Components imported from *.server.* files
|
|
198
|
+
* Mutates the tree in place. Wrapping reuses the original node's position
|
|
199
|
+
* so slot keys and line numbers are unchanged. */
|
|
200
|
+
export function wrapGenerateNodes(mdast) {
|
|
201
|
+
const serverImportNames = collectServerFileImportNames(mdast);
|
|
202
|
+
const shouldWrap = (name) => GENERATED_COMPONENT_NAMES.has(name) || serverImportNames.has(name);
|
|
203
|
+
const wrapInParent = (parent) => {
|
|
204
|
+
if (!parent.children)
|
|
205
|
+
return;
|
|
206
|
+
for (let i = 0; i < parent.children.length; i++) {
|
|
207
|
+
const node = parent.children[i];
|
|
208
|
+
// Use root identifier for dotted names like <Scenes.Hero /> → "Scenes"
|
|
209
|
+
const jsxRootName = typeof node.name === 'string' ? node.name.split('.')[0] : '';
|
|
210
|
+
if ((node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement')
|
|
211
|
+
&& shouldWrap(jsxRootName)) {
|
|
212
|
+
// Wrap in a synthetic <Server> with the same position so slot
|
|
213
|
+
// keying (by start line) stays identical and blankServerContents
|
|
214
|
+
// replaces the right source span.
|
|
215
|
+
parent.children[i] = {
|
|
216
|
+
type: node.type,
|
|
217
|
+
name: 'Server',
|
|
218
|
+
attributes: [],
|
|
219
|
+
children: [node],
|
|
220
|
+
position: node.position ? { ...node.position } : undefined,
|
|
221
|
+
};
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
// Don't descend into <Server> — already server-side
|
|
225
|
+
const isServer = (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement')
|
|
226
|
+
&& node.name === 'Server';
|
|
227
|
+
if (isServer)
|
|
228
|
+
continue;
|
|
229
|
+
// Recurse into other elements
|
|
230
|
+
if (node.children)
|
|
231
|
+
wrapInParent(node);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
wrapInParent(mdast);
|
|
235
|
+
}
|
|
236
|
+
/** Filter mdxjsEsm import nodes to statements whose source is resolvable
|
|
237
|
+
* in the given modules map. Each environment's map only contains the
|
|
238
|
+
* modules that belong there, so this keeps exactly the imports that
|
|
239
|
+
* environment can satisfy — no naming rules. Filtering is per-STATEMENT:
|
|
240
|
+
* contiguous import lines parse as a single mdxjsEsm node, so dropping
|
|
241
|
+
* whole nodes would remove unrelated imports. */
|
|
242
|
+
export function filterImportNodesToModules(importNodes, moduleKeys) {
|
|
243
|
+
return importNodes.map((node) => {
|
|
244
|
+
const estree = node.data?.estree;
|
|
245
|
+
if (!estree?.body)
|
|
246
|
+
return node;
|
|
247
|
+
const body = estree.body.filter((stmt) => {
|
|
248
|
+
if (stmt.type !== 'ImportDeclaration')
|
|
249
|
+
return true;
|
|
250
|
+
const source = stmt.source?.value;
|
|
251
|
+
if (typeof source !== 'string')
|
|
252
|
+
return true;
|
|
253
|
+
return resolveModulePath(source, './', moduleKeys) !== undefined;
|
|
254
|
+
});
|
|
255
|
+
if (body.length === estree.body.length)
|
|
256
|
+
return node;
|
|
257
|
+
return { ...node, data: { ...node.data, estree: { ...estree, body } } };
|
|
258
|
+
});
|
|
259
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type CSSProperties } from 'react';
|
|
2
|
+
export interface NumberControl {
|
|
3
|
+
type: 'number';
|
|
4
|
+
defaultValue: number;
|
|
5
|
+
min: number;
|
|
6
|
+
max: number;
|
|
7
|
+
step: number;
|
|
8
|
+
/** Hidden controls are not shown in the tweakpane UI but still set as uniforms. */
|
|
9
|
+
hidden?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ColorArrayControl {
|
|
12
|
+
type: 'array';
|
|
13
|
+
control: {
|
|
14
|
+
type: 'color';
|
|
15
|
+
};
|
|
16
|
+
/** Maximum number of colors. Determines the GLSL array size. */
|
|
17
|
+
maxCount: number;
|
|
18
|
+
/** Max color slots shown in tweakpane UI. Defaults to maxCount. */
|
|
19
|
+
maxVisible?: number;
|
|
20
|
+
defaultValue: string[];
|
|
21
|
+
}
|
|
22
|
+
export type PropertyControl = NumberControl | ColorArrayControl;
|
|
23
|
+
export interface ShaderConfig {
|
|
24
|
+
/** Display name shown in tweakpane and used as React displayName. */
|
|
25
|
+
title: string;
|
|
26
|
+
/** Fragment shader body (everything after the auto-generated header). */
|
|
27
|
+
fragment: string;
|
|
28
|
+
/** Property controls that become uniforms and tweakpane sliders. */
|
|
29
|
+
propertyControls: Record<string, PropertyControl>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a React component that renders a WebGL2 fragment shader full-screen.
|
|
33
|
+
*
|
|
34
|
+
* The returned component accepts all property control keys as optional props
|
|
35
|
+
* plus a `style` prop. Number controls are exposed in tweakpane as sliders
|
|
36
|
+
* (unless `hidden: true`). Color array items are exposed as individual
|
|
37
|
+
* tweakpane color pickers with swatch UI.
|
|
38
|
+
*
|
|
39
|
+
* Time and resolution are derived from Remotion's hooks, making the shader
|
|
40
|
+
* fully deterministic and seekable.
|
|
41
|
+
*/
|
|
42
|
+
export declare function defineShader(config: ShaderConfig): {
|
|
43
|
+
(props: Record<string, any> & {
|
|
44
|
+
style?: CSSProperties;
|
|
45
|
+
}): import("react").JSX.Element;
|
|
46
|
+
displayName: string;
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=shader-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shader-renderer.d.ts","sourceRoot":"","sources":["../../src/vite/shader-renderer.tsx"],"names":[],"mappings":"AA8BA,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,OAAO,CAAA;AAOnE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAA;IAC1B,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAA;IAChB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,iBAAiB,CAAA;AAE/D,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CAClD;AAoLD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY;YAsEtC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;QAAE,KAAK,CAAC,EAAE,aAAa,CAAA;KAAE;;EA+MzD"}
|