@rafters/astro-data 0.0.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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/astro.d.ts +24 -0
- package/dist/astro.d.ts.map +1 -0
- package/dist/astro.js +26 -0
- package/dist/astro.js.map +1 -0
- package/dist/elements.d.ts +20 -0
- package/dist/elements.d.ts.map +1 -0
- package/dist/elements.js +48 -0
- package/dist/elements.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/cache-memory.d.ts +3 -0
- package/dist/internal/cache-memory.d.ts.map +1 -0
- package/dist/internal/cache-memory.js +0 -0
- package/dist/internal/cache-memory.js.map +1 -0
- package/dist/internal/state.d.ts +22 -0
- package/dist/internal/state.d.ts.map +1 -0
- package/dist/internal/state.js +14 -0
- package/dist/internal/state.js.map +1 -0
- package/dist/nanostores.d.ts +17 -0
- package/dist/nanostores.d.ts.map +1 -0
- package/dist/nanostores.js +12 -0
- package/dist/nanostores.js.map +1 -0
- package/dist/react.d.ts +44 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +95 -0
- package/dist/react.js.map +1 -0
- package/dist/zustand.d.ts +9 -0
- package/dist/zustand.d.ts.map +1 -0
- package/dist/zustand.js +10 -0
- package/dist/zustand.js.map +1 -0
- package/package.json +99 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @rafters/astro-data
|
|
2
|
+
|
|
3
|
+
## 0.0.0
|
|
4
|
+
|
|
5
|
+
Initial scaffold. Package shape, public types, no runtime implementations.
|
|
6
|
+
|
|
7
|
+
The loader and action contract on top of Astro 6, with cache adapter seams for
|
|
8
|
+
Nanostores and Zustand, React and Web Components deliveries, and composition
|
|
9
|
+
points for smugglr (local-first sync) and kelex (schema-generated forms).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rafter Studio
|
|
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,240 @@
|
|
|
1
|
+
# @rafters/astro-data
|
|
2
|
+
|
|
3
|
+
The loader and action contract Astro is missing.
|
|
4
|
+
|
|
5
|
+
Astro has pages, server islands, and Actions. It does not have a loader-and-revalidation contract — the pattern Remix made famous, RR7 carried, and TanStack Router copied. This package is that contract, layered on Astro 6, with end-to-end Zod types, hierarchical revalidation, and a small public surface.
|
|
6
|
+
|
|
7
|
+
Not a framework. A contract.
|
|
8
|
+
|
|
9
|
+
## Status
|
|
10
|
+
|
|
11
|
+
Pre-release. Designed against Astro 6. Not yet published to npm.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @rafters/astro-data
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Pick a cache adapter:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add nanostores @nanostores/react # recommended -- works across React, Solid, Vue, Svelte islands
|
|
23
|
+
# or
|
|
24
|
+
pnpm add zustand # React-only apps
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Astro re-exports its pinned Zod as `astro/zod`. Import `z` from there for action and loader schemas; no separate Zod install required.
|
|
28
|
+
|
|
29
|
+
## Quickstart
|
|
30
|
+
|
|
31
|
+
Configure the cache at app entry:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// src/data.ts
|
|
35
|
+
import { configure } from "@rafters/astro-data";
|
|
36
|
+
import { createNanostoresCache } from "@rafters/astro-data/nanostores";
|
|
37
|
+
|
|
38
|
+
configure({ cache: createNanostoresCache() });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Define a loader:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// src/loaders/dashboard.ts
|
|
45
|
+
import { z } from "astro/zod";
|
|
46
|
+
import type { LoaderArgs } from "@rafters/astro-data";
|
|
47
|
+
import { profiles, stats } from "../db/schema";
|
|
48
|
+
import { eq } from "drizzle-orm";
|
|
49
|
+
|
|
50
|
+
export const loaderInput = z.object({ userId: z.string() });
|
|
51
|
+
|
|
52
|
+
export async function loader({ input, astro }: LoaderArgs<z.infer<typeof loaderInput>>) {
|
|
53
|
+
const db = astro.locals.db;
|
|
54
|
+
return {
|
|
55
|
+
profile: await db.select().from(profiles).where(eq(profiles.id, input.userId)).get(),
|
|
56
|
+
stats: await db.select().from(stats).where(eq(stats.userId, input.userId)).all(),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Define an action:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// src/actions/update-profile.ts
|
|
65
|
+
import { z } from "astro/zod";
|
|
66
|
+
import type { APIContext } from "astro";
|
|
67
|
+
|
|
68
|
+
export const actionInput = z.object({ name: z.string().min(1) });
|
|
69
|
+
export const accept = "form";
|
|
70
|
+
export const revalidates = [["dashboard"]] as const;
|
|
71
|
+
|
|
72
|
+
export async function action(input: z.infer<typeof actionInput>, ctx: APIContext) {
|
|
73
|
+
await ctx.locals.db.updateProfile(input);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Use in a page:
|
|
78
|
+
|
|
79
|
+
```astro
|
|
80
|
+
---
|
|
81
|
+
import * as Dashboard from '../loaders/dashboard'
|
|
82
|
+
import { runLoader } from '@rafters/astro-data'
|
|
83
|
+
import DashboardIsland from '../components/Dashboard'
|
|
84
|
+
|
|
85
|
+
const data = await runLoader(Dashboard, Astro, { userId: Astro.locals.user.id })
|
|
86
|
+
---
|
|
87
|
+
<DashboardIsland initialData={data} client:load />
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Consume from an island:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
// src/components/Dashboard.tsx
|
|
94
|
+
import { useLoaderData, useAction, useNavigation } from "@rafters/astro-data/react";
|
|
95
|
+
import * as Dashboard from "../loaders/dashboard";
|
|
96
|
+
import * as UpdateProfile from "../actions/update-profile";
|
|
97
|
+
|
|
98
|
+
export default function Dashboard({
|
|
99
|
+
initialData,
|
|
100
|
+
}: {
|
|
101
|
+
initialData: Awaited<ReturnType<typeof Dashboard.loader>>;
|
|
102
|
+
}) {
|
|
103
|
+
const data = useLoaderData(Dashboard, initialData);
|
|
104
|
+
const update = useAction(UpdateProfile);
|
|
105
|
+
const nav = useNavigation();
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<>
|
|
109
|
+
<p>{data.profile?.name}</p>
|
|
110
|
+
<button onClick={() => update.run({ name: "New" })} disabled={update.pending}>
|
|
111
|
+
Save
|
|
112
|
+
</button>
|
|
113
|
+
{nav.pending && <span>Saving…</span>}
|
|
114
|
+
</>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
That's the whole contract. Loaders fetch. Actions revalidate. Islands consume.
|
|
120
|
+
|
|
121
|
+
## Concepts
|
|
122
|
+
|
|
123
|
+
### Loaders
|
|
124
|
+
|
|
125
|
+
A loader is a typed, keyed, validated async function. It runs server-side — at build time during SSG, at request time during SSR — and returns data for pages and islands.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
{
|
|
129
|
+
loader: (args: LoaderArgs<I>) => Promise<O>
|
|
130
|
+
loaderInput?: z.ZodType<I>
|
|
131
|
+
key?: readonly string[]
|
|
132
|
+
scope?: 'page' | 'layout'
|
|
133
|
+
staleTime?: number
|
|
134
|
+
refetchOnFocus?: boolean
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Actions
|
|
139
|
+
|
|
140
|
+
An action is a typed, validated server function that may revalidate loaders. Actions ride Astro's `defineAction` runtime: `<form method="POST" action={registerAction(module)}>` works with zero JavaScript, typed errors via `ActionError` and `isInputError()`, session integration via `Astro.session`.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
{
|
|
144
|
+
action: (input: I, context: APIContext) => Promise<O>
|
|
145
|
+
actionInput: z.ZodType<I>
|
|
146
|
+
accept?: 'json' | 'form'
|
|
147
|
+
revalidates?: readonly (readonly string[])[]
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Hierarchical keys
|
|
152
|
+
|
|
153
|
+
Keys are arrays. Invalidation matches by prefix.
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
['dashboard'] invalidates: dashboard, dashboard.*
|
|
157
|
+
['dashboard', 'stats'] invalidates: dashboard.stats, dashboard.stats.*
|
|
158
|
+
['dashboard', 'stats', 'today'] invalidates: dashboard.stats.today only
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
This is RR7's model and TanStack Query's opt-in. It's the right default for an action-revalidates-loaders contract: mutation scope is naturally hierarchical.
|
|
162
|
+
|
|
163
|
+
### Revalidation, not refetching
|
|
164
|
+
|
|
165
|
+
`invalidate` marks loaders stale. Re-running happens on the next consumer demand — the next navigation that needs the loader, or the next island that subscribes to its key. Actions stay cheap; revalidation stays lazy.
|
|
166
|
+
|
|
167
|
+
## Composition
|
|
168
|
+
|
|
169
|
+
The package is the floor. Two optional addons multiply it.
|
|
170
|
+
|
|
171
|
+
### smugglr — local-first SQLite sync
|
|
172
|
+
|
|
173
|
+
[smugglr](https://smugglr.dev) is a SQLite sync engine. Pass its nanostores bridge into the cache adapter and your data becomes durable, syncs across devices, and survives offline.
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { createNanostoresCache } from "@rafters/astro-data/nanostores";
|
|
177
|
+
import { smugglrBridge } from "smugglr/nanostores";
|
|
178
|
+
|
|
179
|
+
configure({
|
|
180
|
+
cache: createNanostoresCache({ store: smugglrBridge({ db: "app" }) }),
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Your loaders and actions don't change. Smugglr keeps the underlying storage in sync with your D1 (or Turso, or rqlite, or any other SQLite backend) in the background. Mutations land locally first, sync when network returns.
|
|
185
|
+
|
|
186
|
+
### kelex — schema-generated forms
|
|
187
|
+
|
|
188
|
+
[kelex](https://github.com/rafters-studio/kelex) reads an action's Zod schema and generates the form for you — fields, labels, validation, error placement, pending UI.
|
|
189
|
+
|
|
190
|
+
```astro
|
|
191
|
+
---
|
|
192
|
+
import * as UpdateProfile from '../actions/update-profile'
|
|
193
|
+
import { kelexForm } from 'kelex/astro'
|
|
194
|
+
---
|
|
195
|
+
{kelexForm(UpdateProfile)}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Without kelex, hand-write your inputs against the schema (the `<Form>` component from `@rafters/astro-data/react` is the bare-bones wrapper). With kelex, the form writes itself.
|
|
199
|
+
|
|
200
|
+
### Independence
|
|
201
|
+
|
|
202
|
+
Both are optional. Adopt zero, one, or both. The package works without either. Each is a force multiplier where it earns its weight.
|
|
203
|
+
|
|
204
|
+
## Public surface
|
|
205
|
+
|
|
206
|
+
See [`src/index.ts`](./src/index.ts) for the full contract. Anything not exported there is internal and not subject to semver.
|
|
207
|
+
|
|
208
|
+
### Subpath exports
|
|
209
|
+
|
|
210
|
+
| Entry | Contents |
|
|
211
|
+
| -------------------------------- | ------------------------------------------------------------------ |
|
|
212
|
+
| `@rafters/astro-data` | Core types, primitives, `Cache` interface |
|
|
213
|
+
| `@rafters/astro-data/react` | `useLoaderData`, `useAction`, `useNavigation`, `useForm`, `<Form>` |
|
|
214
|
+
| `@rafters/astro-data/elements` | `LoaderConsumer`, `ActionConsumer`, `FormConsumer` controllers |
|
|
215
|
+
| `@rafters/astro-data/nanostores` | `createNanostoresCache` |
|
|
216
|
+
| `@rafters/astro-data/zustand` | `createZustandCache` |
|
|
217
|
+
|
|
218
|
+
## Why not TanStack Query?
|
|
219
|
+
|
|
220
|
+
TanStack Query solves the problem of _client-rendered apps with no server data_. Astro renders pages on the server — your initial data is already in the HTML, with no loading flash on first paint. Query's biggest value proposition doesn't apply.
|
|
221
|
+
|
|
222
|
+
What you still want — request dedup, optimistic updates, hierarchical revalidation, staleness control for long sessions — this package provides, sized for Astro's model.
|
|
223
|
+
|
|
224
|
+
If your app is a pure client SPA without Astro, use Query. If it's an Astro app with islands, use this. Different problem shapes, different tools.
|
|
225
|
+
|
|
226
|
+
## Supply chain
|
|
227
|
+
|
|
228
|
+
This package publishes via [npm trusted publishing](https://docs.npmjs.com/trusted-publishers) (OIDC from GitHub Actions). No long-lived `NPM_TOKEN` exists anywhere. Every release ships with [npm provenance attestations](https://docs.npmjs.com/generating-provenance-statements). The release workflow is in [`.github/workflows/release.yml`](./.github/workflows/release.yml) and is the authoritative source.
|
|
229
|
+
|
|
230
|
+
If you see a version of this package on npm without provenance, do not install it. Open an issue.
|
|
231
|
+
|
|
232
|
+
The package has zero runtime dependencies. Peer dependencies (`astro`, `react`, your chosen cache adapter) are listed minimally.
|
|
233
|
+
|
|
234
|
+
## Contributing
|
|
235
|
+
|
|
236
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT
|
package/dist/astro.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { APIContext } from "astro";
|
|
2
|
+
import type { z } from "astro/zod";
|
|
3
|
+
import type { ActionModule } from "./index.js";
|
|
4
|
+
type DefineActionFn = <I, O>(opts: {
|
|
5
|
+
input: z.ZodType<I>;
|
|
6
|
+
accept?: "json" | "form";
|
|
7
|
+
handler: (input: I, context: APIContext) => Promise<O>;
|
|
8
|
+
}) => unknown;
|
|
9
|
+
/**
|
|
10
|
+
* Register an action module with Astro's action system.
|
|
11
|
+
*
|
|
12
|
+
* Usage in `src/actions/index.ts`:
|
|
13
|
+
*
|
|
14
|
+
* import { defineAction } from "astro:actions"
|
|
15
|
+
* import { wrapAction } from "@rafters/astro-data/astro"
|
|
16
|
+
* import * as updateProfile from "../action-defs/update-profile"
|
|
17
|
+
*
|
|
18
|
+
* export const server = {
|
|
19
|
+
* updateProfile: wrapAction(defineAction, updateProfile),
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export declare function wrapAction<M extends ActionModule>(defineAction: DefineActionFn, module: M): unknown;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=astro.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astro.d.ts","sourceRoot":"","sources":["../src/astro.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,KAAK,cAAc,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE;IACjC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACxD,KAAK,OAAO,CAAC;AAEd;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,YAAY,EAC/C,YAAY,EAAE,cAAc,EAC5B,MAAM,EAAE,CAAC,GACR,OAAO,CAMT"}
|
package/dist/astro.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// @rafters/astro-data/astro — Astro-side helpers
|
|
2
|
+
//
|
|
3
|
+
// These helpers run inside an Astro project. The package itself can't import
|
|
4
|
+
// `astro:actions` (it's a virtual module Astro provides), so the consumer
|
|
5
|
+
// passes `defineAction` in.
|
|
6
|
+
/**
|
|
7
|
+
* Register an action module with Astro's action system.
|
|
8
|
+
*
|
|
9
|
+
* Usage in `src/actions/index.ts`:
|
|
10
|
+
*
|
|
11
|
+
* import { defineAction } from "astro:actions"
|
|
12
|
+
* import { wrapAction } from "@rafters/astro-data/astro"
|
|
13
|
+
* import * as updateProfile from "../action-defs/update-profile"
|
|
14
|
+
*
|
|
15
|
+
* export const server = {
|
|
16
|
+
* updateProfile: wrapAction(defineAction, updateProfile),
|
|
17
|
+
* }
|
|
18
|
+
*/
|
|
19
|
+
export function wrapAction(defineAction, module) {
|
|
20
|
+
return defineAction({
|
|
21
|
+
input: module.actionInput,
|
|
22
|
+
accept: module.accept,
|
|
23
|
+
handler: module.action,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=astro.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astro.js","sourceRoot":"","sources":["../src/astro.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,6EAA6E;AAC7E,0EAA0E;AAC1E,4BAA4B;AAY5B;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CACxB,YAA4B,EAC5B,MAAS;IAET,OAAO,YAAY,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC,WAAW;QACzB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,MAAM;KACvB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ActionInput, ActionModule, ActionOutput, LoaderModule, LoaderOutput } from "./index.js";
|
|
2
|
+
export declare class LoaderConsumer<M extends LoaderModule> {
|
|
3
|
+
constructor(_host: HTMLElement, _module: M, _onChange: (data: LoaderOutput<M> | undefined) => void);
|
|
4
|
+
disconnect(): void;
|
|
5
|
+
}
|
|
6
|
+
export declare class ActionConsumer<M extends ActionModule> {
|
|
7
|
+
constructor(_host: HTMLElement, _module: M);
|
|
8
|
+
run(_input: ActionInput<M>): Promise<ActionOutput<M>>;
|
|
9
|
+
get pending(): boolean;
|
|
10
|
+
get error(): Error | null;
|
|
11
|
+
get data(): ActionOutput<M> | null;
|
|
12
|
+
}
|
|
13
|
+
export declare class FormConsumer<M extends ActionModule> {
|
|
14
|
+
constructor(_host: HTMLFormElement, _module: M);
|
|
15
|
+
disconnect(): void;
|
|
16
|
+
get pending(): boolean;
|
|
17
|
+
get errors(): Readonly<Record<string, readonly string[]>>;
|
|
18
|
+
get data(): ActionOutput<M> | null;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=elements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.d.ts","sourceRoot":"","sources":["../src/elements.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc,CAAC,CAAC,SAAS,YAAY;gBAE9C,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,CAAC,EACV,SAAS,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,IAAI;IAIxD,UAAU,IAAI,IAAI;CAGnB;AAED,qBAAa,cAAc,CAAC,CAAC,SAAS,YAAY;gBACpC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;IAG1C,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAGrD,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,KAAK,IAAI,KAAK,GAAG,IAAI,CAExB;IACD,IAAI,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAEjC;CACF;AAED,qBAAa,YAAY,CAAC,CAAC,SAAS,YAAY;gBAClC,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC;IAG9C,UAAU,IAAI,IAAI;IAGlB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAExD;IACD,IAAI,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAEjC;CACF"}
|
package/dist/elements.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// @rafters/astro-data/elements — Web Components delivery
|
|
2
|
+
//
|
|
3
|
+
// Reactive controllers that subscribe to loaders and actions and update host
|
|
4
|
+
// elements. Consumers attach an instance in connectedCallback and call
|
|
5
|
+
// disconnect() in disconnectedCallback.
|
|
6
|
+
export class LoaderConsumer {
|
|
7
|
+
constructor(_host, _module, _onChange) {
|
|
8
|
+
throw new Error("not implemented");
|
|
9
|
+
}
|
|
10
|
+
disconnect() {
|
|
11
|
+
throw new Error("not implemented");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class ActionConsumer {
|
|
15
|
+
constructor(_host, _module) {
|
|
16
|
+
throw new Error("not implemented");
|
|
17
|
+
}
|
|
18
|
+
run(_input) {
|
|
19
|
+
throw new Error("not implemented");
|
|
20
|
+
}
|
|
21
|
+
get pending() {
|
|
22
|
+
throw new Error("not implemented");
|
|
23
|
+
}
|
|
24
|
+
get error() {
|
|
25
|
+
throw new Error("not implemented");
|
|
26
|
+
}
|
|
27
|
+
get data() {
|
|
28
|
+
throw new Error("not implemented");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class FormConsumer {
|
|
32
|
+
constructor(_host, _module) {
|
|
33
|
+
throw new Error("not implemented");
|
|
34
|
+
}
|
|
35
|
+
disconnect() {
|
|
36
|
+
throw new Error("not implemented");
|
|
37
|
+
}
|
|
38
|
+
get pending() {
|
|
39
|
+
throw new Error("not implemented");
|
|
40
|
+
}
|
|
41
|
+
get errors() {
|
|
42
|
+
throw new Error("not implemented");
|
|
43
|
+
}
|
|
44
|
+
get data() {
|
|
45
|
+
throw new Error("not implemented");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=elements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.js","sourceRoot":"","sources":["../src/elements.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,6EAA6E;AAC7E,uEAAuE;AACvE,wCAAwC;AAUxC,MAAM,OAAO,cAAc;IACzB,YACE,KAAkB,EAClB,OAAU,EACV,SAAsD;QAEtD,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,UAAU;QACR,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,cAAc;IACzB,YAAY,KAAkB,EAAE,OAAU;QACxC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,GAAG,CAAC,MAAsB;QACxB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,OAAO;QACT,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,KAAK;QACP,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,IAAI;QACN,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,YAAY;IACvB,YAAY,KAAsB,EAAE,OAAU;QAC5C,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,UAAU;QACR,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,OAAO;QACT,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,MAAM;QACR,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,IAAI;QACN,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { APIContext } from "astro";
|
|
2
|
+
import type { z } from "astro/zod";
|
|
3
|
+
export interface LoaderModule<I = unknown, O = unknown> {
|
|
4
|
+
loader: (args: LoaderArgs<I>) => Promise<O>;
|
|
5
|
+
/** Zod schema for runtime validation. Omit for parameter-less loaders. */
|
|
6
|
+
loaderInput?: z.ZodType<I>;
|
|
7
|
+
/** Hierarchical key. Required in v0.1 (filesystem derivation: v0.2). */
|
|
8
|
+
key: readonly string[];
|
|
9
|
+
/** 'layout' loaders are visible to nested pages; fetch in parallel on navigation. */
|
|
10
|
+
scope?: "page" | "layout";
|
|
11
|
+
/** ms before cached data is considered stale on subscribe. Default: Infinity. */
|
|
12
|
+
staleTime?: number;
|
|
13
|
+
/** Refetch when the window regains focus. Default: false. */
|
|
14
|
+
refetchOnFocus?: boolean;
|
|
15
|
+
/** Reserved for v0.2+ — declarative table reads for sync-driven revalidation. */
|
|
16
|
+
reads?: readonly unknown[];
|
|
17
|
+
}
|
|
18
|
+
export interface ActionModule<I = unknown, O = unknown> {
|
|
19
|
+
action: (input: I, context: APIContext) => Promise<O>;
|
|
20
|
+
/** Zod schema. Required because Astro's defineAction requires it. */
|
|
21
|
+
actionInput: z.ZodType<I>;
|
|
22
|
+
/** Forwards to Astro's defineAction. Default: 'json'. */
|
|
23
|
+
accept?: "json" | "form";
|
|
24
|
+
/** Hierarchical key arrays to invalidate on success. */
|
|
25
|
+
revalidates?: readonly (readonly string[])[];
|
|
26
|
+
}
|
|
27
|
+
export type DataModule = LoaderModule | ActionModule | (LoaderModule & ActionModule);
|
|
28
|
+
export interface LoaderArgs<I = unknown> {
|
|
29
|
+
input: I;
|
|
30
|
+
astro: APIContext;
|
|
31
|
+
}
|
|
32
|
+
export interface Cache {
|
|
33
|
+
get<T>(key: readonly string[]): T | undefined;
|
|
34
|
+
set<T>(key: readonly string[], value: T): void;
|
|
35
|
+
/** Hierarchical: prefix match invalidates all descendants. */
|
|
36
|
+
invalidate(key: readonly string[]): void;
|
|
37
|
+
subscribe(key: readonly string[], listener: () => void): () => void;
|
|
38
|
+
}
|
|
39
|
+
export declare function configure(opts: {
|
|
40
|
+
cache: Cache;
|
|
41
|
+
}): void;
|
|
42
|
+
export declare function createDataLayer(opts: {
|
|
43
|
+
cache: Cache;
|
|
44
|
+
}): DataLayer;
|
|
45
|
+
export interface DataLayer {
|
|
46
|
+
runLoader: typeof runLoader;
|
|
47
|
+
subscribeLoader: typeof subscribeLoader;
|
|
48
|
+
getLoaderData: typeof getLoaderData;
|
|
49
|
+
invalidate: (key: readonly string[]) => void;
|
|
50
|
+
cache: Cache;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Run a loader server-side. Validates input via loaderInput, calls loader,
|
|
54
|
+
* writes the result to the cache at the module's key, returns the value.
|
|
55
|
+
* Used in `.astro` frontmatter and in server islands.
|
|
56
|
+
*/
|
|
57
|
+
export declare function runLoader<M extends LoaderModule>(module: M, astro: APIContext, input?: LoaderInput<M>): Promise<LoaderOutput<M>>;
|
|
58
|
+
/** Subscribe to a loader's cached data. Fires on cache writes and invalidations. */
|
|
59
|
+
export declare function subscribeLoader<M extends LoaderModule>(module: M, listener: (data: LoaderOutput<M> | undefined) => void): () => void;
|
|
60
|
+
/** Synchronously read a loader's current cached value. */
|
|
61
|
+
export declare function getLoaderData<M extends LoaderModule>(module: M): LoaderOutput<M> | undefined;
|
|
62
|
+
/** Manually invalidate a key in the cache. Hierarchical: prefix matches invalidate descendants. */
|
|
63
|
+
export declare function invalidate(key: readonly string[]): void;
|
|
64
|
+
/** Set a loader's cached value directly (used to hydrate the client cache from SSR data). */
|
|
65
|
+
export declare function setLoaderData<M extends LoaderModule>(module: M, value: LoaderOutput<M>): void;
|
|
66
|
+
export type LoaderInput<M extends LoaderModule> = M["loaderInput"] extends z.ZodType<infer I> ? I : undefined;
|
|
67
|
+
export type LoaderOutput<M extends LoaderModule> = Awaited<ReturnType<M["loader"]>>;
|
|
68
|
+
export type ActionInput<M extends ActionModule> = M["actionInput"] extends z.ZodType<infer I> ? I : never;
|
|
69
|
+
export type ActionOutput<M extends ActionModule> = Awaited<ReturnType<M["action"]>>;
|
|
70
|
+
export type { APIContext } from "astro";
|
|
71
|
+
export { z } from "astro/zod";
|
|
72
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,WAAW,CAAC;AAKnC,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACpD,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5C,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,wEAAwE;IACxE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,KAAK,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACpD,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACtD,qEAAqE;IACrE,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1B,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,wDAAwD;IACxD,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;CAC9C;AAED,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,YAAY,GAAG,CAAC,YAAY,GAAG,YAAY,CAAC,CAAC;AAIrF,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,OAAO;IACrC,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,UAAU,CAAC;CACnB;AAID,MAAM,WAAW,KAAK;IACpB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;IAC9C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAC/C,8DAA8D;IAC9D,UAAU,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACzC,SAAS,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CACrE;AAID,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAAI,CAEtD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,SAAS,CAgBjE;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,UAAU,EAAE,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,KAAK,EAAE,KAAK,CAAC;CACd;AAoDD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,YAAY,EAC9C,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,UAAU,EACjB,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAE1B;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,CAAC,SAAS,YAAY,EACpD,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,IAAI,GACpD,MAAM,IAAI,CAEZ;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,CAAC,SAAS,YAAY,EAClD,MAAM,EAAE,CAAC,GACR,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAE7B;AAED,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAEvD;AAED,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,CAAC,SAAS,YAAY,EAClD,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GACrB,IAAI,CAEN;AAID,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,YAAY,IAC5C,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;AAE9D,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEpF,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,YAAY,IAC5C,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE1D,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAIpF,YAAY,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,CAAC,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// @rafters/astro-data — public API
|
|
2
|
+
//
|
|
3
|
+
// The loader and action contract on top of Astro 6.
|
|
4
|
+
// Everything exported here is part of the public surface and subject to semver.
|
|
5
|
+
// Anything under ./internal/ is implementation detail.
|
|
6
|
+
import { defaultState } from "./internal/state.js";
|
|
7
|
+
// ─── Configuration ─────────────────────────────────────────────────────────
|
|
8
|
+
export function configure(opts) {
|
|
9
|
+
defaultState.cache = opts.cache;
|
|
10
|
+
}
|
|
11
|
+
export function createDataLayer(opts) {
|
|
12
|
+
const state = {
|
|
13
|
+
cache: opts.cache,
|
|
14
|
+
actionStates: new Map(),
|
|
15
|
+
actionListeners: new Map(),
|
|
16
|
+
navigation: { pending: false, revalidating: [] },
|
|
17
|
+
navigationListeners: new Set(),
|
|
18
|
+
pendingRevalidations: new Map(),
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
runLoader: ((module, astro, input) => runLoaderWith(state, module, astro, input)),
|
|
22
|
+
subscribeLoader: ((module, listener) => subscribeLoaderWith(state, module, listener)),
|
|
23
|
+
getLoaderData: ((module) => getLoaderDataWith(state, module)),
|
|
24
|
+
invalidate: (key) => invalidateWith(state, key),
|
|
25
|
+
cache: opts.cache,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// ─── Primitives ────────────────────────────────────────────────────────────
|
|
29
|
+
function getCache(state) {
|
|
30
|
+
if (!state.cache) {
|
|
31
|
+
throw new Error("@rafters/astro-data: configure({ cache }) must be called before runtime use");
|
|
32
|
+
}
|
|
33
|
+
return state.cache;
|
|
34
|
+
}
|
|
35
|
+
async function runLoaderWith(state, module, astro, input) {
|
|
36
|
+
const validated = module.loaderInput
|
|
37
|
+
? module.loaderInput.parse(input)
|
|
38
|
+
: undefined;
|
|
39
|
+
const result = (await module.loader({
|
|
40
|
+
input: validated,
|
|
41
|
+
astro,
|
|
42
|
+
}));
|
|
43
|
+
getCache(state).set(module.key, result);
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
function subscribeLoaderWith(state, module, listener) {
|
|
47
|
+
const cache = getCache(state);
|
|
48
|
+
return cache.subscribe(module.key, () => {
|
|
49
|
+
listener(cache.get(module.key));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function getLoaderDataWith(state, module) {
|
|
53
|
+
return getCache(state).get(module.key);
|
|
54
|
+
}
|
|
55
|
+
function invalidateWith(state, key) {
|
|
56
|
+
getCache(state).invalidate(key);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Run a loader server-side. Validates input via loaderInput, calls loader,
|
|
60
|
+
* writes the result to the cache at the module's key, returns the value.
|
|
61
|
+
* Used in `.astro` frontmatter and in server islands.
|
|
62
|
+
*/
|
|
63
|
+
export function runLoader(module, astro, input) {
|
|
64
|
+
return runLoaderWith(defaultState, module, astro, input);
|
|
65
|
+
}
|
|
66
|
+
/** Subscribe to a loader's cached data. Fires on cache writes and invalidations. */
|
|
67
|
+
export function subscribeLoader(module, listener) {
|
|
68
|
+
return subscribeLoaderWith(defaultState, module, listener);
|
|
69
|
+
}
|
|
70
|
+
/** Synchronously read a loader's current cached value. */
|
|
71
|
+
export function getLoaderData(module) {
|
|
72
|
+
return getLoaderDataWith(defaultState, module);
|
|
73
|
+
}
|
|
74
|
+
/** Manually invalidate a key in the cache. Hierarchical: prefix matches invalidate descendants. */
|
|
75
|
+
export function invalidate(key) {
|
|
76
|
+
invalidateWith(defaultState, key);
|
|
77
|
+
}
|
|
78
|
+
/** Set a loader's cached value directly (used to hydrate the client cache from SSR data). */
|
|
79
|
+
export function setLoaderData(module, value) {
|
|
80
|
+
getCache(defaultState).set(module.key, value);
|
|
81
|
+
}
|
|
82
|
+
export { z } from "astro/zod";
|
|
83
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-memory.d.ts","sourceRoot":"","sources":["../../src/internal/cache-memory.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAgBzC,wBAAgB,iBAAiB,IAAI,KAAK,CAuDzC"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-memory.js","sourceRoot":"","sources":["../../src/internal/cache-memory.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,EAAE;AACF,qEAAqE;AACrE,4DAA4D;AAC5D,EAAE;AACF,sEAAsE;AACtE,qEAAqE;AACrE,yCAAyC;AAMzC,SAAS,KAAK,CAAC,GAAsB;IACnC,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,YAAY,CAAC,MAAyB,EAAE,MAAyB;IACxE,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAC5C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAyB,CAAC;IACrD,MAAM,cAAc,GAAG,IAAI,GAAG,EAA6B,CAAC;IAE5D,SAAS,iBAAiB,CAAC,MAAyB;QAClD,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,WAAW,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,MAAM,IAAI,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;gBAC3C,KAAK,MAAM,QAAQ,IAAI,SAAS;oBAAE,QAAQ,EAAE,CAAC;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG,CAAI,GAAsB;YAC3B,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAkB,CAAC;QACjD,CAAC;QAED,GAAG,CAAI,GAAsB,EAAE,KAAQ;YACrC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;YAC9B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9C,IAAI,SAAS;gBAAE,KAAK,MAAM,QAAQ,IAAI,SAAS;oBAAE,QAAQ,EAAE,CAAC;QAC9D,CAAC;QAED,UAAU,CAAC,GAAsB;YAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1B,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC/C,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;oBACzD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;YACD,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAED,SAAS,CAAC,GAAsB,EAAE,QAAkB;YAClD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YACxB,IAAI,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;gBAChB,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAC3B,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAChC,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAClB,OAAO,GAAG,EAAE;gBACV,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACtC,IAAI,CAAC,OAAO;oBAAE,OAAO;gBACrB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACzB,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBACvB,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACzB,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Cache } from "../index.js";
|
|
2
|
+
type ActionStateEntry = {
|
|
3
|
+
pending: boolean;
|
|
4
|
+
error: Error | null;
|
|
5
|
+
data: unknown;
|
|
6
|
+
};
|
|
7
|
+
type NavigationState = {
|
|
8
|
+
pending: boolean;
|
|
9
|
+
revalidating: readonly (readonly string[])[];
|
|
10
|
+
};
|
|
11
|
+
export interface RuntimeState {
|
|
12
|
+
cache: Cache | null;
|
|
13
|
+
actionStates: Map<unknown, ActionStateEntry>;
|
|
14
|
+
actionListeners: Map<unknown, Set<() => void>>;
|
|
15
|
+
navigation: NavigationState;
|
|
16
|
+
navigationListeners: Set<() => void>;
|
|
17
|
+
pendingRevalidations: Map<string, readonly string[]>;
|
|
18
|
+
}
|
|
19
|
+
export declare function createRuntimeState(): RuntimeState;
|
|
20
|
+
export declare const defaultState: RuntimeState;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/internal/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,KAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;CAC9C,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,YAAY,EAAE,GAAG,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAC7C,eAAe,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAC/C,UAAU,EAAE,eAAe,CAAC;IAC5B,mBAAmB,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IACrC,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;CACtD;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CASjD;AAED,eAAO,MAAM,YAAY,EAAE,YAAmC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Module-scoped singletons for default DataLayer.
|
|
2
|
+
// configure({ cache }) sets these; createDataLayer returns an isolated copy.
|
|
3
|
+
export function createRuntimeState() {
|
|
4
|
+
return {
|
|
5
|
+
cache: null,
|
|
6
|
+
actionStates: new Map(),
|
|
7
|
+
actionListeners: new Map(),
|
|
8
|
+
navigation: { pending: false, revalidating: [] },
|
|
9
|
+
navigationListeners: new Set(),
|
|
10
|
+
pendingRevalidations: new Map(),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export const defaultState = createRuntimeState();
|
|
14
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/internal/state.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,6EAA6E;AAwB7E,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,KAAK,EAAE,IAAI;QACX,YAAY,EAAE,IAAI,GAAG,EAAE;QACvB,eAAe,EAAE,IAAI,GAAG,EAAE;QAC1B,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE;QAChD,mBAAmB,EAAE,IAAI,GAAG,EAAE;QAC9B,oBAAoB,EAAE,IAAI,GAAG,EAAE;KAChC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAiB,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Cache } from "./index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Factory shape the cache adapter consumes.
|
|
4
|
+
*
|
|
5
|
+
* v0.1 ships a loose type pending smugglr's nanostores bridge API.
|
|
6
|
+
* When smugglr's surface lands, this narrows without a public-API break
|
|
7
|
+
* for consumers using the default factory.
|
|
8
|
+
*/
|
|
9
|
+
export interface NanostoresStoreFactory {
|
|
10
|
+
createMap<T>(initial?: T): unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface NanostoresCacheOptions {
|
|
13
|
+
/** Reserved: pass smugglr's nanostores bridge here for local-first storage. */
|
|
14
|
+
store?: NanostoresStoreFactory;
|
|
15
|
+
}
|
|
16
|
+
export declare function createNanostoresCache(_opts?: NanostoresCacheOptions): Cache;
|
|
17
|
+
//# sourceMappingURL=nanostores.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nanostores.d.ts","sourceRoot":"","sources":["../src/nanostores.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,sBAAsB;IACrC,+EAA+E;IAC/E,KAAK,CAAC,EAAE,sBAAsB,CAAC;CAChC;AAED,wBAAgB,qBAAqB,CAAC,KAAK,CAAC,EAAE,sBAAsB,GAAG,KAAK,CAG3E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @rafters/astro-data/nanostores — Cache adapter
|
|
2
|
+
//
|
|
3
|
+
// v0.1 wraps an in-memory hierarchical cache. The `store` parameter is the
|
|
4
|
+
// composition seam where smugglr's nanostores bridge slots in for local-first
|
|
5
|
+
// persistence and sync. Until smugglr's bridge API lands, the parameter is
|
|
6
|
+
// reserved and the adapter behaves as in-memory.
|
|
7
|
+
import { createMemoryCache } from "./internal/cache-memory.js";
|
|
8
|
+
export function createNanostoresCache(_opts) {
|
|
9
|
+
// v0.1: backed by in-memory cache. Smugglr bridge composition lands in v0.2.
|
|
10
|
+
return createMemoryCache();
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=nanostores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nanostores.js","sourceRoot":"","sources":["../src/nanostores.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,2EAA2E;AAC3E,iDAAiD;AAGjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAkB/D,MAAM,UAAU,qBAAqB,CAAC,KAA8B;IAClE,6EAA6E;IAC7E,OAAO,iBAAiB,EAAE,CAAC;AAC7B,CAAC"}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { JSX, ReactNode } from "react";
|
|
2
|
+
import { type ActionInput, type ActionModule, type ActionOutput, type LoaderModule, type LoaderOutput } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Subscribe to a loader's cached value. On first mount, the provided initial
|
|
5
|
+
* value is written to the cache so other islands subscribing to the same
|
|
6
|
+
* loader key see consistent state.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useLoaderData<M extends LoaderModule>(module: M, initial?: LoaderOutput<M>): LoaderOutput<M>;
|
|
9
|
+
/** Shape mirroring what `astro:actions`' generated action handles return. */
|
|
10
|
+
export type AstroActionResult<O> = {
|
|
11
|
+
data?: O;
|
|
12
|
+
error?: unknown;
|
|
13
|
+
};
|
|
14
|
+
export type AstroActionFn<I, O> = (input: I) => Promise<AstroActionResult<O>>;
|
|
15
|
+
export interface UseActionResult<M extends ActionModule> {
|
|
16
|
+
run: (input: ActionInput<M>) => Promise<AstroActionResult<ActionOutput<M>>>;
|
|
17
|
+
pending: boolean;
|
|
18
|
+
error: unknown;
|
|
19
|
+
data: ActionOutput<M> | null;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Wrap an Astro action handle with revalidation. Pass the action handle
|
|
24
|
+
* imported from `astro:actions` and the corresponding action module — the
|
|
25
|
+
* module's `revalidates` keys are invalidated on success.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useAction<M extends ActionModule>(astroAction: AstroActionFn<ActionInput<M>, ActionOutput<M>>, module: M): UseActionResult<M>;
|
|
28
|
+
export interface FormProps<M extends ActionModule> {
|
|
29
|
+
astroAction: AstroActionFn<ActionInput<M>, ActionOutput<M>>;
|
|
30
|
+
module: M;
|
|
31
|
+
children: ReactNode;
|
|
32
|
+
onSuccess?: (data: ActionOutput<M>) => void;
|
|
33
|
+
onError?: (error: unknown) => void;
|
|
34
|
+
className?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Bare-bones form wrapper. Intercepts submit, builds FormData -> object,
|
|
38
|
+
* calls the action through useAction (which handles revalidation), and
|
|
39
|
+
* fires onSuccess / onError. Consumers write their own <input> elements.
|
|
40
|
+
*
|
|
41
|
+
* Compose with kelex to generate the inputs from the action's Zod schema.
|
|
42
|
+
*/
|
|
43
|
+
export declare function Form<M extends ActionModule>(props: FormProps<M>): JSX.Element;
|
|
44
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EAKlB,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,YAAY,EAClD,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,GACxB,YAAY,CAAC,CAAC,CAAC,CAyBjB;AAED,6EAA6E;AAC7E,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AACjE,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9E,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,YAAY;IACrD,GAAG,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,YAAY,EAC9C,WAAW,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,EAC3D,MAAM,EAAE,CAAC,GACR,eAAe,CAAC,CAAC,CAAC,CAqCpB;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,YAAY;IAC/C,WAAW,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,YAAY,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CA0B7E"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @rafters/astro-data/react — React delivery
|
|
3
|
+
//
|
|
4
|
+
// Hooks subscribe to the cache via useSyncExternalStore. useAction wraps an
|
|
5
|
+
// Astro action handle and invalidates the module's revalidates keys after
|
|
6
|
+
// success.
|
|
7
|
+
import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
8
|
+
import { getLoaderData, invalidate, setLoaderData, subscribeLoader, } from "./index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Subscribe to a loader's cached value. On first mount, the provided initial
|
|
11
|
+
* value is written to the cache so other islands subscribing to the same
|
|
12
|
+
* loader key see consistent state.
|
|
13
|
+
*/
|
|
14
|
+
export function useLoaderData(module, initial) {
|
|
15
|
+
const hydratedRef = useRef(false);
|
|
16
|
+
if (!hydratedRef.current && initial !== undefined) {
|
|
17
|
+
setLoaderData(module, initial);
|
|
18
|
+
hydratedRef.current = true;
|
|
19
|
+
}
|
|
20
|
+
const subscribe = useCallback((listener) => subscribeLoader(module, listener), [module]);
|
|
21
|
+
const getSnapshot = useCallback(() => getLoaderData(module) ?? initial, [module, initial]);
|
|
22
|
+
const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
23
|
+
if (value === undefined) {
|
|
24
|
+
throw new Error(`@rafters/astro-data/react: useLoaderData called for ${JSON.stringify(module.key)} with no cached value and no initial`);
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Wrap an Astro action handle with revalidation. Pass the action handle
|
|
30
|
+
* imported from `astro:actions` and the corresponding action module — the
|
|
31
|
+
* module's `revalidates` keys are invalidated on success.
|
|
32
|
+
*/
|
|
33
|
+
export function useAction(astroAction, module) {
|
|
34
|
+
const [pending, setPending] = useState(false);
|
|
35
|
+
const [error, setError] = useState(null);
|
|
36
|
+
const [data, setData] = useState(null);
|
|
37
|
+
const run = useCallback(async (input) => {
|
|
38
|
+
setPending(true);
|
|
39
|
+
setError(null);
|
|
40
|
+
try {
|
|
41
|
+
const result = await astroAction(input);
|
|
42
|
+
if (result.error) {
|
|
43
|
+
setError(result.error);
|
|
44
|
+
}
|
|
45
|
+
else if (result.data !== undefined) {
|
|
46
|
+
setData(result.data);
|
|
47
|
+
if (module.revalidates) {
|
|
48
|
+
for (const key of module.revalidates)
|
|
49
|
+
invalidate(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
setError(e);
|
|
56
|
+
return { error: e };
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
setPending(false);
|
|
60
|
+
}
|
|
61
|
+
}, [astroAction, module]);
|
|
62
|
+
const reset = useCallback(() => {
|
|
63
|
+
setPending(false);
|
|
64
|
+
setError(null);
|
|
65
|
+
setData(null);
|
|
66
|
+
}, []);
|
|
67
|
+
return { run, pending, error, data, reset };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Bare-bones form wrapper. Intercepts submit, builds FormData -> object,
|
|
71
|
+
* calls the action through useAction (which handles revalidation), and
|
|
72
|
+
* fires onSuccess / onError. Consumers write their own <input> elements.
|
|
73
|
+
*
|
|
74
|
+
* Compose with kelex to generate the inputs from the action's Zod schema.
|
|
75
|
+
*/
|
|
76
|
+
export function Form(props) {
|
|
77
|
+
const { astroAction, module, children, onSuccess, onError, className } = props;
|
|
78
|
+
const action = useAction(astroAction, module);
|
|
79
|
+
const handleSubmit = useCallback(async (event) => {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
const formData = new FormData(event.currentTarget);
|
|
82
|
+
const payload = Object.fromEntries(formData.entries());
|
|
83
|
+
const result = await action.run(payload);
|
|
84
|
+
if (result.error)
|
|
85
|
+
onError?.(result.error);
|
|
86
|
+
else if (result.data !== undefined)
|
|
87
|
+
onSuccess?.(result.data);
|
|
88
|
+
}, [action, onSuccess, onError]);
|
|
89
|
+
// Hint for kelex / consumers wiring per-field state via context (v0.2).
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
// Reserved for future field-error context provider.
|
|
92
|
+
}, []);
|
|
93
|
+
return (_jsx("form", { className: className, onSubmit: handleSubmit, children: children }));
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":";AAAA,6CAA6C;AAC7C,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,WAAW;AAEX,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAEvF,OAAO,EAML,aAAa,EACb,UAAU,EACV,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAS,EACT,OAAyB;IAEzB,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAClD,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,QAAoB,EAAE,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,EAC3D,CAAC,MAAM,CAAC,CACT,CAAC;IACF,MAAM,WAAW,GAAG,WAAW,CAC7B,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,OAAO,EACtC,CAAC,MAAM,EAAE,OAAO,CAAC,CAClB,CAAC;IAEF,MAAM,KAAK,GAAG,oBAAoB,CAAC,SAAS,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IACxE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,uDAAuD,IAAI,CAAC,SAAS,CACnE,MAAM,CAAC,GAAG,CACX,sCAAsC,CACxC,CAAC;IACJ,CAAC;IACD,OAAO,KAAwB,CAAC;AAClC,CAAC;AAcD;;;;GAIG;AACH,MAAM,UAAU,SAAS,CACvB,WAA2D,EAC3D,MAAS;IAET,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAU,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAC;IAE/D,MAAM,GAAG,GAAG,WAAW,CACrB,KAAK,EAAE,KAAqB,EAA+C,EAAE;QAC3E,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;iBAAM,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBACrC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACrB,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;oBACvB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW;wBAAE,UAAU,CAAC,GAAG,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,QAAQ,CAAC,CAAC,CAAC,CAAC;YACZ,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,EACD,CAAC,WAAW,EAAE,MAAM,CAAC,CACtB,CAAC;IAEF,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,UAAU,CAAC,KAAK,CAAC,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC9C,CAAC;AAWD;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAyB,KAAmB;IAC9D,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAC/E,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAE9C,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,KAAuC,EAAE,EAAE;QAChD,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAmB,CAAC;QACzE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;aACrC,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC,EACD,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAC7B,CAAC;IAEF,wEAAwE;IACxE,SAAS,CAAC,GAAG,EAAE;QACb,oDAAoD;IACtD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,eAAM,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,YAC/C,QAAQ,GACJ,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Cache } from "./index.js";
|
|
2
|
+
export interface ZustandStoreFactory {
|
|
3
|
+
createStore<T>(initial?: T): unknown;
|
|
4
|
+
}
|
|
5
|
+
export interface ZustandCacheOptions {
|
|
6
|
+
store?: ZustandStoreFactory;
|
|
7
|
+
}
|
|
8
|
+
export declare function createZustandCache(_opts?: ZustandCacheOptions): Cache;
|
|
9
|
+
//# sourceMappingURL=zustand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zustand.d.ts","sourceRoot":"","sources":["../src/zustand.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAErE"}
|
package/dist/zustand.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// @rafters/astro-data/zustand — Cache adapter
|
|
2
|
+
//
|
|
3
|
+
// v0.1 wraps an in-memory hierarchical cache. The `store` parameter is the
|
|
4
|
+
// composition seam where smugglr's zustand bridge slots in for local-first
|
|
5
|
+
// persistence and sync.
|
|
6
|
+
import { createMemoryCache } from "./internal/cache-memory.js";
|
|
7
|
+
export function createZustandCache(_opts) {
|
|
8
|
+
return createMemoryCache();
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=zustand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zustand.js","sourceRoot":"","sources":["../src/zustand.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,wBAAwB;AAGxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAU/D,MAAM,UAAU,kBAAkB,CAAC,KAA2B;IAC5D,OAAO,iBAAiB,EAAE,CAAC;AAC7B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rafters/astro-data",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "The loader and action contract Astro is missing. Composes with smugglr for local-first, with kelex for schema-generated forms.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"action",
|
|
7
|
+
"astro",
|
|
8
|
+
"data",
|
|
9
|
+
"loader",
|
|
10
|
+
"local-first",
|
|
11
|
+
"rafters"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
"CHANGELOG.md"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./astro": {
|
|
27
|
+
"types": "./dist/astro.d.ts",
|
|
28
|
+
"import": "./dist/astro.js"
|
|
29
|
+
},
|
|
30
|
+
"./react": {
|
|
31
|
+
"types": "./dist/react.d.ts",
|
|
32
|
+
"import": "./dist/react.js"
|
|
33
|
+
},
|
|
34
|
+
"./elements": {
|
|
35
|
+
"types": "./dist/elements.d.ts",
|
|
36
|
+
"import": "./dist/elements.js"
|
|
37
|
+
},
|
|
38
|
+
"./nanostores": {
|
|
39
|
+
"types": "./dist/nanostores.d.ts",
|
|
40
|
+
"import": "./dist/nanostores.js"
|
|
41
|
+
},
|
|
42
|
+
"./zustand": {
|
|
43
|
+
"types": "./dist/zustand.d.ts",
|
|
44
|
+
"import": "./dist/zustand.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc -p tsconfig.build.json",
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"lint": "oxlint",
|
|
51
|
+
"format": "oxfmt",
|
|
52
|
+
"format:check": "oxfmt --check",
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:spec": "vitest run --config vitest.browser.config.ts",
|
|
55
|
+
"test:all": "pnpm test && pnpm test:spec",
|
|
56
|
+
"verify": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm test"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@changesets/cli": "^2.27.0",
|
|
60
|
+
"@types/react": "^19.0.0",
|
|
61
|
+
"@vitest/browser": "^4.1.0",
|
|
62
|
+
"astro": "^6.1.9",
|
|
63
|
+
"lefthook": "^2.1.4",
|
|
64
|
+
"nanostores": "^1.0.0",
|
|
65
|
+
"oxfmt": "^0.41.0",
|
|
66
|
+
"oxlint": "^1.56.0",
|
|
67
|
+
"playwright": "^1.49.0",
|
|
68
|
+
"react": "^19.2.5",
|
|
69
|
+
"react-dom": "^19.2.5",
|
|
70
|
+
"typescript": "^5.9.3",
|
|
71
|
+
"vitest": "^4.1.0",
|
|
72
|
+
"zustand": "^5.0.0"
|
|
73
|
+
},
|
|
74
|
+
"peerDependencies": {
|
|
75
|
+
"astro": "^6.0.0",
|
|
76
|
+
"nanostores": "^1.0.0",
|
|
77
|
+
"react": "^19.0.0",
|
|
78
|
+
"react-dom": "^19.0.0",
|
|
79
|
+
"zustand": "^5.0.0"
|
|
80
|
+
},
|
|
81
|
+
"peerDependenciesMeta": {
|
|
82
|
+
"nanostores": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"react": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"react-dom": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"zustand": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"engines": {
|
|
96
|
+
"node": ">=22"
|
|
97
|
+
},
|
|
98
|
+
"packageManager": "pnpm@10.32.1"
|
|
99
|
+
}
|