nextjs-asset-manager 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/dist/index.cjs +316 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +75 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +308 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ejiro Asiuwhu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@vite-asset-manager/core');
|
|
4
|
+
var stream = require('stream');
|
|
5
|
+
var Script = require('next/script');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var Script__default = /*#__PURE__*/_interopDefault(Script);
|
|
11
|
+
|
|
12
|
+
// src/handler.ts
|
|
13
|
+
var MockIncomingMessage = class extends stream.Readable {
|
|
14
|
+
url;
|
|
15
|
+
method;
|
|
16
|
+
headers;
|
|
17
|
+
constructor(request) {
|
|
18
|
+
super();
|
|
19
|
+
this.method = request.method;
|
|
20
|
+
this.url = new URL(request.url).pathname + new URL(request.url).search;
|
|
21
|
+
const headers = {};
|
|
22
|
+
request.headers.forEach((value, key) => {
|
|
23
|
+
headers[key.toLowerCase()] = value;
|
|
24
|
+
});
|
|
25
|
+
this.headers = headers;
|
|
26
|
+
}
|
|
27
|
+
_read() {
|
|
28
|
+
}
|
|
29
|
+
async feedBody(request) {
|
|
30
|
+
if (request.body) {
|
|
31
|
+
const reader = request.body.getReader();
|
|
32
|
+
try {
|
|
33
|
+
while (true) {
|
|
34
|
+
const { done, value } = await reader.read();
|
|
35
|
+
if (done) break;
|
|
36
|
+
this.push(Buffer.from(value));
|
|
37
|
+
}
|
|
38
|
+
} finally {
|
|
39
|
+
reader.releaseLock();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
this.push(null);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var MockServerResponse = class extends stream.Writable {
|
|
46
|
+
statusCode = 200;
|
|
47
|
+
headersSent = false;
|
|
48
|
+
headers = /* @__PURE__ */ new Map();
|
|
49
|
+
chunks = [];
|
|
50
|
+
resolveResponse;
|
|
51
|
+
sseController = null;
|
|
52
|
+
isSSE = false;
|
|
53
|
+
responseResolved = false;
|
|
54
|
+
responsePromise;
|
|
55
|
+
constructor() {
|
|
56
|
+
super();
|
|
57
|
+
this.responsePromise = new Promise((resolve) => {
|
|
58
|
+
this.resolveResponse = resolve;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
setHeader(name, value) {
|
|
62
|
+
this.headers.set(name.toLowerCase(), value);
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
getHeader(name) {
|
|
66
|
+
return this.headers.get(name.toLowerCase());
|
|
67
|
+
}
|
|
68
|
+
removeHeader(name) {
|
|
69
|
+
this.headers.delete(name.toLowerCase());
|
|
70
|
+
}
|
|
71
|
+
writeHead(statusCode, headers) {
|
|
72
|
+
this.statusCode = statusCode;
|
|
73
|
+
this.headersSent = true;
|
|
74
|
+
if (headers) {
|
|
75
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
76
|
+
this.headers.set(key.toLowerCase(), value);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const contentType = this.headers.get("content-type");
|
|
80
|
+
if (contentType === "text/event-stream") {
|
|
81
|
+
this.isSSE = true;
|
|
82
|
+
this.resolveSSEResponse();
|
|
83
|
+
}
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
// Capture data from pipe() and write() calls
|
|
87
|
+
_write(chunk, encoding, callback) {
|
|
88
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);
|
|
89
|
+
if (this.isSSE && this.sseController) {
|
|
90
|
+
try {
|
|
91
|
+
this.sseController.enqueue(new Uint8Array(buffer));
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
this.chunks.push(buffer);
|
|
96
|
+
}
|
|
97
|
+
callback();
|
|
98
|
+
}
|
|
99
|
+
_final(callback) {
|
|
100
|
+
if (!this.isSSE && !this.responseResolved) {
|
|
101
|
+
this.resolveNormalResponse();
|
|
102
|
+
}
|
|
103
|
+
callback();
|
|
104
|
+
}
|
|
105
|
+
// Override end() to finalize the response
|
|
106
|
+
end(chunk, encodingOrCallback, callback) {
|
|
107
|
+
if (chunk !== void 0 && chunk !== null) {
|
|
108
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
|
|
109
|
+
if (this.isSSE && this.sseController) {
|
|
110
|
+
try {
|
|
111
|
+
this.sseController.enqueue(new Uint8Array(buf));
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
this.chunks.push(buf);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (!this.isSSE && !this.responseResolved) {
|
|
119
|
+
this.resolveNormalResponse();
|
|
120
|
+
}
|
|
121
|
+
const cb = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
|
|
122
|
+
if (typeof cb === "function") cb();
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
buildHeaders() {
|
|
126
|
+
const headers = new Headers();
|
|
127
|
+
for (const [key, value] of this.headers) {
|
|
128
|
+
if (Array.isArray(value)) {
|
|
129
|
+
for (const v of value) headers.append(key, v);
|
|
130
|
+
} else {
|
|
131
|
+
headers.set(key, String(value));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return headers;
|
|
135
|
+
}
|
|
136
|
+
resolveNormalResponse() {
|
|
137
|
+
if (this.responseResolved) return;
|
|
138
|
+
this.responseResolved = true;
|
|
139
|
+
const body = this.chunks.length > 0 ? new Uint8Array(Buffer.concat(this.chunks)) : null;
|
|
140
|
+
this.resolveResponse(
|
|
141
|
+
new Response(body, {
|
|
142
|
+
status: this.statusCode,
|
|
143
|
+
headers: this.buildHeaders()
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
resolveSSEResponse() {
|
|
148
|
+
if (this.responseResolved) return;
|
|
149
|
+
this.responseResolved = true;
|
|
150
|
+
const stream = new ReadableStream({
|
|
151
|
+
start: (controller) => {
|
|
152
|
+
this.sseController = controller;
|
|
153
|
+
for (const chunk of this.chunks) {
|
|
154
|
+
controller.enqueue(new Uint8Array(chunk));
|
|
155
|
+
}
|
|
156
|
+
this.chunks = [];
|
|
157
|
+
},
|
|
158
|
+
cancel: () => {
|
|
159
|
+
this.emit("close");
|
|
160
|
+
this.sseController = null;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
this.resolveResponse(
|
|
164
|
+
new Response(stream, {
|
|
165
|
+
status: this.statusCode,
|
|
166
|
+
headers: this.buildHeaders()
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
async function callMiddleware(request, middleware) {
|
|
172
|
+
const mockReq = new MockIncomingMessage(request);
|
|
173
|
+
const mockRes = new MockServerResponse();
|
|
174
|
+
let nextCalled = false;
|
|
175
|
+
const next = () => {
|
|
176
|
+
nextCalled = true;
|
|
177
|
+
};
|
|
178
|
+
mockReq.feedBody(request);
|
|
179
|
+
try {
|
|
180
|
+
middleware(
|
|
181
|
+
mockReq,
|
|
182
|
+
mockRes,
|
|
183
|
+
next
|
|
184
|
+
);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error("[nextjs-asset-manager] Middleware error:", error);
|
|
187
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
188
|
+
}
|
|
189
|
+
if (nextCalled) {
|
|
190
|
+
return new Response("Not Found", { status: 404 });
|
|
191
|
+
}
|
|
192
|
+
return mockRes.responsePromise;
|
|
193
|
+
}
|
|
194
|
+
var MANAGER_KEY = /* @__PURE__ */ Symbol.for("__vam_asset_manager__");
|
|
195
|
+
var MIDDLEWARE_KEY = /* @__PURE__ */ Symbol.for("__vam_middleware__");
|
|
196
|
+
var INIT_PROMISE_KEY = /* @__PURE__ */ Symbol.for("__vam_init_promise__");
|
|
197
|
+
var store = globalThis;
|
|
198
|
+
function getOrCreateMiddleware(root, options) {
|
|
199
|
+
return {
|
|
200
|
+
middleware: async () => {
|
|
201
|
+
if (store[MIDDLEWARE_KEY]) {
|
|
202
|
+
return store[MIDDLEWARE_KEY];
|
|
203
|
+
}
|
|
204
|
+
if (!store[INIT_PROMISE_KEY]) {
|
|
205
|
+
store[INIT_PROMISE_KEY] = (async () => {
|
|
206
|
+
let manager = store[MANAGER_KEY];
|
|
207
|
+
if (!manager) {
|
|
208
|
+
manager = new core.AssetManager({ root, options });
|
|
209
|
+
store[MANAGER_KEY] = manager;
|
|
210
|
+
await manager.init();
|
|
211
|
+
if (options.watch) {
|
|
212
|
+
manager.setupWatchers(core.broadcastSSE);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
store[MIDDLEWARE_KEY] = core.createAssetManagerMiddleware({
|
|
216
|
+
base: options.base,
|
|
217
|
+
scanner: manager.scanner,
|
|
218
|
+
importerScanner: manager.importerScanner,
|
|
219
|
+
duplicateScanner: manager.duplicateScanner,
|
|
220
|
+
thumbnailService: manager.thumbnailService,
|
|
221
|
+
root,
|
|
222
|
+
launchEditor: options.launchEditor
|
|
223
|
+
});
|
|
224
|
+
})();
|
|
225
|
+
}
|
|
226
|
+
await store[INIT_PROMISE_KEY];
|
|
227
|
+
return store[MIDDLEWARE_KEY];
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/handler.ts
|
|
233
|
+
function createHandler(userOptions = {}) {
|
|
234
|
+
const resolvedOptions = core.resolveOptions({
|
|
235
|
+
base: "/api/asset-manager",
|
|
236
|
+
include: ["app", "public", "src"],
|
|
237
|
+
aliases: { "@/": "src/" },
|
|
238
|
+
...userOptions
|
|
239
|
+
});
|
|
240
|
+
const root = process.cwd();
|
|
241
|
+
const { middleware: getMiddleware } = getOrCreateMiddleware(
|
|
242
|
+
root,
|
|
243
|
+
resolvedOptions
|
|
244
|
+
);
|
|
245
|
+
async function handler(request) {
|
|
246
|
+
if (process.env.NODE_ENV === "production") {
|
|
247
|
+
return new Response("Not Found", { status: 404 });
|
|
248
|
+
}
|
|
249
|
+
const mw = await getMiddleware();
|
|
250
|
+
return callMiddleware(request, mw);
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
GET: handler,
|
|
254
|
+
POST: handler
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/with-asset-manager.ts
|
|
259
|
+
function withAssetManager(nextConfig = {}, options = {}) {
|
|
260
|
+
const base = options.base ?? "/api/asset-manager";
|
|
261
|
+
if (nextConfig.logging === false) {
|
|
262
|
+
return nextConfig;
|
|
263
|
+
}
|
|
264
|
+
const existingLogging = typeof nextConfig.logging === "object" ? nextConfig.logging : {};
|
|
265
|
+
if (existingLogging.incomingRequests === false) {
|
|
266
|
+
return nextConfig;
|
|
267
|
+
}
|
|
268
|
+
const existingIncoming = typeof existingLogging.incomingRequests === "object" ? existingLogging.incomingRequests : {};
|
|
269
|
+
const existingIgnore = Array.isArray(existingIncoming.ignore) ? existingIncoming.ignore : [];
|
|
270
|
+
const escapedBase = base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
271
|
+
const pattern = new RegExp(escapedBase);
|
|
272
|
+
return {
|
|
273
|
+
...nextConfig,
|
|
274
|
+
logging: {
|
|
275
|
+
...existingLogging,
|
|
276
|
+
incomingRequests: {
|
|
277
|
+
...existingIncoming,
|
|
278
|
+
ignore: [...existingIgnore, pattern]
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function AssetManagerScript({
|
|
284
|
+
base = "/api/asset-manager"
|
|
285
|
+
}) {
|
|
286
|
+
if (process.env.NODE_ENV !== "development") {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
const normalizedBase = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
290
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
291
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
292
|
+
Script__default.default,
|
|
293
|
+
{
|
|
294
|
+
id: "vam-base-url",
|
|
295
|
+
strategy: "beforeInteractive",
|
|
296
|
+
dangerouslySetInnerHTML: {
|
|
297
|
+
__html: `window.__VAM_BASE_URL__ = "${normalizedBase}";`
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
),
|
|
301
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
302
|
+
Script__default.default,
|
|
303
|
+
{
|
|
304
|
+
id: "vam-floating-icon",
|
|
305
|
+
strategy: "afterInteractive",
|
|
306
|
+
src: `${normalizedBase}/floating-icon.js`
|
|
307
|
+
}
|
|
308
|
+
)
|
|
309
|
+
] });
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
exports.AssetManagerScript = AssetManagerScript;
|
|
313
|
+
exports.createHandler = createHandler;
|
|
314
|
+
exports.withAssetManager = withAssetManager;
|
|
315
|
+
//# sourceMappingURL=index.cjs.map
|
|
316
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapter.ts","../src/singleton.ts","../src/handler.ts","../src/with-asset-manager.ts","../src/components/AssetManagerScript.tsx"],"names":["Readable","Writable","AssetManager","broadcastSSE","createAssetManagerMiddleware","resolveOptions","jsxs","Fragment","jsx","Script"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Web API ↔ Node.js HTTP adapter.\n *\n * Next.js App Router API routes use the Web Fetch API (Request/Response),\n * but @vite-asset-manager/core middleware uses Node.js HTTP (IncomingMessage/ServerResponse).\n * This module bridges the two interfaces.\n */\nimport { Readable, Writable } from 'stream'\nimport type { IncomingHttpHeaders } from 'http'\nimport type { AssetManagerMiddleware } from '@vite-asset-manager/core'\n\n/**\n * Mock IncomingMessage that wraps a Web API Request.\n * The core router reads: url, method, headers, and body via Readable events.\n */\nclass MockIncomingMessage extends Readable {\n public url: string\n public method: string\n public headers: IncomingHttpHeaders\n\n constructor(request: Request) {\n super()\n this.method = request.method\n this.url = new URL(request.url).pathname + new URL(request.url).search\n\n // Convert Web Headers to Node.js headers (lowercase keys)\n const headers: IncomingHttpHeaders = {}\n request.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value\n })\n this.headers = headers\n }\n\n _read(): void {\n // No-op — data is pushed via feedBody()\n }\n\n async feedBody(request: Request): Promise<void> {\n if (request.body) {\n const reader = request.body.getReader()\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n this.push(Buffer.from(value))\n }\n } finally {\n reader.releaseLock()\n }\n }\n this.push(null)\n }\n}\n\n/**\n * Mock ServerResponse that captures output and converts to a Web API Response.\n *\n * Supports:\n * - JSON responses (setHeader + end)\n * - Binary streaming via pipe() (file serving, ZIP downloads)\n * - SSE streaming (writeHead with text/event-stream, repeated write calls)\n * - Range requests (statusCode 206)\n */\nclass MockServerResponse extends Writable {\n public statusCode: number = 200\n public headersSent: boolean = false\n\n private headers: Map<string, string | number | string[]> = new Map()\n private chunks: Buffer[] = []\n private resolveResponse!: (response: Response) => void\n private sseController: ReadableStreamDefaultController<Uint8Array> | null =\n null\n private isSSE: boolean = false\n private responseResolved: boolean = false\n\n public readonly responsePromise: Promise<Response>\n\n constructor() {\n super()\n this.responsePromise = new Promise<Response>((resolve) => {\n this.resolveResponse = resolve\n })\n }\n\n setHeader(name: string, value: string | number | string[]): this {\n this.headers.set(name.toLowerCase(), value)\n return this\n }\n\n getHeader(name: string): string | number | string[] | undefined {\n return this.headers.get(name.toLowerCase())\n }\n\n removeHeader(name: string): void {\n this.headers.delete(name.toLowerCase())\n }\n\n writeHead(\n statusCode: number,\n headers?: Record<string, string | string[]>\n ): this {\n this.statusCode = statusCode\n this.headersSent = true\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n this.headers.set(key.toLowerCase(), value)\n }\n }\n\n // Detect SSE and resolve immediately with a streaming Response\n const contentType = this.headers.get('content-type')\n if (contentType === 'text/event-stream') {\n this.isSSE = true\n this.resolveSSEResponse()\n }\n\n return this\n }\n\n // Capture data from pipe() and write() calls\n _write(\n chunk: Buffer | string,\n encoding: BufferEncoding,\n callback: (error?: Error | null) => void\n ): void {\n const buffer = Buffer.isBuffer(chunk)\n ? chunk\n : Buffer.from(chunk, encoding)\n\n if (this.isSSE && this.sseController) {\n try {\n this.sseController.enqueue(new Uint8Array(buffer))\n } catch {\n // Controller may be closed if client disconnected\n }\n } else {\n this.chunks.push(buffer)\n }\n\n callback()\n }\n\n _final(callback: (error?: Error | null) => void): void {\n if (!this.isSSE && !this.responseResolved) {\n this.resolveNormalResponse()\n }\n callback()\n }\n\n // Override end() to finalize the response\n end(chunk?: unknown, encodingOrCallback?: unknown, callback?: unknown): this {\n if (chunk !== undefined && chunk !== null) {\n const buf = Buffer.isBuffer(chunk)\n ? chunk\n : Buffer.from(String(chunk))\n if (this.isSSE && this.sseController) {\n try {\n this.sseController.enqueue(new Uint8Array(buf))\n } catch {\n // Controller may be closed\n }\n } else {\n this.chunks.push(buf)\n }\n }\n\n if (!this.isSSE && !this.responseResolved) {\n this.resolveNormalResponse()\n }\n\n const cb =\n typeof encodingOrCallback === 'function' ? encodingOrCallback : callback\n if (typeof cb === 'function') (cb as () => void)()\n\n return this\n }\n\n private buildHeaders(): Headers {\n const headers = new Headers()\n for (const [key, value] of this.headers) {\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v)\n } else {\n headers.set(key, String(value))\n }\n }\n return headers\n }\n\n private resolveNormalResponse(): void {\n if (this.responseResolved) return\n this.responseResolved = true\n\n const body =\n this.chunks.length > 0\n ? new Uint8Array(Buffer.concat(this.chunks))\n : null\n this.resolveResponse(\n new Response(body, {\n status: this.statusCode,\n headers: this.buildHeaders(),\n })\n )\n }\n\n private resolveSSEResponse(): void {\n if (this.responseResolved) return\n this.responseResolved = true\n\n const stream = new ReadableStream<Uint8Array>({\n start: (controller) => {\n this.sseController = controller\n\n // Flush any data already written before the stream started\n // (e.g., the initial \"connected\" message in handleSSE)\n for (const chunk of this.chunks) {\n controller.enqueue(new Uint8Array(chunk))\n }\n this.chunks = []\n },\n cancel: () => {\n // Client disconnected — emit 'close' so the router cleans up sseClients\n this.emit('close')\n this.sseController = null\n },\n })\n\n this.resolveResponse(\n new Response(stream, {\n status: this.statusCode,\n headers: this.buildHeaders(),\n })\n )\n }\n}\n\n/**\n * Bridge a Web API Request through a Node.js middleware and return a Web API Response.\n */\nexport async function callMiddleware(\n request: Request,\n middleware: AssetManagerMiddleware\n): Promise<Response> {\n const mockReq = new MockIncomingMessage(request)\n const mockRes = new MockServerResponse()\n\n let nextCalled = false\n const next = () => {\n nextCalled = true\n }\n\n // Start feeding the body — chunks are buffered in the Readable\n // until the middleware's parseJsonBody() consumes them\n mockReq.feedBody(request)\n\n // Call the middleware\n try {\n middleware(\n mockReq as unknown as import('http').IncomingMessage,\n mockRes as unknown as import('http').ServerResponse,\n next\n )\n } catch (error) {\n console.error('[nextjs-asset-manager] Middleware error:', error)\n return new Response('Internal Server Error', { status: 500 })\n }\n\n if (nextCalled) {\n return new Response('Not Found', { status: 404 })\n }\n\n // Wait for the response to be built:\n // - Normal responses: resolves when end() is called\n // - SSE: resolves immediately when writeHead detects text/event-stream\n return mockRes.responsePromise\n}\n","/**\n * Singleton management for AssetManager instance.\n *\n * Uses globalThis to survive Next.js HMR module re-evaluation during development.\n * This is the standard pattern (used by Prisma, databases, etc.) to prevent\n * creating duplicate instances when Next.js hot-reloads API route modules.\n */\nimport {\n AssetManager,\n createAssetManagerMiddleware,\n broadcastSSE,\n type ResolvedOptions,\n type AssetManagerMiddleware,\n} from '@vite-asset-manager/core'\n\nconst MANAGER_KEY = Symbol.for('__vam_asset_manager__')\nconst MIDDLEWARE_KEY = Symbol.for('__vam_middleware__')\nconst INIT_PROMISE_KEY = Symbol.for('__vam_init_promise__')\n\ninterface GlobalStore {\n [MANAGER_KEY]?: AssetManager\n [MIDDLEWARE_KEY]?: AssetManagerMiddleware\n [INIT_PROMISE_KEY]?: Promise<void>\n}\n\nconst store = globalThis as unknown as GlobalStore\n\nexport function getOrCreateMiddleware(\n root: string,\n options: ResolvedOptions\n): { middleware: () => Promise<AssetManagerMiddleware> } {\n return {\n middleware: async () => {\n if (store[MIDDLEWARE_KEY]) {\n return store[MIDDLEWARE_KEY]\n }\n\n if (!store[INIT_PROMISE_KEY]) {\n store[INIT_PROMISE_KEY] = (async () => {\n let manager = store[MANAGER_KEY]\n\n if (!manager) {\n manager = new AssetManager({ root, options })\n store[MANAGER_KEY] = manager\n await manager.init()\n\n if (options.watch) {\n manager.setupWatchers(broadcastSSE)\n }\n }\n\n store[MIDDLEWARE_KEY] = createAssetManagerMiddleware({\n base: options.base,\n scanner: manager.scanner,\n importerScanner: manager.importerScanner,\n duplicateScanner: manager.duplicateScanner,\n thumbnailService: manager.thumbnailService,\n root,\n launchEditor: options.launchEditor,\n })\n })()\n }\n\n await store[INIT_PROMISE_KEY]\n return store[MIDDLEWARE_KEY]!\n },\n }\n}\n\nexport function destroyInstance(): void {\n store[MANAGER_KEY]?.destroy()\n store[MANAGER_KEY] = undefined\n store[MIDDLEWARE_KEY] = undefined\n store[INIT_PROMISE_KEY] = undefined\n}\n","/**\n * Next.js App Router handler factory.\n *\n * Returns { GET, POST } route handlers that bridge Web API requests\n * to the core middleware via the adapter.\n */\nimport {\n resolveOptions,\n type AssetManagerOptions,\n} from '@vite-asset-manager/core'\nimport { callMiddleware } from './adapter.js'\nimport { getOrCreateMiddleware } from './singleton.js'\n\nexport interface NextAssetManagerOptions extends AssetManagerOptions {}\n\nexport function createHandler(userOptions: NextAssetManagerOptions = {}) {\n const resolvedOptions = resolveOptions({\n base: '/api/asset-manager',\n include: ['app', 'public', 'src'],\n aliases: { '@/': 'src/' },\n ...userOptions,\n })\n\n const root = process.cwd()\n const { middleware: getMiddleware } = getOrCreateMiddleware(\n root,\n resolvedOptions\n )\n\n async function handler(request: Request): Promise<Response> {\n // Dev-only guard\n if (process.env.NODE_ENV === 'production') {\n return new Response('Not Found', { status: 404 })\n }\n\n const mw = await getMiddleware()\n return callMiddleware(request, mw)\n }\n\n return {\n GET: handler,\n POST: handler,\n }\n}\n","import type { NextConfig } from 'next'\n\nexport interface WithAssetManagerOptions {\n /**\n * Base URL path for the asset manager API routes.\n * Must match the `base` option passed to `createHandler()`.\n * @default '/api/asset-manager'\n */\n base?: string\n}\n\n/**\n * Wraps a Next.js config to suppress dev server request logging\n * for asset manager API routes.\n *\n * @example\n * ```ts\n * // next.config.ts\n * import { withAssetManager } from 'nextjs-asset-manager'\n *\n * const nextConfig: NextConfig = {}\n * export default withAssetManager(nextConfig)\n * ```\n */\nexport function withAssetManager(\n nextConfig: NextConfig = {},\n options: WithAssetManagerOptions = {}\n): NextConfig {\n const base = options.base ?? '/api/asset-manager'\n\n // Respect user's choice to disable logging entirely\n if (nextConfig.logging === false) {\n return nextConfig\n }\n\n const existingLogging =\n typeof nextConfig.logging === 'object' ? nextConfig.logging : {}\n\n // Respect user's choice to disable incoming request logging entirely\n if (existingLogging.incomingRequests === false) {\n return nextConfig\n }\n\n const existingIncoming =\n typeof existingLogging.incomingRequests === 'object'\n ? existingLogging.incomingRequests\n : {}\n\n const existingIgnore = Array.isArray(existingIncoming.ignore)\n ? existingIncoming.ignore\n : []\n\n // Build regex that matches the base path\n const escapedBase = base.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const pattern = new RegExp(escapedBase)\n\n return {\n ...nextConfig,\n logging: {\n ...existingLogging,\n incomingRequests: {\n ...existingIncoming,\n ignore: [...existingIgnore, pattern],\n },\n },\n }\n}\n","'use client'\n\nimport Script from 'next/script'\n\nexport interface AssetManagerScriptProps {\n /**\n * Base URL path for the asset manager dashboard.\n * Must match the `base` option passed to `createHandler()`.\n * @default '/api/asset-manager'\n */\n base?: string\n}\n\n/**\n * Injects the floating icon scripts into a Next.js application.\n * Add this component to your root layout to enable the draggable\n * asset manager panel overlay.\n *\n * Only renders in development mode — zero production footprint.\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { AssetManagerScript } from 'nextjs-asset-manager'\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html><body>\n * {children}\n * <AssetManagerScript />\n * </body></html>\n * )\n * }\n * ```\n */\nexport function AssetManagerScript({\n base = '/api/asset-manager',\n}: AssetManagerScriptProps) {\n if (process.env.NODE_ENV !== 'development') {\n return null\n }\n\n const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base\n\n return (\n <>\n <Script\n id=\"vam-base-url\"\n strategy=\"beforeInteractive\"\n dangerouslySetInnerHTML={{\n __html: `window.__VAM_BASE_URL__ = \"${normalizedBase}\";`,\n }}\n />\n <Script\n id=\"vam-floating-icon\"\n strategy=\"afterInteractive\"\n src={`${normalizedBase}/floating-icon.js`}\n />\n </>\n )\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { AssetManagerOptions } from '@vite-asset-manager/core';
|
|
2
|
+
export { Asset, AssetGroup, AssetManagerOptions, AssetStats, AssetType, EditorType, ImportType, Importer, ResolvedOptions } from '@vite-asset-manager/core';
|
|
3
|
+
import { NextConfig } from 'next';
|
|
4
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Next.js App Router handler factory.
|
|
8
|
+
*
|
|
9
|
+
* Returns { GET, POST } route handlers that bridge Web API requests
|
|
10
|
+
* to the core middleware via the adapter.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
interface NextAssetManagerOptions extends AssetManagerOptions {
|
|
14
|
+
}
|
|
15
|
+
declare function createHandler(userOptions?: NextAssetManagerOptions): {
|
|
16
|
+
GET: (request: Request) => Promise<Response>;
|
|
17
|
+
POST: (request: Request) => Promise<Response>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
interface WithAssetManagerOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Base URL path for the asset manager API routes.
|
|
23
|
+
* Must match the `base` option passed to `createHandler()`.
|
|
24
|
+
* @default '/api/asset-manager'
|
|
25
|
+
*/
|
|
26
|
+
base?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a Next.js config to suppress dev server request logging
|
|
30
|
+
* for asset manager API routes.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* // next.config.ts
|
|
35
|
+
* import { withAssetManager } from 'nextjs-asset-manager'
|
|
36
|
+
*
|
|
37
|
+
* const nextConfig: NextConfig = {}
|
|
38
|
+
* export default withAssetManager(nextConfig)
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
declare function withAssetManager(nextConfig?: NextConfig, options?: WithAssetManagerOptions): NextConfig;
|
|
42
|
+
|
|
43
|
+
interface AssetManagerScriptProps {
|
|
44
|
+
/**
|
|
45
|
+
* Base URL path for the asset manager dashboard.
|
|
46
|
+
* Must match the `base` option passed to `createHandler()`.
|
|
47
|
+
* @default '/api/asset-manager'
|
|
48
|
+
*/
|
|
49
|
+
base?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Injects the floating icon scripts into a Next.js application.
|
|
53
|
+
* Add this component to your root layout to enable the draggable
|
|
54
|
+
* asset manager panel overlay.
|
|
55
|
+
*
|
|
56
|
+
* Only renders in development mode — zero production footprint.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* // app/layout.tsx
|
|
61
|
+
* import { AssetManagerScript } from 'nextjs-asset-manager'
|
|
62
|
+
*
|
|
63
|
+
* export default function RootLayout({ children }) {
|
|
64
|
+
* return (
|
|
65
|
+
* <html><body>
|
|
66
|
+
* {children}
|
|
67
|
+
* <AssetManagerScript />
|
|
68
|
+
* </body></html>
|
|
69
|
+
* )
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
declare function AssetManagerScript({ base, }: AssetManagerScriptProps): react_jsx_runtime.JSX.Element | null;
|
|
74
|
+
|
|
75
|
+
export { AssetManagerScript, type AssetManagerScriptProps, type NextAssetManagerOptions, type WithAssetManagerOptions, createHandler, withAssetManager };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { AssetManagerOptions } from '@vite-asset-manager/core';
|
|
2
|
+
export { Asset, AssetGroup, AssetManagerOptions, AssetStats, AssetType, EditorType, ImportType, Importer, ResolvedOptions } from '@vite-asset-manager/core';
|
|
3
|
+
import { NextConfig } from 'next';
|
|
4
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Next.js App Router handler factory.
|
|
8
|
+
*
|
|
9
|
+
* Returns { GET, POST } route handlers that bridge Web API requests
|
|
10
|
+
* to the core middleware via the adapter.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
interface NextAssetManagerOptions extends AssetManagerOptions {
|
|
14
|
+
}
|
|
15
|
+
declare function createHandler(userOptions?: NextAssetManagerOptions): {
|
|
16
|
+
GET: (request: Request) => Promise<Response>;
|
|
17
|
+
POST: (request: Request) => Promise<Response>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
interface WithAssetManagerOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Base URL path for the asset manager API routes.
|
|
23
|
+
* Must match the `base` option passed to `createHandler()`.
|
|
24
|
+
* @default '/api/asset-manager'
|
|
25
|
+
*/
|
|
26
|
+
base?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a Next.js config to suppress dev server request logging
|
|
30
|
+
* for asset manager API routes.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* // next.config.ts
|
|
35
|
+
* import { withAssetManager } from 'nextjs-asset-manager'
|
|
36
|
+
*
|
|
37
|
+
* const nextConfig: NextConfig = {}
|
|
38
|
+
* export default withAssetManager(nextConfig)
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
declare function withAssetManager(nextConfig?: NextConfig, options?: WithAssetManagerOptions): NextConfig;
|
|
42
|
+
|
|
43
|
+
interface AssetManagerScriptProps {
|
|
44
|
+
/**
|
|
45
|
+
* Base URL path for the asset manager dashboard.
|
|
46
|
+
* Must match the `base` option passed to `createHandler()`.
|
|
47
|
+
* @default '/api/asset-manager'
|
|
48
|
+
*/
|
|
49
|
+
base?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Injects the floating icon scripts into a Next.js application.
|
|
53
|
+
* Add this component to your root layout to enable the draggable
|
|
54
|
+
* asset manager panel overlay.
|
|
55
|
+
*
|
|
56
|
+
* Only renders in development mode — zero production footprint.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* // app/layout.tsx
|
|
61
|
+
* import { AssetManagerScript } from 'nextjs-asset-manager'
|
|
62
|
+
*
|
|
63
|
+
* export default function RootLayout({ children }) {
|
|
64
|
+
* return (
|
|
65
|
+
* <html><body>
|
|
66
|
+
* {children}
|
|
67
|
+
* <AssetManagerScript />
|
|
68
|
+
* </body></html>
|
|
69
|
+
* )
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
declare function AssetManagerScript({ base, }: AssetManagerScriptProps): react_jsx_runtime.JSX.Element | null;
|
|
74
|
+
|
|
75
|
+
export { AssetManagerScript, type AssetManagerScriptProps, type NextAssetManagerOptions, type WithAssetManagerOptions, createHandler, withAssetManager };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { resolveOptions, AssetManager, broadcastSSE, createAssetManagerMiddleware } from '@vite-asset-manager/core';
|
|
2
|
+
import { Readable, Writable } from 'stream';
|
|
3
|
+
import Script from 'next/script';
|
|
4
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/handler.ts
|
|
7
|
+
var MockIncomingMessage = class extends Readable {
|
|
8
|
+
url;
|
|
9
|
+
method;
|
|
10
|
+
headers;
|
|
11
|
+
constructor(request) {
|
|
12
|
+
super();
|
|
13
|
+
this.method = request.method;
|
|
14
|
+
this.url = new URL(request.url).pathname + new URL(request.url).search;
|
|
15
|
+
const headers = {};
|
|
16
|
+
request.headers.forEach((value, key) => {
|
|
17
|
+
headers[key.toLowerCase()] = value;
|
|
18
|
+
});
|
|
19
|
+
this.headers = headers;
|
|
20
|
+
}
|
|
21
|
+
_read() {
|
|
22
|
+
}
|
|
23
|
+
async feedBody(request) {
|
|
24
|
+
if (request.body) {
|
|
25
|
+
const reader = request.body.getReader();
|
|
26
|
+
try {
|
|
27
|
+
while (true) {
|
|
28
|
+
const { done, value } = await reader.read();
|
|
29
|
+
if (done) break;
|
|
30
|
+
this.push(Buffer.from(value));
|
|
31
|
+
}
|
|
32
|
+
} finally {
|
|
33
|
+
reader.releaseLock();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
this.push(null);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var MockServerResponse = class extends Writable {
|
|
40
|
+
statusCode = 200;
|
|
41
|
+
headersSent = false;
|
|
42
|
+
headers = /* @__PURE__ */ new Map();
|
|
43
|
+
chunks = [];
|
|
44
|
+
resolveResponse;
|
|
45
|
+
sseController = null;
|
|
46
|
+
isSSE = false;
|
|
47
|
+
responseResolved = false;
|
|
48
|
+
responsePromise;
|
|
49
|
+
constructor() {
|
|
50
|
+
super();
|
|
51
|
+
this.responsePromise = new Promise((resolve) => {
|
|
52
|
+
this.resolveResponse = resolve;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
setHeader(name, value) {
|
|
56
|
+
this.headers.set(name.toLowerCase(), value);
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
getHeader(name) {
|
|
60
|
+
return this.headers.get(name.toLowerCase());
|
|
61
|
+
}
|
|
62
|
+
removeHeader(name) {
|
|
63
|
+
this.headers.delete(name.toLowerCase());
|
|
64
|
+
}
|
|
65
|
+
writeHead(statusCode, headers) {
|
|
66
|
+
this.statusCode = statusCode;
|
|
67
|
+
this.headersSent = true;
|
|
68
|
+
if (headers) {
|
|
69
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
70
|
+
this.headers.set(key.toLowerCase(), value);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const contentType = this.headers.get("content-type");
|
|
74
|
+
if (contentType === "text/event-stream") {
|
|
75
|
+
this.isSSE = true;
|
|
76
|
+
this.resolveSSEResponse();
|
|
77
|
+
}
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
// Capture data from pipe() and write() calls
|
|
81
|
+
_write(chunk, encoding, callback) {
|
|
82
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);
|
|
83
|
+
if (this.isSSE && this.sseController) {
|
|
84
|
+
try {
|
|
85
|
+
this.sseController.enqueue(new Uint8Array(buffer));
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
this.chunks.push(buffer);
|
|
90
|
+
}
|
|
91
|
+
callback();
|
|
92
|
+
}
|
|
93
|
+
_final(callback) {
|
|
94
|
+
if (!this.isSSE && !this.responseResolved) {
|
|
95
|
+
this.resolveNormalResponse();
|
|
96
|
+
}
|
|
97
|
+
callback();
|
|
98
|
+
}
|
|
99
|
+
// Override end() to finalize the response
|
|
100
|
+
end(chunk, encodingOrCallback, callback) {
|
|
101
|
+
if (chunk !== void 0 && chunk !== null) {
|
|
102
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
|
|
103
|
+
if (this.isSSE && this.sseController) {
|
|
104
|
+
try {
|
|
105
|
+
this.sseController.enqueue(new Uint8Array(buf));
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
this.chunks.push(buf);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!this.isSSE && !this.responseResolved) {
|
|
113
|
+
this.resolveNormalResponse();
|
|
114
|
+
}
|
|
115
|
+
const cb = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
|
|
116
|
+
if (typeof cb === "function") cb();
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
buildHeaders() {
|
|
120
|
+
const headers = new Headers();
|
|
121
|
+
for (const [key, value] of this.headers) {
|
|
122
|
+
if (Array.isArray(value)) {
|
|
123
|
+
for (const v of value) headers.append(key, v);
|
|
124
|
+
} else {
|
|
125
|
+
headers.set(key, String(value));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return headers;
|
|
129
|
+
}
|
|
130
|
+
resolveNormalResponse() {
|
|
131
|
+
if (this.responseResolved) return;
|
|
132
|
+
this.responseResolved = true;
|
|
133
|
+
const body = this.chunks.length > 0 ? new Uint8Array(Buffer.concat(this.chunks)) : null;
|
|
134
|
+
this.resolveResponse(
|
|
135
|
+
new Response(body, {
|
|
136
|
+
status: this.statusCode,
|
|
137
|
+
headers: this.buildHeaders()
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
resolveSSEResponse() {
|
|
142
|
+
if (this.responseResolved) return;
|
|
143
|
+
this.responseResolved = true;
|
|
144
|
+
const stream = new ReadableStream({
|
|
145
|
+
start: (controller) => {
|
|
146
|
+
this.sseController = controller;
|
|
147
|
+
for (const chunk of this.chunks) {
|
|
148
|
+
controller.enqueue(new Uint8Array(chunk));
|
|
149
|
+
}
|
|
150
|
+
this.chunks = [];
|
|
151
|
+
},
|
|
152
|
+
cancel: () => {
|
|
153
|
+
this.emit("close");
|
|
154
|
+
this.sseController = null;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
this.resolveResponse(
|
|
158
|
+
new Response(stream, {
|
|
159
|
+
status: this.statusCode,
|
|
160
|
+
headers: this.buildHeaders()
|
|
161
|
+
})
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
async function callMiddleware(request, middleware) {
|
|
166
|
+
const mockReq = new MockIncomingMessage(request);
|
|
167
|
+
const mockRes = new MockServerResponse();
|
|
168
|
+
let nextCalled = false;
|
|
169
|
+
const next = () => {
|
|
170
|
+
nextCalled = true;
|
|
171
|
+
};
|
|
172
|
+
mockReq.feedBody(request);
|
|
173
|
+
try {
|
|
174
|
+
middleware(
|
|
175
|
+
mockReq,
|
|
176
|
+
mockRes,
|
|
177
|
+
next
|
|
178
|
+
);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error("[nextjs-asset-manager] Middleware error:", error);
|
|
181
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
182
|
+
}
|
|
183
|
+
if (nextCalled) {
|
|
184
|
+
return new Response("Not Found", { status: 404 });
|
|
185
|
+
}
|
|
186
|
+
return mockRes.responsePromise;
|
|
187
|
+
}
|
|
188
|
+
var MANAGER_KEY = /* @__PURE__ */ Symbol.for("__vam_asset_manager__");
|
|
189
|
+
var MIDDLEWARE_KEY = /* @__PURE__ */ Symbol.for("__vam_middleware__");
|
|
190
|
+
var INIT_PROMISE_KEY = /* @__PURE__ */ Symbol.for("__vam_init_promise__");
|
|
191
|
+
var store = globalThis;
|
|
192
|
+
function getOrCreateMiddleware(root, options) {
|
|
193
|
+
return {
|
|
194
|
+
middleware: async () => {
|
|
195
|
+
if (store[MIDDLEWARE_KEY]) {
|
|
196
|
+
return store[MIDDLEWARE_KEY];
|
|
197
|
+
}
|
|
198
|
+
if (!store[INIT_PROMISE_KEY]) {
|
|
199
|
+
store[INIT_PROMISE_KEY] = (async () => {
|
|
200
|
+
let manager = store[MANAGER_KEY];
|
|
201
|
+
if (!manager) {
|
|
202
|
+
manager = new AssetManager({ root, options });
|
|
203
|
+
store[MANAGER_KEY] = manager;
|
|
204
|
+
await manager.init();
|
|
205
|
+
if (options.watch) {
|
|
206
|
+
manager.setupWatchers(broadcastSSE);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
store[MIDDLEWARE_KEY] = createAssetManagerMiddleware({
|
|
210
|
+
base: options.base,
|
|
211
|
+
scanner: manager.scanner,
|
|
212
|
+
importerScanner: manager.importerScanner,
|
|
213
|
+
duplicateScanner: manager.duplicateScanner,
|
|
214
|
+
thumbnailService: manager.thumbnailService,
|
|
215
|
+
root,
|
|
216
|
+
launchEditor: options.launchEditor
|
|
217
|
+
});
|
|
218
|
+
})();
|
|
219
|
+
}
|
|
220
|
+
await store[INIT_PROMISE_KEY];
|
|
221
|
+
return store[MIDDLEWARE_KEY];
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/handler.ts
|
|
227
|
+
function createHandler(userOptions = {}) {
|
|
228
|
+
const resolvedOptions = resolveOptions({
|
|
229
|
+
base: "/api/asset-manager",
|
|
230
|
+
include: ["app", "public", "src"],
|
|
231
|
+
aliases: { "@/": "src/" },
|
|
232
|
+
...userOptions
|
|
233
|
+
});
|
|
234
|
+
const root = process.cwd();
|
|
235
|
+
const { middleware: getMiddleware } = getOrCreateMiddleware(
|
|
236
|
+
root,
|
|
237
|
+
resolvedOptions
|
|
238
|
+
);
|
|
239
|
+
async function handler(request) {
|
|
240
|
+
if (process.env.NODE_ENV === "production") {
|
|
241
|
+
return new Response("Not Found", { status: 404 });
|
|
242
|
+
}
|
|
243
|
+
const mw = await getMiddleware();
|
|
244
|
+
return callMiddleware(request, mw);
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
GET: handler,
|
|
248
|
+
POST: handler
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/with-asset-manager.ts
|
|
253
|
+
function withAssetManager(nextConfig = {}, options = {}) {
|
|
254
|
+
const base = options.base ?? "/api/asset-manager";
|
|
255
|
+
if (nextConfig.logging === false) {
|
|
256
|
+
return nextConfig;
|
|
257
|
+
}
|
|
258
|
+
const existingLogging = typeof nextConfig.logging === "object" ? nextConfig.logging : {};
|
|
259
|
+
if (existingLogging.incomingRequests === false) {
|
|
260
|
+
return nextConfig;
|
|
261
|
+
}
|
|
262
|
+
const existingIncoming = typeof existingLogging.incomingRequests === "object" ? existingLogging.incomingRequests : {};
|
|
263
|
+
const existingIgnore = Array.isArray(existingIncoming.ignore) ? existingIncoming.ignore : [];
|
|
264
|
+
const escapedBase = base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
265
|
+
const pattern = new RegExp(escapedBase);
|
|
266
|
+
return {
|
|
267
|
+
...nextConfig,
|
|
268
|
+
logging: {
|
|
269
|
+
...existingLogging,
|
|
270
|
+
incomingRequests: {
|
|
271
|
+
...existingIncoming,
|
|
272
|
+
ignore: [...existingIgnore, pattern]
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function AssetManagerScript({
|
|
278
|
+
base = "/api/asset-manager"
|
|
279
|
+
}) {
|
|
280
|
+
if (process.env.NODE_ENV !== "development") {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
const normalizedBase = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
284
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
285
|
+
/* @__PURE__ */ jsx(
|
|
286
|
+
Script,
|
|
287
|
+
{
|
|
288
|
+
id: "vam-base-url",
|
|
289
|
+
strategy: "beforeInteractive",
|
|
290
|
+
dangerouslySetInnerHTML: {
|
|
291
|
+
__html: `window.__VAM_BASE_URL__ = "${normalizedBase}";`
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
),
|
|
295
|
+
/* @__PURE__ */ jsx(
|
|
296
|
+
Script,
|
|
297
|
+
{
|
|
298
|
+
id: "vam-floating-icon",
|
|
299
|
+
strategy: "afterInteractive",
|
|
300
|
+
src: `${normalizedBase}/floating-icon.js`
|
|
301
|
+
}
|
|
302
|
+
)
|
|
303
|
+
] });
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export { AssetManagerScript, createHandler, withAssetManager };
|
|
307
|
+
//# sourceMappingURL=index.js.map
|
|
308
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapter.ts","../src/singleton.ts","../src/handler.ts","../src/with-asset-manager.ts","../src/components/AssetManagerScript.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Web API ↔ Node.js HTTP adapter.\n *\n * Next.js App Router API routes use the Web Fetch API (Request/Response),\n * but @vite-asset-manager/core middleware uses Node.js HTTP (IncomingMessage/ServerResponse).\n * This module bridges the two interfaces.\n */\nimport { Readable, Writable } from 'stream'\nimport type { IncomingHttpHeaders } from 'http'\nimport type { AssetManagerMiddleware } from '@vite-asset-manager/core'\n\n/**\n * Mock IncomingMessage that wraps a Web API Request.\n * The core router reads: url, method, headers, and body via Readable events.\n */\nclass MockIncomingMessage extends Readable {\n public url: string\n public method: string\n public headers: IncomingHttpHeaders\n\n constructor(request: Request) {\n super()\n this.method = request.method\n this.url = new URL(request.url).pathname + new URL(request.url).search\n\n // Convert Web Headers to Node.js headers (lowercase keys)\n const headers: IncomingHttpHeaders = {}\n request.headers.forEach((value, key) => {\n headers[key.toLowerCase()] = value\n })\n this.headers = headers\n }\n\n _read(): void {\n // No-op — data is pushed via feedBody()\n }\n\n async feedBody(request: Request): Promise<void> {\n if (request.body) {\n const reader = request.body.getReader()\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n this.push(Buffer.from(value))\n }\n } finally {\n reader.releaseLock()\n }\n }\n this.push(null)\n }\n}\n\n/**\n * Mock ServerResponse that captures output and converts to a Web API Response.\n *\n * Supports:\n * - JSON responses (setHeader + end)\n * - Binary streaming via pipe() (file serving, ZIP downloads)\n * - SSE streaming (writeHead with text/event-stream, repeated write calls)\n * - Range requests (statusCode 206)\n */\nclass MockServerResponse extends Writable {\n public statusCode: number = 200\n public headersSent: boolean = false\n\n private headers: Map<string, string | number | string[]> = new Map()\n private chunks: Buffer[] = []\n private resolveResponse!: (response: Response) => void\n private sseController: ReadableStreamDefaultController<Uint8Array> | null =\n null\n private isSSE: boolean = false\n private responseResolved: boolean = false\n\n public readonly responsePromise: Promise<Response>\n\n constructor() {\n super()\n this.responsePromise = new Promise<Response>((resolve) => {\n this.resolveResponse = resolve\n })\n }\n\n setHeader(name: string, value: string | number | string[]): this {\n this.headers.set(name.toLowerCase(), value)\n return this\n }\n\n getHeader(name: string): string | number | string[] | undefined {\n return this.headers.get(name.toLowerCase())\n }\n\n removeHeader(name: string): void {\n this.headers.delete(name.toLowerCase())\n }\n\n writeHead(\n statusCode: number,\n headers?: Record<string, string | string[]>\n ): this {\n this.statusCode = statusCode\n this.headersSent = true\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n this.headers.set(key.toLowerCase(), value)\n }\n }\n\n // Detect SSE and resolve immediately with a streaming Response\n const contentType = this.headers.get('content-type')\n if (contentType === 'text/event-stream') {\n this.isSSE = true\n this.resolveSSEResponse()\n }\n\n return this\n }\n\n // Capture data from pipe() and write() calls\n _write(\n chunk: Buffer | string,\n encoding: BufferEncoding,\n callback: (error?: Error | null) => void\n ): void {\n const buffer = Buffer.isBuffer(chunk)\n ? chunk\n : Buffer.from(chunk, encoding)\n\n if (this.isSSE && this.sseController) {\n try {\n this.sseController.enqueue(new Uint8Array(buffer))\n } catch {\n // Controller may be closed if client disconnected\n }\n } else {\n this.chunks.push(buffer)\n }\n\n callback()\n }\n\n _final(callback: (error?: Error | null) => void): void {\n if (!this.isSSE && !this.responseResolved) {\n this.resolveNormalResponse()\n }\n callback()\n }\n\n // Override end() to finalize the response\n end(chunk?: unknown, encodingOrCallback?: unknown, callback?: unknown): this {\n if (chunk !== undefined && chunk !== null) {\n const buf = Buffer.isBuffer(chunk)\n ? chunk\n : Buffer.from(String(chunk))\n if (this.isSSE && this.sseController) {\n try {\n this.sseController.enqueue(new Uint8Array(buf))\n } catch {\n // Controller may be closed\n }\n } else {\n this.chunks.push(buf)\n }\n }\n\n if (!this.isSSE && !this.responseResolved) {\n this.resolveNormalResponse()\n }\n\n const cb =\n typeof encodingOrCallback === 'function' ? encodingOrCallback : callback\n if (typeof cb === 'function') (cb as () => void)()\n\n return this\n }\n\n private buildHeaders(): Headers {\n const headers = new Headers()\n for (const [key, value] of this.headers) {\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v)\n } else {\n headers.set(key, String(value))\n }\n }\n return headers\n }\n\n private resolveNormalResponse(): void {\n if (this.responseResolved) return\n this.responseResolved = true\n\n const body =\n this.chunks.length > 0\n ? new Uint8Array(Buffer.concat(this.chunks))\n : null\n this.resolveResponse(\n new Response(body, {\n status: this.statusCode,\n headers: this.buildHeaders(),\n })\n )\n }\n\n private resolveSSEResponse(): void {\n if (this.responseResolved) return\n this.responseResolved = true\n\n const stream = new ReadableStream<Uint8Array>({\n start: (controller) => {\n this.sseController = controller\n\n // Flush any data already written before the stream started\n // (e.g., the initial \"connected\" message in handleSSE)\n for (const chunk of this.chunks) {\n controller.enqueue(new Uint8Array(chunk))\n }\n this.chunks = []\n },\n cancel: () => {\n // Client disconnected — emit 'close' so the router cleans up sseClients\n this.emit('close')\n this.sseController = null\n },\n })\n\n this.resolveResponse(\n new Response(stream, {\n status: this.statusCode,\n headers: this.buildHeaders(),\n })\n )\n }\n}\n\n/**\n * Bridge a Web API Request through a Node.js middleware and return a Web API Response.\n */\nexport async function callMiddleware(\n request: Request,\n middleware: AssetManagerMiddleware\n): Promise<Response> {\n const mockReq = new MockIncomingMessage(request)\n const mockRes = new MockServerResponse()\n\n let nextCalled = false\n const next = () => {\n nextCalled = true\n }\n\n // Start feeding the body — chunks are buffered in the Readable\n // until the middleware's parseJsonBody() consumes them\n mockReq.feedBody(request)\n\n // Call the middleware\n try {\n middleware(\n mockReq as unknown as import('http').IncomingMessage,\n mockRes as unknown as import('http').ServerResponse,\n next\n )\n } catch (error) {\n console.error('[nextjs-asset-manager] Middleware error:', error)\n return new Response('Internal Server Error', { status: 500 })\n }\n\n if (nextCalled) {\n return new Response('Not Found', { status: 404 })\n }\n\n // Wait for the response to be built:\n // - Normal responses: resolves when end() is called\n // - SSE: resolves immediately when writeHead detects text/event-stream\n return mockRes.responsePromise\n}\n","/**\n * Singleton management for AssetManager instance.\n *\n * Uses globalThis to survive Next.js HMR module re-evaluation during development.\n * This is the standard pattern (used by Prisma, databases, etc.) to prevent\n * creating duplicate instances when Next.js hot-reloads API route modules.\n */\nimport {\n AssetManager,\n createAssetManagerMiddleware,\n broadcastSSE,\n type ResolvedOptions,\n type AssetManagerMiddleware,\n} from '@vite-asset-manager/core'\n\nconst MANAGER_KEY = Symbol.for('__vam_asset_manager__')\nconst MIDDLEWARE_KEY = Symbol.for('__vam_middleware__')\nconst INIT_PROMISE_KEY = Symbol.for('__vam_init_promise__')\n\ninterface GlobalStore {\n [MANAGER_KEY]?: AssetManager\n [MIDDLEWARE_KEY]?: AssetManagerMiddleware\n [INIT_PROMISE_KEY]?: Promise<void>\n}\n\nconst store = globalThis as unknown as GlobalStore\n\nexport function getOrCreateMiddleware(\n root: string,\n options: ResolvedOptions\n): { middleware: () => Promise<AssetManagerMiddleware> } {\n return {\n middleware: async () => {\n if (store[MIDDLEWARE_KEY]) {\n return store[MIDDLEWARE_KEY]\n }\n\n if (!store[INIT_PROMISE_KEY]) {\n store[INIT_PROMISE_KEY] = (async () => {\n let manager = store[MANAGER_KEY]\n\n if (!manager) {\n manager = new AssetManager({ root, options })\n store[MANAGER_KEY] = manager\n await manager.init()\n\n if (options.watch) {\n manager.setupWatchers(broadcastSSE)\n }\n }\n\n store[MIDDLEWARE_KEY] = createAssetManagerMiddleware({\n base: options.base,\n scanner: manager.scanner,\n importerScanner: manager.importerScanner,\n duplicateScanner: manager.duplicateScanner,\n thumbnailService: manager.thumbnailService,\n root,\n launchEditor: options.launchEditor,\n })\n })()\n }\n\n await store[INIT_PROMISE_KEY]\n return store[MIDDLEWARE_KEY]!\n },\n }\n}\n\nexport function destroyInstance(): void {\n store[MANAGER_KEY]?.destroy()\n store[MANAGER_KEY] = undefined\n store[MIDDLEWARE_KEY] = undefined\n store[INIT_PROMISE_KEY] = undefined\n}\n","/**\n * Next.js App Router handler factory.\n *\n * Returns { GET, POST } route handlers that bridge Web API requests\n * to the core middleware via the adapter.\n */\nimport {\n resolveOptions,\n type AssetManagerOptions,\n} from '@vite-asset-manager/core'\nimport { callMiddleware } from './adapter.js'\nimport { getOrCreateMiddleware } from './singleton.js'\n\nexport interface NextAssetManagerOptions extends AssetManagerOptions {}\n\nexport function createHandler(userOptions: NextAssetManagerOptions = {}) {\n const resolvedOptions = resolveOptions({\n base: '/api/asset-manager',\n include: ['app', 'public', 'src'],\n aliases: { '@/': 'src/' },\n ...userOptions,\n })\n\n const root = process.cwd()\n const { middleware: getMiddleware } = getOrCreateMiddleware(\n root,\n resolvedOptions\n )\n\n async function handler(request: Request): Promise<Response> {\n // Dev-only guard\n if (process.env.NODE_ENV === 'production') {\n return new Response('Not Found', { status: 404 })\n }\n\n const mw = await getMiddleware()\n return callMiddleware(request, mw)\n }\n\n return {\n GET: handler,\n POST: handler,\n }\n}\n","import type { NextConfig } from 'next'\n\nexport interface WithAssetManagerOptions {\n /**\n * Base URL path for the asset manager API routes.\n * Must match the `base` option passed to `createHandler()`.\n * @default '/api/asset-manager'\n */\n base?: string\n}\n\n/**\n * Wraps a Next.js config to suppress dev server request logging\n * for asset manager API routes.\n *\n * @example\n * ```ts\n * // next.config.ts\n * import { withAssetManager } from 'nextjs-asset-manager'\n *\n * const nextConfig: NextConfig = {}\n * export default withAssetManager(nextConfig)\n * ```\n */\nexport function withAssetManager(\n nextConfig: NextConfig = {},\n options: WithAssetManagerOptions = {}\n): NextConfig {\n const base = options.base ?? '/api/asset-manager'\n\n // Respect user's choice to disable logging entirely\n if (nextConfig.logging === false) {\n return nextConfig\n }\n\n const existingLogging =\n typeof nextConfig.logging === 'object' ? nextConfig.logging : {}\n\n // Respect user's choice to disable incoming request logging entirely\n if (existingLogging.incomingRequests === false) {\n return nextConfig\n }\n\n const existingIncoming =\n typeof existingLogging.incomingRequests === 'object'\n ? existingLogging.incomingRequests\n : {}\n\n const existingIgnore = Array.isArray(existingIncoming.ignore)\n ? existingIncoming.ignore\n : []\n\n // Build regex that matches the base path\n const escapedBase = base.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const pattern = new RegExp(escapedBase)\n\n return {\n ...nextConfig,\n logging: {\n ...existingLogging,\n incomingRequests: {\n ...existingIncoming,\n ignore: [...existingIgnore, pattern],\n },\n },\n }\n}\n","'use client'\n\nimport Script from 'next/script'\n\nexport interface AssetManagerScriptProps {\n /**\n * Base URL path for the asset manager dashboard.\n * Must match the `base` option passed to `createHandler()`.\n * @default '/api/asset-manager'\n */\n base?: string\n}\n\n/**\n * Injects the floating icon scripts into a Next.js application.\n * Add this component to your root layout to enable the draggable\n * asset manager panel overlay.\n *\n * Only renders in development mode — zero production footprint.\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { AssetManagerScript } from 'nextjs-asset-manager'\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html><body>\n * {children}\n * <AssetManagerScript />\n * </body></html>\n * )\n * }\n * ```\n */\nexport function AssetManagerScript({\n base = '/api/asset-manager',\n}: AssetManagerScriptProps) {\n if (process.env.NODE_ENV !== 'development') {\n return null\n }\n\n const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base\n\n return (\n <>\n <Script\n id=\"vam-base-url\"\n strategy=\"beforeInteractive\"\n dangerouslySetInnerHTML={{\n __html: `window.__VAM_BASE_URL__ = \"${normalizedBase}\";`,\n }}\n />\n <Script\n id=\"vam-floating-icon\"\n strategy=\"afterInteractive\"\n src={`${normalizedBase}/floating-icon.js`}\n />\n </>\n )\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nextjs-asset-manager",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Next.js integration for asset management dashboard — browse, search, and manage all your project assets",
|
|
6
|
+
"author": "Ejiro Asiuwhu <ejiroasiuwhu10@gmail.com>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/ejirocodes/vite-plugin-asset-manager#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/ejirocodes/vite-plugin-asset-manager.git",
|
|
12
|
+
"directory": "packages/nextjs"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/ejirocodes/vite-plugin-asset-manager/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"nextjs",
|
|
19
|
+
"next",
|
|
20
|
+
"assets",
|
|
21
|
+
"asset-manager",
|
|
22
|
+
"dashboard",
|
|
23
|
+
"devtools"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"require": {
|
|
35
|
+
"types": "./dist/index.d.cts",
|
|
36
|
+
"default": "./dist/index.cjs"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"main": "./dist/index.cjs",
|
|
41
|
+
"module": "./dist/index.js",
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"files": [
|
|
44
|
+
"dist"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@vite-asset-manager/core": "^1.0.4"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^25.2.3",
|
|
51
|
+
"@types/react": "^19.2.14",
|
|
52
|
+
"next": "^16.1.6",
|
|
53
|
+
"react": "^19.2.4",
|
|
54
|
+
"tsup": "^8.5.1",
|
|
55
|
+
"typescript": "^5.9.3"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"next": ">=14.0.0",
|
|
59
|
+
"react": ">=18.0.0"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsup",
|
|
63
|
+
"dev": "tsup --watch"
|
|
64
|
+
}
|
|
65
|
+
}
|