@chidchanun/bcp 0.1.0 → 0.1.2

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 CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  All notable framework changes are tracked here before release.
4
4
 
5
+ ## 0.1.2 - SSR Link hotfix
6
+
7
+ ### Client routing
8
+
9
+ - Export `Link` through an SSR-safe implementation that uses `React.createElement` semantics without relying on a global `React` binding.
10
+ - Avoid the `ReferenceError: React is not defined` failure when a published BCP package is executed through `tsx` from `node_modules` during server-side rendering.
11
+ - Added an SSR regression test that renders the public `Link` component with `react-dom/server`.
12
+
13
+ ## 0.1.1 - Packaging hotfix
14
+
15
+ ### Packaging and release recovery
16
+
17
+ - Preserve the `bcp` executable in npm package metadata by using npm-normalized `bin` paths.
18
+ - Preserve the `create-bcp-app` executable with the same normalized `bin` convention.
19
+ - Clean-install smoke tests now verify the actual executables created in `node_modules/.bin` and execute the installed `bcp` CLI through an npm script.
20
+ - Partial-release recovery no longer runs publish dry-runs against versions that already exist on npm.
21
+ - Resume mode skips package versions already accepted by npm and continues with the missing package.
22
+ - Successful publishes can be confirmed by the selected npm dist-tag while registry/security processing is still delaying normal version visibility.
23
+ - Added explicit `release:publish:yes` and `release:resume` scripts so publish confirmation does not depend on npm argument forwarding.
24
+
5
25
  ## 0.1.0 - Pre-release
6
26
 
7
27
  ### Framework core
package/docs/releasing.md CHANGED
@@ -4,7 +4,7 @@ The source repository is a private npm workspace package for development. Releas
4
4
 
5
5
  BCP Framework and `create-bcp-app` are prepared for public release under the MIT License. Normal build and test tooling never performs a real `npm publish` automatically. The dedicated release publish command requires explicit confirmation and a matching Git tag.
6
6
 
7
- The selected public npm identities for the first release are:
7
+ The selected public npm identities are:
8
8
 
9
9
  ```text
10
10
  @chidchanun/bcp
@@ -18,7 +18,7 @@ Application source continues importing from `bcp`. `create-bcp-app` stores the s
18
18
  Use the version helper instead of editing package metadata manually:
19
19
 
20
20
  ```bash
21
- npm run version:set -- 0.1.0
21
+ npm run version:set -- 0.1.1
22
22
  ```
23
23
 
24
24
  It synchronizes the release version across:
@@ -43,13 +43,15 @@ This runs type checking, the complete unit/integration/E2E/package test suite, t
43
43
  - synchronized semver metadata
44
44
  - required documentation
45
45
  - MIT license metadata and license files
46
- - staged public package exports
46
+ - staged public package exports and executable metadata
47
47
  - public npm access configuration
48
48
  - exact `v<version>` matching when the check runs from a Git tag
49
49
 
50
+ The package smoke test performs clean installs from packed tarballs and verifies that npm actually creates the `bcp` and `create-bcp-app` executables in `node_modules/.bin`.
51
+
50
52
  ## 3. Verify npm package names and ownership
51
53
 
52
- Before the first publish, authenticate to npm:
54
+ Authenticate to npm before publishing:
53
55
 
54
56
  ```bash
55
57
  npm login
@@ -62,7 +64,7 @@ Then run:
62
64
  npm run release:name-check
63
65
  ```
64
66
 
65
- The default RC package names are now locked by `scripts/release-env.mjs` to:
67
+ The default RC package names are locked by `scripts/release-env.mjs` to:
66
68
 
67
69
  ```text
68
70
  @chidchanun/bcp
@@ -108,7 +110,7 @@ The gate fails when:
108
110
  - `<package>@<local-version>` already exists and therefore cannot be republished
109
111
  - the local version is older than or equal to the registry's current latest version
110
112
 
111
- Because `@chidchanun/bcp` and `create-bcp-app` are new package names at the time of the first RC check, `0.1.0` is valid as their initial release version unless either name/version is published before the release completes.
113
+ A published npm version is immutable. If a packaging defect is discovered after publication, increment the patch version instead of trying to replace the existing version.
112
114
 
113
115
  ## 5. Run npm publish dry-run and clean-install smoke
114
116
 
@@ -116,7 +118,7 @@ Because `@chidchanun/bcp` and `create-bcp-app` are new package names at the time
116
118
  npm run release:dry-run
117
119
  ```
118
120
 
119
- This performs `npm publish --dry-run` for both staged packages, packs fresh tarballs, installs the framework tarball into a temporary clean project, executes the installed BCP CLI, installs the `create-bcp-app` tarball separately, and generates another temporary app from the installed generator.
121
+ This performs `npm publish --dry-run` for both staged packages, packs fresh tarballs, installs the framework tarball into a temporary clean project, verifies the installed `bcp` executable, installs the `create-bcp-app` tarball separately, and verifies its generated executable.
120
122
 
121
123
  No package is uploaded to the npm registry.
122
124
 
@@ -190,7 +192,7 @@ A generated application's `package.json` should therefore contain a dependency e
190
192
  ```json
191
193
  {
192
194
  "dependencies": {
193
- "bcp": "npm:@chidchanun/bcp@^0.1.0"
195
+ "bcp": "npm:@chidchanun/bcp@^0.1.1"
194
196
  }
195
197
  }
196
198
  ```
@@ -201,31 +203,33 @@ Only after `npm run rc:check` passes and `CHANGELOG.md` is ready:
201
203
 
202
204
  ```bash
203
205
  git status
204
- git tag -a v0.1.0 -m "BCP Framework v0.1.0"
205
- git push origin v0.1.0
206
+ git tag -a v0.1.1 -m "BCP Framework v0.1.1"
207
+ git push origin v0.1.1
206
208
  ```
207
209
 
208
210
  Use the actual version from `package.json` in the tag.
209
211
 
210
212
  The GitHub Release Check workflow validates a `v*` tag, rechecks the npm target version, and uploads the npm tarballs as workflow artifacts. It does not publish them.
211
213
 
212
- ## 9. Guarded first publish
214
+ ## 9. Guarded publish
213
215
 
214
216
  After the tag workflow artifacts have been reviewed, publish from an authenticated local npm session with:
215
217
 
216
218
  ```bash
217
- npm run release:publish -- --yes
219
+ npm run release:publish:yes
218
220
  ```
219
221
 
222
+ This explicit script is preferred over forwarding `--yes` through `npm run`, because npm CLI argument forwarding can vary by npm/platform version.
223
+
220
224
  The command refuses to publish unless all of these conditions are true:
221
225
 
222
- - `--yes` is supplied
226
+ - explicit publish confirmation is present
223
227
  - the git working tree is clean
224
228
  - HEAD has the exact tag `v<package-version>`
225
229
  - npm authentication succeeds
226
230
  - the RC checks succeed again
227
231
  - staged package names and versions match the selected release
228
- - the target version has not already been published
232
+ - the target version has not already been accepted by npm
229
233
 
230
234
  For `0.x` releases the default npm dist-tag is:
231
235
 
@@ -242,27 +246,29 @@ latest
242
246
  Override the tag explicitly when needed:
243
247
 
244
248
  ```bash
245
- BCP_DIST_TAG=beta npm run release:publish -- --yes
249
+ BCP_DIST_TAG=beta npm run release:publish:yes
246
250
  ```
247
251
 
248
252
  PowerShell example:
249
253
 
250
254
  ```powershell
251
255
  $env:BCP_DIST_TAG="beta"
252
- npm run release:publish -- --yes
256
+ npm run release:publish:yes
253
257
  ```
254
258
 
255
- The framework publishes first. `create-bcp-app` publishes only after the framework publish succeeds and npm confirms that version is visible in the registry.
259
+ The framework publishes first. After `npm publish` succeeds, the release script accepts either normal version visibility or the selected dist-tag pointing at the new version. This prevents npm registry/security-processing delays from being misclassified as a failed publish.
256
260
 
257
261
  ## 10. Recover from a partial publish
258
262
 
259
- If the framework package was published successfully but publishing `create-bcp-app` failed, fix the external issue without changing the release commit or tag, then use:
263
+ If the framework package was accepted by npm but publishing `create-bcp-app` failed, fix the external issue without changing that release commit or tag, then use:
260
264
 
261
265
  ```bash
262
- npm run release:publish -- --yes --resume
266
+ npm run release:resume
263
267
  ```
264
268
 
265
- `--resume` skips versions that already exist and attempts only the missing package. Do not use `--resume` to overwrite or replace an existing npm version; npm versions are immutable.
269
+ Resume mode intentionally does not run `release:version-check` or `npm publish --dry-run` for the already-published version. It still runs the complete local release checks and package smoke tests, verifies package ownership, skips package versions already accepted by npm, and attempts only the missing package.
270
+
271
+ Do not use resume mode to overwrite or replace an existing npm version; npm versions are immutable.
266
272
 
267
273
  ## 11. Install the preview release
268
274
 
@@ -288,11 +294,11 @@ import {
288
294
 
289
295
  The scoped package can also be installed directly as `@chidchanun/bcp@next`, but applications using the framework's documented `bcp` import path should prefer the alias form above.
290
296
 
291
- ## 12. Trusted publishing after the initial release
297
+ ## 12. Trusted publishing
292
298
 
293
299
  For subsequent releases, prefer npm Trusted Publishing with GitHub Actions instead of a long-lived write token. npm supports GitHub Actions OIDC publishing and recommends trusted publishing for CI-based releases.
294
300
 
295
- The first package version must exist before its npm package settings can be configured for a trusted publisher. After the initial manual release, configure the repository/workflow as a trusted publisher on npm and move the real publish action into the guarded GitHub release workflow.
301
+ After the npm package settings are available, configure the repository/workflow as a trusted publisher and move the real publish action into the guarded GitHub release workflow.
296
302
 
297
303
  ## License
298
304
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chidchanun/bcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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,7 @@
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
28
  },
29
29
  "exports": {
30
30
  ".": {
@@ -1,14 +1,17 @@
1
1
  import "./persistent-layout-runtime.js";
2
2
 
3
3
  export {
4
- Link,
5
4
  navigate,
6
5
  useRouter,
7
- type LinkProps,
8
6
  type NavigationOptions,
9
7
  type Router,
10
8
  } from "./router-v2.js";
11
9
 
10
+ export {
11
+ Link,
12
+ type LinkProps,
13
+ } from "./link.js";
14
+
12
15
  export {
13
16
  useNavigation,
14
17
  type NavigationState,
@@ -0,0 +1,123 @@
1
+ import {
2
+ createElement,
3
+ type MouseEvent,
4
+ } from "react";
5
+
6
+ import {
7
+ navigate,
8
+ useRouter,
9
+ type LinkProps,
10
+ } from "./router-v2.js";
11
+
12
+ export type {
13
+ LinkProps,
14
+ } from "./router-v2.js";
15
+
16
+ export function Link({
17
+ href,
18
+ replace = false,
19
+ scroll = true,
20
+ onClick,
21
+ ...props
22
+ }: LinkProps) {
23
+ useRouter();
24
+
25
+ function handleClick(
26
+ event: MouseEvent<HTMLAnchorElement>
27
+ ) {
28
+ onClick?.(event);
29
+
30
+ if (
31
+ event.defaultPrevented ||
32
+ !shouldInterceptClick(
33
+ event
34
+ )
35
+ ) {
36
+ return;
37
+ }
38
+
39
+ event.preventDefault();
40
+
41
+ void navigate(
42
+ href,
43
+ {
44
+ replace,
45
+ scroll,
46
+ }
47
+ ).catch(
48
+ (error) => {
49
+ if (isAbortError(error)) {
50
+ return;
51
+ }
52
+
53
+ console.error(
54
+ "[BCP Router] navigation failed:",
55
+ error
56
+ );
57
+ window.location.assign(
58
+ href
59
+ );
60
+ }
61
+ );
62
+ }
63
+
64
+ return createElement(
65
+ "a",
66
+ {
67
+ ...props,
68
+ href,
69
+ onClick:
70
+ handleClick,
71
+ }
72
+ );
73
+ }
74
+
75
+ function shouldInterceptClick(
76
+ event: MouseEvent<HTMLAnchorElement>
77
+ ): boolean {
78
+ if (
79
+ event.defaultPrevented ||
80
+ event.button !== 0 ||
81
+ event.metaKey ||
82
+ event.ctrlKey ||
83
+ event.shiftKey ||
84
+ event.altKey
85
+ ) {
86
+ return false;
87
+ }
88
+
89
+ const anchor =
90
+ event.currentTarget;
91
+
92
+ if (
93
+ anchor.target &&
94
+ anchor.target !== "_self"
95
+ ) {
96
+ return false;
97
+ }
98
+
99
+ if (
100
+ anchor.hasAttribute(
101
+ "download"
102
+ )
103
+ ) {
104
+ return false;
105
+ }
106
+
107
+ return (
108
+ new URL(
109
+ anchor.href,
110
+ window.location.href
111
+ ).origin ===
112
+ window.location.origin
113
+ );
114
+ }
115
+
116
+ function isAbortError(
117
+ error: unknown
118
+ ): boolean {
119
+ return (
120
+ error instanceof DOMException &&
121
+ error.name === "AbortError"
122
+ );
123
+ }
@@ -1 +1,11 @@
1
- export * from "./router-v2.js";
1
+ export {
2
+ navigate,
3
+ useRouter,
4
+ type NavigationOptions,
5
+ type Router,
6
+ } from "./router-v2.js";
7
+
8
+ export {
9
+ Link,
10
+ type LinkProps,
11
+ } from "./link.js";