@hitslop/shots 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.
Files changed (151) hide show
  1. package/SKILL.md +536 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +113 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/auth.d.ts +7 -0
  7. package/dist/commands/auth.d.ts.map +1 -0
  8. package/dist/commands/auth.js +106 -0
  9. package/dist/commands/auth.js.map +1 -0
  10. package/dist/commands/crop.d.ts +5 -0
  11. package/dist/commands/crop.d.ts.map +1 -0
  12. package/dist/commands/crop.js +32 -0
  13. package/dist/commands/crop.js.map +1 -0
  14. package/dist/commands/default.d.ts +2 -0
  15. package/dist/commands/default.d.ts.map +1 -0
  16. package/dist/commands/default.js +142 -0
  17. package/dist/commands/default.js.map +1 -0
  18. package/dist/commands/feedback.d.ts +2 -0
  19. package/dist/commands/feedback.d.ts.map +1 -0
  20. package/dist/commands/feedback.js +6 -0
  21. package/dist/commands/feedback.js.map +1 -0
  22. package/dist/commands/generate.d.ts +3 -0
  23. package/dist/commands/generate.d.ts.map +1 -0
  24. package/dist/commands/generate.js +5 -0
  25. package/dist/commands/generate.js.map +1 -0
  26. package/dist/commands/init.d.ts +2 -0
  27. package/dist/commands/init.d.ts.map +1 -0
  28. package/dist/commands/init.js +5 -0
  29. package/dist/commands/init.js.map +1 -0
  30. package/dist/commands/install.d.ts +2 -0
  31. package/dist/commands/install.d.ts.map +1 -0
  32. package/dist/commands/install.js +13 -0
  33. package/dist/commands/install.js.map +1 -0
  34. package/dist/commands/scrape.d.ts +5 -0
  35. package/dist/commands/scrape.d.ts.map +1 -0
  36. package/dist/commands/scrape.js +5 -0
  37. package/dist/commands/scrape.js.map +1 -0
  38. package/dist/commands/studio.d.ts +7 -0
  39. package/dist/commands/studio.d.ts.map +1 -0
  40. package/dist/commands/studio.js +351 -0
  41. package/dist/commands/studio.js.map +1 -0
  42. package/dist/commands/styles.d.ts +2 -0
  43. package/dist/commands/styles.d.ts.map +1 -0
  44. package/dist/commands/styles.js +25 -0
  45. package/dist/commands/styles.js.map +1 -0
  46. package/dist/commands/view.d.ts +2 -0
  47. package/dist/commands/view.d.ts.map +1 -0
  48. package/dist/commands/view.js +25 -0
  49. package/dist/commands/view.js.map +1 -0
  50. package/dist/core/crop-pipeline.d.ts +28 -0
  51. package/dist/core/crop-pipeline.d.ts.map +1 -0
  52. package/dist/core/crop-pipeline.js +82 -0
  53. package/dist/core/crop-pipeline.js.map +1 -0
  54. package/dist/core/generate.d.ts +20 -0
  55. package/dist/core/generate.d.ts.map +1 -0
  56. package/dist/core/generate.js +388 -0
  57. package/dist/core/generate.js.map +1 -0
  58. package/dist/core/init.d.ts +3 -0
  59. package/dist/core/init.d.ts.map +1 -0
  60. package/dist/core/init.js +77 -0
  61. package/dist/core/init.js.map +1 -0
  62. package/dist/core/mock-generator.d.ts +5 -0
  63. package/dist/core/mock-generator.d.ts.map +1 -0
  64. package/dist/core/mock-generator.js +42 -0
  65. package/dist/core/mock-generator.js.map +1 -0
  66. package/dist/core/prompt-builder.d.ts +15 -0
  67. package/dist/core/prompt-builder.d.ts.map +1 -0
  68. package/dist/core/prompt-builder.js +195 -0
  69. package/dist/core/prompt-builder.js.map +1 -0
  70. package/dist/core/providers/fal.d.ts +3 -0
  71. package/dist/core/providers/fal.d.ts.map +1 -0
  72. package/dist/core/providers/fal.js +53 -0
  73. package/dist/core/providers/fal.js.map +1 -0
  74. package/dist/core/providers/index.d.ts +3 -0
  75. package/dist/core/providers/index.d.ts.map +1 -0
  76. package/dist/core/providers/index.js +2 -0
  77. package/dist/core/providers/index.js.map +1 -0
  78. package/dist/core/providers/managed.d.ts +3 -0
  79. package/dist/core/providers/managed.d.ts.map +1 -0
  80. package/dist/core/providers/managed.js +132 -0
  81. package/dist/core/providers/managed.js.map +1 -0
  82. package/dist/core/providers/openai.d.ts +3 -0
  83. package/dist/core/providers/openai.d.ts.map +1 -0
  84. package/dist/core/providers/openai.js +40 -0
  85. package/dist/core/providers/openai.js.map +1 -0
  86. package/dist/core/providers/replicate.d.ts +3 -0
  87. package/dist/core/providers/replicate.d.ts.map +1 -0
  88. package/dist/core/providers/replicate.js +87 -0
  89. package/dist/core/providers/replicate.js.map +1 -0
  90. package/dist/core/providers/resolve.d.ts +3 -0
  91. package/dist/core/providers/resolve.d.ts.map +1 -0
  92. package/dist/core/providers/resolve.js +41 -0
  93. package/dist/core/providers/resolve.js.map +1 -0
  94. package/dist/core/providers/types.d.ts +29 -0
  95. package/dist/core/providers/types.d.ts.map +1 -0
  96. package/dist/core/providers/types.js +2 -0
  97. package/dist/core/providers/types.js.map +1 -0
  98. package/dist/core/scraper.d.ts +22 -0
  99. package/dist/core/scraper.d.ts.map +1 -0
  100. package/dist/core/scraper.js +138 -0
  101. package/dist/core/scraper.js.map +1 -0
  102. package/dist/core/walkthrough.d.ts +10 -0
  103. package/dist/core/walkthrough.d.ts.map +1 -0
  104. package/dist/core/walkthrough.js +116 -0
  105. package/dist/core/walkthrough.js.map +1 -0
  106. package/dist/schema/config.d.ts +45 -0
  107. package/dist/schema/config.d.ts.map +1 -0
  108. package/dist/schema/config.js +36 -0
  109. package/dist/schema/config.js.map +1 -0
  110. package/dist/schema/manifest.d.ts +43 -0
  111. package/dist/schema/manifest.d.ts.map +1 -0
  112. package/dist/schema/manifest.js +5 -0
  113. package/dist/schema/manifest.js.map +1 -0
  114. package/dist/schema/style-meta.d.ts +8 -0
  115. package/dist/schema/style-meta.d.ts.map +1 -0
  116. package/dist/schema/style-meta.js +2 -0
  117. package/dist/schema/style-meta.js.map +1 -0
  118. package/dist/styles/installer.d.ts +2 -0
  119. package/dist/styles/installer.d.ts.map +1 -0
  120. package/dist/styles/installer.js +43 -0
  121. package/dist/styles/installer.js.map +1 -0
  122. package/dist/styles/registry.d.ts +20 -0
  123. package/dist/styles/registry.d.ts.map +1 -0
  124. package/dist/styles/registry.js +96 -0
  125. package/dist/styles/registry.js.map +1 -0
  126. package/dist/util/auth-store.d.ts +12 -0
  127. package/dist/util/auth-store.d.ts.map +1 -0
  128. package/dist/util/auth-store.js +46 -0
  129. package/dist/util/auth-store.js.map +1 -0
  130. package/dist/util/id.d.ts +2 -0
  131. package/dist/util/id.d.ts.map +1 -0
  132. package/dist/util/id.js +14 -0
  133. package/dist/util/id.js.map +1 -0
  134. package/dist/util/json.d.ts +3 -0
  135. package/dist/util/json.d.ts.map +1 -0
  136. package/dist/util/json.js +9 -0
  137. package/dist/util/json.js.map +1 -0
  138. package/dist/util/open.d.ts +2 -0
  139. package/dist/util/open.d.ts.map +1 -0
  140. package/dist/util/open.js +21 -0
  141. package/dist/util/open.js.map +1 -0
  142. package/dist/util/paths.d.ts +9 -0
  143. package/dist/util/paths.d.ts.map +1 -0
  144. package/dist/util/paths.js +21 -0
  145. package/dist/util/paths.js.map +1 -0
  146. package/package.json +37 -0
  147. package/studio/assets/index-BgiuT_Mv.css +1 -0
  148. package/studio/assets/index-DnN633_x.js +9 -0
  149. package/studio/index.html +13 -0
  150. package/styles/clean-premium/meta.json +7 -0
  151. package/styles/clean-premium/prompt.md +16 -0
@@ -0,0 +1,195 @@
1
+ import { getCompositeSize, getPanelDimensions, } from "./crop-pipeline.js";
2
+ // Arc position sort order: hero first, closer last
3
+ const ARC_ORDER = {
4
+ hero: 0,
5
+ differentiator: 1,
6
+ core: 2,
7
+ trust: 3,
8
+ closer: 4,
9
+ };
10
+ /**
11
+ * Build per-panel descriptions from the benefits array, sorted by narrative arc.
12
+ * Returns an array of description strings, one per panel.
13
+ */
14
+ export function buildBenefitPanelDescriptions(benefits, panelCount) {
15
+ const sorted = [...benefits].sort((a, b) => ARC_ORDER[a.arcPosition] - ARC_ORDER[b.arcPosition]);
16
+ const selected = sorted.slice(0, panelCount);
17
+ return selected.map((b, i) => {
18
+ const lines = [
19
+ `PANEL ${i + 1}:`,
20
+ ` Headline: "${b.headline}"`,
21
+ ` Subtitle: "${b.subtitle}"`,
22
+ ` Panel type: ${b.panelType}`,
23
+ ` Feature shown: ${b.feature}`,
24
+ ` Copy approach: ${b.approach}`,
25
+ ` Arc role: ${b.arcPosition}`,
26
+ ];
27
+ return lines.join("\n");
28
+ });
29
+ }
30
+ const LAYOUT_RULES = `
31
+ CRITICAL LAYOUT RULES:
32
+ - Do NOT draw any dividing lines, borders, separators, or visible boundaries between panels. The background gradient must flow continuously and seamlessly across all panels with absolutely no visible seams or edges.
33
+ - Headlines are bold, heavy-weight, large sans-serif white text — prominent and attention-grabbing
34
+ - Subtitles are noticeably smaller, lighter weight, muted color
35
+ - All text and imagery must have generous padding from the panel edges (at least 40px equivalent)
36
+ - Center all content (text, phone mockups, UI elements) horizontally within each panel's column
37
+ - The panels must each work as standalone App Store screenshots when cropped apart
38
+ - No logos, no app icons, no download buttons — just the headline, subtitle, and visual content per panel`;
39
+ const PANEL_LABELS = ["left", "center", "right"];
40
+ export function buildPrompt(config, userPrompt, panelCount = 3, platform = "iphone") {
41
+ const { width, height } = getCompositeSize(panelCount, platform);
42
+ const target = getPanelDimensions(platform);
43
+ if (panelCount === 1) {
44
+ const parts = [];
45
+ parts.push(`Create one ${width}x${height} portrait ${platform} App Store screenshot for "${config.appName}".`, `The final exported panel must work at exactly ${target.width}x${target.height}.`);
46
+ if (config.visualTone) {
47
+ parts.push(`Visual style: ${config.visualTone}.`);
48
+ }
49
+ if (config.brandColors) {
50
+ parts.push(`Brand colors: primary ${config.brandColors.primary}, accent ${config.brandColors.accent}, text ${config.brandColors.text}.`);
51
+ }
52
+ if (config.positioning) {
53
+ parts.push(`App positioning: ${config.positioning}.`);
54
+ }
55
+ if (config.targetAudience) {
56
+ parts.push(`Target audience: ${config.targetAudience}.`);
57
+ }
58
+ parts.push(userPrompt);
59
+ parts.push("Keep all text and UI elements fully visible and legible.", "Do not include app icons, download buttons, or platform badges.");
60
+ return parts.join(" ");
61
+ }
62
+ // Multi-panel composite mode
63
+ // If the user prompt already has per-panel layout (PANEL 1, PANEL 2, etc.), wrap it with canvas + rules
64
+ const hasExplicitPanels = /PANEL\s+\d/i.test(userPrompt);
65
+ const parts = [];
66
+ parts.push(`Create a single wide ${width}x${height} marketing banner divided into ${panelCount} equal vertical ${platform} panels for "${config.appName}".`, `Each final exported panel must work at exactly ${target.width}x${target.height}.`);
67
+ if (config.visualTone) {
68
+ parts.push(`Visual style: ${config.visualTone}.`);
69
+ }
70
+ if (config.brandColors) {
71
+ parts.push(`Brand colors: primary ${config.brandColors.primary}, accent ${config.brandColors.accent}, text ${config.brandColors.text}.`);
72
+ }
73
+ if (config.positioning) {
74
+ parts.push(`App positioning: ${config.positioning}.`);
75
+ }
76
+ if (config.targetAudience) {
77
+ parts.push(`Target audience: ${config.targetAudience}.`);
78
+ }
79
+ if (!hasExplicitPanels) {
80
+ // Use benefits for per-panel descriptions if available
81
+ if (config.benefits && config.benefits.length > 0) {
82
+ const benefitDescriptions = buildBenefitPanelDescriptions(config.benefits, panelCount);
83
+ parts.push(`Each panel is exactly ${Math.floor(width / panelCount)}px wide.`);
84
+ parts.push(...benefitDescriptions);
85
+ }
86
+ else {
87
+ // Generic multi-panel: remind AI to treat each third as its own panel
88
+ parts.push(`Each panel is exactly ${Math.floor(width / panelCount)}px wide.`);
89
+ for (let i = 0; i < panelCount; i++) {
90
+ const label = PANEL_LABELS[i] ?? `panel ${i + 1}`;
91
+ parts.push(`PANEL ${i + 1} (${label} third): a self-contained screenshot composition.`);
92
+ }
93
+ }
94
+ }
95
+ parts.push(userPrompt);
96
+ parts.push(LAYOUT_RULES);
97
+ return parts.join("\n");
98
+ }
99
+ /**
100
+ * Build a prompt using a style template, replacing {{placeholders}} with config values.
101
+ */
102
+ const POSITION_LABELS = ["first (leftmost)", "second (center)", "third (rightmost)"];
103
+ /**
104
+ * Build a focused prompt for a single panel in individual generation mode.
105
+ * Each panel gets the model's full attention with context about its position.
106
+ */
107
+ export function buildPanelPrompt(config, userPrompt, panelIndex, panelCount, platform = "iphone") {
108
+ const position = POSITION_LABELS[panelIndex] ?? `panel ${panelIndex + 1}`;
109
+ const { width, height } = getCompositeSize(1, platform);
110
+ const target = getPanelDimensions(platform);
111
+ const parts = [];
112
+ parts.push(`Create one ${width}x${height} portrait ${platform} App Store screenshot for "${config.appName}".`, `The final exported panel must work at exactly ${target.width}x${target.height}.`, `This is panel ${panelIndex + 1} of ${panelCount} (the ${position} panel in the set).`);
113
+ if (config.visualTone) {
114
+ parts.push(`Visual style: ${config.visualTone}.`);
115
+ }
116
+ if (config.brandColors) {
117
+ parts.push(`Brand colors: primary ${config.brandColors.primary}, accent ${config.brandColors.accent}, text ${config.brandColors.text}.`);
118
+ }
119
+ if (config.positioning) {
120
+ parts.push(`App positioning: ${config.positioning}.`);
121
+ }
122
+ if (config.targetAudience) {
123
+ parts.push(`Target audience: ${config.targetAudience}.`);
124
+ }
125
+ parts.push(`All ${panelCount} panels in this set must share the same visual style, color palette, typography, and background treatment for a cohesive App Store listing.`);
126
+ // Include benefit info for this specific panel if available
127
+ if (config.benefits && config.benefits.length > 0) {
128
+ const benefitDescriptions = buildBenefitPanelDescriptions(config.benefits, panelCount);
129
+ if (benefitDescriptions[panelIndex]) {
130
+ parts.push("", benefitDescriptions[panelIndex]);
131
+ }
132
+ }
133
+ parts.push(userPrompt);
134
+ parts.push("Keep all text and UI elements fully visible and legible.", "Do not include app icons, download buttons, or platform badges.", "Do not draw borders, dividers, or frame edges — this panel stands alone.");
135
+ return parts.join("\n");
136
+ }
137
+ export function buildStyledPrompt(template, config, userPrompt, panelCount = 3, platform = "iphone") {
138
+ const { width, height } = getCompositeSize(panelCount, platform);
139
+ const target = getPanelDimensions(platform);
140
+ let result = template;
141
+ // Build benefit replacement values
142
+ const benefits = config.benefits ?? [];
143
+ const benefitDescriptions = benefits.length > 0
144
+ ? buildBenefitPanelDescriptions(benefits, panelCount)
145
+ : [];
146
+ const allBenefitsText = benefitDescriptions.join("\n\n");
147
+ // Build per-arcPosition benefit lookups
148
+ const benefitsByArc = {};
149
+ const sorted = [...benefits].sort((a, b) => ARC_ORDER[a.arcPosition] - ARC_ORDER[b.arcPosition]);
150
+ for (const b of sorted) {
151
+ if (!benefitsByArc[b.arcPosition]) {
152
+ benefitsByArc[b.arcPosition] = `Headline: "${b.headline}" | Subtitle: "${b.subtitle}" | Feature: ${b.feature}`;
153
+ }
154
+ }
155
+ // Replace {{key}} placeholders with config values
156
+ const replacements = {
157
+ appName: config.appName,
158
+ positioning: config.positioning,
159
+ targetAudience: config.targetAudience,
160
+ visualTone: config.visualTone,
161
+ "brandColors.primary": config.brandColors.primary,
162
+ "brandColors.secondary": config.brandColors.secondary,
163
+ "brandColors.accent": config.brandColors.accent,
164
+ "brandColors.text": config.brandColors.text,
165
+ "aso.title": config.aso.title,
166
+ "aso.subtitle": config.aso.subtitle,
167
+ "aso.description": config.aso.description,
168
+ compositeWidth: String(width),
169
+ compositeHeight: String(height),
170
+ panelWidth: String(Math.floor(width / panelCount)),
171
+ targetWidth: String(target.width),
172
+ targetHeight: String(target.height),
173
+ platform,
174
+ panelCount: String(panelCount),
175
+ benefits: allBenefitsText,
176
+ "benefits.hero": benefitsByArc["hero"] ?? "",
177
+ "benefits.differentiator": benefitsByArc["differentiator"] ?? "",
178
+ "benefits.core": benefitsByArc["core"] ?? "",
179
+ "benefits.trust": benefitsByArc["trust"] ?? "",
180
+ "benefits.closer": benefitsByArc["closer"] ?? "",
181
+ };
182
+ for (const [key, value] of Object.entries(replacements)) {
183
+ result = result.replaceAll(`{{${key}}}`, value);
184
+ }
185
+ // Append user prompt if provided
186
+ if (userPrompt.trim()) {
187
+ result += `\n\n${userPrompt}`;
188
+ }
189
+ // Append layout rules for multi-panel composites
190
+ if (panelCount > 1) {
191
+ result += `\n${LAYOUT_RULES}`;
192
+ }
193
+ return result;
194
+ }
195
+ //# sourceMappingURL=prompt-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../../src/core/prompt-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ImageProvider } from "./types.js";
2
+ export declare function createFalProvider(): ImageProvider;
3
+ //# sourceMappingURL=fal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fal.d.ts","sourceRoot":"","sources":["../../../src/core/providers/fal.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAiC,MAAM,YAAY,CAAC;AAE/E,wBAAgB,iBAAiB,IAAI,aAAa,CAmEjD"}
@@ -0,0 +1,53 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { fal } from "@fal-ai/client";
3
+ export function createFalProvider() {
4
+ const apiKey = process.env.FAL_KEY;
5
+ if (!apiKey) {
6
+ throw new Error("FAL_KEY environment variable is required for the fal provider.");
7
+ }
8
+ fal.config({ credentials: apiKey });
9
+ return {
10
+ name: "fal",
11
+ async generate(input) {
12
+ // Upload reference images if any
13
+ const imageUrls = [];
14
+ for (const ref of input.references) {
15
+ const arrayBuffer = ref.buffer.buffer.slice(ref.buffer.byteOffset, ref.buffer.byteOffset + ref.buffer.byteLength);
16
+ const blob = new Blob([arrayBuffer], { type: ref.mimeType });
17
+ const file = new File([blob], ref.filename, { type: ref.mimeType });
18
+ const url = await fal.storage.upload(file);
19
+ imageUrls.push(url);
20
+ }
21
+ const endpoint = imageUrls.length > 0
22
+ ? "fal-ai/gpt-image-2/edit"
23
+ : "fal-ai/gpt-image-2";
24
+ const inputPayload = {
25
+ prompt: input.prompt,
26
+ image_size: { width: input.width, height: input.height },
27
+ quality: input.quality,
28
+ num_images: 1,
29
+ };
30
+ if (imageUrls.length > 0) {
31
+ inputPayload.image_urls = imageUrls;
32
+ }
33
+ const result = await fal.subscribe(endpoint, { input: inputPayload });
34
+ const imageUrl = result.data
35
+ ?.images?.[0]?.url;
36
+ if (!imageUrl) {
37
+ throw new Error("fal.ai did not return an image URL.");
38
+ }
39
+ const response = await fetch(imageUrl);
40
+ if (!response.ok) {
41
+ throw new Error(`Failed to download fal.ai image: ${response.status} ${response.statusText}`);
42
+ }
43
+ const imageBuffer = Buffer.from(await response.arrayBuffer());
44
+ return {
45
+ imageBuffer,
46
+ actualWidth: input.width,
47
+ actualHeight: input.height,
48
+ provider: "fal",
49
+ };
50
+ },
51
+ };
52
+ }
53
+ //# sourceMappingURL=fal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fal.js","sourceRoot":"","sources":["../../../src/core/providers/fal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type { ProviderName, ManagedBackendProvider, ReferenceImage, GenerateInput, GenerateOutput, ImageProvider, } from "./types.js";
2
+ export { resolveProvider } from "./resolve.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/providers/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { resolveProvider } from "./resolve.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/providers/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ImageProvider } from "./types.js";
2
+ export declare function createManagedProvider(): ImageProvider;
3
+ //# sourceMappingURL=managed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"managed.d.ts","sourceRoot":"","sources":["../../../src/core/providers/managed.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAiC,aAAa,EAAE,MAAM,YAAY,CAAC;AA6B/E,wBAAgB,qBAAqB,IAAI,aAAa,CA2FrD"}
@@ -0,0 +1,132 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { createHash } from "node:crypto";
3
+ import sharp from "sharp";
4
+ import { readManagedAuth } from "../../util/auth-store.js";
5
+ async function sleep(ms) {
6
+ await new Promise((resolve) => setTimeout(resolve, ms));
7
+ }
8
+ export function createManagedProvider() {
9
+ return {
10
+ name: "managed",
11
+ async generate(input) {
12
+ const auth = await readManagedAuth();
13
+ if (!auth) {
14
+ throw new Error("Managed auth is not configured. Run `npx -y @hitslop/shots@latest auth login --api-key <key>` first.");
15
+ }
16
+ if (input.references.length > 0) {
17
+ throw new Error("Managed generation does not support reference images in v1. Use BYOK openai/fal for reference-image generation, or omit --references with --provider managed.");
18
+ }
19
+ const generateRes = await fetch(`${auth.apiUrl}/api/v1/generate`, {
20
+ method: "POST",
21
+ headers: {
22
+ "Authorization": `Bearer ${auth.apiKey}`,
23
+ "Content-Type": "application/json",
24
+ },
25
+ body: JSON.stringify({
26
+ prompt: input.prompt,
27
+ width: input.width,
28
+ height: input.height,
29
+ quality: input.quality,
30
+ panelCount: input.panelCount || 3,
31
+ platform: input.platform || "iphone",
32
+ provider: input.managedProvider || "openai",
33
+ }),
34
+ });
35
+ if (!generateRes.ok) {
36
+ throw new Error(`Managed generation failed: ${generateRes.status} ${await generateRes.text()}`);
37
+ }
38
+ const submitted = (await generateRes.json());
39
+ let job = submitted;
40
+ for (let attempt = 0; attempt < 180; attempt++) {
41
+ const jobRes = await fetch(`${auth.apiUrl}/api/v1/jobs?id=${encodeURIComponent(submitted.jobId)}`, {
42
+ headers: { "Authorization": `Bearer ${auth.apiKey}` },
43
+ });
44
+ if (!jobRes.ok) {
45
+ throw new Error(`Managed job poll failed: ${jobRes.status} ${await jobRes.text()}`);
46
+ }
47
+ job = (await jobRes.json());
48
+ if (job.status === "complete")
49
+ break;
50
+ if (job.status === "failed") {
51
+ throw new Error(job.error || "Managed generation failed.");
52
+ }
53
+ await sleep(2000);
54
+ }
55
+ if (job.status !== "complete") {
56
+ throw new Error(`Managed generation timed out for job ${submitted.jobId}.`);
57
+ }
58
+ if (job.assets?.length) {
59
+ const stitched = await stitchPanels(job.assets);
60
+ return {
61
+ imageBuffer: stitched,
62
+ actualWidth: input.width,
63
+ actualHeight: input.height,
64
+ provider: "managed",
65
+ };
66
+ }
67
+ const imageUrl = job.compositeUrl || job.imageUrl;
68
+ if (!imageUrl) {
69
+ throw new Error("Managed generation completed without a downloadable image URL.");
70
+ }
71
+ const imageRes = await fetch(imageUrl);
72
+ if (!imageRes.ok) {
73
+ throw new Error(`Failed to download managed image: ${imageRes.status} ${imageRes.statusText}`);
74
+ }
75
+ return {
76
+ imageBuffer: Buffer.from(await imageRes.arrayBuffer()),
77
+ actualWidth: input.width,
78
+ actualHeight: input.height,
79
+ provider: "managed",
80
+ };
81
+ },
82
+ };
83
+ }
84
+ async function stitchPanels(assets) {
85
+ const ordered = [...assets].sort((a, b) => a.panelIndex - b.panelIndex);
86
+ const panels = await Promise.all(ordered.map(async (asset) => {
87
+ const response = await fetch(asset.cdnUrl);
88
+ if (!response.ok) {
89
+ throw new Error(`Failed to download managed panel ${asset.panelIndex}: ${response.status}`);
90
+ }
91
+ const bytes = Buffer.from(await response.arrayBuffer());
92
+ await validateManagedAsset(asset, bytes);
93
+ return {
94
+ input: bytes,
95
+ left: (asset.panelIndex - 1) * asset.width,
96
+ top: 0,
97
+ };
98
+ }));
99
+ const first = ordered[0];
100
+ return await sharp({
101
+ create: {
102
+ width: ordered.length * first.width,
103
+ height: first.height,
104
+ channels: 4,
105
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
106
+ },
107
+ })
108
+ .composite(panels)
109
+ .png()
110
+ .toBuffer();
111
+ }
112
+ async function validateManagedAsset(asset, bytes) {
113
+ if (!asset.path || !asset.path.startsWith("/")) {
114
+ throw new Error(`Managed panel ${asset.panelIndex} is missing a Bunny path.`);
115
+ }
116
+ if (asset.byteLength !== bytes.byteLength) {
117
+ throw new Error(`Managed panel ${asset.panelIndex} byte length mismatch: expected ${asset.byteLength}, got ${bytes.byteLength}.`);
118
+ }
119
+ const checksum = createHash("sha256").update(bytes).digest("hex");
120
+ if (asset.checksum !== checksum) {
121
+ throw new Error(`Managed panel ${asset.panelIndex} checksum mismatch.`);
122
+ }
123
+ const metadata = await sharp(bytes).metadata();
124
+ if (metadata.width !== asset.width || metadata.height !== asset.height) {
125
+ throw new Error(`Managed panel ${asset.panelIndex} dimensions mismatch: expected ${asset.width}x${asset.height}, got ${metadata.width || 0}x${metadata.height || 0}.`);
126
+ }
127
+ const expectedFormat = asset.contentType === "image/jpeg" ? "jpeg" : "png";
128
+ if (metadata.format !== expectedFormat) {
129
+ throw new Error(`Managed panel ${asset.panelIndex} content type ${asset.contentType} does not match image format ${metadata.format || "unknown"}.`);
130
+ }
131
+ }
132
+ //# sourceMappingURL=managed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"managed.js","sourceRoot":"","sources":["../../../src/core/providers/managed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ImageProvider } from "./types.js";
2
+ export declare function createOpenAIProvider(): ImageProvider;
3
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/core/providers/openai.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAiC,MAAM,YAAY,CAAC;AAE/E,wBAAgB,oBAAoB,IAAI,aAAa,CAkDpD"}
@@ -0,0 +1,40 @@
1
+ import { Buffer } from "node:buffer";
2
+ import OpenAI, { toFile } from "openai";
3
+ export function createOpenAIProvider() {
4
+ const apiKey = process.env.OPENAI_API_KEY;
5
+ if (!apiKey) {
6
+ throw new Error("OPENAI_API_KEY environment variable is required for the openai provider.");
7
+ }
8
+ const openai = new OpenAI({ apiKey });
9
+ return {
10
+ name: "openai",
11
+ async generate(input) {
12
+ const referenceFiles = await Promise.all(input.references.map((ref) => toFile(ref.buffer, ref.filename, { type: ref.mimeType })));
13
+ const params = {
14
+ model: "gpt-image-2",
15
+ prompt: input.prompt,
16
+ n: 1,
17
+ size: `${input.width}x${input.height}`,
18
+ quality: input.quality,
19
+ };
20
+ const response = referenceFiles.length > 0
21
+ ? await openai.images.edit({
22
+ ...params,
23
+ image: referenceFiles,
24
+ })
25
+ : await openai.images.generate(params);
26
+ const b64 = response.data?.[0]?.b64_json;
27
+ if (!b64) {
28
+ throw new Error("OpenAI did not return image data.");
29
+ }
30
+ const imageBuffer = Buffer.from(b64, "base64");
31
+ return {
32
+ imageBuffer,
33
+ actualWidth: input.width,
34
+ actualHeight: input.height,
35
+ provider: "openai",
36
+ };
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/core/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,MAAM,UAAU,oBAAoB;IAClC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAEtC,OAAO;QACL,IAAI,EAAE,QAAQ;QAEd,KAAK,CAAC,QAAQ,CAAC,KAAoB;YACjC,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,GAAG,CACtC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC3B,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CACzD,CACF,CAAC;YAEF,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,aAAsB;gBAC7B,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,CAAC,EAAE,CAAU;gBACb,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,EAAW;gBAC/C,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC;YAEF,MAAM,QAAQ,GACZ,cAAc,CAAC,MAAM,GAAG,CAAC;gBACvB,CAAC,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;oBACvB,GAAG,MAAM;oBACT,KAAK,EAAE,cAAc;iBACb,CAAC;gBACb,CAAC,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAe,CAAC,CAAC;YAEpD,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;YACzC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YAED,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC/C,OAAO;gBACL,WAAW;gBACX,WAAW,EAAE,KAAK,CAAC,KAAK;gBACxB,YAAY,EAAE,KAAK,CAAC,MAAM;gBAC1B,QAAQ,EAAE,QAAQ;aACnB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ImageProvider } from "./types.js";
2
+ export declare function createReplicateProvider(): ImageProvider;
3
+ //# sourceMappingURL=replicate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replicate.d.ts","sourceRoot":"","sources":["../../../src/core/providers/replicate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAiC,MAAM,YAAY,CAAC;AA4B/E,wBAAgB,uBAAuB,IAAI,aAAa,CA2EvD"}
@@ -0,0 +1,87 @@
1
+ import { Buffer } from "node:buffer";
2
+ import Replicate from "replicate";
3
+ import sharp from "sharp";
4
+ const ASPECT_RATIOS = [
5
+ { ratio: "1:1", w: 1, h: 1 },
6
+ { ratio: "16:9", w: 16, h: 9 },
7
+ { ratio: "9:16", w: 9, h: 16 },
8
+ { ratio: "4:3", w: 4, h: 3 },
9
+ { ratio: "3:4", w: 3, h: 4 },
10
+ { ratio: "3:2", w: 3, h: 2 },
11
+ { ratio: "2:3", w: 2, h: 3 },
12
+ { ratio: "21:9", w: 21, h: 9 },
13
+ { ratio: "9:21", w: 9, h: 21 },
14
+ ];
15
+ function closestAspectRatio(width, height) {
16
+ const target = width / height;
17
+ let bestRatio = ASPECT_RATIOS[0].ratio;
18
+ let bestDiff = Infinity;
19
+ for (const ar of ASPECT_RATIOS) {
20
+ const diff = Math.abs(ar.w / ar.h - target);
21
+ if (diff < bestDiff) {
22
+ bestDiff = diff;
23
+ bestRatio = ar.ratio;
24
+ }
25
+ }
26
+ return bestRatio;
27
+ }
28
+ export function createReplicateProvider() {
29
+ const apiToken = process.env.REPLICATE_API_TOKEN;
30
+ if (!apiToken) {
31
+ throw new Error("REPLICATE_API_TOKEN environment variable is required for the replicate provider.");
32
+ }
33
+ const replicate = new Replicate({ auth: apiToken });
34
+ return {
35
+ name: "replicate",
36
+ async generate(input) {
37
+ const aspectRatio = closestAspectRatio(input.width, input.height);
38
+ // Convert references to data URIs
39
+ const imageDataUris = input.references.map((ref) => {
40
+ const b64 = ref.buffer.toString("base64");
41
+ return `data:${ref.mimeType};base64,${b64}`;
42
+ });
43
+ const replicateInput = {
44
+ prompt: input.prompt,
45
+ aspect_ratio: aspectRatio,
46
+ quality: input.quality,
47
+ n: 1,
48
+ };
49
+ if (imageDataUris.length > 0) {
50
+ replicateInput.image = imageDataUris[0];
51
+ }
52
+ const output = await replicate.run("openai/gpt-image-2", {
53
+ input: replicateInput,
54
+ });
55
+ // Output is typically a FileOutput or array of FileOutput
56
+ let imageUrl;
57
+ if (Array.isArray(output) && output.length > 0) {
58
+ imageUrl = String(output[0]);
59
+ }
60
+ else if (typeof output === "string") {
61
+ imageUrl = output;
62
+ }
63
+ else {
64
+ throw new Error("Replicate did not return usable output.");
65
+ }
66
+ const response = await fetch(imageUrl);
67
+ if (!response.ok) {
68
+ throw new Error(`Failed to download Replicate image: ${response.status} ${response.statusText}`);
69
+ }
70
+ const imageBuffer = Buffer.from(await response.arrayBuffer());
71
+ // Read actual dimensions since Replicate uses aspect ratio presets
72
+ const metadata = await sharp(imageBuffer).metadata();
73
+ const actualWidth = metadata.width ?? input.width;
74
+ const actualHeight = metadata.height ?? input.height;
75
+ if (actualWidth !== input.width || actualHeight !== input.height) {
76
+ console.log(`Note: Replicate returned ${actualWidth}x${actualHeight} (requested ${input.width}x${input.height}, aspect ratio: ${aspectRatio})`);
77
+ }
78
+ return {
79
+ imageBuffer,
80
+ actualWidth,
81
+ actualHeight,
82
+ provider: "replicate",
83
+ };
84
+ },
85
+ };
86
+ }
87
+ //# sourceMappingURL=replicate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replicate.js","sourceRoot":"","sources":["../../../src/core/providers/replicate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ImageProvider } from "./types.js";
2
+ export declare function resolveProvider(explicit?: string): ImageProvider;
3
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/core/providers/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,YAAY,CAAC;AAmB9D,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa,CA8BhE"}