@kamilio/wire 0.1.6 → 0.1.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/README.md +31 -1
- package/dist/executable.d.ts.map +1 -1
- package/dist/executable.js +3 -2
- package/dist/executable.js.map +1 -1
- package/node_modules/provider-asana/dist/asana-project.d.ts +6 -0
- package/node_modules/provider-asana/dist/asana-project.d.ts.map +1 -1
- package/node_modules/provider-asana/dist/asana-task.d.ts +6 -0
- package/node_modules/provider-asana/dist/asana-task.d.ts.map +1 -1
- package/node_modules/provider-asana/dist/index.d.ts +12 -0
- package/node_modules/provider-asana/dist/index.d.ts.map +1 -1
- package/node_modules/provider-chatgpt/dist/chatgpt.d.ts +6 -0
- package/node_modules/provider-chatgpt/dist/chatgpt.d.ts.map +1 -1
- package/node_modules/provider-chatgpt/dist/chatgpt.js +24 -47
- package/node_modules/provider-chatgpt/dist/chatgpt.js.map +1 -1
- package/node_modules/provider-chatgpt/dist/client.d.ts +20 -0
- package/node_modules/provider-chatgpt/dist/client.d.ts.map +1 -0
- package/node_modules/provider-chatgpt/dist/client.js +85 -0
- package/node_modules/provider-chatgpt/dist/client.js.map +1 -0
- package/node_modules/provider-chatgpt/dist/cooldown.d.ts +19 -0
- package/node_modules/provider-chatgpt/dist/cooldown.d.ts.map +1 -0
- package/node_modules/provider-chatgpt/dist/cooldown.js +55 -0
- package/node_modules/provider-chatgpt/dist/cooldown.js.map +1 -0
- package/node_modules/provider-chatgpt/dist/download.d.ts +3 -0
- package/node_modules/provider-chatgpt/dist/download.d.ts.map +1 -0
- package/node_modules/provider-chatgpt/dist/download.js +329 -0
- package/node_modules/provider-chatgpt/dist/download.js.map +1 -0
- package/node_modules/provider-chatgpt/dist/index.d.ts +6 -0
- package/node_modules/provider-chatgpt/dist/index.d.ts.map +1 -1
- package/node_modules/provider-chatgpt/src/chatgpt.ts +21 -46
- package/node_modules/provider-chatgpt/src/client.ts +80 -0
- package/node_modules/provider-chatgpt/src/cooldown.ts +64 -0
- package/node_modules/provider-chatgpt/src/download.ts +301 -0
- package/node_modules/provider-gmail/dist/gmail.d.ts +6 -0
- package/node_modules/provider-gmail/dist/gmail.d.ts.map +1 -1
- package/node_modules/provider-gmail/dist/index.d.ts +6 -0
- package/node_modules/provider-gmail/dist/index.d.ts.map +1 -1
- package/node_modules/provider-google-docs/dist/google-docs.d.ts +6 -0
- package/node_modules/provider-google-docs/dist/google-docs.d.ts.map +1 -1
- package/node_modules/provider-google-docs/dist/google-forms.d.ts +6 -0
- package/node_modules/provider-google-docs/dist/google-forms.d.ts.map +1 -1
- package/node_modules/provider-google-docs/dist/index.d.ts +12 -0
- package/node_modules/provider-google-docs/dist/index.d.ts.map +1 -1
- package/node_modules/provider-notion/dist/index.d.ts +6 -0
- package/node_modules/provider-notion/dist/index.d.ts.map +1 -1
- package/node_modules/provider-notion/dist/notion.d.ts +6 -0
- package/node_modules/provider-notion/dist/notion.d.ts.map +1 -1
- package/node_modules/provider-slack/dist/index.d.ts +6 -0
- package/node_modules/provider-slack/dist/index.d.ts.map +1 -1
- package/node_modules/provider-slack/dist/slack.d.ts +6 -0
- package/node_modules/provider-slack/dist/slack.d.ts.map +1 -1
- package/node_modules/provider-zoom/dist/index.d.ts +6 -0
- package/node_modules/provider-zoom/dist/index.d.ts.map +1 -1
- package/node_modules/provider-zoom/dist/zoom-hub.d.ts +6 -0
- package/node_modules/provider-zoom/dist/zoom-hub.d.ts.map +1 -1
- package/node_modules/wire-core/dist/core/model.d.ts +6 -0
- package/node_modules/wire-core/dist/core/model.d.ts.map +1 -1
- package/node_modules/wire-core/dist/index.d.ts +1 -1
- package/node_modules/wire-core/dist/index.d.ts.map +1 -1
- package/node_modules/wire-core/dist/operations.d.ts +1 -0
- package/node_modules/wire-core/dist/operations.d.ts.map +1 -1
- package/node_modules/wire-core/dist/operations.js +38 -13
- package/node_modules/wire-core/dist/operations.js.map +1 -1
- package/node_modules/wire-core/dist/storage/workspace.d.ts.map +1 -1
- package/node_modules/wire-core/dist/storage/workspace.js +5 -0
- package/node_modules/wire-core/dist/storage/workspace.js.map +1 -1
- package/node_modules/wire-core/src/core/model.ts +8 -0
- package/node_modules/wire-core/src/index.ts +1 -1
- package/node_modules/wire-core/src/operations.ts +37 -12
- package/node_modules/wire-core/src/storage/workspace.ts +5 -0
- package/package.json +1 -1
- package/src/executable.ts +3 -2
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { connectChatgpt, object, text } from "./client.js";
|
|
3
|
+
import { ChatgptCooldownError } from "./cooldown.js";
|
|
4
|
+
function segment(value) {
|
|
5
|
+
const safe = value.replace(/[^\p{L}\p{N}._-]/gu, "-").slice(0, 64);
|
|
6
|
+
return safe === value && safe !== "." && safe !== ".." && safe !== "" ? safe : `${safe || "item"}-${createHash("sha256").update(value).digest("hex").slice(0, 12)}`;
|
|
7
|
+
}
|
|
8
|
+
function items(value) {
|
|
9
|
+
if (!Array.isArray(value))
|
|
10
|
+
throw new Error("ChatGPT list response is missing items");
|
|
11
|
+
return value.map((item) => object(item));
|
|
12
|
+
}
|
|
13
|
+
function identifier(value) {
|
|
14
|
+
const id = text(value["id"]) ?? text(value["conversation_id"]);
|
|
15
|
+
if (id === undefined)
|
|
16
|
+
throw new Error("ChatGPT item is missing its identifier");
|
|
17
|
+
return id;
|
|
18
|
+
}
|
|
19
|
+
function endpoint(path, query) {
|
|
20
|
+
return `${path}?${new URLSearchParams(query)}`;
|
|
21
|
+
}
|
|
22
|
+
function assets(value, context) {
|
|
23
|
+
const found = new Map();
|
|
24
|
+
const addFile = (id, name) => {
|
|
25
|
+
const queryIndex = id.indexOf("?");
|
|
26
|
+
const fileId = (queryIndex === -1 ? id : id.slice(0, queryIndex)).replaceAll("#", "*");
|
|
27
|
+
const query = Object.fromEntries(new URLSearchParams(queryIndex === -1 ? "" : id.slice(queryIndex + 1)));
|
|
28
|
+
if (context.conversation !== undefined)
|
|
29
|
+
query["conversation_id"] = context.conversation;
|
|
30
|
+
if (context.project !== undefined)
|
|
31
|
+
query["gizmo_id"] = context.project;
|
|
32
|
+
const key = `file:${id}`;
|
|
33
|
+
found.set(key, { key, name: name ?? fileId, endpoint: endpoint(`/backend-api/files/download/${encodeURIComponent(fileId)}`, query) });
|
|
34
|
+
};
|
|
35
|
+
const visit = (node, message) => {
|
|
36
|
+
if (typeof node === "string") {
|
|
37
|
+
if (node.startsWith("file-service://") || node.startsWith("sediment://"))
|
|
38
|
+
addFile(node.slice(node.indexOf("://") + 3));
|
|
39
|
+
if (context.conversation !== undefined && message !== undefined) {
|
|
40
|
+
for (const match of node.matchAll(/sandbox:(\/[^\s)\]<>"']+)/g)) {
|
|
41
|
+
const path = match[1];
|
|
42
|
+
const key = `sandbox:${message}:${path}`;
|
|
43
|
+
found.set(key, { key, name: path.split("/").pop() || "file", endpoint: endpoint(`/backend-api/conversation/${encodeURIComponent(context.conversation)}/interpreter/download`, { message_id: message, sandbox_path: path }) });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else if (Array.isArray(node)) {
|
|
48
|
+
for (const child of node)
|
|
49
|
+
visit(child, message);
|
|
50
|
+
}
|
|
51
|
+
else if (node !== null && typeof node === "object") {
|
|
52
|
+
const record = node;
|
|
53
|
+
const currentMessage = record["author"] !== undefined ? text(record["id"]) ?? message : message;
|
|
54
|
+
const fileId = text(record["file_id"]) ?? (/^file[-_]/.test(text(record["id"]) ?? "") ? text(record["id"]) : undefined);
|
|
55
|
+
if (fileId !== undefined)
|
|
56
|
+
addFile(fileId, text(record["name"]) ?? text(record["filename"]));
|
|
57
|
+
const libraryId = text(record["library_file_id"]) ?? (text(record["id"])?.startsWith("libfile_") ? text(record["id"]) : undefined);
|
|
58
|
+
if (fileId === undefined && libraryId !== undefined) {
|
|
59
|
+
const key = `library:${libraryId}`;
|
|
60
|
+
found.set(key, { key, name: text(record["name"]) ?? libraryId, endpoint: `/backend-api/files/library/files/${encodeURIComponent(libraryId)}/content_url` });
|
|
61
|
+
}
|
|
62
|
+
for (const child of Object.values(record))
|
|
63
|
+
visit(child, currentMessage);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
visit(value, context.message);
|
|
67
|
+
return [...found.values()];
|
|
68
|
+
}
|
|
69
|
+
class DownloadWriteError extends Error {
|
|
70
|
+
}
|
|
71
|
+
export async function downloadChatgpt(runtime, url, source, write, render) {
|
|
72
|
+
if (source.type !== "project")
|
|
73
|
+
return null;
|
|
74
|
+
const wholeHistory = source.identifier === "history";
|
|
75
|
+
const base = wholeHistory ? "chatgpt" : `chatgpt/projects/${segment(source.identifier)}`;
|
|
76
|
+
const title = wholeHistory ? "ChatGPT history" : "ChatGPT project";
|
|
77
|
+
const errors = [];
|
|
78
|
+
const skipped = [];
|
|
79
|
+
const records = [];
|
|
80
|
+
const files = [];
|
|
81
|
+
const cooldowns = [];
|
|
82
|
+
const started = runtime.clock.now().toISOString();
|
|
83
|
+
const save = async (path, contents) => {
|
|
84
|
+
try {
|
|
85
|
+
await write(path, contents);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
throw new DownloadWriteError(`Could not write ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const json = (path, value) => save(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
92
|
+
const attempt = async (resource, action) => {
|
|
93
|
+
try {
|
|
94
|
+
return await action();
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (error instanceof DownloadWriteError || error instanceof ChatgptCooldownError)
|
|
98
|
+
throw error;
|
|
99
|
+
errors.push({ resource, error: error instanceof Error ? error.message : String(error) });
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const session = await connectChatgpt(runtime, url, async (cooldown) => {
|
|
104
|
+
cooldowns.push(cooldown);
|
|
105
|
+
await json(`${base}/manifest.json`, { status: "cooldown", source: url, started_at: started, records, files, errors, skipped, cooldowns, retry_at: cooldown.retry_at });
|
|
106
|
+
});
|
|
107
|
+
await json(`${base}/manifest.json`, { status: "in_progress", source: url, started_at: started });
|
|
108
|
+
const paged = async (client, path, query, output, consume, offsetMode = false, filter) => {
|
|
109
|
+
const seen = new Set();
|
|
110
|
+
let cursor;
|
|
111
|
+
let offset = 0;
|
|
112
|
+
let pageNumber = 0;
|
|
113
|
+
for (;;) {
|
|
114
|
+
const parameters = { ...query, ...(offsetMode ? { offset: String(offset) } : cursor === undefined ? {} : { cursor }) };
|
|
115
|
+
const page = object(await client.json(endpoint(path, parameters)));
|
|
116
|
+
const entries = items(page["items"]);
|
|
117
|
+
await json(`${output}/${pageNumber++}.json`, filter === undefined ? page : { ...page, items: entries.filter(filter) });
|
|
118
|
+
for (const item of entries)
|
|
119
|
+
consume(item);
|
|
120
|
+
if (offsetMode) {
|
|
121
|
+
if (page["offset"] !== undefined && page["offset"] !== offset)
|
|
122
|
+
throw new Error(`ChatGPT returned a different offset for ${path}`);
|
|
123
|
+
if (entries.length === 0) {
|
|
124
|
+
if (typeof page["total"] === "number" && offset < page["total"])
|
|
125
|
+
throw new Error(`ChatGPT listing stopped before its reported total: ${path}`);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
const signature = entries.map(identifier).join("|");
|
|
129
|
+
if (seen.has(signature))
|
|
130
|
+
throw new Error(`ChatGPT repeated a page: ${path}`);
|
|
131
|
+
seen.add(signature);
|
|
132
|
+
offset += entries.length;
|
|
133
|
+
if (typeof page["total"] === "number" && offset >= page["total"])
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
if (!("cursor" in page) && !("next_cursor" in page) && page["has_more"] !== false)
|
|
138
|
+
throw new Error(`ChatGPT list response is missing pagination metadata: ${path}`);
|
|
139
|
+
const next = page["cursor"] ?? page["next_cursor"];
|
|
140
|
+
if (next == null || next === "") {
|
|
141
|
+
if (page["has_more"] === true)
|
|
142
|
+
throw new Error(`ChatGPT listing has more items but no cursor: ${path}`);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
if (typeof next !== "string" && typeof next !== "number")
|
|
146
|
+
throw new Error(`Invalid ChatGPT pagination cursor: ${path}`);
|
|
147
|
+
cursor = String(next);
|
|
148
|
+
if (seen.has(cursor))
|
|
149
|
+
throw new Error(`ChatGPT repeated a cursor: ${path}`);
|
|
150
|
+
seen.add(cursor);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const downloadAssets = async (client, references, directory) => {
|
|
155
|
+
const links = [];
|
|
156
|
+
for (const asset of references) {
|
|
157
|
+
await attempt(asset.endpoint, async () => {
|
|
158
|
+
const metadata = object(await client.json(asset.endpoint));
|
|
159
|
+
const downloadUrl = text(metadata["download_url"]) ?? text(metadata["content_url"]);
|
|
160
|
+
if (downloadUrl === undefined)
|
|
161
|
+
throw new Error(`ChatGPT file is unavailable (${String(metadata["status"] ?? "missing URL")})`);
|
|
162
|
+
const bytes = await client.bytes(downloadUrl);
|
|
163
|
+
const name = `${createHash("sha256").update(asset.key).digest("hex").slice(0, 12)}-${segment(asset.name)}`;
|
|
164
|
+
const path = `${directory}/assets/${name}`;
|
|
165
|
+
await save(path, bytes);
|
|
166
|
+
files.push({ path, source: asset.endpoint, bytes: bytes.byteLength, sha256: createHash("sha256").update(bytes).digest("hex") });
|
|
167
|
+
links.push(`- [${asset.name.replace(/[\[\]\r\n]/g, " ")}](assets/${encodeURIComponent(name)})`);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return links;
|
|
171
|
+
};
|
|
172
|
+
const exportAccount = async (client, directory, projectId) => {
|
|
173
|
+
const conversations = new Map();
|
|
174
|
+
const projects = new Map();
|
|
175
|
+
const projectConversations = new Map();
|
|
176
|
+
const addConversation = (entry, owner) => {
|
|
177
|
+
const id = identifier(entry);
|
|
178
|
+
conversations.set(id, { ...conversations.get(id), ...entry });
|
|
179
|
+
const project = owner ?? text(entry["gizmo_id"]) ?? text(entry["conversation_template_id"]);
|
|
180
|
+
if (project?.startsWith("g-p-")) {
|
|
181
|
+
if (!projects.has(project))
|
|
182
|
+
projects.set(project, undefined);
|
|
183
|
+
if (!projectConversations.has(project))
|
|
184
|
+
projectConversations.set(project, new Set());
|
|
185
|
+
projectConversations.get(project).add(id);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
for (const archived of [false, true])
|
|
189
|
+
for (const starred of [false, true]) {
|
|
190
|
+
await attempt(`${client.id}: ${archived ? "archived" : "active"} ${starred ? "starred" : "unstarred"} conversations`, () => paged(client, "/backend-api/conversations", { limit: "100", order: "updated", is_archived: String(archived), is_starred: String(starred) }, `${directory}/listings/${archived ? "archived" : "active"}-${starred ? "starred" : "unstarred"}`, (entry) => {
|
|
191
|
+
if (projectId === undefined || entry["gizmo_id"] === projectId || entry["conversation_template_id"] === projectId)
|
|
192
|
+
addConversation(entry);
|
|
193
|
+
}, true, projectId === undefined ? undefined : (entry) => entry["gizmo_id"] === projectId || entry["conversation_template_id"] === projectId));
|
|
194
|
+
}
|
|
195
|
+
if (projectId === undefined) {
|
|
196
|
+
await attempt(`${client.id}: projects`, () => paged(client, "/backend-api/gizmos/snorlax/sidebar", { owned_only: "false", conversations_per_gizmo: "5", limit: "20" }, `${directory}/listings/projects`, (entry) => {
|
|
197
|
+
const wrapper = object(entry["gizmo"]);
|
|
198
|
+
const project = object(wrapper["gizmo"]);
|
|
199
|
+
const id = identifier(project);
|
|
200
|
+
projects.set(id, wrapper);
|
|
201
|
+
if (entry["conversations"] !== undefined)
|
|
202
|
+
for (const conversation of items(object(entry["conversations"])["items"]))
|
|
203
|
+
addConversation(conversation, id);
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
else
|
|
207
|
+
projects.set(projectId, undefined);
|
|
208
|
+
for (const [id, fallback] of projects) {
|
|
209
|
+
const projectDirectory = projectId === undefined ? `${directory}/projects/${segment(id)}` : directory;
|
|
210
|
+
const metadata = await attempt(`${client.id}: project ${id}`, () => client.json(`/backend-api/gizmos/${encodeURIComponent(id)}`));
|
|
211
|
+
const detail = metadata ?? fallback;
|
|
212
|
+
let projectTitle = id;
|
|
213
|
+
let instructions = "";
|
|
214
|
+
let fileLinks = [];
|
|
215
|
+
if (detail !== undefined) {
|
|
216
|
+
await json(`${projectDirectory}/project.json`, detail);
|
|
217
|
+
await attempt(`${id}: project metadata`, async () => {
|
|
218
|
+
const wrapper = object(detail);
|
|
219
|
+
const project = object(wrapper["gizmo"]);
|
|
220
|
+
projectTitle = text(object(project["display"])["name"]) ?? id;
|
|
221
|
+
instructions = text(project["instructions"]) ?? "";
|
|
222
|
+
fileLinks = await downloadAssets(client, assets(wrapper, { project: id }), projectDirectory);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
await attempt(`${id}: project conversations`, () => paged(client, `/backend-api/gizmos/${encodeURIComponent(id)}/conversations`, { limit: "50", owned_only: "false" }, `${projectDirectory}/listings/conversations`, (entry) => addConversation(entry, id)));
|
|
226
|
+
await attempt(`${id}: project sources`, () => paged(client, `/backend-api/projects/${encodeURIComponent(id)}/connector_scopes`, { limit: "100" }, `${projectDirectory}/sources`, () => { }));
|
|
227
|
+
const ids = [...(projectConversations.get(id) ?? [])];
|
|
228
|
+
const prefix = projectId === undefined ? "../../" : "";
|
|
229
|
+
const markdown = `# ${projectTitle}\n\n## Instructions\n\n${instructions || "No project instructions."}\n\n## Conversations\n\n${ids.map((conversationId) => `- [${conversationId}](${prefix}conversations/${segment(conversationId)}/index.md)`).join("\n") || "No conversations."}\n\n## Files\n\n${fileLinks.join("\n") || "See project.json and sources for source metadata."}\n`;
|
|
230
|
+
await save(`${projectDirectory}/index.md`, markdown);
|
|
231
|
+
records.push({ type: "project", account_id: client.id, id, title: projectTitle, path: `${projectDirectory}/index.md`, conversations: ids });
|
|
232
|
+
}
|
|
233
|
+
for (const [id, listing] of conversations) {
|
|
234
|
+
const conversationDirectory = `${directory}/conversations/${segment(id)}`;
|
|
235
|
+
await json(`${conversationDirectory}/listing.json`, listing);
|
|
236
|
+
await attempt(`${client.id}: conversation ${id}`, async () => {
|
|
237
|
+
const conversation = object(await client.json(`/backend-api/conversation/${encodeURIComponent(id)}`));
|
|
238
|
+
await json(`${conversationDirectory}/conversation.json`, conversation);
|
|
239
|
+
records.push({ type: "conversation", account_id: client.id, id, title: text(conversation["title"]) ?? id, path: `${conversationDirectory}/index.md`, raw: `${conversationDirectory}/conversation.json` });
|
|
240
|
+
const fileLinks = await downloadAssets(client, assets(conversation, { conversation: id }), conversationDirectory);
|
|
241
|
+
await attempt(`${id}: canvases`, async () => {
|
|
242
|
+
const canvases = await client.json(`/backend-api/conversation/${encodeURIComponent(id)}/textdocs`);
|
|
243
|
+
await json(`${conversationDirectory}/textdocs.json`, canvases);
|
|
244
|
+
for (const canvas of items(canvases)) {
|
|
245
|
+
const content = text(canvas["content"]);
|
|
246
|
+
if (content !== undefined)
|
|
247
|
+
await save(`${conversationDirectory}/canvases/${segment(identifier(canvas))}.txt`, content);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
const markdown = await attempt(`${id}: readable transcript`, async () => render(conversation));
|
|
251
|
+
await save(`${conversationDirectory}/index.md`, `${markdown ?? `# ${text(conversation["title"]) ?? id}\n\nThe readable transcript could not be rendered; the full JSON is preserved.\n`}\n## Archive\n\n[Complete conversation JSON (all branches and metadata)](conversation.json)\n\n${fileLinks.join("\n")}\n`);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
if (projectId === undefined) {
|
|
255
|
+
const directories = [undefined];
|
|
256
|
+
const seenDirectories = new Set();
|
|
257
|
+
const library = new Map();
|
|
258
|
+
for (const parent of directories) {
|
|
259
|
+
await attempt(`${client.id}: library ${parent ?? "root"}`, () => paged(client, "/backend-api/files/library/nodes", { include_hidden_files: "true", include_saved_entities: "true", ...(parent === undefined ? {} : { parent_directory_id: parent }) }, `${directory}/library/listings/${parent === undefined ? "root" : segment(parent)}`, (entry) => {
|
|
260
|
+
const id = text(entry["id"]) ?? text(entry["library_file_id"]);
|
|
261
|
+
if (id === undefined)
|
|
262
|
+
throw new Error("ChatGPT Library item is missing its identifier");
|
|
263
|
+
if (entry["type"] === "folder" || entry["kind"] === "folder" || entry["kind"] === "directory" || entry["node_type"] === "directory") {
|
|
264
|
+
if (!seenDirectories.has(id)) {
|
|
265
|
+
seenDirectories.add(id);
|
|
266
|
+
directories.push(id);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else
|
|
270
|
+
library.set(id, entry);
|
|
271
|
+
}));
|
|
272
|
+
}
|
|
273
|
+
for (const [id, entry] of library) {
|
|
274
|
+
const fileDirectory = `${directory}/library/files/${segment(id)}`;
|
|
275
|
+
await json(`${fileDirectory}/metadata.json`, entry);
|
|
276
|
+
const links = await downloadAssets(client, [{ key: `library:${id}`, name: text(entry["name"]) ?? id, endpoint: `/backend-api/files/library/files/${encodeURIComponent(id)}/content_url` }], fileDirectory);
|
|
277
|
+
await save(`${fileDirectory}/index.md`, `# ${text(entry["name"]) ?? id}\n\n${links.join("\n")}\n`);
|
|
278
|
+
}
|
|
279
|
+
for (const path of ["me", "user_system_messages", "settings/user"]) {
|
|
280
|
+
await attempt(`${client.id}: ${path}`, async () => json(`${directory}/account/${path.replaceAll("/", "-")}.json`, await client.json(`/backend-api/${path}`)));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const exportAll = async () => {
|
|
285
|
+
if (!wholeHistory) {
|
|
286
|
+
await exportAccount(session.forAccount(session.accountId), base, source.identifier);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const current = session.forAccount(session.accountId);
|
|
290
|
+
const accounts = await attempt("accounts", () => current.json("/backend-api/accounts/check/v4-2023-04-27"));
|
|
291
|
+
const accountIds = new Set([session.accountId]);
|
|
292
|
+
if (accounts !== undefined) {
|
|
293
|
+
await json(`${base}/accounts.json`, accounts);
|
|
294
|
+
await attempt("account listing", async () => {
|
|
295
|
+
for (const value of Object.values(object(object(accounts)["accounts"]))) {
|
|
296
|
+
const entry = object(value);
|
|
297
|
+
const account = object(entry["account"]);
|
|
298
|
+
const id = text(account["account_id"]);
|
|
299
|
+
if (id === undefined || accountIds.has(id))
|
|
300
|
+
continue;
|
|
301
|
+
if (entry["can_access_with_session"] === false || account["is_deactivated"] === true)
|
|
302
|
+
skipped.push({ type: "account", id, reason: "Not accessible with the current session or deactivated" });
|
|
303
|
+
else
|
|
304
|
+
accountIds.add(id);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
for (const id of accountIds)
|
|
309
|
+
await exportAccount(session.forAccount(id), `${base}/accounts/${segment(id)}`);
|
|
310
|
+
};
|
|
311
|
+
try {
|
|
312
|
+
await exportAll();
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
if (!(error instanceof ChatgptCooldownError))
|
|
316
|
+
throw error;
|
|
317
|
+
errors.push({ resource: error.cooldown.endpoint, error: error.message, retry_at: error.cooldown.retry_at });
|
|
318
|
+
}
|
|
319
|
+
const status = errors.length === 0 ? "complete" : "partial";
|
|
320
|
+
const manifest = { status, source: url, started_at: started, finished_at: runtime.clock.now().toISOString(), records, files, errors, skipped, cooldowns };
|
|
321
|
+
await json(`${base}/manifest.json`, manifest);
|
|
322
|
+
const relative = (path) => path.slice(base.length + 1);
|
|
323
|
+
const lines = records.map((record) => `- ${record["type"]}: [${String(record["title"]).replace(/[\[\]\r\n]/g, " ")}](${relative(record["path"])})`);
|
|
324
|
+
const markdown = `# ${title}\n\nStatus: **${status}**\n\n${records.filter((record) => record["type"] === "conversation").length} conversations, ${records.filter((record) => record["type"] === "project").length} projects, ${files.length} downloaded files.\n\n[Export manifest](manifest.json) records every failure and unavailable account. Raw conversation JSON preserves all returned branches, messages, citations, and metadata; Markdown is the readable active branch. Deleted or expired server data cannot be recovered. Linked external sources are recorded, not recursively fetched.\n\n${lines.join("\n")}\n${errors.length === 0 ? "" : `\n## Incomplete downloads\n\n${errors.map((error) => `- ${error["resource"]}: ${error["error"]}`).join("\n")}\n`}`;
|
|
325
|
+
const path = `${base}/${wholeHistory ? "index" : "export"}.md`;
|
|
326
|
+
const retryAt = errors.map((error) => text(error["retry_at"])).filter((value) => value !== undefined).sort().at(-1);
|
|
327
|
+
return { title, markdown, path, data: { status, manifest: `${base}/manifest.json`, conversations: records.filter((record) => record["type"] === "conversation").length, projects: records.filter((record) => record["type"] === "project").length, files: files.length, errors: errors.length }, ...(errors.length === 0 ? {} : { error: `${errors.length} downloads failed. See ${base}/manifest.json; successfully downloaded data was retained.${retryAt === undefined ? "" : ` Retry no earlier than ${retryAt}.`}` }) };
|
|
328
|
+
}
|
|
329
|
+
//# sourceMappingURL=download.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download.js","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,12 @@ export declare const chatgptProvider: Readonly<{
|
|
|
14
14
|
markdown: string;
|
|
15
15
|
data: import("wire-core").JsonValue;
|
|
16
16
|
}>>;
|
|
17
|
+
download?(input: import("wire-core").RuntimeCapabilities, url: string, source: Readonly<{
|
|
18
|
+
[key: string]: import("wire-core").JsonValue;
|
|
19
|
+
service: string;
|
|
20
|
+
identifier: string;
|
|
21
|
+
type: import("wire-core").ResourceType;
|
|
22
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
17
23
|
synchronize?(input: import("wire-core").RuntimeCapabilities, url: string, source: Readonly<{
|
|
18
24
|
[key: string]: import("wire-core").JsonValue;
|
|
19
25
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE1B,CAAC"}
|
|
@@ -1,27 +1,8 @@
|
|
|
1
1
|
import { defineService } from "wire-core";
|
|
2
2
|
import type { FetchedDocument, JsonObject, JsonValue } from "wire-core";
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return new Error("ChatGPT authentication is missing or expired. Run `wire chatgpt login` once; other commands reuse saved cookies.");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function cookieHeader(cookies: readonly Cookie[]): string {
|
|
10
|
-
return cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join("; ");
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function headers(cookies: readonly Cookie[], referer: string): Record<string, string> {
|
|
14
|
-
return {
|
|
15
|
-
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
|
|
16
|
-
"sec-ch-ua": '"Not:A-Brand";v="99", "Google Chrome";v="145", "Chromium";v="145"',
|
|
17
|
-
"sec-ch-ua-mobile": "?0",
|
|
18
|
-
"sec-ch-ua-platform": '"macOS"',
|
|
19
|
-
"oai-device-id": cookies.find((cookie) => cookie.name === "oai-did")!.value,
|
|
20
|
-
"oai-language": "en-US",
|
|
21
|
-
referer,
|
|
22
|
-
cookie: cookieHeader(cookies),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
3
|
+
import type { RuntimeCapabilities } from "wire-core";
|
|
4
|
+
import { connectChatgpt, object } from "./client.js";
|
|
5
|
+
import { downloadChatgpt } from "./download.js";
|
|
25
6
|
|
|
26
7
|
function formatUpdateTime(value: JsonValue): string {
|
|
27
8
|
if (typeof value === "string") return value;
|
|
@@ -32,19 +13,22 @@ function orderedMessages(conversation: JsonObject): readonly JsonObject[] {
|
|
|
32
13
|
const mapping = conversation["mapping"] as JsonObject;
|
|
33
14
|
if (typeof conversation["current_node"] === "string") {
|
|
34
15
|
const path: JsonObject[] = [];
|
|
16
|
+
const visited = new Set<string>();
|
|
35
17
|
let nodeId = conversation["current_node"] as string | null;
|
|
36
18
|
while (nodeId !== null) {
|
|
19
|
+
if (visited.has(nodeId) || mapping[nodeId] === undefined) throw new Error("Invalid ChatGPT conversation branch");
|
|
20
|
+
visited.add(nodeId);
|
|
37
21
|
const node = mapping[nodeId] as JsonObject;
|
|
38
22
|
const message = node["message"] as JsonObject | null;
|
|
39
|
-
if (message
|
|
40
|
-
nodeId = node["parent"]
|
|
23
|
+
if (message != null) path.push(message);
|
|
24
|
+
nodeId = typeof node["parent"] === "string" ? node["parent"] : null;
|
|
41
25
|
}
|
|
42
26
|
return path.reverse();
|
|
43
27
|
}
|
|
44
28
|
const messages: JsonObject[] = [];
|
|
45
29
|
for (const node of Object.values(mapping)) {
|
|
46
30
|
const message = (node as JsonObject)["message"] as JsonObject | null;
|
|
47
|
-
if (message
|
|
31
|
+
if (message != null) messages.push(message);
|
|
48
32
|
}
|
|
49
33
|
messages.sort((left, right) => {
|
|
50
34
|
const leftTime = left["create_time"] as number | null;
|
|
@@ -150,27 +134,18 @@ function fetchedConversation(conversation: JsonObject): FetchedDocument {
|
|
|
150
134
|
|
|
151
135
|
export const chatgptService = defineService<RuntimeCapabilities>({
|
|
152
136
|
name: "chatgpt",
|
|
153
|
-
matches: (url) => (url.hostname === "chatgpt.com" || url.hostname === "chat.openai.com") && /^\/c\/[^/]+\/?$/.test(url.pathname),
|
|
154
|
-
parse: (url) =>
|
|
137
|
+
matches: (url) => (url.hostname === "chatgpt.com" || url.hostname === "chat.openai.com") && (url.pathname === "/" || /^\/c\/[^/]+\/?$/.test(url.pathname) || /^\/g\/g-p-[^/]+\/project\/?$/.test(url.pathname) || /^\/g\/[^/]+\/c\/[^/]+\/?$/.test(url.pathname)),
|
|
138
|
+
parse: (url) => {
|
|
139
|
+
if (url.pathname === "/") return Object.freeze({ service: "chatgpt", identifier: "history", type: "project" });
|
|
140
|
+
const project = /^\/g\/(g-p-[^/]+)\/project\/?$/.exec(url.pathname);
|
|
141
|
+
if (project !== null) return Object.freeze({ service: "chatgpt", identifier: project[1]!, type: "project" });
|
|
142
|
+
return Object.freeze({ service: "chatgpt", identifier: /\/c\/([^/]+)\/?$/.exec(url.pathname)![1]!, type: "message-thread" });
|
|
143
|
+
},
|
|
144
|
+
download: (runtime, url, source, write) => downloadChatgpt(runtime, url, source, write, conversationMarkdown),
|
|
155
145
|
fetch: async (runtime, url, source) => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
const sessionText = await sessionResponse.text();
|
|
161
|
-
if (!sessionText.startsWith("{")) throw chatgptAuthError();
|
|
162
|
-
const session = JSON.parse(sessionText) as JsonObject;
|
|
163
|
-
if ("error" in session) throw chatgptAuthError();
|
|
164
|
-
if (session["account"] === undefined || session["accessToken"] === undefined) throw chatgptAuthError();
|
|
165
|
-
const account = session["account"] as JsonObject;
|
|
166
|
-
const conversationHeaders = {
|
|
167
|
-
...sessionHeaders,
|
|
168
|
-
authorization: `Bearer ${session["accessToken"] as string}`,
|
|
169
|
-
"chatgpt-account-id": account["id"] as string,
|
|
170
|
-
referer: url,
|
|
171
|
-
};
|
|
172
|
-
const conversationResponse = await runtime.http.request(`https://chatgpt.com/backend-api/conversation/${encodeURIComponent(source.identifier)}`, { headers: conversationHeaders });
|
|
173
|
-
if (!conversationResponse.ok) throw new Error(`ChatGPT conversation download failed. Run \`wire chatgpt login\`. ${await conversationResponse.text()}`);
|
|
174
|
-
return fetchedConversation(await conversationResponse.json() as JsonObject);
|
|
146
|
+
if (source.type === "project") throw new Error("Use `wire download <url>` to export ChatGPT history or projects as a directory.");
|
|
147
|
+
const session = await connectChatgpt(runtime, url);
|
|
148
|
+
const conversation = await session.forAccount(session.accountId).json(`/backend-api/conversation/${encodeURIComponent(source.identifier)}`);
|
|
149
|
+
return fetchedConversation(object(conversation));
|
|
175
150
|
},
|
|
176
151
|
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue, RuntimeCapabilities } from "wire-core";
|
|
2
|
+
import { createChatgptRequester, type Cooldown } from "./cooldown.js";
|
|
3
|
+
|
|
4
|
+
export function authError(): Error {
|
|
5
|
+
return new Error("ChatGPT authentication is missing or expired. Run `wire chatgpt login` once; other commands reuse saved cookies.");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function object(value: JsonValue | undefined): JsonObject {
|
|
9
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("Unexpected ChatGPT object response");
|
|
10
|
+
return value as JsonObject;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function text(value: JsonValue | undefined): string | undefined {
|
|
14
|
+
return typeof value === "string" && value !== "" ? value : undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class ChatgptRequestError extends Error {
|
|
18
|
+
constructor(readonly status: number, readonly endpoint: string) {
|
|
19
|
+
super(`ChatGPT request failed (${status}): ${endpoint}${status === 401 || status === 403 ? ". Run `wire chatgpt login`." : ""}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function connectChatgpt(runtime: RuntimeCapabilities, referer: string, onCooldown?: (value: Cooldown) => Promise<void>) {
|
|
24
|
+
const cookies = await runtime.cookies.loadSaved("chatgpt");
|
|
25
|
+
if (cookies === null) throw authError();
|
|
26
|
+
const device = cookies.find((cookie) => cookie.name === "oai-did")?.value;
|
|
27
|
+
const headers: Record<string, string> = {
|
|
28
|
+
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
|
|
29
|
+
"sec-ch-ua": '"Not:A-Brand";v="99", "Google Chrome";v="145", "Chromium";v="145"',
|
|
30
|
+
"sec-ch-ua-mobile": "?0",
|
|
31
|
+
"sec-ch-ua-platform": '"macOS"',
|
|
32
|
+
...(device === undefined ? {} : { "oai-device-id": device }),
|
|
33
|
+
"oai-language": "en-US",
|
|
34
|
+
referer,
|
|
35
|
+
cookie: cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join("; "),
|
|
36
|
+
};
|
|
37
|
+
const response = await runtime.http.request("https://chatgpt.com/api/auth/session", { headers, signal: AbortSignal.timeout(60000), redirect: "error" });
|
|
38
|
+
const contents = await response.text();
|
|
39
|
+
if (!response.ok || !contents.trimStart().startsWith("{")) throw authError();
|
|
40
|
+
const session = object(JSON.parse(contents) as JsonValue);
|
|
41
|
+
if (session["error"] !== undefined || text(session["accessToken"]) === undefined || session["account"] == null) throw authError();
|
|
42
|
+
const account = object(session["account"]);
|
|
43
|
+
const accountId = text(account["id"]);
|
|
44
|
+
if (accountId === undefined) throw authError();
|
|
45
|
+
headers["authorization"] = `Bearer ${session["accessToken"] as string}`;
|
|
46
|
+
|
|
47
|
+
const request = createChatgptRequester(runtime.http, onCooldown);
|
|
48
|
+
|
|
49
|
+
const forAccount = (id: string) => {
|
|
50
|
+
const authenticated = { ...headers, "chatgpt-account-id": id };
|
|
51
|
+
const json = async (endpoint: string): Promise<JsonValue> => {
|
|
52
|
+
if (!endpoint.startsWith("/backend-api/")) throw new Error("Invalid ChatGPT API endpoint");
|
|
53
|
+
const result = await request(`https://chatgpt.com${endpoint}`, authenticated, endpoint);
|
|
54
|
+
if (!result.ok) throw new ChatgptRequestError(result.status, endpoint);
|
|
55
|
+
return await result.json() as JsonValue;
|
|
56
|
+
};
|
|
57
|
+
const bytes = async (value: string): Promise<Uint8Array> => {
|
|
58
|
+
let url = new URL(value, "https://chatgpt.com");
|
|
59
|
+
for (let redirects = 0; redirects <= 5; redirects++) {
|
|
60
|
+
const trusted = url.hostname === "chatgpt.com" || url.hostname.endsWith(".oaiusercontent.com") || url.hostname.endsWith(".blob.core.windows.net");
|
|
61
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || (url.port !== "" && url.port !== "443") || !trusted) throw new Error("Untrusted ChatGPT file download URL");
|
|
62
|
+
const result = await request(url.href, url.origin === "https://chatgpt.com" ? authenticated : {}, url.origin + url.pathname);
|
|
63
|
+
if ([301, 302, 303, 307, 308].includes(result.status)) {
|
|
64
|
+
const location = result.headers.get("location");
|
|
65
|
+
await result.body?.cancel();
|
|
66
|
+
if (location === null) throw new Error("ChatGPT file redirect is missing its destination");
|
|
67
|
+
url = new URL(location, url);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (!result.ok) throw new ChatgptRequestError(result.status, url.origin + url.pathname);
|
|
71
|
+
return new Uint8Array(await result.arrayBuffer());
|
|
72
|
+
}
|
|
73
|
+
throw new Error("Too many ChatGPT file redirects");
|
|
74
|
+
};
|
|
75
|
+
return { id, json, bytes };
|
|
76
|
+
};
|
|
77
|
+
return { accountId, forAccount };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type ChatgptClient = ReturnType<Awaited<ReturnType<typeof connectChatgpt>>["forAccount"]>;
|