Spaces:
Paused
Paused
File size: 2,289 Bytes
8523e75 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import { gzipSync } from "node:zlib";
import type { FeedbackTraceBundle } from "@paperclipai/shared";
import type { Config } from "../config.js";
const DEFAULT_FEEDBACK_EXPORT_BACKEND_URL = "https://telemetry.paperclip.ing";
function buildFeedbackShareObjectKey(bundle: FeedbackTraceBundle, exportedAt: Date) {
const year = String(exportedAt.getUTCFullYear());
const month = String(exportedAt.getUTCMonth() + 1).padStart(2, "0");
const day = String(exportedAt.getUTCDate()).padStart(2, "0");
return `feedback-traces/${bundle.companyId}/${year}/${month}/${day}/${bundle.exportId ?? bundle.traceId}.json`;
}
export interface FeedbackTraceShareClient {
uploadTraceBundle(bundle: FeedbackTraceBundle): Promise<{ objectKey: string }>;
}
export function createFeedbackTraceShareClientFromConfig(
config: Pick<Config, "feedbackExportBackendUrl" | "feedbackExportBackendToken">,
): FeedbackTraceShareClient {
const baseUrl = config.feedbackExportBackendUrl?.trim() || DEFAULT_FEEDBACK_EXPORT_BACKEND_URL;
const token = config.feedbackExportBackendToken?.trim();
const endpoint = new URL("/feedback-traces", baseUrl).toString();
return {
async uploadTraceBundle(bundle) {
const exportedAt = new Date();
const objectKey = buildFeedbackShareObjectKey(bundle, exportedAt);
const requestBody = JSON.stringify({
objectKey,
exportedAt: exportedAt.toISOString(),
bundle,
});
const response = await fetch(endpoint, {
method: "POST",
headers: {
"content-type": "application/json",
...(token ? { authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify({
encoding: "gzip+base64+json",
payload: gzipSync(requestBody).toString("base64"),
}),
});
if (!response.ok) {
const detail = await response.text().catch(() => "");
throw new Error(detail.trim() || `Feedback trace upload failed with HTTP ${response.status}`);
}
const payload = await response.json().catch(() => null) as { objectKey?: unknown } | null;
return {
objectKey: typeof payload?.objectKey === "string" && payload.objectKey.trim().length > 0
? payload.objectKey
: objectKey,
};
},
};
}
|