@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 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../src/db/schema/usage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage Tracking Database Schema
|
|
3
|
+
*
|
|
4
|
+
* Tables for tracking per-request token consumption and aggregated monthly usage.
|
|
5
|
+
* Used by the quota enforcement engine to check limits before AI requests
|
|
6
|
+
* and record consumption atomically after completion.
|
|
7
|
+
*
|
|
8
|
+
* Pattern: snake_case columns in PostgreSQL, camelCase TypeScript API (via Drizzle mapping)
|
|
9
|
+
*/
|
|
10
|
+
import { pgTable, text, timestamp, integer, real, index, unique, jsonb, } from "drizzle-orm/pg-core";
|
|
11
|
+
import { organization, users } from "./auth";
|
|
12
|
+
/**
|
|
13
|
+
* Usage Records table - Per-request token tracking (QUOTA-05)
|
|
14
|
+
*
|
|
15
|
+
* Every AI request creates one record with input/output/total tokens,
|
|
16
|
+
* the model used, and the agent that handled it. This provides the
|
|
17
|
+
* detailed breakdown for per-model and per-agent reporting (QUOTA-07).
|
|
18
|
+
*/
|
|
19
|
+
export const usageRecords = pgTable("usage_records", {
|
|
20
|
+
id: text("id").primaryKey(),
|
|
21
|
+
workspaceId: text("workspace_id")
|
|
22
|
+
.notNull()
|
|
23
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
24
|
+
userId: text("user_id")
|
|
25
|
+
.notNull()
|
|
26
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
27
|
+
type: text("type").notNull(), // "ai_tokens", "api_call"
|
|
28
|
+
model: text("model"), // "gpt-4o", "gpt-4o-mini"
|
|
29
|
+
agent: text("agent"), // "career-advisor", "sesh"
|
|
30
|
+
inputTokens: integer("input_tokens").notNull().default(0),
|
|
31
|
+
outputTokens: integer("output_tokens").notNull().default(0),
|
|
32
|
+
totalTokens: integer("total_tokens").notNull().default(0),
|
|
33
|
+
/**
|
|
34
|
+
* Raw provider USD cost snapshot (kept under legacy column name for back-compat).
|
|
35
|
+
* Do NOT use for arithmetic — floating-point accumulation causes sub-cent
|
|
36
|
+
* discrepancies over many records. Use chargedMnt (integer MNT) for all math.
|
|
37
|
+
*/
|
|
38
|
+
cost: real("cost").notNull().default(0),
|
|
39
|
+
/** Snapshot of billing margin multiplier applied to this request */
|
|
40
|
+
marginMultiplier: real("margin_multiplier").notNull().default(0),
|
|
41
|
+
/** Snapshot of USD→MNT FX rate used for conversion */
|
|
42
|
+
fxRate: real("fx_rate").notNull().default(0),
|
|
43
|
+
/** Authoritative MNT amount deducted from balance */
|
|
44
|
+
chargedMnt: integer("charged_mnt").notNull().default(0),
|
|
45
|
+
/** Request correlation id for log tracing */
|
|
46
|
+
requestId: text("request_id"),
|
|
47
|
+
/**
|
|
48
|
+
* Owning execution (@intelligo-dev/executions). No FK: the executions
|
|
49
|
+
* table is owned by another package and this column is written by
|
|
50
|
+
* the settlement path, which may run before or after the execution
|
|
51
|
+
* row's terminal update.
|
|
52
|
+
*/
|
|
53
|
+
executionId: text("execution_id"),
|
|
54
|
+
/** Conversation/chat id for grouping in usage dashboards */
|
|
55
|
+
conversationId: text("conversation_id"),
|
|
56
|
+
metadata: text("metadata"), // JSON string for additional data
|
|
57
|
+
recordedAt: timestamp("recorded_at").notNull().defaultNow(),
|
|
58
|
+
}, (table) => [
|
|
59
|
+
index("usage_records_workspace_id_idx").on(table.workspaceId),
|
|
60
|
+
index("usage_records_workspace_recorded_at_idx").on(table.workspaceId, table.recordedAt),
|
|
61
|
+
index("usage_records_workspace_type_idx").on(table.workspaceId, table.type),
|
|
62
|
+
index("usage_records_conversation_id_idx").on(table.conversationId),
|
|
63
|
+
index("usage_records_execution_id_idx").on(table.executionId),
|
|
64
|
+
]);
|
|
65
|
+
/**
|
|
66
|
+
* Monthly Usage table - Aggregated monthly totals for fast quota checks
|
|
67
|
+
*
|
|
68
|
+
* Instead of SUM(totalTokens) on every request, we increment a counter atomically.
|
|
69
|
+
* One row per workspace per billing period. The usage_records table provides
|
|
70
|
+
* the detailed breakdown for reporting; this table provides O(1) quota checks.
|
|
71
|
+
*/
|
|
72
|
+
export const monthlyUsage = pgTable("monthly_usage", {
|
|
73
|
+
id: text("id").primaryKey(),
|
|
74
|
+
workspaceId: text("workspace_id")
|
|
75
|
+
.notNull()
|
|
76
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
77
|
+
periodStart: timestamp("period_start").notNull(),
|
|
78
|
+
periodEnd: timestamp("period_end").notNull(),
|
|
79
|
+
tokensUsed: integer("tokens_used").notNull().default(0),
|
|
80
|
+
/** MNT-denominated total charged this period — authoritative for plan quota */
|
|
81
|
+
chargedMnt: integer("charged_mnt").notNull().default(0),
|
|
82
|
+
requestCount: integer("request_count").notNull().default(0),
|
|
83
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
84
|
+
}, (table) => [
|
|
85
|
+
unique("monthly_usage_workspace_period_unique").on(table.workspaceId, table.periodStart),
|
|
86
|
+
index("monthly_usage_workspace_id_idx").on(table.workspaceId),
|
|
87
|
+
]);
|
|
88
|
+
/**
|
|
89
|
+
* Trial Credits table - One-time trial credit allocation per workspace (TRIAL-01)
|
|
90
|
+
*
|
|
91
|
+
* Each new workspace receives 100K trial tokens on creation.
|
|
92
|
+
* The unique constraint on workspace_id enforces one trial per workspace (TRIAL-07).
|
|
93
|
+
* Trial credits are separate from purchased credits (credit_balances).
|
|
94
|
+
* They act as a fallback when plan quota is exceeded or credit balance is zero.
|
|
95
|
+
*
|
|
96
|
+
* Status flow: active → depleted (credits hit 0) or active → converted (paid plan)
|
|
97
|
+
*/
|
|
98
|
+
// Run drizzle-kit push to apply index
|
|
99
|
+
export const trialCredits = pgTable("trial_credits", {
|
|
100
|
+
id: text("id").primaryKey(),
|
|
101
|
+
workspaceId: text("workspace_id")
|
|
102
|
+
.notNull()
|
|
103
|
+
.unique()
|
|
104
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
105
|
+
initialCredits: integer("initial_credits").notNull().default(100000),
|
|
106
|
+
creditsUsed: integer("credits_used").notNull().default(0),
|
|
107
|
+
creditsRemaining: integer("credits_remaining").notNull().default(100000),
|
|
108
|
+
/** MNT-denominated trial grant (replaces token-denominated columns above) */
|
|
109
|
+
initialCreditsMnt: integer("initial_credits_mnt").notNull().default(5000),
|
|
110
|
+
creditsUsedMnt: integer("credits_used_mnt").notNull().default(0),
|
|
111
|
+
creditsRemainingMnt: integer("credits_remaining_mnt")
|
|
112
|
+
.notNull()
|
|
113
|
+
.default(5000),
|
|
114
|
+
status: text("status").notNull().default("active"), // active|depleted|converted|expired
|
|
115
|
+
provisionedAt: timestamp("provisioned_at").notNull().defaultNow(),
|
|
116
|
+
trialEndDate: timestamp("trial_end_date"), // 14 days from provisioning
|
|
117
|
+
depletedAt: timestamp("depleted_at"),
|
|
118
|
+
convertedAt: timestamp("converted_at"),
|
|
119
|
+
createdByIp: text("created_by_ip"),
|
|
120
|
+
createdByEmail: text("created_by_email"),
|
|
121
|
+
/**
|
|
122
|
+
* Canonical form of createdByEmail used by the per-email abuse
|
|
123
|
+
* check. Stored alongside the raw value so `SELECT count(*)`
|
|
124
|
+
* can use an index instead of a full-table scan + JS filter.
|
|
125
|
+
* See packages/billing/src/trial.ts:normalizeEmailForAbuseCheck.
|
|
126
|
+
*/
|
|
127
|
+
normalizedEmail: text("normalized_email"),
|
|
128
|
+
}, (table) => [
|
|
129
|
+
index("trial_credits_expiry_idx").on(table.status, table.trialEndDate),
|
|
130
|
+
index("trial_credits_normalized_email_idx").on(table.normalizedEmail),
|
|
131
|
+
]);
|
|
132
|
+
/**
|
|
133
|
+
* Rate Limit Entries table - Sliding window rate limiting (QUOTA-10)
|
|
134
|
+
*
|
|
135
|
+
* One row per (workspace, endpoint, minute bucket), with a counter.
|
|
136
|
+
* Each request upserts the row and atomically increments `count`, so N
|
|
137
|
+
* concurrent requests observe 1..N and exactly `limit` are admitted.
|
|
138
|
+
*
|
|
139
|
+
* An earlier version used ON CONFLICT DO NOTHING, which admitted
|
|
140
|
+
* exactly ONE request per minute on every plan — the per-plan limit was
|
|
141
|
+
* never consulted. See packages/billing/src/rate-limit.ts.
|
|
142
|
+
*
|
|
143
|
+
* Old buckets are deleted by the billing-maintenance cron.
|
|
144
|
+
*
|
|
145
|
+
* Database-backed rate limiting is the correct choice for <10K users
|
|
146
|
+
* (no Redis dependency, per architecture decisions).
|
|
147
|
+
*/
|
|
148
|
+
export const rateLimitEntries = pgTable("rate_limit_entries", {
|
|
149
|
+
id: text("id").primaryKey(),
|
|
150
|
+
workspaceId: text("workspace_id")
|
|
151
|
+
.notNull()
|
|
152
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
153
|
+
endpoint: text("endpoint").notNull().default("chat"),
|
|
154
|
+
requestedAt: timestamp("requested_at").notNull().defaultNow(),
|
|
155
|
+
/** Floored minute bucket for unique constraint enforcement */
|
|
156
|
+
minuteBucket: timestamp("minute_bucket").notNull(),
|
|
157
|
+
/** Requests observed in this bucket — incremented via upsert */
|
|
158
|
+
count: integer("count").notNull().default(1),
|
|
159
|
+
}, (table) => [
|
|
160
|
+
index("rate_limit_entries_window_idx").on(table.workspaceId, table.endpoint, table.requestedAt),
|
|
161
|
+
unique("rate_limit_entries_unique_bucket_idx").on(table.workspaceId, table.endpoint, table.minuteBucket),
|
|
162
|
+
]);
|
|
163
|
+
/**
|
|
164
|
+
* Notification History table - Tracks sent notifications for deduplication
|
|
165
|
+
*
|
|
166
|
+
* Records each notification sent (quota warnings, trial alerts) with a
|
|
167
|
+
* period-based deduplication key. The unique constraint on
|
|
168
|
+
* (workspaceId, type, periodKey) prevents sending the same notification
|
|
169
|
+
* twice in the same billing period.
|
|
170
|
+
*
|
|
171
|
+
* Phase 14 will update the channel from "console" to "email" and use
|
|
172
|
+
* Resend for actual delivery. For now, notifications are logged to console.
|
|
173
|
+
*/
|
|
174
|
+
export const notificationHistory = pgTable("notification_history", {
|
|
175
|
+
id: text("id").primaryKey(),
|
|
176
|
+
workspaceId: text("workspace_id")
|
|
177
|
+
.notNull()
|
|
178
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
179
|
+
type: text("type").notNull(), // "quota_warning_80", "quota_warning_100", "trial_warning_20", "trial_depleted"
|
|
180
|
+
periodKey: text("period_key").notNull(), // "2026-02" for monthly, "trial" for one-time
|
|
181
|
+
sentAt: timestamp("sent_at").notNull().defaultNow(),
|
|
182
|
+
channel: text("channel").notNull().default("console"), // "console" now, "email" in Phase 14
|
|
183
|
+
metadata: text("metadata"), // JSON string for additional context
|
|
184
|
+
}, (table) => [
|
|
185
|
+
unique("notification_history_dedup_unique").on(table.workspaceId, table.type, table.periodKey),
|
|
186
|
+
index("notification_history_workspace_id_idx").on(table.workspaceId),
|
|
187
|
+
]);
|
|
188
|
+
/**
|
|
189
|
+
* User Quotas table — per-user, per-action usage counters.
|
|
190
|
+
*
|
|
191
|
+
* One row per user (not per period — one-time payment model). Counters
|
|
192
|
+
* live in the `usage` JSONB map and increment atomically in SQL, so a
|
|
193
|
+
* quota check is O(1) with no SUM over usage_records.
|
|
194
|
+
*/
|
|
195
|
+
export const userQuotas = pgTable("user_quotas", {
|
|
196
|
+
id: text("id").primaryKey(),
|
|
197
|
+
userId: text("user_id")
|
|
198
|
+
.notNull()
|
|
199
|
+
.unique()
|
|
200
|
+
.references(() => users.id, { onDelete: "cascade" }),
|
|
201
|
+
workspaceId: text("workspace_id")
|
|
202
|
+
.notNull()
|
|
203
|
+
.references(() => organization.id, { onDelete: "cascade" }),
|
|
204
|
+
plan: text("plan").notNull().default("free"), // free | standard | pro
|
|
205
|
+
/**
|
|
206
|
+
* Per-action counter map, keyed by the product's own action slugs
|
|
207
|
+
* (`usage["chat"] = 42`). This is the only counter storage.
|
|
208
|
+
*
|
|
209
|
+
* Three career-specific integer columns — chat_messages_used,
|
|
210
|
+
* assessments_used, reports_used — used to sit beside it, written
|
|
211
|
+
* by every product and read in preference to this map. Migration
|
|
212
|
+
* 0038 backfilled them into the map and dropped them: a public
|
|
213
|
+
* schema naming one vertical's actions meant no other vertical
|
|
214
|
+
* could add a counter without a migration to Intelligo (ADR-0004).
|
|
215
|
+
*/
|
|
216
|
+
usage: jsonb("usage").notNull().default({}),
|
|
217
|
+
totalCostUsd: real("total_cost_usd").notNull().default(0),
|
|
218
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
219
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
220
|
+
}, (table) => [
|
|
221
|
+
index("user_quotas_user_id_idx").on(table.userId),
|
|
222
|
+
index("user_quotas_workspace_id_idx").on(table.workspaceId),
|
|
223
|
+
]);
|
|
224
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/db/schema/usage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Connection Validation
|
|
3
|
+
*
|
|
4
|
+
* Validates that the database is connected and tables exist before allowing the app to start.
|
|
5
|
+
*/
|
|
6
|
+
export interface DatabaseValidationResult {
|
|
7
|
+
isConnected: boolean;
|
|
8
|
+
tablesExist: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Check if database connection is valid and tables exist
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateDatabaseConnection(): Promise<DatabaseValidationResult>;
|
|
15
|
+
/**
|
|
16
|
+
* Validate database or throw error (for startup validation)
|
|
17
|
+
*/
|
|
18
|
+
export declare function requireDatabaseConnection(): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/db/validate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,wBAAwB,CAAC,CA8BpF;AAED;;GAEG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqB/D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Connection Validation
|
|
3
|
+
*
|
|
4
|
+
* Validates that the database is connected and tables exist before allowing the app to start.
|
|
5
|
+
*/
|
|
6
|
+
import { db } from "./client";
|
|
7
|
+
import { sql } from "drizzle-orm";
|
|
8
|
+
/**
|
|
9
|
+
* Check if database connection is valid and tables exist
|
|
10
|
+
*/
|
|
11
|
+
export async function validateDatabaseConnection() {
|
|
12
|
+
try {
|
|
13
|
+
// Test database connection
|
|
14
|
+
await db.execute(sql `SELECT 1`);
|
|
15
|
+
// Check if auth tables exist
|
|
16
|
+
const result = await db.execute(sql `
|
|
17
|
+
SELECT COUNT(*) as table_count
|
|
18
|
+
FROM information_schema.tables
|
|
19
|
+
WHERE table_schema = 'public'
|
|
20
|
+
AND table_name IN ('users', 'sessions', 'accounts', 'verifications')
|
|
21
|
+
`);
|
|
22
|
+
const tableCount = Number(result.rows[0]?.table_count ?? 0);
|
|
23
|
+
const tablesExist = tableCount === 4;
|
|
24
|
+
return {
|
|
25
|
+
isConnected: true,
|
|
26
|
+
tablesExist,
|
|
27
|
+
error: tablesExist
|
|
28
|
+
? undefined
|
|
29
|
+
: "Auth tables do not exist. Run 'pnpm --filter @intelligo-dev/core db:push' to create them.",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return {
|
|
34
|
+
isConnected: false,
|
|
35
|
+
tablesExist: false,
|
|
36
|
+
error: error instanceof Error ? error.message : "Unknown database error",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Validate database or throw error (for startup validation)
|
|
42
|
+
*/
|
|
43
|
+
export async function requireDatabaseConnection() {
|
|
44
|
+
const result = await validateDatabaseConnection();
|
|
45
|
+
if (!result.isConnected) {
|
|
46
|
+
throw new Error(`❌ Database connection failed: ${result.error}\n\n` +
|
|
47
|
+
`Make sure DATABASE_URL is configured in .env.local\n` +
|
|
48
|
+
`Example: DATABASE_URL=postgres://user:pass@host/db`);
|
|
49
|
+
}
|
|
50
|
+
if (!result.tablesExist) {
|
|
51
|
+
throw new Error(`❌ Database tables do not exist.\n\n` +
|
|
52
|
+
`Run the following commands to set up the database:\n` +
|
|
53
|
+
` 1. pnpm --filter @intelligo-dev/core db:push\n` +
|
|
54
|
+
` 2. pnpm --filter @intelligo-dev/core db:seed (optional - creates admin user)`);
|
|
55
|
+
}
|
|
56
|
+
console.log("✓ Database connection validated");
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/db/validate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAQlC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,IAAI,CAAC;QACH,2BAA2B;QAC3B,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,UAAU,CAAC,CAAC;QAEhC,6BAA6B;QAC7B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;;;;KAKlC,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC,CAAC;QAC5D,MAAM,WAAW,GAAG,UAAU,KAAK,CAAC,CAAC;QAErC,OAAO;YACL,WAAW,EAAE,IAAI;YACjB,WAAW;YACX,KAAK,EAAE,WAAW;gBAChB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,2FAA2F;SAChG,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,WAAW,EAAE,KAAK;YAClB,WAAW,EAAE,KAAK;YAClB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB;SACzE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB;IAC7C,MAAM,MAAM,GAAG,MAAM,0BAA0B,EAAE,CAAC;IAElD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,iCAAiC,MAAM,CAAC,KAAK,MAAM;YACjD,sDAAsD;YACtD,oDAAoD,CACvD,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,qCAAqC;YACnC,sDAAsD;YACtD,kDAAkD;YAClD,gFAAgF,CACnF,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace-Scoped Query Helpers (WORK-06: Data Isolation)
|
|
3
|
+
*
|
|
4
|
+
* DATA ISOLATION MODEL:
|
|
5
|
+
* - Phase 10 workspace/team operations use Better-Auth organization plugin API exclusively.
|
|
6
|
+
* These APIs provide inherent data isolation — all operations are scoped to the
|
|
7
|
+
* authenticated user's session and active organization. No raw DB queries needed.
|
|
8
|
+
*
|
|
9
|
+
* Better-Auth API isolation guarantees:
|
|
10
|
+
* - auth.api.listOrganizations() — returns ONLY organizations the authenticated user belongs to
|
|
11
|
+
* - auth.api.getFullOrganization() — returns ONLY the active organization (set via session)
|
|
12
|
+
* - auth.api.createInvitation() — requires organizationId from requireWorkspace() (authenticated context)
|
|
13
|
+
* - auth.api.removeMember() — scoped to the organizationId from requireWorkspace()
|
|
14
|
+
* - All other org API methods operate on the authenticated user's session context
|
|
15
|
+
*
|
|
16
|
+
* - Future phases (11+) will add product-specific tables (conversations, knowledge_bases,
|
|
17
|
+
* usage_logs, etc.) that contain a workspaceId column. ALL queries on these tables
|
|
18
|
+
* MUST use the helpers below to enforce workspace-scoped data isolation.
|
|
19
|
+
*
|
|
20
|
+
* USAGE PATTERN (for future phases):
|
|
21
|
+
* import { withWorkspaceFilter } from "@intelligo-dev/core/db/workspace-queries";
|
|
22
|
+
* import { requireWorkspace } from "@intelligo-dev/auth";
|
|
23
|
+
*
|
|
24
|
+
* const { workspace } = await requireWorkspace();
|
|
25
|
+
* const conversations = await db
|
|
26
|
+
* .select()
|
|
27
|
+
* .from(conversationsTable)
|
|
28
|
+
* .where(withWorkspaceFilter(conversationsTable.workspaceId, workspace.id));
|
|
29
|
+
*/
|
|
30
|
+
import { type SQL } from "drizzle-orm";
|
|
31
|
+
import type { PgColumn } from "drizzle-orm/pg-core";
|
|
32
|
+
/**
|
|
33
|
+
* Creates a workspace-scoped WHERE condition for any table with a workspaceId column.
|
|
34
|
+
* Use this in all custom Drizzle queries to enforce data isolation (WORK-06).
|
|
35
|
+
*
|
|
36
|
+
* @param workspaceIdColumn - The workspaceId column from the table schema
|
|
37
|
+
* @param workspaceId - The active workspace ID from requireWorkspace()
|
|
38
|
+
* @returns SQL condition: workspaceId = ?
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const { workspace } = await requireWorkspace();
|
|
43
|
+
* const conversations = await db
|
|
44
|
+
* .select()
|
|
45
|
+
* .from(conversationsTable)
|
|
46
|
+
* .where(workspaceEq(conversationsTable.workspaceId, workspace.id));
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function workspaceEq(workspaceIdColumn: PgColumn, workspaceId: string): SQL;
|
|
50
|
+
/**
|
|
51
|
+
* Combines a workspace scope condition with additional WHERE conditions.
|
|
52
|
+
* Convenience helper to ensure workspaceId is always the first filter.
|
|
53
|
+
*
|
|
54
|
+
* @param workspaceIdColumn - The workspaceId column from the table schema
|
|
55
|
+
* @param workspaceId - The active workspace ID from requireWorkspace()
|
|
56
|
+
* @param additionalConditions - Extra WHERE conditions to AND together
|
|
57
|
+
* @returns Combined SQL condition: workspaceId = ? AND ...
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const { workspace } = await requireWorkspace();
|
|
62
|
+
* const activeConversations = await db
|
|
63
|
+
* .select()
|
|
64
|
+
* .from(conversationsTable)
|
|
65
|
+
* .where(
|
|
66
|
+
* withWorkspaceFilter(
|
|
67
|
+
* conversationsTable.workspaceId,
|
|
68
|
+
* workspace.id,
|
|
69
|
+
* eq(conversationsTable.status, "active")
|
|
70
|
+
* )
|
|
71
|
+
* );
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function withWorkspaceFilter(workspaceIdColumn: PgColumn, workspaceId: string, ...additionalConditions: SQL[]): SQL;
|
|
75
|
+
//# sourceMappingURL=workspace-queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-queries.d.ts","sourceRoot":"","sources":["../../src/db/workspace-queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAW,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,iBAAiB,EAAE,QAAQ,EAC3B,WAAW,EAAE,MAAM,GAClB,GAAG,CAEL;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CACjC,iBAAiB,EAAE,QAAQ,EAC3B,WAAW,EAAE,MAAM,EACnB,GAAG,oBAAoB,EAAE,GAAG,EAAE,GAC7B,GAAG,CAEL"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace-Scoped Query Helpers (WORK-06: Data Isolation)
|
|
3
|
+
*
|
|
4
|
+
* DATA ISOLATION MODEL:
|
|
5
|
+
* - Phase 10 workspace/team operations use Better-Auth organization plugin API exclusively.
|
|
6
|
+
* These APIs provide inherent data isolation — all operations are scoped to the
|
|
7
|
+
* authenticated user's session and active organization. No raw DB queries needed.
|
|
8
|
+
*
|
|
9
|
+
* Better-Auth API isolation guarantees:
|
|
10
|
+
* - auth.api.listOrganizations() — returns ONLY organizations the authenticated user belongs to
|
|
11
|
+
* - auth.api.getFullOrganization() — returns ONLY the active organization (set via session)
|
|
12
|
+
* - auth.api.createInvitation() — requires organizationId from requireWorkspace() (authenticated context)
|
|
13
|
+
* - auth.api.removeMember() — scoped to the organizationId from requireWorkspace()
|
|
14
|
+
* - All other org API methods operate on the authenticated user's session context
|
|
15
|
+
*
|
|
16
|
+
* - Future phases (11+) will add product-specific tables (conversations, knowledge_bases,
|
|
17
|
+
* usage_logs, etc.) that contain a workspaceId column. ALL queries on these tables
|
|
18
|
+
* MUST use the helpers below to enforce workspace-scoped data isolation.
|
|
19
|
+
*
|
|
20
|
+
* USAGE PATTERN (for future phases):
|
|
21
|
+
* import { withWorkspaceFilter } from "@intelligo-dev/core/db/workspace-queries";
|
|
22
|
+
* import { requireWorkspace } from "@intelligo-dev/auth";
|
|
23
|
+
*
|
|
24
|
+
* const { workspace } = await requireWorkspace();
|
|
25
|
+
* const conversations = await db
|
|
26
|
+
* .select()
|
|
27
|
+
* .from(conversationsTable)
|
|
28
|
+
* .where(withWorkspaceFilter(conversationsTable.workspaceId, workspace.id));
|
|
29
|
+
*/
|
|
30
|
+
import { eq, and } from "drizzle-orm";
|
|
31
|
+
/**
|
|
32
|
+
* Creates a workspace-scoped WHERE condition for any table with a workspaceId column.
|
|
33
|
+
* Use this in all custom Drizzle queries to enforce data isolation (WORK-06).
|
|
34
|
+
*
|
|
35
|
+
* @param workspaceIdColumn - The workspaceId column from the table schema
|
|
36
|
+
* @param workspaceId - The active workspace ID from requireWorkspace()
|
|
37
|
+
* @returns SQL condition: workspaceId = ?
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const { workspace } = await requireWorkspace();
|
|
42
|
+
* const conversations = await db
|
|
43
|
+
* .select()
|
|
44
|
+
* .from(conversationsTable)
|
|
45
|
+
* .where(workspaceEq(conversationsTable.workspaceId, workspace.id));
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function workspaceEq(workspaceIdColumn, workspaceId) {
|
|
49
|
+
return eq(workspaceIdColumn, workspaceId);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Combines a workspace scope condition with additional WHERE conditions.
|
|
53
|
+
* Convenience helper to ensure workspaceId is always the first filter.
|
|
54
|
+
*
|
|
55
|
+
* @param workspaceIdColumn - The workspaceId column from the table schema
|
|
56
|
+
* @param workspaceId - The active workspace ID from requireWorkspace()
|
|
57
|
+
* @param additionalConditions - Extra WHERE conditions to AND together
|
|
58
|
+
* @returns Combined SQL condition: workspaceId = ? AND ...
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const { workspace } = await requireWorkspace();
|
|
63
|
+
* const activeConversations = await db
|
|
64
|
+
* .select()
|
|
65
|
+
* .from(conversationsTable)
|
|
66
|
+
* .where(
|
|
67
|
+
* withWorkspaceFilter(
|
|
68
|
+
* conversationsTable.workspaceId,
|
|
69
|
+
* workspace.id,
|
|
70
|
+
* eq(conversationsTable.status, "active")
|
|
71
|
+
* )
|
|
72
|
+
* );
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function withWorkspaceFilter(workspaceIdColumn, workspaceId, ...additionalConditions) {
|
|
76
|
+
return and(eq(workspaceIdColumn, workspaceId), ...additionalConditions);
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=workspace-queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-queries.js","sourceRoot":"","sources":["../../src/db/workspace-queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,EAAE,EAAE,GAAG,EAAY,MAAM,aAAa,CAAC;AAGhD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,WAAW,CACzB,iBAA2B,EAC3B,WAAmB;IAEnB,OAAO,EAAE,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,mBAAmB,CACjC,iBAA2B,EAC3B,WAAmB,EACnB,GAAG,oBAA2B;IAE9B,OAAO,GAAG,CAAC,EAAE,CAAC,iBAAiB,EAAE,WAAW,CAAC,EAAE,GAAG,oBAAoB,CAAE,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document title classifier registry.
|
|
3
|
+
*
|
|
4
|
+
* Vertical product packages register their title patterns here; the
|
|
5
|
+
* document persistence API (./service.ts) uses the same registry to
|
|
6
|
+
* derive agent labels and the "report" filter. Kept in its own module
|
|
7
|
+
* with zero imports so client-safe code and tests can load it without
|
|
8
|
+
* dragging in the server-only persistence chain (db).
|
|
9
|
+
*
|
|
10
|
+
* Ported from @intelligo-dev/agents/documents/classifier (ADR-0009) —
|
|
11
|
+
* unchanged.
|
|
12
|
+
*/
|
|
13
|
+
export type DocumentPatternEntry = {
|
|
14
|
+
/** Stable product slug — same one used across product configs. */
|
|
15
|
+
productSlug: string;
|
|
16
|
+
/** Human-readable agent label rendered in the documents UI. */
|
|
17
|
+
agentLabel: string;
|
|
18
|
+
/** Case-insensitive substring patterns; document matches if its
|
|
19
|
+
* lowercased title contains ANY of these. */
|
|
20
|
+
patterns: string[];
|
|
21
|
+
};
|
|
22
|
+
export declare function registerDocumentPatterns(entry: DocumentPatternEntry): void;
|
|
23
|
+
export declare function classifyDocumentTitle(title: string): {
|
|
24
|
+
productSlug: string | null;
|
|
25
|
+
agentLabel: string;
|
|
26
|
+
};
|
|
27
|
+
/** Returns true when the document looks like it belongs to any registered product. */
|
|
28
|
+
export declare function isProductDocument(title: string, productSlug?: string): boolean;
|
|
29
|
+
export declare function listRegisteredDocumentPatterns(): readonly DocumentPatternEntry[];
|
|
30
|
+
export declare function clearDocumentPatternRegistry(): void;
|
|
31
|
+
//# sourceMappingURL=classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../src/documents/classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,oBAAoB,GAAG;IACjC,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB;kDAC8C;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAIF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAE1E;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG;IACpD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB,CAQA;AAED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAKT;AAED,wBAAgB,8BAA8B,IAAI,SAAS,oBAAoB,EAAE,CAEhF;AAED,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document title classifier registry.
|
|
3
|
+
*
|
|
4
|
+
* Vertical product packages register their title patterns here; the
|
|
5
|
+
* document persistence API (./service.ts) uses the same registry to
|
|
6
|
+
* derive agent labels and the "report" filter. Kept in its own module
|
|
7
|
+
* with zero imports so client-safe code and tests can load it without
|
|
8
|
+
* dragging in the server-only persistence chain (db).
|
|
9
|
+
*
|
|
10
|
+
* Ported from @intelligo-dev/agents/documents/classifier (ADR-0009) —
|
|
11
|
+
* unchanged.
|
|
12
|
+
*/
|
|
13
|
+
const registry = [];
|
|
14
|
+
export function registerDocumentPatterns(entry) {
|
|
15
|
+
registry.push(entry);
|
|
16
|
+
}
|
|
17
|
+
export function classifyDocumentTitle(title) {
|
|
18
|
+
const lower = title.toLowerCase();
|
|
19
|
+
for (const entry of registry) {
|
|
20
|
+
if (entry.patterns.some((p) => lower.includes(p))) {
|
|
21
|
+
return { productSlug: entry.productSlug, agentLabel: entry.agentLabel };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return { productSlug: null, agentLabel: "AI Assistant" };
|
|
25
|
+
}
|
|
26
|
+
/** Returns true when the document looks like it belongs to any registered product. */
|
|
27
|
+
export function isProductDocument(title, productSlug) {
|
|
28
|
+
const { productSlug: matched } = classifyDocumentTitle(title);
|
|
29
|
+
if (!matched)
|
|
30
|
+
return false;
|
|
31
|
+
if (productSlug)
|
|
32
|
+
return matched === productSlug;
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
export function listRegisteredDocumentPatterns() {
|
|
36
|
+
return registry;
|
|
37
|
+
}
|
|
38
|
+
export function clearDocumentPatternRegistry() {
|
|
39
|
+
registry.length = 0;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../src/documents/classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,MAAM,QAAQ,GAA2B,EAAE,CAAC;AAE5C,MAAM,UAAU,wBAAwB,CAAC,KAA2B;IAClE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAa;IAIjD,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AAC3D,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,WAAoB;IAEpB,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC9D,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,IAAI,WAAW;QAAE,OAAO,OAAO,KAAK,WAAW,CAAC;IAChD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC5C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,4BAA4B;IAC1C,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document service error type.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `@intelligo-dev/auth`'s `WorkspaceServiceError` exactly (see that
|
|
5
|
+
* file's doc comment for the full rationale): the documents service
|
|
6
|
+
* (./service.ts) throws this for every failure it recognizes rather
|
|
7
|
+
* than returning an ad-hoc `{ success, error }` envelope — that
|
|
8
|
+
* shaping is a transport concern (a Server Action, a route handler)
|
|
9
|
+
* and belongs one layer up, alongside revalidatePath/Sentry/i18n, none
|
|
10
|
+
* of which this package may depend on (core's dependency allowlist is
|
|
11
|
+
* empty — see tests/architecture/dependency-direction.test.ts).
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* - `not_found` — no document (or no version of it) exists at the
|
|
15
|
+
* given id within the actor's workspace/user scope.
|
|
16
|
+
* - `forbidden` — a document with this id exists but is owned by a
|
|
17
|
+
* different user within the same workspace.
|
|
18
|
+
* - `invalid_input` — a caller-supplied argument failed a basic
|
|
19
|
+
* invariant (e.g. an unparsable or out-of-window delete timestamp).
|
|
20
|
+
* - `database_error` — the underlying insert/update did not return the
|
|
21
|
+
* row it was expected to.
|
|
22
|
+
*/
|
|
23
|
+
export type DocumentServiceErrorCode = "not_found" | "forbidden" | "invalid_input" | "database_error";
|
|
24
|
+
export declare class DocumentServiceError extends Error {
|
|
25
|
+
readonly code: DocumentServiceErrorCode;
|
|
26
|
+
readonly cause?: unknown;
|
|
27
|
+
constructor(code: DocumentServiceErrorCode, message: string, options?: {
|
|
28
|
+
cause?: unknown;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export declare function isDocumentServiceError(error: unknown): error is DocumentServiceError;
|
|
32
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/documents/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,wBAAwB,GAChC,WAAW,GACX,WAAW,GACX,eAAe,GACf,gBAAgB,CAAC;AAErB,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IAIxC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAGvB,IAAI,EAAE,wBAAwB,EAC9B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAUhC;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,oBAAoB,CAE/B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document service error type.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `@intelligo-dev/auth`'s `WorkspaceServiceError` exactly (see that
|
|
5
|
+
* file's doc comment for the full rationale): the documents service
|
|
6
|
+
* (./service.ts) throws this for every failure it recognizes rather
|
|
7
|
+
* than returning an ad-hoc `{ success, error }` envelope — that
|
|
8
|
+
* shaping is a transport concern (a Server Action, a route handler)
|
|
9
|
+
* and belongs one layer up, alongside revalidatePath/Sentry/i18n, none
|
|
10
|
+
* of which this package may depend on (core's dependency allowlist is
|
|
11
|
+
* empty — see tests/architecture/dependency-direction.test.ts).
|
|
12
|
+
*/
|
|
13
|
+
export class DocumentServiceError extends Error {
|
|
14
|
+
constructor(code, message, options) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "DocumentServiceError";
|
|
17
|
+
this.code = code;
|
|
18
|
+
if (options?.cause !== undefined) {
|
|
19
|
+
this.cause = options.cause;
|
|
20
|
+
}
|
|
21
|
+
Object.setPrototypeOf(this, DocumentServiceError.prototype);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function isDocumentServiceError(error) {
|
|
25
|
+
return error instanceof DocumentServiceError;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/documents/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAkBH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAO7C,YACE,IAA8B,EAC9B,OAAe,EACf,OAA6B;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,OAAO,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,IAA4B,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QACtD,CAAC;QACD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC9D,CAAC;CACF;AAED,MAAM,UAAU,sBAAsB,CACpC,KAAc;IAEd,OAAO,KAAK,YAAY,oBAAoB,CAAC;AAC/C,CAAC"}
|