@arronqzy/react-blueprint 1.0.12 → 1.0.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arronqzy/react-blueprint",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "",
5
5
  "files": [
6
6
  "index.ts",
@@ -18,10 +18,10 @@
18
18
  "dayjs": "^1.11.13",
19
19
  "react-dom": "^19",
20
20
  "@xyflow/react": "^12.9.3",
21
- "@arronqzy/blueprint-dsl": "1.0.10",
21
+ "@arronqzy/i18n": "0.1.8",
22
+ "@arronqzy/blueprint-dsl": "1.0.11",
22
23
  "@arronqzy/react-rx-store": "1.1.5",
23
- "@arronqzy/ui": "1.0.6",
24
- "@arronqzy/i18n": "0.1.8"
24
+ "@arronqzy/ui": "1.0.6"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/react": "^19.0.1",
@@ -35,8 +35,8 @@
35
35
  "typescript": "^5.5.4",
36
36
  "vite": "^5.1.4",
37
37
  "@arronqzy/tailwind": "1.0.2",
38
- "@arronqzy/eslint-config": "0.0.0",
39
- "@arronqzy/typescript-config": "1.0.0"
38
+ "@arronqzy/typescript-config": "1.0.0",
39
+ "@arronqzy/eslint-config": "0.0.0"
40
40
  },
41
41
  "keywords": [],
42
42
  "author": "",
@@ -1,4 +1,5 @@
1
1
  export * from "./document";
2
+ export * from "./parse-blueprint-data";
2
3
  export * from "./node-types";
3
4
  export * from "./blueprint-graph";
4
5
  export * from "./react-flow-adapter";
@@ -0,0 +1,106 @@
1
+ import {
2
+ sanitizeBlueprintDocument,
3
+ type BlueprintDocument,
4
+ type BlueprintGraphEdge,
5
+ type BlueprintGraphNode,
6
+ type BlueprintNodeRole,
7
+ } from "./document";
8
+
9
+ export type ParseCheckResult = {
10
+ ok: boolean;
11
+ error?: string;
12
+ };
13
+
14
+ const NODE_ROLES = new Set<BlueprintNodeRole>([
15
+ "blueprint",
16
+ "logic",
17
+ "and",
18
+ "lifecycle",
19
+ "fetch",
20
+ "json",
21
+ "storage",
22
+ "clock",
23
+ "event",
24
+ ]);
25
+
26
+ function isRecord(value: unknown): value is Record<string, unknown> {
27
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
28
+ }
29
+
30
+ function extractBlueprintDocument(data: unknown): unknown {
31
+ if (!isRecord(data)) return data;
32
+ if (isRecord(data.blueprintDocument)) return data.blueprintDocument;
33
+ if (isRecord(data.document) && Array.isArray(data.document.nodes)) {
34
+ return data.document;
35
+ }
36
+ return data;
37
+ }
38
+
39
+ function isFiniteNumber(value: unknown): value is number {
40
+ return typeof value === "number" && Number.isFinite(value);
41
+ }
42
+
43
+ function isBlueprintNode(value: unknown): value is BlueprintGraphNode {
44
+ if (!isRecord(value)) return false;
45
+ if (typeof value.id !== "string" || !value.id) return false;
46
+ if (typeof value.role !== "string" || !NODE_ROLES.has(value.role as BlueprintNodeRole)) {
47
+ return false;
48
+ }
49
+ if (!isRecord(value.position) || !isFiniteNumber(value.position.x) || !isFiniteNumber(value.position.y)) {
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+
55
+ function isBlueprintEdge(value: unknown): value is BlueprintGraphEdge {
56
+ if (!isRecord(value)) return false;
57
+ return (
58
+ typeof value.id === "string" &&
59
+ value.id.length > 0 &&
60
+ typeof value.source === "string" &&
61
+ value.source.length > 0 &&
62
+ typeof value.target === "string" &&
63
+ value.target.length > 0
64
+ );
65
+ }
66
+
67
+ /**
68
+ * 校验数据能否被蓝图解析(工作区 `blueprintDocument`、蓝图导出 JSON 或裸文档均可)。
69
+ */
70
+ export function parseBlueprintData(
71
+ data: unknown
72
+ ): ParseCheckResult & { value?: BlueprintDocument } {
73
+ if (data == null) {
74
+ return { ok: false, error: "empty" };
75
+ }
76
+ const raw = extractBlueprintDocument(data);
77
+ if (!isRecord(raw)) {
78
+ return { ok: false, error: "invalid-blueprint-data" };
79
+ }
80
+ if (!Array.isArray(raw.nodes) || !Array.isArray(raw.edges)) {
81
+ return { ok: false, error: "invalid-blueprint-data" };
82
+ }
83
+ if (!raw.nodes.every(isBlueprintNode) || !raw.edges.every(isBlueprintEdge)) {
84
+ return { ok: false, error: "invalid-blueprint-data" };
85
+ }
86
+ try {
87
+ const value = sanitizeBlueprintDocument({
88
+ id: typeof raw.id === "string" && raw.id ? raw.id : "default",
89
+ name: typeof raw.name === "string" ? raw.name : undefined,
90
+ nodes: raw.nodes as BlueprintGraphNode[],
91
+ edges: raw.edges as BlueprintGraphEdge[],
92
+ allowFalseSignalPropagation:
93
+ typeof raw.allowFalseSignalPropagation === "boolean"
94
+ ? raw.allowFalseSignalPropagation
95
+ : undefined,
96
+ });
97
+ return { ok: true, value };
98
+ } catch {
99
+ return { ok: false, error: "invalid-blueprint-data" };
100
+ }
101
+ }
102
+
103
+ export function validateBlueprintData(data: unknown): ParseCheckResult {
104
+ const parsed = parseBlueprintData(data);
105
+ return parsed.ok ? { ok: true } : { ok: false, error: parsed.error };
106
+ }
@@ -46,6 +46,8 @@ export type UseBlueprintDebugSessionOptions = {
46
46
  viewElementIds: string[],
47
47
  scope: unknown
48
48
  ) => void;
49
+ /** 隔离 IndexedDB / localStorage;空则用全局库 */
50
+ nameSpace?: string | null;
49
51
  };
50
52
 
51
53
  function buildNodeLabelMap(graph: BlueprintGraph): Record<string, string> {
@@ -66,6 +68,7 @@ export function useBlueprintDebugSession({
66
68
  libraryNameById,
67
69
  onExecutionBlocked,
68
70
  onViewScopeUpdate,
71
+ nameSpace = null,
69
72
  }: UseBlueprintDebugSessionOptions) {
70
73
  const runnerRef = useRef<BlueprintGraphRunner | null>(null);
71
74
  const runIdRef = useRef<string | null>(null);
@@ -79,8 +82,12 @@ export function useBlueprintDebugSession({
79
82
  const [logPanelOpen, setLogPanelOpen] = useState(false);
80
83
  const [running, setRunning] = useState(false);
81
84
  const [settings, setSettings] = useState<ExecutionLogSettings>(() =>
82
- readExecutionLogSettings()
85
+ readExecutionLogSettings(nameSpace)
83
86
  );
87
+
88
+ useEffect(() => {
89
+ setSettings(readExecutionLogSettings(nameSpace));
90
+ }, [nameSpace]);
84
91
  const [savedRuns, setSavedRuns] = useState<ExecutionRunRecord[]>([]);
85
92
  const [totalSavedRunCount, setTotalSavedRunCount] = useState(0);
86
93
 
@@ -172,13 +179,13 @@ export function useBlueprintDebugSession({
172
179
  ]);
173
180
 
174
181
  const refreshSavedRuns = useCallback(async () => {
175
- const all = await listExecutionRunRecords();
182
+ const all = await listExecutionRunRecords(undefined, nameSpace);
176
183
  setTotalSavedRunCount(all.length);
177
184
  const items = blueprintId
178
185
  ? all.filter((item) => item.blueprintId === blueprintId)
179
186
  : all;
180
187
  setSavedRuns(items);
181
- }, [blueprintId]);
188
+ }, [blueprintId, nameSpace]);
182
189
 
183
190
  useEffect(() => {
184
191
  if (!logPanelOpen) return;
@@ -187,19 +194,19 @@ export function useBlueprintDebugSession({
187
194
 
188
195
  const enforceSavedRunLimits = useCallback(async () => {
189
196
  const cutoff = retentionCutoffMs(settings.retentionDays);
190
- await purgeExecutionRunsOlderThan(cutoff);
191
- await trimExecutionRunRecordsToMax(settings.maxSavedRuns);
197
+ await purgeExecutionRunsOlderThan(cutoff, nameSpace);
198
+ await trimExecutionRunRecordsToMax(settings.maxSavedRuns, nameSpace);
192
199
  await refreshSavedRuns();
193
- }, [refreshSavedRuns, settings.maxSavedRuns, settings.retentionDays]);
200
+ }, [nameSpace, refreshSavedRuns, settings.maxSavedRuns, settings.retentionDays]);
194
201
 
195
202
  const applyRetention = enforceSavedRunLimits;
196
203
 
197
204
  const clearAllSavedRuns = useCallback(async () => {
198
- const removed = await clearAllExecutionRunRecords();
205
+ const removed = await clearAllExecutionRunRecords(nameSpace);
199
206
  setSavedRuns([]);
200
207
  setTotalSavedRunCount(0);
201
208
  return removed;
202
- }, []);
209
+ }, [nameSpace]);
203
210
 
204
211
  const buildRunRecord = useCallback(
205
212
  (
@@ -229,10 +236,10 @@ export function useBlueprintDebugSession({
229
236
  const persistRunIfNeeded = useCallback(
230
237
  async (record: ExecutionRunRecord) => {
231
238
  if (!settings.autoSave) return;
232
- await putExecutionRunRecord(record);
239
+ await putExecutionRunRecord(record, nameSpace);
233
240
  await enforceSavedRunLimits();
234
241
  },
235
- [enforceSavedRunLimits, settings.autoSave]
242
+ [enforceSavedRunLimits, nameSpace, settings.autoSave]
236
243
  );
237
244
 
238
245
  const beginRun = useCallback(() => {
@@ -420,9 +427,9 @@ export function useBlueprintDebugSession({
420
427
  runnerRef.current?.isDebugQueueEmpty() ? "completed" : "paused",
421
428
  entries
422
429
  );
423
- await putExecutionRunRecord(record);
430
+ await putExecutionRunRecord(record, nameSpace);
424
431
  await enforceSavedRunLimits();
425
- }, [buildRunRecord, enforceSavedRunLimits, entries]);
432
+ }, [buildRunRecord, enforceSavedRunLimits, entries, nameSpace]);
426
433
 
427
434
  const exportCurrentRun = useCallback(() => {
428
435
  if (entries.length === 0) return;
@@ -437,17 +444,17 @@ export function useBlueprintDebugSession({
437
444
  (patch: Partial<ExecutionLogSettings>) => {
438
445
  setSettings((prev) => {
439
446
  const next = { ...prev, ...patch };
440
- writeExecutionLogSettings(next);
447
+ writeExecutionLogSettings(next, nameSpace);
441
448
  return next;
442
449
  });
443
450
  if (patch.maxSavedRuns !== undefined) {
444
451
  const maxSavedRuns = Math.max(1, Math.floor(patch.maxSavedRuns));
445
- void trimExecutionRunRecordsToMax(maxSavedRuns).then(() =>
452
+ void trimExecutionRunRecordsToMax(maxSavedRuns, nameSpace).then(() =>
446
453
  refreshSavedRuns()
447
454
  );
448
455
  }
449
456
  },
450
- [refreshSavedRuns]
457
+ [nameSpace, refreshSavedRuns]
451
458
  );
452
459
 
453
460
  const resetSession = useCallback(() => {
@@ -1,3 +1,4 @@
1
+ import { appStorageKey } from "@arronqzy/blueprint-dsl";
1
2
  import type {
2
3
  BlueprintLibraryListItem,
3
4
  BlueprintLibraryRecord,
@@ -7,9 +8,9 @@ const DB_NAME = "arronqzy-blueprint-library";
7
8
  const DB_VERSION = 1;
8
9
  const STORE_NAME = "blueprints";
9
10
 
10
- function openDb(): Promise<IDBDatabase> {
11
+ function openDb(nameSpace?: string | null): Promise<IDBDatabase> {
11
12
  return new Promise((resolve, reject) => {
12
- const request = indexedDB.open(DB_NAME, DB_VERSION);
13
+ const request = indexedDB.open(appStorageKey(DB_NAME, nameSpace), DB_VERSION);
13
14
  request.onerror = () => reject(request.error ?? new Error("indexeddb-open-failed"));
14
15
  request.onupgradeneeded = () => {
15
16
  const db = request.result;
@@ -25,9 +26,10 @@ function openDb(): Promise<IDBDatabase> {
25
26
 
26
27
  function runTransaction<T>(
27
28
  mode: IDBTransactionMode,
28
- runner: (store: IDBObjectStore) => IDBRequest<T>
29
+ runner: (store: IDBObjectStore) => IDBRequest<T>,
30
+ nameSpace?: string | null
29
31
  ): Promise<T> {
30
- return openDb().then(
32
+ return openDb(nameSpace).then(
31
33
  (db) =>
32
34
  new Promise<T>((resolve, reject) => {
33
35
  const tx = db.transaction(STORE_NAME, mode);
@@ -53,9 +55,13 @@ function runTransaction<T>(
53
55
  );
54
56
  }
55
57
 
56
- export async function listBlueprintLibrary(): Promise<BlueprintLibraryListItem[]> {
57
- const records = await runTransaction<BlueprintLibraryRecord[]>("readonly", (store) =>
58
- store.getAll()
58
+ export async function listBlueprintLibrary(
59
+ nameSpace?: string | null
60
+ ): Promise<BlueprintLibraryListItem[]> {
61
+ const records = await runTransaction<BlueprintLibraryRecord[]>(
62
+ "readonly",
63
+ (store) => store.getAll(),
64
+ nameSpace
59
65
  );
60
66
  return records
61
67
  .map((record) => ({
@@ -69,26 +75,31 @@ export async function listBlueprintLibrary(): Promise<BlueprintLibraryListItem[]
69
75
  }
70
76
 
71
77
  export async function getBlueprintLibraryRecord(
72
- id: string
78
+ id: string,
79
+ nameSpace?: string | null
73
80
  ): Promise<BlueprintLibraryRecord | null> {
74
- const record = await runTransaction<BlueprintLibraryRecord | undefined>("readonly", (store) =>
75
- store.get(id)
81
+ const record = await runTransaction<BlueprintLibraryRecord | undefined>(
82
+ "readonly",
83
+ (store) => store.get(id),
84
+ nameSpace
76
85
  );
77
86
  return record ?? null;
78
87
  }
79
88
 
80
89
  export async function putBlueprintLibraryRecord(
81
- record: BlueprintLibraryRecord
90
+ record: BlueprintLibraryRecord,
91
+ nameSpace?: string | null
82
92
  ): Promise<BlueprintLibraryRecord> {
83
- await runTransaction<IDBValidKey>("readwrite", (store) => store.put(record));
93
+ await runTransaction<IDBValidKey>("readwrite", (store) => store.put(record), nameSpace);
84
94
  return record;
85
95
  }
86
96
 
87
97
  export async function updateBlueprintLibraryMeta(
88
98
  id: string,
89
- patch: { name?: string; remark?: string }
99
+ patch: { name?: string; remark?: string },
100
+ nameSpace?: string | null
90
101
  ): Promise<BlueprintLibraryRecord | null> {
91
- const existing = await getBlueprintLibraryRecord(id);
102
+ const existing = await getBlueprintLibraryRecord(id, nameSpace);
92
103
  if (!existing) return null;
93
104
 
94
105
  const name = patch.name?.trim() || existing.name;
@@ -103,10 +114,13 @@ export async function updateBlueprintLibraryMeta(
103
114
  },
104
115
  };
105
116
 
106
- await putBlueprintLibraryRecord(record);
117
+ await putBlueprintLibraryRecord(record, nameSpace);
107
118
  return record;
108
119
  }
109
120
 
110
- export async function deleteBlueprintLibraryRecord(id: string): Promise<void> {
111
- await runTransaction<undefined>("readwrite", (store) => store.delete(id));
121
+ export async function deleteBlueprintLibraryRecord(
122
+ id: string,
123
+ nameSpace?: string | null
124
+ ): Promise<void> {
125
+ await runTransaction<undefined>("readwrite", (store) => store.delete(id), nameSpace);
112
126
  }
@@ -1,12 +1,13 @@
1
+ import { appStorageKey } from "@arronqzy/blueprint-dsl";
1
2
  import type { ExecutionRunRecord } from "@arronqzy/blueprint-dsl";
2
3
 
3
4
  const DB_NAME = "arronqzy-blueprint-execution-log";
4
5
  const DB_VERSION = 1;
5
6
  const STORE_NAME = "runs";
6
7
 
7
- function openDb(): Promise<IDBDatabase> {
8
+ function openDb(nameSpace?: string | null): Promise<IDBDatabase> {
8
9
  return new Promise((resolve, reject) => {
9
- const request = indexedDB.open(DB_NAME, DB_VERSION);
10
+ const request = indexedDB.open(appStorageKey(DB_NAME, nameSpace), DB_VERSION);
10
11
  request.onerror = () => reject(request.error ?? new Error("indexeddb-open-failed"));
11
12
  request.onupgradeneeded = () => {
12
13
  const db = request.result;
@@ -22,9 +23,10 @@ function openDb(): Promise<IDBDatabase> {
22
23
 
23
24
  function runTransaction<T>(
24
25
  mode: IDBTransactionMode,
25
- runner: (store: IDBObjectStore) => IDBRequest<T>
26
+ runner: (store: IDBObjectStore) => IDBRequest<T>,
27
+ nameSpace?: string | null
26
28
  ): Promise<T> {
27
- return openDb().then(
29
+ return openDb(nameSpace).then(
28
30
  (db) =>
29
31
  new Promise<T>((resolve, reject) => {
30
32
  const tx = db.transaction(STORE_NAME, mode);
@@ -50,28 +52,55 @@ function runTransaction<T>(
50
52
  );
51
53
  }
52
54
 
55
+ function deleteMany(ids: string[], nameSpace?: string | null): Promise<void> {
56
+ return openDb(nameSpace).then(
57
+ (db) =>
58
+ new Promise<void>((resolve, reject) => {
59
+ const tx = db.transaction(STORE_NAME, "readwrite");
60
+ const store = tx.objectStore(STORE_NAME);
61
+ for (const id of ids) {
62
+ store.delete(id);
63
+ }
64
+ tx.oncomplete = () => {
65
+ db.close();
66
+ resolve();
67
+ };
68
+ tx.onerror = () => {
69
+ db.close();
70
+ reject(tx.error ?? new Error("indexeddb-transaction-failed"));
71
+ };
72
+ })
73
+ );
74
+ }
75
+
53
76
  export async function putExecutionRunRecord(
54
- record: ExecutionRunRecord
77
+ record: ExecutionRunRecord,
78
+ nameSpace?: string | null
55
79
  ): Promise<ExecutionRunRecord> {
56
- await runTransaction<IDBValidKey>("readwrite", (store) => store.put(record));
80
+ await runTransaction<IDBValidKey>("readwrite", (store) => store.put(record), nameSpace);
57
81
  return record;
58
82
  }
59
83
 
60
84
  export async function getExecutionRunRecord(
61
- runId: string
85
+ runId: string,
86
+ nameSpace?: string | null
62
87
  ): Promise<ExecutionRunRecord | null> {
63
88
  const record = await runTransaction<ExecutionRunRecord | undefined>(
64
89
  "readonly",
65
- (store) => store.get(runId)
90
+ (store) => store.get(runId),
91
+ nameSpace
66
92
  );
67
93
  return record ?? null;
68
94
  }
69
95
 
70
96
  export async function listExecutionRunRecords(
71
- blueprintId?: string | null
97
+ blueprintId?: string | null,
98
+ nameSpace?: string | null
72
99
  ): Promise<ExecutionRunRecord[]> {
73
- const records = await runTransaction<ExecutionRunRecord[]>("readonly", (store) =>
74
- store.getAll()
100
+ const records = await runTransaction<ExecutionRunRecord[]>(
101
+ "readonly",
102
+ (store) => store.getAll(),
103
+ nameSpace
75
104
  );
76
105
  const filtered = blueprintId
77
106
  ? records.filter((item) => item.blueprintId === blueprintId)
@@ -79,27 +108,37 @@ export async function listExecutionRunRecords(
79
108
  return filtered.sort((a, b) => b.startedAt - a.startedAt);
80
109
  }
81
110
 
82
- export async function deleteExecutionRunRecord(runId: string): Promise<void> {
83
- await runTransaction<undefined>("readwrite", (store) => store.delete(runId));
111
+ export async function deleteExecutionRunRecord(
112
+ runId: string,
113
+ nameSpace?: string | null
114
+ ): Promise<void> {
115
+ await runTransaction<undefined>("readwrite", (store) => store.delete(runId), nameSpace);
84
116
  }
85
117
 
86
- export async function clearAllExecutionRunRecords(): Promise<number> {
87
- const records = await runTransaction<ExecutionRunRecord[]>("readonly", (store) =>
88
- store.getAll()
118
+ export async function clearAllExecutionRunRecords(
119
+ nameSpace?: string | null
120
+ ): Promise<number> {
121
+ const records = await runTransaction<ExecutionRunRecord[]>(
122
+ "readonly",
123
+ (store) => store.getAll(),
124
+ nameSpace
89
125
  );
90
126
  if (records.length === 0) return 0;
91
127
 
92
- await runTransaction<undefined>("readwrite", (store) => store.clear());
128
+ await runTransaction<undefined>("readwrite", (store) => store.clear(), nameSpace);
93
129
  return records.length;
94
130
  }
95
131
 
96
132
  export async function trimExecutionRunRecordsToMax(
97
- maxCount: number
133
+ maxCount: number,
134
+ nameSpace?: string | null
98
135
  ): Promise<number> {
99
136
  if (!Number.isFinite(maxCount) || maxCount < 1) return 0;
100
137
 
101
- const records = await runTransaction<ExecutionRunRecord[]>("readonly", (store) =>
102
- store.getAll()
138
+ const records = await runTransaction<ExecutionRunRecord[]>(
139
+ "readonly",
140
+ (store) => store.getAll(),
141
+ nameSpace
103
142
  );
104
143
  if (records.length <= maxCount) return 0;
105
144
 
@@ -107,52 +146,29 @@ export async function trimExecutionRunRecordsToMax(
107
146
  const overflow = sorted.slice(maxCount);
108
147
  if (overflow.length === 0) return 0;
109
148
 
110
- await openDb().then(
111
- (db) =>
112
- new Promise<void>((resolve, reject) => {
113
- const tx = db.transaction(STORE_NAME, "readwrite");
114
- const store = tx.objectStore(STORE_NAME);
115
- for (const item of overflow) {
116
- store.delete(item.runId);
117
- }
118
- tx.oncomplete = () => {
119
- db.close();
120
- resolve();
121
- };
122
- tx.onerror = () => {
123
- db.close();
124
- reject(tx.error ?? new Error("indexeddb-transaction-failed"));
125
- };
126
- })
149
+ await deleteMany(
150
+ overflow.map((item) => item.runId),
151
+ nameSpace
127
152
  );
128
153
 
129
154
  return overflow.length;
130
155
  }
131
156
 
132
- export async function purgeExecutionRunsOlderThan(cutoffMs: number): Promise<number> {
133
- const records = await runTransaction<ExecutionRunRecord[]>("readonly", (store) =>
134
- store.getAll()
157
+ export async function purgeExecutionRunsOlderThan(
158
+ cutoffMs: number,
159
+ nameSpace?: string | null
160
+ ): Promise<number> {
161
+ const records = await runTransaction<ExecutionRunRecord[]>(
162
+ "readonly",
163
+ (store) => store.getAll(),
164
+ nameSpace
135
165
  );
136
166
  const stale = records.filter((item) => item.startedAt < cutoffMs);
137
167
  if (stale.length === 0) return 0;
138
168
 
139
- await openDb().then(
140
- (db) =>
141
- new Promise<void>((resolve, reject) => {
142
- const tx = db.transaction(STORE_NAME, "readwrite");
143
- const store = tx.objectStore(STORE_NAME);
144
- for (const item of stale) {
145
- store.delete(item.runId);
146
- }
147
- tx.oncomplete = () => {
148
- db.close();
149
- resolve();
150
- };
151
- tx.onerror = () => {
152
- db.close();
153
- reject(tx.error ?? new Error("indexeddb-transaction-failed"));
154
- };
155
- })
169
+ await deleteMany(
170
+ stale.map((item) => item.runId),
171
+ nameSpace
156
172
  );
157
173
 
158
174
  return stale.length;
@@ -1,3 +1,5 @@
1
+ import { appStorageKey } from "@arronqzy/blueprint-dsl";
2
+
1
3
  export type ExecutionLogSettings = {
2
4
  retentionDays: number;
3
5
  autoSave: boolean;
@@ -13,9 +15,11 @@ export const DEFAULT_EXECUTION_LOG_SETTINGS: ExecutionLogSettings = {
13
15
  maxSavedRuns: 80,
14
16
  };
15
17
 
16
- export function readExecutionLogSettings(): ExecutionLogSettings {
18
+ export function readExecutionLogSettings(
19
+ nameSpace?: string | null
20
+ ): ExecutionLogSettings {
17
21
  try {
18
- const raw = localStorage.getItem(SETTINGS_KEY);
22
+ const raw = localStorage.getItem(appStorageKey(SETTINGS_KEY, nameSpace));
19
23
  if (!raw) return { ...DEFAULT_EXECUTION_LOG_SETTINGS };
20
24
  const parsed = JSON.parse(raw) as Partial<ExecutionLogSettings>;
21
25
  return {
@@ -37,9 +41,15 @@ export function readExecutionLogSettings(): ExecutionLogSettings {
37
41
  }
38
42
  }
39
43
 
40
- export function writeExecutionLogSettings(settings: ExecutionLogSettings) {
44
+ export function writeExecutionLogSettings(
45
+ settings: ExecutionLogSettings,
46
+ nameSpace?: string | null
47
+ ) {
41
48
  try {
42
- localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
49
+ localStorage.setItem(
50
+ appStorageKey(SETTINGS_KEY, nameSpace),
51
+ JSON.stringify(settings)
52
+ );
43
53
  } catch {
44
54
  // ignore storage errors
45
55
  }