@santi020k/lumen 1.6.0 → 1.7.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.
@@ -27,6 +27,7 @@ export interface LumenRegistry {
27
27
  }
28
28
  export interface LumenRegistryLoadOptions {
29
29
  headers?: Record<string, string>;
30
+ maxBytes?: number;
30
31
  timeoutMs?: number;
31
32
  token?: string;
32
33
  }
@@ -1 +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"}
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,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf"}
@@ -1 +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;AASD,eAAO,MAAM,uBAAuB,GAAI,WAAU,aAA6B,KAAG,kBAAkB,EAGnG,CAAA;AAED,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,WAAU,aAA6B,KACtC,kBAAkB,GAAG,SAQvB,CAAA;AAmFD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,GAAG,GAAG,EACpB,UAAS,wBAA6B,KACrC,OAAO,CAAC,aAAa,CAevB,CAAA;AAED,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,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;AAwBD,eAAO,MAAM,uBAAuB,GAAI,WAAU,aAA6B,KAAG,kBAAkB,EAGnG,CAAA;AAED,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,WAAU,aAA6B,KACtC,kBAAkB,GAAG,SAQvB,CAAA;AA6JD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,GAAG,GAAG,EACpB,UAAS,wBAA6B,KACrC,OAAO,CAAC,aAAa,CAsBvB,CAAA;AAED,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAA"}
package/dist/registry.js CHANGED
@@ -1,8 +1,17 @@
1
1
  /* eslint-disable complexity */
2
- import { readFile } from 'node:fs/promises';
2
+ import { readFile, stat } from 'node:fs/promises';
3
3
  import { lumenRegistry } from './registry-data.js';
4
+ import { isSafeRegistryFilePath } from './registry-path.js';
4
5
  export { lumenRegistry };
5
6
  const defaultRegistryTimeoutMs = 30_000;
7
+ const defaultRegistryMaxBytes = 5 * 1024 * 1024;
8
+ const resolvePositiveInteger = (value, fallback, name) => {
9
+ const resolved = value ?? fallback;
10
+ if (!Number.isSafeInteger(resolved) || resolved <= 0) {
11
+ throw new Error(`${name} must be a positive integer.`);
12
+ }
13
+ return resolved;
14
+ };
6
15
  const normalizeRegistryEntryName = (name) => name
7
16
  .replaceAll(/([a-z0-9])([A-Z])/g, '$1-$2')
8
17
  .replaceAll(/[\s_]+/g, '-')
@@ -23,7 +32,9 @@ const isRegistryFile = (value) => {
23
32
  if (!value || typeof value !== 'object')
24
33
  return false;
25
34
  const file = value;
26
- return typeof file.path === 'string' && typeof file.source === 'string';
35
+ return (typeof file.path === 'string' &&
36
+ isSafeRegistryFilePath(file.path) &&
37
+ typeof file.source === 'string');
27
38
  };
28
39
  const isString = (entry) => typeof entry === 'string';
29
40
  const isStringArray = (value) => Array.isArray(value) && value.every(isString);
@@ -33,7 +44,7 @@ const isRegistryItem = (value) => {
33
44
  if (!value || typeof value !== 'object')
34
45
  return false;
35
46
  const item = value;
36
- return (typeof item.name === 'string' &&
47
+ return (typeof item.name === 'string' && item.name.trim().length > 0 &&
37
48
  typeof item.type === 'string' &&
38
49
  registryItemTypes.has(item.type) &&
39
50
  (item.components === undefined || isStringArray(item.components)) &&
@@ -43,10 +54,10 @@ const isRegistryComponent = (value) => {
43
54
  if (!value || typeof value !== 'object')
44
55
  return false;
45
56
  const component = value;
46
- return (typeof component.name === 'string' &&
57
+ return (typeof component.name === 'string' && component.name.trim().length > 0 &&
47
58
  component.type === 'component' &&
48
- typeof component.description === 'string' &&
49
- typeof component.category === 'string' &&
59
+ typeof component.description === 'string' && component.description.trim().length > 0 &&
60
+ typeof component.category === 'string' && component.category.trim().length > 0 &&
50
61
  isRegistryFileArray(component.files) &&
51
62
  (component.dependencies === undefined || isStringArray(component.dependencies)));
52
63
  };
@@ -54,16 +65,53 @@ const isLumenRegistry = (value) => {
54
65
  if (!value || typeof value !== 'object')
55
66
  return false;
56
67
  const registry = value;
57
- return (typeof registry.name === 'string' &&
68
+ return (typeof registry.name === 'string' && registry.name.trim().length > 0 &&
58
69
  typeof registry.version === 'number' &&
59
- typeof registry.description === 'string' &&
70
+ Number.isSafeInteger(registry.version) && registry.version > 0 &&
71
+ typeof registry.description === 'string' && registry.description.trim().length > 0 &&
60
72
  isStringArray(registry.packages) &&
61
73
  Array.isArray(registry.items) &&
62
74
  registry.items.every(item => isRegistryItem(item)) &&
63
75
  (registry.components === undefined ||
64
76
  (Array.isArray(registry.components) && registry.components.every(component => isRegistryComponent(component)))));
65
77
  };
66
- const fetchRegistrySource = async (source, options) => {
78
+ const getResponseBody = (response) => response.body;
79
+ const readBoundedResponse = async (response, maxBytes) => {
80
+ const contentLength = Number(response.headers.get('content-length'));
81
+ if (Number.isFinite(contentLength) && contentLength > maxBytes) {
82
+ await response.body?.cancel();
83
+ throw new Error(`Lumen registry exceeds the ${maxBytes} byte limit.`);
84
+ }
85
+ const body = getResponseBody(response);
86
+ if (!body)
87
+ return '';
88
+ const reader = body.getReader();
89
+ const chunks = [];
90
+ let totalBytes = 0;
91
+ try {
92
+ let chunk = await reader.read();
93
+ while (!chunk.done) {
94
+ totalBytes += chunk.value.byteLength;
95
+ if (totalBytes > maxBytes) {
96
+ await reader.cancel();
97
+ throw new Error(`Lumen registry exceeds the ${maxBytes} byte limit.`);
98
+ }
99
+ chunks.push(chunk.value);
100
+ chunk = await reader.read();
101
+ }
102
+ }
103
+ finally {
104
+ reader.releaseLock();
105
+ }
106
+ const bytes = new Uint8Array(totalBytes);
107
+ let offset = 0;
108
+ for (const chunk of chunks) {
109
+ bytes.set(chunk, offset);
110
+ offset += chunk.byteLength;
111
+ }
112
+ return new TextDecoder().decode(bytes);
113
+ };
114
+ const fetchRegistrySource = async (source, options, maxBytes) => {
67
115
  if (options.token && source.startsWith('http://')) {
68
116
  throw new Error('Refusing to send a Lumen registry token over plain HTTP. Use an https:// registry URL.');
69
117
  }
@@ -72,19 +120,33 @@ const fetchRegistrySource = async (source, options) => {
72
120
  ...options.headers,
73
121
  ...(options.token ? { authorization: `Bearer ${options.token}` } : {})
74
122
  },
75
- signal: AbortSignal.timeout(options.timeoutMs ?? defaultRegistryTimeoutMs)
123
+ signal: AbortSignal.timeout(resolvePositiveInteger(options.timeoutMs, defaultRegistryTimeoutMs, 'timeoutMs'))
76
124
  });
77
125
  if (!response.ok) {
78
126
  throw new Error(`Failed to load Lumen registry: ${response.status} ${response.statusText}`);
79
127
  }
80
- return response.text();
128
+ return readBoundedResponse(response, maxBytes);
129
+ };
130
+ const readRegistrySource = async (source, maxBytes) => {
131
+ const details = await stat(source);
132
+ if (details.size > maxBytes) {
133
+ throw new Error(`Lumen registry exceeds the ${maxBytes} byte limit.`);
134
+ }
135
+ return readFile(source, 'utf8');
81
136
  };
82
137
  export const loadLumenRegistry = async (source, options = {}) => {
83
138
  const sourceValue = String(source);
139
+ const maxBytes = resolvePositiveInteger(options.maxBytes, defaultRegistryMaxBytes, 'maxBytes');
84
140
  const raw = sourceValue.startsWith('http://') || sourceValue.startsWith('https://') ?
85
- await fetchRegistrySource(sourceValue, options) :
86
- await readFile(source, 'utf8');
87
- const parsed = JSON.parse(raw);
141
+ await fetchRegistrySource(sourceValue, options, maxBytes) :
142
+ await readRegistrySource(source, maxBytes);
143
+ let parsed;
144
+ try {
145
+ parsed = JSON.parse(raw);
146
+ }
147
+ catch {
148
+ throw new Error('Invalid Lumen registry JSON');
149
+ }
88
150
  if (!isLumenRegistry(parsed)) {
89
151
  throw new Error('Invalid Lumen registry manifest');
90
152
  }
@@ -0,0 +1,29 @@
1
+ export type LumenV2MigrationKind = 'astro-runtime-subpath' | 'react-native-datetime-subpath' | 'sonner-alias-removal' | 'visual-size-alias-removal';
2
+ export interface LumenV2MigrationFinding {
3
+ column: number;
4
+ file: string;
5
+ kind: LumenV2MigrationKind;
6
+ line: number;
7
+ message: string;
8
+ }
9
+ export interface LumenV2SourceMigration {
10
+ changes: LumenV2MigrationFinding[];
11
+ manualReview: LumenV2MigrationFinding[];
12
+ source: string;
13
+ }
14
+ export interface LumenV2MigrationOptions {
15
+ apply?: boolean;
16
+ cwd?: string;
17
+ }
18
+ export interface LumenV2MigrationReport {
19
+ applied: boolean;
20
+ changedFiles: string[];
21
+ changes: LumenV2MigrationFinding[];
22
+ filesScanned: number;
23
+ manualReview: LumenV2MigrationFinding[];
24
+ root: string;
25
+ }
26
+ export declare const migrateLumenV2Source: (source: string, file?: string) => LumenV2SourceMigration;
27
+ export declare const migrateLumenV2: (options?: LumenV2MigrationOptions) => Promise<LumenV2MigrationReport>;
28
+ export declare const formatLumenV2Migration: (report: LumenV2MigrationReport) => string;
29
+ //# sourceMappingURL=v2-migration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-migration.d.ts","sourceRoot":"","sources":["../src/v2-migration.ts"],"names":[],"mappings":"AA4CA,MAAM,MAAM,oBAAoB,GAC5B,uBAAuB,GACzB,+BAA+B,GAC/B,sBAAsB,GACtB,2BAA2B,CAAA;AAE7B,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,oBAAoB,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAClC,YAAY,EAAE,uBAAuB,EAAE,CAAA;IACvC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,uBAAuB,EAAE,CAAA;IACvC,IAAI,EAAE,MAAM,CAAA;CACb;AA8nCD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,MAAM,EACd,aAAiB,KAChB,sBA4DF,CAAA;AAqBD,eAAO,MAAM,cAAc,GACzB,UAAS,uBAA4B,KACpC,OAAO,CAAC,sBAAsB,CAgChC,CAAA;AAED,eAAO,MAAM,sBAAsB,GACjC,QAAQ,sBAAsB,KAC7B,MA0BF,CAAA"}