fimo 0.11.0 → 0.12.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.
- package/README.md +7 -1
- package/assets/content-templates/hooks-template.eta +8 -8
- package/assets/content-templates/next-client-template.eta +102 -0
- package/assets/content-templates/next-server-template.eta +75 -0
- package/assets/content-templates/types-template.eta +2 -2
- package/assets/skills/fimo-cli/SKILL.md +2 -0
- package/assets/skills/fimo-cli/references/deploy.md +22 -1
- package/assets/skills/fimo-cli/references/preview.md +4 -3
- package/assets/skills/fimo-code/references/setup-plain-vite.md +4 -2
- package/assets/skills/fimo-code/references/setup-react-router.md +4 -2
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +49 -47
- package/dist/runtime/content/client/collection-core.d.ts +37 -0
- package/dist/runtime/content/client/collection-core.js +149 -0
- package/dist/runtime/content/client/createContentClient.d.ts +3 -16
- package/dist/runtime/content/client/createContentClient.js +4 -321
- package/dist/runtime/content/client/createSingletonClient.js +3 -108
- package/dist/runtime/content/client/internal.d.ts +1 -3
- package/dist/runtime/content/client/internal.js +3 -21
- package/dist/runtime/content/client/react-content-client.d.ts +10 -0
- package/dist/runtime/content/client/react-content-client.js +165 -0
- package/dist/runtime/content/client/react-singleton-client.d.ts +7 -0
- package/dist/runtime/content/client/react-singleton-client.js +38 -0
- package/dist/runtime/content/client/runtime.d.ts +8 -0
- package/dist/runtime/content/client/runtime.js +7 -0
- package/dist/runtime/content/client/server-content-client.d.ts +9 -0
- package/dist/runtime/content/client/server-content-client.js +35 -0
- package/dist/runtime/content/client/singleton-core.d.ts +26 -0
- package/dist/runtime/content/client/singleton-core.js +73 -0
- package/dist/runtime/content/client/useQueryLocale.d.ts +1 -1
- package/dist/runtime/content/client/useQueryLocale.js +2 -3
- package/dist/runtime/content/client/vite-runtime.d.ts +3 -0
- package/dist/runtime/content/client/vite-runtime.js +23 -0
- package/dist/runtime/content/index.d.ts +16 -0
- package/dist/runtime/content/index.js +10 -0
- package/dist/runtime/content/serialization.d.ts +22 -0
- package/dist/runtime/content/serialization.js +42 -0
- package/dist/runtime/next/Text.d.ts +10 -0
- package/dist/runtime/next/Text.js +18 -0
- package/dist/runtime/next/client-runtime.d.ts +3 -0
- package/dist/runtime/next/client-runtime.js +20 -0
- package/dist/runtime/next/client.d.ts +16 -0
- package/dist/runtime/next/client.js +15 -0
- package/dist/runtime/next/provider.d.ts +10 -0
- package/dist/runtime/next/provider.js +12 -0
- package/dist/runtime/next/server-runtime.d.ts +3 -0
- package/dist/runtime/next/server-runtime.js +20 -0
- package/dist/runtime/next/server.d.ts +11 -0
- package/dist/runtime/next/server.js +10 -0
- package/dist/runtime/primitives/components/Text.d.ts +1 -2
- package/dist/runtime/primitives/lib/query.d.ts +1 -1
- package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +4 -6
- package/dist/runtime/primitives/lib/useFimoLiveValue.js +4 -10
- package/dist/scripts/sync-schemas.js +67 -16
- package/package.json +14 -1
- package/release.json +2 -2
- package/templates/react-router/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
<!-- npm renders this README from the published tarball, so this URL is frozen into every
|
|
2
|
+
version already on the registry: the object must stay at this exact key forever, and
|
|
3
|
+
nothing in CI catches its removal. It is served from the R2 assets bucket rather than
|
|
4
|
+
fimo.ai on purpose — the marketing site rewrites unmatched paths to index.html, so a
|
|
5
|
+
missing asset there returns 200 with an HTML body instead of a 404, which is how the
|
|
6
|
+
previous logo URL stayed broken without anyone noticing. -->
|
|
1
7
|
<p align="center">
|
|
2
8
|
<a href="https://fimo.ai">
|
|
3
|
-
<img src="https://fimo.ai/
|
|
9
|
+
<img src="https://assets.fimo.ai/brand/fimo-mark-512.png" height="80" alt="Fimo" />
|
|
4
10
|
</a>
|
|
5
11
|
</p>
|
|
6
12
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// AUTO-GENERATED by `fimo` from src/schemas/<%= model.uid %>.json - DO NOT EDIT.
|
|
2
2
|
// Change content fields in the schema, then run `fimo validate`.
|
|
3
|
-
// Runtime implementation lives in the project-local
|
|
3
|
+
// Runtime implementation lives in the project-local <%= runtimeImport %> package export.
|
|
4
4
|
<% if (model.isSingleton) { -%>
|
|
5
|
-
import { createSingletonClient } from "
|
|
6
|
-
import type { SingletonContentClient } from "
|
|
7
|
-
import type { ContentSchema } from "
|
|
5
|
+
import { createSingletonClient } from "<%= runtimeImport %>";
|
|
6
|
+
import type { SingletonContentClient } from "<%= runtimeImport %>";
|
|
7
|
+
import type { ContentSchema } from "<%= runtimeImport %>";
|
|
8
8
|
<% } else { -%>
|
|
9
|
-
import { createContentClient } from "
|
|
10
|
-
import type { CollectionContentClient } from "
|
|
11
|
-
import type { ContentSchema } from "
|
|
9
|
+
import { createContentClient } from "<%= runtimeImport %>";
|
|
10
|
+
import type { CollectionContentClient } from "<%= runtimeImport %>";
|
|
11
|
+
import type { ContentSchema } from "<%= runtimeImport %>";
|
|
12
12
|
<% } -%>
|
|
13
13
|
|
|
14
14
|
import schema from "./<%= model.uid %>.json";
|
|
@@ -29,7 +29,7 @@ import type { <%= model.pascal %>, <%= model.pascal %>Fields, <%= model.pascal %
|
|
|
29
29
|
|
|
30
30
|
export type { <%= model.pascal %>, <%= model.pascal %>Fields, <%= model.pascal %>FimoMeta, <%= model.pascal %>Input, <%= model.pascal %>Populate, <%= model.pascal %>Query, <%= model.pascal %>References, <%= model.pascal %>Result, <%= model.pascal %>Sort, <%= model.pascal %>Where } from "./<%= model.pascal %>.types";
|
|
31
31
|
<% if (!model.isSingleton) { -%>
|
|
32
|
-
export type { CollectionPage, CollectionPageInfo, InfiniteListResult } from "
|
|
32
|
+
export type { CollectionPage, CollectionPageInfo, InfiniteListResult } from "<%= runtimeImport %>";
|
|
33
33
|
export type InfiniteListQuery<
|
|
34
34
|
TFields extends <%= model.pascal %>Fields | undefined = undefined,
|
|
35
35
|
TPopulate extends <%= model.pascal %>Populate | undefined = undefined,
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// AUTO-GENERATED by `fimo` from src/schemas/<%= model.uid %>.json - DO NOT EDIT.
|
|
4
|
+
// Client Components import this module. Server Components import ./<%= model.pascal %> instead.
|
|
5
|
+
<% if (model.isSingleton) { -%>
|
|
6
|
+
import { createSingletonClient } from "<%= runtimeImport %>";
|
|
7
|
+
import type { SingletonContentClient } from "<%= runtimeImport %>";
|
|
8
|
+
import type { ContentSchema } from "<%= runtimeImport %>";
|
|
9
|
+
<% } else { -%>
|
|
10
|
+
import { createContentClient } from "<%= runtimeImport %>";
|
|
11
|
+
import type { CollectionContentClient } from "<%= runtimeImport %>";
|
|
12
|
+
import type { ContentSchema } from "<%= runtimeImport %>";
|
|
13
|
+
<% } -%>
|
|
14
|
+
|
|
15
|
+
import schema from "./<%= model.uid %>.json";
|
|
16
|
+
import type { Serialized<%= model.pascal %> } from "./<%= model.pascal %>";
|
|
17
|
+
<%
|
|
18
|
+
if (model.referenceImports && model.referenceImports.length > 0) {
|
|
19
|
+
model.referenceImports.forEach((referenceImport) => {
|
|
20
|
+
-%>
|
|
21
|
+
import * as <%= referenceImport.pascal %> from "./<%= referenceImport.pascal %>.client";
|
|
22
|
+
<%
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (model.isSingleton) {
|
|
26
|
+
-%>
|
|
27
|
+
import type { <%= model.pascal %>, <%= model.pascal %>Input } from "./<%= model.pascal %>.types";
|
|
28
|
+
<% } else { -%>
|
|
29
|
+
import type { <%= model.pascal %>, <%= model.pascal %>Fields, <%= model.pascal %>Input, <%= model.pascal %>Populate, <%= model.pascal %>Query } from "./<%= model.pascal %>.types";
|
|
30
|
+
<% } -%>
|
|
31
|
+
|
|
32
|
+
export type { <%= model.pascal %>, <%= model.pascal %>Fields, <%= model.pascal %>FimoMeta, <%= model.pascal %>Input, <%= model.pascal %>Populate, <%= model.pascal %>Query, <%= model.pascal %>References, <%= model.pascal %>Result, <%= model.pascal %>Sort, <%= model.pascal %>Where } from "./<%= model.pascal %>.types";
|
|
33
|
+
export type { Serialized<%= model.pascal %> };
|
|
34
|
+
<% if (!model.isSingleton) { -%>
|
|
35
|
+
export type { CollectionPage, CollectionPageInfo, InfiniteListResult } from "<%= runtimeImport %>";
|
|
36
|
+
export type InfiniteListQuery<
|
|
37
|
+
TFields extends <%= model.pascal %>Fields | undefined = undefined,
|
|
38
|
+
TPopulate extends <%= model.pascal %>Populate | undefined = undefined,
|
|
39
|
+
> = Omit<<%= model.pascal %>Query<TFields, TPopulate>, "offset">;
|
|
40
|
+
<% } -%>
|
|
41
|
+
|
|
42
|
+
<% if (model.isSingleton) { -%>
|
|
43
|
+
const client: SingletonContentClient<<%= model.pascal %>, <%= model.pascal %>Input> = createSingletonClient<
|
|
44
|
+
<%= model.pascal %>,
|
|
45
|
+
<%= model.pascal %>Input
|
|
46
|
+
>({
|
|
47
|
+
schema: schema as unknown as ContentSchema,
|
|
48
|
+
<% } else { -%>
|
|
49
|
+
const client: CollectionContentClient<<%= model.pascal %>, <%= model.pascal %>Input> = createContentClient<
|
|
50
|
+
<%= model.pascal %>,
|
|
51
|
+
<%= model.pascal %>Input
|
|
52
|
+
>({
|
|
53
|
+
schema: schema as unknown as ContentSchema,
|
|
54
|
+
<% } -%>
|
|
55
|
+
<% if (model.referenceImports && model.referenceImports.length > 0) { -%>
|
|
56
|
+
references: { <%= model.referenceImports.map((referenceImport) => referenceImport.pascal).join(", ") %> },
|
|
57
|
+
<% } -%>
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
<% if (model.isSingleton) { -%>
|
|
61
|
+
export const { get, update, useGet, useSuspenseGet, useUpdate, wrapWithSource, meta } = client;
|
|
62
|
+
<% } else { -%>
|
|
63
|
+
export const {
|
|
64
|
+
wrapWithSource,
|
|
65
|
+
meta,
|
|
66
|
+
getById,
|
|
67
|
+
getBySlug,
|
|
68
|
+
getByField,
|
|
69
|
+
list,
|
|
70
|
+
get,
|
|
71
|
+
create,
|
|
72
|
+
update,
|
|
73
|
+
remove,
|
|
74
|
+
useGetById,
|
|
75
|
+
useGetBySlug,
|
|
76
|
+
useGetByField,
|
|
77
|
+
useList,
|
|
78
|
+
useInfiniteList,
|
|
79
|
+
useGet,
|
|
80
|
+
useSuspenseGetById,
|
|
81
|
+
useSuspenseGet,
|
|
82
|
+
useSuspenseGetByField,
|
|
83
|
+
useSuspenseGetBySlug,
|
|
84
|
+
useCreate,
|
|
85
|
+
useUpdate,
|
|
86
|
+
useRemove,
|
|
87
|
+
} = client;
|
|
88
|
+
<% } -%>
|
|
89
|
+
|
|
90
|
+
type <%= model.pascal %>Source = Pick<<%= model.pascal %>, "id" | "__fimo">;
|
|
91
|
+
|
|
92
|
+
/** Restore source tracking after content crosses a serialized framework boundary. */
|
|
93
|
+
export function hydrate<TValue extends <%= model.pascal %>Source | readonly <%= model.pascal %>Source[]>(
|
|
94
|
+
value: Serialized<%= model.pascal %><TValue>
|
|
95
|
+
): TValue {
|
|
96
|
+
if (Array.isArray(value)) {
|
|
97
|
+
return value.map((entry) => wrapWithSource(entry)) as unknown as TValue;
|
|
98
|
+
}
|
|
99
|
+
return wrapWithSource(value as unknown as Record<string, unknown>) as unknown as TValue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default client;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// AUTO-GENERATED by `fimo` from src/schemas/<%= model.uid %>.json - DO NOT EDIT.
|
|
2
|
+
// Server Components import this module. Client Components import ./<%= model.pascal %>.client instead.
|
|
3
|
+
<% if (model.isSingleton) { -%>
|
|
4
|
+
import { createSingletonClient, serializeContent } from "<%= runtimeImport %>";
|
|
5
|
+
import type { ContentSchema, SerializedContent, SingletonContentClient } from "<%= runtimeImport %>";
|
|
6
|
+
<% } else { -%>
|
|
7
|
+
import { createContentClient, serializeContent } from "<%= runtimeImport %>";
|
|
8
|
+
import type { CollectionContentClient, ContentSchema, SerializedContent } from "<%= runtimeImport %>";
|
|
9
|
+
<% } -%>
|
|
10
|
+
|
|
11
|
+
import schema from "./<%= model.uid %>.json";
|
|
12
|
+
<%
|
|
13
|
+
if (model.referenceImports && model.referenceImports.length > 0) {
|
|
14
|
+
model.referenceImports.forEach((referenceImport) => {
|
|
15
|
+
-%>
|
|
16
|
+
import * as <%= referenceImport.pascal %> from "./<%= referenceImport.pascal %>";
|
|
17
|
+
<%
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
if (model.isSingleton) {
|
|
21
|
+
-%>
|
|
22
|
+
import type { <%= model.pascal %>, <%= model.pascal %>Input } from "./<%= model.pascal %>.types";
|
|
23
|
+
<% } else { -%>
|
|
24
|
+
import type { <%= model.pascal %>, <%= model.pascal %>Fields, <%= model.pascal %>Input, <%= model.pascal %>Populate, <%= model.pascal %>Query } from "./<%= model.pascal %>.types";
|
|
25
|
+
<% } -%>
|
|
26
|
+
|
|
27
|
+
export type { <%= model.pascal %>, <%= model.pascal %>Fields, <%= model.pascal %>FimoMeta, <%= model.pascal %>Input, <%= model.pascal %>Populate, <%= model.pascal %>Query, <%= model.pascal %>References, <%= model.pascal %>Result, <%= model.pascal %>Sort, <%= model.pascal %>Where } from "./<%= model.pascal %>.types";
|
|
28
|
+
<% if (!model.isSingleton) { -%>
|
|
29
|
+
export type { CollectionPage, CollectionPageInfo } from "<%= runtimeImport %>";
|
|
30
|
+
export type InfiniteListQuery<
|
|
31
|
+
TFields extends <%= model.pascal %>Fields | undefined = undefined,
|
|
32
|
+
TPopulate extends <%= model.pascal %>Populate | undefined = undefined,
|
|
33
|
+
> = Omit<<%= model.pascal %>Query<TFields, TPopulate>, "offset">;
|
|
34
|
+
<% } -%>
|
|
35
|
+
|
|
36
|
+
<% if (model.isSingleton) { -%>
|
|
37
|
+
const client: SingletonContentClient<<%= model.pascal %>, <%= model.pascal %>Input> = createSingletonClient<
|
|
38
|
+
<%= model.pascal %>,
|
|
39
|
+
<%= model.pascal %>Input
|
|
40
|
+
>({
|
|
41
|
+
schema: schema as unknown as ContentSchema,
|
|
42
|
+
<% } else { -%>
|
|
43
|
+
const client: CollectionContentClient<<%= model.pascal %>, <%= model.pascal %>Input> = createContentClient<
|
|
44
|
+
<%= model.pascal %>,
|
|
45
|
+
<%= model.pascal %>Input
|
|
46
|
+
>({
|
|
47
|
+
schema: schema as unknown as ContentSchema,
|
|
48
|
+
<% } -%>
|
|
49
|
+
<% if (model.referenceImports && model.referenceImports.length > 0) { -%>
|
|
50
|
+
references: { <%= model.referenceImports.map((referenceImport) => referenceImport.pascal).join(", ") %> },
|
|
51
|
+
<% } -%>
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
type <%= model.pascal %>Source = Pick<<%= model.pascal %>, "id" | "__fimo">;
|
|
55
|
+
declare const SERIALIZED_CONTENT: unique symbol;
|
|
56
|
+
|
|
57
|
+
/** Plain JSON for passing <%= model.pascal %> content through framework data boundaries. */
|
|
58
|
+
export type Serialized<%= model.pascal %><
|
|
59
|
+
TValue extends <%= model.pascal %>Source | readonly <%= model.pascal %>Source[] = <%= model.pascal %>,
|
|
60
|
+
> = SerializedContent<TValue> & { readonly [SERIALIZED_CONTENT]: TValue };
|
|
61
|
+
|
|
62
|
+
/** Convert one <%= model.pascal %> result, or an array of results, into plain JSON. */
|
|
63
|
+
export function serialize<TValue extends <%= model.pascal %>Source | readonly <%= model.pascal %>Source[]>(
|
|
64
|
+
value: TValue
|
|
65
|
+
): Serialized<%= model.pascal %><TValue> {
|
|
66
|
+
return serializeContent(value) as Serialized<%= model.pascal %><TValue>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
<% if (model.isSingleton) { -%>
|
|
70
|
+
export const { get, update, wrapWithSource, meta } = client;
|
|
71
|
+
<% } else { -%>
|
|
72
|
+
export const { wrapWithSource, meta, getById, getBySlug, getByField, list, get, create, update, remove } = client;
|
|
73
|
+
<% } -%>
|
|
74
|
+
|
|
75
|
+
export default client;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
%>
|
|
11
11
|
// AUTO-GENERATED ⚠️ – do not edit by hand
|
|
12
|
-
import { type Fields, type FimoBoolean, type FimoMedia, type FimoPolymorphicReference, type FimoReference, type FimoRichText, type FimoRichTextContent, type FimoString, type Populate, type PopulatedResult, type ProjectedWithPopulate, type Query, type Sort, type Where, type WithReferences } from "
|
|
12
|
+
import { type Fields, type FimoBoolean, type FimoMedia, type FimoPolymorphicReference, type FimoReference, type FimoRichText, type FimoRichTextContent, type FimoString, type Populate, type PopulatedResult, type ProjectedWithPopulate, type Query, type Sort, type Where, type WithReferences } from "<%= runtimeImport %>";
|
|
13
13
|
<%
|
|
14
14
|
if (model.referenceImports && model.referenceImports.length > 0) {
|
|
15
15
|
model.referenceImports.forEach((referenceImport) => {
|
|
@@ -28,7 +28,7 @@ import type { <%= referenceImport.pascal %> } from "./<%= referenceImport.pascal
|
|
|
28
28
|
* <%= model.pascal %> entity interface
|
|
29
29
|
*/
|
|
30
30
|
export interface <%= model.pascal %>FimoMeta {
|
|
31
|
-
contentType:
|
|
31
|
+
contentType: "<%= model.uid %>";
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export interface <%= model.pascal %> extends WithReferences<<%= model.pascal %>References> {
|
|
@@ -44,6 +44,8 @@ Branch on `error.code`, never on `error.message`. The envelope shape is versione
|
|
|
44
44
|
|
|
45
45
|
For shell composition use plain pretty mode (`cd $(fimo …)`); for structured parsing use `--json`. JSON mode disables interactive prompts — commands that need a confirmation will fail fast with `NON_INTERACTIVE_REFUSAL` unless every required arg is on the command line (`--yes`, `--org`, etc.).
|
|
46
46
|
|
|
47
|
+
Pretty output may hide URLs behind clickable labels. Agents should use `--json` and read `data`.
|
|
48
|
+
|
|
47
49
|
## Critical: `.fimo/project.json` is the project link
|
|
48
50
|
|
|
49
51
|
A Fimo project is identified by `.fimo/project.json`, written by `fimo init`. This file connects the local directory to the remote Fimo project. **Never edit it manually.** Most CLI commands find it by walking up from the cwd.
|
|
@@ -19,11 +19,30 @@ fimo deploy --no-restart # skip dev-server restart (HMR-safe
|
|
|
19
19
|
fimo deploy -m "<commit message>" --publish # also publish a new live version
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
- **`fimo deploy`** — commits pending changes, pushes to the current env's branch, syncs that env's preview sandbox,
|
|
22
|
+
- **`fimo deploy`** — commits pending changes, pushes to the current env's branch, syncs that env's preview sandbox, and links to the Preview and Fimo dashboard.
|
|
23
23
|
- **`fimo deploy --publish`** — same as above, then triggers a live publish and prints the live URL. Runs from `main` only. **Only use `--publish` when the user signals "ship it"** — first-time site completion, or an explicit "publish" / "go live" request. Otherwise stick to plain `fimo deploy`. (For a _versioned_ prod release, use `fimo publish` instead — see below.)
|
|
24
24
|
- **`-m`** is the commit message used when there are uncommitted local changes; required in non-interactive shells. Omit if the working tree is already clean.
|
|
25
25
|
- **`--no-restart`** — tells the sandbox to skip the dev-server restart and let Vite HMR pick up the change. Shaves ~3s per deploy. See "Skipping the dev-server restart" below for when it's safe.
|
|
26
26
|
|
|
27
|
+
## Reading deploy destinations
|
|
28
|
+
|
|
29
|
+
Interactive output uses named links. Agents and scripts should request JSON:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
fimo deploy -m "<commit message>" --json
|
|
33
|
+
fimo deploy -m "<commit message>" --publish --json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Read these fields from `data`:
|
|
37
|
+
|
|
38
|
+
| Field | Destination |
|
|
39
|
+
| --------------- | ----------------------------------------------------------- |
|
|
40
|
+
| `preview_url` | Shareable preview. Its token expires, so do not persist it. |
|
|
41
|
+
| `dashboard_url` | Stable, authenticated Fimo project and environment page. |
|
|
42
|
+
| `app_url` | Public live site, returned after a successful `--publish`. |
|
|
43
|
+
|
|
44
|
+
When reporting the result, present the raw values as named Markdown links. If no code changed and you only need fresh destinations, use `fimo preview url --json` instead of deploying again.
|
|
45
|
+
|
|
27
46
|
Public project variables managed with `fimo vars add` and `fimo vars update` are injected into preview/build/deploy environments. Project secrets are not injected into app builds; agents request secrets separately through their own config. See `references/project-vars-and-secrets.md`.
|
|
28
47
|
|
|
29
48
|
## Warm the sandbox early in a session (optional)
|
|
@@ -61,6 +80,8 @@ There's nothing special about this — it's the same `fimo deploy` you'd run lat
|
|
|
61
80
|
|
|
62
81
|
**When in doubt, omit the flag.** The default (restart) is the safe choice — a wasted restart costs 3 seconds; a missing one costs the user serving stale code until they notice and re-deploy.
|
|
63
82
|
|
|
83
|
+
**One case is handled for you:** if the deploy changes the project's route set (a page added, removed, or moved), the API tells the preview to reload regardless of this flag. A router builds its route table once per document, so the new page would otherwise exist but be unreachable — missing from the Studio route selector and 404-ing from the site's own links. This costs a page load, not a restart.
|
|
84
|
+
|
|
64
85
|
## Publishing: `fimo deploy --publish` vs `fimo publish`
|
|
65
86
|
|
|
66
87
|
Two different "go live" mechanisms — pick deliberately:
|
|
@@ -14,24 +14,25 @@ fimo --env feat/redesign preview url # URL for a specific env
|
|
|
14
14
|
fimo preview url --env main --json # structured output for agents / scripts
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
- **
|
|
17
|
+
- **Interactive mode** shows named Preview and Fimo links. When piped, it prints only the raw preview URL, so `fimo preview url | xargs open` and `curl "$(fimo preview url)"` keep working.
|
|
18
18
|
- **JSON mode** (or `FIMO_OUTPUT=json`) emits the standard envelope:
|
|
19
19
|
|
|
20
20
|
```json
|
|
21
21
|
{
|
|
22
22
|
"schema_version": 1,
|
|
23
23
|
"command": "preview url",
|
|
24
|
-
"
|
|
24
|
+
"status": "ok",
|
|
25
25
|
"data": {
|
|
26
26
|
"project_id": "prj_abc",
|
|
27
27
|
"env": "main",
|
|
28
28
|
"preview_url": "https://...",
|
|
29
|
+
"dashboard_url": "https://fimo.ai/app/projects/prj_abc/env/main/preview",
|
|
29
30
|
"expires_at": "2026-06-02T18:42:00.000Z"
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
`expires_at` is the token's hard deadline. If you're caching the URL for more than ~10 minutes, re-run the command.
|
|
35
|
+
Agents should read `data.preview_url` or `data.dashboard_url`, never parse the human output. The dashboard URL is stable; `expires_at` is the preview token's hard deadline. If you're caching the preview URL for more than ~10 minutes, re-run the command.
|
|
35
36
|
|
|
36
37
|
## When to use it
|
|
37
38
|
|
|
@@ -129,12 +129,14 @@ can omit it.
|
|
|
129
129
|
## File: `src/App.tsx`
|
|
130
130
|
|
|
131
131
|
```tsx
|
|
132
|
-
import { Text } from 'fimo/ui';
|
|
132
|
+
import { Text, useLabels } from 'fimo/ui';
|
|
133
133
|
|
|
134
134
|
export function App() {
|
|
135
|
+
const { t } = useLabels();
|
|
136
|
+
|
|
135
137
|
return (
|
|
136
138
|
<main>
|
|
137
|
-
<Text
|
|
139
|
+
<Text value={t('home.hero.title')} as="h1" />
|
|
138
140
|
</main>
|
|
139
141
|
);
|
|
140
142
|
}
|
|
@@ -171,12 +171,14 @@ Page filenames are your choice; the scaffold uses PascalCase (e.g. `Index.tsx`,
|
|
|
171
171
|
## File: `src/pages/Index.tsx`
|
|
172
172
|
|
|
173
173
|
```tsx
|
|
174
|
-
import { Text } from 'fimo/ui';
|
|
174
|
+
import { Text, useLabels } from 'fimo/ui';
|
|
175
175
|
|
|
176
176
|
export default function HomePage() {
|
|
177
|
+
const { t } = useLabels();
|
|
178
|
+
|
|
177
179
|
return (
|
|
178
180
|
<main>
|
|
179
|
-
<Text
|
|
181
|
+
<Text value={t('home.hero.title')} as="h1" />
|
|
180
182
|
</main>
|
|
181
183
|
);
|
|
182
184
|
}
|