@jchat/addon-sdk 0.0.1 → 1.0.0-alpha.10
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/CHANGELOG.md +64 -0
- package/LICENSE +18 -196
- package/README.md +26 -2
- package/dist/cli.d.mts +36 -0
- package/dist/cli.mjs +135 -0
- package/dist/contracts.d.mts +16 -24
- package/dist/diagnostics.d.mts +47 -0
- package/dist/diagnostics.mjs +175 -1
- package/dist/index.d.mts +282 -8
- package/dist/index.mjs +481 -1
- package/dist/ui.d.mts +1 -0
- package/dist/ui.mjs +2 -0
- package/dist/vite.d.mts +63 -11
- package/dist/vite.mjs +335 -4
- package/package.json +45 -12
- package/tsconfig.addon.json +20 -0
package/dist/vite.mjs
CHANGED
|
@@ -1,10 +1,341 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
//#region src/vite.ts
|
|
5
|
+
/**
|
|
6
|
+
* Vite plugin for building JChat sandboxed addon extensions.
|
|
7
|
+
*
|
|
8
|
+
* Configures automatic manifest generation (`manifest.json`), bundles server-side API scripts
|
|
9
|
+
* (`src/api.ts`), embeds scoped Tailwind CSS into the frontend bundle, packages database migrations
|
|
10
|
+
* and seed files, copies documentation (`README.md`), signs database-bearing addon manifests, and
|
|
11
|
+
* zips production build artifacts.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ;```ts
|
|
15
|
+
* import { jchatAddon } from "@jchat/addon-sdk/vite"
|
|
16
|
+
* import manifest from "./src/manifest"
|
|
17
|
+
* import { defineConfig } from "vite"
|
|
18
|
+
*
|
|
19
|
+
* export default defineConfig({
|
|
20
|
+
* plugins: [jchatAddon({ manifest })]
|
|
21
|
+
* })
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @param options - Configuration options for the JChat addon Vite plugin.
|
|
25
|
+
* @returns A Vite {@link Plugin} instance configured for addon compilation.
|
|
26
|
+
*/
|
|
27
|
+
function jchatAddon(options) {
|
|
28
|
+
const { manifest: manifestData } = options;
|
|
29
|
+
let shouldZip = options.zip;
|
|
30
|
+
let developmentBuild = false;
|
|
31
|
+
return {
|
|
32
|
+
name: "jchat-addon",
|
|
33
|
+
apply: "build",
|
|
34
|
+
config(_, env) {
|
|
35
|
+
const rootDir = process.cwd();
|
|
36
|
+
const uiEntry = path.resolve(rootDir, "src/ui.tsx");
|
|
37
|
+
const hasUi = fs.existsSync(uiEntry);
|
|
38
|
+
return {
|
|
39
|
+
define: {
|
|
40
|
+
global: "window",
|
|
41
|
+
"process.env.NODE_ENV": JSON.stringify(env.mode || "production")
|
|
42
|
+
},
|
|
43
|
+
build: {
|
|
44
|
+
outDir: "build",
|
|
45
|
+
emptyOutDir: true,
|
|
46
|
+
minify: env.mode === "production",
|
|
47
|
+
...hasUi ? {
|
|
48
|
+
lib: {
|
|
49
|
+
entry: uiEntry,
|
|
50
|
+
name: manifestData.id,
|
|
51
|
+
formats: ["es"],
|
|
52
|
+
fileName: () => "ui.[hash].js"
|
|
53
|
+
},
|
|
54
|
+
rolldownOptions: {
|
|
55
|
+
external: [
|
|
56
|
+
"react",
|
|
57
|
+
"react-dom",
|
|
58
|
+
"react/jsx-runtime",
|
|
59
|
+
"react/jsx-dev-runtime",
|
|
60
|
+
"jotai",
|
|
61
|
+
"react-hot-toast",
|
|
62
|
+
"@tanstack/react-query",
|
|
63
|
+
"@jchat/addon-sdk",
|
|
64
|
+
"@jchat/addon-sdk/ui"
|
|
65
|
+
],
|
|
66
|
+
output: { format: "esm" }
|
|
67
|
+
}
|
|
68
|
+
} : {}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
configResolved(config) {
|
|
73
|
+
developmentBuild = options.development ?? (config.mode === "development" || process.env.JCHAT_ADDON_DEV === "true" || process.env.NODE_ENV === "development");
|
|
74
|
+
if (shouldZip === void 0) shouldZip = config.mode === "production";
|
|
75
|
+
},
|
|
76
|
+
async writeBundle() {
|
|
77
|
+
const rootDir = process.cwd();
|
|
78
|
+
const pkgPath = path.resolve(rootDir, "package.json");
|
|
79
|
+
if (!fs.existsSync(pkgPath)) return;
|
|
80
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
81
|
+
const buildDir = path.resolve(rootDir, "build");
|
|
82
|
+
if (!fs.existsSync(buildDir)) return;
|
|
83
|
+
const bundleFile = fs.readdirSync(buildDir).find((f) => f.includes("ui") && f.endsWith(".js"));
|
|
84
|
+
if (!bundleFile) return;
|
|
85
|
+
if (options.css !== false) embedCssIntoBundle(buildDir, manifestData.id);
|
|
86
|
+
let manifest = {
|
|
87
|
+
...manifestData,
|
|
88
|
+
version: pkg.version,
|
|
89
|
+
frontend: {
|
|
90
|
+
...manifestData.frontend,
|
|
91
|
+
bundle: `./${bundleFile}`,
|
|
92
|
+
mountPoints: manifestData.frontend?.mountPoints ?? []
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const serverSrcPath = path.resolve(rootDir, "src/api.ts");
|
|
96
|
+
const hasServer = await Bun.file(serverSrcPath).exists();
|
|
97
|
+
if (hasServer) {
|
|
98
|
+
Bun.spawnSync(["bun", ...createAddonServerBuildArguments(serverSrcPath, path.resolve(buildDir, "api.js"), developmentBuild)], { stdio: [
|
|
99
|
+
"inherit",
|
|
100
|
+
"inherit",
|
|
101
|
+
"inherit"
|
|
102
|
+
] });
|
|
103
|
+
manifest = {
|
|
104
|
+
...manifest,
|
|
105
|
+
server: {
|
|
106
|
+
...manifest.server,
|
|
107
|
+
bundle: "./api.js"
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const databaseFiles = [...manifest.server?.migrations ?? [], ...manifest.server?.seeds ?? []];
|
|
112
|
+
for (const directory of ["migrations", "seeds"]) fs.rmSync(path.resolve(buildDir, directory), {
|
|
113
|
+
recursive: true,
|
|
114
|
+
force: true
|
|
115
|
+
});
|
|
116
|
+
for (const relativePath of databaseFiles) {
|
|
117
|
+
if (path.isAbsolute(relativePath) || relativePath.includes("\\") || relativePath.split("/").includes("..")) throw new Error(`Unsafe addon database file path: ${relativePath}`);
|
|
118
|
+
const destination = path.resolve(buildDir, relativePath);
|
|
119
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
120
|
+
}
|
|
121
|
+
await Promise.all(databaseFiles.map(async (relativePath) => {
|
|
122
|
+
const source = path.resolve(rootDir, relativePath);
|
|
123
|
+
if (!await Bun.file(source).exists() || !fs.statSync(source).isFile()) throw new Error(`Missing addon database file: ${relativePath}`);
|
|
124
|
+
const destination = path.resolve(buildDir, relativePath);
|
|
125
|
+
return Bun.write(destination, Bun.file(source));
|
|
126
|
+
}));
|
|
127
|
+
if (manifest.server?.migrations?.length || manifest.server?.seeds?.length) {
|
|
128
|
+
const signingPrivateKey = requireAddonSigningKey(options.signingPrivateKey ?? process.env.JCHAT_ADDON_SIGNING_PRIVATE_KEY, developmentBuild);
|
|
129
|
+
if (signingPrivateKey) {
|
|
130
|
+
const archivePaths = [
|
|
131
|
+
"manifest.json",
|
|
132
|
+
bundleFile,
|
|
133
|
+
...manifest.server?.migrations ?? [],
|
|
134
|
+
...manifest.server?.seeds ?? []
|
|
135
|
+
];
|
|
136
|
+
if (hasServer) archivePaths.push("api.js");
|
|
137
|
+
const resolvedFiles = await Promise.all(archivePaths.map(async (file) => ({
|
|
138
|
+
path: file,
|
|
139
|
+
contents: file === "manifest.json" ? Buffer.from("") : Buffer.from(await Bun.file(path.resolve(buildDir, file)).arrayBuffer())
|
|
140
|
+
})));
|
|
141
|
+
manifest = signAddonManifest(manifest, resolvedFiles, signingPrivateKey);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const readmeSource = path.resolve(rootDir, "README.md");
|
|
145
|
+
if (await Bun.file(readmeSource).exists()) await Bun.write(path.resolve(buildDir, "README.md"), Bun.file(readmeSource));
|
|
146
|
+
const vendorLicensesContent = await generateAddonVendorLicenses(rootDir, manifest.name);
|
|
147
|
+
await Bun.write(path.resolve(buildDir, "vendor-licenses.txt"), vendorLicensesContent);
|
|
148
|
+
const manifestJson = JSON.stringify(manifest, null, 2);
|
|
149
|
+
await Bun.write(path.resolve(buildDir, "manifest.json"), manifestJson);
|
|
150
|
+
if (shouldZip) {
|
|
151
|
+
const zipName = `${manifest.id}-${pkg.version}.zip`;
|
|
152
|
+
const filesToZip = ["manifest.json", bundleFile];
|
|
153
|
+
if (await Bun.file(path.resolve(buildDir, "api.js")).exists()) filesToZip.push("api.js");
|
|
154
|
+
if (await Bun.file(path.resolve(buildDir, "README.md")).exists()) filesToZip.push("README.md");
|
|
155
|
+
if (await Bun.file(path.resolve(buildDir, "vendor-licenses.txt")).exists()) filesToZip.push("vendor-licenses.txt");
|
|
156
|
+
const migrationsDest = path.resolve(buildDir, "migrations");
|
|
157
|
+
if (fs.existsSync(migrationsDest)) filesToZip.push("migrations");
|
|
158
|
+
const seedsDest = path.resolve(buildDir, "seeds");
|
|
159
|
+
if (fs.existsSync(seedsDest)) filesToZip.push("seeds");
|
|
160
|
+
Bun.spawnSync([
|
|
161
|
+
"tar",
|
|
162
|
+
"-a",
|
|
163
|
+
"-cf",
|
|
164
|
+
zipName,
|
|
165
|
+
...filesToZip
|
|
166
|
+
], {
|
|
167
|
+
cwd: buildDir,
|
|
168
|
+
stdio: [
|
|
169
|
+
"inherit",
|
|
170
|
+
"inherit",
|
|
171
|
+
"inherit"
|
|
172
|
+
]
|
|
173
|
+
});
|
|
174
|
+
console.log(`Build Complete: ${manifest.id} v${pkg.version} → ${zipName}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Generates CLI argument parameters for bundling server-side Elysia API scripts (`src/api.ts`) via
|
|
181
|
+
* Bun.
|
|
182
|
+
*
|
|
183
|
+
* @param entryPath - Absolute file path to the server entry script (`src/api.ts`).
|
|
184
|
+
* @param outputPath - Absolute destination file path for the bundled output (`build/api.js`).
|
|
185
|
+
* @param developmentBuild - Indicates whether to enable external sourcemaps or minification.
|
|
186
|
+
* @returns Array of command line arguments for running `bun build`.
|
|
187
|
+
*/
|
|
188
|
+
function createAddonServerBuildArguments(entryPath, outputPath, developmentBuild) {
|
|
189
|
+
return [
|
|
190
|
+
"build",
|
|
191
|
+
entryPath,
|
|
192
|
+
"--target=bun",
|
|
193
|
+
"--format=esm",
|
|
194
|
+
`--outfile=${outputPath}`,
|
|
195
|
+
developmentBuild ? "--sourcemap=inline" : "--minify"
|
|
196
|
+
];
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Cryptographically signs an addon manifest using RSA-SHA256 over all archive file contents.
|
|
200
|
+
*
|
|
201
|
+
* @param manifest - Unsigned or base addon manifest.
|
|
202
|
+
* @param files - List of archive file paths and raw contents to digest.
|
|
203
|
+
* @param privateKey - RSA private key in PEM format.
|
|
204
|
+
* @returns Updated {@link AddonManifest} containing an RSA signature block.
|
|
205
|
+
*/
|
|
206
|
+
function signAddonManifest(manifest, files, privateKey) {
|
|
207
|
+
if (!manifest.publisher?.id) throw new Error("Signed addons require manifest.publisher.id");
|
|
208
|
+
const unsigned = {
|
|
209
|
+
...manifest,
|
|
210
|
+
signature: {
|
|
211
|
+
algorithm: "rsa-sha256",
|
|
212
|
+
digest: "",
|
|
213
|
+
value: ""
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const hash = crypto.createHash("sha256");
|
|
217
|
+
for (const file of [...files].toSorted((a, b) => a.path.localeCompare(b.path))) {
|
|
218
|
+
hash.update(file.path);
|
|
219
|
+
hash.update("\0");
|
|
220
|
+
hash.update(file.path === "manifest.json" ? stableStringify(unsigned) : file.contents);
|
|
221
|
+
hash.update("\0");
|
|
222
|
+
}
|
|
223
|
+
const digest = hash.digest("hex");
|
|
224
|
+
return {
|
|
225
|
+
...unsigned,
|
|
226
|
+
signature: {
|
|
227
|
+
algorithm: "rsa-sha256",
|
|
228
|
+
digest,
|
|
229
|
+
value: crypto.sign("sha256", Buffer.from(digest), privateKey).toString("base64url")
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Resolves the required RSA signing key for database-bearing addons.
|
|
235
|
+
*
|
|
236
|
+
* @param signingPrivateKey - Provided signing key or undefined.
|
|
237
|
+
* @param developmentBuild - Whether the current build is targeting development mode.
|
|
238
|
+
* @returns Resolved signing key string or undefined (in dev builds).
|
|
239
|
+
* @throws {@link Error} If building a database-bearing addon in production without a signing key.
|
|
240
|
+
*/
|
|
241
|
+
function requireAddonSigningKey(signingPrivateKey, developmentBuild) {
|
|
242
|
+
if (signingPrivateKey) return signingPrivateKey;
|
|
243
|
+
if (developmentBuild) return void 0;
|
|
244
|
+
throw new Error("Database-bearing addon builds require JCHAT_ADDON_SIGNING_PRIVATE_KEY");
|
|
245
|
+
}
|
|
246
|
+
function embedCssIntoBundle(buildDir, addonId) {
|
|
247
|
+
const files = fs.readdirSync(buildDir);
|
|
248
|
+
const cssFile = files.find((f) => f.endsWith(".css"));
|
|
249
|
+
const jsFile = files.find((f) => f.includes("ui") && f.endsWith(".js"));
|
|
250
|
+
if (!cssFile || !jsFile) return;
|
|
251
|
+
const cssPath = path.join(buildDir, cssFile);
|
|
252
|
+
const jsPath = path.join(buildDir, jsFile);
|
|
253
|
+
let css = fs.readFileSync(cssPath, "utf-8");
|
|
254
|
+
const js = fs.readFileSync(jsPath, "utf-8");
|
|
255
|
+
if (css.length < 10) css = "";
|
|
256
|
+
else {
|
|
257
|
+
css = css.replace(/:root\s*\{[^}]+\}/g, "");
|
|
258
|
+
css = css.replace(/\.dark\s*\{[^}]+\}/g, "");
|
|
259
|
+
css = css.replace(/\[data-theme=[^\]]+\]\s*\{[^}]+\}/g, "");
|
|
260
|
+
css = css.replace(/\.dark\s*\[data-theme=[^\]]+\]\s*\{[^}]+\}/g, "");
|
|
261
|
+
css = `@scope (#addon-${addonId}) {\n*, ::before, ::after { border-color: var(--border); }\n${css}\n}`;
|
|
262
|
+
}
|
|
263
|
+
const injection = `
|
|
2
264
|
(function() {
|
|
3
|
-
if (typeof document !== 'undefined' && ${JSON.stringify(
|
|
265
|
+
if (typeof document !== 'undefined' && ${JSON.stringify(css)}.length > 0) {
|
|
4
266
|
const style = document.createElement('style');
|
|
5
267
|
style.type = 'text/css';
|
|
6
|
-
style.textContent = ${JSON.stringify(
|
|
268
|
+
style.textContent = ${JSON.stringify(css)};
|
|
7
269
|
document.head.appendChild(style);
|
|
8
270
|
}
|
|
9
271
|
})();
|
|
10
|
-
|
|
272
|
+
`;
|
|
273
|
+
fs.writeFileSync(jsPath, injection + js);
|
|
274
|
+
try {
|
|
275
|
+
fs.unlinkSync(cssPath);
|
|
276
|
+
} catch {}
|
|
277
|
+
}
|
|
278
|
+
function sortValue(child) {
|
|
279
|
+
if (Array.isArray(child)) return child.map(sortValue);
|
|
280
|
+
if (child && typeof child === "object") return Object.fromEntries(Object.entries(child).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, sortValue(nested)]));
|
|
281
|
+
return child;
|
|
282
|
+
}
|
|
283
|
+
function stableStringify(value) {
|
|
284
|
+
return JSON.stringify(sortValue(value));
|
|
285
|
+
}
|
|
286
|
+
async function generateAddonVendorLicenses(addonDir, addonName) {
|
|
287
|
+
const title = addonName ? `${addonName} Addon` : "JChat Addon";
|
|
288
|
+
try {
|
|
289
|
+
const proc = Bun.spawn([
|
|
290
|
+
"bun",
|
|
291
|
+
"pm",
|
|
292
|
+
"licenses",
|
|
293
|
+
"--json",
|
|
294
|
+
"--prod"
|
|
295
|
+
], {
|
|
296
|
+
cwd: addonDir,
|
|
297
|
+
stdout: "pipe",
|
|
298
|
+
stderr: "pipe"
|
|
299
|
+
});
|
|
300
|
+
const output = await new Response(proc.stdout).text();
|
|
301
|
+
await proc.exited;
|
|
302
|
+
const data = JSON.parse(output);
|
|
303
|
+
const lines = [
|
|
304
|
+
"================================================================================",
|
|
305
|
+
`${title} - Third-Party Vendor Licenses & Open Source Attribution`,
|
|
306
|
+
"================================================================================",
|
|
307
|
+
"This distribution incorporates open-source libraries and software components.",
|
|
308
|
+
"Their licenses and attributions are listed below.",
|
|
309
|
+
"================================================================================",
|
|
310
|
+
""
|
|
311
|
+
];
|
|
312
|
+
let totalPackages = 0;
|
|
313
|
+
const sortedCategories = Object.keys(data).toSorted((a, b) => a.localeCompare(b));
|
|
314
|
+
for (const licenseCategory of sortedCategories) {
|
|
315
|
+
const packages = data[licenseCategory];
|
|
316
|
+
if (!packages || packages.length === 0) continue;
|
|
317
|
+
lines.push(`\n## License: ${licenseCategory} (${packages.length} packages)\n`);
|
|
318
|
+
for (const pkg of packages) {
|
|
319
|
+
totalPackages++;
|
|
320
|
+
lines.push(`- Package: ${pkg.name}@${pkg.versions.join(", ")}`);
|
|
321
|
+
if (pkg.description) lines.push(` Description: ${pkg.description}`);
|
|
322
|
+
if (pkg.author) lines.push(` Author: ${pkg.author}`);
|
|
323
|
+
if (pkg.homepage) lines.push(` Homepage: ${pkg.homepage}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
lines.splice(5, 0, `Total Open-Source Dependencies: ${totalPackages}\n`);
|
|
327
|
+
return lines.join("\n") + "\n";
|
|
328
|
+
} catch {
|
|
329
|
+
return [
|
|
330
|
+
"================================================================================",
|
|
331
|
+
`${title} - Third-Party Vendor Licenses & Open Source Attribution`,
|
|
332
|
+
"================================================================================",
|
|
333
|
+
"This distribution incorporates open-source libraries and software components.",
|
|
334
|
+
"See individual package.json files and dependencies for specific license details.",
|
|
335
|
+
"================================================================================",
|
|
336
|
+
""
|
|
337
|
+
].join("\n");
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
//#endregion
|
|
341
|
+
export { createAddonServerBuildArguments, jchatAddon, requireAddonSigningKey, signAddonManifest };
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jchat/addon-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "1.0.0-alpha.10",
|
|
4
4
|
"private": false,
|
|
5
|
+
"description": "JChat Addon SDK for building JChat addons.",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"addon",
|
|
7
8
|
"chat",
|
|
@@ -11,10 +12,20 @@
|
|
|
11
12
|
"sdk",
|
|
12
13
|
"vite"
|
|
13
14
|
],
|
|
14
|
-
"license": "
|
|
15
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/mjjabarullah/jchat.git",
|
|
19
|
+
"directory": "packages/addon-sdk"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"jchat-addon": "./dist/cli.mjs"
|
|
23
|
+
},
|
|
15
24
|
"files": [
|
|
16
25
|
"dist",
|
|
17
|
-
"
|
|
26
|
+
"tsconfig.addon.json",
|
|
27
|
+
"README.md",
|
|
28
|
+
"CHANGELOG.md"
|
|
18
29
|
],
|
|
19
30
|
"type": "module",
|
|
20
31
|
"main": "./dist/index.mjs",
|
|
@@ -24,6 +35,10 @@
|
|
|
24
35
|
"types": "./dist/index.d.mts",
|
|
25
36
|
"import": "./dist/index.mjs"
|
|
26
37
|
},
|
|
38
|
+
"./cli": {
|
|
39
|
+
"types": "./dist/cli.d.mts",
|
|
40
|
+
"import": "./dist/cli.mjs"
|
|
41
|
+
},
|
|
27
42
|
"./diagnostics": {
|
|
28
43
|
"types": "./dist/diagnostics.d.mts",
|
|
29
44
|
"import": "./dist/diagnostics.mjs"
|
|
@@ -31,30 +46,48 @@
|
|
|
31
46
|
"./vite": {
|
|
32
47
|
"types": "./dist/vite.d.mts",
|
|
33
48
|
"import": "./dist/vite.mjs"
|
|
34
|
-
}
|
|
49
|
+
},
|
|
50
|
+
"./ui": {
|
|
51
|
+
"types": "./dist/ui.d.mts",
|
|
52
|
+
"import": "./dist/ui.mjs"
|
|
53
|
+
},
|
|
54
|
+
"./ui/tailwind.css": {
|
|
55
|
+
"style": "./src/tailwind.css",
|
|
56
|
+
"import": "./src/tailwind.css",
|
|
57
|
+
"default": "./src/tailwind.css"
|
|
58
|
+
},
|
|
59
|
+
"./tsconfig.json": "./tsconfig.addon.json"
|
|
35
60
|
},
|
|
36
61
|
"publishConfig": {
|
|
37
62
|
"access": "public"
|
|
38
63
|
},
|
|
39
64
|
"scripts": {
|
|
40
65
|
"build": "tsdown",
|
|
41
|
-
"lint": "oxlint .
|
|
66
|
+
"lint": "oxlint .",
|
|
42
67
|
"format": "oxfmt . --write",
|
|
68
|
+
"test": "bun test",
|
|
43
69
|
"typecheck": "tsc --noEmit",
|
|
44
70
|
"prepack": "bun run build"
|
|
45
71
|
},
|
|
72
|
+
"dependencies": {},
|
|
46
73
|
"devDependencies": {
|
|
47
|
-
"@jchat/icon": "
|
|
48
|
-
"@
|
|
49
|
-
"
|
|
74
|
+
"@jchat/icon": "workspace:*",
|
|
75
|
+
"@jchat/ui": "workspace:*",
|
|
76
|
+
"@tailwindcss/vite": "catalog:",
|
|
77
|
+
"@tanstack/react-query": "catalog:",
|
|
78
|
+
"@types/bun": "catalog:",
|
|
79
|
+
"@types/react": "catalog:",
|
|
80
|
+
"elysia": "catalog:",
|
|
50
81
|
"kysely": "^catalog:",
|
|
51
82
|
"tsdown": "^0.22.14",
|
|
52
|
-
"vite": "
|
|
83
|
+
"vite": "catalog:"
|
|
53
84
|
},
|
|
54
85
|
"peerDependencies": {
|
|
55
|
-
"
|
|
86
|
+
"@tailwindcss/vite": "catalog:",
|
|
87
|
+
"@tanstack/react-query": "catalog:",
|
|
88
|
+
"elysia": "catalog:",
|
|
56
89
|
"kysely": "^catalog:",
|
|
57
|
-
"react": "
|
|
58
|
-
"vite": "
|
|
90
|
+
"react": "catalog:",
|
|
91
|
+
"vite": "catalog:"
|
|
59
92
|
}
|
|
60
93
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"display": "JChat Addon Base",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
9
|
+
"jsx": "react-jsx",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"verbatimModuleSyntax": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"types": ["bun", "vite/client"]
|
|
18
|
+
},
|
|
19
|
+
"exclude": ["build", "dist", "node_modules"]
|
|
20
|
+
}
|