@csszyx/unplugin 0.9.0 → 0.9.2
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/index.cjs +19 -2
- package/dist/index.d.cts +91 -5
- package/dist/index.d.mts +90 -3
- package/dist/index.mjs +4 -2
- package/dist/next-prebuild.cjs +148 -0
- package/dist/next-prebuild.d.cts +66 -0
- package/dist/next-prebuild.d.mts +66 -0
- package/dist/next-prebuild.mjs +131 -0
- package/dist/next-turbo-loader.cjs +210 -0
- package/dist/next-turbo-loader.d.cts +68 -0
- package/dist/next-turbo-loader.d.mts +66 -0
- package/dist/next-turbo-loader.mjs +190 -0
- package/dist/next-watcher.cjs +237 -0
- package/dist/next-watcher.d.cts +106 -0
- package/dist/next-watcher.d.mts +106 -0
- package/dist/next-watcher.mjs +219 -0
- package/dist/shared/unplugin.8er8o6rn.mjs +276 -0
- package/dist/shared/unplugin.B_U4rZvG.cjs +281 -0
- package/dist/shared/{unplugin.BEOG6ePC.mjs → unplugin.BbtspS8t.mjs} +1436 -324
- package/dist/shared/unplugin.BceVw1eW.mjs +184 -0
- package/dist/shared/unplugin.BtQzlC2C.mjs +567 -0
- package/dist/shared/{unplugin.CL0F6RZa.cjs → unplugin.CFp386gH.cjs} +1456 -327
- package/dist/shared/unplugin.CPEWNSA0.d.cts +77 -0
- package/dist/shared/unplugin.CPEWNSA0.d.mts +77 -0
- package/dist/shared/unplugin.CScQRdTp.d.cts +15 -0
- package/dist/shared/unplugin.CScQRdTp.d.mts +15 -0
- package/dist/shared/unplugin.CdZxp0x-.d.mts +16 -0
- package/dist/shared/unplugin.DLrBgECN.d.cts +282 -0
- package/dist/shared/unplugin.DLrBgECN.d.mts +282 -0
- package/dist/shared/unplugin.DUxdYaSG.cjs +205 -0
- package/dist/shared/unplugin.s62yJbu1.cjs +591 -0
- package/dist/shared/unplugin.xeED_qwh.d.cts +16 -0
- package/dist/vite.cjs +3 -1
- package/dist/vite.d.cts +2 -1
- package/dist/vite.d.mts +2 -1
- package/dist/vite.mjs +3 -1
- package/dist/webpack.cjs +3 -1
- package/dist/webpack.d.cts +2 -1
- package/dist/webpack.d.mts +2 -1
- package/dist/webpack.mjs +3 -1
- package/package.json +41 -8
- package/dist/shared/unplugin.DUbr5w-N.d.cts +0 -49
- package/dist/shared/unplugin.DUbr5w-N.d.mts +0 -49
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const nextWatcherCycle = require('./shared/unplugin.s62yJbu1.cjs');
|
|
5
|
+
require('node:fs');
|
|
6
|
+
require('node:crypto');
|
|
7
|
+
require('node:os');
|
|
8
|
+
require('proper-lockfile');
|
|
9
|
+
|
|
10
|
+
function _interopNamespaceCompat(e) {
|
|
11
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
12
|
+
const n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
for (const k in e) {
|
|
15
|
+
n[k] = e[k];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
n.default = e;
|
|
19
|
+
return n;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
23
|
+
|
|
24
|
+
class NextWatcherLoop {
|
|
25
|
+
context;
|
|
26
|
+
cycleOptions;
|
|
27
|
+
debounceMs;
|
|
28
|
+
runCycle;
|
|
29
|
+
setTimeoutFn;
|
|
30
|
+
clearTimeoutFn;
|
|
31
|
+
onError;
|
|
32
|
+
timer;
|
|
33
|
+
disposed = false;
|
|
34
|
+
pendingReasons = /* @__PURE__ */ new Set();
|
|
35
|
+
lastResult;
|
|
36
|
+
lastError;
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param options
|
|
40
|
+
*/
|
|
41
|
+
constructor(options) {
|
|
42
|
+
this.context = options.context;
|
|
43
|
+
this.cycleOptions = options.cycleOptions ?? {};
|
|
44
|
+
this.debounceMs = options.debounceMs ?? 50;
|
|
45
|
+
this.runCycle = options.runCycle ?? nextWatcherCycle.runNextWatcherCycle;
|
|
46
|
+
this.setTimeoutFn = options.setTimeout ?? setTimeout;
|
|
47
|
+
this.clearTimeoutFn = options.clearTimeout ?? clearTimeout;
|
|
48
|
+
this.onError = options.onError;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
*/
|
|
53
|
+
get pending() {
|
|
54
|
+
return this.timer !== void 0;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
*/
|
|
59
|
+
get reasons() {
|
|
60
|
+
return [...this.pendingReasons];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
*
|
|
64
|
+
* @param reason
|
|
65
|
+
*/
|
|
66
|
+
notify(reason = "change") {
|
|
67
|
+
if (this.disposed) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.pendingReasons.add(reason);
|
|
71
|
+
if (this.timer !== void 0) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.timer = this.setTimeoutFn(() => {
|
|
75
|
+
try {
|
|
76
|
+
this.runPendingCycle();
|
|
77
|
+
} catch (error) {
|
|
78
|
+
this.lastError = error;
|
|
79
|
+
this.onError?.(error);
|
|
80
|
+
}
|
|
81
|
+
}, this.debounceMs);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
*
|
|
85
|
+
*/
|
|
86
|
+
flush() {
|
|
87
|
+
if (this.disposed || this.timer === void 0) {
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
return this.runPendingCycle();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
*/
|
|
95
|
+
dispose() {
|
|
96
|
+
if (this.timer !== void 0) {
|
|
97
|
+
this.clearTimeoutFn(this.timer);
|
|
98
|
+
}
|
|
99
|
+
this.timer = void 0;
|
|
100
|
+
this.pendingReasons.clear();
|
|
101
|
+
this.disposed = true;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
*
|
|
105
|
+
*/
|
|
106
|
+
runPendingCycle() {
|
|
107
|
+
const timer = this.timer;
|
|
108
|
+
if (timer !== void 0) {
|
|
109
|
+
this.clearTimeoutFn(timer);
|
|
110
|
+
}
|
|
111
|
+
this.timer = void 0;
|
|
112
|
+
const reasons = [...this.pendingReasons];
|
|
113
|
+
this.pendingReasons.clear();
|
|
114
|
+
const result = this.runCycle(this.context, this.cycleOptions, reasons);
|
|
115
|
+
this.lastResult = result;
|
|
116
|
+
this.lastError = void 0;
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function isNextSafelistShardPath(shardsDir, filePath) {
|
|
122
|
+
if (!path__namespace.isAbsolute(filePath)) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const relative = path__namespace.relative(path__namespace.resolve(shardsDir), path__namespace.resolve(filePath));
|
|
126
|
+
return relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path__namespace.sep}`) && !path__namespace.isAbsolute(relative) && !relative.includes(path__namespace.sep) && !relative.startsWith(".") && relative.endsWith(".json");
|
|
127
|
+
}
|
|
128
|
+
function isNextAppSourcePath(root, filePath) {
|
|
129
|
+
if (!path__namespace.isAbsolute(filePath)) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const relative = path__namespace.relative(path__namespace.resolve(root), path__namespace.resolve(filePath));
|
|
133
|
+
return relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path__namespace.sep}`) && !path__namespace.isAbsolute(relative);
|
|
134
|
+
}
|
|
135
|
+
class NextSafelistWatcher {
|
|
136
|
+
root;
|
|
137
|
+
shardsDir;
|
|
138
|
+
loop;
|
|
139
|
+
started = false;
|
|
140
|
+
closed = false;
|
|
141
|
+
/**
|
|
142
|
+
*
|
|
143
|
+
* @param options
|
|
144
|
+
*/
|
|
145
|
+
constructor(options) {
|
|
146
|
+
this.root = path__namespace.resolve(options.context.root);
|
|
147
|
+
this.shardsDir = path__namespace.resolve(options.context.safelist.shardsDir);
|
|
148
|
+
this.loop = new NextWatcherLoop(options);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
*
|
|
152
|
+
*/
|
|
153
|
+
get pending() {
|
|
154
|
+
return this.loop.pending;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
*
|
|
158
|
+
*/
|
|
159
|
+
get lastResult() {
|
|
160
|
+
return this.loop.lastResult;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
*
|
|
164
|
+
*/
|
|
165
|
+
get lastError() {
|
|
166
|
+
return this.loop.lastError;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Materialize existing shards before accepting live filesystem events.
|
|
170
|
+
*/
|
|
171
|
+
start() {
|
|
172
|
+
if (this.closed) {
|
|
173
|
+
throw new Error("[csszyx] Cannot start a closed Next safelist watcher.");
|
|
174
|
+
}
|
|
175
|
+
if (this.started && this.loop.lastResult) {
|
|
176
|
+
return this.loop.lastResult;
|
|
177
|
+
}
|
|
178
|
+
this.started = true;
|
|
179
|
+
this.loop.notify("initial");
|
|
180
|
+
const result = this.loop.flush();
|
|
181
|
+
if (!result) {
|
|
182
|
+
throw new Error("[csszyx] Next safelist watcher failed to run its initial cycle.");
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Queue a materialization cycle for one relevant shard filesystem event.
|
|
188
|
+
*
|
|
189
|
+
* @param event Normalized add/change/unlink event.
|
|
190
|
+
* @param filePath Absolute event path.
|
|
191
|
+
* @returns Whether the event was accepted.
|
|
192
|
+
*/
|
|
193
|
+
notify(event, filePath) {
|
|
194
|
+
if (this.closed || !this.started || !isNextSafelistShardPath(this.shardsDir, filePath)) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
this.loop.notify(`shard:${event}`);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Queue tombstone cleanup after a source file is removed.
|
|
202
|
+
*
|
|
203
|
+
* @param filePath Absolute deleted source path.
|
|
204
|
+
* @returns Whether the event was accepted.
|
|
205
|
+
*/
|
|
206
|
+
notifySourceRemoval(filePath) {
|
|
207
|
+
if (this.closed || !this.started || !isNextAppSourcePath(this.root, filePath)) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
this.loop.notify("source:unlink");
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Flush any pending event batch immediately.
|
|
215
|
+
*/
|
|
216
|
+
flush() {
|
|
217
|
+
return this.loop.flush();
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Flush pending work before permanently closing the controller.
|
|
221
|
+
*/
|
|
222
|
+
close() {
|
|
223
|
+
if (this.closed) {
|
|
224
|
+
return void 0;
|
|
225
|
+
}
|
|
226
|
+
this.closed = true;
|
|
227
|
+
try {
|
|
228
|
+
return this.loop.flush();
|
|
229
|
+
} finally {
|
|
230
|
+
this.loop.dispose();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
exports.NextSafelistWatcher = NextSafelistWatcher;
|
|
236
|
+
exports.isNextAppSourcePath = isNextAppSourcePath;
|
|
237
|
+
exports.isNextSafelistShardPath = isNextSafelistShardPath;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { N as NextStateContext } from './shared/unplugin.CPEWNSA0.cjs';
|
|
2
|
+
import { a as NextWatcherCycleOptions, N as NextWatcherCycleResult } from './shared/unplugin.xeED_qwh.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
type WatcherTimer = ReturnType<typeof setTimeout>;
|
|
8
|
+
/** Function used to run one materialization cycle. */
|
|
9
|
+
type NextWatcherLoopCycleRunner = (context: NextStateContext, options: NextWatcherCycleOptions, reasons: readonly string[]) => NextWatcherCycleResult;
|
|
10
|
+
/** Timer hooks kept injectable so debounce behavior is deterministic in tests. */
|
|
11
|
+
interface NextWatcherLoopTimerHooks {
|
|
12
|
+
setTimeout?: (callback: () => void, delayMs: number) => WatcherTimer;
|
|
13
|
+
clearTimeout?: (timer: WatcherTimer) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Filesystem events that can change the materialized safelist. */
|
|
17
|
+
type NextSafelistWatchEvent = 'add' | 'change' | 'unlink';
|
|
18
|
+
/** Options for the filesystem-independent Next safelist watcher controller. */
|
|
19
|
+
interface NextSafelistWatcherOptions extends NextWatcherLoopTimerHooks {
|
|
20
|
+
context: NextStateContext;
|
|
21
|
+
cycleOptions?: NextWatcherCycleOptions;
|
|
22
|
+
debounceMs?: number;
|
|
23
|
+
runCycle?: NextWatcherLoopCycleRunner;
|
|
24
|
+
onError?: (error: unknown) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validate one watcher event path against the flat safelist shard directory.
|
|
28
|
+
*
|
|
29
|
+
* The future filesystem adapter must pass absolute paths. Restricting accepted
|
|
30
|
+
* events to direct `.json` children prevents unrelated cache files, atomic
|
|
31
|
+
* write temp files, and paths outside this app root from triggering a cycle.
|
|
32
|
+
*
|
|
33
|
+
* @param shardsDir Absolute safelist shard directory.
|
|
34
|
+
* @param filePath Absolute event path.
|
|
35
|
+
* @returns Whether the event belongs to a materialized shard.
|
|
36
|
+
*/
|
|
37
|
+
declare function isNextSafelistShardPath(shardsDir: string, filePath: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Validate that an absolute source event path belongs to the resolved app root.
|
|
40
|
+
*
|
|
41
|
+
* @param root Absolute Next app root.
|
|
42
|
+
* @param filePath Absolute event path.
|
|
43
|
+
* @returns Whether the source is inside the app root.
|
|
44
|
+
*/
|
|
45
|
+
declare function isNextAppSourcePath(root: string, filePath: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Lifecycle controller between an OS file watcher and the materialization loop.
|
|
48
|
+
*
|
|
49
|
+
* This class deliberately does not import `chokidar` or `fs.watch`. A CLI can
|
|
50
|
+
* own that dependency and feed normalized events here while the state machine
|
|
51
|
+
* remains deterministic and package-size neutral.
|
|
52
|
+
*/
|
|
53
|
+
declare class NextSafelistWatcher {
|
|
54
|
+
private readonly root;
|
|
55
|
+
private readonly shardsDir;
|
|
56
|
+
private readonly loop;
|
|
57
|
+
private started;
|
|
58
|
+
private closed;
|
|
59
|
+
/**
|
|
60
|
+
*
|
|
61
|
+
* @param options
|
|
62
|
+
*/
|
|
63
|
+
constructor(options: NextSafelistWatcherOptions);
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
*/
|
|
67
|
+
get pending(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
*/
|
|
71
|
+
get lastResult(): NextWatcherCycleResult | undefined;
|
|
72
|
+
/**
|
|
73
|
+
*
|
|
74
|
+
*/
|
|
75
|
+
get lastError(): unknown;
|
|
76
|
+
/**
|
|
77
|
+
* Materialize existing shards before accepting live filesystem events.
|
|
78
|
+
*/
|
|
79
|
+
start(): NextWatcherCycleResult;
|
|
80
|
+
/**
|
|
81
|
+
* Queue a materialization cycle for one relevant shard filesystem event.
|
|
82
|
+
*
|
|
83
|
+
* @param event Normalized add/change/unlink event.
|
|
84
|
+
* @param filePath Absolute event path.
|
|
85
|
+
* @returns Whether the event was accepted.
|
|
86
|
+
*/
|
|
87
|
+
notify(event: NextSafelistWatchEvent, filePath: string): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Queue tombstone cleanup after a source file is removed.
|
|
90
|
+
*
|
|
91
|
+
* @param filePath Absolute deleted source path.
|
|
92
|
+
* @returns Whether the event was accepted.
|
|
93
|
+
*/
|
|
94
|
+
notifySourceRemoval(filePath: string): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Flush any pending event batch immediately.
|
|
97
|
+
*/
|
|
98
|
+
flush(): NextWatcherCycleResult | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Flush pending work before permanently closing the controller.
|
|
101
|
+
*/
|
|
102
|
+
close(): NextWatcherCycleResult | undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { NextSafelistWatcher, isNextAppSourcePath, isNextSafelistShardPath };
|
|
106
|
+
export type { NextSafelistWatchEvent, NextSafelistWatcherOptions };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { N as NextStateContext } from './shared/unplugin.CPEWNSA0.mjs';
|
|
2
|
+
import { a as NextWatcherCycleOptions, N as NextWatcherCycleResult } from './shared/unplugin.CdZxp0x-.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
type WatcherTimer = ReturnType<typeof setTimeout>;
|
|
8
|
+
/** Function used to run one materialization cycle. */
|
|
9
|
+
type NextWatcherLoopCycleRunner = (context: NextStateContext, options: NextWatcherCycleOptions, reasons: readonly string[]) => NextWatcherCycleResult;
|
|
10
|
+
/** Timer hooks kept injectable so debounce behavior is deterministic in tests. */
|
|
11
|
+
interface NextWatcherLoopTimerHooks {
|
|
12
|
+
setTimeout?: (callback: () => void, delayMs: number) => WatcherTimer;
|
|
13
|
+
clearTimeout?: (timer: WatcherTimer) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Filesystem events that can change the materialized safelist. */
|
|
17
|
+
type NextSafelistWatchEvent = 'add' | 'change' | 'unlink';
|
|
18
|
+
/** Options for the filesystem-independent Next safelist watcher controller. */
|
|
19
|
+
interface NextSafelistWatcherOptions extends NextWatcherLoopTimerHooks {
|
|
20
|
+
context: NextStateContext;
|
|
21
|
+
cycleOptions?: NextWatcherCycleOptions;
|
|
22
|
+
debounceMs?: number;
|
|
23
|
+
runCycle?: NextWatcherLoopCycleRunner;
|
|
24
|
+
onError?: (error: unknown) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validate one watcher event path against the flat safelist shard directory.
|
|
28
|
+
*
|
|
29
|
+
* The future filesystem adapter must pass absolute paths. Restricting accepted
|
|
30
|
+
* events to direct `.json` children prevents unrelated cache files, atomic
|
|
31
|
+
* write temp files, and paths outside this app root from triggering a cycle.
|
|
32
|
+
*
|
|
33
|
+
* @param shardsDir Absolute safelist shard directory.
|
|
34
|
+
* @param filePath Absolute event path.
|
|
35
|
+
* @returns Whether the event belongs to a materialized shard.
|
|
36
|
+
*/
|
|
37
|
+
declare function isNextSafelistShardPath(shardsDir: string, filePath: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Validate that an absolute source event path belongs to the resolved app root.
|
|
40
|
+
*
|
|
41
|
+
* @param root Absolute Next app root.
|
|
42
|
+
* @param filePath Absolute event path.
|
|
43
|
+
* @returns Whether the source is inside the app root.
|
|
44
|
+
*/
|
|
45
|
+
declare function isNextAppSourcePath(root: string, filePath: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Lifecycle controller between an OS file watcher and the materialization loop.
|
|
48
|
+
*
|
|
49
|
+
* This class deliberately does not import `chokidar` or `fs.watch`. A CLI can
|
|
50
|
+
* own that dependency and feed normalized events here while the state machine
|
|
51
|
+
* remains deterministic and package-size neutral.
|
|
52
|
+
*/
|
|
53
|
+
declare class NextSafelistWatcher {
|
|
54
|
+
private readonly root;
|
|
55
|
+
private readonly shardsDir;
|
|
56
|
+
private readonly loop;
|
|
57
|
+
private started;
|
|
58
|
+
private closed;
|
|
59
|
+
/**
|
|
60
|
+
*
|
|
61
|
+
* @param options
|
|
62
|
+
*/
|
|
63
|
+
constructor(options: NextSafelistWatcherOptions);
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
*/
|
|
67
|
+
get pending(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
*/
|
|
71
|
+
get lastResult(): NextWatcherCycleResult | undefined;
|
|
72
|
+
/**
|
|
73
|
+
*
|
|
74
|
+
*/
|
|
75
|
+
get lastError(): unknown;
|
|
76
|
+
/**
|
|
77
|
+
* Materialize existing shards before accepting live filesystem events.
|
|
78
|
+
*/
|
|
79
|
+
start(): NextWatcherCycleResult;
|
|
80
|
+
/**
|
|
81
|
+
* Queue a materialization cycle for one relevant shard filesystem event.
|
|
82
|
+
*
|
|
83
|
+
* @param event Normalized add/change/unlink event.
|
|
84
|
+
* @param filePath Absolute event path.
|
|
85
|
+
* @returns Whether the event was accepted.
|
|
86
|
+
*/
|
|
87
|
+
notify(event: NextSafelistWatchEvent, filePath: string): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Queue tombstone cleanup after a source file is removed.
|
|
90
|
+
*
|
|
91
|
+
* @param filePath Absolute deleted source path.
|
|
92
|
+
* @returns Whether the event was accepted.
|
|
93
|
+
*/
|
|
94
|
+
notifySourceRemoval(filePath: string): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Flush any pending event batch immediately.
|
|
97
|
+
*/
|
|
98
|
+
flush(): NextWatcherCycleResult | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Flush pending work before permanently closing the controller.
|
|
101
|
+
*/
|
|
102
|
+
close(): NextWatcherCycleResult | undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { NextSafelistWatcher, isNextAppSourcePath, isNextSafelistShardPath };
|
|
106
|
+
export type { NextSafelistWatchEvent, NextSafelistWatcherOptions };
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import { r as runNextWatcherCycle } from './shared/unplugin.BtQzlC2C.mjs';
|
|
3
|
+
import 'node:fs';
|
|
4
|
+
import 'node:crypto';
|
|
5
|
+
import 'node:os';
|
|
6
|
+
import 'proper-lockfile';
|
|
7
|
+
|
|
8
|
+
class NextWatcherLoop {
|
|
9
|
+
context;
|
|
10
|
+
cycleOptions;
|
|
11
|
+
debounceMs;
|
|
12
|
+
runCycle;
|
|
13
|
+
setTimeoutFn;
|
|
14
|
+
clearTimeoutFn;
|
|
15
|
+
onError;
|
|
16
|
+
timer;
|
|
17
|
+
disposed = false;
|
|
18
|
+
pendingReasons = /* @__PURE__ */ new Set();
|
|
19
|
+
lastResult;
|
|
20
|
+
lastError;
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param options
|
|
24
|
+
*/
|
|
25
|
+
constructor(options) {
|
|
26
|
+
this.context = options.context;
|
|
27
|
+
this.cycleOptions = options.cycleOptions ?? {};
|
|
28
|
+
this.debounceMs = options.debounceMs ?? 50;
|
|
29
|
+
this.runCycle = options.runCycle ?? runNextWatcherCycle;
|
|
30
|
+
this.setTimeoutFn = options.setTimeout ?? setTimeout;
|
|
31
|
+
this.clearTimeoutFn = options.clearTimeout ?? clearTimeout;
|
|
32
|
+
this.onError = options.onError;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
get pending() {
|
|
38
|
+
return this.timer !== void 0;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
*/
|
|
43
|
+
get reasons() {
|
|
44
|
+
return [...this.pendingReasons];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @param reason
|
|
49
|
+
*/
|
|
50
|
+
notify(reason = "change") {
|
|
51
|
+
if (this.disposed) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this.pendingReasons.add(reason);
|
|
55
|
+
if (this.timer !== void 0) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.timer = this.setTimeoutFn(() => {
|
|
59
|
+
try {
|
|
60
|
+
this.runPendingCycle();
|
|
61
|
+
} catch (error) {
|
|
62
|
+
this.lastError = error;
|
|
63
|
+
this.onError?.(error);
|
|
64
|
+
}
|
|
65
|
+
}, this.debounceMs);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
*
|
|
69
|
+
*/
|
|
70
|
+
flush() {
|
|
71
|
+
if (this.disposed || this.timer === void 0) {
|
|
72
|
+
return void 0;
|
|
73
|
+
}
|
|
74
|
+
return this.runPendingCycle();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
*/
|
|
79
|
+
dispose() {
|
|
80
|
+
if (this.timer !== void 0) {
|
|
81
|
+
this.clearTimeoutFn(this.timer);
|
|
82
|
+
}
|
|
83
|
+
this.timer = void 0;
|
|
84
|
+
this.pendingReasons.clear();
|
|
85
|
+
this.disposed = true;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
*
|
|
89
|
+
*/
|
|
90
|
+
runPendingCycle() {
|
|
91
|
+
const timer = this.timer;
|
|
92
|
+
if (timer !== void 0) {
|
|
93
|
+
this.clearTimeoutFn(timer);
|
|
94
|
+
}
|
|
95
|
+
this.timer = void 0;
|
|
96
|
+
const reasons = [...this.pendingReasons];
|
|
97
|
+
this.pendingReasons.clear();
|
|
98
|
+
const result = this.runCycle(this.context, this.cycleOptions, reasons);
|
|
99
|
+
this.lastResult = result;
|
|
100
|
+
this.lastError = void 0;
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isNextSafelistShardPath(shardsDir, filePath) {
|
|
106
|
+
if (!path.isAbsolute(filePath)) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const relative = path.relative(path.resolve(shardsDir), path.resolve(filePath));
|
|
110
|
+
return relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative) && !relative.includes(path.sep) && !relative.startsWith(".") && relative.endsWith(".json");
|
|
111
|
+
}
|
|
112
|
+
function isNextAppSourcePath(root, filePath) {
|
|
113
|
+
if (!path.isAbsolute(filePath)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const relative = path.relative(path.resolve(root), path.resolve(filePath));
|
|
117
|
+
return relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
118
|
+
}
|
|
119
|
+
class NextSafelistWatcher {
|
|
120
|
+
root;
|
|
121
|
+
shardsDir;
|
|
122
|
+
loop;
|
|
123
|
+
started = false;
|
|
124
|
+
closed = false;
|
|
125
|
+
/**
|
|
126
|
+
*
|
|
127
|
+
* @param options
|
|
128
|
+
*/
|
|
129
|
+
constructor(options) {
|
|
130
|
+
this.root = path.resolve(options.context.root);
|
|
131
|
+
this.shardsDir = path.resolve(options.context.safelist.shardsDir);
|
|
132
|
+
this.loop = new NextWatcherLoop(options);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
*
|
|
136
|
+
*/
|
|
137
|
+
get pending() {
|
|
138
|
+
return this.loop.pending;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
*
|
|
142
|
+
*/
|
|
143
|
+
get lastResult() {
|
|
144
|
+
return this.loop.lastResult;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
*
|
|
148
|
+
*/
|
|
149
|
+
get lastError() {
|
|
150
|
+
return this.loop.lastError;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Materialize existing shards before accepting live filesystem events.
|
|
154
|
+
*/
|
|
155
|
+
start() {
|
|
156
|
+
if (this.closed) {
|
|
157
|
+
throw new Error("[csszyx] Cannot start a closed Next safelist watcher.");
|
|
158
|
+
}
|
|
159
|
+
if (this.started && this.loop.lastResult) {
|
|
160
|
+
return this.loop.lastResult;
|
|
161
|
+
}
|
|
162
|
+
this.started = true;
|
|
163
|
+
this.loop.notify("initial");
|
|
164
|
+
const result = this.loop.flush();
|
|
165
|
+
if (!result) {
|
|
166
|
+
throw new Error("[csszyx] Next safelist watcher failed to run its initial cycle.");
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Queue a materialization cycle for one relevant shard filesystem event.
|
|
172
|
+
*
|
|
173
|
+
* @param event Normalized add/change/unlink event.
|
|
174
|
+
* @param filePath Absolute event path.
|
|
175
|
+
* @returns Whether the event was accepted.
|
|
176
|
+
*/
|
|
177
|
+
notify(event, filePath) {
|
|
178
|
+
if (this.closed || !this.started || !isNextSafelistShardPath(this.shardsDir, filePath)) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
this.loop.notify(`shard:${event}`);
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Queue tombstone cleanup after a source file is removed.
|
|
186
|
+
*
|
|
187
|
+
* @param filePath Absolute deleted source path.
|
|
188
|
+
* @returns Whether the event was accepted.
|
|
189
|
+
*/
|
|
190
|
+
notifySourceRemoval(filePath) {
|
|
191
|
+
if (this.closed || !this.started || !isNextAppSourcePath(this.root, filePath)) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
this.loop.notify("source:unlink");
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Flush any pending event batch immediately.
|
|
199
|
+
*/
|
|
200
|
+
flush() {
|
|
201
|
+
return this.loop.flush();
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Flush pending work before permanently closing the controller.
|
|
205
|
+
*/
|
|
206
|
+
close() {
|
|
207
|
+
if (this.closed) {
|
|
208
|
+
return void 0;
|
|
209
|
+
}
|
|
210
|
+
this.closed = true;
|
|
211
|
+
try {
|
|
212
|
+
return this.loop.flush();
|
|
213
|
+
} finally {
|
|
214
|
+
this.loop.dispose();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export { NextSafelistWatcher, isNextAppSourcePath, isNextSafelistShardPath };
|