@archiva/archiva-nextjs 0.2.7 → 0.2.81
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.js +26 -1
- package/dist/index.mjs +1 -1
- package/dist/react/client.js +42 -36
- package/dist/react/client.mjs +42 -36
- package/dist/server/index.js +26 -1
- package/dist/server/index.mjs +1 -1
- package/package.json +2 -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
|
+
};
|
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
|
@@ -118,34 +118,13 @@ var CloudCogIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime2.js
|
|
|
118
118
|
}
|
|
119
119
|
);
|
|
120
120
|
function eventToTimelineItem(event, getActorAvatar) {
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
let actorDisplay = event.actorDisplay || null;
|
|
129
|
-
if (!actorDisplay && actorId) {
|
|
130
|
-
if (actorId.includes(":")) {
|
|
131
|
-
const [type, ...rest] = actorId.split(":");
|
|
132
|
-
const idPart = rest.join(":");
|
|
133
|
-
if (type === "service" || type === "system") {
|
|
134
|
-
actorDisplay = `${type.charAt(0).toUpperCase() + type.slice(1)} ${idPart.charAt(0).toUpperCase() + idPart.slice(1)}`;
|
|
135
|
-
} else {
|
|
136
|
-
actorDisplay = idPart.charAt(0).toUpperCase() + idPart.slice(1);
|
|
137
|
-
}
|
|
138
|
-
} else {
|
|
139
|
-
actorDisplay = actorId.charAt(0).toUpperCase() + actorId.slice(1);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (!actorDisplay) {
|
|
143
|
-
actorDisplay = "Unknown Actor";
|
|
144
|
-
}
|
|
145
|
-
const userName = actorDisplay;
|
|
146
|
-
const userHandle = actorIdPart || "unknown";
|
|
147
|
-
const initials = userHandle.charAt(0).toUpperCase();
|
|
148
|
-
const actorAvatarOrIcon = actorId && getActorAvatar ? getActorAvatar(actorId) : void 0;
|
|
121
|
+
const action = event.action.charAt(0).toUpperCase() + event.action.slice(1);
|
|
122
|
+
const description = action;
|
|
123
|
+
const actorId = event.actorId || "unknown";
|
|
124
|
+
const userName = actorId.includes(":") ? actorId.split(":")[1] || actorId : actorId;
|
|
125
|
+
const userHandle = userName;
|
|
126
|
+
const initials = userName.charAt(0).toUpperCase();
|
|
127
|
+
const actorAvatarOrIcon = getActorAvatar ? getActorAvatar(actorId) : void 0;
|
|
149
128
|
let actorAvatar = void 0;
|
|
150
129
|
let actorIcon = void 0;
|
|
151
130
|
if (typeof actorAvatarOrIcon === "string") {
|
|
@@ -153,7 +132,8 @@ function eventToTimelineItem(event, getActorAvatar) {
|
|
|
153
132
|
} else if (actorAvatarOrIcon) {
|
|
154
133
|
actorIcon = actorAvatarOrIcon;
|
|
155
134
|
}
|
|
156
|
-
|
|
135
|
+
const actorType = event.actorType ?? "user";
|
|
136
|
+
if (!actorAvatar && !actorIcon) {
|
|
157
137
|
if (actorType === "user") {
|
|
158
138
|
actorAvatar = "https://www.gravatar.com/avatar?d=mp";
|
|
159
139
|
} else if (actorType === "system") {
|
|
@@ -162,21 +142,30 @@ function eventToTimelineItem(event, getActorAvatar) {
|
|
|
162
142
|
actorIcon = CloudCogIcon;
|
|
163
143
|
}
|
|
164
144
|
}
|
|
165
|
-
const action = event.action.charAt(0).toUpperCase() + event.action.slice(1);
|
|
166
145
|
return {
|
|
167
146
|
id: event.id,
|
|
168
147
|
title: "",
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
148
|
+
// Required by TimelineItem type, but not used in activity layout - matches ActivityLog.tsx line 352
|
|
149
|
+
userName: userName.charAt(0).toUpperCase() + userName.slice(1),
|
|
150
|
+
// Matches ActivityLog.tsx line 353
|
|
151
|
+
actorDisplay: event.actorDisplay ?? void 0,
|
|
152
|
+
// Matches ActivityLog.tsx line 354
|
|
173
153
|
userHandle,
|
|
174
|
-
|
|
154
|
+
// Matches ActivityLog.tsx line 355
|
|
155
|
+
description,
|
|
156
|
+
// Matches ActivityLog.tsx line 356
|
|
175
157
|
entityType: event.entityType.toLowerCase(),
|
|
158
|
+
// Matches ActivityLog.tsx line 357
|
|
159
|
+
timestamp: new Date(event.receivedAt),
|
|
160
|
+
// Matches ActivityLog.tsx line 358 - ensure it's a Date object
|
|
176
161
|
avatar: actorAvatar,
|
|
162
|
+
// Matches ActivityLog.tsx line 359
|
|
177
163
|
icon: actorIcon,
|
|
164
|
+
// Matches ActivityLog.tsx line 360
|
|
178
165
|
avatarFallback: initials,
|
|
166
|
+
// Matches ActivityLog.tsx line 361
|
|
179
167
|
statusIndicator: false,
|
|
168
|
+
// Can be set to true for recent items - matches ActivityLog.tsx line 362
|
|
180
169
|
data: event
|
|
181
170
|
};
|
|
182
171
|
}
|
|
@@ -221,8 +210,25 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
|
|
|
221
210
|
if (!payload || typeof payload !== "object" || !Array.isArray(payload.items)) {
|
|
222
211
|
throw new Error("Invalid response format");
|
|
223
212
|
}
|
|
213
|
+
const items = payload.items.map((item) => {
|
|
214
|
+
if (typeof item !== "object" || item === null) {
|
|
215
|
+
throw new Error("Invalid item format in response");
|
|
216
|
+
}
|
|
217
|
+
const event = item;
|
|
218
|
+
return {
|
|
219
|
+
id: String(event.id ?? ""),
|
|
220
|
+
receivedAt: String(event.receivedAt ?? ""),
|
|
221
|
+
action: String(event.action ?? ""),
|
|
222
|
+
entityType: String(event.entityType ?? ""),
|
|
223
|
+
entityId: String(event.entityId ?? ""),
|
|
224
|
+
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : null,
|
|
225
|
+
actorType: event.actorType && (event.actorType === "user" || event.actorType === "service" || event.actorType === "system") ? event.actorType : void 0,
|
|
226
|
+
actorDisplay: event.actorDisplay !== null && event.actorDisplay !== void 0 ? String(event.actorDisplay) : void 0,
|
|
227
|
+
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
228
|
+
};
|
|
229
|
+
});
|
|
224
230
|
return {
|
|
225
|
-
items
|
|
231
|
+
items,
|
|
226
232
|
nextCursor: typeof payload.nextCursor === "string" ? payload.nextCursor : void 0
|
|
227
233
|
};
|
|
228
234
|
}
|
package/dist/react/client.mjs
CHANGED
|
@@ -73,34 +73,13 @@ var CloudCogIcon = ({ className }) => /* @__PURE__ */ jsxs(
|
|
|
73
73
|
}
|
|
74
74
|
);
|
|
75
75
|
function eventToTimelineItem(event, getActorAvatar) {
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
let actorDisplay = event.actorDisplay || null;
|
|
84
|
-
if (!actorDisplay && actorId) {
|
|
85
|
-
if (actorId.includes(":")) {
|
|
86
|
-
const [type, ...rest] = actorId.split(":");
|
|
87
|
-
const idPart = rest.join(":");
|
|
88
|
-
if (type === "service" || type === "system") {
|
|
89
|
-
actorDisplay = `${type.charAt(0).toUpperCase() + type.slice(1)} ${idPart.charAt(0).toUpperCase() + idPart.slice(1)}`;
|
|
90
|
-
} else {
|
|
91
|
-
actorDisplay = idPart.charAt(0).toUpperCase() + idPart.slice(1);
|
|
92
|
-
}
|
|
93
|
-
} else {
|
|
94
|
-
actorDisplay = actorId.charAt(0).toUpperCase() + actorId.slice(1);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (!actorDisplay) {
|
|
98
|
-
actorDisplay = "Unknown Actor";
|
|
99
|
-
}
|
|
100
|
-
const userName = actorDisplay;
|
|
101
|
-
const userHandle = actorIdPart || "unknown";
|
|
102
|
-
const initials = userHandle.charAt(0).toUpperCase();
|
|
103
|
-
const actorAvatarOrIcon = actorId && getActorAvatar ? getActorAvatar(actorId) : void 0;
|
|
76
|
+
const action = event.action.charAt(0).toUpperCase() + event.action.slice(1);
|
|
77
|
+
const description = action;
|
|
78
|
+
const actorId = event.actorId || "unknown";
|
|
79
|
+
const userName = actorId.includes(":") ? actorId.split(":")[1] || actorId : actorId;
|
|
80
|
+
const userHandle = userName;
|
|
81
|
+
const initials = userName.charAt(0).toUpperCase();
|
|
82
|
+
const actorAvatarOrIcon = getActorAvatar ? getActorAvatar(actorId) : void 0;
|
|
104
83
|
let actorAvatar = void 0;
|
|
105
84
|
let actorIcon = void 0;
|
|
106
85
|
if (typeof actorAvatarOrIcon === "string") {
|
|
@@ -108,7 +87,8 @@ function eventToTimelineItem(event, getActorAvatar) {
|
|
|
108
87
|
} else if (actorAvatarOrIcon) {
|
|
109
88
|
actorIcon = actorAvatarOrIcon;
|
|
110
89
|
}
|
|
111
|
-
|
|
90
|
+
const actorType = event.actorType ?? "user";
|
|
91
|
+
if (!actorAvatar && !actorIcon) {
|
|
112
92
|
if (actorType === "user") {
|
|
113
93
|
actorAvatar = "https://www.gravatar.com/avatar?d=mp";
|
|
114
94
|
} else if (actorType === "system") {
|
|
@@ -117,21 +97,30 @@ function eventToTimelineItem(event, getActorAvatar) {
|
|
|
117
97
|
actorIcon = CloudCogIcon;
|
|
118
98
|
}
|
|
119
99
|
}
|
|
120
|
-
const action = event.action.charAt(0).toUpperCase() + event.action.slice(1);
|
|
121
100
|
return {
|
|
122
101
|
id: event.id,
|
|
123
102
|
title: "",
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
103
|
+
// Required by TimelineItem type, but not used in activity layout - matches ActivityLog.tsx line 352
|
|
104
|
+
userName: userName.charAt(0).toUpperCase() + userName.slice(1),
|
|
105
|
+
// Matches ActivityLog.tsx line 353
|
|
106
|
+
actorDisplay: event.actorDisplay ?? void 0,
|
|
107
|
+
// Matches ActivityLog.tsx line 354
|
|
128
108
|
userHandle,
|
|
129
|
-
|
|
109
|
+
// Matches ActivityLog.tsx line 355
|
|
110
|
+
description,
|
|
111
|
+
// Matches ActivityLog.tsx line 356
|
|
130
112
|
entityType: event.entityType.toLowerCase(),
|
|
113
|
+
// Matches ActivityLog.tsx line 357
|
|
114
|
+
timestamp: new Date(event.receivedAt),
|
|
115
|
+
// Matches ActivityLog.tsx line 358 - ensure it's a Date object
|
|
131
116
|
avatar: actorAvatar,
|
|
117
|
+
// Matches ActivityLog.tsx line 359
|
|
132
118
|
icon: actorIcon,
|
|
119
|
+
// Matches ActivityLog.tsx line 360
|
|
133
120
|
avatarFallback: initials,
|
|
121
|
+
// Matches ActivityLog.tsx line 361
|
|
134
122
|
statusIndicator: false,
|
|
123
|
+
// Can be set to true for recent items - matches ActivityLog.tsx line 362
|
|
135
124
|
data: event
|
|
136
125
|
};
|
|
137
126
|
}
|
|
@@ -176,8 +165,25 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
|
|
|
176
165
|
if (!payload || typeof payload !== "object" || !Array.isArray(payload.items)) {
|
|
177
166
|
throw new Error("Invalid response format");
|
|
178
167
|
}
|
|
168
|
+
const items = payload.items.map((item) => {
|
|
169
|
+
if (typeof item !== "object" || item === null) {
|
|
170
|
+
throw new Error("Invalid item format in response");
|
|
171
|
+
}
|
|
172
|
+
const event = item;
|
|
173
|
+
return {
|
|
174
|
+
id: String(event.id ?? ""),
|
|
175
|
+
receivedAt: String(event.receivedAt ?? ""),
|
|
176
|
+
action: String(event.action ?? ""),
|
|
177
|
+
entityType: String(event.entityType ?? ""),
|
|
178
|
+
entityId: String(event.entityId ?? ""),
|
|
179
|
+
actorId: event.actorId !== null && event.actorId !== void 0 ? String(event.actorId) : null,
|
|
180
|
+
actorType: event.actorType && (event.actorType === "user" || event.actorType === "service" || event.actorType === "system") ? event.actorType : void 0,
|
|
181
|
+
actorDisplay: event.actorDisplay !== null && event.actorDisplay !== void 0 ? String(event.actorDisplay) : void 0,
|
|
182
|
+
source: event.source !== null && event.source !== void 0 ? String(event.source) : null
|
|
183
|
+
};
|
|
184
|
+
});
|
|
179
185
|
return {
|
|
180
|
-
items
|
|
186
|
+
items,
|
|
181
187
|
nextCursor: typeof payload.nextCursor === "string" ? payload.nextCursor : void 0
|
|
182
188
|
};
|
|
183
189
|
}
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archiva/archiva-nextjs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.081",
|
|
4
4
|
"description": "Archiva Next.js SDK - Server Actions and Timeline Component",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"files": ["dist"],
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup src/index.tsx src/react/index.ts src/react/client.ts src/server/index.ts --format esm,cjs --dts",
|
|
33
|
+
"dev": "tsup src/index.tsx src/react/index.ts src/react/client.ts src/server/index.ts --format esm,cjs --dts --watch",
|
|
33
34
|
"test": "vitest run --config vitest.config.ts"
|
|
34
35
|
},
|
|
35
36
|
"peerDependencies": {
|