@archiva/archiva-nextjs 0.2.92 → 0.2.94
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-A3Q4YKTK.mjs +268 -0
- package/dist/chunk-WA7TMG65.mjs +81 -0
- package/dist/index-Bk4DxULy.d.mts +139 -0
- package/dist/index-Bk4DxULy.d.ts +139 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +79 -14
- package/dist/index.mjs +2 -1
- package/dist/react/client.js +141 -30
- package/dist/react/client.mjs +66 -30
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +79 -14
- package/dist/server/index.mjs +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeAuditEventItem
|
|
3
|
+
} from "./chunk-WA7TMG65.mjs";
|
|
4
|
+
|
|
5
|
+
// src/types.ts
|
|
6
|
+
var ArchivaError = class extends Error {
|
|
7
|
+
constructor(params) {
|
|
8
|
+
super(params.message);
|
|
9
|
+
this.statusCode = params.statusCode;
|
|
10
|
+
this.code = params.code;
|
|
11
|
+
this.retryAfterSeconds = params.retryAfterSeconds;
|
|
12
|
+
this.details = params.details;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/client.ts
|
|
17
|
+
var DEFAULT_BASE_URL = "https://api.archiva.app";
|
|
18
|
+
function buildHeaders(apiKey, overrides) {
|
|
19
|
+
const headers = new Headers(overrides);
|
|
20
|
+
headers.set("X-Project-Key", apiKey);
|
|
21
|
+
return headers;
|
|
22
|
+
}
|
|
23
|
+
async function parseError(response) {
|
|
24
|
+
const retryAfterHeader = response.headers.get("Retry-After");
|
|
25
|
+
const retryAfterSeconds = retryAfterHeader ? Number(retryAfterHeader) : void 0;
|
|
26
|
+
let payload = void 0;
|
|
27
|
+
try {
|
|
28
|
+
payload = await response.json();
|
|
29
|
+
} catch {
|
|
30
|
+
payload = void 0;
|
|
31
|
+
}
|
|
32
|
+
const errorMessage = typeof payload === "object" && payload !== null && "error" in payload ? String(payload.error) : response.statusText;
|
|
33
|
+
let code = "HTTP_ERROR";
|
|
34
|
+
if (response.status === 401) {
|
|
35
|
+
code = "UNAUTHORIZED";
|
|
36
|
+
} else if (response.status === 403) {
|
|
37
|
+
code = "FORBIDDEN";
|
|
38
|
+
} else if (response.status === 413) {
|
|
39
|
+
code = "PAYLOAD_TOO_LARGE";
|
|
40
|
+
} else if (response.status === 429) {
|
|
41
|
+
code = "RATE_LIMITED";
|
|
42
|
+
} else if (response.status === 409) {
|
|
43
|
+
code = "IDEMPOTENCY_CONFLICT";
|
|
44
|
+
}
|
|
45
|
+
throw new ArchivaError({
|
|
46
|
+
statusCode: response.status,
|
|
47
|
+
code,
|
|
48
|
+
message: errorMessage,
|
|
49
|
+
retryAfterSeconds,
|
|
50
|
+
details: payload
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function createRequestId() {
|
|
54
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
55
|
+
return crypto.randomUUID();
|
|
56
|
+
}
|
|
57
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
58
|
+
}
|
|
59
|
+
function createIdempotencyKey() {
|
|
60
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
61
|
+
return `idem_${crypto.randomUUID()}`;
|
|
62
|
+
}
|
|
63
|
+
return `idem_${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
64
|
+
}
|
|
65
|
+
async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
|
|
66
|
+
const url = new URL(`${baseUrl}/api/events`);
|
|
67
|
+
if (params.entityId) {
|
|
68
|
+
url.searchParams.set("entityId", params.entityId);
|
|
69
|
+
}
|
|
70
|
+
if (params.actorId) {
|
|
71
|
+
url.searchParams.set("actorId", params.actorId);
|
|
72
|
+
}
|
|
73
|
+
if (params.entityType) {
|
|
74
|
+
url.searchParams.set("entityType", params.entityType);
|
|
75
|
+
}
|
|
76
|
+
if (params.actorType) {
|
|
77
|
+
url.searchParams.set("actorType", params.actorType);
|
|
78
|
+
}
|
|
79
|
+
if (params.limit) {
|
|
80
|
+
url.searchParams.set("limit", String(params.limit));
|
|
81
|
+
}
|
|
82
|
+
if (params.cursor) {
|
|
83
|
+
url.searchParams.set("cursor", params.cursor);
|
|
84
|
+
}
|
|
85
|
+
const response = await fetch(url.toString(), {
|
|
86
|
+
headers: buildHeaders(apiKey)
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
await parseError(response);
|
|
90
|
+
}
|
|
91
|
+
const payload = await response.json();
|
|
92
|
+
if (!payload || typeof payload !== "object" || !Array.isArray(payload.items)) {
|
|
93
|
+
throw new ArchivaError({
|
|
94
|
+
statusCode: response.status,
|
|
95
|
+
code: "HTTP_ERROR",
|
|
96
|
+
message: "Invalid response format",
|
|
97
|
+
details: payload
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const items = payload.items.map((item) => {
|
|
101
|
+
if (typeof item !== "object" || item === null) {
|
|
102
|
+
throw new ArchivaError({
|
|
103
|
+
statusCode: response.status,
|
|
104
|
+
code: "HTTP_ERROR",
|
|
105
|
+
message: "Invalid item format in response",
|
|
106
|
+
details: item
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return normalizeAuditEventItem(item);
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
items,
|
|
113
|
+
nextCursor: typeof payload.nextCursor === "string" ? payload.nextCursor : void 0
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
async function createEvent(apiKey, event, options, baseUrl = DEFAULT_BASE_URL) {
|
|
117
|
+
const idempotencyKey = options?.idempotencyKey ?? createIdempotencyKey();
|
|
118
|
+
const requestId = options?.requestId ?? createRequestId();
|
|
119
|
+
const headers = buildHeaders(apiKey, {
|
|
120
|
+
"Content-Type": "application/json",
|
|
121
|
+
"Idempotency-Key": idempotencyKey,
|
|
122
|
+
"X-Request-Id": requestId
|
|
123
|
+
});
|
|
124
|
+
const response = await fetch(`${baseUrl}/api/ingest/event`, {
|
|
125
|
+
method: "POST",
|
|
126
|
+
headers,
|
|
127
|
+
body: JSON.stringify(event)
|
|
128
|
+
});
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
await parseError(response);
|
|
131
|
+
}
|
|
132
|
+
const payload = await response.json();
|
|
133
|
+
if (!payload || typeof payload !== "object" || typeof payload.eventId !== "string") {
|
|
134
|
+
throw new ArchivaError({
|
|
135
|
+
statusCode: response.status,
|
|
136
|
+
code: "HTTP_ERROR",
|
|
137
|
+
message: "Invalid response format",
|
|
138
|
+
details: payload
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
eventId: payload.eventId,
|
|
143
|
+
replayed: response.status === 200
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async function createEvents(apiKey, events, options, baseUrl = DEFAULT_BASE_URL) {
|
|
147
|
+
const results = await Promise.all(
|
|
148
|
+
events.map(
|
|
149
|
+
(event, index) => createEvent(
|
|
150
|
+
apiKey,
|
|
151
|
+
event,
|
|
152
|
+
{
|
|
153
|
+
...options,
|
|
154
|
+
idempotencyKey: options?.idempotencyKey ? `${options.idempotencyKey}_${index}` : void 0
|
|
155
|
+
},
|
|
156
|
+
baseUrl
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
);
|
|
160
|
+
return {
|
|
161
|
+
eventIds: results.map((r) => r.eventId)
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/actions.ts
|
|
166
|
+
var DEFAULT_BASE_URL2 = "https://api.archiva.app";
|
|
167
|
+
function getApiKey(apiKey) {
|
|
168
|
+
const resolvedKey = apiKey || process.env.ARCHIVA_SECRET_KEY;
|
|
169
|
+
if (!resolvedKey) {
|
|
170
|
+
throw new Error("ARCHIVA_SECRET_KEY environment variable is required, or provide apiKey prop to ArchivaProvider");
|
|
171
|
+
}
|
|
172
|
+
return resolvedKey;
|
|
173
|
+
}
|
|
174
|
+
async function loadEvents2(params, apiKey) {
|
|
175
|
+
const resolvedApiKey = getApiKey(apiKey);
|
|
176
|
+
return loadEvents(resolvedApiKey, params, DEFAULT_BASE_URL2);
|
|
177
|
+
}
|
|
178
|
+
async function createEvent2(event, options, apiKey) {
|
|
179
|
+
const resolvedApiKey = getApiKey(apiKey);
|
|
180
|
+
return createEvent(resolvedApiKey, event, options, DEFAULT_BASE_URL2);
|
|
181
|
+
}
|
|
182
|
+
async function createEvents2(events, options, apiKey) {
|
|
183
|
+
const resolvedApiKey = getApiKey(apiKey);
|
|
184
|
+
return createEvents(resolvedApiKey, events, options, DEFAULT_BASE_URL2);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/server/frontendTokens.ts
|
|
188
|
+
import "server-only";
|
|
189
|
+
var DEFAULT_API_BASE_URL = "https://api.archiva.app";
|
|
190
|
+
async function createFrontendTokenGET(projectId, apiBaseUrl = DEFAULT_API_BASE_URL) {
|
|
191
|
+
const secretKey = process.env.ARCHIVA_SECRET_KEY;
|
|
192
|
+
if (!secretKey || secretKey.trim().length === 0) {
|
|
193
|
+
const exists = process.env.ARCHIVA_SECRET_KEY !== void 0;
|
|
194
|
+
throw new Error(
|
|
195
|
+
`ARCHIVA_SECRET_KEY environment variable is ${exists ? "empty" : "not configured"}. Please set it in your .env.local file (or .env) with a valid value and restart your Next.js dev server. The variable must be in the project root directory and must not be empty.`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
const keyPrefix = secretKey.substring(0, 10);
|
|
199
|
+
console.log("[Archiva] Using API key prefix:", keyPrefix + "...", "Length:", secretKey.length);
|
|
200
|
+
const url = new URL(`${apiBaseUrl}/api/v1/frontend-tokens`);
|
|
201
|
+
const response = await fetch(url.toString(), {
|
|
202
|
+
method: "POST",
|
|
203
|
+
headers: {
|
|
204
|
+
"Content-Type": "application/json",
|
|
205
|
+
"Authorization": `Bearer ${secretKey}`
|
|
206
|
+
},
|
|
207
|
+
body: JSON.stringify({
|
|
208
|
+
scopes: ["timeline:read"],
|
|
209
|
+
...projectId && { projectId }
|
|
210
|
+
})
|
|
211
|
+
});
|
|
212
|
+
if (!response.ok) {
|
|
213
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
214
|
+
const errorMessage = error.error || `Failed to fetch frontend token: ${response.status}`;
|
|
215
|
+
if (errorMessage.includes("ARCHIVA_SECRET_KEY") || response.status === 401 || response.status === 403) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`Archiva API authentication failed. Check that your ARCHIVA_SECRET_KEY is valid and has the correct permissions. API error: ${errorMessage}`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
throw new Error(errorMessage);
|
|
221
|
+
}
|
|
222
|
+
const data = await response.json();
|
|
223
|
+
if (!data.token || typeof data.expiresAt !== "number") {
|
|
224
|
+
throw new Error("Invalid token response format");
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
token: data.token,
|
|
228
|
+
expiresAt: data.expiresAt
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/server/handlers/createFrontendTokenRoute.ts
|
|
233
|
+
import "server-only";
|
|
234
|
+
import { NextResponse } from "next/server";
|
|
235
|
+
var DEFAULT_API_BASE_URL2 = "https://api.archiva.app";
|
|
236
|
+
function createFrontendTokenRoute(options) {
|
|
237
|
+
return async function GET2(request) {
|
|
238
|
+
try {
|
|
239
|
+
const searchParams = request.nextUrl.searchParams;
|
|
240
|
+
const projectId = searchParams.get("projectId") || void 0;
|
|
241
|
+
const apiBaseUrl = options?.apiBaseUrl || DEFAULT_API_BASE_URL2;
|
|
242
|
+
const tokenResponse = await createFrontendTokenGET(projectId, apiBaseUrl);
|
|
243
|
+
return NextResponse.json(tokenResponse);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error("Error fetching frontend token:", error);
|
|
246
|
+
const message = error instanceof Error ? error.message : "Internal server error";
|
|
247
|
+
const statusCode = message.includes("ARCHIVA_SECRET_KEY") ? 500 : 500;
|
|
248
|
+
return NextResponse.json(
|
|
249
|
+
{ error: message },
|
|
250
|
+
{ status: statusCode }
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
async function GET(request) {
|
|
256
|
+
const handler = createFrontendTokenRoute();
|
|
257
|
+
return handler(request);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export {
|
|
261
|
+
ArchivaError,
|
|
262
|
+
loadEvents2 as loadEvents,
|
|
263
|
+
createEvent2 as createEvent,
|
|
264
|
+
createEvents2 as createEvents,
|
|
265
|
+
createFrontendTokenGET,
|
|
266
|
+
createFrontendTokenRoute,
|
|
267
|
+
GET
|
|
268
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/eventNormalizer.ts
|
|
2
|
+
var coerceString = (value) => {
|
|
3
|
+
if (value === null || value === void 0) {
|
|
4
|
+
return void 0;
|
|
5
|
+
}
|
|
6
|
+
if (typeof value === "string") {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
10
|
+
return String(value);
|
|
11
|
+
}
|
|
12
|
+
return void 0;
|
|
13
|
+
};
|
|
14
|
+
var coerceNullableString = (value) => {
|
|
15
|
+
if (value === null || value === void 0) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
if (typeof value === "string") {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
22
|
+
return String(value);
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
26
|
+
var coerceActorType = (value) => {
|
|
27
|
+
if (typeof value !== "string") {
|
|
28
|
+
return void 0;
|
|
29
|
+
}
|
|
30
|
+
const normalized = value.toLowerCase();
|
|
31
|
+
if (normalized === "user" || normalized === "service" || normalized === "system") {
|
|
32
|
+
return normalized;
|
|
33
|
+
}
|
|
34
|
+
return void 0;
|
|
35
|
+
};
|
|
36
|
+
var getActorValue = (event, actorRecord, keys) => {
|
|
37
|
+
for (const key of keys) {
|
|
38
|
+
if (Object.prototype.hasOwnProperty.call(event, key)) {
|
|
39
|
+
return event[key];
|
|
40
|
+
}
|
|
41
|
+
if (actorRecord && Object.prototype.hasOwnProperty.call(actorRecord, key)) {
|
|
42
|
+
return actorRecord[key];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return void 0;
|
|
46
|
+
};
|
|
47
|
+
var normalizeAuditEventItem = (event) => {
|
|
48
|
+
const actorRecord = typeof event.actor === "object" && event.actor !== null ? event.actor : void 0;
|
|
49
|
+
const actorDisplayValue = getActorValue(event, actorRecord, [
|
|
50
|
+
"actorDisplay",
|
|
51
|
+
"actor_display",
|
|
52
|
+
"display",
|
|
53
|
+
"display_name",
|
|
54
|
+
"name"
|
|
55
|
+
]);
|
|
56
|
+
const actorTypeValue = getActorValue(event, actorRecord, [
|
|
57
|
+
"actorType",
|
|
58
|
+
"actor_type",
|
|
59
|
+
"type"
|
|
60
|
+
]);
|
|
61
|
+
const actorIdValue = getActorValue(event, actorRecord, [
|
|
62
|
+
"actorId",
|
|
63
|
+
"actor_id",
|
|
64
|
+
"id"
|
|
65
|
+
]);
|
|
66
|
+
return {
|
|
67
|
+
id: coerceString(event.id) ?? "",
|
|
68
|
+
receivedAt: coerceString(event.receivedAt ?? event.received_at) ?? "",
|
|
69
|
+
action: coerceString(event.action) ?? "",
|
|
70
|
+
entityType: coerceString(event.entityType ?? event.entity_type) ?? "",
|
|
71
|
+
entityId: coerceString(event.entityId ?? event.entity_id) ?? "",
|
|
72
|
+
actorId: coerceNullableString(actorIdValue),
|
|
73
|
+
actorType: coerceActorType(actorTypeValue),
|
|
74
|
+
actorDisplay: coerceString(actorDisplayValue) ?? "",
|
|
75
|
+
source: coerceNullableString(event.source)
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
normalizeAuditEventItem
|
|
81
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
type EventChange = {
|
|
4
|
+
op: "set" | "unset" | "add" | "remove" | "replace" | string;
|
|
5
|
+
path: string;
|
|
6
|
+
before?: unknown;
|
|
7
|
+
after?: unknown;
|
|
8
|
+
};
|
|
9
|
+
type CreateEventInput = {
|
|
10
|
+
action: string;
|
|
11
|
+
entityType: string;
|
|
12
|
+
entityId: string;
|
|
13
|
+
actorType?: string;
|
|
14
|
+
actorId?: string;
|
|
15
|
+
actorDisplay?: string;
|
|
16
|
+
occurredAt?: string;
|
|
17
|
+
source?: string;
|
|
18
|
+
context?: Record<string, unknown>;
|
|
19
|
+
changes?: EventChange[];
|
|
20
|
+
};
|
|
21
|
+
type CreateEventOptions = {
|
|
22
|
+
idempotencyKey?: string;
|
|
23
|
+
requestId?: string;
|
|
24
|
+
};
|
|
25
|
+
type AuditEventListItem = {
|
|
26
|
+
id: string;
|
|
27
|
+
receivedAt: string;
|
|
28
|
+
action: string;
|
|
29
|
+
entityType: string;
|
|
30
|
+
entityId: string;
|
|
31
|
+
actorId: string | null;
|
|
32
|
+
actorType?: 'user' | 'service' | 'system';
|
|
33
|
+
actorDisplay: string;
|
|
34
|
+
source: string | null;
|
|
35
|
+
};
|
|
36
|
+
type PageResult<T> = {
|
|
37
|
+
items: T[];
|
|
38
|
+
nextCursor?: string;
|
|
39
|
+
};
|
|
40
|
+
type LoadEventsParams = {
|
|
41
|
+
entityId?: string;
|
|
42
|
+
actorId?: string;
|
|
43
|
+
entityType?: string;
|
|
44
|
+
actorType?: 'user' | 'service' | 'system';
|
|
45
|
+
limit?: number;
|
|
46
|
+
cursor?: string;
|
|
47
|
+
};
|
|
48
|
+
declare class ArchivaError extends Error {
|
|
49
|
+
statusCode: number;
|
|
50
|
+
code: "UNAUTHORIZED" | "FORBIDDEN" | "PAYLOAD_TOO_LARGE" | "RATE_LIMITED" | "IDEMPOTENCY_CONFLICT" | "HTTP_ERROR";
|
|
51
|
+
retryAfterSeconds?: number;
|
|
52
|
+
details?: unknown;
|
|
53
|
+
constructor(params: {
|
|
54
|
+
statusCode: number;
|
|
55
|
+
code: "UNAUTHORIZED" | "FORBIDDEN" | "PAYLOAD_TOO_LARGE" | "RATE_LIMITED" | "IDEMPOTENCY_CONFLICT" | "HTTP_ERROR";
|
|
56
|
+
message: string;
|
|
57
|
+
retryAfterSeconds?: number;
|
|
58
|
+
details?: unknown;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Server action to load audit events
|
|
64
|
+
*
|
|
65
|
+
* @param params - Query parameters for filtering events
|
|
66
|
+
* @param apiKey - Optional API key (otherwise uses ARCHIVA_SECRET_KEY env var)
|
|
67
|
+
* @returns Paginated list of audit events
|
|
68
|
+
*/
|
|
69
|
+
declare function loadEvents(params: LoadEventsParams, apiKey?: string): Promise<PageResult<AuditEventListItem>>;
|
|
70
|
+
/**
|
|
71
|
+
* Server action to create a single audit event
|
|
72
|
+
*
|
|
73
|
+
* @param event - Event data to create
|
|
74
|
+
* @param options - Optional idempotency and request ID options
|
|
75
|
+
* @param apiKey - Optional API key (otherwise uses ARCHIVA_SECRET_KEY env var)
|
|
76
|
+
* @returns Created event ID and replay status
|
|
77
|
+
*/
|
|
78
|
+
declare function createEvent(event: CreateEventInput, options?: CreateEventOptions, apiKey?: string): Promise<{
|
|
79
|
+
eventId: string;
|
|
80
|
+
replayed: boolean;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Server action to create multiple audit events (bulk)
|
|
84
|
+
*
|
|
85
|
+
* @param events - Array of events to create
|
|
86
|
+
* @param options - Optional idempotency and request ID options
|
|
87
|
+
* @param apiKey - Optional API key (otherwise uses ARCHIVA_SECRET_KEY env var)
|
|
88
|
+
* @returns Array of created event IDs
|
|
89
|
+
*/
|
|
90
|
+
declare function createEvents(events: CreateEventInput[], options?: CreateEventOptions, apiKey?: string): Promise<{
|
|
91
|
+
eventIds: string[];
|
|
92
|
+
}>;
|
|
93
|
+
|
|
94
|
+
interface FrontendTokenResponse {
|
|
95
|
+
token: string;
|
|
96
|
+
expiresAt: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Fetches a frontend token from the Archiva API
|
|
100
|
+
*
|
|
101
|
+
* @param projectId - Optional project ID for scoping
|
|
102
|
+
* @param apiBaseUrl - Archiva API base URL (defaults to https://api.archiva.app)
|
|
103
|
+
* @returns Frontend token response
|
|
104
|
+
*/
|
|
105
|
+
declare function createFrontendTokenGET(projectId?: string, apiBaseUrl?: string): Promise<FrontendTokenResponse>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Next.js route handler for GET /api/archiva/frontend-token
|
|
109
|
+
*
|
|
110
|
+
* This handler can be used in the host app's route file:
|
|
111
|
+
*
|
|
112
|
+
* ```ts
|
|
113
|
+
* // app/api/archiva/frontend-token/route.ts
|
|
114
|
+
* export { GET } from '@archiva/archiva-nextjs/server';
|
|
115
|
+
* ```
|
|
116
|
+
*
|
|
117
|
+
* Or with custom configuration:
|
|
118
|
+
*
|
|
119
|
+
* ```ts
|
|
120
|
+
* import { createFrontendTokenRoute } from '@archiva/archiva-nextjs/server';
|
|
121
|
+
*
|
|
122
|
+
* export const GET = createFrontendTokenRoute({
|
|
123
|
+
* apiBaseUrl: process.env.ARCHIVA_API_URL,
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function createFrontendTokenRoute(options?: {
|
|
128
|
+
apiBaseUrl?: string;
|
|
129
|
+
}): (request: NextRequest) => Promise<NextResponse<FrontendTokenResponse> | NextResponse<{
|
|
130
|
+
error: string;
|
|
131
|
+
}>>;
|
|
132
|
+
/**
|
|
133
|
+
* Default GET handler (for direct export)
|
|
134
|
+
*/
|
|
135
|
+
declare function GET(request: NextRequest): Promise<NextResponse<FrontendTokenResponse> | NextResponse<{
|
|
136
|
+
error: string;
|
|
137
|
+
}>>;
|
|
138
|
+
|
|
139
|
+
export { ArchivaError as A, type CreateEventInput as C, type EventChange as E, type FrontendTokenResponse as F, GET as G, type LoadEventsParams as L, type PageResult as P, createEvents as a, createFrontendTokenGET as b, createEvent as c, createFrontendTokenRoute as d, type CreateEventOptions as e, type AuditEventListItem as f, loadEvents as l };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
type EventChange = {
|
|
4
|
+
op: "set" | "unset" | "add" | "remove" | "replace" | string;
|
|
5
|
+
path: string;
|
|
6
|
+
before?: unknown;
|
|
7
|
+
after?: unknown;
|
|
8
|
+
};
|
|
9
|
+
type CreateEventInput = {
|
|
10
|
+
action: string;
|
|
11
|
+
entityType: string;
|
|
12
|
+
entityId: string;
|
|
13
|
+
actorType?: string;
|
|
14
|
+
actorId?: string;
|
|
15
|
+
actorDisplay?: string;
|
|
16
|
+
occurredAt?: string;
|
|
17
|
+
source?: string;
|
|
18
|
+
context?: Record<string, unknown>;
|
|
19
|
+
changes?: EventChange[];
|
|
20
|
+
};
|
|
21
|
+
type CreateEventOptions = {
|
|
22
|
+
idempotencyKey?: string;
|
|
23
|
+
requestId?: string;
|
|
24
|
+
};
|
|
25
|
+
type AuditEventListItem = {
|
|
26
|
+
id: string;
|
|
27
|
+
receivedAt: string;
|
|
28
|
+
action: string;
|
|
29
|
+
entityType: string;
|
|
30
|
+
entityId: string;
|
|
31
|
+
actorId: string | null;
|
|
32
|
+
actorType?: 'user' | 'service' | 'system';
|
|
33
|
+
actorDisplay: string;
|
|
34
|
+
source: string | null;
|
|
35
|
+
};
|
|
36
|
+
type PageResult<T> = {
|
|
37
|
+
items: T[];
|
|
38
|
+
nextCursor?: string;
|
|
39
|
+
};
|
|
40
|
+
type LoadEventsParams = {
|
|
41
|
+
entityId?: string;
|
|
42
|
+
actorId?: string;
|
|
43
|
+
entityType?: string;
|
|
44
|
+
actorType?: 'user' | 'service' | 'system';
|
|
45
|
+
limit?: number;
|
|
46
|
+
cursor?: string;
|
|
47
|
+
};
|
|
48
|
+
declare class ArchivaError extends Error {
|
|
49
|
+
statusCode: number;
|
|
50
|
+
code: "UNAUTHORIZED" | "FORBIDDEN" | "PAYLOAD_TOO_LARGE" | "RATE_LIMITED" | "IDEMPOTENCY_CONFLICT" | "HTTP_ERROR";
|
|
51
|
+
retryAfterSeconds?: number;
|
|
52
|
+
details?: unknown;
|
|
53
|
+
constructor(params: {
|
|
54
|
+
statusCode: number;
|
|
55
|
+
code: "UNAUTHORIZED" | "FORBIDDEN" | "PAYLOAD_TOO_LARGE" | "RATE_LIMITED" | "IDEMPOTENCY_CONFLICT" | "HTTP_ERROR";
|
|
56
|
+
message: string;
|
|
57
|
+
retryAfterSeconds?: number;
|
|
58
|
+
details?: unknown;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Server action to load audit events
|
|
64
|
+
*
|
|
65
|
+
* @param params - Query parameters for filtering events
|
|
66
|
+
* @param apiKey - Optional API key (otherwise uses ARCHIVA_SECRET_KEY env var)
|
|
67
|
+
* @returns Paginated list of audit events
|
|
68
|
+
*/
|
|
69
|
+
declare function loadEvents(params: LoadEventsParams, apiKey?: string): Promise<PageResult<AuditEventListItem>>;
|
|
70
|
+
/**
|
|
71
|
+
* Server action to create a single audit event
|
|
72
|
+
*
|
|
73
|
+
* @param event - Event data to create
|
|
74
|
+
* @param options - Optional idempotency and request ID options
|
|
75
|
+
* @param apiKey - Optional API key (otherwise uses ARCHIVA_SECRET_KEY env var)
|
|
76
|
+
* @returns Created event ID and replay status
|
|
77
|
+
*/
|
|
78
|
+
declare function createEvent(event: CreateEventInput, options?: CreateEventOptions, apiKey?: string): Promise<{
|
|
79
|
+
eventId: string;
|
|
80
|
+
replayed: boolean;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Server action to create multiple audit events (bulk)
|
|
84
|
+
*
|
|
85
|
+
* @param events - Array of events to create
|
|
86
|
+
* @param options - Optional idempotency and request ID options
|
|
87
|
+
* @param apiKey - Optional API key (otherwise uses ARCHIVA_SECRET_KEY env var)
|
|
88
|
+
* @returns Array of created event IDs
|
|
89
|
+
*/
|
|
90
|
+
declare function createEvents(events: CreateEventInput[], options?: CreateEventOptions, apiKey?: string): Promise<{
|
|
91
|
+
eventIds: string[];
|
|
92
|
+
}>;
|
|
93
|
+
|
|
94
|
+
interface FrontendTokenResponse {
|
|
95
|
+
token: string;
|
|
96
|
+
expiresAt: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Fetches a frontend token from the Archiva API
|
|
100
|
+
*
|
|
101
|
+
* @param projectId - Optional project ID for scoping
|
|
102
|
+
* @param apiBaseUrl - Archiva API base URL (defaults to https://api.archiva.app)
|
|
103
|
+
* @returns Frontend token response
|
|
104
|
+
*/
|
|
105
|
+
declare function createFrontendTokenGET(projectId?: string, apiBaseUrl?: string): Promise<FrontendTokenResponse>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Next.js route handler for GET /api/archiva/frontend-token
|
|
109
|
+
*
|
|
110
|
+
* This handler can be used in the host app's route file:
|
|
111
|
+
*
|
|
112
|
+
* ```ts
|
|
113
|
+
* // app/api/archiva/frontend-token/route.ts
|
|
114
|
+
* export { GET } from '@archiva/archiva-nextjs/server';
|
|
115
|
+
* ```
|
|
116
|
+
*
|
|
117
|
+
* Or with custom configuration:
|
|
118
|
+
*
|
|
119
|
+
* ```ts
|
|
120
|
+
* import { createFrontendTokenRoute } from '@archiva/archiva-nextjs/server';
|
|
121
|
+
*
|
|
122
|
+
* export const GET = createFrontendTokenRoute({
|
|
123
|
+
* apiBaseUrl: process.env.ARCHIVA_API_URL,
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function createFrontendTokenRoute(options?: {
|
|
128
|
+
apiBaseUrl?: string;
|
|
129
|
+
}): (request: NextRequest) => Promise<NextResponse<FrontendTokenResponse> | NextResponse<{
|
|
130
|
+
error: string;
|
|
131
|
+
}>>;
|
|
132
|
+
/**
|
|
133
|
+
* Default GET handler (for direct export)
|
|
134
|
+
*/
|
|
135
|
+
declare function GET(request: NextRequest): Promise<NextResponse<FrontendTokenResponse> | NextResponse<{
|
|
136
|
+
error: string;
|
|
137
|
+
}>>;
|
|
138
|
+
|
|
139
|
+
export { ArchivaError as A, type CreateEventInput as C, type EventChange as E, type FrontendTokenResponse as F, GET as G, type LoadEventsParams as L, type PageResult as P, createEvents as a, createFrontendTokenGET as b, createEvent as c, createFrontendTokenRoute as d, type CreateEventOptions as e, type AuditEventListItem as f, loadEvents as l };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ArchivaProvider, ArchivaProviderProps } from './react/index.mjs';
|
|
2
|
-
export { A as ArchivaError, f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, E as EventChange, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from './index-
|
|
2
|
+
export { A as ArchivaError, f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, E as EventChange, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from './index-Bk4DxULy.mjs';
|
|
3
3
|
import 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
5
|
import 'next/server';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ArchivaProvider, ArchivaProviderProps } from './react/index.js';
|
|
2
|
-
export { A as ArchivaError, f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, E as EventChange, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from './index-
|
|
2
|
+
export { A as ArchivaError, f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, E as EventChange, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from './index-Bk4DxULy.js';
|
|
3
3
|
import 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
5
|
import 'next/server';
|
package/dist/index.js
CHANGED
|
@@ -239,6 +239,84 @@ var ArchivaError = class extends Error {
|
|
|
239
239
|
}
|
|
240
240
|
};
|
|
241
241
|
|
|
242
|
+
// src/eventNormalizer.ts
|
|
243
|
+
var coerceString = (value) => {
|
|
244
|
+
if (value === null || value === void 0) {
|
|
245
|
+
return void 0;
|
|
246
|
+
}
|
|
247
|
+
if (typeof value === "string") {
|
|
248
|
+
return value;
|
|
249
|
+
}
|
|
250
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
251
|
+
return String(value);
|
|
252
|
+
}
|
|
253
|
+
return void 0;
|
|
254
|
+
};
|
|
255
|
+
var coerceNullableString = (value) => {
|
|
256
|
+
if (value === null || value === void 0) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
if (typeof value === "string") {
|
|
260
|
+
return value;
|
|
261
|
+
}
|
|
262
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
263
|
+
return String(value);
|
|
264
|
+
}
|
|
265
|
+
return null;
|
|
266
|
+
};
|
|
267
|
+
var coerceActorType = (value) => {
|
|
268
|
+
if (typeof value !== "string") {
|
|
269
|
+
return void 0;
|
|
270
|
+
}
|
|
271
|
+
const normalized = value.toLowerCase();
|
|
272
|
+
if (normalized === "user" || normalized === "service" || normalized === "system") {
|
|
273
|
+
return normalized;
|
|
274
|
+
}
|
|
275
|
+
return void 0;
|
|
276
|
+
};
|
|
277
|
+
var getActorValue = (event, actorRecord, keys) => {
|
|
278
|
+
for (const key of keys) {
|
|
279
|
+
if (Object.prototype.hasOwnProperty.call(event, key)) {
|
|
280
|
+
return event[key];
|
|
281
|
+
}
|
|
282
|
+
if (actorRecord && Object.prototype.hasOwnProperty.call(actorRecord, key)) {
|
|
283
|
+
return actorRecord[key];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return void 0;
|
|
287
|
+
};
|
|
288
|
+
var normalizeAuditEventItem = (event) => {
|
|
289
|
+
const actorRecord = typeof event.actor === "object" && event.actor !== null ? event.actor : void 0;
|
|
290
|
+
const actorDisplayValue = getActorValue(event, actorRecord, [
|
|
291
|
+
"actorDisplay",
|
|
292
|
+
"actor_display",
|
|
293
|
+
"display",
|
|
294
|
+
"display_name",
|
|
295
|
+
"name"
|
|
296
|
+
]);
|
|
297
|
+
const actorTypeValue = getActorValue(event, actorRecord, [
|
|
298
|
+
"actorType",
|
|
299
|
+
"actor_type",
|
|
300
|
+
"type"
|
|
301
|
+
]);
|
|
302
|
+
const actorIdValue = getActorValue(event, actorRecord, [
|
|
303
|
+
"actorId",
|
|
304
|
+
"actor_id",
|
|
305
|
+
"id"
|
|
306
|
+
]);
|
|
307
|
+
return {
|
|
308
|
+
id: coerceString(event.id) ?? "",
|
|
309
|
+
receivedAt: coerceString(event.receivedAt ?? event.received_at) ?? "",
|
|
310
|
+
action: coerceString(event.action) ?? "",
|
|
311
|
+
entityType: coerceString(event.entityType ?? event.entity_type) ?? "",
|
|
312
|
+
entityId: coerceString(event.entityId ?? event.entity_id) ?? "",
|
|
313
|
+
actorId: coerceNullableString(actorIdValue),
|
|
314
|
+
actorType: coerceActorType(actorTypeValue),
|
|
315
|
+
actorDisplay: coerceString(actorDisplayValue) ?? "",
|
|
316
|
+
source: coerceNullableString(event.source)
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
|
|
242
320
|
// src/client.ts
|
|
243
321
|
var DEFAULT_BASE_URL = "https://api.archiva.app";
|
|
244
322
|
function buildHeaders(apiKey, overrides) {
|
|
@@ -332,20 +410,7 @@ async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
|
|
|
332
410
|
details: item
|
|
333
411
|
});
|
|
334
412
|
}
|
|
335
|
-
|
|
336
|
-
const actorDisplay = event.actorDisplay !== null && event.actorDisplay !== void 0 ? event.actorDisplay : event.actor_display !== null && event.actor_display !== void 0 ? event.actor_display : void 0;
|
|
337
|
-
const actorType = event.actorType !== null && event.actorType !== void 0 ? event.actorType : event.actor_type !== null && event.actor_type !== void 0 ? event.actor_type : void 0;
|
|
338
|
-
return {
|
|
339
|
-
id: String(event.id ?? ""),
|
|
340
|
-
receivedAt: String(event.receivedAt ?? event.received_at ?? ""),
|
|
341
|
-
action: String(event.action ?? ""),
|
|
342
|
-
entityType: String(event.entityType ?? event.entity_type ?? ""),
|
|
343
|
-
entityId: String(event.entityId ?? event.entity_id ?? ""),
|
|
344
|
-
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : event.actor_id !== null && event.actor_id !== void 0 ? String(event.actor_id) : null,
|
|
345
|
-
actorType: actorType && (actorType === "user" || actorType === "service" || actorType === "system") ? actorType : void 0,
|
|
346
|
-
actorDisplay: actorDisplay !== null && actorDisplay !== void 0 ? String(actorDisplay) : void 0,
|
|
347
|
-
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
348
|
-
};
|
|
413
|
+
return normalizeAuditEventItem(item);
|
|
349
414
|
});
|
|
350
415
|
return {
|
|
351
416
|
items,
|
package/dist/index.mjs
CHANGED
package/dist/react/client.js
CHANGED
|
@@ -56,6 +56,84 @@ function useArchiva() {
|
|
|
56
56
|
return useArchivaContext();
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// src/eventNormalizer.ts
|
|
60
|
+
var coerceString = (value) => {
|
|
61
|
+
if (value === null || value === void 0) {
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
if (typeof value === "string") {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
68
|
+
return String(value);
|
|
69
|
+
}
|
|
70
|
+
return void 0;
|
|
71
|
+
};
|
|
72
|
+
var coerceNullableString = (value) => {
|
|
73
|
+
if (value === null || value === void 0) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
if (typeof value === "string") {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
80
|
+
return String(value);
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
};
|
|
84
|
+
var coerceActorType = (value) => {
|
|
85
|
+
if (typeof value !== "string") {
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
const normalized = value.toLowerCase();
|
|
89
|
+
if (normalized === "user" || normalized === "service" || normalized === "system") {
|
|
90
|
+
return normalized;
|
|
91
|
+
}
|
|
92
|
+
return void 0;
|
|
93
|
+
};
|
|
94
|
+
var getActorValue = (event, actorRecord, keys) => {
|
|
95
|
+
for (const key of keys) {
|
|
96
|
+
if (Object.prototype.hasOwnProperty.call(event, key)) {
|
|
97
|
+
return event[key];
|
|
98
|
+
}
|
|
99
|
+
if (actorRecord && Object.prototype.hasOwnProperty.call(actorRecord, key)) {
|
|
100
|
+
return actorRecord[key];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return void 0;
|
|
104
|
+
};
|
|
105
|
+
var normalizeAuditEventItem = (event) => {
|
|
106
|
+
const actorRecord = typeof event.actor === "object" && event.actor !== null ? event.actor : void 0;
|
|
107
|
+
const actorDisplayValue = getActorValue(event, actorRecord, [
|
|
108
|
+
"actorDisplay",
|
|
109
|
+
"actor_display",
|
|
110
|
+
"display",
|
|
111
|
+
"display_name",
|
|
112
|
+
"name"
|
|
113
|
+
]);
|
|
114
|
+
const actorTypeValue = getActorValue(event, actorRecord, [
|
|
115
|
+
"actorType",
|
|
116
|
+
"actor_type",
|
|
117
|
+
"type"
|
|
118
|
+
]);
|
|
119
|
+
const actorIdValue = getActorValue(event, actorRecord, [
|
|
120
|
+
"actorId",
|
|
121
|
+
"actor_id",
|
|
122
|
+
"id"
|
|
123
|
+
]);
|
|
124
|
+
return {
|
|
125
|
+
id: coerceString(event.id) ?? "",
|
|
126
|
+
receivedAt: coerceString(event.receivedAt ?? event.received_at) ?? "",
|
|
127
|
+
action: coerceString(event.action) ?? "",
|
|
128
|
+
entityType: coerceString(event.entityType ?? event.entity_type) ?? "",
|
|
129
|
+
entityId: coerceString(event.entityId ?? event.entity_id) ?? "",
|
|
130
|
+
actorId: coerceNullableString(actorIdValue),
|
|
131
|
+
actorType: coerceActorType(actorTypeValue),
|
|
132
|
+
actorDisplay: coerceString(actorDisplayValue) ?? "",
|
|
133
|
+
source: coerceNullableString(event.source)
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
|
|
59
137
|
// src/react/Timeline.tsx
|
|
60
138
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
61
139
|
function formatTimestamp(timestamp, format = "default") {
|
|
@@ -148,7 +226,7 @@ function eventToTimelineItem(event, getActorAvatar) {
|
|
|
148
226
|
// Required by TimelineItem type, but not used in activity layout - matches ActivityLog.tsx line 352
|
|
149
227
|
userName: userName.charAt(0).toUpperCase() + userName.slice(1),
|
|
150
228
|
// Matches ActivityLog.tsx line 353
|
|
151
|
-
actorDisplay: event.actorDisplay
|
|
229
|
+
actorDisplay: event.actorDisplay,
|
|
152
230
|
// Matches ActivityLog.tsx line 354
|
|
153
231
|
userHandle,
|
|
154
232
|
// Matches ActivityLog.tsx line 355
|
|
@@ -217,20 +295,7 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
|
|
|
217
295
|
if (typeof item !== "object" || item === null) {
|
|
218
296
|
throw new Error("Invalid item format in response");
|
|
219
297
|
}
|
|
220
|
-
|
|
221
|
-
const actorDisplay = event.actorDisplay !== null && event.actorDisplay !== void 0 ? event.actorDisplay : event.actor_display !== null && event.actor_display !== void 0 ? event.actor_display : void 0;
|
|
222
|
-
const actorType = event.actorType !== null && event.actorType !== void 0 ? event.actorType : event.actor_type !== null && event.actor_type !== void 0 ? event.actor_type : void 0;
|
|
223
|
-
return {
|
|
224
|
-
id: String(event.id ?? ""),
|
|
225
|
-
receivedAt: String(event.receivedAt ?? event.received_at ?? ""),
|
|
226
|
-
action: String(event.action ?? ""),
|
|
227
|
-
entityType: String(event.entityType ?? event.entity_type ?? ""),
|
|
228
|
-
entityId: String(event.entityId ?? event.entity_id ?? ""),
|
|
229
|
-
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : event.actor_id !== null && event.actor_id !== void 0 ? String(event.actor_id) : null,
|
|
230
|
-
actorType: actorType && (actorType === "user" || actorType === "service" || actorType === "system") ? actorType : void 0,
|
|
231
|
-
actorDisplay: actorDisplay !== null && actorDisplay !== void 0 ? String(actorDisplay) : void 0,
|
|
232
|
-
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
233
|
-
};
|
|
298
|
+
return normalizeAuditEventItem(item);
|
|
234
299
|
});
|
|
235
300
|
return {
|
|
236
301
|
items,
|
|
@@ -370,23 +435,45 @@ function Timeline({
|
|
|
370
435
|
}) {
|
|
371
436
|
const { apiBaseUrl, getToken, forceRefreshToken } = useArchiva();
|
|
372
437
|
const [allEvents, setAllEvents] = React2.useState([]);
|
|
438
|
+
const [previousEvents, setPreviousEvents] = React2.useState([]);
|
|
373
439
|
const [cursor, setCursor] = React2.useState(void 0);
|
|
374
440
|
const [loading, setLoading] = React2.useState(false);
|
|
375
441
|
const [error, setError] = React2.useState(null);
|
|
376
442
|
const [hasMore, setHasMore] = React2.useState(false);
|
|
377
443
|
const [searchQuery, setSearchQuery] = React2.useState("");
|
|
444
|
+
const queryParamsRef = React2.useRef({});
|
|
445
|
+
const queryParamsKeyRef = React2.useRef("");
|
|
446
|
+
const queryParams = React2.useMemo(() => {
|
|
447
|
+
const params = {
|
|
448
|
+
entityId,
|
|
449
|
+
actorId,
|
|
450
|
+
entityType,
|
|
451
|
+
// Filter by actorType on API side
|
|
452
|
+
actorType: showSystemAndServices ? void 0 : "user",
|
|
453
|
+
limit: initialLimit
|
|
454
|
+
};
|
|
455
|
+
const key = JSON.stringify(params);
|
|
456
|
+
if (key !== queryParamsKeyRef.current) {
|
|
457
|
+
queryParamsKeyRef.current = key;
|
|
458
|
+
queryParamsRef.current = params;
|
|
459
|
+
return params;
|
|
460
|
+
}
|
|
461
|
+
return queryParamsRef.current;
|
|
462
|
+
}, [entityId, actorId, entityType, initialLimit, showSystemAndServices]);
|
|
463
|
+
const allEventsRef = React2.useRef([]);
|
|
464
|
+
React2.useEffect(() => {
|
|
465
|
+
allEventsRef.current = allEvents;
|
|
466
|
+
}, [allEvents]);
|
|
378
467
|
const load = React2.useCallback(
|
|
379
468
|
async (options) => {
|
|
380
469
|
setLoading(true);
|
|
381
470
|
setError(null);
|
|
471
|
+
if (options?.reset && allEventsRef.current.length > 0) {
|
|
472
|
+
setPreviousEvents(allEventsRef.current);
|
|
473
|
+
}
|
|
382
474
|
try {
|
|
383
475
|
const params = {
|
|
384
|
-
|
|
385
|
-
actorId,
|
|
386
|
-
entityType,
|
|
387
|
-
// Filter by actorType on API side
|
|
388
|
-
actorType: showSystemAndServices ? void 0 : "user",
|
|
389
|
-
limit: initialLimit,
|
|
476
|
+
...queryParams,
|
|
390
477
|
cursor: options?.reset ? void 0 : options?.currentCursor ?? cursor
|
|
391
478
|
};
|
|
392
479
|
const response = await fetchEventsWithRetry(
|
|
@@ -395,34 +482,54 @@ function Timeline({
|
|
|
395
482
|
forceRefreshToken,
|
|
396
483
|
params
|
|
397
484
|
);
|
|
398
|
-
setAllEvents((prev) =>
|
|
485
|
+
setAllEvents((prev) => {
|
|
486
|
+
const newEvents = options?.reset ? response.items : [...prev, ...response.items];
|
|
487
|
+
if (options?.reset) {
|
|
488
|
+
setPreviousEvents([]);
|
|
489
|
+
}
|
|
490
|
+
return newEvents;
|
|
491
|
+
});
|
|
399
492
|
setCursor(response.nextCursor);
|
|
400
493
|
setHasMore(Boolean(response.nextCursor));
|
|
401
494
|
} catch (err) {
|
|
402
495
|
setError(err.message);
|
|
496
|
+
setPreviousEvents((prev) => {
|
|
497
|
+
if (options?.reset && prev.length > 0) {
|
|
498
|
+
setAllEvents(prev);
|
|
499
|
+
return [];
|
|
500
|
+
}
|
|
501
|
+
return prev;
|
|
502
|
+
});
|
|
403
503
|
} finally {
|
|
404
504
|
setLoading(false);
|
|
405
505
|
}
|
|
406
506
|
},
|
|
407
|
-
[
|
|
507
|
+
[queryParams, apiBaseUrl, getToken, forceRefreshToken, cursor]
|
|
408
508
|
);
|
|
409
509
|
React2.useEffect(() => {
|
|
410
510
|
setCursor(void 0);
|
|
411
511
|
setAllEvents([]);
|
|
512
|
+
setPreviousEvents([]);
|
|
412
513
|
void load({ reset: true });
|
|
413
|
-
}, [entityId, actorId, entityType, showSystemAndServices]);
|
|
514
|
+
}, [entityId, actorId, entityType, showSystemAndServices, initialLimit]);
|
|
515
|
+
const eventsToFilter = React2.useMemo(() => {
|
|
516
|
+
if (loading && allEvents.length === 0 && previousEvents.length > 0) {
|
|
517
|
+
return previousEvents;
|
|
518
|
+
}
|
|
519
|
+
return allEvents;
|
|
520
|
+
}, [allEvents, loading, previousEvents]);
|
|
414
521
|
const filteredEvents = React2.useMemo(() => {
|
|
415
|
-
return applyClientSideFilters(
|
|
416
|
-
}, [
|
|
522
|
+
return applyClientSideFilters(eventsToFilter, searchQuery, showSystemAndServices);
|
|
523
|
+
}, [eventsToFilter, searchQuery, showSystemAndServices]);
|
|
417
524
|
const timelineItems = React2.useMemo(() => {
|
|
418
525
|
return filteredEvents.slice(0, 10).map(
|
|
419
526
|
(event) => eventToTimelineItem(event, getActorAvatar)
|
|
420
527
|
);
|
|
421
528
|
}, [filteredEvents, getActorAvatar]);
|
|
422
|
-
if (loading && allEvents.length === 0) {
|
|
529
|
+
if (loading && allEvents.length === 0 && previousEvents.length === 0) {
|
|
423
530
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: className || "", style: { width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "3rem", textAlign: "center", color: "#6b7280" }, children: "Loading events..." }) });
|
|
424
531
|
}
|
|
425
|
-
if (error) {
|
|
532
|
+
if (error && allEvents.length === 0) {
|
|
426
533
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: className || "", style: { width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { padding: "1rem", color: "#dc2626", backgroundColor: "#fef2f2", borderRadius: "0.375rem" }, children: [
|
|
427
534
|
"Error: ",
|
|
428
535
|
error
|
|
@@ -438,13 +545,17 @@ function Timeline({
|
|
|
438
545
|
placeholder: "Search actions, entities, IDs, actors, sources..."
|
|
439
546
|
}
|
|
440
547
|
) }),
|
|
441
|
-
searchQuery
|
|
548
|
+
(searchQuery || filteredEvents.length !== eventsToFilter.length) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "0.5rem", fontSize: "0.875rem", color: "#6b7280" }, children: [
|
|
442
549
|
"Showing ",
|
|
443
550
|
filteredEvents.length,
|
|
444
551
|
" of ",
|
|
445
|
-
|
|
552
|
+
eventsToFilter.length,
|
|
446
553
|
" events"
|
|
447
554
|
] }),
|
|
555
|
+
error && allEvents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "1rem", padding: "0.75rem", color: "#dc2626", backgroundColor: "#fef2f2", borderRadius: "0.375rem", fontSize: "0.875rem" }, children: [
|
|
556
|
+
"Error: ",
|
|
557
|
+
error
|
|
558
|
+
] }),
|
|
448
559
|
timelineItems.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "3rem", textAlign: "center", color: "#6b7280" }, children: searchQuery ? "No events match your search." : emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "relative", width: "100%" }, children: timelineItems.map((item, index) => {
|
|
449
560
|
const useActivityLayout = !!(item.actorDisplay || item.userName || item.userHandle);
|
|
450
561
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
package/dist/react/client.mjs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import {
|
|
3
|
+
normalizeAuditEventItem
|
|
4
|
+
} from "../chunk-WA7TMG65.mjs";
|
|
2
5
|
import {
|
|
3
6
|
useArchivaContext
|
|
4
7
|
} from "../chunk-H4TGL57C.mjs";
|
|
@@ -103,7 +106,7 @@ function eventToTimelineItem(event, getActorAvatar) {
|
|
|
103
106
|
// Required by TimelineItem type, but not used in activity layout - matches ActivityLog.tsx line 352
|
|
104
107
|
userName: userName.charAt(0).toUpperCase() + userName.slice(1),
|
|
105
108
|
// Matches ActivityLog.tsx line 353
|
|
106
|
-
actorDisplay: event.actorDisplay
|
|
109
|
+
actorDisplay: event.actorDisplay,
|
|
107
110
|
// Matches ActivityLog.tsx line 354
|
|
108
111
|
userHandle,
|
|
109
112
|
// Matches ActivityLog.tsx line 355
|
|
@@ -172,20 +175,7 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
|
|
|
172
175
|
if (typeof item !== "object" || item === null) {
|
|
173
176
|
throw new Error("Invalid item format in response");
|
|
174
177
|
}
|
|
175
|
-
|
|
176
|
-
const actorDisplay = event.actorDisplay !== null && event.actorDisplay !== void 0 ? event.actorDisplay : event.actor_display !== null && event.actor_display !== void 0 ? event.actor_display : void 0;
|
|
177
|
-
const actorType = event.actorType !== null && event.actorType !== void 0 ? event.actorType : event.actor_type !== null && event.actor_type !== void 0 ? event.actor_type : void 0;
|
|
178
|
-
return {
|
|
179
|
-
id: String(event.id ?? ""),
|
|
180
|
-
receivedAt: String(event.receivedAt ?? event.received_at ?? ""),
|
|
181
|
-
action: String(event.action ?? ""),
|
|
182
|
-
entityType: String(event.entityType ?? event.entity_type ?? ""),
|
|
183
|
-
entityId: String(event.entityId ?? event.entity_id ?? ""),
|
|
184
|
-
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : event.actor_id !== null && event.actor_id !== void 0 ? String(event.actor_id) : null,
|
|
185
|
-
actorType: actorType && (actorType === "user" || actorType === "service" || actorType === "system") ? actorType : void 0,
|
|
186
|
-
actorDisplay: actorDisplay !== null && actorDisplay !== void 0 ? String(actorDisplay) : void 0,
|
|
187
|
-
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
188
|
-
};
|
|
178
|
+
return normalizeAuditEventItem(item);
|
|
189
179
|
});
|
|
190
180
|
return {
|
|
191
181
|
items,
|
|
@@ -325,23 +315,45 @@ function Timeline({
|
|
|
325
315
|
}) {
|
|
326
316
|
const { apiBaseUrl, getToken, forceRefreshToken } = useArchiva();
|
|
327
317
|
const [allEvents, setAllEvents] = React.useState([]);
|
|
318
|
+
const [previousEvents, setPreviousEvents] = React.useState([]);
|
|
328
319
|
const [cursor, setCursor] = React.useState(void 0);
|
|
329
320
|
const [loading, setLoading] = React.useState(false);
|
|
330
321
|
const [error, setError] = React.useState(null);
|
|
331
322
|
const [hasMore, setHasMore] = React.useState(false);
|
|
332
323
|
const [searchQuery, setSearchQuery] = React.useState("");
|
|
324
|
+
const queryParamsRef = React.useRef({});
|
|
325
|
+
const queryParamsKeyRef = React.useRef("");
|
|
326
|
+
const queryParams = React.useMemo(() => {
|
|
327
|
+
const params = {
|
|
328
|
+
entityId,
|
|
329
|
+
actorId,
|
|
330
|
+
entityType,
|
|
331
|
+
// Filter by actorType on API side
|
|
332
|
+
actorType: showSystemAndServices ? void 0 : "user",
|
|
333
|
+
limit: initialLimit
|
|
334
|
+
};
|
|
335
|
+
const key = JSON.stringify(params);
|
|
336
|
+
if (key !== queryParamsKeyRef.current) {
|
|
337
|
+
queryParamsKeyRef.current = key;
|
|
338
|
+
queryParamsRef.current = params;
|
|
339
|
+
return params;
|
|
340
|
+
}
|
|
341
|
+
return queryParamsRef.current;
|
|
342
|
+
}, [entityId, actorId, entityType, initialLimit, showSystemAndServices]);
|
|
343
|
+
const allEventsRef = React.useRef([]);
|
|
344
|
+
React.useEffect(() => {
|
|
345
|
+
allEventsRef.current = allEvents;
|
|
346
|
+
}, [allEvents]);
|
|
333
347
|
const load = React.useCallback(
|
|
334
348
|
async (options) => {
|
|
335
349
|
setLoading(true);
|
|
336
350
|
setError(null);
|
|
351
|
+
if (options?.reset && allEventsRef.current.length > 0) {
|
|
352
|
+
setPreviousEvents(allEventsRef.current);
|
|
353
|
+
}
|
|
337
354
|
try {
|
|
338
355
|
const params = {
|
|
339
|
-
|
|
340
|
-
actorId,
|
|
341
|
-
entityType,
|
|
342
|
-
// Filter by actorType on API side
|
|
343
|
-
actorType: showSystemAndServices ? void 0 : "user",
|
|
344
|
-
limit: initialLimit,
|
|
356
|
+
...queryParams,
|
|
345
357
|
cursor: options?.reset ? void 0 : options?.currentCursor ?? cursor
|
|
346
358
|
};
|
|
347
359
|
const response = await fetchEventsWithRetry(
|
|
@@ -350,34 +362,54 @@ function Timeline({
|
|
|
350
362
|
forceRefreshToken,
|
|
351
363
|
params
|
|
352
364
|
);
|
|
353
|
-
setAllEvents((prev) =>
|
|
365
|
+
setAllEvents((prev) => {
|
|
366
|
+
const newEvents = options?.reset ? response.items : [...prev, ...response.items];
|
|
367
|
+
if (options?.reset) {
|
|
368
|
+
setPreviousEvents([]);
|
|
369
|
+
}
|
|
370
|
+
return newEvents;
|
|
371
|
+
});
|
|
354
372
|
setCursor(response.nextCursor);
|
|
355
373
|
setHasMore(Boolean(response.nextCursor));
|
|
356
374
|
} catch (err) {
|
|
357
375
|
setError(err.message);
|
|
376
|
+
setPreviousEvents((prev) => {
|
|
377
|
+
if (options?.reset && prev.length > 0) {
|
|
378
|
+
setAllEvents(prev);
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
return prev;
|
|
382
|
+
});
|
|
358
383
|
} finally {
|
|
359
384
|
setLoading(false);
|
|
360
385
|
}
|
|
361
386
|
},
|
|
362
|
-
[
|
|
387
|
+
[queryParams, apiBaseUrl, getToken, forceRefreshToken, cursor]
|
|
363
388
|
);
|
|
364
389
|
React.useEffect(() => {
|
|
365
390
|
setCursor(void 0);
|
|
366
391
|
setAllEvents([]);
|
|
392
|
+
setPreviousEvents([]);
|
|
367
393
|
void load({ reset: true });
|
|
368
|
-
}, [entityId, actorId, entityType, showSystemAndServices]);
|
|
394
|
+
}, [entityId, actorId, entityType, showSystemAndServices, initialLimit]);
|
|
395
|
+
const eventsToFilter = React.useMemo(() => {
|
|
396
|
+
if (loading && allEvents.length === 0 && previousEvents.length > 0) {
|
|
397
|
+
return previousEvents;
|
|
398
|
+
}
|
|
399
|
+
return allEvents;
|
|
400
|
+
}, [allEvents, loading, previousEvents]);
|
|
369
401
|
const filteredEvents = React.useMemo(() => {
|
|
370
|
-
return applyClientSideFilters(
|
|
371
|
-
}, [
|
|
402
|
+
return applyClientSideFilters(eventsToFilter, searchQuery, showSystemAndServices);
|
|
403
|
+
}, [eventsToFilter, searchQuery, showSystemAndServices]);
|
|
372
404
|
const timelineItems = React.useMemo(() => {
|
|
373
405
|
return filteredEvents.slice(0, 10).map(
|
|
374
406
|
(event) => eventToTimelineItem(event, getActorAvatar)
|
|
375
407
|
);
|
|
376
408
|
}, [filteredEvents, getActorAvatar]);
|
|
377
|
-
if (loading && allEvents.length === 0) {
|
|
409
|
+
if (loading && allEvents.length === 0 && previousEvents.length === 0) {
|
|
378
410
|
return /* @__PURE__ */ jsx("div", { className: className || "", style: { width: "100%" }, children: /* @__PURE__ */ jsx("div", { style: { padding: "3rem", textAlign: "center", color: "#6b7280" }, children: "Loading events..." }) });
|
|
379
411
|
}
|
|
380
|
-
if (error) {
|
|
412
|
+
if (error && allEvents.length === 0) {
|
|
381
413
|
return /* @__PURE__ */ jsx("div", { className: className || "", style: { width: "100%" }, children: /* @__PURE__ */ jsxs("div", { style: { padding: "1rem", color: "#dc2626", backgroundColor: "#fef2f2", borderRadius: "0.375rem" }, children: [
|
|
382
414
|
"Error: ",
|
|
383
415
|
error
|
|
@@ -393,13 +425,17 @@ function Timeline({
|
|
|
393
425
|
placeholder: "Search actions, entities, IDs, actors, sources..."
|
|
394
426
|
}
|
|
395
427
|
) }),
|
|
396
|
-
searchQuery
|
|
428
|
+
(searchQuery || filteredEvents.length !== eventsToFilter.length) && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "0.5rem", fontSize: "0.875rem", color: "#6b7280" }, children: [
|
|
397
429
|
"Showing ",
|
|
398
430
|
filteredEvents.length,
|
|
399
431
|
" of ",
|
|
400
|
-
|
|
432
|
+
eventsToFilter.length,
|
|
401
433
|
" events"
|
|
402
434
|
] }),
|
|
435
|
+
error && allEvents.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "1rem", padding: "0.75rem", color: "#dc2626", backgroundColor: "#fef2f2", borderRadius: "0.375rem", fontSize: "0.875rem" }, children: [
|
|
436
|
+
"Error: ",
|
|
437
|
+
error
|
|
438
|
+
] }),
|
|
403
439
|
timelineItems.length === 0 ? /* @__PURE__ */ jsx("div", { style: { padding: "3rem", textAlign: "center", color: "#6b7280" }, children: searchQuery ? "No events match your search." : emptyMessage }) : /* @__PURE__ */ jsx("div", { style: { position: "relative", width: "100%" }, children: timelineItems.map((item, index) => {
|
|
404
440
|
const useActivityLayout = !!(item.actorDisplay || item.userName || item.userHandle);
|
|
405
441
|
return /* @__PURE__ */ jsxs(
|
package/dist/server/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from '../index-
|
|
1
|
+
export { f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from '../index-Bk4DxULy.mjs';
|
|
2
2
|
import 'next/server';
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from '../index-
|
|
1
|
+
export { f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from '../index-Bk4DxULy.js';
|
|
2
2
|
import 'next/server';
|
package/dist/server/index.js
CHANGED
|
@@ -113,6 +113,84 @@ var ArchivaError = class extends Error {
|
|
|
113
113
|
}
|
|
114
114
|
};
|
|
115
115
|
|
|
116
|
+
// src/eventNormalizer.ts
|
|
117
|
+
var coerceString = (value) => {
|
|
118
|
+
if (value === null || value === void 0) {
|
|
119
|
+
return void 0;
|
|
120
|
+
}
|
|
121
|
+
if (typeof value === "string") {
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
125
|
+
return String(value);
|
|
126
|
+
}
|
|
127
|
+
return void 0;
|
|
128
|
+
};
|
|
129
|
+
var coerceNullableString = (value) => {
|
|
130
|
+
if (value === null || value === void 0) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
if (typeof value === "string") {
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
137
|
+
return String(value);
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
};
|
|
141
|
+
var coerceActorType = (value) => {
|
|
142
|
+
if (typeof value !== "string") {
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
145
|
+
const normalized = value.toLowerCase();
|
|
146
|
+
if (normalized === "user" || normalized === "service" || normalized === "system") {
|
|
147
|
+
return normalized;
|
|
148
|
+
}
|
|
149
|
+
return void 0;
|
|
150
|
+
};
|
|
151
|
+
var getActorValue = (event, actorRecord, keys) => {
|
|
152
|
+
for (const key of keys) {
|
|
153
|
+
if (Object.prototype.hasOwnProperty.call(event, key)) {
|
|
154
|
+
return event[key];
|
|
155
|
+
}
|
|
156
|
+
if (actorRecord && Object.prototype.hasOwnProperty.call(actorRecord, key)) {
|
|
157
|
+
return actorRecord[key];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return void 0;
|
|
161
|
+
};
|
|
162
|
+
var normalizeAuditEventItem = (event) => {
|
|
163
|
+
const actorRecord = typeof event.actor === "object" && event.actor !== null ? event.actor : void 0;
|
|
164
|
+
const actorDisplayValue = getActorValue(event, actorRecord, [
|
|
165
|
+
"actorDisplay",
|
|
166
|
+
"actor_display",
|
|
167
|
+
"display",
|
|
168
|
+
"display_name",
|
|
169
|
+
"name"
|
|
170
|
+
]);
|
|
171
|
+
const actorTypeValue = getActorValue(event, actorRecord, [
|
|
172
|
+
"actorType",
|
|
173
|
+
"actor_type",
|
|
174
|
+
"type"
|
|
175
|
+
]);
|
|
176
|
+
const actorIdValue = getActorValue(event, actorRecord, [
|
|
177
|
+
"actorId",
|
|
178
|
+
"actor_id",
|
|
179
|
+
"id"
|
|
180
|
+
]);
|
|
181
|
+
return {
|
|
182
|
+
id: coerceString(event.id) ?? "",
|
|
183
|
+
receivedAt: coerceString(event.receivedAt ?? event.received_at) ?? "",
|
|
184
|
+
action: coerceString(event.action) ?? "",
|
|
185
|
+
entityType: coerceString(event.entityType ?? event.entity_type) ?? "",
|
|
186
|
+
entityId: coerceString(event.entityId ?? event.entity_id) ?? "",
|
|
187
|
+
actorId: coerceNullableString(actorIdValue),
|
|
188
|
+
actorType: coerceActorType(actorTypeValue),
|
|
189
|
+
actorDisplay: coerceString(actorDisplayValue) ?? "",
|
|
190
|
+
source: coerceNullableString(event.source)
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
|
|
116
194
|
// src/client.ts
|
|
117
195
|
var DEFAULT_BASE_URL = "https://api.archiva.app";
|
|
118
196
|
function buildHeaders(apiKey, overrides) {
|
|
@@ -206,20 +284,7 @@ async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
|
|
|
206
284
|
details: item
|
|
207
285
|
});
|
|
208
286
|
}
|
|
209
|
-
|
|
210
|
-
const actorDisplay = event.actorDisplay !== null && event.actorDisplay !== void 0 ? event.actorDisplay : event.actor_display !== null && event.actor_display !== void 0 ? event.actor_display : void 0;
|
|
211
|
-
const actorType = event.actorType !== null && event.actorType !== void 0 ? event.actorType : event.actor_type !== null && event.actor_type !== void 0 ? event.actor_type : void 0;
|
|
212
|
-
return {
|
|
213
|
-
id: String(event.id ?? ""),
|
|
214
|
-
receivedAt: String(event.receivedAt ?? event.received_at ?? ""),
|
|
215
|
-
action: String(event.action ?? ""),
|
|
216
|
-
entityType: String(event.entityType ?? event.entity_type ?? ""),
|
|
217
|
-
entityId: String(event.entityId ?? event.entity_id ?? ""),
|
|
218
|
-
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : event.actor_id !== null && event.actor_id !== void 0 ? String(event.actor_id) : null,
|
|
219
|
-
actorType: actorType && (actorType === "user" || actorType === "service" || actorType === "system") ? actorType : void 0,
|
|
220
|
-
actorDisplay: actorDisplay !== null && actorDisplay !== void 0 ? String(actorDisplay) : void 0,
|
|
221
|
-
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
222
|
-
};
|
|
287
|
+
return normalizeAuditEventItem(item);
|
|
223
288
|
});
|
|
224
289
|
return {
|
|
225
290
|
items,
|
package/dist/server/index.mjs
CHANGED