@cortexkit/common-auth 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.
- package/LICENSE +21 -0
- package/README.md +10 -0
- package/dist/fs/atomic-write.d.ts +5 -0
- package/dist/fs/atomic-write.js +22 -0
- package/dist/fs/index.d.ts +5 -0
- package/dist/fs/index.js +3 -0
- package/dist/fs/lock-constants.d.ts +14 -0
- package/dist/fs/lock-constants.js +14 -0
- package/dist/fs/refresh-file-lock.d.ts +18 -0
- package/dist/fs/refresh-file-lock.js +392 -0
- package/dist/fs/with-lock.d.ts +32 -0
- package/dist/fs/with-lock.js +48 -0
- package/dist/logger/capture-sink.d.ts +14 -0
- package/dist/logger/capture-sink.js +13 -0
- package/dist/logger/engine.d.ts +44 -0
- package/dist/logger/engine.js +199 -0
- package/dist/logger/index.d.ts +6 -0
- package/dist/logger/index.js +3 -0
- package/dist/logger/redact.d.ts +11 -0
- package/dist/logger/redact.js +45 -0
- package/dist/rpc/index.d.ts +10 -0
- package/dist/rpc/index.js +5 -0
- package/dist/rpc/notifications.d.ts +29 -0
- package/dist/rpc/notifications.js +57 -0
- package/dist/rpc/port-file.d.ts +20 -0
- package/dist/rpc/port-file.js +164 -0
- package/dist/rpc/rpc-client.d.ts +8 -0
- package/dist/rpc/rpc-client.js +51 -0
- package/dist/rpc/rpc-server.d.ts +19 -0
- package/dist/rpc/rpc-server.js +135 -0
- package/dist/rpc/server-registry.d.ts +11 -0
- package/dist/rpc/server-registry.js +47 -0
- package/dist/sidebar-file/index.d.ts +2 -0
- package/dist/sidebar-file/index.js +1 -0
- package/dist/sidebar-file/sidebar-file.d.ts +23 -0
- package/dist/sidebar-file/sidebar-file.js +84 -0
- package/dist/tui/index.d.ts +8 -0
- package/dist/tui/index.js +21 -0
- package/dist/tui-build/build-tui.d.ts +23 -0
- package/dist/tui-build/build-tui.js +190 -0
- package/dist/tui-build/index.d.ts +3 -0
- package/dist/tui-build/index.js +2 -0
- package/dist/tui-build/publish-list.d.ts +2 -0
- package/dist/tui-build/publish-list.js +20 -0
- package/dist/tui-build/walker.d.ts +8 -0
- package/dist/tui-build/walker.js +171 -0
- package/dist/tui-prefs/index.d.ts +2 -0
- package/dist/tui-prefs/index.js +2 -0
- package/dist/tui-prefs/tui-preferences.d.ts +25 -0
- package/dist/tui-prefs/tui-preferences.js +77 -0
- package/dist/tui-prefs/watcher.d.ts +6 -0
- package/dist/tui-prefs/watcher.js +74 -0
- package/package.json +89 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/** Locate module strings without treating comments or ordinary strings as imports. */
|
|
2
|
+
export function parseImports(code, filename) {
|
|
3
|
+
const tokens = [];
|
|
4
|
+
let position = 0;
|
|
5
|
+
const push = (start) => tokens.push({ text: code.slice(start, position), start, end: position });
|
|
6
|
+
const scan = (templateExpression = false) => {
|
|
7
|
+
let depth = 0;
|
|
8
|
+
while (position < code.length) {
|
|
9
|
+
const start = position;
|
|
10
|
+
const character = code.charAt(position);
|
|
11
|
+
if (/\s/.test(character)) {
|
|
12
|
+
position++;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (code.startsWith('//', position)) {
|
|
16
|
+
position = code.indexOf('\n', position);
|
|
17
|
+
if (position < 0)
|
|
18
|
+
position = code.length;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (code.startsWith('/*', position)) {
|
|
22
|
+
const end = code.indexOf('*/', position + 2);
|
|
23
|
+
position = end < 0 ? code.length : end + 2;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (character === '"' || character === "'") {
|
|
27
|
+
position++;
|
|
28
|
+
while (position < code.length) {
|
|
29
|
+
const next = code[position++];
|
|
30
|
+
if (next === '\\')
|
|
31
|
+
position++;
|
|
32
|
+
else if (next === character)
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
push(start);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (character === '`') {
|
|
39
|
+
position++;
|
|
40
|
+
push(start);
|
|
41
|
+
while (position < code.length) {
|
|
42
|
+
if (code[position] === '\\') {
|
|
43
|
+
position += 2;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (code[position] === '`') {
|
|
47
|
+
position++;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
if (code.startsWith('${', position)) {
|
|
51
|
+
position += 2;
|
|
52
|
+
scan(true);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
position++;
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
// A regex body can contain import-shaped text that is not executable code.
|
|
60
|
+
const previous = tokens.at(-1)?.text;
|
|
61
|
+
if (character === '/' &&
|
|
62
|
+
(!previous ||
|
|
63
|
+
[
|
|
64
|
+
'=',
|
|
65
|
+
'(',
|
|
66
|
+
'[',
|
|
67
|
+
'{',
|
|
68
|
+
',',
|
|
69
|
+
':',
|
|
70
|
+
';',
|
|
71
|
+
'return',
|
|
72
|
+
'=>',
|
|
73
|
+
'!',
|
|
74
|
+
'&&',
|
|
75
|
+
'||',
|
|
76
|
+
].includes(previous))) {
|
|
77
|
+
position++;
|
|
78
|
+
let inClass = false;
|
|
79
|
+
while (position < code.length) {
|
|
80
|
+
const next = code[position++];
|
|
81
|
+
if (next === '\\') {
|
|
82
|
+
position++;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (next === '[')
|
|
86
|
+
inClass = true;
|
|
87
|
+
if (next === ']')
|
|
88
|
+
inClass = false;
|
|
89
|
+
if (next === '/' && !inClass)
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
while (/[a-z]/i.test(code[position] ?? '') && position < code.length)
|
|
93
|
+
position++;
|
|
94
|
+
push(start);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (templateExpression && character === '}' && depth === 0) {
|
|
98
|
+
position++;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (character === '{')
|
|
102
|
+
depth++;
|
|
103
|
+
if (character === '}')
|
|
104
|
+
depth--;
|
|
105
|
+
if (/[\w$]/.test(character)) {
|
|
106
|
+
position++;
|
|
107
|
+
while (position < code.length && /[\w$]/.test(code.charAt(position)))
|
|
108
|
+
position++;
|
|
109
|
+
}
|
|
110
|
+
else
|
|
111
|
+
position++;
|
|
112
|
+
push(start);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
scan();
|
|
116
|
+
const references = [];
|
|
117
|
+
const add = (token) => {
|
|
118
|
+
if (!/^["']/.test(token.text))
|
|
119
|
+
return;
|
|
120
|
+
const specifier = token.text.slice(1, -1).replace(/\\(['"\\])/g, '$1');
|
|
121
|
+
references.push({ specifier, start: token.start, end: token.end });
|
|
122
|
+
};
|
|
123
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
124
|
+
const token = tokens[i];
|
|
125
|
+
if (!token)
|
|
126
|
+
continue;
|
|
127
|
+
if (token.text !== 'import' && token.text !== 'export')
|
|
128
|
+
continue;
|
|
129
|
+
if (tokens[i - 1]?.text === '.')
|
|
130
|
+
continue;
|
|
131
|
+
const next = tokens[i + 1];
|
|
132
|
+
if (!next || next.text === '.')
|
|
133
|
+
continue;
|
|
134
|
+
if (token.text === 'import' && next.text === '(') {
|
|
135
|
+
const argument = tokens[i + 2];
|
|
136
|
+
if (!argument ||
|
|
137
|
+
!/^["']/.test(argument.text) ||
|
|
138
|
+
![')', ','].includes(tokens[i + 3]?.text ?? '')) {
|
|
139
|
+
throw new Error(`Non-literal dynamic import in ${filename}: ${code.slice(next.end, code.indexOf(')', next.end))}`);
|
|
140
|
+
}
|
|
141
|
+
add(argument);
|
|
142
|
+
}
|
|
143
|
+
else if (/^["']/.test(next.text)) {
|
|
144
|
+
add(next);
|
|
145
|
+
}
|
|
146
|
+
else if (['{', '*', 'type'].includes(next.text) ||
|
|
147
|
+
token.text === 'import') {
|
|
148
|
+
for (let j = i + 1; j < tokens.length; j++) {
|
|
149
|
+
const candidate = tokens[j];
|
|
150
|
+
if (!candidate)
|
|
151
|
+
continue;
|
|
152
|
+
if (candidate.text === ';' ||
|
|
153
|
+
candidate.text === 'import' ||
|
|
154
|
+
candidate.text === 'export')
|
|
155
|
+
break;
|
|
156
|
+
if (candidate.text === 'from') {
|
|
157
|
+
const source = tokens[j + 1];
|
|
158
|
+
if (source)
|
|
159
|
+
add(source);
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return references;
|
|
166
|
+
}
|
|
167
|
+
export function isBareSpecifier(specifier) {
|
|
168
|
+
return (!specifier.startsWith('.') &&
|
|
169
|
+
!specifier.startsWith('/') &&
|
|
170
|
+
!specifier.includes(':'));
|
|
171
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { createTuiPreferenceWriter, type PreferenceValue, readTuiPreferences, readTuiPreferencesFile, type TuiPreferencesReaderOptions, type TuiPreferenceWriter, type TuiPreferenceWriterOptions, } from './tui-preferences.js';
|
|
2
|
+
export { type TuiPreferencesWatchOptions, watchTuiPreferences, } from './watcher.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Malformed or missing user-edited files are treated as an empty root. */
|
|
2
|
+
export declare function readTuiPreferencesFile(file: string): Promise<Record<string, unknown>>;
|
|
3
|
+
export interface TuiPreferencesReaderOptions<T> {
|
|
4
|
+
file: string;
|
|
5
|
+
pluginKey: string;
|
|
6
|
+
defaults: T;
|
|
7
|
+
/** The caller owns validation, clamping, and merging of its settings. */
|
|
8
|
+
schema: (entry: unknown, defaults: T) => T;
|
|
9
|
+
}
|
|
10
|
+
export declare function readTuiPreferences<T>(options: TuiPreferencesReaderOptions<T>): Promise<T>;
|
|
11
|
+
export type PreferenceValue = string | number | boolean | null | PreferenceValue[] | {
|
|
12
|
+
[key: string]: PreferenceValue;
|
|
13
|
+
};
|
|
14
|
+
export interface TuiPreferenceWriterOptions {
|
|
15
|
+
file: string;
|
|
16
|
+
pluginKey: string;
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
/** @internal Runs after staging, before the writer's ownership fence. */
|
|
19
|
+
beforeCommit?: () => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export interface TuiPreferenceWriter {
|
|
22
|
+
queueTuiPreferenceUpdate(path: readonly (string | number)[], value: PreferenceValue): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/** Each instance serializes updates; the file lock also excludes other processes. */
|
|
25
|
+
export declare function createTuiPreferenceWriter(options: TuiPreferenceWriterOptions): TuiPreferenceWriter;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { applyEdits, modify, parse } from 'jsonc-parser';
|
|
3
|
+
import { writeJsonAtomic } from '../fs/atomic-write.js';
|
|
4
|
+
import { WRITER_LOCK_CONSTANTS } from '../fs/lock-constants.js';
|
|
5
|
+
import { withLock } from '../fs/with-lock.js';
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
/** Malformed or missing user-edited files are treated as an empty root. */
|
|
10
|
+
export async function readTuiPreferencesFile(file) {
|
|
11
|
+
try {
|
|
12
|
+
const errors = [];
|
|
13
|
+
const root = parse(await readFile(file, 'utf8'), errors, {
|
|
14
|
+
allowTrailingComma: true,
|
|
15
|
+
});
|
|
16
|
+
return errors.length === 0 && isRecord(root) ? root : {};
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function readTuiPreferences(options) {
|
|
23
|
+
const root = await readTuiPreferencesFile(options.file);
|
|
24
|
+
const entry = Object.hasOwn(root, options.pluginKey)
|
|
25
|
+
? root[options.pluginKey]
|
|
26
|
+
: undefined;
|
|
27
|
+
return options.schema(entry, options.defaults);
|
|
28
|
+
}
|
|
29
|
+
const TEMPLATE = `// Shared preferences for TUI plugins.
|
|
30
|
+
// Plugins update individual keys in place and preserve comments.
|
|
31
|
+
{}
|
|
32
|
+
`;
|
|
33
|
+
/** Each instance serializes updates; the file lock also excludes other processes. */
|
|
34
|
+
export function createTuiPreferenceWriter(options) {
|
|
35
|
+
const { file, pluginKey, beforeCommit } = options;
|
|
36
|
+
const lockOptions = {
|
|
37
|
+
...WRITER_LOCK_CONSTANTS.preferences,
|
|
38
|
+
timeoutMs: options.timeoutMs ?? WRITER_LOCK_CONSTANTS.preferences.timeoutMs,
|
|
39
|
+
};
|
|
40
|
+
let chain = Promise.resolve();
|
|
41
|
+
async function writePreference(path, value) {
|
|
42
|
+
await withLock(file, lockOptions, async (lock) => {
|
|
43
|
+
let text;
|
|
44
|
+
try {
|
|
45
|
+
text = await readFile(file, 'utf8');
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error.code !== 'ENOENT')
|
|
49
|
+
throw error;
|
|
50
|
+
text = '';
|
|
51
|
+
}
|
|
52
|
+
if (text.trim() === '')
|
|
53
|
+
text = TEMPLATE;
|
|
54
|
+
const next = applyEdits(text, modify(text, [pluginKey, ...path], value, {
|
|
55
|
+
formattingOptions: { insertSpaces: true, tabSize: 2 },
|
|
56
|
+
}));
|
|
57
|
+
await writeJsonAtomic(file, next, {
|
|
58
|
+
serialize: (value) => String(value),
|
|
59
|
+
beforeRename: async () => {
|
|
60
|
+
await beforeCommit?.();
|
|
61
|
+
await lock.assertOwned();
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
queueTuiPreferenceUpdate(path, value) {
|
|
68
|
+
// Snapshot inputs so queued callers cannot change an update before it runs.
|
|
69
|
+
const savedPath = [...path];
|
|
70
|
+
const savedValue = structuredClone(value);
|
|
71
|
+
const update = chain.then(() => writePreference(savedPath, savedValue));
|
|
72
|
+
// Recover only the stored tail; the caller still sees the original rejection.
|
|
73
|
+
chain = update.catch(() => { });
|
|
74
|
+
return update;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { watch } from 'node:fs';
|
|
2
|
+
export interface TuiPreferencesWatchOptions {
|
|
3
|
+
watchDirectory?: typeof watch;
|
|
4
|
+
}
|
|
5
|
+
/** Watch the directory so atomic file replacement does not detach the watcher. */
|
|
6
|
+
export declare function watchTuiPreferences(file: string, onChange: () => void, options?: TuiPreferencesWatchOptions): () => void;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { readFileSync, watch } from 'node:fs';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { basename, dirname } from 'node:path';
|
|
4
|
+
import { clearTimeout, setTimeout } from 'node:timers';
|
|
5
|
+
/** Watch the directory so atomic file replacement does not detach the watcher. */
|
|
6
|
+
export function watchTuiPreferences(file, onChange, options = {}) {
|
|
7
|
+
const name = basename(file);
|
|
8
|
+
let timer = null;
|
|
9
|
+
// An asynchronous seed could absorb a write made immediately after returning.
|
|
10
|
+
let lastSeen = null;
|
|
11
|
+
try {
|
|
12
|
+
lastSeen = readFileSync(file, 'utf8');
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Missing files can be created later.
|
|
16
|
+
}
|
|
17
|
+
let disposed = false;
|
|
18
|
+
const checkForChange = async () => {
|
|
19
|
+
const text = await readFile(file, 'utf8').catch(() => null);
|
|
20
|
+
if (disposed || text === null || text === lastSeen)
|
|
21
|
+
return;
|
|
22
|
+
lastSeen = text;
|
|
23
|
+
onChange();
|
|
24
|
+
};
|
|
25
|
+
const scheduleCheck = () => {
|
|
26
|
+
if (timer)
|
|
27
|
+
clearTimeout(timer);
|
|
28
|
+
timer = setTimeout(() => {
|
|
29
|
+
timer = null;
|
|
30
|
+
void checkForChange();
|
|
31
|
+
}, 150);
|
|
32
|
+
};
|
|
33
|
+
let watcher = null;
|
|
34
|
+
try {
|
|
35
|
+
watcher = (options.watchDirectory ?? watch)(dirname(file), (_event, filename) => {
|
|
36
|
+
const eventName = filename?.toString();
|
|
37
|
+
const isOurs = eventName === name ||
|
|
38
|
+
(eventName?.startsWith(`${name}.`) && eventName.endsWith('.tmp'));
|
|
39
|
+
if (eventName != null && !isOurs)
|
|
40
|
+
return;
|
|
41
|
+
scheduleCheck();
|
|
42
|
+
});
|
|
43
|
+
watcher.on('error', () => {
|
|
44
|
+
// Polling continues if the native watcher fails after construction.
|
|
45
|
+
watcher?.close();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
if (lastSeen === null)
|
|
50
|
+
return () => { };
|
|
51
|
+
}
|
|
52
|
+
// Poll independently: directory watchers can miss rename events.
|
|
53
|
+
let pollTimer = null;
|
|
54
|
+
const schedulePoll = () => {
|
|
55
|
+
if (disposed || pollTimer)
|
|
56
|
+
return;
|
|
57
|
+
pollTimer = setTimeout(() => {
|
|
58
|
+
pollTimer = null;
|
|
59
|
+
if (disposed)
|
|
60
|
+
return;
|
|
61
|
+
void checkForChange().finally(schedulePoll);
|
|
62
|
+
}, 100);
|
|
63
|
+
pollTimer.unref();
|
|
64
|
+
};
|
|
65
|
+
schedulePoll();
|
|
66
|
+
return () => {
|
|
67
|
+
disposed = true;
|
|
68
|
+
if (timer)
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
if (pollTimer)
|
|
71
|
+
clearTimeout(pollTimer);
|
|
72
|
+
watcher?.close();
|
|
73
|
+
};
|
|
74
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cortexkit/common-auth",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared plumbing for the CortexKit auth plugins: loopback RPC, file locks and atomic writes, logger, sidebar state file, TUI preferences and TUI build.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/cortexkit/common-auth.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"workspaces": [
|
|
12
|
+
"test/fixtures/*"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
"./rpc": {
|
|
16
|
+
"types": "./dist/rpc/index.d.ts",
|
|
17
|
+
"import": "./dist/rpc/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./fs": {
|
|
20
|
+
"types": "./dist/fs/index.d.ts",
|
|
21
|
+
"import": "./dist/fs/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./logger": {
|
|
24
|
+
"types": "./dist/logger/index.d.ts",
|
|
25
|
+
"import": "./dist/logger/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./sidebar-file": {
|
|
28
|
+
"types": "./dist/sidebar-file/index.d.ts",
|
|
29
|
+
"import": "./dist/sidebar-file/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./tui-prefs": {
|
|
32
|
+
"types": "./dist/tui-prefs/index.d.ts",
|
|
33
|
+
"import": "./dist/tui-prefs/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./tui-build": {
|
|
36
|
+
"types": "./dist/tui-build/index.d.ts",
|
|
37
|
+
"import": "./dist/tui-build/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./tui": {
|
|
40
|
+
"types": "./dist/tui/index.d.ts",
|
|
41
|
+
"import": "./dist/tui/index.js"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist/"
|
|
46
|
+
],
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "bun scripts/check-installed-ranges.mjs && tsc -p tsconfig.build.json",
|
|
49
|
+
"test": "bun test",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"types": "bun run typecheck",
|
|
52
|
+
"format": "biome check --write --unsafe .",
|
|
53
|
+
"format:check": "biome format .",
|
|
54
|
+
"lint": "biome lint .",
|
|
55
|
+
"prepublishOnly": "bun run build",
|
|
56
|
+
"check:ranges": "bun scripts/check-installed-ranges.mjs"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"jsonc-parser": "^3.3.1"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"@opentui/core": ">=0.5.12",
|
|
63
|
+
"@opentui/solid": ">=0.5.12",
|
|
64
|
+
"solid-js": "1.9.12"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"@opentui/core": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"@opentui/solid": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"solid-js": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@biomejs/biome": "2.5.14",
|
|
79
|
+
"@opentui/core": ">=0.5.12",
|
|
80
|
+
"@opentui/solid": ">=0.5.12",
|
|
81
|
+
"@tsconfig/bun": "1.0.11",
|
|
82
|
+
"@types/bun": "1.4.2",
|
|
83
|
+
"bun-types": "1.4.2",
|
|
84
|
+
"inline-default": "workspace:*",
|
|
85
|
+
"lefthook": "2.1.14",
|
|
86
|
+
"solid-js": "1.9.12",
|
|
87
|
+
"typescript": "7.0.2"
|
|
88
|
+
}
|
|
89
|
+
}
|