@intelligo-dev/core 1.0.0-beta.1 → 1.0.0-beta.13
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/NOTICE +6 -0
- package/README.md +102 -0
- package/dist/attachments/errors.d.ts +7 -0
- package/dist/attachments/errors.d.ts.map +1 -0
- package/dist/attachments/errors.js +11 -0
- package/dist/attachments/errors.js.map +1 -0
- package/dist/attachments/index.d.ts +8 -0
- package/dist/attachments/index.d.ts.map +1 -0
- package/dist/attachments/index.js +7 -0
- package/dist/attachments/index.js.map +1 -0
- package/dist/attachments/service.d.ts +45 -0
- package/dist/attachments/service.d.ts.map +1 -0
- package/dist/attachments/service.js +100 -0
- package/dist/attachments/service.js.map +1 -0
- package/dist/attachments/types.d.ts +6 -0
- package/dist/attachments/types.d.ts.map +1 -0
- package/dist/attachments/types.js +2 -0
- package/dist/attachments/types.js.map +1 -0
- package/dist/conversations/errors.d.ts +2 -8
- package/dist/conversations/errors.d.ts.map +1 -1
- package/dist/conversations/errors.js +2 -8
- package/dist/conversations/errors.js.map +1 -1
- package/dist/conversations/index.d.ts +4 -12
- package/dist/conversations/index.d.ts.map +1 -1
- package/dist/conversations/index.js +2 -11
- package/dist/conversations/index.js.map +1 -1
- package/dist/conversations/service.d.ts +49 -61
- package/dist/conversations/service.d.ts.map +1 -1
- package/dist/conversations/service.js +110 -83
- package/dist/conversations/service.js.map +1 -1
- package/dist/conversations/types.d.ts +1 -4
- package/dist/conversations/types.d.ts.map +1 -1
- package/dist/conversations/types.js +0 -3
- package/dist/conversations/types.js.map +1 -1
- package/dist/db/client.d.ts +21 -10
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +43 -18
- package/dist/db/client.js.map +1 -1
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +3 -7
- package/dist/db/index.js.map +1 -1
- package/dist/db/schema/agents.d.ts +14 -51
- package/dist/db/schema/agents.d.ts.map +1 -1
- package/dist/db/schema/agents.js +9 -21
- package/dist/db/schema/agents.js.map +1 -1
- package/dist/db/schema/ai.d.ts +86 -1556
- package/dist/db/schema/ai.d.ts.map +1 -1
- package/dist/db/schema/ai.js +32 -236
- package/dist/db/schema/ai.js.map +1 -1
- package/dist/db/schema/auth.d.ts +5 -34
- package/dist/db/schema/auth.d.ts.map +1 -1
- package/dist/db/schema/auth.js +25 -56
- package/dist/db/schema/auth.js.map +1 -1
- package/dist/db/schema/billing.d.ts +136 -107
- package/dist/db/schema/billing.d.ts.map +1 -1
- package/dist/db/schema/billing.js +72 -60
- package/dist/db/schema/billing.js.map +1 -1
- package/dist/db/schema/feature-flags.d.ts +3 -12
- package/dist/db/schema/feature-flags.d.ts.map +1 -1
- package/dist/db/schema/feature-flags.js +3 -12
- package/dist/db/schema/feature-flags.js.map +1 -1
- package/dist/db/schema/identity.d.ts +12 -274
- package/dist/db/schema/identity.d.ts.map +1 -1
- package/dist/db/schema/identity.js +19 -104
- package/dist/db/schema/identity.js.map +1 -1
- package/dist/db/schema/index.d.ts +8 -15
- package/dist/db/schema/index.d.ts.map +1 -1
- package/dist/db/schema/index.js +12 -42
- package/dist/db/schema/index.js.map +1 -1
- package/dist/db/schema/notifications.d.ts +3 -17
- package/dist/db/schema/notifications.d.ts.map +1 -1
- package/dist/db/schema/notifications.js +3 -17
- package/dist/db/schema/notifications.js.map +1 -1
- package/dist/db/schema/usage.d.ts +94 -77
- package/dist/db/schema/usage.d.ts.map +1 -1
- package/dist/db/schema/usage.js +59 -89
- package/dist/db/schema/usage.js.map +1 -1
- package/dist/db/validate.d.ts +2 -11
- package/dist/db/validate.d.ts.map +1 -1
- package/dist/db/validate.js +6 -17
- package/dist/db/validate.js.map +1 -1
- package/dist/db/workspace-queries.d.ts +5 -29
- package/dist/db/workspace-queries.d.ts.map +1 -1
- package/dist/db/workspace-queries.js +5 -29
- package/dist/db/workspace-queries.js.map +1 -1
- package/dist/documents/classifier.d.ts +5 -12
- package/dist/documents/classifier.d.ts.map +1 -1
- package/dist/documents/classifier.js +16 -16
- package/dist/documents/classifier.js.map +1 -1
- package/dist/documents/errors.d.ts +2 -10
- package/dist/documents/errors.d.ts.map +1 -1
- package/dist/documents/errors.js +2 -10
- package/dist/documents/errors.js.map +1 -1
- package/dist/documents/index.d.ts +4 -13
- package/dist/documents/index.d.ts.map +1 -1
- package/dist/documents/index.js +3 -12
- package/dist/documents/index.js.map +1 -1
- package/dist/documents/service.d.ts +19 -26
- package/dist/documents/service.d.ts.map +1 -1
- package/dist/documents/service.js +44 -38
- package/dist/documents/service.js.map +1 -1
- package/dist/documents/types.d.ts +6 -10
- package/dist/documents/types.d.ts.map +1 -1
- package/dist/documents/types.js +0 -3
- package/dist/documents/types.js.map +1 -1
- package/dist/email/brand.d.ts +17 -0
- package/dist/email/brand.d.ts.map +1 -0
- package/dist/email/brand.js +9 -0
- package/dist/email/brand.js.map +1 -0
- package/dist/email/index.d.ts +4 -4
- package/dist/email/index.js +4 -4
- package/dist/email/provider.d.ts +1 -7
- package/dist/email/provider.d.ts.map +1 -1
- package/dist/email/provider.js +10 -19
- package/dist/email/provider.js.map +1 -1
- package/dist/email/send.d.ts +12 -12
- package/dist/email/send.d.ts.map +1 -1
- package/dist/email/send.js +5 -19
- package/dist/email/send.js.map +1 -1
- package/dist/email/senders.d.ts +17 -30
- package/dist/email/senders.d.ts.map +1 -1
- package/dist/email/senders.js +33 -47
- package/dist/email/senders.js.map +1 -1
- package/dist/email/templates/base-layout.d.ts +1 -1
- package/dist/email/templates/base-layout.d.ts.map +1 -1
- package/dist/email/templates/base-layout.js +4 -6
- package/dist/email/templates/base-layout.js.map +1 -1
- package/dist/email/templates/index.d.ts +10 -10
- package/dist/email/templates/index.d.ts.map +1 -1
- package/dist/email/templates/index.js +10 -16
- package/dist/email/templates/index.js.map +1 -1
- package/dist/email/templates/password-reset.d.ts +2 -2
- package/dist/email/templates/password-reset.d.ts.map +1 -1
- package/dist/email/templates/password-reset.js +10 -22
- package/dist/email/templates/password-reset.js.map +1 -1
- package/dist/email/templates/payment-failed.d.ts +2 -2
- package/dist/email/templates/payment-failed.d.ts.map +1 -1
- package/dist/email/templates/payment-failed.js +11 -24
- package/dist/email/templates/payment-failed.js.map +1 -1
- package/dist/email/templates/quota-warning.d.ts +4 -4
- package/dist/email/templates/quota-warning.d.ts.map +1 -1
- package/dist/email/templates/quota-warning.js +19 -39
- package/dist/email/templates/quota-warning.js.map +1 -1
- package/dist/email/templates/subscription-confirmed.d.ts +2 -2
- package/dist/email/templates/subscription-confirmed.d.ts.map +1 -1
- package/dist/email/templates/subscription-confirmed.js +13 -28
- package/dist/email/templates/subscription-confirmed.js.map +1 -1
- package/dist/email/templates/trial-expiry.d.ts +2 -2
- package/dist/email/templates/trial-expiry.d.ts.map +1 -1
- package/dist/email/templates/trial-expiry.js +12 -36
- package/dist/email/templates/trial-expiry.js.map +1 -1
- package/dist/email/templates/trial-warning.d.ts +2 -2
- package/dist/email/templates/trial-warning.d.ts.map +1 -1
- package/dist/email/templates/trial-warning.js +15 -32
- package/dist/email/templates/trial-warning.js.map +1 -1
- package/dist/email/templates/verify-email.d.ts +2 -2
- package/dist/email/templates/verify-email.d.ts.map +1 -1
- package/dist/email/templates/verify-email.js +10 -22
- package/dist/email/templates/verify-email.js.map +1 -1
- package/dist/email/templates/welcome.d.ts +2 -2
- package/dist/email/templates/welcome.d.ts.map +1 -1
- package/dist/email/templates/welcome.js +13 -20
- package/dist/email/templates/welcome.js.map +1 -1
- package/dist/email/templates/workspace-invitation.d.ts +2 -2
- package/dist/email/templates/workspace-invitation.d.ts.map +1 -1
- package/dist/email/templates/workspace-invitation.js +12 -26
- package/dist/email/templates/workspace-invitation.js.map +1 -1
- package/dist/env.d.ts +5 -10
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +41 -31
- package/dist/env.js.map +1 -1
- package/dist/identity/audit.d.ts +11 -24
- package/dist/identity/audit.d.ts.map +1 -1
- package/dist/identity/audit.js +13 -27
- package/dist/identity/audit.js.map +1 -1
- package/dist/identity/errors.d.ts +4 -12
- package/dist/identity/errors.d.ts.map +1 -1
- package/dist/identity/errors.js +2 -8
- package/dist/identity/errors.js.map +1 -1
- package/dist/identity/index.d.ts +5 -13
- package/dist/identity/index.d.ts.map +1 -1
- package/dist/identity/index.js +4 -12
- package/dist/identity/index.js.map +1 -1
- package/dist/identity/service.d.ts +13 -47
- package/dist/identity/service.d.ts.map +1 -1
- package/dist/identity/service.js +31 -78
- package/dist/identity/service.js.map +1 -1
- package/dist/identity/types.d.ts +1 -4
- package/dist/identity/types.d.ts.map +1 -1
- package/dist/identity/types.js +0 -3
- package/dist/identity/types.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -10
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +7 -18
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +45 -49
- package/dist/logger.js.map +1 -1
- package/dist/money.d.ts +95 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/money.js +208 -0
- package/dist/money.js.map +1 -0
- package/dist/notifications/index.d.ts +9 -43
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +9 -49
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/triggers.d.ts +9 -32
- package/dist/notifications/triggers.d.ts.map +1 -1
- package/dist/notifications/triggers.js +21 -58
- package/dist/notifications/triggers.js.map +1 -1
- package/dist/notifications/types.d.ts +1 -10
- package/dist/notifications/types.d.ts.map +1 -1
- package/dist/notifications/types.js +0 -9
- package/dist/notifications/types.js.map +1 -1
- package/dist/prompt.d.ts +38 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +118 -0
- package/dist/prompt.js.map +1 -0
- package/dist/registry.d.ts +32 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +60 -0
- package/dist/registry.js.map +1 -0
- package/dist/request-context.d.ts +49 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +100 -0
- package/dist/request-context.js.map +1 -0
- package/dist/storage/index.d.ts +65 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +109 -0
- package/dist/storage/index.js.map +1 -0
- package/package.json +74 -24
- package/src/attachments/errors.ts +18 -0
- package/src/attachments/index.ts +22 -0
- package/src/attachments/service.ts +178 -0
- package/src/attachments/types.ts +6 -0
- package/src/conversations/errors.ts +45 -0
- package/src/conversations/index.ts +39 -0
- package/src/conversations/service.ts +594 -0
- package/src/conversations/types.ts +15 -0
- package/src/db/client.ts +91 -0
- package/src/db/index.ts +3 -0
- package/src/db/migrations/0000_baseline.sql +652 -0
- package/src/db/migrations/0001_reconcile_chain_built_databases.sql +53 -0
- package/src/db/migrations/0002_webhook_claim_lease.sql +1 -0
- package/src/db/migrations/README.md +74 -36
- package/src/db/migrations/legacy-chain.json +197 -0
- package/src/db/migrations/meta/0000_snapshot.json +4182 -157
- package/src/db/migrations/meta/0002_snapshot.json +2478 -368
- package/src/db/migrations/meta/_journal.json +6 -279
- package/src/db/schema/agents.ts +57 -0
- package/src/db/schema/ai.ts +174 -0
- package/src/db/schema/auth.ts +183 -0
- package/src/db/schema/billing.ts +209 -0
- package/src/db/schema/feature-flags.ts +20 -0
- package/src/db/schema/identity.ts +250 -0
- package/src/db/schema/index.ts +12 -0
- package/src/db/schema/notifications.ts +31 -0
- package/src/db/schema/usage.ts +269 -0
- package/src/db/validate.ts +63 -0
- package/src/db/workspace-queries.ts +64 -0
- package/src/documents/classifier.ts +61 -0
- package/src/documents/errors.ts +44 -0
- package/src/documents/index.ts +24 -0
- package/src/documents/service.ts +256 -0
- package/src/documents/types.ts +24 -0
- package/src/email/brand.ts +24 -0
- package/src/email/index.ts +19 -0
- package/src/email/provider.ts +278 -0
- package/src/email/send.ts +169 -0
- package/src/email/senders.ts +292 -0
- package/src/email/templates/base-layout.tsx +145 -0
- package/src/email/templates/index.ts +28 -0
- package/src/email/templates/password-reset.tsx +72 -0
- package/src/email/templates/payment-failed.tsx +77 -0
- package/src/email/templates/quota-warning.tsx +118 -0
- package/src/email/templates/subscription-confirmed.tsx +91 -0
- package/src/email/templates/trial-expiry.tsx +124 -0
- package/src/email/templates/trial-warning.tsx +104 -0
- package/src/email/templates/verify-email.tsx +72 -0
- package/src/email/templates/welcome.tsx +64 -0
- package/src/email/templates/workspace-invitation.tsx +105 -0
- package/src/env.ts +180 -0
- package/src/identity/audit.ts +65 -0
- package/src/identity/errors.ts +44 -0
- package/src/identity/index.ts +26 -0
- package/src/identity/service.ts +202 -0
- package/src/identity/types.ts +28 -0
- package/src/index.ts +4 -0
- package/src/logger.ts +198 -0
- package/src/money.ts +270 -0
- package/src/notifications/index.ts +108 -0
- package/src/notifications/triggers.ts +158 -0
- package/src/notifications/types.ts +18 -0
- package/src/prompt.ts +142 -0
- package/src/registry.ts +75 -0
- package/src/request-context.ts +137 -0
- package/src/storage/index.ts +153 -0
- package/dist/db/schema/rag.d.ts +0 -171
- package/dist/db/schema/rag.d.ts.map +0 -1
- package/dist/db/schema/rag.js +0 -42
- package/dist/db/schema/rag.js.map +0 -1
- package/src/db/migrations/0000_sharp_night_nurse.sql +0 -52
- package/src/db/migrations/0001_hesitant_vapor.sql +0 -40
- package/src/db/migrations/0002_numerous_lady_vermin.sql +0 -235
- package/src/db/migrations/0003_mighty_jean_grey.sql +0 -37
- package/src/db/migrations/0004_cynical_grandmaster.sql +0 -2
- package/src/db/migrations/0005_careful_switch.sql +0 -8
- package/src/db/migrations/0006_tense_blue_marvel.sql +0 -16
- package/src/db/migrations/0007_next_squadron_sinister.sql +0 -1
- package/src/db/migrations/0008_powerful_scream.sql +0 -39
- package/src/db/migrations/0009_sad_ink.sql +0 -1
- package/src/db/migrations/0010_shocking_omega_flight.sql +0 -2
- package/src/db/migrations/0011_ambiguous_otto_octavius.sql +0 -151
- package/src/db/migrations/0011_hnsw_vector_index.sql +0 -17
- package/src/db/migrations/0012_user_profiles.sql +0 -30
- package/src/db/migrations/0013_trending_seasonal_columns.sql +0 -9
- package/src/db/migrations/0014_add_product_type_to_agents.sql +0 -6
- package/src/db/migrations/0015_new_v1_tables.sql +0 -149
- package/src/db/migrations/0016_document_types.sql +0 -30
- package/src/db/migrations/0017_document_metadata.sql +0 -2
- package/src/db/migrations/0018_identity_graph.sql +0 -200
- package/src/db/migrations/0019_db_driven_prompts.sql +0 -20
- package/src/db/migrations/0020_pending_extractions.sql +0 -35
- package/src/db/migrations/0021_rag_documents.sql +0 -39
- package/src/db/migrations/0022_user_quotas_usage_jsonb.sql +0 -70
- package/src/db/migrations/0023_user_facts_user_scoped_unique.sql +0 -17
- package/src/db/migrations/0024_user_memories_hnsw.sql +0 -23
- package/src/db/migrations/0025_audit_trigger_errcode.sql +0 -21
- package/src/db/migrations/0026_user_profile_snapshots_composite_pk.sql +0 -17
- package/src/db/migrations/0027_billing_settings_mnt_columns.sql +0 -54
- package/src/db/migrations/0028_trial_credits_normalized_email.sql +0 -37
- package/src/db/migrations/0029_usage_records_conversation_idx.sql +0 -13
- package/src/db/migrations/0030_pending_extractions_composite_idx.sql +0 -11
- package/src/db/migrations/0031_rag_documents_hnsw.sql +0 -16
- package/src/db/migrations/0032_rate_limit_unique_idx.sql +0 -16
- package/src/db/migrations/0033_pending_extractions_partial_idx.sql +0 -18
- package/src/db/migrations/0034_rate_limit_count.sql +0 -9
- package/src/db/migrations/0035_credit_reservations.sql +0 -24
- package/src/db/migrations/0036_executions_audit_jobs.sql +0 -96
- package/src/db/migrations/0037_rate_limit_minute_bucket.sql +0 -46
- package/src/db/migrations/0038_user_quotas_generic_usage.sql +0 -25
- package/src/db/migrations/0039_platform_admin_impersonation.sql +0 -27
- package/src/db/migrations/0040_ee_audit_chain.sql +0 -23
- package/src/db/migrations/meta/0001_snapshot.json +0 -631
- package/src/db/migrations/meta/0003_snapshot.json +0 -2488
- package/src/db/migrations/meta/0004_snapshot.json +0 -2500
- package/src/db/migrations/meta/0005_snapshot.json +0 -2548
- package/src/db/migrations/meta/0006_snapshot.json +0 -2650
- package/src/db/migrations/meta/0007_snapshot.json +0 -2657
- package/src/db/migrations/meta/0008_snapshot.json +0 -2719
- package/src/db/migrations/meta/0009_snapshot.json +0 -2726
- package/src/db/migrations/meta/0010_snapshot.json +0 -2739
- package/src/db/migrations/meta/0011_snapshot.json +0 -3886
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Button, Section, Text } from "@react-email/components";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { BaseLayout } from "./base-layout";
|
|
4
|
+
|
|
5
|
+
export interface WorkspaceInvitationEmailProps {
|
|
6
|
+
inviterName: string;
|
|
7
|
+
workspaceName: string;
|
|
8
|
+
role: string;
|
|
9
|
+
acceptUrl: string;
|
|
10
|
+
declineUrl: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function WorkspaceInvitationEmail({
|
|
14
|
+
inviterName,
|
|
15
|
+
workspaceName,
|
|
16
|
+
role,
|
|
17
|
+
acceptUrl,
|
|
18
|
+
declineUrl,
|
|
19
|
+
}: WorkspaceInvitationEmailProps) {
|
|
20
|
+
const text = {
|
|
21
|
+
preview: `${inviterName} invited you to join ${workspaceName}`,
|
|
22
|
+
heading: "You're invited!",
|
|
23
|
+
body: "has invited you to join the workspace",
|
|
24
|
+
as: "as a",
|
|
25
|
+
invitedYou: "",
|
|
26
|
+
acceptButton: "Accept Invitation",
|
|
27
|
+
declineButton: "Decline",
|
|
28
|
+
note: "This invitation expires in 7 days.",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<BaseLayout preview={text.preview}>
|
|
33
|
+
<Text style={headingStyle}>{text.heading}</Text>
|
|
34
|
+
<Text style={bodyTextStyle}>
|
|
35
|
+
<strong>{inviterName}</strong> {text.body}{" "}
|
|
36
|
+
<strong>‘{workspaceName}’</strong> {text.as}{" "}
|
|
37
|
+
<strong>{role}</strong>
|
|
38
|
+
{text.invitedYou ? ` ${text.invitedYou}` : ""}.
|
|
39
|
+
</Text>
|
|
40
|
+
<Section style={buttonGroupStyle}>
|
|
41
|
+
<Button href={acceptUrl} style={acceptButtonStyle}>
|
|
42
|
+
{text.acceptButton}
|
|
43
|
+
</Button>
|
|
44
|
+
<Button href={declineUrl} style={declineButtonStyle}>
|
|
45
|
+
{text.declineButton}
|
|
46
|
+
</Button>
|
|
47
|
+
</Section>
|
|
48
|
+
<Text style={noteStyle}>{text.note}</Text>
|
|
49
|
+
</BaseLayout>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const headingStyle: React.CSSProperties = {
|
|
54
|
+
color: "#18181b",
|
|
55
|
+
fontSize: "22px",
|
|
56
|
+
fontWeight: 700,
|
|
57
|
+
lineHeight: "30px",
|
|
58
|
+
margin: "0 0 16px",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const bodyTextStyle: React.CSSProperties = {
|
|
62
|
+
color: "#18181b",
|
|
63
|
+
fontSize: "15px",
|
|
64
|
+
lineHeight: "24px",
|
|
65
|
+
margin: "0 0 12px",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const buttonGroupStyle: React.CSSProperties = {
|
|
69
|
+
marginTop: "8px",
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const acceptButtonStyle: React.CSSProperties = {
|
|
73
|
+
backgroundColor: "#7c3aed",
|
|
74
|
+
borderRadius: "6px",
|
|
75
|
+
color: "#ffffff",
|
|
76
|
+
display: "inline-block",
|
|
77
|
+
fontSize: "15px",
|
|
78
|
+
fontWeight: 600,
|
|
79
|
+
lineHeight: "100%",
|
|
80
|
+
padding: "12px 24px",
|
|
81
|
+
textDecoration: "none",
|
|
82
|
+
textAlign: "center" as const,
|
|
83
|
+
marginRight: "12px",
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const declineButtonStyle: React.CSSProperties = {
|
|
87
|
+
backgroundColor: "transparent",
|
|
88
|
+
border: "1px solid #d4d4d8",
|
|
89
|
+
borderRadius: "6px",
|
|
90
|
+
color: "#71717a",
|
|
91
|
+
display: "inline-block",
|
|
92
|
+
fontSize: "15px",
|
|
93
|
+
fontWeight: 600,
|
|
94
|
+
lineHeight: "100%",
|
|
95
|
+
padding: "12px 24px",
|
|
96
|
+
textDecoration: "none",
|
|
97
|
+
textAlign: "center" as const,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const noteStyle: React.CSSProperties = {
|
|
101
|
+
color: "#71717a",
|
|
102
|
+
fontSize: "13px",
|
|
103
|
+
lineHeight: "20px",
|
|
104
|
+
marginTop: "20px",
|
|
105
|
+
};
|
package/src/env.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup validation of environment variables: a missing required variable
|
|
3
|
+
* throws immediately instead of when its feature is first used. Some are
|
|
4
|
+
* optional in development (STRIPE_*, RESEND_API_KEY).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
type EnvVar = {
|
|
8
|
+
name: string;
|
|
9
|
+
required: boolean;
|
|
10
|
+
description: string;
|
|
11
|
+
/** Optional minimum length — used for secret strength checks */
|
|
12
|
+
minLength?: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Only variables the framework itself reads. A model provider's key is
|
|
16
|
+
// absent on purpose: which provider a deployment calls is the product's
|
|
17
|
+
// choice, and its SDK reports a missing key on the first request.
|
|
18
|
+
const ENV_VARS: EnvVar[] = [
|
|
19
|
+
{
|
|
20
|
+
name: "DATABASE_URL",
|
|
21
|
+
required: true,
|
|
22
|
+
description: "PostgreSQL connection string",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "BETTER_AUTH_SECRET",
|
|
26
|
+
required: true,
|
|
27
|
+
description:
|
|
28
|
+
"Better-Auth session encryption key (AUTH_SECRET is accepted as a legacy alias)",
|
|
29
|
+
minLength: 32,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "NEXT_PUBLIC_APP_URL",
|
|
33
|
+
required: true,
|
|
34
|
+
description: "Application base URL for auth and redirects",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "STRIPE_SECRET_KEY",
|
|
38
|
+
required: false,
|
|
39
|
+
description: "Stripe API key (billing features)",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "STRIPE_WEBHOOK_SECRET",
|
|
43
|
+
required: false,
|
|
44
|
+
description: "Stripe webhook signature secret",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "RESEND_API_KEY",
|
|
48
|
+
required: false,
|
|
49
|
+
description: "Resend API key (email features)",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "LOOPS_API_KEY",
|
|
53
|
+
required: false,
|
|
54
|
+
description:
|
|
55
|
+
"Loops API key (email features; templates mapped via LOOPS_TRANSACTIONAL_ID_*)",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "EMAIL_PROVIDER",
|
|
59
|
+
required: false,
|
|
60
|
+
description: "Explicit email provider selection (resend | loops | console)",
|
|
61
|
+
},
|
|
62
|
+
// Cron endpoints gate on a Bearer header equal to CRON_SECRET. Optional
|
|
63
|
+
// in development; production should set at least 32 characters.
|
|
64
|
+
{
|
|
65
|
+
name: "CRON_SECRET",
|
|
66
|
+
required: false,
|
|
67
|
+
description: "Shared secret for /api/cron/* Bearer auth",
|
|
68
|
+
minLength: 32,
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
export function validateEnv(): {
|
|
73
|
+
valid: boolean;
|
|
74
|
+
errors: string[];
|
|
75
|
+
warnings: string[];
|
|
76
|
+
} {
|
|
77
|
+
const errors: string[] = [];
|
|
78
|
+
const warnings: string[] = [];
|
|
79
|
+
|
|
80
|
+
for (const envVar of ENV_VARS) {
|
|
81
|
+
let value = process.env[envVar.name];
|
|
82
|
+
// Better-Auth reads BETTER_AUTH_SECRET then AUTH_SECRET; the CLI, the
|
|
83
|
+
// scaffold and this validator use the former.
|
|
84
|
+
if (
|
|
85
|
+
envVar.name === "BETTER_AUTH_SECRET" &&
|
|
86
|
+
!value &&
|
|
87
|
+
process.env.AUTH_SECRET
|
|
88
|
+
) {
|
|
89
|
+
value = process.env.AUTH_SECRET;
|
|
90
|
+
warnings.push(
|
|
91
|
+
"AUTH_SECRET is set but BETTER_AUTH_SECRET is not — rename it; AUTH_SECRET is a legacy alias"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (!value || value.trim() === "") {
|
|
95
|
+
if (envVar.required) {
|
|
96
|
+
errors.push(
|
|
97
|
+
`Missing required env var: ${envVar.name} — ${envVar.description}`
|
|
98
|
+
);
|
|
99
|
+
} else {
|
|
100
|
+
warnings.push(
|
|
101
|
+
`Missing optional env var: ${envVar.name} — ${envVar.description}`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (envVar.minLength && value.length < envVar.minLength) {
|
|
107
|
+
const msg = `${envVar.name} is shorter than ${envVar.minLength} chars — too weak for ${envVar.description}`;
|
|
108
|
+
if (envVar.required) {
|
|
109
|
+
errors.push(msg);
|
|
110
|
+
} else {
|
|
111
|
+
warnings.push(msg);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Resend rejects a send without a sender on a verified domain, and the
|
|
117
|
+
// framework has no domain of its own to fall back on. Loops takes the
|
|
118
|
+
// sender from each template, so only Resend is checked.
|
|
119
|
+
const emailProvider = process.env.EMAIL_PROVIDER?.toLowerCase();
|
|
120
|
+
const sendsThroughResend =
|
|
121
|
+
Boolean(process.env.RESEND_API_KEY?.trim()) &&
|
|
122
|
+
emailProvider !== "loops" &&
|
|
123
|
+
emailProvider !== "console";
|
|
124
|
+
if (sendsThroughResend && !process.env.EMAIL_FROM?.trim()) {
|
|
125
|
+
warnings.push(
|
|
126
|
+
'RESEND_API_KEY is set but EMAIL_FROM is not — every email fails until EMAIL_FROM names a sender on a domain verified with Resend, e.g. "Acme <noreply@acme.com>"'
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Production safety checks
|
|
131
|
+
if (process.env.NODE_ENV === "production") {
|
|
132
|
+
const appUrl = process.env.NEXT_PUBLIC_APP_URL?.trim();
|
|
133
|
+
if (appUrl && !appUrl.startsWith("https://")) {
|
|
134
|
+
warnings.push(
|
|
135
|
+
`NEXT_PUBLIC_APP_URL is ${appUrl}, not an https URL — auth callbacks, email links and secure cookies are built from it`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (!process.env.RESEND_API_KEY && !process.env.LOOPS_API_KEY) {
|
|
139
|
+
warnings.push(
|
|
140
|
+
"No email provider (RESEND_API_KEY or LOOPS_API_KEY) — sign-ups are not email-verified and emails only reach the server console"
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
if (process.env.STRIPE_SECRET_KEY?.startsWith("sk_test_")) {
|
|
144
|
+
warnings.push(
|
|
145
|
+
"STRIPE_SECRET_KEY is a test key in production environment"
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
if (!process.env.CRON_SECRET || process.env.CRON_SECRET.length < 32) {
|
|
149
|
+
// A warning, not an error: the framework ships no cron route of its
|
|
150
|
+
// own, and the maintenance route refuses to serve without it.
|
|
151
|
+
warnings.push(
|
|
152
|
+
"CRON_SECRET unset or shorter than 32 chars — required by any /api/cron/* route you mount"
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Call during app initialization. Throws on missing required variables;
|
|
162
|
+
* logs warnings for optional ones.
|
|
163
|
+
*/
|
|
164
|
+
export function assertEnv(): void {
|
|
165
|
+
const { valid, errors, warnings } = validateEnv();
|
|
166
|
+
|
|
167
|
+
for (const warning of warnings) {
|
|
168
|
+
console.warn(`[Env] ${warning}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!valid) {
|
|
172
|
+
console.error("[Env] Missing required environment variables:");
|
|
173
|
+
for (const error of errors) {
|
|
174
|
+
console.error(` - ${error}`);
|
|
175
|
+
}
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Missing ${errors.length} required environment variable(s). See logs above.`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes `user_memory_audit` rows. Core may not import
|
|
3
|
+
* `@intelligo-dev/audit` (only audit -> core is allowed), so the write lives
|
|
4
|
+
* here and audit exports only the event contract. Internal to identity; not
|
|
5
|
+
* re-exported.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { db } from "../db";
|
|
9
|
+
import { userMemoryAudit } from "../db/schema";
|
|
10
|
+
import type {
|
|
11
|
+
AuditTargetKind,
|
|
12
|
+
AuditAction,
|
|
13
|
+
AuditActorKind,
|
|
14
|
+
UserMemoryAuditRow,
|
|
15
|
+
} from "../db/schema";
|
|
16
|
+
import { IdentityServiceError } from "./errors";
|
|
17
|
+
|
|
18
|
+
export type RecordMemoryAuditInput = {
|
|
19
|
+
userId: string;
|
|
20
|
+
workspaceId: string;
|
|
21
|
+
targetKind: AuditTargetKind;
|
|
22
|
+
targetId: string;
|
|
23
|
+
action: AuditAction;
|
|
24
|
+
actorKind: AuditActorKind;
|
|
25
|
+
actorId?: string;
|
|
26
|
+
beforeValue?: unknown;
|
|
27
|
+
afterValue?: unknown;
|
|
28
|
+
reason?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* `writer` is the transaction of the mutation being audited, so the
|
|
33
|
+
* change and its record commit or fail together.
|
|
34
|
+
*/
|
|
35
|
+
export async function recordMemoryAudit(
|
|
36
|
+
input: RecordMemoryAuditInput,
|
|
37
|
+
writer: Pick<typeof db, "insert"> = db
|
|
38
|
+
): Promise<UserMemoryAuditRow> {
|
|
39
|
+
const [row] = await writer
|
|
40
|
+
.insert(userMemoryAudit)
|
|
41
|
+
.values({
|
|
42
|
+
id: crypto.randomUUID(),
|
|
43
|
+
userId: input.userId,
|
|
44
|
+
workspaceId: input.workspaceId,
|
|
45
|
+
targetKind: input.targetKind,
|
|
46
|
+
targetId: input.targetId,
|
|
47
|
+
action: input.action,
|
|
48
|
+
actorKind: input.actorKind,
|
|
49
|
+
actorId: input.actorId,
|
|
50
|
+
beforeValue: input.beforeValue,
|
|
51
|
+
afterValue: input.afterValue,
|
|
52
|
+
reason: input.reason,
|
|
53
|
+
createdAt: new Date(),
|
|
54
|
+
})
|
|
55
|
+
.returning();
|
|
56
|
+
|
|
57
|
+
if (!row) {
|
|
58
|
+
throw new IdentityServiceError(
|
|
59
|
+
"database_error",
|
|
60
|
+
"Failed to record memory audit event"
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return row;
|
|
65
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by the identity service for every failure it recognizes. Shaping
|
|
3
|
+
* it into a transport envelope is the caller's job.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* - `not_found` — no fact exists at the given id within the actor's
|
|
8
|
+
* workspace/user scope. Covers both "no such fact" and "a fact that
|
|
9
|
+
* belongs to a different user in the same workspace" — deliberately
|
|
10
|
+
* indistinguishable, so an id never reveals whose data exists behind it.
|
|
11
|
+
* - `invalid_input` — a caller-supplied argument failed a basic
|
|
12
|
+
* invariant (e.g. an empty fact id).
|
|
13
|
+
* - `database_error` — the underlying insert did not return the row it
|
|
14
|
+
* was expected to.
|
|
15
|
+
*/
|
|
16
|
+
export type IdentityServiceErrorCode =
|
|
17
|
+
"not_found" | "invalid_input" | "database_error";
|
|
18
|
+
|
|
19
|
+
export class IdentityServiceError extends Error {
|
|
20
|
+
readonly code: IdentityServiceErrorCode;
|
|
21
|
+
// The ES2020 target predates `Error.cause`; declared so `err.cause`
|
|
22
|
+
// type-checks for callers.
|
|
23
|
+
readonly cause?: unknown;
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
code: IdentityServiceErrorCode,
|
|
27
|
+
message: string,
|
|
28
|
+
options?: { cause?: unknown }
|
|
29
|
+
) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "IdentityServiceError";
|
|
32
|
+
this.code = code;
|
|
33
|
+
if (options?.cause !== undefined) {
|
|
34
|
+
(this as { cause?: unknown }).cause = options.cause;
|
|
35
|
+
}
|
|
36
|
+
Object.setPrototypeOf(this, IdentityServiceError.prototype);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isIdentityServiceError(
|
|
41
|
+
error: unknown
|
|
42
|
+
): error is IdentityServiceError {
|
|
43
|
+
return error instanceof IdentityServiceError;
|
|
44
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privacy-facing reads and mutations over the user identity graph: fact
|
|
3
|
+
* listing and deletion, full-identity export, and the memory-audit trail.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
listFacts,
|
|
8
|
+
deleteFact,
|
|
9
|
+
exportIdentity,
|
|
10
|
+
getAuditTrail,
|
|
11
|
+
} from "./service";
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
IdentityServiceError,
|
|
15
|
+
isIdentityServiceError,
|
|
16
|
+
type IdentityServiceErrorCode,
|
|
17
|
+
} from "./errors";
|
|
18
|
+
|
|
19
|
+
export type {
|
|
20
|
+
IdentityActor,
|
|
21
|
+
IdentityExport,
|
|
22
|
+
UserFact,
|
|
23
|
+
UserMemory,
|
|
24
|
+
UserProfileSnapshot,
|
|
25
|
+
UserMemoryAuditRow,
|
|
26
|
+
} from "./types";
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-only reads and mutations over the user identity graph: fact
|
|
3
|
+
* listing and deletion, a full data export, and the memory-audit trail.
|
|
4
|
+
*
|
|
5
|
+
* `deleteFact` does not touch the cached profile snapshot; profile synthesis
|
|
6
|
+
* is the product's AI code, so a caller that owns it re-triggers it.
|
|
7
|
+
*
|
|
8
|
+
* Callers pass a resolved actor (workspaceId, userId); core cannot depend on
|
|
9
|
+
* `@intelligo-dev/auth`. Every query filters by both ids. Every mutation
|
|
10
|
+
* writes a `user_memory_audit` row. Failures throw `IdentityServiceError`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
14
|
+
import { db } from "../db";
|
|
15
|
+
import {
|
|
16
|
+
userFacts,
|
|
17
|
+
userMemories,
|
|
18
|
+
userProfileSnapshots,
|
|
19
|
+
userMemoryAudit,
|
|
20
|
+
} from "../db/schema";
|
|
21
|
+
import type { UserFact, UserMemoryAuditRow } from "../db/schema";
|
|
22
|
+
import { recordMemoryAudit } from "./audit";
|
|
23
|
+
import { IdentityServiceError } from "./errors";
|
|
24
|
+
import type { IdentityActor, IdentityExport } from "./types";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns the fact if the actor owns it. Throws
|
|
28
|
+
* IdentityServiceError("not_found") otherwise — another user's fact is
|
|
29
|
+
* indistinguishable from a missing one.
|
|
30
|
+
*/
|
|
31
|
+
async function verifyFact(
|
|
32
|
+
actor: IdentityActor,
|
|
33
|
+
factId: string
|
|
34
|
+
): Promise<UserFact> {
|
|
35
|
+
const [fact] = await db
|
|
36
|
+
.select()
|
|
37
|
+
.from(userFacts)
|
|
38
|
+
.where(eq(userFacts.id, factId))
|
|
39
|
+
.limit(1);
|
|
40
|
+
|
|
41
|
+
if (
|
|
42
|
+
!fact ||
|
|
43
|
+
fact.userId !== actor.userId ||
|
|
44
|
+
fact.workspaceId !== actor.workspaceId
|
|
45
|
+
) {
|
|
46
|
+
throw new IdentityServiceError("not_found", "Fact not found");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return fact;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** List the actor's facts, most important and most confident first. */
|
|
53
|
+
export async function listFacts(actor: IdentityActor): Promise<UserFact[]> {
|
|
54
|
+
return db
|
|
55
|
+
.select()
|
|
56
|
+
.from(userFacts)
|
|
57
|
+
.where(
|
|
58
|
+
and(
|
|
59
|
+
eq(userFacts.userId, actor.userId),
|
|
60
|
+
eq(userFacts.workspaceId, actor.workspaceId)
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
.orderBy(desc(userFacts.importance), desc(userFacts.confidence));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const MAX_AUDIT_LIMIT = 200;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Read the actor's memory-audit trail, most recent first. Optionally
|
|
70
|
+
* scoped to a single target (e.g. one fact's history).
|
|
71
|
+
*/
|
|
72
|
+
export async function getAuditTrail(
|
|
73
|
+
actor: IdentityActor,
|
|
74
|
+
options?: { limit?: number; targetId?: string }
|
|
75
|
+
): Promise<UserMemoryAuditRow[]> {
|
|
76
|
+
const limit = Math.min(
|
|
77
|
+
Math.max(1, options?.limit ?? MAX_AUDIT_LIMIT),
|
|
78
|
+
MAX_AUDIT_LIMIT
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const baseClause = and(
|
|
82
|
+
eq(userMemoryAudit.userId, actor.userId),
|
|
83
|
+
eq(userMemoryAudit.workspaceId, actor.workspaceId)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return db
|
|
87
|
+
.select()
|
|
88
|
+
.from(userMemoryAudit)
|
|
89
|
+
.where(
|
|
90
|
+
options?.targetId
|
|
91
|
+
? and(baseClause, eq(userMemoryAudit.targetId, options.targetId))
|
|
92
|
+
: baseClause
|
|
93
|
+
)
|
|
94
|
+
.orderBy(desc(userMemoryAudit.createdAt))
|
|
95
|
+
.limit(limit);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Delete a fact and record the deletion in the audit trail. Throws
|
|
100
|
+
* `invalid_input` for an empty id and `not_found` for anything outside
|
|
101
|
+
* the actor's scope. Does not re-trigger profile synthesis.
|
|
102
|
+
*/
|
|
103
|
+
export async function deleteFact(
|
|
104
|
+
actor: IdentityActor,
|
|
105
|
+
factId: string
|
|
106
|
+
): Promise<void> {
|
|
107
|
+
if (!factId || factId.trim().length === 0) {
|
|
108
|
+
throw new IdentityServiceError("invalid_input", "factId is required");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const existing = await verifyFact(actor, factId);
|
|
112
|
+
|
|
113
|
+
await db.transaction(async (tx) => {
|
|
114
|
+
await tx.delete(userFacts).where(eq(userFacts.id, factId));
|
|
115
|
+
await recordMemoryAudit(
|
|
116
|
+
{
|
|
117
|
+
userId: actor.userId,
|
|
118
|
+
workspaceId: actor.workspaceId,
|
|
119
|
+
targetKind: "fact",
|
|
120
|
+
targetId: factId,
|
|
121
|
+
action: "delete",
|
|
122
|
+
actorKind: "user",
|
|
123
|
+
actorId: actor.userId,
|
|
124
|
+
beforeValue: existing,
|
|
125
|
+
reason: "user requested deletion",
|
|
126
|
+
},
|
|
127
|
+
tx
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The actor's full identity graph — facts, memories, latest profile
|
|
134
|
+
* snapshot and audit trail — for a "download my data" flow. Records its own
|
|
135
|
+
* audit row (action "export").
|
|
136
|
+
*/
|
|
137
|
+
export async function exportIdentity(
|
|
138
|
+
actor: IdentityActor
|
|
139
|
+
): Promise<IdentityExport> {
|
|
140
|
+
// Recorded before the reads so the export's own audit row is part of
|
|
141
|
+
// the export — the trail a user downloads should show that download.
|
|
142
|
+
await recordMemoryAudit({
|
|
143
|
+
userId: actor.userId,
|
|
144
|
+
workspaceId: actor.workspaceId,
|
|
145
|
+
targetKind: "snapshot",
|
|
146
|
+
targetId: actor.userId,
|
|
147
|
+
action: "export",
|
|
148
|
+
actorKind: "user",
|
|
149
|
+
actorId: actor.userId,
|
|
150
|
+
reason: "user requested data export",
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const [facts, memories, snapshotRows, audit] = await Promise.all([
|
|
154
|
+
db
|
|
155
|
+
.select()
|
|
156
|
+
.from(userFacts)
|
|
157
|
+
.where(
|
|
158
|
+
and(
|
|
159
|
+
eq(userFacts.userId, actor.userId),
|
|
160
|
+
eq(userFacts.workspaceId, actor.workspaceId)
|
|
161
|
+
)
|
|
162
|
+
),
|
|
163
|
+
db
|
|
164
|
+
.select()
|
|
165
|
+
.from(userMemories)
|
|
166
|
+
.where(
|
|
167
|
+
and(
|
|
168
|
+
eq(userMemories.userId, actor.userId),
|
|
169
|
+
eq(userMemories.workspaceId, actor.workspaceId)
|
|
170
|
+
)
|
|
171
|
+
),
|
|
172
|
+
db
|
|
173
|
+
.select()
|
|
174
|
+
.from(userProfileSnapshots)
|
|
175
|
+
.where(
|
|
176
|
+
and(
|
|
177
|
+
eq(userProfileSnapshots.userId, actor.userId),
|
|
178
|
+
eq(userProfileSnapshots.workspaceId, actor.workspaceId)
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
.limit(1),
|
|
182
|
+
db
|
|
183
|
+
.select()
|
|
184
|
+
.from(userMemoryAudit)
|
|
185
|
+
.where(
|
|
186
|
+
and(
|
|
187
|
+
eq(userMemoryAudit.userId, actor.userId),
|
|
188
|
+
eq(userMemoryAudit.workspaceId, actor.workspaceId)
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
.orderBy(desc(userMemoryAudit.createdAt)),
|
|
192
|
+
]);
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
exportedAt: new Date().toISOString(),
|
|
196
|
+
user: { id: actor.userId, workspaceId: actor.workspaceId },
|
|
197
|
+
facts,
|
|
198
|
+
memories,
|
|
199
|
+
snapshot: snapshotRows[0] ?? null,
|
|
200
|
+
audit,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
UserFact,
|
|
3
|
+
UserMemory,
|
|
4
|
+
UserProfileSnapshot,
|
|
5
|
+
UserMemoryAuditRow,
|
|
6
|
+
} from "../db/schema";
|
|
7
|
+
|
|
8
|
+
export type { UserFact, UserMemory, UserProfileSnapshot, UserMemoryAuditRow };
|
|
9
|
+
|
|
10
|
+
/** Resolved actor identity — every query is scoped to this pair. */
|
|
11
|
+
export type IdentityActor = {
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
userId: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Full identity dump for a GDPR-style "download my data" flow: every
|
|
18
|
+
* fact and memory the actor owns, their latest synthesized profile
|
|
19
|
+
* snapshot (if one exists), and their complete memory-audit trail.
|
|
20
|
+
*/
|
|
21
|
+
export type IdentityExport = {
|
|
22
|
+
exportedAt: string;
|
|
23
|
+
user: { id: string; workspaceId: string };
|
|
24
|
+
facts: UserFact[];
|
|
25
|
+
memories: UserMemory[];
|
|
26
|
+
snapshot: UserProfileSnapshot | null;
|
|
27
|
+
audit: UserMemoryAuditRow[];
|
|
28
|
+
};
|
package/src/index.ts
ADDED