@chidchanun/bcp 0.1.22 → 0.1.24
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 +241 -640
- package/docs/README.md +114 -337
- package/docs/auth-route-guards.md +14 -0
- package/docs/developer-tools.md +83 -12
- package/docs/development-logging.md +234 -6
- package/docs/file-upload.md +280 -0
- package/docs/releases/0.1.22.md +66 -1
- package/docs/releases/0.1.23.md +131 -0
- package/docs/releases/0.1.24.md +166 -0
- package/package.json +3 -2
- package/packages/bundler/src/server-production-actions.ts +15 -0
- package/packages/bundler/src/server-production-guards.ts +15 -0
- package/packages/cli/bin/bcp.mjs +111 -0
- package/packages/client/src/form.tsx +20 -13
- package/packages/client/src/server.ts +31 -0
- package/packages/server/src/dev-hmr.ts +131 -9
- package/packages/server/src/dev-route-graph.ts +91 -0
- package/packages/server/src/logger.ts +474 -0
- package/packages/server/src/middleware-dev-server.ts +217 -9
- package/packages/server/src/upload.ts +556 -0
package/docs/releases/0.1.22.md
CHANGED
|
@@ -12,6 +12,35 @@ BCP 0.1.22 adds the first dedicated Developer Tools milestone.
|
|
|
12
12
|
- Added route conflict and client-boundary validation without starting the dev server.
|
|
13
13
|
- Added development environment diagnostics without printing private environment values.
|
|
14
14
|
- Added unit coverage for CLI parsing, version checks, missing-project diagnostics and deterministic inspection output.
|
|
15
|
+
- Added the `bcp-framework` executable alias for Windows systems where the `bcp` command is already occupied by Microsoft SQL Server's `bcp.exe` utility.
|
|
16
|
+
- Fixed `<Form>` SSR so framework runtime rendering no longer depends on a global `React` binding when an application uses the classic JSX transform.
|
|
17
|
+
- Added CLI preflight protection against installing `bcp` and `@chidchanun/bcp` as two separate framework copies, which can split loader/context state across package instances.
|
|
18
|
+
|
|
19
|
+
## CLI executable compatibility
|
|
20
|
+
|
|
21
|
+
The published package now exposes both executable names:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
bcp
|
|
25
|
+
bcp-framework
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Both names execute the same BCP Framework CLI. Existing applications and npm scripts can continue using `bcp` unchanged.
|
|
29
|
+
|
|
30
|
+
On Windows installations that include Microsoft SQL Server tools, use the collision-free alias for direct shell commands:
|
|
31
|
+
|
|
32
|
+
```powershell
|
|
33
|
+
bcp-framework doctor
|
|
34
|
+
bcp-framework inspect
|
|
35
|
+
bcp-framework dev
|
|
36
|
+
bcp-framework build
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Alternatively, explicitly run the project-local `bcp` executable through npm:
|
|
40
|
+
|
|
41
|
+
```powershell
|
|
42
|
+
npm exec -- bcp doctor
|
|
43
|
+
```
|
|
15
44
|
|
|
16
45
|
## `bcp doctor`
|
|
17
46
|
|
|
@@ -66,11 +95,47 @@ If an application is linked directly to a framework staging directory, the appli
|
|
|
66
95
|
|
|
67
96
|
For local release verification, continue using packed `.tgz` artifacts rather than installing `.package/bcp` as a linked directory.
|
|
68
97
|
|
|
98
|
+
## Duplicate BCP package protection
|
|
99
|
+
|
|
100
|
+
Local tarball verification must keep one BCP package root in the application.
|
|
101
|
+
|
|
102
|
+
Installing a tarball directly when the application already declares an npm alias named `bcp` can leave both of these paths installed:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
node_modules/bcp
|
|
106
|
+
node_modules/@chidchanun/bcp
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
That layout is unsafe because application imports can use one `BcpLoaderDataProvider` context while the CLI/SSR runtime uses the other package copy. The visible error can therefore incorrectly say that `useLoaderData()` has no loader data.
|
|
110
|
+
|
|
111
|
+
BCP 0.1.22 now checks this before runtime commands start and fails with an actionable duplicate-install message.
|
|
112
|
+
|
|
113
|
+
For local tarball verification, install the artifact under the existing dependency key:
|
|
114
|
+
|
|
115
|
+
```powershell
|
|
116
|
+
npm install `
|
|
117
|
+
--no-save `
|
|
118
|
+
--package-lock=false `
|
|
119
|
+
"bcp@file:D:\bcp-framework\.package\artifacts\chidchanun-bcp-0.1.22.tgz"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## SSR JSX-runtime compatibility
|
|
123
|
+
|
|
124
|
+
Framework runtime components must not inherit JSX runtime assumptions from the consuming application's `tsconfig.json`.
|
|
125
|
+
|
|
126
|
+
`<Form>` now renders its provider and native `<form>` element through `createElement()`. This keeps SSR compatible with both automatic JSX runtime projects and projects that still use the classic JSX transform, where unbound generated `React.createElement(...)` calls would otherwise produce:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
ReferenceError: React is not defined
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Regression coverage includes server rendering and a classic-JSX transform check that rejects implicit `React.createElement` output from the Form runtime source.
|
|
133
|
+
|
|
69
134
|
## Compatibility
|
|
70
135
|
|
|
71
136
|
0.1.22 does not change public rendering, routing, database, authentication, validation, middleware or error-handling APIs.
|
|
72
137
|
|
|
73
|
-
The
|
|
138
|
+
The Developer Tools commands and `bcp-framework` executable alias are additive. Existing BCP applications can continue using current commands unchanged.
|
|
74
139
|
|
|
75
140
|
## Next milestone
|
|
76
141
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# BCP Framework 0.1.23
|
|
2
|
+
|
|
3
|
+
BCP 0.1.23 introduces the Logging & Observability foundation and carries forward the stabilization fixes verified against the BCP documentation application during the 0.1.22 release-candidate cycle.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Added structured server logging through `bcp/server`.
|
|
8
|
+
- Added `logger.debug()`, `logger.info()`, `logger.warn()` and `logger.error()`.
|
|
9
|
+
- Added child loggers with persistent structured bindings.
|
|
10
|
+
- Added `requestLogger()` for request-scoped `requestId`, HTTP method and path bindings.
|
|
11
|
+
- Added `attachRequestId()` for explicit `X-Request-Id` response propagation.
|
|
12
|
+
- Added `BCP_LOG_LEVEL=debug|info|warn|error|silent`.
|
|
13
|
+
- Added `BCP_LOG_FORMAT=pretty|json`.
|
|
14
|
+
- Added safe serialization for `Error`, `bigint` and circular structured fields.
|
|
15
|
+
- Development API request logs now flow through the structured logger while framework bootstrap traffic remains filtered.
|
|
16
|
+
- Development module-import and SSR timing lines are normalized into `module.import` and `ssr.render` debug events.
|
|
17
|
+
- Added regression coverage for log filtering, JSON records, error serialization, request-scoped identity and response request IDs.
|
|
18
|
+
|
|
19
|
+
## Server logger
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {
|
|
23
|
+
logger,
|
|
24
|
+
} from "bcp/server";
|
|
25
|
+
|
|
26
|
+
logger.info(
|
|
27
|
+
"User loaded",
|
|
28
|
+
{
|
|
29
|
+
userId: 42,
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The default logger reads its level and format from the environment at log time, so normal application configuration can set:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
BCP_LOG_LEVEL=info
|
|
38
|
+
BCP_LOG_FORMAT=json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Request-scoped logger
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import {
|
|
45
|
+
requestLogger,
|
|
46
|
+
} from "bcp/server";
|
|
47
|
+
|
|
48
|
+
export async function loader() {
|
|
49
|
+
const log =
|
|
50
|
+
await requestLogger({
|
|
51
|
+
feature: "categories",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
log.info(
|
|
55
|
+
"Loading categories"
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
items: [],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The child logger binds:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
requestId
|
|
68
|
+
method
|
|
69
|
+
path
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
using the same request context already used by `requestId()`, `requestMethod()` and `requestUrl()`.
|
|
73
|
+
|
|
74
|
+
## Request ID response helper
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import {
|
|
78
|
+
attachRequestId,
|
|
79
|
+
json,
|
|
80
|
+
} from "bcp/server";
|
|
81
|
+
|
|
82
|
+
export async function GET() {
|
|
83
|
+
return attachRequestId(
|
|
84
|
+
json({
|
|
85
|
+
ok: true,
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The response contains `X-Request-Id` with the active request identity.
|
|
92
|
+
|
|
93
|
+
## Development observability
|
|
94
|
+
|
|
95
|
+
Application API request logs retain the existing development noise filter but are now emitted as structured events with:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
event=http.request
|
|
99
|
+
method
|
|
100
|
+
path
|
|
101
|
+
status
|
|
102
|
+
durationMs
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
SSR and module import measurements are emitted at `debug` level as:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
ssr.render
|
|
109
|
+
module.import
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Set `BCP_LOG_LEVEL=debug` when profiling development rendering.
|
|
113
|
+
|
|
114
|
+
## Stabilization fixes included
|
|
115
|
+
|
|
116
|
+
The 0.1.23 source line also contains the fixes completed while validating 0.1.22 against `bcp-docs`:
|
|
117
|
+
|
|
118
|
+
- the `bcp-framework` Windows-safe executable alias avoids the Microsoft SQL Server `bcp.exe` command collision,
|
|
119
|
+
- `<Form>` SSR no longer depends on an implicit global `React` binding under classic JSX transforms,
|
|
120
|
+
- the CLI detects duplicate `bcp` / `@chidchanun/bcp` installations before they produce split React contexts or misleading `useLoaderData()` failures,
|
|
121
|
+
- local release verification guidance uses packed tarballs under the existing `bcp` dependency key so only one framework copy is installed.
|
|
122
|
+
|
|
123
|
+
## Compatibility
|
|
124
|
+
|
|
125
|
+
Logging is additive and server-only. Existing rendering, routing, loaders, guards, actions, middleware, validation, database and authentication APIs remain compatible.
|
|
126
|
+
|
|
127
|
+
Existing application code does not need to adopt the logger to upgrade to 0.1.23.
|
|
128
|
+
|
|
129
|
+
## Next milestone
|
|
130
|
+
|
|
131
|
+
The next planned milestone is BCP 0.1.24 — File Upload foundation.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# BCP Framework 0.1.24
|
|
2
|
+
|
|
3
|
+
BCP 0.1.24 introduces the File Upload foundation and includes production/development stabilization fixes found while validating the framework against `bcp-docs`.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Added multipart upload parsing through `bcp/server`.
|
|
8
|
+
- Added optional and required uploaded-file helpers.
|
|
9
|
+
- Added maximum multipart and per-file size validation.
|
|
10
|
+
- Added MIME type and extension allowlists.
|
|
11
|
+
- Added safe local file persistence with UUID storage names by default.
|
|
12
|
+
- Added filename sanitization and destination traversal protection.
|
|
13
|
+
- Existing files are not overwritten unless `overwrite: true` is explicitly requested.
|
|
14
|
+
- Saved upload metadata includes SHA-256 checksum, original name, stored name, MIME type and byte size.
|
|
15
|
+
- Added `UploadError` with HTTP-oriented status codes and stable upload error codes.
|
|
16
|
+
- Added unit and package-export regression coverage.
|
|
17
|
+
- Fixed development route graph synchronization so page/client bundles rebuild when the actual route topology changes even if the filesystem watcher reports the change as `change` rather than `add`/`unlink`.
|
|
18
|
+
- Fixed standalone auth guards using `requireAuth()` / `requireRole()` after `bcp build` by keeping `bcp/auth` inside the same bundled request-context runtime as the guard evaluator.
|
|
19
|
+
- Applied the same auth-runtime unification to production form-action bundles so guarded actions do not split request context.
|
|
20
|
+
- Added standalone E2E coverage that builds the application and executes a real `requireRole("admin")` guard with a signed session cookie.
|
|
21
|
+
|
|
22
|
+
## Development client-bundle graph fix
|
|
23
|
+
|
|
24
|
+
A development server could previously reach this inconsistent state:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
routes contains /docs/[...slug]
|
|
28
|
+
clientBundles does not contain /docs/[...slug]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The resulting request failed with:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
BCP Framework Error:
|
|
35
|
+
Error: Client bundle was not found for route "/docs/[...slug]".
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Restarting after deleting `.bcp-framework` rebuilt the graph and hid the problem.
|
|
39
|
+
|
|
40
|
+
BCP 0.1.24 tracks the actual page route graph separately at the dev gateway. When pathname, page file or layout topology changes, the internal development server/client bundler is refreshed automatically on the same upstream port. The behavior no longer depends on whether Windows/editor filesystem events are classified as `add`, `unlink` or `change`.
|
|
41
|
+
|
|
42
|
+
## Production auth-guard request context fix
|
|
43
|
+
|
|
44
|
+
A standalone build could previously fail when an application guard imported authentication helpers from `bcp/auth`:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import {
|
|
48
|
+
requireRole,
|
|
49
|
+
} from "bcp/auth";
|
|
50
|
+
|
|
51
|
+
export async function guard() {
|
|
52
|
+
return requireRole(
|
|
53
|
+
"admin"
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The production guard evaluator bundled its own `runWithRequestContext()` runtime, but `bcp/auth` could remain an external package import. This created two request-context module instances inside one request path:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
guards.mjs request context
|
|
62
|
+
↓
|
|
63
|
+
application guard
|
|
64
|
+
↓
|
|
65
|
+
external bcp/auth
|
|
66
|
+
↓
|
|
67
|
+
second request context
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The authentication helper then failed while reading cookies with:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
BCP Framework: server request APIs can only be used while handling a request.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
BCP 0.1.24 resolves `bcp/auth` into the guard build graph so `requireAuth()`, `requireRole()`, sessions and cookies share the same active request context as the production guard evaluator. The production action bundle uses the same rule because route guards may execute before server mutations.
|
|
77
|
+
|
|
78
|
+
## Upload example
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import {
|
|
82
|
+
parseMultipartFormData,
|
|
83
|
+
requireUploadedFile,
|
|
84
|
+
saveUploadedFile,
|
|
85
|
+
} from "bcp/server";
|
|
86
|
+
|
|
87
|
+
export async function POST(
|
|
88
|
+
request: Request
|
|
89
|
+
) {
|
|
90
|
+
const formData =
|
|
91
|
+
await parseMultipartFormData(
|
|
92
|
+
request,
|
|
93
|
+
{
|
|
94
|
+
maxBytes:
|
|
95
|
+
8 * 1024 * 1024,
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const file =
|
|
100
|
+
requireUploadedFile(
|
|
101
|
+
formData,
|
|
102
|
+
"file",
|
|
103
|
+
{
|
|
104
|
+
maxBytes:
|
|
105
|
+
5 * 1024 * 1024,
|
|
106
|
+
allowedTypes: [
|
|
107
|
+
"image/png",
|
|
108
|
+
"image/jpeg",
|
|
109
|
+
"image/webp",
|
|
110
|
+
],
|
|
111
|
+
allowedExtensions: [
|
|
112
|
+
".png",
|
|
113
|
+
".jpg",
|
|
114
|
+
".jpeg",
|
|
115
|
+
".webp",
|
|
116
|
+
],
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const saved =
|
|
121
|
+
await saveUploadedFile(
|
|
122
|
+
file,
|
|
123
|
+
{
|
|
124
|
+
directory:
|
|
125
|
+
"./uploads",
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
return Response.json(
|
|
130
|
+
saved
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Body-limit relationship
|
|
136
|
+
|
|
137
|
+
The existing BCP security gateway still enforces `server.bodyLimit` / `BCP_BODY_LIMIT` before request bodies reach application handlers.
|
|
138
|
+
|
|
139
|
+
The default framework body limit is 1 MiB. Applications accepting larger files must raise the framework body limit as well as choosing appropriate multipart/file limits.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
export default defineConfig({
|
|
143
|
+
server: {
|
|
144
|
+
bodyLimit:
|
|
145
|
+
10 * 1024 * 1024,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Security model
|
|
151
|
+
|
|
152
|
+
The upload helpers protect storage paths and enforce declared size/type/extension policies, but MIME type and extension do not prove file content. Security-sensitive applications should additionally inspect file signatures/content and run malware scanning when appropriate.
|
|
153
|
+
|
|
154
|
+
The 0.1.24 storage helper targets local filesystem storage. Object-storage adapters and direct streaming are outside this foundation milestone.
|
|
155
|
+
|
|
156
|
+
## Compatibility
|
|
157
|
+
|
|
158
|
+
The upload APIs are additive and server-only. Existing routing, loaders, guards, actions, middleware, authentication, database, validation and logging APIs remain compatible.
|
|
159
|
+
|
|
160
|
+
The dev route-graph fix changes only rebuild behavior when the discovered page topology has actually changed.
|
|
161
|
+
|
|
162
|
+
The production auth-guard change affects bundling only: existing `bcp/auth` application imports and guard APIs remain unchanged.
|
|
163
|
+
|
|
164
|
+
## Next milestone
|
|
165
|
+
|
|
166
|
+
The next planned milestone is BCP 0.1.25 — upload/storage adapters and production file-delivery hardening, unless roadmap priorities are regrouped.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chidchanun/bcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "BCP Framework - a React full-stack framework with file-based routing, SSR, APIs, middleware, islands, caching and standalone production builds.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"node": ">=24.11.0"
|
|
25
25
|
},
|
|
26
26
|
"bin": {
|
|
27
|
-
"bcp": "packages/cli/bin/bcp.mjs"
|
|
27
|
+
"bcp": "packages/cli/bin/bcp.mjs",
|
|
28
|
+
"bcp-framework": "packages/cli/bin/bcp.mjs"
|
|
28
29
|
},
|
|
29
30
|
"exports": {
|
|
30
31
|
".": {
|
|
@@ -131,6 +131,11 @@ export async function buildProductionActions(
|
|
|
131
131
|
frameworkDirectory,
|
|
132
132
|
"../../client/src/server.ts"
|
|
133
133
|
);
|
|
134
|
+
const frameworkAuthEntry =
|
|
135
|
+
path.resolve(
|
|
136
|
+
frameworkDirectory,
|
|
137
|
+
"../../client/src/auth.ts"
|
|
138
|
+
);
|
|
134
139
|
const frameworkServerOnlyEntry =
|
|
135
140
|
path.resolve(
|
|
136
141
|
frameworkDirectory,
|
|
@@ -187,6 +192,16 @@ export async function buildProductionActions(
|
|
|
187
192
|
frameworkServerEntry,
|
|
188
193
|
})
|
|
189
194
|
);
|
|
195
|
+
buildApi.onResolve(
|
|
196
|
+
{
|
|
197
|
+
filter:
|
|
198
|
+
/^bcp\/auth$/,
|
|
199
|
+
},
|
|
200
|
+
() => ({
|
|
201
|
+
path:
|
|
202
|
+
frameworkAuthEntry,
|
|
203
|
+
})
|
|
204
|
+
);
|
|
190
205
|
buildApi.onResolve(
|
|
191
206
|
{
|
|
192
207
|
filter:
|
|
@@ -118,6 +118,11 @@ export async function buildProductionGuards(
|
|
|
118
118
|
frameworkDirectory,
|
|
119
119
|
"../../client/src/server.ts"
|
|
120
120
|
);
|
|
121
|
+
const frameworkAuthEntry =
|
|
122
|
+
path.resolve(
|
|
123
|
+
frameworkDirectory,
|
|
124
|
+
"../../client/src/auth.ts"
|
|
125
|
+
);
|
|
121
126
|
const frameworkServerOnlyEntry =
|
|
122
127
|
path.resolve(
|
|
123
128
|
frameworkDirectory,
|
|
@@ -174,6 +179,16 @@ export async function buildProductionGuards(
|
|
|
174
179
|
frameworkServerEntry,
|
|
175
180
|
})
|
|
176
181
|
);
|
|
182
|
+
buildApi.onResolve(
|
|
183
|
+
{
|
|
184
|
+
filter:
|
|
185
|
+
/^bcp\/auth$/,
|
|
186
|
+
},
|
|
187
|
+
() => ({
|
|
188
|
+
path:
|
|
189
|
+
frameworkAuthEntry,
|
|
190
|
+
})
|
|
191
|
+
);
|
|
177
192
|
buildApi.onResolve(
|
|
178
193
|
{
|
|
179
194
|
filter:
|
package/packages/cli/bin/bcp.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
3
5
|
import {
|
|
4
6
|
spawn,
|
|
5
7
|
} from "node:child_process";
|
|
@@ -7,6 +9,46 @@ import {
|
|
|
7
9
|
fileURLToPath,
|
|
8
10
|
} from "node:url";
|
|
9
11
|
|
|
12
|
+
const command =
|
|
13
|
+
process.argv[2] ??
|
|
14
|
+
"dev";
|
|
15
|
+
|
|
16
|
+
const duplicateInstall =
|
|
17
|
+
findDuplicateFrameworkInstall(
|
|
18
|
+
process.cwd()
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
if (duplicateInstall) {
|
|
22
|
+
const message = [
|
|
23
|
+
"BCP Framework: duplicate framework installations detected.",
|
|
24
|
+
"",
|
|
25
|
+
`bcp: ${duplicateInstall.bcp}`,
|
|
26
|
+
`@chidchanun/bcp: ${duplicateInstall.scoped}`,
|
|
27
|
+
"",
|
|
28
|
+
"The application and the BCP CLI can load different framework copies. This breaks shared React contexts such as useLoaderData() and may produce misleading missing-loader errors.",
|
|
29
|
+
"",
|
|
30
|
+
"Keep only one application dependency named bcp. For local tarball verification install it under the bcp dependency key, for example:",
|
|
31
|
+
"npm install --no-save --package-lock=false \"bcp@file:D:\\\\path\\\\to\\\\chidchanun-bcp-0.1.22.tgz\"",
|
|
32
|
+
].join("\n");
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
command !== "doctor" &&
|
|
36
|
+
command !== "inspect"
|
|
37
|
+
) {
|
|
38
|
+
console.error(
|
|
39
|
+
message
|
|
40
|
+
);
|
|
41
|
+
process.exitCode =
|
|
42
|
+
1;
|
|
43
|
+
process.exit();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.warn(
|
|
47
|
+
message
|
|
48
|
+
);
|
|
49
|
+
console.warn("");
|
|
50
|
+
}
|
|
51
|
+
|
|
10
52
|
const bootstrapFile =
|
|
11
53
|
fileURLToPath(
|
|
12
54
|
new URL(
|
|
@@ -91,3 +133,72 @@ child.once(
|
|
|
91
133
|
code ?? 1;
|
|
92
134
|
}
|
|
93
135
|
);
|
|
136
|
+
|
|
137
|
+
function findDuplicateFrameworkInstall(
|
|
138
|
+
rootDirectory
|
|
139
|
+
) {
|
|
140
|
+
const bcp =
|
|
141
|
+
resolvePackageRoot(
|
|
142
|
+
path.join(
|
|
143
|
+
rootDirectory,
|
|
144
|
+
"node_modules",
|
|
145
|
+
"bcp"
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
const scoped =
|
|
149
|
+
resolvePackageRoot(
|
|
150
|
+
path.join(
|
|
151
|
+
rootDirectory,
|
|
152
|
+
"node_modules",
|
|
153
|
+
"@chidchanun",
|
|
154
|
+
"bcp"
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (
|
|
159
|
+
!bcp ||
|
|
160
|
+
!scoped ||
|
|
161
|
+
normalizePath(bcp) ===
|
|
162
|
+
normalizePath(scoped)
|
|
163
|
+
) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
bcp,
|
|
169
|
+
scoped,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function resolvePackageRoot(
|
|
174
|
+
directory
|
|
175
|
+
) {
|
|
176
|
+
if (
|
|
177
|
+
!fs.existsSync(
|
|
178
|
+
path.join(
|
|
179
|
+
directory,
|
|
180
|
+
"package.json"
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
return fs.realpathSync(
|
|
189
|
+
directory
|
|
190
|
+
);
|
|
191
|
+
} catch {
|
|
192
|
+
return path.resolve(
|
|
193
|
+
directory
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function normalizePath(
|
|
199
|
+
value
|
|
200
|
+
) {
|
|
201
|
+
return process.platform === "win32"
|
|
202
|
+
? value.toLowerCase()
|
|
203
|
+
: value;
|
|
204
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createContext,
|
|
3
|
+
createElement,
|
|
3
4
|
useContext,
|
|
4
5
|
useMemo,
|
|
5
6
|
useState,
|
|
@@ -320,19 +321,25 @@ export function Form({
|
|
|
320
321
|
null
|
|
321
322
|
);
|
|
322
323
|
|
|
323
|
-
return (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
324
|
+
return createElement(
|
|
325
|
+
FormRuntimeContext.Provider,
|
|
326
|
+
{
|
|
327
|
+
value:
|
|
328
|
+
runtimeState,
|
|
329
|
+
},
|
|
330
|
+
createElement(
|
|
331
|
+
"form",
|
|
332
|
+
{
|
|
333
|
+
...props,
|
|
334
|
+
action:
|
|
335
|
+
progressiveAction,
|
|
336
|
+
method:
|
|
337
|
+
"post",
|
|
338
|
+
onSubmit:
|
|
339
|
+
handleSubmit,
|
|
340
|
+
},
|
|
341
|
+
children
|
|
342
|
+
)
|
|
336
343
|
);
|
|
337
344
|
}
|
|
338
345
|
|
|
@@ -15,6 +15,37 @@ export {
|
|
|
15
15
|
type ResponseCookieOptions,
|
|
16
16
|
} from "../../server/src/request-context.js";
|
|
17
17
|
|
|
18
|
+
export {
|
|
19
|
+
attachRequestId,
|
|
20
|
+
createLogger,
|
|
21
|
+
logger,
|
|
22
|
+
requestLogger,
|
|
23
|
+
resolveEnvironmentLogFormat,
|
|
24
|
+
resolveEnvironmentLogLevel,
|
|
25
|
+
|
|
26
|
+
type LogFields,
|
|
27
|
+
type LogFormat,
|
|
28
|
+
type LogLevel,
|
|
29
|
+
type Logger,
|
|
30
|
+
type LoggerOptions,
|
|
31
|
+
} from "../../server/src/logger.js";
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
getUploadedFile,
|
|
35
|
+
parseMultipartFormData,
|
|
36
|
+
requireUploadedFile,
|
|
37
|
+
sanitizeUploadFileName,
|
|
38
|
+
saveUploadedFile,
|
|
39
|
+
UploadError,
|
|
40
|
+
validateUploadedFile,
|
|
41
|
+
|
|
42
|
+
type MultipartUploadOptions,
|
|
43
|
+
type SaveUploadedFileOptions,
|
|
44
|
+
type SavedUploadedFile,
|
|
45
|
+
type UploadConstraints,
|
|
46
|
+
type UploadErrorCode,
|
|
47
|
+
} from "../../server/src/upload.js";
|
|
48
|
+
|
|
18
49
|
export {
|
|
19
50
|
json,
|
|
20
51
|
redirect,
|