@azuro-org/images-generator 1.3.15 → 2.0.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,80 +1,152 @@
1
1
  # @azuro-org/images-generator
2
2
 
3
+ Puppeteer-based image generator: render HTML templates to PNG/JPEG. Uses a shared browser instance; relaunches automatically if the browser disconnects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @azuro-org/images-generator
9
+ ```
10
+
3
11
  ## Usage
4
12
 
13
+ Create a `Generator` instance, call `run()` to start the browser, then use `generate()` for each image. Call `shutdown()` when done to close the browser.
14
+
5
15
  ```typescript
6
- import { generateImage } from '@azuro-org/images-generator';
7
- import template, { type Props } from '@azuro-org/images-generator/lib/templates/bet-nft';
16
+ import { Generator } from '@azuro-org/images-generator';
17
+ import template from '@azuro-org/images-generator/lib/templates/bet-nft';
8
18
 
9
- const props: Props = {
10
- // ...
11
- }
19
+ const generator = new Generator();
20
+
21
+ await generator.run();
12
22
 
13
- // get image buffer
14
- const buffer = generateImage({
23
+ // Single image – returns Uint8Array
24
+ const buffer = await generator.generate({
15
25
  template,
16
- props,
17
- })
26
+ props: { /* ... */ },
27
+ });
18
28
 
19
- // create image file
20
- generateImage({
29
+ // Save to file
30
+ await generator.generate({
21
31
  template,
22
- props,
32
+ props: { /* ... */ },
23
33
  output: './dist',
24
- })
34
+ filename: 'my-image',
35
+ });
36
+
37
+ await generator.shutdown();
38
+ ```
39
+
40
+ ### Batch generation with shutdown
41
+
42
+ Run multiple generations in parallel and close the browser when finished:
43
+
44
+ ```typescript
45
+ await generator.run();
46
+
47
+ await Promise.all([
48
+ generator.generate({ template, props: props1, output: './dist', filename: 'image-1' }),
49
+ generator.generate({ template, props: props2, output: './dist', filename: 'image-2' }),
50
+ ]).finally(() => {
51
+ generator.shutdown();
52
+ });
25
53
  ```
26
54
 
27
- ## Options
55
+ ### Auto-recovery
56
+
57
+ If the browser process exits or crashes, the next `generate()` call will launch a new browser automatically. You can also call `run()` again after a disconnect.
58
+
59
+ ## API
60
+
61
+ ### `Generator`
62
+
63
+ **Constructor**
28
64
 
29
65
  ```typescript
30
- type PuppeteerOptions = Parameters<typeof puppeteer.launch>[0]
66
+ const generator = new Generator(options?: GeneratorOptions);
67
+
68
+ interface GeneratorOptions {
69
+ headless?: boolean; // default: true
70
+ timeout?: number; // default: 30000 (ms)
71
+ args?: string[]; // extra Chromium args
72
+ }
73
+ ```
74
+
75
+ **Methods**
76
+
77
+ - **`run(): Promise<void>`** — Launches the browser. Idempotent if already running.
78
+ - **`generate<P>(props: GenerateProps<P>): Promise<Uint8Array>`** — Renders the template with the given props. Ensures the browser is running (calls `run()` if needed).
79
+ - **`shutdown(): Promise<void>`** — Closes the browser and cleans up.
80
+
81
+ ### `generate()` options
31
82
 
32
- type PuppeteerInitialOptions = {
33
- headless: boolean
34
- devtools: boolean
35
- args: string[]
83
+ ```typescript
84
+ interface GenerateProps<P> {
85
+ template: Template<P>;
86
+ props: P;
87
+ output?: string; // folder path for the output file
88
+ filename?: string; // file name without extension (used with output)
89
+ options?: GenerateOptions;
36
90
  }
37
91
 
38
- generateImage({
39
- output?: string // the folder path where the image will be generated
40
- filename?: string // image name, default is "image"
41
- props: any
42
- modifyPuppeteerOptions?(options: PuppeteerInitialOptions): PuppeteerOptions
43
- })
92
+ interface GenerateOptions {
93
+ quality?: number; // JPEG quality, default 85
94
+ fullPage?: boolean; // default false
95
+ waitForFonts?: boolean; // default true
96
+ waitTimeout?: number; // ms, default 2000
97
+ waitUntil?: 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'; // default 'domcontentloaded'
98
+ skipAnimations?: boolean; // default true
99
+ }
44
100
  ```
45
101
 
102
+ ## Templates
103
+
104
+ Templates are in `lib/templates/<name>` (or `dist/templates/<name>` for ESM). Each template exports a default `Template` and a `Props` type.
105
+
106
+ | Template | Import path |
107
+ |--------------------|----------------------------------------------------------|
108
+ | Bet NFT | `@azuro-org/images-generator/lib/templates/bet-nft` |
109
+ | Bet OG | `@azuro-org/images-generator/lib/templates/bet-og` |
110
+ | Combo Bet OG | `@azuro-org/images-generator/lib/templates/combo-bet-og` |
111
+ | Freebet | `@azuro-org/images-generator/lib/templates/freebet` |
112
+ | Trendle Leaderboard| `@azuro-org/images-generator/lib/templates/trendle-leaderboard` |
113
+ | Trendle Social | `@azuro-org/images-generator/lib/templates/trendle-social` |
114
+ | Trendle Trading | `@azuro-org/images-generator/lib/templates/trendle-trading` |
46
115
 
47
- # Examples
116
+ ---
117
+
118
+ ## Examples
48
119
 
49
120
  <details>
50
121
  <summary><b>Bet Opengraph</b></summary>
51
122
  <p>
52
123
 
53
124
  ```typescript
54
- import { generateImage } from '@azuro-org/images-generator';
125
+ import { Generator } from '@azuro-org/images-generator';
55
126
  import template from '@azuro-org/images-generator/lib/templates/bet-og';
56
127
 
57
- generateImage({
128
+ const generator = new Generator();
129
+ await generator.run();
130
+
131
+ await generator.generate({
58
132
  template,
133
+ output: './dist',
134
+ filename: 'bet-og',
59
135
  props: {
60
136
  title: 'Decentralized betting is awesome!',
61
137
  game: {
62
138
  country: 'International Tournaments',
63
139
  league: 'ESL Challenger League North America',
64
140
  participants: [
65
- {
66
- name: 'WINDINGO',
67
- image: 'https://content.bookmaker.xyz/avatars/provider-3/4757.png',
68
- },
69
- {
70
- name: 'Los Grandes Academy',
71
- image: 'https://content.bookmaker.xyz/avatars/provider-3/4739.png',
72
- },
141
+ { name: 'WINDINGO', image: 'https://content.bookmaker.xyz/avatars/provider-3/4757.png' },
142
+ { name: 'Los Grandes Academy', image: 'https://content.bookmaker.xyz/avatars/provider-3/4739.png' },
73
143
  ],
74
144
  startsAt: Date.now(),
75
- }
145
+ },
76
146
  },
77
- })
147
+ });
148
+
149
+ await generator.shutdown();
78
150
  ```
79
151
 
80
152
  ### Result
@@ -88,34 +160,27 @@ generateImage({
88
160
  <p>
89
161
 
90
162
  ```typescript
91
- import { generateImage } from '@azuro-org/images-generator';
163
+ import { Generator } from '@azuro-org/images-generator';
92
164
  import template from '@azuro-org/images-generator/lib/templates/combo-bet-og';
93
165
 
94
- generateImage({
166
+ const generator = new Generator();
167
+ await generator.run();
168
+
169
+ await generator.generate({
95
170
  template,
171
+ output: './dist',
172
+ filename: 'combo-bet-og',
96
173
  props: {
97
174
  title: 'Decentralized betting is awesome!',
98
175
  data: {
99
176
  totalOdds: 1.57,
100
177
  possiblePayout: 1017.17,
101
178
  asset: 'USDT',
102
- }
179
+ },
103
180
  },
104
- })
181
+ });
105
182
 
106
- // or (for "Winning" label)
107
-
108
- generateImage({
109
- template,
110
- props: {
111
- title: 'Decentralized betting is awesome!',
112
- data: {
113
- totalOdds: 1.57,
114
- payout: 500,
115
- asset: 'USDT',
116
- }
117
- },
118
- })
183
+ await generator.shutdown();
119
184
  ```
120
185
 
121
186
  ### Result
@@ -129,30 +194,31 @@ generateImage({
129
194
  <p>
130
195
 
131
196
  ```typescript
132
- import { generateImage } from '@azuro-org/images-generator';
197
+ import { Generator } from '@azuro-org/images-generator';
133
198
  import template from '@azuro-org/images-generator/lib/templates/bet-nft';
134
199
 
135
- generateImage({
200
+ const generator = new Generator();
201
+ await generator.run();
202
+
203
+ await generator.generate({
136
204
  template,
205
+ output: './dist',
206
+ filename: 'bet-nft',
137
207
  props: {
138
208
  type: 'match',
139
209
  sport: 'Football',
140
210
  league: 'International Tournaments · FIFA - World Cup',
141
- team1: {
142
- img: 'https://content.bookmaker.xyz/avatars/provider-3/4757.png',
143
- name: 'Ecuador',
144
- },
145
- team2: {
146
- img: 'https://content.bookmaker.xyz/avatars/provider-3/4739.png',
147
- name: 'Senegal',
148
- },
211
+ team1: { img: 'https://content.bookmaker.xyz/avatars/provider-3/4757.png', name: 'Ecuador' },
212
+ team2: { img: 'https://content.bookmaker.xyz/avatars/provider-3/4739.png', name: 'Senegal' },
149
213
  date: 'Dec 24, 2020',
150
214
  betAmount: '100 xDAI',
151
215
  outcome: 'Senegal',
152
216
  betOdds: '1.7',
153
217
  currentOdds: '1.2',
154
218
  },
155
- })
219
+ });
220
+
221
+ await generator.shutdown();
156
222
  ```
157
223
 
158
224
  ### Result
@@ -162,20 +228,27 @@ generateImage({
162
228
  </details>
163
229
 
164
230
  <details>
165
- <summary><b>Bet Opengraph</b></summary>
231
+ <summary><b>Freebet</b></summary>
166
232
  <p>
167
233
 
168
234
  ```typescript
169
- import { generateImage } from '@azuro-org/images-generator';
235
+ import { Generator } from '@azuro-org/images-generator';
170
236
  import template from '@azuro-org/images-generator/lib/templates/freebet';
171
237
 
172
- generateImage({
238
+ const generator = new Generator();
239
+ await generator.run();
240
+
241
+ await generator.generate({
173
242
  template,
243
+ output: './dist',
244
+ filename: 'freebet',
174
245
  props: {
175
246
  amount: '5 xDAI',
176
247
  date: '12.01.2022',
177
248
  },
178
- })
249
+ });
250
+
251
+ await generator.shutdown();
179
252
  ```
180
253
 
181
254
  ### Result
@@ -184,53 +257,61 @@ generateImage({
184
257
  </p>
185
258
  </details>
186
259
 
260
+ ---
187
261
 
188
- # Contributing
189
-
190
- ## Add new template
262
+ ## Contributing
191
263
 
192
- 1. Copy `templates/_template` to `templates/{your_template_name}`.
193
- 3. Use `index.html` for HTML. Write CSS in `index.html` file.
194
- 4. Create `templates/{your_template_name}/images` folder for images if required.
264
+ ### Add a new template
195
265
 
266
+ 1. Copy `src/templates/_template` to `src/templates/{your_template_name}`.
267
+ 2. Put layout and styles in `index.html`.
268
+ 3. Add a `images` folder for static assets if needed.
196
269
 
197
- ## Setup generator
270
+ ### Template definition
198
271
 
199
- Edit `{your_template_name}/index.ts` file:
272
+ Use `Template<Props>`, `getBase64Image`, and `downloadImage` from `../../utils`:
200
273
 
201
274
  ```typescript
202
- import path from 'path'
203
-
204
- import { type Template, getFile, downloadImage, createGenerator } from '../../utils'
275
+ import { type Template, downloadImage } from '../../utils';
276
+ import html from './index.html';
205
277
 
206
278
  export type Props = {
207
- team1ImageSrc: string
208
- team2ImageSrc: string
209
- date: string
210
- }
279
+ team1ImageSrc: string;
280
+ team2ImageSrc: string;
281
+ date: string;
282
+ };
211
283
 
212
- const template = {
284
+ const template: Template<Props> = {
213
285
  width: 800,
214
286
  height: 400,
215
287
  type: 'jpeg',
216
288
  html: async (props: Props) => {
217
- const { team1ImageSrc, team2ImageSrc, date } = props
218
-
219
- const html = getFile(path.join(__dirname, 'index.html'))
220
-
221
- const team1Img = await downloadImage(team1ImageSrc)
222
- const team2Img = await downloadImage(team2ImageSrc)
223
-
289
+ const { team1ImageSrc, team2ImageSrc, date } = props;
290
+ const team1Img = await downloadImage(team1ImageSrc);
291
+ const team2Img = await downloadImage(team2ImageSrc);
224
292
  return html
225
293
  .replace('{image1}', team1Img)
226
294
  .replace('{image2}', team2Img)
227
- .replace('{date}', date)
295
+ .replace('{date}', date);
228
296
  },
229
- }
297
+ };
230
298
 
231
- export default template
299
+ export default template;
300
+ ```
301
+
302
+ **Template shape**
303
+
304
+ ```typescript
305
+ type Template<Props> = {
306
+ width: number;
307
+ height: number;
308
+ type: 'png' | 'jpeg';
309
+ html: (props: Props) => string | Promise<string>;
310
+ headless?: boolean;
311
+ scaleFactor?: 1 | 2;
312
+ };
232
313
  ```
233
314
 
234
- ## Publish
315
+ ### Publish
235
316
 
236
- Publish npm package with `npm run publish`. For access to `@azuro-org` scope ask Pavel Ivanov or Stas Onatskiy.
317
+ Publish with `npm publish`. For access to the `@azuro-org` scope, contact the maintainers.
@@ -0,0 +1,31 @@
1
+ import { type Template } from './utils';
2
+ interface GeneratorOptions {
3
+ headless?: boolean;
4
+ timeout?: number;
5
+ args?: string[];
6
+ }
7
+ interface GenerateOptions {
8
+ quality?: number;
9
+ fullPage?: boolean;
10
+ waitForFonts?: boolean;
11
+ waitTimeout?: number;
12
+ waitUntil?: 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';
13
+ skipAnimations?: boolean;
14
+ }
15
+ type GenerateProps<P> = {
16
+ template: Template<P>;
17
+ props: P;
18
+ output?: string;
19
+ filename?: string;
20
+ options?: GenerateOptions;
21
+ };
22
+ declare class Generator {
23
+ private browser;
24
+ private readonly options;
25
+ constructor(options?: GeneratorOptions);
26
+ run(): Promise<void>;
27
+ generate<P>(props: GenerateProps<P>): Promise<Uint8Array>;
28
+ shutdown(): Promise<void>;
29
+ private cleanup;
30
+ }
31
+ export default Generator;