@saasicat/cli 0.27.0 → 1.0.0-rc.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.
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
- // src/tokens.ts
5
- var CLI_CONTEXT_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/Config");
6
- var USER_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/UserPort");
7
- var USER_MANAGEMENT_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/UserManagementPort");
8
- var AUDIT_QUERY_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/AuditQueryPort");
9
- var DOCTOR_CHECKS_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/DoctorChecks");
10
- var MANIFEST_ACCESS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/ManifestAccessPort");
11
- var MANIFEST_CHECKS_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/ManifestChecks");
4
+ // src/cli.tokens.ts
5
+ var CLI_CONTEXT_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/cli/Config");
6
+ var USER_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/cli/UserPort");
7
+ var USER_MANAGEMENT_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/cli/UserManagementPort");
8
+ var AUDIT_QUERY_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/cli/AuditQueryPort");
9
+ var DOCTOR_CHECKS_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/cli/DoctorChecks");
10
+ var MANIFEST_ACCESS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/cli/ManifestAccessPort");
11
+ var MANIFEST_CHECKS_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/cli/ManifestChecks");
12
12
 
13
13
  // src/cli-context.service.ts
14
14
  import * as os from "os";
@@ -1716,6 +1716,269 @@ function patchOptionsFor(plan) {
1716
1716
  }
1717
1717
  __name(patchOptionsFor, "patchOptionsFor");
1718
1718
 
1719
+ // src/codemods/v1-imports.ts
1720
+ var PUBLIC_PREFIXES = [
1721
+ "ui/",
1722
+ "layouts/",
1723
+ "auth/",
1724
+ "pages/"
1725
+ ];
1726
+ function buildImportMap(table) {
1727
+ const map = /* @__PURE__ */ new Map();
1728
+ for (const [from, to] of Object.entries(table.moves)) {
1729
+ const onSurface = PUBLIC_PREFIXES.some((prefix) => to.startsWith(prefix));
1730
+ if (!onSurface && !to.startsWith("@")) continue;
1731
+ if (from.startsWith("components/")) {
1732
+ map.set(from, to);
1733
+ continue;
1734
+ }
1735
+ if (!from.startsWith("pages-standard/")) continue;
1736
+ const file = from.slice("pages-standard/".length);
1737
+ if (file.includes("/")) continue;
1738
+ map.set(from, to);
1739
+ map.set(`pages/${file}`, to);
1740
+ }
1741
+ for (const [from, to] of Object.entries(table.packages ?? {})) {
1742
+ if (from === "_") continue;
1743
+ map.set(from, to);
1744
+ }
1745
+ for (const [from, to] of Object.entries(table.moveDirectories ?? {})) {
1746
+ map.set(`${from}/`, `${to}/`);
1747
+ }
1748
+ return map;
1749
+ }
1750
+ __name(buildImportMap, "buildImportMap");
1751
+ function wentPrivate(map, subpath) {
1752
+ for (const [prefix, target] of map) {
1753
+ if (prefix.endsWith("/") && target.startsWith("internal/") && subpath.startsWith(prefix)) {
1754
+ return true;
1755
+ }
1756
+ }
1757
+ return false;
1758
+ }
1759
+ __name(wentPrivate, "wentPrivate");
1760
+ function rewriteSubpath(map, subpath) {
1761
+ const direct = map.get(subpath);
1762
+ if (direct !== void 0 && direct !== subpath) return direct;
1763
+ for (const [prefix, target] of map) {
1764
+ if (prefix.endsWith("/") && target.startsWith("@") && subpath.startsWith(prefix)) {
1765
+ return `${target}${subpath.slice(prefix.length)}`;
1766
+ }
1767
+ }
1768
+ if (subpath.startsWith("pages-standard/") && !wentPrivate(map, subpath)) {
1769
+ const file = subpath.slice("pages-standard/".length);
1770
+ if (!file.includes("/")) return `pages/${file}`;
1771
+ }
1772
+ return null;
1773
+ }
1774
+ __name(rewriteSubpath, "rewriteSubpath");
1775
+ function isNoLongerPublic(map, subpath) {
1776
+ if (subpath.startsWith("components/")) return !map.has(subpath);
1777
+ return subpath.startsWith("pages-standard/") && wentPrivate(map, subpath);
1778
+ }
1779
+ __name(isNoLongerPublic, "isNoLongerPublic");
1780
+ var UI_VUE_SPECIFIER = /@saasicat\/ui-vue\/([A-Za-z0-9/_.-]+)/g;
1781
+ function rewriteImports(text, map) {
1782
+ const unmapped = /* @__PURE__ */ new Map();
1783
+ let rewritten = 0;
1784
+ const next = text.replace(UI_VUE_SPECIFIER, (whole, subpath) => {
1785
+ const to = rewriteSubpath(map, subpath);
1786
+ if (to === null) {
1787
+ if (isNoLongerPublic(map, subpath)) {
1788
+ unmapped.set(subpath, (unmapped.get(subpath) ?? 0) + 1);
1789
+ }
1790
+ return whole;
1791
+ }
1792
+ rewritten += 1;
1793
+ return to.startsWith("@") ? to : `@saasicat/ui-vue/${to}`;
1794
+ });
1795
+ return {
1796
+ text: next,
1797
+ rewritten,
1798
+ unmapped
1799
+ };
1800
+ }
1801
+ __name(rewriteImports, "rewriteImports");
1802
+
1803
+ // src/codemods/v1-rename.ts
1804
+ var escape = /* @__PURE__ */ __name((s) => s.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&"), "escape");
1805
+ var FROM_SPECIFIER = /from\s*(['"])([^'"]+)\1/g;
1806
+ var isSpace = /* @__PURE__ */ __name((ch) => ch === " " || ch === " " || ch === "\n" || ch === "\r", "isSpace");
1807
+ function namedImports(text) {
1808
+ const found = [];
1809
+ for (const match of text.matchAll(FROM_SPECIFIER)) {
1810
+ let i = (match.index ?? 0) - 1;
1811
+ while (i >= 0 && isSpace(text[i])) i -= 1;
1812
+ if (text[i] !== "}") continue;
1813
+ const close = i;
1814
+ const open = text.lastIndexOf("{", close);
1815
+ if (open < 0) continue;
1816
+ i = open - 1;
1817
+ while (i >= 0 && isSpace(text[i])) i -= 1;
1818
+ let head = text.slice(Math.max(0, i - 3), i + 1);
1819
+ if (head === "type") {
1820
+ i -= 4;
1821
+ while (i >= 0 && isSpace(text[i])) i -= 1;
1822
+ head = text.slice(Math.max(0, i - 5), i + 1);
1823
+ } else {
1824
+ head = text.slice(Math.max(0, i - 5), i + 1);
1825
+ }
1826
+ if (head !== "import") continue;
1827
+ const names = text.slice(open + 1, close).split(",").map((raw) => {
1828
+ const words = raw.trim().split(/\s+/);
1829
+ if (words[0] === "type") words.shift();
1830
+ return words[0] ?? "";
1831
+ }).filter((name) => name.length > 0);
1832
+ found.push({
1833
+ names,
1834
+ specifier: match[2]
1835
+ });
1836
+ }
1837
+ return found;
1838
+ }
1839
+ __name(namedImports, "namedImports");
1840
+ function rewriteNames(text, table) {
1841
+ let next = text;
1842
+ let rewritten = 0;
1843
+ const ambiguous = /* @__PURE__ */ new Set();
1844
+ const perEntry = /* @__PURE__ */ new Map();
1845
+ for (const { names, specifier } of namedImports(text)) {
1846
+ const mapping = table.entryTokens[specifier];
1847
+ for (const name of names) {
1848
+ const knownSomewhere = Object.values(table.entryTokens).some((m) => name in m);
1849
+ if (!knownSomewhere) continue;
1850
+ const already = perEntry.get(name);
1851
+ if (mapping && name in mapping && (already === void 0 || already === mapping[name])) {
1852
+ perEntry.set(name, mapping[name]);
1853
+ } else {
1854
+ if (already !== void 0) perEntry.delete(name);
1855
+ ambiguous.add(`${name} from '${specifier}'`);
1856
+ }
1857
+ }
1858
+ }
1859
+ for (const [from, to] of perEntry) {
1860
+ next = next.replace(new RegExp(`\\b${escape(from)}\\b`, "g"), () => {
1861
+ rewritten += 1;
1862
+ return to;
1863
+ });
1864
+ }
1865
+ for (const [from, to] of Object.entries(table.identifierStems)) {
1866
+ next = next.replace(new RegExp(escape(from), "g"), () => {
1867
+ rewritten += 1;
1868
+ return to;
1869
+ });
1870
+ }
1871
+ for (const [from, to] of Object.entries(table.registryKeys)) {
1872
+ const symbolFor = new RegExp(`(Symbol\\.for\\(\\s*['"\`])${escape(from)}`, "g");
1873
+ next = next.replace(symbolFor, (_, head) => {
1874
+ rewritten += 1;
1875
+ return `${head}${to}`;
1876
+ });
1877
+ if (from.startsWith("@")) continue;
1878
+ const literal = new RegExp(`(['"\`])${escape(from)}`, "g");
1879
+ next = next.replace(literal, (_, quote) => {
1880
+ rewritten += 1;
1881
+ return `${quote}${to}`;
1882
+ });
1883
+ }
1884
+ for (const [from, to] of Object.entries(table.packages ?? {})) {
1885
+ if (from === "_") continue;
1886
+ next = next.replace(new RegExp(`${escape(from)}(?=['"\`/])`, "g"), () => {
1887
+ rewritten += 1;
1888
+ return to;
1889
+ });
1890
+ }
1891
+ for (const [from, to] of Object.entries(table.subpaths)) {
1892
+ next = next.replace(new RegExp(escape(from), "g"), () => {
1893
+ rewritten += 1;
1894
+ return to;
1895
+ });
1896
+ }
1897
+ return {
1898
+ text: next,
1899
+ rewritten,
1900
+ ambiguous: [
1901
+ ...ambiguous
1902
+ ].sort()
1903
+ };
1904
+ }
1905
+ __name(rewriteNames, "rewriteNames");
1906
+ var DEPENDENCY_FIELDS = [
1907
+ "dependencies",
1908
+ "devDependencies",
1909
+ "peerDependencies",
1910
+ "optionalDependencies"
1911
+ ];
1912
+ var UNTRANSLATABLE_RANGE = /^(workspace:|file:|link:|npm:|git\+|https?:)/;
1913
+ function rewriteManifest(text, table, options) {
1914
+ const renames = Object.entries(table.packages ?? {}).filter(([from]) => from !== "_");
1915
+ const ambiguous = [];
1916
+ let manifest;
1917
+ try {
1918
+ manifest = JSON.parse(text);
1919
+ } catch {
1920
+ return {
1921
+ text,
1922
+ rewritten: 0,
1923
+ ambiguous
1924
+ };
1925
+ }
1926
+ let rewritten = 0;
1927
+ for (const field of DEPENDENCY_FIELDS) {
1928
+ const deps = manifest[field];
1929
+ if (!deps || typeof deps !== "object") continue;
1930
+ const entries = Object.entries(deps);
1931
+ const renamed = entries.map(([name, range]) => {
1932
+ const to = renames.find(([from]) => from === name)?.[1];
1933
+ if (!to) return [
1934
+ name,
1935
+ range
1936
+ ];
1937
+ if (UNTRANSLATABLE_RANGE.test(range)) {
1938
+ ambiguous.push(`${name} in ${field} (${range})`);
1939
+ return [
1940
+ name,
1941
+ range
1942
+ ];
1943
+ }
1944
+ rewritten += 1;
1945
+ return [
1946
+ to,
1947
+ options.targetRange
1948
+ ];
1949
+ });
1950
+ manifest[field] = Object.fromEntries(renamed);
1951
+ }
1952
+ const meta = manifest.peerDependenciesMeta;
1953
+ if (meta && typeof meta === "object") {
1954
+ manifest.peerDependenciesMeta = Object.fromEntries(Object.entries(meta).map(([name, flags]) => {
1955
+ const to = renames.find(([from]) => from === name)?.[1];
1956
+ if (!to) return [
1957
+ name,
1958
+ flags
1959
+ ];
1960
+ rewritten += 1;
1961
+ return [
1962
+ to,
1963
+ flags
1964
+ ];
1965
+ }));
1966
+ }
1967
+ if (rewritten === 0) return {
1968
+ text,
1969
+ rewritten: 0,
1970
+ ambiguous
1971
+ };
1972
+ const indent = /^[ \t]+/m.exec(text)?.[0] ?? " ";
1973
+ const trailing = text.endsWith("\n") ? "\n" : "";
1974
+ return {
1975
+ text: JSON.stringify(manifest, null, indent) + trailing,
1976
+ rewritten,
1977
+ ambiguous
1978
+ };
1979
+ }
1980
+ __name(rewriteManifest, "rewriteManifest");
1981
+
1719
1982
  // src/init/patch-app-module.ts
1720
1983
  var MARKER = "SaaSiCatModule.forRoot";
1721
1984
  function patchAppModule(source, options) {
@@ -1840,7 +2103,7 @@ var LIMIT_FILTER_IMPORTS = [
1840
2103
  "import { LimitExceededFilter } from '@saasicat/nest/billing';"
1841
2104
  ].join("\n");
1842
2105
 
1843
- // src/module.ts
2106
+ // src/cli-context.module.ts
1844
2107
  import { Module } from "@nestjs/common";
1845
2108
  import { asProvider } from "@saasicat/nest";
1846
2109
  function _ts_decorate8(decorators, target, key, desc) {
@@ -2925,6 +3188,7 @@ export {
2925
3188
  MfaSetupFlow,
2926
3189
  PLATFORM_DOCTOR_CHECK_PROVIDERS,
2927
3190
  PlanCatalogDoctorCheck,
3191
+ UI_VUE_SPECIFIER,
2928
3192
  USER_MANAGEMENT_PORT_TOKEN,
2929
3193
  USER_PORT_TOKEN,
2930
3194
  UserCommands,
@@ -2939,6 +3203,7 @@ export {
2939
3203
  blankStringLiterals,
2940
3204
  blockBodyLines,
2941
3205
  breaksContract,
3206
+ buildImportMap,
2942
3207
  checkSchema,
2943
3208
  constraintsFor,
2944
3209
  enableFkPointers,
@@ -2950,10 +3215,12 @@ export {
2950
3215
  foreignKeyOf,
2951
3216
  hasBackRelation,
2952
3217
  hasConstraints,
3218
+ isNoLongerPublic,
2953
3219
  isOneToOne,
2954
3220
  kebabCase,
2955
3221
  migrationCreatedBy,
2956
3222
  minimumQuotasPerPlan,
3223
+ namedImports,
2957
3224
  parseBlockAttributes,
2958
3225
  parseEnumValues,
2959
3226
  parseFields,
@@ -2967,6 +3234,10 @@ export {
2967
3234
  quotaKeyPattern,
2968
3235
  relationNameOf,
2969
3236
  reportConstraints,
3237
+ rewriteImports,
3238
+ rewriteManifest,
3239
+ rewriteNames,
3240
+ rewriteSubpath,
2970
3241
  stripLineComment,
2971
3242
  structuralOnly,
2972
3243
  tablesAddressedBy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasicat/cli",
3
- "version": "0.27.0",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "CLI helpers for SaaS platform consumers. Provides CliContextService (identity, MFA, production confirm, audit tag).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -21,16 +21,17 @@
21
21
  "files": [
22
22
  "dist",
23
23
  "bin",
24
- "templates"
24
+ "templates",
25
+ "codemods"
25
26
  ],
26
27
  "bin": {
27
28
  "saasicat": "./bin/saasicat.js"
28
29
  },
29
30
  "dependencies": {
30
31
  "qrcode-terminal": "^0.12.0",
31
- "@saasicat/nest": "^0.27.0",
32
- "@saasicat/spec": "^0.27.0",
33
- "@saasicat/types": "^0.27.0"
32
+ "@saasicat/nest": "^1.0.0-rc.1",
33
+ "@saasicat/spec": "^1.0.0-rc.1",
34
+ "@saasicat/core": "^1.0.0-rc.1"
34
35
  },
35
36
  "peerDependencies": {
36
37
  "@nestjs/common": "^11.0.0",
@@ -49,7 +50,7 @@
49
50
  "repository": {
50
51
  "type": "git",
51
52
  "url": "https://github.com/uelker70/saasicat.git",
52
- "directory": "packages/saas-platform-cli"
53
+ "directory": "packages/cli"
53
54
  },
54
55
  "bugs": {
55
56
  "url": "https://github.com/uelker70/saasicat/issues"
@@ -58,8 +59,8 @@
58
59
  "access": "public"
59
60
  },
60
61
  "scripts": {
61
- "build": "node ../../scripts/build-and-prune.mjs \"tsup src/index.ts --format esm,cjs --dts --external @saasicat/types --external @saasicat/nest --external @nestjs/common --external nest-commander --external qrcode-terminal\"",
62
+ "build": "node ../../scripts/build-and-prune.mjs \"tsup src/index.ts --format esm,cjs --dts --external @saasicat/core --external @saasicat/nest --external @nestjs/common --external nest-commander --external qrcode-terminal\"",
62
63
  "pretest": "pnpm run build",
63
- "test": "node --test tests/**/*.test.js"
64
+ "test": "node --test 'tests/*.test.js'"
64
65
  }
65
66
  }
@@ -1,6 +1,6 @@
1
1
  import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
2
2
  import { Injectable } from '@nestjs/common';
3
- import type { PasswordHasher } from '@saasicat/types';
3
+ import type { PasswordHasher } from '@saasicat/core';
4
4
 
5
5
  const KEY_LENGTH = 64;
6
6
 
@@ -1,4 +1,4 @@
1
- import type { ManifestContribution } from '@saasicat/types';
1
+ import type { ManifestContribution } from '@saasicat/core';
2
2
 
3
3
  /**
4
4
  * What this app adds to the SuperAdmin UI.
@@ -1,4 +1,4 @@
1
- import type { FeatureUiRegistry } from '@saasicat/types';
1
+ import type { FeatureUiRegistry } from '@saasicat/core';
2
2
 
3
3
  /**
4
4
  * Labels and icons for the feature and quota keys discovery finds in your code.
@@ -1,6 +1,6 @@
1
1
  import { Injectable } from '@nestjs/common';
2
2
  import { DefinesQuota } from '@saasicat/nest/discovery';
3
- import type { QuotaProvider } from '@saasicat/types';
3
+ import type { QuotaProvider } from '@saasicat/core';
4
4
 
5
5
  import { PrismaService } from '../prisma/prisma.service';
6
6