sandstone-cli 2.0.8 → 2.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.
@@ -1,279 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import { subscribe } from '@parcel/watcher';
3
- import React from 'react';
4
- import { render } from 'ink';
5
- import { normalizePath } from '../utils.js';
6
- import { _buildCommand, enableConsoleCapture, disableConsoleCapture } from './build.js';
7
- import { WatchUI, getWatchUIAPI } from '../ui/WatchUI.js';
8
- import { initLogger, log, logError, setLiveLogCallback } from '../ui/logger.js';
9
- import { hot } from '@sandstone-mc/hot-hook';
10
- import fs from 'fs-extra';
11
- import { join } from 'node:path';
12
- export async function watchCommand(opts) {
13
- let alreadyBuilding = false;
14
- let needRebuild = false;
15
- let pendingChanges = [];
16
- let buildContext;
17
- let hotInitialized = false;
18
- let lastBuildFailed = false;
19
- const folder = opts.library ? join(opts.path, 'test') : opts.path;
20
- let subscription;
21
- // Initialize logger
22
- initLogger(folder);
23
- // Set up live log callback to send to UI
24
- setLiveLogCallback((level, args) => {
25
- getWatchUIAPI()?.setLiveLog(level, args);
26
- });
27
- // Render Ink UI
28
- let unmountInk;
29
- const handleManualRebuild = () => {
30
- if (pendingChanges.length > 0 && !alreadyBuilding) {
31
- log('Manual rebuild triggered');
32
- onFilesChange(pendingChanges);
33
- pendingChanges = [];
34
- }
35
- };
36
- const { unmount } = render(React.createElement(WatchUI, {
37
- manual: opts.manual ?? false,
38
- onManualRebuild: handleManualRebuild,
39
- // Since this isn't SIGINT, its fine that we don't await this
40
- exit: () => exit(subscription, unmountInk)
41
- }), { patchConsole: false });
42
- unmountInk = unmount;
43
- async function onFilesChange(changes) {
44
- // Synchronous check-and-set to prevent race conditions
45
- if (alreadyBuilding) {
46
- needRebuild = true;
47
- // Accumulate changes for the next build
48
- for (const change of changes) {
49
- if (!pendingChanges.some(c => c.path === change.path)) {
50
- pendingChanges.push(change);
51
- }
52
- }
53
- return;
54
- }
55
- alreadyBuilding = true;
56
- const api = getWatchUIAPI();
57
- api?.setStatus('building');
58
- api?.setChangedFiles(changes);
59
- log('Building...', changes.map(c => c.path).join(', '));
60
- const libChanges = opts.library && Object.hasOwn(globalThis, 'Bun') ? changes.filter((change) => !change.path.includes('test/')) : [];
61
- if (libChanges.length !== 0) {
62
- /* @ts-ignore */
63
- const CLI = Bun.spawn(['bun', 'dev:build'], {
64
- windowsHide: true,
65
- windowsVerbatimArguments: true,
66
- stdout: 'ignore',
67
- stderr: 'ignore',
68
- });
69
- await CLI.exited;
70
- }
71
- // Initialize hot-hook only once on the first build
72
- if (!hotInitialized) {
73
- await hot.init({
74
- root: join(folder, JSON.parse(await fs.readFile(join(folder, 'package.json'), 'utf-8'))['module']),
75
- // Ensure sandstone remains a singleton so CLI and user code share the same pack instance
76
- globalSingletons: ['**/node_modules/sandstone/**', '**/sandstone/dist/**'],
77
- // Disable hot-hook's internal watcher - we use parcel watcher and notify hot-hook
78
- watch: false,
79
- });
80
- hotInitialized = true;
81
- }
82
- if (Object.hasOwn(globalThis, 'Bun') && changes.length > 0) {
83
- // Bun ignores query params for module caching and doesn't support MessagePort
84
- // in register(), so hot-hook's invalidation mechanism is non-functional.
85
- // Instead, clear Bun's module cache for project source files before re-importing.
86
- const resolvedFolder = normalizePath(await fs.realpath(folder));
87
- const resolvedRoot = opts.library ? normalizePath(await fs.realpath(opts.path)) : resolvedFolder;
88
- let clearedCount = 0;
89
- for (const key of Object.keys(require.cache)) {
90
- const normalizedKey = normalizePath(key);
91
- // Only clear modules within the project
92
- if (!normalizedKey.startsWith(resolvedFolder) && !normalizedKey.startsWith(resolvedRoot))
93
- continue;
94
- // Keep sandstone singleton cached so CLI and user code share the same pack instance
95
- if (normalizedKey.includes('/node_modules/sandstone/'))
96
- continue;
97
- delete require.cache[key];
98
- clearedCount++;
99
- }
100
- // If recovering from a failed build but no modules were in cache, Bun had a parse error
101
- // and won't be able to reimport. Exit and ask user to restart.
102
- if (lastBuildFailed && clearedCount === 0) {
103
- getWatchUIAPI()?.setStatus('error', 'Parse error - restart required');
104
- unmountInk?.();
105
- process.stderr.write('\n\x1b[33mBun encountered a parse error and cannot recover. Please restart the watch command.\x1b[0m\n\n');
106
- process.exit(1);
107
- }
108
- }
109
- else {
110
- // Node.js path: use hot-hook's message port invalidation
111
- for (const change of changes) {
112
- hot.notifyFileChange(change.path);
113
- }
114
- if (libChanges.length !== 0) {
115
- const libModuleFiles = await fs.readdir(join(opts.path, 'lib'), { recursive: true });
116
- for (const file of libModuleFiles) {
117
- hot.notifyFileChange(join(opts.path, 'lib', file));
118
- }
119
- }
120
- // Small delay to let the loader process the invalidations
121
- if (changes.length > 0) {
122
- await new Promise(resolve => setTimeout(resolve, 10));
123
- }
124
- }
125
- // Replace global console during build to capture user console.log without messing up Ink UI
126
- enableConsoleCapture();
127
- let result;
128
- try {
129
- result = await _buildCommand(opts, folder, buildContext, true);
130
- }
131
- finally {
132
- disableConsoleCapture();
133
- }
134
- // Store context for subsequent builds
135
- if (result.success && result.sandstoneConfig !== undefined) {
136
- buildContext = {
137
- sandstoneConfig: result.sandstoneConfig,
138
- sandstonePack: result.sandstonePack,
139
- resetSandstonePack: result.resetSandstonePack,
140
- };
141
- }
142
- api?.setBuildResult(result);
143
- if (result.success) {
144
- log(`Build successful: ${result.resourceCounts.functions} functions, ${result.resourceCounts.other} others`);
145
- lastBuildFailed = false;
146
- }
147
- else {
148
- logError(result.error);
149
- lastBuildFailed = true;
150
- }
151
- alreadyBuilding = false;
152
- if (needRebuild) {
153
- needRebuild = false;
154
- // Use accumulated pending changes, then clear them
155
- const nextChanges = [...pendingChanges];
156
- pendingChanges = [];
157
- await onFilesChange(nextChanges);
158
- }
159
- }
160
- let restartTimeout = null;
161
- let debouncedChanges = []; // Accumulate changes during debounce period
162
- let debounceScheduled = false; // Synchronous flag to prevent multiple timeouts
163
- function restart() {
164
- log('Restarting watch process...');
165
- getWatchUIAPI()?.setStatus('restarting');
166
- const [runtime, ...args] = process.argv;
167
- const child = spawn(runtime, args, {
168
- stdio: 'inherit',
169
- detached: true,
170
- });
171
- child.unref();
172
- unmountInk?.();
173
- process.exit(0);
174
- }
175
- const handleEvents = (events) => {
176
- // Whether changes require a full process restart
177
- let needsRestart = false;
178
- // Filter out irrelevant events and categorize
179
- const trackedChanges = [];
180
- for (const e of events) {
181
- const eventPath = normalizePath(e.path);
182
- const lockFile = eventPath.endsWith('.lock') ||
183
- eventPath.endsWith('-lock.yml') ||
184
- eventPath.endsWith('-lock.json');
185
- if (lockFile ||
186
- eventPath.includes('node_modules/') ||
187
- eventPath.endsWith('sandstone.config.ts')) {
188
- needsRestart = true;
189
- }
190
- const inSrc = eventPath.includes('src/');
191
- const inResources = eventPath.includes('resources/');
192
- const endsJs = eventPath.endsWith('.js');
193
- const endsJson = eventPath.endsWith('.json');
194
- const endsTs = eventPath.endsWith('.ts');
195
- if (inSrc || inResources || endsJs || endsJson || endsTs) {
196
- trackedChanges.push({
197
- path: eventPath,
198
- category: categorizeChange(eventPath),
199
- });
200
- }
201
- }
202
- if (trackedChanges.length === 0 && !needsRestart) {
203
- return;
204
- }
205
- if (needsRestart) {
206
- if (restartTimeout) {
207
- clearTimeout(restartTimeout);
208
- }
209
- // Debounce restart to allow package manager to finish
210
- restartTimeout = setTimeout(restart, 500);
211
- return;
212
- }
213
- // Accumulate changes, deduplicating by path
214
- for (const change of trackedChanges) {
215
- if (!debouncedChanges.some(c => c.path === change.path)) {
216
- debouncedChanges.push(change);
217
- }
218
- }
219
- // Use a synchronous flag to ensure only one timeout is scheduled
220
- // This prevents race conditions when parcel watcher fires multiple callbacks rapidly
221
- if (debounceScheduled)
222
- return;
223
- debounceScheduled = true;
224
- setTimeout(() => {
225
- debounceScheduled = false;
226
- const changesToProcess = [...debouncedChanges];
227
- debouncedChanges = []; // Clear for next batch
228
- if (changesToProcess.length === 0) {
229
- return;
230
- }
231
- if (opts.manual) {
232
- // In manual mode, accumulate changes and wait for user input
233
- pendingChanges = [...pendingChanges, ...changesToProcess];
234
- getWatchUIAPI()?.setStatus('pending');
235
- getWatchUIAPI()?.setChangedFiles(pendingChanges);
236
- }
237
- else {
238
- // Auto mode - rebuild immediately
239
- // onFilesChange handles the "already building" case internally
240
- onFilesChange(changesToProcess);
241
- }
242
- }, 200);
243
- };
244
- log('Watch started');
245
- // Initial build
246
- await onFilesChange([]);
247
- subscription = await subscribe(opts.path, (err, events) => {
248
- if (err) {
249
- logError(err);
250
- return;
251
- }
252
- handleEvents(events);
253
- }, {
254
- ignore: ['**/.git/**/*', '**/.sandstone/**/*', '**/resources/cache/**/*', '**/*tmp*', 'lib/**/*'],
255
- });
256
- // Handle cleanup on exit
257
- process.on('SIGINT', async () => await exit(subscription, unmountInk));
258
- }
259
- async function exit(subscription, unmountInk) {
260
- log('Watch stopped');
261
- unmountInk?.();
262
- await subscription.unsubscribe();
263
- process.exit(0);
264
- }
265
- function categorizeChange(eventPath) {
266
- if (eventPath.includes('src/'))
267
- return 'src';
268
- if (eventPath.includes('resources/'))
269
- return 'resources';
270
- if (eventPath.endsWith('sandstone.config.ts'))
271
- return 'config';
272
- if (eventPath.endsWith('.lock') ||
273
- eventPath.endsWith('-lock.yml') ||
274
- eventPath.endsWith('-lock.json') ||
275
- eventPath.includes('node_modules/')) {
276
- return 'dependencies';
277
- }
278
- return 'other';
279
- }
package/lib/create.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env bun
2
- export {};
package/lib/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env bun
2
- export {};
package/lib/shared.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare const BuildDeclares: Record<string, [string, string, RegExp, boolean]>;
package/lib/shared.js DELETED
@@ -1,20 +0,0 @@
1
- export const BuildDeclares = {
2
- // Flags
3
- dry: ['-d, --dry', 'Do not save the pack. Mostly useful with `verbose`.'],
4
- verbose: ['-f, --verbose', 'Fully log all resulting resources: functions, advancements...'],
5
- root: ['-r, --root', 'Save the pack & resource pack in the .minecraft/datapacks & .minecraft/resource_packs folders. Override the value specified in the configuration file.'],
6
- fullTrace: ['-t, --full-trace', 'Show the full stack trace on errors.'],
7
- strictErrors: ['-s, --strict-errors', 'Stop pack compilation on type errors.'],
8
- production: ['-p, --production', 'Runs Sandstone in production mode. This sets process.env.SANDSTONE_ENV to "production".'],
9
- // Values
10
- path: ['--path <path>', 'Path of the folder containing your sandstone workspace.', './'],
11
- name: ['-n, --name <name>', 'Name of the datapack. Override the value specified in the configuration file.'],
12
- namespace: ['-ns, --namespace <namespace>', 'The default namespace. Override the value specified in the configuration file.'],
13
- world: ['-w, --world <name>', 'The name of the world to save the packs in. Override the value specified in the configuration file.'],
14
- clientPath: ['-c, --client-path <path>', 'Path of the client folder. Override the value specified in the configuration file.'],
15
- serverPath: ['--server-path <path>', 'Path of the server folder. Override the value specified in the configuration file.'],
16
- // TODO: ssh
17
- enableSymlinks: ['--enable-symlinks', 'Force enable/disable symlinks. Defaults to false. Useful if you want to enable symlinks on Windows.'],
18
- manual: ['-m, --manual', 'Manual reload mode - press r or Enter to rebuild after changes.'],
19
- library: ['-l, --library', 'Library mode - watches a library workspace based on the library project template.'],
20
- }; // Haha TypeScript funny
@@ -1,9 +0,0 @@
1
- import type { WatchUIAPI } from './types.js';
2
- interface WatchUIProps {
3
- manual: boolean;
4
- onManualRebuild?: () => void;
5
- exit?: () => void;
6
- }
7
- export declare function WatchUI({ manual, onManualRebuild, exit }: WatchUIProps): import("react/jsx-runtime").JSX.Element;
8
- export declare function getWatchUIAPI(): WatchUIAPI | undefined;
9
- export {};
package/lib/ui/WatchUI.js DELETED
@@ -1,183 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useCallback, useEffect } from 'react';
3
- import { Box, Text, useInput } from 'ink';
4
- import Spinner from 'ink-spinner';
5
- import { format } from 'util';
6
- import { drainLiveLogBuffer } from './logger.js';
7
- const CONTENT_LINES = 8;
8
- function formatChangedFiles(files) {
9
- if (files.length === 0)
10
- return 'No recent changes';
11
- const paths = files.map(f => f.path.split(/[/\\]/).pop() || f.path);
12
- if (paths.length <= 3)
13
- return paths.join(', ');
14
- return `${paths.slice(0, 3).join(', ')} +${paths.length - 3} more`;
15
- }
16
- function groupByCategory(files) {
17
- const groups = {
18
- src: [],
19
- resources: [],
20
- config: [],
21
- dependencies: [],
22
- other: [],
23
- };
24
- for (const file of files) {
25
- const name = file.path.split(/[/\\]/).pop() || file.path;
26
- groups[file.category].push(name);
27
- }
28
- return groups;
29
- }
30
- const categoryLabels = {
31
- src: 'src',
32
- resources: 'resources',
33
- config: 'config',
34
- dependencies: 'dependencies',
35
- other: 'other',
36
- };
37
- function ContentDisplay({ mode, logLines, errorText, changes, scrollOffset }) {
38
- let contentData = [];
39
- if (mode === 'error' && errorText) {
40
- contentData = errorText.split('\n').map(line => ({ text: line || ' ', color: 'red' }));
41
- }
42
- else if (mode === 'changes') {
43
- const groups = groupByCategory(changes);
44
- const nonEmpty = Object.entries(groups).filter(([, files]) => files.length > 0);
45
- contentData.push({ text: 'Changes by category:', color: undefined });
46
- for (const [category, files] of nonEmpty.slice(0, 4)) {
47
- const fileList = files.slice(0, 3).join(', ') + (files.length > 3 ? ` +${files.length - 3} more` : '');
48
- const suffix = category === 'dependencies' ? ' (restart required)' : '';
49
- contentData.push({ text: ` ${categoryLabels[category]}: ${fileList}${suffix}`, color: 'cyan' });
50
- }
51
- if (nonEmpty.length === 0) {
52
- contentData.push({ text: ' No changes tracked', color: 'gray' });
53
- }
54
- }
55
- else {
56
- contentData = logLines.map(line => ({ text: line }));
57
- }
58
- const totalLines = contentData.length;
59
- const hasMore = totalLines > CONTENT_LINES;
60
- let visibleLines;
61
- let scrollInfo = '';
62
- if (mode === 'logs') {
63
- const start = Math.max(0, totalLines - scrollOffset - CONTENT_LINES);
64
- const end = Math.max(0, totalLines - scrollOffset);
65
- visibleLines = contentData.slice(start, end);
66
- if (hasMore) {
67
- const canUp = scrollOffset < totalLines - CONTENT_LINES;
68
- const canDown = scrollOffset > 0;
69
- scrollInfo = `${canUp ? '▲' : ''}${canDown ? '▼' : ''} (${start + 1}-${end}/${totalLines})`;
70
- }
71
- }
72
- else {
73
- visibleLines = contentData.slice(scrollOffset, scrollOffset + CONTENT_LINES);
74
- if (hasMore) {
75
- const canUp = scrollOffset > 0;
76
- const canDown = scrollOffset + CONTENT_LINES < totalLines;
77
- scrollInfo = `${canUp ? '▲' : ''}${canDown ? '▼' : ''} (${scrollOffset + 1}-${scrollOffset + visibleLines.length}/${totalLines})`;
78
- }
79
- }
80
- const padding = CONTENT_LINES - visibleLines.length;
81
- const paddingBefore = mode === 'logs' ? padding : 0;
82
- const paddingAfter = mode === 'logs' ? 0 : padding;
83
- return (_jsxs(_Fragment, { children: [Array.from({ length: paddingBefore }).map((_, i) => (_jsx(Text, { children: " " }, `pad-before-${i}`))), visibleLines.map((line, i) => (_jsx(Text, { color: line.color, children: line.text }, `content-${i}`))), Array.from({ length: paddingAfter }).map((_, i) => (_jsx(Text, { children: " " }, `pad-after-${i}`))), _jsx(Text, { color: "gray", children: scrollInfo || ' ' })] }));
84
- }
85
- export function WatchUI({ manual, onManualRebuild, exit }) {
86
- const [status, setStatusState] = useState(manual ? 'pending' : 'watching');
87
- const [reason, setReason] = useState();
88
- const [changedFiles, setChangedFilesState] = useState([]);
89
- const [buildResult, setBuildResultState] = useState(null);
90
- const [logLines, setLogLinesState] = useState([]);
91
- const [scrollOffset, setScrollOffset] = useState(0);
92
- const isError = status === 'error' && buildResult?.error;
93
- const isManualPending = manual && status === 'pending' && changedFiles.length > 0;
94
- const contentMode = isError ? 'error' : isManualPending ? 'changes' : 'logs';
95
- useEffect(() => {
96
- setScrollOffset(0);
97
- }, [contentMode, buildResult?.error]);
98
- const setStatus = useCallback((newStatus, newReason) => {
99
- setStatusState(newStatus);
100
- setReason(newReason);
101
- }, []);
102
- const setChangedFiles = useCallback((files) => {
103
- setChangedFilesState(files);
104
- }, []);
105
- const setBuildResult = useCallback((result) => {
106
- setBuildResultState(result);
107
- if (result.success) {
108
- setStatusState(manual ? 'pending' : 'watching');
109
- }
110
- else {
111
- setStatusState('error');
112
- }
113
- }, [manual]);
114
- const setLiveLog = useCallback((level, args) => {
115
- const formatted = format(...args).split('\n');
116
- setLogLinesState((prev) => {
117
- const newLines = [...prev];
118
- newLines.push(`> ${level !== false ? `[${level}] ` : ''}${formatted[0]}`, ...formatted.slice(1).map((line) => `> ${line}`));
119
- return newLines;
120
- });
121
- }, []);
122
- const getMaxScroll = useCallback(() => {
123
- if (isError && buildResult?.error) {
124
- return Math.max(0, buildResult.error.split('\n').length - CONTENT_LINES);
125
- }
126
- else if (isManualPending) {
127
- return 0;
128
- }
129
- else {
130
- return Math.max(0, logLines.length - CONTENT_LINES);
131
- }
132
- }, [isError, isManualPending, buildResult?.error, logLines.length]);
133
- useInput((input, key) => {
134
- if (input === 'q') {
135
- exit();
136
- }
137
- const maxScroll = getMaxScroll();
138
- if (key.upArrow) {
139
- setScrollOffset(prev => Math.min(maxScroll, prev + 1));
140
- }
141
- else if (key.downArrow) {
142
- setScrollOffset(prev => Math.max(0, prev - 1));
143
- }
144
- if (manual && status === 'pending') {
145
- if (input === 'r' || key.return) {
146
- onManualRebuild?.();
147
- }
148
- }
149
- });
150
- useEffect(() => {
151
- const api = {
152
- setStatus,
153
- setChangedFiles,
154
- setBuildResult,
155
- setLiveLog,
156
- };
157
- globalThis.__watchUIAPI = api;
158
- drainLiveLogBuffer();
159
- return () => {
160
- delete globalThis.__watchUIAPI;
161
- };
162
- }, [setStatus, setChangedFiles, setBuildResult, setLiveLog]);
163
- const statusText = {
164
- watching: 'Watching for changes...',
165
- building: 'Building...',
166
- restarting: 'Restarting...',
167
- error: 'Build Error',
168
- pending: 'Pending changes',
169
- };
170
- const showSpinner = status === 'building' || status === 'restarting';
171
- const statusColor = status === 'error' ? 'red' : status === 'pending' ? 'yellow' : 'green';
172
- const footerParts = [];
173
- if (manual)
174
- footerParts.push('R/Enter: rebuild');
175
- if (logLines.length > CONTENT_LINES || (isError && buildResult?.error && buildResult.error.split('\n').length > CONTENT_LINES)) {
176
- footerParts.push('↑↓: scroll');
177
- }
178
- footerParts.push('Q: exit');
179
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, color: "yellow", children: ["Watch Mode", manual ? _jsx(Text, { color: "cyan", children: " (Manual)" }) : ''] }), _jsxs(Text, { children: [showSpinner && _jsxs(_Fragment, { children: [_jsx(Text, { color: "cyan", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { children: " " })] }), _jsx(Text, { color: statusColor, children: statusText[status] }), reason && _jsxs(Text, { color: "gray", children: [" (", reason, ")"] })] }), _jsx(Text, { children: " " }), _jsx(ContentDisplay, { mode: contentMode, logLines: logLines, errorText: buildResult?.error ?? null, changes: changedFiles, scrollOffset: scrollOffset }), _jsx(Text, { children: " " }), _jsxs(Text, { color: "gray", children: ["Changed: ", formatChangedFiles(changedFiles)] }), buildResult?.resourceCounts ? (_jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: buildResult.resourceCounts.functions }), " functions | ", _jsx(Text, { color: "cyan", children: buildResult.resourceCounts.other }), " others"] })) : (_jsx(Text, { color: "gray", children: "No build results yet" })), isError ? _jsx(Text, { color: "yellow", children: "Waiting for changes to retry..." }) : _jsx(Text, { children: " " }), _jsx(Text, { color: "gray", children: footerParts.join(' | ') })] }));
180
- }
181
- export function getWatchUIAPI() {
182
- return globalThis.__watchUIAPI;
183
- }
@@ -1,20 +0,0 @@
1
- declare let liveLogCallback: ((level: string | false, args: unknown[]) => void) | null;
2
- export declare function initLogger(rootFolder: string): () => Promise<void>;
3
- /**
4
- * Initialize the logger without file writing.
5
- * Use this for `sand build` where we want logging but no persistent log file.
6
- */
7
- export declare function initLoggerNoFile(): void;
8
- /**
9
- * Set whether the logger should suppress live output.
10
- */
11
- export declare function setSilent(value: boolean): void;
12
- export declare function setLiveLogCallback(callback: typeof liveLogCallback): void;
13
- export declare function drainLiveLogBuffer(): void;
14
- export declare function log(...args: unknown[]): void;
15
- export declare function logInfo(...args: unknown[]): void;
16
- export declare function logWarn(...args: unknown[]): void;
17
- export declare function logDebug(...args: unknown[]): void;
18
- export declare function logTrace(...args: unknown[]): void;
19
- export declare function logError(error: unknown): void;
20
- export {};