From fd364fd156217b44e5e4fde2eaee3350967ee069 Mon Sep 17 00:00:00 2001 From: edmand46 Date: Wed, 12 Aug 2026 23:58:30 +0300 Subject: [PATCH] Add ProjectStorageDomain with projectStorage sync --- src/client/RudderClient.ts | 5 +++++ src/domains/ProjectStorageDomain.ts | 26 ++++++++++++++++++++++++++ src/generated/api.ts | 13 +++++++++++++ src/generated/index.ts | 1 + src/generated/project-storage.ts | 29 +++++++++++++++++++++++++++++ src/index.ts | 6 ++++++ 6 files changed, 80 insertions(+) create mode 100644 src/domains/ProjectStorageDomain.ts create mode 100644 src/generated/project-storage.ts diff --git a/src/client/RudderClient.ts b/src/client/RudderClient.ts index 56c4144..0ab680b 100644 --- a/src/client/RudderClient.ts +++ b/src/client/RudderClient.ts @@ -35,6 +35,7 @@ import { CatalogDomain } from '../domains/CatalogDomain.js'; import { InventoryDomain } from '../domains/InventoryDomain.js'; import { ConfigDomain } from '../domains/ConfigDomain.js'; import { StorageDomain } from '../domains/StorageDomain.js'; +import { ProjectStorageDomain } from '../domains/ProjectStorageDomain.js'; import { StoresDomain } from '../domains/StoresDomain.js'; /** A domain the client can bulk-invalidate (re-login) or reset (logout). */ @@ -55,6 +56,7 @@ export class RudderClient public readonly inventory: InventoryDomain; public readonly remoteConfig: ConfigDomain; public readonly storage: StorageDomain; + public readonly projectStorage: ProjectStorageDomain; public readonly stores: StoresDomain; private readonly effectsCenter: EffectsCenter; @@ -109,6 +111,7 @@ export class RudderClient this.inventory = new InventoryDomain(ctx, this.catalog); this.remoteConfig = new ConfigDomain(ctx); this.storage = new StorageDomain(ctx); + this.projectStorage = new ProjectStorageDomain(ctx); this.stores = new StoresDomain(ctx, () => { this.player.invalidate(); this.inventory.invalidate(); @@ -124,6 +127,7 @@ export class RudderClient this.inventory, this.remoteConfig, this.storage, + this.projectStorage, this.stores, ]); this.auth = new AuthService( @@ -231,6 +235,7 @@ export class RudderClient this.inventory, this.remoteConfig, this.storage, + this.projectStorage, this.stores, ]; } diff --git a/src/domains/ProjectStorageDomain.ts b/src/domains/ProjectStorageDomain.ts new file mode 100644 index 0000000..903c038 --- /dev/null +++ b/src/domains/ProjectStorageDomain.ts @@ -0,0 +1,26 @@ +import { SyncedState } from '../state/SyncedState.js'; +import type { RudderContext } from '../core/context.js'; +import { api } from '../generated/api.js'; +import type { + GetProjectStorageResponse, + ProjectStorageUpdateItem, +} from '../generated/project-storage.js'; + +/** + * ProjectStorageDomain — project-wide key/value storage as an observable + * entity, plus its mutations. Synced under revision key `projectStorage`; + * mutations invalidate it so subscribers observe fresh data. + */ +export class ProjectStorageDomain extends SyncedState { + readonly syncKey = 'projectStorage'; + + constructor(private readonly ctx: RudderContext) { + super(() => api.getProjectStorage(ctx, { limit: 100 })); + } + + /** Saves project storage items, then invalidates. */ + async save(items: ProjectStorageUpdateItem[]): Promise { + await api.updateProjectStorage(this.ctx, { items }); + this.invalidate(); + } +} diff --git a/src/generated/api.ts b/src/generated/api.ts index f6c7f90..4b6f6a1 100644 --- a/src/generated/api.ts +++ b/src/generated/api.ts @@ -6,6 +6,7 @@ import type { ListCatalogItemsResponse } from './catalog.js'; import type { GetInventoryResponse } from './inventory.js'; import type { GetRankingResponse, SubmitScoreRequest } from './leaderboards.js'; import type { PlayerProfile } from './player.js'; +import type { GetProjectStorageResponse, UpdateProjectStorageRequest } from './project-storage.js'; import type { ClaimQuestRequest, ClaimQuestResponse, ListQuestsRequest, ListQuestsResponse } from './quests.js'; import type { ListRemoteConfigsResponse, RemoteConfig } from './remote-config.js'; import type { GetScenarioRunRequest, GetScenarioRunResponse, HandleScenarioCallbackRequest, HandleScenarioCallbackResponse, TriggerScenarioRequest, TriggerScenarioResponse, UpdateScenarioCounterRequest, UpdateScenarioCounterResponse } from './scenarios.js'; @@ -88,6 +89,12 @@ export const api = { ): Promise => t.request('GET', '/sdk/v1/player/information'), + getProjectStorage: ( + t: Transport, + query?: { types?: string; limit?: number; cursor?: string }, + ): Promise => + t.request('GET', `/sdk/v1/project-storage${qs([['types', query?.types], ['limit', query?.limit], ['cursor', query?.cursor]])}`), + getRanking: ( t: Transport, path: { slug: string }, @@ -213,6 +220,12 @@ export const api = { ): Promise => t.request('POST', '/sdk/v1/scenarios/trigger', body), + updateProjectStorage: ( + t: Transport, + body: UpdateProjectStorageRequest, + ): Promise => + t.request('PUT', '/sdk/v1/project-storage', body), + updateScenarioCounter: ( t: Transport, body: UpdateScenarioCounterRequest, diff --git a/src/generated/index.ts b/src/generated/index.ts index 766db4e..3b5ff7a 100644 --- a/src/generated/index.ts +++ b/src/generated/index.ts @@ -7,6 +7,7 @@ export * from './common.js'; export * from './inventory.js'; export * from './leaderboards.js'; export * from './player.js'; +export * from './project-storage.js'; export * from './quests.js'; export * from './remote-config.js'; export * from './scenarios.js'; diff --git a/src/generated/project-storage.ts b/src/generated/project-storage.ts new file mode 100644 index 0000000..c9a98d8 --- /dev/null +++ b/src/generated/project-storage.ts @@ -0,0 +1,29 @@ +// Code generated by apigen. DO NOT EDIT. + +export interface GetProjectStorageResponse { + "items"?: ProjectStorageItem[]; + "nextCursor"?: string; +} + +export interface ProjectStorageItem { + "data"?: string; + "expiresAt"?: string; + "id"?: string; + "readPermission"?: "public" | "serverOnly"; + "size"?: number; + "type"?: string; + "updatedAt"?: string; + "version"?: number; + "writePermission"?: "public" | "serverOnly"; +} + +export interface ProjectStorageUpdateItem { + "data"?: string; + "type"?: string; +} + +export interface UpdateProjectStorageRequest { + "idempotencyKey"?: string; + "items"?: ProjectStorageUpdateItem[]; +} + diff --git a/src/index.ts b/src/index.ts index f935bd8..f0683c0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -48,6 +48,7 @@ export type { CatalogDomain } from './domains/CatalogDomain.js'; export type { InventoryDomain } from './domains/InventoryDomain.js'; export type { ConfigDomain } from './domains/ConfigDomain.js'; export type { StorageDomain } from './domains/StorageDomain.js'; +export type { ProjectStorageDomain } from './domains/ProjectStorageDomain.js'; export type { StoresDomain } from './domains/StoresDomain.js'; // Effects @@ -80,6 +81,11 @@ export type { } from './generated/stores.js'; export type { RankEntry } from './generated/leaderboards.js'; export type { StorageItem, GetStorageResponse } from './generated/storage.js'; +export type { + ProjectStorageItem, + GetProjectStorageResponse, + ProjectStorageUpdateItem, +} from './generated/project-storage.js'; export type { RemoteConfig } from './generated/remote-config.js'; export type { Quest,