@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,64 @@
|
|
|
1
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
+
import type { HttpCapability } from "wire-core";
|
|
3
|
+
|
|
4
|
+
export type Cooldown = {
|
|
5
|
+
endpoint: string;
|
|
6
|
+
status: number;
|
|
7
|
+
attempt: number;
|
|
8
|
+
delay_ms: number;
|
|
9
|
+
retry_at: string;
|
|
10
|
+
source: "retry-after-seconds" | "retry-after-date" | "exponential-backoff";
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export class ChatgptCooldownError extends Error {
|
|
14
|
+
constructor(readonly cooldown: Cooldown) {
|
|
15
|
+
super(`ChatGPT is still rate-limited after ${cooldown.attempt} attempts. No further requests were sent. Retry no earlier than ${cooldown.retry_at} (${cooldown.source}).`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function responseCooldown(response: Response, now: number, attempt: number, endpoint: string): Cooldown {
|
|
20
|
+
const retryAfter = response.headers.get("retry-after")?.trim();
|
|
21
|
+
let milliseconds = 1000 * 2 ** (attempt - 1);
|
|
22
|
+
let source: Cooldown["source"] = "exponential-backoff";
|
|
23
|
+
if (retryAfter !== undefined && /^\d+$/.test(retryAfter) && Number.isSafeInteger(Number(retryAfter) * 1000)) {
|
|
24
|
+
milliseconds = Number(retryAfter) * 1000;
|
|
25
|
+
source = "retry-after-seconds";
|
|
26
|
+
} else if (retryAfter !== undefined && /^[A-Za-z]/.test(retryAfter) && Number.isFinite(Date.parse(retryAfter))) {
|
|
27
|
+
const serverDate = Date.parse(response.headers.get("date") ?? "");
|
|
28
|
+
milliseconds = Math.max(0, Date.parse(retryAfter) - (Number.isFinite(serverDate) ? serverDate : now));
|
|
29
|
+
source = "retry-after-date";
|
|
30
|
+
}
|
|
31
|
+
if (!Number.isFinite(new Date(now + milliseconds).getTime())) {
|
|
32
|
+
milliseconds = 1000 * 2 ** (attempt - 1);
|
|
33
|
+
source = "exponential-backoff";
|
|
34
|
+
}
|
|
35
|
+
return { endpoint, status: response.status, attempt, delay_ms: milliseconds, retry_at: new Date(now + milliseconds).toISOString(), source };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createChatgptRequester(
|
|
39
|
+
http: HttpCapability,
|
|
40
|
+
onCooldown: (value: Cooldown) => Promise<void> = async () => {},
|
|
41
|
+
timing = { now: () => Date.now(), sleep: (milliseconds: number) => delay(milliseconds) },
|
|
42
|
+
) {
|
|
43
|
+
const deadlines = new Map<string, number>();
|
|
44
|
+
let stopped: ChatgptCooldownError | undefined;
|
|
45
|
+
return async (url: string, headers: Record<string, string>, endpoint: string): Promise<Response> => {
|
|
46
|
+
if (stopped !== undefined) throw stopped;
|
|
47
|
+
const origin = new URL(url).origin;
|
|
48
|
+
for (let attempt = 1; ; attempt++) {
|
|
49
|
+
while (timing.now() < (deadlines.get(origin) ?? 0)) await timing.sleep(Math.min(2147483647, deadlines.get(origin)! - timing.now()));
|
|
50
|
+
const response = await http.request(url, { headers, redirect: "manual", signal: AbortSignal.timeout(60000) });
|
|
51
|
+
if (![429, 500, 502, 503, 504].includes(response.status)) return response;
|
|
52
|
+
const cooldown = responseCooldown(response, timing.now(), attempt, endpoint);
|
|
53
|
+
deadlines.set(origin, Math.max(deadlines.get(origin) ?? 0, Date.parse(cooldown.retry_at)));
|
|
54
|
+
await onCooldown(cooldown);
|
|
55
|
+
if (attempt === 5) {
|
|
56
|
+
if (response.status !== 429) return response;
|
|
57
|
+
await response.body?.cancel();
|
|
58
|
+
stopped = new ChatgptCooldownError(cooldown);
|
|
59
|
+
throw stopped;
|
|
60
|
+
}
|
|
61
|
+
await response.body?.cancel();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import type { DownloadedDocument, DownloadWriter, JsonObject, JsonValue, RuntimeCapabilities, Source } from "wire-core";
|
|
3
|
+
import { connectChatgpt, object, text, type ChatgptClient } from "./client.js";
|
|
4
|
+
import { ChatgptCooldownError } from "./cooldown.js";
|
|
5
|
+
|
|
6
|
+
function segment(value: string): string {
|
|
7
|
+
const safe = value.replace(/[^\p{L}\p{N}._-]/gu, "-").slice(0, 64);
|
|
8
|
+
return safe === value && safe !== "." && safe !== ".." && safe !== "" ? safe : `${safe || "item"}-${createHash("sha256").update(value).digest("hex").slice(0, 12)}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function items(value: JsonValue | undefined): readonly JsonObject[] {
|
|
12
|
+
if (!Array.isArray(value)) throw new Error("ChatGPT list response is missing items");
|
|
13
|
+
return value.map((item) => object(item));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function identifier(value: JsonObject): string {
|
|
17
|
+
const id = text(value["id"]) ?? text(value["conversation_id"]);
|
|
18
|
+
if (id === undefined) throw new Error("ChatGPT item is missing its identifier");
|
|
19
|
+
return id;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function endpoint(path: string, query: Record<string, string>): string {
|
|
23
|
+
return `${path}?${new URLSearchParams(query)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type Asset = { key: string; name: string; endpoint: string };
|
|
27
|
+
|
|
28
|
+
function assets(value: JsonValue, context: { conversation?: string; project?: string; message?: string }): Asset[] {
|
|
29
|
+
const found = new Map<string, Asset>();
|
|
30
|
+
const addFile = (id: string, name?: string) => {
|
|
31
|
+
const queryIndex = id.indexOf("?");
|
|
32
|
+
const fileId = (queryIndex === -1 ? id : id.slice(0, queryIndex)).replaceAll("#", "*");
|
|
33
|
+
const query: Record<string, string> = Object.fromEntries(new URLSearchParams(queryIndex === -1 ? "" : id.slice(queryIndex + 1)));
|
|
34
|
+
if (context.conversation !== undefined) query["conversation_id"] = context.conversation;
|
|
35
|
+
if (context.project !== undefined) query["gizmo_id"] = context.project;
|
|
36
|
+
const key = `file:${id}`;
|
|
37
|
+
found.set(key, { key, name: name ?? fileId, endpoint: endpoint(`/backend-api/files/download/${encodeURIComponent(fileId)}`, query) });
|
|
38
|
+
};
|
|
39
|
+
const visit = (node: JsonValue, message?: string) => {
|
|
40
|
+
if (typeof node === "string") {
|
|
41
|
+
if (node.startsWith("file-service://") || node.startsWith("sediment://")) addFile(node.slice(node.indexOf("://") + 3));
|
|
42
|
+
if (context.conversation !== undefined && message !== undefined) {
|
|
43
|
+
for (const match of node.matchAll(/sandbox:(\/[^\s)\]<>"']+)/g)) {
|
|
44
|
+
const path = match[1]!;
|
|
45
|
+
const key = `sandbox:${message}:${path}`;
|
|
46
|
+
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 }) });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else if (Array.isArray(node)) {
|
|
50
|
+
for (const child of node) visit(child, message);
|
|
51
|
+
} else if (node !== null && typeof node === "object") {
|
|
52
|
+
const record = node as JsonObject;
|
|
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) addFile(fileId, text(record["name"]) ?? text(record["filename"]));
|
|
56
|
+
const libraryId = text(record["library_file_id"]) ?? (text(record["id"])?.startsWith("libfile_") ? text(record["id"]) : undefined);
|
|
57
|
+
if (fileId === undefined && libraryId !== undefined) {
|
|
58
|
+
const key = `library:${libraryId}`;
|
|
59
|
+
found.set(key, { key, name: text(record["name"]) ?? libraryId, endpoint: `/backend-api/files/library/files/${encodeURIComponent(libraryId)}/content_url` });
|
|
60
|
+
}
|
|
61
|
+
for (const child of Object.values(record)) visit(child, currentMessage);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
visit(value, context.message);
|
|
65
|
+
return [...found.values()];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class DownloadWriteError extends Error {}
|
|
69
|
+
|
|
70
|
+
export async function downloadChatgpt(
|
|
71
|
+
runtime: RuntimeCapabilities,
|
|
72
|
+
url: string,
|
|
73
|
+
source: Source,
|
|
74
|
+
write: DownloadWriter,
|
|
75
|
+
render: (conversation: JsonObject) => string,
|
|
76
|
+
): Promise<DownloadedDocument | null> {
|
|
77
|
+
if (source.type !== "project") return null;
|
|
78
|
+
const wholeHistory = source.identifier === "history";
|
|
79
|
+
const base = wholeHistory ? "chatgpt" : `chatgpt/projects/${segment(source.identifier)}`;
|
|
80
|
+
const title = wholeHistory ? "ChatGPT history" : "ChatGPT project";
|
|
81
|
+
const errors: JsonObject[] = [];
|
|
82
|
+
const skipped: JsonObject[] = [];
|
|
83
|
+
const records: JsonObject[] = [];
|
|
84
|
+
const files: JsonObject[] = [];
|
|
85
|
+
const cooldowns: JsonObject[] = [];
|
|
86
|
+
const started = runtime.clock.now().toISOString();
|
|
87
|
+
const save: DownloadWriter = async (path, contents) => {
|
|
88
|
+
try { await write(path, contents); }
|
|
89
|
+
catch (error) { throw new DownloadWriteError(`Could not write ${path}: ${error instanceof Error ? error.message : String(error)}`); }
|
|
90
|
+
};
|
|
91
|
+
const json = (path: string, value: JsonValue) => save(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
92
|
+
const attempt = async <Result>(resource: string, action: () => Promise<Result>): Promise<Result | undefined> => {
|
|
93
|
+
try { return await action(); }
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error instanceof DownloadWriteError || error instanceof ChatgptCooldownError) throw error;
|
|
96
|
+
errors.push({ resource, error: error instanceof Error ? error.message : String(error) });
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const session = await connectChatgpt(runtime, url, async (cooldown) => {
|
|
101
|
+
cooldowns.push(cooldown);
|
|
102
|
+
await json(`${base}/manifest.json`, { status: "cooldown", source: url, started_at: started, records, files, errors, skipped, cooldowns, retry_at: cooldown.retry_at });
|
|
103
|
+
});
|
|
104
|
+
await json(`${base}/manifest.json`, { status: "in_progress", source: url, started_at: started });
|
|
105
|
+
|
|
106
|
+
const paged = async (client: ChatgptClient, path: string, query: Record<string, string>, output: string, consume: (value: JsonObject) => void, offsetMode = false, filter?: (value: JsonObject) => boolean) => {
|
|
107
|
+
const seen = new Set<string>();
|
|
108
|
+
let cursor: string | undefined;
|
|
109
|
+
let offset = 0;
|
|
110
|
+
let pageNumber = 0;
|
|
111
|
+
for (;;) {
|
|
112
|
+
const parameters = { ...query, ...(offsetMode ? { offset: String(offset) } : cursor === undefined ? {} : { cursor }) };
|
|
113
|
+
const page = object(await client.json(endpoint(path, parameters)));
|
|
114
|
+
const entries = items(page["items"]);
|
|
115
|
+
await json(`${output}/${pageNumber++}.json`, filter === undefined ? page : { ...page, items: entries.filter(filter) });
|
|
116
|
+
for (const item of entries) consume(item);
|
|
117
|
+
if (offsetMode) {
|
|
118
|
+
if (page["offset"] !== undefined && page["offset"] !== offset) throw new Error(`ChatGPT returned a different offset for ${path}`);
|
|
119
|
+
if (entries.length === 0) {
|
|
120
|
+
if (typeof page["total"] === "number" && offset < page["total"]) throw new Error(`ChatGPT listing stopped before its reported total: ${path}`);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
const signature = entries.map(identifier).join("|");
|
|
124
|
+
if (seen.has(signature)) throw new Error(`ChatGPT repeated a page: ${path}`);
|
|
125
|
+
seen.add(signature);
|
|
126
|
+
offset += entries.length;
|
|
127
|
+
if (typeof page["total"] === "number" && offset >= page["total"]) break;
|
|
128
|
+
} else {
|
|
129
|
+
if (!("cursor" in page) && !("next_cursor" in page) && page["has_more"] !== false) throw new Error(`ChatGPT list response is missing pagination metadata: ${path}`);
|
|
130
|
+
const next = page["cursor"] ?? page["next_cursor"];
|
|
131
|
+
if (next == null || next === "") {
|
|
132
|
+
if (page["has_more"] === true) throw new Error(`ChatGPT listing has more items but no cursor: ${path}`);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
if (typeof next !== "string" && typeof next !== "number") throw new Error(`Invalid ChatGPT pagination cursor: ${path}`);
|
|
136
|
+
cursor = String(next);
|
|
137
|
+
if (seen.has(cursor)) throw new Error(`ChatGPT repeated a cursor: ${path}`);
|
|
138
|
+
seen.add(cursor);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const downloadAssets = async (client: ChatgptClient, references: readonly Asset[], directory: string) => {
|
|
144
|
+
const links: string[] = [];
|
|
145
|
+
for (const asset of references) {
|
|
146
|
+
await attempt(asset.endpoint, async () => {
|
|
147
|
+
const metadata = object(await client.json(asset.endpoint));
|
|
148
|
+
const downloadUrl = text(metadata["download_url"]) ?? text(metadata["content_url"]);
|
|
149
|
+
if (downloadUrl === undefined) throw new Error(`ChatGPT file is unavailable (${String(metadata["status"] ?? "missing URL")})`);
|
|
150
|
+
const bytes = await client.bytes(downloadUrl);
|
|
151
|
+
const name = `${createHash("sha256").update(asset.key).digest("hex").slice(0, 12)}-${segment(asset.name)}`;
|
|
152
|
+
const path = `${directory}/assets/${name}`;
|
|
153
|
+
await save(path, bytes);
|
|
154
|
+
files.push({ path, source: asset.endpoint, bytes: bytes.byteLength, sha256: createHash("sha256").update(bytes).digest("hex") });
|
|
155
|
+
links.push(`- [${asset.name.replace(/[\[\]\r\n]/g, " ")}](assets/${encodeURIComponent(name)})`);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return links;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const exportAccount = async (client: ChatgptClient, directory: string, projectId?: string) => {
|
|
162
|
+
const conversations = new Map<string, JsonObject>();
|
|
163
|
+
const projects = new Map<string, JsonObject | undefined>();
|
|
164
|
+
const projectConversations = new Map<string, Set<string>>();
|
|
165
|
+
const addConversation = (entry: JsonObject, owner?: string) => {
|
|
166
|
+
const id = identifier(entry);
|
|
167
|
+
conversations.set(id, { ...conversations.get(id), ...entry });
|
|
168
|
+
const project = owner ?? text(entry["gizmo_id"]) ?? text(entry["conversation_template_id"]);
|
|
169
|
+
if (project?.startsWith("g-p-")) {
|
|
170
|
+
if (!projects.has(project)) projects.set(project, undefined);
|
|
171
|
+
if (!projectConversations.has(project)) projectConversations.set(project, new Set());
|
|
172
|
+
projectConversations.get(project)!.add(id);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
for (const archived of [false, true]) for (const starred of [false, true]) {
|
|
176
|
+
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) => {
|
|
177
|
+
if (projectId === undefined || entry["gizmo_id"] === projectId || entry["conversation_template_id"] === projectId) addConversation(entry);
|
|
178
|
+
}, true, projectId === undefined ? undefined : (entry) => entry["gizmo_id"] === projectId || entry["conversation_template_id"] === projectId));
|
|
179
|
+
}
|
|
180
|
+
if (projectId === undefined) {
|
|
181
|
+
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) => {
|
|
182
|
+
const wrapper = object(entry["gizmo"]);
|
|
183
|
+
const project = object(wrapper["gizmo"]);
|
|
184
|
+
const id = identifier(project);
|
|
185
|
+
projects.set(id, wrapper);
|
|
186
|
+
if (entry["conversations"] !== undefined) for (const conversation of items(object(entry["conversations"])["items"])) addConversation(conversation, id);
|
|
187
|
+
}));
|
|
188
|
+
} else projects.set(projectId, undefined);
|
|
189
|
+
|
|
190
|
+
for (const [id, fallback] of projects) {
|
|
191
|
+
const projectDirectory = projectId === undefined ? `${directory}/projects/${segment(id)}` : directory;
|
|
192
|
+
const metadata = await attempt(`${client.id}: project ${id}`, () => client.json(`/backend-api/gizmos/${encodeURIComponent(id)}`));
|
|
193
|
+
const detail = metadata ?? fallback;
|
|
194
|
+
let projectTitle = id;
|
|
195
|
+
let instructions = "";
|
|
196
|
+
let fileLinks: string[] = [];
|
|
197
|
+
if (detail !== undefined) {
|
|
198
|
+
await json(`${projectDirectory}/project.json`, detail);
|
|
199
|
+
await attempt(`${id}: project metadata`, async () => {
|
|
200
|
+
const wrapper = object(detail);
|
|
201
|
+
const project = object(wrapper["gizmo"]);
|
|
202
|
+
projectTitle = text(object(project["display"])["name"]) ?? id;
|
|
203
|
+
instructions = text(project["instructions"]) ?? "";
|
|
204
|
+
fileLinks = await downloadAssets(client, assets(wrapper, { project: id }), projectDirectory);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
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)));
|
|
208
|
+
await attempt(`${id}: project sources`, () => paged(client, `/backend-api/projects/${encodeURIComponent(id)}/connector_scopes`, { limit: "100" }, `${projectDirectory}/sources`, () => {}));
|
|
209
|
+
const ids = [...(projectConversations.get(id) ?? [])];
|
|
210
|
+
const prefix = projectId === undefined ? "../../" : "";
|
|
211
|
+
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`;
|
|
212
|
+
await save(`${projectDirectory}/index.md`, markdown);
|
|
213
|
+
records.push({ type: "project", account_id: client.id, id, title: projectTitle, path: `${projectDirectory}/index.md`, conversations: ids });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
for (const [id, listing] of conversations) {
|
|
217
|
+
const conversationDirectory = `${directory}/conversations/${segment(id)}`;
|
|
218
|
+
await json(`${conversationDirectory}/listing.json`, listing);
|
|
219
|
+
await attempt(`${client.id}: conversation ${id}`, async () => {
|
|
220
|
+
const conversation = object(await client.json(`/backend-api/conversation/${encodeURIComponent(id)}`));
|
|
221
|
+
await json(`${conversationDirectory}/conversation.json`, conversation);
|
|
222
|
+
records.push({ type: "conversation", account_id: client.id, id, title: text(conversation["title"]) ?? id, path: `${conversationDirectory}/index.md`, raw: `${conversationDirectory}/conversation.json` });
|
|
223
|
+
const fileLinks = await downloadAssets(client, assets(conversation, { conversation: id }), conversationDirectory);
|
|
224
|
+
await attempt(`${id}: canvases`, async () => {
|
|
225
|
+
const canvases = await client.json(`/backend-api/conversation/${encodeURIComponent(id)}/textdocs`);
|
|
226
|
+
await json(`${conversationDirectory}/textdocs.json`, canvases);
|
|
227
|
+
for (const canvas of items(canvases)) {
|
|
228
|
+
const content = text(canvas["content"]);
|
|
229
|
+
if (content !== undefined) await save(`${conversationDirectory}/canvases/${segment(identifier(canvas))}.txt`, content);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const markdown = await attempt(`${id}: readable transcript`, async () => render(conversation));
|
|
233
|
+
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`);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (projectId === undefined) {
|
|
238
|
+
const directories: (string | undefined)[] = [undefined];
|
|
239
|
+
const seenDirectories = new Set<string>();
|
|
240
|
+
const library = new Map<string, JsonObject>();
|
|
241
|
+
for (const parent of directories) {
|
|
242
|
+
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) => {
|
|
243
|
+
const id = text(entry["id"]) ?? text(entry["library_file_id"]);
|
|
244
|
+
if (id === undefined) throw new Error("ChatGPT Library item is missing its identifier");
|
|
245
|
+
if (entry["type"] === "folder" || entry["kind"] === "folder" || entry["kind"] === "directory" || entry["node_type"] === "directory") {
|
|
246
|
+
if (!seenDirectories.has(id)) { seenDirectories.add(id); directories.push(id); }
|
|
247
|
+
} else library.set(id, entry);
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
for (const [id, entry] of library) {
|
|
251
|
+
const fileDirectory = `${directory}/library/files/${segment(id)}`;
|
|
252
|
+
await json(`${fileDirectory}/metadata.json`, entry);
|
|
253
|
+
const links = await downloadAssets(client, [{ key: `library:${id}`, name: text(entry["name"]) ?? id, endpoint: `/backend-api/files/library/files/${encodeURIComponent(id)}/content_url` }], fileDirectory);
|
|
254
|
+
await save(`${fileDirectory}/index.md`, `# ${text(entry["name"]) ?? id}\n\n${links.join("\n")}\n`);
|
|
255
|
+
}
|
|
256
|
+
for (const path of ["me", "user_system_messages", "settings/user"]) {
|
|
257
|
+
await attempt(`${client.id}: ${path}`, async () => json(`${directory}/account/${path.replaceAll("/", "-")}.json`, await client.json(`/backend-api/${path}`)));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const exportAll = async () => {
|
|
263
|
+
if (!wholeHistory) {
|
|
264
|
+
await exportAccount(session.forAccount(session.accountId), base, source.identifier);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const current = session.forAccount(session.accountId);
|
|
268
|
+
const accounts = await attempt("accounts", () => current.json("/backend-api/accounts/check/v4-2023-04-27"));
|
|
269
|
+
const accountIds = new Set([session.accountId]);
|
|
270
|
+
if (accounts !== undefined) {
|
|
271
|
+
await json(`${base}/accounts.json`, accounts);
|
|
272
|
+
await attempt("account listing", async () => {
|
|
273
|
+
for (const value of Object.values(object(object(accounts)["accounts"]))) {
|
|
274
|
+
const entry = object(value);
|
|
275
|
+
const account = object(entry["account"]);
|
|
276
|
+
const id = text(account["account_id"]);
|
|
277
|
+
if (id === undefined || accountIds.has(id)) continue;
|
|
278
|
+
if (entry["can_access_with_session"] === false || account["is_deactivated"] === true) skipped.push({ type: "account", id, reason: "Not accessible with the current session or deactivated" });
|
|
279
|
+
else accountIds.add(id);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
for (const id of accountIds) await exportAccount(session.forAccount(id), `${base}/accounts/${segment(id)}`);
|
|
284
|
+
};
|
|
285
|
+
try {
|
|
286
|
+
await exportAll();
|
|
287
|
+
} catch (error) {
|
|
288
|
+
if (!(error instanceof ChatgptCooldownError)) throw error;
|
|
289
|
+
errors.push({ resource: error.cooldown.endpoint, error: error.message, retry_at: error.cooldown.retry_at });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const status = errors.length === 0 ? "complete" : "partial";
|
|
293
|
+
const manifest = { status, source: url, started_at: started, finished_at: runtime.clock.now().toISOString(), records, files, errors, skipped, cooldowns };
|
|
294
|
+
await json(`${base}/manifest.json`, manifest);
|
|
295
|
+
const relative = (path: string) => path.slice(base.length + 1);
|
|
296
|
+
const lines = records.map((record) => `- ${record["type"]}: [${String(record["title"]).replace(/[\[\]\r\n]/g, " ")}](${relative(record["path"] as string)})`);
|
|
297
|
+
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`}`;
|
|
298
|
+
const path = `${base}/${wholeHistory ? "index" : "export"}.md`;
|
|
299
|
+
const retryAt = errors.map((error) => text(error["retry_at"])).filter((value) => value !== undefined).sort().at(-1);
|
|
300
|
+
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}.`}` }) };
|
|
301
|
+
}
|
|
@@ -13,6 +13,12 @@ export declare const gmailService: Readonly<{
|
|
|
13
13
|
markdown: string;
|
|
14
14
|
data: import("wire-core").JsonValue;
|
|
15
15
|
}>>;
|
|
16
|
+
download?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
|
+
[key: string]: import("wire-core").JsonValue;
|
|
18
|
+
service: string;
|
|
19
|
+
identifier: string;
|
|
20
|
+
type: import("wire-core").ResourceType;
|
|
21
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
16
22
|
synchronize?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
23
|
[key: string]: import("wire-core").JsonValue;
|
|
18
24
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../src/gmail.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AA4DrD,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../src/gmail.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AA4DrD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BvB,CAAC"}
|
|
@@ -14,6 +14,12 @@ export declare const gmailProvider: 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,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAExB,CAAC"}
|
|
@@ -13,6 +13,12 @@ export declare const googleDocsService: Readonly<{
|
|
|
13
13
|
markdown: string;
|
|
14
14
|
data: JsonValue;
|
|
15
15
|
}>>;
|
|
16
|
+
download?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
|
+
[key: string]: JsonValue;
|
|
18
|
+
service: string;
|
|
19
|
+
identifier: string;
|
|
20
|
+
type: import("wire-core").ResourceType;
|
|
21
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
16
22
|
synchronize?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
23
|
[key: string]: JsonValue;
|
|
18
24
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-docs.d.ts","sourceRoot":"","sources":["../src/google-docs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA+B,SAAS,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AA2yBrG,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"google-docs.d.ts","sourceRoot":"","sources":["../src/google-docs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA+B,SAAS,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AA2yBrG,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqB5B,CAAC"}
|
|
@@ -13,6 +13,12 @@ export declare const googleFormsService: Readonly<{
|
|
|
13
13
|
markdown: string;
|
|
14
14
|
data: JsonValue;
|
|
15
15
|
}>>;
|
|
16
|
+
download?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
|
+
[key: string]: JsonValue;
|
|
18
|
+
service: string;
|
|
19
|
+
identifier: string;
|
|
20
|
+
type: import("wire-core").ResourceType;
|
|
21
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
16
22
|
synchronize?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
23
|
[key: string]: JsonValue;
|
|
18
24
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-forms.d.ts","sourceRoot":"","sources":["../src/google-forms.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,SAAS,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAuKrG,eAAO,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"google-forms.d.ts","sourceRoot":"","sources":["../src/google-forms.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,SAAS,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAuKrG,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU7B,CAAC"}
|
|
@@ -15,6 +15,12 @@ export declare const googleDocsProvider: Readonly<{
|
|
|
15
15
|
markdown: string;
|
|
16
16
|
data: import("wire-core").JsonValue;
|
|
17
17
|
}>>;
|
|
18
|
+
download?(input: import("wire-core").RuntimeCapabilities, url: string, source: Readonly<{
|
|
19
|
+
[key: string]: import("wire-core").JsonValue;
|
|
20
|
+
service: string;
|
|
21
|
+
identifier: string;
|
|
22
|
+
type: import("wire-core").ResourceType;
|
|
23
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
18
24
|
synchronize?(input: import("wire-core").RuntimeCapabilities, url: string, source: Readonly<{
|
|
19
25
|
[key: string]: import("wire-core").JsonValue;
|
|
20
26
|
service: string;
|
|
@@ -40,6 +46,12 @@ export declare const googleDocsProvider: Readonly<{
|
|
|
40
46
|
markdown: string;
|
|
41
47
|
data: import("wire-core").JsonValue;
|
|
42
48
|
}>>;
|
|
49
|
+
download?(input: import("wire-core").RuntimeCapabilities, url: string, source: Readonly<{
|
|
50
|
+
[key: string]: import("wire-core").JsonValue;
|
|
51
|
+
service: string;
|
|
52
|
+
identifier: string;
|
|
53
|
+
type: import("wire-core").ResourceType;
|
|
54
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
43
55
|
synchronize?(input: import("wire-core").RuntimeCapabilities, url: string, source: Readonly<{
|
|
44
56
|
[key: string]: import("wire-core").JsonValue;
|
|
45
57
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,eAAO,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE7B,CAAC"}
|
|
@@ -16,6 +16,12 @@ export declare const notionProvider: Readonly<{
|
|
|
16
16
|
markdown: string;
|
|
17
17
|
data: import("wire-core").JsonValue;
|
|
18
18
|
}>>;
|
|
19
|
+
download?(input: import("wire-core").RuntimeCapabilities, url: string, source: Readonly<{
|
|
20
|
+
[key: string]: import("wire-core").JsonValue;
|
|
21
|
+
service: string;
|
|
22
|
+
identifier: string;
|
|
23
|
+
type: import("wire-core").ResourceType;
|
|
24
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
19
25
|
synchronize?(input: import("wire-core").RuntimeCapabilities, url: string, source: Readonly<{
|
|
20
26
|
[key: string]: import("wire-core").JsonValue;
|
|
21
27
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC3O,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACxI,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC3O,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACxI,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEzB,CAAC"}
|
|
@@ -13,6 +13,12 @@ export declare const notionService: Readonly<{
|
|
|
13
13
|
markdown: string;
|
|
14
14
|
data: import("wire-core").JsonValue;
|
|
15
15
|
}>>;
|
|
16
|
+
download?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
|
+
[key: string]: import("wire-core").JsonValue;
|
|
18
|
+
service: string;
|
|
19
|
+
identifier: string;
|
|
20
|
+
type: import("wire-core").ResourceType;
|
|
21
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
16
22
|
synchronize?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
23
|
[key: string]: import("wire-core").JsonValue;
|
|
18
24
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notion.d.ts","sourceRoot":"","sources":["../src/notion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAKrD,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"notion.d.ts","sourceRoot":"","sources":["../src/notion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAKrD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOxB,CAAC"}
|
|
@@ -14,6 +14,12 @@ export declare const slackProvider: 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,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAExB,CAAC"}
|
|
@@ -13,6 +13,12 @@ export declare const slackService: Readonly<{
|
|
|
13
13
|
markdown: string;
|
|
14
14
|
data: import("wire-core").JsonValue;
|
|
15
15
|
}>>;
|
|
16
|
+
download?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
|
+
[key: string]: import("wire-core").JsonValue;
|
|
18
|
+
service: string;
|
|
19
|
+
identifier: string;
|
|
20
|
+
type: import("wire-core").ResourceType;
|
|
21
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
16
22
|
synchronize?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
23
|
[key: string]: import("wire-core").JsonValue;
|
|
18
24
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../src/slack.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAgDrD,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../src/slack.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAgDrD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkEvB,CAAC"}
|
|
@@ -14,6 +14,12 @@ export declare const zoomProvider: 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,eAAe,CAAC;AAC/C,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEvB,CAAC"}
|
|
@@ -13,6 +13,12 @@ export declare const zoomHubService: Readonly<{
|
|
|
13
13
|
markdown: string;
|
|
14
14
|
data: import("wire-core").JsonValue;
|
|
15
15
|
}>>;
|
|
16
|
+
download?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
|
+
[key: string]: import("wire-core").JsonValue;
|
|
18
|
+
service: string;
|
|
19
|
+
identifier: string;
|
|
20
|
+
type: import("wire-core").ResourceType;
|
|
21
|
+
}>, write: import("wire-core").DownloadWriter): Promise<import("wire-core").DownloadedDocument | null>;
|
|
16
22
|
synchronize?(input: RuntimeCapabilities, url: string, source: Readonly<{
|
|
17
23
|
[key: string]: import("wire-core").JsonValue;
|
|
18
24
|
service: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zoom-hub.d.ts","sourceRoot":"","sources":["../src/zoom-hub.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAwJrD,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"zoom-hub.d.ts","sourceRoot":"","sources":["../src/zoom-hub.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAwJrD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmEzB,CAAC"}
|
|
@@ -46,11 +46,17 @@ export type FetchedDocument = Readonly<{
|
|
|
46
46
|
export type UploadedDocument = FetchedDocument & Readonly<{
|
|
47
47
|
url: string;
|
|
48
48
|
}>;
|
|
49
|
+
export type DownloadWriter = (path: string, contents: string | Uint8Array) => Promise<void>;
|
|
50
|
+
export type DownloadedDocument = FetchedDocument & Readonly<{
|
|
51
|
+
path: string;
|
|
52
|
+
error?: string;
|
|
53
|
+
}>;
|
|
49
54
|
export type Service<FetchInput = never> = Readonly<{
|
|
50
55
|
name: string;
|
|
51
56
|
matches(url: URL): boolean;
|
|
52
57
|
parse(url: URL): Source;
|
|
53
58
|
fetch(input: FetchInput, url: string, source: Source): Promise<FetchedDocument>;
|
|
59
|
+
download?(input: FetchInput, url: string, source: Source, write: DownloadWriter): Promise<DownloadedDocument | null>;
|
|
54
60
|
synchronize?(input: FetchInput, url: string, source: Source, base: JsonValue, markdown: string, markdownPath: string): Promise<FetchedDocument>;
|
|
55
61
|
upload?(input: FetchInput, markdown: string, markdownPath: string): Promise<UploadedDocument>;
|
|
56
62
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/core/model.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/core/model.ts"],"names":[],"mappings":"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"}
|