initial
This commit is contained in:
		
							
								
								
									
										66
									
								
								.gitea/workflows/default_nottags.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								.gitea/workflows/default_nottags.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| name: Default (not tags) | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     tags-ignore: | ||||
|       - '**' | ||||
|  | ||||
| env: | ||||
|   IMAGE: code.foss.global/hosttoday/ht-docker-node:npmci | ||||
|   NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git | ||||
|   NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}} | ||||
|   NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}} | ||||
|   NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}} | ||||
|   NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}} | ||||
|  | ||||
| jobs: | ||||
|   security: | ||||
|     runs-on: ubuntu-latest | ||||
|     continue-on-error: true | ||||
|     container: | ||||
|       image: ${{ env.IMAGE }} | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|  | ||||
|       - name: Install pnpm and npmci | ||||
|         run: | | ||||
|           pnpm install -g pnpm | ||||
|           pnpm install -g @ship.zone/npmci | ||||
|  | ||||
|       - name: Run npm prepare | ||||
|         run: npmci npm prepare | ||||
|  | ||||
|       - name: Audit production dependencies | ||||
|         run: | | ||||
|           npmci command npm config set registry https://registry.npmjs.org | ||||
|           npmci command pnpm audit --audit-level=high --prod | ||||
|         continue-on-error: true | ||||
|  | ||||
|       - name: Audit development dependencies | ||||
|         run: | | ||||
|           npmci command npm config set registry https://registry.npmjs.org | ||||
|           npmci command pnpm audit --audit-level=high --dev | ||||
|         continue-on-error: true | ||||
|  | ||||
|   test: | ||||
|     if: ${{ always() }} | ||||
|     needs: security | ||||
|     runs-on: ubuntu-latest | ||||
|     container: | ||||
|       image: ${{ env.IMAGE }} | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|  | ||||
|       - name: Test stable | ||||
|         run: | | ||||
|           npmci node install stable | ||||
|           npmci npm install | ||||
|           npmci npm test | ||||
|  | ||||
|       - name: Test build | ||||
|         run: | | ||||
|           npmci node install stable | ||||
|           npmci npm install | ||||
|           npmci npm build | ||||
							
								
								
									
										124
									
								
								.gitea/workflows/default_tags.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								.gitea/workflows/default_tags.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| name: Default (tags) | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     tags: | ||||
|       - '*' | ||||
|  | ||||
| env: | ||||
|   IMAGE: code.foss.global/hosttoday/ht-docker-node:npmci | ||||
|   NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git | ||||
|   NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}} | ||||
|   NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}} | ||||
|   NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}} | ||||
|   NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}} | ||||
|  | ||||
| jobs: | ||||
|   security: | ||||
|     runs-on: ubuntu-latest | ||||
|     continue-on-error: true | ||||
|     container: | ||||
|       image: ${{ env.IMAGE }} | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|  | ||||
|       - name: Prepare | ||||
|         run: | | ||||
|           pnpm install -g pnpm | ||||
|           pnpm install -g @ship.zone/npmci | ||||
|           npmci npm prepare | ||||
|  | ||||
|       - name: Audit production dependencies | ||||
|         run: | | ||||
|           npmci command npm config set registry https://registry.npmjs.org | ||||
|           npmci command pnpm audit --audit-level=high --prod | ||||
|         continue-on-error: true | ||||
|  | ||||
|       - name: Audit development dependencies | ||||
|         run: | | ||||
|           npmci command npm config set registry https://registry.npmjs.org | ||||
|           npmci command pnpm audit --audit-level=high --dev | ||||
|         continue-on-error: true | ||||
|  | ||||
|   test: | ||||
|     if: ${{ always() }} | ||||
|     needs: security | ||||
|     runs-on: ubuntu-latest | ||||
|     container: | ||||
|       image: ${{ env.IMAGE }} | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|  | ||||
|       - name: Prepare | ||||
|         run: | | ||||
|           pnpm install -g pnpm | ||||
|           pnpm install -g @ship.zone/npmci | ||||
|           npmci npm prepare | ||||
|  | ||||
|       - name: Test stable | ||||
|         run: | | ||||
|           npmci node install stable | ||||
|           npmci npm install | ||||
|           npmci npm test | ||||
|  | ||||
|       - name: Test build | ||||
|         run: | | ||||
|           npmci node install stable | ||||
|           npmci npm install | ||||
|           npmci npm build | ||||
|  | ||||
|   release: | ||||
|     needs: test | ||||
|     if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') | ||||
|     runs-on: ubuntu-latest | ||||
|     container: | ||||
|       image: ${{ env.IMAGE }} | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|  | ||||
|       - name: Prepare | ||||
|         run: | | ||||
|           pnpm install -g pnpm | ||||
|           pnpm install -g @ship.zone/npmci | ||||
|           npmci npm prepare | ||||
|  | ||||
|       - name: Release | ||||
|         run: | | ||||
|           npmci node install stable | ||||
|           npmci npm publish | ||||
|  | ||||
|   metadata: | ||||
|     needs: test | ||||
|     if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') | ||||
|     runs-on: ubuntu-latest | ||||
|     container: | ||||
|       image: ${{ env.IMAGE }} | ||||
|     continue-on-error: true | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|  | ||||
|       - name: Prepare | ||||
|         run: | | ||||
|           pnpm install -g pnpm | ||||
|           pnpm install -g @ship.zone/npmci | ||||
|           npmci npm prepare | ||||
|  | ||||
|       - name: Code quality | ||||
|         run: | | ||||
|           npmci command npm install -g typescript | ||||
|           npmci npm install | ||||
|  | ||||
|       - name: Trigger | ||||
|         run: npmci trigger | ||||
|  | ||||
|       - name: Build docs and upload artifacts | ||||
|         run: | | ||||
|           npmci node install stable | ||||
|           npmci npm install | ||||
|           pnpm install -g @git.zone/tsdoc | ||||
|           npmci command tsdoc | ||||
|         continue-on-error: true | ||||
							
								
								
									
										20
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| .nogit/ | ||||
|  | ||||
| # artifacts | ||||
| coverage/ | ||||
| public/ | ||||
| pages/ | ||||
|  | ||||
| # installs | ||||
| node_modules/ | ||||
|  | ||||
| # caches | ||||
| .yarn/ | ||||
| .cache/ | ||||
| .rpt2_cache | ||||
|  | ||||
| # builds | ||||
| dist/ | ||||
| dist_*/ | ||||
|  | ||||
| # custom | ||||
							
								
								
									
										11
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| { | ||||
|   "version": "0.2.0", | ||||
|   "configurations": [ | ||||
|     { | ||||
|       "command": "npm test", | ||||
|       "name": "Run npm test", | ||||
|       "request": "launch", | ||||
|       "type": "node-terminal" | ||||
|     } | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										26
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| { | ||||
|   "json.schemas": [ | ||||
|     { | ||||
|       "fileMatch": ["/npmextra.json"], | ||||
|       "schema": { | ||||
|         "type": "object", | ||||
|         "properties": { | ||||
|           "npmci": { | ||||
|             "type": "object", | ||||
|             "description": "settings for npmci" | ||||
|           }, | ||||
|           "gitzone": { | ||||
|             "type": "object", | ||||
|             "description": "settings for gitzone", | ||||
|             "properties": { | ||||
|               "projectType": { | ||||
|                 "type": "string", | ||||
|                 "enum": ["website", "element", "service", "npm", "wcc"] | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										18
									
								
								npmextra.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								npmextra.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| { | ||||
|   "gitzone": { | ||||
|     "projectType": "npm", | ||||
|     "module": { | ||||
|       "githost": "code.foss.global", | ||||
|       "gitscope": "push.rocks", | ||||
|       "gitrepo": "smartimap", | ||||
|       "description": "stream messages over imap", | ||||
|       "npmPackagename": "@push.rocks/smartimap", | ||||
|       "license": "MIT", | ||||
|       "projectDomain": "push.rocks" | ||||
|     } | ||||
|   }, | ||||
|   "npmci": { | ||||
|     "npmGlobalTools": [], | ||||
|     "npmAccessLevel": "public" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										53
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| { | ||||
|   "name": "@push.rocks/smartimap", | ||||
|   "version": "1.0.1", | ||||
|   "private": false, | ||||
|   "description": "stream messages over imap", | ||||
|   "main": "dist_ts/index.js", | ||||
|   "typings": "dist_ts/index.d.ts", | ||||
|   "type": "module", | ||||
|   "author": "Task Venture Capital GmbH", | ||||
|   "license": "MIT", | ||||
|   "scripts": { | ||||
|     "test": "(tstest test/ --web)", | ||||
|     "build": "(tsbuild --web --allowimplicitany)", | ||||
|     "buildDocs": "(tsdoc)" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@git.zone/tsbuild": "^2.1.25", | ||||
|     "@git.zone/tsbundle": "^2.0.5", | ||||
|     "@git.zone/tsrun": "^1.2.46", | ||||
|     "@git.zone/tstest": "^1.0.44", | ||||
|     "@push.rocks/tapbundle": "^5.3.0", | ||||
|     "@types/node": "^22.5.5" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@types/imapflow": "^1.0.19", | ||||
|     "@types/mailparser": "^3.4.4", | ||||
|     "imapflow": "^1.0.164", | ||||
|     "mailparser": "^3.7.1" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "git+https://code.foss.global/push.rocks/smartimap.git" | ||||
|   }, | ||||
|   "bugs": { | ||||
|     "url": "https://code.foss.global/push.rocks/smartimap/issues" | ||||
|   }, | ||||
|   "homepage": "https://code.foss.global/push.rocks/smartimap#readme", | ||||
|   "browserslist": [ | ||||
|     "last 1 chrome versions" | ||||
|   ], | ||||
|   "files": [ | ||||
|     "ts/**/*", | ||||
|     "ts_web/**/*", | ||||
|     "dist/**/*", | ||||
|     "dist_*/**/*", | ||||
|     "dist_ts/**/*", | ||||
|     "dist_ts_web/**/*", | ||||
|     "assets/**/*", | ||||
|     "cli.js", | ||||
|     "npmextra.json", | ||||
|     "readme.md" | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										7093
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7093
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3
									
								
								readme.hints.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								readme.hints.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| # Project Readme Hints | ||||
|  | ||||
| This is the initial readme hints file. | ||||
							
								
								
									
										7
									
								
								readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								readme.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # @push.rocks/smartimap | ||||
|  | ||||
| stream messages over imap | ||||
|  | ||||
| ## How to create the docs | ||||
|  | ||||
| To create docs run gitzone aidoc. | ||||
							
								
								
									
										39
									
								
								test/test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								test/test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| import { expect, expectAsync, tap } from '@push.rocks/tapbundle'; | ||||
| import { tapNodeTools } from '@push.rocks/tapbundle/node'; | ||||
| import * as smartimap from '../ts/index.js'; | ||||
|  | ||||
| let testSmartImap: smartimap.SmartImap; | ||||
|  | ||||
| tap.test('smartimap', async () => { | ||||
|   testSmartImap = new smartimap.SmartImap({ | ||||
|     host: await tapNodeTools.getEnvVarOnDemand('IMAP_URL'), | ||||
|     port: 993, | ||||
|     secure: true, | ||||
|     auth: { | ||||
|       user: await tapNodeTools.getEnvVarOnDemand('IMAP_USER'), | ||||
|       pass: await tapNodeTools.getEnvVarOnDemand('IMAP_PASSWORD'), | ||||
|     }, | ||||
|     mailbox: 'INBOX', | ||||
|     filter: { seen: true, to: await tapNodeTools.getEnvVarOnDemand('IMAP_USER') }, | ||||
|   }); | ||||
|  | ||||
|   await testSmartImap.connect(); | ||||
|  | ||||
|   testSmartImap.on('message', (message) => { | ||||
|     console.log(message); | ||||
|   }); | ||||
|  | ||||
|   testSmartImap.on('error', (error) => { | ||||
|     console.error(error); | ||||
|   }); | ||||
|  | ||||
|   testSmartImap.on('connected', () => { | ||||
|     console.log('Connected'); | ||||
|   }); | ||||
|  | ||||
|   testSmartImap.on('disconnected', () => { | ||||
|     console.log('Disconnected'); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
							
								
								
									
										103
									
								
								ts/classes.smartimap.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								ts/classes.smartimap.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| import * as plugins from './smartimap.plugins.js'; | ||||
|  | ||||
| export interface SmartImapConfig { | ||||
|     host: string; | ||||
|     port?: number; // Defaults to 993 if secure, else 143 | ||||
|     secure?: boolean; // Defaults to true | ||||
|     auth: { | ||||
|         user: string; | ||||
|         pass: string; | ||||
|     }; | ||||
|     mailbox?: string; // Defaults to 'INBOX' | ||||
|     filter?: plugins.imapflow.SearchObject; // IMAP search criteria object | ||||
| } | ||||
|  | ||||
| export class SmartImap extends plugins.events.EventEmitter { | ||||
|     private client: plugins.imapflow.ImapFlow; | ||||
|     private mailbox: string; | ||||
|     private filter: plugins.imapflow.SearchObject; | ||||
|     private connected: boolean = false; | ||||
|     private processing: boolean = false; | ||||
|     private seenUids: Set<number> = new Set(); | ||||
|  | ||||
|     constructor(private config: SmartImapConfig) { | ||||
|         super(); | ||||
|  | ||||
|         this.mailbox = config.mailbox || 'INBOX'; | ||||
|         this.filter = config.filter || { seen: false }; // Updated default filter | ||||
|  | ||||
|         this.client = new plugins.imapflow.ImapFlow({ | ||||
|             host: config.host, | ||||
|             port: config.port || (config.secure === false ? 143 : 993), | ||||
|             secure: config.secure !== false, | ||||
|             auth: config.auth, | ||||
|             logger: false, // Set to console for debugging | ||||
|         }); | ||||
|  | ||||
|         this.client.on('error', (error) => { | ||||
|             this.emit('error', error); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public async connect(): Promise<void> { | ||||
|         try { | ||||
|             await this.client.connect(); | ||||
|             this.connected = true; | ||||
|             await this.client.mailboxOpen(this.mailbox); // Removed { reopen: true } | ||||
|             this.emit('connected'); | ||||
|             this.setupIdle(); | ||||
|         } catch (error) { | ||||
|             this.emit('error', error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async setupIdle(): Promise<void> { | ||||
|         this.client.on('exists', async () => { | ||||
|             await this.fetchNewMessages(); | ||||
|         }); | ||||
|  | ||||
|         // Initial fetch | ||||
|         await this.fetchNewMessages(); | ||||
|     } | ||||
|  | ||||
|     private async fetchNewMessages(): Promise<void> { | ||||
|         if (this.processing) return; | ||||
|         this.processing = true; | ||||
|  | ||||
|         try { | ||||
|             const searchResult = await this.client.search(this.filter); | ||||
|  | ||||
|             // Convert searchResult to a regular array | ||||
|             const searchResultArray = Array.from(searchResult); | ||||
|  | ||||
|             const newUids = searchResultArray.filter((uid) => !this.seenUids.has(uid)); | ||||
|             if (newUids.length === 0) { | ||||
|                 this.processing = false; | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Fetch messages | ||||
|             for await (const message of this.client.fetch(newUids, { envelope: true, source: true })) { | ||||
|                 const parsed = await plugins.mailparser.simpleParser(message.source); | ||||
|                 this.emit('message', parsed); | ||||
|                 this.seenUids.add(message.uid); | ||||
|             } | ||||
|         } catch (error) { | ||||
|             this.emit('error', error); | ||||
|         } finally { | ||||
|             this.processing = false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public setFilter(filter: plugins.imapflow.SearchObject): void { | ||||
|         this.filter = filter; | ||||
|     } | ||||
|  | ||||
|     public async disconnect(): Promise<void> { | ||||
|         if (this.connected) { | ||||
|             await this.client.logout(); | ||||
|             this.connected = false; | ||||
|             this.emit('disconnected'); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								ts/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ts/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| export * from './classes.smartimap.js'; | ||||
							
								
								
									
										15
									
								
								ts/smartimap.plugins.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								ts/smartimap.plugins.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| // node native | ||||
| import * as events from 'events'; | ||||
|  | ||||
| export { | ||||
|   events, | ||||
| } | ||||
|  | ||||
| // third party | ||||
| import * as mailparser from 'mailparser'; | ||||
| import * as imapflow from 'imapflow'; | ||||
|  | ||||
| export { | ||||
|   mailparser, | ||||
|   imapflow, | ||||
| } | ||||
							
								
								
									
										14
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "experimentalDecorators": true, | ||||
|     "useDefineForClassFields": false, | ||||
|     "target": "ES2022", | ||||
|     "module": "NodeNext", | ||||
|     "moduleResolution": "NodeNext", | ||||
|     "esModuleInterop": true, | ||||
|     "verbatimModuleSyntax": true | ||||
|   }, | ||||
|   "exclude": [ | ||||
|     "dist_*/**/*.d.ts" | ||||
|   ] | ||||
| } | ||||
		Reference in New Issue
	
	Block a user