@sdods/db 0.2.0

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.
Files changed (87) hide show
  1. package/LICENSE +17 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/col.d.ts +32 -0
  4. package/dist/col.js +58 -0
  5. package/dist/create-db.d.ts +14 -0
  6. package/dist/create-db.js +58 -0
  7. package/dist/driver.d.ts +10 -0
  8. package/dist/driver.js +16 -0
  9. package/dist/ids.d.ts +2 -0
  10. package/dist/ids.js +2 -0
  11. package/dist/index.d.ts +17 -0
  12. package/dist/index.js +22 -0
  13. package/dist/ingest/attachments.d.ts +40 -0
  14. package/dist/ingest/attachments.js +154 -0
  15. package/dist/ingest/cucumber-ingest.d.ts +40 -0
  16. package/dist/ingest/cucumber-ingest.js +543 -0
  17. package/dist/ingest/finalize.d.ts +28 -0
  18. package/dist/ingest/finalize.js +132 -0
  19. package/dist/ingest/index.d.ts +26 -0
  20. package/dist/ingest/index.js +193 -0
  21. package/dist/ingest/message-index.d.ts +64 -0
  22. package/dist/ingest/message-index.js +146 -0
  23. package/dist/ingest/parse-ndjson.d.ts +10 -0
  24. package/dist/ingest/parse-ndjson.js +35 -0
  25. package/dist/ingest/pw-json-ingest.d.ts +14 -0
  26. package/dist/ingest/pw-json-ingest.js +259 -0
  27. package/dist/ingest/runner-json-ingest.d.ts +14 -0
  28. package/dist/ingest/runner-json-ingest.js +259 -0
  29. package/dist/ingest/types.d.ts +62 -0
  30. package/dist/ingest/types.js +89 -0
  31. package/dist/insights.d.ts +62 -0
  32. package/dist/insights.js +184 -0
  33. package/dist/migrate.d.ts +30 -0
  34. package/dist/migrate.js +114 -0
  35. package/dist/migrations/0001_platform_init.d.ts +5 -0
  36. package/dist/migrations/0001_platform_init.js +48 -0
  37. package/dist/migrations/0002_results.d.ts +5 -0
  38. package/dist/migrations/0002_results.js +124 -0
  39. package/dist/migrations/0003_improvement.d.ts +5 -0
  40. package/dist/migrations/0003_improvement.js +56 -0
  41. package/dist/migrations/0004_test_data.d.ts +5 -0
  42. package/dist/migrations/0004_test_data.js +48 -0
  43. package/dist/migrations/0005_integrations_agents_audit.d.ts +5 -0
  44. package/dist/migrations/0005_integrations_agents_audit.js +100 -0
  45. package/dist/migrations/0006_schedules.d.ts +5 -0
  46. package/dist/migrations/0006_schedules.js +34 -0
  47. package/dist/migrations/0007_hierarchy.d.ts +5 -0
  48. package/dist/migrations/0007_hierarchy.js +76 -0
  49. package/dist/migrations/0008_runner_naming.d.ts +14 -0
  50. package/dist/migrations/0008_runner_naming.js +35 -0
  51. package/dist/migrations/helpers.d.ts +15 -0
  52. package/dist/migrations/helpers.js +30 -0
  53. package/dist/migrations/index.d.ts +6 -0
  54. package/dist/migrations/index.js +22 -0
  55. package/dist/repos/auth.d.ts +109 -0
  56. package/dist/repos/auth.js +258 -0
  57. package/dist/repos/hierarchy.d.ts +151 -0
  58. package/dist/repos/hierarchy.js +465 -0
  59. package/dist/repos/improvement.d.ts +84 -0
  60. package/dist/repos/improvement.js +242 -0
  61. package/dist/repos/index.d.ts +8 -0
  62. package/dist/repos/index.js +8 -0
  63. package/dist/repos/platform.d.ts +250 -0
  64. package/dist/repos/platform.js +429 -0
  65. package/dist/repos/projects.d.ts +87 -0
  66. package/dist/repos/projects.js +118 -0
  67. package/dist/repos/runs.d.ts +306 -0
  68. package/dist/repos/runs.js +321 -0
  69. package/dist/repos/test-data.d.ts +84 -0
  70. package/dist/repos/test-data.js +291 -0
  71. package/dist/schema.d.ts +514 -0
  72. package/dist/schema.js +37 -0
  73. package/dist/scopes.d.ts +2 -0
  74. package/dist/scopes.js +2 -0
  75. package/dist/switch/export.d.ts +15 -0
  76. package/dist/switch/export.js +67 -0
  77. package/dist/switch/import.d.ts +16 -0
  78. package/dist/switch/import.js +106 -0
  79. package/dist/switch/index.d.ts +5 -0
  80. package/dist/switch/index.js +5 -0
  81. package/dist/switch/prune.d.ts +19 -0
  82. package/dist/switch/prune.js +50 -0
  83. package/dist/switch/switch.d.ts +34 -0
  84. package/dist/switch/switch.js +133 -0
  85. package/dist/test-data.d.ts +22 -0
  86. package/dist/test-data.js +79 -0
  87. package/package.json +50 -0
@@ -0,0 +1,242 @@
1
+ import { sql } from 'kysely';
2
+ import { enc, nowIso, readBool, readJson, readTs } from '../col.js';
3
+ import { newId } from '../ids.js';
4
+ export async function insertHealEvent(db, driver, input) {
5
+ const id = newId();
6
+ const e = input.event;
7
+ await db
8
+ .insertInto('heal_events')
9
+ .values({
10
+ id,
11
+ project_id: input.projectId,
12
+ run_id: input.runId,
13
+ scenario_id: input.scenarioId ?? null,
14
+ attempt_id: input.attemptId ?? null,
15
+ step_id: input.stepId ?? null,
16
+ page_url: e.pageUrl ?? null,
17
+ original_selector: e.originalSelector,
18
+ context_json: enc.json(e.context ?? {}),
19
+ strategy_used: e.strategyUsed ?? null,
20
+ healed_selector: e.healedSelector ?? null,
21
+ candidates_json: enc.json(e.candidates ?? []),
22
+ succeeded: enc.bool(driver, e.succeeded),
23
+ duration_ms: e.durationMs ?? null,
24
+ source: input.source ?? 'runtime',
25
+ accepted: null,
26
+ accepted_by: null,
27
+ created_at: e.at ?? nowIso(),
28
+ })
29
+ .execute();
30
+ return id;
31
+ }
32
+ /** Increment counters for one selector (upsert on project_id + selector). */
33
+ export async function bumpLocatorStats(db, projectId, d) {
34
+ const at = d.at ?? nowIso();
35
+ const existing = await db
36
+ .selectFrom('locator_stats')
37
+ .select(['id'])
38
+ .where('project_id', '=', projectId)
39
+ .where('selector', '=', d.selector)
40
+ .executeTakeFirst();
41
+ const fails = d.fails ?? 0;
42
+ const heals = d.heals ?? 0;
43
+ const uses = d.uses ?? 0;
44
+ if (existing) {
45
+ await db
46
+ .updateTable('locator_stats')
47
+ .set((eb) => ({
48
+ fail_count: eb('fail_count', '+', fails),
49
+ heal_count: eb('heal_count', '+', heals),
50
+ use_count: eb('use_count', '+', uses),
51
+ ...(fails > 0 ? { last_failed_at: at } : {}),
52
+ ...(heals > 0 ? { last_healed_at: at } : {}),
53
+ ...(d.lastStrategy ? { last_strategy: d.lastStrategy } : {}),
54
+ ...(d.suggestedSelector ? { suggested_selector: d.suggestedSelector } : {}),
55
+ ...(d.pageHint ? { page_hint: d.pageHint } : {}),
56
+ updated_at: at,
57
+ }))
58
+ .where('id', '=', existing.id)
59
+ .execute();
60
+ return;
61
+ }
62
+ await db
63
+ .insertInto('locator_stats')
64
+ .values({
65
+ id: newId(),
66
+ project_id: projectId,
67
+ selector: d.selector,
68
+ page_hint: d.pageHint ?? null,
69
+ fail_count: fails,
70
+ heal_count: heals,
71
+ use_count: uses,
72
+ last_failed_at: fails > 0 ? at : null,
73
+ last_healed_at: heals > 0 ? at : null,
74
+ last_strategy: d.lastStrategy ?? null,
75
+ suggested_selector: d.suggestedSelector ?? null,
76
+ updated_at: at,
77
+ })
78
+ .execute();
79
+ }
80
+ export async function listLocatorStats(db, projectId, limit = 50) {
81
+ const rows = await db
82
+ .selectFrom('locator_stats')
83
+ .selectAll()
84
+ .where('project_id', '=', projectId)
85
+ .orderBy('fail_count', 'desc')
86
+ .orderBy('heal_count', 'desc')
87
+ .limit(limit)
88
+ .execute();
89
+ return rows.map((r) => ({
90
+ id: r.id,
91
+ selector: r.selector,
92
+ pageHint: r.page_hint,
93
+ failCount: r.fail_count,
94
+ healCount: r.heal_count,
95
+ useCount: r.use_count,
96
+ lastFailedAt: readTs(r.last_failed_at),
97
+ lastHealedAt: readTs(r.last_healed_at),
98
+ lastStrategy: r.last_strategy,
99
+ suggestedSelector: r.suggested_selector,
100
+ }));
101
+ }
102
+ export async function listHealEvents(db, opts) {
103
+ let q = db
104
+ .selectFrom('heal_events')
105
+ .selectAll()
106
+ .orderBy('created_at', 'desc')
107
+ .limit(opts.limit ?? 100);
108
+ if (opts.projectId)
109
+ q = q.where('project_id', '=', opts.projectId);
110
+ if (opts.runId)
111
+ q = q.where('run_id', '=', opts.runId);
112
+ const rows = await q.execute();
113
+ return rows.map((h) => ({
114
+ id: h.id,
115
+ runId: h.run_id,
116
+ scenarioId: h.scenario_id,
117
+ pageUrl: h.page_url,
118
+ originalSelector: h.original_selector,
119
+ context: readJson(h.context_json) ?? {},
120
+ strategyUsed: h.strategy_used,
121
+ healedSelector: h.healed_selector,
122
+ candidates: readJson(h.candidates_json) ?? [],
123
+ succeeded: readBool(h.succeeded),
124
+ durationMs: h.duration_ms,
125
+ createdAt: readTs(h.created_at),
126
+ }));
127
+ }
128
+ /**
129
+ * Recompute flaky stats for one (project, fingerprint, runner_project) over the last `window` runs.
130
+ */
131
+ export async function recomputeFlakyStats(db, driver, input) {
132
+ const window = input.window ?? 20;
133
+ const rows = await db
134
+ .selectFrom('scenarios')
135
+ .innerJoin('runs', 'runs.id', 'scenarios.run_id')
136
+ .select([
137
+ 'scenarios.status as status',
138
+ 'scenarios.flaky as flaky',
139
+ 'scenarios.run_id as run_id',
140
+ 'scenarios.feature_uri as feature_uri',
141
+ 'scenarios.scenario_name as scenario_name',
142
+ 'scenarios.finished_at as finished_at',
143
+ 'runs.started_at as run_started_at',
144
+ 'runs.created_at as run_created_at',
145
+ ])
146
+ .where('scenarios.project_id', '=', input.projectId)
147
+ .where('scenarios.fingerprint', '=', input.fingerprint)
148
+ .where('scenarios.runner_project', '=', input.runnerProject)
149
+ .orderBy(sql `coalesce(runs.started_at, runs.created_at)`, 'desc')
150
+ .limit(window)
151
+ .execute();
152
+ if (rows.length === 0)
153
+ return;
154
+ const runsCount = rows.length;
155
+ const passCount = rows.filter((r) => r.status === 'passed' && !readBool(r.flaky)).length;
156
+ const failCount = rows.filter((r) => r.status === 'failed' || r.status === 'timedOut').length;
157
+ const flakyCount = rows.filter((r) => readBool(r.flaky)).length;
158
+ const flakyRate = (flakyCount + failCount) / runsCount;
159
+ let failStreak = 0;
160
+ for (const r of rows) {
161
+ if (r.status === 'failed' || r.status === 'timedOut')
162
+ failStreak++;
163
+ else
164
+ break;
165
+ }
166
+ const last = rows[0];
167
+ const lastFailed = rows.find((r) => r.status === 'failed' || r.status === 'timedOut');
168
+ const existing = await db
169
+ .selectFrom('flaky_stats')
170
+ .select(['id'])
171
+ .where('project_id', '=', input.projectId)
172
+ .where('fingerprint', '=', input.fingerprint)
173
+ .where('runner_project', '=', input.runnerProject)
174
+ .executeTakeFirst();
175
+ const values = {
176
+ feature_uri: last.feature_uri,
177
+ scenario_name: last.scenario_name,
178
+ window_size: window,
179
+ runs_count: runsCount,
180
+ pass_count: passCount,
181
+ fail_count: failCount,
182
+ flaky_count: flakyCount,
183
+ flaky_rate: Number(flakyRate.toFixed(4)),
184
+ fail_streak: failStreak,
185
+ last_status: last.status,
186
+ last_run_id: last.run_id,
187
+ last_failed_at: lastFailed ? readTs(lastFailed.finished_at) : null,
188
+ updated_at: nowIso(),
189
+ };
190
+ if (existing) {
191
+ await db.updateTable('flaky_stats').set(values).where('id', '=', existing.id).execute();
192
+ }
193
+ else {
194
+ await db
195
+ .insertInto('flaky_stats')
196
+ .values({
197
+ id: newId(),
198
+ project_id: input.projectId,
199
+ fingerprint: input.fingerprint,
200
+ runner_project: input.runnerProject,
201
+ quarantined: enc.bool(driver, false),
202
+ ...values,
203
+ })
204
+ .execute();
205
+ }
206
+ }
207
+ export async function listFlakyStats(db, projectId, limit = 50) {
208
+ const rows = await db
209
+ .selectFrom('flaky_stats')
210
+ .selectAll()
211
+ .where('project_id', '=', projectId)
212
+ .orderBy('flaky_rate', 'desc')
213
+ .orderBy('fail_streak', 'desc')
214
+ .limit(limit)
215
+ .execute();
216
+ return rows.map((r) => ({
217
+ id: r.id,
218
+ fingerprint: r.fingerprint,
219
+ runnerProject: r.runner_project,
220
+ featureUri: r.feature_uri,
221
+ scenarioName: r.scenario_name,
222
+ windowSize: r.window_size,
223
+ runsCount: r.runs_count,
224
+ passCount: r.pass_count,
225
+ failCount: r.fail_count,
226
+ flakyCount: r.flaky_count,
227
+ flakyRate: Number(r.flaky_rate),
228
+ failStreak: r.fail_streak,
229
+ lastStatus: r.last_status,
230
+ lastRunId: r.last_run_id,
231
+ lastFailedAt: readTs(r.last_failed_at),
232
+ quarantined: readBool(r.quarantined),
233
+ }));
234
+ }
235
+ export async function setQuarantine(db, driver, id, quarantined) {
236
+ await db
237
+ .updateTable('flaky_stats')
238
+ .set({ quarantined: enc.bool(driver, quarantined), updated_at: nowIso() })
239
+ .where('id', '=', id)
240
+ .execute();
241
+ }
242
+ //# sourceMappingURL=improvement.js.map
@@ -0,0 +1,8 @@
1
+ export * from './projects.js';
2
+ export * from './runs.js';
3
+ export * from './improvement.js';
4
+ export * from './test-data.js';
5
+ export * from './auth.js';
6
+ export * from './platform.js';
7
+ export * from './hierarchy.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,8 @@
1
+ export * from './projects.js';
2
+ export * from './runs.js';
3
+ export * from './improvement.js';
4
+ export * from './test-data.js';
5
+ export * from './auth.js';
6
+ export * from './platform.js';
7
+ export * from './hierarchy.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,250 @@
1
+ import type { Kysely } from 'kysely';
2
+ import type { Driver } from '../driver.js';
3
+ import type { Database } from '../schema.js';
4
+ export declare function upsertIntegration(db: Kysely<Database>, driver: Driver, input: {
5
+ projectId: string;
6
+ provider: string;
7
+ config: Record<string, unknown>;
8
+ secretEnv?: Record<string, string>;
9
+ enabled?: boolean;
10
+ }): Promise<string>;
11
+ export declare function listIntegrations(db: Kysely<Database>, projectId: string): Promise<{
12
+ id: string;
13
+ provider: string;
14
+ config: Record<string, unknown>;
15
+ secretEnv: Record<string, string>;
16
+ enabled: boolean;
17
+ lastSyncAt: string | null;
18
+ }[]>;
19
+ export declare function upsertIssueLink(db: Kysely<Database>, input: {
20
+ projectId: string;
21
+ integrationId?: string | null;
22
+ provider: string;
23
+ fingerprint: string;
24
+ scenarioName?: string | null;
25
+ externalKey: string;
26
+ externalUrl?: string | null;
27
+ status?: string;
28
+ source?: string;
29
+ lastRunId?: string | null;
30
+ }): Promise<string>;
31
+ export declare function findOpenIssueLink(db: Kysely<Database>, projectId: string, provider: string, fingerprint: string): Promise<{
32
+ id: any;
33
+ projectId: any;
34
+ integrationId: any;
35
+ provider: any;
36
+ fingerprint: any;
37
+ scenarioName: any;
38
+ externalKey: any;
39
+ externalUrl: any;
40
+ status: any;
41
+ source: any;
42
+ lastRunId: any;
43
+ lastSyncedAt: string | null;
44
+ } | null>;
45
+ export declare function listIssueLinks(db: Kysely<Database>, opts: {
46
+ projectId?: string;
47
+ fingerprint?: string;
48
+ provider?: string;
49
+ }): Promise<{
50
+ id: any;
51
+ projectId: any;
52
+ integrationId: any;
53
+ provider: any;
54
+ fingerprint: any;
55
+ scenarioName: any;
56
+ externalKey: any;
57
+ externalUrl: any;
58
+ status: any;
59
+ source: any;
60
+ lastRunId: any;
61
+ lastSyncedAt: string | null;
62
+ }[]>;
63
+ export declare function setIssueLinkStatus(db: Kysely<Database>, id: string, status: string): Promise<void>;
64
+ export declare function upsertProposal(db: Kysely<Database>, input: {
65
+ id: string;
66
+ projectId: string;
67
+ role: string;
68
+ status?: string;
69
+ summary?: string | null;
70
+ manifest: Record<string, unknown>;
71
+ costUsd?: number | null;
72
+ model?: string | null;
73
+ createdBy?: string | null;
74
+ }): Promise<void>;
75
+ export declare function reviewProposal(db: Kysely<Database>, id: string, status: 'accepted' | 'rejected', reviewedBy?: string | null): Promise<void>;
76
+ export declare function listProposals(db: Kysely<Database>, opts?: {
77
+ projectId?: string;
78
+ status?: string;
79
+ limit?: number;
80
+ }): Promise<{
81
+ id: string;
82
+ projectId: string;
83
+ role: string;
84
+ status: string;
85
+ summary: string | null;
86
+ manifest: Record<string, unknown>;
87
+ costUsd: number | null;
88
+ model: string | null;
89
+ createdBy: string | null;
90
+ reviewedBy: string | null;
91
+ createdAt: string | null;
92
+ reviewedAt: string | null;
93
+ }[]>;
94
+ export declare function createAgentJob(db: Kysely<Database>, input: {
95
+ projectId: string;
96
+ kind: string;
97
+ goal?: string | null;
98
+ input?: Record<string, unknown>;
99
+ provider?: string | null;
100
+ model?: string | null;
101
+ startedBy?: string | null;
102
+ }): Promise<string>;
103
+ export declare function updateAgentJob(db: Kysely<Database>, id: string, patch: Partial<{
104
+ status: string;
105
+ output: Record<string, unknown>;
106
+ diffText: string | null;
107
+ logRel: string | null;
108
+ tokensIn: number;
109
+ tokensOut: number;
110
+ costUsd: number;
111
+ turns: number;
112
+ proposalId: string | null;
113
+ startedAt: string;
114
+ finishedAt: string;
115
+ error: string | null;
116
+ reviewedBy: string | null;
117
+ reviewedAt: string;
118
+ }>): Promise<void>;
119
+ export declare function getAgentJob(db: Kysely<Database>, id: string): Promise<{
120
+ id: any;
121
+ projectId: any;
122
+ kind: any;
123
+ goal: any;
124
+ status: any;
125
+ input: Record<string, unknown>;
126
+ output: Record<string, unknown> | null;
127
+ diffText: any;
128
+ logRel: any;
129
+ provider: any;
130
+ model: any;
131
+ tokensIn: any;
132
+ tokensOut: any;
133
+ costUsd: any;
134
+ turns: any;
135
+ proposalId: any;
136
+ startedBy: any;
137
+ startedAt: string | null;
138
+ finishedAt: string | null;
139
+ error: any;
140
+ createdAt: string | null;
141
+ } | null>;
142
+ export declare function listAgentJobs(db: Kysely<Database>, opts?: {
143
+ projectId?: string;
144
+ status?: string;
145
+ limit?: number;
146
+ }): Promise<{
147
+ id: any;
148
+ projectId: any;
149
+ kind: any;
150
+ goal: any;
151
+ status: any;
152
+ input: Record<string, unknown>;
153
+ output: Record<string, unknown> | null;
154
+ diffText: any;
155
+ logRel: any;
156
+ provider: any;
157
+ model: any;
158
+ tokensIn: any;
159
+ tokensOut: any;
160
+ costUsd: any;
161
+ turns: any;
162
+ proposalId: any;
163
+ startedBy: any;
164
+ startedAt: string | null;
165
+ finishedAt: string | null;
166
+ error: any;
167
+ createdAt: string | null;
168
+ }[]>;
169
+ export interface ScheduleUpsert {
170
+ projectId: string;
171
+ environmentId?: string | null;
172
+ name: string;
173
+ cronExpr: string;
174
+ timezone?: string;
175
+ runInput: Record<string, unknown>;
176
+ overlapPolicy?: string;
177
+ jitterSeconds?: number;
178
+ catchUp?: boolean;
179
+ enabled?: boolean;
180
+ notify?: unknown;
181
+ retentionRuns?: number | null;
182
+ nextRunAt?: string | null;
183
+ createdBy?: string | null;
184
+ }
185
+ export declare function upsertSchedule(db: Kysely<Database>, driver: Driver, s: ScheduleUpsert): Promise<string>;
186
+ export declare function listSchedules(db: Kysely<Database>, projectId?: string): Promise<{
187
+ id: string;
188
+ projectId: string;
189
+ environmentId: string | null;
190
+ name: string;
191
+ cronExpr: string;
192
+ timezone: string;
193
+ runInput: Record<string, unknown>;
194
+ overlapPolicy: string;
195
+ jitterSeconds: number;
196
+ catchUp: boolean;
197
+ enabled: boolean;
198
+ notify: {};
199
+ retentionRuns: number | null;
200
+ nextRunAt: string | null;
201
+ lastRunId: string | null;
202
+ lastStatus: string | null;
203
+ }[]>;
204
+ export declare function updateScheduleState(db: Kysely<Database>, id: string, patch: {
205
+ nextRunAt?: string | null;
206
+ lastRunId?: string | null;
207
+ lastStatus?: string | null;
208
+ enabled?: boolean;
209
+ }, driver: Driver): Promise<void>;
210
+ export declare function deleteSchedule(db: Kysely<Database>, id: string): Promise<void>;
211
+ export declare function recordScheduleRun(db: Kysely<Database>, input: {
212
+ scheduleId: string;
213
+ runId?: string | null;
214
+ status: string;
215
+ note?: string | null;
216
+ }): Promise<void>;
217
+ export declare function listScheduleRuns(db: Kysely<Database>, scheduleId: string, limit?: number): Promise<{
218
+ id: string;
219
+ status: string;
220
+ run_id: string | null;
221
+ schedule_id: string;
222
+ fired_at: string;
223
+ note: string | null;
224
+ }[]>;
225
+ export declare function audit(db: Kysely<Database>, input: {
226
+ actorUserId?: string | null;
227
+ actorType?: 'user' | 'cli' | 'system' | 'token';
228
+ action: string;
229
+ targetType?: string | null;
230
+ targetId?: string | null;
231
+ details?: Record<string, unknown>;
232
+ ip?: string | null;
233
+ }): Promise<void>;
234
+ export declare function listAudit(db: Kysely<Database>, opts?: {
235
+ limit?: number;
236
+ before?: string;
237
+ }): Promise<{
238
+ details: unknown;
239
+ createdAt: string | null;
240
+ id: string;
241
+ created_at: string;
242
+ ip: string | null;
243
+ actor_user_id: string | null;
244
+ actor_type: string;
245
+ action: string;
246
+ target_type: string | null;
247
+ target_id: string | null;
248
+ details_json: Record<string, unknown> | null;
249
+ }[]>;
250
+ //# sourceMappingURL=platform.d.ts.map