openmates 0.15.0-alpha.37 → 0.15.0-alpha.38
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/{chunk-AAMJQMNZ.js → chunk-N2TP5WZI.js} +274 -10
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -21788,6 +21788,243 @@ function redactUrl(rawUrl) {
|
|
|
21788
21788
|
return url.toString();
|
|
21789
21789
|
}
|
|
21790
21790
|
|
|
21791
|
+
// src/accountExportArchive.ts
|
|
21792
|
+
var ACCOUNT_EXPORT_FORBIDDEN_FIELD_NAMES = /* @__PURE__ */ new Set([
|
|
21793
|
+
"access_token",
|
|
21794
|
+
"api_key",
|
|
21795
|
+
"backup_code_hash",
|
|
21796
|
+
"encrypted_master_key",
|
|
21797
|
+
"lookup_hash",
|
|
21798
|
+
"password_hash",
|
|
21799
|
+
"private_key",
|
|
21800
|
+
"raw_key",
|
|
21801
|
+
"refresh_token",
|
|
21802
|
+
"share_key",
|
|
21803
|
+
"signing_secret",
|
|
21804
|
+
"token_hash",
|
|
21805
|
+
"totp_seed",
|
|
21806
|
+
"webhook_secret"
|
|
21807
|
+
]);
|
|
21808
|
+
var ACCOUNT_EXPORT_REDACTION_CATEGORIES = [
|
|
21809
|
+
"api_credentials",
|
|
21810
|
+
"authentication_tokens",
|
|
21811
|
+
"key_material",
|
|
21812
|
+
"password_and_recovery_hashes",
|
|
21813
|
+
"webhook_secrets"
|
|
21814
|
+
];
|
|
21815
|
+
var ACCOUNT_EXPORT_FORBIDDEN_VALUE_PATTERNS = [
|
|
21816
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
21817
|
+
/(?:^|[^a-z0-9])sk-(?:api|proj|live|test)[-_a-z0-9]{6,}/i,
|
|
21818
|
+
/#key=[A-Za-z0-9_-]{8,}/
|
|
21819
|
+
];
|
|
21820
|
+
async function writeAccountExportArchive(bundle, flags = {}) {
|
|
21821
|
+
const { mkdir: mkdir2, mkdtemp, rm, writeFile: writeFile2 } = await import("fs/promises");
|
|
21822
|
+
const { tmpdir: tmpdir2 } = await import("os");
|
|
21823
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
21824
|
+
const { join: join7, dirname: dirname6 } = await import("path");
|
|
21825
|
+
const exportId = safeArchiveSegment(String(bundle.export.export_id ?? `export-${Date.now()}`));
|
|
21826
|
+
const archiveFormat = flags.format === "directory" ? "directory" : "zip";
|
|
21827
|
+
const outputPath = typeof flags.output === "string" ? flags.output : join7(process.cwd(), archiveFormat === "zip" ? `openmates-account-export-${exportId}.zip` : `openmates-account-export-${exportId}`);
|
|
21828
|
+
const stagingDir = archiveFormat === "directory" ? outputPath : await mkdtemp(join7(tmpdir2(), `openmates-account-export-${exportId}-`));
|
|
21829
|
+
const writtenFiles = [];
|
|
21830
|
+
async function writeArchiveText(relativePath, content) {
|
|
21831
|
+
assertAccountExportTextSafe(content, relativePath);
|
|
21832
|
+
const fullPath = join7(stagingDir, relativePath);
|
|
21833
|
+
await mkdir2(dirname6(fullPath), { recursive: true });
|
|
21834
|
+
await writeFile2(fullPath, content, "utf-8");
|
|
21835
|
+
writtenFiles.push(relativePath);
|
|
21836
|
+
}
|
|
21837
|
+
await writeArchiveText("README.md", buildAccountExportReadme(bundle));
|
|
21838
|
+
await writeArchiveText("manifest.yml", serializeArchiveYaml(bundle.manifest));
|
|
21839
|
+
await writeArchiveText("manifest.json", `${JSON.stringify(bundle.manifest, null, 2)}
|
|
21840
|
+
`);
|
|
21841
|
+
await writeArchiveText("export-report.yml", serializeArchiveYaml(buildAccountExportReport(bundle)));
|
|
21842
|
+
const domainPayloads = collectAccountExportDomainPayloads(bundle.chunks);
|
|
21843
|
+
for (const [domain, payloads] of Object.entries(domainPayloads)) {
|
|
21844
|
+
const domainFile = payloads.length === 1 ? payloads[0] : { chunks: payloads };
|
|
21845
|
+
await writeArchiveText(`domains/${safeArchiveSegment(domain)}.json`, `${JSON.stringify(domainFile, null, 2)}
|
|
21846
|
+
`);
|
|
21847
|
+
}
|
|
21848
|
+
await writeAccountExportChatFiles(domainPayloads.chats ?? [], writeArchiveText);
|
|
21849
|
+
if (archiveFormat === "directory") return { output: outputPath, format: "directory", files: writtenFiles.length };
|
|
21850
|
+
await mkdir2(dirname6(outputPath), { recursive: true });
|
|
21851
|
+
try {
|
|
21852
|
+
execFileSync3("zip", ["-r", outputPath, "."], { cwd: stagingDir, stdio: "pipe" });
|
|
21853
|
+
return { output: outputPath, format: "zip", files: writtenFiles.length };
|
|
21854
|
+
} finally {
|
|
21855
|
+
await rm(stagingDir, { recursive: true, force: true });
|
|
21856
|
+
}
|
|
21857
|
+
}
|
|
21858
|
+
function assertAccountExportPayloadSafe(value, path = "$export") {
|
|
21859
|
+
if (value === null || value === void 0) return;
|
|
21860
|
+
if (typeof value === "string") {
|
|
21861
|
+
for (const pattern of ACCOUNT_EXPORT_FORBIDDEN_VALUE_PATTERNS) {
|
|
21862
|
+
if (pattern.test(value)) throw new Error(`Account export contains forbidden secret-like value at ${path}`);
|
|
21863
|
+
}
|
|
21864
|
+
return;
|
|
21865
|
+
}
|
|
21866
|
+
if (typeof value !== "object") return;
|
|
21867
|
+
if (Array.isArray(value)) {
|
|
21868
|
+
value.forEach((item, index) => assertAccountExportPayloadSafe(item, `${path}[${index}]`));
|
|
21869
|
+
return;
|
|
21870
|
+
}
|
|
21871
|
+
for (const [key, child] of Object.entries(value)) {
|
|
21872
|
+
const normalizedKey = key.toLowerCase();
|
|
21873
|
+
if (ACCOUNT_EXPORT_FORBIDDEN_FIELD_NAMES.has(normalizedKey)) {
|
|
21874
|
+
throw new Error(`Account export contains forbidden secret field '${key}' at ${path}`);
|
|
21875
|
+
}
|
|
21876
|
+
assertAccountExportPayloadSafe(child, `${path}.${key}`);
|
|
21877
|
+
}
|
|
21878
|
+
}
|
|
21879
|
+
function sanitizeAccountExportManifest(manifest) {
|
|
21880
|
+
const copy = JSON.parse(JSON.stringify(manifest));
|
|
21881
|
+
const report = copy.report;
|
|
21882
|
+
if (report && typeof report === "object" && !Array.isArray(report)) {
|
|
21883
|
+
const reportObject = report;
|
|
21884
|
+
if (Array.isArray(reportObject.redactions)) {
|
|
21885
|
+
reportObject.redactions = ACCOUNT_EXPORT_REDACTION_CATEGORIES;
|
|
21886
|
+
}
|
|
21887
|
+
}
|
|
21888
|
+
assertAccountExportPayloadSafe(copy, "$manifest");
|
|
21889
|
+
return copy;
|
|
21890
|
+
}
|
|
21891
|
+
function assertAccountExportTextSafe(content, relativePath) {
|
|
21892
|
+
for (const pattern of ACCOUNT_EXPORT_FORBIDDEN_VALUE_PATTERNS) {
|
|
21893
|
+
if (pattern.test(content)) throw new Error(`Account export file ${relativePath} contains forbidden secret-like content`);
|
|
21894
|
+
}
|
|
21895
|
+
for (const field of ACCOUNT_EXPORT_FORBIDDEN_FIELD_NAMES) {
|
|
21896
|
+
if (new RegExp(`"?${field}"?\\s*:`, "i").test(content)) {
|
|
21897
|
+
throw new Error(`Account export file ${relativePath} contains forbidden secret field '${field}'`);
|
|
21898
|
+
}
|
|
21899
|
+
}
|
|
21900
|
+
}
|
|
21901
|
+
function buildAccountExportReadme(bundle) {
|
|
21902
|
+
const selectedDomains = Array.isArray(bundle.manifest.selected_domains) ? bundle.manifest.selected_domains.map(String) : [];
|
|
21903
|
+
return [
|
|
21904
|
+
"# OpenMates Account Export",
|
|
21905
|
+
"",
|
|
21906
|
+
`Export ID: ${String(bundle.export.export_id ?? "unknown")}`,
|
|
21907
|
+
`Status: ${String(bundle.export.status ?? "unknown")}`,
|
|
21908
|
+
`Schema: ${String(bundle.manifest.schema_version ?? "account-export-v1")}`,
|
|
21909
|
+
`Exported at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
21910
|
+
"",
|
|
21911
|
+
"## Contents",
|
|
21912
|
+
"",
|
|
21913
|
+
"- `manifest.yml` records selected domains, filters, and domain status.",
|
|
21914
|
+
"- `export-report.yml` summarizes completion, failures, and redacted categories.",
|
|
21915
|
+
"- `domains/` contains one JSON file per exported domain.",
|
|
21916
|
+
"- `chats/` contains one Markdown and one YAML file per chat when chat rows include readable content.",
|
|
21917
|
+
"",
|
|
21918
|
+
"## Selected Domains",
|
|
21919
|
+
"",
|
|
21920
|
+
...selectedDomains.length > 0 ? selectedDomains.map((domain) => `- ${domain}`) : ["- none"],
|
|
21921
|
+
"",
|
|
21922
|
+
"Reusable credentials, token hashes, private keys, and raw secrets are intentionally excluded.",
|
|
21923
|
+
""
|
|
21924
|
+
].join("\n");
|
|
21925
|
+
}
|
|
21926
|
+
function buildAccountExportReport(bundle) {
|
|
21927
|
+
const report = bundle.manifest.report && typeof bundle.manifest.report === "object" && !Array.isArray(bundle.manifest.report) ? bundle.manifest.report : {};
|
|
21928
|
+
return {
|
|
21929
|
+
export_id: bundle.export.export_id ?? null,
|
|
21930
|
+
status: bundle.export.status ?? report.status ?? "unknown",
|
|
21931
|
+
selected_domains: Array.isArray(bundle.manifest.selected_domains) ? bundle.manifest.selected_domains : [],
|
|
21932
|
+
failures: Array.isArray(report.failures) ? report.failures : [],
|
|
21933
|
+
redacted_secret_categories: ACCOUNT_EXPORT_REDACTION_CATEGORIES,
|
|
21934
|
+
partial_requires_acceptance: Boolean(report.partial_requires_acceptance)
|
|
21935
|
+
};
|
|
21936
|
+
}
|
|
21937
|
+
function collectAccountExportDomainPayloads(chunks) {
|
|
21938
|
+
const grouped = {};
|
|
21939
|
+
for (const chunk of chunks) {
|
|
21940
|
+
const domain = safeArchiveSegment(String(chunk.domain ?? "unknown"));
|
|
21941
|
+
const payload = chunk.payload && typeof chunk.payload === "object" && !Array.isArray(chunk.payload) ? chunk.payload : { value: chunk.payload ?? null };
|
|
21942
|
+
grouped[domain] = grouped[domain] ?? [];
|
|
21943
|
+
grouped[domain].push({
|
|
21944
|
+
chunk_id: chunk.chunk_id ?? null,
|
|
21945
|
+
sequence: chunk.sequence ?? null,
|
|
21946
|
+
status: chunk.status ?? null,
|
|
21947
|
+
...payload
|
|
21948
|
+
});
|
|
21949
|
+
}
|
|
21950
|
+
return grouped;
|
|
21951
|
+
}
|
|
21952
|
+
async function writeAccountExportChatFiles(chatPayloads, writeArchiveText) {
|
|
21953
|
+
const chats = [];
|
|
21954
|
+
for (const payload of chatPayloads) {
|
|
21955
|
+
if (Array.isArray(payload.items)) {
|
|
21956
|
+
chats.push(...payload.items.filter((item) => item !== null && typeof item === "object" && !Array.isArray(item)));
|
|
21957
|
+
}
|
|
21958
|
+
}
|
|
21959
|
+
for (const [index, chat] of chats.entries()) {
|
|
21960
|
+
const chatId = safeArchiveSegment(String(chat.id ?? chat.chat_id ?? `chat-${index + 1}`));
|
|
21961
|
+
await writeArchiveText(`chats/${chatId}.yml`, serializeArchiveYaml({ chat, messages: Array.isArray(chat.messages) ? chat.messages : [] }));
|
|
21962
|
+
await writeArchiveText(`chats/${chatId}.md`, buildAccountExportChatMarkdown(chat));
|
|
21963
|
+
}
|
|
21964
|
+
}
|
|
21965
|
+
function buildAccountExportChatMarkdown(chat) {
|
|
21966
|
+
const title = String(chat.title ?? chat.name ?? chat.id ?? chat.chat_id ?? "Untitled Chat");
|
|
21967
|
+
const lines = [`# ${title}`, ""];
|
|
21968
|
+
if (typeof chat.summary === "string" && chat.summary.trim()) {
|
|
21969
|
+
lines.push("## Summary", "", chat.summary.trim(), "");
|
|
21970
|
+
}
|
|
21971
|
+
const messages = Array.isArray(chat.messages) ? chat.messages : [];
|
|
21972
|
+
if (messages.length > 0) {
|
|
21973
|
+
lines.push("## Messages", "");
|
|
21974
|
+
for (const message of messages) {
|
|
21975
|
+
if (!message || typeof message !== "object" || Array.isArray(message)) continue;
|
|
21976
|
+
const record = message;
|
|
21977
|
+
lines.push(`### ${String(record.role ?? record.sender ?? "message")}`, "", String(record.content ?? record.text ?? ""), "");
|
|
21978
|
+
}
|
|
21979
|
+
} else {
|
|
21980
|
+
lines.push("No readable message records were included in this export chunk.", "");
|
|
21981
|
+
}
|
|
21982
|
+
return `${lines.join("\n")}
|
|
21983
|
+
`;
|
|
21984
|
+
}
|
|
21985
|
+
function serializeArchiveYaml(data, indent = 0) {
|
|
21986
|
+
const pad2 = " ".repeat(indent);
|
|
21987
|
+
let out = "";
|
|
21988
|
+
for (const [key, val] of Object.entries(data)) {
|
|
21989
|
+
if (val === null || val === void 0) {
|
|
21990
|
+
out += `${pad2}${key}: null
|
|
21991
|
+
`;
|
|
21992
|
+
} else if (typeof val === "boolean" || typeof val === "number") {
|
|
21993
|
+
out += `${pad2}${key}: ${val}
|
|
21994
|
+
`;
|
|
21995
|
+
} else if (typeof val === "string") {
|
|
21996
|
+
out += val.includes("\n") ? `${pad2}${key}: |
|
|
21997
|
+
${val.split("\n").map((line) => `${pad2} ${line}`).join("\n")}
|
|
21998
|
+
` : `${pad2}${key}: ${quoteYamlString(val)}
|
|
21999
|
+
`;
|
|
22000
|
+
} else if (Array.isArray(val)) {
|
|
22001
|
+
out += `${pad2}${key}:
|
|
22002
|
+
`;
|
|
22003
|
+
for (const item of val) {
|
|
22004
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
22005
|
+
out += `${pad2}-
|
|
22006
|
+
${serializeArchiveYaml(item, indent + 2)}`;
|
|
22007
|
+
} else {
|
|
22008
|
+
out += `${pad2}- ${typeof item === "string" ? quoteYamlString(item) : String(item)}
|
|
22009
|
+
`;
|
|
22010
|
+
}
|
|
22011
|
+
}
|
|
22012
|
+
} else if (typeof val === "object") {
|
|
22013
|
+
out += `${pad2}${key}:
|
|
22014
|
+
${serializeArchiveYaml(val, indent + 1)}`;
|
|
22015
|
+
}
|
|
22016
|
+
}
|
|
22017
|
+
return out;
|
|
22018
|
+
}
|
|
22019
|
+
function quoteYamlString(value) {
|
|
22020
|
+
const needsQuote = value.includes(":") || value.includes("#") || value.startsWith("{") || value.startsWith("[") || value === "" || ["true", "false", "null"].includes(value);
|
|
22021
|
+
return needsQuote ? `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"` : value;
|
|
22022
|
+
}
|
|
22023
|
+
function safeArchiveSegment(value) {
|
|
22024
|
+
const cleaned = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
22025
|
+
return cleaned || "unknown";
|
|
22026
|
+
}
|
|
22027
|
+
|
|
21791
22028
|
// ../ui/src/demo_chats/data/example_chats/gigantic-airplanes.ts
|
|
21792
22029
|
var giganticAirplanesChat = {
|
|
21793
22030
|
chat_id: "example-gigantic-airplanes",
|
|
@@ -40085,6 +40322,15 @@ Only output the final Markdown table. Do NOT include explanations, notes, or any
|
|
|
40085
40322
|
new_chat: {
|
|
40086
40323
|
text: "New chat"
|
|
40087
40324
|
},
|
|
40325
|
+
ideabucket_badge: {
|
|
40326
|
+
text: "IdeaBucket"
|
|
40327
|
+
},
|
|
40328
|
+
ideabucket_draft: {
|
|
40329
|
+
text: "IdeaBucket draft"
|
|
40330
|
+
},
|
|
40331
|
+
ideabucket_input_pill: {
|
|
40332
|
+
text: "IdeaBucket for today"
|
|
40333
|
+
},
|
|
40088
40334
|
request_feature: {
|
|
40089
40335
|
text: "Request feature"
|
|
40090
40336
|
},
|
|
@@ -62962,26 +63208,44 @@ async function runAccountExport(client, flags) {
|
|
|
62962
63208
|
client.getAccountExportManifest(exportId),
|
|
62963
63209
|
client.listAccountExportChunks(exportId)
|
|
62964
63210
|
]);
|
|
62965
|
-
const
|
|
62966
|
-
|
|
63211
|
+
const downloadedChunks = [];
|
|
63212
|
+
try {
|
|
63213
|
+
for (const chunk of chunks.chunks) {
|
|
63214
|
+
const chunkId = String(chunk.chunk_id ?? "");
|
|
63215
|
+
const downloaded = chunkId ? await client.getAccountExportChunk(exportId, chunkId) : chunk;
|
|
63216
|
+
assertAccountExportPayloadSafe(downloaded);
|
|
63217
|
+
downloadedChunks.push(downloaded);
|
|
63218
|
+
}
|
|
63219
|
+
} catch (error) {
|
|
63220
|
+
await client.cancelAccountExport(exportId).catch(() => void 0);
|
|
63221
|
+
throw error;
|
|
63222
|
+
}
|
|
63223
|
+
let completed = await client.completeAccountExport(exportId);
|
|
63224
|
+
const completedStatus = String(completed.export.status ?? "");
|
|
63225
|
+
if (completedStatus === "partial") {
|
|
63226
|
+
if (flags["accept-partial"] !== true) {
|
|
63227
|
+
throw new Error(`Account export ${exportId} is partial. Re-run with --accept-partial to accept it, or inspect/cancel the job first.`);
|
|
63228
|
+
}
|
|
63229
|
+
completed = await client.acceptPartialAccountExport(exportId);
|
|
63230
|
+
}
|
|
63231
|
+
const bundle = {
|
|
62967
63232
|
export: completed.export,
|
|
62968
|
-
manifest: manifest.manifest,
|
|
62969
|
-
chunks:
|
|
63233
|
+
manifest: sanitizeAccountExportManifest(manifest.manifest),
|
|
63234
|
+
chunks: downloadedChunks
|
|
62970
63235
|
};
|
|
63236
|
+
const archive = await writeAccountExportArchive(bundle, flags);
|
|
63237
|
+
return { ...bundle, archive };
|
|
62971
63238
|
}
|
|
62972
63239
|
function printAccountExportBundle(bundle, flags) {
|
|
62973
|
-
if (typeof flags.output === "string") {
|
|
62974
|
-
writeFileSync7(flags.output, `${JSON.stringify(bundle, null, 2)}
|
|
62975
|
-
`, "utf-8");
|
|
62976
|
-
}
|
|
62977
63240
|
if (flags.json === true) {
|
|
62978
|
-
printJson2(
|
|
63241
|
+
printJson2(bundle);
|
|
62979
63242
|
return;
|
|
62980
63243
|
}
|
|
62981
63244
|
const exportRecord = bundle.export && typeof bundle.export === "object" ? bundle.export : {};
|
|
63245
|
+
const archive = bundle.archive && typeof bundle.archive === "object" ? bundle.archive : {};
|
|
62982
63246
|
process.stdout.write(`Account export ${String(exportRecord.export_id ?? "")} ${String(exportRecord.status ?? "unknown")}
|
|
62983
63247
|
`);
|
|
62984
|
-
if (typeof
|
|
63248
|
+
if (typeof archive.output === "string") process.stdout.write(`Wrote ${archive.output}
|
|
62985
63249
|
`);
|
|
62986
63250
|
}
|
|
62987
63251
|
function printApiKeyList(result, flags) {
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED