@opengeni/db 0.27.9 → 0.28.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/dist/{chunk-2JFRTKTG.js → chunk-DBS5HPEW.js} +11 -1
- package/dist/chunk-DBS5HPEW.js.map +1 -0
- package/dist/{chunk-NX2JNJJP.js → chunk-HT5T62CC.js} +2538 -2283
- package/dist/chunk-HT5T62CC.js.map +1 -0
- package/dist/index.d.ts +69 -36
- package/dist/index.js +4146 -2924
- package/dist/index.js.map +1 -1
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +2 -2
- package/dist/schema.d.ts +129 -96
- package/dist/schema.js +19 -1
- package/dist/transcription-recordings-schema.d.ts +1226 -0
- package/dist/transcription-recordings.d.ts +228 -0
- package/drizzle/0170_resumable_transcription_recordings.sql +440 -0
- package/drizzle/0172_retire_model_visible_github_token.sql +86 -0
- package/drizzle/0173_codex_auth_boundaries.sql +107 -0
- package/drizzle/0174_session_wake_live_interruption.sql +80 -0
- package/drizzle/0175_resumable_transcription_provider_deadline.sql +24 -0
- package/package.json +4 -4
- package/src/index.ts +585 -245
- package/src/runtime-posture.ts +10 -0
- package/src/schema.ts +63 -51
- package/src/transcription-recordings-schema.ts +250 -0
- package/src/transcription-recordings.ts +1508 -0
- package/dist/chunk-2JFRTKTG.js.map +0 -1
- package/dist/chunk-NX2JNJJP.js.map +0 -1
package/src/runtime-posture.ts
CHANGED
|
@@ -18,6 +18,7 @@ export const FORCE_RLS_TABLES = [
|
|
|
18
18
|
"billing_customers",
|
|
19
19
|
"capability_catalog_items",
|
|
20
20
|
"capability_installations",
|
|
21
|
+
"codex_apps_settings",
|
|
21
22
|
"codex_capacity_waiters",
|
|
22
23
|
"codex_credential_leases",
|
|
23
24
|
"codex_reset_redemption_attempts",
|
|
@@ -117,6 +118,10 @@ export const FORCE_RLS_TABLES = [
|
|
|
117
118
|
"slack_interactions",
|
|
118
119
|
"social_connections",
|
|
119
120
|
"social_posts",
|
|
121
|
+
"transcription_recording_chunks",
|
|
122
|
+
"transcription_recording_objects",
|
|
123
|
+
"transcription_recording_segments",
|
|
124
|
+
"transcription_recordings",
|
|
120
125
|
"usage_events",
|
|
121
126
|
"workspace_artifact_events",
|
|
122
127
|
"workspace_artifact_versions",
|
|
@@ -172,6 +177,7 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
172
177
|
"billing_customers",
|
|
173
178
|
"capability_catalog_items",
|
|
174
179
|
"capability_installations",
|
|
180
|
+
"codex_apps_settings",
|
|
175
181
|
"codex_capacity_waiters",
|
|
176
182
|
"codex_credential_leases",
|
|
177
183
|
"codex_reset_redemption_attempts",
|
|
@@ -246,6 +252,10 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
246
252
|
"social_connections",
|
|
247
253
|
"social_posts",
|
|
248
254
|
"stripe_webhook_events",
|
|
255
|
+
"transcription_recording_chunks",
|
|
256
|
+
"transcription_recording_objects",
|
|
257
|
+
"transcription_recording_segments",
|
|
258
|
+
"transcription_recordings",
|
|
249
259
|
"usage_events",
|
|
250
260
|
"workspace_artifacts",
|
|
251
261
|
"workspace_captures",
|
package/src/schema.ts
CHANGED
|
@@ -497,7 +497,8 @@ export const workspaceVariableSetVariables = pgTable(
|
|
|
497
497
|
}),
|
|
498
498
|
);
|
|
499
499
|
|
|
500
|
-
// Per-workspace ChatGPT/Codex subscription credential. One row per
|
|
500
|
+
// Per-workspace ChatGPT/Codex subscription credential. One row per connected
|
|
501
|
+
// ChatGPT account within a workspace.
|
|
501
502
|
// access/refresh/id tokens live INSIDE credential_encrypted (v1 AES-256-GCM,
|
|
502
503
|
// same envelope as workspace_variable_set_variables); the other columns are
|
|
503
504
|
// plaintext metadata (header value + UI). RLS-isolated per workspace.
|
|
@@ -536,21 +537,11 @@ export const codexSubscriptionCredentials = pgTable(
|
|
|
536
537
|
// usage cap on a rotation turn; the rotation engine treats `exhausted_until > now()` as
|
|
537
538
|
// capped/skip so it isn't immediately re-picked. Self-clears via the now() comparison.
|
|
538
539
|
exhaustedUntil: timestamp("exhausted_until", { withTimezone: true }),
|
|
539
|
-
// P4 connector-aware rotation cache (plaintext metadata; NEVER a token). The set
|
|
540
|
-
// of ORIGINAL-dotted connector namespaces (github/gmail/linear/…) this account
|
|
541
|
-
// exposes via codex_apps, captured from the per-turn tools/list. null ⇒ never
|
|
542
|
-
// probed (the ranker treats it as unknown: never credited as covering, never
|
|
543
|
-
// excluded). The writer only ever sets a NON-empty set, so a flaky empty turn
|
|
544
|
-
// can't false-drop coverage. connectorsCheckedAt is the freshness clock.
|
|
545
|
-
connectorNamespaces: text("connector_namespaces").array(),
|
|
546
|
-
connectorsCheckedAt: timestamp("connectors_checked_at", {
|
|
547
|
-
withTimezone: true,
|
|
548
|
-
}),
|
|
549
540
|
// Workspace-local, server-held fairness cursor. Provider usage headers are
|
|
550
541
|
// capacity hints, never the sole allocator: live lease count is ranked first
|
|
551
542
|
// and this cursor deterministically breaks equal-load/equal-capacity ties.
|
|
552
543
|
// This flag controls NEW automatic allocations only. Credential health,
|
|
553
|
-
// refresh, encrypted material, and already-
|
|
544
|
+
// refresh, encrypted material, and an already-leased in-flight turn are
|
|
554
545
|
// intentionally independent. account eligibility policy owns toggle OCC/audit and product UI.
|
|
555
546
|
allocatorEnabled: boolean("allocator_enabled").notNull().default(true),
|
|
556
547
|
// Independent OCC/audit sequence for the allocator toggle. Token refresh
|
|
@@ -586,6 +577,54 @@ export const codexSubscriptionCredentials = pgTable(
|
|
|
586
577
|
table.workspaceId,
|
|
587
578
|
table.id,
|
|
588
579
|
),
|
|
580
|
+
workspaceAccountIdentity: uniqueIndex(
|
|
581
|
+
"codex_subscription_credentials_workspace_account_id_idx",
|
|
582
|
+
).on(table.workspaceId, table.accountId, table.id),
|
|
583
|
+
}),
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
// Optional workspace-level credential used only for ChatGPT connected Apps.
|
|
587
|
+
// Inference selection, usage, cooldown, allocator, pins, and leases never read
|
|
588
|
+
// this row. A durable null row retains the OCC sequence after designation clear.
|
|
589
|
+
export const codexAppsSettings = pgTable(
|
|
590
|
+
"codex_apps_settings",
|
|
591
|
+
{
|
|
592
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
593
|
+
accountId: uuid("account_id")
|
|
594
|
+
.notNull()
|
|
595
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
596
|
+
workspaceId: uuid("workspace_id")
|
|
597
|
+
.notNull()
|
|
598
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
599
|
+
credentialId: uuid("credential_id"),
|
|
600
|
+
version: integer("version").notNull().default(1),
|
|
601
|
+
designatedAt: timestamp("designated_at", { withTimezone: true }),
|
|
602
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
603
|
+
},
|
|
604
|
+
(table) => ({
|
|
605
|
+
workspaceAccount: foreignKey({
|
|
606
|
+
name: "codex_apps_settings_workspace_account_fk",
|
|
607
|
+
columns: [table.workspaceId, table.accountId],
|
|
608
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
609
|
+
}).onDelete("cascade"),
|
|
610
|
+
credentialScope: foreignKey({
|
|
611
|
+
name: "codex_apps_settings_credential_scope_fk",
|
|
612
|
+
columns: [table.workspaceId, table.accountId, table.credentialId],
|
|
613
|
+
foreignColumns: [
|
|
614
|
+
codexSubscriptionCredentials.workspaceId,
|
|
615
|
+
codexSubscriptionCredentials.accountId,
|
|
616
|
+
codexSubscriptionCredentials.id,
|
|
617
|
+
],
|
|
618
|
+
}).onDelete("cascade"),
|
|
619
|
+
workspace: uniqueIndex("codex_apps_settings_workspace_idx").on(table.workspaceId),
|
|
620
|
+
designationShape: check(
|
|
621
|
+
"codex_apps_settings_designation_shape_chk",
|
|
622
|
+
sql`${table.version} > 0 and (
|
|
623
|
+
(${table.credentialId} is null and ${table.designatedAt} is null)
|
|
624
|
+
or
|
|
625
|
+
(${table.credentialId} is not null and ${table.designatedAt} is not null)
|
|
626
|
+
)`,
|
|
627
|
+
),
|
|
589
628
|
}),
|
|
590
629
|
);
|
|
591
630
|
|
|
@@ -1460,10 +1499,9 @@ export const sessions = pgTable(
|
|
|
1460
1499
|
nestedAgentDepthPolicySessionId: uuid("nested_agent_depth_policy_session_id"),
|
|
1461
1500
|
temporalWorkflowId: text("temporal_workflow_id"),
|
|
1462
1501
|
activeTurnId: uuid("active_turn_id"),
|
|
1463
|
-
// Actual input tokens reported for the
|
|
1464
|
-
//
|
|
1465
|
-
//
|
|
1466
|
-
// usage has completed.
|
|
1502
|
+
// Actual input tokens reported for the latest authoritative ordinary model
|
|
1503
|
+
// call. Compaction/context clearing invalidates it to null; local history
|
|
1504
|
+
// estimates must never be stored here.
|
|
1467
1505
|
lastInputTokens: integer("last_input_tokens"),
|
|
1468
1506
|
// Operator /compact request flag. The API sets
|
|
1469
1507
|
// it true; the worker honors it BEFORE the next turn's model call by forcing
|
|
@@ -3519,25 +3557,9 @@ export const agentRunStates = pgTable("agent_run_states", {
|
|
|
3519
3557
|
stateVersion: integer("state_version").notNull(),
|
|
3520
3558
|
serializedRunState: text("serialized_run_state").notNull(),
|
|
3521
3559
|
pendingApprovals: jsonb("pending_approvals").$type<unknown[]>().notNull().default([]),
|
|
3522
|
-
//
|
|
3523
|
-
//
|
|
3524
|
-
//
|
|
3525
|
-
// RunState blob round-trips `reasoning.encrypted_content` minted by the
|
|
3526
|
-
// ChatGPT/Codex backend — account/org-bound, so a foreign blob 400s — and the
|
|
3527
|
-
// foreign reasoning ids the Responses backend validates; but the blob carries
|
|
3528
|
-
// NO per-item producer tag (those live only on session_history_items). So we
|
|
3529
|
-
// stamp the freezing account here: on an approval resume whose codex account
|
|
3530
|
-
// DIFFERS from this value,
|
|
3531
|
-
// the replay path neutralizes every reasoning item's account-bound identity
|
|
3532
|
-
// (encrypted_content + provider id) in the blob before it reaches the model.
|
|
3533
|
-
// Deliberately NO FK: provenance must OUTLIVE the account's hard-disconnect (a
|
|
3534
|
-
// stale-but-null tag still mismatches a live codex id, so the strip stays
|
|
3535
|
-
// correct either way). NULL on both sides (non-codex freeze + non-codex
|
|
3536
|
-
// resume) is a no-op, so single-account and non-codex sessions are unchanged.
|
|
3537
|
-
frozenCodexCredentialId: uuid("frozen_codex_credential_id"),
|
|
3538
|
-
// Exact provider rejection invalidates only the opaque reasoning identity
|
|
3539
|
-
// inside this frozen state. The serialized receipt remains durable and
|
|
3540
|
-
// auditable; the resume path neutralizes its provider-bound identity.
|
|
3560
|
+
// Exact provider rejection marks the latest current-turn receipt only when it
|
|
3561
|
+
// was part of the rejected request. The serialized receipt remains durable;
|
|
3562
|
+
// recovery builds a temporary view without unusable opaque artifacts.
|
|
3541
3563
|
providerArtifactInvalidatedAt: timestamp("provider_artifact_invalidated_at", {
|
|
3542
3564
|
withTimezone: true,
|
|
3543
3565
|
}),
|
|
@@ -3661,22 +3683,11 @@ export const sessionHistoryItems = pgTable(
|
|
|
3661
3683
|
// inserts ONE synthetic active summary row at the boundary. Defaults true so
|
|
3662
3684
|
// every existing and normally-appended row is live.
|
|
3663
3685
|
active: boolean("active").notNull().default(true),
|
|
3664
|
-
//
|
|
3665
|
-
//
|
|
3666
|
-
//
|
|
3667
|
-
//
|
|
3668
|
-
//
|
|
3669
|
-
// into a turn running on account B 400s. The read path drops the encrypted
|
|
3670
|
-
// reasoning of any item whose producer != the turn's current codex account.
|
|
3671
|
-
// Deliberately NO FK: provenance must OUTLIVE the account's hard-disconnect
|
|
3672
|
-
// (an ON DELETE SET NULL would erase the tag, and a stale-but-null tag still
|
|
3673
|
-
// mismatches a live codex id so the strip stays correct either way).
|
|
3674
|
-
producerCodexCredentialId: uuid("producer_codex_credential_id"),
|
|
3675
|
-
// An exact provider 400 can prove that an otherwise same-credential opaque
|
|
3676
|
-
// reasoning artifact is no longer decryptable. Keep the original item and
|
|
3677
|
-
// producer provenance immutable, but record the attempt-fenced rejection so
|
|
3678
|
-
// later model reads omit only the provider-bound identity. No FK: the receipt
|
|
3679
|
-
// must outlive operational attempt retention just like producer provenance.
|
|
3686
|
+
// An exact provider 400 can prove that the request's active opaque artifact
|
|
3687
|
+
// set is no longer usable. Keep each canonical item immutable, but record the
|
|
3688
|
+
// attempt-fenced rejection on the exact candidate row IDs so later model
|
|
3689
|
+
// reads build a temporary projection. No FK: the receipt must outlive
|
|
3690
|
+
// operational attempt retention.
|
|
3680
3691
|
providerArtifactInvalidatedAt: timestamp("provider_artifact_invalidated_at", {
|
|
3681
3692
|
withTimezone: true,
|
|
3682
3693
|
}),
|
|
@@ -6025,3 +6036,4 @@ export * from "./workspace-instruction-policies-schema";
|
|
|
6025
6036
|
export * from "./preference-registry-schema";
|
|
6026
6037
|
export * from "./memory-governance-schema";
|
|
6027
6038
|
export * from "./scoped-knowledge-schema";
|
|
6039
|
+
export * from "./transcription-recordings-schema";
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import {
|
|
3
|
+
boolean,
|
|
4
|
+
check,
|
|
5
|
+
index,
|
|
6
|
+
integer,
|
|
7
|
+
jsonb,
|
|
8
|
+
pgTable,
|
|
9
|
+
primaryKey,
|
|
10
|
+
text,
|
|
11
|
+
timestamp,
|
|
12
|
+
uniqueIndex,
|
|
13
|
+
uuid,
|
|
14
|
+
} from "drizzle-orm/pg-core";
|
|
15
|
+
|
|
16
|
+
export const transcriptionRecordingStateValues = [
|
|
17
|
+
"uploading",
|
|
18
|
+
"segmenting",
|
|
19
|
+
"ready",
|
|
20
|
+
"transcribing",
|
|
21
|
+
"complete",
|
|
22
|
+
"failed",
|
|
23
|
+
"discarded",
|
|
24
|
+
] as const;
|
|
25
|
+
|
|
26
|
+
export const transcriptionRecordingChunkStateValues = ["uploading", "complete"] as const;
|
|
27
|
+
export const transcriptionRecordingObjectKindValues = ["chunk", "segment"] as const;
|
|
28
|
+
|
|
29
|
+
export const transcriptionRecordingSegmentStateValues = [
|
|
30
|
+
"preparing",
|
|
31
|
+
"pending",
|
|
32
|
+
"transcribing",
|
|
33
|
+
"complete",
|
|
34
|
+
"failed",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
export const transcriptionRecordings = pgTable(
|
|
38
|
+
"transcription_recordings",
|
|
39
|
+
{
|
|
40
|
+
id: uuid("id").primaryKey(),
|
|
41
|
+
accountId: uuid("account_id").notNull(),
|
|
42
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
43
|
+
subjectId: text("subject_id").notNull(),
|
|
44
|
+
mimeType: text("mime_type").notNull(),
|
|
45
|
+
state: text("state", { enum: transcriptionRecordingStateValues })
|
|
46
|
+
.notNull()
|
|
47
|
+
.default("uploading"),
|
|
48
|
+
nextChunkNumber: integer("next_chunk_number").notNull().default(0),
|
|
49
|
+
chunkCount: integer("chunk_count").notNull().default(0),
|
|
50
|
+
totalBytes: integer("total_bytes").notNull().default(0),
|
|
51
|
+
totalDurationMilliseconds: integer("total_duration_milliseconds").notNull().default(0),
|
|
52
|
+
segmentCount: integer("segment_count").notNull().default(0),
|
|
53
|
+
completedSegmentCount: integer("completed_segment_count").notNull().default(0),
|
|
54
|
+
transcriptText: text("transcript_text"),
|
|
55
|
+
languages: jsonb("languages").$type<string[]>().notNull().default([]),
|
|
56
|
+
errorCode: text("error_code"),
|
|
57
|
+
retryable: boolean("retryable").notNull().default(false),
|
|
58
|
+
providerId: text("provider_id"),
|
|
59
|
+
processingGeneration: integer("processing_generation").notNull().default(0),
|
|
60
|
+
processingOwner: uuid("processing_owner"),
|
|
61
|
+
processingStartedAt: timestamp("processing_started_at", { withTimezone: true }),
|
|
62
|
+
objectsCleanedAt: timestamp("objects_cleaned_at", { withTimezone: true }),
|
|
63
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
64
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
65
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
|
66
|
+
},
|
|
67
|
+
(table) => ({
|
|
68
|
+
exactAuthority: uniqueIndex("transcription_recordings_exact_authority_uq").on(
|
|
69
|
+
table.accountId,
|
|
70
|
+
table.workspaceId,
|
|
71
|
+
table.subjectId,
|
|
72
|
+
table.id,
|
|
73
|
+
),
|
|
74
|
+
subjectCreated: index("transcription_recordings_subject_created_idx").on(
|
|
75
|
+
table.workspaceId,
|
|
76
|
+
table.subjectId,
|
|
77
|
+
table.createdAt,
|
|
78
|
+
),
|
|
79
|
+
expiry: index("transcription_recordings_expiry_idx").on(table.expiresAt, table.id),
|
|
80
|
+
valuesValid: check(
|
|
81
|
+
"transcription_recordings_values_check",
|
|
82
|
+
sql`${table.nextChunkNumber} >= 0
|
|
83
|
+
and ${table.chunkCount} >= 0
|
|
84
|
+
and ${table.totalBytes} >= 0
|
|
85
|
+
and ${table.totalDurationMilliseconds} >= 0
|
|
86
|
+
and ${table.segmentCount} >= 0
|
|
87
|
+
and ${table.completedSegmentCount} >= 0
|
|
88
|
+
and ${table.completedSegmentCount} <= ${table.segmentCount}
|
|
89
|
+
and octet_length(${table.subjectId}) between 1 and 1024
|
|
90
|
+
and octet_length(${table.mimeType}) between 1 and 128
|
|
91
|
+
and (
|
|
92
|
+
${table.providerId} is null
|
|
93
|
+
or octet_length(${table.providerId}) between 1 and 128
|
|
94
|
+
)`,
|
|
95
|
+
),
|
|
96
|
+
processingValid: check(
|
|
97
|
+
"transcription_recordings_processing_check",
|
|
98
|
+
sql`(
|
|
99
|
+
${table.processingOwner} is null
|
|
100
|
+
and ${table.processingStartedAt} is null
|
|
101
|
+
) or (
|
|
102
|
+
${table.processingOwner} is not null
|
|
103
|
+
and ${table.processingStartedAt} is not null
|
|
104
|
+
)`,
|
|
105
|
+
),
|
|
106
|
+
}),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
export const transcriptionRecordingObjects = pgTable(
|
|
110
|
+
"transcription_recording_objects",
|
|
111
|
+
{
|
|
112
|
+
accountId: uuid("account_id").notNull(),
|
|
113
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
114
|
+
subjectId: text("subject_id").notNull(),
|
|
115
|
+
recordingId: uuid("recording_id").notNull(),
|
|
116
|
+
objectKey: text("object_key").primaryKey(),
|
|
117
|
+
kind: text("kind", { enum: transcriptionRecordingObjectKindValues }).notNull(),
|
|
118
|
+
cleanupAfter: timestamp("cleanup_after", { withTimezone: true }).notNull(),
|
|
119
|
+
cleanupClaimId: uuid("cleanup_claim_id"),
|
|
120
|
+
cleanupClaimedAt: timestamp("cleanup_claimed_at", { withTimezone: true }),
|
|
121
|
+
cleanedAt: timestamp("cleaned_at", { withTimezone: true }),
|
|
122
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
123
|
+
},
|
|
124
|
+
(table) => ({
|
|
125
|
+
dueCleanup: index("transcription_recording_objects_due_cleanup_idx")
|
|
126
|
+
.on(table.cleanupAfter, table.objectKey)
|
|
127
|
+
.where(sql`${table.cleanedAt} is null`),
|
|
128
|
+
claimRecovery: index("transcription_recording_objects_claim_recovery_idx")
|
|
129
|
+
.on(table.cleanupClaimedAt, table.objectKey)
|
|
130
|
+
.where(sql`${table.cleanedAt} is null and ${table.cleanupClaimId} is not null`),
|
|
131
|
+
valuesValid: check(
|
|
132
|
+
"transcription_recording_objects_values_check",
|
|
133
|
+
sql`octet_length(${table.objectKey}) between 1 and 1024
|
|
134
|
+
and (
|
|
135
|
+
(${table.cleanupClaimId} is null and ${table.cleanupClaimedAt} is null)
|
|
136
|
+
or (${table.cleanupClaimId} is not null and ${table.cleanupClaimedAt} is not null)
|
|
137
|
+
)
|
|
138
|
+
and (
|
|
139
|
+
${table.cleanedAt} is null
|
|
140
|
+
or (${table.cleanupClaimId} is null and ${table.cleanupClaimedAt} is null)
|
|
141
|
+
)`,
|
|
142
|
+
),
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
export const transcriptionRecordingChunks = pgTable(
|
|
147
|
+
"transcription_recording_chunks",
|
|
148
|
+
{
|
|
149
|
+
accountId: uuid("account_id").notNull(),
|
|
150
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
151
|
+
subjectId: text("subject_id").notNull(),
|
|
152
|
+
recordingId: uuid("recording_id").notNull(),
|
|
153
|
+
chunkNumber: integer("chunk_number").notNull(),
|
|
154
|
+
state: text("state", { enum: transcriptionRecordingChunkStateValues })
|
|
155
|
+
.notNull()
|
|
156
|
+
.default("uploading"),
|
|
157
|
+
byteLength: integer("byte_length").notNull(),
|
|
158
|
+
sha256: text("sha256").notNull(),
|
|
159
|
+
startMilliseconds: integer("start_milliseconds").notNull(),
|
|
160
|
+
durationMilliseconds: integer("duration_milliseconds").notNull(),
|
|
161
|
+
objectKey: text("object_key").notNull(),
|
|
162
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
163
|
+
completedAt: timestamp("completed_at", { withTimezone: true }),
|
|
164
|
+
},
|
|
165
|
+
(table) => ({
|
|
166
|
+
pk: primaryKey({
|
|
167
|
+
name: "transcription_recording_chunks_pk",
|
|
168
|
+
columns: [table.recordingId, table.chunkNumber],
|
|
169
|
+
}),
|
|
170
|
+
recordingOrder: index("transcription_recording_chunks_order_idx").on(
|
|
171
|
+
table.workspaceId,
|
|
172
|
+
table.recordingId,
|
|
173
|
+
table.chunkNumber,
|
|
174
|
+
),
|
|
175
|
+
objectKey: uniqueIndex("transcription_recording_chunks_object_key_uq").on(table.objectKey),
|
|
176
|
+
valuesValid: check(
|
|
177
|
+
"transcription_recording_chunks_values_check",
|
|
178
|
+
sql`${table.chunkNumber} >= 0
|
|
179
|
+
and ${table.byteLength} > 0
|
|
180
|
+
and ${table.startMilliseconds} >= 0
|
|
181
|
+
and ${table.durationMilliseconds} >= 0
|
|
182
|
+
and ${table.sha256} ~ '^[0-9a-f]{64}$'
|
|
183
|
+
and octet_length(${table.objectKey}) between 1 and 1024
|
|
184
|
+
and (
|
|
185
|
+
(${table.state} = 'uploading' and ${table.completedAt} is null)
|
|
186
|
+
or (${table.state} = 'complete' and ${table.completedAt} is not null)
|
|
187
|
+
)`,
|
|
188
|
+
),
|
|
189
|
+
}),
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
export const transcriptionRecordingSegments = pgTable(
|
|
193
|
+
"transcription_recording_segments",
|
|
194
|
+
{
|
|
195
|
+
accountId: uuid("account_id").notNull(),
|
|
196
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
197
|
+
subjectId: text("subject_id").notNull(),
|
|
198
|
+
recordingId: uuid("recording_id").notNull(),
|
|
199
|
+
segmentNumber: integer("segment_number").notNull(),
|
|
200
|
+
generation: integer("generation").notNull(),
|
|
201
|
+
state: text("state", { enum: transcriptionRecordingSegmentStateValues })
|
|
202
|
+
.notNull()
|
|
203
|
+
.default("preparing"),
|
|
204
|
+
byteLength: integer("byte_length").notNull(),
|
|
205
|
+
sha256: text("sha256").notNull(),
|
|
206
|
+
startMilliseconds: integer("start_milliseconds").notNull(),
|
|
207
|
+
durationMilliseconds: integer("duration_milliseconds").notNull(),
|
|
208
|
+
objectKey: text("object_key").notNull(),
|
|
209
|
+
attemptId: uuid("attempt_id"),
|
|
210
|
+
attemptStartedAt: timestamp("attempt_started_at", { withTimezone: true }),
|
|
211
|
+
attemptDeadlineAt: timestamp("attempt_deadline_at", { withTimezone: true }),
|
|
212
|
+
transcriptText: text("transcript_text"),
|
|
213
|
+
languages: jsonb("languages").$type<string[]>().notNull().default([]),
|
|
214
|
+
providerId: text("provider_id"),
|
|
215
|
+
errorCode: text("error_code"),
|
|
216
|
+
retryable: boolean("retryable").notNull().default(false),
|
|
217
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
218
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
219
|
+
},
|
|
220
|
+
(table) => ({
|
|
221
|
+
pk: primaryKey({
|
|
222
|
+
name: "transcription_recording_segments_pk",
|
|
223
|
+
columns: [table.recordingId, table.segmentNumber],
|
|
224
|
+
}),
|
|
225
|
+
recordingOrder: index("transcription_recording_segments_order_idx").on(
|
|
226
|
+
table.workspaceId,
|
|
227
|
+
table.recordingId,
|
|
228
|
+
table.segmentNumber,
|
|
229
|
+
),
|
|
230
|
+
objectKey: uniqueIndex("transcription_recording_segments_object_key_uq").on(table.objectKey),
|
|
231
|
+
valuesValid: check(
|
|
232
|
+
"transcription_recording_segments_values_check",
|
|
233
|
+
sql`${table.segmentNumber} >= 0
|
|
234
|
+
and ${table.generation} > 0
|
|
235
|
+
and ${table.byteLength} > 0
|
|
236
|
+
and ${table.startMilliseconds} >= 0
|
|
237
|
+
and ${table.durationMilliseconds} > 0
|
|
238
|
+
and ${table.sha256} ~ '^[0-9a-f]{64}$'
|
|
239
|
+
and octet_length(${table.objectKey}) between 1 and 1024
|
|
240
|
+
and (
|
|
241
|
+
(${table.attemptId} is null
|
|
242
|
+
and ${table.attemptStartedAt} is null
|
|
243
|
+
and ${table.attemptDeadlineAt} is null)
|
|
244
|
+
or (${table.attemptId} is not null
|
|
245
|
+
and ${table.attemptStartedAt} is not null
|
|
246
|
+
and ${table.attemptDeadlineAt} is not null)
|
|
247
|
+
)`,
|
|
248
|
+
),
|
|
249
|
+
}),
|
|
250
|
+
);
|