create-bw-app 0.9.4 → 0.9.5
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/README.md +3 -0
- package/package.json +1 -1
- package/src/cli.mjs +5 -0
- package/src/constants.mjs +1 -0
- package/src/generator.mjs +2 -0
- package/src/update.mjs +67 -1
- package/template/base/AGENTS.md +1 -0
- package/template/base/app/playground/auth/page.tsx +1 -1
- package/template/base/app/preview/app-shell/page.tsx +1 -1
- package/template/base/{app/preview → components}/app-shell-preview.tsx +2 -2
- package/template/base/docs/ai/README.md +3 -0
- package/template/base/docs/ai/examples.md +2 -0
- package/template/modules/crm/app/api/crm/_shared/create-module-route-handler.ts +13 -0
- package/template/modules/crm/app/api/crm/contacts/route.ts +6 -4
- package/template/modules/crm/app/api/crm/organizations/route.ts +6 -4
- package/template/modules/crm/app/api/crm/owners/route.ts +6 -4
- package/template/modules/crm/app/api/crm/stats/route.ts +6 -4
- /package/template/base/{app/playground/auth → components}/auth-playground.tsx +0 -0
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@ pnpm dlx create-bw-app update --target-dir ./apps/client-portal
|
|
|
41
41
|
Current updater behavior:
|
|
42
42
|
|
|
43
43
|
- updates installed `@brightweblabs/*` packages only
|
|
44
|
+
- in published mode, resolves those `@brightweblabs/*` target versions from npm at update time
|
|
45
|
+
- fails the update if npm resolution fails unless you pass `--allow-stale-fallback`
|
|
44
46
|
- re-syncs managed BrightWeb config files such as `next.config.ts`, `config/modules.ts`, and `config/shell.ts`
|
|
45
47
|
- reports missing or drifted starter files and only rewrites them with `--refresh-starters`
|
|
46
48
|
- prints the follow-up install command unless `--install` is passed
|
|
@@ -54,6 +56,7 @@ Current updater behavior:
|
|
|
54
56
|
- prompts to install dependencies immediately
|
|
55
57
|
- copies a clean Next.js App Router starter template
|
|
56
58
|
- platform apps include BrightWeb auth, shell wiring, and optional module starter surfaces
|
|
59
|
+
- platform apps include a local `components/` folder for app-owned UI alongside the shared BrightWeb packages
|
|
57
60
|
- site apps include Next.js, Tailwind CSS v4, and local component primitives
|
|
58
61
|
- writes `package.json`, `next.config.ts`, `.gitignore`, and `README.md` for both templates
|
|
59
62
|
- platform apps also write `.env.local`, `AGENTS.md`, `docs/ai/README.md`, `docs/ai/examples.md`, `docs/ai/app-context.json`, and generated config files for brand and module state
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -42,6 +42,11 @@ function parseArgv(argv) {
|
|
|
42
42
|
continue;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
if (token === "--allow-stale-fallback") {
|
|
46
|
+
options.allowStaleFallback = true;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
const [rawKey, inlineValue] = token.slice(2).split("=", 2);
|
|
46
51
|
const key = toCamelCase(rawKey);
|
|
47
52
|
const nextValue = inlineValue ?? argv[index + 1];
|
package/src/constants.mjs
CHANGED
|
@@ -136,6 +136,7 @@ Update options:
|
|
|
136
136
|
--target-dir <path> Existing app directory to update (defaults to cwd)
|
|
137
137
|
--workspace-root <path> BrightWeb workspace root for workspace:* apps
|
|
138
138
|
--package-manager <name> Override package manager: pnpm, npm, yarn, or bun
|
|
139
|
+
--allow-stale-fallback Use baked-in BrightWeb package versions if npm lookup fails
|
|
139
140
|
--install Run install after writing package changes
|
|
140
141
|
--refresh-starters Rewrite starter route files from the latest template
|
|
141
142
|
--dry-run Print the update plan without writing files
|
package/src/generator.mjs
CHANGED
|
@@ -631,6 +631,7 @@ export function createAppContextFile({
|
|
|
631
631
|
".env.local",
|
|
632
632
|
],
|
|
633
633
|
appRoutesRoot: "app",
|
|
634
|
+
componentsRoot: "components",
|
|
634
635
|
configRoot: "config",
|
|
635
636
|
brandAssetsRoot: "public/brand",
|
|
636
637
|
},
|
|
@@ -638,6 +639,7 @@ export function createAppContextFile({
|
|
|
638
639
|
ownership: {
|
|
639
640
|
appOwned: [
|
|
640
641
|
"app/**",
|
|
642
|
+
"components/**",
|
|
641
643
|
"config/**",
|
|
642
644
|
"docs/ai/**",
|
|
643
645
|
"public/brand/**",
|
package/src/update.mjs
CHANGED
|
@@ -76,6 +76,62 @@ function collectInstalledBrightwebPackages(manifest) {
|
|
|
76
76
|
return installed;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
async function resolvePublishedBrightwebVersions(installedBrightwebPackages, options = {}) {
|
|
80
|
+
const packageNames = Array.from(installedBrightwebPackages.keys()).sort();
|
|
81
|
+
|
|
82
|
+
if (packageNames.length === 0) {
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
87
|
+
if (typeof fetchImpl !== "function") {
|
|
88
|
+
throw new Error("Published updates require fetch support to resolve BrightWeb package versions from npm.");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const fallbackVersionMap = options.fallbackVersionMap || {};
|
|
92
|
+
const allowStaleFallback = options.allowStaleFallback === true;
|
|
93
|
+
const resolvedVersions = {};
|
|
94
|
+
const failures = [];
|
|
95
|
+
|
|
96
|
+
await Promise.all(
|
|
97
|
+
packageNames.map(async (packageName) => {
|
|
98
|
+
try {
|
|
99
|
+
const response = await fetchImpl(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`);
|
|
100
|
+
if (!response?.ok) {
|
|
101
|
+
throw new Error(`npm registry responded with ${response?.status ?? "an unknown error"}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const payload = await response.json();
|
|
105
|
+
if (!payload?.version || typeof payload.version !== "string") {
|
|
106
|
+
throw new Error("npm registry response did not include a version");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
resolvedVersions[packageName] = `^${payload.version}`;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
const fallbackVersion = fallbackVersionMap[packageName];
|
|
112
|
+
if (allowStaleFallback && fallbackVersion) {
|
|
113
|
+
resolvedVersions[packageName] = fallbackVersion;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
118
|
+
failures.push(`${packageName}: ${message}`);
|
|
119
|
+
}
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (failures.length > 0) {
|
|
124
|
+
const fallbackHint = allowStaleFallback
|
|
125
|
+
? "No baked-in fallback version was available for at least one package."
|
|
126
|
+
: "Re-run with --allow-stale-fallback to use the CLI's baked-in BrightWeb package versions instead.";
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Failed to resolve published BrightWeb package versions from npm.\n${failures.join("\n")}\n${fallbackHint}`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return resolvedVersions;
|
|
133
|
+
}
|
|
134
|
+
|
|
79
135
|
function parseConfiguredModules(content) {
|
|
80
136
|
const enabledModules = [];
|
|
81
137
|
|
|
@@ -339,6 +395,13 @@ export async function buildBrightwebAppUpdatePlan(argvOptions = {}, runtimeOptio
|
|
|
339
395
|
const packageManager = detectPackageManager(argvOptions.packageManager || runtimeOptions.packageManager);
|
|
340
396
|
const installedModules = detectInstalledModules(installedBrightwebPackagesMap);
|
|
341
397
|
const versionMap = await getVersionMap(workspaceRoot);
|
|
398
|
+
const brightwebVersionOverrides = dependencyMode === "published"
|
|
399
|
+
? await resolvePublishedBrightwebVersions(installedBrightwebPackagesMap, {
|
|
400
|
+
fetchImpl: runtimeOptions.fetchImpl,
|
|
401
|
+
fallbackVersionMap: versionMap,
|
|
402
|
+
allowStaleFallback: argvOptions.allowStaleFallback || runtimeOptions.allowStaleFallback,
|
|
403
|
+
})
|
|
404
|
+
: {};
|
|
342
405
|
const dbRegistry = await getDbModuleRegistry(workspaceRoot);
|
|
343
406
|
const dbInstallPlan = template === "platform"
|
|
344
407
|
? createDbInstallPlan({
|
|
@@ -356,7 +419,10 @@ export async function buildBrightwebAppUpdatePlan(argvOptions = {}, runtimeOptio
|
|
|
356
419
|
template,
|
|
357
420
|
dependencyMode,
|
|
358
421
|
installedModules,
|
|
359
|
-
versionMap
|
|
422
|
+
versionMap: {
|
|
423
|
+
...versionMap,
|
|
424
|
+
...brightwebVersionOverrides,
|
|
425
|
+
},
|
|
360
426
|
});
|
|
361
427
|
const packageJsonUpdate = mergeManagedPackageUpdates({
|
|
362
428
|
manifest,
|
package/template/base/AGENTS.md
CHANGED
|
@@ -8,6 +8,7 @@ This generated project is a BrightWeb platform starter. Use this file as the loc
|
|
|
8
8
|
- `docs/ai/README.md`: app-specific routing guide for agents.
|
|
9
9
|
- `docs/ai/examples.md`: common setup and customization flows.
|
|
10
10
|
- `docs/ai/app-context.json`: machine-readable app summary for quick discovery.
|
|
11
|
+
- `components/`: local app components used by starter routes and future product surfaces.
|
|
11
12
|
- `config/brand.ts`: client identity, naming, and contact defaults.
|
|
12
13
|
- `config/modules.ts`: selected module set and runtime enablement.
|
|
13
14
|
- `config/client.ts`: starter-facing derived state used by the home page and setup surfaces.
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
type ResolvedClientAppShellConfig,
|
|
13
13
|
} from "@brightweblabs/app-shell";
|
|
14
14
|
import { LayoutTemplate, Sparkles, Users } from "lucide-react";
|
|
15
|
-
import { starterBrandConfig } from "
|
|
16
|
-
import { getStarterShellConfig } from "
|
|
15
|
+
import { starterBrandConfig } from "../config/brand";
|
|
16
|
+
import { getStarterShellConfig } from "../config/shell";
|
|
17
17
|
|
|
18
18
|
const mockUser = {
|
|
19
19
|
email: "admin@starter-client.test",
|
|
@@ -9,6 +9,7 @@ It is intentionally app-scoped. It explains the generated project you are in, no
|
|
|
9
9
|
This app is a normal Next.js App Router project with BrightWeb runtime wiring layered on top.
|
|
10
10
|
|
|
11
11
|
- `app/`: route tree, layouts, pages, starter previews, and playground routes.
|
|
12
|
+
- `components/`: local React components used by starter routes and app-owned product work.
|
|
12
13
|
- `config/`: generated app configuration for brand, env readiness, enabled modules, bootstrap content, and shell registration.
|
|
13
14
|
- `public/brand/`: starter logos used by the shell lockups.
|
|
14
15
|
- `.env.local`: local service configuration for Supabase, Resend, and runtime URLs.
|
|
@@ -18,6 +19,7 @@ This app is a normal Next.js App Router project with BrightWeb runtime wiring la
|
|
|
18
19
|
- `docs/ai/app-context.json`: machine-readable summary of this app's template, starter routes, and first-read files.
|
|
19
20
|
- `docs/ai/examples.md`: common setup and customization workflows.
|
|
20
21
|
- `README.md`: first-run setup steps.
|
|
22
|
+
- `components/`: local app component layer for starter surfaces and future product UI.
|
|
21
23
|
- `config/brand.ts`: client name, product name, support inboxes, and brand color.
|
|
22
24
|
- `config/modules.ts`: module metadata and enablement flags for CRM, Projects, and Admin.
|
|
23
25
|
- `config/client.ts`: aggregated state consumed by starter pages.
|
|
@@ -33,6 +35,7 @@ This app is a normal Next.js App Router project with BrightWeb runtime wiring la
|
|
|
33
35
|
|
|
34
36
|
- Change client identity first in `config/brand.ts`.
|
|
35
37
|
- Check module presence in `config/modules.ts` before editing or creating module-specific routes.
|
|
38
|
+
- Add app-specific UI in `components/` before forking shared package code.
|
|
36
39
|
- Use `config/shell.ts` when navigation or toolbar behavior needs to change.
|
|
37
40
|
- Use `config/bootstrap.ts` and `config/client.ts` when the setup checklist or readiness messaging is wrong.
|
|
38
41
|
- Keep starter validation routes until the real product routes replace their purpose.
|
|
@@ -18,6 +18,7 @@ Goal: get the generated starter running with real credentials.
|
|
|
18
18
|
Goal: update the starter to the real client name and support details.
|
|
19
19
|
|
|
20
20
|
- Edit `config/brand.ts`.
|
|
21
|
+
- Move route-specific presentation into `components/` when the home or preview surfaces need app-owned UI.
|
|
21
22
|
- Check `config/client.ts` or `config/bootstrap.ts` if starter copy still references old defaults.
|
|
22
23
|
- Validate the home page and `/preview/app-shell` after the change.
|
|
23
24
|
|
|
@@ -26,6 +27,7 @@ Goal: update the starter to the real client name and support details.
|
|
|
26
27
|
Goal: move from validation surfaces to product-owned pages.
|
|
27
28
|
|
|
28
29
|
- Build the real routes in `app/` first.
|
|
30
|
+
- Keep reusable route UI in `components/` so the app follows the expected Next.js folder split.
|
|
29
31
|
- Update `config/shell.ts` if navigation or toolbar behavior changes.
|
|
30
32
|
- Remove `/bootstrap`, `/preview/app-shell`, or `/playground/*` only after links and config references are cleaned up.
|
|
31
33
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type RouteHandler = (request: Request) => Response | Promise<Response>;
|
|
2
|
+
|
|
3
|
+
type ModuleWithHandler<THandlerName extends string> = Record<THandlerName, RouteHandler>;
|
|
4
|
+
|
|
5
|
+
export function createModuleRouteHandler<THandlerName extends string>(
|
|
6
|
+
loadModule: () => Promise<ModuleWithHandler<THandlerName>>,
|
|
7
|
+
handlerName: THandlerName,
|
|
8
|
+
): RouteHandler {
|
|
9
|
+
return async function moduleRouteHandler(request: Request) {
|
|
10
|
+
const module = await loadModule();
|
|
11
|
+
return module[handlerName](request);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createModuleRouteHandler } from "../_shared/create-module-route-handler";
|
|
2
|
+
|
|
1
3
|
export const dynamic = "force-dynamic";
|
|
2
4
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export const GET = createModuleRouteHandler(
|
|
6
|
+
() => import("@brightweblabs/module-crm"),
|
|
7
|
+
"handleCrmContactsGetRequest",
|
|
8
|
+
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createModuleRouteHandler } from "../_shared/create-module-route-handler";
|
|
2
|
+
|
|
1
3
|
export const dynamic = "force-dynamic";
|
|
2
4
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export const GET = createModuleRouteHandler(
|
|
6
|
+
() => import("@brightweblabs/module-crm"),
|
|
7
|
+
"handleCrmOrganizationsGetRequest",
|
|
8
|
+
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createModuleRouteHandler } from "../_shared/create-module-route-handler";
|
|
2
|
+
|
|
1
3
|
export const dynamic = "force-dynamic";
|
|
2
4
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export const GET = createModuleRouteHandler(
|
|
6
|
+
() => import("@brightweblabs/module-crm"),
|
|
7
|
+
"handleCrmOwnersGetRequest",
|
|
8
|
+
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createModuleRouteHandler } from "../_shared/create-module-route-handler";
|
|
2
|
+
|
|
1
3
|
export const dynamic = "force-dynamic";
|
|
2
4
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export const GET = createModuleRouteHandler(
|
|
6
|
+
() => import("@brightweblabs/module-crm"),
|
|
7
|
+
"handleCrmStatsGetRequest",
|
|
8
|
+
);
|
|
File without changes
|