@wtree/payload-ecommerce-coupon 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/dist/client/hooks.d.ts +15 -0
- package/dist/client/hooks.d.ts.map +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/couponCollections.d.ts +13 -0
- package/dist/couponCollections.d.ts.map +1 -0
- package/dist/hooks/applyCoupon.d.ts +10 -0
- package/dist/hooks/applyCoupon.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +111 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wtree
|
|
4
|
+
|
|
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 furnished
|
|
10
|
+
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @wtree/payload-ecommerce-coupon
|
|
2
|
+
|
|
3
|
+
[](https://npmjs.com/package/@wtree/payload-ecommerce-coupon)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
|
|
7
|
+
Production-ready coupon and referral system plugin for **Payload CMS** with seamless integration to the **@payloadcms/plugin-ecommerce** package.
|
|
8
|
+
|
|
9
|
+
## 🚀 Features
|
|
10
|
+
|
|
11
|
+
- ✅ **Coupon Management** – Create and manage discount codes with flexible conditions
|
|
12
|
+
- ✅ **Referral Programs** – Partner commission + customer discount split configuration
|
|
13
|
+
- ✅ **Referral Partners** – Onboard, approve, and track affiliate partners
|
|
14
|
+
- ✅ **REST API** – Validate, apply, and track coupons and referral codes
|
|
15
|
+
- ✅ **Frontend Hooks** – `useCouponCode()` and `validateCouponCode()` for React/Next.js
|
|
16
|
+
- ✅ **Auto-Integration** – Extends ecommerce collections automatically
|
|
17
|
+
- ✅ **Type-Safe** – Full TypeScript support with strict types
|
|
18
|
+
- ✅ **Tested** – 80%+ unit test coverage with Vitest
|
|
19
|
+
- ✅ **Production-Ready** – Follow Payload CMS best practices
|
|
20
|
+
|
|
21
|
+
## 📦 Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @wtree/payload-ecommerce-coupon
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Requirements
|
|
28
|
+
|
|
29
|
+
- `payload@^3.0.0` (Payload CMS)
|
|
30
|
+
- `@payloadcms/plugin-ecommerce@>=3.0.0` (required peer dependency)
|
|
31
|
+
- `node@>=18.0.0`
|
|
32
|
+
|
|
33
|
+
## 🔧 Quick Start
|
|
34
|
+
|
|
35
|
+
### 1. Register the Plugin
|
|
36
|
+
|
|
37
|
+
In your `payload.config.ts`:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { buildConfig } from 'payload'
|
|
41
|
+
import { ecommercePlugin } from '@payloadcms/plugin-ecommerce'
|
|
42
|
+
import { payloadEcommerceCoupon } from '@wtree/payload-ecommerce-coupon'
|
|
43
|
+
|
|
44
|
+
export default buildConfig({
|
|
45
|
+
plugins: [
|
|
46
|
+
ecommercePlugin({
|
|
47
|
+
// your ecommerce configuration
|
|
48
|
+
}),
|
|
49
|
+
payloadEcommerceCoupon({
|
|
50
|
+
enabled: true,
|
|
51
|
+
defaultCurrency: 'USD',
|
|
52
|
+
allowStackWithOtherCoupons: false,
|
|
53
|
+
autoIntegrate: true,
|
|
54
|
+
}),
|
|
55
|
+
],
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Frontend Integration
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { useCouponCode } from '@wtree/payload-ecommerce-coupon'
|
|
63
|
+
|
|
64
|
+
const result = await useCouponCode({
|
|
65
|
+
code: 'WELCOME10',
|
|
66
|
+
cartID: 'your-cart-id',
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
if (result.success) {
|
|
70
|
+
console.log('Discount:', result.discount)
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 🌐 REST API Endpoints
|
|
75
|
+
|
|
76
|
+
### POST /api/ecommerce/coupons/validate
|
|
77
|
+
|
|
78
|
+
Validate a coupon without applying it.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
curl -X POST http://localhost:3000/api/ecommerce/coupons/validate \
|
|
82
|
+
-H "Content-Type: application/json" \
|
|
83
|
+
-d '{"code": "WELCOME10", "cartValue": 5000}'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### POST /api/ecommerce/coupons/apply
|
|
87
|
+
|
|
88
|
+
Apply a coupon to a cart.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
curl -X POST http://localhost:3000/api/ecommerce/coupons/apply \
|
|
92
|
+
-H "Content-Type: application/json" \
|
|
93
|
+
-d '{"code": "WELCOME10", "cartID": "cart-123", "cartValue": 5000}'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## ⚙️ Configuration
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
export type CouponPluginOptions = {
|
|
100
|
+
enabled?: boolean // default: true
|
|
101
|
+
allowStackWithOtherCoupons?: boolean // default: false
|
|
102
|
+
defaultCurrency?: string // default: 'USD'
|
|
103
|
+
autoIntegrate?: boolean // default: true
|
|
104
|
+
collections?: {
|
|
105
|
+
couponsSlug?: string
|
|
106
|
+
referralProgramsSlug?: string
|
|
107
|
+
referralCodesSlug?: string
|
|
108
|
+
referralPartnersSlug?: string
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 🧪 Testing
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Run tests
|
|
117
|
+
npm test
|
|
118
|
+
|
|
119
|
+
# Watch mode
|
|
120
|
+
npm run test:watch
|
|
121
|
+
|
|
122
|
+
# Coverage report
|
|
123
|
+
npm run test:coverage
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 📚 Documentation
|
|
127
|
+
|
|
128
|
+
For detailed usage examples and advanced configurations:
|
|
129
|
+
- [Coupon Management Guide](./docs/coupons.md)
|
|
130
|
+
- [Referral Programs Setup](./docs/referral.md)
|
|
131
|
+
- [API Reference](./docs/api.md)
|
|
132
|
+
- [Compatibility Matrix](./COMPATIBILITY.md)
|
|
133
|
+
|
|
134
|
+
## 🔗 Links
|
|
135
|
+
|
|
136
|
+
- **GitHub**: https://github.com/technewwings/payload-ecommerce-coupon
|
|
137
|
+
- **NPM**: https://npmjs.com/package/@wtree/payload-ecommerce-coupon
|
|
138
|
+
- **Payload CMS**: https://payloadcms.com
|
|
139
|
+
|
|
140
|
+
## 📄 License
|
|
141
|
+
|
|
142
|
+
MIT License © 2026 wtree. See [LICENSE](./LICENSE) for details.
|
|
143
|
+
|
|
144
|
+
## 🤝 Contributing
|
|
145
|
+
|
|
146
|
+
Contributions are welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ApplyCouponHook, ApplyCouponResponse } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Apply a coupon code to a cart
|
|
4
|
+
* @param options - Coupon code, cart ID, and customer email
|
|
5
|
+
* @returns Response with success status, discount amount, and coupon details
|
|
6
|
+
*/
|
|
7
|
+
export declare function useCouponCode(options: ApplyCouponHook): Promise<ApplyCouponResponse>;
|
|
8
|
+
/**
|
|
9
|
+
* Validate a coupon code without applying it
|
|
10
|
+
* @param code - Coupon code to validate
|
|
11
|
+
* @param cartValue - Optional cart value in smallest currency unit
|
|
12
|
+
* @returns Response with validation result and coupon details
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateCouponCode(code: string, cartValue?: number): Promise<ApplyCouponResponse>;
|
|
15
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/client/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEpE;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA8C1F;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,mBAAmB,CAAC,CA2C9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CollectionConfig } from 'payload';
|
|
2
|
+
export type BuildCollectionsArgs = {
|
|
3
|
+
couponsSlug: string;
|
|
4
|
+
referralProgramsSlug: string;
|
|
5
|
+
referralCodesSlug: string;
|
|
6
|
+
defaultCurrency?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const buildCouponCollections: ({ couponsSlug, referralCodesSlug, referralProgramsSlug, defaultCurrency, }: BuildCollectionsArgs) => {
|
|
9
|
+
couponsCollection: CollectionConfig;
|
|
10
|
+
referralProgramsCollection: CollectionConfig;
|
|
11
|
+
referralCodesCollection: CollectionConfig;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=couponCollections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"couponCollections.d.ts","sourceRoot":"","sources":["../src/couponCollections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,iBAAiB,EAAE,MAAM,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,4EAKpC,oBAAoB,KAAG;IACxB,iBAAiB,EAAE,gBAAgB,CAAA;IACnC,0BAA0B,EAAE,gBAAgB,CAAA;IAC5C,uBAAuB,EAAE,gBAAgB,CAAA;CA8Q1C,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Config } from 'payload';
|
|
2
|
+
export type ApplyCouponHooksArgs = {
|
|
3
|
+
config: Config;
|
|
4
|
+
_allowStackWithOtherCoupons: boolean;
|
|
5
|
+
couponsSlug: string;
|
|
6
|
+
_referralProgramsSlug: string;
|
|
7
|
+
referralCodesSlug: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const applyCouponHooks: ({ config, _allowStackWithOtherCoupons, couponsSlug, _referralProgramsSlug, referralCodesSlug, }: ApplyCouponHooksArgs) => Config;
|
|
10
|
+
//# sourceMappingURL=applyCoupon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyCoupon.d.ts","sourceRoot":"","sources":["../../src/hooks/applyCoupon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,2BAA2B,EAAE,OAAO,CAAA;IACpC,WAAW,EAAE,MAAM,CAAA;IACnB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,iGAM9B,oBAAoB,KAAG,MAwCzB,CAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { CouponPluginOptions, ApplyCouponResponse, ApplyCouponHook } from './types';
|
|
2
|
+
export { useCouponCode, validateCouponCode } from './client/hooks';
|
|
3
|
+
export declare const payloadEcommerceCoupon: (pluginOptions?: import("./types").CouponPluginOptions) => (incomingConfig: import("payload").Config) => import("payload").Config;
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACxF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAElE,eAAO,MAAM,sBAAsB,8DAFG,wCAAsB,6BAEM,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/plugin.ts
|
|
3
|
+
const payloadEcommerceCouponPlugin = (pluginOptions = {}) => (incomingConfig) => {
|
|
4
|
+
const { enabled = true, defaultCurrency = "USD", allowStackWithOtherCoupons = false, collections: collectionConfig = {}, autoIntegrate = true } = pluginOptions;
|
|
5
|
+
if (!enabled) return incomingConfig;
|
|
6
|
+
return { ...incomingConfig };
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/client/hooks.ts
|
|
11
|
+
/**
|
|
12
|
+
* Apply a coupon code to a cart
|
|
13
|
+
* @param options - Coupon code, cart ID, and customer email
|
|
14
|
+
* @returns Response with success status, discount amount, and coupon details
|
|
15
|
+
*/
|
|
16
|
+
async function useCouponCode(options) {
|
|
17
|
+
const { code, cartID, customerEmail } = options;
|
|
18
|
+
if (!code) return {
|
|
19
|
+
success: false,
|
|
20
|
+
message: "Coupon code is required",
|
|
21
|
+
error: "Code is missing"
|
|
22
|
+
};
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch("/api/ecommerce/coupons/apply", {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
code,
|
|
29
|
+
cartID,
|
|
30
|
+
customerEmail
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
const data = await response.json();
|
|
34
|
+
if (!response.ok) return {
|
|
35
|
+
success: false,
|
|
36
|
+
message: data.error || "Failed to apply coupon",
|
|
37
|
+
error: data.error
|
|
38
|
+
};
|
|
39
|
+
const couponData = data.coupon;
|
|
40
|
+
return {
|
|
41
|
+
success: data.success,
|
|
42
|
+
message: data.message,
|
|
43
|
+
discount: data.discount,
|
|
44
|
+
coupon: couponData ? {
|
|
45
|
+
code: couponData.code || "",
|
|
46
|
+
type: couponData.type || "percentage",
|
|
47
|
+
value: couponData.value || 0
|
|
48
|
+
} : void 0
|
|
49
|
+
};
|
|
50
|
+
} catch (error) {
|
|
51
|
+
const message = error instanceof Error ? error.message : "Network error";
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
message,
|
|
55
|
+
error: message
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validate a coupon code without applying it
|
|
61
|
+
* @param code - Coupon code to validate
|
|
62
|
+
* @param cartValue - Optional cart value in smallest currency unit
|
|
63
|
+
* @returns Response with validation result and coupon details
|
|
64
|
+
*/
|
|
65
|
+
async function validateCouponCode(code, cartValue) {
|
|
66
|
+
if (!code) return {
|
|
67
|
+
success: false,
|
|
68
|
+
message: "Code required",
|
|
69
|
+
error: "Code missing"
|
|
70
|
+
};
|
|
71
|
+
try {
|
|
72
|
+
const response = await fetch("/api/ecommerce/coupons/validate", {
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: { "Content-Type": "application/json" },
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
code,
|
|
77
|
+
cartValue
|
|
78
|
+
})
|
|
79
|
+
});
|
|
80
|
+
const data = await response.json();
|
|
81
|
+
if (!response.ok) return {
|
|
82
|
+
success: false,
|
|
83
|
+
message: data.error || "Invalid coupon",
|
|
84
|
+
error: data.error
|
|
85
|
+
};
|
|
86
|
+
const couponData = data.coupon;
|
|
87
|
+
return {
|
|
88
|
+
success: data.success,
|
|
89
|
+
message: data.message,
|
|
90
|
+
coupon: couponData ? {
|
|
91
|
+
code: couponData.code || "",
|
|
92
|
+
type: couponData.type || "percentage",
|
|
93
|
+
value: couponData.value || 0
|
|
94
|
+
} : void 0
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const message = error instanceof Error ? error.message : "Network error";
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
message,
|
|
101
|
+
error: message
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/index.ts
|
|
108
|
+
const payloadEcommerceCoupon = payloadEcommerceCouponPlugin;
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
exports.payloadEcommerceCoupon = payloadEcommerceCoupon;
|
|
112
|
+
exports.useCouponCode = useCouponCode;
|
|
113
|
+
exports.validateCouponCode = validateCouponCode;
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/plugin.ts","../src/client/hooks.ts","../src/index.ts"],"sourcesContent":["import type { Config } from 'payload'\nimport type { CouponPluginOptions } from './types'\n\nexport const payloadEcommerceCouponPlugin =\n (pluginOptions: CouponPluginOptions = {}) =>\n (incomingConfig: Config): Config => {\n const {\n enabled = true,\n defaultCurrency = 'USD',\n allowStackWithOtherCoupons = false,\n collections: collectionConfig = {},\n autoIntegrate = true,\n } = pluginOptions\n\n // Assign to underscore-prefixed variables for intentionally unused params\n const _defaultCurrency = defaultCurrency\n const _allowStackWithOtherCoupons = allowStackWithOtherCoupons\n const _collectionConfig = collectionConfig\n const _autoIntegrate = autoIntegrate\n\n if (!enabled) return incomingConfig\n\n const config = { ...incomingConfig }\n\n // TODO: Add collections\n // TODO: Add endpoints\n // TODO: Add hooks\n // TODO: Auto-integrate with ecommerce collections\n\n return config\n }\n","import type { ApplyCouponHook, ApplyCouponResponse } from '../types'\n\n/**\n * Apply a coupon code to a cart\n * @param options - Coupon code, cart ID, and customer email\n * @returns Response with success status, discount amount, and coupon details\n */\nexport async function useCouponCode(options: ApplyCouponHook): Promise<ApplyCouponResponse> {\n const { code, cartID, customerEmail } = options\n\n if (!code) {\n return {\n success: false,\n message: 'Coupon code is required',\n error: 'Code is missing',\n }\n }\n\n try {\n const response = await fetch('/api/ecommerce/coupons/apply', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code, cartID, customerEmail }),\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n message: (data.error as string) || 'Failed to apply coupon',\n error: data.error as string,\n }\n }\n\n const couponData = data.coupon as Record<string, unknown> | undefined\n\n return {\n success: data.success as boolean,\n message: data.message as string,\n discount: data.discount as number,\n coupon: couponData\n ? {\n code: (couponData.code as string) || '',\n type: (couponData.type as 'percentage' | 'fixed') || 'percentage',\n value: (couponData.value as number) || 0,\n }\n : undefined,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, message, error: message }\n }\n}\n\n/**\n * Validate a coupon code without applying it\n * @param code - Coupon code to validate\n * @param cartValue - Optional cart value in smallest currency unit\n * @returns Response with validation result and coupon details\n */\nexport async function validateCouponCode(\n code: string,\n cartValue?: number,\n): Promise<ApplyCouponResponse> {\n if (!code) {\n return {\n success: false,\n message: 'Code required',\n error: 'Code missing',\n }\n }\n\n try {\n const response = await fetch('/api/ecommerce/coupons/validate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code, cartValue }),\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n message: (data.error as string) || 'Invalid coupon',\n error: data.error as string,\n }\n }\n\n const couponData = data.coupon as Record<string, unknown> | undefined\n\n return {\n success: data.success as boolean,\n message: data.message as string,\n coupon: couponData\n ? {\n code: (couponData.code as string) || '',\n type: (couponData.type as 'percentage' | 'fixed') || 'percentage',\n value: (couponData.value as number) || 0,\n }\n : undefined,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, message, error: message }\n }\n}\n","import { payloadEcommerceCouponPlugin } from './plugin'\n\nexport type { CouponPluginOptions, ApplyCouponResponse, ApplyCouponHook } from './types'\nexport { useCouponCode, validateCouponCode } from './client/hooks'\n\nexport const payloadEcommerceCoupon = payloadEcommerceCouponPlugin\n"],"mappings":";;AAGA,MAAa,gCACV,gBAAqC,EAAE,MACvC,mBAAmC;CAClC,MAAM,EACJ,UAAU,MACV,kBAAkB,OAClB,6BAA6B,OAC7B,aAAa,mBAAmB,EAAE,EAClC,gBAAgB,SACd;AAQJ,KAAI,CAAC,QAAS,QAAO;AASrB,QAPe,EAAE,GAAG,gBAAgB;;;;;;;;;;ACfxC,eAAsB,cAAc,SAAwD;CAC1F,MAAM,EAAE,MAAM,QAAQ,kBAAkB;AAExC,KAAI,CAAC,KACH,QAAO;EACL,SAAS;EACT,SAAS;EACT,OAAO;EACR;AAGH,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,gCAAgC;GAC3D,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU;IAAE;IAAM;IAAQ;IAAe,CAAC;GACtD,CAAC;EAEF,MAAM,OAAQ,MAAM,SAAS,MAAM;AAEnC,MAAI,CAAC,SAAS,GACZ,QAAO;GACL,SAAS;GACT,SAAU,KAAK,SAAoB;GACnC,OAAO,KAAK;GACb;EAGH,MAAM,aAAa,KAAK;AAExB,SAAO;GACL,SAAS,KAAK;GACd,SAAS,KAAK;GACd,UAAU,KAAK;GACf,QAAQ,aACJ;IACE,MAAO,WAAW,QAAmB;IACrC,MAAO,WAAW,QAAmC;IACrD,OAAQ,WAAW,SAAoB;IACxC,GACD;GACL;UACM,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,SAAO;GAAE,SAAS;GAAO;GAAS,OAAO;GAAS;;;;;;;;;AAUtD,eAAsB,mBACpB,MACA,WAC8B;AAC9B,KAAI,CAAC,KACH,QAAO;EACL,SAAS;EACT,SAAS;EACT,OAAO;EACR;AAGH,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,mCAAmC;GAC9D,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU;IAAE;IAAM;IAAW,CAAC;GAC1C,CAAC;EAEF,MAAM,OAAQ,MAAM,SAAS,MAAM;AAEnC,MAAI,CAAC,SAAS,GACZ,QAAO;GACL,SAAS;GACT,SAAU,KAAK,SAAoB;GACnC,OAAO,KAAK;GACb;EAGH,MAAM,aAAa,KAAK;AAExB,SAAO;GACL,SAAS,KAAK;GACd,SAAS,KAAK;GACd,QAAQ,aACJ;IACE,MAAO,WAAW,QAAmB;IACrC,MAAO,WAAW,QAAmC;IACrD,OAAQ,WAAW,SAAoB;IACxC,GACD;GACL;UACM,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,SAAO;GAAE,SAAS;GAAO;GAAS,OAAO;GAAS;;;;;;ACpGtD,MAAa,yBAAyB"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
//#region src/plugin.ts
|
|
2
|
+
const payloadEcommerceCouponPlugin = (pluginOptions = {}) => (incomingConfig) => {
|
|
3
|
+
const { enabled = true, defaultCurrency = "USD", allowStackWithOtherCoupons = false, collections: collectionConfig = {}, autoIntegrate = true } = pluginOptions;
|
|
4
|
+
if (!enabled) return incomingConfig;
|
|
5
|
+
return { ...incomingConfig };
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/client/hooks.ts
|
|
10
|
+
/**
|
|
11
|
+
* Apply a coupon code to a cart
|
|
12
|
+
* @param options - Coupon code, cart ID, and customer email
|
|
13
|
+
* @returns Response with success status, discount amount, and coupon details
|
|
14
|
+
*/
|
|
15
|
+
async function useCouponCode(options) {
|
|
16
|
+
const { code, cartID, customerEmail } = options;
|
|
17
|
+
if (!code) return {
|
|
18
|
+
success: false,
|
|
19
|
+
message: "Coupon code is required",
|
|
20
|
+
error: "Code is missing"
|
|
21
|
+
};
|
|
22
|
+
try {
|
|
23
|
+
const response = await fetch("/api/ecommerce/coupons/apply", {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: { "Content-Type": "application/json" },
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
code,
|
|
28
|
+
cartID,
|
|
29
|
+
customerEmail
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
const data = await response.json();
|
|
33
|
+
if (!response.ok) return {
|
|
34
|
+
success: false,
|
|
35
|
+
message: data.error || "Failed to apply coupon",
|
|
36
|
+
error: data.error
|
|
37
|
+
};
|
|
38
|
+
const couponData = data.coupon;
|
|
39
|
+
return {
|
|
40
|
+
success: data.success,
|
|
41
|
+
message: data.message,
|
|
42
|
+
discount: data.discount,
|
|
43
|
+
coupon: couponData ? {
|
|
44
|
+
code: couponData.code || "",
|
|
45
|
+
type: couponData.type || "percentage",
|
|
46
|
+
value: couponData.value || 0
|
|
47
|
+
} : void 0
|
|
48
|
+
};
|
|
49
|
+
} catch (error) {
|
|
50
|
+
const message = error instanceof Error ? error.message : "Network error";
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
message,
|
|
54
|
+
error: message
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validate a coupon code without applying it
|
|
60
|
+
* @param code - Coupon code to validate
|
|
61
|
+
* @param cartValue - Optional cart value in smallest currency unit
|
|
62
|
+
* @returns Response with validation result and coupon details
|
|
63
|
+
*/
|
|
64
|
+
async function validateCouponCode(code, cartValue) {
|
|
65
|
+
if (!code) return {
|
|
66
|
+
success: false,
|
|
67
|
+
message: "Code required",
|
|
68
|
+
error: "Code missing"
|
|
69
|
+
};
|
|
70
|
+
try {
|
|
71
|
+
const response = await fetch("/api/ecommerce/coupons/validate", {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: { "Content-Type": "application/json" },
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
code,
|
|
76
|
+
cartValue
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
const data = await response.json();
|
|
80
|
+
if (!response.ok) return {
|
|
81
|
+
success: false,
|
|
82
|
+
message: data.error || "Invalid coupon",
|
|
83
|
+
error: data.error
|
|
84
|
+
};
|
|
85
|
+
const couponData = data.coupon;
|
|
86
|
+
return {
|
|
87
|
+
success: data.success,
|
|
88
|
+
message: data.message,
|
|
89
|
+
coupon: couponData ? {
|
|
90
|
+
code: couponData.code || "",
|
|
91
|
+
type: couponData.type || "percentage",
|
|
92
|
+
value: couponData.value || 0
|
|
93
|
+
} : void 0
|
|
94
|
+
};
|
|
95
|
+
} catch (error) {
|
|
96
|
+
const message = error instanceof Error ? error.message : "Network error";
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
message,
|
|
100
|
+
error: message
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/index.ts
|
|
107
|
+
const payloadEcommerceCoupon = payloadEcommerceCouponPlugin;
|
|
108
|
+
|
|
109
|
+
//#endregion
|
|
110
|
+
export { payloadEcommerceCoupon, useCouponCode, validateCouponCode };
|
|
111
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/plugin.ts","../src/client/hooks.ts","../src/index.ts"],"sourcesContent":["import type { Config } from 'payload'\nimport type { CouponPluginOptions } from './types'\n\nexport const payloadEcommerceCouponPlugin =\n (pluginOptions: CouponPluginOptions = {}) =>\n (incomingConfig: Config): Config => {\n const {\n enabled = true,\n defaultCurrency = 'USD',\n allowStackWithOtherCoupons = false,\n collections: collectionConfig = {},\n autoIntegrate = true,\n } = pluginOptions\n\n // Assign to underscore-prefixed variables for intentionally unused params\n const _defaultCurrency = defaultCurrency\n const _allowStackWithOtherCoupons = allowStackWithOtherCoupons\n const _collectionConfig = collectionConfig\n const _autoIntegrate = autoIntegrate\n\n if (!enabled) return incomingConfig\n\n const config = { ...incomingConfig }\n\n // TODO: Add collections\n // TODO: Add endpoints\n // TODO: Add hooks\n // TODO: Auto-integrate with ecommerce collections\n\n return config\n }\n","import type { ApplyCouponHook, ApplyCouponResponse } from '../types'\n\n/**\n * Apply a coupon code to a cart\n * @param options - Coupon code, cart ID, and customer email\n * @returns Response with success status, discount amount, and coupon details\n */\nexport async function useCouponCode(options: ApplyCouponHook): Promise<ApplyCouponResponse> {\n const { code, cartID, customerEmail } = options\n\n if (!code) {\n return {\n success: false,\n message: 'Coupon code is required',\n error: 'Code is missing',\n }\n }\n\n try {\n const response = await fetch('/api/ecommerce/coupons/apply', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code, cartID, customerEmail }),\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n message: (data.error as string) || 'Failed to apply coupon',\n error: data.error as string,\n }\n }\n\n const couponData = data.coupon as Record<string, unknown> | undefined\n\n return {\n success: data.success as boolean,\n message: data.message as string,\n discount: data.discount as number,\n coupon: couponData\n ? {\n code: (couponData.code as string) || '',\n type: (couponData.type as 'percentage' | 'fixed') || 'percentage',\n value: (couponData.value as number) || 0,\n }\n : undefined,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, message, error: message }\n }\n}\n\n/**\n * Validate a coupon code without applying it\n * @param code - Coupon code to validate\n * @param cartValue - Optional cart value in smallest currency unit\n * @returns Response with validation result and coupon details\n */\nexport async function validateCouponCode(\n code: string,\n cartValue?: number,\n): Promise<ApplyCouponResponse> {\n if (!code) {\n return {\n success: false,\n message: 'Code required',\n error: 'Code missing',\n }\n }\n\n try {\n const response = await fetch('/api/ecommerce/coupons/validate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code, cartValue }),\n })\n\n const data = (await response.json()) as Record<string, unknown>\n\n if (!response.ok) {\n return {\n success: false,\n message: (data.error as string) || 'Invalid coupon',\n error: data.error as string,\n }\n }\n\n const couponData = data.coupon as Record<string, unknown> | undefined\n\n return {\n success: data.success as boolean,\n message: data.message as string,\n coupon: couponData\n ? {\n code: (couponData.code as string) || '',\n type: (couponData.type as 'percentage' | 'fixed') || 'percentage',\n value: (couponData.value as number) || 0,\n }\n : undefined,\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Network error'\n return { success: false, message, error: message }\n }\n}\n","import { payloadEcommerceCouponPlugin } from './plugin'\n\nexport type { CouponPluginOptions, ApplyCouponResponse, ApplyCouponHook } from './types'\nexport { useCouponCode, validateCouponCode } from './client/hooks'\n\nexport const payloadEcommerceCoupon = payloadEcommerceCouponPlugin\n"],"mappings":";AAGA,MAAa,gCACV,gBAAqC,EAAE,MACvC,mBAAmC;CAClC,MAAM,EACJ,UAAU,MACV,kBAAkB,OAClB,6BAA6B,OAC7B,aAAa,mBAAmB,EAAE,EAClC,gBAAgB,SACd;AAQJ,KAAI,CAAC,QAAS,QAAO;AASrB,QAPe,EAAE,GAAG,gBAAgB;;;;;;;;;;ACfxC,eAAsB,cAAc,SAAwD;CAC1F,MAAM,EAAE,MAAM,QAAQ,kBAAkB;AAExC,KAAI,CAAC,KACH,QAAO;EACL,SAAS;EACT,SAAS;EACT,OAAO;EACR;AAGH,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,gCAAgC;GAC3D,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU;IAAE;IAAM;IAAQ;IAAe,CAAC;GACtD,CAAC;EAEF,MAAM,OAAQ,MAAM,SAAS,MAAM;AAEnC,MAAI,CAAC,SAAS,GACZ,QAAO;GACL,SAAS;GACT,SAAU,KAAK,SAAoB;GACnC,OAAO,KAAK;GACb;EAGH,MAAM,aAAa,KAAK;AAExB,SAAO;GACL,SAAS,KAAK;GACd,SAAS,KAAK;GACd,UAAU,KAAK;GACf,QAAQ,aACJ;IACE,MAAO,WAAW,QAAmB;IACrC,MAAO,WAAW,QAAmC;IACrD,OAAQ,WAAW,SAAoB;IACxC,GACD;GACL;UACM,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,SAAO;GAAE,SAAS;GAAO;GAAS,OAAO;GAAS;;;;;;;;;AAUtD,eAAsB,mBACpB,MACA,WAC8B;AAC9B,KAAI,CAAC,KACH,QAAO;EACL,SAAS;EACT,SAAS;EACT,OAAO;EACR;AAGH,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,mCAAmC;GAC9D,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU;IAAE;IAAM;IAAW,CAAC;GAC1C,CAAC;EAEF,MAAM,OAAQ,MAAM,SAAS,MAAM;AAEnC,MAAI,CAAC,SAAS,GACZ,QAAO;GACL,SAAS;GACT,SAAU,KAAK,SAAoB;GACnC,OAAO,KAAK;GACb;EAGH,MAAM,aAAa,KAAK;AAExB,SAAO;GACL,SAAS,KAAK;GACd,SAAS,KAAK;GACd,QAAQ,aACJ;IACE,MAAO,WAAW,QAAmB;IACrC,MAAO,WAAW,QAAmC;IACrD,OAAQ,WAAW,SAAoB;IACxC,GACD;GACL;UACM,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,SAAO;GAAE,SAAS;GAAO;GAAS,OAAO;GAAS;;;;;;ACpGtD,MAAa,yBAAyB"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElD,eAAO,MAAM,4BAA4B,GACtC,gBAAe,mBAAwB,MACvC,gBAAgB,MAAM,KAAG,MAyBzB,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type CouponPluginCollections = {
|
|
2
|
+
couponsSlug?: string;
|
|
3
|
+
referralProgramsSlug?: string;
|
|
4
|
+
referralCodesSlug?: string;
|
|
5
|
+
referralPartnersSlug?: string;
|
|
6
|
+
};
|
|
7
|
+
export type CouponPluginOptions = {
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
allowStackWithOtherCoupons?: boolean;
|
|
10
|
+
defaultCurrency?: string;
|
|
11
|
+
collections?: CouponPluginCollections;
|
|
12
|
+
autoIntegrate?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export type ApplyCouponHook = {
|
|
15
|
+
code: string;
|
|
16
|
+
cartID?: string;
|
|
17
|
+
customerEmail?: string;
|
|
18
|
+
};
|
|
19
|
+
export type ApplyCouponResponse = {
|
|
20
|
+
success: boolean;
|
|
21
|
+
message: string;
|
|
22
|
+
discount?: number;
|
|
23
|
+
coupon?: {
|
|
24
|
+
code: string;
|
|
25
|
+
type: 'percentage' | 'fixed';
|
|
26
|
+
value: number;
|
|
27
|
+
};
|
|
28
|
+
error?: string;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,WAAW,CAAC,EAAE,uBAAuB,CAAA;IACrC,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,YAAY,GAAG,OAAO,CAAA;QAC5B,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;IACD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "@wtree/payload-ecommerce-coupon",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Production-ready coupon and referral system plugin for Payload CMS Ecommerce Plugin",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "bun run clean && rolldown -c && tsc --declaration --emitDeclarationOnly --outDir dist",
|
|
23
|
+
"clean": "rm -rf dist",
|
|
24
|
+
"dev": "rolldown -c --watch",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"test:coverage": "vitest run --coverage",
|
|
28
|
+
"lint": "eslint src --ext .ts",
|
|
29
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
30
|
+
"prepublishOnly": "bun run test && bun run build",
|
|
31
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
32
|
+
"format:check": "prettier --check \"src/**/*.ts\""
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"payload",
|
|
36
|
+
"payloadcms",
|
|
37
|
+
"payload-plugin",
|
|
38
|
+
"ecommerce",
|
|
39
|
+
"coupon",
|
|
40
|
+
"referral",
|
|
41
|
+
"promotion",
|
|
42
|
+
"discount"
|
|
43
|
+
],
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/technewwings/payload-ecommerce-coupon.git"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/technewwings/payload-ecommerce-coupon/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/technewwings/payload-ecommerce-coupon#readme",
|
|
52
|
+
"author": "wtree",
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18.0.0"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"payload": "^3.0.0",
|
|
59
|
+
"@payloadcms/plugin-ecommerce": ">=3.0.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@eslint/js": "^9.39.2",
|
|
63
|
+
"@types/node": "^25.0.9",
|
|
64
|
+
"@typescript-eslint/eslint-plugin": "^8.53.1",
|
|
65
|
+
"@typescript-eslint/parser": "^8.53.1",
|
|
66
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
67
|
+
"eslint": "^9.39.2",
|
|
68
|
+
"eslint-config-prettier": "^10.1.8",
|
|
69
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
70
|
+
"prettier": "^3.0.0",
|
|
71
|
+
"rolldown": "^1.0.0-beta.60",
|
|
72
|
+
"typescript": "^5.0.0",
|
|
73
|
+
"typescript-eslint": "8.53.1",
|
|
74
|
+
"vitest": "^4.0.17"
|
|
75
|
+
},
|
|
76
|
+
"dependencies": {}
|
|
77
|
+
}
|