1import * as Predicate from "effect/Predicate";
2import * as Schema from "effect/Schema";
3import * as SchemaIssue from "effect/SchemaIssue";
4
5function summarizeSchemaIssue(issue: SchemaIssue.Issue): string {
6 switch (issue._tag) {
7 case "Filter":
8 case "Encoding":
9 case "Pointer":
10 return `${issue._tag}(${summarizeSchemaIssue(issue.issue)})`;
11 case "Composite":
12 case "AnyOf":
13 return `${issue._tag}(${issue.issues.map(summarizeSchemaIssue).join(",")})`;
14 default:
15 return issue._tag;
16 }
17}
18
19export const PersistenceErrorCorrelation = Schema.Union([
20 Schema.Struct({ sessionId: Schema.String }),
21 Schema.Struct({ currentSessionId: Schema.String }),
22 Schema.Struct({ pairingLinkId: Schema.String }),
23 Schema.Struct({ threadId: Schema.String }),
24]);
25export type PersistenceErrorCorrelation = typeof PersistenceErrorCorrelation.Type;
26
27export class PersistenceSqlError extends Schema.TaggedError<PersistenceSqlError>()(
28 "PersistenceSqlError",
29 {
30 operation: Schema.String,
31 detail: Schema.optional(Schema.String),
32 correlation: Schema.optional(PersistenceErrorCorrelation),
33 cause: Schema.optional(Schema.Defect()),
34 },
35) {
36 override get message(): string {
37 return this.detail === undefined
38 ? `SQL error in ${this.operation}`
39 : `SQL error in ${this.operation}: ${this.detail}`;
40 }
41}
42
43export class PersistenceDecodeError extends Schema.TaggedError<PersistenceDecodeError>()(
44 "PersistenceDecodeError",
45 {
46 operation: Schema.String,
47 issue: Schema.String,
48 correlation: Schema.optional(PersistenceErrorCorrelation),
49 cause: Schema.optional(Schema.Defect()),
50 },
51) {
52 static fromSchemaError(
53 operation: string,
54 cause: Schema.SchemaError,
55 correlation?: PersistenceErrorCorrelation,
56 ): PersistenceDecodeError {
57 return new PersistenceDecodeError({
58 operation,
59 issue: summarizeSchemaIssue(cause.issue),
60 ...(correlation === undefined ? {} : { correlation }),
61 cause,
62 });
63 }
64
65 override get message(): string {
66 return `Decode error in ${this.operation}: ${this.issue}`;
67 }
68}
69
70function sqliteCondition(cause: unknown): string | undefined {
71 let value = cause;
72 for (let depth = 0; depth < 4 && Predicate.isObject(value); depth += 1) {
73 if (
74 "errcode" in value &&
75 typeof value.errcode === "number" &&
76 "errstr" in value &&
77 typeof value.errstr === "string"
78 ) {
79 return `SQLITE(${value.errcode}) ${value.errstr}`;
80 }
81 value = "cause" in value ? value.cause : undefined;
82 }
83 return undefined;
84}
85
86// Keep rejected payloads out of diagnostics; report only schema issue tags or normalized driver conditions.
87function describeSqlCause(cause: unknown): string | undefined {
88 if (Schema.isSchemaError(cause)) return summarizeSchemaIssue(cause.issue);
89 return sqliteCondition(cause);
90}
91
92export function toPersistenceSqlError(operation: string) {
93 return (cause: unknown): PersistenceSqlError => {
94 const detail = describeSqlCause(cause);
95 return new PersistenceSqlError({
96 operation,
97 ...(detail === undefined ? {} : { detail }),
98 cause,
99 });
100 };
101}
102
103export function toPersistenceDecodeError(operation: string) {
104 return (cause: Schema.SchemaError): PersistenceDecodeError =>
105 PersistenceDecodeError.fromSchemaError(operation, cause);
106}
107
108export type OrchestrationEventStoreError = PersistenceSqlError | PersistenceDecodeError;
109
110export type OrchestrationCommandReceiptRepositoryError =
111 | PersistenceSqlError
112 | PersistenceDecodeError;
113
114export type ProviderSessionRuntimeRepositoryError = PersistenceSqlError | PersistenceDecodeError;
115export type AuthPairingLinkRepositoryError = PersistenceSqlError | PersistenceDecodeError;
116export type AuthSessionRepositoryError = PersistenceSqlError | PersistenceDecodeError;
117export type PullRequestFilesViewedRepositoryError = PersistenceSqlError | PersistenceDecodeError;
118export type PullRequestReviewGuideRepositoryError = PersistenceSqlError | PersistenceDecodeError;
119
120export type ProjectionRepositoryError = PersistenceSqlError | PersistenceDecodeError;