@reportforge/playwright-pdf 0.16.0 → 0.17.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/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
+ ## [0.17.0] - 2026-07-09
7
+
8
+ ### Added
9
+
10
+ - **The reporter now tells you when a newer version is available.** Each run ends with one info line naming the current and latest version and the update command, e.g. `Update available: 0.16.1 -> 0.17.0. Run: npm i -D @reportforge/playwright-pdf@latest`. The latest published version is piggybacked on the existing license activate/refresh call, so there are no extra network calls; the notice never blocks or fails a run and disappears once you update.
11
+ - **Admins can send release announcement emails.** A new `/admin/announce` panel builds the email body from the changelog entry for a chosen version and sends it to a selected audience (active subscribers, all subscribers, or active plus recently churned within 90 days), with a preview step and idempotency protection against duplicate sends.
12
+
13
+ ---
14
+
15
+ ## [0.16.1] - 2026-07-09
16
+
17
+ ### Changed
18
+
19
+ - **Relicensed from MIT to the Elastic License 2.0** (source-available). The source stays readable, copyable, and modifiable; the license does not allow offering the software as a hosted service, bypassing or removing the license-key check, or stripping license/copyright notices. Surfaces updated together: `LICENSE`, `package.json` license metadata, README badge + License section, docs badge, marketing footer, pricing FAQ, and legal terms (§2 License grant, §7 IP, `lastUpdated`).
20
+
21
+ ---
22
+
6
23
  ## [0.16.0] - 2026-07-07
7
24
 
8
25
  ### Added
package/LICENSE CHANGED
@@ -1,21 +1,95 @@
1
- MIT License
2
-
3
1
  Copyright (c) 2026 ReportForge
4
2
 
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.
3
+ Elastic License 2.0
4
+
5
+ URL: https://www.elastic.co/licensing/elastic-license
6
+
7
+ ## Acceptance
8
+
9
+ By using the software, you agree to all of the terms and conditions below.
10
+
11
+ ## Copyright License
12
+
13
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
14
+ non-sublicensable, non-transferable license to use, copy, distribute, make
15
+ available, and prepare derivative works of the software, in each case subject to
16
+ the limitations and conditions below.
17
+
18
+ ## Limitations
19
+
20
+ You may not provide the software to third parties as a hosted or managed
21
+ service, where the service provides users with access to any substantial set of
22
+ the features or functionality of the software.
23
+
24
+ You may not move, change, disable, or circumvent the license key functionality
25
+ in the software, and you may not remove or obscure any functionality in the
26
+ software that is protected by the license key.
27
+
28
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
29
+ of the licensor in the software. Any use of the licensor’s trademarks is subject
30
+ to applicable law.
31
+
32
+ ## Patents
33
+
34
+ The licensor grants you a license, under any patent claims the licensor can
35
+ license, or becomes able to license, to make, have made, use, sell, offer for
36
+ sale, import and have imported the software, in each case subject to the
37
+ limitations and conditions in this license. This license does not cover any
38
+ patent claims that you cause to be infringed by modifications or additions to
39
+ the software. If you or your company make any written claim that the software
40
+ infringes or contributes to infringement of any patent, your patent license for
41
+ the software granted under these terms ends immediately. If your company makes
42
+ such a claim, your patent license ends immediately for work on behalf of your
43
+ company.
44
+
45
+ ## Notices
46
+
47
+ You must ensure that anyone who gets a copy of any part of the software from you
48
+ also gets a copy of these terms.
49
+
50
+ If you modify the software, you must include in any modified copies of the
51
+ software prominent notices stating that you have modified the software.
52
+
53
+ ## No Other Rights
54
+
55
+ These terms do not imply any licenses other than those expressly granted in
56
+ these terms.
57
+
58
+ ## Termination
59
+
60
+ If you use the software in violation of these terms, such use is not licensed,
61
+ and your licenses will automatically terminate. If the licensor provides you
62
+ with a notice of your violation, and you cease all violation of this license no
63
+ later than 30 days after you receive that notice, your licenses will be
64
+ reinstated retroactively. However, if you violate these terms after such
65
+ reinstatement, any additional violation of these terms will cause your licenses
66
+ to terminate automatically and permanently.
67
+
68
+ ## No Liability
69
+
70
+ *As far as the law allows, the software comes as is, without any warranty or
71
+ condition, and the licensor will not be liable to you for any damages arising
72
+ out of these terms or the use or nature of the software, under any kind of
73
+ legal claim.*
74
+
75
+ ## Definitions
76
+
77
+ The **licensor** is the entity offering these terms, and the **software** is the
78
+ software the licensor makes available under these terms, including any portion
79
+ of it.
80
+
81
+ **you** refers to the individual or entity agreeing to these terms.
82
+
83
+ **your company** is any legal entity, sole proprietorship, or other kind of
84
+ organization that you work for, plus all organizations that have control over,
85
+ are under the control of, or are under common control with that
86
+ organization. **control** means ownership of substantially all the assets of an
87
+ entity, or the power to direct its management and policies by vote, contract, or
88
+ otherwise. Control can be direct or indirect.
89
+
90
+ **your licenses** are all the licenses granted to you for the software under
91
+ these terms.
92
+
93
+ **use** means anything you do with the software requiring one of your licenses.
94
+
95
+ **trademark** means trademarks, service marks, and similar rights.
package/README.md CHANGED
@@ -6,7 +6,7 @@ Drop it into any Playwright project and get a PDF report on every CI run. No cha
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/@reportforge/playwright-pdf.svg)](https://www.npmjs.com/package/@reportforge/playwright-pdf)
8
8
  [![Node](https://img.shields.io/node/v/@reportforge/playwright-pdf.svg)](https://nodejs.org/)
9
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
9
+ [![License](https://img.shields.io/badge/license-Elastic--2.0-blue.svg)](./LICENSE)
10
10
 
11
11
  <p align="center">
12
12
  <a href="https://reportforge.org/pricing">
@@ -47,7 +47,7 @@ Three templates, one reporter. Every PDF is fully offline: fonts, charts, and sc
47
47
 
48
48
  - **3 templates**: `minimal` (developer), `detailed` (QA team), `executive` (stakeholders)
49
49
  - **Detailed reports**: KPI dashboard, suite breakdown with inline failure detail (error, screenshot, root-cause chip) under each failed test, CI/CD environment
50
- - **Embedded Chart.js**: pass-rate doughnut + per-suite bar chart, bundled inline (no CDN); every suite gets its own bar large runs switch to full-width suite charts that continue across pages, so per-suite coverage and failures stay visible run-wide
50
+ - **Embedded Chart.js**: pass-rate doughnut + per-suite bar chart, bundled inline (no CDN); every suite gets its own bar, and large runs switch to full-width suite charts that continue across pages, so per-suite coverage and failures stay visible run-wide
51
51
  - **Self-contained PDFs**: screenshots, fonts, logos all embedded; share or archive with confidence
52
52
  - **Custom branding**: logo, primary/accent colours, watermark, PDF password encryption
53
53
  - **Dynamic filenames**: `{date}`, `{branch}`, `{status}` tokens in the output path
@@ -63,6 +63,7 @@ Three templates, one reporter. Every PDF is fully offline: fonts, charts, and sc
63
63
  - **Configurable sections**: add or remove any report section per template via `sections`.
64
64
  - **Executive report brief band**: leads with a plain-language brief (trend + root causes) and one hero pass-rate number instead of a flat KPI grid
65
65
  - **Hybrid licensing**: one short key unlocks it; reports keep rendering offline via a cached JWT between refreshes
66
+ - **Update notice**: when a newer reporter version is published, each run ends with one info line naming it and the update command; delivered over the existing license refresh, no extra network calls
66
67
 
67
68
  ---
68
69
 
@@ -97,7 +98,7 @@ npx playwright test
97
98
 
98
99
  > **See it first.** Run `npx @reportforge/playwright-pdf demo` to generate a realistic sample PDF in under 60 seconds, no license key required. Supports `--template=minimal|detailed|executive` and `--output=<path>`.
99
100
 
100
- > **License required.** Start a **[7-day free trial at reportforge.org/pricing](https://reportforge.org/pricing)**: card required, no charge until day 8. Paste the resulting `RFSU-…` key into `RF_LICENSE_KEY`. Without a valid license the reporter logs a warning and skips PDF generation; your Playwright tests still run normally.
101
+ > **License required.** Start a **[7-day free trial at reportforge.org/pricing](https://reportforge.org/pricing)**: card required, no charge until day 8. Paste the resulting `RFSU-…` key into `RF_LICENSE_KEY`. Without a valid license the reporter logs a warning and skips PDF generation; your Playwright tests still run normally. When a newer reporter version exists, runs end with a one-line update notice.
101
102
 
102
103
  ---
103
104
 
@@ -157,7 +158,7 @@ reporter: [['@reportforge/playwright-pdf', {
157
158
  | Plan | INR | USD | Includes |
158
159
  |---|---|---|---|
159
160
  | **Monthly** | **₹999 / month** | **$12 / month** | All three templates · custom branding · PDF encryption · up to 25 active machines · priority email support |
160
- | **Yearly** | **₹8,499 / year** | **$99 / year** | Everything in Monthly · ~2931% saving vs monthly |
161
+ | **Yearly** | **₹8,499 / year** | **$99 / year** | Everything in Monthly · ~29-31% saving vs monthly |
161
162
 
162
163
  Currency is auto-detected by region; toggle on the pricing page.
163
164
 
@@ -198,7 +199,7 @@ All options are the second element of the reporter tuple.
198
199
  | `notify` | `object` | n/a | Notification channels: `slack`, `teams` (each `{ url, enabled, on }`), `discord` (`{ url, enabled, on, attachPdf }`), `email` (`{ to, enabled, on, attachPdf }`). See the Notifications docs. |
199
200
  | `failureAnalysis` | `object` | `{ enabled: true }` | Offline failure root-cause analysis (embedded Naive Bayes; no runtime network). Fields: `enabled` (default `true`), `maxClusters` (default `10`), `minStrength` (`weak`\|`moderate`\|`strong`, default `weak`), `maxFailuresToAnalyse` (default `500`), `collectUnclassified` (default `true`), `autoUpdateModel` (default `true`). See the Failure Analysis docs. |
200
201
  | `capture` | `object` | `{}` (off) | Opt-in rich execution capture for the defect log (reporter-side; no fixtures, no test-code changes). Fields: `steps` (a copy-pasteable "Steps to Reproduce" outline built from the Playwright step tree; each row is a Markdown list line indented under its parent `test.step`, default `false`), `apiSteps` (include every top-level `pw:api` action (click/fill/check/goto) in the outline for a full action trail; without it the outline shows only `test.step` intent + `expect` assertions, default `false`), `console` (Node stdout/stderr tail, default `false`), `evidence` (trace/video file links, default `false`), `maxSteps` (default `50`), `maxConsoleLines` (default `50`). Renders in the Defect Log section of the `detailed` template. |
201
- | `live` | `object` | `{}` (off) | Opt-in live test-execution streaming. When `enabled`, the reporter prints an unguessable watch link to the CI logs at run start and streams per-test progress to the hosted dashboard while tests run; all shards of one CI run converge on a single live view. Fields: `enabled` (default `false`), `runId` (override the auto-derived run id), `serverUrl` (override the streaming server), `steps` (`none`\|`failed`\|`intent`\|`all`, default `failed`; `intent` shows only your `test.step` names plus any failing step), `console` (stream stdout/stderr tails, default `false`), `flushMs` (batch debounce 50010000, default `2000`). The PDF at the end of the run is unaffected. Requires an active subscription with the `live` entitlement. See the Live Runs docs. |
202
+ | `live` | `object` | `{}` (off) | Opt-in live test-execution streaming. When `enabled`, the reporter prints an unguessable watch link to the CI logs at run start and streams per-test progress to the hosted dashboard while tests run; all shards of one CI run converge on a single live view. Fields: `enabled` (default `false`), `runId` (override the auto-derived run id), `serverUrl` (override the streaming server), `steps` (`none`\|`failed`\|`intent`\|`all`, default `failed`; `intent` shows only your `test.step` names plus any failing step), `console` (stream stdout/stderr tails, default `false`), `flushMs` (batch debounce 500-10000, default `2000`). The PDF at the end of the run is unaffected. Requires an active subscription with the `live` entitlement. See the Live Runs docs. |
202
203
  | `historyFile` | `string` | `~/.reportforge/{key}/history.json` | Path to the history JSON file. Relative paths resolve from `cwd`. Enables pass-rate trending charts in the `detailed` template. |
203
204
  | `historySize` | `number` | `10` | Maximum number of test runs to keep in the history file (integer ≥ 2). Older runs are pruned on append. |
204
205
  | `showTrend` | `boolean` | `true` | Show the pass-rate sparkline and delta badge in the `detailed` template. Set to `false` to disable history tracking entirely. |
@@ -225,7 +226,7 @@ reporter: [
225
226
  enabled: true,
226
227
  steps: 'failed', // 'none' | 'failed' | 'intent' | 'all'
227
228
  // console: false, // stream stdout/stderr tails (off by default; see note)
228
- // flushMs: 2000, // batch debounce (50010000)
229
+ // flushMs: 2000, // batch debounce (500-10000)
229
230
  },
230
231
  }],
231
232
  ],
@@ -678,4 +679,4 @@ Questions and bug reports: email [support@reportforge.org](mailto:support@report
678
679
 
679
680
  ## License
680
681
 
681
- MIT. See [LICENSE](./LICENSE).
682
+ [Elastic License 2.0](./LICENSE), source-available. Read, copy, and modify the source freely. Three things the license does not allow: offering the software as a hosted service, bypassing or removing the license-key check, and stripping license or copyright notices. Generating PDF reports requires an active subscription.
package/dist/index.d.mts CHANGED
@@ -379,6 +379,13 @@ interface LicenseInfo {
379
379
  * field was persisted — treat absence as "no extra features".
380
380
  */
381
381
  features?: string[];
382
+ /**
383
+ * Latest published npm version of the reporter, as last reported by the
384
+ * license server (activate/refresh piggyback). Absent when the server
385
+ * could not reach the registry or the cache predates this field. Used
386
+ * only for the non-blocking run-end update notice.
387
+ */
388
+ latestVersion?: string;
382
389
  }
383
390
 
384
391
  /**
@@ -417,6 +424,7 @@ interface LicenseInfo {
417
424
  declare class PdfReporter implements Reporter {
418
425
  private readonly options;
419
426
  private readonly cwd;
427
+ private readonly version;
420
428
  private readonly licenseClient;
421
429
  private readonly dataCollector;
422
430
  private readonly pdfGenerator;
package/dist/index.d.ts CHANGED
@@ -379,6 +379,13 @@ interface LicenseInfo {
379
379
  * field was persisted — treat absence as "no extra features".
380
380
  */
381
381
  features?: string[];
382
+ /**
383
+ * Latest published npm version of the reporter, as last reported by the
384
+ * license server (activate/refresh piggyback). Absent when the server
385
+ * could not reach the registry or the cache predates this field. Used
386
+ * only for the non-blocking run-end update notice.
387
+ */
388
+ latestVersion?: string;
382
389
  }
383
390
 
384
391
  /**
@@ -417,6 +424,7 @@ interface LicenseInfo {
417
424
  declare class PdfReporter implements Reporter {
418
425
  private readonly options;
419
426
  private readonly cwd;
427
+ private readonly version;
420
428
  private readonly licenseClient;
421
429
  private readonly dataCollector;
422
430
  private readonly pdfGenerator;
package/dist/index.js CHANGED
@@ -10995,7 +10995,8 @@ var LicenseClient = class {
10995
10995
  fingerprintHash: this.fingerprint.hash,
10996
10996
  machinesUsed: result.machinesUsed,
10997
10997
  machineLimit: result.machineLimit,
10998
- features: payload.features
10998
+ features: payload.features,
10999
+ latestVersion: result.latestVersion
10999
11000
  };
11000
11001
  writeCache(entry);
11001
11002
  logger.debug(`license path=${cached ? "refresh" : "activate"} response`, {
@@ -11014,7 +11015,8 @@ var LicenseClient = class {
11014
11015
  expiry: new Date(payload.exp * 1e3),
11015
11016
  machinesUsed: result.machinesUsed,
11016
11017
  machineLimit: result.machineLimit,
11017
- features: payload.features
11018
+ features: payload.features,
11019
+ latestVersion: result.latestVersion
11018
11020
  };
11019
11021
  } catch (err) {
11020
11022
  const msg = err.message;
@@ -11111,13 +11113,47 @@ function toLicenseInfo(payload, cached, normalizedKey, source) {
11111
11113
  // Prefer the signed `features` claim (authenticated) over the unauthenticated
11112
11114
  // sidecar — falls back to the sidecar only for caches written before the
11113
11115
  // payload was threaded through here.
11114
- features: payload.features ?? cached.features
11116
+ features: payload.features ?? cached.features,
11117
+ latestVersion: cached.latestVersion
11115
11118
  };
11116
11119
  }
11117
11120
  function normalizeUrl(url) {
11118
11121
  return url.endsWith("/") ? url.slice(0, -1) : url;
11119
11122
  }
11120
11123
 
11124
+ // src/license/update-notice.ts
11125
+ init_cjs_shims();
11126
+
11127
+ // src/license/version.ts
11128
+ init_cjs_shims();
11129
+ function parseTriple(v) {
11130
+ if (!v) return null;
11131
+ const m = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(v.trim());
11132
+ if (!m) return null;
11133
+ return [Number(m[1]), Number(m[2]), Number(m[3])];
11134
+ }
11135
+ function isNewer(latest, current) {
11136
+ const l = parseTriple(latest);
11137
+ const c = parseTriple(current);
11138
+ if (!l || !c) return false;
11139
+ if (l[0] !== c[0]) return l[0] > c[0];
11140
+ if (l[1] !== c[1]) return l[1] > c[1];
11141
+ return l[2] > c[2];
11142
+ }
11143
+
11144
+ // src/license/update-notice.ts
11145
+ function maybePrintUpdateNotice(licenseInfo, currentVersion) {
11146
+ try {
11147
+ const latest = licenseInfo?.latestVersion;
11148
+ if (!latest || !isNewer(latest, currentVersion)) return;
11149
+ const shown = latest.replace(/[^\w.+-]/g, "");
11150
+ logger.info(
11151
+ `Update available: ${currentVersion} -> ${shown}. Run: npm i -D @reportforge/playwright-pdf@latest`
11152
+ );
11153
+ } catch {
11154
+ }
11155
+ }
11156
+
11121
11157
  // src/analysis/index.ts
11122
11158
  init_cjs_shims();
11123
11159
 
@@ -14119,8 +14155,8 @@ var PdfReporter = class {
14119
14155
  this.liveConsole = false;
14120
14156
  this.options = parseOptions(rawOptions);
14121
14157
  this.dataCollector = new DataCollector(this.options.capture);
14122
- const version = true ? "0.16.0" : "0.x";
14123
- logger.info(`@reportforge/playwright-pdf v${version} initialised`);
14158
+ this.version = true ? "0.17.0" : "0.x";
14159
+ logger.info(`@reportforge/playwright-pdf v${this.version} initialised`);
14124
14160
  this.licenseClient = new LicenseClient({
14125
14161
  licenseKey: this.options.licenseKey,
14126
14162
  serverUrl: this.options.serverUrl,
@@ -14193,7 +14229,10 @@ var PdfReporter = class {
14193
14229
  const licenseInfo = await this.license();
14194
14230
  if (!licenseInfo) return;
14195
14231
  const collected = this._collectData(result);
14196
- if (!collected) return;
14232
+ if (!collected) {
14233
+ maybePrintUpdateNotice(licenseInfo, this.version);
14234
+ return;
14235
+ }
14197
14236
  if (this.options.showTrend && collected.stats.total > 0) {
14198
14237
  try {
14199
14238
  this._appendTrend(collected);
@@ -14218,6 +14257,7 @@ var PdfReporter = class {
14218
14257
  const sender = new NotificationSender();
14219
14258
  await sender.sendAll(reportData, this.options.notify, pdfPaths);
14220
14259
  }
14260
+ maybePrintUpdateNotice(licenseInfo, this.version);
14221
14261
  }
14222
14262
  _collectData(result) {
14223
14263
  if (this.options.shardResults && this.options.shardResults.length > 0) {
package/dist/index.mjs CHANGED
@@ -10996,7 +10996,8 @@ var LicenseClient = class {
10996
10996
  fingerprintHash: this.fingerprint.hash,
10997
10997
  machinesUsed: result.machinesUsed,
10998
10998
  machineLimit: result.machineLimit,
10999
- features: payload.features
10999
+ features: payload.features,
11000
+ latestVersion: result.latestVersion
11000
11001
  };
11001
11002
  writeCache(entry);
11002
11003
  logger.debug(`license path=${cached ? "refresh" : "activate"} response`, {
@@ -11015,7 +11016,8 @@ var LicenseClient = class {
11015
11016
  expiry: new Date(payload.exp * 1e3),
11016
11017
  machinesUsed: result.machinesUsed,
11017
11018
  machineLimit: result.machineLimit,
11018
- features: payload.features
11019
+ features: payload.features,
11020
+ latestVersion: result.latestVersion
11019
11021
  };
11020
11022
  } catch (err) {
11021
11023
  const msg = err.message;
@@ -11112,13 +11114,47 @@ function toLicenseInfo(payload, cached, normalizedKey, source) {
11112
11114
  // Prefer the signed `features` claim (authenticated) over the unauthenticated
11113
11115
  // sidecar — falls back to the sidecar only for caches written before the
11114
11116
  // payload was threaded through here.
11115
- features: payload.features ?? cached.features
11117
+ features: payload.features ?? cached.features,
11118
+ latestVersion: cached.latestVersion
11116
11119
  };
11117
11120
  }
11118
11121
  function normalizeUrl(url) {
11119
11122
  return url.endsWith("/") ? url.slice(0, -1) : url;
11120
11123
  }
11121
11124
 
11125
+ // src/license/update-notice.ts
11126
+ init_esm_shims();
11127
+
11128
+ // src/license/version.ts
11129
+ init_esm_shims();
11130
+ function parseTriple(v) {
11131
+ if (!v) return null;
11132
+ const m = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(v.trim());
11133
+ if (!m) return null;
11134
+ return [Number(m[1]), Number(m[2]), Number(m[3])];
11135
+ }
11136
+ function isNewer(latest, current) {
11137
+ const l = parseTriple(latest);
11138
+ const c = parseTriple(current);
11139
+ if (!l || !c) return false;
11140
+ if (l[0] !== c[0]) return l[0] > c[0];
11141
+ if (l[1] !== c[1]) return l[1] > c[1];
11142
+ return l[2] > c[2];
11143
+ }
11144
+
11145
+ // src/license/update-notice.ts
11146
+ function maybePrintUpdateNotice(licenseInfo, currentVersion) {
11147
+ try {
11148
+ const latest = licenseInfo?.latestVersion;
11149
+ if (!latest || !isNewer(latest, currentVersion)) return;
11150
+ const shown = latest.replace(/[^\w.+-]/g, "");
11151
+ logger.info(
11152
+ `Update available: ${currentVersion} -> ${shown}. Run: npm i -D @reportforge/playwright-pdf@latest`
11153
+ );
11154
+ } catch {
11155
+ }
11156
+ }
11157
+
11122
11158
  // src/analysis/index.ts
11123
11159
  init_esm_shims();
11124
11160
 
@@ -14120,8 +14156,8 @@ var PdfReporter = class {
14120
14156
  this.liveConsole = false;
14121
14157
  this.options = parseOptions(rawOptions);
14122
14158
  this.dataCollector = new DataCollector(this.options.capture);
14123
- const version = true ? "0.16.0" : "0.x";
14124
- logger.info(`@reportforge/playwright-pdf v${version} initialised`);
14159
+ this.version = true ? "0.17.0" : "0.x";
14160
+ logger.info(`@reportforge/playwright-pdf v${this.version} initialised`);
14125
14161
  this.licenseClient = new LicenseClient({
14126
14162
  licenseKey: this.options.licenseKey,
14127
14163
  serverUrl: this.options.serverUrl,
@@ -14194,7 +14230,10 @@ var PdfReporter = class {
14194
14230
  const licenseInfo = await this.license();
14195
14231
  if (!licenseInfo) return;
14196
14232
  const collected = this._collectData(result);
14197
- if (!collected) return;
14233
+ if (!collected) {
14234
+ maybePrintUpdateNotice(licenseInfo, this.version);
14235
+ return;
14236
+ }
14198
14237
  if (this.options.showTrend && collected.stats.total > 0) {
14199
14238
  try {
14200
14239
  this._appendTrend(collected);
@@ -14219,6 +14258,7 @@ var PdfReporter = class {
14219
14258
  const sender = new NotificationSender();
14220
14259
  await sender.sendAll(reportData, this.options.notify, pdfPaths);
14221
14260
  }
14261
+ maybePrintUpdateNotice(licenseInfo, this.version);
14222
14262
  }
14223
14263
  _collectData(result) {
14224
14264
  if (this.options.shardResults && this.options.shardResults.length > 0) {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@reportforge/playwright-pdf",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Playwright Test reporter that generates designed PDF reports: minimal, detailed, and executive templates with CI/CD integrations",
5
- "license": "MIT",
5
+ "license": "Elastic-2.0",
6
6
  "author": "ReportForge",
7
7
  "homepage": "https://reportforge.org",
8
8
  "repository": {