nestjs-puppeteer 2.1.0 → 2.3.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.
@@ -0,0 +1,81 @@
1
+ # Beads - AI-Native Issue Tracking
2
+
3
+ Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
4
+
5
+ ## What is Beads?
6
+
7
+ Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
8
+
9
+ **Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
10
+
11
+ ## Quick Start
12
+
13
+ ### Essential Commands
14
+
15
+ ```bash
16
+ # Create new issues
17
+ bd create "Add user authentication"
18
+
19
+ # View all issues
20
+ bd list
21
+
22
+ # View issue details
23
+ bd show <issue-id>
24
+
25
+ # Update issue status
26
+ bd update <issue-id> --claim
27
+ bd update <issue-id> --status done
28
+
29
+ # Sync with Dolt remote
30
+ bd dolt push
31
+ ```
32
+
33
+ ### Working with Issues
34
+
35
+ Issues in Beads are:
36
+ - **Git-native**: Stored in Dolt database with version control and branching
37
+ - **AI-friendly**: CLI-first design works perfectly with AI coding agents
38
+ - **Branch-aware**: Issues can follow your branch workflow
39
+ - **Always in sync**: Auto-syncs with your commits
40
+
41
+ ## Why Beads?
42
+
43
+ ✨ **AI-Native Design**
44
+ - Built specifically for AI-assisted development workflows
45
+ - CLI-first interface works seamlessly with AI coding agents
46
+ - No context switching to web UIs
47
+
48
+ 🚀 **Developer Focused**
49
+ - Issues live in your repo, right next to your code
50
+ - Works offline, syncs when you push
51
+ - Fast, lightweight, and stays out of your way
52
+
53
+ 🔧 **Git Integration**
54
+ - Automatic sync with git commits
55
+ - Branch-aware issue tracking
56
+ - Dolt-native three-way merge resolution
57
+
58
+ ## Get Started with Beads
59
+
60
+ Try Beads in your own projects:
61
+
62
+ ```bash
63
+ # Install Beads
64
+ curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
65
+
66
+ # Initialize in your repo
67
+ bd init
68
+
69
+ # Create your first issue
70
+ bd create "Try out Beads"
71
+ ```
72
+
73
+ ## Learn More
74
+
75
+ - **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
76
+ - **Quick Start Guide**: Run `bd quickstart`
77
+ - **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
78
+
79
+ ---
80
+
81
+ *Beads: Issue tracking that moves at the speed of thought* ⚡
@@ -0,0 +1,56 @@
1
+ # Beads Configuration File
2
+ # This file configures default behavior for all bd commands in this repository
3
+ # All settings can also be set via environment variables (BD_* prefix)
4
+ # or overridden with command-line flags
5
+
6
+ # Issue prefix for this repository (used by bd init)
7
+ # If not set, bd init will auto-detect from directory name
8
+ # Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
9
+ # issue-prefix: ""
10
+
11
+ # Use no-db mode: JSONL-only, no Dolt database
12
+ # When true, bd will use .beads/issues.jsonl as the source of truth
13
+ # no-db: false
14
+
15
+ # Enable JSON output by default
16
+ # json: false
17
+
18
+ # Feedback title formatting for mutating commands (create/update/close/dep/edit)
19
+ # 0 = hide titles, N > 0 = truncate to N characters
20
+ # output:
21
+ # title-length: 255
22
+
23
+ # Default actor for audit trails (overridden by BEADS_ACTOR or --actor)
24
+ # actor: ""
25
+
26
+ # Export events (audit trail) to .beads/events.jsonl on each flush/sync
27
+ # When enabled, new events are appended incrementally using a high-water mark.
28
+ # Use 'bd export --events' to trigger manually regardless of this setting.
29
+ # events-export: false
30
+
31
+ # Multi-repo configuration (experimental - bd-307)
32
+ # Allows hydrating from multiple repositories and routing writes to the correct database
33
+ # repos:
34
+ # primary: "." # Primary repo (where this database lives)
35
+ # additional: # Additional repos to hydrate from (read-only)
36
+ # - ~/beads-planning # Personal planning repo
37
+ # - ~/work-planning # Work planning repo
38
+
39
+ # JSONL backup (periodic export for off-machine recovery)
40
+ # Auto-enabled when a git remote exists. Override explicitly:
41
+ # backup:
42
+ # enabled: false # Disable auto-backup entirely
43
+ # interval: 15m # Minimum time between auto-exports
44
+ # git-push: false # Disable git push (export locally only)
45
+ # git-repo: "" # Separate git repo for backups (default: project repo)
46
+
47
+ # Integration settings (access with 'bd config get/set')
48
+ # These are stored in the database, not in this file:
49
+ # - jira.url
50
+ # - jira.project
51
+ # - linear.url
52
+ # - linear.api-key
53
+ # - github.org
54
+ # - github.repo
55
+
56
+ sync.remote: "git+https://github.com/oblakstudio/nestjs-puppeteer"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
4
+
5
+ # --- BEGIN BEADS INTEGRATION v1.0.2 ---
6
+ # This section is managed by beads. Do not remove these markers.
7
+ if command -v bd >/dev/null 2>&1; then
8
+ export BD_GIT_HOOK=1
9
+ _bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
10
+ if command -v timeout >/dev/null 2>&1; then
11
+ timeout "$_bd_timeout" bd hooks run post-checkout "$@"
12
+ _bd_exit=$?
13
+ if [ $_bd_exit -eq 124 ]; then
14
+ echo >&2 "beads: hook 'post-checkout' timed out after ${_bd_timeout}s — continuing without beads"
15
+ _bd_exit=0
16
+ fi
17
+ else
18
+ bd hooks run post-checkout "$@"
19
+ _bd_exit=$?
20
+ fi
21
+ if [ $_bd_exit -eq 3 ]; then
22
+ echo >&2 "beads: database not initialized — skipping hook 'post-checkout'"
23
+ _bd_exit=0
24
+ fi
25
+ if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
26
+ fi
27
+ # --- END BEADS INTEGRATION v1.0.2 ---
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
4
+
5
+ # --- BEGIN BEADS INTEGRATION v1.0.2 ---
6
+ # This section is managed by beads. Do not remove these markers.
7
+ if command -v bd >/dev/null 2>&1; then
8
+ export BD_GIT_HOOK=1
9
+ _bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
10
+ if command -v timeout >/dev/null 2>&1; then
11
+ timeout "$_bd_timeout" bd hooks run post-merge "$@"
12
+ _bd_exit=$?
13
+ if [ $_bd_exit -eq 124 ]; then
14
+ echo >&2 "beads: hook 'post-merge' timed out after ${_bd_timeout}s — continuing without beads"
15
+ _bd_exit=0
16
+ fi
17
+ else
18
+ bd hooks run post-merge "$@"
19
+ _bd_exit=$?
20
+ fi
21
+ if [ $_bd_exit -eq 3 ]; then
22
+ echo >&2 "beads: database not initialized — skipping hook 'post-merge'"
23
+ _bd_exit=0
24
+ fi
25
+ if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
26
+ fi
27
+ # --- END BEADS INTEGRATION v1.0.2 ---
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
4
+
5
+ # --- BEGIN BEADS INTEGRATION v1.0.2 ---
6
+ # This section is managed by beads. Do not remove these markers.
7
+ if command -v bd >/dev/null 2>&1; then
8
+ export BD_GIT_HOOK=1
9
+ _bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
10
+ if command -v timeout >/dev/null 2>&1; then
11
+ timeout "$_bd_timeout" bd hooks run pre-commit "$@"
12
+ _bd_exit=$?
13
+ if [ $_bd_exit -eq 124 ]; then
14
+ echo >&2 "beads: hook 'pre-commit' timed out after ${_bd_timeout}s — continuing without beads"
15
+ _bd_exit=0
16
+ fi
17
+ else
18
+ bd hooks run pre-commit "$@"
19
+ _bd_exit=$?
20
+ fi
21
+ if [ $_bd_exit -eq 3 ]; then
22
+ echo >&2 "beads: database not initialized — skipping hook 'pre-commit'"
23
+ _bd_exit=0
24
+ fi
25
+ if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
26
+ fi
27
+ # --- END BEADS INTEGRATION v1.0.2 ---
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
4
+
5
+ # --- BEGIN BEADS INTEGRATION v1.0.2 ---
6
+ # This section is managed by beads. Do not remove these markers.
7
+ if command -v bd >/dev/null 2>&1; then
8
+ export BD_GIT_HOOK=1
9
+ _bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
10
+ if command -v timeout >/dev/null 2>&1; then
11
+ timeout "$_bd_timeout" bd hooks run pre-push "$@"
12
+ _bd_exit=$?
13
+ if [ $_bd_exit -eq 124 ]; then
14
+ echo >&2 "beads: hook 'pre-push' timed out after ${_bd_timeout}s — continuing without beads"
15
+ _bd_exit=0
16
+ fi
17
+ else
18
+ bd hooks run pre-push "$@"
19
+ _bd_exit=$?
20
+ fi
21
+ if [ $_bd_exit -eq 3 ]; then
22
+ echo >&2 "beads: database not initialized — skipping hook 'pre-push'"
23
+ _bd_exit=0
24
+ fi
25
+ if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
26
+ fi
27
+ # --- END BEADS INTEGRATION v1.0.2 ---
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env sh
2
+ # Injected by beads (GH#3132): husky helper layout not mirrored into this dir.
3
+ export PATH="$PWD/node_modules/.bin:$PATH"
4
+
5
+ # --- BEGIN BEADS INTEGRATION v1.0.2 ---
6
+ # This section is managed by beads. Do not remove these markers.
7
+ if command -v bd >/dev/null 2>&1; then
8
+ export BD_GIT_HOOK=1
9
+ _bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
10
+ if command -v timeout >/dev/null 2>&1; then
11
+ timeout "$_bd_timeout" bd hooks run prepare-commit-msg "$@"
12
+ _bd_exit=$?
13
+ if [ $_bd_exit -eq 124 ]; then
14
+ echo >&2 "beads: hook 'prepare-commit-msg' timed out after ${_bd_timeout}s — continuing without beads"
15
+ _bd_exit=0
16
+ fi
17
+ else
18
+ bd hooks run prepare-commit-msg "$@"
19
+ _bd_exit=$?
20
+ fi
21
+ if [ $_bd_exit -eq 3 ]; then
22
+ echo >&2 "beads: database not initialized — skipping hook 'prepare-commit-msg'"
23
+ _bd_exit=0
24
+ fi
25
+ if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
26
+ fi
27
+ # --- END BEADS INTEGRATION v1.0.2 ---
@@ -0,0 +1,10 @@
1
+ {"id":"nestjs-puppeteer-cg9","title":"Handle puppeteer-extra global plugin state — dedupe + document caveat","description":"lib/puppeteer-core.module.ts:45 calls puppeteer.use(plugin) per module options. puppeteer-extra is a global singleton so plugins from different forRoot() calls bleed across browsers. Repeated module re-registration in tests stacks plugins. At minimum: dedupe (skip if already registered) and add a JSDoc warning on PuppeteerModuleOptions.plugins. Investigate per-browser scoping if puppeteer-extra exposes a non-singleton API.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:11:06Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T09:46:33Z","started_at":"2026-05-09T09:41:54Z","closed_at":"2026-05-09T09:46:33Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
2
+ {"id":"nestjs-puppeteer-x6e","title":"Verify and fix multi-browser shutdown closes every Browser instance","description":"lib/puppeteer-core.module.ts:103-114 onApplicationShutdown resolves 'getBrowserToken(this.options)' from its own moduleRef. With multiple PuppeteerCoreModule instances, each instance closes only its own browser. Add a multi-browser e2e spec asserting both browsers actually disconnect on app close. Fix any leak found.","notes":"Investigation: added tests/e2e/puppeteer-multi-browser.spec.ts covering both forRoot and forRootAsync with two distinct browser instances. Verified via browser.process().pid that Puppeteer spawns separate Chromium processes per instance and that browser.connected flips to false on app.close() for both. No leak found: each PuppeteerCoreModule instance receives its own scoped PUPPETEER_MODULE_OPTIONS, so getBrowserToken(this.options) in onApplicationShutdown resolves the correct per-instance browser token. Closing as verified-by-test.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:10:59Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T09:22:29Z","started_at":"2026-05-09T09:16:55Z","closed_at":"2026-05-09T09:22:29Z","close_reason":"Verified by new e2e spec; per-instance shutdown works correctly.","dependency_count":0,"dependent_count":0,"comment_count":0}
3
+ {"id":"nestjs-puppeteer-5cn","title":"Tune up CI workflows: release.yml + pull_request.yml","description":"Both GitHub Actions workflows have drifted from current repo layout and modern CI practice.\n\nrelease.yml is broken at job-time:\n- runs npm test (no such script in package.json)\n- npm clean-install in test/ directory which does not exist\n- extra_plugins: @semantic-release/github duplicates plugin already in .releaserc\n- triggers on beta and *.x branches that .releaserc does not configure\n\npull_request.yml drifted:\n- Node 21 in matrix (EOL)\n- job named 'test' actually only does lint and audit; lint depends on test_matrix unnecessarily\n- push: branches: [renovate/**] trigger duplicates the pull_request trigger Renovate already fires\n- coverage re-runs full Chromium e2e on every PR just to upload Codecov\n\nDecisions (confirmed with user):\n- Trust merge queue; release runs build + publish only\n- Trim release branches to master + next\n- Node matrix: 20, 22, 24\n- Coverage only on merge_group\n\nPlan file: ~/.claude/plans/i-did-some-changes-mellow-hare.md","status":"closed","priority":2,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T10:39:27Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T10:40:18Z","started_at":"2026-05-09T10:39:35Z","closed_at":"2026-05-09T10:40:18Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
4
+ {"id":"nestjs-puppeteer-ro3","title":"Audit major dependency bumps flagged by ncu","description":"Several deps have major-version bumps available. Each needs review of breaking changes and CI impact before applying:\n\n- @commitlint/cli, @commitlint/config-angular: 18 → 21\n- @types/jest: 29 → 30 (paired with jest 30)\n- @types/node: ^20 → ^25\n- @types/supertest: 6 → 7 (paired with supertest 7)\n- @typescript-eslint/eslint-plugin, @typescript-eslint/parser: 6 → 8\n- eslint: 8 → 10 (flat config migration required)\n- eslint-config-prettier: 9 → 10\n- jest: 29 → 30\n- lint-staged: ^15 → ^17\n- supertest: 6 → 7\n- typescript: ^5 → ^6\n\nNOTE: puppeteer ^23 → ^24 is being handled separately and is NOT in scope for this issue.\n\nApplied safe bumps in nestjs-puppeteer-qim.","status":"open","priority":2,"issue_type":"task","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:46:04Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T10:00:21Z","dependency_count":0,"dependent_count":0,"comment_count":0}
5
+ {"id":"nestjs-puppeteer-qim","title":"Dependency sanity check and bumps","description":"Audit dependencies, devDependencies, and peerDependencies in package.json against the current registry. Identify outdated packages (npm outdated). For each: classify as safe-bump (patch/minor) vs major (needs review). Apply safe bumps in one commit; flag majors with a short note for the user to decide. Re-run lint, build, and e2e after bumping. Do NOT bump peerDependency ranges without confirming the public-API impact.","status":"closed","priority":2,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:11:29Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T09:46:33Z","started_at":"2026-05-09T09:43:41Z","closed_at":"2026-05-09T09:46:33Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
6
+ {"id":"nestjs-puppeteer-abp","title":"Validate forRootAsync requires one of useFactory/useClass/useExisting","description":"lib/puppeteer-core.module.ts:145-147 type-asserts (options.useClass || options.useExisting) as Type — if all three of useFactory/useClass/useExisting are missing, the inject array contains undefined and DI fails with a confusing error. Throw an explicit 'PuppeteerModule.forRootAsync requires one of useFactory, useClass, or useExisting' early.","status":"closed","priority":2,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:11:19Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T09:26:38Z","started_at":"2026-05-09T09:24:56Z","closed_at":"2026-05-09T09:26:38Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
7
+ {"id":"nestjs-puppeteer-2a4","title":"Tighten public types — drop any from forRoot and async options","description":"lib/puppeteer-core.module.ts:35 has 'forRoot(options: any = {})' — should be 'PuppeteerModuleOptions'. lib/interfaces/puppeteer-options.interface.ts:33-34 has 'useFactory?: (...args: any[])' and 'inject?: any[]' — should match @nestjs/typeorm convention using InjectionToken[] / OptionalFactoryDependency. Pure type-tightening, no runtime change.","status":"closed","priority":2,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:10:45Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T09:13:06Z","started_at":"2026-05-09T09:11:35Z","closed_at":"2026-05-09T09:13:06Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
8
+ {"id":"nestjs-puppeteer-y6o","title":"Modernize puppeteer launch-options type for v23 compatibility","description":"lib/interfaces/puppeteer-options.interface.ts uses Partial\u003cPuppeteerNodeLaunchOptions\u003e. Puppeteer v23 renamed this to LaunchOptions. Pick a type strategy that works across the peer-dep range '^21 || ^22 || ^23' without breaking consumers. Verify in a clean install against each major.","status":"closed","priority":3,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:11:25Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T10:07:47Z","started_at":"2026-05-09T10:01:10Z","closed_at":"2026-05-09T10:07:47Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
9
+ {"id":"nestjs-puppeteer-az3","title":"Detect duplicate browser name registration","description":"lib/puppeteer-core.module.ts:54,84 registers a browser provider keyed by getBrowserToken(options). Two forRoot() calls with the same 'name' silently overwrite the DI token — no warning. Throw a clear error or log a warning when a duplicate name is detected (track registered names in a module-level Set).","status":"closed","priority":3,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:11:17Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T10:07:47Z","started_at":"2026-05-09T10:01:10Z","closed_at":"2026-05-09T10:07:47Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
10
+ {"id":"nestjs-puppeteer-ct4","title":"Improve onApplicationShutdown error logging (preserve stack)","description":"lib/puppeteer-core.module.ts:111-113 currently logs 'e?.message' only — drops stack and breaks for non-Error throws. Pass the full error to this.logger.error so the Nest logger can format it properly.","status":"closed","priority":3,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-05-09T09:11:08Z","created_by":"Sibin Grasic","updated_at":"2026-05-09T09:30:13Z","started_at":"2026-05-09T09:29:15Z","closed_at":"2026-05-09T09:30:13Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
@@ -0,0 +1,7 @@
1
+ {
2
+ "database": "dolt",
3
+ "backend": "dolt",
4
+ "dolt_mode": "embedded",
5
+ "dolt_database": "nestjs_puppeteer",
6
+ "project_id": "49c89952-9557-4a98-a3b1-7ad2f04c402b"
7
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "hooks": {
3
+ "PreCompact": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "command": "bd prime",
8
+ "type": "command"
9
+ }
10
+ ],
11
+ "matcher": ""
12
+ }
13
+ ],
14
+ "SessionStart": [
15
+ {
16
+ "hooks": [
17
+ {
18
+ "command": "bd prime",
19
+ "type": "command"
20
+ }
21
+ ],
22
+ "matcher": ""
23
+ }
24
+ ]
25
+ }
26
+ }
package/AGENTS.md ADDED
@@ -0,0 +1,88 @@
1
+ # Agent Instructions
2
+
3
+ This project uses **bd** (beads) for issue tracking. Run `bd prime` for full workflow context.
4
+
5
+ ## Quick Reference
6
+
7
+ ```bash
8
+ bd ready # Find available work
9
+ bd show <id> # View issue details
10
+ bd update <id> --claim # Claim work atomically
11
+ bd close <id> # Complete work
12
+ bd dolt push # Push beads data to remote
13
+ ```
14
+
15
+ ## Non-Interactive Shell Commands
16
+
17
+ **ALWAYS use non-interactive flags** with file operations to avoid hanging on confirmation prompts.
18
+
19
+ Shell commands like `cp`, `mv`, and `rm` may be aliased to include `-i` (interactive) mode on some systems, causing the agent to hang indefinitely waiting for y/n input.
20
+
21
+ **Use these forms instead:**
22
+ ```bash
23
+ # Force overwrite without prompting
24
+ cp -f source dest # NOT: cp source dest
25
+ mv -f source dest # NOT: mv source dest
26
+ rm -f file # NOT: rm file
27
+
28
+ # For recursive operations
29
+ rm -rf directory # NOT: rm -r directory
30
+ cp -rf source dest # NOT: cp -r source dest
31
+ ```
32
+
33
+ **Other commands that may prompt:**
34
+ - `scp` - use `-o BatchMode=yes` for non-interactive
35
+ - `ssh` - use `-o BatchMode=yes` to fail instead of prompting
36
+ - `apt-get` - use `-y` flag
37
+ - `brew` - use `HOMEBREW_NO_AUTO_UPDATE=1` env var
38
+
39
+ <!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:ca08a54f -->
40
+ ## Beads Issue Tracker
41
+
42
+ This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands.
43
+
44
+ ### Quick Reference
45
+
46
+ ```bash
47
+ bd ready # Find available work
48
+ bd show <id> # View issue details
49
+ bd update <id> --claim # Claim work
50
+ bd close <id> # Complete work
51
+ ```
52
+
53
+ ### Rules
54
+
55
+ - Use `bd` for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists
56
+ - Run `bd prime` for detailed command reference and session close protocol
57
+ - Use `bd remember` for persistent knowledge — do NOT use MEMORY.md files
58
+
59
+ ## Session Completion
60
+
61
+ **When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
62
+
63
+ **MANDATORY WORKFLOW:**
64
+
65
+ 1. **File issues for remaining work** - Create issues for anything that needs follow-up
66
+ 2. **Run quality gates** (if code changed) - Tests, linters, builds
67
+ 3. **Update issue status** - Close finished work, update in-progress items
68
+ 4. **PUSH TO REMOTE** - This is MANDATORY:
69
+ ```bash
70
+ git pull --rebase
71
+ bd dolt push
72
+ git push
73
+ git status # MUST show "up to date with origin"
74
+ ```
75
+ 5. **Clean up** - Clear stashes, prune remote branches
76
+ 6. **Verify** - All changes committed AND pushed
77
+ 7. **Hand off** - Provide context for next session
78
+
79
+ **CRITICAL RULES:**
80
+ - Work is NOT complete until `git push` succeeds
81
+ - NEVER stop before pushing - that leaves work stranded locally
82
+ - NEVER say "ready to push when you are" - YOU must push
83
+ - If push fails, resolve and retry until it succeeds
84
+ <!-- END BEADS INTEGRATION -->
85
+
86
+ ## Commit Authorship
87
+
88
+ **NEVER** add `Co-Authored-By: <LLM>` (or any equivalent LLM-attribution trailer) to git commits in this repo. This applies to every commit, every branch, every PR — no exceptions, even if the harness suggests it by default. Commits are authored by the human running the session.
package/CLAUDE.md ADDED
@@ -0,0 +1,106 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ <!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:ca08a54f -->
6
+ ## Beads Issue Tracker
7
+
8
+ This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands.
9
+
10
+ ### Quick Reference
11
+
12
+ ```bash
13
+ bd ready # Find available work
14
+ bd show <id> # View issue details
15
+ bd update <id> --claim # Claim work
16
+ bd close <id> # Complete work
17
+ ```
18
+
19
+ ### Rules
20
+
21
+ - Use `bd` for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists
22
+ - Run `bd prime` for detailed command reference and session close protocol
23
+ - Use `bd remember` for persistent knowledge — do NOT use MEMORY.md files
24
+
25
+ ## Session Completion
26
+
27
+ **When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
28
+
29
+ **MANDATORY WORKFLOW:**
30
+
31
+ 1. **File issues for remaining work** - Create issues for anything that needs follow-up
32
+ 2. **Run quality gates** (if code changed) - Tests, linters, builds
33
+ 3. **Update issue status** - Close finished work, update in-progress items
34
+ 4. **PUSH TO REMOTE** - This is MANDATORY:
35
+ ```bash
36
+ git pull --rebase
37
+ bd dolt push
38
+ git push
39
+ git status # MUST show "up to date with origin"
40
+ ```
41
+ 5. **Clean up** - Clear stashes, prune remote branches
42
+ 6. **Verify** - All changes committed AND pushed
43
+ 7. **Hand off** - Provide context for next session
44
+
45
+ **CRITICAL RULES:**
46
+ - Work is NOT complete until `git push` succeeds
47
+ - NEVER stop before pushing - that leaves work stranded locally
48
+ - NEVER say "ready to push when you are" - YOU must push
49
+ - If push fails, resolve and retry until it succeeds
50
+ <!-- END BEADS INTEGRATION -->
51
+
52
+ ## Commit Authorship
53
+
54
+ **NEVER** add `Co-Authored-By: <LLM>` (or any equivalent LLM-attribution trailer) to git commits in this repo. This applies to every commit, every branch, every PR — no exceptions, even if the harness suggests it by default. Commits are authored by the human running the session.
55
+
56
+ ## Build & Test
57
+
58
+ Node.js >= 20 (see `.nvmrc`). Package is published as `nestjs-puppeteer`; source lives in `lib/` and compiles to `dist/`. Peer deps span `@nestjs/common`/`@nestjs/core` `^10 || ^11` and `puppeteer` `^21 || ^22 || ^23` — public API and types must stay compatible across all of these.
59
+
60
+ ```bash
61
+ npm install
62
+ npm run build # rm -rf dist && tsc -p tsconfig.json
63
+ npm run watch # incremental tsc
64
+ npm run lint # eslint 'lib/**/*.ts' --fix
65
+ npm run format # prettier --write "**/*.ts"
66
+ npm run test:e2e # jest --config ./tests/jest-e2e.json --runInBand
67
+ npm run test:e2e:cov # with coverage
68
+ npm run test:e2e:dev # watch mode
69
+
70
+ # Run a single e2e spec
71
+ npx jest --config ./tests/jest-e2e.json --runInBand tests/e2e/puppeteer.spec.ts
72
+ ```
73
+
74
+ There are no unit tests — all tests are e2e specs in `tests/e2e/*.spec.ts` that boot a NestJS app via `@nestjs/testing` and drive it with `supertest`. They launch real Chromium, so they need a working Puppeteer install. CI runs them under AppArmor (`aa-exec --profile=chrome`) on Ubuntu — locally that prefix is not needed.
75
+
76
+ The `stealth-check` test in `tests/e2e/puppeteer-with-plugin.spec.ts` hits `https://arh.antoinevastel.com/bots/areyouheadless` and requires network access.
77
+
78
+ ## Architecture Overview
79
+
80
+ This is a thin NestJS wrapper around `puppeteer-extra` that exposes a `Browser` (and named `Page`s) through Nest's DI container. The whole library is ~6 small files in `lib/`.
81
+
82
+ **Two-module pattern (mirrors `@nestjs/typeorm`, `@nestjs/mongoose`, etc.):**
83
+
84
+ - `PuppeteerModule` (`lib/puppeteer.module.ts`) — public façade with three statics: `forRoot`, `forRootAsync`, `forFeature`. Holds no state; delegates to the core module.
85
+ - `PuppeteerCoreModule` (`lib/puppeteer-core.module.ts`) — `@Global()`, owns the singleton `Browser` and the plugin registration. Implements `OnApplicationShutdown` to call `browser.close()` cleanly. The async branch (`forRootAsync`) supports `useFactory` / `useClass` / `useExisting` via `PuppeteerOptionsFactory.createPuppeteerOptions(name?)`.
86
+
87
+ **DI token scheme (`lib/common/puppeteer.utils.ts`):**
88
+
89
+ - Default (unnamed) browser → injected as the `Browser` class itself: `@InjectBrowser()`.
90
+ - Named browser → string token `\`${name}Browser\``: `@InjectBrowser('foo')`.
91
+ - Page token: `\`${browserPrefix}${page}Page\``, where `browserPrefix` is `''` for the default browser and `\`${name}_\`` otherwise. Built by `getPageToken` and consumed by `@InjectPage(page, browser?)`.
92
+
93
+ This is why `forFeature(pages, browser?)` must receive the *same* browser identifier (string name or options object) used at `forRoot` — the tokens are derived from it, not looked up. Mismatched names produce DI resolution errors, not runtime warnings.
94
+
95
+ **Plugin handling:** `options.plugins` is an array of `PuppeteerExtraPlugin`s. The core module calls `puppeteer.use(plugin)` for each before launching. Because `puppeteer-extra` mutates global state, plugins registered on one browser affect any subsequent `puppeteer.launch()` in the same process — keep this in mind when adding multi-browser tests.
96
+
97
+ > Per README: most `puppeteer-extra` plugins are **not compatible** with Chrome's "new headless" mode. When using plugins (e.g. stealth), pass `headless: true`, not `headless: 'new'`.
98
+
99
+ **Public API surface** (re-exported from `lib/index.ts`): `PuppeteerModule`, `PuppeteerCoreModule`, decorators (`InjectBrowser`, `InjectPage`), token helpers (`getBrowserToken`, `getPageToken`, `getBrowserPrefix`), constants, and the `PuppeteerModuleOptions` / `PuppeteerModuleAsyncOptions` / `PuppeteerOptionsFactory` interfaces. Treat anything exported here as a breaking-change surface.
100
+
101
+ ## Conventions & Patterns
102
+
103
+ - **Commits:** Angular conventional commits enforced by commitlint + Husky (`.commitlintrc.json`). Allowed types: `build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test, sample`. Subject case is permissive (sentence/start/pascal/upper/lower) but a type prefix is required. Releases are fully automated by `semantic-release` on `master` and `next` — version bumps and CHANGELOG come from commit messages, so be deliberate about `feat:` vs `fix:` vs `chore:`.
104
+ - **TypeScript:** `strict: true`, `target: ES2019`, `module: commonjs`, decorators + `emitDecoratorMetadata` on. `rootDir` is `lib/`; tests live outside it and are excluded from the build.
105
+ - **Tests are intentionally outside `rootDir`** — they import the library via relative paths (`'../../lib'`), not via the package name. Don't add a path alias just to make this prettier; it would break `tsc` output.
106
+ - **Non-interactive shell commands:** `cp`, `mv`, `rm` may be aliased to `-i` mode. Use `-f` (or `-rf`) so commands don't hang waiting on y/n. See `AGENTS.md` for the full list.
package/README.md CHANGED
@@ -3,12 +3,14 @@
3
3
  # nestjs-puppeteer
4
4
  Puppeteer module for Nest framework (node.js)
5
5
 
6
- [![npm](https://img.shields.io/npm/v/nestjs-puppeteer?logo=npm)](https://npmjs/package/nestjs-puppeteer)
6
+ [![npm](https://img.shields.io/npm/v/nestjs-puppeteer?logo=npm)](https://npmjs.com/package/nestjs-puppeteer)
7
+ [![NestJS Peer Dep](https://img.shields.io/npm/dependency-version/nestjs-puppeteer/peer/@nestjs/core?logo=nestjs&logoColor=E42844)](https://www.npmjs.com/package/@nestjs/core)
8
+ [![Puppeteer Peer Dep](https://img.shields.io/npm/dependency-version/nestjs-puppeteer/peer/puppeteer?logo=puppeteer&logoColor=%23fff)](https://www.npmjs.com/package/puppeteer)
7
9
  ![npm](https://img.shields.io/npm/dm/nestjs-puppeteer)
8
- ![GitHub](https://img.shields.io/github/license/oblakstudio/nestjs-puppeteer)
9
- [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)
10
- ![Puppeter Peer Dep](https://img.shields.io/npm/dependency-version/nestjs-puppeteer/peer/@nestjs/core?logo=nestjs&logoColor=E42844)
11
- ![NestJS Peer Dep](https://img.shields.io/npm/dependency-version/nestjs-puppeteer/peer/puppeteer?logo=puppeteer&logoColor=%23fff)
10
+ [![License](https://img.shields.io/github/license/oblakstudio/nestjs-puppeteer)](https://github.com/oblakstudio/nestjs-puppeteer/blob/master/LICENSE)
11
+ ![Codecov](https://img.shields.io/codecov/c/github/oblakstudio/nestjs-puppeteer?logo=codecov&color=%23F01F7A)
12
+ [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)
13
+
12
14
 
13
15
  </div>
14
16
 
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getBrowserPrefix = exports.getPageToken = exports.getBrowserToken = void 0;
3
+ exports.getBrowserToken = getBrowserToken;
4
+ exports.getPageToken = getPageToken;
5
+ exports.getBrowserPrefix = getBrowserPrefix;
4
6
  const puppeteer_1 = require("puppeteer");
5
7
  const puppeteer_constants_1 = require("../puppeteer.constants");
6
8
  function getBrowserToken(browser = puppeteer_constants_1.DEFAULT_BROWSER_NAME) {
@@ -12,12 +14,10 @@ function getBrowserToken(browser = puppeteer_constants_1.DEFAULT_BROWSER_NAME) {
12
14
  ? puppeteer_1.Browser
13
15
  : `${browser.name}Browser`;
14
16
  }
15
- exports.getBrowserToken = getBrowserToken;
16
17
  function getPageToken(page, browser = puppeteer_constants_1.DEFAULT_BROWSER_NAME) {
17
18
  const browserPrefix = getBrowserPrefix(browser);
18
19
  return `${browserPrefix}${page}Page`;
19
20
  }
20
- exports.getPageToken = getPageToken;
21
21
  function getBrowserPrefix(browser = puppeteer_constants_1.DEFAULT_BROWSER_NAME) {
22
22
  return puppeteer_constants_1.DEFAULT_BROWSER_NAME === browser
23
23
  ? ''
@@ -27,4 +27,3 @@ function getBrowserPrefix(browser = puppeteer_constants_1.DEFAULT_BROWSER_NAME)
27
27
  ? ''
28
28
  : `${browser.name}_`;
29
29
  }
30
- exports.getBrowserPrefix = getBrowserPrefix;
@@ -1,20 +1,35 @@
1
- import { ModuleMetadata, Type } from '@nestjs/common';
2
- import { PuppeteerNodeLaunchOptions } from 'puppeteer';
1
+ import { InjectionToken, ModuleMetadata, OptionalFactoryDependency, Type } from '@nestjs/common';
2
+ import { PuppeteerNode } from 'puppeteer';
3
3
  import { PuppeteerExtraPlugin } from 'puppeteer-extra';
4
+ /**
5
+ * Launch options accepted by the installed puppeteer's `launch()`. Resolved
6
+ * structurally so the same type works across the supported peer-dep range
7
+ * (^21 || ^22 || ^23), where the canonical name has been renamed/deprecated
8
+ * (`PuppeteerLaunchOptions` → `PuppeteerNodeLaunchOptions` → `LaunchOptions`).
9
+ */
10
+ type LaunchOptions = NonNullable<Parameters<PuppeteerNode['launch']>[0]>;
4
11
  export type PuppeteerModuleOptions = {
5
12
  /**
6
13
  * Browser name
7
14
  */
8
15
  name?: string;
9
16
  /**
10
- * Array of puppeteer-extra plugins
17
+ * Array of puppeteer-extra plugins.
18
+ *
19
+ * NOTE: puppeteer-extra registers plugins on a process-global singleton, so
20
+ * any plugin you list here affects every subsequent `puppeteer.launch()` in
21
+ * the same process — including launches by other PuppeteerModule instances
22
+ * that did not opt into the plugin. The module dedupes by plugin name to
23
+ * avoid stacking on repeated module re-registration, but it cannot scope a
24
+ * plugin to a single browser. Most plugins (e.g. stealth) are also
25
+ * incompatible with Chrome's "new headless" mode; pass `headless: true`.
11
26
  */
12
27
  plugins?: PuppeteerExtraPlugin[];
13
28
  /**
14
29
  * Is the module global
15
30
  */
16
31
  isGlobal?: boolean;
17
- } & Partial<PuppeteerNodeLaunchOptions>;
32
+ } & Partial<LaunchOptions>;
18
33
  export interface PuppeteerOptionsFactory {
19
34
  createPuppeteerOptions(browserName?: string): Promise<PuppeteerModuleOptions> | PuppeteerModuleOptions;
20
35
  }
@@ -24,5 +39,6 @@ export interface PuppeteerModuleAsyncOptions extends Pick<ModuleMetadata, 'impor
24
39
  useExisting?: Type<PuppeteerOptionsFactory>;
25
40
  useClass?: Type<PuppeteerOptionsFactory>;
26
41
  useFactory?: (...args: any[]) => Promise<PuppeteerModuleOptions> | PuppeteerModuleOptions;
27
- inject?: any[];
42
+ inject?: Array<InjectionToken | OptionalFactoryDependency>;
28
43
  }
44
+ export {};
@@ -6,7 +6,7 @@ export declare class PuppeteerCoreModule implements OnApplicationShutdown {
6
6
  private readonly moduleRef;
7
7
  private readonly logger;
8
8
  constructor(options: PuppeteerModuleOptions, moduleRef: ModuleRef);
9
- static forRoot(options?: any): DynamicModule;
9
+ static forRoot(options?: PuppeteerModuleOptions): DynamicModule;
10
10
  static forRootAsync(options: PuppeteerModuleAsyncOptions): DynamicModule;
11
11
  onApplicationShutdown(): Promise<void>;
12
12
  private static createAsyncProviders;
@@ -22,6 +22,53 @@ const core_1 = require("@nestjs/core");
22
22
  const puppeteer_extra_1 = __importDefault(require("puppeteer-extra"));
23
23
  const puppeteer_constants_1 = require("./puppeteer.constants");
24
24
  const common_2 = require("./common");
25
+ const pluginRegistrationLogger = new common_1.Logger('PuppeteerModule');
26
+ const registeredBrowserNames = new Set();
27
+ function resolveBrowserKey(name) {
28
+ return name && name !== puppeteer_constants_1.DEFAULT_BROWSER_NAME ? name : puppeteer_constants_1.DEFAULT_BROWSER_NAME;
29
+ }
30
+ /**
31
+ * Reserve a browser name on the process-level registry. Two PuppeteerModule
32
+ * registrations sharing the same `name` (or both omitting it) would otherwise
33
+ * silently overwrite each other's DI token, leaving one Browser unreachable
34
+ * and un-shutdown. Throw immediately so the misconfiguration is loud.
35
+ */
36
+ function claimBrowserName(name) {
37
+ const key = resolveBrowserKey(name);
38
+ if (registeredBrowserNames.has(key)) {
39
+ const label = key === puppeteer_constants_1.DEFAULT_BROWSER_NAME ? 'default (unnamed)' : `"${key}"`;
40
+ throw new Error(`PuppeteerModule: a browser with name ${label} is already registered. ` +
41
+ `Each PuppeteerModule.forRoot()/forRootAsync() call must use a unique \`name\`.`);
42
+ }
43
+ registeredBrowserNames.add(key);
44
+ }
45
+ function releaseBrowserName(name) {
46
+ registeredBrowserNames.delete(resolveBrowserKey(name));
47
+ }
48
+ /**
49
+ * Register plugins on the global puppeteer-extra singleton, skipping any whose
50
+ * name is already registered. puppeteer-extra holds plugin state in module
51
+ * scope, so naive re-registration (e.g. multiple forRoot calls in tests) would
52
+ * stack duplicate plugins on every subsequent launch.
53
+ */
54
+ function registerPlugins(plugins) {
55
+ if (!(plugins === null || plugins === void 0 ? void 0 : plugins.length)) {
56
+ return [];
57
+ }
58
+ const registered = new Set(puppeteer_extra_1.default.pluginNames);
59
+ for (const plugin of plugins) {
60
+ const name = plugin === null || plugin === void 0 ? void 0 : plugin.name;
61
+ if (typeof name === 'string' && registered.has(name)) {
62
+ pluginRegistrationLogger.warn(`Skipping duplicate puppeteer-extra plugin "${name}" — already registered on the global instance.`);
63
+ continue;
64
+ }
65
+ puppeteer_extra_1.default.use(plugin);
66
+ if (typeof name === 'string') {
67
+ registered.add(name);
68
+ }
69
+ }
70
+ return plugins;
71
+ }
25
72
  let PuppeteerCoreModule = PuppeteerCoreModule_1 = class PuppeteerCoreModule {
26
73
  constructor(options, moduleRef) {
27
74
  this.options = options;
@@ -29,19 +76,14 @@ let PuppeteerCoreModule = PuppeteerCoreModule_1 = class PuppeteerCoreModule {
29
76
  this.logger = new common_1.Logger('PuppeteerModule');
30
77
  }
31
78
  static forRoot(options = {}) {
79
+ claimBrowserName(options.name);
32
80
  const puppeteerModuleOptions = {
33
81
  provide: puppeteer_constants_1.PUPPETEER_MODULE_OPTIONS,
34
82
  useValue: options,
35
83
  };
36
84
  const pluginProvider = {
37
85
  provide: puppeteer_constants_1.PUPPETEER_BROWSER_PLUGINS,
38
- useFactory: async (options) => {
39
- if (options.plugins) {
40
- options.plugins.forEach((plugin) => puppeteer_extra_1.default.use(plugin));
41
- return options.plugins;
42
- }
43
- return [];
44
- },
86
+ useFactory: async (options) => registerPlugins(options.plugins),
45
87
  inject: [puppeteer_constants_1.PUPPETEER_MODULE_OPTIONS],
46
88
  };
47
89
  const browserProvider = {
@@ -60,15 +102,13 @@ let PuppeteerCoreModule = PuppeteerCoreModule_1 = class PuppeteerCoreModule {
60
102
  };
61
103
  }
62
104
  static forRootAsync(options) {
105
+ if (!options.useFactory && !options.useClass && !options.useExisting) {
106
+ throw new Error('PuppeteerModule.forRootAsync requires one of useFactory, useClass, or useExisting');
107
+ }
108
+ claimBrowserName(options.name);
63
109
  const pluginProvider = {
64
110
  provide: puppeteer_constants_1.PUPPETEER_BROWSER_PLUGINS,
65
- useFactory: async (options) => {
66
- if (options.plugins) {
67
- options.plugins.forEach((plugin) => puppeteer_extra_1.default.use(plugin));
68
- return options.plugins;
69
- }
70
- return [];
71
- },
111
+ useFactory: async (options) => registerPlugins(options.plugins),
72
112
  inject: [puppeteer_constants_1.PUPPETEER_MODULE_OPTIONS],
73
113
  };
74
114
  const browserProvider = {
@@ -96,7 +136,15 @@ let PuppeteerCoreModule = PuppeteerCoreModule_1 = class PuppeteerCoreModule {
96
136
  }
97
137
  }
98
138
  catch (e) {
99
- this.logger.error(e === null || e === void 0 ? void 0 : e.message);
139
+ if (e instanceof Error) {
140
+ this.logger.error(`Failed to close browser: ${e.message}`, e.stack);
141
+ }
142
+ else {
143
+ this.logger.error(`Failed to close browser: ${String(e)}`);
144
+ }
145
+ }
146
+ finally {
147
+ releaseBrowserName(this.options.name);
100
148
  }
101
149
  }
102
150
  static createAsyncProviders(options) {
@@ -113,6 +161,7 @@ let PuppeteerCoreModule = PuppeteerCoreModule_1 = class PuppeteerCoreModule {
113
161
  ];
114
162
  }
115
163
  static createAsyncOptionsProvider(options) {
164
+ var _a;
116
165
  if (options.useFactory) {
117
166
  return {
118
167
  provide: puppeteer_constants_1.PUPPETEER_MODULE_OPTIONS,
@@ -120,10 +169,8 @@ let PuppeteerCoreModule = PuppeteerCoreModule_1 = class PuppeteerCoreModule {
120
169
  inject: options.inject || [],
121
170
  };
122
171
  }
123
- const inject = [
124
- (options.useClass ||
125
- options.useExisting),
126
- ];
172
+ const factory = ((_a = options.useClass) !== null && _a !== void 0 ? _a : options.useExisting);
173
+ const inject = [factory];
127
174
  return {
128
175
  provide: puppeteer_constants_1.PUPPETEER_MODULE_OPTIONS,
129
176
  useFactory: async (optionsFactory) => await optionsFactory.createPuppeteerOptions(options.name),
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createPuppeteerProviders = void 0;
3
+ exports.createPuppeteerProviders = createPuppeteerProviders;
4
4
  const common_1 = require("./common");
5
5
  function createPuppeteerProviders(pages, browser) {
6
6
  return (pages || []).map((page) => ({
@@ -11,4 +11,3 @@ function createPuppeteerProviders(pages, browser) {
11
11
  inject: [(0, common_1.getBrowserToken)(browser)]
12
12
  }));
13
13
  }
14
- exports.createPuppeteerProviders = createPuppeteerProviders;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nestjs-puppeteer",
3
3
  "description": "Puppeteer module for NestJS",
4
- "version": "2.1.0",
4
+ "version": "2.3.0",
5
5
  "license": "MIT",
6
6
  "author": {
7
7
  "name": "Sibin Grasic",
@@ -20,44 +20,44 @@
20
20
  "semantic-release": "semantic-release"
21
21
  },
22
22
  "engines": {
23
- "node": ">=18"
23
+ "node": ">=20"
24
24
  },
25
25
  "main": "dist/index.js",
26
26
  "types": "dist/index.d.ts",
27
27
  "devDependencies": {
28
- "@commitlint/cli": "18.6.0",
29
- "@commitlint/config-angular": "18.6.0",
30
- "@nestjs/common": "10.3.1",
31
- "@nestjs/core": "10.3.1",
32
- "@nestjs/platform-express": "10.3.1",
33
- "@nestjs/testing": "10.3.1",
34
- "@types/jest": "29.5.11",
28
+ "@commitlint/cli": "18.6.1",
29
+ "@commitlint/config-angular": "18.6.1",
30
+ "@nestjs/common": "^11",
31
+ "@nestjs/core": "^11",
32
+ "@nestjs/platform-express": "^11",
33
+ "@nestjs/testing": "^11",
34
+ "@types/jest": "29.5.14",
35
35
  "@types/node": "^20",
36
- "@types/supertest": "6.0.2",
37
- "@typescript-eslint/eslint-plugin": "6.20.0",
38
- "@typescript-eslint/parser": "6.20.0",
39
- "eslint": "8.56.0",
40
- "eslint-config-prettier": "9.1.0",
41
- "eslint-plugin-import": "2.29.1",
42
- "husky": "^9.0.7",
36
+ "@types/supertest": "6.0.3",
37
+ "@typescript-eslint/eslint-plugin": "6.21.0",
38
+ "@typescript-eslint/parser": "6.21.0",
39
+ "eslint": "8.57.1",
40
+ "eslint-config-prettier": "9.1.2",
41
+ "eslint-plugin-import": "2.32.0",
42
+ "husky": "^9.1.7",
43
43
  "jest": "29.7.0",
44
- "lint-staged": "^15.2.1",
45
- "puppeteer": "^21",
44
+ "lint-staged": "^15.5.2",
45
+ "puppeteer": "^23",
46
46
  "puppeteer-extra": "^3.3.6",
47
47
  "puppeteer-extra-plugin-stealth": "^2.11.2",
48
- "reflect-metadata": "^0.1.13",
49
- "rxjs": "^7.8.1",
48
+ "reflect-metadata": "^0.2",
49
+ "rxjs": "^7.8.2",
50
50
  "supertest": "6.3.4",
51
- "ts-jest": "29.1.2",
51
+ "ts-jest": "29.4.9",
52
52
  "typescript": "^5"
53
53
  },
54
54
  "peerDependencies": {
55
- "@nestjs/common": "^9.0 || ^10.0",
56
- "@nestjs/core": "^9.0.0 || ^10.0",
57
- "puppeteer": "^21",
55
+ "@nestjs/common": "^10 || ^11",
56
+ "@nestjs/core": "^10 | ^11",
57
+ "puppeteer": "^21 || ^22 || ^23",
58
58
  "puppeteer-extra": "^3",
59
- "reflect-metadata": "^0.1.13",
60
- "rxjs": "^7.8.0"
59
+ "reflect-metadata": "*",
60
+ "rxjs": "*"
61
61
  },
62
62
  "lint-staged": {
63
63
  "**/*.{ts,json}": []