Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion config/partners.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
# Desk URL env (book-level): DESK_DOMAIN — must resolve via active SKINS[].hosts
# (bare book-level DOMAIN env is retired). Prefer TOML url= on each out when known.
# Capacity rows: live_products = [ { name, per_bet_max, max_win, active } ]
# (legacy key `skins` still dual-read on parse)
# @see https://bun.com/docs/runtime/toml
# @see docs/SEAT-OPS.md

Expand Down
7 changes: 3 additions & 4 deletions docs/PARTNER-FANTASY-ULTRA.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ Partner → Communication → Accounts/Outs → Assets → Finance.
| **Partner** | `partners` | Financial owner (profit split, commission) |
| **Account (out)** | `betting_accounts` | Place to bet: provider + limits + `env_prefix` for secrets |
| **Skin** (white-label) | `src/domain/skins.ts` | `buckeye`, `ace`, `metallic`, `sts`, `1bv`, `lvaction`, `magnum` |
| **Live product** | `src/domain/live-products.ts` + capacity `meta.skins[]` | `plive` / `ezlive` / `ultralive` / `maglive` (`dark` capacity-only) |
| **Live product** | `src/domain/live-products.ts` + capacity `meta.liveProducts[]` | `plive` / `ezlive` / `ultralive` / `maglive` (`dark` capacity-only) |
| **Adapter surface** | `AdapterId` (`fantasy402`, `kalshi`) | DTO token on inventory/book rows — **not** seat `partnerId`; distinct from mapper `AdapterId` (`fantasy-ultra` …) |
| **Provider** (legacy env) | env / outs column mirror | Still on outs / env; `fantasy402` is BookId + mapper token → skin `buckeye` |
| **Sports map** | `src/domain/` + `provider_sport_mappings` seed | Live-product keys primary; optional legacy `fantasy402` dual-write |
Expand Down Expand Up @@ -488,14 +488,13 @@ On `seedFantasy402FromEnv` / `upsertBettingAccount` (`partner/out-identity.ts`):

1. Resolve host via `getSkinByHost(url)` → white-label `skinId` (unknown host →
reject; add to `SKINS[].hosts`)
2. Parse capacity from `meta.liveProducts` (dual-**read** legacy `meta.skins`
only when `liveProducts` is absent)
2. Parse capacity from `meta.liveProducts` only (legacy `meta.skins` ignored)
3. Assert capacity ⊆ skin `offeredLiveProducts` (plus legacy `dark` / numeric
Ultra wire)
4. Derive `AdapterBinding`: `adapterId` (`fantasy-ultra` | `kalshi` |
`unmapped`) + `mapperKind` + `bookEnvToken`
5. Stamp `skinId`, `mapper`, `liveProducts`, `defaultLiveProduct` only —
writers **drop** legacy `meta.skins` / `defaultSkin` (no dual-write)
writers **drop** any legacy `meta.skins` / `defaultSkin`
6. `getPartnerAdapter` selects Fantasy Ultra when
`adapterId === "fantasy-ultra"`

Expand Down
2 changes: 1 addition & 1 deletion docs/SEAT-OPS.md
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ url = "https://fantasy402.com"
# book_id = "fantasy402"
working_balance = 20000
vault_id = "vault-out-SPEN-3"
skins = [
live_products = [
{ name = "ezlive", per_bet_max = 500, max_win = 2500, active = true },
]
```
Expand Down
5 changes: 2 additions & 3 deletions src/domain/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,12 @@ Host is the gateway on account seed/upsert via **OutIdentity**

1. `getSkinByHost(url)` → `SkinId` (unknown host → reject)
2. `getBookByHost(url)` → desk `BookId` (optional stamp)
3. Parse capacity from `meta.liveProducts` (dual-**read** legacy `meta.skins`
only when `liveProducts` is absent)
3. Parse capacity from `meta.liveProducts` only (legacy `meta.skins` ignored)
4. Assert capacity ⊆ `offeredLiveProducts` (+ `dark` / numeric Ultra wire)
5. Derive `AdapterBinding` (`adapterId`: `fantasy-ultra` | `kalshi` |
`unmapped`)
6. Stamp `skinId`, `bookId`, `mapper`, `liveProducts`, `defaultLiveProduct`
only — writers **drop** legacy `meta.skins` / `defaultSkin` (no dual-write)
only — writers **drop** any legacy `meta.skins` / `defaultSkin`
7. `getPartnerAdapter` switches on `adapterId === "fantasy-ultra"` (not partner
string)

Expand Down
3 changes: 0 additions & 3 deletions src/domain/books.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,6 @@ export function bookOffersLiveProduct(bookId: BookId | string, product: string):
return skinOffersLiveProduct(skinId, product);
}

/** @deprecated use bookOffersLiveProduct */
export const bookOffersSkin = bookOffersLiveProduct;

export type BookMatrixRow = {
bookId: BookId;
skinId: SkinId;
Expand Down
7 changes: 0 additions & 7 deletions src/domain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,21 +119,15 @@ export {
export {
BINDING_STATUSES,
LIVE_PRODUCT_SPORT_BINDINGS,
SKIN_SPORT_BINDINGS,
listLiveProductSportBindings,
listSkinSportBindings,
liveProductHasSportCoverage,
liveProductsWithBindings,
skinHasSportCoverage,
skinsWithBindings,
type BindingStatus,
type LiveProductSportBinding,
type SkinSportBinding,
} from './live-product-sport-bindings.ts';

export {
DEFAULT_COVERAGE_LIVE_PRODUCT,
DEFAULT_COVERAGE_SKIN,
WIDGET_FAVORITES_SPORT_ID,
resolveSport,
type ResolveSportQuery,
Expand Down Expand Up @@ -188,7 +182,6 @@ export {
BOOK_IDS,
HOST_TO_BOOK,
bookOffersLiveProduct,
bookOffersSkin,
buildBookMatrixRows,
formatBooksMatrixText,
getBook,
Expand Down
23 changes: 0 additions & 23 deletions src/domain/live-product-sport-bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ export type LiveProductSportBinding = {
status: BindingStatus;
};

/** @deprecated alias — use LiveProductSportBinding */
export type SkinSportBinding = LiveProductSportBinding;

type BindingSeed = {
sportId: SportId;
inventoryBucket: string;
Expand Down Expand Up @@ -161,9 +158,6 @@ export const LIVE_PRODUCT_SPORT_BINDINGS: readonly LiveProductSportBinding[] = [
...EZLIVE,
];

/** @deprecated use LIVE_PRODUCT_SPORT_BINDINGS */
export const SKIN_SPORT_BINDINGS = LIVE_PRODUCT_SPORT_BINDINGS;

const byProduct = new Map<LiveProductId, LiveProductSportBinding[]>([
['plive', PLIVE],
['ezlive', EZLIVE],
Expand All @@ -178,32 +172,15 @@ export function listLiveProductSportBindings(
return LIVE_PRODUCT_SPORT_BINDINGS;
}

/** @deprecated use listLiveProductSportBindings */
export function listSkinSportBindings(
liveProduct?: LiveProductId
): readonly LiveProductSportBinding[] {
return listLiveProductSportBindings(liveProduct);
}

export function liveProductHasSportCoverage(liveProduct: LiveProductId, sportId: SportId): boolean {
const rows = byProduct.get(liveProduct) ?? [];
return rows.some(
r => r.sportId === sportId && r.status !== 'unsupported' && r.status !== 'unknown'
);
}

/** @deprecated use liveProductHasSportCoverage */
export function skinHasSportCoverage(liveProduct: LiveProductId, sportId: SportId): boolean {
return liveProductHasSportCoverage(liveProduct, sportId);
}

export function liveProductsWithBindings(): LiveProductId[] {
return (['plive', 'ezlive', 'ultralive', 'maglive'] as const).filter(
p => (byProduct.get(p)?.length ?? 0) > 0
);
}

/** @deprecated use liveProductsWithBindings */
export function skinsWithBindings(): LiveProductId[] {
return liveProductsWithBindings();
}
7 changes: 1 addition & 6 deletions src/domain/resolve-sport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ export const WIDGET_FAVORITES_SPORT_ID = 214;
export type ResolveSportQuery = {
/** Live product that owns the binding (plive / ezlive / …). */
liveProduct: string;
/** @deprecated use liveProduct */
skin?: string;
inventoryBucket?: string;
apiSportId?: number;
widgetSportId?: number;
Expand All @@ -35,7 +33,7 @@ function asLiveProduct(raw: string): LiveProductId | undefined {
}

export function resolveSport(query: ResolveSportQuery): ResolvedSport | undefined {
const liveProduct = asLiveProduct(query.liveProduct ?? query.skin ?? '');
const liveProduct = asLiveProduct(query.liveProduct);
if (!liveProduct) return undefined;

const rows = listLiveProductSportBindings(liveProduct);
Expand Down Expand Up @@ -71,6 +69,3 @@ export function resolveSport(query: ResolveSportQuery): ResolvedSport | undefine

/** Default live product for Fantasy402/Buckeye compatibility lookups. */
export const DEFAULT_COVERAGE_LIVE_PRODUCT: LiveProductId = 'plive';

/** @deprecated use DEFAULT_COVERAGE_LIVE_PRODUCT */
export const DEFAULT_COVERAGE_SKIN = DEFAULT_COVERAGE_LIVE_PRODUCT;
10 changes: 5 additions & 5 deletions src/partner/finance-cron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export type FinanceCronOutRow = {
partnerCode: string;
provider: string;
totalPerBetMax: number;
skinCount: number;
productCount: number;
liveProducts: Array<{ name: string; perBetMax: number }>;
workingBalance: number | null;
envPrefix: string;
Expand Down Expand Up @@ -298,11 +298,11 @@ export function formatFinanceCronReportText(report: FinanceCronReport): string {
const v = getPartnerVisual(g.partnerCode);
lines.push(` ${g.partnerCode} ${v.hex} capacity=$${g.totalCapacity} outs=${g.outs.length}`);
for (const o of g.outs) {
const skinBits = o.liveProducts.map(s => `$${s.perBetMax} ${s.name}`).join(' + ');
const productBits = o.liveProducts.map(s => `$${s.perBetMax} ${s.name}`).join(' + ');
const envMark = o.envOk ? 'env✓' : `env✗ ${o.missingKeys.join(',')}`;
const login = o.loginOk === true ? ' login✓' : o.loginOk === false ? ` login✗` : '';
lines.push(
` └── ${o.outId} $${o.totalPerBetMax}${skinBits ? ` (${skinBits})` : ''} ${envMark}${login}`
` └── ${o.outId} $${o.totalPerBetMax}${productBits ? ` (${productBits})` : ''} ${envMark}${login}`
);
}
}
Expand Down Expand Up @@ -371,7 +371,7 @@ export async function runFinanceCron(
partnerCode,
provider: a.provider,
totalPerBetMax: cap.totalPerBetMax,
skinCount: cap.liveProducts.length,
productCount: cap.liveProducts.length,
liveProducts: cap.liveProducts.map(s => ({
name: s.name,
perBetMax: s.perBetMax,
Expand Down Expand Up @@ -444,7 +444,7 @@ export async function runFinanceCron(
totalPerBetMax: r.totalPerBetMax,
workingBalance: r.workingBalance,
envOk: r.envOk,
skinCount: r.skinCount,
productCount: r.productCount,
extra: {
missingKeys: r.missingKeys,
loginOk: r.loginOk,
Expand Down
7 changes: 0 additions & 7 deletions src/partner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ export {
BOOKS,
BOOK_IDS,
DEFAULT_COVERAGE_LIVE_PRODUCT,
DEFAULT_COVERAGE_SKIN,
HOST_TO_BOOK,
HOST_TO_SKIN,
LEGACY_CAPACITY_LIVE_PRODUCTS,
Expand All @@ -200,12 +199,10 @@ export {
RETIRED_BARE_BOOK_DOMAIN_ENVS,
deskDomainFromEnvMap,
SKIN_IDS,
SKIN_SPORT_BINDINGS,
SKINS,
SPORTS,
SPORT_CATEGORIES,
bookOffersLiveProduct,
bookOffersSkin,
buildBookMatrixRows,
formatBooksMatrixText,
getBook,
Expand All @@ -226,7 +223,6 @@ export {
listBooksForSkin,
listLiveProductSportBindings,
listLiveProducts,
listSkinSportBindings,
listSkins,
listSports,
liveProductHasSportCoverage,
Expand All @@ -237,11 +233,9 @@ export {
resolveBookId,
resolveSkinId,
resolveSport,
skinHasSportCoverage,
skinIdForBook,
skinOfferedCatalogNames,
skinOffersLiveProduct,
skinsWithBindings,
type BindingStatus,
type BookId,
type BookMatrixRow,
Expand All @@ -255,7 +249,6 @@ export {
type SkinId,
type SkinMapper,
type SkinRecord,
type SkinSportBinding,
type SportCategory,
type SportId,
type SportRecord,
Expand Down
5 changes: 3 additions & 2 deletions src/partner/ledger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ export function writeDeskSnapshot(
totalPerBetMax: number;
workingBalance: number | null;
envOk: boolean;
skinCount: number;
/** Active live-product capacity row count. */
productCount: number;
currency?: string;
extra?: Record<string, unknown>;
nowMs?: number;
Expand Down Expand Up @@ -161,7 +162,7 @@ export function writeDeskSnapshot(
totalPerBetMax: input.totalPerBetMax,
workingBalance: input.workingBalance,
envOk: input.envOk,
skinCount: input.skinCount,
productCount: input.productCount,
...(input.extra ?? {}),
}),
createdAt: nowMs,
Expand Down
24 changes: 7 additions & 17 deletions src/partner/out-capacity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,10 @@ export type OutMeta = {
partnerCode?: string;
/** Shared account balance across live products (out-level). */
workingBalance?: number;
/** @deprecated use defaultLiveProduct */
defaultSkin?: CapacityWireName;
/** Default live-product / Ultra wire for this out. */
defaultLiveProduct?: CapacityWireName;
/** Canonical capacity rows (live products). */
liveProducts?: MetaCapacityRow[];
/**
* Legacy capacity rows (name = live product wire).
* Read-only dual path — writers stamp `liveProducts` only.
*/
skins?: MetaCapacityRow[];
/**
* White-label SkinId (buckeye / ace / …) — host gateway identity.
* Distinct from capacity live-product names.
Expand Down Expand Up @@ -168,8 +161,9 @@ export function parseOutMeta(metaJson: string | null | undefined): OutMeta {

/**
* Resolve active live-product capacity for an account.
* Prefer meta.liveProducts[]; dual-read legacy meta.skins[]; else column fallback.
* Reads meta.liveProducts[] only; falls back to maxStake/maxWin + defaultLiveProduct (or "2").
* (Kept here to avoid import cycle with out-identity — same rules as parseCapacityFromMeta.)
* `skin` column on betting_accounts is ignored (always null on write).
*/
export function resolveOutCapacity(input: {
id: string;
Expand All @@ -182,8 +176,7 @@ export function resolveOutCapacity(input: {
if (input.status && input.status !== 'active') return [];

const meta = parseOutMeta(input.metaJson);
const source =
meta.liveProducts && meta.liveProducts.length > 0 ? meta.liveProducts : (meta.skins ?? []);
const source = meta.liveProducts ?? [];

const fromMeta = source
.map((row): OutCapacityRow | null => {
Expand All @@ -201,10 +194,7 @@ export function resolveOutCapacity(input: {
return fromMeta.filter(s => s.active);
}

const defaultName =
meta.defaultLiveProduct?.trim() ||
meta.defaultSkin?.trim() ||
(input.skin != null && Number.isFinite(input.skin) ? String(input.skin) : '2');
const defaultName = meta.defaultLiveProduct?.trim() || '2';
return [
{
name: defaultName,
Expand Down Expand Up @@ -325,7 +315,7 @@ export function concentrationByOut(
.sort((a, b) => b.share - a.share || a.outId.localeCompare(b.outId));
}

/** Build meta_json capacity (writes liveProducts only; readers dual-read legacy skins). */
/** Build meta_json capacity (writes liveProducts only; strips legacy skins keys). */
export function buildOutCapacityMeta(input: {
liveProducts: OutCapacityRow[];
workingBalance?: number;
Expand Down Expand Up @@ -356,8 +346,8 @@ export function buildOutCapacityMeta(input: {
liveProducts: rows,
};
// Never re-emit legacy capacity keys when building fresh meta
delete meta.skins;
delete meta.defaultSkin;
delete (meta as Record<string, unknown>).skins;
delete (meta as Record<string, unknown>).defaultSkin;
if (input.workingBalance != null) meta.workingBalance = input.workingBalance;
if (input.vaultId) meta.vaultId = input.vaultId;
if (input.partnerCode) meta.partnerCode = input.partnerCode;
Expand Down
Loading