@mapled/react 0.0.1 → 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/README.md CHANGED
@@ -1,10 +1,221 @@
1
1
  # @mapled/react
2
2
 
3
- React helpers for [Mapled](https://mapled.io), the hosted headless CMS for sites built with AI: published content in a React single-page app (Vite and the like).
3
+ React helpers for [Mapled](https://mapled.io), the hosted headless CMS for sites built with AI: published content in a React single-page app — Vite, Create React App, anything that renders in the browser. One provider, three hooks. Built on [`@mapled/client`](https://www.npmjs.com/package/@mapled/client); a Next.js site uses [`@mapled/next`](https://www.npmjs.com/package/@mapled/next) instead.
4
4
 
5
- **This version holds no code yet.** 0.0.1 exists so that the releases that follow can be published from CI; the first release is 0.1.0.
5
+ ## Install
6
6
 
7
- Until then:
7
+ ```bash
8
+ npm install @mapled/react
9
+ ```
8
10
 
9
- - a Next.js site uses [`@mapled/next`](https://www.npmjs.com/package/@mapled/next);
10
- - any other site reads the Delivery API over HTTP — «Without Next.js: the HTTP API» in the [`@mapled/next` README](https://www.npmjs.com/package/@mapled/next).
11
+ `@mapled/client` comes with it. Put the project's **delivery key** (Mapled: Integrations → Your site) in `.env`:
12
+
13
+ ```bash
14
+ VITE_MAPLED_KEY=mk_live_…
15
+ ```
16
+
17
+ It is bundled into the page, which is fine for this key and for no other: it reads published content only. A server key or a webhook signing secret never goes under a `VITE_` name.
18
+
19
+ ## Wire it up
20
+
21
+ ```tsx
22
+ // src/mapled.ts
23
+ import { createClient } from "@mapled/client";
24
+ import { typedHooks } from "@mapled/react";
25
+ import type { MapledSchema } from "./mapled-types";
26
+
27
+ export const mapled = createClient<MapledSchema>({ key: import.meta.env.VITE_MAPLED_KEY });
28
+ export const { useSingle, useRecords, useRecord } = typedHooks<MapledSchema>();
29
+ ```
30
+
31
+ ```tsx
32
+ // src/main.tsx
33
+ import { StrictMode } from "react";
34
+ import { createRoot } from "react-dom/client";
35
+ import { MapledProvider } from "@mapled/react";
36
+ import { mapled } from "./mapled";
37
+ import { App } from "./App";
38
+
39
+ createRoot(document.getElementById("root")!).render(
40
+ <StrictMode>
41
+ <MapledProvider client={mapled}>
42
+ <App />
43
+ </MapledProvider>
44
+ </StrictMode>,
45
+ );
46
+ ```
47
+
48
+ `mapled-types.ts` is written by `npx @mapled/cli types generate`; with `typedHooks<MapledSchema>()` keys are checked and `data` has each collection's own type. Without types, import `useSingle`, `useRecords` and `useRecord` straight from `@mapled/react`.
49
+
50
+ ## Read content
51
+
52
+ Every hook answers `{ data, loading, error, refetch }`.
53
+
54
+ ```tsx
55
+ // src/pages/Home.tsx
56
+ import Markdown from "react-markdown";
57
+ import { assetUrl } from "@mapled/client";
58
+ import { useSingle } from "../mapled";
59
+
60
+ export function Home() {
61
+ const { data: home, loading, error } = useSingle("homepage");
62
+ if (loading) return <p>Loading…</p>;
63
+ if (error || !home) return <p>Nothing here yet.</p>;
64
+ return (
65
+ <main>
66
+ <h1>{home.data.headline}</h1>
67
+ {home.data.hero ? <img src={assetUrl(home.data.hero, { width: 1200 })} alt="" /> : null}
68
+ <Markdown>{home.data.intro ?? ""}</Markdown>
69
+ </main>
70
+ );
71
+ }
72
+ ```
73
+
74
+ ```tsx
75
+ // src/pages/Blog.tsx
76
+ import { Link } from "react-router-dom";
77
+ import { useRecords } from "../mapled";
78
+
79
+ export function Blog() {
80
+ const { data, loading } = useRecords("posts", { sort: "-date", limit: 20, fields: ["title", "slug", "date"] });
81
+ if (loading && !data) return <p>Loading…</p>;
82
+ return (
83
+ <ul>
84
+ {data?.records.map((post) => (
85
+ <li key={post.id}>
86
+ <Link to={`/blog/${post.data.slug}`}>{post.data.title}</Link>
87
+ </li>
88
+ ))}
89
+ </ul>
90
+ );
91
+ }
92
+ ```
93
+
94
+ ```tsx
95
+ // src/pages/Post.tsx
96
+ import Markdown from "react-markdown";
97
+ import { useParams } from "react-router-dom";
98
+ import { useRecord } from "../mapled";
99
+
100
+ export function Post() {
101
+ const { slug } = useParams();
102
+ const { data: post, loading } = useRecord("posts", slug ? { slug } : null);
103
+ if (loading) return <p>Loading…</p>;
104
+ if (!post) return <p>This post doesn't exist.</p>;
105
+ return (
106
+ <article>
107
+ <h1>{post.data.title}</h1>
108
+ <Markdown>{post.data.body}</Markdown>
109
+ </article>
110
+ );
111
+ }
112
+ ```
113
+
114
+ - `useSingle(key, options?)` — `data` is the single's record, or `null` while it is empty.
115
+ - `useRecords(collection, options?)` — `data` is `{ records, total, release }`; options are the client's: `filter`, `sort`, `limit`, `offset`, `fields`, `expand`.
116
+ - `useRecord(collection, { slug } | { id } | null, options?)` — `data` is `null` when the record isn't published; `null` instead of a reference reads nothing (a router param that hasn't arrived).
117
+ - Components that ask for the same thing share one request; an inline options object is the same read on every render.
118
+ - Rich text values are Markdown — render them with a Markdown component, never as raw HTML.
119
+ - `useMapled()` hands out the client for a read the hooks don't cover.
120
+
121
+ ## Preview
122
+
123
+ Nothing to add: when someone opens **Preview** in Mapled, the page opens with a one-time token in its address, the client trades it for a draft session, and the hooks show drafts in that tab. Say so on the page:
124
+
125
+ ```tsx
126
+ // src/PreviewBar.tsx
127
+ import { usePreview } from "@mapled/react";
128
+
129
+ export function PreviewBar() {
130
+ const preview = usePreview();
131
+ if (!preview.active) return null;
132
+ return (
133
+ <p role="status">
134
+ You are looking at a preview. <button onClick={preview.exit}>Back to the published site</button>
135
+ </p>
136
+ );
137
+ }
138
+ ```
139
+
140
+ Mapled has to know where the site lives and that it renders in the browser: the site manifest's `framework` is `"react-spa"` (`npx @mapled/cli scan --write`, `bindings push` — or your AI agent's `push_site_manifest`), and **Production domain** in Project settings holds the site's public address (an agent sets it with `set_site_url`). There is no webhook to configure and no route to mount.
141
+
142
+ ## Live updates
143
+
144
+ A publish shows when the page is loaded again. To follow it while the page is open:
145
+
146
+ ```tsx
147
+ // src/LiveApp.tsx
148
+ import { MapledProvider } from "@mapled/react";
149
+ import { mapled } from "./mapled";
150
+ import { App } from "./App";
151
+
152
+ export function LiveApp() {
153
+ return (
154
+ <MapledProvider client={mapled} live>
155
+ <App />
156
+ </MapledProvider>
157
+ );
158
+ }
159
+ ```
160
+
161
+ Each open tab then asks Mapled for the release pointer once a minute (`live={{ interval: 30 }}` for thirty seconds, never under fifteen) while it is visible, and the hooks read again — pinned to the new release — when it moves; what was on screen stays there until the new answer arrives. It is off by default because every check is a request of the delivery key's budget (1,200 a minute).
162
+
163
+ ## Forms
164
+
165
+ `submitForm` from `@mapled/client` posts a visitor's submission:
166
+
167
+ ```tsx
168
+ // src/ContactForm.tsx
169
+ import { useState, type FormEvent } from "react";
170
+ import { submitForm } from "@mapled/client";
171
+
172
+ const CONSENT = "I agree to be contacted about my request.";
173
+
174
+ export function ContactForm() {
175
+ const [state, setState] = useState<"idle" | "sending" | "sent" | "failed">("idle");
176
+
177
+ async function submit(event: FormEvent<HTMLFormElement>) {
178
+ event.preventDefault();
179
+ const form = event.currentTarget;
180
+ setState("sending");
181
+ const answer = await submitForm("contact", form, {
182
+ key: import.meta.env.VITE_MAPLED_KEY,
183
+ consent: new FormData(form).get("consent") ? CONSENT : undefined,
184
+ });
185
+ setState(answer.ok ? "sent" : "failed");
186
+ }
187
+
188
+ if (state === "sent") return <p>Thank you — we'll be in touch.</p>;
189
+ return (
190
+ <form onSubmit={submit}>
191
+ <input name="name" required />
192
+ <input name="email" type="email" required />
193
+ <textarea name="message" required />
194
+ <input name="_gotcha" tabIndex={-1} autoComplete="off" aria-hidden="true" style={{ display: "none" }} />
195
+ <label>
196
+ <input name="consent" type="checkbox" required /> {CONSENT}
197
+ </label>
198
+ <button disabled={state === "sending"}>Send</button>
199
+ {state === "failed" ? <p>That didn't go through. Try again in a minute.</p> : null}
200
+ </form>
201
+ );
202
+ }
203
+ ```
204
+
205
+ ## Check the integration
206
+
207
+ ```bash
208
+ npx @mapled/cli doctor
209
+ ```
210
+
211
+ doctor knows a single-page app: it wants `VITE_MAPLED_KEY` and no webhook secret, reads ○ «Not needed» for the webhook and the routes, and fails an env file that puts a server key or a signing secret under a public prefix.
212
+
213
+ ## API
214
+
215
+ | Export | |
216
+ | --- | --- |
217
+ | `MapledProvider` | `client`, `live?` (`true` or `{ interval }`) |
218
+ | `useSingle`, `useRecords`, `useRecord` | `{ data, loading, error, refetch }` |
219
+ | `typedHooks<MapledSchema>()` | The same three hooks, typed by the generated schema |
220
+ | `usePreview()` | `{ active, exit }` |
221
+ | `useMapled()` | The provider's client |
@@ -0,0 +1,95 @@
1
+ /** React helpers for Mapled: published content in a React single-page
2
+ app. One provider holds the client; the hooks read through it, share
3
+ a read between the components that ask for the same thing, show
4
+ drafts when the page was opened from Mapled's Preview, and — with
5
+ `live` — follow a publish while the page is open. The reads, the
6
+ preview link and the release watch are "@mapled/client"'s. */
7
+ import { type ReactNode } from "react";
8
+ import { type ContentSchema, type ListOptions, type ListResult, type MapledClient, type MapledRecord, type ReadOptions } from "@mapled/client";
9
+ /** What a hook answers: `data` is null until the first answer (and for
10
+ a record that isn't published). When the same read is asked again —
11
+ `refetch`, a publish the page heard — the previous answer stays in
12
+ `data` until the next one arrives. */
13
+ export type ReadState<T> = {
14
+ data: T | null;
15
+ loading: boolean;
16
+ error: Error | null;
17
+ /** Ask again, past anything the page remembers. */
18
+ refetch: () => void;
19
+ };
20
+ type Entry = {
21
+ status: "loading" | "done" | "error";
22
+ data?: unknown;
23
+ error?: Error;
24
+ };
25
+ /** Reads by key: one request however many components ask, the answer
26
+ kept for the ones that mount later. */
27
+ declare class ReadStore {
28
+ private entries;
29
+ private listeners;
30
+ private generation;
31
+ get(key: string): Entry | undefined;
32
+ subscribe(key: string, listener: () => void): () => void;
33
+ private set;
34
+ /** Starts the read unless it is known or on its way; `force` asks again. */
35
+ ensure(key: string, read: () => Promise<unknown>, force?: boolean): void;
36
+ }
37
+ type Live = boolean | {
38
+ interval?: number;
39
+ };
40
+ type ContextValue = {
41
+ client: MapledClient;
42
+ store: ReadStore;
43
+ /** the release the page follows once a publish was heard; undefined = the latest */
44
+ release: number | undefined;
45
+ /** null until the client has looked for a preview link: nothing is read
46
+ before that, so a preview never starts with published content */
47
+ preview: boolean | null;
48
+ };
49
+ export type MapledProviderProps = {
50
+ /** `createClient({ key })` from "@mapled/client" — make it once, outside the component. */
51
+ client: MapledClient<any>;
52
+ /** Follow publishes while the page is open: Mapled is asked for the
53
+ release pointer — once a minute by default, only in a visible tab —
54
+ and the hooks read again when it moves. Off by default: every check
55
+ is a request of the delivery key's budget. */
56
+ live?: Live;
57
+ children?: ReactNode;
58
+ };
59
+ export declare function MapledProvider({ client, live, children }: MapledProviderProps): import("react").FunctionComponentElement<import("react").ProviderProps<ContextValue | null>>;
60
+ /** The client the provider holds — for a read the hooks don't cover. */
61
+ export declare function useMapled<S extends ContentSchema = ContentSchema>(): MapledClient<S>;
62
+ /** Whether the page shows drafts (it was opened from Mapled's Preview),
63
+ and the way out: back to published content, read again. */
64
+ export declare function usePreview(): {
65
+ active: boolean;
66
+ exit: () => void;
67
+ };
68
+ type Data = Record<string, unknown>;
69
+ type HookReadOptions = Omit<ReadOptions, "signal" | "release">;
70
+ type HookListOptions = Omit<ListOptions, "signal" | "release">;
71
+ /** How one record is named: by the collection's slug field, or by id.
72
+ Null (no slug in the address yet) reads nothing. */
73
+ export type RecordRef = {
74
+ slug: string;
75
+ } | {
76
+ id: string;
77
+ } | null | undefined;
78
+ /** A single — "homepage", "settings". `data` is its record, or null while it is empty. */
79
+ export declare function useSingle<T = Data>(key: string, options?: HookReadOptions): ReadState<MapledRecord<T>>;
80
+ /** Published records of a collection: `data` is `{ records, total, release }`. */
81
+ export declare function useRecords<T = Data>(collection: string, options?: HookListOptions): ReadState<ListResult<T>>;
82
+ /** One record, by `{ slug }` or `{ id }`; `data` is null when it isn't published. */
83
+ export declare function useRecord<T = Data>(collection: string, ref: RecordRef, options?: HookReadOptions): ReadState<MapledRecord<T>>;
84
+ type CollectionsOf<S extends ContentSchema> = S["collections"] extends object ? S["collections"] : Record<string, Data>;
85
+ type SinglesOf<S extends ContentSchema> = S["singles"] extends object ? S["singles"] : Record<string, Data>;
86
+ /** The same hooks, typed by the `MapledSchema` that `mapled types
87
+ generate` writes: `export const { useSingle, useRecords, useRecord } =
88
+ typedHooks<MapledSchema>()` — keys are checked, `data` has the
89
+ collection's own type. */
90
+ export declare function typedHooks<S extends ContentSchema>(): {
91
+ useSingle: <K extends keyof SinglesOf<S> & string>(key: K, options?: HookReadOptions) => ReadState<MapledRecord<SinglesOf<S>[K]>>;
92
+ useRecords: <K extends keyof CollectionsOf<S> & string>(collection: K, options?: HookListOptions) => ReadState<ListResult<CollectionsOf<S>[K]>>;
93
+ useRecord: <K extends keyof CollectionsOf<S> & string>(collection: K, ref: RecordRef, options?: HookReadOptions) => ReadState<MapledRecord<CollectionsOf<S>[K]>>;
94
+ };
95
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,167 @@
1
+ "use client";
2
+ /** React helpers for Mapled: published content in a React single-page
3
+ app. One provider holds the client; the hooks read through it, share
4
+ a read between the components that ask for the same thing, show
5
+ drafts when the page was opened from Mapled's Preview, and — with
6
+ `live` — follow a publish while the page is open. The reads, the
7
+ preview link and the release watch are "@mapled/client"'s. */
8
+ import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
9
+ import { endPreview } from "@mapled/client";
10
+ const MAX_ENTRIES = 300;
11
+ const LOADING = { status: "loading" };
12
+ /** Reads by key: one request however many components ask, the answer
13
+ kept for the ones that mount later. */
14
+ class ReadStore {
15
+ entries = new Map();
16
+ listeners = new Map();
17
+ generation = new Map();
18
+ get(key) {
19
+ return this.entries.get(key);
20
+ }
21
+ subscribe(key, listener) {
22
+ let set = this.listeners.get(key);
23
+ if (!set)
24
+ this.listeners.set(key, (set = new Set()));
25
+ set.add(listener);
26
+ return () => {
27
+ set.delete(listener);
28
+ if (set.size === 0)
29
+ this.listeners.delete(key);
30
+ };
31
+ }
32
+ set(key, entry) {
33
+ this.entries.delete(key);
34
+ this.entries.set(key, entry);
35
+ if (this.entries.size > MAX_ENTRIES) {
36
+ // oldest first, never one a mounted component is looking at
37
+ for (const old of this.entries.keys()) {
38
+ if (this.entries.size <= MAX_ENTRIES)
39
+ break;
40
+ if (!this.listeners.has(old))
41
+ this.entries.delete(old);
42
+ }
43
+ }
44
+ for (const listener of this.listeners.get(key) ?? [])
45
+ listener();
46
+ }
47
+ /** Starts the read unless it is known or on its way; `force` asks again. */
48
+ ensure(key, read, force = false) {
49
+ const known = this.entries.get(key);
50
+ if (known && !force)
51
+ return;
52
+ const mine = (this.generation.get(key) ?? 0) + 1;
53
+ this.generation.set(key, mine);
54
+ // a forced read keeps showing what it had
55
+ this.set(key, known && force ? { ...known, status: "loading" } : LOADING);
56
+ read().then((data) => {
57
+ if (this.generation.get(key) === mine)
58
+ this.set(key, { status: "done", data });
59
+ }, (error) => {
60
+ if (this.generation.get(key) === mine) {
61
+ this.set(key, { status: "error", error: error instanceof Error ? error : new Error(String(error)) });
62
+ }
63
+ });
64
+ }
65
+ }
66
+ const MapledContext = createContext(null);
67
+ export function MapledProvider({ client, live = false, children }) {
68
+ const store = useMemo(() => new ReadStore(), [client]);
69
+ const [release, setRelease] = useState(undefined);
70
+ const [preview, setPreview] = useState(null);
71
+ useEffect(() => {
72
+ let mounted = true;
73
+ setRelease(undefined);
74
+ setPreview(null);
75
+ client.isPreview().then((on) => mounted && setPreview(on), () => mounted && setPreview(false));
76
+ return () => {
77
+ mounted = false;
78
+ };
79
+ }, [client]);
80
+ const interval = typeof live === "object" ? live.interval : undefined;
81
+ const watching = Boolean(live) && preview === false;
82
+ useEffect(() => {
83
+ // drafts have no releases to follow
84
+ if (!watching)
85
+ return;
86
+ return client.watch((next) => setRelease(next.release), { interval });
87
+ }, [client, watching, interval]);
88
+ const value = useMemo(() => ({ client, store, release, preview }), [client, store, release, preview]);
89
+ return createElement(MapledContext.Provider, { value }, children);
90
+ }
91
+ function useMapledContext() {
92
+ const value = useContext(MapledContext);
93
+ if (!value)
94
+ throw new Error("Mapled: wrap the app in <MapledProvider client={…}> before using its hooks.");
95
+ return value;
96
+ }
97
+ /** The client the provider holds — for a read the hooks don't cover. */
98
+ export function useMapled() {
99
+ return useMapledContext().client;
100
+ }
101
+ /** Whether the page shows drafts (it was opened from Mapled's Preview),
102
+ and the way out: back to published content, read again. */
103
+ export function usePreview() {
104
+ const preview = useMapledContext().preview === true;
105
+ const exit = useCallback(() => {
106
+ endPreview();
107
+ if (typeof window !== "undefined")
108
+ window.location.reload();
109
+ }, []);
110
+ return { active: preview, exit };
111
+ }
112
+ const noop = () => { };
113
+ function useRead(id, read) {
114
+ const { store, release, preview } = useMapledContext();
115
+ // drafts are unversioned; a followed release is part of what is asked
116
+ const pin = preview ? undefined : release;
117
+ const key = id === null || preview === null ? null : `${preview ? "draft" : (pin ?? "latest")}|${id}`;
118
+ const readRef = useRef(read);
119
+ readRef.current = read;
120
+ const entry = useSyncExternalStore(useCallback((listener) => (key === null ? noop : store.subscribe(key, listener)), [store, key]), () => (key === null ? undefined : store.get(key)), () => undefined);
121
+ useEffect(() => {
122
+ if (key !== null)
123
+ store.ensure(key, () => readRef.current(pin === undefined ? {} : { release: pin }));
124
+ }, [store, key, pin]);
125
+ const refetch = useCallback(() => {
126
+ if (key !== null)
127
+ store.ensure(key, () => readRef.current(pin === undefined ? {} : { release: pin }), true);
128
+ }, [store, key, pin]);
129
+ // the same read under a new release (a publish was heard) or asked again:
130
+ // what was on screen stays there until the next answer. Another read —
131
+ // another slug, other options — starts from nothing.
132
+ const last = useRef(null);
133
+ if (id !== null && entry?.status === "done")
134
+ last.current = { id, data: (entry.data ?? null) };
135
+ return {
136
+ data: entry?.status === "done" ? (entry.data ?? null) : last.current?.id === id ? last.current.data : null,
137
+ loading: id !== null && (key === null || !entry || entry.status === "loading"),
138
+ error: entry?.status === "error" ? (entry.error ?? null) : null,
139
+ refetch,
140
+ };
141
+ }
142
+ /** A single — "homepage", "settings". `data` is its record, or null while it is empty. */
143
+ export function useSingle(key, options = {}) {
144
+ const { client } = useMapledContext();
145
+ return useRead(`single|${key}|${JSON.stringify(options)}`, (pin) => client.getSingle(key, { ...options, ...pin }));
146
+ }
147
+ /** Published records of a collection: `data` is `{ records, total, release }`. */
148
+ export function useRecords(collection, options = {}) {
149
+ const { client } = useMapledContext();
150
+ return useRead(`records|${collection}|${JSON.stringify(options)}`, (pin) => client.getRecords(collection, { ...options, ...pin }));
151
+ }
152
+ /** One record, by `{ slug }` or `{ id }`; `data` is null when it isn't published. */
153
+ export function useRecord(collection, ref, options = {}) {
154
+ const { client } = useMapledContext();
155
+ const by = !ref ? null : "slug" in ref ? (ref.slug ? `slug:${ref.slug}` : null) : ref.id ? `id:${ref.id}` : null;
156
+ return useRead(by === null ? null : `record|${collection}|${by}|${JSON.stringify(options)}`, (pin) => {
157
+ const opts = { ...options, ...pin };
158
+ return (ref && "slug" in ref ? client.getRecordBySlug(collection, ref.slug, opts) : client.getRecord(collection, ref.id, opts));
159
+ });
160
+ }
161
+ /** The same hooks, typed by the `MapledSchema` that `mapled types
162
+ generate` writes: `export const { useSingle, useRecords, useRecord } =
163
+ typedHooks<MapledSchema>()` — keys are checked, `data` has the
164
+ collection's own type. */
165
+ export function typedHooks() {
166
+ return { useSingle, useRecords, useRecord };
167
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mapled/react",
3
- "version": "0.0.1",
4
- "description": "React helpers for Mapled, the hosted headless CMS for sites built with AI — published content in a React single-page app. 0.0.1 holds no code yet; 0.1.0 is the first release.",
3
+ "version": "0.1.0",
4
+ "description": "React helpers for Mapled — published content in a React single-page app (Vite and the like): a provider and hooks over @mapled/client, with preview and publish notifications.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://mapled.io",
7
7
  "keywords": [
@@ -9,6 +9,7 @@
9
9
  "cms",
10
10
  "headless-cms",
11
11
  "react",
12
+ "hooks",
12
13
  "spa",
13
14
  "vite"
14
15
  ],
@@ -26,7 +27,7 @@
26
27
  }
27
28
  },
28
29
  "files": [
29
- "README.md"
30
+ "dist"
30
31
  ],
31
32
  "scripts": {
32
33
  "build": "tsc -p tsconfig.json",
@@ -35,7 +36,7 @@
35
36
  "typecheck": "tsc --noEmit -p tsconfig.json"
36
37
  },
37
38
  "dependencies": {
38
- "@mapled/client": "^0.0.1"
39
+ "@mapled/client": "^0.1.0"
39
40
  },
40
41
  "peerDependencies": {
41
42
  "react": ">=18"