@archiva/archiva-nextjs 0.2.6 → 0.2.8
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-SQG3CD5M.mjs +275 -0
- package/dist/index-BJ8aJsbs.d.mts +139 -0
- package/dist/index-BJ8aJsbs.d.ts +139 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +26 -1
- package/dist/index.mjs +1 -1
- package/dist/react/client.js +30 -27
- package/dist/react/client.mjs +30 -27
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +26 -1
- package/dist/server/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var ArchivaError = class extends Error {
|
|
3
|
+
constructor(params) {
|
|
4
|
+
super(params.message);
|
|
5
|
+
this.statusCode = params.statusCode;
|
|
6
|
+
this.code = params.code;
|
|
7
|
+
this.retryAfterSeconds = params.retryAfterSeconds;
|
|
8
|
+
this.details = params.details;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/client.ts
|
|
13
|
+
var DEFAULT_BASE_URL = "https://api.archiva.app";
|
|
14
|
+
function buildHeaders(apiKey, overrides) {
|
|
15
|
+
const headers = new Headers(overrides);
|
|
16
|
+
headers.set("X-Project-Key", apiKey);
|
|
17
|
+
return headers;
|
|
18
|
+
}
|
|
19
|
+
async function parseError(response) {
|
|
20
|
+
const retryAfterHeader = response.headers.get("Retry-After");
|
|
21
|
+
const retryAfterSeconds = retryAfterHeader ? Number(retryAfterHeader) : void 0;
|
|
22
|
+
let payload = void 0;
|
|
23
|
+
try {
|
|
24
|
+
payload = await response.json();
|
|
25
|
+
} catch {
|
|
26
|
+
payload = void 0;
|
|
27
|
+
}
|
|
28
|
+
const errorMessage = typeof payload === "object" && payload !== null && "error" in payload ? String(payload.error) : response.statusText;
|
|
29
|
+
let code = "HTTP_ERROR";
|
|
30
|
+
if (response.status === 401) {
|
|
31
|
+
code = "UNAUTHORIZED";
|
|
32
|
+
} else if (response.status === 403) {
|
|
33
|
+
code = "FORBIDDEN";
|
|
34
|
+
} else if (response.status === 413) {
|
|
35
|
+
code = "PAYLOAD_TOO_LARGE";
|
|
36
|
+
} else if (response.status === 429) {
|
|
37
|
+
code = "RATE_LIMITED";
|
|
38
|
+
} else if (response.status === 409) {
|
|
39
|
+
code = "IDEMPOTENCY_CONFLICT";
|
|
40
|
+
}
|
|
41
|
+
throw new ArchivaError({
|
|
42
|
+
statusCode: response.status,
|
|
43
|
+
code,
|
|
44
|
+
message: errorMessage,
|
|
45
|
+
retryAfterSeconds,
|
|
46
|
+
details: payload
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function createRequestId() {
|
|
50
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
51
|
+
return crypto.randomUUID();
|
|
52
|
+
}
|
|
53
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
54
|
+
}
|
|
55
|
+
function createIdempotencyKey() {
|
|
56
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
57
|
+
return `idem_${crypto.randomUUID()}`;
|
|
58
|
+
}
|
|
59
|
+
return `idem_${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
60
|
+
}
|
|
61
|
+
async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
|
|
62
|
+
const url = new URL(`${baseUrl}/api/events`);
|
|
63
|
+
if (params.entityId) {
|
|
64
|
+
url.searchParams.set("entityId", params.entityId);
|
|
65
|
+
}
|
|
66
|
+
if (params.actorId) {
|
|
67
|
+
url.searchParams.set("actorId", params.actorId);
|
|
68
|
+
}
|
|
69
|
+
if (params.entityType) {
|
|
70
|
+
url.searchParams.set("entityType", params.entityType);
|
|
71
|
+
}
|
|
72
|
+
if (params.actorType) {
|
|
73
|
+
url.searchParams.set("actorType", params.actorType);
|
|
74
|
+
}
|
|
75
|
+
if (params.limit) {
|
|
76
|
+
url.searchParams.set("limit", String(params.limit));
|
|
77
|
+
}
|
|
78
|
+
if (params.cursor) {
|
|
79
|
+
url.searchParams.set("cursor", params.cursor);
|
|
80
|
+
}
|
|
81
|
+
const response = await fetch(url.toString(), {
|
|
82
|
+
headers: buildHeaders(apiKey)
|
|
83
|
+
});
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
await parseError(response);
|
|
86
|
+
}
|
|
87
|
+
const payload = await response.json();
|
|
88
|
+
if (!payload || typeof payload !== "object" || !Array.isArray(payload.items)) {
|
|
89
|
+
throw new ArchivaError({
|
|
90
|
+
statusCode: response.status,
|
|
91
|
+
code: "HTTP_ERROR",
|
|
92
|
+
message: "Invalid response format",
|
|
93
|
+
details: payload
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const items = payload.items.map((item) => {
|
|
97
|
+
if (typeof item !== "object" || item === null) {
|
|
98
|
+
throw new ArchivaError({
|
|
99
|
+
statusCode: response.status,
|
|
100
|
+
code: "HTTP_ERROR",
|
|
101
|
+
message: "Invalid item format in response",
|
|
102
|
+
details: item
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const event = item;
|
|
106
|
+
return {
|
|
107
|
+
id: String(event.id ?? ""),
|
|
108
|
+
receivedAt: String(event.receivedAt ?? ""),
|
|
109
|
+
action: String(event.action ?? ""),
|
|
110
|
+
entityType: String(event.entityType ?? ""),
|
|
111
|
+
entityId: String(event.entityId ?? ""),
|
|
112
|
+
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : null,
|
|
113
|
+
actorType: event.actorType && (event.actorType === "user" || event.actorType === "service" || event.actorType === "system") ? event.actorType : void 0,
|
|
114
|
+
actorDisplay: event.actorDisplay !== null && event.actorDisplay !== void 0 ? String(event.actorDisplay) : void 0,
|
|
115
|
+
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
items,
|
|
120
|
+
nextCursor: typeof payload.nextCursor === "string" ? payload.nextCursor : void 0
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async function createEvent(apiKey, event, options, baseUrl = DEFAULT_BASE_URL) {
|
|
124
|
+
const idempotencyKey = options?.idempotencyKey ?? createIdempotencyKey();
|
|
125
|
+
const requestId = options?.requestId ?? createRequestId();
|
|
126
|
+
const headers = buildHeaders(apiKey, {
|
|
127
|
+
"Content-Type": "application/json",
|
|
128
|
+
"Idempotency-Key": idempotencyKey,
|
|
129
|
+
"X-Request-Id": requestId
|
|
130
|
+
});
|
|
131
|
+
const response = await fetch(`${baseUrl}/api/ingest/event`, {
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers,
|
|
134
|
+
body: JSON.stringify(event)
|
|
135
|
+
});
|
|
136
|
+
if (!response.ok) {
|
|
137
|
+
await parseError(response);
|
|
138
|
+
}
|
|
139
|
+
const payload = await response.json();
|
|
140
|
+
if (!payload || typeof payload !== "object" || typeof payload.eventId !== "string") {
|
|
141
|
+
throw new ArchivaError({
|
|
142
|
+
statusCode: response.status,
|
|
143
|
+
code: "HTTP_ERROR",
|
|
144
|
+
message: "Invalid response format",
|
|
145
|
+
details: payload
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
eventId: payload.eventId,
|
|
150
|
+
replayed: response.status === 200
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async function createEvents(apiKey, events, options, baseUrl = DEFAULT_BASE_URL) {
|
|
154
|
+
const results = await Promise.all(
|
|
155
|
+
events.map(
|
|
156
|
+
(event, index) => createEvent(
|
|
157
|
+
apiKey,
|
|
158
|
+
event,
|
|
159
|
+
{
|
|
160
|
+
...options,
|
|
161
|
+
idempotencyKey: options?.idempotencyKey ? `${options.idempotencyKey}_${index}` : void 0
|
|
162
|
+
},
|
|
163
|
+
baseUrl
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
return {
|
|
168
|
+
eventIds: results.map((r) => r.eventId)
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/actions.ts
|
|
173
|
+
var DEFAULT_BASE_URL2 = "https://api.archiva.app";
|
|
174
|
+
function getApiKey(apiKey) {
|
|
175
|
+
const resolvedKey = apiKey || process.env.ARCHIVA_SECRET_KEY;
|
|
176
|
+
if (!resolvedKey) {
|
|
177
|
+
throw new Error("ARCHIVA_SECRET_KEY environment variable is required, or provide apiKey prop to ArchivaProvider");
|
|
178
|
+
}
|
|
179
|
+
return resolvedKey;
|
|
180
|
+
}
|
|
181
|
+
async function loadEvents2(params, apiKey) {
|
|
182
|
+
const resolvedApiKey = getApiKey(apiKey);
|
|
183
|
+
return loadEvents(resolvedApiKey, params, DEFAULT_BASE_URL2);
|
|
184
|
+
}
|
|
185
|
+
async function createEvent2(event, options, apiKey) {
|
|
186
|
+
const resolvedApiKey = getApiKey(apiKey);
|
|
187
|
+
return createEvent(resolvedApiKey, event, options, DEFAULT_BASE_URL2);
|
|
188
|
+
}
|
|
189
|
+
async function createEvents2(events, options, apiKey) {
|
|
190
|
+
const resolvedApiKey = getApiKey(apiKey);
|
|
191
|
+
return createEvents(resolvedApiKey, events, options, DEFAULT_BASE_URL2);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/server/frontendTokens.ts
|
|
195
|
+
import "server-only";
|
|
196
|
+
var DEFAULT_API_BASE_URL = "https://api.archiva.app";
|
|
197
|
+
async function createFrontendTokenGET(projectId, apiBaseUrl = DEFAULT_API_BASE_URL) {
|
|
198
|
+
const secretKey = process.env.ARCHIVA_SECRET_KEY;
|
|
199
|
+
if (!secretKey || secretKey.trim().length === 0) {
|
|
200
|
+
const exists = process.env.ARCHIVA_SECRET_KEY !== void 0;
|
|
201
|
+
throw new Error(
|
|
202
|
+
`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.`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
const keyPrefix = secretKey.substring(0, 10);
|
|
206
|
+
console.log("[Archiva] Using API key prefix:", keyPrefix + "...", "Length:", secretKey.length);
|
|
207
|
+
const url = new URL(`${apiBaseUrl}/api/v1/frontend-tokens`);
|
|
208
|
+
const response = await fetch(url.toString(), {
|
|
209
|
+
method: "POST",
|
|
210
|
+
headers: {
|
|
211
|
+
"Content-Type": "application/json",
|
|
212
|
+
"Authorization": `Bearer ${secretKey}`
|
|
213
|
+
},
|
|
214
|
+
body: JSON.stringify({
|
|
215
|
+
scopes: ["timeline:read"],
|
|
216
|
+
...projectId && { projectId }
|
|
217
|
+
})
|
|
218
|
+
});
|
|
219
|
+
if (!response.ok) {
|
|
220
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
221
|
+
const errorMessage = error.error || `Failed to fetch frontend token: ${response.status}`;
|
|
222
|
+
if (errorMessage.includes("ARCHIVA_SECRET_KEY") || response.status === 401 || response.status === 403) {
|
|
223
|
+
throw new Error(
|
|
224
|
+
`Archiva API authentication failed. Check that your ARCHIVA_SECRET_KEY is valid and has the correct permissions. API error: ${errorMessage}`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
throw new Error(errorMessage);
|
|
228
|
+
}
|
|
229
|
+
const data = await response.json();
|
|
230
|
+
if (!data.token || typeof data.expiresAt !== "number") {
|
|
231
|
+
throw new Error("Invalid token response format");
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
token: data.token,
|
|
235
|
+
expiresAt: data.expiresAt
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// src/server/handlers/createFrontendTokenRoute.ts
|
|
240
|
+
import "server-only";
|
|
241
|
+
import { NextResponse } from "next/server";
|
|
242
|
+
var DEFAULT_API_BASE_URL2 = "https://api.archiva.app";
|
|
243
|
+
function createFrontendTokenRoute(options) {
|
|
244
|
+
return async function GET2(request) {
|
|
245
|
+
try {
|
|
246
|
+
const searchParams = request.nextUrl.searchParams;
|
|
247
|
+
const projectId = searchParams.get("projectId") || void 0;
|
|
248
|
+
const apiBaseUrl = options?.apiBaseUrl || DEFAULT_API_BASE_URL2;
|
|
249
|
+
const tokenResponse = await createFrontendTokenGET(projectId, apiBaseUrl);
|
|
250
|
+
return NextResponse.json(tokenResponse);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error("Error fetching frontend token:", error);
|
|
253
|
+
const message = error instanceof Error ? error.message : "Internal server error";
|
|
254
|
+
const statusCode = message.includes("ARCHIVA_SECRET_KEY") ? 500 : 500;
|
|
255
|
+
return NextResponse.json(
|
|
256
|
+
{ error: message },
|
|
257
|
+
{ status: statusCode }
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
async function GET(request) {
|
|
263
|
+
const handler = createFrontendTokenRoute();
|
|
264
|
+
return handler(request);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export {
|
|
268
|
+
ArchivaError,
|
|
269
|
+
loadEvents2 as loadEvents,
|
|
270
|
+
createEvent2 as createEvent,
|
|
271
|
+
createEvents2 as createEvents,
|
|
272
|
+
createFrontendTokenGET,
|
|
273
|
+
createFrontendTokenRoute,
|
|
274
|
+
GET
|
|
275
|
+
};
|
|
@@ -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 | null;
|
|
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 | null;
|
|
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-BJ8aJsbs.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-BJ8aJsbs.js';
|
|
3
3
|
import 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
5
|
import 'next/server';
|
package/dist/index.js
CHANGED
|
@@ -299,6 +299,9 @@ async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
|
|
|
299
299
|
if (params.entityType) {
|
|
300
300
|
url.searchParams.set("entityType", params.entityType);
|
|
301
301
|
}
|
|
302
|
+
if (params.actorType) {
|
|
303
|
+
url.searchParams.set("actorType", params.actorType);
|
|
304
|
+
}
|
|
302
305
|
if (params.limit) {
|
|
303
306
|
url.searchParams.set("limit", String(params.limit));
|
|
304
307
|
}
|
|
@@ -320,8 +323,30 @@ async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
|
|
|
320
323
|
details: payload
|
|
321
324
|
});
|
|
322
325
|
}
|
|
326
|
+
const items = payload.items.map((item) => {
|
|
327
|
+
if (typeof item !== "object" || item === null) {
|
|
328
|
+
throw new ArchivaError({
|
|
329
|
+
statusCode: response.status,
|
|
330
|
+
code: "HTTP_ERROR",
|
|
331
|
+
message: "Invalid item format in response",
|
|
332
|
+
details: item
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
const event = item;
|
|
336
|
+
return {
|
|
337
|
+
id: String(event.id ?? ""),
|
|
338
|
+
receivedAt: String(event.receivedAt ?? ""),
|
|
339
|
+
action: String(event.action ?? ""),
|
|
340
|
+
entityType: String(event.entityType ?? ""),
|
|
341
|
+
entityId: String(event.entityId ?? ""),
|
|
342
|
+
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : null,
|
|
343
|
+
actorType: event.actorType && (event.actorType === "user" || event.actorType === "service" || event.actorType === "system") ? event.actorType : void 0,
|
|
344
|
+
actorDisplay: event.actorDisplay !== null && event.actorDisplay !== void 0 ? String(event.actorDisplay) : void 0,
|
|
345
|
+
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
346
|
+
};
|
|
347
|
+
});
|
|
323
348
|
return {
|
|
324
|
-
items
|
|
349
|
+
items,
|
|
325
350
|
nextCursor: typeof payload.nextCursor === "string" ? payload.nextCursor : void 0
|
|
326
351
|
};
|
|
327
352
|
}
|
package/dist/index.mjs
CHANGED
package/dist/react/client.js
CHANGED
|
@@ -119,30 +119,32 @@ var CloudCogIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime2.js
|
|
|
119
119
|
);
|
|
120
120
|
function eventToTimelineItem(event, getActorAvatar) {
|
|
121
121
|
const actorId = event.actorId;
|
|
122
|
-
|
|
122
|
+
const actorType = event.actorType || "user";
|
|
123
123
|
let actorIdPart = actorId || "";
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
if (actorId && actorId.includes(":")) {
|
|
125
|
+
const [, ...rest] = actorId.split(":");
|
|
126
|
+
actorIdPart = rest.join(":") || actorId;
|
|
127
|
+
}
|
|
128
|
+
let actorDisplay = event.actorDisplay || null;
|
|
129
|
+
if (!actorDisplay && actorId) {
|
|
126
130
|
if (actorId.includes(":")) {
|
|
127
131
|
const [type, ...rest] = actorId.split(":");
|
|
128
|
-
|
|
129
|
-
actorIdPart = rest.join(":");
|
|
132
|
+
const idPart = rest.join(":");
|
|
130
133
|
if (type === "service" || type === "system") {
|
|
131
|
-
actorDisplay = `${type.charAt(0).toUpperCase() + type.slice(1)} ${
|
|
134
|
+
actorDisplay = `${type.charAt(0).toUpperCase() + type.slice(1)} ${idPart.charAt(0).toUpperCase() + idPart.slice(1)}`;
|
|
132
135
|
} else {
|
|
133
|
-
actorDisplay =
|
|
136
|
+
actorDisplay = idPart.charAt(0).toUpperCase() + idPart.slice(1);
|
|
134
137
|
}
|
|
135
138
|
} else {
|
|
136
|
-
actorIdPart = actorId;
|
|
137
139
|
actorDisplay = actorId.charAt(0).toUpperCase() + actorId.slice(1);
|
|
138
140
|
}
|
|
139
|
-
}
|
|
141
|
+
}
|
|
142
|
+
if (!actorDisplay) {
|
|
140
143
|
actorDisplay = "Unknown Actor";
|
|
141
|
-
actorIdPart = "unknown";
|
|
142
144
|
}
|
|
143
145
|
const userName = actorDisplay;
|
|
144
|
-
const userHandle = actorIdPart;
|
|
145
|
-
const initials =
|
|
146
|
+
const userHandle = actorIdPart || "unknown";
|
|
147
|
+
const initials = userHandle.charAt(0).toUpperCase();
|
|
146
148
|
const actorAvatarOrIcon = actorId && getActorAvatar ? getActorAvatar(actorId) : void 0;
|
|
147
149
|
let actorAvatar = void 0;
|
|
148
150
|
let actorIcon = void 0;
|
|
@@ -189,6 +191,9 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
|
|
|
189
191
|
if (params.entityType) {
|
|
190
192
|
url.searchParams.set("entityType", params.entityType);
|
|
191
193
|
}
|
|
194
|
+
if (params.actorType) {
|
|
195
|
+
url.searchParams.set("actorType", params.actorType);
|
|
196
|
+
}
|
|
192
197
|
if (params.limit) {
|
|
193
198
|
url.searchParams.set("limit", String(params.limit));
|
|
194
199
|
}
|
|
@@ -318,22 +323,18 @@ function SimpleAvatar({
|
|
|
318
323
|
}
|
|
319
324
|
);
|
|
320
325
|
}
|
|
321
|
-
function getActorType(actorId) {
|
|
322
|
-
if (!actorId) return "user";
|
|
323
|
-
if (actorId.includes(":")) {
|
|
324
|
-
const [type] = actorId.split(":");
|
|
325
|
-
if (type === "service" || type === "system") {
|
|
326
|
-
return type;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
return "user";
|
|
330
|
-
}
|
|
331
326
|
function applyClientSideFilters(events, searchQuery, showSystemAndServices) {
|
|
332
327
|
let filtered = events;
|
|
333
328
|
if (!showSystemAndServices) {
|
|
334
329
|
filtered = filtered.filter((event) => {
|
|
335
|
-
|
|
336
|
-
|
|
330
|
+
if (event.actorType) {
|
|
331
|
+
return event.actorType === "user";
|
|
332
|
+
}
|
|
333
|
+
if (event.actorId && event.actorId.includes(":")) {
|
|
334
|
+
const [type] = event.actorId.split(":");
|
|
335
|
+
return type !== "service" && type !== "system";
|
|
336
|
+
}
|
|
337
|
+
return true;
|
|
337
338
|
});
|
|
338
339
|
}
|
|
339
340
|
if (!searchQuery.trim()) {
|
|
@@ -341,7 +342,7 @@ function applyClientSideFilters(events, searchQuery, showSystemAndServices) {
|
|
|
341
342
|
}
|
|
342
343
|
const query = searchQuery.toLowerCase();
|
|
343
344
|
return filtered.filter((event) => {
|
|
344
|
-
return event.action.toLowerCase().includes(query) || event.entityType.toLowerCase().includes(query) || event.entityId.toLowerCase().includes(query) || event.actorId && event.actorId.toLowerCase().includes(query) || event.source && event.source.toLowerCase().includes(query);
|
|
345
|
+
return event.action.toLowerCase().includes(query) || event.entityType.toLowerCase().includes(query) || event.entityId.toLowerCase().includes(query) || event.actorId && event.actorId.toLowerCase().includes(query) || event.source && event.source.toLowerCase().includes(query) || event.actorDisplay && event.actorDisplay.toLowerCase().includes(query);
|
|
345
346
|
});
|
|
346
347
|
}
|
|
347
348
|
function Timeline({
|
|
@@ -372,6 +373,8 @@ function Timeline({
|
|
|
372
373
|
entityId,
|
|
373
374
|
actorId,
|
|
374
375
|
entityType,
|
|
376
|
+
// Filter by actorType on API side
|
|
377
|
+
actorType: showSystemAndServices ? void 0 : "user",
|
|
375
378
|
limit: initialLimit,
|
|
376
379
|
cursor: options?.reset ? void 0 : options?.currentCursor ?? cursor
|
|
377
380
|
};
|
|
@@ -390,13 +393,13 @@ function Timeline({
|
|
|
390
393
|
setLoading(false);
|
|
391
394
|
}
|
|
392
395
|
},
|
|
393
|
-
[entityId, actorId, entityType, initialLimit, apiBaseUrl, getToken, forceRefreshToken, cursor]
|
|
396
|
+
[entityId, actorId, entityType, initialLimit, apiBaseUrl, getToken, forceRefreshToken, cursor, showSystemAndServices]
|
|
394
397
|
);
|
|
395
398
|
React2.useEffect(() => {
|
|
396
399
|
setCursor(void 0);
|
|
397
400
|
setAllEvents([]);
|
|
398
401
|
void load({ reset: true });
|
|
399
|
-
}, [entityId, actorId, entityType]);
|
|
402
|
+
}, [entityId, actorId, entityType, showSystemAndServices]);
|
|
400
403
|
const filteredEvents = React2.useMemo(() => {
|
|
401
404
|
return applyClientSideFilters(allEvents, searchQuery, showSystemAndServices);
|
|
402
405
|
}, [allEvents, searchQuery, showSystemAndServices]);
|
package/dist/react/client.mjs
CHANGED
|
@@ -74,30 +74,32 @@ var CloudCogIcon = ({ className }) => /* @__PURE__ */ jsxs(
|
|
|
74
74
|
);
|
|
75
75
|
function eventToTimelineItem(event, getActorAvatar) {
|
|
76
76
|
const actorId = event.actorId;
|
|
77
|
-
|
|
77
|
+
const actorType = event.actorType || "user";
|
|
78
78
|
let actorIdPart = actorId || "";
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
if (actorId && actorId.includes(":")) {
|
|
80
|
+
const [, ...rest] = actorId.split(":");
|
|
81
|
+
actorIdPart = rest.join(":") || actorId;
|
|
82
|
+
}
|
|
83
|
+
let actorDisplay = event.actorDisplay || null;
|
|
84
|
+
if (!actorDisplay && actorId) {
|
|
81
85
|
if (actorId.includes(":")) {
|
|
82
86
|
const [type, ...rest] = actorId.split(":");
|
|
83
|
-
|
|
84
|
-
actorIdPart = rest.join(":");
|
|
87
|
+
const idPart = rest.join(":");
|
|
85
88
|
if (type === "service" || type === "system") {
|
|
86
|
-
actorDisplay = `${type.charAt(0).toUpperCase() + type.slice(1)} ${
|
|
89
|
+
actorDisplay = `${type.charAt(0).toUpperCase() + type.slice(1)} ${idPart.charAt(0).toUpperCase() + idPart.slice(1)}`;
|
|
87
90
|
} else {
|
|
88
|
-
actorDisplay =
|
|
91
|
+
actorDisplay = idPart.charAt(0).toUpperCase() + idPart.slice(1);
|
|
89
92
|
}
|
|
90
93
|
} else {
|
|
91
|
-
actorIdPart = actorId;
|
|
92
94
|
actorDisplay = actorId.charAt(0).toUpperCase() + actorId.slice(1);
|
|
93
95
|
}
|
|
94
|
-
}
|
|
96
|
+
}
|
|
97
|
+
if (!actorDisplay) {
|
|
95
98
|
actorDisplay = "Unknown Actor";
|
|
96
|
-
actorIdPart = "unknown";
|
|
97
99
|
}
|
|
98
100
|
const userName = actorDisplay;
|
|
99
|
-
const userHandle = actorIdPart;
|
|
100
|
-
const initials =
|
|
101
|
+
const userHandle = actorIdPart || "unknown";
|
|
102
|
+
const initials = userHandle.charAt(0).toUpperCase();
|
|
101
103
|
const actorAvatarOrIcon = actorId && getActorAvatar ? getActorAvatar(actorId) : void 0;
|
|
102
104
|
let actorAvatar = void 0;
|
|
103
105
|
let actorIcon = void 0;
|
|
@@ -144,6 +146,9 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
|
|
|
144
146
|
if (params.entityType) {
|
|
145
147
|
url.searchParams.set("entityType", params.entityType);
|
|
146
148
|
}
|
|
149
|
+
if (params.actorType) {
|
|
150
|
+
url.searchParams.set("actorType", params.actorType);
|
|
151
|
+
}
|
|
147
152
|
if (params.limit) {
|
|
148
153
|
url.searchParams.set("limit", String(params.limit));
|
|
149
154
|
}
|
|
@@ -273,22 +278,18 @@ function SimpleAvatar({
|
|
|
273
278
|
}
|
|
274
279
|
);
|
|
275
280
|
}
|
|
276
|
-
function getActorType(actorId) {
|
|
277
|
-
if (!actorId) return "user";
|
|
278
|
-
if (actorId.includes(":")) {
|
|
279
|
-
const [type] = actorId.split(":");
|
|
280
|
-
if (type === "service" || type === "system") {
|
|
281
|
-
return type;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
return "user";
|
|
285
|
-
}
|
|
286
281
|
function applyClientSideFilters(events, searchQuery, showSystemAndServices) {
|
|
287
282
|
let filtered = events;
|
|
288
283
|
if (!showSystemAndServices) {
|
|
289
284
|
filtered = filtered.filter((event) => {
|
|
290
|
-
|
|
291
|
-
|
|
285
|
+
if (event.actorType) {
|
|
286
|
+
return event.actorType === "user";
|
|
287
|
+
}
|
|
288
|
+
if (event.actorId && event.actorId.includes(":")) {
|
|
289
|
+
const [type] = event.actorId.split(":");
|
|
290
|
+
return type !== "service" && type !== "system";
|
|
291
|
+
}
|
|
292
|
+
return true;
|
|
292
293
|
});
|
|
293
294
|
}
|
|
294
295
|
if (!searchQuery.trim()) {
|
|
@@ -296,7 +297,7 @@ function applyClientSideFilters(events, searchQuery, showSystemAndServices) {
|
|
|
296
297
|
}
|
|
297
298
|
const query = searchQuery.toLowerCase();
|
|
298
299
|
return filtered.filter((event) => {
|
|
299
|
-
return event.action.toLowerCase().includes(query) || event.entityType.toLowerCase().includes(query) || event.entityId.toLowerCase().includes(query) || event.actorId && event.actorId.toLowerCase().includes(query) || event.source && event.source.toLowerCase().includes(query);
|
|
300
|
+
return event.action.toLowerCase().includes(query) || event.entityType.toLowerCase().includes(query) || event.entityId.toLowerCase().includes(query) || event.actorId && event.actorId.toLowerCase().includes(query) || event.source && event.source.toLowerCase().includes(query) || event.actorDisplay && event.actorDisplay.toLowerCase().includes(query);
|
|
300
301
|
});
|
|
301
302
|
}
|
|
302
303
|
function Timeline({
|
|
@@ -327,6 +328,8 @@ function Timeline({
|
|
|
327
328
|
entityId,
|
|
328
329
|
actorId,
|
|
329
330
|
entityType,
|
|
331
|
+
// Filter by actorType on API side
|
|
332
|
+
actorType: showSystemAndServices ? void 0 : "user",
|
|
330
333
|
limit: initialLimit,
|
|
331
334
|
cursor: options?.reset ? void 0 : options?.currentCursor ?? cursor
|
|
332
335
|
};
|
|
@@ -345,13 +348,13 @@ function Timeline({
|
|
|
345
348
|
setLoading(false);
|
|
346
349
|
}
|
|
347
350
|
},
|
|
348
|
-
[entityId, actorId, entityType, initialLimit, apiBaseUrl, getToken, forceRefreshToken, cursor]
|
|
351
|
+
[entityId, actorId, entityType, initialLimit, apiBaseUrl, getToken, forceRefreshToken, cursor, showSystemAndServices]
|
|
349
352
|
);
|
|
350
353
|
React.useEffect(() => {
|
|
351
354
|
setCursor(void 0);
|
|
352
355
|
setAllEvents([]);
|
|
353
356
|
void load({ reset: true });
|
|
354
|
-
}, [entityId, actorId, entityType]);
|
|
357
|
+
}, [entityId, actorId, entityType, showSystemAndServices]);
|
|
355
358
|
const filteredEvents = React.useMemo(() => {
|
|
356
359
|
return applyClientSideFilters(allEvents, searchQuery, showSystemAndServices);
|
|
357
360
|
}, [allEvents, searchQuery, showSystemAndServices]);
|
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-BJ8aJsbs.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-BJ8aJsbs.js';
|
|
2
2
|
import 'next/server';
|
package/dist/server/index.js
CHANGED
|
@@ -173,6 +173,9 @@ async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
|
|
|
173
173
|
if (params.entityType) {
|
|
174
174
|
url.searchParams.set("entityType", params.entityType);
|
|
175
175
|
}
|
|
176
|
+
if (params.actorType) {
|
|
177
|
+
url.searchParams.set("actorType", params.actorType);
|
|
178
|
+
}
|
|
176
179
|
if (params.limit) {
|
|
177
180
|
url.searchParams.set("limit", String(params.limit));
|
|
178
181
|
}
|
|
@@ -194,8 +197,30 @@ async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
|
|
|
194
197
|
details: payload
|
|
195
198
|
});
|
|
196
199
|
}
|
|
200
|
+
const items = payload.items.map((item) => {
|
|
201
|
+
if (typeof item !== "object" || item === null) {
|
|
202
|
+
throw new ArchivaError({
|
|
203
|
+
statusCode: response.status,
|
|
204
|
+
code: "HTTP_ERROR",
|
|
205
|
+
message: "Invalid item format in response",
|
|
206
|
+
details: item
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const event = item;
|
|
210
|
+
return {
|
|
211
|
+
id: String(event.id ?? ""),
|
|
212
|
+
receivedAt: String(event.receivedAt ?? ""),
|
|
213
|
+
action: String(event.action ?? ""),
|
|
214
|
+
entityType: String(event.entityType ?? ""),
|
|
215
|
+
entityId: String(event.entityId ?? ""),
|
|
216
|
+
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : null,
|
|
217
|
+
actorType: event.actorType && (event.actorType === "user" || event.actorType === "service" || event.actorType === "system") ? event.actorType : void 0,
|
|
218
|
+
actorDisplay: event.actorDisplay !== null && event.actorDisplay !== void 0 ? String(event.actorDisplay) : void 0,
|
|
219
|
+
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
220
|
+
};
|
|
221
|
+
});
|
|
197
222
|
return {
|
|
198
|
-
items
|
|
223
|
+
items,
|
|
199
224
|
nextCursor: typeof payload.nextCursor === "string" ? payload.nextCursor : void 0
|
|
200
225
|
};
|
|
201
226
|
}
|
package/dist/server/index.mjs
CHANGED