feat: scaffold workspace with search, fetch, and extract packages

This commit is contained in:
2026-08-08 10:43:00 +08:00
parent 405602a943
commit 1de559c321
30 changed files with 1381 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
{
"name": "@tts/shared",
"version": "0.0.0",
"private": true,
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"lint": "echo \"no lint configured\""
},
"dependencies": {
"zod": "^3.24.1"
},
"devDependencies": {
"typescript": "^5.7.2"
}
}
+2
View File
@@ -0,0 +1,2 @@
export * from './types.js';
export * from './schemas.js';
+54
View File
@@ -0,0 +1,54 @@
import { z } from 'zod';
/** Validate a Workshop item ID (a non-empty run of digits). */
export const itemIdSchema = z
.string()
.regex(/^\d+$/, 'Item ID must be a number')
.min(1);
/** Query params for `GET /search`. */
export const searchQuerySchema = z.object({
q: z.string().trim().min(1, 'Search query is required'),
page: z.coerce.number().int().min(1).default(1),
});
export const assetKindSchema = z.enum([
'pdf',
'deckFace',
'deckBack',
'image',
'imageSecondary',
]);
export const assetRefSchema = z.object({
kind: assetKindSchema,
url: z.string().url(),
ownerGuid: z.string(),
});
export const extractedObjectSchema = z.object({
guid: z.string(),
name: z.string(),
type: z.string(),
parentGuid: z.string().optional(),
childrenGuids: z.array(z.string()),
refs: z.array(assetRefSchema),
});
export const workshopItemSchema = z.object({
id: z.string(),
title: z.string(),
author: z.string(),
previewImageUrl: z.string(),
fileUrl: z.string().optional(),
description: z.string().optional(),
tags: z.array(z.string()).optional(),
timeCreated: z.number().optional(),
timeUpdated: z.number().optional(),
});
export const searchResultSchema = z.object({
items: z.array(workshopItemSchema),
page: z.number(),
hasMore: z.boolean(),
});
+84
View File
@@ -0,0 +1,84 @@
/**
* A single object inside a Tabletop Simulator save file.
* Mirrors the structure produced by BSON-deserializing a TTS save.
*/
export interface TTSObject {
Name: string;
GUID: string;
Description: string;
/** Set by `markParent` during traversal; not present in the raw save. */
Parent?: TTSObject;
CustomPDF?: {
PDFUrl: string;
};
ContainedObjects?: TTSObject[];
CardID?: number;
CustomDeck?: {
[key: number]: {
BackURL: string;
FaceURL: string;
UniqueBack: boolean;
NumHeight: number;
NumWidth: number;
};
};
CustomImage?: {
ImageURL: string;
ImageSecondaryURL: string;
};
}
/** A full Tabletop Simulator save file. */
export interface TTSMod {
GameMode: string;
Date: string;
ObjectStates: TTSObject[];
}
/** Metadata for a Workshop item, from the Steam Web API. */
export interface WorkshopItem {
id: string;
title: string;
author: string;
previewImageUrl: string;
fileUrl?: string;
description?: string;
tags?: string[];
timeCreated?: number;
timeUpdated?: number;
}
/** A page of Workshop search results. */
export interface SearchResult {
items: WorkshopItem[];
page: number;
hasMore: boolean;
}
/** A reference to an external asset embedded in a TTS object. */
export type AssetKind =
| 'pdf'
| 'deckFace'
| 'deckBack'
| 'image'
| 'imageSecondary';
export interface AssetRef {
kind: AssetKind;
url: string;
/** GUID of the object that owns this reference. */
ownerGuid: string;
}
/** A flattened, lightweight view of an object for inspection/rendering. */
export interface ExtractedObject {
guid: string;
name: string;
type: string;
parentGuid?: string;
childrenGuids: string[];
refs: AssetRef[];
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"]
}