@intelligo-dev/core 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/dist/conversations/errors.d.ts +31 -0
- package/dist/conversations/errors.d.ts.map +1 -0
- package/dist/conversations/errors.js +25 -0
- package/dist/conversations/errors.js.map +1 -0
- package/dist/conversations/index.d.ts +13 -0
- package/dist/conversations/index.d.ts.map +1 -0
- package/dist/conversations/index.js +12 -0
- package/dist/conversations/index.js.map +1 -0
- package/dist/conversations/service.d.ts +132 -0
- package/dist/conversations/service.d.ts.map +1 -0
- package/dist/conversations/service.js +347 -0
- package/dist/conversations/service.js.map +1 -0
- package/dist/conversations/types.d.ts +10 -0
- package/dist/conversations/types.d.ts.map +1 -0
- package/dist/conversations/types.js +5 -0
- package/dist/conversations/types.js.map +1 -0
- package/dist/db/client.d.ts +19 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +52 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/index.d.ts +4 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +8 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema/agents.d.ts +400 -0
- package/dist/db/schema/agents.d.ts.map +1 -0
- package/dist/db/schema/agents.js +39 -0
- package/dist/db/schema/agents.js.map +1 -0
- package/dist/db/schema/ai.d.ts +2222 -0
- package/dist/db/schema/ai.d.ts.map +1 -0
- package/dist/db/schema/ai.js +313 -0
- package/dist/db/schema/ai.js.map +1 -0
- package/dist/db/schema/auth.d.ts +1222 -0
- package/dist/db/schema/auth.d.ts.map +1 -0
- package/dist/db/schema/auth.js +162 -0
- package/dist/db/schema/auth.js.map +1 -0
- package/dist/db/schema/billing.d.ts +1199 -0
- package/dist/db/schema/billing.d.ts.map +1 -0
- package/dist/db/schema/billing.js +150 -0
- package/dist/db/schema/billing.js.map +1 -0
- package/dist/db/schema/feature-flags.d.ts +143 -0
- package/dist/db/schema/feature-flags.d.ts.map +1 -0
- package/dist/db/schema/feature-flags.js +25 -0
- package/dist/db/schema/feature-flags.js.map +1 -0
- package/dist/db/schema/identity.d.ts +1295 -0
- package/dist/db/schema/identity.d.ts.map +1 -0
- package/dist/db/schema/identity.js +258 -0
- package/dist/db/schema/identity.js.map +1 -0
- package/dist/db/schema/index.d.ts +16 -0
- package/dist/db/schema/index.d.ts.map +1 -0
- package/dist/db/schema/index.js +43 -0
- package/dist/db/schema/index.js.map +1 -0
- package/dist/db/schema/notifications.d.ts +182 -0
- package/dist/db/schema/notifications.d.ts.map +1 -0
- package/dist/db/schema/notifications.js +38 -0
- package/dist/db/schema/notifications.js.map +1 -0
- package/dist/db/schema/rag.d.ts +171 -0
- package/dist/db/schema/rag.d.ts.map +1 -0
- package/dist/db/schema/rag.js +42 -0
- package/dist/db/schema/rag.js.map +1 -0
- package/dist/db/schema/usage.d.ts +1193 -0
- package/dist/db/schema/usage.d.ts.map +1 -0
- package/dist/db/schema/usage.js +224 -0
- package/dist/db/schema/usage.js.map +1 -0
- package/dist/db/validate.d.ts +19 -0
- package/dist/db/validate.d.ts.map +1 -0
- package/dist/db/validate.js +58 -0
- package/dist/db/validate.js.map +1 -0
- package/dist/db/workspace-queries.d.ts +75 -0
- package/dist/db/workspace-queries.d.ts.map +1 -0
- package/dist/db/workspace-queries.js +78 -0
- package/dist/db/workspace-queries.js.map +1 -0
- package/dist/documents/classifier.d.ts +31 -0
- package/dist/documents/classifier.d.ts.map +1 -0
- package/dist/documents/classifier.js +41 -0
- package/dist/documents/classifier.js.map +1 -0
- package/dist/documents/errors.d.ts +32 -0
- package/dist/documents/errors.d.ts.map +1 -0
- package/dist/documents/errors.js +27 -0
- package/dist/documents/errors.js.map +1 -0
- package/dist/documents/index.d.ts +14 -0
- package/dist/documents/index.d.ts.map +1 -0
- package/dist/documents/index.js +13 -0
- package/dist/documents/index.js.map +1 -0
- package/dist/documents/service.d.ts +54 -0
- package/dist/documents/service.d.ts.map +1 -0
- package/dist/documents/service.js +146 -0
- package/dist/documents/service.js.map +1 -0
- package/dist/documents/types.d.ts +27 -0
- package/dist/documents/types.d.ts.map +1 -0
- package/dist/documents/types.js +5 -0
- package/dist/documents/types.js.map +1 -0
- package/dist/email/index.d.ts +5 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +5 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/provider.d.ts +68 -0
- package/dist/email/provider.d.ts.map +1 -0
- package/dist/email/provider.js +199 -0
- package/dist/email/provider.js.map +1 -0
- package/dist/email/send.d.ts +47 -0
- package/dist/email/send.d.ts.map +1 -0
- package/dist/email/send.js +110 -0
- package/dist/email/send.js.map +1 -0
- package/dist/email/senders.d.ts +93 -0
- package/dist/email/senders.d.ts.map +1 -0
- package/dist/email/senders.js +232 -0
- package/dist/email/senders.js.map +1 -0
- package/dist/email/templates/base-layout.d.ts +7 -0
- package/dist/email/templates/base-layout.d.ts.map +1 -0
- package/dist/email/templates/base-layout.js +69 -0
- package/dist/email/templates/base-layout.js.map +1 -0
- package/dist/email/templates/index.d.ts +11 -0
- package/dist/email/templates/index.d.ts.map +1 -0
- package/dist/email/templates/index.js +17 -0
- package/dist/email/templates/index.js.map +1 -0
- package/dist/email/templates/password-reset.d.ts +7 -0
- package/dist/email/templates/password-reset.d.ts.map +1 -0
- package/dist/email/templates/password-reset.js +59 -0
- package/dist/email/templates/password-reset.js.map +1 -0
- package/dist/email/templates/payment-failed.d.ts +8 -0
- package/dist/email/templates/payment-failed.d.ts.map +1 -0
- package/dist/email/templates/payment-failed.js +62 -0
- package/dist/email/templates/payment-failed.js.map +1 -0
- package/dist/email/templates/quota-warning.d.ts +11 -0
- package/dist/email/templates/quota-warning.d.ts.map +1 -0
- package/dist/email/templates/quota-warning.js +82 -0
- package/dist/email/templates/quota-warning.js.map +1 -0
- package/dist/email/templates/subscription-confirmed.d.ts +9 -0
- package/dist/email/templates/subscription-confirmed.d.ts.map +1 -0
- package/dist/email/templates/subscription-confirmed.js +72 -0
- package/dist/email/templates/subscription-confirmed.js.map +1 -0
- package/dist/email/templates/trial-expiry.d.ts +9 -0
- package/dist/email/templates/trial-expiry.d.ts.map +1 -0
- package/dist/email/templates/trial-expiry.js +86 -0
- package/dist/email/templates/trial-expiry.js.map +1 -0
- package/dist/email/templates/trial-warning.d.ts +11 -0
- package/dist/email/templates/trial-warning.d.ts.map +1 -0
- package/dist/email/templates/trial-warning.js +70 -0
- package/dist/email/templates/trial-warning.js.map +1 -0
- package/dist/email/templates/verify-email.d.ts +7 -0
- package/dist/email/templates/verify-email.d.ts.map +1 -0
- package/dist/email/templates/verify-email.js +59 -0
- package/dist/email/templates/verify-email.js.map +1 -0
- package/dist/email/templates/welcome.d.ts +7 -0
- package/dist/email/templates/welcome.d.ts.map +1 -0
- package/dist/email/templates/welcome.js +51 -0
- package/dist/email/templates/welcome.js.map +1 -0
- package/dist/email/templates/workspace-invitation.d.ts +10 -0
- package/dist/email/templates/workspace-invitation.d.ts.map +1 -0
- package/dist/email/templates/workspace-invitation.js +79 -0
- package/dist/email/templates/workspace-invitation.js.map +1 -0
- package/dist/env.d.ts +21 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +129 -0
- package/dist/env.js.map +1 -0
- package/dist/identity/audit.d.ts +39 -0
- package/dist/identity/audit.d.ts.map +1 -0
- package/dist/identity/audit.js +51 -0
- package/dist/identity/audit.js.map +1 -0
- package/dist/identity/errors.d.ts +32 -0
- package/dist/identity/errors.d.ts.map +1 -0
- package/dist/identity/errors.js +25 -0
- package/dist/identity/errors.js.map +1 -0
- package/dist/identity/index.d.ts +16 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +15 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/service.d.ts +70 -0
- package/dist/identity/service.d.ts.map +1 -0
- package/dist/identity/service.js +179 -0
- package/dist/identity/service.js.map +1 -0
- package/dist/identity/types.d.ts +27 -0
- package/dist/identity/types.d.ts.map +1 -0
- package/dist/identity/types.js +5 -0
- package/dist/identity/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +50 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +183 -0
- package/dist/logger.js.map +1 -0
- package/dist/notifications/index.d.ts +86 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +112 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/triggers.d.ts +68 -0
- package/dist/notifications/triggers.d.ts.map +1 -0
- package/dist/notifications/triggers.js +145 -0
- package/dist/notifications/triggers.js.map +1 -0
- package/dist/notifications/types.d.ts +19 -0
- package/dist/notifications/types.d.ts.map +1 -0
- package/dist/notifications/types.js +11 -0
- package/dist/notifications/types.js.map +1 -0
- package/package.json +101 -0
- package/src/db/migrations/0000_sharp_night_nurse.sql +52 -0
- package/src/db/migrations/0001_hesitant_vapor.sql +40 -0
- package/src/db/migrations/0002_numerous_lady_vermin.sql +235 -0
- package/src/db/migrations/0003_mighty_jean_grey.sql +37 -0
- package/src/db/migrations/0004_cynical_grandmaster.sql +2 -0
- package/src/db/migrations/0005_careful_switch.sql +8 -0
- package/src/db/migrations/0006_tense_blue_marvel.sql +16 -0
- package/src/db/migrations/0007_next_squadron_sinister.sql +1 -0
- package/src/db/migrations/0008_powerful_scream.sql +39 -0
- package/src/db/migrations/0009_sad_ink.sql +1 -0
- package/src/db/migrations/0010_shocking_omega_flight.sql +2 -0
- package/src/db/migrations/0011_ambiguous_otto_octavius.sql +151 -0
- package/src/db/migrations/0011_hnsw_vector_index.sql +17 -0
- package/src/db/migrations/0012_user_profiles.sql +30 -0
- package/src/db/migrations/0013_trending_seasonal_columns.sql +9 -0
- package/src/db/migrations/0014_add_product_type_to_agents.sql +6 -0
- package/src/db/migrations/0015_new_v1_tables.sql +149 -0
- package/src/db/migrations/0016_document_types.sql +30 -0
- package/src/db/migrations/0017_document_metadata.sql +2 -0
- package/src/db/migrations/0018_identity_graph.sql +200 -0
- package/src/db/migrations/0019_db_driven_prompts.sql +20 -0
- package/src/db/migrations/0020_pending_extractions.sql +35 -0
- package/src/db/migrations/0021_rag_documents.sql +39 -0
- package/src/db/migrations/0022_user_quotas_usage_jsonb.sql +70 -0
- package/src/db/migrations/0023_user_facts_user_scoped_unique.sql +17 -0
- package/src/db/migrations/0024_user_memories_hnsw.sql +23 -0
- package/src/db/migrations/0025_audit_trigger_errcode.sql +21 -0
- package/src/db/migrations/0026_user_profile_snapshots_composite_pk.sql +17 -0
- package/src/db/migrations/0027_billing_settings_mnt_columns.sql +54 -0
- package/src/db/migrations/0028_trial_credits_normalized_email.sql +37 -0
- package/src/db/migrations/0029_usage_records_conversation_idx.sql +13 -0
- package/src/db/migrations/0030_pending_extractions_composite_idx.sql +11 -0
- package/src/db/migrations/0031_rag_documents_hnsw.sql +16 -0
- package/src/db/migrations/0032_rate_limit_unique_idx.sql +16 -0
- package/src/db/migrations/0033_pending_extractions_partial_idx.sql +18 -0
- package/src/db/migrations/0034_rate_limit_count.sql +9 -0
- package/src/db/migrations/0035_credit_reservations.sql +24 -0
- package/src/db/migrations/0036_executions_audit_jobs.sql +96 -0
- package/src/db/migrations/0037_rate_limit_minute_bucket.sql +46 -0
- package/src/db/migrations/0038_user_quotas_generic_usage.sql +25 -0
- package/src/db/migrations/0039_platform_admin_impersonation.sql +27 -0
- package/src/db/migrations/0040_ee_audit_chain.sql +23 -0
- package/src/db/migrations/README.md +57 -0
- package/src/db/migrations/meta/0000_snapshot.json +348 -0
- package/src/db/migrations/meta/0001_snapshot.json +631 -0
- package/src/db/migrations/meta/0002_snapshot.json +2269 -0
- package/src/db/migrations/meta/0003_snapshot.json +2488 -0
- package/src/db/migrations/meta/0004_snapshot.json +2500 -0
- package/src/db/migrations/meta/0005_snapshot.json +2548 -0
- package/src/db/migrations/meta/0006_snapshot.json +2650 -0
- package/src/db/migrations/meta/0007_snapshot.json +2657 -0
- package/src/db/migrations/meta/0008_snapshot.json +2719 -0
- package/src/db/migrations/meta/0009_snapshot.json +2726 -0
- package/src/db/migrations/meta/0010_snapshot.json +2739 -0
- package/src/db/migrations/meta/0011_snapshot.json +3886 -0
- package/src/db/migrations/meta/_journal.json +300 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documents Module (ADR-0009)
|
|
3
|
+
*
|
|
4
|
+
* Document lifecycle: save, list, read, delete versions, plus
|
|
5
|
+
* ownership and workspace/user access checks. See ./service.ts for
|
|
6
|
+
* the full module doc comment.
|
|
7
|
+
*
|
|
8
|
+
* Use via subpath import: @intelligo-dev/core/documents
|
|
9
|
+
*/
|
|
10
|
+
export { getUserDocuments, getDocument, saveDocument, deleteDocumentVersions, } from "./service";
|
|
11
|
+
export { DocumentServiceError, isDocumentServiceError, type DocumentServiceErrorCode, } from "./errors";
|
|
12
|
+
export type { DocumentActor, DocumentFilter, DocumentListItem } from "./types";
|
|
13
|
+
export { registerDocumentPatterns, classifyDocumentTitle, isProductDocument, listRegisteredDocumentPatterns, clearDocumentPatternRegistry, type DocumentPatternEntry, } from "./classifier";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/documents/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,wBAAwB,GAC9B,MAAM,UAAU,CAAC;AAElB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE/E,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,8BAA8B,EAC9B,4BAA4B,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documents Module (ADR-0009)
|
|
3
|
+
*
|
|
4
|
+
* Document lifecycle: save, list, read, delete versions, plus
|
|
5
|
+
* ownership and workspace/user access checks. See ./service.ts for
|
|
6
|
+
* the full module doc comment.
|
|
7
|
+
*
|
|
8
|
+
* Use via subpath import: @intelligo-dev/core/documents
|
|
9
|
+
*/
|
|
10
|
+
export { getUserDocuments, getDocument, saveDocument, deleteDocumentVersions, } from "./service";
|
|
11
|
+
export { DocumentServiceError, isDocumentServiceError, } from "./errors";
|
|
12
|
+
export { registerDocumentPatterns, classifyDocumentTitle, isProductDocument, listRegisteredDocumentPatterns, clearDocumentPatternRegistry, } from "./classifier";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/documents/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GAEvB,MAAM,UAAU,CAAC;AAIlB,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,8BAA8B,EAC9B,4BAA4B,GAE7B,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document Persistence Service — Server-only
|
|
3
|
+
*
|
|
4
|
+
* Core CRUD operations for AI-generated document artifacts with
|
|
5
|
+
* workspace + user isolation. Ported from
|
|
6
|
+
* @intelligo-dev/agents/documents (ADR-0009): the tables (`documents`,
|
|
7
|
+
* `document_types`) always lived in @intelligo-dev/core's schema, only the
|
|
8
|
+
* service layer sat in a dissolving package.
|
|
9
|
+
*
|
|
10
|
+
* Callers pass a resolved actor (workspaceId, userId) rather than this
|
|
11
|
+
* module resolving one itself — @intelligo-dev/core cannot depend on
|
|
12
|
+
* @intelligo-dev/auth (see tests/architecture/dependency-direction.test.ts),
|
|
13
|
+
* so `requireWorkspace()` moved to the caller. Every query still
|
|
14
|
+
* filters by workspaceId AND userId internally; the actor is never
|
|
15
|
+
* trusted to have done that itself.
|
|
16
|
+
*
|
|
17
|
+
* Failure is reported by throwing `DocumentServiceError` (a small,
|
|
18
|
+
* typed code set) rather than returning a `{ success, error }`
|
|
19
|
+
* envelope — that shaping, plus any error-reporting side effect
|
|
20
|
+
* (Sentry, logging), is a transport concern the caller applies at the
|
|
21
|
+
* Server Action / route boundary.
|
|
22
|
+
*
|
|
23
|
+
* This module is SERVER-ONLY. Do not import from client components.
|
|
24
|
+
*/
|
|
25
|
+
import type { DocumentActor, DocumentFilter, DocumentListItem } from "./types";
|
|
26
|
+
/**
|
|
27
|
+
* Get all documents for the actor. Ordered by most recently created
|
|
28
|
+
* first. Uses DISTINCT ON to get the latest version of each document.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getUserDocuments(actor: DocumentActor, filter?: DocumentFilter): Promise<DocumentListItem[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Get a single document by id, scoped to the actor.
|
|
33
|
+
* Throws DocumentServiceError("not_found") if no such document exists.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getDocument(actor: DocumentActor, id: string): Promise<DocumentListItem>;
|
|
36
|
+
/**
|
|
37
|
+
* Save (create new version of) a document.
|
|
38
|
+
* Throws DocumentServiceError("forbidden") if a document with this id
|
|
39
|
+
* already exists in the workspace under a different user.
|
|
40
|
+
*/
|
|
41
|
+
export declare function saveDocument(actor: DocumentActor, params: {
|
|
42
|
+
id: string;
|
|
43
|
+
title: string;
|
|
44
|
+
content: string;
|
|
45
|
+
kind: string;
|
|
46
|
+
}): Promise<DocumentListItem>;
|
|
47
|
+
/**
|
|
48
|
+
* Delete all versions of a document created after `timestamp`.
|
|
49
|
+
* Throws DocumentServiceError("invalid_input") for an unparsable
|
|
50
|
+
* timestamp or one older than the delete window, and ("not_found") if
|
|
51
|
+
* no document exists at that id within the actor's scope.
|
|
52
|
+
*/
|
|
53
|
+
export declare function deleteDocumentVersions(actor: DocumentActor, id: string, timestamp: string): Promise<DocumentListItem[]>;
|
|
54
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/documents/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAyB/E;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,aAAa,EACpB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAuB7B;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,gBAAgB,CAAC,CAkB3B;AAMD;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE;IACN,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,GACA,OAAO,CAAC,gBAAgB,CAAC,CAuC3B;AAQD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA4C7B"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document Persistence Service — Server-only
|
|
3
|
+
*
|
|
4
|
+
* Core CRUD operations for AI-generated document artifacts with
|
|
5
|
+
* workspace + user isolation. Ported from
|
|
6
|
+
* @intelligo-dev/agents/documents (ADR-0009): the tables (`documents`,
|
|
7
|
+
* `document_types`) always lived in @intelligo-dev/core's schema, only the
|
|
8
|
+
* service layer sat in a dissolving package.
|
|
9
|
+
*
|
|
10
|
+
* Callers pass a resolved actor (workspaceId, userId) rather than this
|
|
11
|
+
* module resolving one itself — @intelligo-dev/core cannot depend on
|
|
12
|
+
* @intelligo-dev/auth (see tests/architecture/dependency-direction.test.ts),
|
|
13
|
+
* so `requireWorkspace()` moved to the caller. Every query still
|
|
14
|
+
* filters by workspaceId AND userId internally; the actor is never
|
|
15
|
+
* trusted to have done that itself.
|
|
16
|
+
*
|
|
17
|
+
* Failure is reported by throwing `DocumentServiceError` (a small,
|
|
18
|
+
* typed code set) rather than returning a `{ success, error }`
|
|
19
|
+
* envelope — that shaping, plus any error-reporting side effect
|
|
20
|
+
* (Sentry, logging), is a transport concern the caller applies at the
|
|
21
|
+
* Server Action / route boundary.
|
|
22
|
+
*
|
|
23
|
+
* This module is SERVER-ONLY. Do not import from client components.
|
|
24
|
+
*/
|
|
25
|
+
import { and, desc, eq, gt } from "drizzle-orm";
|
|
26
|
+
import { db } from "../db";
|
|
27
|
+
import { documents } from "../db/schema";
|
|
28
|
+
import { classifyDocumentTitle, isProductDocument } from "./classifier";
|
|
29
|
+
import { DocumentServiceError } from "./errors";
|
|
30
|
+
function toListItem(doc) {
|
|
31
|
+
return {
|
|
32
|
+
id: doc.id,
|
|
33
|
+
title: doc.title,
|
|
34
|
+
kind: doc.kind,
|
|
35
|
+
createdAt: doc.createdAt.toISOString(),
|
|
36
|
+
agentLabel: classifyDocumentTitle(doc.title).agentLabel,
|
|
37
|
+
content: doc.content,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Query Operations
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/**
|
|
44
|
+
* Get all documents for the actor. Ordered by most recently created
|
|
45
|
+
* first. Uses DISTINCT ON to get the latest version of each document.
|
|
46
|
+
*/
|
|
47
|
+
export async function getUserDocuments(actor, filter) {
|
|
48
|
+
const uniqueDocs = await db
|
|
49
|
+
.selectDistinctOn([documents.id])
|
|
50
|
+
.from(documents)
|
|
51
|
+
.where(and(eq(documents.workspaceId, actor.workspaceId), eq(documents.userId, actor.userId)))
|
|
52
|
+
.orderBy(documents.id, desc(documents.createdAt));
|
|
53
|
+
let result = uniqueDocs.map(toListItem);
|
|
54
|
+
const filterType = filter?.type ?? "all";
|
|
55
|
+
if (filterType !== "all") {
|
|
56
|
+
result =
|
|
57
|
+
filterType === "report"
|
|
58
|
+
? result.filter((doc) => isProductDocument(doc.title))
|
|
59
|
+
: result.filter((doc) => doc.kind === filterType);
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get a single document by id, scoped to the actor.
|
|
65
|
+
* Throws DocumentServiceError("not_found") if no such document exists.
|
|
66
|
+
*/
|
|
67
|
+
export async function getDocument(actor, id) {
|
|
68
|
+
const [doc] = await db
|
|
69
|
+
.selectDistinctOn([documents.id])
|
|
70
|
+
.from(documents)
|
|
71
|
+
.where(and(eq(documents.id, id), eq(documents.workspaceId, actor.workspaceId), eq(documents.userId, actor.userId)))
|
|
72
|
+
.orderBy(documents.id, desc(documents.createdAt));
|
|
73
|
+
if (!doc) {
|
|
74
|
+
throw new DocumentServiceError("not_found", "Document not found");
|
|
75
|
+
}
|
|
76
|
+
return toListItem(doc);
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Mutation Operations
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
/**
|
|
82
|
+
* Save (create new version of) a document.
|
|
83
|
+
* Throws DocumentServiceError("forbidden") if a document with this id
|
|
84
|
+
* already exists in the workspace under a different user.
|
|
85
|
+
*/
|
|
86
|
+
export async function saveDocument(actor, params) {
|
|
87
|
+
const existingDocs = await db
|
|
88
|
+
.select()
|
|
89
|
+
.from(documents)
|
|
90
|
+
.where(and(eq(documents.id, params.id), eq(documents.workspaceId, actor.workspaceId)));
|
|
91
|
+
if (existingDocs.length > 0) {
|
|
92
|
+
const firstDoc = existingDocs[0];
|
|
93
|
+
if (firstDoc && firstDoc.userId !== actor.userId) {
|
|
94
|
+
throw new DocumentServiceError("forbidden", "Document belongs to a different user");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const [newDocument] = await db
|
|
98
|
+
.insert(documents)
|
|
99
|
+
.values({
|
|
100
|
+
id: params.id,
|
|
101
|
+
userId: actor.userId,
|
|
102
|
+
workspaceId: actor.workspaceId,
|
|
103
|
+
title: params.title,
|
|
104
|
+
content: params.content,
|
|
105
|
+
kind: params.kind,
|
|
106
|
+
createdAt: new Date(),
|
|
107
|
+
})
|
|
108
|
+
.returning();
|
|
109
|
+
if (!newDocument) {
|
|
110
|
+
throw new DocumentServiceError("database_error", "Failed to save document");
|
|
111
|
+
}
|
|
112
|
+
return toListItem(newDocument);
|
|
113
|
+
}
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Delete Operations
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
const MAX_DELETE_WINDOW_DAYS = 30;
|
|
118
|
+
/**
|
|
119
|
+
* Delete all versions of a document created after `timestamp`.
|
|
120
|
+
* Throws DocumentServiceError("invalid_input") for an unparsable
|
|
121
|
+
* timestamp or one older than the delete window, and ("not_found") if
|
|
122
|
+
* no document exists at that id within the actor's scope.
|
|
123
|
+
*/
|
|
124
|
+
export async function deleteDocumentVersions(actor, id, timestamp) {
|
|
125
|
+
const parsedTimestamp = new Date(timestamp);
|
|
126
|
+
if (Number.isNaN(parsedTimestamp.getTime())) {
|
|
127
|
+
throw new DocumentServiceError("invalid_input", "Invalid timestamp");
|
|
128
|
+
}
|
|
129
|
+
const oldestAllowed = new Date(Date.now() - MAX_DELETE_WINDOW_DAYS * 24 * 60 * 60 * 1000);
|
|
130
|
+
if (parsedTimestamp < oldestAllowed) {
|
|
131
|
+
throw new DocumentServiceError("invalid_input", `timestamp must be within the last ${MAX_DELETE_WINDOW_DAYS} days`);
|
|
132
|
+
}
|
|
133
|
+
const existingDocs = await db
|
|
134
|
+
.select()
|
|
135
|
+
.from(documents)
|
|
136
|
+
.where(and(eq(documents.id, id), eq(documents.workspaceId, actor.workspaceId), eq(documents.userId, actor.userId)));
|
|
137
|
+
if (existingDocs.length === 0) {
|
|
138
|
+
throw new DocumentServiceError("not_found", "Document not found");
|
|
139
|
+
}
|
|
140
|
+
const deletedDocs = await db
|
|
141
|
+
.delete(documents)
|
|
142
|
+
.where(and(eq(documents.id, id), eq(documents.workspaceId, actor.workspaceId), eq(documents.userId, actor.userId), gt(documents.createdAt, parsedTimestamp)))
|
|
143
|
+
.returning();
|
|
144
|
+
return deletedDocs.map(toListItem);
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/documents/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the documents service.
|
|
3
|
+
*/
|
|
4
|
+
/** Resolved actor identity — every query is scoped to this pair. */
|
|
5
|
+
export type DocumentActor = {
|
|
6
|
+
workspaceId: string;
|
|
7
|
+
userId: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Document filter type
|
|
11
|
+
*/
|
|
12
|
+
export type DocumentFilter = {
|
|
13
|
+
type?: "all" | "report" | "text" | "code" | "sheet" | "image";
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Document list item returned by getUserDocuments / getDocument /
|
|
17
|
+
* saveDocument / deleteDocumentVersions.
|
|
18
|
+
*/
|
|
19
|
+
export type DocumentListItem = {
|
|
20
|
+
id: string;
|
|
21
|
+
title: string;
|
|
22
|
+
kind: string;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
agentLabel: string;
|
|
25
|
+
content: string | null;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/documents/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;CAC/D,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/documents/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { sendEmail, type SendEmailParams, type SendEmailWithComponentParams, type SendEmailResult, } from "./send";
|
|
2
|
+
export { getEmailProvider, resetEmailProviderCache, type EmailProvider, type EmailProviderName, type EmailSendParams, type EmailTemplateRef, ResendProvider, LoopsProvider, ConsoleProvider, } from "./provider";
|
|
3
|
+
export * from "./templates";
|
|
4
|
+
export * from "./senders";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/email/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,eAAe,GACrB,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/email/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,GAIV,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EAKvB,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-neutral template descriptor attached to every framework email.
|
|
3
|
+
*
|
|
4
|
+
* HTML-capable providers (Resend) ignore it — they send the rendered HTML.
|
|
5
|
+
* Template-based providers (Loops) require it: `key` is resolved to the
|
|
6
|
+
* provider-side template id and `variables` become the template's dynamic
|
|
7
|
+
* data. Keys are stable framework identifiers, e.g. "verify-email".
|
|
8
|
+
*/
|
|
9
|
+
export interface EmailTemplateRef {
|
|
10
|
+
key: string;
|
|
11
|
+
variables?: Record<string, string | number>;
|
|
12
|
+
}
|
|
13
|
+
export interface EmailSendParams {
|
|
14
|
+
to: string | string[];
|
|
15
|
+
subject: string;
|
|
16
|
+
html: string;
|
|
17
|
+
from?: string;
|
|
18
|
+
replyTo?: string;
|
|
19
|
+
template?: EmailTemplateRef;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Common interface every email provider must implement.
|
|
23
|
+
*/
|
|
24
|
+
export interface EmailProvider {
|
|
25
|
+
send(params: EmailSendParams): Promise<{
|
|
26
|
+
id: string;
|
|
27
|
+
}>;
|
|
28
|
+
}
|
|
29
|
+
export declare class ResendProvider implements EmailProvider {
|
|
30
|
+
private client;
|
|
31
|
+
constructor(apiKey: string);
|
|
32
|
+
send(params: EmailSendParams): Promise<{
|
|
33
|
+
id: string;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export declare class LoopsProvider implements EmailProvider {
|
|
37
|
+
private apiKey;
|
|
38
|
+
private transactionalIds?;
|
|
39
|
+
constructor(apiKey: string, transactionalIds?: Record<string, string> | undefined);
|
|
40
|
+
private resolveTransactionalId;
|
|
41
|
+
send(params: EmailSendParams): Promise<{
|
|
42
|
+
id: string;
|
|
43
|
+
}>;
|
|
44
|
+
}
|
|
45
|
+
export declare class ConsoleProvider implements EmailProvider {
|
|
46
|
+
send(params: EmailSendParams): Promise<{
|
|
47
|
+
id: string;
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
export type EmailProviderName = "resend" | "loops" | "console";
|
|
51
|
+
/** Test-only: clear the cached provider so env changes take effect. */
|
|
52
|
+
export declare function resetEmailProviderCache(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Returns the email provider based on environment variables.
|
|
55
|
+
*
|
|
56
|
+
* Priority:
|
|
57
|
+
* 1. EMAIL_PROVIDER env var → explicit selection (with API key validation)
|
|
58
|
+
* 2. RESEND_API_KEY → ResendProvider (auto-detect; preferred because it can
|
|
59
|
+
* send every framework email without per-template setup)
|
|
60
|
+
* 3. LOOPS_API_KEY → LoopsProvider (auto-detect; needs
|
|
61
|
+
* LOOPS_TRANSACTIONAL_ID_* mappings for the templates you use)
|
|
62
|
+
* 4. (none) → ConsoleProvider
|
|
63
|
+
*
|
|
64
|
+
* The provider instance is cached (singleton) so a new client is NOT created
|
|
65
|
+
* on every call.
|
|
66
|
+
*/
|
|
67
|
+
export declare function getEmailProvider(): EmailProvider;
|
|
68
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/email/provider.ts"],"names":[],"mappings":"AAcA;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAaD,qBAAa,cAAe,YAAW,aAAa;IAClD,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAIpB,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAwB7D;AAiBD,qBAAa,aAAc,YAAW,aAAa;IAE/C,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,gBAAgB,CAAC;gBADjB,MAAM,EAAE,MAAM,EACd,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAA;IAGnD,OAAO,CAAC,sBAAsB;IAWxB,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CA6D7D;AAMD,qBAAa,eAAgB,YAAW,aAAa;IAC7C,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAW7D;AAMD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAI/D,uEAAuE;AACvE,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAoChD"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Resend } from "resend";
|
|
2
|
+
/** Error with an HTTP-ish status code so send.ts can decide retryability. */
|
|
3
|
+
function statusError(message, statusCode) {
|
|
4
|
+
const err = new Error(message);
|
|
5
|
+
err.statusCode = statusCode;
|
|
6
|
+
return err;
|
|
7
|
+
}
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// ResendProvider
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
export class ResendProvider {
|
|
12
|
+
constructor(apiKey) {
|
|
13
|
+
this.client = new Resend(apiKey);
|
|
14
|
+
}
|
|
15
|
+
async send(params) {
|
|
16
|
+
const { data, error } = await this.client.emails.send({
|
|
17
|
+
from: params.from ?? "Intelligo <noreply@intelligo.dev>",
|
|
18
|
+
to: Array.isArray(params.to) ? params.to : [params.to],
|
|
19
|
+
subject: params.subject,
|
|
20
|
+
html: params.html,
|
|
21
|
+
replyTo: params.replyTo,
|
|
22
|
+
});
|
|
23
|
+
if (error) {
|
|
24
|
+
// Resend returns an error object rather than throwing
|
|
25
|
+
const err = new Error(error.message);
|
|
26
|
+
// Resend error names map to HTTP status categories
|
|
27
|
+
if (error.name === "validation_error" ||
|
|
28
|
+
error.name === "missing_required_field") {
|
|
29
|
+
err.statusCode = 400;
|
|
30
|
+
}
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
return { id: data?.id ?? "unknown" };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// LoopsProvider
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Loops transactional emails are designed in the Loops dashboard and sent by
|
|
40
|
+
// template id — the API accepts no raw HTML and exactly one recipient per
|
|
41
|
+
// call. Template keys resolve to ids through (in order):
|
|
42
|
+
// 1. the `transactionalIds` map passed to the constructor
|
|
43
|
+
// 2. env: LOOPS_TRANSACTIONAL_ID_<KEY> (key upper-snaked,
|
|
44
|
+
// e.g. "verify-email" → LOOPS_TRANSACTIONAL_ID_VERIFY_EMAIL)
|
|
45
|
+
// `from`/`replyTo` are ignored — the sender is configured per template in
|
|
46
|
+
// Loops itself.
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
const LOOPS_API_URL = "https://app.loops.so/api/v1/transactional";
|
|
49
|
+
export class LoopsProvider {
|
|
50
|
+
constructor(apiKey, transactionalIds) {
|
|
51
|
+
this.apiKey = apiKey;
|
|
52
|
+
this.transactionalIds = transactionalIds;
|
|
53
|
+
}
|
|
54
|
+
resolveTransactionalId(key) {
|
|
55
|
+
const mapped = this.transactionalIds?.[key];
|
|
56
|
+
if (mapped) {
|
|
57
|
+
return mapped;
|
|
58
|
+
}
|
|
59
|
+
const envName = `LOOPS_TRANSACTIONAL_ID_${key
|
|
60
|
+
.toUpperCase()
|
|
61
|
+
.replace(/-/g, "_")}`;
|
|
62
|
+
return process.env[envName];
|
|
63
|
+
}
|
|
64
|
+
async send(params) {
|
|
65
|
+
const template = params.template;
|
|
66
|
+
if (!template) {
|
|
67
|
+
throw statusError(`Loops requires a template key (subject: "${params.subject}") — Loops cannot send raw HTML. Use a framework sender or pass { template }.`, 400);
|
|
68
|
+
}
|
|
69
|
+
const transactionalId = this.resolveTransactionalId(template.key);
|
|
70
|
+
if (!transactionalId) {
|
|
71
|
+
throw statusError(`No Loops transactional id mapped for template "${template.key}". Set LOOPS_TRANSACTIONAL_ID_${template.key
|
|
72
|
+
.toUpperCase()
|
|
73
|
+
.replace(/-/g, "_")} or pass a transactionalIds map to LoopsProvider.`, 400);
|
|
74
|
+
}
|
|
75
|
+
const recipients = Array.isArray(params.to) ? params.to : [params.to];
|
|
76
|
+
// Loops accepts a single recipient per request — fan out sequentially so
|
|
77
|
+
// a failure surfaces with normal retry semantics in send.ts.
|
|
78
|
+
for (const email of recipients) {
|
|
79
|
+
const response = await fetch(LOOPS_API_URL, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: {
|
|
82
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
83
|
+
"Content-Type": "application/json",
|
|
84
|
+
},
|
|
85
|
+
body: JSON.stringify({
|
|
86
|
+
transactionalId,
|
|
87
|
+
email,
|
|
88
|
+
dataVariables: template.variables ?? {},
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
let detail = "";
|
|
93
|
+
try {
|
|
94
|
+
const body = (await response.json());
|
|
95
|
+
detail = body.message ?? body.error?.message ?? "";
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Non-JSON error body — status code alone is enough
|
|
99
|
+
}
|
|
100
|
+
throw statusError(`Loops send failed (${response.status}) for template "${template.key}"${detail ? `: ${detail}` : ""}`, response.status);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Loops returns { success: true } with no message id
|
|
104
|
+
return { id: `loops:${transactionalId}` };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// ConsoleProvider (development fallback)
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
export class ConsoleProvider {
|
|
111
|
+
async send(params) {
|
|
112
|
+
const recipient = Array.isArray(params.to)
|
|
113
|
+
? params.to.join(", ")
|
|
114
|
+
: params.to;
|
|
115
|
+
console.log(`[Email] Would send to: ${recipient}, subject: ${params.subject}`);
|
|
116
|
+
return { id: `console-${Date.now()}` };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
let cachedProvider = null;
|
|
120
|
+
/** Test-only: clear the cached provider so env changes take effect. */
|
|
121
|
+
export function resetEmailProviderCache() {
|
|
122
|
+
cachedProvider = null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Returns the email provider based on environment variables.
|
|
126
|
+
*
|
|
127
|
+
* Priority:
|
|
128
|
+
* 1. EMAIL_PROVIDER env var → explicit selection (with API key validation)
|
|
129
|
+
* 2. RESEND_API_KEY → ResendProvider (auto-detect; preferred because it can
|
|
130
|
+
* send every framework email without per-template setup)
|
|
131
|
+
* 3. LOOPS_API_KEY → LoopsProvider (auto-detect; needs
|
|
132
|
+
* LOOPS_TRANSACTIONAL_ID_* mappings for the templates you use)
|
|
133
|
+
* 4. (none) → ConsoleProvider
|
|
134
|
+
*
|
|
135
|
+
* The provider instance is cached (singleton) so a new client is NOT created
|
|
136
|
+
* on every call.
|
|
137
|
+
*/
|
|
138
|
+
export function getEmailProvider() {
|
|
139
|
+
if (cachedProvider) {
|
|
140
|
+
return cachedProvider;
|
|
141
|
+
}
|
|
142
|
+
const explicit = process.env.EMAIL_PROVIDER?.toLowerCase();
|
|
143
|
+
if (explicit) {
|
|
144
|
+
cachedProvider = resolveExplicitProvider(explicit);
|
|
145
|
+
if (cachedProvider) {
|
|
146
|
+
return cachedProvider;
|
|
147
|
+
}
|
|
148
|
+
// Unknown value — warn and fall through to auto-detect
|
|
149
|
+
console.warn(`[Email] Unknown EMAIL_PROVIDER="${process.env.EMAIL_PROVIDER}", falling back to auto-detect`);
|
|
150
|
+
}
|
|
151
|
+
// Auto-detect from available API keys (backwards compatible)
|
|
152
|
+
const resendKey = process.env.RESEND_API_KEY;
|
|
153
|
+
if (resendKey) {
|
|
154
|
+
console.log("[Email] Using Resend provider");
|
|
155
|
+
cachedProvider = new ResendProvider(resendKey);
|
|
156
|
+
return cachedProvider;
|
|
157
|
+
}
|
|
158
|
+
const loopsKey = process.env.LOOPS_API_KEY;
|
|
159
|
+
if (loopsKey) {
|
|
160
|
+
console.log("[Email] Using Loops provider");
|
|
161
|
+
cachedProvider = new LoopsProvider(loopsKey);
|
|
162
|
+
return cachedProvider;
|
|
163
|
+
}
|
|
164
|
+
console.log("[Email] Using console provider (no API key set)");
|
|
165
|
+
cachedProvider = new ConsoleProvider();
|
|
166
|
+
return cachedProvider;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Resolve an explicit EMAIL_PROVIDER value to a provider instance.
|
|
170
|
+
* Returns null for unknown values so the caller can fall through to auto-detect.
|
|
171
|
+
*/
|
|
172
|
+
function resolveExplicitProvider(provider) {
|
|
173
|
+
switch (provider) {
|
|
174
|
+
case "resend": {
|
|
175
|
+
const key = process.env.RESEND_API_KEY;
|
|
176
|
+
if (!key) {
|
|
177
|
+
console.warn("[Email] EMAIL_PROVIDER=resend but RESEND_API_KEY is not set, falling back to console");
|
|
178
|
+
return new ConsoleProvider();
|
|
179
|
+
}
|
|
180
|
+
console.log("[Email] Using Resend provider (explicit)");
|
|
181
|
+
return new ResendProvider(key);
|
|
182
|
+
}
|
|
183
|
+
case "loops": {
|
|
184
|
+
const key = process.env.LOOPS_API_KEY;
|
|
185
|
+
if (!key) {
|
|
186
|
+
console.warn("[Email] EMAIL_PROVIDER=loops but LOOPS_API_KEY is not set, falling back to console");
|
|
187
|
+
return new ConsoleProvider();
|
|
188
|
+
}
|
|
189
|
+
console.log("[Email] Using Loops provider (explicit)");
|
|
190
|
+
return new LoopsProvider(key);
|
|
191
|
+
}
|
|
192
|
+
case "console":
|
|
193
|
+
console.log("[Email] Using console provider (explicit)");
|
|
194
|
+
return new ConsoleProvider();
|
|
195
|
+
default:
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/email/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import { type EmailTemplateRef } from "./provider";
|
|
3
|
+
export interface SendEmailParams {
|
|
4
|
+
to: string | string[];
|
|
5
|
+
subject: string;
|
|
6
|
+
html: string;
|
|
7
|
+
/** Defaults to EMAIL_FROM env var or "Intelligo <noreply@intelligo.dev>" */
|
|
8
|
+
from?: string;
|
|
9
|
+
replyTo?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Provider-neutral template descriptor. Required by template-based
|
|
12
|
+
* providers (Loops); ignored by HTML-capable providers (Resend).
|
|
13
|
+
*/
|
|
14
|
+
template?: EmailTemplateRef;
|
|
15
|
+
}
|
|
16
|
+
export interface SendEmailWithComponentParams {
|
|
17
|
+
to: string | string[];
|
|
18
|
+
subject: string;
|
|
19
|
+
/** A React Email component element. Will be rendered to HTML before sending. */
|
|
20
|
+
react: React.ReactElement;
|
|
21
|
+
/** Defaults to EMAIL_FROM env var or "Intelligo <noreply@intelligo.dev>" */
|
|
22
|
+
from?: string;
|
|
23
|
+
replyTo?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Provider-neutral template descriptor. Required by template-based
|
|
26
|
+
* providers (Loops); ignored by HTML-capable providers (Resend).
|
|
27
|
+
*/
|
|
28
|
+
template?: EmailTemplateRef;
|
|
29
|
+
}
|
|
30
|
+
export interface SendEmailResult {
|
|
31
|
+
success: boolean;
|
|
32
|
+
id?: string;
|
|
33
|
+
error?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Send an email through the configured provider with retry logic.
|
|
37
|
+
*
|
|
38
|
+
* Accepts either raw HTML via `{ html }` or a React Email component via
|
|
39
|
+
* `{ react }`. When a React element is provided, it is rendered to HTML
|
|
40
|
+
* using `@react-email/components`'s `render()` before sending.
|
|
41
|
+
*
|
|
42
|
+
* This function NEVER throws. All errors are caught and returned as
|
|
43
|
+
* `{ success: false, error: "..." }`. This prevents email failures
|
|
44
|
+
* from crashing the application (TECH-08).
|
|
45
|
+
*/
|
|
46
|
+
export declare function sendEmail(params: SendEmailParams | SendEmailWithComponentParams): Promise<SendEmailResult>;
|
|
47
|
+
//# sourceMappingURL=send.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/email/send.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAcrE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC;IAC1B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2CD;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,eAAe,GAAG,4BAA4B,GACrD,OAAO,CAAC,eAAe,CAAC,CAgF1B"}
|