From 7791baff20ececf220c62fdeb864e6211951b2d4 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Tue, 24 Dec 2024 09:43:23 -0500 Subject: [PATCH] Big bang --- .gitattributes | 1 + .gitignore | 175 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 15 ++++ bun.lockb | Bin 0 -> 13883 bytes index.ts | 4 ++ package.json | 16 +++++ src/bones/index.ts | 1 + src/bones/types.ts | 89 +++++++++++++++++++++++ src/config.ts | 20 ++++++ src/types.ts | 23 ++++++ tsconfig.json | 27 +++++++ 11 files changed, 371 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 README.md create mode 100755 bun.lockb create mode 100644 index.ts create mode 100644 package.json create mode 100644 src/bones/index.ts create mode 100644 src/bones/types.ts create mode 100644 src/config.ts create mode 100644 src/types.ts create mode 100644 tsconfig.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..81c05ed --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.lockb binary diff=lockb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b1ee42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..5d3181b --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# email-comments + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.1.42. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..93f63c1cba7ec9eadf5c0450dbb29bef43a885ef GIT binary patch literal 13883 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 literal 0 HcmV?d00001 diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..9716130 --- /dev/null +++ b/index.ts @@ -0,0 +1,4 @@ + +import { config } from "./src/config.ts"; + +console.log(config) diff --git a/package.json b/package.json new file mode 100644 index 0000000..218b3df --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "email-comments", + "module": "index.ts", + "type": "module", + "devDependencies": { + "@types/bun": "^1.1.14" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@types/imapflow": "^1.0.19", + "imapflow": "^1.0.171", + "zod": "^3.24.1" + } +} \ No newline at end of file diff --git a/src/bones/index.ts b/src/bones/index.ts new file mode 100644 index 0000000..c9f6f04 --- /dev/null +++ b/src/bones/index.ts @@ -0,0 +1 @@ +export * from './types' diff --git a/src/bones/types.ts b/src/bones/types.ts new file mode 100644 index 0000000..f8399c4 --- /dev/null +++ b/src/bones/types.ts @@ -0,0 +1,89 @@ +/** Type alias for something that may or may not be wrapped in a promise. */ +export type Awaitable = T | Promise + +/** Type alias for something that may be undefined. */ +export type Maybe = T | undefined + +export type MaybeArr = { + [Index in keyof T]: Maybe +} & {length: T['length']} + +export type Either = Left | Right + +export type Left = [T, undefined] + +export type Right = [undefined, T] + +export function isLeft(what: Either): what is Left { + return typeof what[1] === 'undefined' +} + +export function isRight(what: Either): what is Right { + return typeof what[0] === 'undefined' +} + +export function left(what: T): Left { + return [what, undefined] +} + +export function right(what: T): Right { + return [undefined, what] +} + +export function unleft(what: Left): T { + return what[0] +} + +export function unright(what: Right): T { + return what[1] +} + +/** Type alias for a callback that accepts a typed argument. */ +export type ParameterizedCallback = ((arg: T) => any) + +/** A key-value form of a given type. */ +export type KeyValue = {key: string, value: T} + +/** Simple helper method to verify that a key is a keyof some object. */ +export function isKeyof(key: unknown, obj: T): key is keyof T { + if ( typeof key !== 'string' && typeof key !== 'symbol' ) { + return false + } + + return key in obj +} + +/** A typescript-compatible version of Object.hasOwnProperty. */ +export function hasOwnProperty(obj: X, prop: Y): obj is X & Record { // eslint-disable-line @typescript-eslint/ban-types + return Object.hasOwnProperty.call(obj, prop) +} + +/** + * TypeScript helper for creating tagged-types. + */ +export interface TypeTag { + readonly __typeTag: S +} + +export type PrefixTypeArray = [T, ...TArr] +export type SuffixTypeArray = [...TArr, T] +export type TypeArraySignature = (...params: TArr) => TReturn + +export type MethodsOf any> = { + [K in keyof T]: T[K] extends TMethod ? K : never +}[keyof T] + +export type MethodType any> = { + [K in keyof TClass]: TClass[K] extends TMethod ? TClass[K] : never +}[TKey] + +export type Awaited = T extends PromiseLike ? U : T + +export type Integer = TypeTag<'@extollo/lib.Integer'> & number + +export function isInteger(num: number): num is Integer { + return !isNaN(num) && parseInt(String(num), 10) === num +} + +export type ArrayElement = + ArrayType extends readonly (infer ElementType)[] ? ElementType : never; diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..54afd59 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,20 @@ +import {castCommentsConfig, type CommentsConfig} from "./types.ts"; + +const maybeConfig: any = { + mail: { + imap: { + host: process.env.CHORUS_IMAP_HOST, + port: process.env.CHORUS_IMAP_PORT || 993, + auth: { + user: process.env.CHORUS_IMAP_USER, + pass: process.env.CHORUS_IMAP_PASS, + }, + }, + threads: { + type: 'alias', + template: process.env.CHORUS_THREAD_TEMPLATE, + }, + }, +} + +export const config: CommentsConfig = castCommentsConfig(maybeConfig) diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..426d2f3 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,23 @@ +import {z} from "zod"; + +const commentsConfigSchema = z.object({ + mail: z.object({ + imap: z.object({ + host: z.string(), + port: z.number({ coerce: true }), + auth: z.object({ + user: z.string(), + pass: z.string(), + }), + }), + threads: z.object({ + type: z.string(), // fixme : in validation + template: z.string(), + }), + }), +}) + +export type CommentsConfig = z.infer +export const castCommentsConfig = (what: unknown): CommentsConfig => { + return commentsConfigSchema.parse(what) +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +}