@happyvertical/images 0.74.8

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/AGENT.md ADDED
@@ -0,0 +1,33 @@
1
+ # @happyvertical/images
2
+
3
+ <!-- BEGIN AGENT:GENERATED -->
4
+ ## Purpose
5
+ Image processing utilities with adapter pattern for scaling from static to enterprise
6
+
7
+ ## Package Map
8
+ - Package: `@happyvertical/images`
9
+ - Hierarchy path: `@happyvertical/sdk > packages > images`
10
+ - Workspace position: `15 of 30` local packages
11
+ - Internal dependencies: none
12
+ - Internal dependents: `@happyvertical/video`
13
+ - Knowledge graph files: `AGENT.md`, `metadata.json`, `ecosystem-manifest.json`
14
+
15
+ ## Build & Test
16
+ ```bash
17
+ pnpm --filter @happyvertical/images build
18
+ pnpm --filter @happyvertical/images test
19
+ pnpm --filter @happyvertical/images clean
20
+ ```
21
+
22
+ ## Agent Correction Loops
23
+ - If Vite or TypeScript reports missing packages, run `pnpm install` at the repo root and rerun `pnpm --filter @happyvertical/images build`.
24
+ - If tests or exports fail after API, type, or bundle changes, run `pnpm --filter @happyvertical/images clean` followed by `pnpm --filter @happyvertical/images build` and `pnpm --filter @happyvertical/images test`.
25
+ - If failures span multiple packages or Turborepo ordering looks wrong, run `pnpm build` and `pnpm typecheck` from the repo root before retrying package-scoped commands.
26
+
27
+ ## Ecosystem Relationships
28
+ - Provides: Image processing utilities with adapter pattern for scaling from static to enterprise
29
+ - Implements: none
30
+ - Requires: @resvg/resvg-js, jimp, satori, sharp
31
+ - Stability: stable (Primary package surface is described as implemented and production-oriented.)
32
+ <!-- END AGENT:GENERATED -->
33
+
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright <2025> <Happy Vertical Corporation>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,176 @@
1
+ import { ConvertOptions, HashAlgorithm, ImageDimensions, ImageInput, ImageMetadata, ImageProcessorInterface, ImgproxyOptions, ResizeOptions, ThumbnailOptions } from '../shared/types.js';
2
+ /**
3
+ * Options for generating signed imgproxy URLs
4
+ */
5
+ export interface SignedUrlOptions {
6
+ /**
7
+ * Width in pixels (0 for auto)
8
+ */
9
+ width?: number;
10
+ /**
11
+ * Height in pixels (0 for auto)
12
+ */
13
+ height?: number;
14
+ /**
15
+ * Resize mode
16
+ * - 'cover': Fill dimensions, crop excess
17
+ * - 'contain': Fit within dimensions, may have empty space
18
+ * - 'fill': Force exact dimensions (may distort)
19
+ */
20
+ fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
21
+ /**
22
+ * Output quality (1-100)
23
+ */
24
+ quality?: number;
25
+ /**
26
+ * Output format (jpeg, png, webp, avif, etc.)
27
+ */
28
+ format?: string;
29
+ }
30
+ /**
31
+ * Generate a signed imgproxy URL
32
+ *
33
+ * Standalone function for generating signed URLs without creating an adapter instance.
34
+ * Useful for client-side usage or when you only need URL generation.
35
+ *
36
+ * @param source - Source image URL (must be http/https)
37
+ * @param config - imgproxy server configuration
38
+ * @param options - Processing options
39
+ * @returns Signed imgproxy URL
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * import { signImgproxyUrl } from '@happyvertical/images';
44
+ *
45
+ * const url = signImgproxyUrl(
46
+ * 'https://example.com/image.jpg',
47
+ * {
48
+ * baseUrl: 'https://imgproxy.example.com',
49
+ * key: 'hex-encoded-key',
50
+ * salt: 'hex-encoded-salt'
51
+ * },
52
+ * { width: 300, height: 200, format: 'webp' }
53
+ * );
54
+ * ```
55
+ */
56
+ export declare function signImgproxyUrl(source: string, config: {
57
+ baseUrl: string;
58
+ key?: string;
59
+ salt?: string;
60
+ }, options?: SignedUrlOptions): string;
61
+ /**
62
+ * imgproxy adapter for remote image processing
63
+ *
64
+ * Offloads image processing to a self-hosted imgproxy server.
65
+ * Supports URL signing for secure access.
66
+ *
67
+ * Features:
68
+ * - Scalable remote processing
69
+ * - URL-based API
70
+ * - Signed URLs for security
71
+ * - CDN-friendly outputs
72
+ *
73
+ * Limitations:
74
+ * - Requires network access to imgproxy server
75
+ * - Input must be accessible via URL (not local paths)
76
+ * - Hash computation not directly supported (requires fetching image)
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const processor = new ImgproxyAdapter({
81
+ * type: 'imgproxy',
82
+ * baseUrl: 'https://imgproxy.example.com',
83
+ * key: 'hex-encoded-key',
84
+ * salt: 'hex-encoded-salt'
85
+ * });
86
+ *
87
+ * await processor.thumbnail(
88
+ * 'https://example.com/image.jpg',
89
+ * '/tmp/thumb.jpg',
90
+ * { maxWidth: 300 }
91
+ * );
92
+ * ```
93
+ */
94
+ export declare class ImgproxyAdapter implements ImageProcessorInterface {
95
+ private baseUrl;
96
+ private key?;
97
+ private salt?;
98
+ constructor(options: ImgproxyOptions);
99
+ /**
100
+ * Generate a signed imgproxy URL without fetching the image
101
+ *
102
+ * This is useful for:
103
+ * - Client-side usage where you want to display images directly
104
+ * - Debugging URL signing issues
105
+ * - Pre-generating URLs for batch processing
106
+ *
107
+ * @param source - Source image URL (must be http/https)
108
+ * @param options - Processing options
109
+ * @returns Signed imgproxy URL
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * const adapter = new ImgproxyAdapter({
114
+ * type: 'imgproxy',
115
+ * baseUrl: 'https://imgproxy.example.com',
116
+ * key: 'hex-key',
117
+ * salt: 'hex-salt'
118
+ * });
119
+ *
120
+ * // Generate thumbnail URL
121
+ * const url = adapter.getSignedUrl('https://example.com/image.jpg', {
122
+ * width: 300,
123
+ * height: 200,
124
+ * fit: 'cover',
125
+ * format: 'webp'
126
+ * });
127
+ * // Returns: https://imgproxy.example.com/SIGNATURE/rs:fill:300:200/aHR0cHM6Ly9.../image.webp
128
+ * ```
129
+ */
130
+ getSignedUrl(source: string, options?: {
131
+ width?: number;
132
+ height?: number;
133
+ fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
134
+ quality?: number;
135
+ format?: string;
136
+ }): string;
137
+ /**
138
+ * Sign a path using HMAC-SHA256
139
+ */
140
+ private sign;
141
+ /**
142
+ * Encode source URL for imgproxy
143
+ */
144
+ private encodeSource;
145
+ /**
146
+ * Build imgproxy URL
147
+ */
148
+ private buildUrl;
149
+ /**
150
+ * Convert ImageInput to URL string
151
+ */
152
+ private toUrl;
153
+ getDimensions(input: ImageInput): Promise<ImageDimensions>;
154
+ thumbnail(input: ImageInput, output: string, options?: ThumbnailOptions): Promise<void>;
155
+ convert(input: ImageInput, output: string, options?: ConvertOptions): Promise<void>;
156
+ getMetadata(input: ImageInput): Promise<ImageMetadata>;
157
+ hash(_input: ImageInput, _algorithm?: HashAlgorithm): Promise<string>;
158
+ resize(input: ImageInput, output: string, options: ResizeOptions): Promise<void>;
159
+ /**
160
+ * Build imgproxy processing string
161
+ */
162
+ private buildProcessingString;
163
+ /**
164
+ * Map fit mode to imgproxy resize type
165
+ */
166
+ private mapFitToResizeType;
167
+ /**
168
+ * Fetch image from imgproxy and save to file
169
+ */
170
+ private fetchAndSave;
171
+ /**
172
+ * Infer image format from file extension
173
+ */
174
+ private inferFormat;
175
+ }
176
+ //# sourceMappingURL=imgproxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imgproxy.d.ts","sourceRoot":"","sources":["../../src/adapters/imgproxy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,eAAe,EAEf,UAAU,EACV,aAAa,EACb,uBAAuB,EACvB,eAAe,EACf,aAAa,EACb,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAE1D;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE;IACN,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,EACD,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAQR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,eAAgB,YAAW,uBAAuB;IAC7D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,GAAG,CAAC,CAAS;IACrB,OAAO,CAAC,IAAI,CAAC,CAAS;gBAEV,OAAO,EAAE,eAAe;IASpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,YAAY,CACV,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;QAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACZ,GACL,MAAM;IAsBT;;OAEG;IACH,OAAO,CAAC,IAAI;IAkBZ;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAYhB;;OAEG;IACH,OAAO,CAAC,KAAK;IAqBP,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC;IAoC1D,SAAS,CACb,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC;IA+BV,OAAO,CACX,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC;IA2BV,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAwCtD,IAAI,CACR,MAAM,EAAE,UAAU,EAClB,UAAU,GAAE,aAA4B,GACvC,OAAO,CAAC,MAAM,CAAC;IASZ,MAAM,CACV,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC;IAkChB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA0B7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;OAEG;YACW,YAAY;IAiB1B;;OAEG;IACH,OAAO,CAAC,WAAW;CAcpB"}
@@ -0,0 +1,66 @@
1
+ import { ConvertOptions, HashAlgorithm, ImageDimensions, ImageInput, ImageMetadata, ImageProcessorInterface, JimpOptions, ResizeOptions, ThumbnailOptions } from '../shared/types.js';
2
+ /**
3
+ * Jimp adapter for pure JavaScript image processing
4
+ *
5
+ * Provides a fallback option when Sharp (native library) is not available.
6
+ * Useful for:
7
+ * - Serverless environments (AWS Lambda, Vercel Edge)
8
+ * - Environments without native compilation support
9
+ * - Cross-platform compatibility
10
+ *
11
+ * Limitations compared to Sharp:
12
+ * - Slower processing speed
13
+ * - Limited EXIF/metadata extraction
14
+ * - No AVIF support
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const processor = new JimpAdapter();
19
+ * const dims = await processor.getDimensions('/path/to/image.jpg');
20
+ * console.log(dims); // { width: 1920, height: 1080 }
21
+ * ```
22
+ */
23
+ export declare class JimpAdapter implements ImageProcessorInterface {
24
+ private jimpStatic;
25
+ private options;
26
+ /**
27
+ * Create a new Jimp adapter
28
+ * @param options - Jimp adapter options
29
+ */
30
+ constructor(options?: JimpOptions);
31
+ /**
32
+ * Lazily load Jimp module
33
+ */
34
+ private getJimp;
35
+ getDimensions(input: ImageInput): Promise<ImageDimensions>;
36
+ thumbnail(input: ImageInput, output: string, options?: ThumbnailOptions): Promise<void>;
37
+ convert(input: ImageInput, output: string, options?: ConvertOptions): Promise<void>;
38
+ getMetadata(input: ImageInput): Promise<ImageMetadata>;
39
+ hash(input: ImageInput, algorithm?: HashAlgorithm): Promise<string>;
40
+ resize(input: ImageInput, output: string, options: ResizeOptions): Promise<void>;
41
+ /**
42
+ * Write image with quality settings based on output format
43
+ */
44
+ private writeWithOptions;
45
+ /**
46
+ * Infer image format from file extension
47
+ */
48
+ private inferFormat;
49
+ /**
50
+ * Get MIME type from format
51
+ */
52
+ private mimeFromFormat;
53
+ /**
54
+ * Get format from MIME type
55
+ */
56
+ private formatFromMime;
57
+ /**
58
+ * Try to determine MIME type from input
59
+ */
60
+ private getMimeFromInput;
61
+ /**
62
+ * Map Jimp errors to our error types
63
+ */
64
+ private mapError;
65
+ }
66
+ //# sourceMappingURL=jimp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jimp.d.ts","sourceRoot":"","sources":["../../src/adapters/jimp.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,eAAe,EAEf,UAAU,EACV,aAAa,EACb,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AA6B5B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,WAAY,YAAW,uBAAuB;IACzD,OAAO,CAAC,UAAU,CAA2B;IAE7C,OAAO,CAAC,OAAO,CAAc;IAE7B;;;OAGG;gBACS,OAAO,GAAE,WAA8B;IAInD;;OAEG;YACW,OAAO;IAgBf,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC;IAU1D,SAAS,CACb,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC;IAgCV,OAAO,CACX,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC;IAUV,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAqBtD,IAAI,CACR,KAAK,EAAE,UAAU,EACjB,SAAS,GAAE,aAA4B,GACtC,OAAO,CAAC,MAAM,CAAC;IAwCZ,MAAM,CACV,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC;IA8BhB;;OAEG;YACW,gBAAgB;IAoB9B;;OAEG;IACH,OAAO,CAAC,WAAW;IAgBnB;;OAEG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAUxB;;OAEG;IACH,OAAO,CAAC,QAAQ;CA0BjB"}
@@ -0,0 +1,56 @@
1
+ import { ConvertOptions, HashAlgorithm, ImageDimensions, ImageInput, ImageMetadata, ImageProcessorInterface, ResizeOptions, SharpOptions, ThumbnailOptions } from '../shared/types.js';
2
+ /**
3
+ * Sharp adapter for high-performance image processing
4
+ *
5
+ * Uses the native sharp library which provides:
6
+ * - Fast image resizing and format conversion
7
+ * - Rich metadata extraction including EXIF, IPTC, XMP
8
+ * - Perceptual hashing for image deduplication
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const processor = new SharpAdapter();
13
+ * const dims = await processor.getDimensions('/path/to/image.jpg');
14
+ * console.log(dims); // { width: 1920, height: 1080 }
15
+ * ```
16
+ */
17
+ export declare class SharpAdapter implements ImageProcessorInterface {
18
+ private sharp;
19
+ private options;
20
+ /**
21
+ * Create a new Sharp adapter
22
+ * @param options - Sharp adapter options
23
+ */
24
+ constructor(options?: SharpOptions);
25
+ /**
26
+ * Lazily load sharp module
27
+ */
28
+ private getSharp;
29
+ getDimensions(input: ImageInput): Promise<ImageDimensions>;
30
+ thumbnail(input: ImageInput, output: string, options?: ThumbnailOptions): Promise<void>;
31
+ convert(input: ImageInput, output: string, options?: ConvertOptions): Promise<void>;
32
+ getMetadata(input: ImageInput): Promise<ImageMetadata>;
33
+ hash(input: ImageInput, algorithm?: HashAlgorithm): Promise<string>;
34
+ resize(input: ImageInput, output: string, options: ResizeOptions): Promise<void>;
35
+ /**
36
+ * Infer image format from file extension
37
+ */
38
+ private inferFormat;
39
+ /**
40
+ * Parse EXIF buffer to object (basic parsing)
41
+ */
42
+ private parseExifBuffer;
43
+ /**
44
+ * Parse IPTC buffer to object (basic parsing)
45
+ */
46
+ private parseIptcBuffer;
47
+ /**
48
+ * Parse XMP buffer to object (basic parsing)
49
+ */
50
+ private parseXmpBuffer;
51
+ /**
52
+ * Map sharp errors to our error types
53
+ */
54
+ private mapError;
55
+ }
56
+ //# sourceMappingURL=sharp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharp.d.ts","sourceRoot":"","sources":["../../src/adapters/sharp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,eAAe,EAEf,UAAU,EACV,aAAa,EACb,uBAAuB,EACvB,aAAa,EACb,YAAY,EACZ,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAa,YAAW,uBAAuB;IAC1D,OAAO,CAAC,KAAK,CAAuC;IAEpD,OAAO,CAAC,OAAO,CAAe;IAE9B;;;OAGG;gBACS,OAAO,GAAE,YAAiB;IAItC;;OAEG;YACW,QAAQ;IAehB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC;IAiB1D,SAAS,CACb,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC;IA0BV,OAAO,CACX,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC;IAYV,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IA2BtD,IAAI,CACR,KAAK,EAAE,UAAU,EACjB,SAAS,GAAE,aAA4B,GACtC,OAAO,CAAC,MAAM,CAAC;IA6BZ,MAAM,CACV,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC;IAwBhB;;OAEG;IACH,OAAO,CAAC,WAAW;IAenB;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;IACH,OAAO,CAAC,QAAQ;CAmBjB"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=claude-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-context.d.ts","sourceRoot":"","sources":["../../src/cli/claude-context.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, mkdirSync, copyFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ const Dirname = dirname(fileURLToPath(import.meta.url));
6
+ const pkgRoot = join(Dirname, "../..");
7
+ const targetDir = join(process.cwd(), ".claude");
8
+ if (!existsSync(targetDir)) {
9
+ mkdirSync(targetDir, { recursive: true });
10
+ }
11
+ const pkgName = "images";
12
+ const agentMdSrc = existsSync(join(pkgRoot, "AGENT.md")) ? join(pkgRoot, "AGENT.md") : join(pkgRoot, "CLAUDE.md");
13
+ const metaSrc = existsSync(join(pkgRoot, "metadata.json")) ? join(pkgRoot, "metadata.json") : join(pkgRoot, ".claude-meta.json");
14
+ if (existsSync(agentMdSrc)) {
15
+ copyFileSync(agentMdSrc, join(targetDir, `have-${pkgName}.md`));
16
+ }
17
+ if (existsSync(metaSrc)) {
18
+ copyFileSync(metaSrc, join(targetDir, `have-${pkgName}.meta.json`));
19
+ }
20
+ console.log(`✓ Installed @happyvertical/${pkgName} context to .claude/`);
21
+ //# sourceMappingURL=claude-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-context.js","sources":["../../src/cli/claude-context.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI script to install agent context for @happyvertical/images\n * Run the published context installer binary for this package.\n */\nimport { copyFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst Dirname = dirname(fileURLToPath(import.meta.url));\nconst pkgRoot = join(Dirname, '../..');\nconst targetDir = join(process.cwd(), '.claude');\n\nif (!existsSync(targetDir)) {\n mkdirSync(targetDir, { recursive: true });\n}\n\nconst pkgName = 'images';\nconst agentMdSrc = existsSync(join(pkgRoot, 'AGENT.md'))\n ? join(pkgRoot, 'AGENT.md')\n : join(pkgRoot, 'CLAUDE.md');\nconst metaSrc = existsSync(join(pkgRoot, 'metadata.json'))\n ? join(pkgRoot, 'metadata.json')\n : join(pkgRoot, '.claude-meta.json');\n\nif (existsSync(agentMdSrc)) {\n copyFileSync(agentMdSrc, join(targetDir, `have-${pkgName}.md`));\n}\n\nif (existsSync(metaSrc)) {\n copyFileSync(metaSrc, join(targetDir, `have-${pkgName}.meta.json`));\n}\n\nconsole.log(`✓ Installed @happyvertical/${pkgName} context to .claude/`);\n"],"names":[],"mappings":";;;;AASA,MAAM,UAAU,QAAQ,cAAc,YAAY,GAAG,CAAC;AACtD,MAAM,UAAU,KAAK,SAAS,OAAO;AACrC,MAAM,YAAY,KAAK,QAAQ,IAAA,GAAO,SAAS;AAE/C,IAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,YAAU,WAAW,EAAE,WAAW,KAAA,CAAM;AAC1C;AAEA,MAAM,UAAU;AAChB,MAAM,aAAa,WAAW,KAAK,SAAS,UAAU,CAAC,IACnD,KAAK,SAAS,UAAU,IACxB,KAAK,SAAS,WAAW;AAC7B,MAAM,UAAU,WAAW,KAAK,SAAS,eAAe,CAAC,IACrD,KAAK,SAAS,eAAe,IAC7B,KAAK,SAAS,mBAAmB;AAErC,IAAI,WAAW,UAAU,GAAG;AAC1B,eAAa,YAAY,KAAK,WAAW,QAAQ,OAAO,KAAK,CAAC;AAChE;AAEA,IAAI,WAAW,OAAO,GAAG;AACvB,eAAa,SAAS,KAAK,WAAW,QAAQ,OAAO,YAAY,CAAC;AACpE;AAEA,QAAQ,IAAI,8BAA8B,OAAO,sBAAsB;"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Headline Card Generator
3
+ *
4
+ * Generates branded social media / OG images with article titles.
5
+ * Uses Satori (Vercel's JSX-to-SVG) and resvg for PNG output.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { generateHeadlineCard } from '@happyvertical/images';
10
+ *
11
+ * const result = await generateHeadlineCard('Breaking: Major Discovery', {
12
+ * brandColor: '#1a56db',
13
+ * subtitle: 'Science News',
14
+ * template: 'news'
15
+ * });
16
+ *
17
+ * await writeFile('og-image.png', result.buffer);
18
+ * ```
19
+ */
20
+ /**
21
+ * Template style for headline cards
22
+ */
23
+ export type HeadlineCardTemplate = 'default' | 'news' | 'minimal';
24
+ /**
25
+ * Options for headline card generation
26
+ */
27
+ export interface HeadlineCardOptions {
28
+ /**
29
+ * Width in pixels
30
+ * @default 1200
31
+ */
32
+ width?: number;
33
+ /**
34
+ * Height in pixels
35
+ * @default 630
36
+ */
37
+ height?: number;
38
+ /**
39
+ * Primary brand color (hex)
40
+ * @default '#3b82f6'
41
+ */
42
+ brandColor?: string;
43
+ /**
44
+ * Background color (hex)
45
+ * @default '#ffffff'
46
+ */
47
+ backgroundColor?: string;
48
+ /**
49
+ * Secondary text color (hex)
50
+ * @default '#64748b'
51
+ */
52
+ textColor?: string;
53
+ /**
54
+ * Optional subtitle/category
55
+ */
56
+ subtitle?: string;
57
+ /**
58
+ * Optional logo URL (will be fetched and embedded)
59
+ */
60
+ logoUrl?: string;
61
+ /**
62
+ * Logo data as base64 or buffer (alternative to logoUrl)
63
+ */
64
+ logoData?: string | Buffer;
65
+ /**
66
+ * Card template style
67
+ * @default 'default'
68
+ */
69
+ template?: HeadlineCardTemplate;
70
+ /**
71
+ * Font family name (must be available via Google Fonts or provide fontData)
72
+ * @default 'Inter'
73
+ */
74
+ fontFamily?: string;
75
+ /**
76
+ * Custom font data (loaded font buffer)
77
+ */
78
+ fontData?: ArrayBuffer;
79
+ }
80
+ /**
81
+ * Result from headline card generation
82
+ */
83
+ export interface HeadlineCardResult {
84
+ /** PNG image buffer */
85
+ buffer: Buffer;
86
+ /** Image width */
87
+ width: number;
88
+ /** Image height */
89
+ height: number;
90
+ /** MIME type (always image/png) */
91
+ mimeType: 'image/png';
92
+ }
93
+ /**
94
+ * Generate a headline card image
95
+ *
96
+ * Creates a branded social media / OG image with the article title.
97
+ * Supports multiple templates and customization options.
98
+ *
99
+ * @param title - The headline text to display
100
+ * @param options - Customization options
101
+ * @returns Promise resolving to PNG image result
102
+ *
103
+ * @example Basic usage
104
+ * ```typescript
105
+ * const result = await generateHeadlineCard('Breaking News: AI Advances');
106
+ * await fs.writeFile('og-image.png', result.buffer);
107
+ * ```
108
+ *
109
+ * @example With branding
110
+ * ```typescript
111
+ * const result = await generateHeadlineCard('Local Council Approves Budget', {
112
+ * brandColor: '#1a56db',
113
+ * subtitle: 'Town News',
114
+ * template: 'news'
115
+ * });
116
+ * ```
117
+ *
118
+ * @example Full customization
119
+ * ```typescript
120
+ * const result = await generateHeadlineCard('The Future of Technology', {
121
+ * width: 1200,
122
+ * height: 630,
123
+ * brandColor: '#059669',
124
+ * backgroundColor: '#f8fafc',
125
+ * subtitle: 'Technology',
126
+ * template: 'minimal',
127
+ * fontFamily: 'Roboto'
128
+ * });
129
+ * ```
130
+ */
131
+ export declare function generateHeadlineCard(title: string, options?: HeadlineCardOptions): Promise<HeadlineCardResult>;
132
+ /**
133
+ * Reset cached font data (useful for testing)
134
+ */
135
+ export declare function resetFontCache(): void;
136
+ //# sourceMappingURL=headline-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headline-card.d.ts","sourceRoot":"","sources":["../src/headline-card.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA2BH;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAE3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAEhC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,QAAQ,EAAE,WAAW,CAAC;CACvB;AAoWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAsF7B;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAGrC"}