@agentshouse/mdruntime-families 0.0.0-stage → 0.1.0-c057d9ec05303

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anton (trof3039)
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 CHANGED
@@ -1,3 +1,55 @@
1
- # Temporary Holding Version
1
+ # `@agentshouse/mdruntime-families`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ react-admin and Refine data providers over the
4
+ [`@agentshouse/mdruntime`](https://www.npmjs.com/package/@agentshouse/mdruntime)
5
+ client, so an App built on either framework reads and writes its Rooms.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @agentshouse/mdruntime-families @agentshouse/mdruntime
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Each resource names the MD Type of its records and the folder they live in.
16
+ A record's id is its Path in the Room, prefixed by the Room's locator and `/`
17
+ when the App reaches several Rooms; a new record is created in the first.
18
+
19
+ ```ts
20
+ import { QueryClient } from '@tanstack/react-query';
21
+ import { dataProvider } from '@agentshouse/mdruntime-families/react-admin';
22
+
23
+ const resources = { contacts: { type: 'contact', folder: 'contacts' } };
24
+ const queryClient = new QueryClient();
25
+ const provider = dataProvider(runtime, { resources, queryClient });
26
+ // <Admin dataProvider={provider} queryClient={queryClient}>
27
+ ```
28
+
29
+ ```ts
30
+ import { dataProvider, liveProvider } from '@agentshouse/mdruntime-families/refine';
31
+
32
+ // <Refine dataProvider={dataProvider(runtime, { resources })}
33
+ // liveProvider={liveProvider(runtime, { resources })} options={{ liveMode: 'auto' }}>
34
+ ```
35
+
36
+ `runtime` is the client the host hands the App. A filter or sort field such
37
+ as `address.city` reads the value at `/address/city`. react-admin filters
38
+ compare for equality, a list for membership, and the suffixes `_gt`, `_gte`,
39
+ `_lt`, `_lte` and `_neq` compare as named; Refine filters take `eq`, `ne`,
40
+ `lt`, `gt`, `lte`, `gte`, `in`, `nin`, `or` and `and`. A field the Room schema
41
+ declares a reference, at any depth, holds the referenced record's id; `id` and
42
+ a reference compare only for equality and membership. Pages and totals are
43
+ counted over every matching record, and a page reads only its own window of
44
+ the Room; a list asked for without a page reads every record, window by
45
+ window. react-admin's `update` writes the fields
46
+ that differ from `previousData`, based on it, so the Save of a field another
47
+ writer changed meanwhile is refused; Refine's `update` and either `updateMany`
48
+ compare with the stored record. A list stays current: react-admin's queries of
49
+ a resource are invalidated, and Refine's live mode refetches, when a record a
50
+ page or a read shows changes, a record a filter names starts or stops matching
51
+ it, or a page's total changes.
52
+
53
+ ## License
54
+
55
+ MIT
@@ -0,0 +1,15 @@
1
+ import type { MdRuntimeClient } from '@agentshouse/mdruntime/client';
2
+ import type { DataProvider } from 'ra-core';
3
+ import { type Resources } from './records.js';
4
+ export type { Resource, Resources } from './records.js';
5
+ export type Invalidating = {
6
+ invalidateQueries(filters: {
7
+ queryKey: readonly unknown[];
8
+ }): Promise<unknown>;
9
+ };
10
+ export type DataProviderOptions = {
11
+ readonly resources: Resources;
12
+ readonly queryClient: Invalidating;
13
+ };
14
+ export declare function dataProvider(client: MdRuntimeClient, options: DataProviderOptions): DataProvider;
15
+ //# sourceMappingURL=react-admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-admin.d.ts","sourceRoot":"","sources":["../src/react-admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAEV,YAAY,EAYb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE5F,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,MAAM,YAAY,GAAG;IACzB,iBAAiB,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChF,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;CACpC,CAAC;AAgCF,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAqFhG"}
@@ -0,0 +1,79 @@
1
+ import { records } from './records.js';
2
+ const OPERATORS = [
3
+ ['_gte', '$gte'],
4
+ ['_gt', '$gt'],
5
+ ['_lte', '$lte'],
6
+ ['_lt', '$lt'],
7
+ ['_neq', '$ne'],
8
+ ];
9
+ function clause(key, value) {
10
+ const list = Array.isArray(value);
11
+ const operator = OPERATORS.find(([suffix]) => key.endsWith(suffix));
12
+ if (operator === undefined)
13
+ return { field: key, operator: list ? '$in' : '$eq', value };
14
+ return {
15
+ field: key.slice(0, -operator[0].length),
16
+ operator: list && operator[1] === '$ne' ? '$nin' : operator[1],
17
+ value,
18
+ };
19
+ }
20
+ function pageOf(pagination) {
21
+ if (pagination === undefined)
22
+ return null;
23
+ return { start: (pagination.page - 1) * pagination.perPage, size: pagination.perPage };
24
+ }
25
+ export function dataProvider(client, options) {
26
+ const held = records(client, options.resources);
27
+ const live = new Map();
28
+ function watched(resource) {
29
+ const known = live.get(resource);
30
+ if (known !== undefined)
31
+ return known;
32
+ const watching = held.watch(resource, () => {
33
+ void options.queryClient.invalidateQueries({ queryKey: [resource] });
34
+ });
35
+ live.set(resource, watching);
36
+ watching.catch(() => live.delete(resource));
37
+ return watching;
38
+ }
39
+ async function listed(resource, { filter, sort, pagination }) {
40
+ await watched(resource);
41
+ const named = Object.entries(filter ?? {});
42
+ const { entries, total } = await held.list(resource, named.length === 0 ? null : { every: named.map(([key, value]) => clause(key, value)) }, sort === undefined
43
+ ? []
44
+ : [{ field: sort.field, direction: sort.order === 'DESC' ? 'desc' : 'asc' }], pageOf(pagination));
45
+ return { data: [...entries], total };
46
+ }
47
+ return {
48
+ getList: async (resource, params) => (await listed(resource, params)),
49
+ getOne: async (resource, { id }) => {
50
+ await watched(resource);
51
+ return { data: await held.one(resource, id) };
52
+ },
53
+ getMany: async (resource, { ids }) => {
54
+ await watched(resource);
55
+ return { data: await held.many(resource, ids) };
56
+ },
57
+ getManyReference: async (resource, { target, id, filter, ...listing }) => (await listed(resource, {
58
+ ...listing,
59
+ filter: { ...filter, [target]: id },
60
+ })),
61
+ create: async (resource, { data }) => ({ data: await held.create(resource, data) }),
62
+ update: async (resource, { id, data, previousData }) => {
63
+ const [entry] = await held.update(resource, [id], data, previousData);
64
+ return { data: entry };
65
+ },
66
+ updateMany: async (resource, { ids, data }) => {
67
+ await held.update(resource, ids, data, null);
68
+ return { data: ids };
69
+ },
70
+ delete: async (resource, { id }) => {
71
+ const [entry] = await held.remove(resource, [id]);
72
+ return { data: entry };
73
+ },
74
+ deleteMany: async (resource, { ids }) => {
75
+ await held.remove(resource, ids);
76
+ return { data: ids };
77
+ },
78
+ };
79
+ }
@@ -0,0 +1,44 @@
1
+ import type { MdRuntimeClient } from '@agentshouse/mdruntime/client';
2
+ export type Resource = {
3
+ readonly type: string;
4
+ readonly folder: string;
5
+ };
6
+ export type Resources = Readonly<Record<string, Resource>>;
7
+ export type Key = string | number;
8
+ export type Fields = Readonly<Record<string, unknown>>;
9
+ export type Entry = {
10
+ readonly id: string;
11
+ readonly [field: string]: unknown;
12
+ };
13
+ export type Order = {
14
+ readonly field: string;
15
+ readonly direction: 'asc' | 'desc';
16
+ };
17
+ export type Operator = '$eq' | '$ne' | '$gt' | '$gte' | '$lt' | '$lte' | '$in' | '$nin';
18
+ export type Clause = {
19
+ readonly every: readonly Clause[];
20
+ } | {
21
+ readonly some: readonly Clause[];
22
+ } | {
23
+ readonly field: string;
24
+ readonly operator: Operator;
25
+ readonly value: unknown;
26
+ };
27
+ export type Page = {
28
+ readonly start: number;
29
+ readonly size: number;
30
+ };
31
+ export type Listed = {
32
+ readonly entries: readonly Entry[];
33
+ readonly total: number;
34
+ };
35
+ export declare function records(client: MdRuntimeClient, resources: Resources): {
36
+ list(name: string, clause: Clause | null, order: readonly Order[], page: Page | null): Promise<Listed>;
37
+ many(name: string, ids: readonly Key[]): Promise<Entry[]>;
38
+ one(name: string, id: Key): Promise<Entry>;
39
+ create(name: string, data: Fields): Promise<Entry>;
40
+ update(name: string, ids: readonly Key[], data: Fields, shown: Fields | null): Promise<Entry[]>;
41
+ remove(name: string, ids: readonly Key[]): Promise<Entry[]>;
42
+ watch(name: string, heard: () => void): Promise<() => void>;
43
+ };
44
+ //# sourceMappingURL=records.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../src/records.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE3D,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC;AAElC,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvD,MAAM,MAAM,KAAK,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE/E,MAAM,MAAM,KAAK,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;CAAE,CAAC;AAEnF,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAExF,MAAM,MAAM,MAAM,GACd;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACrC;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACpC;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAErF,MAAM,MAAM,IAAI,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,MAAM,MAAM,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAiTpF,wBAAgB,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS;IAob3D,IAAI,OACF,MAAM,UACJ,MAAM,GAAG,IAAI,SACd,SAAS,KAAK,EAAE,QACjB,IAAI,GAAG,IAAI,GAChB,OAAO,CAAC,MAAM,CAAC;IAuBZ,IAAI,OAAO,MAAM,OAAO,SAAS,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAOzD,GAAG,OAAO,MAAM,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC;IAM1C,MAAM,OAAO,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAqBlD,MAAM,OACJ,MAAM,OACP,SAAS,GAAG,EAAE,QACb,MAAM,SACL,MAAM,GAAG,IAAI,GACnB,OAAO,CAAC,KAAK,EAAE,CAAC;IAab,MAAM,OAAO,MAAM,OAAO,SAAS,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAkB3D,KAAK,OAAO,MAAM,SAAS,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;EAmBpE"}
@@ -0,0 +1,672 @@
1
+ import { ARRAY_INDEX, equalValue, escapePointer, itemFacts, memberFacts, pointerSegments, references, relative, target, } from '@agentshouse/mdmodel';
2
+ const FIELDS = { fields: 'all' };
3
+ const REMOVABLE = { fields: 'all', markdown: true };
4
+ const BY_ID = [{ field: 'id', direction: 'asc' }];
5
+ const RESERVED = new Set(['id', 'type']);
6
+ const TRUE = { kind: 'true' };
7
+ const FALSE = { kind: 'false' };
8
+ const WATCHED = new WeakMap();
9
+ const EQUALITY = {
10
+ $eq: true,
11
+ $in: true,
12
+ $ne: false,
13
+ $nin: false,
14
+ };
15
+ function pointer(field) {
16
+ return field
17
+ .split('.')
18
+ .map((segment) => `/${escapePointer(segment)}`)
19
+ .join('');
20
+ }
21
+ function listed(value) {
22
+ return Array.isArray(value) ? value : [value];
23
+ }
24
+ function factsAt(facts, field) {
25
+ let reached = facts;
26
+ for (const segment of field.split('.')) {
27
+ if (reached?.type === 'array' && ARRAY_INDEX.test(segment)) {
28
+ reached = itemFacts(reached, Number(segment));
29
+ continue;
30
+ }
31
+ while (reached?.type === 'array')
32
+ reached = reached.items;
33
+ reached = reached === undefined ? undefined : memberFacts(reached, segment);
34
+ }
35
+ return reached;
36
+ }
37
+ function referring(facts) {
38
+ return facts?.reference !== undefined || facts?.items?.reference !== undefined;
39
+ }
40
+ function relinked(fields, definition, each) {
41
+ const copy = structuredClone(fields);
42
+ if (definition === undefined)
43
+ return copy;
44
+ const document = { content: '', type: undefined, fields, preamble: '', sections: {} };
45
+ for (const { pointer, value } of references(document, definition)) {
46
+ const segments = pointerSegments(pointer);
47
+ const last = segments.pop();
48
+ let held = copy;
49
+ for (const segment of segments)
50
+ held = held[segment];
51
+ if (last !== undefined)
52
+ held[last] = each(value);
53
+ }
54
+ return copy;
55
+ }
56
+ function idOf(shelf, room, path) {
57
+ return shelf.rooms.length > 1 ? `${room}/${path}` : path;
58
+ }
59
+ function keyOf(shelf, document) {
60
+ return idOf(shelf, document.room, document.path);
61
+ }
62
+ function placeOf(shelf, id) {
63
+ const text = String(id);
64
+ if (shelf.rooms.length > 1) {
65
+ const cut = text.indexOf('/');
66
+ if (cut <= 0)
67
+ throw new Error(`${text} names no Room`);
68
+ return { room: text.slice(0, cut), path: text.slice(cut + 1) };
69
+ }
70
+ const [room] = shelf.rooms;
71
+ if (room === undefined)
72
+ throw new Error('no Room is reached');
73
+ return { room, path: text };
74
+ }
75
+ function equality(field, operator) {
76
+ const equal = EQUALITY[operator];
77
+ if (equal === undefined)
78
+ throw new Error(`${field} compares only for equality`);
79
+ return equal;
80
+ }
81
+ function sorting(shelf, { field, direction }) {
82
+ if (field !== 'id')
83
+ return [{ by: { field: pointer(field) }, direction }];
84
+ const path = { by: 'path', direction };
85
+ return shelf.rooms.length > 1 ? [{ by: 'room', direction }, path] : [path];
86
+ }
87
+ function entryOf(shelf, document) {
88
+ const fields = Object.fromEntries(Object.entries(document.fields ?? {}).filter(([field]) => !RESERVED.has(field)));
89
+ const read = relinked(fields, shelf.definitions.get(document.room), (link) => {
90
+ const found = target(document.path, link);
91
+ return found === null ? link : idOf(shelf, document.room, found);
92
+ });
93
+ return { ...read, id: keyOf(shelf, document) };
94
+ }
95
+ function written(shelf, place, field, value) {
96
+ return relinked({ [field]: value }, shelf.definitions.get(place.room), (id) => {
97
+ const to = placeOf(shelf, id);
98
+ if (to.room !== place.room)
99
+ throw new Error(`${field} names a record in another Room`);
100
+ return relative(place.path, to.path);
101
+ })[field];
102
+ }
103
+ function changed(shelf, { place, document }, data, shown) {
104
+ const current = entryOf(shelf, document);
105
+ const prior = shown ?? current;
106
+ const stored = document.fields ?? {};
107
+ const fields = {};
108
+ for (const [field, value] of Object.entries(data)) {
109
+ if (RESERVED.has(field) || value === undefined || equalValue(value, prior[field]))
110
+ continue;
111
+ const base = equalValue(prior[field], current[field])
112
+ ? Object.hasOwn(stored, field)
113
+ ? { value: stored[field] }
114
+ : null
115
+ : prior[field] === undefined
116
+ ? null
117
+ : { value: written(shelf, place, field, prior[field]) };
118
+ fields[field] = { value: written(shelf, place, field, value), base };
119
+ }
120
+ return Object.keys(fields).length === 0 ? null : { fields };
121
+ }
122
+ function byRoom(items) {
123
+ const rooms = new Map();
124
+ for (const item of items) {
125
+ rooms.set(item.place.room, [...(rooms.get(item.place.room) ?? []), item]);
126
+ }
127
+ return rooms;
128
+ }
129
+ function complete(answer) {
130
+ return !('pending' in answer);
131
+ }
132
+ function placeKey({ room, path }) {
133
+ return JSON.stringify([room, path]);
134
+ }
135
+ function joined(kind, items) {
136
+ const absorbing = kind === 'and' ? FALSE : TRUE;
137
+ const neutral = kind === 'and' ? TRUE : FALSE;
138
+ const kept = items
139
+ .flatMap((item) => (item.kind === kind ? item.items : [item]))
140
+ .filter((item) => item.kind !== neutral.kind);
141
+ if (kept.some((item) => item.kind === absorbing.kind))
142
+ return absorbing;
143
+ if (kept.length === 0)
144
+ return neutral;
145
+ return kept.length === 1 ? kept[0] : { kind, items: kept };
146
+ }
147
+ function formulaOf(shelf, room, clause) {
148
+ if ('every' in clause) {
149
+ return joined('and', clause.every.map((one) => formulaOf(shelf, room, one)));
150
+ }
151
+ if ('some' in clause) {
152
+ return joined('or', clause.some.map((one) => formulaOf(shelf, room, one)));
153
+ }
154
+ const { field, operator, value } = clause;
155
+ const reference = [...shelf.definitions.values()].some((definition) => referring(factsAt(definition.frontmatter, field)));
156
+ if (field !== 'id' && !reference) {
157
+ return { kind: 'where', where: { [pointer(field)]: { [operator]: value } } };
158
+ }
159
+ const equal = equality(field, operator);
160
+ const places = listed(value).map((id) => (id === null ? null : placeOf(shelf, id)));
161
+ const paths = places.flatMap((place) => place !== null && place.room === room ? [place.path] : []);
162
+ if (field === 'id') {
163
+ if (paths.length === 0)
164
+ return equal ? FALSE : TRUE;
165
+ return { kind: 'path', paths: new Set(paths), holds: equal };
166
+ }
167
+ const values = [...paths, ...(places.includes(null) ? [null] : [])];
168
+ if (values.length === 0 || !referring(factsAt(shelf.definitions.get(room)?.frontmatter, field))) {
169
+ return equal ? FALSE : TRUE;
170
+ }
171
+ return { kind: 'where', where: { [pointer(field)]: { [equal ? '$in' : '$nin']: values } } };
172
+ }
173
+ function namedPaths(formula) {
174
+ if (formula.kind === 'path')
175
+ return [...formula.paths];
176
+ if (formula.kind === 'and' || formula.kind === 'or') {
177
+ return [...new Set(formula.items.flatMap(namedPaths))];
178
+ }
179
+ return [];
180
+ }
181
+ function decided(formula, path) {
182
+ if (formula.kind === 'path') {
183
+ return (path !== null && formula.paths.has(path)) === formula.holds ? TRUE : FALSE;
184
+ }
185
+ if (formula.kind === 'and' || formula.kind === 'or') {
186
+ return joined(formula.kind, formula.items.map((item) => decided(item, path)));
187
+ }
188
+ return formula;
189
+ }
190
+ function whereOf(formula) {
191
+ if (formula.kind === 'where')
192
+ return formula.where;
193
+ if (formula.kind === 'and')
194
+ return { $and: formula.items.map((item) => whereOf(item) ?? {}) };
195
+ if (formula.kind === 'or')
196
+ return { $or: formula.items.map((item) => whereOf(item) ?? {}) };
197
+ return undefined;
198
+ }
199
+ function filtered(where) {
200
+ return where === undefined ? {} : { where };
201
+ }
202
+ function afterOf(after) {
203
+ return after === undefined ? {} : { after };
204
+ }
205
+ function watchedOf(client) {
206
+ const held = WATCHED.get(client);
207
+ if (held !== undefined)
208
+ return held;
209
+ const fresh = {
210
+ walks: new Map(),
211
+ listeners: new Map(),
212
+ read: new Map(),
213
+ watching: new Map(),
214
+ };
215
+ WATCHED.set(client, fresh);
216
+ return fresh;
217
+ }
218
+ export function records(client, resources) {
219
+ const { walks, listeners, read, watching } = watchedOf(client);
220
+ async function answerOf(query) {
221
+ const answer = await client.query(query);
222
+ if (complete(answer))
223
+ return answer;
224
+ const observation = await client.observe('query', query);
225
+ try {
226
+ return await new Promise((resolve) => {
227
+ const settle = (value) => {
228
+ if (complete(value))
229
+ resolve(value);
230
+ };
231
+ observation.subscribe(settle);
232
+ settle(observation.current());
233
+ });
234
+ }
235
+ finally {
236
+ observation.close();
237
+ }
238
+ }
239
+ async function everyOf(query) {
240
+ const walked = { documents: [], windows: [] };
241
+ let after;
242
+ do {
243
+ const window = { ...query, ...afterOf(after) };
244
+ const answer = await answerOf(window);
245
+ walked.windows.push(window);
246
+ walked.documents.push(...answer.documents);
247
+ after = answer.next;
248
+ } while (after !== undefined);
249
+ return walked;
250
+ }
251
+ function resourceOf(name) {
252
+ const resource = Object.hasOwn(resources, name) ? resources[name] : undefined;
253
+ if (resource === undefined)
254
+ throw new Error(`${name} is not a configured resource`);
255
+ return resource;
256
+ }
257
+ async function shelfOf(name) {
258
+ const resource = resourceOf(name);
259
+ const rooms = (await client.rooms()).map((room) => room.locator);
260
+ const definitions = new Map();
261
+ for (const room of rooms) {
262
+ const schema = (await client.types(room)).collection;
263
+ if (schema.types === null)
264
+ continue;
265
+ const definition = schema.types.find((type) => type.name === resource.type);
266
+ if (definition === undefined)
267
+ continue;
268
+ definitions.set(room, definition);
269
+ }
270
+ return { resource, rooms, definitions };
271
+ }
272
+ function folderOf(shelf) {
273
+ return { types: [shelf.resource.type], pathPrefix: shelf.resource.folder };
274
+ }
275
+ function closed(observations) {
276
+ void observations?.then((all) => {
277
+ for (const observation of all)
278
+ observation.close();
279
+ }, () => { });
280
+ }
281
+ function touched(name) {
282
+ walks.delete(name);
283
+ read.delete(name);
284
+ const held = watching.get(name);
285
+ if (held !== undefined) {
286
+ watching.set(name, new Map());
287
+ for (const observations of held.values())
288
+ closed(observations);
289
+ }
290
+ for (const heard of listeners.get(name) ?? [])
291
+ heard();
292
+ }
293
+ function observed(name, view, queries) {
294
+ const held = watching.get(name);
295
+ if (held === undefined)
296
+ return;
297
+ const before = held.get(view);
298
+ const opening = Promise.all(queries.map(async (query) => {
299
+ const observation = await client.observe('query', query);
300
+ observation.subscribe(() => {
301
+ if (watching.get(name)?.get(view) === opening)
302
+ touched(name);
303
+ });
304
+ return observation;
305
+ }));
306
+ held.set(view, opening);
307
+ opening.catch(() => {
308
+ if (watching.get(name)?.get(view) === opening)
309
+ held.delete(view);
310
+ });
311
+ closed(before);
312
+ }
313
+ function remember(name, view, queries) {
314
+ const views = read.get(name) ?? new Map();
315
+ views.set(view, queries);
316
+ read.set(name, views);
317
+ observed(name, view, queries);
318
+ }
319
+ async function selectionOf(shelf, clause) {
320
+ const streams = new Map();
321
+ const named = [];
322
+ const lookups = [];
323
+ for (const room of shelf.rooms) {
324
+ const formula = clause === null ? TRUE : formulaOf(shelf, room, clause);
325
+ const paths = namedPaths(formula);
326
+ const rest = decided(formula, null);
327
+ if (rest.kind !== 'false') {
328
+ const where = whereOf(rest);
329
+ const key = JSON.stringify(where ?? null);
330
+ const stream = streams.get(key) ?? { rooms: [], where, excluded: new Set() };
331
+ stream.rooms.push(room);
332
+ for (const path of paths)
333
+ stream.excluded.add(placeKey({ room, path }));
334
+ streams.set(key, stream);
335
+ }
336
+ const each = new Map();
337
+ for (const path of paths) {
338
+ const kept = decided(formula, path);
339
+ if (kept.kind === 'false')
340
+ continue;
341
+ const where = whereOf(kept);
342
+ const key = JSON.stringify(where ?? null);
343
+ const held = each.get(key) ?? { where, paths: [] };
344
+ held.paths.push(path);
345
+ each.set(key, held);
346
+ }
347
+ for (const { where, paths: these } of each.values()) {
348
+ const lookup = {
349
+ ...folderOf(shelf),
350
+ rooms: [room],
351
+ paths: these,
352
+ ...filtered(where),
353
+ select: {},
354
+ };
355
+ const found = await everyOf(lookup);
356
+ lookups.push(...found.windows);
357
+ named.push(...found.documents.map(({ room: at, path }) => ({ room: at, path })));
358
+ }
359
+ }
360
+ return { streams: [...streams.values()], named, lookups };
361
+ }
362
+ function streamQuery(shelf, stream, orderBy) {
363
+ return {
364
+ ...folderOf(shelf),
365
+ rooms: stream.rooms,
366
+ ...filtered(stream.where),
367
+ orderBy,
368
+ select: {},
369
+ };
370
+ }
371
+ function walkOf(name, query) {
372
+ const fresh = { total: null, cursors: new Map([[0, undefined]]) };
373
+ if (!watching.has(name))
374
+ return fresh;
375
+ const walked = walks.get(name) ?? new Map();
376
+ walks.set(name, walked);
377
+ const key = JSON.stringify(query);
378
+ const walk = walked.get(key) ?? fresh;
379
+ walked.set(key, walk);
380
+ return walk;
381
+ }
382
+ async function cursorAt({ cursors }, query, start) {
383
+ let at = Math.max(...[...cursors.keys()].filter((one) => one <= start));
384
+ let after = cursors.get(at);
385
+ while (at < start) {
386
+ const window = await answerOf({ ...query, limit: start - at, ...afterOf(after) });
387
+ if (window.next === undefined)
388
+ return null;
389
+ at += window.documents.length;
390
+ after = window.next;
391
+ cursors.set(at, after);
392
+ }
393
+ return after;
394
+ }
395
+ function prefixOf({ cursors }, query, start) {
396
+ const at = [...cursors.keys()]
397
+ .filter((one) => one <= start)
398
+ .sort((left, right) => left - right);
399
+ return at.slice(1).map((to, index) => ({
400
+ ...query,
401
+ limit: to - at[index],
402
+ ...afterOf(cursors.get(at[index])),
403
+ }));
404
+ }
405
+ async function paged(name, shelf, view, query, { start, size }, again = true) {
406
+ const walk = walkOf(name, query);
407
+ const after = await cursorAt(walk, query, start);
408
+ const window = {
409
+ ...query,
410
+ ...(after === null ? { limit: 0 } : { select: FIELDS, limit: size, ...afterOf(after) }),
411
+ total: true,
412
+ };
413
+ const page = await answerOf(window);
414
+ const total = page.total ?? 0;
415
+ if (walk.total !== null && walk.total !== total && again) {
416
+ walks.get(name)?.delete(JSON.stringify(query));
417
+ return paged(name, shelf, view, query, { start, size }, false);
418
+ }
419
+ walk.total = total;
420
+ if (page.next !== undefined && after !== null) {
421
+ walk.cursors.set(start + page.documents.length, page.next);
422
+ }
423
+ remember(name, view, [
424
+ ...(start === 0 || after === null ? [] : prefixOf(walk, query, start)),
425
+ after === null ? { ...query, limit: start, total: true } : window,
426
+ ]);
427
+ return { entries: page.documents.map((document) => entryOf(shelf, document)), total };
428
+ }
429
+ async function sortedPlaces(shelf, places, orderBy) {
430
+ if (places.length <= 1)
431
+ return [...places];
432
+ const wanted = new Set(places.map(placeKey));
433
+ const sorted = await everyOf({
434
+ ...folderOf(shelf),
435
+ rooms: [...new Set(places.map(({ room }) => room))],
436
+ paths: [...new Set(places.map(({ path }) => path))],
437
+ orderBy,
438
+ select: {},
439
+ });
440
+ return sorted.documents.flatMap(({ room, path }) => wanted.has(placeKey({ room, path })) ? [{ room, path }] : []);
441
+ }
442
+ function streamSource(query, excluded) {
443
+ let after;
444
+ const source = {
445
+ buffer: [],
446
+ more: true,
447
+ windows: [],
448
+ async read(limit) {
449
+ const asked = { ...query, ...(limit === null ? {} : { limit }), ...afterOf(after) };
450
+ const window = await answerOf(asked);
451
+ after = window.next;
452
+ source.more = after !== undefined;
453
+ source.windows.push(asked);
454
+ source.buffer.push(...window.documents.flatMap(({ room, path }) => excluded.has(placeKey({ room, path })) ? [] : [{ room, path }]));
455
+ },
456
+ };
457
+ return source;
458
+ }
459
+ async function mergedPlaces(shelf, selection, orderBy, end) {
460
+ const queries = selection.streams.map((stream) => streamQuery(shelf, stream, orderBy));
461
+ const streams = selection.streams.map((stream, at) => streamSource(queries[at], stream.excluded));
462
+ const sources = [
463
+ ...streams,
464
+ {
465
+ buffer: await sortedPlaces(shelf, selection.named, orderBy),
466
+ more: false,
467
+ windows: [],
468
+ read: async () => { },
469
+ },
470
+ ];
471
+ const merged = [];
472
+ while (merged.length < end) {
473
+ const wanted = end - merged.length;
474
+ for (const source of sources) {
475
+ while (source.buffer.length === 0 && source.more) {
476
+ await source.read(Number.isFinite(wanted) ? wanted : null);
477
+ }
478
+ }
479
+ const filled = sources.filter((source) => source.buffer.length > 0);
480
+ if (filled.length === 0)
481
+ break;
482
+ const order = filled.length === 1
483
+ ? [...filled[0].buffer]
484
+ : await sortedPlaces(shelf, filled.flatMap((source) => source.buffer), orderBy);
485
+ const at = order.map(placeKey);
486
+ const cut = Math.min(order.length - 1, ...filled
487
+ .filter((source) => source.more)
488
+ .map((source) => at.indexOf(placeKey(source.buffer[source.buffer.length - 1]))));
489
+ const emitted = order.slice(0, cut + 1);
490
+ const gone = new Set(emitted.map(placeKey));
491
+ for (const source of filled) {
492
+ source.buffer = source.buffer.filter((place) => !gone.has(placeKey(place)));
493
+ }
494
+ merged.push(...emitted);
495
+ }
496
+ return {
497
+ places: merged.slice(0, end),
498
+ windows: streams.flatMap((source, at) => [
499
+ { ...queries[at], limit: 0, total: true },
500
+ ...source.windows,
501
+ ]),
502
+ };
503
+ }
504
+ async function totalOf(shelf, selection, orderBy) {
505
+ let total = selection.named.length;
506
+ for (const stream of selection.streams) {
507
+ const query = streamQuery(shelf, stream, orderBy);
508
+ total += (await answerOf({ ...query, limit: 0, total: true })).total ?? 0;
509
+ const excluded = new Map();
510
+ for (const key of stream.excluded) {
511
+ const [room, path] = JSON.parse(key);
512
+ excluded.set(room, [...(excluded.get(room) ?? []), path]);
513
+ }
514
+ for (const [room, paths] of excluded) {
515
+ const counted = { ...query, rooms: [room], paths, limit: 0, total: true };
516
+ total -= (await answerOf(counted)).total ?? 0;
517
+ }
518
+ }
519
+ return total;
520
+ }
521
+ async function placed(shelf, places, select) {
522
+ const queries = [];
523
+ const documents = new Map();
524
+ const rooms = new Map();
525
+ for (const { room, path } of places) {
526
+ rooms.set(room, (rooms.get(room) ?? new Set()).add(path));
527
+ }
528
+ for (const [room, paths] of rooms) {
529
+ const walked = await everyOf({
530
+ ...folderOf(shelf),
531
+ rooms: [room],
532
+ paths: [...paths],
533
+ select,
534
+ });
535
+ queries.push(...walked.windows);
536
+ for (const document of walked.documents)
537
+ documents.set(placeKey(document), document);
538
+ }
539
+ return { queries, documents };
540
+ }
541
+ async function merged(name, shelf, view, selection, orderBy, page) {
542
+ const end = page === null ? Number.POSITIVE_INFINITY : page.start + page.size;
543
+ const { places, windows } = await mergedPlaces(shelf, selection, orderBy, end);
544
+ const shown = page === null ? places : places.slice(page.start);
545
+ const { queries, documents } = await placed(shelf, shown, FIELDS);
546
+ remember(name, view, [...windows, ...selection.lookups, ...queries]);
547
+ return {
548
+ entries: shown.flatMap((place) => {
549
+ const document = documents.get(placeKey(place));
550
+ return document === undefined ? [] : [entryOf(shelf, document)];
551
+ }),
552
+ total: page === null ? places.length : await totalOf(shelf, selection, orderBy),
553
+ };
554
+ }
555
+ async function found(name, shelf, ids, select) {
556
+ const places = ids.map((id) => placeOf(shelf, id));
557
+ const { queries, documents } = await placed(shelf, places, select);
558
+ remember(name, JSON.stringify(['named', places.map(placeKey)]), queries);
559
+ return places.map((place) => ({ place, document: documents.get(placeKey(place)) ?? null }));
560
+ }
561
+ async function held(name, shelf, ids, select) {
562
+ return (await found(name, shelf, ids, select)).map(({ place, document }) => {
563
+ if (document === null)
564
+ throw new Error(`no ${shelf.resource.type} is held at ${place.path}`);
565
+ return { place, document };
566
+ });
567
+ }
568
+ async function saved(name, room, parts) {
569
+ if (parts.size === 0)
570
+ return;
571
+ walks.delete(name);
572
+ const result = await client.saveParts(room, [...parts].map(([path, one]) => ({ path, parts: one })));
573
+ if (result.outcome === 'refused') {
574
+ throw Object.assign(new Error(`the Save was refused as ${result.code}`, { cause: result }), {
575
+ code: result.code,
576
+ retryable: result.retryable,
577
+ });
578
+ }
579
+ }
580
+ return {
581
+ async list(name, clause, order, page) {
582
+ const shelf = await shelfOf(name);
583
+ const selection = await selectionOf(shelf, clause);
584
+ const orderBy = (order.length === 0 ? BY_ID : order).flatMap((one) => sorting(shelf, one));
585
+ const view = JSON.stringify(['list', clause, order]);
586
+ const [stream] = selection.streams;
587
+ if (selection.streams.length === 1 &&
588
+ stream.excluded.size === 0 &&
589
+ selection.named.length === 0) {
590
+ const query = streamQuery(shelf, stream, orderBy);
591
+ if (page !== null)
592
+ return paged(name, shelf, view, query, page);
593
+ const all = await everyOf({ ...query, select: FIELDS });
594
+ remember(name, view, all.windows);
595
+ return {
596
+ entries: all.documents.map((document) => entryOf(shelf, document)),
597
+ total: all.documents.length,
598
+ };
599
+ }
600
+ return merged(name, shelf, view, selection, orderBy, page);
601
+ },
602
+ async many(name, ids) {
603
+ const shelf = await shelfOf(name);
604
+ return (await found(name, shelf, ids, FIELDS)).flatMap(({ document }) => document === null ? [] : [entryOf(shelf, document)]);
605
+ },
606
+ async one(name, id) {
607
+ const shelf = await shelfOf(name);
608
+ const [{ document }] = await held(name, shelf, [id], FIELDS);
609
+ return entryOf(shelf, document);
610
+ },
611
+ async create(name, data) {
612
+ const shelf = await shelfOf(name);
613
+ const [room] = shelf.rooms;
614
+ if (room === undefined)
615
+ throw new Error('no Room is reached');
616
+ const file = `${crypto.randomUUID()}.md`;
617
+ const { type, folder } = shelf.resource;
618
+ const place = { room, path: folder === '' ? file : `${folder}/${file}` };
619
+ const fields = Object.fromEntries(Object.entries(data)
620
+ .filter(([field, value]) => !RESERVED.has(field) && value !== undefined)
621
+ .map(([field, value]) => [field, written(shelf, place, field, value)]));
622
+ await saved(name, room, new Map([[place.path, { creation: { type, fields, sections: {} } }]]));
623
+ const [{ document }] = await held(name, shelf, [idOf(shelf, room, place.path)], FIELDS);
624
+ return entryOf(shelf, document);
625
+ },
626
+ async update(name, ids, data, shown) {
627
+ const shelf = await shelfOf(name);
628
+ for (const [room, inRoom] of byRoom(await held(name, shelf, ids, FIELDS))) {
629
+ const parts = new Map();
630
+ for (const one of inRoom) {
631
+ const part = changed(shelf, one, data, shown);
632
+ if (part !== null)
633
+ parts.set(one.place.path, part);
634
+ }
635
+ await saved(name, room, parts);
636
+ }
637
+ return (await held(name, shelf, ids, FIELDS)).map(({ document }) => entryOf(shelf, document));
638
+ },
639
+ async remove(name, ids) {
640
+ const shelf = await shelfOf(name);
641
+ const removed = await held(name, shelf, ids, REMOVABLE);
642
+ for (const [room, inRoom] of byRoom(removed)) {
643
+ await saved(name, room, new Map(inRoom.map(({ place, document }) => [
644
+ place.path,
645
+ { removal: { base: document.markdown ?? null } },
646
+ ])));
647
+ }
648
+ return removed.map(({ document }) => entryOf(shelf, document));
649
+ },
650
+ async watch(name, heard) {
651
+ resourceOf(name);
652
+ const hearing = listeners.get(name) ?? new Set();
653
+ listeners.set(name, hearing);
654
+ hearing.add(heard);
655
+ if (!watching.has(name)) {
656
+ watching.set(name, new Map());
657
+ for (const [view, queries] of read.get(name) ?? [])
658
+ observed(name, view, queries);
659
+ }
660
+ return () => {
661
+ hearing.delete(heard);
662
+ if (hearing.size > 0)
663
+ return;
664
+ listeners.delete(name);
665
+ const observations = watching.get(name);
666
+ watching.delete(name);
667
+ for (const one of observations?.values() ?? [])
668
+ closed(one);
669
+ };
670
+ },
671
+ };
672
+ }
@@ -0,0 +1,10 @@
1
+ import type { MdRuntimeClient } from '@agentshouse/mdruntime/client';
2
+ import type { DataProvider, LiveProvider } from '@refinedev/core';
3
+ import { type Resources } from './records.js';
4
+ export type { Resource, Resources } from './records.js';
5
+ export type ProviderOptions = {
6
+ readonly resources: Resources;
7
+ };
8
+ export declare function dataProvider(client: MdRuntimeClient, options: ProviderOptions): DataProvider;
9
+ export declare function liveProvider(client: MdRuntimeClient, options: ProviderOptions): LiveProvider;
10
+ //# sourceMappingURL=refine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refine.d.ts","sourceRoot":"","sources":["../src/refine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAMV,YAAY,EAMZ,YAAY,EAIb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAML,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC;AA+BhE,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,GAAG,YAAY,CAiF5F;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,GAAG,YAAY,CAW5F"}
package/dist/refine.js ADDED
@@ -0,0 +1,65 @@
1
+ import { records, } from './records.js';
2
+ const OPERATORS = {
3
+ eq: '$eq',
4
+ ne: '$ne',
5
+ lt: '$lt',
6
+ gt: '$gt',
7
+ lte: '$lte',
8
+ gte: '$gte',
9
+ in: '$in',
10
+ nin: '$nin',
11
+ };
12
+ function clause(filter) {
13
+ if (!('field' in filter)) {
14
+ const each = filter.value.map(clause);
15
+ return filter.operator === 'or' ? { some: each } : { every: each };
16
+ }
17
+ const operator = Object.hasOwn(OPERATORS, filter.operator)
18
+ ? OPERATORS[filter.operator]
19
+ : undefined;
20
+ if (operator === undefined)
21
+ throw new Error(`the ${filter.operator} filter has no condition`);
22
+ return { field: filter.field, operator, value: filter.value };
23
+ }
24
+ function pageOf(pagination) {
25
+ const { currentPage = 1, pageSize = 10, mode = 'server' } = pagination ?? {};
26
+ if (mode !== 'server')
27
+ return null;
28
+ return { start: (currentPage - 1) * pageSize, size: pageSize };
29
+ }
30
+ export function dataProvider(client, options) {
31
+ const held = records(client, options.resources);
32
+ return {
33
+ getList: async ({ resource, filters, sorters, pagination, }) => {
34
+ const { entries, total } = await held.list(resource, filters === undefined || filters.length === 0 ? null : { every: filters.map(clause) }, (sorters ?? []).map(({ field, order }) => ({ field, direction: order })), pageOf(pagination));
35
+ return { data: [...entries], total };
36
+ },
37
+ getMany: async ({ resource, ids, }) => ({ data: await held.many(resource, ids) }),
38
+ getOne: async ({ resource, id }) => ({ data: await held.one(resource, id) }),
39
+ create: async ({ resource, variables, }) => ({ data: await held.create(resource, variables) }),
40
+ update: async ({ resource, id, variables, }) => {
41
+ const [entry] = await held.update(resource, [id], variables, null);
42
+ return { data: entry };
43
+ },
44
+ updateMany: async ({ resource, ids, variables, }) => ({
45
+ data: await held.update(resource, ids, variables, null),
46
+ }),
47
+ deleteOne: async ({ resource, id, }) => {
48
+ const [entry] = await held.remove(resource, [id]);
49
+ return { data: entry };
50
+ },
51
+ deleteMany: async ({ resource, ids, }) => ({ data: await held.remove(resource, ids) }),
52
+ getApiUrl: () => '',
53
+ };
54
+ }
55
+ export function liveProvider(client, options) {
56
+ const held = records(client, options.resources);
57
+ return {
58
+ subscribe: ({ channel, params, callback }) => held.watch(String(params?.resource), () => {
59
+ callback({ channel, type: '*', payload: {}, date: new Date() });
60
+ }),
61
+ unsubscribe: (subscription) => {
62
+ void subscription.then((close) => close());
63
+ },
64
+ };
65
+ }
package/package.json CHANGED
@@ -1,6 +1,47 @@
1
1
  {
2
2
  "name": "@agentshouse/mdruntime-families",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0-c057d9ec05303",
4
+ "description": "react-admin and Refine data providers over the MD Runtime client",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "engines": {
12
+ "node": ">=24.21.0"
13
+ },
14
+ "exports": {
15
+ "./react-admin": {
16
+ "types": "./dist/react-admin.d.ts",
17
+ "default": "./dist/react-admin.js"
18
+ },
19
+ "./refine": {
20
+ "types": "./dist/refine.d.ts",
21
+ "default": "./dist/refine.js"
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "README.md",
28
+ "LICENSE"
29
+ ],
30
+ "dependencies": {
31
+ "@agentshouse/mdmodel": "0.1.0-ccf1367190878",
32
+ "@agentshouse/mdruntime": "0.1.0-cedb03eaa48b6"
33
+ },
34
+ "peerDependencies": {
35
+ "@refinedev/core": ">=5",
36
+ "ra-core": ">=5",
37
+ "react": ">=18"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "@refinedev/core": {
41
+ "optional": true
42
+ },
43
+ "ra-core": {
44
+ "optional": true
45
+ }
46
+ }
47
+ }