feat: modules and resources domains, drop removed domains, regenerated models
This commit is contained in:
@@ -1,54 +0,0 @@
|
||||
import type { RemoteConfig } from '../generated/remote-config.js';
|
||||
import { SyncedState } from './SyncedState.js';
|
||||
|
||||
export type RemoteConfigShape = Record<string, unknown>;
|
||||
type RemoteConfigKey<TConfig extends RemoteConfigShape> = Extract<keyof TConfig, string>;
|
||||
|
||||
/**
|
||||
* RemoteConfigState — typed remote configuration as an observable entity.
|
||||
*
|
||||
* `get()` parses values synchronously from the loaded snapshot based on their
|
||||
* declared `valueType` and returns the default value while not loaded.
|
||||
*/
|
||||
export class RemoteConfigState<
|
||||
TConfig extends RemoteConfigShape = RemoteConfigShape,
|
||||
> extends SyncedState<Map<string, RemoteConfig>> {
|
||||
get<TKey extends RemoteConfigKey<TConfig>>(key: TKey): TConfig[TKey] | undefined;
|
||||
get<TKey extends RemoteConfigKey<TConfig>>(key: TKey, defaultValue: TConfig[TKey]): TConfig[TKey];
|
||||
get<TKey extends RemoteConfigKey<TConfig>>(
|
||||
key: TKey,
|
||||
defaultValue?: TConfig[TKey],
|
||||
): TConfig[TKey] | undefined {
|
||||
const config = this.data?.get(key);
|
||||
if (!config || config.value == null) return defaultValue;
|
||||
return parseValue(config.value, config.valueType, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
function parseValue<T>(
|
||||
value: string,
|
||||
valueType: string | undefined,
|
||||
defaultValue: T | undefined,
|
||||
): T | undefined {
|
||||
try {
|
||||
switch ((valueType ?? '').toLowerCase()) {
|
||||
case 'int':
|
||||
case 'integer':
|
||||
return Number.parseInt(value, 10) as unknown as T;
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'number':
|
||||
return Number.parseFloat(value) as unknown as T;
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
return (value === 'true') as unknown as T;
|
||||
case 'json':
|
||||
case 'object':
|
||||
return JSON.parse(value) as T;
|
||||
default:
|
||||
return value as unknown as T;
|
||||
}
|
||||
} catch {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import type { CatalogItem } from '../generated/catalog.js';
|
||||
import type { PlayerInventoryItem } from '../generated/inventory.js';
|
||||
|
||||
/** A fully-resolved owned item: player inventory row merged with its catalog entry. */
|
||||
export interface InventoryItem {
|
||||
slug: string;
|
||||
amount: number;
|
||||
name: string;
|
||||
properties: Record<string, unknown>;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
/** @internal Merges owned inventory rows with their catalog entries. */
|
||||
export function mergeInventory(
|
||||
owned: PlayerInventoryItem[],
|
||||
catalog: Map<string, CatalogItem>,
|
||||
): InventoryItem[] {
|
||||
return owned.map((item) => {
|
||||
const slug = item.slug ?? '';
|
||||
const entry = catalog.get(slug);
|
||||
return {
|
||||
slug,
|
||||
amount: item.amount ?? 0,
|
||||
name: item.nameOverride || entry?.name || slug,
|
||||
properties: { ...(entry?.properties ?? {}), ...(item.propertiesOverride ?? {}) },
|
||||
tags: entry?.tags ?? [],
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import type {
|
||||
Offer,
|
||||
OfferContent,
|
||||
OfferPrice,
|
||||
Store,
|
||||
PurchaseOfferResponse,
|
||||
} from '../generated/stores.js';
|
||||
|
||||
export interface BuyOptions {
|
||||
idempotencyKey?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire-level purchase executor provided by the stores domain
|
||||
* (`StoresDomain.purchase`).
|
||||
*/
|
||||
export type PurchaseOffer = (
|
||||
storeSlug: string,
|
||||
offerSlug: string,
|
||||
options?: BuyOptions,
|
||||
) => Promise<PurchaseOfferResponse>;
|
||||
|
||||
export class OfferHandle {
|
||||
public readonly id: string;
|
||||
public readonly slug: string;
|
||||
public readonly name?: string;
|
||||
public readonly price?: OfferPrice;
|
||||
public readonly contents: OfferContent[];
|
||||
public readonly maxPurchases?: number;
|
||||
|
||||
constructor(
|
||||
private readonly purchase: PurchaseOffer,
|
||||
private readonly storeSlug: string,
|
||||
private readonly offer: Offer,
|
||||
) {
|
||||
if (!offer.id) {
|
||||
throw new Error('Rudder Stores: offer.id is required');
|
||||
}
|
||||
if (!offer.slug) {
|
||||
throw new Error('Rudder Stores: offer.slug is required');
|
||||
}
|
||||
this.id = offer.id;
|
||||
this.slug = offer.slug;
|
||||
this.name = offer.name;
|
||||
this.price = offer.price;
|
||||
this.contents = offer.contents ?? [];
|
||||
this.maxPurchases = offer.maxPurchases;
|
||||
}
|
||||
|
||||
async buy(options: BuyOptions = {}): Promise<PurchaseOfferResponse> {
|
||||
return this.purchase(this.storeSlug, this.slug, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class ShopHandle {
|
||||
public readonly slug: string;
|
||||
public readonly name?: string;
|
||||
public readonly description?: string;
|
||||
public readonly data?: { [key: string]: unknown };
|
||||
public readonly offers: OfferHandle[];
|
||||
|
||||
constructor(
|
||||
purchase: PurchaseOffer,
|
||||
store: Store,
|
||||
) {
|
||||
if (!store.slug) {
|
||||
throw new Error('Rudder Stores: store.slug is required');
|
||||
}
|
||||
this.slug = store.slug;
|
||||
this.name = store.name;
|
||||
this.description = store.description;
|
||||
this.data = store.data;
|
||||
this.offers = (store.offers ?? []).map(
|
||||
(offer) => new OfferHandle(purchase, this.slug, offer),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user