@tomradex/domain 0.0.0-stage → 0.2.16

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/schema.js ADDED
@@ -0,0 +1,56 @@
1
+ import { z } from "zod";
2
+ export const itemKindSchema = z.enum(["ticket", "epic"]);
3
+ export const workTypeSchema = z.enum(["coding", "general"]);
4
+ export const itemStatusSchema = z.enum(["backlog", "todo", "doing", "verifying", "done", "cancelled"]);
5
+ // Agents read a bare 0–4 as "1 is most urgent" unless told otherwise.
6
+ export const prioritySchema = z.literal([0, 1, 2, 3, 4]).describe("0 none, 1 low, 2 medium, 3 high, 4 urgent — higher is more urgent");
7
+ export const listItemsFilterSchema = z.object({
8
+ projectId: z.string().optional(),
9
+ boardId: z.string().optional(),
10
+ status: itemStatusSchema.optional(),
11
+ kind: itemKindSchema.optional(),
12
+ workType: workTypeSchema.optional(),
13
+ priority: prioritySchema.optional(),
14
+ label: z.string().optional(),
15
+ parentId: z.string().nullable().optional().describe("The parent item's id or key, e.g. TOM-12; null for none"),
16
+ search: z.string().optional()
17
+ });
18
+ export const fieldValueSchema = z.union([z.string(), z.number()]);
19
+ /** A key set to null clears the value. */
20
+ export const fieldsPatchSchema = z.record(z.string(), fieldValueSchema.nullable());
21
+ export const filterClauseSchema = z.object({
22
+ field: z.string(),
23
+ op: z.enum(["in", "not-in", "contains", "gte", "lte"]),
24
+ values: z.array(fieldValueSchema.nullable())
25
+ });
26
+ export const sortKeySchema = z.object({ field: z.string(), dir: z.enum(["asc", "desc"]) });
27
+ export const createItemSchema = z.object({
28
+ playbookId: z.string().min(1).nullable().optional(),
29
+ title: z.string().min(1),
30
+ body: z.string().nullable().optional(),
31
+ kind: itemKindSchema.optional(),
32
+ workType: workTypeSchema.optional(),
33
+ status: itemStatusSchema.optional(),
34
+ priority: prioritySchema.optional(),
35
+ labels: z.array(z.string()).optional(),
36
+ parentId: z.string().nullable().optional().describe("The parent item's id or key, e.g. TOM-12; null for none"),
37
+ projectId: z.string().optional(),
38
+ boardId: z.string().optional(),
39
+ fields: fieldsPatchSchema.optional()
40
+ });
41
+ export const patchSchema = z.object({
42
+ playbookId: z.string().min(1).nullable().optional(),
43
+ title: z.string().optional(),
44
+ body: z.string().nullable().optional(),
45
+ kind: itemKindSchema.optional(),
46
+ workType: workTypeSchema.optional(),
47
+ status: itemStatusSchema.optional(),
48
+ priority: prioritySchema.optional(),
49
+ labels: z.array(z.string()).optional(),
50
+ blocks: z.array(z.string()).optional().describe("Ids or keys of the items this one blocks"),
51
+ parentId: z.string().nullable().optional().describe("The parent item's id or key, e.g. TOM-12; null for none"),
52
+ rank: z.number().optional(),
53
+ boardId: z.string().optional().describe("Move the item to this workstream (list_workstreams)"),
54
+ fields: fieldsPatchSchema.optional()
55
+ });
56
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1,311 @@
1
+ import type { Layout, ViewQuery } from "./query.js";
2
+ import type { TicketEvidence } from "./delivery.js";
3
+ export type ItemKind = "ticket" | "epic";
4
+ export type WorkType = "coding" | "general";
5
+ export type ItemStatus = "backlog" | "todo" | "doing" | "verifying" | "done" | "cancelled";
6
+ export declare const ITEM_STATUSES: readonly ItemStatus[];
7
+ /** 0 None · 1 Low · 2 Medium (default) · 3 High · 4 Urgent. */
8
+ export type Priority = 0 | 1 | 2 | 3 | 4;
9
+ export declare const DEFAULT_PRIORITY: Priority;
10
+ /** Who wrote a change. Human edits are 'human'; every agent or plugin write is 'ai:<source>'. */
11
+ /** Who wrote: a person, a model, or a sync reading evidence in from outside (`sync:git` — a merge moved the ticket). */
12
+ export type Author = "human" | `ai:${string}` | `sync:${string}`;
13
+ /** Derived from updatedBy + humanLocked; never stored. */
14
+ export type Provenance = "human" | "ai" | "sync" | "locked";
15
+ /** A stored custom-field value. Dates are ISO `YYYY-MM-DD`; selects hold the option id. */
16
+ export type FieldValue = string | number;
17
+ export interface Item {
18
+ evidence: TicketEvidence;
19
+ id: string;
20
+ projectId: string;
21
+ /** The board that owns this issue. Dragging never changes it. */
22
+ boardId: string;
23
+ /** Per-project sequence behind the human key. Never reused. */
24
+ keyNum: number;
25
+ /** Display key, e.g. TOM-142. */
26
+ key: string;
27
+ title: string;
28
+ body: string | null;
29
+ kind: ItemKind;
30
+ workType: WorkType;
31
+ playbookId: string | null;
32
+ status: ItemStatus;
33
+ priority: Priority;
34
+ parentId: string | null;
35
+ rank: number;
36
+ labels: string[];
37
+ /** Ids of the items this one blocks. */
38
+ blocks: string[];
39
+ /** Ids of the items that block this one — the inverse of their `blocks`. */
40
+ blockedBy: string[];
41
+ /** Custom field values by field id. Built-in fields are the columns above. */
42
+ fields: Record<string, FieldValue>;
43
+ updatedAt: number;
44
+ updatedBy: Author;
45
+ version: number;
46
+ /** When set, AI writes may not touch title/body. */
47
+ humanLocked: boolean;
48
+ }
49
+ /** `fields` merges: a key set to null clears that value, absent keys are left alone. */
50
+ export type Patch = Partial<Pick<Item, "title" | "body" | "kind" | "workType" | "playbookId" | "status" | "priority" | "parentId" | "rank" | "boardId" | "labels" | "blocks" | "humanLocked">> & {
51
+ fields?: Record<string, FieldValue | null>;
52
+ };
53
+ export type OplogEntity = "item" | "board" | "view";
54
+ /**
55
+ * 'delete' is reversible — the row carries the snapshot undo restores from.
56
+ * 'purge' is a human-only permanent destroy: the entity's own history goes with
57
+ * it and the tombstone carries no snapshot, so undo walks straight past it.
58
+ * 'rank' is one item's manual position in one view — logged so it travels and
59
+ * can be undone, kept apart so history reads as decisions, not drags.
60
+ * 'merge' is a note a sync left behind: the same field changed on two machines,
61
+ * `before` holds the value that lost and `after` the one that stands. Undo
62
+ * steps over it; taking the loser back is an ordinary edit.
63
+ */
64
+ export type OplogOp = "create" | "update" | "delete" | "purge" | "rank" | "merge";
65
+ export interface OplogEntry {
66
+ seq: number;
67
+ entity: OplogEntity;
68
+ entityId: string;
69
+ op: OplogOp;
70
+ baseVersion: number | null;
71
+ before: unknown | null;
72
+ after: unknown | null;
73
+ by: Author;
74
+ at: number;
75
+ /** The agent run this write belongs to; null for a write made outside one. */
76
+ runId: string | null;
77
+ /** The machine that made the write; `device:deviceSeq` is the op's identity across machines. */
78
+ device: string;
79
+ /** The op's position in its own machine's sequence; null only for rows written before devices existed. */
80
+ deviceSeq: number | null;
81
+ /** The fields the op changed (the whole entity for a create); what the folder's log carries. */
82
+ patch: Record<string, unknown> | null;
83
+ /** The extension that made the write; null for the app itself. Local to this machine. */
84
+ via: string | null;
85
+ }
86
+ export interface UndoResult {
87
+ entry: OplogEntry;
88
+ /** One line describing what was reverted, for the toast. */
89
+ summary: string;
90
+ }
91
+ /** Result of reverting one agent run. `kept` names writes left in place because someone edited the entity afterwards. */
92
+ export interface UndoRunResult {
93
+ reverted: number;
94
+ /** `entity` is an oplog entity, or what another undo provider calls its own (a file, a setting). */
95
+ kept: {
96
+ entity: string;
97
+ entityId: string;
98
+ label: string;
99
+ reason: string;
100
+ }[];
101
+ }
102
+ /**
103
+ * One record of the project's history as the timeline shows it: a backlog
104
+ * write, a file operation, or anything a plugin logs through its own undo
105
+ * provider. `ref` (`provider:id`) names it to `oplog.revert` and `oplog.rollback`.
106
+ */
107
+ export interface UndoRecord {
108
+ ref: string;
109
+ provider: string;
110
+ id: string;
111
+ /** What kind of thing it touched: `item`, `board`, `view`, `file`, or a plugin's own. */
112
+ entity: string;
113
+ entityId: string;
114
+ /** What happened to it: an oplog op, or a file op (`write`, `mkdir`, `move`, `copy`, `remove`, `import`). */
115
+ op: string;
116
+ /** The entity's name for a sentence: an issue key, a view name, a file path. */
117
+ label: string;
118
+ /** A second name when the op has one — where a file moved or was copied to. */
119
+ target: string | null;
120
+ by: Author;
121
+ at: number;
122
+ runId: string | null;
123
+ /** The machine that made it; a record from another machine is history, never undoable here. */
124
+ device: string;
125
+ /** False for purges, merge notes and other machines' writes. */
126
+ undoable: boolean;
127
+ /** Set while the record sits in the redo stack; a new write anywhere clears that stack. */
128
+ undoneAt: number | null;
129
+ }
130
+ /** One step the timeline took: the record it acted on and a line for the toast. */
131
+ export interface UndoStep {
132
+ record: UndoRecord;
133
+ summary: string;
134
+ }
135
+ /** Moving the timeline's cursor to a record: the steps taken, and why it stopped short when it did. */
136
+ export interface RollbackResult {
137
+ steps: UndoStep[];
138
+ stopped: string | null;
139
+ }
140
+ export interface CreateItemInput {
141
+ projectId?: string;
142
+ boardId: string;
143
+ title: string;
144
+ body?: string | null;
145
+ kind?: ItemKind;
146
+ workType?: WorkType;
147
+ playbookId?: string | null;
148
+ status?: ItemStatus;
149
+ priority?: Priority;
150
+ parentId?: string | null;
151
+ rank?: number;
152
+ labels?: string[];
153
+ fields?: Record<string, FieldValue | null>;
154
+ by: Author;
155
+ }
156
+ export interface ListItemsFilter {
157
+ projectId?: string;
158
+ boardId?: string;
159
+ status?: ItemStatus;
160
+ kind?: ItemKind;
161
+ workType?: WorkType;
162
+ priority?: Priority;
163
+ parentId?: string | null;
164
+ label?: string;
165
+ /** Words that must all appear in title or body, as substrings in any script; matches come most relevant first. */
166
+ search?: string;
167
+ /** At most this many rows, from the front of the order: the most relevant when searching. */
168
+ limit?: number;
169
+ /** When no item has every search term, fall back to items with some of them, best matches first. */
170
+ widen?: boolean;
171
+ }
172
+ export interface Project {
173
+ id: string;
174
+ name: string;
175
+ description: string | null;
176
+ /** Prefix of the human issue key, e.g. 'TOM' in TOM-142. */
177
+ keyPrefix: string;
178
+ archived: boolean;
179
+ /** The tour a first run opens with: this machine's own, never in the account's catalog. */
180
+ sample?: boolean;
181
+ createdAt: number;
182
+ updatedAt: number;
183
+ }
184
+ export interface CreateProjectInput {
185
+ name: string;
186
+ description?: string | null;
187
+ keyPrefix?: string;
188
+ /** The language the seeded workstream and views are named in: "en" (the default) or "zh". */
189
+ locale?: string;
190
+ }
191
+ export type ProjectPatch = Partial<Pick<Project, "name" | "description" | "archived">>;
192
+ /**
193
+ * A board is a workstream — an option of the built-in Workstream field. Every
194
+ * issue belongs to exactly one; a drag on a Workstream column writes it like
195
+ * any other field.
196
+ */
197
+ export interface Board {
198
+ id: string;
199
+ projectId: string;
200
+ name: string;
201
+ icon: string;
202
+ note: string | null;
203
+ rank: number;
204
+ /** The code repository this workstream stands for, if any; several workstreams may share one. */
205
+ repoId: string | null;
206
+ /** Where in that repository the workstream's code lives; '' for the root. */
207
+ repoPath: string;
208
+ createdAt: number;
209
+ updatedAt: number;
210
+ }
211
+ export interface CreateBoardInput {
212
+ projectId: string;
213
+ name: string;
214
+ icon?: string;
215
+ note?: string | null;
216
+ rank?: number;
217
+ repoId?: string | null;
218
+ repoPath?: string;
219
+ }
220
+ export type BoardPatch = Partial<Pick<Board, "name" | "icon" | "note" | "rank" | "repoId" | "repoPath">>;
221
+ /**
222
+ * A code repository a project's workstreams stand for. Shared: the remote URL
223
+ * is its identity everywhere. Where it is checked out on this machine is the
224
+ * catalog's business, never a row here.
225
+ */
226
+ export interface Repo {
227
+ id: string;
228
+ projectId: string;
229
+ remote: string;
230
+ name: string;
231
+ defaultBranch: string;
232
+ createdAt: number;
233
+ updatedAt: number;
234
+ }
235
+ export interface CreateRepoInput {
236
+ projectId: string;
237
+ remote: string;
238
+ name?: string;
239
+ defaultBranch?: string;
240
+ }
241
+ export type RepoPatch = Partial<Pick<Repo, "name" | "defaultBranch" | "remote">>;
242
+ /** A saved, named way of looking at the project's backlog: one layout and one query. */
243
+ export interface View {
244
+ id: string;
245
+ projectId: string;
246
+ name: string;
247
+ icon: string;
248
+ layout: Layout;
249
+ query: ViewQuery;
250
+ rank: number;
251
+ createdAt: number;
252
+ updatedAt: number;
253
+ }
254
+ export interface CreateViewInput {
255
+ projectId: string;
256
+ name: string;
257
+ icon?: string;
258
+ layout?: Layout;
259
+ query?: Partial<ViewQuery>;
260
+ rank?: number;
261
+ }
262
+ export type ViewPatch = Partial<Pick<View, "name" | "icon" | "layout" | "query" | "rank">>;
263
+ export type BuiltInTheme = "light" | "dark" | "matcha" | "dawn";
264
+ export type ThemePreference = "system" | BuiltInTheme | `custom:${string}`;
265
+ export declare const THEME_TOKEN_NAMES: readonly ["bg", "surface", "surface-warm", "fg", "fg-2", "muted", "meta", "border", "border-soft", "accent", "accent-on", "accent-light", "accent-active", "success", "warn", "danger", "tag-bg-faint", "tag-bg-soft", "tag-bg-base", "tag-bg-strong", "tag-fg"];
266
+ export type ThemeTokenName = (typeof THEME_TOKEN_NAMES)[number];
267
+ export declare const THEME_FONT_NAMES: readonly ["font-display", "font-body", "font-mono"];
268
+ export type ThemeFontName = (typeof THEME_FONT_NAMES)[number];
269
+ export declare const THEME_FONT_SIZE_NAMES: readonly ["text-xs", "text-sm", "text-base", "text-md", "text-lg", "text-xl", "text-2xl"];
270
+ export declare const THEME_FONT_WEIGHT_NAMES: readonly ["font-weight-regular", "font-weight-medium"];
271
+ export declare const THEME_TYPOGRAPHY_NAMES: readonly ["font-display", "font-body", "font-mono", "text-xs", "text-sm", "text-base", "text-md", "text-lg", "text-xl", "text-2xl", "font-weight-regular", "font-weight-medium"];
272
+ export type ThemeTypographyName = (typeof THEME_TYPOGRAPHY_NAMES)[number];
273
+ export interface CustomTheme {
274
+ id: `custom:${string}`;
275
+ name: string;
276
+ base: BuiltInTheme;
277
+ icon: "i-sun" | "i-moon" | "i-leaf" | "i-tag" | "i-bug" | "i-board" | "i-stack" | "i-sliders";
278
+ tokens: Record<ThemeTokenName, string>;
279
+ fonts: Record<ThemeTypographyName, string>;
280
+ }
281
+ export type ThemeAutomationMode = "none" | "system" | "schedule" | "shuffle";
282
+ export interface ThemeScheduleRule {
283
+ start: string;
284
+ end: string;
285
+ theme: Exclude<ThemePreference, "system">;
286
+ }
287
+ export interface ThemeAutomation {
288
+ mode: ThemeAutomationMode;
289
+ defaultTheme: Exclude<ThemePreference, "system">;
290
+ schedule: ThemeScheduleRule[];
291
+ shuffleMinutes: number;
292
+ }
293
+ /**
294
+ * 'system' follows the OS locale, falling back to English when no language
295
+ * the app has matches it; otherwise a language tag — one the app ships
296
+ * ("en", "zh", "zh-Hant", "ja", "es", "de", "fr", "ru") or one a language pack adds.
297
+ */
298
+ export type LanguagePreference = "system" | (string & {});
299
+ export interface LlmSettings {
300
+ apiKey: string;
301
+ baseURL: string;
302
+ model: string;
303
+ }
304
+ /** Settings are sections keyed by id; plugins register their own. */
305
+ export interface AppSettings {
306
+ theme: ThemePreference;
307
+ language: LanguagePreference;
308
+ llm?: LlmSettings;
309
+ [section: string]: unknown;
310
+ }
311
+ //# sourceMappingURL=types.d.ts.map
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ export const ITEM_STATUSES = ["backlog", "todo", "doing", "verifying", "done", "cancelled"];
2
+ export const DEFAULT_PRIORITY = 2;
3
+ export const THEME_TOKEN_NAMES = ["bg", "surface", "surface-warm", "fg", "fg-2", "muted", "meta", "border", "border-soft", "accent", "accent-on", "accent-light", "accent-active", "success", "warn", "danger", "tag-bg-faint", "tag-bg-soft", "tag-bg-base", "tag-bg-strong", "tag-fg"];
4
+ export const THEME_FONT_NAMES = ["font-display", "font-body", "font-mono"];
5
+ export const THEME_FONT_SIZE_NAMES = ["text-xs", "text-sm", "text-base", "text-md", "text-lg", "text-xl", "text-2xl"];
6
+ export const THEME_FONT_WEIGHT_NAMES = ["font-weight-regular", "font-weight-medium"];
7
+ export const THEME_TYPOGRAPHY_NAMES = [...THEME_FONT_NAMES, ...THEME_FONT_SIZE_NAMES, ...THEME_FONT_WEIGHT_NAMES];
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,39 @@
1
+ import { type Dictionaries, type LanguageTag } from "./language.js";
2
+ /**
3
+ * What the backend says to a person, kept as one book of templates per
4
+ * package. A template names its values as {{slot}}; the code picks which
5
+ * template to use and fills it, so a translation is data and nothing more.
6
+ * Prompts written for an agent are not words: they stay in code, in English.
7
+ */
8
+ /** The languages Tomrade's own code writes in, each complete. Any other language reads English, or what an installed language pack brings. */
9
+ export type WordsLocale = "en" | "zh";
10
+ export declare const wordsLocale: (locale: unknown) => WordsLocale;
11
+ /** The `{{slot}}` names a template asks for. */
12
+ export type Slots<S extends string> = S extends `${string}{{${infer V}}}${infer R}` ? V | Slots<R> : never;
13
+ type Fill<S extends string> = [Slots<S>] extends [never] ? [] : [vars: Record<Slots<S>, string | number>];
14
+ type SameSlots<A extends string, B extends string> = [Slots<A>] extends [Slots<B>] ? ([Slots<B>] extends [Slots<A>] ? true : false) : false;
15
+ /** Each translation is complete and names exactly the slots its English does. */
16
+ type Translation<E extends Record<string, string>, Z> = {
17
+ [K in keyof E]: K extends keyof Z ? (Z[K] extends string ? (SameSlots<E[K], Z[K]> extends true ? Z[K] : `slots differ from en: ${E[K]}`) : string) : string;
18
+ };
19
+ export interface Speak<E extends Record<string, string>> {
20
+ <K extends keyof E & string>(key: K, ...vars: Fill<E[K]>): string;
21
+ /** The language asked for; a word it lacks reads English. */
22
+ readonly locale: LanguageTag;
23
+ }
24
+ export type WordBook<E extends Record<string, string>> = (locale: unknown) => Speak<E>;
25
+ export declare const fillSlots: (template: string, vars?: Record<string, string | number>) => string;
26
+ export declare function defineWords<const E extends Record<string, string>, const Z extends Record<string, string>>(id: string, book: {
27
+ en: E;
28
+ zh: Z & Translation<E, Z>;
29
+ }): WordBook<E>;
30
+ /** The English of every book defined so far, keyed by book id. */
31
+ export declare const englishWords: () => Dictionaries;
32
+ /**
33
+ * A language pack's words for the backend's books, spoken from now on. An
34
+ * entry English lacks, or one asking for other slots, reads English. The
35
+ * pack installed last speaks first. Returns the undo.
36
+ */
37
+ export declare function installWords(locale: LanguageTag, books: Dictionaries): () => void;
38
+ export {};
39
+ //# sourceMappingURL=words.d.ts.map
package/dist/words.js ADDED
@@ -0,0 +1,45 @@
1
+ import { languageTag, sameSlots } from "./language.js";
2
+ export const wordsLocale = (locale) => (locale === "zh" ? "zh" : "en");
3
+ export const fillSlots = (template, vars) => vars ? template.replace(/\{\{(\w+)\}\}/g, (_, name) => String(vars[name] ?? "")) : template;
4
+ /** Every book's English, by id: what a language pack translates. */
5
+ const english = new Map();
6
+ /** Language → book → key: what installed language packs bring, each layer kept apart so one can be taken back. */
7
+ const packs = new Map();
8
+ export function defineWords(id, book) {
9
+ english.set(id, book.en);
10
+ const zh = book.zh;
11
+ return (locale) => {
12
+ const lang = languageTag(locale);
13
+ const speak = (key, vars) => {
14
+ const source = book.en[key];
15
+ let text;
16
+ // A pack's entry stands in only for a key English has, asking for the same values.
17
+ for (const layer of packs.get(lang) ?? []) {
18
+ const said = layer[id]?.[key];
19
+ if (text === undefined && source !== undefined && typeof said === "string" && sameSlots(source, said))
20
+ text = said;
21
+ }
22
+ return fillSlots(text ?? (lang === "zh" ? zh[key] : undefined) ?? source ?? key, vars);
23
+ };
24
+ return Object.assign(speak, { locale: lang });
25
+ };
26
+ }
27
+ /** The English of every book defined so far, keyed by book id. */
28
+ export const englishWords = () => Object.fromEntries(english);
29
+ /**
30
+ * A language pack's words for the backend's books, spoken from now on. An
31
+ * entry English lacks, or one asking for other slots, reads English. The
32
+ * pack installed last speaks first. Returns the undo.
33
+ */
34
+ export function installWords(locale, books) {
35
+ const tag = languageTag(locale);
36
+ packs.set(tag, [books, ...(packs.get(tag) ?? [])]);
37
+ return () => {
38
+ const rest = (packs.get(tag) ?? []).filter((l) => l !== books);
39
+ if (rest.length)
40
+ packs.set(tag, rest);
41
+ else
42
+ packs.delete(tag);
43
+ };
44
+ }
45
+ //# sourceMappingURL=words.js.map
package/package.json CHANGED
@@ -1,6 +1,28 @@
1
1
  {
2
2
  "name": "@tomradex/domain",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.16",
4
+ "type": "module",
5
+ "author": "Haoyuan Tang",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "license": "Apache-2.0",
13
+ "description": "Tomrade's domain types and schemas: the issues, fields, boards, views and history a plugin reads",
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "dependencies": {
26
+ "zod": "^4.4.3"
27
+ }
28
+ }