@zampsn/old-man-yells-at 1.0.0 → 1.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/README.md CHANGED
@@ -1,5 +1,11 @@
1
- [![ci](https://github.com/zampsn/old-man-yells-at/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/zampsn/old-man-yells-at/actions/workflows/ci.yaml)
2
- [![codecov](https://codecov.io/gh/zampsn/old-man-yells-at/graph/badge.svg?token=ACgVjXxFeS)](https://codecov.io/gh/zampsn/old-man-yells-at)
3
- [![Version](https://img.shields.io/github/v/release/zampsn/old-man-yells-at)](https://github.com/zampsn/old-man-yells-at/releases)
1
+ <p align="center"><img src="/static/old-man-yells-at.png" width="128" alt="Old man yells at" /></p>
2
+ <h3 align="center">old-man-yells-at</h3>
3
+ <p align="center">
4
+ <a href="https://npmjs.com/package/@zampsn/old-man-yells-at"><img src="https://badgen.net/npm/v/@zampsn/old-man-yells-at" alt="npm"></a>
5
+ <a href="https://github.com/zampsn/old-man-yells-at/actions"><img src="https://github.com/zampsn/old-man-yells-at/actions/workflows/ci.yaml/badge.svg" alt="workflow status">
6
+ <a href="https://codecov.io/gh/zampsn/old-man-yells-at"><img src="https://codecov.io/gh/zampsn/old-man-yells-at/graph/badge.svg?token=ACgVjXxFeS" alt="code coverage"/></a></a>
7
+ </p>
4
8
 
5
- # old-man-yells-at
9
+ ---
10
+
11
+ You've got an opinion. A strong one. About something that probably doesn't deserve this much energy. old-man-yells-at is a TypeScript package that turns that frustration into art — specifically, Abe Simpson shaking his fist at whatever you point it at. Pass in a target, get back a meme. Simple as that.
@@ -0,0 +1,13 @@
1
+ import type sharp from 'sharp';
2
+ export declare class Builder {
3
+ private readonly inputPath;
4
+ private readonly templateBuffer;
5
+ private outputWidth;
6
+ private outputHeight;
7
+ constructor(inputPath: string, templateBuffer: Buffer);
8
+ resize(width: number, height: number): this;
9
+ toSharp(): Promise<sharp.Sharp>;
10
+ toBuffer(): Promise<Buffer>;
11
+ toFile(outputPath: string): Promise<void>;
12
+ }
13
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,qBAAa,OAAO;IAChB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,YAAY,CAAwB;gBAEhC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;IAKrD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAMrC,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAS/B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAI3B,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlD"}
@@ -0,0 +1,32 @@
1
+ import { compositeImages } from './composite.js';
2
+ const DEFAULT_SIZE = 128;
3
+ export class Builder {
4
+ inputPath;
5
+ templateBuffer;
6
+ outputWidth = DEFAULT_SIZE;
7
+ outputHeight = DEFAULT_SIZE;
8
+ constructor(inputPath, templateBuffer) {
9
+ this.inputPath = inputPath;
10
+ this.templateBuffer = templateBuffer;
11
+ }
12
+ resize(width, height) {
13
+ this.outputWidth = width;
14
+ this.outputHeight = height;
15
+ return this;
16
+ }
17
+ async toSharp() {
18
+ return compositeImages({
19
+ inputPath: this.inputPath,
20
+ templateBuffer: this.templateBuffer,
21
+ width: this.outputWidth,
22
+ height: this.outputHeight,
23
+ });
24
+ }
25
+ async toBuffer() {
26
+ return (await this.toSharp()).toBuffer();
27
+ }
28
+ async toFile(outputPath) {
29
+ await (await this.toSharp()).toFile(outputPath);
30
+ }
31
+ }
32
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,YAAY,GAAG,GAAG,CAAC;AAEzB,MAAM,OAAO,OAAO;IACC,SAAS,CAAS;IAClB,cAAc,CAAS;IAChC,WAAW,GAAW,YAAY,CAAC;IACnC,YAAY,GAAW,YAAY,CAAC;IAE5C,YAAY,SAAiB,EAAE,cAAsB;QACjD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;IAED,MAAM,CAAC,KAAa,EAAE,MAAc;QAChC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;QAC3B,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO;QACT,OAAO,eAAe,CAAC;YACnB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,KAAK,EAAE,IAAI,CAAC,WAAW;YACvB,MAAM,EAAE,IAAI,CAAC,YAAY;SAC5B,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,QAAQ;QACV,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB;QAC3B,MAAM,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACpD,CAAC;CACJ"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,8 @@
1
+ import { yellAt } from './yell-at.js';
2
+ yellAt('test/fixtures/test-input.png')
3
+ .then((res) => res.toFile('temp.png'))
4
+ .catch((err) => {
5
+ console.error('Failed to yell at image', err);
6
+ process.exit(1);
7
+ });
8
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,CAAC,8BAA8B,CAAC;KACjC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;KACrC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACX,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import sharp from 'sharp';
2
+ import type { CompositeOptions } from './types.js';
3
+ export declare const compositeImages: (options: CompositeOptions) => Promise<sharp.Sharp>;
4
+ //# sourceMappingURL=composite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composite.d.ts","sourceRoot":"","sources":["../src/composite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,eAAO,MAAM,eAAe,GAAU,SAAS,gBAAgB,KAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CASpF,CAAC"}
@@ -0,0 +1,11 @@
1
+ import sharp from 'sharp';
2
+ const OVERLAY_SIZE = 48;
3
+ export const compositeImages = async (options) => {
4
+ const { inputPath, templateBuffer, width, height } = options;
5
+ const overlay = await sharp(inputPath).resize(OVERLAY_SIZE, OVERLAY_SIZE, { fit: 'cover' }).toBuffer();
6
+ return sharp(templateBuffer)
7
+ .resize(width, height, { fit: 'cover' })
8
+ .composite([{ input: overlay, top: 16, left: 0 }])
9
+ .png();
10
+ };
11
+ //# sourceMappingURL=composite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composite.js","sourceRoot":"","sources":["../src/composite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,OAAyB,EAAwB,EAAE;IACrF,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAE7D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEvG,OAAO,KAAK,CAAC,cAAc,CAAC;SACvB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;SACvC,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;SACjD,GAAG,EAAE,CAAC;AACf,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- export declare const FOO = "bar";
2
- export interface User {
3
- name: string;
4
- }
1
+ export { yellAt } from './yell-at.js';
2
+ export { Builder } from './builder.js';
5
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,GAAG,QAAQ,CAAC;AAEzB,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- export const FOO = 'bar';
1
+ export { yellAt } from './yell-at.js';
2
+ export { Builder } from './builder.js';
2
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,GAAG,GAAG,KAAK,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const getTemplateBuffer: () => Promise<Buffer>;
2
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,MAAM,CAQxD,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @summary template fetches the old-man-yells-at.png base image from GitHub.
3
+ *
4
+ * For security, we verify the checksum of the image on first access.
5
+ */
6
+ import { createHash } from 'node:crypto';
7
+ const EXPECTED_CHECKSUM = '7e0095f6b841b97f2745afcdc803b0895028de7caeeeb665e158ef6a20f35b80';
8
+ const TEMPLATE_URL = 'https://github.com/zampsn/old-man-yells-at/blob/main/static/old-man-yells-at.png?raw=true';
9
+ let cachedTemplate;
10
+ const verifyChecksum = (buffer) => {
11
+ const hash = createHash('sha256').update(buffer).digest('hex');
12
+ if (hash !== EXPECTED_CHECKSUM) {
13
+ throw new Error(`Template image checksum mismatch. Expected ${EXPECTED_CHECKSUM}, got ${hash}`);
14
+ }
15
+ };
16
+ const loadFromRemote = async () => {
17
+ const response = await fetch(TEMPLATE_URL);
18
+ if (!response.ok) {
19
+ throw new Error(`Failed to fetch template image: ${response.status} ${response.statusText}`);
20
+ }
21
+ return Buffer.from(await response.arrayBuffer());
22
+ };
23
+ export const getTemplateBuffer = async () => {
24
+ if (cachedTemplate)
25
+ return cachedTemplate;
26
+ const buffer = await loadFromRemote();
27
+ verifyChecksum(buffer);
28
+ cachedTemplate = buffer;
29
+ return buffer;
30
+ };
31
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,iBAAiB,GAAG,kEAAkE,CAAC;AAC7F,MAAM,YAAY,GAAG,2FAA2F,CAAC;AAEjH,IAAI,cAAkC,CAAC;AAEvC,MAAM,cAAc,GAAG,CAAC,MAAc,EAAQ,EAAE;IAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/D,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,8CAA8C,iBAAiB,SAAS,IAAI,EAAE,CAAC,CAAC;IACpG,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,KAAK,IAAqB,EAAE;IAC/C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACjG,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;AACrD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,IAAqB,EAAE;IACzD,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAE1C,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;IACtC,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,cAAc,GAAG,MAAM,CAAC;IACxB,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface CompositeOptions {
2
+ readonly inputPath: string;
3
+ readonly templateBuffer: Buffer;
4
+ readonly width: number;
5
+ readonly height: number;
6
+ }
7
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import { Builder } from './builder.js';
2
+ export declare const yellAt: (imagePath: string) => Promise<Builder>;
3
+ //# sourceMappingURL=yell-at.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yell-at.d.ts","sourceRoot":"","sources":["../src/yell-at.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,eAAO,MAAM,MAAM,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,OAAO,CAG/D,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { Builder } from './builder.js';
2
+ import { getTemplateBuffer } from './template.js';
3
+ export const yellAt = async (imagePath) => {
4
+ const templateBuffer = await getTemplateBuffer();
5
+ return new Builder(imagePath, templateBuffer);
6
+ };
7
+ //# sourceMappingURL=yell-at.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yell-at.js","sourceRoot":"","sources":["../src/yell-at.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,EAAE,SAAiB,EAAoB,EAAE;IAChE,MAAM,cAAc,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACjD,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AAClD,CAAC,CAAC"}
package/package.json CHANGED
@@ -24,7 +24,8 @@
24
24
  "main": "./dist/index.js",
25
25
  "types": "./dist/index.d.ts",
26
26
  "files": [
27
- "dist"
27
+ "dist",
28
+ "static"
28
29
  ],
29
30
  "publishConfig": {
30
31
  "access": "public",
@@ -35,6 +36,7 @@
35
36
  },
36
37
  "devDependencies": {
37
38
  "@eslint/js": "^10.0.1",
39
+ "@types/node": "^25.5.0",
38
40
  "@vitest/coverage-v8": "^4.1.1",
39
41
  "eslint": "^10.1.0",
40
42
  "eslint-config-prettier": "^10.1.8",
@@ -45,5 +47,8 @@
45
47
  "typescript-eslint": "^8.57.2",
46
48
  "vitest": "^4.1.1"
47
49
  },
48
- "version": "1.0.0"
50
+ "dependencies": {
51
+ "sharp": "^0.34.5"
52
+ },
53
+ "version": "1.1.0"
49
54
  }
Binary file