@aklinker1/viteshot 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aaron
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ <div align="center">
2
+
3
+ # ViteShot
4
+
5
+ Build and generate store screenshots and promo images with code, powered by Vite.
6
+
7
+ </div>
8
+
9
+ ## Why?
10
+
11
+ With AI, it's common for developers with less design experience to generate store screenshots and promo images. However, one shot image generation models aren't very good at this yet.
12
+
13
+ However, AI is really good at building *simple* UIs with HTML! ViteShot provides a simple way for agents in your preferred dev environment to create and generate images in a structured, easy-to-iterate way.
14
+
15
+ ## Get Started
16
+
17
+ 1. Add Vite and ViteShot as dev dependencies to your project:
18
+
19
+ ```sh
20
+ bun add -D vite @aklinker1/viteshot
21
+ ```
22
+
23
+ 2. Initialize the `./store` directory:
24
+
25
+ ```sh
26
+ bun viteshot init ./store
27
+ ```
28
+
29
+ 3. Add the following scripts to your `package.json`:
30
+
31
+ ```sh
32
+ {
33
+ "scripts": {
34
+ "store:dev": "viteshot dev ./store",
35
+ "store:generate": "viteshot generate ./store",
36
+ }
37
+ }
38
+ ```
39
+
40
+ Then generate your screenshots with `bun store:generate`! Screenshots will be output to `store/screenshots`.
41
+
42
+ ## Design Files
43
+
44
+ Your screenshot designs go in `store/designs/{name}@{width}x{height}.{ext}`.
45
+
46
+ - `{name}`: The name of your screenshot, it can be anything (ex: "small-marquee", "screenshot-1", etc).
47
+ - `{width}x{height}`: The size your screenshot should be rendered at (ex: "1280x600", "640x400").
48
+ - `{ext}`: ViteShot supports a variety of file extensions, so you can build your designs using your preferred frontend framework!
49
+
50
+ ### HTML (Recommended)
51
+
52
+ You don't need a frontend framework to build a simple static layout.
53
+
54
+ ```html
55
+ <div>My screenshot design</div>
56
+ ```
57
+
58
+ ### Vue
59
+
60
+ TODO
61
+
62
+ ### Svelte
63
+
64
+ TODO
65
+
66
+ ### React
67
+
68
+ TODO
69
+
70
+ ## Styling
71
+
72
+ 1. Setup your framework (like installing the TailwindCSS Vite plugin)
73
+ 2. In your screenshots file, `<link>` to your CSS file, import your CSS file, or import your UI framework's components
74
+
75
+ And that's it!
76
+
77
+ ## Assets
78
+
79
+ Create an `assets` directory and reference them via `assets/<filename>`. Vite will load them.
@@ -0,0 +1,85 @@
1
+ /** Main JS module for displaying the different screenshots */
2
+ import screenshots from "viteshot-virtual/screenshots";
3
+ import locales from "viteshot-virtual/locales";
4
+
5
+ declare const app: HTMLDivElement;
6
+
7
+ // Language management
8
+
9
+ const CURRENT_LANGUAGE_STORAGE_KEY = "viteshot:current-language";
10
+
11
+ let currentLanguageId: string | undefined = locales[0]?.language;
12
+
13
+ function restoreLanguage() {
14
+ const oldId = localStorage.getItem(CURRENT_LANGUAGE_STORAGE_KEY);
15
+ if (!oldId) return;
16
+
17
+ const oldLocale = locales.find((l) => l.id === oldId);
18
+ if (!oldLocale) return;
19
+
20
+ currentLanguageId = oldId;
21
+ }
22
+
23
+ function setLanguage(languageId: string): void {
24
+ currentLanguageId = languageId;
25
+ localStorage.setItem(CURRENT_LANGUAGE_STORAGE_KEY, languageId);
26
+ }
27
+
28
+ // UI Rendering
29
+
30
+ function renderScreenshots() {
31
+ app.innerHTML = "";
32
+
33
+ const header = document.createElement("div");
34
+ {
35
+ header.className = "header";
36
+
37
+ const h1 = document.createElement("h1");
38
+ h1.textContent = "Dashboard";
39
+ header.append(h1);
40
+
41
+ if (locales.length > 0) {
42
+ const select = document.createElement("select");
43
+
44
+ for (const locale of locales) {
45
+ const option = document.createElement("option");
46
+ option.value = locale.id;
47
+ option.textContent = locale.language;
48
+ select.append(option);
49
+ }
50
+
51
+ if (currentLanguageId) select.value = currentLanguageId;
52
+
53
+ select.addEventListener("change", () => {
54
+ setLanguage(select.value);
55
+ renderScreenshots();
56
+ });
57
+
58
+ header.append(select);
59
+ }
60
+ }
61
+ app.append(header);
62
+
63
+ const listItems = screenshots.map((screenshot) => {
64
+ const li = document.createElement("li");
65
+ li.id = screenshot.id;
66
+ li.className = "list-item";
67
+
68
+ const p = document.createElement("p");
69
+ p.textContent = screenshot.name;
70
+ li.append(p);
71
+
72
+ const iframe = document.createElement("iframe");
73
+ iframe.src = `/screenshot/${currentLanguageId ? encodeURIComponent(currentLanguageId) : "null"}/${encodeURIComponent(screenshot.id)}`;
74
+ if (screenshot.width) iframe.width = String(screenshot.width);
75
+ if (screenshot.width) iframe.height = String(screenshot.height);
76
+ li.append(iframe);
77
+
78
+ return li;
79
+ });
80
+
81
+ app.append(...listItems);
82
+ }
83
+
84
+ restoreLanguage();
85
+ renderScreenshots();
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.mjs ADDED
@@ -0,0 +1,18 @@
1
+ import { n as createServer, t as generateScreenshots } from "./generate-screenshots-bbolMzf5.mjs";
2
+
3
+ //#region src/cli.ts
4
+ const [command, ..._args] = process.argv.slice(2);
5
+ switch (command) {
6
+ case "dev":
7
+ const server = await createServer("example");
8
+ await server.listen();
9
+ server.printUrls();
10
+ break;
11
+ case "generate":
12
+ await generateScreenshots("example");
13
+ process.exit(0);
14
+ default: break;
15
+ }
16
+
17
+ //#endregion
18
+ export { };
@@ -0,0 +1,300 @@
1
+ import { dirname, extname, join, relative, resolve } from "node:path";
2
+ import { pathToFileURL } from "node:url";
3
+ import { mkdir, readFile, readdir, rm } from "node:fs/promises";
4
+ import natsort from "natural-compare-lite";
5
+ import { createServer } from "vite";
6
+ import puppeteer from "puppeteer-core";
7
+ import pMap from "p-map";
8
+ import { Mutex } from "async-mutex";
9
+
10
+ //#region src/templates/favicon.svg?raw
11
+ var favicon_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" width=\"200\" height=\"200\">\n <polygon points=\"50,15 61,40 88,40 66,57 74,82 50,65 26,82 34,57 12,40 39,40\" fill=\"yellow\" stroke=\"black\" stroke-width=\"1\"/>\n</svg>\n";
12
+
13
+ //#endregion
14
+ //#region src/templates/dashboard.html?raw
15
+ var dashboard_default = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Viteshot</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n min-width: 0;\n min-height: 0;\n list-style: none;\n }\n\n .app {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n }\n .header {\n display: flex;\n align-items: center;\n gap: 1rem;\n }\n .header h1 {\n flex: 1;\n }\n .header select {\n flex-shrink: 0;\n padding-left: 0.25rem;\n }\n .list-item {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n </style>\n </head>\n <body>\n <div id=\"app\" class=\"app\"></div>\n <script type=\"module\" src=\"/viteshot-assets/dashboard.ts\"><\/script>\n </body>\n</html>\n";
16
+
17
+ //#endregion
18
+ //#region src/templates/screenshot.html?raw
19
+ var screenshot_default = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Screenshot</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />\n <style>\n body {\n margin: 0;\n padding: 0;\n }\n </style>\n </head>\n <body>\n <div id=\"app\" class=\"app\"></div>\n <script type=\"module\">\n import { renderScreenshot } from \"/viteshot-virtual/render-screenshot/{{screenshot.id}}\";\n import messages from \"/viteshot-virtual/messages/{{locale.id}}\";\n\n renderScreenshot(app, messages);\n <\/script>\n </body>\n</html>\n";
20
+
21
+ //#endregion
22
+ //#region src/templates/render-html-screenshot.js?raw
23
+ var render_html_screenshot_default = "import HTML from \"/@fs/{{path}}?raw\";\n\nexport function renderScreenshot(container, messages) {\n container.innerHTML = Object.entries(messages).reduce(\n (text, [key, value]) => text.replaceAll(`{{${key}}}`, value),\n HTML,\n );\n}\n";
24
+
25
+ //#endregion
26
+ //#region src/utils.ts
27
+ async function getViteshotAssetsDir() {
28
+ if (process.env.DEV) return resolve("assets");
29
+ else return import.meta.resolve("viteshot");
30
+ }
31
+
32
+ //#endregion
33
+ //#region src/core/get-locales.ts
34
+ async function getLocales(localesDir) {
35
+ const jsonFilenames = (await readdir(localesDir, {})).filter((file) => file.endsWith(".json"));
36
+ return await Promise.all(jsonFilenames.map(async (file) => {
37
+ const ext = extname(file);
38
+ const text = await readFile(join(localesDir, file), "utf-8");
39
+ const messages = JSON.parse(text);
40
+ return {
41
+ id: file,
42
+ language: file.slice(0, -ext.length),
43
+ messages
44
+ };
45
+ }));
46
+ }
47
+
48
+ //#endregion
49
+ //#region src/core/get-screenshots.ts
50
+ async function getScreenshots(designsDir) {
51
+ return (await readdir(designsDir, {
52
+ recursive: true,
53
+ withFileTypes: true
54
+ })).filter((file) => file.isFile()).map((file) => {
55
+ const path = join(file.parentPath, file.name);
56
+ const ext = extname(file.name);
57
+ const filenameNoExt = file.name.slice(0, -ext.length);
58
+ const [name, size] = filenameNoExt.split("@", 2);
59
+ const [width, height] = size ? size.split("x").map((value) => Number(value)) : [];
60
+ return {
61
+ id: relative(designsDir, path),
62
+ path,
63
+ ext,
64
+ filenameNoExt,
65
+ name,
66
+ size,
67
+ width,
68
+ height
69
+ };
70
+ }).toSorted((a, b) => natsort(a.id, b.id));
71
+ }
72
+
73
+ //#endregion
74
+ //#region src/core/resolver-plugin.ts
75
+ function resolveTemplate(options) {
76
+ return (server) => () => server.middlewares.use(async (req, res, next) => {
77
+ if (!req.originalUrl) return;
78
+ const url = new URL(req.originalUrl, "http://localhost");
79
+ if (!options.match(url)) return next();
80
+ const text = options.vars == null ? options.template : applyTemplateVars(options.template, options.vars(url));
81
+ return res.end(options.transform ? await server.transformIndexHtml(req.originalUrl, text) : text);
82
+ });
83
+ }
84
+ const VIRTUAL_SCREENSHOTS_FILTER = { id: [/viteshot-virtual\/screenshots/] };
85
+ const VIRTUAL_LOCALES_FILTER = { id: [/viteshot-virtual\/locales/] };
86
+ function applyTemplateVars(template, vars) {
87
+ return Object.entries(vars).reduce((template, [key, value]) => template.replaceAll(`{{${key}}}`, value), template);
88
+ }
89
+ const RENDER_SCREENSHOT_JS_TEMPLATES = { ".html": render_html_screenshot_default };
90
+ const resolverPlugin = (config) => [
91
+ {
92
+ name: "viteshot:resolve-favicon",
93
+ configureServer: resolveTemplate({
94
+ match: (url) => url.pathname === "/favicon.svg",
95
+ template: favicon_default
96
+ })
97
+ },
98
+ {
99
+ name: "viteshot:resolve-dashboard-html",
100
+ configureServer: resolveTemplate({
101
+ match: (url) => url.pathname === "/",
102
+ template: dashboard_default,
103
+ transform: true
104
+ })
105
+ },
106
+ {
107
+ name: "viteshot:resolve-screenshot-html",
108
+ configureServer: resolveTemplate({
109
+ match: (url) => /\/screenshot\/.*?\/.*?/.test(url.pathname),
110
+ template: screenshot_default,
111
+ transform: true,
112
+ vars: (url) => {
113
+ const [localeId, screenshotId] = url.pathname.slice(12).split("/");
114
+ return {
115
+ "screenshot.id": screenshotId,
116
+ "locale.id": localeId
117
+ };
118
+ }
119
+ })
120
+ },
121
+ {
122
+ name: "viteshot:resolve-assets",
123
+ resolveId: {
124
+ filter: { id: [/\/viteshot-assets\//] },
125
+ handler: async (id) => {
126
+ return join(await getViteshotAssetsDir(), id.slice(17));
127
+ }
128
+ }
129
+ },
130
+ {
131
+ name: "viteshot:resolve-virtual:screenshots",
132
+ resolveId: {
133
+ filter: VIRTUAL_SCREENSHOTS_FILTER,
134
+ handler: (id) => id
135
+ },
136
+ load: {
137
+ filter: VIRTUAL_SCREENSHOTS_FILTER,
138
+ handler: async () => {
139
+ const screenshots = await getScreenshots(config.designsDir);
140
+ return `export default ${JSON.stringify(screenshots)}`;
141
+ }
142
+ }
143
+ },
144
+ {
145
+ name: "viteshot:resolve-virtual:locales",
146
+ resolveId: {
147
+ filter: VIRTUAL_LOCALES_FILTER,
148
+ handler: (id) => id
149
+ },
150
+ load: {
151
+ filter: VIRTUAL_LOCALES_FILTER,
152
+ handler: async () => {
153
+ const locales = await getLocales(config.localesDir);
154
+ return `export default ${JSON.stringify(locales)}`;
155
+ }
156
+ }
157
+ },
158
+ {
159
+ name: "viteshot:resolve-virtual:render-screenshot",
160
+ resolveId: {
161
+ filter: { id: [/^\/viteshot-virtual\/render-screenshot/] },
162
+ handler: (id) => id
163
+ },
164
+ load: {
165
+ filter: { id: [/^\/viteshot-virtual\/render-screenshot/] },
166
+ handler: (id) => {
167
+ const screenshotId = decodeURIComponent(id.slice(36));
168
+ if (!screenshotId) throw Error(`Required query param "id" not provided for ${id}`);
169
+ const ext = extname(screenshotId);
170
+ const path = join(config.designsDir, screenshotId);
171
+ const template = RENDER_SCREENSHOT_JS_TEMPLATES[ext];
172
+ if (!template) throw Error(`Unsupported screenshot file type (${ext}). Must be one of ${Object.keys(RENDER_SCREENSHOT_JS_TEMPLATES).join(", ")}`);
173
+ return applyTemplateVars(template, { path });
174
+ }
175
+ }
176
+ },
177
+ {
178
+ name: "viteshot:resolve-virtual:messages",
179
+ resolveId: {
180
+ filter: { id: [/\/viteshot-virtual\/messages/] },
181
+ handler: (id) => {
182
+ const localeId = id.slice(27);
183
+ if (!localeId) throw Error(`Required query param "id" not provided for ${id}`);
184
+ return join(config.localesDir, localeId);
185
+ }
186
+ }
187
+ }
188
+ ];
189
+
190
+ //#endregion
191
+ //#region src/core/config.ts
192
+ function defineConfig(config) {
193
+ return config;
194
+ }
195
+ async function importConfig(root) {
196
+ const configFileUrl = pathToFileURL(join(root, "viteshot.config")).href;
197
+ try {
198
+ return (await import(configFileUrl)).default ?? {};
199
+ } catch (err) {
200
+ if (err?.message?.includes?.("Cannot find module")) return {};
201
+ throw err;
202
+ }
203
+ }
204
+ async function resolveConfig(dir = process.cwd()) {
205
+ const root = resolve(dir);
206
+ const { localesDir: _localesDir, designsDir: _designsDir, screenshotsDir: _screenshotsDir, screenshotsConcurrency: _screenshotsConcurrency, ...vite } = await importConfig(root);
207
+ const designsDir = _designsDir ? resolve(root, _designsDir) : join(root, "designs");
208
+ const screenshotsDir = _screenshotsDir ? resolve(root, _screenshotsDir) : join(root, "screenshots");
209
+ const config = {
210
+ root,
211
+ localesDir: _localesDir ? resolve(root, _localesDir) : join(root, "locales"),
212
+ designsDir,
213
+ screenshotsDir,
214
+ screenshotsConcurrency: _screenshotsConcurrency || 1,
215
+ vite: {
216
+ ...vite,
217
+ configFile: false
218
+ }
219
+ };
220
+ config.vite.plugins ??= [];
221
+ config.vite.plugins.push(resolverPlugin(config));
222
+ config.vite.resolve ??= {};
223
+ config.vite.resolve.external ??= [];
224
+ const external = config.vite.resolve.external;
225
+ if (Array.isArray(external)) external.push("viteshot-assets/dashboard.ts", "viteshot-assets/screenshot.ts", "viteshot-virtual/render-screenshot?id={{screenshot.id}}", "viteshot-virtual/locale?id={{locale.id}}");
226
+ return config;
227
+ }
228
+
229
+ //#endregion
230
+ //#region src/core/create-server.ts
231
+ async function createServer$1(dir) {
232
+ return createServer((await resolveConfig(dir)).vite);
233
+ }
234
+
235
+ //#endregion
236
+ //#region src/core/generate-screenshots.ts
237
+ async function generateScreenshots(dir) {
238
+ const config = await resolveConfig(dir);
239
+ const cwd = process.cwd();
240
+ const screenshots = await getScreenshots(config.designsDir);
241
+ const locales = await getLocales(config.localesDir);
242
+ console.log(`\n\x1b[1mGenerating ${screenshots.length * (locales.length || 1)} screenshots...\x1b[0m\n`);
243
+ let server;
244
+ let browser;
245
+ try {
246
+ await rm(config.screenshotsDir, {
247
+ recursive: true,
248
+ force: true
249
+ });
250
+ await mkdir(config.screenshotsDir, { recursive: true });
251
+ server = await createServer(config.vite);
252
+ server.listen();
253
+ const { port } = server.config.server;
254
+ browser = await puppeteer.launch({ executablePath: process.env.VITESHOT_CHROME_PATH });
255
+ const screenshotMutex = new Mutex();
256
+ await pMap(screenshots.flatMap((screenshot) => locales.map((locale) => ({
257
+ screenshot,
258
+ locale
259
+ }))), async ({ screenshot, locale }) => {
260
+ const outputId = (locale ? `${locale.language}/` : "") + screenshot.id.slice(0, -screenshot.ext.length) + ".webp";
261
+ const outputPath = join(config.screenshotsDir, outputId);
262
+ await mkdir(dirname(outputPath), { recursive: true });
263
+ const page = await browser.newPage({ background: true });
264
+ await page.goto(`http://localhost:${port}/screenshot/${locale?.id ?? "null"}/${screenshot.id}`, {
265
+ waitUntil: "networkidle0",
266
+ timeout: 5e3
267
+ });
268
+ await screenshotMutex.runExclusive(async () => {
269
+ await page.bringToFront();
270
+ await page.screenshot({
271
+ captureBeyondViewport: true,
272
+ clip: {
273
+ x: 0,
274
+ y: 0,
275
+ width: screenshot.width,
276
+ height: screenshot.height
277
+ },
278
+ type: "webp",
279
+ quality: 100,
280
+ path: outputPath
281
+ });
282
+ });
283
+ console.log(` ✅ \x1b[2m./${relative(cwd, config.screenshotsDir)}/\x1b[0m\x1b[36m${outputId}\x1b[0m`);
284
+ await page.close();
285
+ }, {
286
+ concurrency: config.screenshotsConcurrency,
287
+ stopOnError: true
288
+ });
289
+ } catch (err) {
290
+ if (err?.message === "An `executablePath` or `channel` must be specified for `puppeteer-core`") throw Error(`Chromium not detected. Set the VITESHOT_CHROME_PATH env var to your Chromium executable.`);
291
+ else throw err;
292
+ } finally {
293
+ await browser?.close().catch(() => {});
294
+ await server?.close().catch(() => {});
295
+ console.log("");
296
+ }
297
+ }
298
+
299
+ //#endregion
300
+ export { getScreenshots as a, resolveConfig as i, createServer$1 as n, defineConfig as r, generateScreenshots as t };
@@ -0,0 +1,43 @@
1
+ import { InlineConfig as InlineConfig$1, UserConfig as UserConfig$1, ViteDevServer } from "vite";
2
+
3
+ //#region src/core/config.d.ts
4
+ type UserConfig = UserConfig$1 & {
5
+ localesDir?: string;
6
+ designsDir?: string;
7
+ screenshotsDir?: string;
8
+ screenshotsConcurrency?: number;
9
+ };
10
+ type InlineConfig = UserConfig & {
11
+ root: string;
12
+ };
13
+ type ResolvedConfig = {
14
+ root: string;
15
+ localesDir: string;
16
+ designsDir: string;
17
+ screenshotsDir: string;
18
+ screenshotsConcurrency: number;
19
+ vite: InlineConfig$1;
20
+ };
21
+ declare function defineConfig(config: UserConfig): UserConfig;
22
+ declare function resolveConfig(dir?: string): Promise<ResolvedConfig>;
23
+ //#endregion
24
+ //#region src/core/create-server.d.ts
25
+ declare function createServer(dir?: string): Promise<ViteDevServer>;
26
+ //#endregion
27
+ //#region src/core/generate-screenshots.d.ts
28
+ declare function generateScreenshots(dir?: string): Promise<void>;
29
+ //#endregion
30
+ //#region src/core/get-screenshots.d.ts
31
+ type Screenshot = {
32
+ id: string;
33
+ path: string;
34
+ ext: string;
35
+ filenameNoExt: string;
36
+ name: string;
37
+ size: string | undefined;
38
+ width: number | undefined;
39
+ height: number | undefined;
40
+ };
41
+ declare function getScreenshots(designsDir: string): Promise<Screenshot[]>;
42
+ //#endregion
43
+ export { InlineConfig, ResolvedConfig, Screenshot, UserConfig, createServer, defineConfig, generateScreenshots, getScreenshots, resolveConfig };
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { a as getScreenshots, i as resolveConfig, n as createServer, r as defineConfig, t as generateScreenshots } from "./generate-screenshots-bbolMzf5.mjs";
2
+
3
+ export { createServer, defineConfig, generateScreenshots, getScreenshots, resolveConfig };
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@aklinker1/viteshot",
3
+ "description": "Build and generate store screenshots and promo images with code, powered by Vite",
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "packageManager": "bun@1.3.9",
7
+ "scripts": {
8
+ "viteshot": "bun run -d process.env.DEV:\"true\" src/cli.ts",
9
+ "dev": "bun viteshot dev example",
10
+ "generate": "bun viteshot generate example",
11
+ "build": "tsdown src/index.ts src/cli.ts"
12
+ },
13
+ "dependencies": {
14
+ "async-mutex": "^0.5.0",
15
+ "natural-compare-lite": "^1.4.0",
16
+ "p-map": "^7.0.4",
17
+ "p-queue": "^9.1.0",
18
+ "puppeteer-core": "^24.37.5"
19
+ },
20
+ "peerDependencies": {
21
+ "vite": "^5 || ^6 || ^7"
22
+ },
23
+ "devDependencies": {
24
+ "@aklinker1/check": "^2.2.0",
25
+ "@types/bun": "latest",
26
+ "@types/natural-compare-lite": "^1.4.2",
27
+ "@typescript/native-preview": "^7.0.0-dev.20260223.1",
28
+ "oxlint": "^1.50.0",
29
+ "prettier": "^3.8.1",
30
+ "prettier-plugin-jsdoc": "^1.8.0",
31
+ "publint": "^0.3.17",
32
+ "puppeteer": "^24.37.5",
33
+ "tsdown": "^0.20.3",
34
+ "typescript": "^5",
35
+ "vite": "^7.3.1"
36
+ },
37
+ "types": "dist/index.d.mts",
38
+ "module": "dist/index.mjs",
39
+ "bin": {
40
+ "viteshot": "dist/cli.mjs"
41
+ },
42
+ "exports": {
43
+ ".": {
44
+ "types": "./dist/index.d.mts",
45
+ "import": "./dist/index.mjs",
46
+ "require": "./dist/index.cjs"
47
+ }
48
+ },
49
+ "license": "MIT",
50
+ "author": {
51
+ "email": "aaronklinker1@gmail.com",
52
+ "name": "Aaron Klinker"
53
+ },
54
+ "homepage": "https://jsr.io/@aklinker1/viteshot",
55
+ "repository": {
56
+ "url": "https://github.com/aklinker1/viteshot"
57
+ },
58
+ "files": [
59
+ "dist",
60
+ "assets"
61
+ ],
62
+ "publishConfig": {
63
+ "access": "public"
64
+ },
65
+ "keywords": [
66
+ "vite",
67
+ "promo",
68
+ "images",
69
+ "screenshot",
70
+ "generate",
71
+ "store"
72
+ ]
73
+ }