@shopnex/cj-plugin 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -0
- package/dist/CjConfig.d.ts +7 -0
- package/dist/CjConfig.js +93 -0
- package/dist/CjConfig.js.map +1 -0
- package/dist/cj-settings.js +41 -2
- package/dist/cj-settings.js.map +1 -1
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/exports/rsc.js +3 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +31 -11
- package/dist/index.js.map +1 -1
- package/dist/rsc/ApiToken.d.ts +9 -0
- package/dist/rsc/ApiToken.js +21 -0
- package/dist/rsc/ApiToken.js.map +1 -0
- package/dist/rsc/ApiToken.scss +5 -0
- package/dist/sdk/access-token.d.ts +2 -1
- package/dist/sdk/access-token.js +15 -13
- package/dist/sdk/access-token.js.map +1 -1
- package/dist/sdk/products/products.js.map +1 -1
- package/dist/service/create-order.hook.js +10 -4
- package/dist/service/create-order.hook.js.map +1 -1
- package/dist/service/sync-products.js +1 -0
- package/dist/service/sync-products.js.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util/manage-tokens.d.ts +4 -0
- package/dist/util/manage-tokens.js +41 -0
- package/dist/util/manage-tokens.js.map +1 -0
- package/package.json +1 -1
package/README.md
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# CJ Dropshipping Plugin for Payload CMS
|
2
|
+
|
3
|
+
This plugin integrates **CJ Dropshipping** into your **Payload CMS** project by:
|
4
|
+
|
5
|
+
- Adding "CJ" as a product source.
|
6
|
+
- Automatically creating CJ orders after local orders are created.
|
7
|
+
- (Optionally) generating a `cj-settings` collection for managing API credentials dynamically.
|
8
|
+
- Syncing CJ credentials on app initialization.
|
9
|
+
|
10
|
+
---
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
```bash
|
15
|
+
pnpm install @shopnex/cj-plugin
|
16
|
+
```
|
17
|
+
|
18
|
+
or
|
19
|
+
|
20
|
+
```bash
|
21
|
+
npm install @shopnex/cj-plugin
|
22
|
+
```
|
23
|
+
|
24
|
+
or
|
25
|
+
|
26
|
+
```bash
|
27
|
+
yarn add @shopnex/cj-plugin
|
28
|
+
```
|
29
|
+
|
30
|
+
---
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
Import and add the `cjPlugin` to your Payload config:
|
35
|
+
|
36
|
+
```ts
|
37
|
+
import { buildConfig } from "payload/config";
|
38
|
+
import { cjPlugin } from "@shopnex/cj-plugin";
|
39
|
+
|
40
|
+
export default buildConfig({
|
41
|
+
collections: [
|
42
|
+
// your collections
|
43
|
+
],
|
44
|
+
plugins: [
|
45
|
+
cjPlugin({
|
46
|
+
cjApiKey: "your-cj-api-key",
|
47
|
+
cjEmailAddress: "your-email@example.com",
|
48
|
+
cjRefreshToken: "optional-refresh-token", // optional
|
49
|
+
asCollection: true, // optional - creates a cj-settings collection
|
50
|
+
collectionOverrides: {
|
51
|
+
// optional - override fields or settings for the cj-settings collection
|
52
|
+
},
|
53
|
+
}),
|
54
|
+
],
|
55
|
+
});
|
56
|
+
```
|
57
|
+
|
58
|
+
---
|
59
|
+
|
60
|
+
## Plugin Options
|
61
|
+
|
62
|
+
| Option | Type | Required | Description |
|
63
|
+
| --------------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------- |
|
64
|
+
| `cjApiKey` | `string` | Yes | Your CJ Dropshipping API key. |
|
65
|
+
| `cjEmailAddress` | `string` | Yes | Your CJ account email address. |
|
66
|
+
| `cjRefreshToken` | `string` | No | Your CJ refresh token if available. |
|
67
|
+
| `asCollection` | `boolean` | No | If true, automatically creates a `cj-settings` collection to manage CJ API credentials per tenant/shop. |
|
68
|
+
| `collectionOverrides` | `object` | No | Allows overriding the default `cj-settings` collection config (fields, hooks, etc). |
|
69
|
+
|
70
|
+
---
|
71
|
+
|
72
|
+
## What the Plugin Does
|
73
|
+
|
74
|
+
- **Modifies the `products` collection**:
|
75
|
+
- Adds a `source` option: `{ label: 'CJ', value: 'cj' }`.
|
76
|
+
- **Hooks into the `orders` collection**:
|
77
|
+
- On every new order or update, triggers the CJ order creation logic automatically.
|
78
|
+
- **Manages CJ credentials dynamically**:
|
79
|
+
- On Payload startup (`onInit`), loads all `cj-settings` documents and sets up credentials per shop.
|
80
|
+
- **Optional `cj-settings` collection**:
|
81
|
+
- If `asCollection` is true, a new `cj-settings` collection will be added automatically.
|
82
|
+
- Useful for multi-tenant setups or dynamically changing credentials.
|
83
|
+
|
84
|
+
---
|
85
|
+
|
86
|
+
## Example: cj-settings Collection
|
87
|
+
|
88
|
+
If `asCollection: true`, the following collection will be generated by default:
|
89
|
+
|
90
|
+
| Field | Type | Description |
|
91
|
+
| ---------- | -------- | --------------------------------- |
|
92
|
+
| `shop` | Relation | Reference to your shop or tenant. |
|
93
|
+
| `email` | Text | Your CJ email address. |
|
94
|
+
| `apiToken` | Text | Your CJ API key. |
|
95
|
+
|
96
|
+
You can override this structure with `collectionOverrides`.
|
97
|
+
|
98
|
+
---
|
99
|
+
|
100
|
+
## Notes
|
101
|
+
|
102
|
+
- The plugin assumes you have a `products` collection with a `source` select field already created.
|
103
|
+
- It assumes you have an `orders` collection.
|
104
|
+
- Make sure the `source` field in `products` uses a `select` type with `options` array.
|
105
|
+
|
106
|
+
---
|
107
|
+
|
108
|
+
## License
|
109
|
+
|
110
|
+
MIT
|
package/dist/CjConfig.js
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
import { decryptToken, encryptToken } from "./util/manage-tokens";
|
2
|
+
import { syncProducts } from "./service/sync-products";
|
3
|
+
export const CjConfigCollection = ({ overrides })=>({
|
4
|
+
slug: "cj-settings",
|
5
|
+
access: {
|
6
|
+
...overrides?.access
|
7
|
+
},
|
8
|
+
admin: {
|
9
|
+
group: "Plugins"
|
10
|
+
},
|
11
|
+
fields: [
|
12
|
+
{
|
13
|
+
label: "Credentials",
|
14
|
+
type: "collapsible",
|
15
|
+
fields: [
|
16
|
+
{
|
17
|
+
type: "row",
|
18
|
+
fields: [
|
19
|
+
{
|
20
|
+
name: "emailAddress",
|
21
|
+
type: "text"
|
22
|
+
},
|
23
|
+
{
|
24
|
+
name: "apiToken",
|
25
|
+
type: "text",
|
26
|
+
admin: {
|
27
|
+
components: {
|
28
|
+
Field: "@shopnex/cj-plugin/rsc#ApiToken"
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
]
|
33
|
+
}
|
34
|
+
]
|
35
|
+
},
|
36
|
+
{
|
37
|
+
label: "Logo Area POD",
|
38
|
+
name: "pod",
|
39
|
+
type: "upload",
|
40
|
+
relationTo: "media"
|
41
|
+
},
|
42
|
+
{
|
43
|
+
name: "items",
|
44
|
+
type: "array",
|
45
|
+
admin: {
|
46
|
+
description: "A list of product URLs to sync with CJ Dropshipping"
|
47
|
+
},
|
48
|
+
fields: [
|
49
|
+
{
|
50
|
+
name: "productUrl",
|
51
|
+
type: "text"
|
52
|
+
}
|
53
|
+
],
|
54
|
+
label: "Products",
|
55
|
+
labels: {
|
56
|
+
plural: "Product URLs",
|
57
|
+
singular: "Product URL"
|
58
|
+
}
|
59
|
+
}
|
60
|
+
],
|
61
|
+
hooks: {
|
62
|
+
beforeChange: [
|
63
|
+
({ data })=>{
|
64
|
+
const tokenToEncrypt = data.apiToken;
|
65
|
+
const encryptedToken = encryptToken(tokenToEncrypt);
|
66
|
+
data.apiToken = encryptedToken;
|
67
|
+
}
|
68
|
+
],
|
69
|
+
beforeRead: [
|
70
|
+
({ doc })=>{
|
71
|
+
doc.apiToken = doc?.apiToken && decryptToken(doc.apiToken);
|
72
|
+
}
|
73
|
+
],
|
74
|
+
afterChange: [
|
75
|
+
async ({ doc, req: { payload } })=>{
|
76
|
+
const productIds = doc.items.map((item)=>{
|
77
|
+
const match = item.productUrl.match(/(?<=-p-)([0-9A-Fa-f-]+)(?=\.html)/);
|
78
|
+
return match ? match[0] : null;
|
79
|
+
});
|
80
|
+
await syncProducts(productIds, payload);
|
81
|
+
},
|
82
|
+
({ doc })=>{
|
83
|
+
doc.apiToken = doc.apiToken && decryptToken(doc.apiToken);
|
84
|
+
}
|
85
|
+
]
|
86
|
+
},
|
87
|
+
labels: {
|
88
|
+
singular: "CJ Dropshipping",
|
89
|
+
plural: "CJ Configs"
|
90
|
+
}
|
91
|
+
});
|
92
|
+
|
93
|
+
//# sourceMappingURL=CjConfig.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../src/CjConfig.ts"],"sourcesContent":["import { CollectionConfig } from \"payload\";\nimport { decryptToken, encryptToken } from \"./util/manage-tokens\";\nimport { syncProducts } from \"./service/sync-products\";\n\nexport type CjCollectionProps = {\n overrides?: {\n access: CollectionConfig[\"access\"];\n };\n};\n\nexport const CjConfigCollection = ({ overrides }: CjCollectionProps): CollectionConfig => ({\n slug: \"cj-settings\",\n access: {\n ...overrides?.access,\n },\n admin: {\n group: \"Plugins\",\n },\n fields: [\n {\n label: \"Credentials\",\n type: \"collapsible\",\n fields: [\n {\n type: \"row\",\n fields: [\n {\n name: \"emailAddress\",\n type: \"text\",\n },\n {\n name: \"apiToken\",\n type: \"text\",\n admin: {\n components: {\n Field: \"@shopnex/cj-plugin/rsc#ApiToken\",\n },\n },\n },\n ],\n },\n ],\n },\n {\n label: \"Logo Area POD\",\n name: \"pod\",\n type: \"upload\",\n relationTo: \"media\",\n },\n {\n name: \"items\",\n type: \"array\",\n admin: {\n description: \"A list of product URLs to sync with CJ Dropshipping\",\n },\n fields: [\n {\n name: \"productUrl\",\n type: \"text\",\n },\n ],\n label: \"Products\",\n labels: {\n plural: \"Product URLs\",\n singular: \"Product URL\",\n },\n },\n ],\n hooks: {\n beforeChange: [\n ({ data }) => {\n const tokenToEncrypt = data.apiToken;\n const encryptedToken = encryptToken(tokenToEncrypt);\n data.apiToken = encryptedToken;\n },\n ],\n beforeRead: [\n ({ doc }) => {\n doc.apiToken = doc?.apiToken && decryptToken(doc.apiToken);\n },\n ],\n afterChange: [\n async ({ doc, req: { payload } }) => {\n const productIds = doc.items.map((item: any) => {\n const match = item.productUrl.match(/(?<=-p-)([0-9A-Fa-f-]+)(?=\\.html)/);\n return match ? match[0] : null;\n });\n await syncProducts(productIds, payload);\n },\n ({ doc }) => {\n doc.apiToken = doc.apiToken && decryptToken(doc.apiToken);\n },\n ],\n },\n labels: {\n singular: \"CJ Dropshipping\",\n plural: \"CJ Configs\",\n },\n});\n"],"names":["decryptToken","encryptToken","syncProducts","CjConfigCollection","overrides","slug","access","admin","group","fields","label","type","name","components","Field","relationTo","description","labels","plural","singular","hooks","beforeChange","data","tokenToEncrypt","apiToken","encryptedToken","beforeRead","doc","afterChange","req","payload","productIds","items","map","item","match","productUrl"],"mappings":"AACA,SAASA,YAAY,EAAEC,YAAY,QAAQ,uBAAuB;AAClE,SAASC,YAAY,QAAQ,0BAA0B;AAQvD,OAAO,MAAMC,qBAAqB,CAAC,EAAEC,SAAS,EAAqB,GAAwB,CAAA;QACvFC,MAAM;QACNC,QAAQ;YACJ,GAAGF,WAAWE,MAAM;QACxB;QACAC,OAAO;YACHC,OAAO;QACX;QACAC,QAAQ;YACJ;gBACIC,OAAO;gBACPC,MAAM;gBACNF,QAAQ;oBACJ;wBACIE,MAAM;wBACNF,QAAQ;4BACJ;gCACIG,MAAM;gCACND,MAAM;4BACV;4BACA;gCACIC,MAAM;gCACND,MAAM;gCACNJ,OAAO;oCACHM,YAAY;wCACRC,OAAO;oCACX;gCACJ;4BACJ;yBACH;oBACL;iBACH;YACL;YACA;gBACIJ,OAAO;gBACPE,MAAM;gBACND,MAAM;gBACNI,YAAY;YAChB;YACA;gBACIH,MAAM;gBACND,MAAM;gBACNJ,OAAO;oBACHS,aAAa;gBACjB;gBACAP,QAAQ;oBACJ;wBACIG,MAAM;wBACND,MAAM;oBACV;iBACH;gBACDD,OAAO;gBACPO,QAAQ;oBACJC,QAAQ;oBACRC,UAAU;gBACd;YACJ;SACH;QACDC,OAAO;YACHC,cAAc;gBACV,CAAC,EAAEC,IAAI,EAAE;oBACL,MAAMC,iBAAiBD,KAAKE,QAAQ;oBACpC,MAAMC,iBAAiBxB,aAAasB;oBACpCD,KAAKE,QAAQ,GAAGC;gBACpB;aACH;YACDC,YAAY;gBACR,CAAC,EAAEC,GAAG,EAAE;oBACJA,IAAIH,QAAQ,GAAGG,KAAKH,YAAYxB,aAAa2B,IAAIH,QAAQ;gBAC7D;aACH;YACDI,aAAa;gBACT,OAAO,EAAED,GAAG,EAAEE,KAAK,EAAEC,OAAO,EAAE,EAAE;oBAC5B,MAAMC,aAAaJ,IAAIK,KAAK,CAACC,GAAG,CAAC,CAACC;wBAC9B,MAAMC,QAAQD,KAAKE,UAAU,CAACD,KAAK,CAAC;wBACpC,OAAOA,QAAQA,KAAK,CAAC,EAAE,GAAG;oBAC9B;oBACA,MAAMjC,aAAa6B,YAAYD;gBACnC;gBACA,CAAC,EAAEH,GAAG,EAAE;oBACJA,IAAIH,QAAQ,GAAGG,IAAIH,QAAQ,IAAIxB,aAAa2B,IAAIH,QAAQ;gBAC5D;aACH;QACL;QACAP,QAAQ;YACJE,UAAU;YACVD,QAAQ;QACZ;IACJ,CAAA,EAAG"}
|
package/dist/cj-settings.js
CHANGED
@@ -1,14 +1,38 @@
|
|
1
1
|
import { syncProducts } from "./service/sync-products";
|
2
|
+
import { decryptToken, encryptToken } from "./util/manage-tokens";
|
2
3
|
export const CjSettings = {
|
3
4
|
slug: "cj-settings",
|
4
5
|
access: {
|
5
|
-
read: ()=>true
|
6
|
-
update: ({ req })=>!!req.user?.roles?.includes("user")
|
6
|
+
read: ()=>true
|
7
7
|
},
|
8
8
|
admin: {
|
9
9
|
group: "Plugins"
|
10
10
|
},
|
11
11
|
fields: [
|
12
|
+
{
|
13
|
+
label: "Credentials",
|
14
|
+
type: "collapsible",
|
15
|
+
fields: [
|
16
|
+
{
|
17
|
+
type: "row",
|
18
|
+
fields: [
|
19
|
+
{
|
20
|
+
name: "emailAddress",
|
21
|
+
type: "text"
|
22
|
+
},
|
23
|
+
{
|
24
|
+
name: "apiToken",
|
25
|
+
type: "text",
|
26
|
+
admin: {
|
27
|
+
components: {
|
28
|
+
Field: "@shopnex/cj-plugin/rsc#ApiToken"
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
]
|
33
|
+
}
|
34
|
+
]
|
35
|
+
},
|
12
36
|
{
|
13
37
|
label: "Logo Area POD",
|
14
38
|
name: "pod",
|
@@ -35,6 +59,18 @@ export const CjSettings = {
|
|
35
59
|
}
|
36
60
|
],
|
37
61
|
hooks: {
|
62
|
+
beforeChange: [
|
63
|
+
({ data })=>{
|
64
|
+
const tokenToEncrypt = data.apiToken;
|
65
|
+
const encryptedToken = encryptToken(tokenToEncrypt);
|
66
|
+
data.apiToken = encryptedToken;
|
67
|
+
}
|
68
|
+
],
|
69
|
+
beforeRead: [
|
70
|
+
({ doc })=>{
|
71
|
+
doc.apiToken = doc.apiToken && decryptToken(doc.apiToken);
|
72
|
+
}
|
73
|
+
],
|
38
74
|
afterChange: [
|
39
75
|
async ({ doc, req: { payload } })=>{
|
40
76
|
const productIds = doc.items.map((item)=>{
|
@@ -42,6 +78,9 @@ export const CjSettings = {
|
|
42
78
|
return match ? match[0] : null;
|
43
79
|
});
|
44
80
|
await syncProducts(productIds, payload);
|
81
|
+
},
|
82
|
+
({ doc })=>{
|
83
|
+
doc.apiToken = doc.apiToken && decryptToken(doc.apiToken);
|
45
84
|
}
|
46
85
|
]
|
47
86
|
},
|
package/dist/cj-settings.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/cj-settings.ts"],"sourcesContent":["import type { GlobalConfig } from \"payload\";\n\nimport { syncProducts } from \"./service/sync-products\";\n\nexport const CjSettings: GlobalConfig = {\n slug: \"cj-settings\",\n access: {\n read: () => true,\n update: ({ req }) => !!req.user?.roles?.includes(\"user\"),\n },\n admin: {\n group: \"Plugins\",\n },\n fields: [\n {\n label: \"Logo Area POD\",\n name: \"pod\",\n type: \"upload\",\n relationTo: \"media\",\n },\n {\n name: \"items\",\n type: \"array\",\n admin: {\n description: \"A list of product URLs to sync with CJ Dropshipping\",\n },\n fields: [\n {\n name: \"productUrl\",\n type: \"text\",\n },\n ],\n label: \"Products\",\n labels: {\n plural: \"Product URLs\",\n singular: \"Product URL\",\n },\n },\n ],\n hooks: {\n afterChange: [\n async ({ doc, req: { payload } }) => {\n const productIds = doc.items.map((item: any) => {\n const match = item.productUrl.match(/(?<=-p-)([0-9A-Fa-f-]+)(?=\\.html)/);\n return match ? match[0] : null;\n });\n await syncProducts(productIds, payload);\n },\n ],\n },\n label: \"CJ Dropshipping\",\n};\n"],"names":["syncProducts","CjSettings","slug","access","read","
|
1
|
+
{"version":3,"sources":["../src/cj-settings.ts"],"sourcesContent":["import type { GlobalConfig } from \"payload\";\n\nimport { syncProducts } from \"./service/sync-products\";\nimport { decryptToken, encryptToken } from \"./util/manage-tokens\";\n\nexport const CjSettings: GlobalConfig = {\n slug: \"cj-settings\",\n access: {\n read: () => true,\n // update: ({ req }) => !!req.user?.roles?.includes(\"user\"),\n },\n admin: {\n group: \"Plugins\",\n },\n fields: [\n {\n label: \"Credentials\",\n type: \"collapsible\",\n fields: [\n {\n type: \"row\",\n fields: [\n {\n name: \"emailAddress\",\n type: \"text\",\n },\n {\n name: \"apiToken\",\n type: \"text\",\n admin: {\n components: {\n Field: \"@shopnex/cj-plugin/rsc#ApiToken\",\n },\n },\n },\n ],\n },\n ],\n },\n {\n label: \"Logo Area POD\",\n name: \"pod\",\n type: \"upload\",\n relationTo: \"media\",\n },\n {\n name: \"items\",\n type: \"array\",\n admin: {\n description: \"A list of product URLs to sync with CJ Dropshipping\",\n },\n fields: [\n {\n name: \"productUrl\",\n type: \"text\",\n },\n ],\n label: \"Products\",\n labels: {\n plural: \"Product URLs\",\n singular: \"Product URL\",\n },\n },\n ],\n hooks: {\n beforeChange: [\n ({ data }) => {\n const tokenToEncrypt = data.apiToken;\n const encryptedToken = encryptToken(tokenToEncrypt);\n data.apiToken = encryptedToken;\n },\n ],\n beforeRead: [\n ({ doc }) => {\n doc.apiToken = doc.apiToken && decryptToken(doc.apiToken);\n },\n ],\n afterChange: [\n async ({ doc, req: { payload } }) => {\n const productIds = doc.items.map((item: any) => {\n const match = item.productUrl.match(/(?<=-p-)([0-9A-Fa-f-]+)(?=\\.html)/);\n return match ? match[0] : null;\n });\n await syncProducts(productIds, payload);\n },\n ({ doc }) => {\n doc.apiToken = doc.apiToken && decryptToken(doc.apiToken);\n },\n ],\n },\n label: \"CJ Dropshipping\",\n};\n"],"names":["syncProducts","decryptToken","encryptToken","CjSettings","slug","access","read","admin","group","fields","label","type","name","components","Field","relationTo","description","labels","plural","singular","hooks","beforeChange","data","tokenToEncrypt","apiToken","encryptedToken","beforeRead","doc","afterChange","req","payload","productIds","items","map","item","match","productUrl"],"mappings":"AAEA,SAASA,YAAY,QAAQ,0BAA0B;AACvD,SAASC,YAAY,EAAEC,YAAY,QAAQ,uBAAuB;AAElE,OAAO,MAAMC,aAA2B;IACpCC,MAAM;IACNC,QAAQ;QACJC,MAAM,IAAM;IAEhB;IACAC,OAAO;QACHC,OAAO;IACX;IACAC,QAAQ;QACJ;YACIC,OAAO;YACPC,MAAM;YACNF,QAAQ;gBACJ;oBACIE,MAAM;oBACNF,QAAQ;wBACJ;4BACIG,MAAM;4BACND,MAAM;wBACV;wBACA;4BACIC,MAAM;4BACND,MAAM;4BACNJ,OAAO;gCACHM,YAAY;oCACRC,OAAO;gCACX;4BACJ;wBACJ;qBACH;gBACL;aACH;QACL;QACA;YACIJ,OAAO;YACPE,MAAM;YACND,MAAM;YACNI,YAAY;QAChB;QACA;YACIH,MAAM;YACND,MAAM;YACNJ,OAAO;gBACHS,aAAa;YACjB;YACAP,QAAQ;gBACJ;oBACIG,MAAM;oBACND,MAAM;gBACV;aACH;YACDD,OAAO;YACPO,QAAQ;gBACJC,QAAQ;gBACRC,UAAU;YACd;QACJ;KACH;IACDC,OAAO;QACHC,cAAc;YACV,CAAC,EAAEC,IAAI,EAAE;gBACL,MAAMC,iBAAiBD,KAAKE,QAAQ;gBACpC,MAAMC,iBAAiBvB,aAAaqB;gBACpCD,KAAKE,QAAQ,GAAGC;YACpB;SACH;QACDC,YAAY;YACR,CAAC,EAAEC,GAAG,EAAE;gBACJA,IAAIH,QAAQ,GAAGG,IAAIH,QAAQ,IAAIvB,aAAa0B,IAAIH,QAAQ;YAC5D;SACH;QACDI,aAAa;YACT,OAAO,EAAED,GAAG,EAAEE,KAAK,EAAEC,OAAO,EAAE,EAAE;gBAC5B,MAAMC,aAAaJ,IAAIK,KAAK,CAACC,GAAG,CAAC,CAACC;oBAC9B,MAAMC,QAAQD,KAAKE,UAAU,CAACD,KAAK,CAAC;oBACpC,OAAOA,QAAQA,KAAK,CAAC,EAAE,GAAG;gBAC9B;gBACA,MAAMnC,aAAa+B,YAAYD;YACnC;YACA,CAAC,EAAEH,GAAG,EAAE;gBACJA,IAAIH,QAAQ,GAAGG,IAAIH,QAAQ,IAAIvB,aAAa0B,IAAIH,QAAQ;YAC5D;SACH;IACL;IACAd,OAAO;AACX,EAAE"}
|
@@ -0,0 +1 @@
|
|
1
|
+
export { ApiToken } from "../rsc/ApiToken";
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../../src/exports/rsc.ts"],"sourcesContent":["export { ApiToken } from \"../rsc/ApiToken\";\n"],"names":["ApiToken"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,kBAAkB"}
|
package/dist/index.d.ts
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
import type { Config } from
|
1
|
+
import type { Config } from "payload";
|
2
|
+
import { CjCollectionProps } from "./CjConfig";
|
2
3
|
interface PluginOptions {
|
3
4
|
cjApiKey: string;
|
4
5
|
cjEmailAddress: string;
|
5
6
|
cjRefreshToken?: string;
|
7
|
+
asCollection?: boolean;
|
8
|
+
collectionOverrides?: CjCollectionProps["overrides"];
|
6
9
|
}
|
7
10
|
export declare const cjPlugin: (pluginOptions: PluginOptions) => (config: Config) => Config;
|
8
11
|
export {};
|
package/dist/index.js
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import {
|
1
|
+
import { setTenantCredentials } from "./sdk/access-token";
|
2
|
+
import { createOrderHook } from "./service/create-order.hook";
|
3
|
+
import { CjConfigCollection } from "./CjConfig";
|
4
4
|
const updateCollection = (collection)=>{
|
5
|
-
if (collection.slug ===
|
5
|
+
if (collection.slug === "orders") {
|
6
6
|
return {
|
7
7
|
...collection,
|
8
8
|
hooks: {
|
@@ -17,18 +17,38 @@ const updateCollection = (collection)=>{
|
|
17
17
|
return collection;
|
18
18
|
};
|
19
19
|
export const cjPlugin = (pluginOptions)=>(config)=>{
|
20
|
-
const updatedCollections = config.collections?.map(updateCollection);
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
const updatedCollections = config.collections?.map(updateCollection) || [];
|
21
|
+
if (pluginOptions.asCollection) {
|
22
|
+
updatedCollections.push(CjConfigCollection({
|
23
|
+
overrides: pluginOptions.collectionOverrides
|
24
|
+
}));
|
25
|
+
}
|
26
|
+
const productCollection = updatedCollections.find((collection)=>collection.slug === "products");
|
27
|
+
const sourceField = productCollection?.fields?.find((field)=>field.name === "source");
|
28
|
+
sourceField.options.push({
|
29
|
+
label: "CJ",
|
30
|
+
value: "cj"
|
25
31
|
});
|
32
|
+
const incomingOnInit = config.onInit;
|
33
|
+
config.onInit = async (payload)=>{
|
34
|
+
if (incomingOnInit) {
|
35
|
+
await incomingOnInit(payload);
|
36
|
+
}
|
37
|
+
const cjSettings = await payload.find({
|
38
|
+
collection: "cj-settings"
|
39
|
+
});
|
40
|
+
cjSettings.docs.forEach((config)=>{
|
41
|
+
setTenantCredentials(config?.shop?.slug || "default", {
|
42
|
+
emailAddress: config.email,
|
43
|
+
password: config.apiToken
|
44
|
+
});
|
45
|
+
});
|
46
|
+
};
|
26
47
|
return {
|
27
48
|
...config,
|
28
49
|
collections: updatedCollections,
|
29
50
|
globals: [
|
30
|
-
...config.globals || []
|
31
|
-
CjSettings
|
51
|
+
...config.globals || []
|
32
52
|
]
|
33
53
|
};
|
34
54
|
};
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config } from
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, FieldBase, SelectField } from \"payload\";\nimport { setTenantCredentials } from \"./sdk/access-token\";\nimport { createOrderHook } from \"./service/create-order.hook\";\nimport { CjConfigCollection, CjCollectionProps } from \"./CjConfig\";\n\ninterface PluginOptions {\n cjApiKey: string;\n cjEmailAddress: string;\n cjRefreshToken?: string;\n asCollection?: boolean;\n collectionOverrides?: CjCollectionProps[\"overrides\"];\n}\n\nconst updateCollection = (collection: CollectionConfig) => {\n if (collection.slug === \"orders\") {\n return {\n ...collection,\n hooks: {\n ...collection.hooks,\n afterChange: [...(collection.hooks?.afterChange || []), createOrderHook],\n },\n };\n }\n return collection;\n};\n\nexport const cjPlugin =\n (pluginOptions: PluginOptions) =>\n (config: Config): Config => {\n const updatedCollections = config.collections?.map(updateCollection) || [];\n\n if (pluginOptions.asCollection) {\n updatedCollections.push(\n CjConfigCollection({ overrides: pluginOptions.collectionOverrides }),\n );\n }\n\n const productCollection = updatedCollections.find(\n (collection) => collection.slug === \"products\",\n );\n\n const sourceField = productCollection?.fields?.find(\n (field) => (field as SelectField).name === \"source\",\n ) as SelectField;\n\n sourceField.options.push({\n label: \"CJ\",\n value: \"cj\",\n });\n\n const incomingOnInit = config.onInit;\n\n config.onInit = async (payload) => {\n if (incomingOnInit) {\n await incomingOnInit(payload);\n }\n const cjSettings = await payload.find({\n collection: \"cj-settings\",\n });\n cjSettings.docs.forEach((config: any) => {\n setTenantCredentials(config?.shop?.slug || \"default\", {\n emailAddress: config.email,\n password: config.apiToken,\n });\n });\n };\n\n return {\n ...config,\n collections: updatedCollections,\n globals: [...(config.globals || [])],\n };\n };\n"],"names":["setTenantCredentials","createOrderHook","CjConfigCollection","updateCollection","collection","slug","hooks","afterChange","cjPlugin","pluginOptions","config","updatedCollections","collections","map","asCollection","push","overrides","collectionOverrides","productCollection","find","sourceField","fields","field","name","options","label","value","incomingOnInit","onInit","payload","cjSettings","docs","forEach","shop","emailAddress","email","password","apiToken","globals"],"mappings":"AACA,SAASA,oBAAoB,QAAQ,qBAAqB;AAC1D,SAASC,eAAe,QAAQ,8BAA8B;AAC9D,SAASC,kBAAkB,QAA2B,aAAa;AAUnE,MAAMC,mBAAmB,CAACC;IACtB,IAAIA,WAAWC,IAAI,KAAK,UAAU;QAC9B,OAAO;YACH,GAAGD,UAAU;YACbE,OAAO;gBACH,GAAGF,WAAWE,KAAK;gBACnBC,aAAa;uBAAKH,WAAWE,KAAK,EAAEC,eAAe,EAAE;oBAAGN;iBAAgB;YAC5E;QACJ;IACJ;IACA,OAAOG;AACX;AAEA,OAAO,MAAMI,WACT,CAACC,gBACD,CAACC;QACG,MAAMC,qBAAqBD,OAAOE,WAAW,EAAEC,IAAIV,qBAAqB,EAAE;QAE1E,IAAIM,cAAcK,YAAY,EAAE;YAC5BH,mBAAmBI,IAAI,CACnBb,mBAAmB;gBAAEc,WAAWP,cAAcQ,mBAAmB;YAAC;QAE1E;QAEA,MAAMC,oBAAoBP,mBAAmBQ,IAAI,CAC7C,CAACf,aAAeA,WAAWC,IAAI,KAAK;QAGxC,MAAMe,cAAcF,mBAAmBG,QAAQF,KAC3C,CAACG,QAAU,AAACA,MAAsBC,IAAI,KAAK;QAG/CH,YAAYI,OAAO,CAACT,IAAI,CAAC;YACrBU,OAAO;YACPC,OAAO;QACX;QAEA,MAAMC,iBAAiBjB,OAAOkB,MAAM;QAEpClB,OAAOkB,MAAM,GAAG,OAAOC;YACnB,IAAIF,gBAAgB;gBAChB,MAAMA,eAAeE;YACzB;YACA,MAAMC,aAAa,MAAMD,QAAQV,IAAI,CAAC;gBAClCf,YAAY;YAChB;YACA0B,WAAWC,IAAI,CAACC,OAAO,CAAC,CAACtB;gBACrBV,qBAAqBU,QAAQuB,MAAM5B,QAAQ,WAAW;oBAClD6B,cAAcxB,OAAOyB,KAAK;oBAC1BC,UAAU1B,OAAO2B,QAAQ;gBAC7B;YACJ;QACJ;QAEA,OAAO;YACH,GAAG3B,MAAM;YACTE,aAAaD;YACb2B,SAAS;mBAAK5B,OAAO4B,OAAO,IAAI,EAAE;aAAE;QACxC;IACJ,EAAE"}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
"use client";
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
3
|
+
import React from "react";
|
4
|
+
import { PasswordField } from "@payloadcms/ui";
|
5
|
+
import "./ApiToken.scss";
|
6
|
+
export function ApiToken({ path, readOnly, label = "API Token" }) {
|
7
|
+
return /*#__PURE__*/ _jsx(PasswordField, {
|
8
|
+
autoComplete: "new-password",
|
9
|
+
field: {
|
10
|
+
name: "password",
|
11
|
+
label: "API Token"
|
12
|
+
},
|
13
|
+
indexPath: "",
|
14
|
+
parentPath: "",
|
15
|
+
parentSchemaPath: "",
|
16
|
+
path: path,
|
17
|
+
schemaPath: "password"
|
18
|
+
});
|
19
|
+
}
|
20
|
+
|
21
|
+
//# sourceMappingURL=ApiToken.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../../src/rsc/ApiToken.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport { PasswordField } from \"@payloadcms/ui\";\nimport \"./ApiToken.scss\";\n\ninterface ApiTokenProps {\n path: string;\n readOnly?: boolean;\n label?: string;\n}\n\nexport function ApiToken({ path, readOnly, label = \"API Token\" }: ApiTokenProps) {\n return (\n <PasswordField\n autoComplete=\"new-password\"\n field={{\n name: \"password\",\n label: \"API Token\",\n }}\n indexPath=\"\"\n parentPath=\"\"\n parentSchemaPath=\"\"\n path={path}\n schemaPath=\"password\"\n />\n );\n}\n"],"names":["React","PasswordField","ApiToken","path","readOnly","label","autoComplete","field","name","indexPath","parentPath","parentSchemaPath","schemaPath"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAQ;AAC1B,SAASC,aAAa,QAAQ,iBAAiB;AAC/C,OAAO,kBAAkB;AAQzB,OAAO,SAASC,SAAS,EAAEC,IAAI,EAAEC,QAAQ,EAAEC,QAAQ,WAAW,EAAiB;IAC3E,qBACI,KAACJ;QACGK,cAAa;QACbC,OAAO;YACHC,MAAM;YACNH,OAAO;QACX;QACAI,WAAU;QACVC,YAAW;QACXC,kBAAiB;QACjBR,MAAMA;QACNS,YAAW;;AAGvB"}
|
@@ -4,5 +4,6 @@ type Credentials = {
|
|
4
4
|
refreshToken?: string;
|
5
5
|
};
|
6
6
|
export declare const getCurrentAccessToken: () => Promise<string>;
|
7
|
-
export declare const
|
7
|
+
export declare const setTenantCredentials: (shopId: string, creds: Credentials) => void;
|
8
|
+
export declare const getTenantAccessToken: (shopId: string) => Promise<string>;
|
8
9
|
export {};
|
package/dist/sdk/access-token.js
CHANGED
@@ -1,22 +1,24 @@
|
|
1
|
-
import * as cjSdk from
|
2
|
-
|
1
|
+
import * as cjSdk from "./cj-sdk";
|
2
|
+
const tenantCredentialsMap = new Map();
|
3
3
|
export const getCurrentAccessToken = async ()=>{
|
4
|
-
|
5
|
-
|
4
|
+
const shopId = '1';
|
5
|
+
const accessToken = await getTenantAccessToken(shopId);
|
6
|
+
return accessToken;
|
7
|
+
};
|
8
|
+
export const setTenantCredentials = (shopId, creds)=>{
|
9
|
+
tenantCredentialsMap.set(shopId, creds);
|
10
|
+
};
|
11
|
+
export const getTenantAccessToken = async (shopId)=>{
|
12
|
+
const creds = tenantCredentialsMap.get(shopId);
|
13
|
+
if (!creds?.emailAddress || !creds?.password) {
|
14
|
+
throw new Error(`Credentials for tenant ${shopId} are missing or incomplete`);
|
6
15
|
}
|
7
|
-
const { emailAddress, password, refreshToken } =
|
8
|
-
let accessToken = (await cjSdk.refreshAccessToken(refreshToken ||
|
16
|
+
const { emailAddress, password, refreshToken } = creds;
|
17
|
+
let accessToken = (await cjSdk.refreshAccessToken(refreshToken || "")).accessToken;
|
9
18
|
if (!accessToken) {
|
10
19
|
accessToken = (await cjSdk.getAccessToken(emailAddress, password)).accessToken;
|
11
20
|
}
|
12
21
|
return accessToken;
|
13
22
|
};
|
14
|
-
export const setCurrentAccessToken = ({ emailAddress, password, refreshToken })=>{
|
15
|
-
credentials = {
|
16
|
-
emailAddress,
|
17
|
-
password,
|
18
|
-
refreshToken
|
19
|
-
};
|
20
|
-
};
|
21
23
|
|
22
24
|
//# sourceMappingURL=access-token.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/sdk/access-token.ts"],"sourcesContent":["import * as cjSdk from
|
1
|
+
{"version":3,"sources":["../../src/sdk/access-token.ts"],"sourcesContent":["import * as cjSdk from \"./cj-sdk\";\n\ntype Credentials = {\n emailAddress: string;\n password: string;\n refreshToken?: string;\n};\n\nconst tenantCredentialsMap = new Map<string, Credentials>();\n\nexport const getCurrentAccessToken = async () => {\n const shopId = '1'\n const accessToken = await getTenantAccessToken(shopId);\n return accessToken\n};\n\nexport const setTenantCredentials = (shopId: string, creds: Credentials) => {\n tenantCredentialsMap.set(shopId, creds);\n};\n\nexport const getTenantAccessToken = async (shopId: string) => {\n const creds = tenantCredentialsMap.get(shopId);\n\n if (!creds?.emailAddress || !creds?.password) {\n throw new Error(`Credentials for tenant ${shopId} are missing or incomplete`);\n }\n\n const { emailAddress, password, refreshToken } = creds;\n let accessToken = (await cjSdk.refreshAccessToken(refreshToken || \"\")).accessToken;\n if (!accessToken) {\n accessToken = (await cjSdk.getAccessToken(emailAddress, password)).accessToken;\n }\n return accessToken;\n};\n"],"names":["cjSdk","tenantCredentialsMap","Map","getCurrentAccessToken","shopId","accessToken","getTenantAccessToken","setTenantCredentials","creds","set","get","emailAddress","password","Error","refreshToken","refreshAccessToken","getAccessToken"],"mappings":"AAAA,YAAYA,WAAW,WAAW;AAQlC,MAAMC,uBAAuB,IAAIC;AAEjC,OAAO,MAAMC,wBAAwB;IACjC,MAAMC,SAAS;IACf,MAAMC,cAAc,MAAMC,qBAAqBF;IAC/C,OAAOC;AACX,EAAE;AAEF,OAAO,MAAME,uBAAuB,CAACH,QAAgBI;IACjDP,qBAAqBQ,GAAG,CAACL,QAAQI;AACrC,EAAE;AAEF,OAAO,MAAMF,uBAAuB,OAAOF;IACvC,MAAMI,QAAQP,qBAAqBS,GAAG,CAACN;IAEvC,IAAI,CAACI,OAAOG,gBAAgB,CAACH,OAAOI,UAAU;QAC1C,MAAM,IAAIC,MAAM,CAAC,uBAAuB,EAAET,OAAO,0BAA0B,CAAC;IAChF;IAEA,MAAM,EAAEO,YAAY,EAAEC,QAAQ,EAAEE,YAAY,EAAE,GAAGN;IACjD,IAAIH,cAAc,AAAC,CAAA,MAAML,MAAMe,kBAAkB,CAACD,gBAAgB,GAAE,EAAGT,WAAW;IAClF,IAAI,CAACA,aAAa;QACdA,cAAc,AAAC,CAAA,MAAML,MAAMgB,cAAc,CAACL,cAAcC,SAAQ,EAAGP,WAAW;IAClF;IACA,OAAOA;AACX,EAAE"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../../src/sdk/products/products.ts"],"sourcesContent":["import type { APIResponse } from '../../error-types'\nimport type {\n CategoryFirstLevel,\n CategoryListResponse,\n Product,\n ProductDetails,\n ProductListResponse,\n} from './product-types.ts'\n\nimport { cjApiClient } from '../../api-client'\nimport { getCurrentAccessToken } from '../access-token'\n\nexport async function getProductCategory(\n accessToken: string,\n params: any,\n): Promise<APIResponse<CategoryFirstLevel[]>> {\n try {\n const response = await cjApiClient.get<CategoryListResponse>('/product/getCategory', {\n headers: { 'CJ-Access-Token': accessToken },\n params,\n })\n\n const data = response.data.data\n if (!data) {\n return { error: 'No categories found' }\n }\n\n return { data }\n } catch (error: any) {\n console.error(`Error fetching categories [${error.code}]: ${error.message}`)\n return { error: error.message || 'Failed to fetch categories' }\n }\n}\n\nexport async function getProductList(\n params: Record<string, any> = {},\n): Promise<APIResponse<Product[]>> {\n const defaultParams = {\n pageNum: 1,\n pageSize: 20,\n }\n const query = { ...defaultParams, ...params }\n\n try {\n const accessToken = await getCurrentAccessToken()
|
1
|
+
{"version":3,"sources":["../../../src/sdk/products/products.ts"],"sourcesContent":["import type { APIResponse } from '../../error-types'\nimport type {\n CategoryFirstLevel,\n CategoryListResponse,\n Product,\n ProductDetails,\n ProductListResponse,\n} from './product-types.ts'\n\nimport { cjApiClient } from '../../api-client'\nimport { getCurrentAccessToken } from '../access-token'\n\nexport async function getProductCategory(\n accessToken: string,\n params: any,\n): Promise<APIResponse<CategoryFirstLevel[]>> {\n try {\n const response = await cjApiClient.get<CategoryListResponse>('/product/getCategory', {\n headers: { 'CJ-Access-Token': accessToken },\n params,\n })\n\n const data = response.data.data\n if (!data) {\n return { error: 'No categories found' }\n }\n\n return { data }\n } catch (error: any) {\n console.error(`Error fetching categories [${error.code}]: ${error.message}`)\n return { error: error.message || 'Failed to fetch categories' }\n }\n}\n\nexport async function getProductList(\n params: Record<string, any> = {},\n): Promise<APIResponse<Product[]>> {\n const defaultParams = {\n pageNum: 1,\n pageSize: 20,\n }\n const query = { ...defaultParams, ...params }\n\n try {\n const accessToken = await getCurrentAccessToken();\n const response = await cjApiClient.get<ProductListResponse>(\n 'https://developers.cjdropshipping.com/api2.0/v1/product/list',\n {\n headers: {\n 'CJ-Access-Token': accessToken,\n },\n params: query,\n },\n )\n\n const data = response.data\n\n if (!data.result) {\n return { error: data.message || 'Failed to fetch product list' }\n }\n\n if (!data.data?.list) {\n return { error: 'No products found' }\n }\n\n return { data: data.data.list }\n } catch (error: any) {\n console.error(`Error fetching product list [${error.code}]: ${error.message}`)\n return { error: error.message || 'Failed to fetch product list' }\n }\n}\n\nexport async function getProductDetails(queryParams: {\n pid?: string\n productSku?: string\n variantSku?: string\n}): Promise<APIResponse<ProductDetails>> {\n const { pid, productSku, variantSku } = queryParams\n if (!pid && !productSku && !variantSku) {\n return {\n error: 'One of pid, productSku, or variantSku must be provided.',\n }\n }\n\n try {\n const accessToken = await getCurrentAccessToken()\n const response = await cjApiClient.get<{\n code: number\n data: ProductDetails\n message: string\n result: boolean\n }>('https://developers.cjdropshipping.com/api2.0/v1/product/query', {\n headers: {\n 'CJ-Access-Token': accessToken,\n },\n params: queryParams,\n })\n\n if (!response.data.result) {\n return {\n error: response.data.message || 'Failed to fetch product details',\n }\n }\n\n return { data: response.data.data }\n } catch (error: any) {\n console.error(`Error fetching product details [${error.code}]: ${error.message}`)\n return { error: error.message || 'Failed to fetch product details' }\n }\n}\n"],"names":["cjApiClient","getCurrentAccessToken","getProductCategory","accessToken","params","response","get","headers","data","error","console","code","message","getProductList","defaultParams","pageNum","pageSize","query","result","list","getProductDetails","queryParams","pid","productSku","variantSku"],"mappings":"AASA,SAASA,WAAW,QAAQ,mBAAkB;AAC9C,SAASC,qBAAqB,QAAQ,kBAAiB;AAEvD,OAAO,eAAeC,mBACpBC,WAAmB,EACnBC,MAAW;IAEX,IAAI;QACF,MAAMC,WAAW,MAAML,YAAYM,GAAG,CAAuB,wBAAwB;YACnFC,SAAS;gBAAE,mBAAmBJ;YAAY;YAC1CC;QACF;QAEA,MAAMI,OAAOH,SAASG,IAAI,CAACA,IAAI;QAC/B,IAAI,CAACA,MAAM;YACT,OAAO;gBAAEC,OAAO;YAAsB;QACxC;QAEA,OAAO;YAAED;QAAK;IAChB,EAAE,OAAOC,OAAY;QACnBC,QAAQD,KAAK,CAAC,CAAC,2BAA2B,EAAEA,MAAME,IAAI,CAAC,GAAG,EAAEF,MAAMG,OAAO,EAAE;QAC3E,OAAO;YAAEH,OAAOA,MAAMG,OAAO,IAAI;QAA6B;IAChE;AACF;AAEA,OAAO,eAAeC,eACpBT,SAA8B,CAAC,CAAC;IAEhC,MAAMU,gBAAgB;QACpBC,SAAS;QACTC,UAAU;IACZ;IACA,MAAMC,QAAQ;QAAE,GAAGH,aAAa;QAAE,GAAGV,MAAM;IAAC;IAE5C,IAAI;QACF,MAAMD,cAAc,MAAMF;QAC1B,MAAMI,WAAW,MAAML,YAAYM,GAAG,CACpC,gEACA;YACEC,SAAS;gBACP,mBAAmBJ;YACrB;YACAC,QAAQa;QACV;QAGF,MAAMT,OAAOH,SAASG,IAAI;QAE1B,IAAI,CAACA,KAAKU,MAAM,EAAE;YAChB,OAAO;gBAAET,OAAOD,KAAKI,OAAO,IAAI;YAA+B;QACjE;QAEA,IAAI,CAACJ,KAAKA,IAAI,EAAEW,MAAM;YACpB,OAAO;gBAAEV,OAAO;YAAoB;QACtC;QAEA,OAAO;YAAED,MAAMA,KAAKA,IAAI,CAACW,IAAI;QAAC;IAChC,EAAE,OAAOV,OAAY;QACnBC,QAAQD,KAAK,CAAC,CAAC,6BAA6B,EAAEA,MAAME,IAAI,CAAC,GAAG,EAAEF,MAAMG,OAAO,EAAE;QAC7E,OAAO;YAAEH,OAAOA,MAAMG,OAAO,IAAI;QAA+B;IAClE;AACF;AAEA,OAAO,eAAeQ,kBAAkBC,WAIvC;IACC,MAAM,EAAEC,GAAG,EAAEC,UAAU,EAAEC,UAAU,EAAE,GAAGH;IACxC,IAAI,CAACC,OAAO,CAACC,cAAc,CAACC,YAAY;QACtC,OAAO;YACLf,OAAO;QACT;IACF;IAEA,IAAI;QACF,MAAMN,cAAc,MAAMF;QAC1B,MAAMI,WAAW,MAAML,YAAYM,GAAG,CAKnC,iEAAiE;YAClEC,SAAS;gBACP,mBAAmBJ;YACrB;YACAC,QAAQiB;QACV;QAEA,IAAI,CAAChB,SAASG,IAAI,CAACU,MAAM,EAAE;YACzB,OAAO;gBACLT,OAAOJ,SAASG,IAAI,CAACI,OAAO,IAAI;YAClC;QACF;QAEA,OAAO;YAAEJ,MAAMH,SAASG,IAAI,CAACA,IAAI;QAAC;IACpC,EAAE,OAAOC,OAAY;QACnBC,QAAQD,KAAK,CAAC,CAAC,gCAAgC,EAAEA,MAAME,IAAI,CAAC,GAAG,EAAEF,MAAMG,OAAO,EAAE;QAChF,OAAO;YAAEH,OAAOA,MAAMG,OAAO,IAAI;QAAkC;IACrE;AACF"}
|
@@ -4,14 +4,20 @@ export const createOrderHook = async ({ doc, req })=>{
|
|
4
4
|
return;
|
5
5
|
}
|
6
6
|
const payload = req.payload;
|
7
|
-
const cjSettings = await payload.
|
8
|
-
|
7
|
+
const cjSettings = await payload.find({
|
8
|
+
collection: "cj-settings",
|
9
|
+
where: {
|
10
|
+
shop: {
|
11
|
+
equals: doc.shopId
|
12
|
+
}
|
13
|
+
}
|
9
14
|
});
|
10
|
-
const
|
15
|
+
const cjConfig = cjSettings?.docs[0];
|
16
|
+
const podProperties = cjConfig?.pod?.url ? [
|
11
17
|
{
|
12
18
|
areaName: "LogoArea",
|
13
19
|
links: [
|
14
|
-
|
20
|
+
cjConfig?.pod?.url
|
15
21
|
],
|
16
22
|
type: "1",
|
17
23
|
layer: []
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/service/create-order.hook.ts"],"sourcesContent":["import type { BasePayload, CollectionAfterChangeHook, Document } from \"payload\";\n\nimport * as cjSdk from \"../sdk/cj-sdk\";\n\nexport interface Orders extends Document {\n id: string;\n items: Array<{\n productUrl: string;\n quantity: number;\n variant: {\n variantId: string;\n };\n }>;\n}\n\nexport const createOrderHook: CollectionAfterChangeHook<Orders> = async ({ doc, req }) => {\n if (doc.orderStatus !== \"processing\") {\n return;\n }\n const payload: BasePayload = req.payload;\n const cjSettings
|
1
|
+
{"version":3,"sources":["../../src/service/create-order.hook.ts"],"sourcesContent":["import type { BasePayload, CollectionAfterChangeHook, Document } from \"payload\";\n\nimport * as cjSdk from \"../sdk/cj-sdk\";\n\nexport interface Orders extends Document {\n id: string;\n items: Array<{\n productUrl: string;\n quantity: number;\n variant: {\n variantId: string;\n };\n }>;\n}\n\nexport const createOrderHook: CollectionAfterChangeHook<Orders> = async ({ doc, req }) => {\n if (doc.orderStatus !== \"processing\") {\n return;\n }\n const payload: BasePayload = req.payload;\n const cjSettings = await payload.find({\n collection: \"cj-settings\",\n where: {\n shop: {\n equals: doc.shopId,\n },\n },\n });\n const cjConfig: any = cjSettings?.docs[0];\n const podProperties = cjConfig?.pod?.url\n ? [\n {\n areaName: \"LogoArea\",\n links: [cjConfig?.pod?.url],\n type: \"1\",\n layer: [],\n },\n ]\n : [];\n const result = await cjSdk.createOrder({\n consigneeID: doc.billingAddress?.name || \"\",\n email: doc.billingAddress?.email || \"\",\n fromCountryCode: \"CN\",\n houseNumber: doc.shippingAddress?.address?.line2 || \"\",\n iossType: 1,\n logisticName: \"CJPacket Liquid US\",\n orderNumber: doc.orderId,\n payType: 2,\n products: doc.items.map((item) => ({\n quantity: item.quantity,\n vid: item.variant.variantId,\n })),\n podProperties,\n remark: \"\",\n shippingAddress: doc.shippingAddress?.address?.line1 || \"\",\n shippingAddress2: doc.shippingAddress?.address?.line2 || \"\",\n shippingCity: doc.shippingAddress?.address?.city || \"\",\n shippingCountry: doc.shippingAddress?.address?.country || \"\",\n shippingCountryCode: doc.shippingAddress?.address?.country || \"\",\n shippingCounty: doc.shippingAddress?.address?.city || \"\",\n shippingCustomerName: doc.shippingAddress?.name || \"\",\n shippingPhone: doc.shippingAddress?.phone || \"+9999999999\",\n shippingProvince: doc.shippingAddress?.address?.state || \"\",\n shippingZip: doc.shippingAddress?.address?.postal_code || \"\",\n taxId: \"\",\n });\n\n const orderResult = await payload.update({\n collection: \"orders\",\n data: {\n orderStatus: \"shipped\",\n },\n where: {\n id: {\n equals: doc.orderId,\n },\n },\n });\n\n return {\n cjResult: result,\n orderResult,\n };\n};\n"],"names":["cjSdk","createOrderHook","doc","req","orderStatus","payload","cjSettings","find","collection","where","shop","equals","shopId","cjConfig","docs","podProperties","pod","url","areaName","links","type","layer","result","createOrder","consigneeID","billingAddress","name","email","fromCountryCode","houseNumber","shippingAddress","address","line2","iossType","logisticName","orderNumber","orderId","payType","products","items","map","item","quantity","vid","variant","variantId","remark","line1","shippingAddress2","shippingCity","city","shippingCountry","country","shippingCountryCode","shippingCounty","shippingCustomerName","shippingPhone","phone","shippingProvince","state","shippingZip","postal_code","taxId","orderResult","update","data","id","cjResult"],"mappings":"AAEA,YAAYA,WAAW,gBAAgB;AAavC,OAAO,MAAMC,kBAAqD,OAAO,EAAEC,GAAG,EAAEC,GAAG,EAAE;IACjF,IAAID,IAAIE,WAAW,KAAK,cAAc;QAClC;IACJ;IACA,MAAMC,UAAuBF,IAAIE,OAAO;IACxC,MAAMC,aAAa,MAAMD,QAAQE,IAAI,CAAC;QAClCC,YAAY;QACZC,OAAO;YACHC,MAAM;gBACFC,QAAQT,IAAIU,MAAM;YACtB;QACJ;IACJ;IACA,MAAMC,WAAgBP,YAAYQ,IAAI,CAAC,EAAE;IACzC,MAAMC,gBAAgBF,UAAUG,KAAKC,MAC/B;QACI;YACIC,UAAU;YACVC,OAAO;gBAACN,UAAUG,KAAKC;aAAI;YAC3BG,MAAM;YACNC,OAAO,EAAE;QACb;KACH,GACD,EAAE;IACR,MAAMC,SAAS,MAAMtB,MAAMuB,WAAW,CAAC;QACnCC,aAAatB,IAAIuB,cAAc,EAAEC,QAAQ;QACzCC,OAAOzB,IAAIuB,cAAc,EAAEE,SAAS;QACpCC,iBAAiB;QACjBC,aAAa3B,IAAI4B,eAAe,EAAEC,SAASC,SAAS;QACpDC,UAAU;QACVC,cAAc;QACdC,aAAajC,IAAIkC,OAAO;QACxBC,SAAS;QACTC,UAAUpC,IAAIqC,KAAK,CAACC,GAAG,CAAC,CAACC,OAAU,CAAA;gBAC/BC,UAAUD,KAAKC,QAAQ;gBACvBC,KAAKF,KAAKG,OAAO,CAACC,SAAS;YAC/B,CAAA;QACA9B;QACA+B,QAAQ;QACRhB,iBAAiB5B,IAAI4B,eAAe,EAAEC,SAASgB,SAAS;QACxDC,kBAAkB9C,IAAI4B,eAAe,EAAEC,SAASC,SAAS;QACzDiB,cAAc/C,IAAI4B,eAAe,EAAEC,SAASmB,QAAQ;QACpDC,iBAAiBjD,IAAI4B,eAAe,EAAEC,SAASqB,WAAW;QAC1DC,qBAAqBnD,IAAI4B,eAAe,EAAEC,SAASqB,WAAW;QAC9DE,gBAAgBpD,IAAI4B,eAAe,EAAEC,SAASmB,QAAQ;QACtDK,sBAAsBrD,IAAI4B,eAAe,EAAEJ,QAAQ;QACnD8B,eAAetD,IAAI4B,eAAe,EAAE2B,SAAS;QAC7CC,kBAAkBxD,IAAI4B,eAAe,EAAEC,SAAS4B,SAAS;QACzDC,aAAa1D,IAAI4B,eAAe,EAAEC,SAAS8B,eAAe;QAC1DC,OAAO;IACX;IAEA,MAAMC,cAAc,MAAM1D,QAAQ2D,MAAM,CAAC;QACrCxD,YAAY;QACZyD,MAAM;YACF7D,aAAa;QACjB;QACAK,OAAO;YACHyD,IAAI;gBACAvD,QAAQT,IAAIkC,OAAO;YACvB;QACJ;IACJ;IAEA,OAAO;QACH+B,UAAU7C;QACVyC;IACJ;AACJ,EAAE"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/service/sync-products.ts"],"sourcesContent":["import type { DefaultNodeTypes, TypedEditorState } from \"@payloadcms/richtext-lexical\";\nimport type { BasePayload } from \"payload\";\n\nimport { convertHTMLToLexical, editorConfigFactory } from \"@payloadcms/richtext-lexical\";\nimport decimal from \"decimal.js\";\nimport { JSDOM } from \"jsdom\";\n\nimport type { ProductDetails } from \"../sdk/products/product-types\";\n\nimport * as cjSdk from \"../sdk/cj-sdk\";\nimport path, { dirname, join } from \"path\";\nimport fs from \"fs\";\nimport { promisify } from \"util\";\nimport { pipeline } from \"stream\";\nimport { writeFile } from \"fs/promises\";\nimport { fileURLToPath } from \"url\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst streamPipeline = promisify(pipeline);\n\ninterface Product {\n description: TypedEditorState<DefaultNodeTypes>;\n pid: string;\n title: string;\n variants?: Array<{\n imageUrl?: string;\n options?: Array<{ option: string; value: string }>;\n price?: number;\n vid: string;\n }>;\n}\n\nconst delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst download = async (uri: string, filename: string): Promise<void> => {\n try {\n const response = await fetch(uri);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${uri}: ${response.statusText}`);\n }\n\n const contentType = response.headers.get(\"content-type\");\n const contentLength = response.headers.get(\"content-length\");\n\n console.log(\"content-type:\", contentType);\n console.log(\"content-length:\", contentLength);\n\n const buffer = Buffer.from(await response.arrayBuffer());\n\n await writeFile(filename, buffer);\n\n console.log(\"Download complete:\", filename);\n } catch (error) {\n console.error(\"Error downloading file:\", error);\n }\n};\n\n\nasync function uploadImageToPayload(src: string, payload: BasePayload): Promise<any | null> {\n const tempFilePath = path.join(__dirname, \"temp-image.jpg\");\n\n try {\n // Fetch the image\n const response = await fetch(src);\n if (!response.ok) throw new Error(`Failed to fetch image: ${response.statusText}`);\n\n // Stream the response body to a temporary file\n await download(src, tempFilePath);\n\n // Upload the image using Payload's Local API\n const uploadedImage = await payload.create({\n collection: \"media\",\n data: {\n alt: \"Some alt text\",\n },\n\n filePath: tempFilePath,\n });\n\n console.log(\"Uploaded media document:\", uploadedImage);\n\n // Clean up: delete the temporary file\n fs.unlink(tempFilePath, (err) => {\n if (err) console.error(\"Error deleting temporary file:\", err);\n });\n\n return {\n id: uploadedImage.id,\n alt: uploadedImage.alt || \"\",\n prefix: \"media\",\n updatedAt: uploadedImage.updatedAt,\n createdAt: uploadedImage.createdAt,\n url: uploadedImage.url,\n thumbnailURL: uploadedImage.thumbnailURL || null,\n filename: uploadedImage.filename,\n mimeType: uploadedImage.mimeType,\n filesize: uploadedImage.filesize,\n width: uploadedImage.width,\n height: uploadedImage.height,\n focalX: 50,\n focalY: 50,\n };\n } catch (error) {\n console.error(\"Error uploading image:\", error);\n }\n}\nfunction mapMockProductToSchema(\n product: ProductDetails,\n editorConfig: any,\n rate: number,\n payload: BasePayload,\n) {\n return {\n description: convertHTMLToLexical({\n editorConfig,\n html: product.description || \"\",\n JSDOM,\n // uploadImage: async (src: string) => {\n // return uploadImageToPayload(src, payload);\n // },\n }),\n pid: product.pid,\n title: product.productNameEn,\n variants: product.variants?.map((variant) => ({\n imageUrl: variant.variantImage, // Map image URL to 'id' if using media collection\n options: variant.variantKey?.split(\"-\").map((key, index) => ({\n option: index === 0 ? \"Color\" : \"Size\", // Assuming 'Color' and 'Size', adjust keys if needed\n value: key,\n })),\n price: new decimal(variant.variantSellPrice || 0).mul(rate).toNumber().toFixed(2),\n vid: variant.vid,\n })),\n };\n}\n\nconst findProductById = async (productId: string) => {\n const result = await cjSdk.getProductDetails({\n pid: productId,\n });\n return result.data;\n};\n\nconst createOrUpdateProduct = async (\n product: Omit<Product, \"createdAt\" | \"id\" | \"updatedAt\">,\n payload: BasePayload,\n) => {\n const { totalDocs } = await payload.count({\n collection: \"products\",\n where: {\n pid: {\n equals: product.pid,\n },\n },\n });\n\n if (totalDocs === 0) {\n return payload.create({\n collection: \"products\",\n data: { ...product } as any,\n });\n }\n};\n\nexport const fetchExchangeRates = async () => {\n const response = await fetch(\"https://open.er-api.com/v6/latest/USD\");\n const data = await response.json();\n\n return data;\n};\n\nexport const syncProducts = async (productIds: string[], payload: BasePayload) => {\n const exchangeRates = await fetchExchangeRates();\n const storeSettings = await payload.findGlobal({\n slug: \"store-settings\",\n });\n const rate = exchangeRates.rates[storeSettings.currency || \"USD\"];\n\n const editorConfig = await editorConfigFactory.default({\n config: payload.config,\n });\n const products: ProductDetails[] = [];\n for (const productId of productIds) {\n const product = await findProductById(productId);\n if (!product) {\n continue;\n }\n products.push(product);\n await delay(1010);\n }\n const mappedProducts = products.map((product) => {\n return mapMockProductToSchema(product, editorConfig, rate, payload);\n });\n\n await Promise.all(\n mappedProducts.map((product) => createOrUpdateProduct(product as any, payload)),\n );\n\n return products;\n};\n"],"names":["convertHTMLToLexical","editorConfigFactory","decimal","JSDOM","cjSdk","path","dirname","fs","promisify","pipeline","writeFile","fileURLToPath","__filename","url","__dirname","streamPipeline","delay","ms","Promise","resolve","setTimeout","download","uri","filename","response","fetch","ok","Error","statusText","contentType","headers","get","contentLength","console","log","buffer","Buffer","from","arrayBuffer","error","uploadImageToPayload","src","payload","tempFilePath","join","uploadedImage","create","collection","data","alt","filePath","unlink","err","id","prefix","updatedAt","createdAt","thumbnailURL","mimeType","filesize","width","height","focalX","focalY","mapMockProductToSchema","product","editorConfig","rate","description","html","pid","title","productNameEn","variants","map","variant","imageUrl","variantImage","options","variantKey","split","key","index","option","value","price","variantSellPrice","mul","toNumber","toFixed","vid","findProductById","productId","result","getProductDetails","createOrUpdateProduct","totalDocs","count","where","equals","fetchExchangeRates","json","syncProducts","productIds","exchangeRates","storeSettings","findGlobal","slug","rates","currency","default","config","products","push","mappedProducts","all"],"mappings":"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"}
|
1
|
+
{"version":3,"sources":["../../src/service/sync-products.ts"],"sourcesContent":["import type { DefaultNodeTypes, TypedEditorState } from \"@payloadcms/richtext-lexical\";\nimport type { BasePayload } from \"payload\";\n\nimport { convertHTMLToLexical, editorConfigFactory } from \"@payloadcms/richtext-lexical\";\nimport decimal from \"decimal.js\";\nimport { JSDOM } from \"jsdom\";\n\nimport type { ProductDetails } from \"../sdk/products/product-types\";\n\nimport * as cjSdk from \"../sdk/cj-sdk\";\nimport path, { dirname, join } from \"path\";\nimport fs from \"fs\";\nimport { promisify } from \"util\";\nimport { pipeline } from \"stream\";\nimport { writeFile } from \"fs/promises\";\nimport { fileURLToPath } from \"url\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst streamPipeline = promisify(pipeline);\n\ninterface Product {\n description: TypedEditorState<DefaultNodeTypes>;\n pid: string;\n title: string;\n source: \"manual\" | \"cj\";\n variants?: Array<{\n imageUrl?: string;\n options?: Array<{ option: string; value: string }>;\n price?: number;\n vid: string;\n }>;\n}\n\nconst delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst download = async (uri: string, filename: string): Promise<void> => {\n try {\n const response = await fetch(uri);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${uri}: ${response.statusText}`);\n }\n\n const contentType = response.headers.get(\"content-type\");\n const contentLength = response.headers.get(\"content-length\");\n\n console.log(\"content-type:\", contentType);\n console.log(\"content-length:\", contentLength);\n\n const buffer = Buffer.from(await response.arrayBuffer());\n\n await writeFile(filename, buffer);\n\n console.log(\"Download complete:\", filename);\n } catch (error) {\n console.error(\"Error downloading file:\", error);\n }\n};\n\nasync function uploadImageToPayload(src: string, payload: BasePayload): Promise<any | null> {\n const tempFilePath = path.join(__dirname, \"temp-image.jpg\");\n\n try {\n // Fetch the image\n const response = await fetch(src);\n if (!response.ok) throw new Error(`Failed to fetch image: ${response.statusText}`);\n\n // Stream the response body to a temporary file\n await download(src, tempFilePath);\n\n // Upload the image using Payload's Local API\n const uploadedImage = await payload.create({\n collection: \"media\",\n data: {\n alt: \"Some alt text\",\n },\n\n filePath: tempFilePath,\n });\n\n console.log(\"Uploaded media document:\", uploadedImage);\n\n // Clean up: delete the temporary file\n fs.unlink(tempFilePath, (err) => {\n if (err) console.error(\"Error deleting temporary file:\", err);\n });\n\n return {\n id: uploadedImage.id,\n alt: uploadedImage.alt || \"\",\n prefix: \"media\",\n updatedAt: uploadedImage.updatedAt,\n createdAt: uploadedImage.createdAt,\n url: uploadedImage.url,\n thumbnailURL: uploadedImage.thumbnailURL || null,\n filename: uploadedImage.filename,\n mimeType: uploadedImage.mimeType,\n filesize: uploadedImage.filesize,\n width: uploadedImage.width,\n height: uploadedImage.height,\n focalX: 50,\n focalY: 50,\n };\n } catch (error) {\n console.error(\"Error uploading image:\", error);\n }\n}\nfunction mapMockProductToSchema(\n product: ProductDetails,\n editorConfig: any,\n rate: number,\n payload: BasePayload,\n) {\n return {\n description: convertHTMLToLexical({\n editorConfig,\n html: product.description || \"\",\n JSDOM,\n // uploadImage: async (src: string) => {\n // return uploadImageToPayload(src, payload);\n // },\n }),\n source: \"cj\",\n pid: product.pid,\n title: product.productNameEn,\n variants: product.variants?.map((variant) => ({\n imageUrl: variant.variantImage, // Map image URL to 'id' if using media collection\n options: variant.variantKey?.split(\"-\").map((key, index) => ({\n option: index === 0 ? \"Color\" : \"Size\", // Assuming 'Color' and 'Size', adjust keys if needed\n value: key,\n })),\n price: new decimal(variant.variantSellPrice || 0).mul(rate).toNumber().toFixed(2),\n vid: variant.vid,\n })),\n };\n}\n\nconst findProductById = async (productId: string) => {\n const result = await cjSdk.getProductDetails({\n pid: productId,\n });\n return result.data;\n};\n\nconst createOrUpdateProduct = async (\n product: Omit<Product, \"createdAt\" | \"id\" | \"updatedAt\">,\n payload: BasePayload,\n) => {\n const { totalDocs } = await payload.count({\n collection: \"products\",\n where: {\n pid: {\n equals: product.pid,\n },\n },\n });\n\n if (totalDocs === 0) {\n return payload.create({\n collection: \"products\",\n data: { ...product } as any,\n });\n }\n};\n\nexport const fetchExchangeRates = async () => {\n const response = await fetch(\"https://open.er-api.com/v6/latest/USD\");\n const data = await response.json();\n\n return data;\n};\n\nexport const syncProducts = async (productIds: string[], payload: BasePayload) => {\n const exchangeRates = await fetchExchangeRates();\n const storeSettings = await payload.findGlobal({\n slug: \"store-settings\",\n });\n const rate = exchangeRates.rates[storeSettings.currency || \"USD\"];\n\n const editorConfig = await editorConfigFactory.default({\n config: payload.config,\n });\n const products: ProductDetails[] = [];\n for (const productId of productIds) {\n const product = await findProductById(productId);\n if (!product) {\n continue;\n }\n products.push(product);\n await delay(1010);\n }\n const mappedProducts = products.map((product) => {\n return mapMockProductToSchema(product, editorConfig, rate, payload);\n });\n\n await Promise.all(\n mappedProducts.map((product) => createOrUpdateProduct(product as any, payload)),\n );\n\n return products;\n};\n"],"names":["convertHTMLToLexical","editorConfigFactory","decimal","JSDOM","cjSdk","path","dirname","fs","promisify","pipeline","writeFile","fileURLToPath","__filename","url","__dirname","streamPipeline","delay","ms","Promise","resolve","setTimeout","download","uri","filename","response","fetch","ok","Error","statusText","contentType","headers","get","contentLength","console","log","buffer","Buffer","from","arrayBuffer","error","uploadImageToPayload","src","payload","tempFilePath","join","uploadedImage","create","collection","data","alt","filePath","unlink","err","id","prefix","updatedAt","createdAt","thumbnailURL","mimeType","filesize","width","height","focalX","focalY","mapMockProductToSchema","product","editorConfig","rate","description","html","source","pid","title","productNameEn","variants","map","variant","imageUrl","variantImage","options","variantKey","split","key","index","option","value","price","variantSellPrice","mul","toNumber","toFixed","vid","findProductById","productId","result","getProductDetails","createOrUpdateProduct","totalDocs","count","where","equals","fetchExchangeRates","json","syncProducts","productIds","exchangeRates","storeSettings","findGlobal","slug","rates","currency","default","config","products","push","mappedProducts","all"],"mappings":"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"}
|
package/dist/types.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export interface CJApiResponse<T> {\n code: number;\n result: boolean;\n message: string;\n data: T | null;\n requestId: string;\n}\n\nexport interface AccessTokenResponse {\n code: number;\n result: boolean;\n message: string;\n data: {\n accessToken: string;\n accessTokenExpiryDate: string | Date;\n refreshToken: string;\n refreshTokenExpiryDate: string | Date;\n createDate: string;\n } | null;\n requestId: string;\n}\n\nexport interface Variant {\n vid: string;\n pid: string;\n variantName: string | null;\n variantNameEn: string | null;\n variantSku: string;\n variantImage: string | null;\n variantStandard: string | null;\n variantUnit: string | null;\n variantProperty: string | null;\n variantKey: string;\n variantLength: number;\n variantWidth: number;\n variantHeight: number;\n variantVolume: number;\n variantWeight: number;\n variantSellPrice: number;\n variantSugSellPrice: number;\n createTime: string;\n}\n\nexport interface ProductDetailResponseData {\n pid: string;\n productName: string[];\n productNameEn: string;\n productSku: string;\n productImage: string;\n productWeight: number;\n productUnit: string;\n productType: string;\n categoryId: string;\n categoryName: string;\n entryCode: string;\n entryName: string;\n entryNameEn: string;\n materialName: string[];\n materialNameEn: string[];\n materialKey: string[];\n packingWeight: number;\n packingName: string[];\n packingNameEn: string[];\n packingKey: string[];\n productKey: string[];\n productKeyEn: string;\n sellPrice: number;\n sourceFrom: number;\n description: string;\n suggestSellPrice: string;\n listedNum: number;\n status: string;\n supplierName: string;\n supplierId: string;\n variants: Variant[];\n createrTime: string;\n}\n"],"names":[],"mappings":"AA2CA,WAiCC"}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import crypto from "crypto";
|
2
|
+
const getKey = (rawKey)=>{
|
3
|
+
return crypto.createHash("sha256").update(rawKey).digest();
|
4
|
+
};
|
5
|
+
const getTenantSecret = (tenantId)=>{
|
6
|
+
const key = tenantId;
|
7
|
+
if (!key) throw new Error(`Missing secret for tenant: ${tenantId}`);
|
8
|
+
return Buffer.from(key, "hex");
|
9
|
+
};
|
10
|
+
export const encryptToken = (token)=>{
|
11
|
+
const key = getKey(process.env.ENCRYPTION_KEY);
|
12
|
+
const iv = crypto.randomBytes(12);
|
13
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
14
|
+
const encrypted = Buffer.concat([
|
15
|
+
cipher.update(token, "utf8"),
|
16
|
+
cipher.final()
|
17
|
+
]);
|
18
|
+
const tag = cipher.getAuthTag();
|
19
|
+
const result = {
|
20
|
+
iv: iv.toString("hex"),
|
21
|
+
tag: tag.toString("hex"),
|
22
|
+
content: encrypted.toString("hex")
|
23
|
+
};
|
24
|
+
return Buffer.from(JSON.stringify(result)).toString("base64");
|
25
|
+
};
|
26
|
+
export const decryptToken = (encryptedToken)=>{
|
27
|
+
const key = getKey(process.env.ENCRYPTION_KEY);
|
28
|
+
const decoded = JSON.parse(Buffer.from(encryptedToken, "base64").toString("utf8"));
|
29
|
+
const iv = Buffer.from(decoded.iv, "hex");
|
30
|
+
const tag = Buffer.from(decoded.tag, "hex");
|
31
|
+
const content = Buffer.from(decoded.content, "hex");
|
32
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
|
33
|
+
decipher.setAuthTag(tag);
|
34
|
+
const decrypted = Buffer.concat([
|
35
|
+
decipher.update(content),
|
36
|
+
decipher.final()
|
37
|
+
]);
|
38
|
+
return decrypted.toString("utf8");
|
39
|
+
};
|
40
|
+
|
41
|
+
//# sourceMappingURL=manage-tokens.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../../src/util/manage-tokens.ts"],"sourcesContent":["import crypto from \"crypto\";\n\ntype TokenPayload = string;\ntype EncryptedData = {\n iv: string;\n tag: string;\n content: string;\n};\n\nconst getKey = (rawKey: string): Buffer => {\n return crypto.createHash(\"sha256\").update(rawKey).digest();\n};\n\nconst getTenantSecret = (tenantId: string): Buffer => {\n const key = tenantId;\n if (!key) throw new Error(`Missing secret for tenant: ${tenantId}`);\n return Buffer.from(key, \"hex\");\n};\n\nexport const encryptToken = (token: TokenPayload): string => {\n const key = getKey(process.env.ENCRYPTION_KEY!);\n const iv = crypto.randomBytes(12);\n const cipher = crypto.createCipheriv(\"aes-256-gcm\", key, iv);\n\n const encrypted = Buffer.concat([cipher.update(token, \"utf8\"), cipher.final()]);\n\n const tag = cipher.getAuthTag();\n\n const result: EncryptedData = {\n iv: iv.toString(\"hex\"),\n tag: tag.toString(\"hex\"),\n content: encrypted.toString(\"hex\"),\n };\n\n return Buffer.from(JSON.stringify(result)).toString(\"base64\");\n};\n\nexport const decryptToken = (encryptedToken: string): string => {\n const key = getKey(process.env.ENCRYPTION_KEY!);\n const decoded = JSON.parse(\n Buffer.from(encryptedToken, \"base64\").toString(\"utf8\"),\n ) as EncryptedData;\n\n const iv = Buffer.from(decoded.iv, \"hex\");\n const tag = Buffer.from(decoded.tag, \"hex\");\n const content = Buffer.from(decoded.content, \"hex\");\n\n const decipher = crypto.createDecipheriv(\"aes-256-gcm\", key, iv);\n decipher.setAuthTag(tag);\n\n const decrypted = Buffer.concat([decipher.update(content), decipher.final()]);\n\n return decrypted.toString(\"utf8\");\n};\n"],"names":["crypto","getKey","rawKey","createHash","update","digest","getTenantSecret","tenantId","key","Error","Buffer","from","encryptToken","token","process","env","ENCRYPTION_KEY","iv","randomBytes","cipher","createCipheriv","encrypted","concat","final","tag","getAuthTag","result","toString","content","JSON","stringify","decryptToken","encryptedToken","decoded","parse","decipher","createDecipheriv","setAuthTag","decrypted"],"mappings":"AAAA,OAAOA,YAAY,SAAS;AAS5B,MAAMC,SAAS,CAACC;IACZ,OAAOF,OAAOG,UAAU,CAAC,UAAUC,MAAM,CAACF,QAAQG,MAAM;AAC5D;AAEA,MAAMC,kBAAkB,CAACC;IACrB,MAAMC,MAAMD;IACZ,IAAI,CAACC,KAAK,MAAM,IAAIC,MAAM,CAAC,2BAA2B,EAAEF,UAAU;IAClE,OAAOG,OAAOC,IAAI,CAACH,KAAK;AAC5B;AAEA,OAAO,MAAMI,eAAe,CAACC;IACzB,MAAML,MAAMP,OAAOa,QAAQC,GAAG,CAACC,cAAc;IAC7C,MAAMC,KAAKjB,OAAOkB,WAAW,CAAC;IAC9B,MAAMC,SAASnB,OAAOoB,cAAc,CAAC,eAAeZ,KAAKS;IAEzD,MAAMI,YAAYX,OAAOY,MAAM,CAAC;QAACH,OAAOf,MAAM,CAACS,OAAO;QAASM,OAAOI,KAAK;KAAG;IAE9E,MAAMC,MAAML,OAAOM,UAAU;IAE7B,MAAMC,SAAwB;QAC1BT,IAAIA,GAAGU,QAAQ,CAAC;QAChBH,KAAKA,IAAIG,QAAQ,CAAC;QAClBC,SAASP,UAAUM,QAAQ,CAAC;IAChC;IAEA,OAAOjB,OAAOC,IAAI,CAACkB,KAAKC,SAAS,CAACJ,SAASC,QAAQ,CAAC;AACxD,EAAE;AAEF,OAAO,MAAMI,eAAe,CAACC;IACzB,MAAMxB,MAAMP,OAAOa,QAAQC,GAAG,CAACC,cAAc;IAC7C,MAAMiB,UAAUJ,KAAKK,KAAK,CACtBxB,OAAOC,IAAI,CAACqB,gBAAgB,UAAUL,QAAQ,CAAC;IAGnD,MAAMV,KAAKP,OAAOC,IAAI,CAACsB,QAAQhB,EAAE,EAAE;IACnC,MAAMO,MAAMd,OAAOC,IAAI,CAACsB,QAAQT,GAAG,EAAE;IACrC,MAAMI,UAAUlB,OAAOC,IAAI,CAACsB,QAAQL,OAAO,EAAE;IAE7C,MAAMO,WAAWnC,OAAOoC,gBAAgB,CAAC,eAAe5B,KAAKS;IAC7DkB,SAASE,UAAU,CAACb;IAEpB,MAAMc,YAAY5B,OAAOY,MAAM,CAAC;QAACa,SAAS/B,MAAM,CAACwB;QAAUO,SAASZ,KAAK;KAAG;IAE5E,OAAOe,UAAUX,QAAQ,CAAC;AAC9B,EAAE"}
|