c95f2c6 ←19ea0abantonApr 11, 2026 api

edit api.ts via macOS

M /sublimated/undefined +53 -1
7 unmodified lines
8 authorName: string;
9 authorType: string;
10 message: string | null;
11 createdAt: string;
12 commitHash: string | null;
12}
13
15export interface VersionsResponse {
16 versions: Version[];
14export class AuthRequiredError extends Error {
15 constructor(public status: number) {
16 super(`auth required (${status})`);
17 this.name = "AuthRequiredError";
18 }
19}
20
21// Raw wire format from api.sublimated.com
22interface RawActor {
23 username: string | null;
24 name: string | null;
25 role: string;
26 actor_type: string;
27}
28
29interface RawVersion {
30 id: string;
31 item_id: string;
32 version: number;
33 content_hash: string;
34 blob_sha1: string | null;
35 size_bytes: number;
36 message: string | null;
37 name: string | null;
38 created_at: string;
39 actors: RawActor[];
40}
41
42interface ApiEnvelope<T> {
43 ok: boolean;
44 data?: T;
45 error?: { type: string; message?: string };
46}
47
48export interface TestConnectionResult {
49 ok: boolean;
50 username?: string;
51 error?: string;
11 unmodified lines
63 }
64 const response = await requestUrl({
65 url: `${API_BASE}${path}`,
66 headers,
67 throw: false,
68 });
69
70 if (response.status === 401 || response.status === 403) {
71 throw new AuthRequiredError(response.status);
72 }
73 if (response.status >= 400) {
74 throw new Error(
75 `API error ${response.status}: ${response.text}`
76 );
77 }
78
46 return response.json as T;
79 const body = response.json as ApiEnvelope<T>;
80 if (!body.ok || body.data === undefined) {
81 const msg = body.error?.message || body.error?.type || "unknown error";
82 throw new Error(`API error: ${msg}`);
83 }
84 return body.data;
85 }
86
87 async getVersions(
88 spaceSlug: string,
89 itemId: string
90 ): Promise<Version[]> {
53 const data = await this.request<VersionsResponse>(
91 const raw = await this.request<RawVersion[]>(
92 `/v1/spaces/${encodeURIComponent(spaceSlug)}/items/${encodeURIComponent(itemId)}/versions`
93 );
56 return data.versions;
94 return raw.map(mapVersion);
95 }
96
97 async testConnection(): Promise<TestConnectionResult> {
98 try {
8 unmodified lines
107 };
108 }
109 }
110}
111
112function mapVersion(r: RawVersion): Version {
113 // pick the author actor; fall back to the first actor or a placeholder
114 const author =
115 r.actors.find((a) => a.role === "author") ?? r.actors[0] ?? null;
116 return {
117 id: r.id,
118 number: r.version,
119 authorName: author?.name ?? author?.username ?? "unknown",
120 authorType: author?.actor_type ?? "person",
121 message: r.message,
122 createdAt: r.created_at,
123 };
124}