@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,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Service — Server-only
|
|
3
|
+
*
|
|
4
|
+
* Privacy-facing reads and mutations over the user identity graph:
|
|
5
|
+
* fact listing/deletion, a full-identity data export, and the
|
|
6
|
+
* memory-audit trail that records every mutation to a user's facts,
|
|
7
|
+
* memories, and synthesized profile snapshot. Ported from Ignite's
|
|
8
|
+
* `actions/identity.ts` (ADR-0008/ADR-0009 precedent — see
|
|
9
|
+
* `../documents/service.ts` and `../conversations/service.ts` for the
|
|
10
|
+
* same move): the tables (`user_facts`, `user_memories`,
|
|
11
|
+
* `user_profile_snapshots`, `user_memory_audit`) always lived in
|
|
12
|
+
* `@intelligo-dev/core`'s schema (`../db/schema/identity.ts`, documented
|
|
13
|
+
* there as "a platform-level memory primitive — separate from any
|
|
14
|
+
* single product"); only the service layer sat in the product
|
|
15
|
+
* application.
|
|
16
|
+
*
|
|
17
|
+
* What did NOT come with it (stays product/agents-side):
|
|
18
|
+
* - `updateMyFactImportance` and the `synthesizeProfile()` re-trigger
|
|
19
|
+
* Ignite's `deleteMyFact` ran after deleting — synthesis is
|
|
20
|
+
* `@intelligo-dev/agents`' concern (deprecated, dissolving under
|
|
21
|
+
* ADR-0008), and this package cannot depend on it. `deleteFact`
|
|
22
|
+
* below does not touch the cached snapshot; a caller that also
|
|
23
|
+
* owns a synthesis engine re-triggers it after calling this.
|
|
24
|
+
*
|
|
25
|
+
* Callers pass a resolved actor (workspaceId, userId) rather than this
|
|
26
|
+
* module resolving one itself — `@intelligo-dev/core` cannot depend on
|
|
27
|
+
* `@intelligo-dev/auth` (see tests/architecture/dependency-direction.test.ts).
|
|
28
|
+
* Every query filters by workspaceId AND userId internally; the actor
|
|
29
|
+
* is never trusted to have done that itself.
|
|
30
|
+
*
|
|
31
|
+
* Every mutation writes a `user_memory_audit` row via the internal
|
|
32
|
+
* `recordMemoryAudit` (./audit.ts). See that file's doc comment for
|
|
33
|
+
* why the writer lives here rather than in `@intelligo-dev/audit`, which
|
|
34
|
+
* is where ADR-0008 names its destination — the allowlist only grants
|
|
35
|
+
* audit -> core, never core -> audit
|
|
36
|
+
* (tests/architecture/dependency-direction.test.ts), so
|
|
37
|
+
* `@intelligo-dev/audit` exports the event *contract* only.
|
|
38
|
+
*
|
|
39
|
+
* Failure is reported by throwing `IdentityServiceError` rather than
|
|
40
|
+
* returning a `{ success, error }` envelope — see ./errors.ts.
|
|
41
|
+
*
|
|
42
|
+
* This module is SERVER-ONLY. Do not import from client components.
|
|
43
|
+
*/
|
|
44
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
45
|
+
import { db } from "../db";
|
|
46
|
+
import { userFacts, userMemories, userProfileSnapshots, userMemoryAudit, } from "../db/schema";
|
|
47
|
+
import { recordMemoryAudit } from "./audit";
|
|
48
|
+
import { IdentityServiceError } from "./errors";
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Internal helpers
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
/**
|
|
53
|
+
* Verify fact ownership and return the row. Throws
|
|
54
|
+
* IdentityServiceError("not_found") for both a missing fact and one
|
|
55
|
+
* owned by a different user/workspace — a fact belonging to someone
|
|
56
|
+
* else should be indistinguishable from one that doesn't exist at all
|
|
57
|
+
* (same reasoning as `../conversations/service.ts`'s
|
|
58
|
+
* `verifyConversation`).
|
|
59
|
+
*/
|
|
60
|
+
async function verifyFact(actor, factId) {
|
|
61
|
+
const [fact] = await db
|
|
62
|
+
.select()
|
|
63
|
+
.from(userFacts)
|
|
64
|
+
.where(eq(userFacts.id, factId))
|
|
65
|
+
.limit(1);
|
|
66
|
+
if (!fact ||
|
|
67
|
+
fact.userId !== actor.userId ||
|
|
68
|
+
fact.workspaceId !== actor.workspaceId) {
|
|
69
|
+
throw new IdentityServiceError("not_found", "Fact not found");
|
|
70
|
+
}
|
|
71
|
+
return fact;
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Reads
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
/** List the actor's facts, most important and most confident first. */
|
|
77
|
+
export async function listFacts(actor) {
|
|
78
|
+
return db
|
|
79
|
+
.select()
|
|
80
|
+
.from(userFacts)
|
|
81
|
+
.where(and(eq(userFacts.userId, actor.userId), eq(userFacts.workspaceId, actor.workspaceId)))
|
|
82
|
+
.orderBy(desc(userFacts.importance), desc(userFacts.confidence));
|
|
83
|
+
}
|
|
84
|
+
const MAX_AUDIT_LIMIT = 200;
|
|
85
|
+
/**
|
|
86
|
+
* Read the actor's memory-audit trail, most recent first. Optionally
|
|
87
|
+
* scoped to a single target (e.g. one fact's history).
|
|
88
|
+
*/
|
|
89
|
+
export async function getAuditTrail(actor, options) {
|
|
90
|
+
const limit = Math.min(Math.max(1, options?.limit ?? MAX_AUDIT_LIMIT), MAX_AUDIT_LIMIT);
|
|
91
|
+
const baseClause = and(eq(userMemoryAudit.userId, actor.userId), eq(userMemoryAudit.workspaceId, actor.workspaceId));
|
|
92
|
+
return db
|
|
93
|
+
.select()
|
|
94
|
+
.from(userMemoryAudit)
|
|
95
|
+
.where(options?.targetId
|
|
96
|
+
? and(baseClause, eq(userMemoryAudit.targetId, options.targetId))
|
|
97
|
+
: baseClause)
|
|
98
|
+
.orderBy(desc(userMemoryAudit.createdAt))
|
|
99
|
+
.limit(limit);
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Mutations
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
/**
|
|
105
|
+
* Delete a fact and record the deletion in the audit trail. Throws
|
|
106
|
+
* `invalid_input` for an empty id and `not_found` for anything outside
|
|
107
|
+
* the actor's scope (see `verifyFact`). Does NOT re-trigger profile
|
|
108
|
+
* synthesis — see the module doc comment.
|
|
109
|
+
*/
|
|
110
|
+
export async function deleteFact(actor, factId) {
|
|
111
|
+
if (!factId || factId.trim().length === 0) {
|
|
112
|
+
throw new IdentityServiceError("invalid_input", "factId is required");
|
|
113
|
+
}
|
|
114
|
+
const existing = await verifyFact(actor, factId);
|
|
115
|
+
await db.delete(userFacts).where(eq(userFacts.id, factId));
|
|
116
|
+
await recordMemoryAudit({
|
|
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
|
+
}
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Export — full identity dump for GDPR / "download my data"
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
/**
|
|
132
|
+
* Aggregate the actor's full identity graph — facts, memories, latest
|
|
133
|
+
* profile snapshot, and full audit trail — for a data-export flow.
|
|
134
|
+
* Records its own audit row (action "export"): the export operation
|
|
135
|
+
* audits itself, same as the ported Ignite implementation.
|
|
136
|
+
*/
|
|
137
|
+
export async function exportIdentity(actor) {
|
|
138
|
+
// Recorded before the reads so the export's own audit row is part of
|
|
139
|
+
// the export — the trail a user downloads should show that download.
|
|
140
|
+
await recordMemoryAudit({
|
|
141
|
+
userId: actor.userId,
|
|
142
|
+
workspaceId: actor.workspaceId,
|
|
143
|
+
targetKind: "snapshot",
|
|
144
|
+
targetId: actor.userId,
|
|
145
|
+
action: "export",
|
|
146
|
+
actorKind: "user",
|
|
147
|
+
actorId: actor.userId,
|
|
148
|
+
reason: "user requested data export",
|
|
149
|
+
});
|
|
150
|
+
const [facts, memories, snapshotRows, audit] = await Promise.all([
|
|
151
|
+
db
|
|
152
|
+
.select()
|
|
153
|
+
.from(userFacts)
|
|
154
|
+
.where(and(eq(userFacts.userId, actor.userId), eq(userFacts.workspaceId, actor.workspaceId))),
|
|
155
|
+
db
|
|
156
|
+
.select()
|
|
157
|
+
.from(userMemories)
|
|
158
|
+
.where(and(eq(userMemories.userId, actor.userId), eq(userMemories.workspaceId, actor.workspaceId))),
|
|
159
|
+
db
|
|
160
|
+
.select()
|
|
161
|
+
.from(userProfileSnapshots)
|
|
162
|
+
.where(and(eq(userProfileSnapshots.userId, actor.userId), eq(userProfileSnapshots.workspaceId, actor.workspaceId)))
|
|
163
|
+
.limit(1),
|
|
164
|
+
db
|
|
165
|
+
.select()
|
|
166
|
+
.from(userMemoryAudit)
|
|
167
|
+
.where(and(eq(userMemoryAudit.userId, actor.userId), eq(userMemoryAudit.workspaceId, actor.workspaceId)))
|
|
168
|
+
.orderBy(desc(userMemoryAudit.createdAt)),
|
|
169
|
+
]);
|
|
170
|
+
return {
|
|
171
|
+
exportedAt: new Date().toISOString(),
|
|
172
|
+
user: { id: actor.userId, workspaceId: actor.workspaceId },
|
|
173
|
+
facts,
|
|
174
|
+
memories,
|
|
175
|
+
snapshot: snapshotRows[0] ?? null,
|
|
176
|
+
audit,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/identity/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the identity service.
|
|
3
|
+
*/
|
|
4
|
+
import type { UserFact, UserMemory, UserProfileSnapshot, UserMemoryAuditRow } from "../db/schema";
|
|
5
|
+
export type { UserFact, UserMemory, UserProfileSnapshot, UserMemoryAuditRow };
|
|
6
|
+
/** Resolved actor identity — every query is scoped to this pair. */
|
|
7
|
+
export type IdentityActor = {
|
|
8
|
+
workspaceId: string;
|
|
9
|
+
userId: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Full identity dump for a GDPR-style "download my data" flow: every
|
|
13
|
+
* fact and memory the actor owns, their latest synthesized profile
|
|
14
|
+
* snapshot (if one exists), and their complete memory-audit trail.
|
|
15
|
+
*/
|
|
16
|
+
export type IdentityExport = {
|
|
17
|
+
exportedAt: string;
|
|
18
|
+
user: {
|
|
19
|
+
id: string;
|
|
20
|
+
workspaceId: string;
|
|
21
|
+
};
|
|
22
|
+
facts: UserFact[];
|
|
23
|
+
memories: UserMemory[];
|
|
24
|
+
snapshot: UserProfileSnapshot | null;
|
|
25
|
+
audit: UserMemoryAuditRow[];
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/identity/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;AAE9E,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/identity/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC;AAG/B,cAAc,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const version = "0.0.0";
|
|
2
|
+
// Re-export database client
|
|
3
|
+
export * from "./db";
|
|
4
|
+
// Email module -- use subpath import: @intelligo-dev/core/email
|
|
5
|
+
// Notifications module -- use subpath import: @intelligo-dev/core/notifications
|
|
6
|
+
// Conversations module -- use subpath import: @intelligo-dev/core/conversations
|
|
7
|
+
// Documents module -- use subpath import: @intelligo-dev/core/documents
|
|
8
|
+
// Identity module -- use subpath import: @intelligo-dev/core/identity
|
|
9
|
+
// Logger -- use subpath import: @intelligo-dev/core/logger
|
|
10
|
+
// Env -- use subpath import: @intelligo-dev/core/env
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,4BAA4B;AAC5B,cAAc,MAAM,CAAC;AAErB,gEAAgE;AAChE,gFAAgF;AAChF,gFAAgF;AAChF,wEAAwE;AACxE,sEAAsE;AACtE,2DAA2D;AAC3D,qDAAqD"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Logger with PII Redaction (Pino-backed)
|
|
3
|
+
*
|
|
4
|
+
* A structured logger that:
|
|
5
|
+
* - Uses pino for high-performance JSON logging in production
|
|
6
|
+
* - Redacts PII in production (emails, workspace IDs, UUIDs)
|
|
7
|
+
* - Passes through unredacted in development for debugging
|
|
8
|
+
* - Maintains the same API as the previous custom logger
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { createLogger } from "@intelligo-dev/core/logger";
|
|
13
|
+
* const log = createLogger("MyModule");
|
|
14
|
+
* log.info("User created", { email: "user@example.com" });
|
|
15
|
+
* // Production: {"level":30,"module":"MyModule","msg":"User created","email":"u***@example.com"}
|
|
16
|
+
* // Development: {"level":30,"module":"MyModule","msg":"User created","email":"user@example.com"}
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import pino from "pino";
|
|
20
|
+
/**
|
|
21
|
+
* Field name fragments whose values are always replaced with [REDACTED]
|
|
22
|
+
* regardless of environment. These cover credentials and secrets — never
|
|
23
|
+
* appropriate to log even in development. Email/id redaction is a
|
|
24
|
+
* separate concern (production-only PII protection).
|
|
25
|
+
*
|
|
26
|
+
* Exported so a consumer's Sentry PII scrubber
|
|
27
|
+
* shares the same field list — a secret name added here is stripped
|
|
28
|
+
* from both the log stream and the Sentry event in one move.
|
|
29
|
+
*/
|
|
30
|
+
export declare const CREDENTIAL_KEY_FRAGMENTS: readonly ["password", "passwd", "secret", "token", "apikey", "api_key", "authorization", "auth_header", "cookie", "session_token", "session_secret", "credit_card", "creditcard", "card_number", "cvv"];
|
|
31
|
+
/** True when `key` contains any credential fragment (case-insensitive substring). */
|
|
32
|
+
export declare function isCredentialKey(key: string): boolean;
|
|
33
|
+
declare class Logger {
|
|
34
|
+
private pino;
|
|
35
|
+
constructor(context: string);
|
|
36
|
+
info(message: string, data?: Record<string, unknown>): void;
|
|
37
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
38
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
39
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
40
|
+
}
|
|
41
|
+
export declare function createLogger(context: string): Logger;
|
|
42
|
+
/**
|
|
43
|
+
* Create a logger that writes to a custom pino destination.
|
|
44
|
+
* Used for testing — allows capturing log output in a writable stream.
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
export declare function _createLoggerWithStream(context: string, stream: pino.DestinationStream): Logger;
|
|
48
|
+
export { Logger };
|
|
49
|
+
export declare const logger: Logger;
|
|
50
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AA0BxB;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,yMAgB3B,CAAC;AAEX,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGpD;AAiDD,cAAM,MAAM;IACV,OAAO,CAAC,IAAI,CAAc;gBAEd,OAAO,EAAE,MAAM;IAI3B,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAQpD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAQpD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAQrD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOtD;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,IAAI,CAAC,iBAAiB,GAC7B,MAAM,CAiBR;AAED,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,eAAO,MAAM,MAAM,QAAsB,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Logger with PII Redaction (Pino-backed)
|
|
3
|
+
*
|
|
4
|
+
* A structured logger that:
|
|
5
|
+
* - Uses pino for high-performance JSON logging in production
|
|
6
|
+
* - Redacts PII in production (emails, workspace IDs, UUIDs)
|
|
7
|
+
* - Passes through unredacted in development for debugging
|
|
8
|
+
* - Maintains the same API as the previous custom logger
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { createLogger } from "@intelligo-dev/core/logger";
|
|
13
|
+
* const log = createLogger("MyModule");
|
|
14
|
+
* log.info("User created", { email: "user@example.com" });
|
|
15
|
+
* // Production: {"level":30,"module":"MyModule","msg":"User created","email":"u***@example.com"}
|
|
16
|
+
* // Development: {"level":30,"module":"MyModule","msg":"User created","email":"user@example.com"}
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import pino from "pino";
|
|
20
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
21
|
+
/**
|
|
22
|
+
* Redact email addresses in production.
|
|
23
|
+
* user@example.com -> u***@example.com
|
|
24
|
+
*/
|
|
25
|
+
function redactEmail(email) {
|
|
26
|
+
if (!isProduction)
|
|
27
|
+
return email;
|
|
28
|
+
const [local, domain] = email.split("@");
|
|
29
|
+
if (!local || !domain)
|
|
30
|
+
return "***@***";
|
|
31
|
+
return `${local[0]}***@${domain}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Redact IDs in production (workspace IDs, UUIDs).
|
|
35
|
+
* ws_abc123def456 -> ws_a...f456
|
|
36
|
+
* 550e8400-e29b-41d4-a716-446655440000 -> 550e...0000
|
|
37
|
+
*/
|
|
38
|
+
function redactId(id) {
|
|
39
|
+
if (!isProduction)
|
|
40
|
+
return id;
|
|
41
|
+
if (id.length <= 8)
|
|
42
|
+
return id;
|
|
43
|
+
return `${id.slice(0, 4)}...${id.slice(-4)}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Field name fragments whose values are always replaced with [REDACTED]
|
|
47
|
+
* regardless of environment. These cover credentials and secrets — never
|
|
48
|
+
* appropriate to log even in development. Email/id redaction is a
|
|
49
|
+
* separate concern (production-only PII protection).
|
|
50
|
+
*
|
|
51
|
+
* Exported so a consumer's Sentry PII scrubber
|
|
52
|
+
* shares the same field list — a secret name added here is stripped
|
|
53
|
+
* from both the log stream and the Sentry event in one move.
|
|
54
|
+
*/
|
|
55
|
+
export const CREDENTIAL_KEY_FRAGMENTS = [
|
|
56
|
+
"password",
|
|
57
|
+
"passwd",
|
|
58
|
+
"secret",
|
|
59
|
+
"token",
|
|
60
|
+
"apikey",
|
|
61
|
+
"api_key",
|
|
62
|
+
"authorization",
|
|
63
|
+
"auth_header",
|
|
64
|
+
"cookie",
|
|
65
|
+
"session_token",
|
|
66
|
+
"session_secret",
|
|
67
|
+
"credit_card",
|
|
68
|
+
"creditcard",
|
|
69
|
+
"card_number",
|
|
70
|
+
"cvv",
|
|
71
|
+
];
|
|
72
|
+
/** True when `key` contains any credential fragment (case-insensitive substring). */
|
|
73
|
+
export function isCredentialKey(key) {
|
|
74
|
+
const lower = key.toLowerCase();
|
|
75
|
+
return CREDENTIAL_KEY_FRAGMENTS.some((needle) => lower.includes(needle));
|
|
76
|
+
}
|
|
77
|
+
function redactData(data) {
|
|
78
|
+
const redacted = {};
|
|
79
|
+
for (const [key, value] of Object.entries(data)) {
|
|
80
|
+
// Always-redacted fields: credentials, tokens, secrets — these
|
|
81
|
+
// never appear in logs, even in dev. Catches accidental
|
|
82
|
+
// log.info("login attempt", { password: ... }) drift.
|
|
83
|
+
if (isCredentialKey(key)) {
|
|
84
|
+
redacted[key] = "[REDACTED]";
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// PII redaction (email/id) is production-only so dev debugging
|
|
88
|
+
// still works against real values.
|
|
89
|
+
if (!isProduction) {
|
|
90
|
+
redacted[key] = value;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (typeof value === "string") {
|
|
94
|
+
if (key.toLowerCase().includes("email")) {
|
|
95
|
+
redacted[key] = redactEmail(value);
|
|
96
|
+
}
|
|
97
|
+
else if (key.toLowerCase().includes("id") ||
|
|
98
|
+
key.toLowerCase().includes("workspace")) {
|
|
99
|
+
redacted[key] = redactId(value);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
redacted[key] = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
redacted[key] = value;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return redacted;
|
|
110
|
+
}
|
|
111
|
+
/** Base pino instance */
|
|
112
|
+
const baseLogger = pino({
|
|
113
|
+
level: isProduction ? "info" : "debug",
|
|
114
|
+
formatters: {
|
|
115
|
+
level(label) {
|
|
116
|
+
return { level: label };
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
timestamp: isProduction ? pino.stdTimeFunctions.isoTime : false,
|
|
120
|
+
});
|
|
121
|
+
class Logger {
|
|
122
|
+
constructor(context) {
|
|
123
|
+
this.pino = baseLogger.child({ module: context });
|
|
124
|
+
}
|
|
125
|
+
info(message, data) {
|
|
126
|
+
if (data) {
|
|
127
|
+
this.pino.info(redactData(data), message);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
this.pino.info(message);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
warn(message, data) {
|
|
134
|
+
if (data) {
|
|
135
|
+
this.pino.warn(redactData(data), message);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
this.pino.warn(message);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
error(message, data) {
|
|
142
|
+
if (data) {
|
|
143
|
+
this.pino.error(redactData(data), message);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
this.pino.error(message);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
debug(message, data) {
|
|
150
|
+
if (data) {
|
|
151
|
+
this.pino.debug(redactData(data), message);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
this.pino.debug(message);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export function createLogger(context) {
|
|
159
|
+
return new Logger(context);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Create a logger that writes to a custom pino destination.
|
|
163
|
+
* Used for testing — allows capturing log output in a writable stream.
|
|
164
|
+
* @internal
|
|
165
|
+
*/
|
|
166
|
+
export function _createLoggerWithStream(context, stream) {
|
|
167
|
+
const customBase = pino({
|
|
168
|
+
level: isProduction ? "info" : "debug",
|
|
169
|
+
formatters: {
|
|
170
|
+
level(label) {
|
|
171
|
+
return { level: label };
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
timestamp: false,
|
|
175
|
+
}, stream);
|
|
176
|
+
const instance = new Logger(context);
|
|
177
|
+
// Override the internal pino child with one writing to custom stream
|
|
178
|
+
instance.pino = customBase.child({ module: context });
|
|
179
|
+
return instance;
|
|
180
|
+
}
|
|
181
|
+
export { Logger };
|
|
182
|
+
export const logger = createLogger("app");
|
|
183
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notifications Module
|
|
3
|
+
*
|
|
4
|
+
* CRUD operations for user notifications. These are used by server actions
|
|
5
|
+
* in the consumer application to power the notification bell, list, and
|
|
6
|
+
* mark-as-read functionality.
|
|
7
|
+
*
|
|
8
|
+
* Notifications are user-scoped (not workspace-scoped) so a user can see
|
|
9
|
+
* all their notifications across workspaces.
|
|
10
|
+
*/
|
|
11
|
+
import type { CreateNotificationParams } from "./types";
|
|
12
|
+
export type { NotificationType, CreateNotificationParams } from "./types";
|
|
13
|
+
export { triggerQuotaNotification, triggerTrialNotification, triggerPaymentFailedNotification, triggerTeamMemberJoinedNotification, } from "./triggers";
|
|
14
|
+
/**
|
|
15
|
+
* Create a new notification for a user
|
|
16
|
+
*
|
|
17
|
+
* Serializes metadata to JSON string if provided.
|
|
18
|
+
* Returns the created notification.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createNotification(params: CreateNotificationParams): Promise<{
|
|
21
|
+
id: string;
|
|
22
|
+
createdAt: Date;
|
|
23
|
+
userId: string;
|
|
24
|
+
metadata: string | null;
|
|
25
|
+
workspaceId: string | null;
|
|
26
|
+
type: string;
|
|
27
|
+
title: string;
|
|
28
|
+
message: string;
|
|
29
|
+
isRead: boolean;
|
|
30
|
+
} | undefined>;
|
|
31
|
+
/**
|
|
32
|
+
* Get unread notifications for a user
|
|
33
|
+
*
|
|
34
|
+
* Returns notifications where isRead is false, ordered by newest first.
|
|
35
|
+
* Parses metadata JSON string back to object.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getUnreadNotifications(userId: string, limit?: number): Promise<({
|
|
38
|
+
id: string;
|
|
39
|
+
userId: string;
|
|
40
|
+
workspaceId: string | null;
|
|
41
|
+
type: string;
|
|
42
|
+
title: string;
|
|
43
|
+
message: string;
|
|
44
|
+
isRead: boolean;
|
|
45
|
+
metadata: string | null;
|
|
46
|
+
createdAt: Date;
|
|
47
|
+
} & {
|
|
48
|
+
metadata: Record<string, unknown> | null;
|
|
49
|
+
})[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Get all notifications for a user (read and unread)
|
|
52
|
+
*
|
|
53
|
+
* Returns notifications ordered by newest first.
|
|
54
|
+
* Parses metadata JSON string back to object.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getNotifications(userId: string, limit?: number): Promise<({
|
|
57
|
+
id: string;
|
|
58
|
+
userId: string;
|
|
59
|
+
workspaceId: string | null;
|
|
60
|
+
type: string;
|
|
61
|
+
title: string;
|
|
62
|
+
message: string;
|
|
63
|
+
isRead: boolean;
|
|
64
|
+
metadata: string | null;
|
|
65
|
+
createdAt: Date;
|
|
66
|
+
} & {
|
|
67
|
+
metadata: Record<string, unknown> | null;
|
|
68
|
+
})[]>;
|
|
69
|
+
/**
|
|
70
|
+
* Get count of unread notifications for a user
|
|
71
|
+
*
|
|
72
|
+
* Used for the notification bell badge number.
|
|
73
|
+
*/
|
|
74
|
+
export declare function getNotificationCount(userId: string): Promise<number>;
|
|
75
|
+
/**
|
|
76
|
+
* Mark a single notification as read
|
|
77
|
+
*
|
|
78
|
+
* Security: requires both notificationId and userId to ensure
|
|
79
|
+
* users can only mark their own notifications.
|
|
80
|
+
*/
|
|
81
|
+
export declare function markAsRead(notificationId: string, userId: string): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Mark all unread notifications as read for a user
|
|
84
|
+
*/
|
|
85
|
+
export declare function markAllAsRead(userId: string): Promise<void>;
|
|
86
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/notifications/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAGxD,YAAY,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAG1E,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,gCAAgC,EAChC,mCAAmC,GACpC,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB;;;;;;;;;;eAcxE;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAW;;;;;;;;;;;cAoFD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;MAxEhD;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW;;;;;;;;;;;cAgEtD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;MAvDhD;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS1E;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,iBAUtE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,iBAOjD"}
|