agentmail-clone-v1 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/.env.example +20 -0
  2. package/.github/workflows/docs-deploy.yml +37 -0
  3. package/.github/workflows/landing-preview.yml +43 -0
  4. package/.github/workflows/openapi-lint.yml +31 -0
  5. package/.github/workflows/sdk-generate-check.yml +66 -0
  6. package/.github/workflows/sdk-release.yml +62 -0
  7. package/CHANGELOG.md +10 -0
  8. package/README.md +208 -0
  9. package/RELEASING.md +43 -0
  10. package/docs/api-reference/api-keys.mdx +11 -0
  11. package/docs/api-reference/domains.mdx +13 -0
  12. package/docs/api-reference/emails.mdx +26 -0
  13. package/docs/api-reference/inboxes.mdx +13 -0
  14. package/docs/api-reference/metrics.mdx +10 -0
  15. package/docs/authentication.mdx +25 -0
  16. package/docs/docs.json +35 -0
  17. package/docs/errors.mdx +34 -0
  18. package/docs/favicon.svg +5 -0
  19. package/docs/idempotency.mdx +18 -0
  20. package/docs/index.mdx +24 -0
  21. package/docs/quickstart.mdx +134 -0
  22. package/landing/DEPLOYING.md +33 -0
  23. package/landing/favicon.svg +5 -0
  24. package/landing/index.html +129 -0
  25. package/landing/main.js +45 -0
  26. package/landing/privacy.html +29 -0
  27. package/landing/styles.css +356 -0
  28. package/landing/terms.html +29 -0
  29. package/netlify.toml +15 -0
  30. package/openapi/openapi.yaml +1016 -0
  31. package/package.json +34 -0
  32. package/render.yaml +48 -0
  33. package/scripts/generate-sdk-py.sh +16 -0
  34. package/scripts/generate-sdk-ts.sh +16 -0
  35. package/scripts/migrate.js +66 -0
  36. package/scripts/validate-docs.js +56 -0
  37. package/scripts/validate-landing.js +39 -0
  38. package/sdks/python/README.md +40 -0
  39. package/sdks/python/emailagent_sdk/__init__.py +157 -0
  40. package/sdks/python/generated/.openapi-generator/FILES +101 -0
  41. package/sdks/python/generated/.openapi-generator/VERSION +1 -0
  42. package/sdks/python/generated/.openapi-generator-ignore +23 -0
  43. package/sdks/python/generated/emailagent_sdk_generated/__init__.py +105 -0
  44. package/sdks/python/generated/emailagent_sdk_generated/api/__init__.py +9 -0
  45. package/sdks/python/generated/emailagent_sdk_generated/api/api_keys_api.py +1162 -0
  46. package/sdks/python/generated/emailagent_sdk_generated/api/domains_api.py +1168 -0
  47. package/sdks/python/generated/emailagent_sdk_generated/api/emails_api.py +1232 -0
  48. package/sdks/python/generated/emailagent_sdk_generated/api/inboxes_api.py +1191 -0
  49. package/sdks/python/generated/emailagent_sdk_generated/api/metrics_api.py +285 -0
  50. package/sdks/python/generated/emailagent_sdk_generated/api_client.py +801 -0
  51. package/sdks/python/generated/emailagent_sdk_generated/api_response.py +21 -0
  52. package/sdks/python/generated/emailagent_sdk_generated/configuration.py +586 -0
  53. package/sdks/python/generated/emailagent_sdk_generated/docs/APIKeysApi.md +334 -0
  54. package/sdks/python/generated/emailagent_sdk_generated/docs/ApiKeyCreated.md +35 -0
  55. package/sdks/python/generated/emailagent_sdk_generated/docs/ApiKeyCreatedResponse.md +29 -0
  56. package/sdks/python/generated/emailagent_sdk_generated/docs/ApiKeyListItem.md +35 -0
  57. package/sdks/python/generated/emailagent_sdk_generated/docs/ApiKeyListResponse.md +29 -0
  58. package/sdks/python/generated/emailagent_sdk_generated/docs/CreateApiKeyRequest.md +30 -0
  59. package/sdks/python/generated/emailagent_sdk_generated/docs/CreateApiKeyRequestScopes.md +29 -0
  60. package/sdks/python/generated/emailagent_sdk_generated/docs/CreateDomainRequest.md +29 -0
  61. package/sdks/python/generated/emailagent_sdk_generated/docs/CreateInboxRequest.md +31 -0
  62. package/sdks/python/generated/emailagent_sdk_generated/docs/Domain.md +37 -0
  63. package/sdks/python/generated/emailagent_sdk_generated/docs/DomainListResponse.md +29 -0
  64. package/sdks/python/generated/emailagent_sdk_generated/docs/DomainResponse.md +29 -0
  65. package/sdks/python/generated/emailagent_sdk_generated/docs/DomainsApi.md +336 -0
  66. package/sdks/python/generated/emailagent_sdk_generated/docs/Email.md +43 -0
  67. package/sdks/python/generated/emailagent_sdk_generated/docs/EmailListResponse.md +29 -0
  68. package/sdks/python/generated/emailagent_sdk_generated/docs/EmailResponse.md +29 -0
  69. package/sdks/python/generated/emailagent_sdk_generated/docs/EmailsApi.md +353 -0
  70. package/sdks/python/generated/emailagent_sdk_generated/docs/ErrorResponse.md +29 -0
  71. package/sdks/python/generated/emailagent_sdk_generated/docs/Inbox.md +38 -0
  72. package/sdks/python/generated/emailagent_sdk_generated/docs/InboxListResponse.md +29 -0
  73. package/sdks/python/generated/emailagent_sdk_generated/docs/InboxResponse.md +29 -0
  74. package/sdks/python/generated/emailagent_sdk_generated/docs/InboxesApi.md +337 -0
  75. package/sdks/python/generated/emailagent_sdk_generated/docs/MetricsApi.md +83 -0
  76. package/sdks/python/generated/emailagent_sdk_generated/docs/MetricsData.md +35 -0
  77. package/sdks/python/generated/emailagent_sdk_generated/docs/MetricsResponse.md +29 -0
  78. package/sdks/python/generated/emailagent_sdk_generated/docs/OkResponse.md +29 -0
  79. package/sdks/python/generated/emailagent_sdk_generated/docs/PlanLimits.md +32 -0
  80. package/sdks/python/generated/emailagent_sdk_generated/docs/SendEmailRequest.md +32 -0
  81. package/sdks/python/generated/emailagent_sdk_generated/docs/UpdateEmailReadRequest.md +29 -0
  82. package/sdks/python/generated/emailagent_sdk_generated/docs/UpdateInboxRequest.md +29 -0
  83. package/sdks/python/generated/emailagent_sdk_generated/exceptions.py +216 -0
  84. package/sdks/python/generated/emailagent_sdk_generated/models/__init__.py +41 -0
  85. package/sdks/python/generated/emailagent_sdk_generated/models/api_key_created.py +113 -0
  86. package/sdks/python/generated/emailagent_sdk_generated/models/api_key_created_response.py +91 -0
  87. package/sdks/python/generated/emailagent_sdk_generated/models/api_key_list_item.py +123 -0
  88. package/sdks/python/generated/emailagent_sdk_generated/models/api_key_list_response.py +95 -0
  89. package/sdks/python/generated/emailagent_sdk_generated/models/create_api_key_request.py +93 -0
  90. package/sdks/python/generated/emailagent_sdk_generated/models/create_api_key_request_scopes.py +143 -0
  91. package/sdks/python/generated/emailagent_sdk_generated/models/create_domain_request.py +87 -0
  92. package/sdks/python/generated/emailagent_sdk_generated/models/create_inbox_request.py +91 -0
  93. package/sdks/python/generated/emailagent_sdk_generated/models/domain.py +134 -0
  94. package/sdks/python/generated/emailagent_sdk_generated/models/domain_list_response.py +95 -0
  95. package/sdks/python/generated/emailagent_sdk_generated/models/domain_response.py +91 -0
  96. package/sdks/python/generated/emailagent_sdk_generated/models/email.py +175 -0
  97. package/sdks/python/generated/emailagent_sdk_generated/models/email_list_response.py +95 -0
  98. package/sdks/python/generated/emailagent_sdk_generated/models/email_response.py +91 -0
  99. package/sdks/python/generated/emailagent_sdk_generated/models/error_response.py +87 -0
  100. package/sdks/python/generated/emailagent_sdk_generated/models/inbox.py +136 -0
  101. package/sdks/python/generated/emailagent_sdk_generated/models/inbox_list_response.py +95 -0
  102. package/sdks/python/generated/emailagent_sdk_generated/models/inbox_response.py +91 -0
  103. package/sdks/python/generated/emailagent_sdk_generated/models/metrics_data.py +110 -0
  104. package/sdks/python/generated/emailagent_sdk_generated/models/metrics_response.py +91 -0
  105. package/sdks/python/generated/emailagent_sdk_generated/models/ok_response.py +87 -0
  106. package/sdks/python/generated/emailagent_sdk_generated/models/plan_limits.py +93 -0
  107. package/sdks/python/generated/emailagent_sdk_generated/models/send_email_request.py +93 -0
  108. package/sdks/python/generated/emailagent_sdk_generated/models/update_email_read_request.py +87 -0
  109. package/sdks/python/generated/emailagent_sdk_generated/models/update_inbox_request.py +92 -0
  110. package/sdks/python/generated/emailagent_sdk_generated/rest.py +258 -0
  111. package/sdks/python/generated/emailagent_sdk_generated/test/__init__.py +0 -0
  112. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_key_created.py +68 -0
  113. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_key_created_response.py +52 -0
  114. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_key_list_item.py +66 -0
  115. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_key_list_response.py +56 -0
  116. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_keys_api.py +59 -0
  117. package/sdks/python/generated/emailagent_sdk_generated/test/test_create_api_key_request.py +53 -0
  118. package/sdks/python/generated/emailagent_sdk_generated/test/test_create_api_key_request_scopes.py +50 -0
  119. package/sdks/python/generated/emailagent_sdk_generated/test/test_create_domain_request.py +52 -0
  120. package/sdks/python/generated/emailagent_sdk_generated/test/test_create_inbox_request.py +54 -0
  121. package/sdks/python/generated/emailagent_sdk_generated/test/test_domain.py +70 -0
  122. package/sdks/python/generated/emailagent_sdk_generated/test/test_domain_list_response.py +56 -0
  123. package/sdks/python/generated/emailagent_sdk_generated/test/test_domain_response.py +52 -0
  124. package/sdks/python/generated/emailagent_sdk_generated/test/test_domains_api.py +59 -0
  125. package/sdks/python/generated/emailagent_sdk_generated/test/test_email.py +79 -0
  126. package/sdks/python/generated/emailagent_sdk_generated/test/test_email_list_response.py +56 -0
  127. package/sdks/python/generated/emailagent_sdk_generated/test/test_email_response.py +52 -0
  128. package/sdks/python/generated/emailagent_sdk_generated/test/test_emails_api.py +59 -0
  129. package/sdks/python/generated/emailagent_sdk_generated/test/test_error_response.py +52 -0
  130. package/sdks/python/generated/emailagent_sdk_generated/test/test_inbox.py +68 -0
  131. package/sdks/python/generated/emailagent_sdk_generated/test/test_inbox_list_response.py +56 -0
  132. package/sdks/python/generated/emailagent_sdk_generated/test/test_inbox_response.py +52 -0
  133. package/sdks/python/generated/emailagent_sdk_generated/test/test_inboxes_api.py +59 -0
  134. package/sdks/python/generated/emailagent_sdk_generated/test/test_metrics_api.py +38 -0
  135. package/sdks/python/generated/emailagent_sdk_generated/test/test_metrics_data.py +72 -0
  136. package/sdks/python/generated/emailagent_sdk_generated/test/test_metrics_response.py +74 -0
  137. package/sdks/python/generated/emailagent_sdk_generated/test/test_ok_response.py +52 -0
  138. package/sdks/python/generated/emailagent_sdk_generated/test/test_plan_limits.py +58 -0
  139. package/sdks/python/generated/emailagent_sdk_generated/test/test_send_email_request.py +56 -0
  140. package/sdks/python/generated/emailagent_sdk_generated/test/test_update_email_read_request.py +52 -0
  141. package/sdks/python/generated/emailagent_sdk_generated/test/test_update_inbox_request.py +52 -0
  142. package/sdks/python/generated/emailagent_sdk_generated_README.md +140 -0
  143. package/sdks/python/openapitools.json +7 -0
  144. package/sdks/python/pyproject.toml +19 -0
  145. package/sdks/typescript/README.md +41 -0
  146. package/sdks/typescript/generated/.openapi-generator/FILES +41 -0
  147. package/sdks/typescript/generated/.openapi-generator/VERSION +1 -0
  148. package/sdks/typescript/generated/.openapi-generator-ignore +23 -0
  149. package/sdks/typescript/generated/package.json +21 -0
  150. package/sdks/typescript/generated/src/apis/APIKeysApi.ts +314 -0
  151. package/sdks/typescript/generated/src/apis/DomainsApi.ts +314 -0
  152. package/sdks/typescript/generated/src/apis/EmailsApi.ts +350 -0
  153. package/sdks/typescript/generated/src/apis/InboxesApi.ts +329 -0
  154. package/sdks/typescript/generated/src/apis/MetricsApi.ts +93 -0
  155. package/sdks/typescript/generated/src/apis/index.ts +7 -0
  156. package/sdks/typescript/generated/src/index.ts +5 -0
  157. package/sdks/typescript/generated/src/models/ApiKeyCreated.ts +123 -0
  158. package/sdks/typescript/generated/src/models/ApiKeyCreatedResponse.ts +74 -0
  159. package/sdks/typescript/generated/src/models/ApiKeyListItem.ts +121 -0
  160. package/sdks/typescript/generated/src/models/ApiKeyListResponse.ts +74 -0
  161. package/sdks/typescript/generated/src/models/CreateApiKeyRequest.ts +82 -0
  162. package/sdks/typescript/generated/src/models/CreateApiKeyRequestScopes.ts +45 -0
  163. package/sdks/typescript/generated/src/models/CreateDomainRequest.ts +66 -0
  164. package/sdks/typescript/generated/src/models/CreateInboxRequest.ts +82 -0
  165. package/sdks/typescript/generated/src/models/Domain.ts +152 -0
  166. package/sdks/typescript/generated/src/models/DomainListResponse.ts +74 -0
  167. package/sdks/typescript/generated/src/models/DomainResponse.ts +74 -0
  168. package/sdks/typescript/generated/src/models/Email.ts +222 -0
  169. package/sdks/typescript/generated/src/models/EmailListResponse.ts +74 -0
  170. package/sdks/typescript/generated/src/models/EmailResponse.ts +74 -0
  171. package/sdks/typescript/generated/src/models/ErrorResponse.ts +66 -0
  172. package/sdks/typescript/generated/src/models/Inbox.ts +159 -0
  173. package/sdks/typescript/generated/src/models/InboxListResponse.ts +74 -0
  174. package/sdks/typescript/generated/src/models/InboxResponse.ts +74 -0
  175. package/sdks/typescript/generated/src/models/MetricsData.ts +139 -0
  176. package/sdks/typescript/generated/src/models/MetricsResponse.ts +74 -0
  177. package/sdks/typescript/generated/src/models/OkResponse.ts +66 -0
  178. package/sdks/typescript/generated/src/models/PlanLimits.ts +93 -0
  179. package/sdks/typescript/generated/src/models/SendEmailRequest.ts +91 -0
  180. package/sdks/typescript/generated/src/models/UpdateEmailReadRequest.ts +66 -0
  181. package/sdks/typescript/generated/src/models/UpdateInboxRequest.ts +66 -0
  182. package/sdks/typescript/generated/src/models/index.ts +27 -0
  183. package/sdks/typescript/generated/src/runtime.ts +432 -0
  184. package/sdks/typescript/generated/tsconfig.esm.json +7 -0
  185. package/sdks/typescript/generated/tsconfig.json +16 -0
  186. package/sdks/typescript/openapitools.json +8 -0
  187. package/sdks/typescript/package.json +27 -0
  188. package/sdks/typescript/src/index.ts +138 -0
  189. package/sdks/typescript/tsconfig.json +14 -0
  190. package/sql/001_init.sql +143 -0
  191. package/sql/002_local_auth.sql +38 -0
  192. package/sql/003_domain_routes.sql +2 -0
  193. package/sql/004_reliability_primitives.sql +75 -0
  194. package/sql/005_auth_email_flows.sql +22 -0
  195. package/src/config.js +30 -0
  196. package/src/db.js +25 -0
  197. package/src/lib/api-auth.js +55 -0
  198. package/src/lib/auth.js +71 -0
  199. package/src/lib/csrf.js +46 -0
  200. package/src/lib/dodo.js +67 -0
  201. package/src/lib/email-templates.js +67 -0
  202. package/src/lib/idempotency.js +85 -0
  203. package/src/lib/mailgun.js +188 -0
  204. package/src/lib/plan.js +24 -0
  205. package/src/lib/rate-limit.js +43 -0
  206. package/src/lib/security.js +62 -0
  207. package/src/lib/session.js +21 -0
  208. package/src/lib/store.js +638 -0
  209. package/src/lib/transactional-mailer.js +54 -0
  210. package/src/lib/validation.js +30 -0
  211. package/src/routes/api.js +485 -0
  212. package/src/routes/app.js +699 -0
  213. package/src/routes/auth.js +404 -0
  214. package/src/routes/webhooks.js +257 -0
  215. package/src/server.js +79 -0
  216. package/src/views/pages/admin.ejs +58 -0
  217. package/src/views/pages/api-keys.ejs +56 -0
  218. package/src/views/pages/billing.ejs +71 -0
  219. package/src/views/pages/domains.ejs +106 -0
  220. package/src/views/pages/inboxes.ejs +127 -0
  221. package/src/views/pages/login.ejs +57 -0
  222. package/src/views/pages/metrics.ejs +34 -0
  223. package/src/views/pages/reset-password.ejs +19 -0
  224. package/src/views/partials/bottom.ejs +3 -0
  225. package/src/views/partials/csrf-field.ejs +3 -0
  226. package/src/views/partials/flash.ejs +3 -0
  227. package/src/views/partials/top.ejs +130 -0
package/.env.example ADDED
@@ -0,0 +1,20 @@
1
+ NODE_ENV=development
2
+ PORT=3000
3
+ APP_BASE_URL=http://localhost:3000
4
+ APP_SHARED_DOMAIN=emailagent.dev
5
+ ADMIN_EMAIL=jagan.ganti@gmail.com
6
+ SESSION_SECRET=replace-with-a-long-random-secret-at-least-32-chars
7
+ API_KEY_HASH_SECRET=replace-with-another-long-random-secret-at-least-32-chars
8
+
9
+ DATABASE_URL=postgres://postgres:postgres@localhost:5432/agentmail
10
+
11
+ MAILGUN_API_KEY=
12
+ MAILGUN_REGION=us
13
+ MAILGUN_WEBHOOK_SIGNING_KEY=
14
+ MAILGUN_ACCOUNT_DOMAIN=
15
+ MAIL_FROM_EMAIL=
16
+
17
+ DODO_PAYMENTS_API_KEY=
18
+ DODO_PAYMENTS_ENVIRONMENT=test_mode
19
+ DODO_PAYMENTS_WEBHOOK_KEY=
20
+ DODO_PAYMENTS_PRODUCT_ID_PAID=
@@ -0,0 +1,37 @@
1
+ name: Docs Validate and Deploy
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - 'docs/**'
7
+ - 'openapi/**'
8
+ - 'scripts/validate-docs.js'
9
+ - '.github/workflows/docs-deploy.yml'
10
+ - 'package.json'
11
+ push:
12
+ branches:
13
+ - main
14
+ paths:
15
+ - 'docs/**'
16
+ - 'openapi/**'
17
+ - 'scripts/validate-docs.js'
18
+ - '.github/workflows/docs-deploy.yml'
19
+ - 'package.json'
20
+
21
+ jobs:
22
+ docs-validate:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v4
27
+
28
+ - name: Setup Node
29
+ uses: actions/setup-node@v4
30
+ with:
31
+ node-version: '22'
32
+
33
+ - name: Install dependencies
34
+ run: npm ci
35
+
36
+ - name: Validate docs structure
37
+ run: npm run docs:validate
@@ -0,0 +1,43 @@
1
+ name: Landing Validate and Preview
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - 'landing/**'
7
+ - 'scripts/validate-landing.js'
8
+ - 'package.json'
9
+ - '.github/workflows/landing-preview.yml'
10
+
11
+ jobs:
12
+ landing-validate:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Setup Node
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: '22'
22
+
23
+ - name: Install dependencies
24
+ run: npm ci
25
+
26
+ - name: Validate landing pages
27
+ run: npm run landing:validate
28
+
29
+ landing-preview:
30
+ if: ${{ secrets.NETLIFY_AUTH_TOKEN != '' && secrets.NETLIFY_SITE_ID != '' }}
31
+ needs: landing-validate
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - name: Checkout
35
+ uses: actions/checkout@v4
36
+
37
+ - name: Deploy Netlify preview
38
+ uses: netlify/actions/cli@master
39
+ with:
40
+ args: deploy --dir=landing --alias pr-${{ github.event.pull_request.number }} --message "Landing preview for PR #${{ github.event.pull_request.number }}"
41
+ env:
42
+ NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
43
+ NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
@@ -0,0 +1,31 @@
1
+ name: OpenAPI Lint
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - 'openapi/**'
7
+ - 'package.json'
8
+ push:
9
+ branches:
10
+ - main
11
+ paths:
12
+ - 'openapi/**'
13
+ - 'package.json'
14
+
15
+ jobs:
16
+ lint-openapi:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - name: Checkout
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Setup Node
23
+ uses: actions/setup-node@v4
24
+ with:
25
+ node-version: '22'
26
+
27
+ - name: Install dependencies
28
+ run: npm ci
29
+
30
+ - name: Lint OpenAPI
31
+ run: npm run lint:openapi
@@ -0,0 +1,66 @@
1
+ name: SDK Generate Check
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - 'openapi/**'
7
+ - 'sdks/**'
8
+ - 'scripts/generate-sdk-*.sh'
9
+ - '.github/workflows/sdk-generate-check.yml'
10
+ - 'package.json'
11
+ push:
12
+ branches:
13
+ - main
14
+ paths:
15
+ - 'openapi/**'
16
+ - 'sdks/**'
17
+ - 'scripts/generate-sdk-*.sh'
18
+ - '.github/workflows/sdk-generate-check.yml'
19
+ - 'package.json'
20
+
21
+ jobs:
22
+ sdk-check:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v4
27
+
28
+ - name: Setup Node
29
+ uses: actions/setup-node@v4
30
+ with:
31
+ node-version: '22'
32
+
33
+ - name: Setup Java
34
+ uses: actions/setup-java@v4
35
+ with:
36
+ distribution: temurin
37
+ java-version: '21'
38
+
39
+ - name: Setup Python
40
+ uses: actions/setup-python@v5
41
+ with:
42
+ python-version: '3.11'
43
+
44
+ - name: Install root dependencies
45
+ run: npm ci
46
+
47
+ - name: Generate SDKs
48
+ run: npm run generate:sdks
49
+
50
+ - name: Check generated output is committed
51
+ run: git diff --exit-code
52
+
53
+ - name: TypeScript SDK build smoke test
54
+ run: |
55
+ npm --prefix sdks/typescript install --no-fund --no-audit
56
+ npm --prefix sdks/typescript run build
57
+
58
+ - name: Python SDK build smoke test
59
+ run: |
60
+ python -m pip install --upgrade pip build
61
+ python -m build sdks/python
62
+ python -m pip install -e sdks/python
63
+ python - <<'PY'
64
+ import emailagent_sdk
65
+ print('emailagent_sdk import ok')
66
+ PY
@@ -0,0 +1,62 @@
1
+ name: SDK Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'sdk-ts-v*'
7
+ - 'sdk-py-v*'
8
+
9
+ jobs:
10
+ publish-typescript:
11
+ if: startsWith(github.ref, 'refs/tags/sdk-ts-v')
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Checkout
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Setup Node
18
+ uses: actions/setup-node@v4
19
+ with:
20
+ node-version: '22'
21
+ registry-url: 'https://registry.npmjs.org'
22
+
23
+ - name: Set package version from tag
24
+ working-directory: sdks/typescript
25
+ run: |
26
+ VERSION="${GITHUB_REF_NAME#sdk-ts-v}"
27
+ npm version "$VERSION" --no-git-tag-version
28
+
29
+ - name: Install and build
30
+ run: |
31
+ npm --prefix sdks/typescript install --no-fund --no-audit
32
+ npm --prefix sdks/typescript run build
33
+
34
+ - name: Publish npm package
35
+ working-directory: sdks/typescript
36
+ run: npm publish --access public
37
+ env:
38
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
39
+
40
+ publish-python:
41
+ if: startsWith(github.ref, 'refs/tags/sdk-py-v')
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - name: Checkout
45
+ uses: actions/checkout@v4
46
+
47
+ - name: Setup Python
48
+ uses: actions/setup-python@v5
49
+ with:
50
+ python-version: '3.11'
51
+
52
+ - name: Build Python package
53
+ run: |
54
+ python -m pip install --upgrade pip build
55
+ VERSION="${GITHUB_REF_NAME#sdk-py-v}"
56
+ sed -i "s/^version = .*/version = \"$VERSION\"/" sdks/python/pyproject.toml
57
+ python -m build sdks/python
58
+
59
+ - name: Publish to PyPI
60
+ uses: pypa/gh-action-pypi-publish@release/v1
61
+ with:
62
+ packages-dir: sdks/python/dist
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 - Docs and SDK Foundation
4
+
5
+ - Added Mintlify docs workspace under `docs/`.
6
+ - Added API docs pages and deployment guidance for `docs.emailagent.dev`.
7
+ - Added SDK scaffolding for TypeScript and Python in `sdks/`.
8
+ - Added OpenAPI-driven SDK generation scripts.
9
+ - Added GitHub Actions workflows for OpenAPI lint, SDK generation checks, SDK releases, and docs deployment.
10
+ - Added release policy in `RELEASING.md`.
package/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # Agent Inbox SaaS (V1)
2
+
3
+ Fastify + Postgres + HTMX app with:
4
+ - Local signup/login (name + email + password)
5
+ - Signup email verification, welcome email, and forgot/reset password email flow
6
+ - Default organization creation on signup/login
7
+ - Inboxes page (CRUD + compose + messages)
8
+ - Domains page (CRUD + DNS records + verification)
9
+ - API Keys page (create/list/revoke)
10
+ - Metrics page (monthly usage + plan limits)
11
+ - Billing page (free vs paid table + upgrade flow)
12
+ - Admin page (restricted by admin email) for global metrics and plan-limit tuning
13
+ - Mailgun adapter for sends, domain provisioning, and inbound/event webhooks
14
+ - Dodo Payments checkout integration for free -> paid upgrade
15
+ - API-key based external API for agent operations
16
+ - Reliability primitives: idempotency keys, webhook dedupe, basic rate limiting, delivery status tracking
17
+
18
+ ## Stack
19
+ - Node.js (Fastify)
20
+ - PostgreSQL
21
+ - EJS + HTMX
22
+ - Mailgun (optional but integrated)
23
+
24
+ ## Plan enforcement
25
+ - Free plan: `1` inbox, `0` custom domains, `1000` monthly outbound emails
26
+ - Paid plan: `10` inboxes, `1` custom domain, `10000` monthly outbound emails
27
+
28
+ Default org plan is `free` at signup.
29
+
30
+ ## Host mapping
31
+ - Landing: `https://emailagent.dev`
32
+ - App UI: `https://app.emailagent.dev`
33
+ - API: `https://api.emailagent.dev`
34
+ - Docs: `https://docs.emailagent.dev`
35
+
36
+ Important: production Render env vars must use public production URLs. Do not use localhost values in production (`APP_BASE_URL` especially).
37
+
38
+ ## Quick start
39
+ 1. Install deps:
40
+ ```bash
41
+ npm install
42
+ ```
43
+ 2. Copy env file:
44
+ ```bash
45
+ cp .env.example .env
46
+ ```
47
+ 3. Configure `.env`:
48
+ - `DATABASE_URL`
49
+ - `APP_BASE_URL`
50
+ - `APP_SHARED_DOMAIN`
51
+ - `ADMIN_EMAIL`
52
+ - `SESSION_SECRET`
53
+ - `API_KEY_HASH_SECRET`
54
+ - Mailgun creds (optional for local mock behavior)
55
+ - Optional `MAIL_FROM_EMAIL` (defaults to `no-reply@MAILGUN_ACCOUNT_DOMAIN`)
56
+ - Dodo Payments creds (required for in-app upgrade flow)
57
+ 4. Run migration:
58
+ ```bash
59
+ npm run migrate
60
+ ```
61
+ 5. Start server:
62
+ ```bash
63
+ npm run dev
64
+ ```
65
+ 6. Open:
66
+ - UI: `http://localhost:3000`
67
+ - Health: `http://localhost:3000/healthz`
68
+
69
+ ## Run locally (app + landing + docs)
70
+ Open separate terminals from `/Users/jaganganti/Documents/emailagent`.
71
+
72
+ 1. App (Fastify):
73
+ ```bash
74
+ npm run dev
75
+ ```
76
+ - URL: `http://localhost:3000`
77
+
78
+ 2. Landing site (static):
79
+ ```bash
80
+ npm run landing:dev
81
+ ```
82
+ - URL: `http://localhost:8080`
83
+
84
+ 3. Docs (Mintlify):
85
+ ```bash
86
+ cd docs
87
+ npx mintlify dev
88
+ ```
89
+ - URL: `http://localhost:3000` (or use `npx mintlify dev --port 3001` if 3000 is busy)
90
+
91
+ ## Docs and SDK workspace
92
+ - Public landing site: `landing/`
93
+ - Mintlify docs config and pages: `docs/`
94
+ - OpenAPI source of truth: `openapi/openapi.yaml`
95
+ - TypeScript SDK: `sdks/typescript/`
96
+ - Python SDK: `sdks/python/`
97
+
98
+ Validation and generation:
99
+
100
+ ```bash
101
+ npm run lint:openapi
102
+ npm run docs:validate
103
+ npm run landing:validate
104
+ npm run generate:sdks
105
+ ```
106
+
107
+ ## Landing deployment (Netlify)
108
+ - Netlify publish directory: `landing`
109
+ - Root domain: `emailagent.dev`
110
+ - `www.emailagent.dev` should redirect to apex
111
+ - Detailed setup: `landing/DEPLOYING.md`
112
+ - Optional PR preview workflow requires GitHub secrets:
113
+ - `NETLIFY_AUTH_TOKEN`
114
+ - `NETLIFY_SITE_ID`
115
+
116
+ ## Mailgun endpoints used
117
+ - `POST /v4/domains` (create custom domain)
118
+ - `PUT /v4/domains/{name}/verify` (verify)
119
+ - `DELETE /v4/domains/{name}` (delete)
120
+ - `POST /v3/{domain}/messages` (send email)
121
+
122
+ Webhooks in this app:
123
+ - `POST /webhooks/mailgun/inbound`
124
+ - `POST /webhooks/mailgun/events`
125
+ - `POST /webhooks/dodo`
126
+
127
+ ## Shared-domain inbound route (manual)
128
+ For shared-domain inboxes (for example `agent@emailagent.dev`), configure Mailgun Routes manually:
129
+
130
+ - Expression: `match_recipient('.*@emailagent.dev')`
131
+ - Action 1: `forward('https://app.emailagent.dev/webhooks/mailgun/inbound')`
132
+ - Action 2: `stop()`
133
+
134
+ Set `MAILGUN_WEBHOOK_SIGNING_KEY` in app env to validate webhook signatures.
135
+
136
+ Expected inbound webhook responses:
137
+
138
+ | Response | Meaning |
139
+ | --- | --- |
140
+ | `200 {"ok":true}` | Inbound accepted and stored |
141
+ | `200 {"ok":true,"duplicate":true}` | Duplicate webhook ignored |
142
+ | `202 {"ok":true,"ignored":true}` | Recipient does not match active inbox |
143
+ | `401 {"error":"invalid signature"}` | Signing key mismatch |
144
+
145
+ Inbound smoke test:
146
+ 1. Create inbox on shared domain.
147
+ 2. Send external email to that inbox.
148
+ 3. Confirm message appears in dashboard.
149
+ 4. Confirm message via `GET /api/v1/emails?inboxId=<inbox_uuid>`.
150
+
151
+ ## Custom Domain Onboarding
152
+ - Paid users can add custom domains from `/app/domains`.
153
+ - App creates the domain in Mailgun, fetches DNS records, and stores pending/active status.
154
+ - App auto-provisions an inbound Mailgun route per custom domain that forwards to:
155
+ - `<APP_BASE_URL>/webhooks/mailgun/inbound`
156
+ - Verify DNS refreshes records and status, and ensures inbound route is present.
157
+ - Deleting a domain removes both Mailgun route and Mailgun domain (best effort), then soft-deletes locally.
158
+
159
+ ## Dodo Payments env vars
160
+ - `DODO_PAYMENTS_API_KEY`
161
+ - `DODO_PAYMENTS_ENVIRONMENT` (`test_mode` or `live_mode`)
162
+ - `DODO_PAYMENTS_WEBHOOK_KEY`
163
+ - `DODO_PAYMENTS_PRODUCT_ID_PAID` (the $10/mo paid plan product ID in Dodo)
164
+
165
+ ## API key auth
166
+ Use `Authorization: Bearer <api_key>`.
167
+
168
+ For mutating API calls, provide an optional `Idempotency-Key` header.
169
+ If the same key is retried with the same payload, the cached response is returned.
170
+
171
+ Example scopes:
172
+ - `inboxes:read`, `inboxes:write`
173
+ - `emails:read`, `emails:write`, `emails:send`
174
+ - `domains:read`, `domains:write`
175
+ - `keys:read`, `keys:write`
176
+ - `metrics:read`
177
+ - `*` (full access)
178
+
179
+ ## External API (V1)
180
+
181
+ Canonical API contract: `openapi/openapi.yaml`
182
+
183
+ - `GET /api/v1/inboxes`
184
+ - `POST /api/v1/inboxes`
185
+ - `PATCH /api/v1/inboxes/:id`
186
+ - `DELETE /api/v1/inboxes/:id`
187
+ - `POST /api/v1/emails/send`
188
+ - `GET /api/v1/emails`
189
+ - `PATCH /api/v1/emails/:id/read`
190
+ - `DELETE /api/v1/emails/:id`
191
+ - `GET /api/v1/domains`
192
+ - `POST /api/v1/domains`
193
+ - `POST /api/v1/domains/:id/verify`
194
+ - `DELETE /api/v1/domains/:id`
195
+ - `GET /api/v1/api-keys`
196
+ - `POST /api/v1/api-keys`
197
+ - `POST /api/v1/api-keys/:id/revoke`
198
+ - `POST /api/v1/api-keys/:id/rotate`
199
+ - `GET /api/v1/metrics`
200
+
201
+ ## Notes
202
+ - This is V1 and intentionally excludes pods/threading.
203
+ - Domain creation is blocked on free plan.
204
+ - All dashboard pages are accessible to authenticated users; feature limits are enforced on actions.
205
+ - To upgrade an org to paid for testing:
206
+ ```sql
207
+ UPDATE organizations SET plan = 'paid' WHERE id = '<org_id>';
208
+ ```
package/RELEASING.md ADDED
@@ -0,0 +1,43 @@
1
+ # Releasing
2
+
3
+ ## API contract policy
4
+
5
+ - `openapi/openapi.yaml` is the source of truth.
6
+ - V1 policy is additive-only.
7
+ - Breaking changes require a new major API version.
8
+
9
+ ## SDK versioning
10
+
11
+ - SDKs use semantic versioning.
12
+ - Patch: docs, bug fixes, non-breaking generation updates.
13
+ - Minor: additive endpoint/schema changes.
14
+ - Major: breaking SDK API changes.
15
+
16
+ ## Tag conventions
17
+
18
+ - TypeScript SDK release tag: `sdk-ts-vX.Y.Z`
19
+ - Python SDK release tag: `sdk-py-vX.Y.Z`
20
+
21
+ ## Required secrets
22
+
23
+ GitHub Actions secrets:
24
+
25
+ - `NPM_TOKEN` for npm publish
26
+ - `PYPI_API_TOKEN` for PyPI publish
27
+ - `MINTLIFY_DEPLOY_HOOK_URL` for docs deploy hook (optional but recommended)
28
+
29
+ ## Release checklist
30
+
31
+ 1. `npm run lint:openapi`
32
+ 2. `npm run docs:validate`
33
+ 3. `PATH="/opt/homebrew/opt/openjdk@21/bin:$PATH" npm run generate:sdks`
34
+ 4. `npm run check:sdk:drift`
35
+ 5. OpenAPI changes reviewed and accepted
36
+ 6. SDK generation check passes in CI
37
+ 7. Create release tags and push:
38
+ - `git tag sdk-ts-v0.1.0`
39
+ - `git tag sdk-py-v0.1.0`
40
+ - `git push origin sdk-ts-v0.1.0 sdk-py-v0.1.0`
41
+ 8. Verify package availability:
42
+ - npm: `npm view emailagent-sdk version`
43
+ - PyPI: `https://pypi.org/project/emailagent-sdk/`
@@ -0,0 +1,11 @@
1
+ ---
2
+ title: API Keys API
3
+ description: Create, rotate, revoke, and list API keys.
4
+ ---
5
+
6
+ Endpoints:
7
+
8
+ - `GET /api/v1/api-keys`
9
+ - `POST /api/v1/api-keys`
10
+ - `POST /api/v1/api-keys/{id}/rotate`
11
+ - `POST /api/v1/api-keys/{id}/revoke`
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: Domains API
3
+ description: Manage custom domains and DNS verification.
4
+ ---
5
+
6
+ Endpoints:
7
+
8
+ - `GET /api/v1/domains`
9
+ - `POST /api/v1/domains`
10
+ - `POST /api/v1/domains/{id}/verify`
11
+ - `DELETE /api/v1/domains/{id}`
12
+
13
+ Custom domains are plan-gated.
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: Emails API
3
+ description: Send outbound email and consume inbound/outbound records.
4
+ ---
5
+
6
+ Endpoints:
7
+
8
+ - `POST /api/v1/emails/send`
9
+ - `GET /api/v1/emails`
10
+ - `PATCH /api/v1/emails/{id}/read`
11
+ - `DELETE /api/v1/emails/{id}`
12
+
13
+ Use `Idempotency-Key` for retries and to avoid duplicate sends.
14
+
15
+ Required scopes:
16
+
17
+ - `emails:send` for `POST /api/v1/emails/send`
18
+ - `emails:read` for `GET /api/v1/emails`
19
+ - `emails:write` for `PATCH /api/v1/emails/{id}/read` and `DELETE /api/v1/emails/{id}`
20
+
21
+ Example:
22
+
23
+ ```bash
24
+ curl -X GET "https://api.emailagent.dev/api/v1/emails?inboxId=<inbox_uuid>" \
25
+ -H "Authorization: Bearer <api_key>"
26
+ ```
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: Inboxes API
3
+ description: Create, list, update, and delete inboxes.
4
+ ---
5
+
6
+ Endpoints:
7
+
8
+ - `GET /api/v1/inboxes`
9
+ - `POST /api/v1/inboxes`
10
+ - `PATCH /api/v1/inboxes/{id}`
11
+ - `DELETE /api/v1/inboxes/{id}`
12
+
13
+ See full schema in `openapi/openapi.yaml`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ title: Metrics API
3
+ description: View current usage and plan limits.
4
+ ---
5
+
6
+ Endpoint:
7
+
8
+ - `GET /api/v1/metrics`
9
+
10
+ Returns sent/inbound counts and current plan limits.
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: Authentication
3
+ description: API key authentication and scopes.
4
+ ---
5
+
6
+ All API requests use bearer auth:
7
+
8
+ ```http
9
+ Authorization: Bearer <api_key>
10
+ ```
11
+
12
+ ## Scope model
13
+
14
+ Common scopes:
15
+
16
+ - `inboxes:read`, `inboxes:write`
17
+ - `emails:read`, `emails:write`, `emails:send`
18
+ - `domains:read`, `domains:write`
19
+ - `keys:read`, `keys:write`
20
+ - `metrics:read`
21
+ - `*` for full access
22
+
23
+ If scope is missing, API returns `403`.
24
+
25
+ If API key is missing or invalid, API returns `401`.
package/docs/docs.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://mintlify.com/docs.json",
3
+ "name": "EmailAgent Docs",
4
+ "theme": "mint",
5
+ "favicon": "/favicon.svg",
6
+ "colors": {
7
+ "primary": "#0c6f5c",
8
+ "light": "#0f8270",
9
+ "dark": "#0a5a4b"
10
+ },
11
+ "navigation": {
12
+ "groups": [
13
+ {
14
+ "group": "Getting Started",
15
+ "pages": [
16
+ "index",
17
+ "quickstart",
18
+ "authentication",
19
+ "idempotency",
20
+ "errors"
21
+ ]
22
+ },
23
+ {
24
+ "group": "API Reference",
25
+ "pages": [
26
+ "api-reference/inboxes",
27
+ "api-reference/emails",
28
+ "api-reference/domains",
29
+ "api-reference/api-keys",
30
+ "api-reference/metrics"
31
+ ]
32
+ }
33
+ ]
34
+ }
35
+ }