@contentrain/skills 0.1.0
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/LICENSE +21 -0
- package/README.md +102 -0
- package/dist/index.cjs +35 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +13 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +35 -0
- package/dist/index.mjs.map +1 -0
- package/frameworks/astro.md +334 -0
- package/frameworks/expo.md +66 -0
- package/frameworks/next.md +296 -0
- package/frameworks/node.md +63 -0
- package/frameworks/nuxt.md +274 -0
- package/frameworks/react-native.md +80 -0
- package/frameworks/react.md +71 -0
- package/frameworks/sveltekit.md +324 -0
- package/frameworks/vue.md +76 -0
- package/package.json +62 -0
- package/workflows/contentrain-bulk.md +92 -0
- package/workflows/contentrain-content.md +154 -0
- package/workflows/contentrain-diff.md +55 -0
- package/workflows/contentrain-doctor.md +55 -0
- package/workflows/contentrain-generate.md +352 -0
- package/workflows/contentrain-init.md +91 -0
- package/workflows/contentrain-model.md +134 -0
- package/workflows/contentrain-normalize.md +294 -0
- package/workflows/contentrain-review.md +162 -0
- package/workflows/contentrain-serve.md +88 -0
- package/workflows/contentrain-translate.md +172 -0
- package/workflows/contentrain-validate-fix.md +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Contentrain
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# `@contentrain/skills`
|
|
2
|
+
|
|
3
|
+
Workflow skills and framework guides for Contentrain-aware AI agents.
|
|
4
|
+
|
|
5
|
+
This package is the procedural layer of the Contentrain ecosystem. It tells an agent how to apply the policy from `@contentrain/rules` in concrete tasks such as:
|
|
6
|
+
|
|
7
|
+
- initializing a project
|
|
8
|
+
- creating content
|
|
9
|
+
- running normalize
|
|
10
|
+
- reviewing and submitting changes
|
|
11
|
+
- generating the SDK client
|
|
12
|
+
- translating content
|
|
13
|
+
|
|
14
|
+
If `@contentrain/rules` defines constraints, `@contentrain/skills` defines execution playbooks.
|
|
15
|
+
|
|
16
|
+
## ๐ Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add @contentrain/skills
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## ๐ฆ What It Contains
|
|
23
|
+
|
|
24
|
+
### Workflow skills
|
|
25
|
+
|
|
26
|
+
Published under `workflows/*`:
|
|
27
|
+
|
|
28
|
+
- `contentrain-init.md`
|
|
29
|
+
- `contentrain-model.md`
|
|
30
|
+
- `contentrain-content.md`
|
|
31
|
+
- `contentrain-bulk.md`
|
|
32
|
+
- `contentrain-normalize.md`
|
|
33
|
+
- `contentrain-validate-fix.md`
|
|
34
|
+
- `contentrain-review.md`
|
|
35
|
+
- `contentrain-diff.md`
|
|
36
|
+
- `contentrain-doctor.md`
|
|
37
|
+
- `contentrain-serve.md`
|
|
38
|
+
- `contentrain-translate.md`
|
|
39
|
+
- `contentrain-generate.md`
|
|
40
|
+
|
|
41
|
+
### Framework guides
|
|
42
|
+
|
|
43
|
+
Published under `frameworks/*`:
|
|
44
|
+
|
|
45
|
+
- `nuxt.md`
|
|
46
|
+
- `next.md`
|
|
47
|
+
- `astro.md`
|
|
48
|
+
- `sveltekit.md`
|
|
49
|
+
- `vue.md`
|
|
50
|
+
- `react.md`
|
|
51
|
+
- `expo.md`
|
|
52
|
+
- `react-native.md`
|
|
53
|
+
- `node.md`
|
|
54
|
+
|
|
55
|
+
## ๐งฐ Public Exports
|
|
56
|
+
|
|
57
|
+
The package root exports:
|
|
58
|
+
|
|
59
|
+
- `WORKFLOW_SKILLS`
|
|
60
|
+
- `FRAMEWORK_GUIDES`
|
|
61
|
+
|
|
62
|
+
## ๐งช Example
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { WORKFLOW_SKILLS, FRAMEWORK_GUIDES } from '@contentrain/skills'
|
|
66
|
+
|
|
67
|
+
console.log(WORKFLOW_SKILLS)
|
|
68
|
+
console.log(FRAMEWORK_GUIDES.includes('next'))
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## ๐ง Design Role
|
|
72
|
+
|
|
73
|
+
`@contentrain/skills` is for step-by-step execution guidance:
|
|
74
|
+
|
|
75
|
+
- `skills` = procedures and operational playbooks
|
|
76
|
+
- `rules` = policy and non-negotiable constraints
|
|
77
|
+
|
|
78
|
+
In practice:
|
|
79
|
+
|
|
80
|
+
- use `@contentrain/rules` to understand what is allowed
|
|
81
|
+
- use `@contentrain/skills` to decide which workflow to run next
|
|
82
|
+
|
|
83
|
+
## ๐ Relationship To Other Packages
|
|
84
|
+
|
|
85
|
+
- `@contentrain/mcp` provides the actual tool surface
|
|
86
|
+
- `@contentrain/rules` defines policy and quality constraints
|
|
87
|
+
- `contentrain` exposes CLI and serve workflows
|
|
88
|
+
- `@contentrain/query` provides the generated content runtime
|
|
89
|
+
|
|
90
|
+
## ๐ Build
|
|
91
|
+
|
|
92
|
+
From the monorepo root:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pnpm --filter @contentrain/skills build
|
|
96
|
+
pnpm --filter @contentrain/skills test
|
|
97
|
+
pnpm --filter @contentrain/skills typecheck
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## ๐ License
|
|
101
|
+
|
|
102
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* @contentrain/skills โ AI agent skills for Contentrain
|
|
5
|
+
*
|
|
6
|
+
* Step-by-step workflow procedures and framework integration guides.
|
|
7
|
+
*/
|
|
8
|
+
const WORKFLOW_SKILLS = [
|
|
9
|
+
"contentrain-init",
|
|
10
|
+
"contentrain-model",
|
|
11
|
+
"contentrain-content",
|
|
12
|
+
"contentrain-bulk",
|
|
13
|
+
"contentrain-normalize",
|
|
14
|
+
"contentrain-validate-fix",
|
|
15
|
+
"contentrain-review",
|
|
16
|
+
"contentrain-diff",
|
|
17
|
+
"contentrain-doctor",
|
|
18
|
+
"contentrain-serve",
|
|
19
|
+
"contentrain-translate",
|
|
20
|
+
"contentrain-generate"
|
|
21
|
+
];
|
|
22
|
+
const FRAMEWORK_GUIDES = [
|
|
23
|
+
"nuxt",
|
|
24
|
+
"next",
|
|
25
|
+
"astro",
|
|
26
|
+
"sveltekit",
|
|
27
|
+
"vue",
|
|
28
|
+
"react",
|
|
29
|
+
"expo",
|
|
30
|
+
"react-native",
|
|
31
|
+
"node"
|
|
32
|
+
];
|
|
33
|
+
//#endregion
|
|
34
|
+
exports.FRAMEWORK_GUIDES = FRAMEWORK_GUIDES;
|
|
35
|
+
exports.WORKFLOW_SKILLS = WORKFLOW_SKILLS;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* @contentrain/skills โ AI agent skills for Contentrain
|
|
4
|
+
*
|
|
5
|
+
* Step-by-step workflow procedures and framework integration guides.
|
|
6
|
+
*/
|
|
7
|
+
declare const WORKFLOW_SKILLS: readonly ["contentrain-init", "contentrain-model", "contentrain-content", "contentrain-bulk", "contentrain-normalize", "contentrain-validate-fix", "contentrain-review", "contentrain-diff", "contentrain-doctor", "contentrain-serve", "contentrain-translate", "contentrain-generate"];
|
|
8
|
+
type WorkflowSkill = (typeof WORKFLOW_SKILLS)[number];
|
|
9
|
+
declare const FRAMEWORK_GUIDES: readonly ["nuxt", "next", "astro", "sveltekit", "vue", "react", "expo", "react-native", "node"];
|
|
10
|
+
type FrameworkGuide = (typeof FRAMEWORK_GUIDES)[number];
|
|
11
|
+
//#endregion
|
|
12
|
+
export { FRAMEWORK_GUIDES, FrameworkGuide, WORKFLOW_SKILLS, WorkflowSkill };
|
|
13
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;AAQA;;;;cAAa,eAAA;AAAA,KAeD,aAAA,WAAwB,eAAA;AAAA,cAIvB,gBAAA;AAAA,KACD,cAAA,WAAyB,gBAAA"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* @contentrain/skills โ AI agent skills for Contentrain
|
|
4
|
+
*
|
|
5
|
+
* Step-by-step workflow procedures and framework integration guides.
|
|
6
|
+
*/
|
|
7
|
+
declare const WORKFLOW_SKILLS: readonly ["contentrain-init", "contentrain-model", "contentrain-content", "contentrain-bulk", "contentrain-normalize", "contentrain-validate-fix", "contentrain-review", "contentrain-diff", "contentrain-doctor", "contentrain-serve", "contentrain-translate", "contentrain-generate"];
|
|
8
|
+
type WorkflowSkill = (typeof WORKFLOW_SKILLS)[number];
|
|
9
|
+
declare const FRAMEWORK_GUIDES: readonly ["nuxt", "next", "astro", "sveltekit", "vue", "react", "expo", "react-native", "node"];
|
|
10
|
+
type FrameworkGuide = (typeof FRAMEWORK_GUIDES)[number];
|
|
11
|
+
//#endregion
|
|
12
|
+
export { FRAMEWORK_GUIDES, FrameworkGuide, WORKFLOW_SKILLS, WorkflowSkill };
|
|
13
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;AAQA;;;;cAAa,eAAA;AAAA,KAeD,aAAA,WAAwB,eAAA;AAAA,cAIvB,gBAAA;AAAA,KACD,cAAA,WAAyB,gBAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* @contentrain/skills โ AI agent skills for Contentrain
|
|
4
|
+
*
|
|
5
|
+
* Step-by-step workflow procedures and framework integration guides.
|
|
6
|
+
*/
|
|
7
|
+
const WORKFLOW_SKILLS = [
|
|
8
|
+
"contentrain-init",
|
|
9
|
+
"contentrain-model",
|
|
10
|
+
"contentrain-content",
|
|
11
|
+
"contentrain-bulk",
|
|
12
|
+
"contentrain-normalize",
|
|
13
|
+
"contentrain-validate-fix",
|
|
14
|
+
"contentrain-review",
|
|
15
|
+
"contentrain-diff",
|
|
16
|
+
"contentrain-doctor",
|
|
17
|
+
"contentrain-serve",
|
|
18
|
+
"contentrain-translate",
|
|
19
|
+
"contentrain-generate"
|
|
20
|
+
];
|
|
21
|
+
const FRAMEWORK_GUIDES = [
|
|
22
|
+
"nuxt",
|
|
23
|
+
"next",
|
|
24
|
+
"astro",
|
|
25
|
+
"sveltekit",
|
|
26
|
+
"vue",
|
|
27
|
+
"react",
|
|
28
|
+
"expo",
|
|
29
|
+
"react-native",
|
|
30
|
+
"node"
|
|
31
|
+
];
|
|
32
|
+
//#endregion
|
|
33
|
+
export { FRAMEWORK_GUIDES, WORKFLOW_SKILLS };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @contentrain/skills โ AI agent skills for Contentrain\n *\n * Step-by-step workflow procedures and framework integration guides.\n */\n\n// โโโ Workflow Skills โโโ\n\nexport const WORKFLOW_SKILLS = [\n 'contentrain-init',\n 'contentrain-model',\n 'contentrain-content',\n 'contentrain-bulk',\n 'contentrain-normalize',\n 'contentrain-validate-fix',\n 'contentrain-review',\n 'contentrain-diff',\n 'contentrain-doctor',\n 'contentrain-serve',\n 'contentrain-translate',\n 'contentrain-generate',\n] as const\n\nexport type WorkflowSkill = (typeof WORKFLOW_SKILLS)[number]\n\n// โโโ Framework Guides โโโ\n\nexport const FRAMEWORK_GUIDES = ['nuxt', 'next', 'astro', 'sveltekit', 'vue', 'react', 'expo', 'react-native', 'node'] as const\nexport type FrameworkGuide = (typeof FRAMEWORK_GUIDES)[number]\n"],"mappings":";;;;;;AAQA,MAAa,kBAAkB;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAMD,MAAa,mBAAmB;CAAC;CAAQ;CAAQ;CAAS;CAAa;CAAO;CAAS;CAAQ;CAAgB;CAAO"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# Contentrain + Astro
|
|
2
|
+
|
|
3
|
+
> Framework guide for consuming Contentrain-managed content in Astro projects.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Setup
|
|
8
|
+
|
|
9
|
+
### 1.1 SDK Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @contentrain/query # or npm/yarn
|
|
13
|
+
npx contentrain generate
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The generator reads `.contentrain/models/` and produces a typed client in `.contentrain/client/`. Your `package.json` must include the subpath import:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"imports": {
|
|
21
|
+
"#contentrain": {
|
|
22
|
+
"types": "./.contentrain/client/index.d.ts",
|
|
23
|
+
"import": "./.contentrain/client/index.mjs",
|
|
24
|
+
"require": "./.contentrain/client/index.cjs",
|
|
25
|
+
"default": "./.contentrain/client/index.mjs"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The generator adds this automatically. Restart the Astro dev server after initial generation.
|
|
32
|
+
|
|
33
|
+
### 1.2 Watch Mode
|
|
34
|
+
|
|
35
|
+
Run the generator alongside Astro dev:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx contentrain generate --watch &
|
|
39
|
+
npx astro dev
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 2. Imports
|
|
45
|
+
|
|
46
|
+
All SDK functions are imported from the `#contentrain` subpath:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { query, singleton, dictionary, document } from '#contentrain'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This import works in `.astro` component frontmatter, API routes, and any server-side script. The SDK reads JSON files from the file system โ no runtime API calls.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 3. Querying Content
|
|
57
|
+
|
|
58
|
+
### 3.1 Collections
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
const posts = query('blog-post').locale('en').all()
|
|
62
|
+
const featured = query('blog-post').locale('en').where('featured', true).all()
|
|
63
|
+
const sorted = query('blog-post').locale('en').sort('publishedAt', 'desc').all()
|
|
64
|
+
const post = query('blog-post').locale('en').where('id', 'abc-123').first()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3.2 Singletons
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const hero = singleton('hero').locale('en').get()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 3.3 Dictionaries
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const label = dictionary('ui-labels').locale('en').get('submit_button')
|
|
77
|
+
const allLabels = dictionary('ui-labels').locale('en').get()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3.4 Documents
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const article = document('blog-article').locale('en').bySlug('getting-started')
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 3.5 Relations
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const posts = query('blog-post').locale('en').include('author', 'tags').all()
|
|
90
|
+
// post.author โ full author object
|
|
91
|
+
// post.tags โ array of full tag objects
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 4. Astro Integration Patterns
|
|
97
|
+
|
|
98
|
+
### 4.1 Page Components
|
|
99
|
+
|
|
100
|
+
SDK calls go in the frontmatter (the `---` fenced section):
|
|
101
|
+
|
|
102
|
+
```astro
|
|
103
|
+
---
|
|
104
|
+
import { query } from '#contentrain'
|
|
105
|
+
|
|
106
|
+
const posts = query('blog-post').locale('en').sort('publishedAt', 'desc').all()
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
<ul>
|
|
110
|
+
{posts.map(post => (
|
|
111
|
+
<li><a href={`/blog/${post.slug}`}>{post.title}</a></li>
|
|
112
|
+
))}
|
|
113
|
+
</ul>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 4.2 Dynamic Routes
|
|
117
|
+
|
|
118
|
+
For `src/pages/blog/[slug].astro`:
|
|
119
|
+
|
|
120
|
+
```astro
|
|
121
|
+
---
|
|
122
|
+
import { query, document } from '#contentrain'
|
|
123
|
+
|
|
124
|
+
export function getStaticPaths() {
|
|
125
|
+
const posts = query('blog-post').locale('en').all()
|
|
126
|
+
return posts.map(post => ({
|
|
127
|
+
params: { slug: post.slug },
|
|
128
|
+
props: { post }
|
|
129
|
+
}))
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const { post } = Astro.props
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
<article>
|
|
136
|
+
<h1>{post.title}</h1>
|
|
137
|
+
</article>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 4.3 Layout Data
|
|
141
|
+
|
|
142
|
+
Provide global content (navigation, footer) from layouts:
|
|
143
|
+
|
|
144
|
+
```astro
|
|
145
|
+
---
|
|
146
|
+
import { singleton, dictionary } from '#contentrain'
|
|
147
|
+
|
|
148
|
+
const nav = singleton('navigation').locale('en').get()
|
|
149
|
+
const footerLabels = dictionary('footer-labels').locale('en').get()
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
<nav>
|
|
153
|
+
{nav.items.map(item => <a href={item.url}>{item.label}</a>)}
|
|
154
|
+
</nav>
|
|
155
|
+
<slot />
|
|
156
|
+
<footer>
|
|
157
|
+
<!-- footer content -->
|
|
158
|
+
</footer>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 5. i18n Integration
|
|
164
|
+
|
|
165
|
+
### 5.1 Astro Built-in i18n
|
|
166
|
+
|
|
167
|
+
Astro provides built-in i18n routing. Combine it with Contentrain locale support:
|
|
168
|
+
|
|
169
|
+
```astro
|
|
170
|
+
---
|
|
171
|
+
// src/pages/[locale]/blog/[slug].astro
|
|
172
|
+
import { document } from '#contentrain'
|
|
173
|
+
|
|
174
|
+
export function getStaticPaths() {
|
|
175
|
+
const locales = ['en', 'tr', 'de']
|
|
176
|
+
const paths = []
|
|
177
|
+
for (const locale of locales) {
|
|
178
|
+
const posts = document('blog-article').locale(locale).all()
|
|
179
|
+
for (const post of posts) {
|
|
180
|
+
paths.push({
|
|
181
|
+
params: { locale, slug: post.slug },
|
|
182
|
+
props: { post, locale }
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return paths
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const { post } = Astro.props
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
<article>
|
|
193
|
+
<h1>{post.title}</h1>
|
|
194
|
+
</article>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 5.2 Current Locale Access
|
|
198
|
+
|
|
199
|
+
Use `Astro.currentLocale` (available when i18n is configured in `astro.config.mjs`) to pass the locale to SDK calls:
|
|
200
|
+
|
|
201
|
+
```astro
|
|
202
|
+
---
|
|
203
|
+
import { query } from '#contentrain'
|
|
204
|
+
|
|
205
|
+
const locale = Astro.currentLocale ?? 'en'
|
|
206
|
+
const posts = query('blog-post').locale(locale).all()
|
|
207
|
+
---
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 5.3 Dictionary Strings
|
|
211
|
+
|
|
212
|
+
Contentrain dictionaries can serve as the translation source for UI strings:
|
|
213
|
+
|
|
214
|
+
```astro
|
|
215
|
+
---
|
|
216
|
+
import { dictionary } from '#contentrain'
|
|
217
|
+
|
|
218
|
+
const locale = Astro.currentLocale ?? 'en'
|
|
219
|
+
const t = dictionary('ui-labels').locale(locale).get()
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
<button>{t.submit_button}</button>
|
|
223
|
+
<p>{t.welcome_message}</p>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 6. Content Collections Integration
|
|
229
|
+
|
|
230
|
+
### 6.1 Astro Content Collections
|
|
231
|
+
|
|
232
|
+
Astro's content collections can coexist with Contentrain. Define a collection that points to `.contentrain/content/`:
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
// src/content/config.ts
|
|
236
|
+
import { defineCollection, z } from 'astro:content'
|
|
237
|
+
|
|
238
|
+
const blog = defineCollection({
|
|
239
|
+
type: 'content',
|
|
240
|
+
schema: z.object({
|
|
241
|
+
title: z.string(),
|
|
242
|
+
description: z.string(),
|
|
243
|
+
publishedAt: z.string()
|
|
244
|
+
})
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
export const collections = { blog }
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Symlink or copy `.contentrain/content/blog/` to `src/content/blog/` if using Astro's content layer, or use the SDK directly for simpler setups.
|
|
251
|
+
|
|
252
|
+
### 6.2 Markdown Rendering
|
|
253
|
+
|
|
254
|
+
For document-kind entries with markdown bodies, render them using Astro's built-in markdown support or a markdown component:
|
|
255
|
+
|
|
256
|
+
```astro
|
|
257
|
+
---
|
|
258
|
+
import { document } from '#contentrain'
|
|
259
|
+
|
|
260
|
+
const article = document('blog-article').locale('en').bySlug('getting-started')
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
<article>
|
|
264
|
+
<h1>{article.title}</h1>
|
|
265
|
+
<Fragment set:html={article.bodyHtml} />
|
|
266
|
+
</article>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## 7. Islands Architecture
|
|
272
|
+
|
|
273
|
+
### 7.1 Static Parent, Dynamic Child
|
|
274
|
+
|
|
275
|
+
Content data is fetched in the static Astro component and passed to interactive island components as props:
|
|
276
|
+
|
|
277
|
+
```astro
|
|
278
|
+
---
|
|
279
|
+
import { query } from '#contentrain'
|
|
280
|
+
import SearchWidget from '../components/SearchWidget.tsx'
|
|
281
|
+
|
|
282
|
+
const posts = query('blog-post').locale('en').all()
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
<!-- Static content -->
|
|
286
|
+
<h1>Blog</h1>
|
|
287
|
+
|
|
288
|
+
<!-- Interactive island with content data -->
|
|
289
|
+
<SearchWidget client:load posts={posts} />
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The content is embedded in the static HTML. The island component receives it as serialized props โ no client-side data fetching required.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## 8. Build and Deployment
|
|
297
|
+
|
|
298
|
+
### 8.1 Static Output (Default)
|
|
299
|
+
|
|
300
|
+
Astro builds static HTML by default. All SDK calls resolve at build time:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
npx astro build
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Output goes to `dist/`. Content is baked into the HTML โ zero runtime dependencies.
|
|
307
|
+
|
|
308
|
+
### 8.2 SSR Mode
|
|
309
|
+
|
|
310
|
+
With SSR enabled (`output: 'server'` or `output: 'hybrid'` in `astro.config.mjs`), SDK calls execute on the server at request time. Content is still file-based.
|
|
311
|
+
|
|
312
|
+
### 8.3 Deployment Flow
|
|
313
|
+
|
|
314
|
+
1. Content changes are committed to Git via MCP tools.
|
|
315
|
+
2. Push triggers platform rebuild (Vercel, Netlify, Cloudflare Pages).
|
|
316
|
+
3. `astro build` runs, SDK reads `.contentrain/` content.
|
|
317
|
+
4. Static pages are generated with embedded content.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## 9. Type Safety
|
|
322
|
+
|
|
323
|
+
The generated client provides full TypeScript types:
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import { query } from '#contentrain'
|
|
327
|
+
|
|
328
|
+
// Fully typed โ autocomplete for all fields
|
|
329
|
+
const posts = query('blog-post').locale('en').all()
|
|
330
|
+
posts[0].title // string
|
|
331
|
+
posts[0].author // Author type when using .include('author')
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Keep the generator running in watch mode during development to stay in sync with model changes.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Contentrain + Expo / React Native
|
|
2
|
+
|
|
3
|
+
> Framework guide for Metro-style consumers of the generated Contentrain client.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @contentrain/query
|
|
11
|
+
npx contentrain generate
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The generated client exposes a CommonJS bootstrap path for Metro-like consumers.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 2. Bootstrap Pattern
|
|
19
|
+
|
|
20
|
+
Use the CJS wrapper and initialize it once:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// app/content.ts
|
|
24
|
+
let clientPromise: Promise<any> | null = null
|
|
25
|
+
|
|
26
|
+
export function getContentrainClient() {
|
|
27
|
+
if (!clientPromise) {
|
|
28
|
+
clientPromise = require('#contentrain').init()
|
|
29
|
+
}
|
|
30
|
+
return clientPromise
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then use it from app code:
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { useEffect, useState } from 'react'
|
|
38
|
+
import { Text, View } from 'react-native'
|
|
39
|
+
import { getContentrainClient } from './content'
|
|
40
|
+
|
|
41
|
+
export function HomeScreen() {
|
|
42
|
+
const [title, setTitle] = useState('')
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
getContentrainClient().then((client) => {
|
|
46
|
+
setTitle(client.singleton('hero').locale('en').get().title)
|
|
47
|
+
})
|
|
48
|
+
}, [])
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<View>
|
|
52
|
+
<Text>{title}</Text>
|
|
53
|
+
</View>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 3. Rules
|
|
61
|
+
|
|
62
|
+
- use `require('#contentrain').init()` for the bootstrap
|
|
63
|
+
- cache the promise; do not initialize on every render
|
|
64
|
+
- treat the client as read-only generated data
|
|
65
|
+
- re-run `contentrain generate` after content/model changes
|
|
66
|
+
|