@botlr/cli 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +71 -11
- package/dist/cli.js +274 -21
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +143 -8
- package/dist/index.js +182 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SectionSourceScope, SectionManifest, SectionSourceFileInput, SectionSourceScopeSummary, SectionSourceSummary, SectionFieldSchema, SectionSchemaField, SectionFormBuilderNode, BotlrClient } from '@botlr/sdk';
|
|
1
|
+
import { SectionSourceScope, SectionManifest, SectionSourceFileInput, SectionSourceScopeSummary, SectionSourceSummary, SectionFieldSchema, SectionSchemaField, SectionFormBuilderNode, SectionSchema, SectionSchemaFormat, BotlrClient, SectionSchemaPushMode } from '@botlr/sdk';
|
|
2
2
|
|
|
3
3
|
declare const CONFIG_FILE = "botlr.config.json";
|
|
4
4
|
declare const DEFAULT_FRAMEWORK = "react-next";
|
|
@@ -308,17 +308,75 @@ interface SchemaDrift {
|
|
|
308
308
|
/** Props the dashboard defines that the code does not list. */
|
|
309
309
|
missingInCode: string[];
|
|
310
310
|
}
|
|
311
|
-
/** The manifest's `schema` when it is a
|
|
312
|
-
declare function manifestSchema(manifest: SectionManifest):
|
|
311
|
+
/** The manifest's `schema` when it is a schema object in either format, else null. */
|
|
312
|
+
declare function manifestSchema(manifest: SectionManifest): SectionSchema | null;
|
|
313
313
|
/**
|
|
314
|
-
* Key difference between the code's schema
|
|
315
|
-
*
|
|
316
|
-
* the keys match.
|
|
314
|
+
* Key difference between the code's schema and the definition's schema
|
|
315
|
+
* (either format on either side; FormBuilder schemas contribute their node
|
|
316
|
+
* names). Null when the manifest has no schema object or the keys match.
|
|
317
317
|
*/
|
|
318
318
|
declare function compareSchemas(manifest: SectionManifest, definitionSchema: unknown): SchemaDrift | null;
|
|
319
|
-
/** The warning text for a drift, one line per direction,
|
|
319
|
+
/** The warning text for a drift, one line per direction, naming the two commands that resolve it. */
|
|
320
320
|
declare function formatDriftWarning(name: string, drift: SchemaDrift): string;
|
|
321
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Field-key diff between two props schemas, for `botlr schema push` to show
|
|
324
|
+
* before it replaces the dashboard's schema with the code's. Field DSL keys
|
|
325
|
+
* are the object's keys; FormBuilder schemas contribute their node names
|
|
326
|
+
* (groups flattened), so the two formats can be compared with each other.
|
|
327
|
+
*/
|
|
328
|
+
|
|
329
|
+
interface SchemaKeyDiff {
|
|
330
|
+
/** Keys the new schema has that the current one lacks. */
|
|
331
|
+
added: string[];
|
|
332
|
+
/** Keys the current schema has that the new one lacks. */
|
|
333
|
+
removed: string[];
|
|
334
|
+
/** Keys both have. */
|
|
335
|
+
kept: string[];
|
|
336
|
+
}
|
|
337
|
+
/** The field keys of a schema in either format, in schema order and without duplicates. */
|
|
338
|
+
declare function schemaKeys(schema: unknown): string[];
|
|
339
|
+
/** Keys added, removed and kept going from `current` to `next`; each list sorted. */
|
|
340
|
+
declare function diffSchemaKeys(current: unknown, next: unknown): SchemaKeyDiff;
|
|
341
|
+
interface SchemaPushPreview {
|
|
342
|
+
name: string;
|
|
343
|
+
/** The dashboard's current schema. */
|
|
344
|
+
current: unknown;
|
|
345
|
+
/** Its format as the server reports it, else as detected. */
|
|
346
|
+
currentFormat: SectionSchemaFormat | null;
|
|
347
|
+
/** The manifest's schema, about to replace it. */
|
|
348
|
+
next: unknown;
|
|
349
|
+
nextFormat: SectionSchemaFormat | null;
|
|
350
|
+
diff: SchemaKeyDiff;
|
|
351
|
+
/** Whether `--force` was given. */
|
|
352
|
+
force: boolean;
|
|
353
|
+
/** What the server is expected to do with this push. */
|
|
354
|
+
expected: ExpectedPushMode;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* - `replaced`: same format, or `--force`
|
|
358
|
+
* - `merged`: field-DSL fields at a FormBuilder schema; the server adds nodes and keeps the rest
|
|
359
|
+
* - `conflict`: a FormBuilder schema at a field-DSL one; the server answers 409 without `--force`
|
|
360
|
+
*/
|
|
361
|
+
type ExpectedPushMode = "replaced" | "merged" | "conflict";
|
|
362
|
+
/** True when both formats are known and differ. */
|
|
363
|
+
declare function formatsDiffer(preview: Pick<SchemaPushPreview, "currentFormat" | "nextFormat">): boolean;
|
|
364
|
+
declare function expectedPushMode(preview: Pick<SchemaPushPreview, "currentFormat" | "nextFormat" | "force">): ExpectedPushMode;
|
|
365
|
+
/** The preview for a push, with formats detected from the schemas unless given. */
|
|
366
|
+
declare function previewSchemaPush(name: string, current: unknown, next: unknown, options?: {
|
|
367
|
+
currentFormat?: SectionSchemaFormat | null;
|
|
368
|
+
nextFormat?: SectionSchemaFormat | null;
|
|
369
|
+
force?: boolean;
|
|
370
|
+
}): SchemaPushPreview;
|
|
371
|
+
/**
|
|
372
|
+
* The diff as the CLI prints it: one header line with both formats and
|
|
373
|
+
* field counts (and, for a merge, what the server will do), then one line
|
|
374
|
+
* per non-empty direction. The `kept` line is always printed, with "none"
|
|
375
|
+
* when nothing survives. In a merge the dashboard's extra nodes are kept,
|
|
376
|
+
* so that line says so instead of "removed".
|
|
377
|
+
*/
|
|
378
|
+
declare function formatSchemaDiff(preview: SchemaPushPreview): string;
|
|
379
|
+
|
|
322
380
|
/** A client from the resolved config. `needPersonalToken` makes a missing `BOTLR_PAT` an error up front. */
|
|
323
381
|
declare function clientFor(config: ResolvedConfig, options?: {
|
|
324
382
|
needPersonalToken?: boolean;
|
|
@@ -411,4 +469,81 @@ interface InitResult {
|
|
|
411
469
|
*/
|
|
412
470
|
declare function initSections(config: ResolvedConfig, options?: InitOptions): Promise<InitResult[]>;
|
|
413
471
|
|
|
414
|
-
|
|
472
|
+
/**
|
|
473
|
+
* `botlr schema pull` and `botlr schema push`: the explicit way to resolve
|
|
474
|
+
* drift between the manifest's `schema` (what the code expects) and the
|
|
475
|
+
* dashboard's definition schema. A source push never touches the schema;
|
|
476
|
+
* these two commands do, in the direction the user picks.
|
|
477
|
+
*/
|
|
478
|
+
|
|
479
|
+
interface SchemaPullOptions {
|
|
480
|
+
/** Section names; empty with `all: true` means every manifest in the sections directory. */
|
|
481
|
+
names: string[];
|
|
482
|
+
all?: boolean;
|
|
483
|
+
/** Do not write `<name>.props.ts`; also off when the config says `types: false`. */
|
|
484
|
+
noTypes?: boolean;
|
|
485
|
+
}
|
|
486
|
+
interface SchemaPullResult {
|
|
487
|
+
name: string;
|
|
488
|
+
/** Whether `<name>.botlr.json` changed; false when its `schema` already equalled the dashboard's. */
|
|
489
|
+
changed: boolean;
|
|
490
|
+
/** The manifest file. */
|
|
491
|
+
file: string;
|
|
492
|
+
format?: string;
|
|
493
|
+
/** What happened to `<name>.props.ts`; absent when types are off or the pull failed. */
|
|
494
|
+
types?: PropsTypesUpdate;
|
|
495
|
+
/** Why nothing was written: no manifest, or no section type of that name in the app. */
|
|
496
|
+
error?: string;
|
|
497
|
+
}
|
|
498
|
+
/** Copy the dashboard's schema into each manifest's `schema`, then regenerate the prop types. */
|
|
499
|
+
declare function pullSchemas(config: ResolvedConfig, options: SchemaPullOptions): Promise<SchemaPullResult[]>;
|
|
500
|
+
interface SchemaPushOptions {
|
|
501
|
+
name: string;
|
|
502
|
+
/** Replace the schema outright whatever the formats, instead of merging into a FormBuilder schema. */
|
|
503
|
+
force?: boolean;
|
|
504
|
+
/**
|
|
505
|
+
* Asked once with the preview before anything is sent; return false to
|
|
506
|
+
* stop. Omit to push without asking (`--yes`).
|
|
507
|
+
*/
|
|
508
|
+
confirm?: (preview: SchemaPushPreview) => Promise<boolean> | boolean;
|
|
509
|
+
/** Do not write `<name>.props.ts` afterwards; also off when the config says `types: false`. */
|
|
510
|
+
noTypes?: boolean;
|
|
511
|
+
}
|
|
512
|
+
interface SchemaPushResult {
|
|
513
|
+
name: string;
|
|
514
|
+
preview: SchemaPushPreview;
|
|
515
|
+
/** False when `confirm` said no; nothing was sent. */
|
|
516
|
+
pushed: boolean;
|
|
517
|
+
/** From the server: false when nothing had to change. */
|
|
518
|
+
changed?: boolean;
|
|
519
|
+
previousFormat?: string;
|
|
520
|
+
format?: string;
|
|
521
|
+
/** What the server did: replaced the schema, or merged the code's fields into a FormBuilder schema. */
|
|
522
|
+
mode?: SectionSchemaPushMode;
|
|
523
|
+
/** Field names that became new nodes (`merged`). */
|
|
524
|
+
added?: string[];
|
|
525
|
+
/** Node names only the dashboard defines, kept (`merged`). */
|
|
526
|
+
dashboardOnly?: string[];
|
|
527
|
+
types?: PropsTypesUpdate;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* A FormBuilder schema pushed at a field-DSL definition without `--force`:
|
|
531
|
+
* raised before anything is sent when the formats are known (then `preview`
|
|
532
|
+
* is set), or from the server's 409.
|
|
533
|
+
*/
|
|
534
|
+
declare class SchemaFormatConflict extends Error {
|
|
535
|
+
readonly sectionName: string;
|
|
536
|
+
readonly currentFormat: string;
|
|
537
|
+
readonly newFormat: string;
|
|
538
|
+
readonly preview?: SchemaPushPreview | undefined;
|
|
539
|
+
constructor(sectionName: string, currentFormat: string, newFormat: string, message?: string, preview?: SchemaPushPreview | undefined);
|
|
540
|
+
}
|
|
541
|
+
/** 422: the server refused the schema (not an object of fields, or the definition is not project-scoped). */
|
|
542
|
+
declare class SchemaRejected extends Error {
|
|
543
|
+
readonly sectionName: string;
|
|
544
|
+
constructor(sectionName: string, message: string);
|
|
545
|
+
}
|
|
546
|
+
/** Send the manifest's `schema` to the dashboard, after showing the diff and asking. */
|
|
547
|
+
declare function pushSchema(config: ResolvedConfig, options: SchemaPushOptions): Promise<SchemaPushResult>;
|
|
548
|
+
|
|
549
|
+
export { type BotlrCliConfigFile, CONFIG_FILE, ConfigError, type ConfigOverrides, DEFAULT_FRAMEWORK, DEFAULT_REGISTRY_FILE, DEFAULT_SECTIONS_DIR, type DefinitionMeta, type DeriveOptions, type DerivedManifest, type ExpectedPushMode, type GenerateOptions, type InitOptions, type InitResult, LOCK_DIR, LOCK_FILE, type LockEntry, MANIFEST_KEY_ORDER, MANIFEST_SUFFIX, ManifestError, PROPS_SUFFIX, type PropField, type PropsTypesUpdate, type PullOptions, type PullResult, type PushOptions, type PushResult, REGISTRY_FILE, type RegistryAddition, type RegistryEditResult, type RegistryEntry, type RegistryUpdate, type ResolvedConfig, type SchemaDrift, SchemaFormatConflict, type SchemaKeyDiff, type SchemaPullOptions, type SchemaPullResult, type SchemaPushOptions, type SchemaPushPreview, type SchemaPushResult, SchemaRejected, type SectionStatus, type SectionStatusRow, type SectionsLock, type StatusInput, addRegistryEntry, clientFor, collectDslFields, collectFields, collectFormBuilderFields, compareSchemas, computeStatus, deriveManifests, diffSchemaKeys, expectedPushMode, findConfigFile, formatDriftWarning, formatManifest, formatSchemaDiff, formatsDiffer, generatePropsSource, hasRegistry, importPathFor, initSections, listManifests, listSections, loadConfig, lockPath, manifestPath, manifestSchema, manifestsEqual, nextLockEntry, normalizeManifest, optionUnion, parseDefinition, parseImports, parseRegistry, parseZodSchema, pascalCase, previewSchemaPush, propsInterfaceName, propsPath, pullSchemas, pullSections, pushSchema, pushSection, readConfigFile, readLock, readManifest, readNpmVersions, readSectionFiles, registerSection, remoteForLock, safeJoin, schemaFieldNames, schemaKeys, sectionStatuses, tsTypeForField, updateLock, validateManifest, writeLock, writeManifest, writeManifestIfChanged, writePropsTypes, writeSectionFiles, zodFieldToSchemaField };
|
package/dist/index.js
CHANGED
|
@@ -805,15 +805,15 @@ async function writePropsTypes(sectionsDir, manifest, schema) {
|
|
|
805
805
|
}
|
|
806
806
|
|
|
807
807
|
// src/drift.ts
|
|
808
|
-
import {
|
|
808
|
+
import { schemaFormat } from "@botlr/sdk";
|
|
809
809
|
function manifestSchema(manifest) {
|
|
810
810
|
const schema = manifest.schema;
|
|
811
|
-
return
|
|
811
|
+
return schemaFormat(schema) ? schema : null;
|
|
812
812
|
}
|
|
813
813
|
function compareSchemas(manifest, definitionSchema) {
|
|
814
814
|
const code = manifestSchema(manifest);
|
|
815
815
|
if (!code) return null;
|
|
816
|
-
const codeKeys = new Set(
|
|
816
|
+
const codeKeys = new Set(schemaFieldNames(code));
|
|
817
817
|
const dashboardKeys = new Set(schemaFieldNames(definitionSchema));
|
|
818
818
|
const missingInDashboard = [...codeKeys].filter((k) => !dashboardKeys.has(k)).sort();
|
|
819
819
|
const missingInCode = [...dashboardKeys].filter((k) => !codeKeys.has(k)).sort();
|
|
@@ -828,7 +828,65 @@ function formatDriftWarning(name, drift) {
|
|
|
828
828
|
if (drift.missingInCode.length) {
|
|
829
829
|
lines.push(` the dashboard defines props the code does not list: ${drift.missingInCode.join(", ")}`);
|
|
830
830
|
}
|
|
831
|
-
lines.push(` the dashboard owns the schema
|
|
831
|
+
lines.push(` the dashboard owns the schema; a code push never changes it. To resolve:`);
|
|
832
|
+
lines.push(` botlr schema pull ${name} takes the dashboard's schema into ${name}.botlr.json`);
|
|
833
|
+
lines.push(` botlr schema push ${name} sends the code's schema to the dashboard`);
|
|
834
|
+
return lines.join("\n");
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// src/schema-diff.ts
|
|
838
|
+
import { schemaFormat as schemaFormat2 } from "@botlr/sdk";
|
|
839
|
+
function schemaKeys(schema) {
|
|
840
|
+
return [...new Set(schemaFieldNames(schema))];
|
|
841
|
+
}
|
|
842
|
+
function diffSchemaKeys(current, next) {
|
|
843
|
+
const currentKeys = new Set(schemaKeys(current));
|
|
844
|
+
const nextKeys = new Set(schemaKeys(next));
|
|
845
|
+
return {
|
|
846
|
+
added: [...nextKeys].filter((k) => !currentKeys.has(k)).sort(),
|
|
847
|
+
removed: [...currentKeys].filter((k) => !nextKeys.has(k)).sort(),
|
|
848
|
+
kept: [...nextKeys].filter((k) => currentKeys.has(k)).sort()
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
function formatsDiffer(preview) {
|
|
852
|
+
return !!preview.currentFormat && !!preview.nextFormat && preview.currentFormat !== preview.nextFormat;
|
|
853
|
+
}
|
|
854
|
+
function expectedPushMode(preview) {
|
|
855
|
+
if (preview.force || !formatsDiffer(preview)) return "replaced";
|
|
856
|
+
return preview.currentFormat === "form-builder" && preview.nextFormat === "field-dsl" ? "merged" : "conflict";
|
|
857
|
+
}
|
|
858
|
+
function previewSchemaPush(name, current, next, options = {}) {
|
|
859
|
+
const formats = {
|
|
860
|
+
currentFormat: options.currentFormat ?? schemaFormat2(current),
|
|
861
|
+
nextFormat: options.nextFormat ?? schemaFormat2(next),
|
|
862
|
+
force: options.force ?? false
|
|
863
|
+
};
|
|
864
|
+
return { name, current, next, diff: diffSchemaKeys(current, next), ...formats, expected: expectedPushMode(formats) };
|
|
865
|
+
}
|
|
866
|
+
function plural(n, word) {
|
|
867
|
+
return `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
868
|
+
}
|
|
869
|
+
function formatName(format) {
|
|
870
|
+
return format ?? "unknown";
|
|
871
|
+
}
|
|
872
|
+
function formatSchemaDiff(preview) {
|
|
873
|
+
const { diff, expected } = preview;
|
|
874
|
+
let header = `schema of '${preview.name}': dashboard has ${formatName(preview.currentFormat)} (${plural(schemaKeys(preview.current).length, "field")}), code has ${formatName(preview.nextFormat)} (${plural(schemaKeys(preview.next).length, "field")})`;
|
|
875
|
+
if (expected === "merged") {
|
|
876
|
+
header += ": the server will add the missing fields as FormBuilder nodes and keep the dashboard's (format kept; --force would replace it)";
|
|
877
|
+
}
|
|
878
|
+
const lines = [header];
|
|
879
|
+
if (diff.added.length) lines.push(` + added ${diff.added.join(", ")}`);
|
|
880
|
+
if (diff.removed.length) {
|
|
881
|
+
lines.push(expected === "merged" ? ` ~ dashboard only, kept ${diff.removed.join(", ")}` : ` - removed ${diff.removed.join(", ")}`);
|
|
882
|
+
}
|
|
883
|
+
lines.push(` = kept ${diff.kept.length ? diff.kept.join(", ") : "none"}`);
|
|
884
|
+
if (formatsDiffer(preview) && expected !== "merged") {
|
|
885
|
+
lines.push(
|
|
886
|
+
preview.force ? ` the formats differ: replacing ${preview.currentFormat} with ${preview.nextFormat} (--force)` : ` the formats differ: the push needs --force to replace ${preview.currentFormat} with ${preview.nextFormat}`
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
if (!diff.added.length && !diff.removed.length) lines.push(" the field keys match; only field settings may change");
|
|
832
890
|
return lines.join("\n");
|
|
833
891
|
}
|
|
834
892
|
|
|
@@ -1078,6 +1136,116 @@ async function initSections(config, options = {}) {
|
|
|
1078
1136
|
}
|
|
1079
1137
|
return results;
|
|
1080
1138
|
}
|
|
1139
|
+
|
|
1140
|
+
// src/commands/schema.ts
|
|
1141
|
+
import {
|
|
1142
|
+
BotlrError,
|
|
1143
|
+
BotlrSchemaFormatConflictError,
|
|
1144
|
+
botlrErrorMessage
|
|
1145
|
+
} from "@botlr/sdk";
|
|
1146
|
+
function isNotFound(error) {
|
|
1147
|
+
return error instanceof BotlrError && error.status === 404;
|
|
1148
|
+
}
|
|
1149
|
+
async function pullSchemas(config, options) {
|
|
1150
|
+
const client = clientFor(config);
|
|
1151
|
+
const names = options.all ? await listManifests(config.sectionsDir) : options.names;
|
|
1152
|
+
const results = [];
|
|
1153
|
+
for (const name of names) {
|
|
1154
|
+
let manifest;
|
|
1155
|
+
try {
|
|
1156
|
+
manifest = await readManifest(config.sectionsDir, name);
|
|
1157
|
+
} catch (error) {
|
|
1158
|
+
results.push({ name, changed: false, file: "", error: error.message });
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
let definition;
|
|
1162
|
+
try {
|
|
1163
|
+
definition = (await client.sections.getSchema(name)).definition;
|
|
1164
|
+
} catch (error) {
|
|
1165
|
+
if (!isNotFound(error)) throw error;
|
|
1166
|
+
results.push({ name, changed: false, file: "", error: `the app has no section type '${name}' (botlr push ${name} --create adds one)` });
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1169
|
+
const updated = { ...manifest, schema: definition.schema };
|
|
1170
|
+
const written = await writeManifestIfChanged(config.sectionsDir, name, updated);
|
|
1171
|
+
const types = config.types && !options.noTypes ? await writePropsTypes(config.sectionsDir, manifest, definition.schema) : void 0;
|
|
1172
|
+
results.push({ name, changed: written.changed, file: written.file, format: definition.format, types });
|
|
1173
|
+
}
|
|
1174
|
+
return results;
|
|
1175
|
+
}
|
|
1176
|
+
var SchemaFormatConflict = class extends Error {
|
|
1177
|
+
constructor(sectionName, currentFormat, newFormat, message, preview) {
|
|
1178
|
+
super(message ?? `the schema of '${sectionName}' is stored as ${currentFormat}, the manifest's is ${newFormat}`);
|
|
1179
|
+
this.sectionName = sectionName;
|
|
1180
|
+
this.currentFormat = currentFormat;
|
|
1181
|
+
this.newFormat = newFormat;
|
|
1182
|
+
this.preview = preview;
|
|
1183
|
+
this.name = "SchemaFormatConflict";
|
|
1184
|
+
}
|
|
1185
|
+
sectionName;
|
|
1186
|
+
currentFormat;
|
|
1187
|
+
newFormat;
|
|
1188
|
+
preview;
|
|
1189
|
+
};
|
|
1190
|
+
var SchemaRejected = class extends Error {
|
|
1191
|
+
constructor(sectionName, message) {
|
|
1192
|
+
super(message);
|
|
1193
|
+
this.sectionName = sectionName;
|
|
1194
|
+
this.name = "SchemaRejected";
|
|
1195
|
+
}
|
|
1196
|
+
sectionName;
|
|
1197
|
+
};
|
|
1198
|
+
async function pushSchema(config, options) {
|
|
1199
|
+
const client = clientFor(config, { needPersonalToken: true });
|
|
1200
|
+
const { name } = options;
|
|
1201
|
+
const manifest = await readManifest(config.sectionsDir, name);
|
|
1202
|
+
const next = manifest.schema;
|
|
1203
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) {
|
|
1204
|
+
throw new ManifestError(
|
|
1205
|
+
`${name}.botlr.json has no 'schema' object to push; add one, or run 'botlr schema pull ${name}' to take the dashboard's`
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
let current;
|
|
1209
|
+
try {
|
|
1210
|
+
current = (await client.sections.getSchema(name)).definition;
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
if (!isNotFound(error)) throw error;
|
|
1213
|
+
throw new ManifestError(`the app has no section type '${name}'; push the code first with 'botlr push ${name} --create'`);
|
|
1214
|
+
}
|
|
1215
|
+
const force = options.force ?? false;
|
|
1216
|
+
const preview = previewSchemaPush(name, current.schema, next, { currentFormat: current.format, force });
|
|
1217
|
+
if (preview.expected === "conflict") {
|
|
1218
|
+
throw new SchemaFormatConflict(name, preview.currentFormat, preview.nextFormat, void 0, preview);
|
|
1219
|
+
}
|
|
1220
|
+
if (options.confirm && !await options.confirm(preview)) {
|
|
1221
|
+
return { name, preview, pushed: false };
|
|
1222
|
+
}
|
|
1223
|
+
let response;
|
|
1224
|
+
try {
|
|
1225
|
+
response = await client.sections.putSchema(name, { schema: next, force });
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
if (error instanceof BotlrSchemaFormatConflictError) {
|
|
1228
|
+
throw new SchemaFormatConflict(name, error.currentFormat, error.newFormat, botlrErrorMessage(error));
|
|
1229
|
+
}
|
|
1230
|
+
if (error instanceof BotlrError && error.status === 422) {
|
|
1231
|
+
throw new SchemaRejected(name, botlrErrorMessage(error) ?? "the server rejected the schema (422)");
|
|
1232
|
+
}
|
|
1233
|
+
throw error;
|
|
1234
|
+
}
|
|
1235
|
+
const types = config.types && !options.noTypes ? await writePropsTypes(config.sectionsDir, manifest, response.definition.schema) : void 0;
|
|
1236
|
+
return {
|
|
1237
|
+
name,
|
|
1238
|
+
preview,
|
|
1239
|
+
pushed: true,
|
|
1240
|
+
changed: response.changed,
|
|
1241
|
+
previousFormat: response.previousFormat,
|
|
1242
|
+
format: response.definition.format,
|
|
1243
|
+
mode: response.mode,
|
|
1244
|
+
added: response.added,
|
|
1245
|
+
dashboardOnly: response.dashboardOnly,
|
|
1246
|
+
types
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1081
1249
|
export {
|
|
1082
1250
|
CONFIG_FILE,
|
|
1083
1251
|
ConfigError,
|
|
@@ -1091,6 +1259,8 @@ export {
|
|
|
1091
1259
|
ManifestError,
|
|
1092
1260
|
PROPS_SUFFIX,
|
|
1093
1261
|
REGISTRY_FILE,
|
|
1262
|
+
SchemaFormatConflict,
|
|
1263
|
+
SchemaRejected,
|
|
1094
1264
|
addRegistryEntry,
|
|
1095
1265
|
clientFor,
|
|
1096
1266
|
collectDslFields,
|
|
@@ -1099,9 +1269,13 @@ export {
|
|
|
1099
1269
|
compareSchemas,
|
|
1100
1270
|
computeStatus,
|
|
1101
1271
|
deriveManifests,
|
|
1272
|
+
diffSchemaKeys,
|
|
1273
|
+
expectedPushMode,
|
|
1102
1274
|
findConfigFile,
|
|
1103
1275
|
formatDriftWarning,
|
|
1104
1276
|
formatManifest,
|
|
1277
|
+
formatSchemaDiff,
|
|
1278
|
+
formatsDiffer,
|
|
1105
1279
|
generatePropsSource,
|
|
1106
1280
|
hasRegistry,
|
|
1107
1281
|
importPathFor,
|
|
@@ -1121,9 +1295,12 @@ export {
|
|
|
1121
1295
|
parseRegistry,
|
|
1122
1296
|
parseZodSchema,
|
|
1123
1297
|
pascalCase,
|
|
1298
|
+
previewSchemaPush,
|
|
1124
1299
|
propsInterfaceName,
|
|
1125
1300
|
propsPath,
|
|
1301
|
+
pullSchemas,
|
|
1126
1302
|
pullSections,
|
|
1303
|
+
pushSchema,
|
|
1127
1304
|
pushSection,
|
|
1128
1305
|
readConfigFile,
|
|
1129
1306
|
readLock,
|
|
@@ -1134,6 +1311,7 @@ export {
|
|
|
1134
1311
|
remoteForLock,
|
|
1135
1312
|
safeJoin,
|
|
1136
1313
|
schemaFieldNames,
|
|
1314
|
+
schemaKeys,
|
|
1137
1315
|
sectionStatuses,
|
|
1138
1316
|
tsTypeForField,
|
|
1139
1317
|
updateLock,
|