a homebrewed DnD campaign based in the Honkai: Star Rail universe
hsr honkaistarrail dnd
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

reorganize schemas + implement some mechanics

also upgrades the storybook csf addon

+587 -283
+23 -2
app/src/lib/server/db/index.ts
··· 1 1 import { DATABASE_URL } from '$env/static/private' 2 2 import { drizzle } from 'drizzle-orm/node-postgres' 3 3 import * as authSchemas from './schemas/auth' 4 - import * as dndSchemas from './schemas/dnd' 4 + import * as dndCampaignSchemas from './schemas/dnd/campaign' 5 + import * as dndCharacterSchemas from './schemas/dnd/character' 6 + import * as dndClassSchemas from './schemas/dnd/class' 7 + import * as dndEquipmentSchemas from './schemas/dnd/equipment' 8 + import * as dndFactionSchemas from './schemas/dnd/faction' 9 + import * as dndLanguageSchemas from './schemas/dnd/language' 10 + import * as dndConditionSchemas from './schemas/dnd/mechanic' 11 + import * as dndOriginSchemas from './schemas/dnd/origin' 12 + import * as dndSourcebookSchemas from './schemas/dnd/sourcebook' 13 + import * as dndSpellSchemas from './schemas/dnd/spell' 5 14 6 15 if (DATABASE_URL === '') throw new Error('DATABASE_URL is not set') 7 16 8 17 export const db = drizzle(DATABASE_URL, { 9 - schema: { ...dndSchemas, ...authSchemas }, 18 + schema: { 19 + ...dndCampaignSchemas, 20 + ...dndCharacterSchemas, 21 + ...dndClassSchemas, 22 + ...dndConditionSchemas, 23 + ...dndEquipmentSchemas, 24 + ...dndFactionSchemas, 25 + ...dndLanguageSchemas, 26 + ...dndOriginSchemas, 27 + ...dndSourcebookSchemas, 28 + ...dndSpellSchemas, 29 + ...authSchemas, 30 + }, 10 31 }) 11 32 export type DatabaseConn = typeof db
+1 -1
app/src/lib/server/db/repos/background.ts
··· 1 1 import { eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 2 2 import type { DatabaseConn } from '..' 3 - import { background } from '../schemas/dnd' 3 + import { background } from '../schemas/dnd/origin' 4 4 import { selectColumns, querySingle, type TableColumnNames } from '../utils' 5 5 6 6 export type BackgroundTable = typeof background
+1 -1
app/src/lib/server/db/repos/campaign-member.ts
··· 2 2 import type { DatabaseConn } from '..' 3 3 import type { Campaign } from './campaign' 4 4 import { user } from '../schemas/auth' 5 - import { campaignMember } from '../schemas/dnd' 5 + import { campaignMember } from '../schemas/dnd/campaign' 6 6 7 7 export type CampaignMemberTable = typeof campaignMember 8 8 export type CampaignMember = InferSelectModel<CampaignMemberTable>
+2 -1
app/src/lib/server/db/repos/campaign.ts
··· 1 1 import { eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 2 2 import type { DatabaseConn } from '..' 3 3 import { user } from '../schemas/auth' 4 - import { campaign, campaignSession, campaignSourceMaterial, sourceBook } from '../schemas/dnd' 4 + import { campaign, campaignSession, campaignSourceMaterial } from '../schemas/dnd/campaign' 5 + import { sourceBook } from '../schemas/dnd/sourcebook' 5 6 import { querySingle, selectColumns, type TableColumnNames } from '../utils' 6 7 7 8 export type CampaignTable = typeof campaign
+162
app/src/lib/server/db/repos/character-status.ts
··· 1 + import { and, eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 2 + import type { Character } from './character' 3 + import { type DatabaseConn } from '..' 4 + import { 5 + characterCondition, 6 + characterConditionImmunity, 7 + characterDmgResistance, 8 + characterDmgVulnerability, 9 + characterDmgImmunity, 10 + } from '../schemas/dnd/character' 11 + import { condition } from '../schemas/dnd/mechanic' 12 + import { damage } from '../schemas/dnd/mechanic' 13 + 14 + export type CharacterCondition = InferSelectModel<typeof characterCondition> 15 + export type NewCharacterCondition = InferInsertModel<typeof characterCondition> 16 + export type UpdateCharacterCondition = Partial<Omit<NewCharacterCondition, 'id'>> 17 + 18 + export type CharacterConditionImmunity = InferSelectModel<typeof characterConditionImmunity> 19 + export type NewCharacterConditionImmunity = InferInsertModel<typeof characterConditionImmunity> 20 + export type UpdateCharacterConditionImmunity = Partial<Omit<NewCharacterConditionImmunity, 'id'>> 21 + 22 + export type CharacterResistance = InferSelectModel<typeof characterDmgResistance> 23 + export type NewCharacterResistance = InferInsertModel<typeof characterDmgResistance> 24 + export type UpdateCharacterResistance = Partial<Omit<NewCharacterResistance, 'id'>> 25 + 26 + export type CharacterVulnerability = InferSelectModel<typeof characterDmgVulnerability> 27 + export type NewCharacterVulnerability = InferInsertModel<typeof characterDmgVulnerability> 28 + export type UpdateCharacterVulnerability = Partial<Omit<NewCharacterVulnerability, 'id'>> 29 + 30 + export type CharacterImmunity = InferSelectModel<typeof characterDmgImmunity> 31 + export type NewCharacterImmunity = InferInsertModel<typeof characterDmgImmunity> 32 + export type UpdateCharacterImmunity = Partial<Omit<NewCharacterImmunity, 'id'>> 33 + 34 + export class CharacterStatusRepository { 35 + private db: DatabaseConn 36 + public constructor(db: DatabaseConn) { 37 + this.db = db 38 + } 39 + 40 + public async getConditions(id: Character['id']) { 41 + return await this.db 42 + .select() 43 + .from(characterCondition) 44 + .where(eq(characterCondition.characterId, id)) 45 + .leftJoin(condition, eq(condition.id, characterCondition.conditionId)) 46 + } 47 + 48 + public async removeCondition(model: CharacterCondition) { 49 + return await this.db 50 + .delete(characterCondition) 51 + .where( 52 + and( 53 + eq(characterCondition.characterId, model.characterId), 54 + eq(characterCondition.conditionId, model.conditionId), 55 + ), 56 + ) 57 + } 58 + 59 + public async removeAllConditions(id: Character['id']) { 60 + return await this.db.delete(characterCondition).where(eq(characterCondition.characterId, id)) 61 + } 62 + 63 + public async getConditionImmunities(id: Character['id']) { 64 + return await this.db 65 + .select() 66 + .from(characterConditionImmunity) 67 + .where(eq(characterConditionImmunity.characterId, id)) 68 + .leftJoin(condition, eq(condition.id, characterConditionImmunity.conditionId)) 69 + } 70 + 71 + public async removeConditionImmunity(model: CharacterConditionImmunity) { 72 + return await this.db 73 + .delete(characterConditionImmunity) 74 + .where( 75 + and( 76 + eq(characterConditionImmunity.characterId, model.characterId), 77 + eq(characterConditionImmunity.conditionId, model.conditionId), 78 + ), 79 + ) 80 + } 81 + 82 + public async removeAllConditionImmunities(id: Character['id']) { 83 + return await this.db 84 + .delete(characterConditionImmunity) 85 + .where(eq(characterConditionImmunity.characterId, id)) 86 + } 87 + 88 + public async getResistances(id: Character['id']) { 89 + return await this.db 90 + .select() 91 + .from(characterDmgResistance) 92 + .where(eq(characterDmgResistance.characterId, id)) 93 + .leftJoin(damage, eq(damage.id, characterDmgResistance.damageId)) 94 + } 95 + 96 + public async removeResistance(model: CharacterResistance) { 97 + return await this.db 98 + .delete(characterDmgResistance) 99 + .where( 100 + and( 101 + eq(characterDmgResistance.characterId, model.characterId), 102 + eq(characterDmgResistance.damageId, model.damageId), 103 + ), 104 + ) 105 + } 106 + 107 + public async removeAllResistances(id: Character['id']) { 108 + return await this.db 109 + .delete(characterDmgResistance) 110 + .where(eq(characterDmgResistance.characterId, id)) 111 + } 112 + 113 + public async getVulnerabilities(id: Character['id']) { 114 + return await this.db 115 + .select() 116 + .from(characterDmgVulnerability) 117 + .where(eq(characterDmgVulnerability.characterId, id)) 118 + .leftJoin(damage, eq(damage.id, characterDmgVulnerability.damageId)) 119 + } 120 + 121 + public async removeVulnerability(model: CharacterVulnerability) { 122 + return await this.db 123 + .delete(characterDmgVulnerability) 124 + .where( 125 + and( 126 + eq(characterDmgVulnerability.characterId, model.characterId), 127 + eq(characterDmgVulnerability.damageId, model.damageId), 128 + ), 129 + ) 130 + } 131 + 132 + public async removeAllVulnerabilities(id: Character['id']) { 133 + return await this.db 134 + .delete(characterDmgVulnerability) 135 + .where(eq(characterDmgVulnerability.characterId, id)) 136 + } 137 + 138 + public async getImmunities(id: Character['id']) { 139 + return await this.db 140 + .select() 141 + .from(characterDmgImmunity) 142 + .where(eq(characterDmgImmunity.characterId, id)) 143 + .leftJoin(damage, eq(damage.id, characterDmgImmunity.damageId)) 144 + } 145 + 146 + public async removeImmunity(model: CharacterImmunity) { 147 + return await this.db 148 + .delete(characterDmgImmunity) 149 + .where( 150 + and( 151 + eq(characterDmgImmunity.characterId, model.characterId), 152 + eq(characterDmgImmunity.damageId, model.damageId), 153 + ), 154 + ) 155 + } 156 + 157 + public async removeAllImmunities(id: Character['id']) { 158 + return await this.db 159 + .delete(characterDmgImmunity) 160 + .where(eq(characterDmgImmunity.characterId, id)) 161 + } 162 + }
+13 -8
app/src/lib/server/db/repos/character.ts
··· 1 1 import { eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 2 2 import type { DatabaseConn } from '..' 3 - import type { User, UserId } from './auth' 3 + import type { UserId } from './auth' 4 4 import { user } from '../schemas/auth' 5 - import { character, background, species } from '../schemas/dnd' 5 + import { character, characterLanguage } from '../schemas/dnd/character' 6 + import { language } from '../schemas/dnd/language' 7 + import { background, species } from '../schemas/dnd/origin' 6 8 import { querySingle } from '../utils' 7 9 8 10 export type CharacterTable = typeof character ··· 35 37 .then(querySingle) 36 38 } 37 39 38 - public async getCharactersByUser(userId: UserId): Promise< 39 - { 40 - character: Character 41 - user: User | null 42 - }[] 43 - > { 40 + public async getCharactersByUser(userId: UserId) { 44 41 return await this.db 45 42 .select() 46 43 .from(character) ··· 50 47 51 48 public async updateCharacter(id: Character['id'], update: UpdateCharacter) { 52 49 return await this.db.update(character).set(update).where(eq(character.id, id)) 50 + } 51 + 52 + public async getLanguages(id: Character['id']) { 53 + return await this.db 54 + .select() 55 + .from(characterLanguage) 56 + .where(eq(characterLanguage.characterId, id)) 57 + .leftJoin(language, eq(language.id, characterLanguage.languageId)) 53 58 } 54 59 }
+23
app/src/lib/server/db/repos/condition.ts
··· 1 + import { eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 2 + import type { DatabaseConn } from '..' 3 + import { condition } from '../schemas/dnd/mechanic' 4 + 5 + export type ConditionTable = typeof condition 6 + export type Condition = InferSelectModel<ConditionTable> 7 + export type NewCondition = InferInsertModel<ConditionTable> 8 + export type UpdateCondition = Partial<Omit<NewCondition, 'id'>> 9 + 10 + export class ConditionRepository { 11 + private db: DatabaseConn 12 + public constructor(db: DatabaseConn) { 13 + this.db = db 14 + } 15 + 16 + public async createCondition(model: NewCondition) { 17 + return await this.db.insert(condition).values(model) 18 + } 19 + 20 + public async getCondition(id: Condition['id']) { 21 + return await this.db.select().from(condition).where(eq(condition.id, id)) 22 + } 23 + }
+2 -1
app/src/lib/server/db/repos/equipment.ts
··· 1 1 import { eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 2 2 import type { DatabaseConn } from '..' 3 - import { equipment, sourceBook } from '../schemas/dnd' 3 + import { equipment } from '../schemas/dnd/equipment' 4 + import { sourceBook } from '../schemas/dnd/sourcebook' 4 5 import { querySingle, selectColumns, type TableColumnNames } from '../utils' 5 6 6 7 export type EquipmentTable = typeof equipment
+2 -1
app/src/lib/server/db/repos/faction.ts
··· 1 1 import { eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 2 2 import { type DatabaseConn } from '..' 3 - import { faction, sourceBook } from '../schemas/dnd' 3 + import { faction } from '../schemas/dnd/faction' 4 + import { sourceBook } from '../schemas/dnd/sourcebook' 4 5 import { querySingle, selectColumns, type TableColumnNames } from '../utils' 5 6 6 7 export type FactionTable = typeof faction
+1 -1
app/src/lib/server/db/repos/source-book.ts
··· 1 1 import { eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 2 2 import type { DatabaseConn } from '..' 3 - import { sourceBook } from '../schemas/dnd' 3 + import { sourceBook } from '../schemas/dnd/sourcebook' 4 4 import { querySingle, selectColumns, type TableColumnNames } from '../utils' 5 5 6 6 export type SourceBookTable = typeof sourceBook
+2 -1
app/src/lib/server/db/repos/species.ts
··· 1 1 import { eq, type InferSelectModel } from 'drizzle-orm' 2 2 import type { DatabaseConn } from '..' 3 - import { sourceBook, species } from '../schemas/dnd' 3 + import { species } from '../schemas/dnd/origin' 4 + import { sourceBook } from '../schemas/dnd/sourcebook' 4 5 import { querySingle, selectColumns, type TableColumnNames } from '../utils' 5 6 6 7 export type SpeciesTable = typeof species
+2 -1
app/src/lib/server/db/repos/spell.ts
··· 1 1 import type { SpellDuration } from '@starlight/types/dnd' 2 2 import { eq, type InferInsertModel, type InferSelectModel } from 'drizzle-orm' 3 3 import type { DatabaseConn } from '..' 4 - import { sourceBook, spell, spellDamage } from '../schemas/dnd' 4 + import { sourceBook } from '../schemas/dnd/sourcebook' 5 + import { spell, spellDamage } from '../schemas/dnd/spell' 5 6 import { querySingle, selectColumns, type TableColumnNames } from '../utils' 6 7 7 8 export type SpellTable = typeof spell
-250
app/src/lib/server/db/schemas/dnd.ts
··· 1 - import { 2 - boolean, 3 - integer, 4 - jsonb, 5 - pgTable, 6 - smallint, 7 - text, 8 - timestamp, 9 - varchar, 10 - } from 'drizzle-orm/pg-core' 11 - import { user } from './auth' 12 - 13 - export const sourceBook = pgTable('source_book', { 14 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 15 - name: varchar('name', { length: 255 }).unique().notNull(), 16 - description: varchar('name', { length: 255 }).notNull(), 17 - isArchived: boolean('is_archived').default(false).notNull(), 18 - createdAt: timestamp('created_at').defaultNow().notNull(), 19 - archivedAt: timestamp('archived_at'), 20 - }) 21 - 22 - export const species = pgTable('species', { 23 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 24 - sourceBookId: integer('source_book_id') 25 - .notNull() 26 - .references(() => sourceBook.id, { onDelete: 'cascade' }), 27 - name: varchar('name', { length: 64 }).notNull(), 28 - description: varchar('name', { length: 255 }).notNull(), 29 - creatureType: varchar('creature_name', { length: 32 }).notNull(), 30 - size: smallint('size').notNull(), 31 - walkSpeed: smallint('walk_speed').notNull(), 32 - swimSpeed: smallint('swim_speed').default(0).notNull(), 33 - climbSpeed: smallint('climb_speed').default(0).notNull(), 34 - flySpeed: smallint('fly_speed').default(0).notNull(), 35 - burrowSpeed: smallint('burrow_speed').default(0).notNull(), 36 - createdAt: timestamp('created_at').defaultNow().notNull(), 37 - }) 38 - 39 - // (table) => [ 40 - // check('walk_speed_is_nonnegative', isNonNegative(table.walkSpeed)), 41 - // check('swim_speed_is_nonnegative', isNonNegative(table.swimSpeed)), 42 - // check('climb_speed_is_nonnegative', isNonNegative(table.climbSpeed)), 43 - // check('fly_speed_is_nonnegative', isNonNegative(table.flySpeed)), 44 - // check('burrow_speed_is_nonnegative', isNonNegative(table.burrowSpeed)), 45 - // ], 46 - 47 - export const speciesFeature = pgTable('species_feature', { 48 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 49 - sourceBookId: integer('source_book_id') 50 - .notNull() 51 - .references(() => sourceBook.id, { onDelete: 'cascade' }), 52 - speciesId: integer('species_id') 53 - .notNull() 54 - .references(() => species.id, { onDelete: 'cascade' }), 55 - builtIn: boolean().notNull(), 56 - name: varchar('name', { length: 255 }).notNull(), 57 - description: varchar('name', { length: 255 }).notNull(), 58 - modifiers: jsonb('modifiers').notNull(), 59 - }) 60 - 61 - export const playableClass = pgTable('playable_class', { 62 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 63 - sourceBookId: integer('source_book_id') 64 - .notNull() 65 - .references(() => sourceBook.id, { onDelete: 'cascade' }), 66 - name: varchar('name', { length: 255 }).notNull(), 67 - description: varchar('name', { length: 1024 }).notNull(), 68 - createdAt: timestamp('created_at').defaultNow().notNull(), 69 - }) 70 - 71 - export const characterClass = pgTable( 72 - 'character_class', 73 - { 74 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 75 - characterId: integer('character_id') 76 - .notNull() 77 - .references(() => character.id), 78 - classId: integer('class') 79 - .notNull() 80 - .references(() => playableClass.id), 81 - level: smallint('level').notNull(), 82 - }, 83 - //(table) => [check('class_level', isBetweenIncl(table.level, 1, 20))], 84 - ) 85 - 86 - export const background = pgTable('background', { 87 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 88 - name: varchar('name', { length: 255 }).notNull(), 89 - description: varchar('name', { length: 1024 }).notNull(), 90 - }) 91 - 92 - export const character = pgTable( 93 - 'character', 94 - { 95 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 96 - ownerId: varchar('owner_id', { length: 36 }) 97 - .notNull() 98 - .references(() => user.id), 99 - campaignId: integer('campaign_id').references(() => campaign.id), 100 - name: varchar('name', { length: 255 }).notNull(), 101 - backgroundId: integer('background_id') 102 - .notNull() 103 - .references(() => background.id), 104 - speciesId: integer('species_id') 105 - .notNull() 106 - .references(() => species.id), 107 - level: integer('level').notNull(), 108 - pronouns: varchar('pronouns', { length: 255 }), 109 - alignment: smallint('alignment'), 110 - age: varchar('height', { length: 255 }), 111 - hair: varchar('hair', { length: 255 }), 112 - gender: varchar('gender', { length: 255 }), 113 - height: varchar('height', { length: 255 }), 114 - weight: varchar('weight', { length: 255 }), 115 - credits: integer('credits').default(0).notNull(), 116 - createdAt: timestamp('created_at').defaultNow().notNull(), 117 - updatedAt: timestamp('updated_at') 118 - .defaultNow() 119 - .$onUpdate(() => /* @__PURE__ */ new Date()) 120 - .notNull(), 121 - }, 122 - // (table) => [ 123 - // check('character_level', isBetweenIncl(table.level, 1, 20)), 124 - // check('age', isNonNegative(table.age)), 125 - // ], 126 - ) 127 - 128 - export const characterClasses = pgTable('character_classes', { 129 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 130 - characterId: integer('character_id') 131 - .notNull() 132 - .references(() => character.id), 133 - classId: integer('class_id') 134 - .notNull() 135 - .references(() => playableClass.id), 136 - }) 137 - 138 - export const spellDamage = pgTable('spell_damage', { 139 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 140 - sourceBookId: integer('source_book_id') 141 - .notNull() 142 - .references(() => sourceBook.id, { onDelete: 'cascade' }), 143 - name: varchar('name', { length: 255 }).unique().notNull(), 144 - description: varchar('name', { length: 255 }).notNull(), 145 - }) 146 - 147 - export const spell = pgTable( 148 - 'spell', 149 - { 150 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 151 - sourceBookId: integer('source_book_id') 152 - .notNull() 153 - .references(() => sourceBook.id), 154 - name: varchar('name', { length: 255 }).notNull(), 155 - description: varchar('description', { length: 1024 }).notNull(), 156 - level: smallint('level').notNull(), 157 - school: integer('school').notNull(), 158 - components: integer().notNull(), 159 - materialComponents: varchar('material_components', { length: 255 }), 160 - damage: integer('damage').references(() => spellDamage.id), 161 - duration: jsonb('duration').notNull(), 162 - isRitual: boolean('is_ritual').notNull(), 163 - needsConcentration: boolean('needs_concentration').notNull(), 164 - createdAt: timestamp('created_at').defaultNow().notNull(), 165 - updatedAt: timestamp('updated_at') 166 - .defaultNow() 167 - .$onUpdate(() => /* @__PURE__ */ new Date()) 168 - .notNull(), 169 - }, 170 - // (table) => [check('spell_level', isBetweenIncl(table.level, 0, 9))], 171 - ) 172 - 173 - export const equipment = pgTable('equipment', { 174 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 175 - sourceBookId: integer('source_book_id') 176 - .notNull() 177 - .references(() => sourceBook.id), 178 - name: varchar('name', { length: 255 }).notNull(), 179 - description: varchar('description', { length: 1024 }).notNull(), 180 - weight: jsonb('weight').$type<{ value: number; unit: string }>(), 181 - cost: jsonb('cost').$type<{ value: number; unit: string }>(), 182 - isMagicItem: boolean(), 183 - isAttunable: boolean(), 184 - createdAt: timestamp('created_at').defaultNow().notNull(), 185 - updatedAt: timestamp('updated_at').defaultNow().notNull(), 186 - }) 187 - 188 - export const faction = pgTable('faction', { 189 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 190 - sourceBookId: integer('source_book_id') 191 - .notNull() 192 - .references(() => sourceBook.id), 193 - name: varchar('name', { length: 255 }).notNull(), 194 - description: varchar('description', { length: 1024 }).notNull(), 195 - }) 196 - 197 - // model for symmetric relationships between factions 198 - export const factionRelationship = pgTable('faction_relationship', { 199 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 200 - factionId1: integer('faction_id1') 201 - .notNull() 202 - .references(() => faction.id), 203 - factionId2: integer('faction_id2') 204 - .notNull() 205 - .references(() => faction.id), 206 - reason: varchar('description', { length: 1024 }).notNull(), 207 - createdAt: timestamp('created_at').defaultNow().notNull(), 208 - }) 209 - 210 - export const campaign = pgTable('campaign', { 211 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 212 - ownerId: text('owner_id') 213 - .notNull() 214 - .references(() => user.id), 215 - name: varchar('name', { length: 255 }).notNull(), 216 - description: varchar('name', { length: 1024 }).notNull(), 217 - createdAt: timestamp('created_at').defaultNow().notNull(), 218 - endedAt: timestamp('ended_at'), 219 - }) 220 - 221 - export const campaignMember = pgTable('campaign_member', { 222 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 223 - campaignId: integer('campaign_id') 224 - .notNull() 225 - .references(() => campaign.id), 226 - memberId: text('member_id') 227 - .notNull() 228 - .references(() => user.id), 229 - inviteAccepted: boolean().default(false).notNull(), 230 - invitedAt: timestamp('invitedAt').defaultNow().notNull(), 231 - }) 232 - 233 - export const campaignSourceMaterial = pgTable('campaign_source_material', { 234 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 235 - campaignId: integer('campaign_id') 236 - .notNull() 237 - .references(() => campaign.id), 238 - sourceBookId: integer('source_book_id') 239 - .notNull() 240 - .references(() => sourceBook.id), 241 - }) 242 - 243 - export const campaignSession = pgTable('campaign_session', { 244 - id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 245 - campaignId: integer('campaign_id') 246 - .notNull() 247 - .references(() => campaign.id, { onDelete: 'cascade' }), 248 - createdAt: timestamp('created_at').defaultNow().notNull(), 249 - endedAt: timestamp('ended_at'), 250 - })
+45
app/src/lib/server/db/schemas/dnd/campaign.ts
··· 1 + import { boolean, integer, pgTable, text, timestamp, varchar } from 'drizzle-orm/pg-core' 2 + import { user } from '../auth' 3 + import { sourceBook } from './sourcebook' 4 + 5 + export const campaign = pgTable('campaign', { 6 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 7 + ownerId: text('owner_id') 8 + .notNull() 9 + .references(() => user.id), 10 + name: varchar('name', { length: 255 }).notNull(), 11 + description: varchar('name', { length: 1024 }).notNull(), 12 + createdAt: timestamp('created_at').defaultNow().notNull(), 13 + endedAt: timestamp('ended_at'), 14 + }) 15 + 16 + export const campaignMember = pgTable('campaign_member', { 17 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 18 + campaignId: integer('campaign_id') 19 + .notNull() 20 + .references(() => campaign.id), 21 + memberId: text('member_id') 22 + .notNull() 23 + .references(() => user.id), 24 + inviteAccepted: boolean().default(false).notNull(), 25 + invitedAt: timestamp('invitedAt').defaultNow().notNull(), 26 + }) 27 + 28 + export const campaignSourceMaterial = pgTable('campaign_source_material', { 29 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 30 + campaignId: integer('campaign_id') 31 + .notNull() 32 + .references(() => campaign.id), 33 + sourceBookId: integer('source_book_id') 34 + .notNull() 35 + .references(() => sourceBook.id), 36 + }) 37 + 38 + export const campaignSession = pgTable('campaign_session', { 39 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 40 + campaignId: integer('campaign_id') 41 + .notNull() 42 + .references(() => campaign.id, { onDelete: 'cascade' }), 43 + createdAt: timestamp('created_at').defaultNow().notNull(), 44 + endedAt: timestamp('ended_at'), 45 + })
+107
app/src/lib/server/db/schemas/dnd/character.ts
··· 1 + import { integer, pgTable, smallint, timestamp, varchar } from 'drizzle-orm/pg-core' 2 + import { user } from '../auth' 3 + import { campaign } from './campaign' 4 + import { language } from './language' 5 + import { condition } from './mechanic' 6 + import { damage } from './mechanic' 7 + import { background, species } from './origin' 8 + 9 + export const character = pgTable( 10 + 'character', 11 + { 12 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 13 + ownerId: varchar('owner_id', { length: 36 }) 14 + .notNull() 15 + .references(() => user.id), 16 + campaignId: integer('campaign_id').references(() => campaign.id), 17 + name: varchar('name', { length: 255 }).notNull(), 18 + backgroundId: integer('background_id') 19 + .notNull() 20 + .references(() => background.id), 21 + speciesId: integer('species_id') 22 + .notNull() 23 + .references(() => species.id), 24 + level: integer('level').notNull(), 25 + pronouns: varchar('pronouns', { length: 255 }), 26 + alignment: smallint('alignment'), 27 + age: varchar('height', { length: 255 }), 28 + hair: varchar('hair', { length: 255 }), 29 + gender: varchar('gender', { length: 255 }), 30 + height: varchar('height', { length: 255 }), 31 + weight: varchar('weight', { length: 255 }), 32 + credits: integer('credits').default(0).notNull(), 33 + createdAt: timestamp('created_at').defaultNow().notNull(), 34 + updatedAt: timestamp('updated_at') 35 + .defaultNow() 36 + .$onUpdate(() => /* @__PURE__ */ new Date()) 37 + .notNull(), 38 + }, 39 + // (table) => [ 40 + // check('character_level', isBetweenIncl(table.level, 1, 20)), 41 + // check('age', isNonNegative(table.age)), 42 + // ], 43 + ) 44 + 45 + export const characterLanguage = pgTable('character_language', { 46 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 47 + characterId: integer('character_id') 48 + .notNull() 49 + .references(() => character.id), 50 + languageId: integer('language_id') 51 + .notNull() 52 + .references(() => language.id), 53 + }) 54 + 55 + /* condition and condition immunities */ 56 + 57 + export const characterCondition = pgTable('character_condition', { 58 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 59 + characterId: integer('character_id') 60 + .notNull() 61 + .references(() => character.id), 62 + conditionId: integer('condition_id') 63 + .notNull() 64 + .references(() => condition.id), 65 + }) 66 + 67 + export const characterConditionImmunity = pgTable('character_condition_immunity', { 68 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 69 + characterId: integer('character_id') 70 + .notNull() 71 + .references(() => character.id), 72 + conditionId: integer('condition_id') 73 + .notNull() 74 + .references(() => condition.id), 75 + }) 76 + 77 + /* damage resistances, vulnerabilities, and immunities */ 78 + 79 + export const characterDmgResistance = pgTable('character_dmg_resistance', { 80 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 81 + characterId: integer('character_id') 82 + .notNull() 83 + .references(() => character.id), 84 + damageId: integer('damage_id') 85 + .notNull() 86 + .references(() => damage.id), 87 + }) 88 + 89 + export const characterDmgVulnerability = pgTable('character_dmg_vulnerability', { 90 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 91 + characterId: integer('character_id') 92 + .notNull() 93 + .references(() => character.id), 94 + damageId: integer('damage_id') 95 + .notNull() 96 + .references(() => damage.id), 97 + }) 98 + 99 + export const characterDmgImmunity = pgTable('character_dmg_immunity', { 100 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 101 + characterId: integer('character_id') 102 + .notNull() 103 + .references(() => character.id), 104 + damageId: integer('damage_id') 105 + .notNull() 106 + .references(() => damage.id), 107 + })
+38
app/src/lib/server/db/schemas/dnd/class.ts
··· 1 + import { integer, pgTable, smallint, timestamp, varchar } from 'drizzle-orm/pg-core' 2 + import { character } from './character' 3 + import { sourceBook } from './sourcebook' 4 + 5 + export const playableClass = pgTable('playable_class', { 6 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 7 + sourceBookId: integer('source_book_id') 8 + .notNull() 9 + .references(() => sourceBook.id, { onDelete: 'cascade' }), 10 + name: varchar('name', { length: 255 }).notNull(), 11 + description: varchar('name', { length: 1024 }).notNull(), 12 + createdAt: timestamp('created_at').defaultNow().notNull(), 13 + }) 14 + 15 + export const characterClass = pgTable( 16 + 'character_class', 17 + { 18 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 19 + characterId: integer('character_id') 20 + .notNull() 21 + .references(() => character.id), 22 + classId: integer('class') 23 + .notNull() 24 + .references(() => playableClass.id), 25 + level: smallint('level').notNull(), 26 + }, 27 + //(table) => [check('class_level', isBetweenIncl(table.level, 1, 20))], 28 + ) 29 + 30 + export const characterClasses = pgTable('character_classes', { 31 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 32 + characterId: integer('character_id') 33 + .notNull() 34 + .references(() => character.id), 35 + classId: integer('class_id') 36 + .notNull() 37 + .references(() => playableClass.id), 38 + })
+17
app/src/lib/server/db/schemas/dnd/equipment.ts
··· 1 + import { boolean, integer, jsonb, pgTable, timestamp, varchar } from 'drizzle-orm/pg-core' 2 + import { sourceBook } from './sourcebook' 3 + 4 + export const equipment = pgTable('equipment', { 5 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 6 + sourceBookId: integer('source_book_id') 7 + .notNull() 8 + .references(() => sourceBook.id), 9 + name: varchar('name', { length: 255 }).notNull(), 10 + description: varchar('description', { length: 1024 }).notNull(), 11 + weight: jsonb('weight').$type<{ value: number; unit: string }>(), 12 + cost: jsonb('cost').$type<{ value: number; unit: string }>(), 13 + isMagicItem: boolean(), 14 + isAttunable: boolean(), 15 + createdAt: timestamp('created_at').defaultNow().notNull(), 16 + updatedAt: timestamp('updated_at').defaultNow().notNull(), 17 + })
+24
app/src/lib/server/db/schemas/dnd/faction.ts
··· 1 + import { integer, pgTable, timestamp, varchar } from 'drizzle-orm/pg-core' 2 + import { sourceBook } from './sourcebook' 3 + 4 + export const faction = pgTable('faction', { 5 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 6 + sourceBookId: integer('source_book_id') 7 + .notNull() 8 + .references(() => sourceBook.id), 9 + name: varchar('name', { length: 255 }).notNull(), 10 + description: varchar('description', { length: 1024 }).notNull(), 11 + }) 12 + 13 + // model for symmetric relationships between factions 14 + export const factionRelationship = pgTable('faction_relationship', { 15 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 16 + factionId1: integer('faction_id1') 17 + .notNull() 18 + .references(() => faction.id), 19 + factionId2: integer('faction_id2') 20 + .notNull() 21 + .references(() => faction.id), 22 + reason: varchar('description', { length: 1024 }).notNull(), 23 + createdAt: timestamp('created_at').defaultNow().notNull(), 24 + })
+10
app/src/lib/server/db/schemas/dnd/language.ts
··· 1 + import { integer, pgTable, varchar } from 'drizzle-orm/pg-core' 2 + import { sourceBook } from './sourcebook' 3 + 4 + export const language = pgTable('language', { 5 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 6 + sourceBookId: integer('sourcebook_id') 7 + .notNull() 8 + .references(() => sourceBook.id), 9 + name: varchar('name', { length: 255 }).notNull(), 10 + })
+19
app/src/lib/server/db/schemas/dnd/mechanic.ts
··· 1 + import { integer, pgTable, varchar } from 'drizzle-orm/pg-core' 2 + import { sourceBook } from './sourcebook' 3 + 4 + export const condition = pgTable('condition', { 5 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 6 + sourceBookId: integer('source_book_id') 7 + .notNull() 8 + .references(() => sourceBook.id), 9 + name: varchar('name', { length: 255 }).notNull(), 10 + }) 11 + 12 + export const damage = pgTable('spell_damage', { 13 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 14 + sourceBookId: integer('source_book_id') 15 + .notNull() 16 + .references(() => sourceBook.id, { onDelete: 'cascade' }), 17 + name: varchar('name', { length: 255 }).unique().notNull(), 18 + description: varchar('name', { length: 255 }).notNull(), 19 + })
+39
app/src/lib/server/db/schemas/dnd/origin.ts
··· 1 + import { boolean, integer, jsonb, pgTable, smallint, timestamp, varchar } from 'drizzle-orm/pg-core' 2 + import { sourceBook } from './sourcebook' 3 + 4 + export const background = pgTable('background', { 5 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 6 + name: varchar('name', { length: 255 }).notNull(), 7 + description: varchar('name', { length: 1024 }).notNull(), 8 + }) 9 + 10 + export const species = pgTable('species', { 11 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 12 + sourceBookId: integer('source_book_id') 13 + .notNull() 14 + .references(() => sourceBook.id, { onDelete: 'cascade' }), 15 + name: varchar('name', { length: 64 }).notNull(), 16 + description: varchar('name', { length: 255 }).notNull(), 17 + creatureType: varchar('creature_name', { length: 32 }).notNull(), 18 + size: smallint('size').notNull(), 19 + walkSpeed: smallint('walk_speed').notNull(), 20 + swimSpeed: smallint('swim_speed').default(0).notNull(), 21 + climbSpeed: smallint('climb_speed').default(0).notNull(), 22 + flySpeed: smallint('fly_speed').default(0).notNull(), 23 + burrowSpeed: smallint('burrow_speed').default(0).notNull(), 24 + createdAt: timestamp('created_at').defaultNow().notNull(), 25 + }) 26 + 27 + export const speciesFeature = pgTable('species_feature', { 28 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 29 + sourceBookId: integer('source_book_id') 30 + .notNull() 31 + .references(() => sourceBook.id, { onDelete: 'cascade' }), 32 + speciesId: integer('species_id') 33 + .notNull() 34 + .references(() => species.id, { onDelete: 'cascade' }), 35 + builtIn: boolean().notNull(), 36 + name: varchar('name', { length: 255 }).notNull(), 37 + description: varchar('name', { length: 255 }).notNull(), 38 + modifiers: jsonb('modifiers').notNull(), 39 + })
+10
app/src/lib/server/db/schemas/dnd/sourcebook.ts
··· 1 + import { boolean, integer, pgTable, timestamp, varchar } from 'drizzle-orm/pg-core' 2 + 3 + export const sourceBook = pgTable('source_book', { 4 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 5 + name: varchar('name', { length: 255 }).unique().notNull(), 6 + description: varchar('name', { length: 255 }).notNull(), 7 + isArchived: boolean('is_archived').default(false).notNull(), 8 + createdAt: timestamp('created_at').defaultNow().notNull(), 9 + archivedAt: timestamp('archived_at'), 10 + })
+29
app/src/lib/server/db/schemas/dnd/spell.ts
··· 1 + import { boolean, integer, jsonb, pgTable, smallint, timestamp, varchar } from 'drizzle-orm/pg-core' 2 + import { damage } from './mechanic' 3 + import { sourceBook } from './sourcebook' 4 + 5 + export const spell = pgTable( 6 + 'spell', 7 + { 8 + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), 9 + sourceBookId: integer('source_book_id') 10 + .notNull() 11 + .references(() => sourceBook.id), 12 + name: varchar('name', { length: 255 }).notNull(), 13 + description: varchar('description', { length: 1024 }).notNull(), 14 + level: smallint('level').notNull(), 15 + school: integer('school').notNull(), 16 + components: integer().notNull(), 17 + materialComponents: varchar('material_components', { length: 255 }), 18 + damage: integer('damage').references(() => damage.id), 19 + duration: jsonb('duration').notNull(), 20 + isRitual: boolean('is_ritual').notNull(), 21 + needsConcentration: boolean('needs_concentration').notNull(), 22 + createdAt: timestamp('created_at').defaultNow().notNull(), 23 + updatedAt: timestamp('updated_at') 24 + .defaultNow() 25 + .$onUpdate(() => /* @__PURE__ */ new Date()) 26 + .notNull(), 27 + }, 28 + // (table) => [check('spell_level', isBetweenIncl(table.level, 0, 9))], 29 + )
+6 -6
app/src/lib/server/db/utils.ts
··· 1 - import type { AnyPgColumn, SelectedFields } from 'drizzle-orm/pg-core' 2 - import { getTableColumns, type SQL, sql, Table } from 'drizzle-orm' 1 + import type { SQL, SQLWrapper } from 'drizzle-orm' 2 + import type { SelectedFields } from 'drizzle-orm/pg-core' 3 + import { getTableColumns, sql, Table } from 'drizzle-orm' 3 4 4 - export function sqlLower(email: AnyPgColumn): SQL<string> { 5 + export function sqlLower(email: SQLWrapper): SQL<string> { 5 6 return sql<string>`lower(${email})` 6 7 } 7 8 ··· 9 10 return sql<boolean>`${bool ? '1' : '0'}` 10 11 } 11 12 12 - export function isBetweenIncl(expr: StringLike, min: number, max: number): SQL<string> { 13 + export function isBetweenIncl(expr: SQLWrapper, min: number, max: number): SQL<string> { 13 14 return sql<string>`${expr} >= ${min} AND ${expr} <= ${max}` 14 15 } 15 16 16 - export function isNonNegative<T extends string>(expr: T): SQL<`${T} >= 0`> { 17 + export function isNonNegative(expr: SQLWrapper): SQL<string> { 17 18 return sql`${expr} >= 0` 18 19 } 19 20 ··· 21 22 return results.at(0) ?? null 22 23 } 23 24 24 - export type StringLike = string | { toString(): string } 25 25 export type WhereExpr = SQL<unknown> | ((aliases: SelectedFields) => SQL | undefined) | undefined 26 26 export type TableColumns<T extends Table> = T['_']['columns'] 27 27 export type TableColumnNames<T extends Table> = keyof TableColumns<T>
+8 -8
pnpm-lock.yaml
··· 84 84 specifier: ^10.3.1 85 85 version: 10.3.1 86 86 '@storybook/addon-svelte-csf': 87 - specifier: ^5.0.12 88 - version: 5.0.12 87 + specifier: ^5.1.0 88 + version: 5.1.0 89 89 '@storybook/addon-themes': 90 90 specifier: ^10.3.1 91 91 version: 10.3.1 ··· 213 213 version: 10.3.1(@types/react@19.2.14)(esbuild@0.27.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) 214 214 '@storybook/addon-svelte-csf': 215 215 specifier: catalog:storybook 216 - version: 5.0.12(@storybook/svelte@10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0))(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)))(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) 216 + version: 5.1.0(@storybook/svelte@10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0))(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)))(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) 217 217 '@storybook/addon-themes': 218 218 specifier: catalog:storybook 219 219 version: 10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) ··· 2298 2298 peerDependencies: 2299 2299 storybook: ^10.3.1 2300 2300 2301 - '@storybook/addon-svelte-csf@5.0.12': 2302 - resolution: {integrity: sha512-bT7Xaxk9hQ8ZGNVtUN9IVe5ZqJAbO5iSE0TBdMsIPmY6qSG0WTm3H7HqUsb/+EdHOjykmTf2Tbs3eJt8jkpwVg==} 2301 + '@storybook/addon-svelte-csf@5.1.0': 2302 + resolution: {integrity: sha512-Y3xtcLhTgNKnYSqyutjvGZu+UmvAZS/1TVA9s75snIpN/pOlrScBwNYDtbCkYxyxvrwNQLAkQV4qovLUtytjag==} 2303 2303 peerDependencies: 2304 2304 '@storybook/svelte': ^0.0.0-0 || ^8.2.0 || ^9.0.0 || ^9.1.0-0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 2305 - '@sveltejs/vite-plugin-svelte': ^4.0.0 || ^5.0.0 || ^6.0.0 2305 + '@sveltejs/vite-plugin-svelte': ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 2306 2306 storybook: ^0.0.0-0 || ^8.2.0 || ^9.0.0 || ^9.1.0-0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 2307 2307 svelte: ^5.0.0 2308 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 2308 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 2309 2309 2310 2310 '@storybook/addon-themes@10.3.1': 2311 2311 resolution: {integrity: sha512-Y4ZCof3C+nsXvfhDmUvxt1klnZ6SPh1tLuDWo4eE8MUG1jQ2tixiIQX6Ups8fqfYCN8RgjcDDHnIyNZRZlgB2Q==} ··· 6251 6251 - vite 6252 6252 - webpack 6253 6253 6254 - '@storybook/addon-svelte-csf@5.0.12(@storybook/svelte@10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0))(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)))(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': 6254 + '@storybook/addon-svelte-csf@5.1.0(@storybook/svelte@10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0))(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)))(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': 6255 6255 dependencies: 6256 6256 '@storybook/csf': 0.1.13 6257 6257 '@storybook/svelte': 10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(svelte@5.54.0)
+1 -1
pnpm-workspace.yaml
··· 37 37 storybook: 38 38 '@storybook/addon-a11y': ^10.3.1 39 39 '@storybook/addon-docs': ^10.3.1 40 - '@storybook/addon-svelte-csf': ^5.0.12 40 + '@storybook/addon-svelte-csf': ^5.1.0 41 41 '@storybook/addon-themes': ^10.3.1 42 42 '@storybook/addon-vitest': ^10.3.1 43 43 '@storybook/svelte': ^10.3.1