File size: 3,901 Bytes
76289e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import {
  encodeOpenClawStateWorkerError,
  hydrateOpenClawStateWorkerError,
  retainOpenClawStateWorkerErrorPayload,
  type OpenClawStateWorkerErrorPayload,
} from "../state/openclaw-state-worker-error.js";
import {
  PluginStateStoreError,
  type PluginStateStoreErrorCode,
  type PluginStateStoreOperation,
} from "./plugin-state-store.types.js";

type PluginStateWorkerCause =
  | { canonical: OpenClawStateWorkerErrorPayload }
  | {
      name: string;
      message: string;
      code?: string | number;
      errcode?: number;
      cause?: PluginStateWorkerCause;
    };

export type PluginStateWorkerFailure = {
  message: string;
  code: PluginStateStoreErrorCode;
  operation: PluginStateStoreOperation;
  path?: string;
  cause?: PluginStateWorkerCause;
};

// Preserve classification fields and causal messages, not arbitrary error properties or stacks.
function captureCause(
  value: unknown,
  seen = new Set<object>(),
): PluginStateWorkerCause | undefined {
  if (value === undefined) {
    return undefined;
  }
  const canonical = encodeOpenClawStateWorkerError(value);
  if (canonical) {
    return { canonical };
  }
  if (
    value === null ||
    typeof value === "string" ||
    typeof value === "number" ||
    typeof value === "boolean" ||
    typeof value === "bigint" ||
    typeof value === "symbol"
  ) {
    return { name: "Error", message: String(value) };
  }
  if (typeof value !== "object") {
    return { name: "Error", message: "Unknown SQLite error cause" };
  }
  if (seen.has(value) || seen.size >= 8) {
    return { name: "Error", message: "Additional SQLite error cause omitted" };
  }
  seen.add(value);
  const name = "name" in value && typeof value.name === "string" ? value.name : "Error";
  const message = "message" in value && typeof value.message === "string" ? value.message : name;
  const code = "code" in value ? value.code : undefined;
  const errcode = "errcode" in value ? value.errcode : undefined;
  const cause = "cause" in value ? captureCause(value.cause, seen) : undefined;
  return {
    name,
    message,
    ...(typeof code === "string" || typeof code === "number" ? { code } : {}),
    ...(typeof errcode === "number" ? { errcode } : {}),
    ...(cause ? { cause } : {}),
  };
}

const errorConstructors = new Map<string, ErrorConstructor>([
  ["Error", Error],
  ["TypeError", TypeError],
  ["SyntaxError", SyntaxError],
  ["RangeError", RangeError],
  ["ReferenceError", ReferenceError],
  ["URIError", URIError],
  ["EvalError", EvalError],
]);

function restoreCause(value: PluginStateWorkerCause | undefined): Error | undefined {
  if (value && "canonical" in value) {
    const retained = new Error("SQLite worker error cause");
    retainOpenClawStateWorkerErrorPayload(retained, value.canonical);
    return hydrateOpenClawStateWorkerError(retained);
  }
  const Constructor = value ? (errorConstructors.get(value.name) ?? Error) : Error;
  return value
    ? Object.assign(new Constructor(value.message, { cause: restoreCause(value.cause) }), {
        name: value.name,
        ...(value.code === undefined ? {} : { code: value.code }),
        ...(value.errcode === undefined ? {} : { errcode: value.errcode }),
      })
    : undefined;
}

export function capturePluginStateWorkerFailure(
  error: PluginStateStoreError,
): PluginStateWorkerFailure {
  const cause = captureCause(error.cause);
  return {
    message: error.message,
    code: error.code,
    operation: error.operation,
    ...(error.path === undefined ? {} : { path: error.path }),
    ...(cause ? { cause } : {}),
  };
}

export function restorePluginStateWorkerFailure(
  error: PluginStateWorkerFailure,
): PluginStateStoreError {
  return new PluginStateStoreError(error.message, {
    code: error.code,
    operation: error.operation,
    ...(error.path === undefined ? {} : { path: error.path }),
    cause: restoreCause(error.cause),
  });
}