busa-cli 0.10.2 → 0.10.3
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-DGRADZF2.js → chunk-MLTXEKPL.js} +34 -22
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
|
@@ -1556,6 +1556,8 @@ import {
|
|
|
1556
1556
|
cloudContract,
|
|
1557
1557
|
createBusabaseClient,
|
|
1558
1558
|
DEFAULT_BASE_URL as DEFAULT_BASE_URL2,
|
|
1559
|
+
getRecordByField,
|
|
1560
|
+
grepAssets,
|
|
1559
1561
|
normalizeBaseUrl as normalizeBaseUrl2
|
|
1560
1562
|
} from "busabase-sdk";
|
|
1561
1563
|
import {
|
|
@@ -2486,15 +2488,15 @@ var reportProgress = (message) => {
|
|
|
2486
2488
|
};
|
|
2487
2489
|
var STATE_ONLY_BACKUP_MESSAGE = [
|
|
2488
2490
|
"--state-only backup is not implemented, and will not be \u2014 it is superseded by",
|
|
2489
|
-
"`busabase-cli
|
|
2491
|
+
"`busabase-cli export`, which writes the same state-level content as a readable,",
|
|
2490
2492
|
"diffable directory you can push to GitHub:",
|
|
2491
2493
|
"",
|
|
2492
|
-
" busabase-cli
|
|
2494
|
+
" busabase-cli export <node-slug> -o ./my-package",
|
|
2493
2495
|
" busabase-cli install https://github.com/<you>/<repo>",
|
|
2494
2496
|
"",
|
|
2495
2497
|
"`busabase-cli backup` stays the full-fidelity backup path (raw rows, original ids,",
|
|
2496
2498
|
"history) \u2014 run it without --state-only. The two formats are deliberately separate:",
|
|
2497
|
-
"a backup carries the audit events, comments, reviews and ACLs that
|
|
2499
|
+
"a backup carries the audit events, comments, reviews and ACLs that an exported",
|
|
2498
2500
|
"package must never leak."
|
|
2499
2501
|
].join("\n");
|
|
2500
2502
|
var STATE_ONLY_RESTORE_MESSAGE = [
|
|
@@ -4009,7 +4011,7 @@ var PACKAGE_COMPUTED_FIELD_TYPES = [
|
|
|
4009
4011
|
"auto_number",
|
|
4010
4012
|
"formula",
|
|
4011
4013
|
// `lookup` is derived from OTHER records and resolved at read time, so it
|
|
4012
|
-
// shows up in `headCommit.fields` like any other value — but
|
|
4014
|
+
// shows up in `headCommit.fields` like any other value — but exporting it
|
|
4013
4015
|
// would ship derived data as if it were authored, and install would strip it
|
|
4014
4016
|
// server-side anyway.
|
|
4015
4017
|
"lookup",
|
|
@@ -4753,7 +4755,7 @@ var collectNode = async (client, source, options) => {
|
|
|
4753
4755
|
slug: source.slug,
|
|
4754
4756
|
name: source.name,
|
|
4755
4757
|
description: source.description ?? "",
|
|
4756
|
-
// `
|
|
4758
|
+
// `export` always writes position, so round trips preserve sibling order exactly.
|
|
4757
4759
|
position: source.position
|
|
4758
4760
|
};
|
|
4759
4761
|
switch (source.type) {
|
|
@@ -4785,7 +4787,7 @@ var collectBase = async (client, source, common, options) => {
|
|
|
4785
4787
|
const base = await client.bases.get({ baseId });
|
|
4786
4788
|
if (!base) {
|
|
4787
4789
|
throw new Error(
|
|
4788
|
-
`Base node "${source.slug}" has no Base behind it (looked up ${baseId}). The space may be mid-migration; re-run
|
|
4790
|
+
`Base node "${source.slug}" has no Base behind it (looked up ${baseId}). The space may be mid-migration; re-run export.`
|
|
4789
4791
|
);
|
|
4790
4792
|
}
|
|
4791
4793
|
const views = await client.bases.listViews({ baseId: base.id });
|
|
@@ -4836,7 +4838,7 @@ var toPackageField = (field, context) => {
|
|
|
4836
4838
|
const targetSlug = context.baseSlugById.get(targetBaseId);
|
|
4837
4839
|
if (!targetSlug) {
|
|
4838
4840
|
throw new Error(
|
|
4839
|
-
`Field "${context.baseSlug}.${field.slug}" relates to a Base that no longer exists (${targetBaseId}). Fix the field before
|
|
4841
|
+
`Field "${context.baseSlug}.${field.slug}" relates to a Base that no longer exists (${targetBaseId}). Fix the field before exporting.`
|
|
4840
4842
|
);
|
|
4841
4843
|
}
|
|
4842
4844
|
options.targetBaseSlug = targetSlug;
|
|
@@ -4986,7 +4988,7 @@ var assertSelfContained = (tree, options) => {
|
|
|
4986
4988
|
if (field.type !== "relation" || !targetBaseSlug) continue;
|
|
4987
4989
|
if (!packagedBaseSlugs.has(targetBaseSlug)) {
|
|
4988
4990
|
throw new Error(
|
|
4989
|
-
`Field "${node.slug}.${field.slug}" relates to Base "${targetBaseSlug}", which is outside the subtree being
|
|
4991
|
+
`Field "${node.slug}.${field.slug}" relates to Base "${targetBaseSlug}", which is outside the subtree being exported. A package must be self-contained \u2014 export a subtree that includes both Bases, or remove the field.`
|
|
4990
4992
|
);
|
|
4991
4993
|
}
|
|
4992
4994
|
}
|
|
@@ -5003,7 +5005,7 @@ var assertSelfContained = (tree, options) => {
|
|
|
5003
5005
|
}
|
|
5004
5006
|
if (dangling > 0) {
|
|
5005
5007
|
options.warn(
|
|
5006
|
-
`Base "${node.slug}" has ${dangling} relation value(s) pointing at records outside the
|
|
5008
|
+
`Base "${node.slug}" has ${dangling} relation value(s) pointing at records outside the exported subtree \u2014 they were dropped.`
|
|
5007
5009
|
);
|
|
5008
5010
|
}
|
|
5009
5011
|
}
|
|
@@ -5913,7 +5915,7 @@ var renderInstallReport = (targetFolderSlug, result) => {
|
|
|
5913
5915
|
}
|
|
5914
5916
|
return lines.join("\n");
|
|
5915
5917
|
};
|
|
5916
|
-
var
|
|
5918
|
+
var runExport = async (client, nodeSlugOrId, options) => {
|
|
5917
5919
|
const nodes = await client.nodes.list();
|
|
5918
5920
|
const source = findSourceNode(nodes, nodeSlugOrId);
|
|
5919
5921
|
const warnings = [];
|
|
@@ -5930,14 +5932,14 @@ var runPublish = async (client, nodeSlugOrId, options) => {
|
|
|
5930
5932
|
}
|
|
5931
5933
|
if (options.json) {
|
|
5932
5934
|
return {
|
|
5933
|
-
|
|
5935
|
+
exported: !options.dryRun,
|
|
5934
5936
|
package: manifest.name,
|
|
5935
5937
|
outDir: options.outDir,
|
|
5936
5938
|
files: [...files.keys()].sort(),
|
|
5937
5939
|
warnings
|
|
5938
5940
|
};
|
|
5939
5941
|
}
|
|
5940
|
-
return
|
|
5942
|
+
return renderExportReport(options, manifest, files, warnings);
|
|
5941
5943
|
};
|
|
5942
5944
|
var resolveManifest = async (outDir, nameFlag, nodeName, nodeSlug) => {
|
|
5943
5945
|
const existing = await readExistingManifest(outDir);
|
|
@@ -5959,7 +5961,7 @@ var readExistingManifest = async (outDir) => {
|
|
|
5959
5961
|
return void 0;
|
|
5960
5962
|
}
|
|
5961
5963
|
};
|
|
5962
|
-
var
|
|
5964
|
+
var renderExportReport = (options, manifest, files, warnings) => {
|
|
5963
5965
|
const lines = [];
|
|
5964
5966
|
lines.push(
|
|
5965
5967
|
options.dryRun ? `Dry run \u2014 would write ${files.size} file(s) to ${options.outDir}:` : `Wrote ${files.size} file(s) to ${options.outDir}:`
|
|
@@ -5972,7 +5974,7 @@ var renderPublishReport = (options, manifest, files, warnings) => {
|
|
|
5972
5974
|
}
|
|
5973
5975
|
if (!options.dryRun) {
|
|
5974
5976
|
lines.push("");
|
|
5975
|
-
lines.push("Now
|
|
5977
|
+
lines.push("Now push it to GitHub:");
|
|
5976
5978
|
lines.push(` cd ${options.outDir}`);
|
|
5977
5979
|
lines.push(
|
|
5978
5980
|
' git init && git add . && git commit -m "Add ${name} package"'.replace(
|
|
@@ -6893,6 +6895,16 @@ Examples:
|
|
|
6893
6895
|
addGlobalFlags(records.command("get")).description("Get one record").requiredOption("--record-id <id>", "record id").action(
|
|
6894
6896
|
runAction(state, (client, opts) => client.records.get({ recordId: opts.recordId }))
|
|
6895
6897
|
);
|
|
6898
|
+
addGlobalFlags(records.command("get-by-field")).description("Get one record by an exact field value").requiredOption("--base-id <id>", "Base id").requiredOption("--field-slug <slug>", "field slug").requiredOption("--value-text <value>", "exact field value").action(
|
|
6899
|
+
runAction(
|
|
6900
|
+
state,
|
|
6901
|
+
(client, opts) => getRecordByField(client, {
|
|
6902
|
+
baseId: opts.baseId,
|
|
6903
|
+
fieldSlug: opts.fieldSlug,
|
|
6904
|
+
valueText: opts.valueText
|
|
6905
|
+
})
|
|
6906
|
+
)
|
|
6907
|
+
);
|
|
6896
6908
|
addGlobalFlags(records.command("change-requests")).description("Change Requests for a record").requiredOption("--record-id <id>", "record id").action(
|
|
6897
6909
|
runAction(
|
|
6898
6910
|
state,
|
|
@@ -6981,7 +6993,7 @@ Examples:
|
|
|
6981
6993
|
addGlobalFlags(assetsCommand.command("grep")).description("Search every text-bearing asset in scope").requiredOption("--pattern <regex>", "literal or regex pattern").option("--flags <flags>", 'RegExp flags, e.g. "i" for case-insensitive').option("--asset-ids <ids...>", "scope: specific asset ids").option("--drive-path <path>", "scope: Drive/Skill mounted path prefix").option("--mime-types <types...>", "scope: MIME types").option("--max-matches <n>", "max matches (default 100, cap 1000)", parsePositiveInt).option("--context-lines <n>", "lines of before/after context (default 0, cap 10)", parseNum).action(
|
|
6982
6994
|
runAction(
|
|
6983
6995
|
state,
|
|
6984
|
-
(client, opts) => client
|
|
6996
|
+
(client, opts) => grepAssets(client, {
|
|
6985
6997
|
pattern: opts.pattern,
|
|
6986
6998
|
flags: opts.flags,
|
|
6987
6999
|
scope: opts.assetIds || opts.drivePath || opts.mimeTypes ? {
|
|
@@ -7043,19 +7055,19 @@ field with nothing linked yet does not trigger this.`
|
|
|
7043
7055
|
})
|
|
7044
7056
|
)
|
|
7045
7057
|
);
|
|
7046
|
-
addGlobalFlags(program.command("
|
|
7058
|
+
addGlobalFlags(program.command("export")).description("Export a node subtree as a Busabase package directory you can push to GitHub").argument("<node-slug-or-id>", "the folder/node to export").requiredOption("-o, --out-dir <dir>", "output directory for the package").option("--name <name>", "package name (default: reuse busabase.json, else the node slug)").option("--dry-run", "list the files that would be written and write nothing").addHelpText(
|
|
7047
7059
|
"after",
|
|
7048
7060
|
`
|
|
7049
|
-
Output is deterministic:
|
|
7061
|
+
Output is deterministic: exporting twice from an unchanged space produces
|
|
7050
7062
|
byte-identical files, so a GitHub diff shows exactly what changed.
|
|
7051
7063
|
|
|
7052
7064
|
Examples:
|
|
7053
|
-
busabase-cli
|
|
7054
|
-
busabase-cli
|
|
7065
|
+
busabase-cli export support-kb -o ./support-kb-template
|
|
7066
|
+
busabase-cli export support-kb -o ./support-kb-template --name "Support KB" --dry-run`
|
|
7055
7067
|
).action(
|
|
7056
7068
|
runArgAction(
|
|
7057
7069
|
state,
|
|
7058
|
-
(nodeSlugOrId, client, opts, config) =>
|
|
7070
|
+
(nodeSlugOrId, client, opts, config) => runExport(client, nodeSlugOrId, {
|
|
7059
7071
|
outDir: opts.outDir,
|
|
7060
7072
|
name: opts.name,
|
|
7061
7073
|
dryRun: Boolean(opts.dryRun),
|
|
@@ -7067,7 +7079,7 @@ Examples:
|
|
|
7067
7079
|
addGlobalFlags(program.command("backup")).description("Back up the active space to a full-fidelity .bbdump archive").option("-o, --out-file <file>", "output archive path", "space.bbdump").option(
|
|
7068
7080
|
"--no-history",
|
|
7069
7081
|
"full-fidelity rows, but omit the history tables (commits, change requests, operations, comments, reviews, audit events)"
|
|
7070
|
-
).option("--state-only", "superseded by `busabase-cli
|
|
7082
|
+
).option("--state-only", "superseded by `busabase-cli export` \u2014 see the error text").addHelpText(
|
|
7071
7083
|
"after",
|
|
7072
7084
|
`
|
|
7073
7085
|
A backup is full fidelity: raw rows with their original ids, every doc body, and
|
|
@@ -7079,7 +7091,7 @@ Examples:
|
|
|
7079
7091
|
busabase-cli backup -o ./backups/acme-2026-07-19.bbdump
|
|
7080
7092
|
busabase-cli backup --no-history # smaller: current state only
|
|
7081
7093
|
|
|
7082
|
-
To hand content to someone else rather than back it up, use \`busabase-cli
|
|
7094
|
+
To hand content to someone else rather than back it up, use \`busabase-cli export\`,
|
|
7083
7095
|
which writes a readable, diffable package directory you can push to GitHub.`
|
|
7084
7096
|
).action(
|
|
7085
7097
|
runAction(
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "busa-cli",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Command-line client for the Busabase OpenAPI REST API. Talks to a local or remote `busabase server`. Short-name alias for busabase-cli.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/busabase/busabase/tree/main/apps/busabase-cli",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@zip.js/zip.js": "^2.8.20",
|
|
35
35
|
"busabase-package": "workspace:*",
|
|
36
|
-
"busabase-sdk": "0.10.
|
|
36
|
+
"busabase-sdk": "0.10.3",
|
|
37
37
|
"commander": "^14.0.0",
|
|
38
38
|
"tar-stream": "^3.1.7",
|
|
39
39
|
"yaml": "^2.9.0",
|