fimo 0.3.3-staging.25 → 0.3.4-staging.26

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/build/vite/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,MAAM,CAAC;AA2EjD,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;;;;;;;OAUG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAGD,wBAAgB,IAAI,CAAC,IAAI,GAAE,eAAoB,GAAG,YAAY,EAAE,CAsB/D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/build/vite/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,MAAM,CAAC;AAmFjD,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;;;;;;;OAUG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAGD,wBAAgB,IAAI,CAAC,IAAI,GAAE,eAAoB,GAAG,YAAY,EAAE,CAsB/D"}
@@ -34,7 +34,15 @@ function bundleFimoIntoSsrPlugin() {
34
34
  config: () => ({
35
35
  ssr: { noExternal: ['fimo'] },
36
36
  optimizeDeps: {
37
- include: ['fimo/ui'],
37
+ // Pre-include fimo's scanner-invisible dependency surface. The
38
+ // scanner can't traverse the fimo package (virtual: imports), so deps
39
+ // reached only THROUGH fimo (its react-router adapter subpath, its
40
+ // internal react-query usage) get discovered mid-first-load — vite
41
+ // re-optimizes and 504s the in-flight generation's chunks ("Outdated
42
+ // Optimize Dep") and the app never mounts (blank preview; caught by
43
+ // content/query e2e). Deps the template's own source imports (react,
44
+ // react-router) are scanner-visible and need no listing.
45
+ include: ['fimo/ui', 'fimo/react-router', '@tanstack/react-query'],
38
46
  rolldownOptions: {
39
47
  plugins: [
40
48
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "bundled": true,
3
3
  "bundler": "esbuild",
4
- "bundledAt": "2026-07-07T08:12:37.579Z",
4
+ "bundledAt": "2026-07-07T09:17:55.884Z",
5
5
  "cliVersion": "0.3.3",
6
6
  "external": [
7
7
  "oxc-parser",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "0.3.3-staging.25",
3
+ "version": "0.3.4-staging.26",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "bin": {
6
6
  "fimo": "dist/cli/index.js"
@@ -10,8 +10,8 @@
10
10
  // governs a bare `npm i -g fimo` with no env set. The sandbox always
11
11
  // overrides it via the injected `.env`.
12
12
 
13
- import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
14
- import { resolve } from 'node:path';
13
+ import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
14
+ import { join, resolve } from 'node:path';
15
15
 
16
16
  import { ALLOWED_API_URLS } from './channels.mjs';
17
17
 
@@ -120,3 +120,51 @@ export function computePublishVersion(baseVersion, channel, opts = {}) {
120
120
  const n = opts.runId ?? String(Date.now());
121
121
  return `${base}-${channel.distTag}.${n}`;
122
122
  }
123
+
124
+ const BUMP_RANK = { patch: 1, minor: 2, major: 3 };
125
+
126
+ /**
127
+ * Peek at pending changeset files and compute the version the next
128
+ * `changeset version` run will produce for `fimo`. Prerelease channels use
129
+ * this as their base so a staging build advertises the version prod will
130
+ * actually ship (`0.3.4-staging.26` while 0.3.4 is pending) instead of the
131
+ * already-released base. No pending changesets (or no .changeset dir) →
132
+ * base unchanged.
133
+ *
134
+ * @param {string} baseVersion - package.json version
135
+ * @param {string} changesetDir - absolute path to the repo's .changeset dir
136
+ * @returns {string}
137
+ */
138
+ export function nextVersionFromChangesets(baseVersion, changesetDir) {
139
+ let entries;
140
+ try {
141
+ entries = readdirSync(changesetDir);
142
+ } catch {
143
+ return baseVersion;
144
+ }
145
+
146
+ let maxBump = null;
147
+ for (const name of entries) {
148
+ if (!name.endsWith('.md') || name === 'README.md') {
149
+ continue;
150
+ }
151
+ const text = readFileSync(join(changesetDir, name), 'utf8');
152
+ const frontmatter = text.match(/^---\n([\s\S]*?)\n---/)?.[1] ?? '';
153
+ const bump = frontmatter.match(/['"]?fimo['"]?\s*:\s*(patch|minor|major)/)?.[1];
154
+ if (bump && (!maxBump || BUMP_RANK[bump] > BUMP_RANK[maxBump])) {
155
+ maxBump = bump;
156
+ }
157
+ }
158
+
159
+ if (!maxBump) {
160
+ return baseVersion;
161
+ }
162
+ const [major, minor, patch] = baseVersion.split('-')[0].split('.').map(Number);
163
+ if (maxBump === 'major') {
164
+ return `${major + 1}.0.0`;
165
+ }
166
+ if (maxBump === 'minor') {
167
+ return `${major}.${minor + 1}.0`;
168
+ }
169
+ return `${major}.${minor}.${patch + 1}`;
170
+ }
@@ -0,0 +1,81 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+
5
+ import { afterEach, describe, expect, it } from 'vitest';
6
+
7
+ // @ts-expect-error plain mjs module without types
8
+ import { computePublishVersion, nextVersionFromChangesets } from './release-core.mjs';
9
+
10
+ const stagingChannel = { prerelease: true, distTag: 'staging' };
11
+ const latestChannel = { prerelease: false, distTag: 'latest' };
12
+
13
+ describe('computePublishVersion', () => {
14
+ it('returns the base version verbatim for stable channels', () => {
15
+ expect(computePublishVersion('0.3.3', latestChannel, { runId: '7' })).toBe('0.3.3');
16
+ });
17
+
18
+ it('synthesizes a prerelease version from the run id', () => {
19
+ expect(computePublishVersion('0.3.3', stagingChannel, { runId: '26' })).toBe('0.3.3-staging.26');
20
+ });
21
+
22
+ it('strips an existing prerelease suffix before synthesizing', () => {
23
+ expect(computePublishVersion('0.3.3-staging.9', stagingChannel, { runId: '26' })).toBe('0.3.3-staging.26');
24
+ });
25
+ });
26
+
27
+ describe('nextVersionFromChangesets', () => {
28
+ let dir: string;
29
+
30
+ afterEach(() => {
31
+ if (dir) {
32
+ rmSync(dir, { recursive: true, force: true });
33
+ }
34
+ });
35
+
36
+ function changesetDir(files: Record<string, string>): string {
37
+ dir = mkdtempSync(join(tmpdir(), 'changesets-'));
38
+ writeFileSync(join(dir, 'README.md'), '# Changesets\n');
39
+ for (const [name, frontmatter] of Object.entries(files)) {
40
+ writeFileSync(join(dir, name), `---\n${frontmatter}\n---\n\nsummary\n`);
41
+ }
42
+ return dir;
43
+ }
44
+
45
+ it('returns the base when the directory does not exist', () => {
46
+ expect(nextVersionFromChangesets('0.3.3', '/nonexistent/.changeset')).toBe('0.3.3');
47
+ });
48
+
49
+ it('returns the base when no changesets are pending', () => {
50
+ expect(nextVersionFromChangesets('0.3.3', changesetDir({}))).toBe('0.3.3');
51
+ });
52
+
53
+ it('applies a patch bump for pending patch changesets', () => {
54
+ const d = changesetDir({ 'a.md': "'fimo': patch" });
55
+ expect(nextVersionFromChangesets('0.3.3', d)).toBe('0.3.4');
56
+ });
57
+
58
+ it('takes the max bump across pending changesets', () => {
59
+ const d = changesetDir({
60
+ 'a.md': "'fimo': patch",
61
+ 'b.md': "'fimo': minor",
62
+ 'c.md': "'fimo': patch",
63
+ });
64
+ expect(nextVersionFromChangesets('0.3.3', d)).toBe('0.4.0');
65
+ });
66
+
67
+ it('handles major bumps and double-quoted package names', () => {
68
+ const d = changesetDir({ 'a.md': '"fimo": major' });
69
+ expect(nextVersionFromChangesets('0.3.3', d)).toBe('1.0.0');
70
+ });
71
+
72
+ it('ignores changesets for other packages', () => {
73
+ const d = changesetDir({ 'a.md': "'@fimo/fimovm': minor" });
74
+ expect(nextVersionFromChangesets('0.3.3', d)).toBe('0.3.3');
75
+ });
76
+
77
+ it('ignores an existing prerelease suffix on the base', () => {
78
+ const d = changesetDir({ 'a.md': "'fimo': patch" });
79
+ expect(nextVersionFromChangesets('0.3.3-staging.9', d)).toBe('0.3.4');
80
+ });
81
+ });
@@ -35,6 +35,7 @@ import { resolveChannel } from './lib/channels.mjs';
35
35
  import { writeDevReleaseState } from './lib/dev-release-state.mjs';
36
36
  import {
37
37
  computePublishVersion,
38
+ nextVersionFromChangesets,
38
39
  pinTemplateFimo,
39
40
  stripTemplateLockfile,
40
41
  writeReleaseJson,
@@ -90,7 +91,12 @@ if (channel.distTag === 'latest' && !isCI && !bootstrap) {
90
91
  }
91
92
 
92
93
  const pkg = JSON.parse(readFileSync(PKG_PATH, 'utf8'));
93
- const baseVersion = pkg.version;
94
+ // Prerelease channels base off the version the pending changesets will
95
+ // produce at the next production release, so a staging build advertises the
96
+ // version prod will actually ship.
97
+ const baseVersion = channel.prerelease
98
+ ? nextVersionFromChangesets(pkg.version, resolve(CLI_ROOT, '../../.changeset'))
99
+ : pkg.version;
94
100
  const runId = process.env.GITHUB_RUN_NUMBER;
95
101
  const publishVersion = computePublishVersion(baseVersion, channel, { runId });
96
102
 
@@ -21,7 +21,7 @@
21
21
  "cmdk": "^1.1.1",
22
22
  "date-fns": "^4.1.0",
23
23
  "embla-carousel-react": "^8.6.0",
24
- "fimo": "0.3.3-staging.25",
24
+ "fimo": "0.3.4-staging.26",
25
25
  "input-otp": "^1.4.2",
26
26
  "isbot": "^5",
27
27
  "lucide-react": "^0.577.0",