@asteroidcms/core-utils 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 +70 -0
- package/README.md +327 -0
- package/dist/index.cjs +1470 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +266 -0
- package/dist/index.d.ts +266 -0
- package/dist/index.js +1455 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Asteroid CMS Core Utils — Proprietary License
|
|
2
|
+
Copyright (c) 2026 Asteroid. All rights reserved.
|
|
3
|
+
|
|
4
|
+
This software and its associated source code, documentation, type
|
|
5
|
+
definitions, build artifacts, and any accompanying files (collectively,
|
|
6
|
+
the "Software") are the exclusive intellectual property of Asteroid
|
|
7
|
+
("Licensor"). The Software is licensed, not sold.
|
|
8
|
+
|
|
9
|
+
1. Grant of License
|
|
10
|
+
Subject to the terms below, Licensor grants you ("Licensee") a
|
|
11
|
+
personal, non-exclusive, non-transferable, non-sublicensable,
|
|
12
|
+
revocable, royalty-free license to install and use the Software,
|
|
13
|
+
solely as a dependency of an application, to integrate with Asteroid
|
|
14
|
+
CMS services. This grant covers use of the Software in its original,
|
|
15
|
+
unmodified form, including normal package-manager installation,
|
|
16
|
+
bundling, and execution of the Software as part of the Licensee's
|
|
17
|
+
application.
|
|
18
|
+
|
|
19
|
+
2. Restrictions
|
|
20
|
+
Licensee shall NOT, in whole or in part, directly or indirectly:
|
|
21
|
+
(a) copy, reproduce, fork, mirror, or republish the Software or any
|
|
22
|
+
portion of its source code, except as strictly required for the
|
|
23
|
+
internal operation of Licensee's own application;
|
|
24
|
+
(b) modify, adapt, translate, refactor, port, or create derivative
|
|
25
|
+
works of the Software;
|
|
26
|
+
(c) redistribute, sublicense, sell, rent, lease, lend, host, or
|
|
27
|
+
otherwise make the Software (modified or unmodified) available
|
|
28
|
+
to any third party as a standalone library, package, service,
|
|
29
|
+
or component;
|
|
30
|
+
(d) remove, alter, or obscure any copyright, trademark, attribution,
|
|
31
|
+
or proprietary notice contained in the Software;
|
|
32
|
+
(e) reverse-engineer, decompile, or disassemble the Software, except
|
|
33
|
+
to the extent such activity is expressly permitted by applicable
|
|
34
|
+
law notwithstanding this restriction;
|
|
35
|
+
(f) use the Software to build, train, or evaluate a product that
|
|
36
|
+
competes with Asteroid CMS or this package.
|
|
37
|
+
|
|
38
|
+
3. Ownership
|
|
39
|
+
All right, title, and interest in and to the Software, including all
|
|
40
|
+
intellectual property rights therein, are and shall remain the sole
|
|
41
|
+
and exclusive property of Asteroid. No rights are granted to
|
|
42
|
+
Licensee other than as expressly set forth in this License. All
|
|
43
|
+
rights not expressly granted are reserved by Asteroid.
|
|
44
|
+
|
|
45
|
+
4. Termination
|
|
46
|
+
This License is effective until terminated. It will terminate
|
|
47
|
+
automatically, without notice, if Licensee breaches any term of this
|
|
48
|
+
License. Upon termination, Licensee must cease all use of the
|
|
49
|
+
Software and destroy all copies in Licensee's possession or control.
|
|
50
|
+
|
|
51
|
+
5. No Warranty
|
|
52
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
53
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
54
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
|
|
55
|
+
NON-INFRINGEMENT.
|
|
56
|
+
|
|
57
|
+
6. Limitation of Liability
|
|
58
|
+
IN NO EVENT SHALL ASTEROID OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
59
|
+
CLAIM, DAMAGES, OR OTHER LIABILITY — WHETHER IN AN ACTION OF
|
|
60
|
+
CONTRACT, TORT, OR OTHERWISE — ARISING FROM, OUT OF, OR IN
|
|
61
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
62
|
+
SOFTWARE.
|
|
63
|
+
|
|
64
|
+
7. Governing Law
|
|
65
|
+
This License shall be governed by and construed in accordance with
|
|
66
|
+
the laws of the jurisdiction in which Asteroid is established,
|
|
67
|
+
without regard to its conflict-of-laws principles.
|
|
68
|
+
|
|
69
|
+
For licensing inquiries, partnership, or to request rights beyond the
|
|
70
|
+
scope of this License, contact: legal@theasteroid.tech
|
package/README.md
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>
|
|
3
|
+
<div style="display: inline-flex; align-items: center; gap: 4px;">
|
|
4
|
+
<img src="https://cms.theasteroid.tech/logo/logo_gradient.svg" alt="@asteroidcms" height="25px" />
|
|
5
|
+
<span>/core-utils</span>
|
|
6
|
+
</div>
|
|
7
|
+
</h1>
|
|
8
|
+
<p>Seamless integration utilities for <a href="https://cms.theasteroid.tech">Asteroid CMS</a> — a single React provider, Apollo client, content hooks, media helpers, and a rich-text renderer.</p>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
- **Provider-driven** — configure `cmsUrl`, `apiKey`, and Apollo behavior in one place
|
|
12
|
+
- **API-key auth only** — sends `x-api-key` on every request, nothing else
|
|
13
|
+
- **Typed hooks** — `useCmsContent` / `useCmsMutate` build GraphQL on the fly from a declarative selection
|
|
14
|
+
- **Tree-shakeable** — ESM + CJS + types, `@apollo/client`/`react` as peer deps
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @asteroidcms/core-utils @apollo/client graphql react react-dom
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @apollo/client-integration-nextjs # for nextjs (optional)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`@apollo/client`, `graphql`, `react`, and `react-dom` are peer dependencies.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Quick start
|
|
33
|
+
|
|
34
|
+
Wrap your app once:
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { AsteroidCMSProvider } from "@asteroidcms/core-utils";
|
|
38
|
+
|
|
39
|
+
export function Root() {
|
|
40
|
+
return (
|
|
41
|
+
<AsteroidCMSProvider
|
|
42
|
+
cmsUrl="https://cms-api.example.com"
|
|
43
|
+
apiKey={import.meta.env.VITE_CMS_API_KEY}
|
|
44
|
+
>
|
|
45
|
+
<App />
|
|
46
|
+
</AsteroidCMSProvider>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Then use the hooks anywhere:
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { useCmsContent, useCmsImage } from "@asteroidcms/core-utils";
|
|
55
|
+
|
|
56
|
+
function NewsList() {
|
|
57
|
+
const cmsImage = useCmsImage();
|
|
58
|
+
const { data, loading } = useCmsContent<Article[]>({
|
|
59
|
+
schema_slug: "news",
|
|
60
|
+
limit: 10,
|
|
61
|
+
status: "PUBLISHED",
|
|
62
|
+
select: ["title", "slug", "publish_date", "cover_image"],
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (loading) return <p>Loading…</p>;
|
|
66
|
+
return (
|
|
67
|
+
<ul>
|
|
68
|
+
{data?.map((a) => (
|
|
69
|
+
<li key={a.slug}>
|
|
70
|
+
<img src={cmsImage(a.cover_image)} alt="" />
|
|
71
|
+
<a href={`/news/${a.slug}`}>{a.title}</a>
|
|
72
|
+
</li>
|
|
73
|
+
))}
|
|
74
|
+
</ul>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## `<AsteroidCMSProvider>`
|
|
82
|
+
|
|
83
|
+
| Prop | Type | Required | Default | Description |
|
|
84
|
+
| --------------- | ------------------------------ | -------- | ------------------ | ------------------------------------------------------------ |
|
|
85
|
+
| `cmsUrl` | `string` | ✓ | — | Base URL of the Asteroid CMS API. |
|
|
86
|
+
| `apiKey` | `string` | ✓ | — | Sent on every request as the `x-api-key` header. |
|
|
87
|
+
| `graphqlPath` | `string` | | `/graphql` | Path appended to `cmsUrl` for the GraphQL endpoint. |
|
|
88
|
+
| `mediaPath` | `string` | | `/media/canonical` | Path used by `cmsImage` / `useCmsImage`. |
|
|
89
|
+
| `headers` | `Record<string, string>` | | `{}` | Extra headers merged onto every GraphQL request. |
|
|
90
|
+
| `onError` | `(error: unknown) => void` | | — | Called for each GraphQL / network / protocol error. |
|
|
91
|
+
| `cacheConfig` | `InMemoryCacheConfig` | | — | Forwarded to `new InMemoryCache(...)` — e.g. `typePolicies`. |
|
|
92
|
+
| `apolloOptions` | `Partial<ApolloClientOptions>` | | — | Escape hatch — overrides any field on the Apollo client. |
|
|
93
|
+
| `client` | `ApolloClient` | | — | Bring your own pre-built client; skips the internal factory. |
|
|
94
|
+
|
|
95
|
+
Example with everything wired:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
<AsteroidCMSProvider
|
|
99
|
+
cmsUrl="https://cms-api.example.com"
|
|
100
|
+
apiKey={process.env.NEXT_PUBLIC_CMS_API_KEY!}
|
|
101
|
+
headers={{ "x-tenant": "acme" }}
|
|
102
|
+
onError={(err) => toast.error(String((err as Error).message ?? err))}
|
|
103
|
+
cacheConfig={{
|
|
104
|
+
typePolicies: {
|
|
105
|
+
Query: {
|
|
106
|
+
fields: { contentEntries: { keyArgs: ["schema_slug", "filter"] } },
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
<App />
|
|
112
|
+
</AsteroidCMSProvider>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## `useCmsContent`
|
|
118
|
+
|
|
119
|
+
React hook for **querying** content. Builds a GraphQL document from a declarative selection.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const { data, loading, error, refetch } = useCmsContent<T>({
|
|
123
|
+
schema_slug, // required
|
|
124
|
+
entrySlug, // when set → single entry, otherwise list
|
|
125
|
+
select, // fields / nested references
|
|
126
|
+
fullData, // include raw `data` object
|
|
127
|
+
limit,
|
|
128
|
+
offset, // list pagination
|
|
129
|
+
status, // "DRAFT" | "PUBLISHED" | "ARCHIVED"
|
|
130
|
+
filter, // { category: "politics", region: "bagmati" }
|
|
131
|
+
search, // [{ field: "title", value: "gagan", mode: "i" }]
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Single entry
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
const { data: article } = useCmsContent({
|
|
139
|
+
schema_slug: "news",
|
|
140
|
+
entrySlug: "police-launch-probe",
|
|
141
|
+
fullData: true,
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Paginated + filtered list
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
const { data: politics } = useCmsContent({
|
|
149
|
+
schema_slug: "news",
|
|
150
|
+
limit: 20,
|
|
151
|
+
offset: 0,
|
|
152
|
+
status: "PUBLISHED",
|
|
153
|
+
filter: { category: "politics" },
|
|
154
|
+
select: ["title", "slug", "publish_date"],
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Regex search
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
const { data: matches } = useCmsContent({
|
|
162
|
+
schema_slug: "news",
|
|
163
|
+
search: [{ field: "title", value: "gagan", mode: "i" }],
|
|
164
|
+
select: ["title", "slug"],
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Deeply nested references with aliasing
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
const { data: topStories } = useCmsContent({
|
|
172
|
+
schema_slug: "top_stories",
|
|
173
|
+
select: [
|
|
174
|
+
{ field: "slug", as: "id" },
|
|
175
|
+
"order",
|
|
176
|
+
{
|
|
177
|
+
field: "news",
|
|
178
|
+
single: true,
|
|
179
|
+
as: "featuredNews",
|
|
180
|
+
select: [
|
|
181
|
+
"title",
|
|
182
|
+
"publish_date",
|
|
183
|
+
{
|
|
184
|
+
field: "category",
|
|
185
|
+
single: true,
|
|
186
|
+
select: [{ field: "title", as: "categoryName" }],
|
|
187
|
+
},
|
|
188
|
+
{ field: "author", single: true, select: ["name", "avatar"] },
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
});
|
|
193
|
+
// → topStories[0].featuredNews.categoryName
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## `useCmsMutate`
|
|
199
|
+
|
|
200
|
+
`create` / `update` / `delete` against a schema, with the same selection syntax.
|
|
201
|
+
|
|
202
|
+
### Create
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
const { mutate: subscribe } = useCmsMutate({
|
|
206
|
+
schema_slug: "news_letter_response",
|
|
207
|
+
mutationType: "create",
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
subscribe({
|
|
211
|
+
variables: { data: { email: "a@b.com", name: "Abhishek" } },
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Update
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
const { mutate: updateArticle } = useCmsMutate({
|
|
219
|
+
schema_slug: "news",
|
|
220
|
+
mutationType: "update",
|
|
221
|
+
entryId: "abc123",
|
|
222
|
+
select: ["title", "slug"],
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
updateArticle({ variables: { data: { title: "New title" } } });
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Delete
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
const { mutate: removeComment } = useCmsMutate({
|
|
232
|
+
schema_slug: "comment",
|
|
233
|
+
mutationType: "delete",
|
|
234
|
+
entryId: "xyz789",
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
removeComment();
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## `cmsImage` / `useCmsImage`
|
|
243
|
+
|
|
244
|
+
Build a canonical media URL for an asset id.
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
// Inside React — preferred
|
|
248
|
+
const cmsImage = useCmsImage();
|
|
249
|
+
<img src={cmsImage(article.cover_image)} alt="" />;
|
|
250
|
+
|
|
251
|
+
// Outside React (loaders, scripts, SSR)
|
|
252
|
+
import { cmsImage } from "@asteroidcms/core-utils";
|
|
253
|
+
cmsImage(id, { cmsUrl: "https://cms-api.example.com" });
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## `<RichTextContent>`
|
|
259
|
+
|
|
260
|
+
Render Asteroid CMS rich-text JSON/HTML with syntax-highlighted code blocks (via `highlight.js`).
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { RichTextContent } from "@asteroidcms/core-utils";
|
|
264
|
+
|
|
265
|
+
<RichTextContent
|
|
266
|
+
content={article.body}
|
|
267
|
+
classMap={{ p: "my-2 leading-relaxed", h2: "text-2xl font-bold" }}
|
|
268
|
+
/>;
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Or use the parser directly:
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
import { parseRichText } from "@asteroidcms/core-utils";
|
|
275
|
+
|
|
276
|
+
const html = parseRichText(article.body, {
|
|
277
|
+
classMap: {
|
|
278
|
+
/* ... */
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Advanced — bring your own Apollo client
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
import { ApolloClient, InMemoryCache } from "@apollo/client";
|
|
289
|
+
import { AsteroidCMSProvider } from "@asteroidcms/core-utils";
|
|
290
|
+
|
|
291
|
+
const client = new ApolloClient({ uri: "...", cache: new InMemoryCache() });
|
|
292
|
+
|
|
293
|
+
<AsteroidCMSProvider cmsUrl="..." apiKey="..." client={client}>
|
|
294
|
+
<App />
|
|
295
|
+
</AsteroidCMSProvider>;
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Or build the client yourself with the same factory used internally:
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
import { createApolloClient } from "@asteroidcms/core-utils";
|
|
302
|
+
|
|
303
|
+
const client = createApolloClient({
|
|
304
|
+
cmsUrl: "https://cms-api.example.com",
|
|
305
|
+
apiKey: "...",
|
|
306
|
+
});
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Development
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
npm install
|
|
315
|
+
npm run typecheck
|
|
316
|
+
npm run build # writes dist/index.js, dist/index.cjs, dist/index.d.ts
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
Proprietary — Copyright © Asteroid. All rights reserved.
|
|
324
|
+
|
|
325
|
+
This package is licensed for use only; copying, modifying, or
|
|
326
|
+
redistributing the source — in whole or in part — is not permitted.
|
|
327
|
+
See [LICENSE](./LICENSE) for the full terms.
|