Conversation
There was a problem hiding this comment.
Pull request overview
This PR standardizes the repo’s TypeScript/Jest/ESLint configuration and CI workflows to align build + validation behavior across local development and GitHub Actions, alongside broad import hygiene changes (type-only imports / ordering) across src and tests.
Changes:
- Updates TS build/typecheck configuration (module + moduleResolution, build script changes) and adds dedicated ESLint tsconfig.
- Introduces Jest and ESLint flat-config files and adjusts numerous imports across tests/src to satisfy lint/type rules.
- Adds/updates GitHub Actions workflows for release checks and publishing, plus contributor guidance and an
.env.example.
Reviewed changes
Copilot reviewed 67 out of 69 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Switches TS module settings and narrows compilation include set to src/**. |
| tsconfig.eslint.json | Adds an ESLint-specific TS project for type-aware linting. |
| package.json | Updates build/typecheck scripts, sets package type, and adjusts dependency versions. |
| jest.config.ts | Adds standalone Jest configuration (migrated from package.json). |
| eslint.config.js | Adds ESLint v9 flat config with TS + import ordering rules. |
| .github/workflows/release-check.yml | Adds PR-time “release checks” CI workflow (format/lint/typecheck/test/build + optional Sonar). |
| .github/workflows/publish.yml | Refines npm publish workflow steps and node version. |
| .github/copilot-instructions.md | Adds a project-specific contributor/developer guide. |
| .env.example | Adds example environment variable template for local/dev setups. |
| src/paymentKit.module.ts | Reorders imports / consolidates stack wiring imports. |
| src/nest/controllers/internal-webhook.controller.ts | Converts some imports to type-only and reorders. |
| src/main.ts | Minor formatting/import spacing changes. |
| src/core/services/webhook-mode.service.ts | Converts imports to type-only and reorders. |
| src/core/services/webhook-event-dispatcher.service.ts | Converts webhook type imports to type-only. |
| src/core/services/payment-engine.service.ts | Reorders imports and converts some to type-only. |
| src/core/services/gateway-registry.service.ts | Converts imports to type-only and adds spacing. |
| src/core/services/error-normalizer.service.ts | Splits type/value imports and reorders. |
| src/core/ports/payment-gateway.port.ts | Converts multiple imports to type-only. |
| src/core/ports/payment-engine.port.ts | Converts import to type-only. |
| src/core/gateways/stripe/stripe.gateway.ts | Reorders imports; normalizes type/value import usage. |
| src/core/gateways/stripe/stripe.client.ts | Converts config import to type-only. |
| src/core/gateways/stripe/stripe-webhook.handler.ts | Converts imports to type-only and reorders. |
| src/core/gateways/stripe/stripe-webhook-normalizer.ts | Converts imports to type-only. |
| src/core/gateways/stripe/stripe-payments.client.ts | Reorders imports; converts some to type-only. |
| src/core/gateways/stripe/stripe-error.mapper.ts | Splits type/value imports; converts GatewayKey to type-only. |
| src/core/gateways/paypal/paypal.gateway.ts | Reorders imports; normalizes type/value import usage. |
| src/core/gateways/paypal/paypal.client.ts | Reorders type-only imports. |
| src/core/gateways/paypal/paypal-webhook.handler.ts | Reorders imports; converts to type-only. |
| src/core/gateways/paypal/paypal-webhook-normalizer.ts | Converts webhook imports to type-only. |
| src/core/gateways/paypal/paypal-payments.client.ts | Reorders imports; converts PaypalClient to type-only. |
| src/core/gateways/paypal/paypal-error.mapper.ts | Splits type/value imports. |
| src/core/entities/payment.entity.ts | Converts entity imports to type-only and reorders. |
| src/core/entities/refund.entity.ts | Converts imports to type-only and reorders. |
| src/config/paymentKit.config.ts | Converts WebhookMode import to type-only. |
| src/config/paymentKit.config-loader.ts | Reorders imports between common/config and gateway-specific configs. |
| src/common/types/webhook.types.ts | Converts GatewayKey import to type-only. |
| src/common/errors/normalized-error.model.ts | Converts GatewayKey import to type-only. |
| test/unit/paymentKit.module.spec.ts | Reorders imports and uses type-only import. |
| test/unit/core/services/webhook/webhook-mode.service.spec.ts | Reorders imports and uses type-only import. |
| test/unit/core/services/webhook/webhook-gateway-router.service.spec.ts | Reorders imports; uses type-only imports consistently. |
| test/unit/core/services/webhook/webhook-gateway-router.normalization.spec.ts | Reorders imports; uses type-only imports consistently. |
| test/unit/core/services/webhook/webhook-event-dispatcher.service.spec.ts | Reorders type-only import. |
| test/unit/core/services/payment-engine.service.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/services/gateway-registry.service.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/services/error-mappers/stripe-error-mapper.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/services/error-mappers/paypal-error-mapper.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/services/error-mappers/error-normalizer.service.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/stripe/stripe.gateway.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/stripe/stripe.client.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/stripe/stripe-webhook.handler.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/stripe/stripe-webhook-verifier.spec.ts | Reorders imports and adds spacing. |
| test/unit/core/gateways/stripe/stripe-payments.client.spec.ts | Reorders imports and adjusts type-only groupings. |
| test/unit/core/gateways/stripe/stripe-error.mapper.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/paypal/paypal.gateway.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/paypal/paypal.client.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/paypal/paypal-webhook.handler.spec.ts | Reorders type-only imports. |
| test/unit/core/gateways/paypal/paypal-webhook-verifier.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/paypal/paypal-payments.client.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/gateways/paypal/paypal-error.mapper.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/core/entities/payment-and-refund.entity.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/controllers/internal-webhook.controller.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/config/paymentKit.config.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/config/paymentKit.config-loader.spec.ts | Reorders imports; normalizes type-only imports. |
| test/unit/common/errors/normalized-error.model.spec.ts | Reorders imports; normalizes type-only imports. |
| test/integration/stripe/stripe-payments.integration.spec.ts | Converts imports to type-only where appropriate and reorders. |
| test/integration/setup.ts | Splits type/value imports and reorders. |
| test/app.e2e-spec.ts | Converts imports to type-only and reorders. |
Comments suppressed due to low confidence (7)
.github/workflows/release-check.yml:52
- This workflow runs
npm run format, which modifies files rather than validating formatting. In CI, that can let unformatted code pass (and can create a dirty working tree). Usenpm run format:check(or an equivalent check-only command) for PR validation.
- name: Format
run: npm run format
- name: Typecheck
run: npm run typecheck
tsconfig.eslint.json:8
tsconfig.eslint.jsonincludes*.jsbut it extendstsconfig.jsonwhich does not enableallowJs. WithparserOptions.project, that can cause TypeScript program/diagnostic issues during linting. Either remove*.jsfrom the include list, or setcompilerOptions.allowJs(and optionallycheckJs) in the ESLint tsconfig if you intend to type-check JS files.
src/core/services/webhook-mode.service.ts:6- Spelling typo in the doc comment (
aruond). Rename toaroundfor readability in generated docs/IDE hints.
src/core/services/error-normalizer.service.ts:10 - The
ErrorNormalizerinterface parameter name has a typo (contexxt). While parameter names don't affect TypeScript assignability, this reduces readability and can propagate into generated docs/IDE hints. Rename it tocontext.
export interface ErrorNormalizer {
normalize(error: unknown, contexxt: { gateway: GatewayKey }): NormalizedError;
}
src/common/types/webhook.types.ts:6
- Spelling in the WebhookMode doc comment has typos (
hendling,PaymekntKit). Please correct these to keep public types/docs polished.
/**
* Webhook hendling mode for PaymekntKit.
*
* - "internal": Webhooks are handled internally by PaymentKit.
.github/copilot-instructions.md:74
- This contributor guide describes a project structure and path aliases (
src/adapters,src/controllers,@adapters/*,@controllers/*) that don't exist in the current repo (the code usessrc/core/gatewaysandsrc/nest/controllers, andtsconfig.jsondefines different aliases like@src/*and@nest/*). Please update the guide to match the actual structure/aliases (or update the codebase to match the documented structure) to avoid misleading contributors.
## 🏗️ PaymentKit Project Structure
PaymentKit uses a Hexagonal Architecture (Ports & Adapters) for gateway abstraction.
src/
index.ts # PUBLIC API exports
paymentKit.module.ts # Main NestJS module
common/
constants.ts # DI tokens, magic strings
errors/ # Error models
types/ # Shared type definitions
utils/ # Helper functions
config/
paymentKit.config.ts # Public config interface
paymentKit.config-loader.ts # Env-based config builder
gateways/ # Gateway-specific configs
stripe.config.ts
paypal.config.ts
core/
entities/ # Domain entities
payment.entity.ts
refund.entity.ts
payment-status.enum.ts
value-objects/
money.value-object.ts
ports/ # Interface contracts (Hexagonal)
payment-gateway.port.ts
payment-engine.port.ts
services/
payment-engine.service.ts # Main orchestrator
gateway-registry.service.ts
error-normalizer.service.ts
adapters/ # Gateway implementations
stripe/
stripe.gateway.ts
stripe-webhook.handler.ts
stripe-payments.client.ts
paypal/
paypal.gateway.ts
paypal-webhook.handler.ts
paypal-payments.client.ts
controllers/
payments.controller.ts # Main API endpoints
webhooks.controller.ts # Internal webhook controller
package.json:19
package.jsonis now marked as ESM ("type": "module"), buttsconfig.jsoncompiles to CommonJS ("module": "commonjs") andmain/exportspoint todist/*.js. That combination will cause Node to treat the emitted CommonJS files as ESM at runtime (e.g.,node dist/main/ consumers importingdist/index.js), which typically fails. Align the package type and TS output (either removetype: module, or switch TS output to ESM and updateexports/file extensions/entrypoints accordingly).
"type": "module",
"description": "Unified payments package for NestJS (Stripe, PayPal).",
"author": "Zaiid Moumni",
"private": false,
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/CISCODE-MA/PaymentKit"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
jest.config.ts
Outdated
| '^@config/(.*)$': '<rootDir>/src/config/$1', | ||
| '^@core/(.*)$': '<rootDir>/src/core/$1', | ||
| '^@adapters/(.*)$': '<rootDir>/src/adapters/$1', | ||
| '^@controllers/(.*)$': '<rootDir>/src/controllers/$1', |
There was a problem hiding this comment.
jest.config.ts is missing path alias mappings that are used throughout the tests (e.g. @src/*, @nest/*, and @gateways/* are in tsconfig.json and referenced in test/**). Without these, Jest will fail module resolution. Add the missing moduleNameMapper entries (or generate them from tsconfig.json paths) so Jest matches the TS compiler resolution.
| '^@controllers/(.*)$': '<rootDir>/src/controllers/$1', | |
| '^@controllers/(.*)$': '<rootDir>/src/controllers/$1', | |
| '^@src/(.*)$': '<rootDir>/src/$1', | |
| '^@nest/(.*)$': '<rootDir>/src/nest/$1', | |
| '^@gateways/(.*)$': '<rootDir>/src/gateways/$1', |
| "@nestjs/cli": "^11.0.0", | ||
| "@nestjs/schematics": "^11.0.0", | ||
| "@nestjs/testing": "^11.0.1", | ||
| "@nestjs/cli": "^7.6.0", |
There was a problem hiding this comment.
@nestjs/cli is pinned to ^7.6.0 while the project depends on Nest v11 (@nestjs/common/core/testing are 11.x). This major-version mismatch can break nest start and other CLI-driven tasks. Update @nestjs/cli to a compatible v11 version (or adjust the Nest dependency versions to match the CLI major).
| "@nestjs/cli": "^7.6.0", | |
| "@nestjs/cli": "^11.0.0", |
- Add changeset config and release note - Move copilot instructions to .github/instructions - Add sonarqube MCP instructions - Update publish workflow - Add Jest path aliases and skip integration tests without env vars
- Prefix unused parameters with underscore (_) to comply with ESLint rules - Update examples for ecommerce checkout, webhook handling, and refund operations - All examples now pass linting checks
- Applied prettier formatting to examples - Fixed ESLint configuration to include examples folder - All code passes linting and formatting standards
|
| STRIPE_SECRET_KEY=sk_test_your-secret-key | ||
| STRIPE_WEBHOOK_SECRET=whsec_your-webhook-secret |
There was a problem hiding this comment.
The env var names in this example don’t match what the Stripe config builder reads (PAYMENTKIT_STRIPE_API_KEY / PAYMENTKIT_STRIPE_WEBHOOK_SECRET). As written, users copying this file won’t be able to bootstrap PaymentKit from env.
| STRIPE_SECRET_KEY=sk_test_your-secret-key | |
| STRIPE_WEBHOOK_SECRET=whsec_your-webhook-secret | |
| PAYMENTKIT_STRIPE_API_KEY=sk_test_your-secret-key | |
| PAYMENTKIT_STRIPE_WEBHOOK_SECRET=whsec_your-webhook-secret |
| PAYPAL_CLIENT_ID=your-client-id | ||
| PAYPAL_CLIENT_SECRET=your-client-secret | ||
| PAYPAL_MODE=sandbox | ||
| PAYPAL_WEBHOOK_ID=your-webhook-id |
There was a problem hiding this comment.
The env var names in this example don’t match what the PayPal config builder reads (PAYMENTKIT_PAYPAL_CLIENT_ID / PAYMENTKIT_PAYPAL_CLIENT_SECRET / optional PAYMENTKIT_PAYPAL_WEBHOOK_ID). Update these names so the example is usable.
| PAYPAL_CLIENT_ID=your-client-id | |
| PAYPAL_CLIENT_SECRET=your-client-secret | |
| PAYPAL_MODE=sandbox | |
| PAYPAL_WEBHOOK_ID=your-webhook-id | |
| PAYMENTKIT_PAYPAL_CLIENT_ID=your-client-id | |
| PAYMENTKIT_PAYPAL_CLIENT_SECRET=your-client-secret | |
| PAYPAL_MODE=sandbox | |
| PAYMENTKIT_PAYPAL_WEBHOOK_ID=your-webhook-id |
| { | ||
| "name": "@ciscode/paymentkit", | ||
| "version": "1.2.0", | ||
| "type": "module", |
There was a problem hiding this comment.
"type": "module" makes Node treat emitted dist/*.js as ESM, but tsconfig.json emits CommonJS ("module": "commonjs") and main/exports point at dist/index.js. This will break node dist/main and consumers importing dist/index.js. Align the package/module format by either removing/setting type to commonjs, or switching TS emit + exports to proper ESM (or dual CJS/ESM conditional exports).
| "type": "module", | |
| "type": "commonjs", |
| parserOptions: { | ||
| project: './tsconfig.eslint.json', | ||
| tsconfigRootDir: import.meta.dirname, | ||
| ecmaVersion: 'latest', | ||
| sourceType: 'module', |
There was a problem hiding this comment.
import.meta.dirname is not part of the standard import.meta API and is undefined in many Node environments. ESLint will fail to resolve tsconfigRootDir if this is undefined. Use a fileURLToPath(import.meta.url) + path.dirname(...) pattern (or keep this config as .mjs and use __dirname via createRequire/URL conversion) to compute the directory reliably.
| const REQUIRED_ENV = [ | ||
| 'PAYMENTKIT_ENVIRONMENT', | ||
| 'PAYMENTKIT_STRIPE_SECRET_KEY', | ||
| 'PAYMENTKIT_PAYPAL_CLIENT_ID', | ||
| 'PAYMENTKIT_PAYPAL_SECRET', |
There was a problem hiding this comment.
REQUIRED_ENV is checking for PAYMENTKIT_STRIPE_SECRET_KEY / PAYMENTKIT_PAYPAL_SECRET, but the actual config expects PAYMENTKIT_STRIPE_API_KEY and PAYMENTKIT_PAYPAL_CLIENT_SECRET. Update this list so integration tests are gated on the correct variables.
| adapters/ # Gateway implementations | ||
| stripe/ | ||
| stripe.gateway.ts | ||
| stripe-webhook.handler.ts | ||
| stripe-payments.client.ts | ||
| paypal/ | ||
| paypal.gateway.ts | ||
| paypal-webhook.handler.ts | ||
| paypal-payments.client.ts |
There was a problem hiding this comment.
This doc’s project structure lists gateway implementations under src/adapters/..., but the actual codebase has them under src/core/gateways/.... Updating the diagram/paths will prevent contributors from creating files in the wrong place.
| adapters/ # Gateway implementations | |
| stripe/ | |
| stripe.gateway.ts | |
| stripe-webhook.handler.ts | |
| stripe-payments.client.ts | |
| paypal/ | |
| paypal.gateway.ts | |
| paypal-webhook.handler.ts | |
| paypal-payments.client.ts | |
| gateways/ # Gateway implementations | |
| stripe/ | |
| stripe.gateway.ts | |
| stripe-webhook.handler.ts | |
| stripe-payments.client.ts | |
| paypal/ | |
| paypal.gateway.ts | |
| paypal-webhook.handler.ts | |
| paypal-payments.client.ts |
| controllers/ | ||
| payments.controller.ts # Main API endpoints | ||
| webhooks.controller.ts # Internal webhook controller |
There was a problem hiding this comment.
This doc references src/controllers/..., but this repository’s Nest layer lives under src/nest/controllers/... (and there is no src/controllers folder). Adjust the structure + examples to match the real layout to avoid incorrect imports.
| controllers/ | |
| payments.controller.ts # Main API endpoints | |
| webhooks.controller.ts # Internal webhook controller | |
| nest/ | |
| controllers/ | |
| payments.controller.ts # Main API endpoints | |
| webhooks.controller.ts # Internal webhook controller |
| '^@gateways/(.*)$': '<rootDir>/src/gateways/$1', | ||
| '^@nest/(.*)$': '<rootDir>/src/nest/$1', | ||
| '^@adapters/(.*)$': '<rootDir>/src/adapters/$1', | ||
| '^@controllers/(.*)$': '<rootDir>/src/controllers/$1', |
There was a problem hiding this comment.
This Jest config maps @gateways/*, @adapters/*, and @controllers/* to directories that don't exist in this repo (src/gateways, src/adapters, src/controllers). If these aliases are legacy, removing them reduces confusion; if they are intended, update them to actual directories (e.g., src/core/gateways, src/nest/controllers).
| '^@gateways/(.*)$': '<rootDir>/src/gateways/$1', | |
| '^@nest/(.*)$': '<rootDir>/src/nest/$1', | |
| '^@adapters/(.*)$': '<rootDir>/src/adapters/$1', | |
| '^@controllers/(.*)$': '<rootDir>/src/controllers/$1', | |
| '^@nest/(.*)$': '<rootDir>/src/nest/$1', |
| branches: | ||
| - master |
There was a problem hiding this comment.
This workflow publishes on every push to master. Because it only checks that some v*.*.* tag exists in the repo (not that a new tag was pushed), most pushes to master will attempt to republish the same version and fail (npm ERR! You cannot publish over the previously published versions). Prefer triggering on tag pushes (on.push.tags: ['v*.*.*']) or use semantic-release/changesets to create a new version/tag before publishing.
| branches: | |
| - master | |
| tags: | |
| - 'v*.*.*' |
|
|
||
| echo "✅ Valid tag found: $TAG" | ||
| echo "✅ Version matches package.json: $PKG_VERSION" | ||
| echo "TAG_VERSION=$TAG" >> $GITHUB_ENV |
There was a problem hiding this comment.
The workflow exports TAG_VERSION=$TAG, but TAG_VERSION was computed earlier without the v prefix (TAG_VERSION="${TAG#v}"). If this env var is used later, it will be incorrect; export the computed value (or rename the env var to avoid confusion).
| echo "TAG_VERSION=$TAG" >> $GITHUB_ENV | |
| echo "TAG_VERSION=$TAG_VERSION" >> $GITHUB_ENV |


Standardization Pull Request
Changes
Status