@santi020k/lumen 0.1.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.
@@ -0,0 +1,33 @@
1
+ export interface LumenRegistryFile {
2
+ path: string;
3
+ source: string;
4
+ }
5
+ export interface LumenRegistryComponent {
6
+ category: string;
7
+ dependencies?: readonly string[];
8
+ description: string;
9
+ files: readonly (LumenRegistryFile | string)[];
10
+ name: string;
11
+ type: 'component';
12
+ }
13
+ export interface LumenRegistryItem {
14
+ components?: readonly string[];
15
+ files?: readonly (LumenRegistryFile | string)[];
16
+ name: string;
17
+ type: 'component-set' | 'documentation' | 'recipe';
18
+ }
19
+ export type LumenRegistryEntry = LumenRegistryComponent | LumenRegistryItem;
20
+ export interface LumenRegistry {
21
+ components?: readonly LumenRegistryComponent[];
22
+ description: string;
23
+ items: readonly LumenRegistryItem[];
24
+ name: string;
25
+ packages: readonly string[];
26
+ version: number;
27
+ }
28
+ export interface LumenRegistryLoadOptions {
29
+ headers?: Record<string, string>;
30
+ timeoutMs?: number;
31
+ token?: string;
32
+ }
33
+ //# sourceMappingURL=registry-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-types.d.ts","sourceRoot":"","sources":["../src/registry-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,SAAS,CAAC,iBAAiB,GAAG,MAAM,CAAC,EAAE,CAAA;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,WAAW,CAAA;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,KAAK,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,MAAM,CAAC,EAAE,CAAA;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,eAAe,GAAG,eAAe,GAAG,QAAQ,CAAA;CACnD;AAED,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG,iBAAiB,CAAA;AAE3E,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,SAAS,iBAAiB,EAAE,CAAA;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { lumenRegistry } from './registry-data.js';
2
+ import type { LumenRegistry, LumenRegistryComponent, LumenRegistryEntry, LumenRegistryFile, LumenRegistryItem, LumenRegistryLoadOptions } from './registry-types.js';
3
+ export { lumenRegistry };
4
+ export type { LumenRegistry, LumenRegistryComponent, LumenRegistryEntry, LumenRegistryFile, LumenRegistryItem, LumenRegistryLoadOptions };
5
+ export declare const getLumenRegistryEntries: (registry?: LumenRegistry) => LumenRegistryEntry[];
6
+ export declare const getLumenRegistryItem: (name: string, registry?: LumenRegistry) => LumenRegistryEntry | undefined;
7
+ export declare const loadLumenRegistry: (source: string | URL, options?: LumenRegistryLoadOptions) => Promise<LumenRegistry>;
8
+ export { addLumenRegistryItem, type LumenAddOptions, type LumenAddResult, type LumenAddTarget, type LumenMergeConflict } from './installer.js';
9
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,aAAa,EAAE,CAAA;AAExB,YAAY,EACV,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACzB,CAAA;AAOD,eAAO,MAAM,uBAAuB,GAAI,WAAU,aAA6B,KAAG,kBAAkB,EAGnG,CAAA;AAED,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,WAAU,aAA6B,KACtC,kBAAkB,GAAG,SAMvB,CAAA;AAgFD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,GAAG,GAAG,EACpB,UAAS,wBAA6B,KACrC,OAAO,CAAC,aAAa,CAcvB,CAAA;AAED,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,89 @@
1
+ /* eslint-disable complexity */
2
+ import { readFile } from 'node:fs/promises';
3
+ import { lumenRegistry } from './registry-data.js';
4
+ export { lumenRegistry };
5
+ const defaultRegistryTimeoutMs = 30_000;
6
+ const normalizeRegistryEntryName = (name) => name.replaceAll(/([a-z0-9])([A-Z])/g, '$1-$2').replaceAll(/[\s_]+/g, '-').toLowerCase();
7
+ export const getLumenRegistryEntries = (registry = lumenRegistry) => [
8
+ ...(registry.components ?? []),
9
+ ...registry.items
10
+ ];
11
+ export const getLumenRegistryItem = (name, registry = lumenRegistry) => {
12
+ const normalizedName = normalizeRegistryEntryName(name);
13
+ const entries = getLumenRegistryEntries(registry);
14
+ return entries.find(item => item.name === name) ??
15
+ entries.find(item => normalizeRegistryEntryName(item.name) === normalizedName);
16
+ };
17
+ const isRegistryFile = (value) => {
18
+ if (typeof value === 'string')
19
+ return value.length > 0;
20
+ if (!value || typeof value !== 'object')
21
+ return false;
22
+ const file = value;
23
+ return typeof file.path === 'string' && typeof file.source === 'string';
24
+ };
25
+ const isStringArray = (value) => Array.isArray(value) && value.every(entry => typeof entry === 'string');
26
+ const isRegistryFileArray = (value) => Array.isArray(value) && value.every(entry => isRegistryFile(entry));
27
+ const registryItemTypes = new Set(['component-set', 'documentation', 'recipe']);
28
+ const isRegistryItem = (value) => {
29
+ if (!value || typeof value !== 'object')
30
+ return false;
31
+ const item = value;
32
+ return typeof item.name === 'string' &&
33
+ typeof item.type === 'string' &&
34
+ registryItemTypes.has(item.type) &&
35
+ (item.components === undefined || isStringArray(item.components)) &&
36
+ (item.files === undefined || isRegistryFileArray(item.files));
37
+ };
38
+ const isRegistryComponent = (value) => {
39
+ if (!value || typeof value !== 'object')
40
+ return false;
41
+ const component = value;
42
+ return typeof component.name === 'string' &&
43
+ component.type === 'component' &&
44
+ typeof component.description === 'string' &&
45
+ typeof component.category === 'string' &&
46
+ isRegistryFileArray(component.files) &&
47
+ (component.dependencies === undefined || isStringArray(component.dependencies));
48
+ };
49
+ const isLumenRegistry = (value) => {
50
+ if (!value || typeof value !== 'object')
51
+ return false;
52
+ const registry = value;
53
+ return typeof registry.name === 'string' &&
54
+ typeof registry.version === 'number' &&
55
+ typeof registry.description === 'string' &&
56
+ isStringArray(registry.packages) &&
57
+ Array.isArray(registry.items) &&
58
+ registry.items.every(item => isRegistryItem(item)) &&
59
+ (registry.components === undefined ||
60
+ (Array.isArray(registry.components) && registry.components.every(component => isRegistryComponent(component))));
61
+ };
62
+ const fetchRegistrySource = async (source, options) => {
63
+ if (options.token && source.startsWith('http://')) {
64
+ throw new Error('Refusing to send a Lumen registry token over plain HTTP. Use an https:// registry URL.');
65
+ }
66
+ const response = await fetch(source, {
67
+ headers: {
68
+ ...options.headers,
69
+ ...(options.token ? { authorization: `Bearer ${options.token}` } : {})
70
+ },
71
+ signal: AbortSignal.timeout(options.timeoutMs ?? defaultRegistryTimeoutMs)
72
+ });
73
+ if (!response.ok) {
74
+ throw new Error(`Failed to load Lumen registry: ${response.status} ${response.statusText}`);
75
+ }
76
+ return response.text();
77
+ };
78
+ export const loadLumenRegistry = async (source, options = {}) => {
79
+ const sourceValue = String(source);
80
+ const raw = sourceValue.startsWith('http://') || sourceValue.startsWith('https://')
81
+ ? await fetchRegistrySource(sourceValue, options)
82
+ : await readFile(source, 'utf8');
83
+ const parsed = JSON.parse(raw);
84
+ if (!isLumenRegistry(parsed)) {
85
+ throw new Error('Invalid Lumen registry manifest');
86
+ }
87
+ return parsed;
88
+ };
89
+ export { addLumenRegistryItem } from './installer.js';
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@santi020k/lumen",
3
+ "version": "0.1.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Umbrella package for the Lumen multi-framework primitive UI system.",
8
+ "type": "module",
9
+ "sideEffects": [
10
+ "./styles.css"
11
+ ],
12
+ "main": "./dist/index.js",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ },
20
+ "./registry": {
21
+ "types": "./dist/registry.d.ts",
22
+ "import": "./dist/registry.js"
23
+ },
24
+ "./styles.css": "./styles.css",
25
+ "./package.json": "./package.json"
26
+ },
27
+ "files": [
28
+ "bin",
29
+ "dist",
30
+ "styles.css",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
34
+ "bin": {
35
+ "lumen": "./bin/lumen.mjs"
36
+ },
37
+ "dependencies": {
38
+ "@santi020k/lumen-core": "^0.1.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^26.1.1",
42
+ "@vitest/coverage-v8": "^4.1.10",
43
+ "typescript": "^6.0.3",
44
+ "vitest": "^4.1.10"
45
+ },
46
+ "engines": {
47
+ "node": ">=22.18.0"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/santi020k/lumen.git",
52
+ "directory": "packages/lumen"
53
+ },
54
+ "homepage": "https://lumen.santi020k.com",
55
+ "bugs": {
56
+ "url": "https://github.com/santi020k/lumen/issues"
57
+ },
58
+ "author": {
59
+ "name": "Santiago Molina",
60
+ "url": "https://santi020k.com"
61
+ },
62
+ "license": "MIT",
63
+ "scripts": {
64
+ "build": "tsc -p tsconfig.build.json",
65
+ "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput",
66
+ "typecheck": "tsc -p tsconfig.json --noEmit",
67
+ "test": "vitest run --config ../../vitest.config.ts --project lumen",
68
+ "test:coverage": "vitest run --config ../../vitest.config.ts --project lumen --coverage",
69
+ "lint": "eslint . --no-warn-ignored",
70
+ "lint:fix": "eslint . --fix --no-warn-ignored",
71
+ "clean": "rm -rf dist coverage"
72
+ }
73
+ }