@game-infra/story-schemas 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/contracts.d.ts +165 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +104 -0
- package/dist/contracts.js.map +1 -0
- package/dist/designContent.d.ts +236 -0
- package/dist/designContent.d.ts.map +1 -0
- package/dist/designContent.js +195 -0
- package/dist/designContent.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/nodePaths.d.ts +107 -0
- package/dist/nodePaths.d.ts.map +1 -0
- package/dist/nodePaths.js +123 -0
- package/dist/nodePaths.js.map +1 -0
- package/dist/storyPayloads.d.ts +226 -0
- package/dist/storyPayloads.d.ts.map +1 -0
- package/dist/storyPayloads.js +142 -0
- package/dist/storyPayloads.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a beat is addressed.
|
|
3
|
+
*
|
|
4
|
+
* A story beat's identity is the trail of choices taken to reach it — nothing
|
|
5
|
+
* else. That is what makes "has this branch been travelled before?" a lookup
|
|
6
|
+
* rather than a search, and it is why both the client minting ids and the
|
|
7
|
+
* service sweeping subtrees have to agree on the spelling. They agree here.
|
|
8
|
+
*
|
|
9
|
+
* Two spellings, one meaning:
|
|
10
|
+
*
|
|
11
|
+
* - `nodeId` — `root`, then choice ids joined with `.`. It is the row's
|
|
12
|
+
* `contentId`, and it travels as a single URL path segment
|
|
13
|
+
* (`/design-content/story-node/:scopeId/:contentId`), which a slash would
|
|
14
|
+
* split. The dot is also what `cascade=prefix` sweeps on.
|
|
15
|
+
* - `path` — the same trail joined with `/`, empty at the opening. This one is
|
|
16
|
+
* for reading: it is what a breadcrumb shows.
|
|
17
|
+
*/
|
|
18
|
+
/** The opening beat of every story. */
|
|
19
|
+
export const ROOT_NODE_ID = "root";
|
|
20
|
+
/** Separator between choice ids inside a node id. */
|
|
21
|
+
export const NODE_ID_SEPARATOR = ".";
|
|
22
|
+
/**
|
|
23
|
+
* The id of the beat reached by taking `choiceIds` in order.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { storyNodeId } from '@game-infra/story-schemas'
|
|
28
|
+
*
|
|
29
|
+
* storyNodeId([]) // 'root'
|
|
30
|
+
* storyNodeId(['take-the-tunnel', 'follow-the-voice']) // 'root.take-the-tunnel.follow-the-voice'
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function storyNodeId(choiceIds) {
|
|
34
|
+
return [ROOT_NODE_ID, ...choiceIds].join(NODE_ID_SEPARATOR);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The readable trail for the same beat, empty at the opening.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { storyNodePath } from '@game-infra/story-schemas'
|
|
42
|
+
*
|
|
43
|
+
* storyNodePath(['take-the-tunnel', 'follow-the-voice']) // 'take-the-tunnel/follow-the-voice'
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function storyNodePath(choiceIds) {
|
|
47
|
+
return choiceIds.join("/");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The choice trail a node id encodes. The inverse of {@link storyNodeId}.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { storyNodeChoiceIds } from '@game-infra/story-schemas'
|
|
55
|
+
*
|
|
56
|
+
* storyNodeChoiceIds('root.take-the-tunnel') // ['take-the-tunnel']
|
|
57
|
+
* storyNodeChoiceIds('root') // []
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function storyNodeChoiceIds(nodeId) {
|
|
61
|
+
const segments = nodeId.split(NODE_ID_SEPARATOR);
|
|
62
|
+
return segments[0] === ROOT_NODE_ID ? segments.slice(1) : segments;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The id of the beat one choice further on.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* import { childStoryNodeId } from '@game-infra/story-schemas'
|
|
70
|
+
*
|
|
71
|
+
* childStoryNodeId('root', 'take-the-tunnel') // 'root.take-the-tunnel'
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export function childStoryNodeId(parentNodeId, choiceId) {
|
|
75
|
+
return `${parentNodeId}${NODE_ID_SEPARATOR}${choiceId}`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The id of the beat this one branched from, or `undefined` at the opening.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* import { parentStoryNodeId } from '@game-infra/story-schemas'
|
|
83
|
+
*
|
|
84
|
+
* parentStoryNodeId('root.take-the-tunnel') // 'root'
|
|
85
|
+
* parentStoryNodeId('root') // undefined
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function parentStoryNodeId(nodeId) {
|
|
89
|
+
const cut = nodeId.lastIndexOf(NODE_ID_SEPARATOR);
|
|
90
|
+
return cut === -1 ? undefined : nodeId.slice(0, cut);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* How many choices deep a beat sits. The opening is 0.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* import { storyNodeDepth } from '@game-infra/story-schemas'
|
|
98
|
+
*
|
|
99
|
+
* storyNodeDepth('root.take-the-tunnel.follow-the-voice') // 2
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export function storyNodeDepth(nodeId) {
|
|
103
|
+
return storyNodeChoiceIds(nodeId).length;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Whether `nodeId` sits at or below `ancestorId`. This is `cascade=prefix`,
|
|
107
|
+
* expressed for a client that holds the tree in memory.
|
|
108
|
+
*
|
|
109
|
+
* The separator is part of the test on purpose: `root.take` is not an ancestor
|
|
110
|
+
* of `root.taken`, however alike the two ids look.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* import { isStoryNodeAtOrBelow } from '@game-infra/story-schemas'
|
|
115
|
+
*
|
|
116
|
+
* isStoryNodeAtOrBelow('root.take.left', 'root.take') // true
|
|
117
|
+
* isStoryNodeAtOrBelow('root.taken', 'root.take') // false
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export function isStoryNodeAtOrBelow(nodeId, ancestorId) {
|
|
121
|
+
return nodeId === ancestorId || nodeId.startsWith(`${ancestorId}${NODE_ID_SEPARATOR}`);
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=nodePaths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodePaths.js","sourceRoot":"","sources":["../src/nodePaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,uCAAuC;AACvC,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AAEnC,qDAAqD;AACrD,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAErC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,SAA4B;IACtD,OAAO,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,SAA4B;IACxD,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACjD,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAAoB,EAAE,QAAgB;IACrE,OAAO,GAAG,YAAY,GAAG,iBAAiB,GAAG,QAAQ,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;IAClD,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,UAAkB;IACrE,OAAO,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,iBAAiB,EAAE,CAAC,CAAC;AACzF,CAAC"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { type InferOutput } from "valibot";
|
|
2
|
+
/**
|
|
3
|
+
* What goes *inside* a design-content row's `data` for story mode.
|
|
4
|
+
*
|
|
5
|
+
* A story beat is an **encounter stage** and a branch is a **choice** — the
|
|
6
|
+
* same shapes the event editor already uses, not parallel ones. A branching
|
|
7
|
+
* story and a multi-stage event are the same object seen from two angles: both
|
|
8
|
+
* are prose with gated, consequential branches out of it. Reusing the DTOs is
|
|
9
|
+
* what lets an arc be published as an ordinary `event_definitions` row, and
|
|
10
|
+
* what gives story branches preconditions and consequences for free.
|
|
11
|
+
*
|
|
12
|
+
* These schemas are not attached to any endpoint. The service stores `data` as
|
|
13
|
+
* an opaque string and never parses it — see `designContent.ts` — but two
|
|
14
|
+
* clients reading the same rows still have to agree, so the shapes live here.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { StoryBeatPayloadSchema } from '@game-infra/story-schemas'
|
|
19
|
+
* import { safeParse } from 'valibot'
|
|
20
|
+
*
|
|
21
|
+
* const parsed = safeParse(StoryBeatPayloadSchema, JSON.parse(row.data ?? '{}'))
|
|
22
|
+
* if (parsed.success) console.log(parsed.output.description, parsed.output.choices)
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* A world's own fields; its content lives in rows scoped to it.
|
|
27
|
+
*
|
|
28
|
+
* This one has no event-editor counterpart — an event belongs to a game, but a
|
|
29
|
+
* design world is the thing a game's events are written against.
|
|
30
|
+
*/
|
|
31
|
+
export declare const WorldPayloadSchema: import("valibot").ObjectSchema<{
|
|
32
|
+
readonly title: import("valibot").StringSchema<undefined>;
|
|
33
|
+
/** The one-paragraph pitch. */
|
|
34
|
+
readonly premise: import("valibot").StringSchema<undefined>;
|
|
35
|
+
readonly setting: import("valibot").StringSchema<undefined>;
|
|
36
|
+
readonly tone: import("valibot").StringSchema<undefined>;
|
|
37
|
+
readonly themes: import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
38
|
+
}, undefined>;
|
|
39
|
+
export type WorldPayload = InferOutput<typeof WorldPayloadSchema>;
|
|
40
|
+
/**
|
|
41
|
+
* A story arc: the header of a multi-stage event, plus the few fields a story
|
|
42
|
+
* needs that an event does not.
|
|
43
|
+
*
|
|
44
|
+
* Every field up to `globalEffects` is an `EventDefinitionDTO` field under its
|
|
45
|
+
* own name, so assembling an arc and its beats into an event definition is a
|
|
46
|
+
* copy rather than a translation. `conditionsToTrigger` gates whether the arc
|
|
47
|
+
* is offered at all; `globalEffects` fires when it concludes.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import type { StoryArcPayload } from '@game-infra/story-schemas'
|
|
52
|
+
*
|
|
53
|
+
* const arc: StoryArcPayload = {
|
|
54
|
+
* title: 'The Quiet Forge Answers',
|
|
55
|
+
* description: 'Something inside the intact sky-forge is calling people by name.',
|
|
56
|
+
* rarity: 'rare',
|
|
57
|
+
* isRecurring: false,
|
|
58
|
+
* isMultiStage: true,
|
|
59
|
+
* conditionsToTrigger: [{ type: 'StatAtLeast', params: { statId: 'wits', value: 6 } }],
|
|
60
|
+
* globalEffects: [{ type: 'SetFlag', params: { flag: 'forge-answered', value: true } }],
|
|
61
|
+
* hook: 'Tallow hears their own voice from behind a sealed door.',
|
|
62
|
+
* tags: ['mystery', 'descent'],
|
|
63
|
+
* protagonistId: 'tallow',
|
|
64
|
+
* openingLocationId: 'quiet-forge',
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare const StoryArcPayloadSchema: import("valibot").ObjectSchema<{
|
|
69
|
+
readonly title: import("valibot").StringSchema<undefined>;
|
|
70
|
+
readonly description: import("valibot").UnionSchema<[import("valibot").StringSchema<undefined>, import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>], undefined>;
|
|
71
|
+
readonly rarity: import("valibot").StringSchema<undefined>;
|
|
72
|
+
readonly isRecurring: import("valibot").BooleanSchema<undefined>;
|
|
73
|
+
readonly isMultiStage: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
|
|
74
|
+
/** Gates whether this arc is offered. Same shape as an event's trigger conditions. */
|
|
75
|
+
readonly conditionsToTrigger: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
76
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
77
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
78
|
+
}, undefined>, undefined>, undefined>;
|
|
79
|
+
readonly eventParticipantPersonas: import("valibot").OptionalSchema<import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").ObjectSchema<{
|
|
80
|
+
readonly id: import("valibot").StringSchema<undefined>;
|
|
81
|
+
readonly entityId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
82
|
+
readonly type: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
83
|
+
readonly relationship: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").StringSchema<undefined>, import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>], undefined>, undefined>;
|
|
84
|
+
readonly requiredTraits: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
|
|
85
|
+
readonly excludedTraits: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
|
|
86
|
+
readonly haveMet: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
|
|
87
|
+
}, undefined>, undefined>, undefined>;
|
|
88
|
+
/** Applied when the arc concludes, whichever ending it reached. */
|
|
89
|
+
readonly globalEffects: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
90
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
91
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
92
|
+
}, undefined>, undefined>, undefined>;
|
|
93
|
+
/** The opening image — what the player is looking at when it starts. */
|
|
94
|
+
readonly hook: import("valibot").StringSchema<undefined>;
|
|
95
|
+
readonly tags: import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
96
|
+
/** A character id from the world, when the arc has one in mind. */
|
|
97
|
+
readonly protagonistId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
98
|
+
/** A location id from the world, when the arc opens somewhere in particular. */
|
|
99
|
+
readonly openingLocationId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
100
|
+
}, undefined>;
|
|
101
|
+
export type StoryArcPayload = InferOutput<typeof StoryArcPayloadSchema>;
|
|
102
|
+
/** Whether a beat's narration came from a model or from the player's own words. */
|
|
103
|
+
export declare const STORY_BEAT_ORIGINS: readonly ["generated", "authored"];
|
|
104
|
+
export declare const StoryBeatOriginSchema: import("valibot").PicklistSchema<readonly ["generated", "authored"], undefined>;
|
|
105
|
+
export type StoryBeatOrigin = InferOutput<typeof StoryBeatOriginSchema>;
|
|
106
|
+
/**
|
|
107
|
+
* One beat of a story: an `EncounterStageDTO`, plus how it came to exist.
|
|
108
|
+
*
|
|
109
|
+
* `description` is the narration the player reads and `choices` are the
|
|
110
|
+
* branches out of it, each a full `ChoiceDefinitionDTO` — so a branch carries
|
|
111
|
+
* `conditionsToShow`, `conditionsToEnable`, `consumableConditions`, `effects`
|
|
112
|
+
* and an outcome config exactly as an event's choice does.
|
|
113
|
+
*
|
|
114
|
+
* The beat's *address* is not in here — it is the row's `contentId`, the trail
|
|
115
|
+
* of choices taken to reach it (see `nodePaths.ts`). Keeping the address out of
|
|
116
|
+
* the payload is what keeps the two from disagreeing. The stage's own `id` is
|
|
117
|
+
* the event-editor-facing id, used when the arc is published as an event.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* import type { StoryBeatPayload } from '@game-infra/story-schemas'
|
|
122
|
+
*
|
|
123
|
+
* const beat: StoryBeatPayload = {
|
|
124
|
+
* id: 'root',
|
|
125
|
+
* title: 'The sealed door',
|
|
126
|
+
* description: 'The tunnel breathes out ash as you climb down…',
|
|
127
|
+
* choices: {
|
|
128
|
+
* 'force-the-door': {
|
|
129
|
+
* id: 'force-the-door',
|
|
130
|
+
* name: 'Force the door',
|
|
131
|
+
* effects: [{ type: 'ModifyStat', params: { statId: 'grit', amount: -1 } }],
|
|
132
|
+
* conditionsToEnable: [{ type: 'StatAtLeast', params: { statId: 'grit', value: 5 } }],
|
|
133
|
+
* },
|
|
134
|
+
* },
|
|
135
|
+
* model: 'aion',
|
|
136
|
+
* origin: 'generated',
|
|
137
|
+
* revision: 0,
|
|
138
|
+
* notes: [],
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export declare const StoryBeatPayloadSchema: import("valibot").ObjectSchema<{
|
|
143
|
+
readonly id: import("valibot").StringSchema<undefined>;
|
|
144
|
+
readonly title: import("valibot").StringSchema<undefined>;
|
|
145
|
+
readonly description: import("valibot").StringSchema<undefined>;
|
|
146
|
+
readonly choices: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").ObjectSchema<{
|
|
147
|
+
readonly id: import("valibot").StringSchema<undefined>;
|
|
148
|
+
readonly name: import("valibot").StringSchema<undefined>;
|
|
149
|
+
readonly description: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
150
|
+
readonly effects: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
151
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
152
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
153
|
+
}, undefined>, undefined>;
|
|
154
|
+
readonly conditionsToShow: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
155
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
156
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
157
|
+
}, undefined>, undefined>, undefined>;
|
|
158
|
+
readonly conditionsToEnable: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
159
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
160
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
161
|
+
}, undefined>, undefined>, undefined>;
|
|
162
|
+
readonly consumableConditions: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
163
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
164
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
165
|
+
}, undefined>, undefined>, undefined>;
|
|
166
|
+
readonly outcomeConfig: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
|
|
167
|
+
readonly baseDifficulty: import("valibot").NumberSchema<undefined>;
|
|
168
|
+
readonly statBonuses: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
169
|
+
readonly stat: import("valibot").StringSchema<undefined>;
|
|
170
|
+
readonly multiplier: import("valibot").NumberSchema<undefined>;
|
|
171
|
+
}, undefined>, undefined>, undefined>;
|
|
172
|
+
readonly skillBonuses: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
173
|
+
readonly skillId: import("valibot").StringSchema<undefined>;
|
|
174
|
+
readonly multiplier: import("valibot").NumberSchema<undefined>;
|
|
175
|
+
}, undefined>, undefined>, undefined>;
|
|
176
|
+
readonly onSuccess: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
177
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
178
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
179
|
+
}, undefined>, undefined>;
|
|
180
|
+
readonly onFailure: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
181
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
182
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
183
|
+
}, undefined>, undefined>;
|
|
184
|
+
}, undefined>, undefined>;
|
|
185
|
+
readonly conditionalOutcome: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
|
|
186
|
+
readonly type: import("valibot").LiteralSchema<"conditional", undefined>;
|
|
187
|
+
readonly branches: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
188
|
+
readonly id: import("valibot").StringSchema<undefined>;
|
|
189
|
+
readonly conditions: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
190
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
191
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
192
|
+
}, undefined>, undefined>;
|
|
193
|
+
readonly priority: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
|
|
194
|
+
readonly outcome: import("valibot").ObjectSchema<{
|
|
195
|
+
readonly description: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
196
|
+
readonly effects: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
197
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
198
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
199
|
+
}, undefined>, undefined>;
|
|
200
|
+
}, undefined>;
|
|
201
|
+
}, undefined>, undefined>;
|
|
202
|
+
readonly defaultBranch: import("valibot").ObjectSchema<{
|
|
203
|
+
readonly description: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
204
|
+
readonly effects: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
205
|
+
readonly type: import("valibot").StringSchema<undefined>;
|
|
206
|
+
readonly params: import("valibot").RecordSchema<import("valibot").StringSchema<undefined>, import("valibot").UnknownSchema, undefined>;
|
|
207
|
+
}, undefined>, undefined>;
|
|
208
|
+
}, undefined>;
|
|
209
|
+
}, undefined>, undefined>;
|
|
210
|
+
}, undefined>, undefined>;
|
|
211
|
+
/** The model that wrote this beat, so a re-read can say what produced it. */
|
|
212
|
+
readonly model: import("valibot").StringSchema<undefined>;
|
|
213
|
+
readonly origin: import("valibot").PicklistSchema<readonly ["generated", "authored"], undefined>;
|
|
214
|
+
/** 0 for the first draft, then one per regeneration. */
|
|
215
|
+
readonly revision: import("valibot").NumberSchema<undefined>;
|
|
216
|
+
/** The author's regeneration notes, oldest first. */
|
|
217
|
+
readonly notes: import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
218
|
+
}, undefined>;
|
|
219
|
+
export type StoryBeatPayload = InferOutput<typeof StoryBeatPayloadSchema>;
|
|
220
|
+
/**
|
|
221
|
+
* Re-exported so a story client needs one import, not two, for the shapes it
|
|
222
|
+
* reads out of a beat.
|
|
223
|
+
*/
|
|
224
|
+
export { ActivationDTOSchema, ChoiceDefinitionDTOSchema, ConsumableConditionDTOSchema, EncounterStageDTOSchema, PreconditionDTOSchema, } from "@game-infra/event-schemas";
|
|
225
|
+
export type { ActivationDTO, ChoiceDefinitionDTO, ConsumableConditionDTO, EncounterStageDTO, PreconditionDTO, } from "@game-infra/event-schemas";
|
|
226
|
+
//# sourceMappingURL=storyPayloads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storyPayloads.d.ts","sourceRoot":"","sources":["../src/storyPayloads.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,KAAK,WAAW,EASjB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;IAE7B,+BAA+B;;;;;aAK/B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,qBAAqB;;;;;;IAMhC,sFAAsF;;;;;;;;;;;;;;IAGtF,mEAAmE;;;;;IAKnE,wEAAwE;;;IAGxE,mEAAmE;;IAEnE,gFAAgF;;aAEhF,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAExE,mFAAmF;AACnF,eAAO,MAAM,kBAAkB,YAAI,WAAW,EAAE,UAAU,CAAU,CAAC;AAErE,eAAO,MAAM,qBAAqB,iFAA+B,CAAC;AAElE,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEjC,6EAA6E;;;IAG7E,wDAAwD;;IAExD,qDAAqD;;aAErD,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE1E;;;GAGG;AACH,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,4BAA4B,EAC5B,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,GAChB,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { ActivationDTOSchema, EncounterStageDTOSchema, EventDescriptionSchema, EventRaritySchema, EventParticipantPersonaDTOSchema, PreconditionDTOSchema, } from "@game-infra/event-schemas";
|
|
2
|
+
import { array, boolean, number, object, optional, picklist, record, string, } from "valibot";
|
|
3
|
+
/**
|
|
4
|
+
* What goes *inside* a design-content row's `data` for story mode.
|
|
5
|
+
*
|
|
6
|
+
* A story beat is an **encounter stage** and a branch is a **choice** — the
|
|
7
|
+
* same shapes the event editor already uses, not parallel ones. A branching
|
|
8
|
+
* story and a multi-stage event are the same object seen from two angles: both
|
|
9
|
+
* are prose with gated, consequential branches out of it. Reusing the DTOs is
|
|
10
|
+
* what lets an arc be published as an ordinary `event_definitions` row, and
|
|
11
|
+
* what gives story branches preconditions and consequences for free.
|
|
12
|
+
*
|
|
13
|
+
* These schemas are not attached to any endpoint. The service stores `data` as
|
|
14
|
+
* an opaque string and never parses it — see `designContent.ts` — but two
|
|
15
|
+
* clients reading the same rows still have to agree, so the shapes live here.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { StoryBeatPayloadSchema } from '@game-infra/story-schemas'
|
|
20
|
+
* import { safeParse } from 'valibot'
|
|
21
|
+
*
|
|
22
|
+
* const parsed = safeParse(StoryBeatPayloadSchema, JSON.parse(row.data ?? '{}'))
|
|
23
|
+
* if (parsed.success) console.log(parsed.output.description, parsed.output.choices)
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* A world's own fields; its content lives in rows scoped to it.
|
|
28
|
+
*
|
|
29
|
+
* This one has no event-editor counterpart — an event belongs to a game, but a
|
|
30
|
+
* design world is the thing a game's events are written against.
|
|
31
|
+
*/
|
|
32
|
+
export const WorldPayloadSchema = object({
|
|
33
|
+
title: string(),
|
|
34
|
+
/** The one-paragraph pitch. */
|
|
35
|
+
premise: string(),
|
|
36
|
+
setting: string(),
|
|
37
|
+
tone: string(),
|
|
38
|
+
themes: array(string()),
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* A story arc: the header of a multi-stage event, plus the few fields a story
|
|
42
|
+
* needs that an event does not.
|
|
43
|
+
*
|
|
44
|
+
* Every field up to `globalEffects` is an `EventDefinitionDTO` field under its
|
|
45
|
+
* own name, so assembling an arc and its beats into an event definition is a
|
|
46
|
+
* copy rather than a translation. `conditionsToTrigger` gates whether the arc
|
|
47
|
+
* is offered at all; `globalEffects` fires when it concludes.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import type { StoryArcPayload } from '@game-infra/story-schemas'
|
|
52
|
+
*
|
|
53
|
+
* const arc: StoryArcPayload = {
|
|
54
|
+
* title: 'The Quiet Forge Answers',
|
|
55
|
+
* description: 'Something inside the intact sky-forge is calling people by name.',
|
|
56
|
+
* rarity: 'rare',
|
|
57
|
+
* isRecurring: false,
|
|
58
|
+
* isMultiStage: true,
|
|
59
|
+
* conditionsToTrigger: [{ type: 'StatAtLeast', params: { statId: 'wits', value: 6 } }],
|
|
60
|
+
* globalEffects: [{ type: 'SetFlag', params: { flag: 'forge-answered', value: true } }],
|
|
61
|
+
* hook: 'Tallow hears their own voice from behind a sealed door.',
|
|
62
|
+
* tags: ['mystery', 'descent'],
|
|
63
|
+
* protagonistId: 'tallow',
|
|
64
|
+
* openingLocationId: 'quiet-forge',
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export const StoryArcPayloadSchema = object({
|
|
69
|
+
title: string(),
|
|
70
|
+
description: EventDescriptionSchema,
|
|
71
|
+
rarity: EventRaritySchema,
|
|
72
|
+
isRecurring: boolean(),
|
|
73
|
+
isMultiStage: optional(boolean()),
|
|
74
|
+
/** Gates whether this arc is offered. Same shape as an event's trigger conditions. */
|
|
75
|
+
conditionsToTrigger: optional(array(PreconditionDTOSchema)),
|
|
76
|
+
eventParticipantPersonas: optional(record(string(), EventParticipantPersonaDTOSchema)),
|
|
77
|
+
/** Applied when the arc concludes, whichever ending it reached. */
|
|
78
|
+
globalEffects: optional(array(ActivationDTOSchema)),
|
|
79
|
+
// Story-only fields, ignored when the arc is published as an event.
|
|
80
|
+
/** The opening image — what the player is looking at when it starts. */
|
|
81
|
+
hook: string(),
|
|
82
|
+
tags: array(string()),
|
|
83
|
+
/** A character id from the world, when the arc has one in mind. */
|
|
84
|
+
protagonistId: optional(string()),
|
|
85
|
+
/** A location id from the world, when the arc opens somewhere in particular. */
|
|
86
|
+
openingLocationId: optional(string()),
|
|
87
|
+
});
|
|
88
|
+
/** Whether a beat's narration came from a model or from the player's own words. */
|
|
89
|
+
export const STORY_BEAT_ORIGINS = ["generated", "authored"];
|
|
90
|
+
export const StoryBeatOriginSchema = picklist(STORY_BEAT_ORIGINS);
|
|
91
|
+
/**
|
|
92
|
+
* One beat of a story: an `EncounterStageDTO`, plus how it came to exist.
|
|
93
|
+
*
|
|
94
|
+
* `description` is the narration the player reads and `choices` are the
|
|
95
|
+
* branches out of it, each a full `ChoiceDefinitionDTO` — so a branch carries
|
|
96
|
+
* `conditionsToShow`, `conditionsToEnable`, `consumableConditions`, `effects`
|
|
97
|
+
* and an outcome config exactly as an event's choice does.
|
|
98
|
+
*
|
|
99
|
+
* The beat's *address* is not in here — it is the row's `contentId`, the trail
|
|
100
|
+
* of choices taken to reach it (see `nodePaths.ts`). Keeping the address out of
|
|
101
|
+
* the payload is what keeps the two from disagreeing. The stage's own `id` is
|
|
102
|
+
* the event-editor-facing id, used when the arc is published as an event.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* import type { StoryBeatPayload } from '@game-infra/story-schemas'
|
|
107
|
+
*
|
|
108
|
+
* const beat: StoryBeatPayload = {
|
|
109
|
+
* id: 'root',
|
|
110
|
+
* title: 'The sealed door',
|
|
111
|
+
* description: 'The tunnel breathes out ash as you climb down…',
|
|
112
|
+
* choices: {
|
|
113
|
+
* 'force-the-door': {
|
|
114
|
+
* id: 'force-the-door',
|
|
115
|
+
* name: 'Force the door',
|
|
116
|
+
* effects: [{ type: 'ModifyStat', params: { statId: 'grit', amount: -1 } }],
|
|
117
|
+
* conditionsToEnable: [{ type: 'StatAtLeast', params: { statId: 'grit', value: 5 } }],
|
|
118
|
+
* },
|
|
119
|
+
* },
|
|
120
|
+
* model: 'aion',
|
|
121
|
+
* origin: 'generated',
|
|
122
|
+
* revision: 0,
|
|
123
|
+
* notes: [],
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export const StoryBeatPayloadSchema = object({
|
|
128
|
+
...EncounterStageDTOSchema.entries,
|
|
129
|
+
/** The model that wrote this beat, so a re-read can say what produced it. */
|
|
130
|
+
model: string(),
|
|
131
|
+
origin: StoryBeatOriginSchema,
|
|
132
|
+
/** 0 for the first draft, then one per regeneration. */
|
|
133
|
+
revision: number(),
|
|
134
|
+
/** The author's regeneration notes, oldest first. */
|
|
135
|
+
notes: array(string()),
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* Re-exported so a story client needs one import, not two, for the shapes it
|
|
139
|
+
* reads out of a beat.
|
|
140
|
+
*/
|
|
141
|
+
export { ActivationDTOSchema, ChoiceDefinitionDTOSchema, ConsumableConditionDTOSchema, EncounterStageDTOSchema, PreconditionDTOSchema, } from "@game-infra/event-schemas";
|
|
142
|
+
//# sourceMappingURL=storyPayloads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storyPayloads.js","sourceRoot":"","sources":["../src/storyPayloads.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,EACjB,gCAAgC,EAChC,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,KAAK,EACL,OAAO,EACP,MAAM,EACN,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,GACP,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;IACvC,KAAK,EAAE,MAAM,EAAE;IACf,+BAA+B;IAC/B,OAAO,EAAE,MAAM,EAAE;IACjB,OAAO,EAAE,MAAM,EAAE;IACjB,IAAI,EAAE,MAAM,EAAE;IACd,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;CACxB,CAAC,CAAC;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;IAC1C,KAAK,EAAE,MAAM,EAAE;IACf,WAAW,EAAE,sBAAsB;IACnC,MAAM,EAAE,iBAAiB;IACzB,WAAW,EAAE,OAAO,EAAE;IACtB,YAAY,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC;IACjC,sFAAsF;IACtF,mBAAmB,EAAE,QAAQ,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC3D,wBAAwB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,gCAAgC,CAAC,CAAC;IACtF,mEAAmE;IACnE,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAEnD,oEAAoE;IAEpE,wEAAwE;IACxE,IAAI,EAAE,MAAM,EAAE;IACd,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;IACrB,mEAAmE;IACnE,aAAa,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;IACjC,gFAAgF;IAChF,iBAAiB,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;CACtC,CAAC,CAAC;AAIH,mFAAmF;AACnF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,UAAU,CAAU,CAAC;AAErE,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;AAIlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;IAC3C,GAAG,uBAAuB,CAAC,OAAO;IAClC,6EAA6E;IAC7E,KAAK,EAAE,MAAM,EAAE;IACf,MAAM,EAAE,qBAAqB;IAC7B,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE;IAClB,qDAAqD;IACrD,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;CACvB,CAAC,CAAC;AAIH;;;GAGG;AACH,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,4BAA4B,EAC5B,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@game-infra/story-schemas",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Story-mode API contract: branching arcs and beats built on the event-editor's encounter-stage and choice DTOs, behind one design-content resource",
|
|
5
|
+
"homepage": "https://github.com/kibertoad/game-infra/tree/main/packages/schemas/story-schemas#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/kibertoad/game-infra/issues"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/kibertoad/game-infra.git",
|
|
13
|
+
"directory": "packages/schemas/story-schemas"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@toad-contracts/core": "0.4.0",
|
|
31
|
+
"@toad-contracts/valibot": "0.5.0",
|
|
32
|
+
"@game-infra/api-schemas-core": "0.3.0",
|
|
33
|
+
"@game-infra/event-schemas": "1.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^26.1.2",
|
|
37
|
+
"rimraf": "^6.1.3",
|
|
38
|
+
"typescript": "^7.0.2",
|
|
39
|
+
"valibot": "^1.4.2",
|
|
40
|
+
"vitest": "^4.1.10"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"valibot": "^1.4.0"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "rimraf dist && tsc --project tsconfig.build.json",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"clean": "rimraf dist"
|
|
50
|
+
}
|
|
51
|
+
}
|