fimo 0.2.5-staging.14 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "0.2.5-staging.14",
3
+ "version": "0.2.5",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "bin": {
6
6
  "fimo": "dist/cli/index.js"
package/release.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "source": "npm",
3
- "apiUrl": "https://api.staging.fimo.team",
4
- "webUrl": "https://staging.fimo.team"
3
+ "apiUrl": "https://api.fimo.ai",
4
+ "webUrl": "https://fimo.ai"
5
5
  }
@@ -0,0 +1,155 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+ const SCRIPT = path.resolve(__dirname, '../assets/skills/fimo-migration/scripts/write-migration-report.mjs');
11
+
12
+ interface GateResult {
13
+ status: number | null;
14
+ report: string;
15
+ }
16
+
17
+ let dir: string;
18
+
19
+ beforeEach(() => {
20
+ dir = mkdtempSync(path.join(tmpdir(), 'fimo-qa-gate-'));
21
+ });
22
+
23
+ afterEach(() => {
24
+ rmSync(dir, { recursive: true, force: true });
25
+ });
26
+
27
+ function runGate(manifest: unknown, opts: { withBuildArtifact?: boolean } = {}): GateResult {
28
+ mkdirSync(path.join(dir, '.fimo', 'migration'), { recursive: true });
29
+ writeFileSync(path.join(dir, '.fimo', 'migration', 'manifest.json'), JSON.stringify(manifest, null, 2));
30
+ if (opts.withBuildArtifact) {
31
+ mkdirSync(path.join(dir, 'dist', 'client'), { recursive: true });
32
+ writeFileSync(path.join(dir, 'dist', 'client', 'index.html'), '<html></html>');
33
+ }
34
+ const reportPath = path.join(dir, 'report.md');
35
+ const child = spawnSync(process.execPath, [SCRIPT, dir, '--no-update-manifest', '--output', reportPath], {
36
+ encoding: 'utf8',
37
+ });
38
+ return { status: child.status, report: readFileSync(reportPath, 'utf8') };
39
+ }
40
+
41
+ function statusLine(report: string): string {
42
+ const lines = report.split('\n');
43
+ const idx = lines.findIndex((line) => line.trim() === '## Status');
44
+ return lines[idx + 2]?.trim() ?? '';
45
+ }
46
+
47
+ function checkFailed(report: string, id: string): boolean {
48
+ return report.includes(`- [ ] `) && new RegExp(`- \\[ \\] .*\\(${id}\\)`).test(report);
49
+ }
50
+
51
+ describe('migration QA gate (write-migration-report.mjs)', () => {
52
+ it('fails generated-only entries even when seed JSON exists (no silent pass)', () => {
53
+ const { status, report } = runGate({
54
+ source: { mode: 'url-only', platform: 'wix' },
55
+ routes: [{ route: '/', status: 'verified' }],
56
+ contentTypes: [{ name: 'game', status: 'generated' }],
57
+ entries: [{ contentType: 'game', sourceCount: 11, generatedCount: 11, importedCount: 0 }],
58
+ media: [],
59
+ forms: [],
60
+ unresolved: [],
61
+ });
62
+ expect(status).toBe(1);
63
+ expect(statusLine(report)).toBe('draft-only');
64
+ expect(checkFailed(report, 'cms-counts')).toBe(true);
65
+ expect(checkFailed(report, 'schemas-pushed')).toBe(true);
66
+ });
67
+
68
+ it('fails referenced media that is only bundled locally under public/', () => {
69
+ const { status, report } = runGate({
70
+ source: { mode: 'url-only', platform: 'wix' },
71
+ routes: [{ route: '/', status: 'verified' }],
72
+ contentTypes: [],
73
+ entries: [],
74
+ media: [{ id: 'm1', referencedBy: ['/'], status: 'imported', targetUrl: '/assets/thepark/hero.webp' }],
75
+ forms: [],
76
+ unresolved: [],
77
+ });
78
+ expect(status).toBe(1);
79
+ expect(statusLine(report)).toBe('draft-only');
80
+ expect(checkFailed(report, 'media-covered')).toBe(true);
81
+ expect(report).toContain('Uploaded to Fimo: 0');
82
+ expect(report).toContain('Bundled locally (not uploaded): 1');
83
+ });
84
+
85
+ it('passes when entries are imported, schemas pushed, and media uploaded to Fimo', () => {
86
+ const { status, report } = runGate(
87
+ {
88
+ source: { mode: 'url-only', platform: 'wix' },
89
+ routes: [{ route: '/', status: 'verified' }],
90
+ contentTypes: [{ name: 'game', status: 'imported' }],
91
+ entries: [{ contentType: 'game', sourceCount: 3, generatedCount: 3, importedCount: 3, status: 'imported' }],
92
+ media: [
93
+ { id: 'm1', referencedBy: ['/'], targetAssetId: '11111111-1111-1111-1111-111111111111' },
94
+ {
95
+ id: 'm2',
96
+ referencedBy: ['/'],
97
+ targetUrl: 'https://assets.fimo.team/abc/hero.webp',
98
+ sourceUrl: 'https://static.wixstatic.com/hero.webp',
99
+ },
100
+ ],
101
+ forms: [],
102
+ unresolved: [],
103
+ },
104
+ { withBuildArtifact: true }
105
+ );
106
+ expect(status).toBe(0);
107
+ expect(statusLine(report)).toBe('complete');
108
+ expect(report).toContain('Uploaded to Fimo: 2');
109
+ });
110
+
111
+ it('rejects a target URL that merely echoes the source URL (nothing uploaded)', () => {
112
+ const { status, report } = runGate({
113
+ source: { mode: 'url-only', platform: 'wix' },
114
+ routes: [{ route: '/', status: 'verified' }],
115
+ contentTypes: [],
116
+ entries: [],
117
+ media: [
118
+ {
119
+ id: 'm1',
120
+ referencedBy: ['/'],
121
+ sourceUrl: 'https://static.wixstatic.com/hero.webp',
122
+ targetUrl: 'https://static.wixstatic.com/hero.webp',
123
+ },
124
+ ],
125
+ forms: [],
126
+ unresolved: [],
127
+ });
128
+ expect(status).toBe(1);
129
+ expect(checkFailed(report, 'media-covered')).toBe(true);
130
+ });
131
+
132
+ it('allows complete-with-unresolved when gaps are explicit, owner-visible unresolved items', () => {
133
+ const { status, report } = runGate(
134
+ {
135
+ source: { mode: 'url-only', platform: 'wix' },
136
+ routes: [{ route: '/', status: 'verified' }],
137
+ contentTypes: [{ name: 'game', status: 'unresolved' }],
138
+ entries: [{ contentType: 'game', sourceCount: 5, generatedCount: 5, importedCount: 0, status: 'unresolved' }],
139
+ media: [{ id: 'm1', referencedBy: ['/'], status: 'unresolved' }],
140
+ forms: [],
141
+ unresolved: [
142
+ {
143
+ severity: 'high',
144
+ area: 'cms',
145
+ message: 'Game entries need a source export before import.',
146
+ suggestedAction: 'Provide the Wix CMS export and re-run import.',
147
+ },
148
+ ],
149
+ },
150
+ { withBuildArtifact: true }
151
+ );
152
+ expect(status).toBe(0);
153
+ expect(statusLine(report)).toBe('complete-with-unresolved');
154
+ });
155
+ });
@@ -8,6 +8,8 @@ node_modules/
8
8
  dist/
9
9
  build/
10
10
 
11
+ /.react-router/
12
+
11
13
  # Env
12
14
  .env
13
15
  .env.*
@@ -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.2.5-staging.14",
24
+ "fimo": "0.2.5",
25
25
  "input-otp": "^1.4.2",
26
26
  "isbot": "^5",
27
27
  "lucide-react": "^0.577.0",
@@ -4,3 +4,7 @@
4
4
  # here: pnpm refuses to have both an allowlist and allow-all-builds
5
5
  # (ERR_PNPM_CONFIG_CONFLICT_BUILT_DEPENDENCIES), which makes sandbox installs
6
6
  # fail before the project's `fimo` dep is available.
7
+
8
+ allowBuilds:
9
+ esbuild: true
10
+ fimo: true