@dalexto/lexsys-cli 0.0.6 → 0.1.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/commands/status.d.ts +6 -0
- package/dist/config/config.d.ts +1 -0
- package/dist/index.js +106 -7
- package/dist/registry/remote.d.ts +14 -1
- package/package.json +2 -2
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
interface RunStatusOptions {
|
|
2
|
+
json?: boolean;
|
|
2
3
|
noFallback?: boolean;
|
|
3
4
|
}
|
|
5
|
+
export interface StatusEntry {
|
|
6
|
+
name: string;
|
|
7
|
+
canonicalName: string;
|
|
8
|
+
drift: "synced" | "drift" | "missing";
|
|
9
|
+
}
|
|
4
10
|
export declare const runStatus: (options?: RunStatusOptions) => Promise<void>;
|
|
5
11
|
export {};
|
package/dist/config/config.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -131,7 +131,8 @@ var defaultConfig = {
|
|
|
131
131
|
aliases: defaultAliasesConfig,
|
|
132
132
|
tailwind: defaultTailwindConfig,
|
|
133
133
|
installed: [],
|
|
134
|
-
registryUrl: null
|
|
134
|
+
registryUrl: null,
|
|
135
|
+
registryAllowlist: []
|
|
135
136
|
};
|
|
136
137
|
var getConfigPath = () => {
|
|
137
138
|
return join(getCwd(), "lexsys.config.json");
|
|
@@ -158,7 +159,10 @@ var loadConfig = async () => {
|
|
|
158
159
|
...defaultTailwindConfig,
|
|
159
160
|
...parsed.tailwind
|
|
160
161
|
},
|
|
161
|
-
installed: normalizeInstalled(parsed.installed)
|
|
162
|
+
installed: normalizeInstalled(parsed.installed),
|
|
163
|
+
registryAllowlist: Array.isArray(parsed.registryAllowlist) ? parsed.registryAllowlist.filter((entry) => {
|
|
164
|
+
return typeof entry === "string" && entry.length > 0;
|
|
165
|
+
}) : defaultConfig.registryAllowlist
|
|
162
166
|
};
|
|
163
167
|
if (isLegacyInstalledRecord(parsed.installed)) {
|
|
164
168
|
await saveConfig(config);
|
|
@@ -822,6 +826,21 @@ var parseRegistryStyles = (styles) => {
|
|
|
822
826
|
}
|
|
823
827
|
return styles;
|
|
824
828
|
};
|
|
829
|
+
var computeRemoteRegistryChecksum = (manifest) => {
|
|
830
|
+
return hashContent(JSON.stringify(manifest));
|
|
831
|
+
};
|
|
832
|
+
var verifyRemoteRegistryChecksum = (manifest) => {
|
|
833
|
+
if (!manifest.checksum) {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
const { checksum, ...rest } = manifest;
|
|
837
|
+
const computed = computeRemoteRegistryChecksum(rest);
|
|
838
|
+
if (computed !== checksum) {
|
|
839
|
+
throw new Error(
|
|
840
|
+
`Remote registry checksum mismatch. Expected ${checksum}, computed ${computed}.`
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
825
844
|
var parseRemoteRegistry = (value) => {
|
|
826
845
|
if (Array.isArray(value)) {
|
|
827
846
|
return {
|
|
@@ -846,8 +865,36 @@ var parseRemoteRegistry = (value) => {
|
|
|
846
865
|
}
|
|
847
866
|
parsed.styles = parseRegistryStyles(manifest.styles);
|
|
848
867
|
}
|
|
868
|
+
if (manifest.checksum !== void 0) {
|
|
869
|
+
if (typeof manifest.checksum !== "string" || manifest.checksum.length === 0) {
|
|
870
|
+
throw new Error(
|
|
871
|
+
"Remote registry manifest checksum must be a non-empty string."
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
parsed.checksum = manifest.checksum;
|
|
875
|
+
}
|
|
876
|
+
verifyRemoteRegistryChecksum(parsed);
|
|
849
877
|
return parsed;
|
|
850
878
|
};
|
|
879
|
+
var isRegistryUrlAllowed = (url, allowlist) => {
|
|
880
|
+
if (!allowlist?.length) {
|
|
881
|
+
return true;
|
|
882
|
+
}
|
|
883
|
+
let parsed;
|
|
884
|
+
try {
|
|
885
|
+
parsed = new URL(url);
|
|
886
|
+
} catch {
|
|
887
|
+
return false;
|
|
888
|
+
}
|
|
889
|
+
const host = parsed.hostname;
|
|
890
|
+
const origin = parsed.origin;
|
|
891
|
+
return allowlist.some((entry) => {
|
|
892
|
+
if (entry === host || entry === origin || entry === url) {
|
|
893
|
+
return true;
|
|
894
|
+
}
|
|
895
|
+
return url.startsWith(entry);
|
|
896
|
+
});
|
|
897
|
+
};
|
|
851
898
|
var fetchRemoteRegistry = async (url) => {
|
|
852
899
|
const response = await fetch(url);
|
|
853
900
|
if (!response.ok) {
|
|
@@ -860,7 +907,16 @@ var fetchRemoteRegistry = async (url) => {
|
|
|
860
907
|
// src/registry/source.ts
|
|
861
908
|
var getRegistrySource = async () => {
|
|
862
909
|
const config = await loadConfig();
|
|
863
|
-
|
|
910
|
+
const registryUrl = config.registryUrl;
|
|
911
|
+
if (!registryUrl) {
|
|
912
|
+
return "local";
|
|
913
|
+
}
|
|
914
|
+
if (!isRegistryUrlAllowed(registryUrl, config.registryAllowlist)) {
|
|
915
|
+
throw new Error(
|
|
916
|
+
`Registry URL is not allowed by registryAllowlist: ${registryUrl}`
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
return registryUrl;
|
|
864
920
|
};
|
|
865
921
|
|
|
866
922
|
// src/registry/provider.ts
|
|
@@ -1447,8 +1503,13 @@ Shows template drift for tracked components (up to date vs out of sync).
|
|
|
1447
1503
|
For project paths and registry connectivity, use \`lexsys doctor\`.
|
|
1448
1504
|
|
|
1449
1505
|
Options
|
|
1506
|
+
--json, -j Print installed component drift as JSON
|
|
1450
1507
|
--no-fallback Fail instead of falling back to local registry
|
|
1451
1508
|
--help, -h Show this help
|
|
1509
|
+
|
|
1510
|
+
Examples
|
|
1511
|
+
lexsys st
|
|
1512
|
+
lexsys st --json
|
|
1452
1513
|
`,
|
|
1453
1514
|
reset: `
|
|
1454
1515
|
Usage
|
|
@@ -2666,6 +2727,10 @@ var runStatus = async (options = {}) => {
|
|
|
2666
2727
|
const config = await loadConfig();
|
|
2667
2728
|
const installed = config.installed ?? [];
|
|
2668
2729
|
if (!installed.length) {
|
|
2730
|
+
if (options.json) {
|
|
2731
|
+
console.log(JSON.stringify({ installed: [] }, null, 2));
|
|
2732
|
+
return;
|
|
2733
|
+
}
|
|
2669
2734
|
console.log("No Lexsys components are currently tracked.");
|
|
2670
2735
|
return;
|
|
2671
2736
|
}
|
|
@@ -2674,19 +2739,52 @@ var runStatus = async (options = {}) => {
|
|
|
2674
2739
|
fallback: !options.noFallback
|
|
2675
2740
|
});
|
|
2676
2741
|
} catch (error) {
|
|
2742
|
+
if (options.json) {
|
|
2743
|
+
console.log(
|
|
2744
|
+
JSON.stringify(
|
|
2745
|
+
{
|
|
2746
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2747
|
+
},
|
|
2748
|
+
null,
|
|
2749
|
+
2
|
|
2750
|
+
)
|
|
2751
|
+
);
|
|
2752
|
+
process.exitCode = 1;
|
|
2753
|
+
return;
|
|
2754
|
+
}
|
|
2677
2755
|
printRegistryResolveFailure(error);
|
|
2678
2756
|
return;
|
|
2679
2757
|
}
|
|
2680
|
-
|
|
2758
|
+
const entries = [];
|
|
2681
2759
|
for (const name of installed) {
|
|
2682
2760
|
const item = await findItem(name);
|
|
2683
2761
|
if (!item) {
|
|
2684
|
-
|
|
2762
|
+
entries.push({
|
|
2763
|
+
name,
|
|
2764
|
+
canonicalName: name,
|
|
2765
|
+
drift: "missing"
|
|
2766
|
+
});
|
|
2685
2767
|
continue;
|
|
2686
2768
|
}
|
|
2687
2769
|
const driftStatus = await getComponentDriftStatus(name);
|
|
2688
|
-
|
|
2689
|
-
|
|
2770
|
+
entries.push({
|
|
2771
|
+
name: item.name,
|
|
2772
|
+
canonicalName: item.canonicalName,
|
|
2773
|
+
drift: driftStatus === "drift" ? "drift" : "synced"
|
|
2774
|
+
});
|
|
2775
|
+
}
|
|
2776
|
+
if (options.json) {
|
|
2777
|
+
console.log(JSON.stringify({ installed: entries }, null, 2));
|
|
2778
|
+
return;
|
|
2779
|
+
}
|
|
2780
|
+
console.log("Installed Lexsys components:\n");
|
|
2781
|
+
for (const entry of entries) {
|
|
2782
|
+
if (entry.drift === "missing") {
|
|
2783
|
+
console.log(`- ${entry.name} (missing from registry)`);
|
|
2784
|
+
continue;
|
|
2785
|
+
}
|
|
2786
|
+
const status = entry.drift === "drift" ? "out of sync with registry" : "up to date with registry";
|
|
2787
|
+
console.log(`- ${entry.canonicalName} (${status})`);
|
|
2690
2788
|
}
|
|
2691
2789
|
};
|
|
2692
2790
|
|
|
@@ -3429,6 +3527,7 @@ try {
|
|
|
3429
3527
|
process.exit(0);
|
|
3430
3528
|
}
|
|
3431
3529
|
await runStatus({
|
|
3530
|
+
json: hasFlag(args, "--json", "-j"),
|
|
3432
3531
|
noFallback: args.includes("--no-fallback")
|
|
3433
3532
|
});
|
|
3434
3533
|
process.exit(0);
|
|
@@ -3,13 +3,26 @@ export interface RemoteRegistryManifest {
|
|
|
3
3
|
version: string;
|
|
4
4
|
items: RegistryItem[];
|
|
5
5
|
styles?: RegistryStyle[];
|
|
6
|
+
checksum?: string;
|
|
6
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Computes a SHA-256 checksum for a remote manifest (excluding the checksum field).
|
|
10
|
+
*/
|
|
11
|
+
export declare const computeRemoteRegistryChecksum: (manifest: Omit<RemoteRegistryManifest, "checksum">) => string;
|
|
12
|
+
/**
|
|
13
|
+
* Verifies an optional manifest checksum when publishers include one.
|
|
14
|
+
*/
|
|
15
|
+
export declare const verifyRemoteRegistryChecksum: (manifest: RemoteRegistryManifest) => void;
|
|
7
16
|
/**
|
|
8
17
|
* Parses a remote registry JSON payload into a manifest object.
|
|
9
18
|
*
|
|
10
19
|
* Accepts either:
|
|
11
|
-
* - a manifest object `{ version, items, styles? }`
|
|
20
|
+
* - a manifest object `{ version, items, styles?, checksum? }`
|
|
12
21
|
* - a legacy bare array of registry items (version becomes `"unknown"`)
|
|
13
22
|
*/
|
|
14
23
|
export declare const parseRemoteRegistry: (value: unknown) => RemoteRegistryManifest;
|
|
24
|
+
/**
|
|
25
|
+
* Returns true when the registry URL host or prefix matches an allowlist entry.
|
|
26
|
+
*/
|
|
27
|
+
export declare const isRegistryUrlAllowed: (url: string, allowlist: string[] | undefined) => boolean;
|
|
15
28
|
export declare const fetchRemoteRegistry: (url: string) => Promise<RemoteRegistryManifest>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dalexto/lexsys-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Registry-first CLI that installs Lexsys React UI components into your project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"prompts": "^2.4.2",
|
|
35
|
-
"@dalexto/lexsys-registry": "0.
|
|
35
|
+
"@dalexto/lexsys-registry": "0.1.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^25.9.1",
|