@infinite-room-labs/claudesync-core 0.1.0
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/auth/__tests__/env.test.d.ts +2 -0
- package/dist/auth/__tests__/env.test.d.ts.map +1 -0
- package/dist/auth/__tests__/env.test.js +42 -0
- package/dist/auth/__tests__/env.test.js.map +1 -0
- package/dist/auth/__tests__/firefox.test.d.ts +2 -0
- package/dist/auth/__tests__/firefox.test.d.ts.map +1 -0
- package/dist/auth/__tests__/firefox.test.js +291 -0
- package/dist/auth/__tests__/firefox.test.js.map +1 -0
- package/dist/auth/env.d.ts +10 -0
- package/dist/auth/env.d.ts.map +1 -0
- package/dist/auth/env.js +46 -0
- package/dist/auth/env.js.map +1 -0
- package/dist/auth/errors.d.ts +4 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/errors.js +7 -0
- package/dist/auth/errors.js.map +1 -0
- package/dist/auth/firefox.d.ts +12 -0
- package/dist/auth/firefox.d.ts.map +1 -0
- package/dist/auth/firefox.js +190 -0
- package/dist/auth/firefox.js.map +1 -0
- package/dist/auth/types.d.ts +10 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/client/__tests__/client.test.d.ts +2 -0
- package/dist/client/__tests__/client.test.d.ts.map +1 -0
- package/dist/client/__tests__/client.test.js +50 -0
- package/dist/client/__tests__/client.test.js.map +1 -0
- package/dist/client/__tests__/endpoints.test.d.ts +2 -0
- package/dist/client/__tests__/endpoints.test.d.ts.map +1 -0
- package/dist/client/__tests__/endpoints.test.js +26 -0
- package/dist/client/__tests__/endpoints.test.js.map +1 -0
- package/dist/client/client.d.ts +54 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +144 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/endpoints.d.ts +18 -0
- package/dist/client/endpoints.d.ts.map +1 -0
- package/dist/client/endpoints.js +25 -0
- package/dist/client/endpoints.js.map +1 -0
- package/dist/client/errors.d.ts +11 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +22 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/export/__tests__/bundle-builder.test.d.ts +2 -0
- package/dist/export/__tests__/bundle-builder.test.d.ts.map +1 -0
- package/dist/export/__tests__/bundle-builder.test.js +272 -0
- package/dist/export/__tests__/bundle-builder.test.js.map +1 -0
- package/dist/export/__tests__/conversation-formatter.test.d.ts +2 -0
- package/dist/export/__tests__/conversation-formatter.test.d.ts.map +1 -0
- package/dist/export/__tests__/conversation-formatter.test.js +99 -0
- package/dist/export/__tests__/conversation-formatter.test.js.map +1 -0
- package/dist/export/bundle-builder.d.ts +24 -0
- package/dist/export/bundle-builder.d.ts.map +1 -0
- package/dist/export/bundle-builder.js +94 -0
- package/dist/export/bundle-builder.js.map +1 -0
- package/dist/export/conversation-formatter.d.ts +23 -0
- package/dist/export/conversation-formatter.d.ts.map +1 -0
- package/dist/export/conversation-formatter.js +40 -0
- package/dist/export/conversation-formatter.js.map +1 -0
- package/dist/export/git-exporter.d.ts +12 -0
- package/dist/export/git-exporter.d.ts.map +1 -0
- package/dist/export/git-exporter.js +68 -0
- package/dist/export/git-exporter.js.map +1 -0
- package/dist/export/types.d.ts +27 -0
- package/dist/export/types.d.ts.map +1 -0
- package/dist/export/types.js +2 -0
- package/dist/export/types.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/models/__tests__/schemas.test.d.ts +2 -0
- package/dist/models/__tests__/schemas.test.d.ts.map +1 -0
- package/dist/models/__tests__/schemas.test.js +189 -0
- package/dist/models/__tests__/schemas.test.js.map +1 -0
- package/dist/models/schemas.d.ts +805 -0
- package/dist/models/schemas.d.ts.map +1 -0
- package/dist/models/schemas.js +119 -0
- package/dist/models/schemas.js.map +1 -0
- package/dist/models/types.d.ts +15 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +2 -0
- package/dist/models/types.js.map +1 -0
- package/dist/tree/__tests__/message-tree.test.d.ts +2 -0
- package/dist/tree/__tests__/message-tree.test.d.ts.map +1 -0
- package/dist/tree/__tests__/message-tree.test.js +176 -0
- package/dist/tree/__tests__/message-tree.test.js.map +1 -0
- package/dist/tree/message-tree.d.ts +35 -0
- package/dist/tree/message-tree.d.ts.map +1 -0
- package/dist/tree/message-tree.js +70 -0
- package/dist/tree/message-tree.js.map +1 -0
- package/package.json +31 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { AuthError } from "./errors.js";
|
|
2
|
+
import Database from "better-sqlite3";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { platform } from "node:process";
|
|
7
|
+
const DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36";
|
|
8
|
+
/**
|
|
9
|
+
* Candidate Firefox root directories, in priority order.
|
|
10
|
+
* The first one that exists wins.
|
|
11
|
+
*/
|
|
12
|
+
function getFirefoxRootCandidates() {
|
|
13
|
+
const home = homedir();
|
|
14
|
+
if (platform === "darwin") {
|
|
15
|
+
return [join(home, "Library", "Application Support", "Firefox")];
|
|
16
|
+
}
|
|
17
|
+
// Linux: Snap is default on Ubuntu 24.04, so check it first
|
|
18
|
+
return [
|
|
19
|
+
join(home, ".mozilla", "firefox"),
|
|
20
|
+
join(home, "snap", "firefox", "common", ".mozilla", "firefox"),
|
|
21
|
+
join(home, ".var", "app", "org.mozilla.firefox", ".mozilla", "firefox"),
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse `profiles.ini` to find the default profile directory.
|
|
26
|
+
*
|
|
27
|
+
* The INI file contains `[Profile0]`, `[Profile1]`, etc. sections.
|
|
28
|
+
* We pick the first profile where `Default=1`, falling back to `[Profile0]`.
|
|
29
|
+
* The `Path` key is relative to the Firefox root (when `IsRelative=1`)
|
|
30
|
+
* or absolute.
|
|
31
|
+
*/
|
|
32
|
+
function resolveProfileDir(firefoxRoot) {
|
|
33
|
+
const iniPath = join(firefoxRoot, "profiles.ini");
|
|
34
|
+
if (!existsSync(iniPath)) {
|
|
35
|
+
throw new AuthError(`Firefox profiles.ini not found at ${iniPath}. ` +
|
|
36
|
+
"Is Firefox installed?");
|
|
37
|
+
}
|
|
38
|
+
const content = readFileSync(iniPath, "utf-8");
|
|
39
|
+
const lines = content.split(/\r?\n/);
|
|
40
|
+
let currentPath = null;
|
|
41
|
+
let currentIsRelative = true;
|
|
42
|
+
let currentIsDefault = false;
|
|
43
|
+
let fallbackPath = null;
|
|
44
|
+
let fallbackIsRelative = true;
|
|
45
|
+
let inProfileSection = false;
|
|
46
|
+
for (const line of lines) {
|
|
47
|
+
const trimmed = line.trim();
|
|
48
|
+
// Section header
|
|
49
|
+
if (trimmed.startsWith("[")) {
|
|
50
|
+
// Before moving to a new section, check if the previous section was the default
|
|
51
|
+
if (inProfileSection && currentIsDefault && currentPath) {
|
|
52
|
+
return currentIsRelative
|
|
53
|
+
? join(firefoxRoot, currentPath)
|
|
54
|
+
: currentPath;
|
|
55
|
+
}
|
|
56
|
+
inProfileSection = /^\[Profile\d+\]$/i.test(trimmed);
|
|
57
|
+
if (inProfileSection) {
|
|
58
|
+
// Reset per-section state
|
|
59
|
+
currentPath = null;
|
|
60
|
+
currentIsRelative = true;
|
|
61
|
+
currentIsDefault = false;
|
|
62
|
+
// Track the very first profile as fallback
|
|
63
|
+
if (fallbackPath === null) {
|
|
64
|
+
// We'll set fallbackPath when we encounter the Path key
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (!inProfileSection)
|
|
70
|
+
continue;
|
|
71
|
+
const eqIdx = trimmed.indexOf("=");
|
|
72
|
+
if (eqIdx === -1)
|
|
73
|
+
continue;
|
|
74
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
75
|
+
const value = trimmed.slice(eqIdx + 1).trim();
|
|
76
|
+
if (key === "Path") {
|
|
77
|
+
currentPath = value;
|
|
78
|
+
if (fallbackPath === null) {
|
|
79
|
+
fallbackPath = value;
|
|
80
|
+
fallbackIsRelative = currentIsRelative;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if (key === "IsRelative") {
|
|
84
|
+
currentIsRelative = value === "1";
|
|
85
|
+
// Update fallback if this is the first profile section
|
|
86
|
+
if (fallbackPath === null) {
|
|
87
|
+
fallbackIsRelative = currentIsRelative;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (key === "Default" && value === "1") {
|
|
91
|
+
currentIsDefault = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Check the last section (loop may have ended inside a profile section)
|
|
95
|
+
if (inProfileSection && currentIsDefault && currentPath) {
|
|
96
|
+
return currentIsRelative
|
|
97
|
+
? join(firefoxRoot, currentPath)
|
|
98
|
+
: currentPath;
|
|
99
|
+
}
|
|
100
|
+
// No explicit default found -- use the first profile
|
|
101
|
+
if (fallbackPath) {
|
|
102
|
+
return fallbackIsRelative
|
|
103
|
+
? join(firefoxRoot, fallbackPath)
|
|
104
|
+
: fallbackPath;
|
|
105
|
+
}
|
|
106
|
+
throw new AuthError(`No profile entries found in ${iniPath}. ` +
|
|
107
|
+
"The profiles.ini file may be corrupted.");
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Auto-discover the Firefox profile directory by checking standard paths.
|
|
111
|
+
*/
|
|
112
|
+
function discoverProfilePath() {
|
|
113
|
+
const candidates = getFirefoxRootCandidates();
|
|
114
|
+
for (const root of candidates) {
|
|
115
|
+
if (existsSync(root)) {
|
|
116
|
+
return resolveProfileDir(root);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
throw new AuthError("Could not find a Firefox installation. Checked:\n" +
|
|
120
|
+
candidates.map((c) => ` - ${c}`).join("\n") +
|
|
121
|
+
"\n\nProvide the profile path explicitly via the profilePath option.");
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Read the `sessionKey` cookie for claude.ai from Firefox's cookies.sqlite.
|
|
125
|
+
*
|
|
126
|
+
* Opens the database in read-only mode with `immutable=1` URI flag to avoid
|
|
127
|
+
* interfering with Firefox's WAL journal while the browser is running.
|
|
128
|
+
*/
|
|
129
|
+
function readSessionCookie(profilePath) {
|
|
130
|
+
const cookiesPath = join(profilePath, "cookies.sqlite");
|
|
131
|
+
if (!existsSync(cookiesPath)) {
|
|
132
|
+
throw new AuthError(`cookies.sqlite not found at ${cookiesPath}. ` +
|
|
133
|
+
"Make sure the Firefox profile path is correct and Firefox has been used at least once.");
|
|
134
|
+
}
|
|
135
|
+
const uri = `file:${cookiesPath}?immutable=1`;
|
|
136
|
+
let db = null;
|
|
137
|
+
try {
|
|
138
|
+
db = new Database(uri, { readonly: true, fileMustExist: true });
|
|
139
|
+
const row = db
|
|
140
|
+
.prepare("SELECT value FROM moz_cookies WHERE host LIKE '%claude.ai%' AND name = 'sessionKey'")
|
|
141
|
+
.get();
|
|
142
|
+
if (!row) {
|
|
143
|
+
throw new AuthError("No sessionKey cookie found for claude.ai in Firefox. " +
|
|
144
|
+
"Make sure you are logged in to claude.ai in Firefox.");
|
|
145
|
+
}
|
|
146
|
+
return row.value;
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
if (db) {
|
|
150
|
+
db.close();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export class FirefoxProfileAuth {
|
|
155
|
+
sessionKey;
|
|
156
|
+
userAgent;
|
|
157
|
+
cachedOrgId = null;
|
|
158
|
+
constructor(options) {
|
|
159
|
+
const profilePath = options?.profilePath ?? discoverProfilePath();
|
|
160
|
+
this.sessionKey = readSessionCookie(profilePath);
|
|
161
|
+
this.userAgent = DEFAULT_USER_AGENT;
|
|
162
|
+
}
|
|
163
|
+
async getHeaders() {
|
|
164
|
+
return {
|
|
165
|
+
Cookie: `sessionKey=${this.sessionKey}`,
|
|
166
|
+
"User-Agent": this.userAgent,
|
|
167
|
+
Accept: "application/json",
|
|
168
|
+
"Content-Type": "application/json",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async getOrganizationId() {
|
|
172
|
+
if (this.cachedOrgId) {
|
|
173
|
+
return this.cachedOrgId;
|
|
174
|
+
}
|
|
175
|
+
const headers = await this.getHeaders();
|
|
176
|
+
const response = await fetch("https://claude.ai/api/organizations", {
|
|
177
|
+
headers,
|
|
178
|
+
});
|
|
179
|
+
if (!response.ok) {
|
|
180
|
+
throw new AuthError(`Failed to fetch organizations: ${response.status} ${response.statusText}`);
|
|
181
|
+
}
|
|
182
|
+
const orgs = await response.json();
|
|
183
|
+
if (!Array.isArray(orgs) || orgs.length === 0 || !orgs[0].uuid) {
|
|
184
|
+
throw new AuthError("No organizations found for this session");
|
|
185
|
+
}
|
|
186
|
+
this.cachedOrgId = orgs[0].uuid;
|
|
187
|
+
return this.cachedOrgId;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=firefox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firefox.js","sourceRoot":"","sources":["../../src/auth/firefox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface AuthProvider {
|
|
2
|
+
/** Build the HTTP headers needed for claude.ai API requests */
|
|
3
|
+
getHeaders(): Promise<Record<string, string>>;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the organization UUID for this session.
|
|
6
|
+
* Makes an API call to /api/organizations on first call, caches the result.
|
|
7
|
+
*/
|
|
8
|
+
getOrganizationId(): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAE9C;;;OAGG;IACH,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACtC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../../src/client/__tests__/client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { ClaudeSyncClient } from "../client.js";
|
|
3
|
+
// Mock AuthProvider that returns fixed headers
|
|
4
|
+
function createMockAuth() {
|
|
5
|
+
return {
|
|
6
|
+
getHeaders: async () => ({
|
|
7
|
+
Cookie: "test-cookie",
|
|
8
|
+
"User-Agent": "test-agent",
|
|
9
|
+
}),
|
|
10
|
+
getOrganizationId: async () => "org-123",
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
describe("ClaudeSyncClient", () => {
|
|
14
|
+
it("constructs with an auth provider", () => {
|
|
15
|
+
const client = new ClaudeSyncClient(createMockAuth());
|
|
16
|
+
expect(client).toBeDefined();
|
|
17
|
+
});
|
|
18
|
+
it("constructs with custom rate limit delay", () => {
|
|
19
|
+
const client = new ClaudeSyncClient(createMockAuth(), {
|
|
20
|
+
rateLimitDelayMs: 500,
|
|
21
|
+
});
|
|
22
|
+
expect(client).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
it("exposes listOrganizations method", () => {
|
|
25
|
+
const client = new ClaudeSyncClient(createMockAuth());
|
|
26
|
+
expect(typeof client.listOrganizations).toBe("function");
|
|
27
|
+
});
|
|
28
|
+
it("exposes listConversations as async iterable", () => {
|
|
29
|
+
const client = new ClaudeSyncClient(createMockAuth());
|
|
30
|
+
expect(typeof client.listConversations).toBe("function");
|
|
31
|
+
});
|
|
32
|
+
it("exposes listConversationsAll convenience method", () => {
|
|
33
|
+
const client = new ClaudeSyncClient(createMockAuth());
|
|
34
|
+
expect(typeof client.listConversationsAll).toBe("function");
|
|
35
|
+
});
|
|
36
|
+
it("exposes getConversation method", () => {
|
|
37
|
+
const client = new ClaudeSyncClient(createMockAuth());
|
|
38
|
+
expect(typeof client.getConversation).toBe("function");
|
|
39
|
+
});
|
|
40
|
+
it("exposes searchConversations method", () => {
|
|
41
|
+
const client = new ClaudeSyncClient(createMockAuth());
|
|
42
|
+
expect(typeof client.searchConversations).toBe("function");
|
|
43
|
+
});
|
|
44
|
+
it("exposes artifact methods", () => {
|
|
45
|
+
const client = new ClaudeSyncClient(createMockAuth());
|
|
46
|
+
expect(typeof client.listArtifacts).toBe("function");
|
|
47
|
+
expect(typeof client.downloadArtifact).toBe("function");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../../src/client/__tests__/client.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,+CAA+C;AAC/C,SAAS,cAAc;IACrB,OAAO;QACL,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YACvB,MAAM,EAAE,aAAa;YACrB,YAAY,EAAE,YAAY;SAC3B,CAAC;QACF,iBAAiB,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;KACzC,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,EAAE;YACpD,gBAAgB,EAAE,GAAG;SACtB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.test.d.ts","sourceRoot":"","sources":["../../../src/client/__tests__/endpoints.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildUrl, ENDPOINTS } from "../endpoints.js";
|
|
3
|
+
describe("buildUrl", () => {
|
|
4
|
+
it("builds organizations URL", () => {
|
|
5
|
+
expect(buildUrl(ENDPOINTS.organizations)).toBe("https://claude.ai/api/organizations");
|
|
6
|
+
});
|
|
7
|
+
it("builds conversations list URL", () => {
|
|
8
|
+
expect(buildUrl(ENDPOINTS.conversations("org-123"))).toBe("https://claude.ai/api/organizations/org-123/chat_conversations");
|
|
9
|
+
});
|
|
10
|
+
it("builds single conversation URL", () => {
|
|
11
|
+
expect(buildUrl(ENDPOINTS.conversation("org-123", "chat-456"))).toBe("https://claude.ai/api/organizations/org-123/chat_conversations/chat-456");
|
|
12
|
+
});
|
|
13
|
+
it("builds search URL", () => {
|
|
14
|
+
expect(buildUrl(ENDPOINTS.search("org-123", "hello", 10))).toBe("https://claude.ai/api/organizations/org-123/conversation/search?query=hello&n=10");
|
|
15
|
+
});
|
|
16
|
+
it("builds projects URL", () => {
|
|
17
|
+
expect(buildUrl(ENDPOINTS.projects("org-123"))).toBe("https://claude.ai/api/organizations/org-123/projects");
|
|
18
|
+
});
|
|
19
|
+
it("builds wiggle list-files URL", () => {
|
|
20
|
+
expect(buildUrl(ENDPOINTS.artifactListFiles("org-123", "conv-456"))).toBe("https://claude.ai/api/organizations/org-123/conversations/conv-456/wiggle/list-files");
|
|
21
|
+
});
|
|
22
|
+
it("builds wiggle download-file URL", () => {
|
|
23
|
+
expect(buildUrl(ENDPOINTS.artifactDownloadFile("org-123", "conv-456", "/mnt/user-data/outputs/file.md"))).toBe("https://claude.ai/api/organizations/org-123/conversations/conv-456/wiggle/download-file?path=%2Fmnt%2Fuser-data%2Foutputs%2Ffile.md");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=endpoints.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.test.js","sourceRoot":"","sources":["../../../src/client/__tests__/endpoints.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEtD,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAC5C,qCAAqC,CACtC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CACvD,gEAAgE,CACjE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAClE,yEAAyE,CAC1E,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAC7D,kFAAkF,CACnF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAClD,sDAAsD,CACvD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CACJ,QAAQ,CAAC,SAAS,CAAC,iBAAiB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAC7D,CAAC,IAAI,CACJ,sFAAsF,CACvF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CACJ,QAAQ,CACN,SAAS,CAAC,oBAAoB,CAC5B,SAAS,EACT,UAAU,EACV,gCAAgC,CACjC,CACF,CACF,CAAC,IAAI,CACJ,qIAAqI,CACtI,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AuthProvider } from "../auth/types.js";
|
|
2
|
+
import type { Organization, ConversationSummary, Conversation, SearchResponse, ArtifactListResponse, Project, ProjectDoc } from "../models/types.js";
|
|
3
|
+
export interface ClientOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Delay in milliseconds between API requests to avoid rate limiting.
|
|
6
|
+
* Default: 300ms.
|
|
7
|
+
*/
|
|
8
|
+
rateLimitDelayMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class ClaudeSyncClient {
|
|
11
|
+
private readonly auth;
|
|
12
|
+
private readonly rateLimitDelayMs;
|
|
13
|
+
private lastRequestTime;
|
|
14
|
+
constructor(auth: AuthProvider, options?: ClientOptions);
|
|
15
|
+
private throttle;
|
|
16
|
+
private request;
|
|
17
|
+
private requestRaw;
|
|
18
|
+
listOrganizations(): Promise<Organization[]>;
|
|
19
|
+
/**
|
|
20
|
+
* List conversations as an async iterable.
|
|
21
|
+
* Currently the API returns all conversations in one response (no pagination),
|
|
22
|
+
* but this interface is forward-compatible with future pagination.
|
|
23
|
+
*/
|
|
24
|
+
listConversations(orgId: string): AsyncIterable<ConversationSummary>;
|
|
25
|
+
/**
|
|
26
|
+
* Convenience method that collects all conversations into an array.
|
|
27
|
+
* Use listConversations() for streaming/lazy processing of large lists.
|
|
28
|
+
*/
|
|
29
|
+
listConversationsAll(orgId: string): Promise<ConversationSummary[]>;
|
|
30
|
+
getConversation(orgId: string, chatId: string): Promise<Conversation>;
|
|
31
|
+
/**
|
|
32
|
+
* Search conversations. Handles double-JSON-encoded responses defensively:
|
|
33
|
+
* the API sometimes returns a JSON string containing another JSON string.
|
|
34
|
+
*/
|
|
35
|
+
searchConversations(orgId: string, query: string, limit?: number): Promise<SearchResponse>;
|
|
36
|
+
listProjects(orgId: string): Promise<Project[]>;
|
|
37
|
+
getProjectDocs(orgId: string, projectId: string): Promise<ProjectDoc[]>;
|
|
38
|
+
getProjectConversations(orgId: string, projectId: string): Promise<ConversationSummary[]>;
|
|
39
|
+
listArtifacts(orgId: string, conversationId: string): Promise<ArtifactListResponse>;
|
|
40
|
+
/**
|
|
41
|
+
* Download an artifact file from the wiggle filesystem.
|
|
42
|
+
* Returns string for text content, Uint8Array for binary content.
|
|
43
|
+
*
|
|
44
|
+
* Security: validates that the path matches the expected artifact path prefix
|
|
45
|
+
* to prevent path traversal attacks.
|
|
46
|
+
*/
|
|
47
|
+
downloadArtifact(orgId: string, conversationId: string, path: string): Promise<string | Uint8Array>;
|
|
48
|
+
/**
|
|
49
|
+
* Get the safe local filename for an artifact path.
|
|
50
|
+
* Uses path.basename() to prevent path traversal on local writes.
|
|
51
|
+
*/
|
|
52
|
+
static safeFilename(artifactPath: string): string;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAYrD,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,OAAO,EACP,UAAU,EACX,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAKD,qBAAa,gBAAgB;IAKzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,eAAe,CAAK;gBAGT,IAAI,EAAE,YAAY,EACnC,OAAO,CAAC,EAAE,aAAa;YAKX,QAAQ;YAWR,OAAO;YAwBP,UAAU;IA0BlB,iBAAiB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAOlD;;;;OAIG;IACI,iBAAiB,CACtB,KAAK,EAAE,MAAM,GACZ,aAAa,CAAC,mBAAmB,CAAC;IAYrC;;;OAGG;IACG,oBAAoB,CACxB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAQ3B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,CAAC;IAOxB;;;OAGG;IACG,mBAAmB,CACvB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,KAAK,SAAK,GACT,OAAO,CAAC,cAAc,CAAC;IAYpB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO/C,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,CAAC;IAOlB,uBAAuB,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAS3B,aAAa,CACjB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,oBAAoB,CAAC;IAOhC;;;;;;OAMG;IACG,gBAAgB,CACpB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC;IAsB/B;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;CAGlD"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { buildUrl, ENDPOINTS } from "./endpoints.js";
|
|
2
|
+
import { ClaudeSyncError, RateLimitError } from "./errors.js";
|
|
3
|
+
import { OrganizationSchema, ConversationSummarySchema, ConversationSchema, SearchResponseSchema, ArtifactListResponseSchema, ProjectSchema, ProjectDocSchema, } from "../models/schemas.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { basename } from "node:path";
|
|
6
|
+
/** Expected path prefix for wiggle artifact files */
|
|
7
|
+
const ARTIFACT_PATH_PREFIX = "/mnt/user-data/";
|
|
8
|
+
export class ClaudeSyncClient {
|
|
9
|
+
auth;
|
|
10
|
+
rateLimitDelayMs;
|
|
11
|
+
lastRequestTime = 0;
|
|
12
|
+
constructor(auth, options) {
|
|
13
|
+
this.auth = auth;
|
|
14
|
+
this.rateLimitDelayMs = options?.rateLimitDelayMs ?? 300;
|
|
15
|
+
}
|
|
16
|
+
async throttle() {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
const elapsed = now - this.lastRequestTime;
|
|
19
|
+
if (elapsed < this.rateLimitDelayMs) {
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, this.rateLimitDelayMs - elapsed));
|
|
21
|
+
}
|
|
22
|
+
this.lastRequestTime = Date.now();
|
|
23
|
+
}
|
|
24
|
+
async request(url) {
|
|
25
|
+
await this.throttle();
|
|
26
|
+
const headers = await this.auth.getHeaders();
|
|
27
|
+
const response = await fetch(url, { headers });
|
|
28
|
+
if (response.status === 429) {
|
|
29
|
+
const body = await response.json().catch(() => null);
|
|
30
|
+
const resetsAt = body?.error?.resets_at ??
|
|
31
|
+
Math.floor(Date.now() / 1000) + 60;
|
|
32
|
+
throw new RateLimitError(resetsAt);
|
|
33
|
+
}
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new ClaudeSyncError(`API request failed: ${response.status} ${response.statusText}`, response.status);
|
|
36
|
+
}
|
|
37
|
+
return response.json();
|
|
38
|
+
}
|
|
39
|
+
async requestRaw(url) {
|
|
40
|
+
await this.throttle();
|
|
41
|
+
const headers = await this.auth.getHeaders();
|
|
42
|
+
const response = await fetch(url, { headers });
|
|
43
|
+
if (response.status === 429) {
|
|
44
|
+
const body = await response.json().catch(() => null);
|
|
45
|
+
const resetsAt = body?.error?.resets_at ??
|
|
46
|
+
Math.floor(Date.now() / 1000) + 60;
|
|
47
|
+
throw new RateLimitError(resetsAt);
|
|
48
|
+
}
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new ClaudeSyncError(`API request failed: ${response.status} ${response.statusText}`, response.status);
|
|
51
|
+
}
|
|
52
|
+
return response;
|
|
53
|
+
}
|
|
54
|
+
// --- Organizations ---
|
|
55
|
+
async listOrganizations() {
|
|
56
|
+
const data = await this.request(buildUrl(ENDPOINTS.organizations));
|
|
57
|
+
return z.array(OrganizationSchema).parse(data);
|
|
58
|
+
}
|
|
59
|
+
// --- Conversations ---
|
|
60
|
+
/**
|
|
61
|
+
* List conversations as an async iterable.
|
|
62
|
+
* Currently the API returns all conversations in one response (no pagination),
|
|
63
|
+
* but this interface is forward-compatible with future pagination.
|
|
64
|
+
*/
|
|
65
|
+
async *listConversations(orgId) {
|
|
66
|
+
const data = await this.request(buildUrl(ENDPOINTS.conversations(orgId)));
|
|
67
|
+
const conversations = z
|
|
68
|
+
.array(ConversationSummarySchema)
|
|
69
|
+
.parse(data);
|
|
70
|
+
for (const conv of conversations) {
|
|
71
|
+
yield conv;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Convenience method that collects all conversations into an array.
|
|
76
|
+
* Use listConversations() for streaming/lazy processing of large lists.
|
|
77
|
+
*/
|
|
78
|
+
async listConversationsAll(orgId) {
|
|
79
|
+
const results = [];
|
|
80
|
+
for await (const conv of this.listConversations(orgId)) {
|
|
81
|
+
results.push(conv);
|
|
82
|
+
}
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
async getConversation(orgId, chatId) {
|
|
86
|
+
const data = await this.request(buildUrl(ENDPOINTS.conversation(orgId, chatId)));
|
|
87
|
+
return ConversationSchema.parse(data);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Search conversations. Handles double-JSON-encoded responses defensively:
|
|
91
|
+
* the API sometimes returns a JSON string containing another JSON string.
|
|
92
|
+
*/
|
|
93
|
+
async searchConversations(orgId, query, limit = 20) {
|
|
94
|
+
const data = await this.request(buildUrl(ENDPOINTS.search(orgId, query, limit)));
|
|
95
|
+
// Defensive double-parse: API returns double-JSON-encoded responses
|
|
96
|
+
const parsed = typeof data === "string" ? JSON.parse(data) : data;
|
|
97
|
+
return SearchResponseSchema.parse(parsed);
|
|
98
|
+
}
|
|
99
|
+
// --- Projects ---
|
|
100
|
+
async listProjects(orgId) {
|
|
101
|
+
const data = await this.request(buildUrl(ENDPOINTS.projects(orgId)));
|
|
102
|
+
return z.array(ProjectSchema).parse(data);
|
|
103
|
+
}
|
|
104
|
+
async getProjectDocs(orgId, projectId) {
|
|
105
|
+
const data = await this.request(buildUrl(ENDPOINTS.projectDocs(orgId, projectId)));
|
|
106
|
+
return z.array(ProjectDocSchema).parse(data);
|
|
107
|
+
}
|
|
108
|
+
async getProjectConversations(orgId, projectId) {
|
|
109
|
+
const data = await this.request(buildUrl(ENDPOINTS.projectConversations(orgId, projectId)));
|
|
110
|
+
return z.array(ConversationSummarySchema).parse(data);
|
|
111
|
+
}
|
|
112
|
+
// --- Artifacts (wiggle filesystem) ---
|
|
113
|
+
async listArtifacts(orgId, conversationId) {
|
|
114
|
+
const data = await this.request(buildUrl(ENDPOINTS.artifactListFiles(orgId, conversationId)));
|
|
115
|
+
return ArtifactListResponseSchema.parse(data);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Download an artifact file from the wiggle filesystem.
|
|
119
|
+
* Returns string for text content, Uint8Array for binary content.
|
|
120
|
+
*
|
|
121
|
+
* Security: validates that the path matches the expected artifact path prefix
|
|
122
|
+
* to prevent path traversal attacks.
|
|
123
|
+
*/
|
|
124
|
+
async downloadArtifact(orgId, conversationId, path) {
|
|
125
|
+
// Security: validate artifact path against expected pattern
|
|
126
|
+
if (!path.startsWith(ARTIFACT_PATH_PREFIX)) {
|
|
127
|
+
throw new ClaudeSyncError(`Invalid artifact path: ${path}. Expected path starting with ${ARTIFACT_PATH_PREFIX}`);
|
|
128
|
+
}
|
|
129
|
+
const response = await this.requestRaw(buildUrl(ENDPOINTS.artifactDownloadFile(orgId, conversationId, path)));
|
|
130
|
+
const contentType = response.headers.get("content-type") ?? "text/plain";
|
|
131
|
+
if (contentType.startsWith("text/")) {
|
|
132
|
+
return response.text();
|
|
133
|
+
}
|
|
134
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get the safe local filename for an artifact path.
|
|
138
|
+
* Uses path.basename() to prevent path traversal on local writes.
|
|
139
|
+
*/
|
|
140
|
+
static safeFilename(artifactPath) {
|
|
141
|
+
return basename(artifactPath);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const ENDPOINTS: {
|
|
2
|
+
readonly bootstrap: "/api/bootstrap";
|
|
3
|
+
readonly account: "/api/account";
|
|
4
|
+
readonly organizations: "/api/organizations";
|
|
5
|
+
readonly conversations: (orgId: string) => string;
|
|
6
|
+
readonly conversation: (orgId: string, chatId: string) => string;
|
|
7
|
+
readonly search: (orgId: string, query: string, limit: number) => string;
|
|
8
|
+
readonly projects: (orgId: string) => string;
|
|
9
|
+
readonly project: (orgId: string, projectId: string) => string;
|
|
10
|
+
readonly projectDocs: (orgId: string, projectId: string) => string;
|
|
11
|
+
readonly projectFiles: (orgId: string, projectId: string) => string;
|
|
12
|
+
readonly projectConversations: (orgId: string, projectId: string) => string;
|
|
13
|
+
readonly artifactListFiles: (orgId: string, conversationId: string) => string;
|
|
14
|
+
readonly artifactDownloadFile: (orgId: string, conversationId: string, path: string) => string;
|
|
15
|
+
readonly artifactStorageInfo: (orgId: string, artifactId: string) => string;
|
|
16
|
+
};
|
|
17
|
+
export declare function buildUrl(path: string): string;
|
|
18
|
+
//# sourceMappingURL=endpoints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.d.ts","sourceRoot":"","sources":["../../src/client/endpoints.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS;;;;oCAOG,MAAM;mCAEP,MAAM,UAAU,MAAM;6BAE5B,MAAM,SAAS,MAAM,SAAS,MAAM;+BAIlC,MAAM;8BAEP,MAAM,aAAa,MAAM;kCAErB,MAAM,aAAa,MAAM;mCAExB,MAAM,aAAa,MAAM;2CAEjB,MAAM,aAAa,MAAM;wCAI5B,MAAM,kBAAkB,MAAM;2CAGhD,MAAM,kBACG,MAAM,QAChB,MAAM;0CAGe,MAAM,cAAc,MAAM;CAE/C,CAAC;AAEX,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const BASE_URL = "https://claude.ai";
|
|
2
|
+
export const ENDPOINTS = {
|
|
3
|
+
// Bootstrap & Account
|
|
4
|
+
bootstrap: "/api/bootstrap",
|
|
5
|
+
account: "/api/account",
|
|
6
|
+
organizations: "/api/organizations",
|
|
7
|
+
// Conversations
|
|
8
|
+
conversations: (orgId) => `/api/organizations/${orgId}/chat_conversations`,
|
|
9
|
+
conversation: (orgId, chatId) => `/api/organizations/${orgId}/chat_conversations/${chatId}`,
|
|
10
|
+
search: (orgId, query, limit) => `/api/organizations/${orgId}/conversation/search?query=${encodeURIComponent(query)}&n=${limit}`,
|
|
11
|
+
// Projects
|
|
12
|
+
projects: (orgId) => `/api/organizations/${orgId}/projects`,
|
|
13
|
+
project: (orgId, projectId) => `/api/organizations/${orgId}/projects/${projectId}`,
|
|
14
|
+
projectDocs: (orgId, projectId) => `/api/organizations/${orgId}/projects/${projectId}/docs`,
|
|
15
|
+
projectFiles: (orgId, projectId) => `/api/organizations/${orgId}/projects/${projectId}/files`,
|
|
16
|
+
projectConversations: (orgId, projectId) => `/api/organizations/${orgId}/projects/${projectId}/conversations`,
|
|
17
|
+
// Artifacts (wiggle filesystem)
|
|
18
|
+
artifactListFiles: (orgId, conversationId) => `/api/organizations/${orgId}/conversations/${conversationId}/wiggle/list-files`,
|
|
19
|
+
artifactDownloadFile: (orgId, conversationId, path) => `/api/organizations/${orgId}/conversations/${conversationId}/wiggle/download-file?path=${encodeURIComponent(path)}`,
|
|
20
|
+
artifactStorageInfo: (orgId, artifactId) => `/api/organizations/${orgId}/artifacts/wiggle_artifact/${artifactId}/manage/storage/info`,
|
|
21
|
+
};
|
|
22
|
+
export function buildUrl(path) {
|
|
23
|
+
return `${BASE_URL}${path}`;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=endpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.js","sourceRoot":"","sources":["../../src/client/endpoints.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,mBAAmB,CAAC;AAErC,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,sBAAsB;IACtB,SAAS,EAAE,gBAAgB;IAC3B,OAAO,EAAE,cAAc;IACvB,aAAa,EAAE,oBAAoB;IAEnC,gBAAgB;IAChB,aAAa,EAAE,CAAC,KAAa,EAAE,EAAE,CAC/B,sBAAsB,KAAK,qBAAqB;IAClD,YAAY,EAAE,CAAC,KAAa,EAAE,MAAc,EAAE,EAAE,CAC9C,sBAAsB,KAAK,uBAAuB,MAAM,EAAE;IAC5D,MAAM,EAAE,CAAC,KAAa,EAAE,KAAa,EAAE,KAAa,EAAE,EAAE,CACtD,sBAAsB,KAAK,8BAA8B,kBAAkB,CAAC,KAAK,CAAC,MAAM,KAAK,EAAE;IAEjG,WAAW;IACX,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE,CAC1B,sBAAsB,KAAK,WAAW;IACxC,OAAO,EAAE,CAAC,KAAa,EAAE,SAAiB,EAAE,EAAE,CAC5C,sBAAsB,KAAK,aAAa,SAAS,EAAE;IACrD,WAAW,EAAE,CAAC,KAAa,EAAE,SAAiB,EAAE,EAAE,CAChD,sBAAsB,KAAK,aAAa,SAAS,OAAO;IAC1D,YAAY,EAAE,CAAC,KAAa,EAAE,SAAiB,EAAE,EAAE,CACjD,sBAAsB,KAAK,aAAa,SAAS,QAAQ;IAC3D,oBAAoB,EAAE,CAAC,KAAa,EAAE,SAAiB,EAAE,EAAE,CACzD,sBAAsB,KAAK,aAAa,SAAS,gBAAgB;IAEnE,gCAAgC;IAChC,iBAAiB,EAAE,CAAC,KAAa,EAAE,cAAsB,EAAE,EAAE,CAC3D,sBAAsB,KAAK,kBAAkB,cAAc,oBAAoB;IACjF,oBAAoB,EAAE,CACpB,KAAa,EACb,cAAsB,EACtB,IAAY,EACZ,EAAE,CACF,sBAAsB,KAAK,kBAAkB,cAAc,8BAA8B,kBAAkB,CAAC,IAAI,CAAC,EAAE;IACrH,mBAAmB,EAAE,CAAC,KAAa,EAAE,UAAkB,EAAE,EAAE,CACzD,sBAAsB,KAAK,8BAA8B,UAAU,sBAAsB;CACnF,CAAC;AAEX,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,GAAG,QAAQ,GAAG,IAAI,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class ClaudeSyncError extends Error {
|
|
2
|
+
readonly statusCode?: number | undefined;
|
|
3
|
+
constructor(message: string, statusCode?: number | undefined);
|
|
4
|
+
}
|
|
5
|
+
export declare class RateLimitError extends ClaudeSyncError {
|
|
6
|
+
readonly resetsAt: number;
|
|
7
|
+
constructor(resetsAt: number, message?: string);
|
|
8
|
+
/** Seconds until rate limit resets */
|
|
9
|
+
get sleepSeconds(): number;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/client/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,eAAgB,SAAQ,KAAK;aAGtB,UAAU,CAAC,EAAE,MAAM;gBADnC,OAAO,EAAE,MAAM,EACC,UAAU,CAAC,EAAE,MAAM,YAAA;CAKtC;AAED,qBAAa,cAAe,SAAQ,eAAe;aAE/B,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM,EAChC,OAAO,CAAC,EAAE,MAAM;IAUlB,sCAAsC;IACtC,IAAI,YAAY,IAAI,MAAM,CAEzB;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export class ClaudeSyncError extends Error {
|
|
2
|
+
statusCode;
|
|
3
|
+
constructor(message, statusCode) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.statusCode = statusCode;
|
|
6
|
+
this.name = "ClaudeSyncError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class RateLimitError extends ClaudeSyncError {
|
|
10
|
+
resetsAt;
|
|
11
|
+
constructor(resetsAt, message) {
|
|
12
|
+
super(message ??
|
|
13
|
+
`Rate limited. Resets at ${new Date(resetsAt * 1000).toISOString()}`, 429);
|
|
14
|
+
this.resetsAt = resetsAt;
|
|
15
|
+
this.name = "RateLimitError";
|
|
16
|
+
}
|
|
17
|
+
/** Seconds until rate limit resets */
|
|
18
|
+
get sleepSeconds() {
|
|
19
|
+
return Math.max(0, Math.ceil(this.resetsAt - Date.now() / 1000));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.js.map
|