@idosgames/module-sdk 0.2.1 → 0.3.1
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/dist/index.cjs +1 -1
- package/dist/index.d.cts +89 -1
- package/dist/index.d.ts +89 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var S=/^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*@[1-9]\d*$/;function x(e){return typeof e=="string"&&S.test(e)}function M(e){let t=e.indexOf(":");return t<0?"":e.slice(0,t)}var l=/^(string|number|boolean)(\[\])?(\?)?$/;function u(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function c(e,t){return e==="number"?typeof t=="number"&&Number.isFinite(t):typeof t===e}function f(e,t,r){if(!u(t))return `${r||"payload"} must be an object`;for(let[n,o]of Object.entries(e)){let i=r?`${r}.${n}`:n,a=t[n];if(typeof o!="string"){let p=f(o,a,i);if(p)return p;continue}let d=l.exec(o);if(!d)return `${i}: invalid descriptor "${o}"`;let[,s="",g,m]=d;if(a===void 0){if(m)continue;return `${i} is missing`}if(g){if(!Array.isArray(a))return `${i} must be ${s}[]`;if(!a.every(p=>c(s,p)))return `${i} must contain only ${s} values`;continue}if(!c(s,a))return `${i} must be a ${s}`}return null}function y(e,t){for(let[r,n]of Object.entries(e)){let o=t?`${t}.${r}`:r;if(typeof n=="string"){if(!l.test(n))throw new Error(`shape(): field "${o}" has invalid type "${n}" \u2014 use "string" | "number" | "boolean", optionally with "[]" and/or a trailing "?"`)}else if(u(n))y(n,o);else throw new Error(`shape(): field "${o}" must be a type string or an object`)}}function h(e){return y(e,""),{descriptor:e,check:t=>f(e,t,"")}}function v(e,t){if(!x(e))throw new Error(`defineTopic(): "${e}" is not a valid topic name \u2014 expected "<module-id>:<event>@<major>", e.g. "idle-rpg:character-upgraded@1"`);return {name:e,shape:t}}var E={modeChanged:v("host:mode-changed@1",h({from:"string?",to:"string"}))};var T=["currency-bar","wallet","status","account"];function D(e){return typeof e=="string"&&T.includes(e)}function $(e){return e}exports.SHARED_UI_ROLES=T;exports.TOPIC_NAME_RE=S;exports.defineModule=$;exports.defineTopic=v;exports.hostTopics=E;exports.isSharedUiRole=D;exports.isTopicName=x;exports.shape=h;exports.topicNamespace=M;
|
package/dist/index.d.cts
CHANGED
|
@@ -132,6 +132,70 @@ interface SharedUiContext {
|
|
|
132
132
|
}
|
|
133
133
|
declare function isSharedUiRole(value: unknown): value is SharedUiRole;
|
|
134
134
|
|
|
135
|
+
/** Bytes of one file. Strings are UTF-8 encoded (JSON saves are the common case). */
|
|
136
|
+
type ContentFileData = Blob | ArrayBuffer | Uint8Array | string;
|
|
137
|
+
/** Something local the player can publish (a saved world, a level they built). */
|
|
138
|
+
interface LocalContentItem {
|
|
139
|
+
id: string;
|
|
140
|
+
name: string;
|
|
141
|
+
/** Epoch ms of the last change — lists are shown newest first. */
|
|
142
|
+
updatedAt?: number;
|
|
143
|
+
/** One line under the name ("recipe world · 256×256"). */
|
|
144
|
+
subtitle?: string;
|
|
145
|
+
}
|
|
146
|
+
/** What `capture` hands to the Workshop to publish. Roles and MIME types must fit the title's content type config. */
|
|
147
|
+
interface CapturedContent {
|
|
148
|
+
files: Array<{
|
|
149
|
+
role: string;
|
|
150
|
+
contentType: string;
|
|
151
|
+
data: ContentFileData;
|
|
152
|
+
}>;
|
|
153
|
+
thumbnail?: {
|
|
154
|
+
contentType: "image/png" | "image/jpeg" | "image/webp";
|
|
155
|
+
data: ContentFileData;
|
|
156
|
+
};
|
|
157
|
+
suggestedTitle?: string;
|
|
158
|
+
suggestedDescription?: string;
|
|
159
|
+
tags?: string[];
|
|
160
|
+
metadata?: Record<string, string>;
|
|
161
|
+
}
|
|
162
|
+
/** What the Workshop hands to `open` after the player got access. */
|
|
163
|
+
interface DownloadedContent {
|
|
164
|
+
contentID: string;
|
|
165
|
+
title?: string | null;
|
|
166
|
+
/** Revision of the publication — lets a game tell an update from a first download. */
|
|
167
|
+
revision?: number | null;
|
|
168
|
+
files: Array<{
|
|
169
|
+
role: string;
|
|
170
|
+
contentType: string;
|
|
171
|
+
data: ArrayBuffer;
|
|
172
|
+
}>;
|
|
173
|
+
}
|
|
174
|
+
interface ContentTypeHandler {
|
|
175
|
+
/** Must equal a key of `Workshop.ContentTypes` in the title config (e.g. "voxelcraft.world"). */
|
|
176
|
+
type: string;
|
|
177
|
+
/** Shown in the Workshop's type filter and publish wizard. */
|
|
178
|
+
label: string;
|
|
179
|
+
icon?: string;
|
|
180
|
+
/** Mode (route id) to switch to after `open` — the game that plays this content. */
|
|
181
|
+
modeId?: string;
|
|
182
|
+
/** Local items the player can publish. Omit when the type cannot be published from the game. */
|
|
183
|
+
listLocal?(): Promise<LocalContentItem[]>;
|
|
184
|
+
/** Serialize one local item for publishing. */
|
|
185
|
+
capture?(localId: string): Promise<CapturedContent>;
|
|
186
|
+
/** Load downloaded content into the game (import a world, start a level). */
|
|
187
|
+
open?(content: DownloadedContent): Promise<void>;
|
|
188
|
+
}
|
|
189
|
+
/** `ctx.content` — the host's registry of content types, shared by every module of the session. */
|
|
190
|
+
interface ContentRegistry {
|
|
191
|
+
/** Register (or replace) the handler of a type. Returns an unregister function. */
|
|
192
|
+
registerType(handler: ContentTypeHandler): () => void;
|
|
193
|
+
getType(type: string): ContentTypeHandler | undefined;
|
|
194
|
+
listTypes(): ContentTypeHandler[];
|
|
195
|
+
/** Called when a type is registered or removed (a UI re-renders its type list). */
|
|
196
|
+
subscribe(listener: () => void): () => void;
|
|
197
|
+
}
|
|
198
|
+
|
|
135
199
|
/** What a module is, for catalog/UI purposes. Not every module is a game. */
|
|
136
200
|
type ModuleType = "game" | "app" | "ai-app";
|
|
137
201
|
/**
|
|
@@ -213,6 +277,20 @@ interface ModuleManifest {
|
|
|
213
277
|
* AI Coder's hygiene notes compare this with the `defineTopic("…")` literals in `src/`.
|
|
214
278
|
*/
|
|
215
279
|
events?: ModuleEventsManifest;
|
|
280
|
+
/**
|
|
281
|
+
* Data collections this module needs (the title's `DataCollections` section): collection id →
|
|
282
|
+
* declaration, in the engine's JSON shape (`Kind`, `Fields`, `SortKeys`, `Access`, …). When the AI
|
|
283
|
+
* Coder composes a project it merges them into the title config, so a module brings its own data
|
|
284
|
+
* structures along instead of the agent re-inventing them. Ids MUST be prefixed with the module id
|
|
285
|
+
* (`"guild-system:guilds"`) — two modules never collide. Roles the rules reference go to
|
|
286
|
+
* `dataRoles`. Declare only what no ready platform module covers.
|
|
287
|
+
*/
|
|
288
|
+
collections?: Record<string, unknown>;
|
|
289
|
+
/** Title user roles the module's collection rules reference (role id → `{ DisplayName }`). */
|
|
290
|
+
dataRoles?: Record<string, {
|
|
291
|
+
DisplayName?: string;
|
|
292
|
+
Description?: string;
|
|
293
|
+
}>;
|
|
216
294
|
}
|
|
217
295
|
/**
|
|
218
296
|
* The manifest a module exports. The host calls `setup` exactly once, passing shared services;
|
|
@@ -257,6 +335,16 @@ interface ModuleContext {
|
|
|
257
335
|
registerPanel(panel: UiPanel): void;
|
|
258
336
|
/** Register a nav / mode entry so the player can switch to this module. */
|
|
259
337
|
registerRoute(entry: RouteEntry): void;
|
|
338
|
+
/**
|
|
339
|
+
* Content types other modules can publish and open (see `ContentTypeHandler`). A game registers
|
|
340
|
+
* its type here; the Workshop module reads the registry — neither imports the other.
|
|
341
|
+
*/
|
|
342
|
+
content: ContentRegistry;
|
|
343
|
+
/**
|
|
344
|
+
* Switch the host to another mode (a route id registered by any module) — e.g. the Workshop opens a
|
|
345
|
+
* world and hands the screen to the game. Unknown ids are ignored.
|
|
346
|
+
*/
|
|
347
|
+
navigate(modeId: string): void;
|
|
260
348
|
/**
|
|
261
349
|
* Publish a debug surface for the AI Coder's agent — what the module IS and what it can be told
|
|
262
350
|
* to DO. Optional: a module without it simply stays opaque to the agent.
|
|
@@ -371,4 +459,4 @@ interface SharedEventBus<Events extends Record<string, unknown> = Record<string,
|
|
|
371
459
|
/** Identity helper that pins a module literal to the `Module` type for editor help and errors. */
|
|
372
460
|
declare function defineModule(module: Module): Module;
|
|
373
461
|
|
|
374
|
-
export { type EngineScene, type InferShape, type Module, type ModuleAgentApi, type ModuleAuthor, type ModuleContext, type ModuleEngine, type ModuleEventEmit, type ModuleEventListen, type ModuleEvents, type ModuleEventsManifest, type ModuleManifest, type ModuleMedia, type ModuleMeta, type ModuleSharedUi, type ModuleType, type PanelSlot, type RouteEntry, SHARED_UI_ROLES, type SceneMountContext, type Shape, type ShapeDescriptor, type ShapeLeaf, type ShapeLeafSpec, type SharedEventBus, type SharedUiContext, type SharedUiRole, type SurfaceAllocator, type SurfaceHandle, type SurfaceKind, TOPIC_NAME_RE, type Topic, type TopicName, type TopicPayload, type UiPanel, defineModule, defineTopic, hostTopics, isSharedUiRole, isTopicName, shape, topicNamespace };
|
|
462
|
+
export { type CapturedContent, type ContentFileData, type ContentRegistry, type ContentTypeHandler, type DownloadedContent, type EngineScene, type InferShape, type LocalContentItem, type Module, type ModuleAgentApi, type ModuleAuthor, type ModuleContext, type ModuleEngine, type ModuleEventEmit, type ModuleEventListen, type ModuleEvents, type ModuleEventsManifest, type ModuleManifest, type ModuleMedia, type ModuleMeta, type ModuleSharedUi, type ModuleType, type PanelSlot, type RouteEntry, SHARED_UI_ROLES, type SceneMountContext, type Shape, type ShapeDescriptor, type ShapeLeaf, type ShapeLeafSpec, type SharedEventBus, type SharedUiContext, type SharedUiRole, type SurfaceAllocator, type SurfaceHandle, type SurfaceKind, TOPIC_NAME_RE, type Topic, type TopicName, type TopicPayload, type UiPanel, defineModule, defineTopic, hostTopics, isSharedUiRole, isTopicName, shape, topicNamespace };
|
package/dist/index.d.ts
CHANGED
|
@@ -132,6 +132,70 @@ interface SharedUiContext {
|
|
|
132
132
|
}
|
|
133
133
|
declare function isSharedUiRole(value: unknown): value is SharedUiRole;
|
|
134
134
|
|
|
135
|
+
/** Bytes of one file. Strings are UTF-8 encoded (JSON saves are the common case). */
|
|
136
|
+
type ContentFileData = Blob | ArrayBuffer | Uint8Array | string;
|
|
137
|
+
/** Something local the player can publish (a saved world, a level they built). */
|
|
138
|
+
interface LocalContentItem {
|
|
139
|
+
id: string;
|
|
140
|
+
name: string;
|
|
141
|
+
/** Epoch ms of the last change — lists are shown newest first. */
|
|
142
|
+
updatedAt?: number;
|
|
143
|
+
/** One line under the name ("recipe world · 256×256"). */
|
|
144
|
+
subtitle?: string;
|
|
145
|
+
}
|
|
146
|
+
/** What `capture` hands to the Workshop to publish. Roles and MIME types must fit the title's content type config. */
|
|
147
|
+
interface CapturedContent {
|
|
148
|
+
files: Array<{
|
|
149
|
+
role: string;
|
|
150
|
+
contentType: string;
|
|
151
|
+
data: ContentFileData;
|
|
152
|
+
}>;
|
|
153
|
+
thumbnail?: {
|
|
154
|
+
contentType: "image/png" | "image/jpeg" | "image/webp";
|
|
155
|
+
data: ContentFileData;
|
|
156
|
+
};
|
|
157
|
+
suggestedTitle?: string;
|
|
158
|
+
suggestedDescription?: string;
|
|
159
|
+
tags?: string[];
|
|
160
|
+
metadata?: Record<string, string>;
|
|
161
|
+
}
|
|
162
|
+
/** What the Workshop hands to `open` after the player got access. */
|
|
163
|
+
interface DownloadedContent {
|
|
164
|
+
contentID: string;
|
|
165
|
+
title?: string | null;
|
|
166
|
+
/** Revision of the publication — lets a game tell an update from a first download. */
|
|
167
|
+
revision?: number | null;
|
|
168
|
+
files: Array<{
|
|
169
|
+
role: string;
|
|
170
|
+
contentType: string;
|
|
171
|
+
data: ArrayBuffer;
|
|
172
|
+
}>;
|
|
173
|
+
}
|
|
174
|
+
interface ContentTypeHandler {
|
|
175
|
+
/** Must equal a key of `Workshop.ContentTypes` in the title config (e.g. "voxelcraft.world"). */
|
|
176
|
+
type: string;
|
|
177
|
+
/** Shown in the Workshop's type filter and publish wizard. */
|
|
178
|
+
label: string;
|
|
179
|
+
icon?: string;
|
|
180
|
+
/** Mode (route id) to switch to after `open` — the game that plays this content. */
|
|
181
|
+
modeId?: string;
|
|
182
|
+
/** Local items the player can publish. Omit when the type cannot be published from the game. */
|
|
183
|
+
listLocal?(): Promise<LocalContentItem[]>;
|
|
184
|
+
/** Serialize one local item for publishing. */
|
|
185
|
+
capture?(localId: string): Promise<CapturedContent>;
|
|
186
|
+
/** Load downloaded content into the game (import a world, start a level). */
|
|
187
|
+
open?(content: DownloadedContent): Promise<void>;
|
|
188
|
+
}
|
|
189
|
+
/** `ctx.content` — the host's registry of content types, shared by every module of the session. */
|
|
190
|
+
interface ContentRegistry {
|
|
191
|
+
/** Register (or replace) the handler of a type. Returns an unregister function. */
|
|
192
|
+
registerType(handler: ContentTypeHandler): () => void;
|
|
193
|
+
getType(type: string): ContentTypeHandler | undefined;
|
|
194
|
+
listTypes(): ContentTypeHandler[];
|
|
195
|
+
/** Called when a type is registered or removed (a UI re-renders its type list). */
|
|
196
|
+
subscribe(listener: () => void): () => void;
|
|
197
|
+
}
|
|
198
|
+
|
|
135
199
|
/** What a module is, for catalog/UI purposes. Not every module is a game. */
|
|
136
200
|
type ModuleType = "game" | "app" | "ai-app";
|
|
137
201
|
/**
|
|
@@ -213,6 +277,20 @@ interface ModuleManifest {
|
|
|
213
277
|
* AI Coder's hygiene notes compare this with the `defineTopic("…")` literals in `src/`.
|
|
214
278
|
*/
|
|
215
279
|
events?: ModuleEventsManifest;
|
|
280
|
+
/**
|
|
281
|
+
* Data collections this module needs (the title's `DataCollections` section): collection id →
|
|
282
|
+
* declaration, in the engine's JSON shape (`Kind`, `Fields`, `SortKeys`, `Access`, …). When the AI
|
|
283
|
+
* Coder composes a project it merges them into the title config, so a module brings its own data
|
|
284
|
+
* structures along instead of the agent re-inventing them. Ids MUST be prefixed with the module id
|
|
285
|
+
* (`"guild-system:guilds"`) — two modules never collide. Roles the rules reference go to
|
|
286
|
+
* `dataRoles`. Declare only what no ready platform module covers.
|
|
287
|
+
*/
|
|
288
|
+
collections?: Record<string, unknown>;
|
|
289
|
+
/** Title user roles the module's collection rules reference (role id → `{ DisplayName }`). */
|
|
290
|
+
dataRoles?: Record<string, {
|
|
291
|
+
DisplayName?: string;
|
|
292
|
+
Description?: string;
|
|
293
|
+
}>;
|
|
216
294
|
}
|
|
217
295
|
/**
|
|
218
296
|
* The manifest a module exports. The host calls `setup` exactly once, passing shared services;
|
|
@@ -257,6 +335,16 @@ interface ModuleContext {
|
|
|
257
335
|
registerPanel(panel: UiPanel): void;
|
|
258
336
|
/** Register a nav / mode entry so the player can switch to this module. */
|
|
259
337
|
registerRoute(entry: RouteEntry): void;
|
|
338
|
+
/**
|
|
339
|
+
* Content types other modules can publish and open (see `ContentTypeHandler`). A game registers
|
|
340
|
+
* its type here; the Workshop module reads the registry — neither imports the other.
|
|
341
|
+
*/
|
|
342
|
+
content: ContentRegistry;
|
|
343
|
+
/**
|
|
344
|
+
* Switch the host to another mode (a route id registered by any module) — e.g. the Workshop opens a
|
|
345
|
+
* world and hands the screen to the game. Unknown ids are ignored.
|
|
346
|
+
*/
|
|
347
|
+
navigate(modeId: string): void;
|
|
260
348
|
/**
|
|
261
349
|
* Publish a debug surface for the AI Coder's agent — what the module IS and what it can be told
|
|
262
350
|
* to DO. Optional: a module without it simply stays opaque to the agent.
|
|
@@ -371,4 +459,4 @@ interface SharedEventBus<Events extends Record<string, unknown> = Record<string,
|
|
|
371
459
|
/** Identity helper that pins a module literal to the `Module` type for editor help and errors. */
|
|
372
460
|
declare function defineModule(module: Module): Module;
|
|
373
461
|
|
|
374
|
-
export { type EngineScene, type InferShape, type Module, type ModuleAgentApi, type ModuleAuthor, type ModuleContext, type ModuleEngine, type ModuleEventEmit, type ModuleEventListen, type ModuleEvents, type ModuleEventsManifest, type ModuleManifest, type ModuleMedia, type ModuleMeta, type ModuleSharedUi, type ModuleType, type PanelSlot, type RouteEntry, SHARED_UI_ROLES, type SceneMountContext, type Shape, type ShapeDescriptor, type ShapeLeaf, type ShapeLeafSpec, type SharedEventBus, type SharedUiContext, type SharedUiRole, type SurfaceAllocator, type SurfaceHandle, type SurfaceKind, TOPIC_NAME_RE, type Topic, type TopicName, type TopicPayload, type UiPanel, defineModule, defineTopic, hostTopics, isSharedUiRole, isTopicName, shape, topicNamespace };
|
|
462
|
+
export { type CapturedContent, type ContentFileData, type ContentRegistry, type ContentTypeHandler, type DownloadedContent, type EngineScene, type InferShape, type LocalContentItem, type Module, type ModuleAgentApi, type ModuleAuthor, type ModuleContext, type ModuleEngine, type ModuleEventEmit, type ModuleEventListen, type ModuleEvents, type ModuleEventsManifest, type ModuleManifest, type ModuleMedia, type ModuleMeta, type ModuleSharedUi, type ModuleType, type PanelSlot, type RouteEntry, SHARED_UI_ROLES, type SceneMountContext, type Shape, type ShapeDescriptor, type ShapeLeaf, type ShapeLeafSpec, type SharedEventBus, type SharedUiContext, type SharedUiRole, type SurfaceAllocator, type SurfaceHandle, type SurfaceKind, TOPIC_NAME_RE, type Topic, type TopicName, type TopicPayload, type UiPanel, defineModule, defineTopic, hostTopics, isSharedUiRole, isTopicName, shape, topicNamespace };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var S=/^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*@[1-9]\d*$/;function x(e){return typeof e=="string"&&S.test(e)}function M(e){let t=e.indexOf(":");return t<0?"":e.slice(0,t)}var l=/^(string|number|boolean)(\[\])?(\?)?$/;function u(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function c(e,t){return e==="number"?typeof t=="number"&&Number.isFinite(t):typeof t===e}function f(e,t,r){if(!u(t))return `${r||"payload"} must be an object`;for(let[n,o]of Object.entries(e)){let i=r?`${r}.${n}`:n,a=t[n];if(typeof o!="string"){let p=f(o,a,i);if(p)return p;continue}let d=l.exec(o);if(!d)return `${i}: invalid descriptor "${o}"`;let[,s="",g,m]=d;if(a===void 0){if(m)continue;return `${i} is missing`}if(g){if(!Array.isArray(a))return `${i} must be ${s}[]`;if(!a.every(p=>c(s,p)))return `${i} must contain only ${s} values`;continue}if(!c(s,a))return `${i} must be a ${s}`}return null}function y(e,t){for(let[r,n]of Object.entries(e)){let o=t?`${t}.${r}`:r;if(typeof n=="string"){if(!l.test(n))throw new Error(`shape(): field "${o}" has invalid type "${n}" \u2014 use "string" | "number" | "boolean", optionally with "[]" and/or a trailing "?"`)}else if(u(n))y(n,o);else throw new Error(`shape(): field "${o}" must be a type string or an object`)}}function h(e){return y(e,""),{descriptor:e,check:t=>f(e,t,"")}}function v(e,t){if(!x(e))throw new Error(`defineTopic(): "${e}" is not a valid topic name \u2014 expected "<module-id>:<event>@<major>", e.g. "idle-rpg:character-upgraded@1"`);return {name:e,shape:t}}var E={modeChanged:v("host:mode-changed@1",h({from:"string?",to:"string"}))};var T=["currency-bar","wallet","status","account"];function D(e){return typeof e=="string"&&T.includes(e)}function $(e){return e}export{T as SHARED_UI_ROLES,S as TOPIC_NAME_RE,$ as defineModule,v as defineTopic,E as hostTopics,D as isSharedUiRole,x as isTopicName,h as shape,M as topicNamespace};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idosgames/module-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "The composable-module contract for the iDosGames host shell: Module / ModuleContext types plus tiny authoring helpers. Framework-neutral at runtime — a module can be a game (Three/Phaser), a plain app, or an AI app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"//": "@idosgames/core is a real range, not '*': a published contract must name the version of core whose IDosGamesClient/SdkEvents shapes it references. Bump in step with core (see RELEASING.md). react is an OPTIONAL peer — the contract references React's ComponentType type only (a UI panel is a React component), which is erased at build, so a runtime-only module needs no React.",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@idosgames/core": "^0.
|
|
49
|
+
"@idosgames/core": "^0.14.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"react": "^18.3.1 || ^19.0.0"
|