Scaffold and Phase 1

This commit is contained in:
2026-05-02 19:46:42 -05:00
parent ab74e7cad4
commit d909cb7c30
92 changed files with 4967 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
{
"name": "@storybid/shared",
"version": "0.0.1",
"private": true,
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"dev": "tsc --watch"
},
"devDependencies": {
"typescript": "*"
}
}
+8
View File
@@ -0,0 +1,8 @@
export * from "./types/auction.js";
export * from "./types/bidder.js";
export * from "./types/bid.js";
export * from "./types/event.js";
export * from "./types/organization.js";
export * from "./types/payment.js";
export * from "./types/socket-events.js";
export * from "./types/roles.js";
+72
View File
@@ -0,0 +1,72 @@
export type AuctionType = "live" | "silent";
export type AuctionStatus = "draft" | "active" | "paused" | "closed";
export interface Auction {
id: string;
eventId: string;
type: AuctionType;
name: string;
status: AuctionStatus;
sortOrder: number;
createdAt: string;
updatedAt: string;
}
// ── Auction Item ──────────────────────────────────────────────────────────────
export type ItemState =
| "preview"
| "active"
| "going_once"
| "going_twice"
| "sold"
| "passed"
| "closed"; // silent auction final state
export interface AuctionItem {
id: string;
auctionId: string;
lotNumber: string;
title: string;
description: string | null;
donorName: string | null;
category: string | null;
fairMarketValue: number | null;
openingBid: number;
reservePrice: number | null;
currentHighBid: number | null;
currentHighBidderId: string | null;
bidIncrement: number;
state: ItemState;
pickupNotes: string | null;
sortOrder: number;
// Silent-auction specific
silentWindowId: string | null;
softCloseEnabled: boolean;
softCloseExtendMinutes: number;
createdAt: string;
updatedAt: string;
}
export interface ItemMedia {
id: string;
itemId: string;
mediaType: "image" | "video" | "document" | "embed";
url: string;
thumbnailUrl: string | null;
caption: string | null;
sortOrder: number;
createdAt: string;
}
export interface SilentAuctionWindow {
id: string;
auctionId: string;
name: string;
opensAt: string;
closesAt: string;
softCloseEnabled: boolean;
softCloseExtendMinutes: number;
status: "pending" | "open" | "closed";
}
+38
View File
@@ -0,0 +1,38 @@
export type OriginMode =
| "public" // bid arrived via public FQDN
| "local_dns" // bid arrived via event-LAN hostname
| "local_ip" // bid arrived via raw local IP
| "offline_queue"; // bid was queued client-side and synced later
export type SyncStatus = "synced" | "pending" | "conflict" | "rejected";
export interface Bid {
id: string;
itemId: string;
bidderId: string;
amount: number;
/** ISO-8601 timestamp from the client clock at intent time */
clientCreatedAt: string;
/** ISO-8601 timestamp when the server accepted the bid */
serverReceivedAt: string;
originMode: OriginMode;
syncStatus: SyncStatus;
deviceId: string;
/** Client-side monotonic sequence within the device session */
clientSeq: number;
isWinning: boolean;
createdAt: string;
}
// Outbox entry stored in IndexedDB before network sync
export interface OutboxBid {
localId: string; // UUID generated client-side
itemId: string;
bidderId: string;
amount: number;
clientCreatedAt: string;
deviceId: string;
clientSeq: number;
attempts: number;
lastAttemptAt: string | null;
}
+24
View File
@@ -0,0 +1,24 @@
export interface Bidder {
id: string;
organizationId: string;
email: string | null;
phone: string | null;
firstName: string;
lastName: string;
paddleNumber: string | null;
tableAssignment: string | null;
notes: string | null;
paymentMethodOnFile: boolean;
checkInStatus: "pending" | "checked_in";
createdAt: string;
updatedAt: string;
}
export interface BidderAuthMethod {
id: string;
bidderId: string;
type: "email_magic_link" | "sms_otp";
identifier: string; // email address or E.164 phone number
verifiedAt: string | null;
createdAt: string;
}
+17
View File
@@ -0,0 +1,17 @@
export type EventStatus = "draft" | "published" | "active" | "closed" | "archived";
export interface AuctionEvent {
id: string;
organizationId: string;
name: string;
slug: string;
description: string | null;
venueAddress: string | null;
startAt: string;
endAt: string;
status: EventStatus;
timezone: string;
bannerImageUrl: string | null;
createdAt: string;
updatedAt: string;
}
+12
View File
@@ -0,0 +1,12 @@
export interface Organization {
id: string;
name: string;
slug: string;
logoUrl: string | null;
primaryColor: string | null;
stripeAccountId: string | null;
publicUrl: string | null;
localHostname: string | null;
createdAt: string;
updatedAt: string;
}
+51
View File
@@ -0,0 +1,51 @@
export type InvoiceStatus =
| "draft"
| "open"
| "paid"
| "partially_paid"
| "void";
export interface Invoice {
id: string;
bidderId: string;
eventId: string;
stripeInvoiceId: string | null;
totalAmount: number;
paidAmount: number;
status: InvoiceStatus;
createdAt: string;
updatedAt: string;
}
export interface Payment {
id: string;
invoiceId: string;
stripePaymentIntentId: string | null;
amount: number;
currency: string;
status: "pending" | "succeeded" | "failed" | "refunded";
createdAt: string;
}
export interface PaddleRaiseCampaign {
id: string;
eventId: string;
name: string;
goal: number | null;
totalRaised: number;
tiers: number[]; // suggested donation amounts
isActive: boolean;
createdAt: string;
updatedAt: string;
}
export interface Donation {
id: string;
eventId: string;
bidderId: string | null;
campaignId: string | null;
amount: number;
anonymous: boolean;
stripePaymentIntentId: string | null;
createdAt: string;
}
+15
View File
@@ -0,0 +1,15 @@
export type UserRole =
| "admin"
| "event_manager"
| "auctioneer"
| "spotter"
| "checkin_staff"
| "bidder";
export const STAFF_ROLES: UserRole[] = [
"admin",
"event_manager",
"auctioneer",
"spotter",
"checkin_staff",
];
@@ -0,0 +1,68 @@
import type { ItemState, AuctionItem } from "./auction.js";
import type { Bid } from "./bid.js";
// ── Events emitted by the SERVER ──────────────────────────────────────────────
export interface ServerToClientEvents {
// Live auction
item_activated: (payload: { item: AuctionItem }) => void;
next_live_bid: (payload: { itemId: string; amount: number }) => void;
live_bid_accepted: (payload: { bid: Bid; item: AuctionItem }) => void;
item_state_changed: (payload: { itemId: string; state: ItemState }) => void;
item_sold: (payload: { itemId: string; winnerId: string; amount: number }) => void;
// Silent auction
silent_bid_accepted: (payload: { bid: Bid; item: AuctionItem }) => void;
silent_outbid: (payload: { itemId: string; yourBidderId: string; newAmount: number }) => void;
silent_window_closing: (payload: { windowId: string; closesAt: string }) => void;
silent_window_extended: (payload: { windowId: string; newClosesAt: string }) => void;
silent_item_closed: (payload: { itemId: string; winnerId: string | null; finalAmount: number | null }) => void;
// Paddle raise
paddle_raise_update: (payload: { campaignId: string; totalRaised: number }) => void;
// Connectivity / sync
sync_status_changed: (payload: { status: "connected" | "local" | "offline" }) => void;
bid_sync_result: (payload: { localId: string; accepted: boolean; bid?: Bid; error?: string }) => void;
}
// ── Events emitted by the CLIENT ──────────────────────────────────────────────
export interface ClientToServerEvents {
// Bidder joins/leaves a room scoped to an event
join_event: (eventId: string) => void;
leave_event: (eventId: string) => void;
// Live bid (amount is the auctioneer-called amount shown in UI)
place_live_bid: (payload: { itemId: string; amount: number; deviceId: string; clientSeq: number; clientCreatedAt: string }) => void;
// Silent bid
place_silent_bid: (payload: { itemId: string; amount: number; deviceId: string; clientSeq: number; clientCreatedAt: string }) => void;
// Sync queued outbox bids after reconnect
sync_outbox: (bids: Array<{ localId: string; itemId: string; amount: number; deviceId: string; clientSeq: number; clientCreatedAt: string }>) => void;
// Auctioneer controls
auctioneer_activate_item: (itemId: string) => void;
auctioneer_call_next_bid: (payload: { itemId: string; amount: number }) => void;
auctioneer_accept_bid: (payload: { itemId: string; bidderId: string; amount: number }) => void;
auctioneer_going_once: (itemId: string) => void;
auctioneer_going_twice: (itemId: string) => void;
auctioneer_sold: (itemId: string) => void;
auctioneer_pass: (itemId: string) => void;
}
// ── Shared inter-server events (for Redis adapter) ───────────────────────────
export interface InterServerEvents {
ping: () => void;
}
// ── Per-socket data ───────────────────────────────────────────────────────────
export interface SocketData {
bidderId?: string;
staffId?: string;
role?: string;
deviceId?: string;
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"]
}