@brightspot/ui-builder 1.0.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.
@@ -0,0 +1,26 @@
1
+ import js from '@eslint/js'
2
+ import prettier from 'eslint-plugin-prettier/recommended'
3
+ import globals from 'globals'
4
+ import ts from 'typescript-eslint'
5
+
6
+ /** @type {import('eslint').Linter.Config[]} */
7
+ export default [
8
+ { name: '@brightspot/ui-builder/globals', languageOptions: { globals: globals.browser } },
9
+ { name: '@brightspot/ui-builder/js', ...js.configs.recommended },
10
+ ...ts.configs.recommended.map(c => ({ ...c, name: `@brightspot/ui-builder/${c.name ?? 'ts'}` })),
11
+ {
12
+ name: '@brightspot/ui-builder/rules',
13
+ rules: {
14
+ semi: ['error', 'never'],
15
+ 'no-empty': 'off',
16
+ 'no-prototype-builtins': 'off',
17
+ '@typescript-eslint/no-empty-function': 'off',
18
+ '@typescript-eslint/no-this-alias': 'off',
19
+ '@typescript-eslint/no-var-requires': 'off',
20
+ '@typescript-eslint/no-unused-vars': 'off',
21
+ '@typescript-eslint/no-require-imports': 'off',
22
+ '@typescript-eslint/no-explicit-any': 'warn',
23
+ },
24
+ },
25
+ prettier,
26
+ ]
@@ -0,0 +1,19 @@
1
+ /** @type {import('prettier').Config} */
2
+ export default {
3
+ arrowParens: 'avoid',
4
+ bracketSpacing: true,
5
+ htmlWhitespaceSensitivity: 'css',
6
+ insertPragma: false,
7
+ bracketSameLine: false,
8
+ jsxSingleQuote: false,
9
+ printWidth: 120,
10
+ proseWrap: 'preserve',
11
+ quoteProps: 'as-needed',
12
+ requirePragma: false,
13
+ semi: false,
14
+ singleQuote: true,
15
+ tabWidth: 2,
16
+ useTabs: false,
17
+ organizeImportsSkipDestructiveCodeActions: true,
18
+ plugins: ['prettier-plugin-organize-imports'],
19
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "noEmit": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "verbatimModuleSyntax": true
14
+ }
15
+ }
@@ -0,0 +1 @@
1
+ export declare function build(): Promise<void>;
@@ -0,0 +1,11 @@
1
+ import { build as viteBuild } from 'vite';
2
+ import { log } from '../lib/logger.js';
3
+ import { resolveConfig } from '../lib/resolve-config.js';
4
+ import { createBuildConfig } from '../vite/vite-config.js';
5
+ export async function build() {
6
+ log.info('Building IIFE bundle...');
7
+ const { basePath } = resolveConfig();
8
+ const config = createBuildConfig(basePath);
9
+ await viteBuild(config);
10
+ log.success('Build complete — output in dist/');
11
+ }
@@ -0,0 +1,6 @@
1
+ interface DevOptions {
2
+ port?: number;
3
+ url?: string;
4
+ }
5
+ export declare function dev(opts: DevOptions): Promise<void>;
6
+ export {};
@@ -0,0 +1,14 @@
1
+ import { createServer } from 'vite';
2
+ import { log } from '../lib/logger.js';
3
+ import { resolveConfig } from '../lib/resolve-config.js';
4
+ import { resolveTarget } from '../lib/resolve-target.js';
5
+ import { createDevConfig } from '../vite/vite-config.js';
6
+ export async function dev(opts) {
7
+ const { basePath } = resolveConfig();
8
+ const target = opts.url ?? resolveTarget();
9
+ const config = createDevConfig({ target, port: opts.port, basePath });
10
+ const server = await createServer(config);
11
+ await server.listen();
12
+ server.printUrls();
13
+ log.success('Dev server running — proxying to ' + target);
14
+ }
@@ -0,0 +1 @@
1
+ export declare function init(): Promise<void>;
@@ -0,0 +1,73 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { log } from '../lib/logger.js';
4
+ import { resolveTarget } from '../lib/resolve-target.js';
5
+ const cwd = process.cwd();
6
+ export async function init() {
7
+ log.info('Initializing Brightspot UI project...');
8
+ writeTsConfig();
9
+ writeEslintConfig();
10
+ patchPackageJson();
11
+ scaffoldEntryPoint();
12
+ resolveTarget();
13
+ log.success('Project initialized. Run `brightspot-ui dev` to start developing.');
14
+ }
15
+ function writeTsConfig() {
16
+ const tsConfigPath = path.join(cwd, 'tsconfig.json');
17
+ if (fs.existsSync(tsConfigPath)) {
18
+ log.warn('tsconfig.json already exists — skipping');
19
+ return;
20
+ }
21
+ const config = {
22
+ extends: '@brightspot/ui-builder/configs/tsconfig.base.json',
23
+ };
24
+ fs.writeFileSync(tsConfigPath, JSON.stringify(config, null, 2) + '\n');
25
+ log.success('Created tsconfig.json');
26
+ }
27
+ function writeEslintConfig() {
28
+ const eslintConfigPath = path.join(cwd, 'eslint.config.mjs');
29
+ if (fs.existsSync(eslintConfigPath)) {
30
+ log.warn('eslint.config.mjs already exists — skipping');
31
+ return;
32
+ }
33
+ const content = `import config from '@brightspot/ui-builder/configs/eslint.config.mjs'
34
+
35
+ export default [...config]
36
+ `;
37
+ fs.writeFileSync(eslintConfigPath, content);
38
+ log.success('Created eslint.config.mjs');
39
+ }
40
+ function patchPackageJson() {
41
+ const pkgPath = path.join(cwd, 'package.json');
42
+ if (!fs.existsSync(pkgPath)) {
43
+ log.warn('No package.json found — skipping script injection');
44
+ return;
45
+ }
46
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
47
+ pkg.scripts = pkg.scripts ?? {};
48
+ pkg.scripts.dev = 'brightspot-ui dev';
49
+ pkg.scripts.build = 'brightspot-ui build';
50
+ pkg.prettier = '@brightspot/ui-builder/configs/prettier.config.mjs';
51
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
52
+ log.success('Patched package.json (scripts + prettier)');
53
+ }
54
+ function scaffoldEntryPoint() {
55
+ const srcDir = path.join(cwd, 'src');
56
+ const entryPath = path.join(srcDir, 'index.ts');
57
+ if (fs.existsSync(entryPath)) {
58
+ log.warn('src/index.ts already exists — skipping');
59
+ return;
60
+ }
61
+ if (!fs.existsSync(srcDir)) {
62
+ fs.mkdirSync(srcDir, { recursive: true });
63
+ }
64
+ const template = `// Entry point for Brightspot CMS bundle
65
+ // Import your styles:
66
+ // import './styles/main.css'
67
+
68
+ // Import your modules:
69
+ // import './tour'
70
+ `;
71
+ fs.writeFileSync(entryPath, template);
72
+ log.success('Created src/index.ts');
73
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ program.name('brightspot-ui').description('Zero-config build toolkit for Brightspot CMS front-end development.');
4
+ program
5
+ .command('init')
6
+ .description('Scaffold config files for a new Brightspot front-end project')
7
+ .action(async () => {
8
+ const { init } = await import('./commands/init.js');
9
+ await init();
10
+ });
11
+ program
12
+ .command('dev [url]')
13
+ .description('Start Vite dev server with HTTPS proxy to Brightspot')
14
+ .option('--port <port>', 'Dev server port', parseInt)
15
+ .action(async (url, opts) => {
16
+ const { dev } = await import('./commands/dev.js');
17
+ await dev({ ...opts, url });
18
+ });
19
+ program
20
+ .command('build')
21
+ .description('Build IIFE bundle for production')
22
+ .action(async () => {
23
+ const { build } = await import('./commands/build.js');
24
+ await build();
25
+ });
26
+ program.parse();
@@ -0,0 +1,6 @@
1
+ export declare const log: {
2
+ info(msg: string): void;
3
+ success(msg: string): void;
4
+ warn(msg: string): void;
5
+ error(msg: string): void;
6
+ };
@@ -0,0 +1,15 @@
1
+ import pc from 'picocolors';
2
+ export const log = {
3
+ info(msg) {
4
+ console.log(pc.cyan('ℹ'), msg);
5
+ },
6
+ success(msg) {
7
+ console.log(pc.green('✔'), msg);
8
+ },
9
+ warn(msg) {
10
+ console.log(pc.yellow('⚠'), msg);
11
+ },
12
+ error(msg) {
13
+ console.error(pc.red('✖'), msg);
14
+ },
15
+ };
@@ -0,0 +1,5 @@
1
+ interface BuilderConfig {
2
+ basePath: string;
3
+ }
4
+ export declare function resolveConfig(): BuilderConfig;
5
+ export {};
@@ -0,0 +1,25 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { log } from './logger.js';
4
+ const DEFAULT_BASE_PATH = '/_resource/dist/';
5
+ export function resolveConfig() {
6
+ const pkgPath = path.resolve(process.cwd(), 'package.json');
7
+ try {
8
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
9
+ const config = pkg['brightspot-ui'];
10
+ if (config?.basePath) {
11
+ const basePath = config.basePath;
12
+ if (!basePath.startsWith('/') || !basePath.endsWith('/')) {
13
+ log.warn(`basePath "${basePath}" must start and end with "/" — using default`);
14
+ return { basePath: DEFAULT_BASE_PATH };
15
+ }
16
+ log.info(`basePath: ${basePath}`);
17
+ return { basePath };
18
+ }
19
+ }
20
+ catch {
21
+ // package.json not found or unreadable — use defaults
22
+ }
23
+ log.info(`basePath: ${DEFAULT_BASE_PATH} (default)`);
24
+ return { basePath: DEFAULT_BASE_PATH };
25
+ }
@@ -0,0 +1 @@
1
+ export declare function resolveTarget(): string;
@@ -0,0 +1,19 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { log } from './logger.js';
5
+ const LOCAL_URL_PATH = path.join(os.homedir(), '.brightspot', 'local-url');
6
+ const DEFAULT_TARGET = 'http://localhost';
7
+ export function resolveTarget() {
8
+ try {
9
+ const url = fs.readFileSync(LOCAL_URL_PATH, 'utf8').trim();
10
+ if (url) {
11
+ log.info(`Proxy target: ${url}`);
12
+ return url;
13
+ }
14
+ }
15
+ catch {
16
+ log.warn(`${LOCAL_URL_PATH} not found — falling back to ${DEFAULT_TARGET}`);
17
+ }
18
+ return DEFAULT_TARGET;
19
+ }
@@ -0,0 +1,7 @@
1
+ import type { Plugin } from 'vite';
2
+ /**
3
+ * Serves a dev bootstrap script at the bundle.js path so that Vite's
4
+ * HMR client and the real entry point are loaded as ES modules.
5
+ * Also serves an empty style.css since Vite injects CSS via JS in dev.
6
+ */
7
+ export declare function devEntryPlugin(basePath: string, entry: string): Plugin;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Serves a dev bootstrap script at the bundle.js path so that Vite's
3
+ * HMR client and the real entry point are loaded as ES modules.
4
+ * Also serves an empty style.css since Vite injects CSS via JS in dev.
5
+ */
6
+ export function devEntryPlugin(basePath, entry) {
7
+ const bundlePath = `${basePath}bundle.js`;
8
+ const cssPath = `${basePath}style.css`;
9
+ return {
10
+ name: 'brightspot-dev-entry',
11
+ configureServer(server) {
12
+ server.middlewares.use((req, res, next) => {
13
+ const pathname = req.url?.split('?')[0];
14
+ if (pathname === bundlePath) {
15
+ res.setHeader('Content-Type', 'application/javascript');
16
+ res.end(`import('/@vite/client');import('/${entry}');`);
17
+ return;
18
+ }
19
+ if (pathname === cssPath) {
20
+ res.setHeader('Content-Type', 'text/css');
21
+ res.end('');
22
+ return;
23
+ }
24
+ next();
25
+ });
26
+ },
27
+ };
28
+ }
@@ -0,0 +1,10 @@
1
+ import type { InlineConfig } from 'vite';
2
+ interface DevConfigOptions {
3
+ target: string;
4
+ port?: number;
5
+ basePath: string;
6
+ entry?: string;
7
+ }
8
+ export declare function createDevConfig({ target, port, basePath, entry }: DevConfigOptions): InlineConfig;
9
+ export declare function createBuildConfig(basePath: string): InlineConfig;
10
+ export {};
@@ -0,0 +1,59 @@
1
+ import path from 'node:path';
2
+ import { devEntryPlugin } from './plugin-html-inject.js';
3
+ export function createDevConfig({ target, port, basePath, entry = 'src/index.ts' }) {
4
+ const cwd = process.cwd();
5
+ const escaped = basePath.replace(/^\//, '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
6
+ const entryDir = entry.split('/')[0] + '/';
7
+ return {
8
+ root: cwd,
9
+ base: '/',
10
+ plugins: [mkcertPlugin(), devEntryPlugin(basePath, entry)],
11
+ resolve: {
12
+ preserveSymlinks: true,
13
+ },
14
+ server: {
15
+ port,
16
+ proxy: {
17
+ [`^/(?!(${escaped}|${entryDir}|@vite|@fs|node_modules))`]: {
18
+ target,
19
+ autoRewrite: true,
20
+ changeOrigin: true,
21
+ configure: proxy => {
22
+ proxy.on('proxyReq', proxyReq => {
23
+ proxyReq.setHeader('x-forwarded-proto', 'https');
24
+ proxyReq.setHeader('x-brightspot-dev', '1');
25
+ });
26
+ },
27
+ },
28
+ },
29
+ },
30
+ };
31
+ }
32
+ export function createBuildConfig(basePath) {
33
+ const cwd = process.cwd();
34
+ return {
35
+ root: cwd,
36
+ base: basePath,
37
+ resolve: {
38
+ preserveSymlinks: true,
39
+ },
40
+ build: {
41
+ lib: {
42
+ entry: path.resolve(cwd, 'src/index.ts'),
43
+ formats: ['iife'],
44
+ name: 'BrightspotTheme',
45
+ fileName: () => 'bundle.js',
46
+ },
47
+ rollupOptions: {
48
+ output: {
49
+ assetFileNames: () => 'style.css',
50
+ },
51
+ },
52
+ cssCodeSplit: false,
53
+ },
54
+ };
55
+ }
56
+ async function mkcertPlugin() {
57
+ const mkcert = await import('vite-plugin-mkcert');
58
+ return mkcert.default();
59
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@brightspot/ui-builder",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "license": "UNLICENSED",
6
+ "description": "Zero-config build toolkit for Brightspot CMS front-end development.",
7
+ "bin": {
8
+ "brightspot-ui": "./dist/index.js"
9
+ },
10
+ "exports": {
11
+ "./configs/tsconfig.base.json": "./configs/tsconfig.base.json",
12
+ "./configs/eslint.config.mjs": "./configs/eslint.config.mjs",
13
+ "./configs/prettier.config.mjs": "./configs/prettier.config.mjs"
14
+ },
15
+ "files": [
16
+ "dist/**/*",
17
+ "configs/**/*"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc --noEmitOnError && chmod +x ./dist/index.js",
21
+ "clean": "shx rm -rf ./dist/*"
22
+ },
23
+ "dependencies": {
24
+ "commander": "^13.0.0",
25
+ "picocolors": "^1.1.0",
26
+ "vite": "^7.0.0",
27
+ "vite-plugin-mkcert": "^1.17.0",
28
+ "eslint": "^9.39.0",
29
+ "@eslint/js": "^9.23.0",
30
+ "typescript-eslint": "^8.29.0",
31
+ "eslint-plugin-prettier": "^5.5.0",
32
+ "eslint-config-prettier": "^10.0.0",
33
+ "prettier": "^3.2.0",
34
+ "prettier-plugin-organize-imports": "^4.3.0",
35
+ "typescript": "^5.9.0",
36
+ "autoprefixer": "^10.0.0",
37
+ "globals": "^16.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "shx": "^0.4.0",
41
+ "@types/node": "^24.10.0"
42
+ }
43
+ }