fimo 2.1.0 → 2.2.0-staging.1

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.
@@ -8,9 +8,13 @@ export const astroServerContentRuntime = {
8
8
  },
9
9
  headers(extra) {
10
10
  const headers = { ...extra };
11
- const env = import.meta.env.FIMO_ENV?.trim();
12
- if (env) {
13
- headers['X-Fimo-Env'] = env;
11
+ // `FIMO_ENV` is the variable name a customer's deployed build reads and
12
+ // keeps its spelling; only the header this build emits is canonical
13
+ // (branch-cutover ledger, F5). Builds already in production keep sending
14
+ // `X-Fimo-Env`, which the API still accepts.
15
+ const branch = import.meta.env.FIMO_ENV?.trim();
16
+ if (branch) {
17
+ headers['X-Fimo-Branch'] = branch;
14
18
  }
15
19
  return headers;
16
20
  },
@@ -46,9 +46,13 @@ async function fetchEntries(baseUrl, schema, rootDir, locale) {
46
46
  url.searchParams.set('limit', '1');
47
47
  }
48
48
  const headers = {};
49
- const env = readEnvValue(rootDir, 'FIMO_ENV') ?? resolveLocalRuntimeEnv({ cwd: rootDir })?.env;
50
- if (env) {
51
- headers['X-Fimo-Env'] = env;
49
+ // `FIMO_ENV` is a customer-facing variable name and keeps its spelling; the
50
+ // header this build emits is canonical (branch-cutover ledger, F5). A
51
+ // deployed site always talks to the current API, and builds produced by an
52
+ // older `fimo` keep sending `X-Fimo-Env`, which the API still accepts.
53
+ const branch = readEnvValue(rootDir, 'FIMO_ENV') ?? resolveLocalRuntimeEnv({ cwd: rootDir })?.env;
54
+ if (branch) {
55
+ headers['X-Fimo-Branch'] = branch;
52
56
  }
53
57
  for (let attempt = 1; attempt <= MAX_FETCH_ATTEMPTS; attempt += 1) {
54
58
  const res = await fetch(url, { headers });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * How a local checkout names and addresses a Fimo Branch — runtime-safe copy.
3
+ *
4
+ * TRAP: this looks like a duplicate of `@fimo/api-contracts` and it is, on
5
+ * purpose. `dist/runtime/` and `dist/build/` ship UNBUNDLED inside the `fimo`
6
+ * npm package and can only import published dependencies; `@fimo/api-contracts`
7
+ * is a private workspace package, so a runtime import of it breaks every user
8
+ * project (`ERR_MODULE_NOT_FOUND` from `vite.config.ts`). The CLI binary is
9
+ * bundled and may import contracts freely — the runtime may not.
10
+ *
11
+ * The two copies must agree byte-for-byte or a checkout computes a different
12
+ * tenant host than the API hands out. `branch-identity.test.ts` pins them
13
+ * together against a corpus; change one, and that test tells you to change the
14
+ * other.
15
+ */
16
+ export declare const DEFAULT_BRANCH = "main";
17
+ export declare const PROD_BRANCH_PREFIX = "release/";
18
+ /** Mirror of `isValidBranch` in `@fimo/api-contracts`. */
19
+ export declare function isValidBranch(branch: string): boolean;
20
+ /**
21
+ * Mirror of `envResourceKey` in `@fimo/api-contracts`. Keeps that name on both
22
+ * sides: its OUTPUT is a live tenant hostname and R2 prefix, and the symbol
23
+ * rename is a later slice (branch-cutover ledger, F10).
24
+ */
25
+ export declare function envResourceKey(branch: string): string;
26
+ /** Mirror of `buildTenantApiUrl` in `@fimo/api-contracts`. */
27
+ export declare function buildTenantApiUrl(projectId: string, branch: string, tenantApiBaseUrl: string): string;
28
+ /**
29
+ * Content-API aliases a local checkout exposes — one per framework family
30
+ * that has a Fimo startup hook (Vite/React Router, Next, Astro, SvelteKit).
31
+ * Add a key when its framework's hook lands, not before: an alias no runtime
32
+ * reads is one more line to reason about when a site talks to the wrong Branch.
33
+ *
34
+ * These are process-env variable names in a CUSTOMER's app; they keep their
35
+ * `ENV` spelling (branch-cutover ledger, F3 "Preserve").
36
+ */
37
+ export declare const LOCAL_CONTENT_API_ENV_KEYS: readonly ['FIMO_CONTENT_API_URL', 'VITE_API_URL', 'NEXT_PUBLIC_FIMO_API_URL', 'PUBLIC_FIMO_API_URL'];
38
+ /**
39
+ * Branch selectors a runtime turns into the Branch request header.
40
+ *
41
+ * `FIMO_ENV` / `NEXT_PUBLIC_FIMO_ENV` are the variable names a customer's
42
+ * deployed build reads; renaming either breaks it (branch-cutover ledger,
43
+ * "Names that must not be mechanically renamed").
44
+ */
45
+ export declare const LOCAL_ENV_SELECTOR_KEYS: readonly ['FIMO_ENV', 'NEXT_PUBLIC_FIMO_ENV'];
46
+ /**
47
+ * Both halves move together. The tenant URL selects the Branch for content
48
+ * reads (each Branch has its own host); the selectors select it for every
49
+ * service that reads the Branch header. Setting one without the other points a
50
+ * checkout at two different Branches.
51
+ */
52
+ export declare function buildLocalRuntimeEnv(options: {
53
+ readonly tenantApiUrl: string;
54
+ readonly branch: string;
55
+ }): Record<string, string>;
56
+ //# sourceMappingURL=branch-identity.d.ts.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * How a local checkout names and addresses a Fimo env — runtime-safe copy.
2
+ * How a local checkout names and addresses a Fimo Branch — runtime-safe copy.
3
3
  *
4
4
  * TRAP: this looks like a duplicate of `@fimo/api-contracts` and it is, on
5
5
  * purpose. `dist/runtime/` and `dist/build/` ship UNBUNDLED inside the `fimo`
@@ -9,32 +9,32 @@
9
9
  * bundled and may import contracts freely — the runtime may not.
10
10
  *
11
11
  * The two copies must agree byte-for-byte or a checkout computes a different
12
- * tenant host than the API hands out. `env-identity.test.ts` pins them
12
+ * tenant host than the API hands out. `branch-identity.test.ts` pins them
13
13
  * together against a corpus; change one, and that test tells you to change the
14
14
  * other.
15
15
  */
16
- export const DEFAULT_ENV = 'main';
17
- export const PROD_ENV_PREFIX = 'release/';
18
- const ENV_ID_REGEX = /^[a-zA-Z0-9._/-]+$/;
19
- const MAX_ENV_LENGTH = 255;
20
- /** Mirror of `isValidEnv` in `@fimo/api-contracts`. */
21
- export function isValidEnv(env) {
22
- if (typeof env !== 'string') {
16
+ export const DEFAULT_BRANCH = 'main';
17
+ export const PROD_BRANCH_PREFIX = 'release/';
18
+ const BRANCH_ID_REGEX = /^[a-zA-Z0-9._/-]+$/;
19
+ const MAX_BRANCH_LENGTH = 255;
20
+ /** Mirror of `isValidBranch` in `@fimo/api-contracts`. */
21
+ export function isValidBranch(branch) {
22
+ if (typeof branch !== 'string') {
23
23
  return false;
24
24
  }
25
- if (env.length === 0 || env.length > MAX_ENV_LENGTH) {
25
+ if (branch.length === 0 || branch.length > MAX_BRANCH_LENGTH) {
26
26
  return false;
27
27
  }
28
- if (env.startsWith('-') || env.startsWith('.')) {
28
+ if (branch.startsWith('-') || branch.startsWith('.')) {
29
29
  return false;
30
30
  }
31
- if (env.includes('//') || env.includes('--')) {
31
+ if (branch.includes('//') || branch.includes('--')) {
32
32
  return false;
33
33
  }
34
- if (env.split('/').some((segment) => segment === '..')) {
34
+ if (branch.split('/').some((segment) => segment === '..')) {
35
35
  return false;
36
36
  }
37
- return ENV_ID_REGEX.test(env);
37
+ return BRANCH_ID_REGEX.test(branch);
38
38
  }
39
39
  function fnv1a8(s) {
40
40
  let h = 0x811c9dc5;
@@ -44,27 +44,34 @@ function fnv1a8(s) {
44
44
  }
45
45
  return (h >>> 0).toString(16).padStart(8, '0');
46
46
  }
47
- /** Mirror of `envResourceKey` in `@fimo/api-contracts`. */
48
- export function envResourceKey(env) {
49
- const base = env
47
+ /**
48
+ * Mirror of `envResourceKey` in `@fimo/api-contracts`. Keeps that name on both
49
+ * sides: its OUTPUT is a live tenant hostname and R2 prefix, and the symbol
50
+ * rename is a later slice (branch-cutover ledger, F10).
51
+ */
52
+ export function envResourceKey(branch) {
53
+ const base = branch
50
54
  .toLowerCase()
51
55
  .replace(/[^a-z0-9]+/g, '-')
52
56
  .replace(/^-+|-+$/g, '')
53
57
  .slice(0, 15);
54
- const hash = fnv1a8(env);
58
+ const hash = fnv1a8(branch);
55
59
  return base ? `${base}-${hash}` : hash;
56
60
  }
57
61
  /** Mirror of `buildTenantApiUrl` in `@fimo/api-contracts`. */
58
- export function buildTenantApiUrl(projectId, env, tenantApiBaseUrl) {
62
+ export function buildTenantApiUrl(projectId, branch, tenantApiBaseUrl) {
59
63
  const url = new URL(tenantApiBaseUrl);
60
- url.hostname = `${projectId}-${envResourceKey(env)}.${url.hostname}`;
64
+ url.hostname = `${projectId}-${envResourceKey(branch)}.${url.hostname}`;
61
65
  return url.toString().replace(/\/$/, '');
62
66
  }
63
67
  /**
64
68
  * Content-API aliases a local checkout exposes — one per framework family
65
69
  * that has a Fimo startup hook (Vite/React Router, Next, Astro, SvelteKit).
66
70
  * Add a key when its framework's hook lands, not before: an alias no runtime
67
- * reads is one more line to reason about when a site talks to the wrong env.
71
+ * reads is one more line to reason about when a site talks to the wrong Branch.
72
+ *
73
+ * These are process-env variable names in a CUSTOMER's app; they keep their
74
+ * `ENV` spelling (branch-cutover ledger, F3 "Preserve").
68
75
  */
69
76
  export const LOCAL_CONTENT_API_ENV_KEYS = [
70
77
  'FIMO_CONTENT_API_URL',
@@ -72,17 +79,23 @@ export const LOCAL_CONTENT_API_ENV_KEYS = [
72
79
  'NEXT_PUBLIC_FIMO_API_URL',
73
80
  'PUBLIC_FIMO_API_URL',
74
81
  ];
75
- /** Env selectors a runtime turns into the `X-Fimo-Env` request header. */
82
+ /**
83
+ * Branch selectors a runtime turns into the Branch request header.
84
+ *
85
+ * `FIMO_ENV` / `NEXT_PUBLIC_FIMO_ENV` are the variable names a customer's
86
+ * deployed build reads; renaming either breaks it (branch-cutover ledger,
87
+ * "Names that must not be mechanically renamed").
88
+ */
76
89
  export const LOCAL_ENV_SELECTOR_KEYS = ['FIMO_ENV', 'NEXT_PUBLIC_FIMO_ENV'];
77
90
  /**
78
- * Both halves move together. The tenant URL selects the env for content reads
79
- * (each env has its own host); the selectors select it for every service that
80
- * reads `X-Fimo-Env`. Setting one without the other points a checkout at two
81
- * different envs.
91
+ * Both halves move together. The tenant URL selects the Branch for content
92
+ * reads (each Branch has its own host); the selectors select it for every
93
+ * service that reads the Branch header. Setting one without the other points a
94
+ * checkout at two different Branches.
82
95
  */
83
96
  export function buildLocalRuntimeEnv(options) {
84
97
  return {
85
98
  ...Object.fromEntries(LOCAL_CONTENT_API_ENV_KEYS.map((key) => [key, options.tenantApiUrl])),
86
- ...Object.fromEntries(LOCAL_ENV_SELECTOR_KEYS.map((key) => [key, options.env])),
99
+ ...Object.fromEntries(LOCAL_ENV_SELECTOR_KEYS.map((key) => [key, options.branch])),
87
100
  };
88
101
  }
@@ -38,9 +38,9 @@ export declare function resolveLocalRuntimeEnv(options: {
38
38
  readonly cwd: string;
39
39
  }): LocalRuntimeEnv | null;
40
40
  /**
41
- * The one case where "explicit wins" pins the app to the WRONG env: an
41
+ * The one case where "explicit wins" pins the app to the WRONG Branch: an
42
42
  * explicit tenant URL that Fimo itself minted for this project (old-CLI
43
- * `fimo clone` seeded the clone-time env's URL into `.env`) and that disagrees
43
+ * `fimo clone` seeded the clone-time Branch's URL into `.env`) and that disagrees
44
44
  * with the branch. A URL the user typed — `http://localhost:4000` — is never
45
45
  * reported; that is the override the design exists to protect.
46
46
  */
@@ -19,7 +19,7 @@ import { execFileSync } from 'node:child_process';
19
19
  import fs from 'node:fs';
20
20
  import path from 'node:path';
21
21
  import { CURRENT_PROJECT_LAYOUT, LEGACY_PROJECT_LAYOUT } from '../project-layout.js';
22
- import { DEFAULT_ENV, LOCAL_CONTENT_API_ENV_KEYS, buildLocalRuntimeEnv, buildTenantApiUrl, isValidEnv, } from './env-identity.js';
22
+ import { DEFAULT_BRANCH, LOCAL_CONTENT_API_ENV_KEYS, buildLocalRuntimeEnv, buildTenantApiUrl, isValidBranch, } from './branch-identity.js';
23
23
  /**
24
24
  * Derive the local runtime env, or `null` when this directory is not a linked
25
25
  * Fimo project (or the link predates `tenantApiBaseUrl` — nothing safe to
@@ -31,21 +31,23 @@ export function resolveLocalRuntimeEnv(options) {
31
31
  if (!root || !link) {
32
32
  return null;
33
33
  }
34
- const branch = currentBranch(root);
35
- const env = branch ?? DEFAULT_ENV;
36
- const tenantApiUrl = buildTenantApiUrl(link.projectId, env, link.tenantApiBaseUrl);
34
+ const gitBranch = currentBranch(root);
35
+ const branch = gitBranch ?? DEFAULT_BRANCH;
36
+ const tenantApiUrl = buildTenantApiUrl(link.projectId, branch, link.tenantApiBaseUrl);
37
37
  return {
38
- env,
38
+ // `env` stays the field name: `resolveLocalRuntimeEnv` is a published
39
+ // `fimo/config` export that framework adapters destructure.
40
+ env: branch,
39
41
  tenantApiUrl,
40
- source: branch ? 'branch' : 'fallback',
41
- values: buildLocalRuntimeEnv({ tenantApiUrl, env }),
42
+ source: gitBranch ? 'branch' : 'fallback',
43
+ values: buildLocalRuntimeEnv({ tenantApiUrl, branch }),
42
44
  link,
43
45
  };
44
46
  }
45
47
  /**
46
- * The one case where "explicit wins" pins the app to the WRONG env: an
48
+ * The one case where "explicit wins" pins the app to the WRONG Branch: an
47
49
  * explicit tenant URL that Fimo itself minted for this project (old-CLI
48
- * `fimo clone` seeded the clone-time env's URL into `.env`) and that disagrees
50
+ * `fimo clone` seeded the clone-time Branch's URL into `.env`) and that disagrees
49
51
  * with the branch. A URL the user typed — `http://localhost:4000` — is never
50
52
  * reported; that is the override the design exists to protect.
51
53
  */
@@ -128,7 +130,7 @@ function currentBranch(root) {
128
130
  stdio: ['ignore', 'pipe', 'ignore'],
129
131
  encoding: 'utf-8',
130
132
  }).trim();
131
- return branch && branch !== 'HEAD' && isValidEnv(branch) ? branch : null;
133
+ return branch && branch !== 'HEAD' && isValidBranch(branch) ? branch : null;
132
134
  }
133
135
  catch {
134
136
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "2.1.0",
3
+ "version": "2.2.0-staging.1",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "keywords": [
6
6
  "astro-component"
@@ -184,12 +184,12 @@
184
184
  "devDependencies": {
185
185
  "@clack/core": "^1.2.0",
186
186
  "@clack/prompts": "^1.2.0",
187
- "@fimo/agents-bundle": "2.1.0",
188
- "@fimo/api-contracts": "2.1.0",
189
- "@fimo/cli-kit": "2.1.0",
190
- "@fimo/framework-detect": "2.1.0",
191
- "@fimo/routes": "2.1.0",
192
- "@fimo/tsconfig": "2.1.0",
187
+ "@fimo/agents-bundle": "2.2.0-staging.1",
188
+ "@fimo/api-contracts": "2.2.0-staging.1",
189
+ "@fimo/cli-kit": "2.2.0-staging.1",
190
+ "@fimo/framework-detect": "2.2.0-staging.1",
191
+ "@fimo/routes": "2.2.0-staging.1",
192
+ "@fimo/tsconfig": "2.2.0-staging.1",
193
193
  "@types/node": "22.18.6",
194
194
  "agent-install": "^0.0.5",
195
195
  "astro": "^7.1.6",
package/release.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "source": "npm",
3
- "apiUrl": "https://api.fimo.ai",
4
- "webUrl": "https://fimo.ai"
3
+ "apiUrl": "https://api.staging.fimo.team",
4
+ "webUrl": "https://staging.fimo.team"
5
5
  }
@@ -9,8 +9,8 @@
9
9
  "check": "astro sync && astro check"
10
10
  },
11
11
  "dependencies": {
12
- "fimo": "2.1.0",
13
- "fimo-astro": "2.1.0"
12
+ "fimo": "2.2.0-staging.1",
13
+ "fimo-astro": "2.2.0-staging.1"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@astrojs/check": "^0.9.10",
@@ -12,9 +12,9 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@tanstack/react-query": "^5.80.6",
15
- "fimo": "2.1.0",
16
- "fimo-next": "2.1.0",
17
- "fimo-react": "2.1.0",
15
+ "fimo": "2.2.0-staging.1",
16
+ "fimo-next": "2.2.0-staging.1",
17
+ "fimo-react": "2.2.0-staging.1",
18
18
  "next": "^16.3.0",
19
19
  "react": "^19.2.7",
20
20
  "react-dom": "^19.2.7"
@@ -21,10 +21,10 @@
21
21
  "cmdk": "^1.1.1",
22
22
  "date-fns": "^4.1.0",
23
23
  "embla-carousel-react": "^8.6.0",
24
- "fimo": "2.1.0",
25
- "fimo-react": "2.1.0",
26
- "fimo-react-router": "2.1.0",
27
- "fimo-vite": "2.1.0",
24
+ "fimo": "2.2.0-staging.1",
25
+ "fimo-react": "2.2.0-staging.1",
26
+ "fimo-react-router": "2.2.0-staging.1",
27
+ "fimo-vite": "2.2.0-staging.1",
28
28
  "input-otp": "^1.4.2",
29
29
  "isbot": "^5",
30
30
  "lucide-react": "^0.577.0",
@@ -11,8 +11,8 @@
11
11
  "prepare": "svelte-kit sync"
12
12
  },
13
13
  "dependencies": {
14
- "fimo": "2.1.0",
15
- "fimo-sveltekit": "2.1.0"
14
+ "fimo": "2.2.0-staging.1",
15
+ "fimo-sveltekit": "2.2.0-staging.1"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@sveltejs/kit": "^2.70.2",
@@ -11,10 +11,10 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@tanstack/react-query": "^5.80.6",
14
- "fimo": "2.1.0",
15
- "fimo-react": "2.1.0",
16
- "fimo-react-router": "2.1.0",
17
- "fimo-vite": "2.1.0",
14
+ "fimo": "2.2.0-staging.1",
15
+ "fimo-react": "2.2.0-staging.1",
16
+ "fimo-react-router": "2.2.0-staging.1",
17
+ "fimo-vite": "2.2.0-staging.1",
18
18
  "react": "^19.2.7",
19
19
  "react-dom": "^19.2.7",
20
20
  "react-router": "^8.3.0"
@@ -1,43 +0,0 @@
1
- /**
2
- * How a local checkout names and addresses a Fimo env — runtime-safe copy.
3
- *
4
- * TRAP: this looks like a duplicate of `@fimo/api-contracts` and it is, on
5
- * purpose. `dist/runtime/` and `dist/build/` ship UNBUNDLED inside the `fimo`
6
- * npm package and can only import published dependencies; `@fimo/api-contracts`
7
- * is a private workspace package, so a runtime import of it breaks every user
8
- * project (`ERR_MODULE_NOT_FOUND` from `vite.config.ts`). The CLI binary is
9
- * bundled and may import contracts freely — the runtime may not.
10
- *
11
- * The two copies must agree byte-for-byte or a checkout computes a different
12
- * tenant host than the API hands out. `env-identity.test.ts` pins them
13
- * together against a corpus; change one, and that test tells you to change the
14
- * other.
15
- */
16
- export declare const DEFAULT_ENV = "main";
17
- export declare const PROD_ENV_PREFIX = "release/";
18
- /** Mirror of `isValidEnv` in `@fimo/api-contracts`. */
19
- export declare function isValidEnv(env: string): boolean;
20
- /** Mirror of `envResourceKey` in `@fimo/api-contracts`. */
21
- export declare function envResourceKey(env: string): string;
22
- /** Mirror of `buildTenantApiUrl` in `@fimo/api-contracts`. */
23
- export declare function buildTenantApiUrl(projectId: string, env: string, tenantApiBaseUrl: string): string;
24
- /**
25
- * Content-API aliases a local checkout exposes — one per framework family
26
- * that has a Fimo startup hook (Vite/React Router, Next, Astro, SvelteKit).
27
- * Add a key when its framework's hook lands, not before: an alias no runtime
28
- * reads is one more line to reason about when a site talks to the wrong env.
29
- */
30
- export declare const LOCAL_CONTENT_API_ENV_KEYS: readonly ['FIMO_CONTENT_API_URL', 'VITE_API_URL', 'NEXT_PUBLIC_FIMO_API_URL', 'PUBLIC_FIMO_API_URL'];
31
- /** Env selectors a runtime turns into the `X-Fimo-Env` request header. */
32
- export declare const LOCAL_ENV_SELECTOR_KEYS: readonly ['FIMO_ENV', 'NEXT_PUBLIC_FIMO_ENV'];
33
- /**
34
- * Both halves move together. The tenant URL selects the env for content reads
35
- * (each env has its own host); the selectors select it for every service that
36
- * reads `X-Fimo-Env`. Setting one without the other points a checkout at two
37
- * different envs.
38
- */
39
- export declare function buildLocalRuntimeEnv(options: {
40
- readonly tenantApiUrl: string;
41
- readonly env: string;
42
- }): Record<string, string>;
43
- //# sourceMappingURL=env-identity.d.ts.map