save work
This commit is contained in:
127
.vscode/launch.json
vendored
127
.vscode/launch.json
vendored
@ -2,44 +2,113 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Next.js: debug server-side",
|
"name": "Debug Send Emails (No Previous Emails)",
|
||||||
"type": "node-terminal",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"command": "npm run dev",
|
"runtimeExecutable": "node",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"--require",
|
||||||
|
"ts-node/register"
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}/src/scripts/send-emails-to-customers.ts",
|
||||||
|
"--count=0"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
"<node_internals>/**"
|
"<node_internals>/**"
|
||||||
],
|
],
|
||||||
"console": "integratedTerminal"
|
"env": {
|
||||||
|
"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.scripts.json",
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"outFiles": [
|
||||||
|
"${workspaceFolder}/**/*.js"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Next.js: debug client-side",
|
"name": "Debug Send Emails (1 Previous Email)",
|
||||||
"type": "chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"url": "http://localhost:3000",
|
|
||||||
"webRoot": "${workspaceFolder}",
|
|
||||||
"sourceMapPathOverrides": {
|
|
||||||
"webpack://_N_E/*": "${webRoot}/*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Next.js: debug full stack",
|
|
||||||
"type": "node-terminal",
|
|
||||||
"request": "launch",
|
|
||||||
"command": "npm run dev",
|
|
||||||
"serverReadyAction": {
|
|
||||||
"pattern": "started server on .+, url: (https?://.+)",
|
|
||||||
"uriFormat": "%s",
|
|
||||||
"action": "debugWithChrome"
|
|
||||||
},
|
|
||||||
"console": "integratedTerminal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Next.js: attach to server",
|
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "attach",
|
"request": "launch",
|
||||||
"port": 9229,
|
"runtimeExecutable": "node",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"--require",
|
||||||
|
"ts-node/register"
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}/src/scripts/send-emails-to-customers.ts",
|
||||||
|
"--count=1"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
"<node_internals>/**"
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.scripts.json",
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"outFiles": [
|
||||||
|
"${workspaceFolder}/**/*.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug Send Emails (With LMStudio Config)",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"runtimeExecutable": "node",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"--require",
|
||||||
|
"ts-node/register"
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}/src/scripts/send-emails-to-customers.ts",
|
||||||
|
"--count=0",
|
||||||
|
"--lmstudio-url=http://localhost:1234/v1/chat/completions",
|
||||||
|
"--model=local-model",
|
||||||
|
"--temperature=0.7"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.scripts.json",
|
||||||
|
"NODE_ENV": "development",
|
||||||
|
"GMAIL_USER": "your.email@gmail.com",
|
||||||
|
"GMAIL_APP_PASSWORD": "your-app-password"
|
||||||
|
},
|
||||||
|
"outFiles": [
|
||||||
|
"${workspaceFolder}/**/*.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug Send Emails (Dry Run)",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"runtimeExecutable": "node",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"--require",
|
||||||
|
"ts-node/register"
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}/src/scripts/send-emails-to-customers.ts",
|
||||||
|
"--count=0",
|
||||||
|
"--dry-run=true"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.scripts.json",
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"outFiles": [
|
||||||
|
"${workspaceFolder}/**/*.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
116
package-lock.json
generated
116
package-lock.json
generated
@ -18,7 +18,9 @@
|
|||||||
"@editorjs/marker": "^1.4.0",
|
"@editorjs/marker": "^1.4.0",
|
||||||
"@editorjs/paragraph": "^2.11.7",
|
"@editorjs/paragraph": "^2.11.7",
|
||||||
"@editorjs/quote": "^2.7.6",
|
"@editorjs/quote": "^2.7.6",
|
||||||
|
"@types/axios": "^0.14.4",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
|
"axios": "^1.8.4",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"csv-parse": "^5.6.0",
|
"csv-parse": "^5.6.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
@ -1499,6 +1501,15 @@
|
|||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/axios": {
|
||||||
|
"version": "0.14.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.4.tgz",
|
||||||
|
"integrity": "sha512-9JgOaunvQdsQ/qW2OPmE5+hCeUB52lQSolecrFrthct55QekhmXEwT203s20RL+UHtCQc15y3VXpby9E7Kkh/g==",
|
||||||
|
"deprecated": "This is a stub types definition. axios provides its own type definitions, so you do not need this installed.",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/bcrypt": {
|
"node_modules/@types/bcrypt": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz",
|
||||||
@ -2335,6 +2346,11 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
|
},
|
||||||
"node_modules/available-typed-arrays": {
|
"node_modules/available-typed-arrays": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||||
@ -2370,6 +2386,16 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
|
||||||
|
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/axobject-query": {
|
"node_modules/axobject-query": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||||
@ -2570,7 +2596,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
@ -2735,6 +2760,17 @@
|
|||||||
"color-support": "bin.js"
|
"color-support": "bin.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
@ -2930,6 +2966,14 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delegates": {
|
"node_modules/delegates": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||||
@ -2992,7 +3036,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.1",
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
@ -3144,7 +3187,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -3154,7 +3196,6 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -3192,7 +3233,6 @@
|
|||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0"
|
"es-errors": "^1.3.0"
|
||||||
@ -3205,7 +3245,6 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
@ -3836,6 +3875,25 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
|
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/for-each": {
|
"node_modules/for-each": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||||
@ -3880,6 +3938,20 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fs-constants": {
|
"node_modules/fs-constants": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
@ -3908,7 +3980,6 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
@ -3988,7 +4059,6 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.2",
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
@ -4013,7 +4083,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dunder-proto": "^1.0.1",
|
"dunder-proto": "^1.0.1",
|
||||||
@ -4128,7 +4197,6 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -4207,7 +4275,6 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -4220,7 +4287,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-symbols": "^1.0.3"
|
"has-symbols": "^1.0.3"
|
||||||
@ -4242,7 +4308,6 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
@ -5493,7 +5558,6 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -5523,6 +5587,25 @@
|
|||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mimic-response": {
|
"node_modules/mimic-response": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||||
@ -6537,6 +6620,11 @@
|
|||||||
"react-is": "^16.13.1"
|
"react-is": "^16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||||
|
},
|
||||||
"node_modules/pump": {
|
"node_modules/pump": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||||
|
|||||||
@ -23,7 +23,9 @@
|
|||||||
"@editorjs/marker": "^1.4.0",
|
"@editorjs/marker": "^1.4.0",
|
||||||
"@editorjs/paragraph": "^2.11.7",
|
"@editorjs/paragraph": "^2.11.7",
|
||||||
"@editorjs/quote": "^2.7.6",
|
"@editorjs/quote": "^2.7.6",
|
||||||
|
"@types/axios": "^0.14.4",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
|
"axios": "^1.8.4",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"csv-parse": "^5.6.0",
|
"csv-parse": "^5.6.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
|||||||
@ -3,20 +3,132 @@ import { getDataSource } from '../lib/database';
|
|||||||
import { Customer } from '../lib/database/entities/Customer';
|
import { Customer } from '../lib/database/entities/Customer';
|
||||||
import { ContactRecord } from '../lib/database/entities/ContactRecord';
|
import { ContactRecord } from '../lib/database/entities/ContactRecord';
|
||||||
import { sendEmail } from '../lib/email';
|
import { sendEmail } from '../lib/email';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
// Get command line arguments
|
// Get command line arguments
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const emailCountArg = args.find(arg => arg.startsWith('--count='));
|
const emailCountArg = args.find(arg => arg.startsWith('--count='));
|
||||||
|
const lmStudioUrlArg = args.find(arg => arg.startsWith('--lmstudio-url='));
|
||||||
|
const modelArg = args.find(arg => arg.startsWith('--model='));
|
||||||
|
const temperatureArg = args.find(arg => arg.startsWith('--temperature='));
|
||||||
|
const dryRunArg = args.find(arg => arg.startsWith('--dry-run='));
|
||||||
|
|
||||||
|
// Parse arguments with defaults
|
||||||
const defaultEmailCount = 0;
|
const defaultEmailCount = 0;
|
||||||
const emailCount = emailCountArg
|
const emailCount = emailCountArg
|
||||||
? parseInt(emailCountArg.split('=')[1], 10)
|
? parseInt(emailCountArg.split('=')[1], 10)
|
||||||
: defaultEmailCount;
|
: defaultEmailCount;
|
||||||
|
|
||||||
|
// LMStudio API settings
|
||||||
|
const lmStudioUrl = lmStudioUrlArg
|
||||||
|
? lmStudioUrlArg.split('=')[1]
|
||||||
|
: 'http://localhost:3000/v1/chat/completions'; // Default LMStudio API endpoint
|
||||||
|
const model = modelArg
|
||||||
|
? modelArg.split('=')[1]
|
||||||
|
: 'local-model'; // Default model name
|
||||||
|
const temperature = temperatureArg
|
||||||
|
? parseFloat(temperatureArg.split('=')[1])
|
||||||
|
: 0.7; // Default temperature
|
||||||
|
|
||||||
|
// Dry run mode - generate content but don't send emails or create records
|
||||||
|
const dryRun = dryRunArg
|
||||||
|
? dryRunArg.split('=')[1].toLowerCase() === 'true'
|
||||||
|
: false;
|
||||||
|
|
||||||
if (isNaN(emailCount) || emailCount < 0) {
|
if (isNaN(emailCount) || emailCount < 0) {
|
||||||
console.error('Error: Email count must be a non-negative number');
|
console.error('Error: Email count must be a non-negative number');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to generate email content using LMStudio API
|
||||||
|
async function generateEmailContent(
|
||||||
|
customer: Customer,
|
||||||
|
emailCount: number
|
||||||
|
): Promise<{ subject: string; body: string }> {
|
||||||
|
try {
|
||||||
|
console.log(`Generating email content for ${customer.name} using LMStudio API...`);
|
||||||
|
|
||||||
|
// Create a prompt based on customer info and email count
|
||||||
|
let prompt = '';
|
||||||
|
if (emailCount === 0) {
|
||||||
|
prompt = `Generate a welcome email for a new customer named ${customer.name} from ${customer.url}.
|
||||||
|
This is the first contact with them. The email should be professional but friendly.
|
||||||
|
Return ONLY a JSON object with 'subject' and 'body' fields. The body should be in HTML format.`;
|
||||||
|
}/* else if (emailCount === 1) {
|
||||||
|
prompt = `Generate a follow-up email for customer ${customer.name} from ${customer.url}.
|
||||||
|
This is the second contact with them. The email should reference a previous welcome email and provide more value.
|
||||||
|
Return ONLY a JSON object with 'subject' and 'body' fields. The body should be in HTML format.`;
|
||||||
|
} else {
|
||||||
|
prompt = `Generate a relationship-building email for a regular customer named ${customer.name} from ${customer.url}.
|
||||||
|
This is contact number ${emailCount + 1} with them. The email should be personalized and provide specific value.
|
||||||
|
Return ONLY a JSON object with 'subject' and 'body' fields. The body should be in HTML format.`;
|
||||||
|
} */
|
||||||
|
|
||||||
|
// Call LMStudio API
|
||||||
|
const response = await axios.post(
|
||||||
|
lmStudioUrl,
|
||||||
|
{
|
||||||
|
model: model,
|
||||||
|
messages: [
|
||||||
|
{ role: 'system', content: 'You are an expert email copywriter who creates engaging, professional emails.' },
|
||||||
|
{ role: 'user', content: prompt }
|
||||||
|
],
|
||||||
|
temperature: temperature,
|
||||||
|
max_tokens: 1000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Parse the response to extract the JSON
|
||||||
|
const assistantMessage = response.data.choices[0].message.content;
|
||||||
|
|
||||||
|
// Try to extract JSON from the response
|
||||||
|
try {
|
||||||
|
// Look for JSON object in the response
|
||||||
|
const jsonMatch = assistantMessage.match(/\{[\s\S]*\}/);
|
||||||
|
if (jsonMatch) {
|
||||||
|
const jsonStr = jsonMatch[0];
|
||||||
|
const emailContent = JSON.parse(jsonStr);
|
||||||
|
|
||||||
|
if (emailContent.subject && emailContent.body) {
|
||||||
|
return {
|
||||||
|
subject: emailContent.subject,
|
||||||
|
body: emailContent.body
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we couldn't parse JSON or it doesn't have required fields
|
||||||
|
throw new Error('Could not parse valid JSON from LMStudio response');
|
||||||
|
} catch (parseError) {
|
||||||
|
console.warn('Failed to parse JSON from LMStudio response, using fallback content');
|
||||||
|
console.warn('LMStudio response:', assistantMessage);
|
||||||
|
|
||||||
|
// Fallback content
|
||||||
|
return {
|
||||||
|
subject: `Update from Our Company - Contact #${emailCount + 1}`,
|
||||||
|
body: `<h1>Hello ${customer.name}!</h1><p>Thank you for your continued interest in our services. We appreciate your business.</p>`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Unknown error occurred';
|
||||||
|
|
||||||
|
console.error('Error calling LMStudio API:', errorMessage);
|
||||||
|
|
||||||
|
// Fallback content in case of API error
|
||||||
|
return {
|
||||||
|
subject: `Important Update - Contact #${emailCount + 1}`,
|
||||||
|
body: `<h1>Hello ${customer.name}!</h1><p>Thank you for your interest in our services. We look forward to working with you!</p>`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
try {
|
try {
|
||||||
console.log('Initializing database connection...');
|
console.log('Initializing database connection...');
|
||||||
@ -71,30 +183,28 @@ async function main() {
|
|||||||
console.log('\nSending emails to customers...');
|
console.log('\nSending emails to customers...');
|
||||||
|
|
||||||
// Send emails to each customer
|
// Send emails to each customer
|
||||||
let emailSubject = 'Welcome to Our Service';
|
|
||||||
let emailBody = 'Thank you for your interest in our services. We look forward to working with you!';
|
|
||||||
|
|
||||||
// Customize email based on email count
|
|
||||||
if (emailCount === 0) {
|
|
||||||
emailSubject = 'Welcome to Our Service';
|
|
||||||
emailBody = 'Thank you for your interest in our services. We look forward to working with you!';
|
|
||||||
} else if (emailCount === 1) {
|
|
||||||
emailSubject = 'Follow-up on Our Services';
|
|
||||||
emailBody = 'We hope you found our previous information helpful. Here are some additional details about our services.';
|
|
||||||
} else {
|
|
||||||
emailSubject = `Important Update - Contact #${emailCount + 1}`;
|
|
||||||
emailBody = 'We wanted to share some important updates about our services that might interest you.';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const customer of filteredCustomers) {
|
for (const customer of filteredCustomers) {
|
||||||
console.log(`Sending email to ${customer.name} (${customer.email})...`);
|
console.log(`Processing email for ${customer.name} (${customer.email})...`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Generate email content using LMStudio
|
||||||
|
const emailContent = await generateEmailContent(customer, emailCount);
|
||||||
|
|
||||||
|
console.log(`Generated subject: ${emailContent.subject}`);
|
||||||
|
|
||||||
|
if (dryRun) {
|
||||||
|
console.log(`[DRY RUN] Would send email to ${customer.name} (${customer.email})`);
|
||||||
|
console.log(`[DRY RUN] Subject: ${emailContent.subject}`);
|
||||||
|
console.log(`[DRY RUN] Body: ${emailContent.body.replace(/<[^>]*>/g, '')}`);
|
||||||
|
console.log(`[DRY RUN] No email sent and no contact record created.`);
|
||||||
|
} else {
|
||||||
|
console.log(`Sending email to ${customer.name}...`);
|
||||||
|
|
||||||
const result = await sendEmail(
|
const result = await sendEmail(
|
||||||
customer.id,
|
customer.id,
|
||||||
emailSubject,
|
emailContent.subject,
|
||||||
emailBody,
|
emailContent.body.replace(/<[^>]*>/g, ''), // Plain text version (strip HTML)
|
||||||
`<h1>Hello ${customer.name}!</h1><p>${emailBody}</p>`
|
emailContent.body // HTML version
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@ -102,8 +212,13 @@ async function main() {
|
|||||||
} else {
|
} else {
|
||||||
console.error(`❌ Failed to send email to ${customer.email}: ${result.error}`);
|
console.error(`❌ Failed to send email to ${customer.email}: ${result.error}`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`❌ Error sending email to ${customer.email}:`, error);
|
const errorMessage = error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Unknown error occurred';
|
||||||
|
|
||||||
|
console.error(`❌ Error sending email to ${customer.email}:`, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a small delay between emails to avoid rate limiting
|
// Add a small delay between emails to avoid rate limiting
|
||||||
@ -114,13 +229,21 @@ async function main() {
|
|||||||
await dataSource.destroy();
|
await dataSource.destroy();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('An error occurred:', error);
|
const errorMessage = error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Unknown error occurred';
|
||||||
|
|
||||||
|
console.error('An error occurred:', errorMessage);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the main function
|
// Run the main function
|
||||||
main().catch(error => {
|
main().catch(error => {
|
||||||
console.error('Unhandled error:', error);
|
const errorMessage = error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: 'Unknown error occurred';
|
||||||
|
|
||||||
|
console.error('Unhandled error:', errorMessage);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user