@happyvertical/smrt-cli 0.56.2 → 0.57.1

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.
Files changed (31) hide show
  1. package/AGENTS.md +1 -1
  2. package/agents/commerce-money-upgrade.md +49 -0
  3. package/dist/{AuditLogCollection-WDHL-_AF-PMKF1FIA.js → AuditLogCollection-WDHL-_AF-BLRue0-Z.js} +1 -1
  4. package/dist/{OidcIdentity-BUblgQLs-C2jGl4xb.js → OidcIdentity-BUblgQLs-DQzfrrkW.js} +2 -2
  5. package/dist/{OidcIdentityCollection-ClOyaHeF-CRqOi6OR.js → OidcIdentityCollection-ClOyaHeF-BA4QgOyy.js} +1 -1
  6. package/dist/{ProfileAssetCollection-CRMcjLJ--D0B9tdFm.js → ProfileAssetCollection-CRMcjLJ--BxEDTPbM.js} +3 -3
  7. package/dist/{ProfileCollection-C4INKh7Y-EfdCjHJy.js → ProfileCollection-C4INKh7Y-C28k9KAj.js} +17 -17
  8. package/dist/{ProfileLinkCollection-DFfZRsgv-Do3CZRe8.js → ProfileLinkCollection-DFfZRsgv-B4oOqnC5.js} +2 -2
  9. package/dist/{ProfileMetadataCollection-BIYKy4Y3-D_5z9xC7.js → ProfileMetadataCollection-BIYKy4Y3-D07YJojE.js} +1 -1
  10. package/dist/{ProfileMetafieldCollection-Buz7gzag-BBp96ZxU.js → ProfileMetafieldCollection-Buz7gzag-1uok776P.js} +1 -1
  11. package/dist/{ProfileRelationshipCollection-C4g_QLI4-DdNSbq9T.js → ProfileRelationshipCollection-C4g_QLI4-CzNBurq5.js} +1 -1
  12. package/dist/{ProfileTypeCollection-B7kwi1mU-7uzgnnJA.js → ProfileTypeCollection-B7kwi1mU-JJeGJVd9.js} +2 -2
  13. package/dist/commands/db-status.d.ts.map +1 -1
  14. package/dist/commands/db-upgrade-commerce-money.d.ts +23 -0
  15. package/dist/commands/db-upgrade-commerce-money.d.ts.map +1 -0
  16. package/dist/commands/utilities.d.ts.map +1 -1
  17. package/dist/{commands-DQMwpnIx.js → commands-DkW9egBl.js} +215 -247
  18. package/dist/{dist-Clv0HeDN.js → dist-ByE1kAL-.js} +3 -3
  19. package/dist/{dist-UCD6F1L5.js → dist-C7z_OoIl.js} +4 -4
  20. package/dist/{dist-D8ESE6vP.js → dist-CvOObIMo.js} +16 -16
  21. package/dist/dist-TzhaT84W.js +21 -0
  22. package/dist/{dist-DHxqJOJ1.js → dist-mVN37-aQ.js} +2 -2
  23. package/dist/index.js +11 -11
  24. package/dist/loaders/git-loader.d.ts.map +1 -1
  25. package/dist/{oidcProvisioningPrimitives-DNP9EZlU-B_amql6n.js → oidcProvisioningPrimitives-DNP9EZlU-DrF67XCR.js} +3 -3
  26. package/dist/{resolveIdentity-CkyqvctR-DvYT2fSs.js → resolveIdentity-CkyqvctR-rQR3kTaK.js} +14 -14
  27. package/package.json +10 -10
  28. package/agents/commerce-money-migration.md +0 -48
  29. package/dist/commands/db-commerce-money.d.ts +0 -5
  30. package/dist/commands/db-commerce-money.d.ts.map +0 -1
  31. package/dist/dist-D1ZvOIhb.js +0 -21
@@ -13,7 +13,7 @@ import { ObjectRegistry, SchemaComparer, checkLiveSchemaParity, collectForeignKe
13
13
  import { loadExternalManifestSync } from "@happyvertical/smrt-core/manifest";
14
14
  import { execFile, execFileSync, execSync, spawn, spawnSync } from "node:child_process";
15
15
  import { homedir, tmpdir } from "node:os";
16
- import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
16
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
17
17
  import { extract } from "tar";
18
18
  import { access, cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
19
19
  import { createLogger } from "@happyvertical/logger";
@@ -2783,6 +2783,178 @@ function formatParityReport(report, options = {}) {
2783
2783
  return lines;
2784
2784
  }
2785
2785
  //#endregion
2786
+ //#region src/loaders/consumer-package.ts
2787
+ function importTarget(value) {
2788
+ if (typeof value === "string") return value;
2789
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
2790
+ const conditions = value;
2791
+ return importTarget(conditions.import) ?? importTarget(conditions.node) ?? importTarget(conditions.default);
2792
+ }
2793
+ /** Resolve a package entry from the invoking consumer project, not the CLI's install. */
2794
+ async function resolveConsumerPackageEntry(packageName, projectRoot = process.cwd()) {
2795
+ const searchRoots = [];
2796
+ let directory = resolve(projectRoot);
2797
+ for (;;) {
2798
+ searchRoots.push(join(directory, "node_modules"));
2799
+ const parent = dirname(directory);
2800
+ if (parent === directory) break;
2801
+ directory = parent;
2802
+ }
2803
+ for (const root of searchRoots) {
2804
+ const packageRoot = join(root, ...packageName.split("/"));
2805
+ try {
2806
+ const manifest = JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8"));
2807
+ const exportsMap = manifest.exports && typeof manifest.exports === "object" ? manifest.exports : null;
2808
+ const entry = importTarget(exportsMap && "." in exportsMap ? exportsMap["."] : manifest.exports) ?? manifest.module ?? manifest.main ?? null;
2809
+ if (!entry) throw new Error(`Package ${packageName} has no importable root entry`);
2810
+ const resolved = resolve(packageRoot, entry);
2811
+ const withinPackage = relative(packageRoot, resolved);
2812
+ if (isAbsolute(withinPackage) || withinPackage === ".." || withinPackage.startsWith(`..${sep}`)) throw new Error(`Package ${packageName} root export escapes its package`);
2813
+ return resolved;
2814
+ } catch (error) {
2815
+ if (error.code === "ENOENT") continue;
2816
+ throw error;
2817
+ }
2818
+ }
2819
+ throw new Error(`Package '${packageName}' is not installed in ${projectRoot}. Install it in the project that invokes this command.`);
2820
+ }
2821
+ /** Import an optional command provider through the consumer's package graph. */
2822
+ async function importConsumerPackage(packageName, projectRoot = process.cwd()) {
2823
+ return import(
2824
+ /* @vite-ignore */
2825
+ pathToFileURL(await resolveConsumerPackageEntry(packageName, projectRoot)).href
2826
+ );
2827
+ }
2828
+ //#endregion
2829
+ //#region src/commands/db-upgrade-commerce-money.ts
2830
+ var COMMERCE_PACKAGE = "@happyvertical/smrt-commerce";
2831
+ /** The upgrade command, as named in commerce's refusal. */
2832
+ var COMMERCE_MONEY_UPGRADE_COMMAND = "smrt db:upgrade-commerce-money";
2833
+ function loadCommerce() {
2834
+ return importConsumerPackage(COMMERCE_PACKAGE);
2835
+ }
2836
+ function errorMessage(error) {
2837
+ const message = error instanceof Error ? error.message : String(error);
2838
+ const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
2839
+ return `${typeof code === "string" && code ? `[${code}] ` : ""}${message}`;
2840
+ }
2841
+ /**
2842
+ * `db:status` precondition: an error when the database holds commerce money
2843
+ * data from an earlier version. Empty when commerce is not installed.
2844
+ */
2845
+ async function checkCommerceMoneyPreconditions(db) {
2846
+ let commerce;
2847
+ try {
2848
+ commerce = await loadCommerce();
2849
+ } catch {
2850
+ return [];
2851
+ }
2852
+ if (typeof commerce.findCommerceMoneyUpgradeNeeds !== "function") return [];
2853
+ if (db.tableExists && !await db.tableExists("invoices")) return [];
2854
+ let status;
2855
+ try {
2856
+ status = await commerce.findCommerceMoneyUpgradeNeeds(db);
2857
+ } catch (error) {
2858
+ return [{
2859
+ name: "commerce-money-upgrade",
2860
+ status: "warning",
2861
+ message: `Commerce money data could not be checked: ${redactDatabaseUrlsInText(errorMessage(error))}`,
2862
+ recommendation: `Run ${COMMERCE_MONEY_UPGRADE_COMMAND} --check.`,
2863
+ details: {}
2864
+ }];
2865
+ }
2866
+ const tenantless = status.tenantlessDocuments ?? [];
2867
+ if (status.oldSchema.length === 0 && status.tenants.length === 0 && tenantless.length === 0) return [];
2868
+ return [{
2869
+ name: "commerce-money-upgrade",
2870
+ status: "error",
2871
+ message: `COMMERCE_DATA_NEEDS_UPGRADE: commerce money data from an earlier version (${status.tenants.length} tenant(s) to convert${status.oldSchema.length ? `; old columns ${status.oldSchema.join(", ")}` : ""}${tenantless.length ? `; ${tenantless.length} document row(s) without a tenant to assign or delete` : ""}). Commerce refuses it until it is upgraded.`,
2872
+ recommendation: `Run ${COMMERCE_MONEY_UPGRADE_COMMAND} (add --tenant-id <id> to convert one tenant).`,
2873
+ details: {
2874
+ oldSchema: status.oldSchema,
2875
+ tenants: status.tenants,
2876
+ tenantlessDocuments: tenantless.length
2877
+ }
2878
+ }];
2879
+ }
2880
+ async function configuredDatabase() {
2881
+ const { getPackageConfig } = await import("@happyvertical/smrt-config");
2882
+ const { DEFAULT_CLI_CONFIG } = await import("./config-CdJRSMRi.js").then((n) => n.n);
2883
+ const config = getPackageConfig("cli", DEFAULT_CLI_CONFIG);
2884
+ if (!config.database?.url || config.database.url === ":memory:") throw new Error("Database configuration required for db:upgrade-commerce-money. Configure database.url in smrt.config.ts (or DATABASE_URL).");
2885
+ await autoDiscoverAndLoad();
2886
+ const { getDatabase } = await import("@happyvertical/sql");
2887
+ const dbType = config.database.type || "sqlite";
2888
+ return {
2889
+ db: await getDatabase({
2890
+ type: dbType,
2891
+ url: config.database.url
2892
+ }),
2893
+ dbType,
2894
+ dbUrl: config.database.url
2895
+ };
2896
+ }
2897
+ var dbUpgradeCommerceMoneyCommand = {
2898
+ name: "db:upgrade-commerce-money",
2899
+ description: "Convert commerce money data written by an earlier version to the current money model, once. Each tenant converts atomically; an issued document that does not reconcile exactly fails its tenant.",
2900
+ aliases: ["commerce-money:upgrade"],
2901
+ args: [],
2902
+ options: {
2903
+ "tenant-id": {
2904
+ type: "string",
2905
+ description: "Convert only this tenant."
2906
+ },
2907
+ check: {
2908
+ type: "boolean",
2909
+ description: "Report what needs the upgrade without changing anything.",
2910
+ default: false
2911
+ }
2912
+ },
2913
+ handler: async (_args, options) => {
2914
+ let db;
2915
+ try {
2916
+ const configured = await configuredDatabase();
2917
+ db = configured.db;
2918
+ const commerce = await loadCommerce();
2919
+ console.log("\n💰 Commerce money upgrade\n");
2920
+ console.log(`✓ Connected to ${formatDatabaseDisplayUrl(configured.dbType, configured.dbUrl)}\n`);
2921
+ if (options.check) {
2922
+ const status = await commerce.findCommerceMoneyUpgradeNeeds(db);
2923
+ for (const need of status.tenants) console.log(` ${need.tenantId}: ${need.reason}`);
2924
+ if (status.oldSchema.length) console.log(` old columns: ${status.oldSchema.join(", ")}`);
2925
+ const tenantless = status.tenantlessDocuments ?? [];
2926
+ for (const row of tenantless) console.log(` ${row.table} ${row.id}: no tenant (assign or delete)`);
2927
+ if (status.tenants.length === 0 && status.oldSchema.length === 0 && tenantless.length === 0) console.log("Nothing to upgrade.\n");
2928
+ else {
2929
+ console.log(`\n${status.tenants.length} tenant(s) need the upgrade. No database changes made.\n`);
2930
+ process.exitCode = 1;
2931
+ }
2932
+ return;
2933
+ }
2934
+ const tenantId = options["tenant-id"]?.trim() || void 0;
2935
+ const result = await commerce.upgradeCommerceMoney(db, { tenantId });
2936
+ for (const tenant of result.upgraded) {
2937
+ console.log(`✓ ${tenant.tenantId}: ${tenant.issuedBackfilled} issued document(s) backfilled, ${tenant.draftsRecomputed} draft(s) recomputed.`);
2938
+ for (const draft of tenant.changedDrafts) console.log(` ${draft.documentType} ${draft.documentId}: total ${draft.old.totalMinor} -> ${draft.next.totalMinor}`);
2939
+ if (tenant.componentsWithoutLiabilityAccount.length) console.log(` created tax components without a liability account: ${tenant.componentsWithoutLiabilityAccount.join(", ")}`);
2940
+ }
2941
+ for (const failure of result.failures) console.error(`✗ ${failure.tenantId || "(no tenant)"}${failure.documentType ? ` ${failure.documentType} ${failure.documentId}` : ""}: ${failure.reason}`);
2942
+ if (result.droppedSchema.length) console.log(`\n✓ Removed earlier-version columns: ${result.droppedSchema.join(", ")}`);
2943
+ if (result.failures.length || result.remaining.length) {
2944
+ console.error(`\n❌ ${result.remaining.length} tenant(s) and ${(result.tenantlessDocuments ?? []).length} row(s) without a tenant still need attention.\n`);
2945
+ process.exitCode = 1;
2946
+ return;
2947
+ }
2948
+ console.log("\nCommerce money upgrade complete.\n");
2949
+ } catch (error) {
2950
+ console.error(`\n❌ Commerce money upgrade failed: ${redactDatabaseUrlsInText(errorMessage(error))}\n`);
2951
+ process.exitCode = 1;
2952
+ } finally {
2953
+ await closeDatabaseConnection(db);
2954
+ }
2955
+ }
2956
+ };
2957
+ //#endregion
2786
2958
  //#region src/commands/schema-contract.ts
2787
2959
  var SchemaContractError = class extends Error {
2788
2960
  report;
@@ -3458,12 +3630,16 @@ var dbStatusCommand = {
3458
3630
  diff = await comparer.compare(manifestSchemas);
3459
3631
  status.drift = summarizeSchemaDiff(diff);
3460
3632
  status.notes = summarizeSchemaNotes(diff);
3461
- status.preconditions = [...await checkTenantIdUuidPreconditions({
3462
- db,
3463
- dbType,
3464
- dbUrl,
3465
- manifestSchemas
3466
- }), ...checkTenantNaturalKeyUniques(comparer.getLiveSchemaSnapshot())];
3633
+ status.preconditions = [
3634
+ ...await checkTenantIdUuidPreconditions({
3635
+ db,
3636
+ dbType,
3637
+ dbUrl,
3638
+ manifestSchemas
3639
+ }),
3640
+ ...checkTenantNaturalKeyUniques(comparer.getLiveSchemaSnapshot()),
3641
+ ...await checkCommerceMoneyPreconditions(db)
3642
+ ];
3467
3643
  status.failedMigrations = summarizeFailedMigrations(failed, getUnresolvedGeneratedMigrationNames(diff.changes));
3468
3644
  if (options.parity) try {
3469
3645
  status.parity = await checkLiveSchemaParity({
@@ -5607,6 +5783,13 @@ function countObjects(data) {
5607
5783
  var logger$1 = createLogger({ level: "info" });
5608
5784
  var tempDirectories = /* @__PURE__ */ new Set();
5609
5785
  var cleanupHandlersRegistered = false;
5786
+ async function removeTempDirectory(tempDir) {
5787
+ await rm(tempDir, {
5788
+ recursive: true,
5789
+ force: true
5790
+ });
5791
+ tempDirectories.delete(tempDir);
5792
+ }
5610
5793
  /**
5611
5794
  * Register cleanup handlers for temporary directories
5612
5795
  * Ensures temp directories are removed on process termination
@@ -5619,15 +5802,19 @@ function registerCleanupHandlers() {
5619
5802
  const dirs = Array.from(tempDirectories);
5620
5803
  await Promise.all(dirs.map(async (dir) => {
5621
5804
  try {
5622
- await rm(dir, {
5623
- recursive: true,
5624
- force: true
5625
- });
5626
- tempDirectories.delete(dir);
5805
+ await removeTempDirectory(dir);
5627
5806
  } catch (_error) {}
5628
5807
  }));
5629
5808
  };
5630
- process.on("exit", () => {});
5809
+ process.on("exit", () => {
5810
+ for (const dir of Array.from(tempDirectories)) try {
5811
+ rmSync(dir, {
5812
+ recursive: true,
5813
+ force: true
5814
+ });
5815
+ tempDirectories.delete(dir);
5816
+ } catch (_error) {}
5817
+ });
5631
5818
  process.on("SIGINT", async () => {
5632
5819
  await cleanup();
5633
5820
  process.exit(130);
@@ -5840,10 +6027,11 @@ async function loadGitTemplate(gitUrl) {
5840
6027
  }
5841
6028
  }
5842
6029
  } catch (error) {
5843
- await rm(tempDir, {
5844
- recursive: true,
5845
- force: true
5846
- });
6030
+ try {
6031
+ await removeTempDirectory(tempDir);
6032
+ } catch (cleanupError) {
6033
+ throw new AggregateError([error, cleanupError], `Template load failed and temporary directory cleanup failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
6034
+ }
5847
6035
  throw error;
5848
6036
  }
5849
6037
  }
@@ -5864,11 +6052,13 @@ function getGitTemplateDir(config) {
5864
6052
  * Cleanup temporary directory after template is used
5865
6053
  */
5866
6054
  async function cleanupGitTemplate(config) {
5867
- const tempDir = config.__tempDir;
5868
- if (tempDir) await rm(tempDir, {
5869
- recursive: true,
5870
- force: true
5871
- });
6055
+ const gitConfig = config;
6056
+ const tempDir = gitConfig.__tempDir;
6057
+ if (tempDir) {
6058
+ await removeTempDirectory(tempDir);
6059
+ delete gitConfig.__tempDir;
6060
+ delete gitConfig.__templateRoot;
6061
+ }
5872
6062
  }
5873
6063
  /**
5874
6064
  * Validate template configuration has required fields
@@ -8061,226 +8251,6 @@ function scanProjectForUnlayeredResets(root, options = {}) {
8061
8251
  };
8062
8252
  }
8063
8253
  //#endregion
8064
- //#region src/loaders/consumer-package.ts
8065
- function importTarget(value) {
8066
- if (typeof value === "string") return value;
8067
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
8068
- const conditions = value;
8069
- return importTarget(conditions.import) ?? importTarget(conditions.node) ?? importTarget(conditions.default);
8070
- }
8071
- /** Resolve a package entry from the invoking consumer project, not the CLI's install. */
8072
- async function resolveConsumerPackageEntry(packageName, projectRoot = process.cwd()) {
8073
- const searchRoots = [];
8074
- let directory = resolve(projectRoot);
8075
- for (;;) {
8076
- searchRoots.push(join(directory, "node_modules"));
8077
- const parent = dirname(directory);
8078
- if (parent === directory) break;
8079
- directory = parent;
8080
- }
8081
- for (const root of searchRoots) {
8082
- const packageRoot = join(root, ...packageName.split("/"));
8083
- try {
8084
- const manifest = JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8"));
8085
- const exportsMap = manifest.exports && typeof manifest.exports === "object" ? manifest.exports : null;
8086
- const entry = importTarget(exportsMap && "." in exportsMap ? exportsMap["."] : manifest.exports) ?? manifest.module ?? manifest.main ?? null;
8087
- if (!entry) throw new Error(`Package ${packageName} has no importable root entry`);
8088
- const resolved = resolve(packageRoot, entry);
8089
- const withinPackage = relative(packageRoot, resolved);
8090
- if (isAbsolute(withinPackage) || withinPackage === ".." || withinPackage.startsWith(`..${sep}`)) throw new Error(`Package ${packageName} root export escapes its package`);
8091
- return resolved;
8092
- } catch (error) {
8093
- if (error.code === "ENOENT") continue;
8094
- throw error;
8095
- }
8096
- }
8097
- throw new Error(`Package '${packageName}' is not installed in ${projectRoot}. Install it in the project that invokes this command.`);
8098
- }
8099
- /** Import an optional command provider through the consumer's package graph. */
8100
- async function importConsumerPackage(packageName, projectRoot = process.cwd()) {
8101
- return import(
8102
- /* @vite-ignore */
8103
- pathToFileURL(await resolveConsumerPackageEntry(packageName, projectRoot)).href
8104
- );
8105
- }
8106
- //#endregion
8107
- //#region src/commands/db-commerce-money.ts
8108
- var COMMERCE_PACKAGE = "@happyvertical/smrt-commerce";
8109
- function loadCommerceMoneyModule() {
8110
- return importConsumerPackage(COMMERCE_PACKAGE);
8111
- }
8112
- function requiredOption(value, name) {
8113
- const normalized = value?.trim();
8114
- if (!normalized) throw new Error(`--${name} is required`);
8115
- return normalized;
8116
- }
8117
- function reportOutput(options) {
8118
- const jsonPath = options["json-path"]?.trim();
8119
- const csvPath = options["csv-path"]?.trim();
8120
- if (Boolean(jsonPath) !== Boolean(csvPath)) throw new Error("--json-path and --csv-path must be supplied together");
8121
- return jsonPath && csvPath ? {
8122
- jsonPath,
8123
- csvPath
8124
- } : void 0;
8125
- }
8126
- function renderReport(report) {
8127
- for (const tenant of report.tenants) {
8128
- const reasons = Object.entries(tenant.reasonCounts).filter(([, count]) => Number(count) > 0).map(([reason, count]) => `${reason}=${count}`).join(", ");
8129
- console.log(` ${tenant.tenantId}: ${tenant.documentCount} document(s), ${tenant.changingDraftCount} changing draft(s), ${tenant.issuedUnpostedFallbackTaxCount} issued/unposted fallback-tax document(s)${reasons ? `; ${reasons}` : ""}`);
8130
- }
8131
- for (const document of report.documents) {
8132
- if (document.reasons.length === 0) continue;
8133
- console.log(` ${document.tenantId}/${document.documentType}/${document.documentId}: ${document.reasons.join(", ")}`);
8134
- }
8135
- }
8136
- function errorMessage(error) {
8137
- const message = error instanceof Error ? error.message : String(error);
8138
- const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
8139
- return `${typeof code === "string" && code ? `[${code}] ` : ""}${message}`;
8140
- }
8141
- async function configuredDatabase(command) {
8142
- const { getPackageConfig } = await import("@happyvertical/smrt-config");
8143
- const { DEFAULT_CLI_CONFIG } = await import("./config-CdJRSMRi.js").then((n) => n.n);
8144
- const config = getPackageConfig("cli", DEFAULT_CLI_CONFIG);
8145
- if (!config.database?.url || config.database.url === ":memory:") throw new Error(`Database configuration required for ${command}. Configure database.url in smrt.config.ts (or DATABASE_URL).`);
8146
- await autoDiscoverAndLoad();
8147
- const { getDatabase } = await import("@happyvertical/sql");
8148
- const dbType = config.database.type || "sqlite";
8149
- return {
8150
- db: await getDatabase({
8151
- type: dbType,
8152
- url: config.database.url
8153
- }),
8154
- dbType,
8155
- dbUrl: config.database.url
8156
- };
8157
- }
8158
- function commonOptions() {
8159
- return { "tenant-id": {
8160
- type: "string",
8161
- description: "Authoritative tenant identifier."
8162
- } };
8163
- }
8164
- var dbPreflightCommerceMoneyCommand = {
8165
- name: "db:preflight-commerce-money",
8166
- description: "Read and report legacy Commerce line amounts before activating the v2 money model. Never writes database state.",
8167
- aliases: ["commerce-money:preflight"],
8168
- args: [],
8169
- options: {
8170
- ...commonOptions(),
8171
- "json-path": {
8172
- type: "string",
8173
- description: "Write the deterministic JSON report to this path."
8174
- },
8175
- "csv-path": {
8176
- type: "string",
8177
- description: "Write the deterministic CSV report to this path."
8178
- }
8179
- },
8180
- handler: async (_args, options) => {
8181
- let db;
8182
- try {
8183
- const out = reportOutput(options);
8184
- const configured = await configuredDatabase("db:preflight-commerce-money");
8185
- db = configured.db;
8186
- const { preflightCommerceLineAmounts } = await loadCommerceMoneyModule();
8187
- console.log("\n💰 Commerce money preflight\n");
8188
- console.log(`✓ Connected to ${formatDatabaseDisplayUrl(configured.dbType, configured.dbUrl)}\n`);
8189
- const tenantId = options["tenant-id"]?.trim() || void 0;
8190
- const report = await preflightCommerceLineAmounts(db, {
8191
- out,
8192
- tenantId
8193
- });
8194
- renderReport(report);
8195
- if (out) console.log(`\n✓ Wrote ${out.jsonPath} and ${out.csvPath}.`);
8196
- console.log(`\nPreflight complete: ${report.documents.length} document(s) across ${report.tenants.length} tenant(s). No database changes made.\n`);
8197
- } catch (error) {
8198
- console.error(`\n❌ Commerce money preflight failed: ${redactDatabaseUrlsInText(errorMessage(error))}\n`);
8199
- process.exitCode = 1;
8200
- } finally {
8201
- await closeDatabaseConnection(db);
8202
- }
8203
- }
8204
- };
8205
- var dbMigrateCommerceMoneyCommand = {
8206
- name: "db:migrate-commerce-money",
8207
- description: "Migrate one tenant to the Commerce v2 money model after reviewing preflight output.",
8208
- aliases: ["commerce-money:migrate"],
8209
- args: [],
8210
- options: {
8211
- ...commonOptions(),
8212
- "accept-draft-changes": {
8213
- type: "boolean",
8214
- description: "Accept draft total changes identified by the preflight.",
8215
- default: false
8216
- },
8217
- "migration-id": {
8218
- type: "string",
8219
- description: "Resume the active tenant migration with its owner identity."
8220
- }
8221
- },
8222
- handler: async (_args, options) => {
8223
- let db;
8224
- try {
8225
- const tenantId = requiredOption(options["tenant-id"], "tenant-id");
8226
- const configured = await configuredDatabase("db:migrate-commerce-money");
8227
- db = configured.db;
8228
- const { migrateCommerceLineAmounts } = await loadCommerceMoneyModule();
8229
- console.log("\n💰 Commerce money migration\n");
8230
- console.log(`✓ Connected to ${formatDatabaseDisplayUrl(configured.dbType, configured.dbUrl)}\n`);
8231
- const migrationId = options["migration-id"]?.trim() || randomUUID();
8232
- console.log(`Migration owner: ${migrationId} (reuse with --migration-id after an interrupted attempt).\n`);
8233
- const result = await migrateCommerceLineAmounts(db, {
8234
- tenantId,
8235
- acceptDraftChanges: options["accept-draft-changes"] === true,
8236
- migrationId
8237
- });
8238
- renderReport(result.report);
8239
- console.log(`\n✓ Tenant ${result.tenantId} activated v2 money model (migration ${result.migrationId}); migrated ${result.migrated}, resumed ${result.resumed}.\n`);
8240
- } catch (error) {
8241
- console.error(`\n❌ Commerce money migration failed: ${redactDatabaseUrlsInText(errorMessage(error))}\n`);
8242
- process.exitCode = 1;
8243
- } finally {
8244
- await closeDatabaseConnection(db);
8245
- }
8246
- }
8247
- };
8248
- var dbRollbackCommerceMoneyCommand = {
8249
- name: "db:rollback-commerce-money",
8250
- description: "Restore one Commerce tenant from its durable v2 money migration journal.",
8251
- aliases: ["commerce-money:rollback"],
8252
- args: [],
8253
- options: {
8254
- ...commonOptions(),
8255
- "migration-id": {
8256
- type: "string",
8257
- description: "Migration owner identity recorded during activation."
8258
- }
8259
- },
8260
- handler: async (_args, options) => {
8261
- let db;
8262
- try {
8263
- const tenantId = requiredOption(options["tenant-id"], "tenant-id");
8264
- const migrationId = requiredOption(options["migration-id"], "migration-id");
8265
- const configured = await configuredDatabase("db:rollback-commerce-money");
8266
- db = configured.db;
8267
- const { rollbackCommerceLineAmounts } = await loadCommerceMoneyModule();
8268
- console.log("\n💰 Commerce money rollback\n");
8269
- console.log(`✓ Connected to ${formatDatabaseDisplayUrl(configured.dbType, configured.dbUrl)}\n`);
8270
- const result = await rollbackCommerceLineAmounts(db, {
8271
- tenantId,
8272
- migrationId
8273
- });
8274
- console.log(`\n✓ Tenant ${result.tenantId} migration ${result.migrationId} rolled back; restored ${result.restored}, already restored ${result.alreadyRestored}.\n`);
8275
- } catch (error) {
8276
- console.error(`\n❌ Commerce money rollback failed: ${redactDatabaseUrlsInText(errorMessage(error))}\n`);
8277
- process.exitCode = 1;
8278
- } finally {
8279
- await closeDatabaseConnection(db);
8280
- }
8281
- }
8282
- };
8283
- //#endregion
8284
8254
  //#region src/commands/db-drop-framework-base-tables.ts
8285
8255
  /**
8286
8256
  * db:drop-framework-base-tables Command
@@ -8432,7 +8402,7 @@ var dbMaterializeTenantHierarchyCommand = {
8432
8402
  if (!config.database?.url || config.database.url === ":memory:") throw new Error("Database configuration required for db:materialize-tenant-hierarchy. Configure database.url in smrt.config.ts (or DATABASE_URL).");
8433
8403
  const dbType = config.database.type || "sqlite";
8434
8404
  const { getDatabase } = await import("@happyvertical/sql");
8435
- const { materializeTenantHierarchy, TenantHierarchyMaterializationError } = await import("./dist-D8ESE6vP.js");
8405
+ const { materializeTenantHierarchy, TenantHierarchyMaterializationError } = await import("./dist-CvOObIMo.js");
8436
8406
  db = await getDatabase({
8437
8407
  type: dbType,
8438
8408
  url: config.database.url
@@ -8641,7 +8611,7 @@ var dbMigrateLedgerAccountsCommand = {
8641
8611
  if (dbType !== "postgres") throw new Error("db:migrate-ledger-accounts currently supports PostgreSQL only; no changes were made. See the smrt-ledgers README for SQLite.");
8642
8612
  await autoDiscoverAndLoad();
8643
8613
  const { getDatabase } = await import("@happyvertical/sql");
8644
- const { migrateLedgerAccountsTable, planLedgerAccountsTableMove } = await import("./dist-UCD6F1L5.js");
8614
+ const { migrateLedgerAccountsTable, planLedgerAccountsTableMove } = await import("./dist-C7z_OoIl.js");
8645
8615
  db = await getDatabase({
8646
8616
  type: dbType,
8647
8617
  url: config.database.url
@@ -12615,9 +12585,7 @@ export default testManifest;
12615
12585
  "db:migrate-null-equal-indexes": dbMigrateNullEqualIndexesCommand,
12616
12586
  "db:migrate-agent-schedule-slugs": dbMigrateAgentScheduleSlugsCommand,
12617
12587
  "db:migrate-ledger-accounts": dbMigrateLedgerAccountsCommand,
12618
- "db:preflight-commerce-money": dbPreflightCommerceMoneyCommand,
12619
- "db:migrate-commerce-money": dbMigrateCommerceMoneyCommand,
12620
- "db:rollback-commerce-money": dbRollbackCommerceMoneyCommand,
12588
+ "db:upgrade-commerce-money": dbUpgradeCommerceMoneyCommand,
12621
12589
  "db:migrate-qualified-names": dbMigrateQualifiedNamesCommand,
12622
12590
  "db:materialize-tenant-hierarchy": dbMaterializeTenantHierarchyCommand,
12623
12591
  "db:drop-framework-base-tables": dbDropFrameworkBaseTablesCommand,