0.4.0: battlepass levelNumber fix, UGC removed, regenerated API types, CI publish on tags
CI / check (push) Successful in 59s
CI / publish (push) Failing after 23s

This commit is contained in:
edmand46
2026-08-19 17:48:55 +03:00
parent 25f66be16a
commit 322a2c0706
9 changed files with 42 additions and 90 deletions
+27
View File
@@ -3,6 +3,7 @@ name: CI
on: on:
push: push:
branches: [main, master] branches: [main, master]
tags: ['v*']
pull_request: pull_request:
jobs: jobs:
@@ -29,3 +30,29 @@ jobs:
- name: Build - name: Build
run: npm run build run: npm run build
publish:
if: startsWith(github.ref, 'refs/tags/v')
needs: check
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
registry-url: https://hub.rudder.build/api/packages/rudder/npm/
- name: Install
run: npm ci
- name: Build
run: npm run build
- name: Publish
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITEA_TOKEN }}
+10
View File
@@ -1,5 +1,15 @@
# Changelog # Changelog
## 0.4.0
- Fixed `BattlePassLevelSession.level` reading node data key `level` — the
admin editor writes `levelNumber`, so tiers always reported `0`. The session
now reads `levelNumber`, matching the editor and server validation.
- UGC support removed from the generated wire types (`src/generated/ugc.ts`
deleted by apigen); no UGC surface was ever exposed by this SDK.
- Generated API types regenerated from the gateway openapi spec, adding the
new platform operations.
## 0.3.0 ## 0.3.0
Breaking changes — the package was aligned with the Rudder SDK glossary and Breaking changes — the package was aligned with the Rudder SDK glossary and
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@rudder/js-sdk", "name": "@rudder/js-sdk",
"version": "0.1.0", "version": "0.4.0",
"publishConfig": { "publishConfig": {
"registry": "https://hub.rudder.build/api/packages/rudder/npm/" "registry": "https://hub.rudder.build/api/packages/rudder/npm/"
}, },
-37
View File
@@ -12,7 +12,6 @@ import type { ListRemoteConfigsResponse, RemoteConfig } from './remote-config.js
import type { GetScenarioRunRequest, GetScenarioRunResponse, HandleScenarioCallbackRequest, HandleScenarioCallbackResponse, TriggerScenarioRequest, TriggerScenarioResponse, UpdateScenarioCounterRequest, UpdateScenarioCounterResponse } from './scenarios.js'; import type { GetScenarioRunRequest, GetScenarioRunResponse, HandleScenarioCallbackRequest, HandleScenarioCallbackResponse, TriggerScenarioRequest, TriggerScenarioResponse, UpdateScenarioCounterRequest, UpdateScenarioCounterResponse } from './scenarios.js';
import type { GetStorageResponse, UpdateStorageRequest } from './storage.js'; import type { GetStorageResponse, UpdateStorageRequest } from './storage.js';
import type { ListStoresResponse, PurchaseOfferRequest, PurchaseOfferResponse, Store } from './stores.js'; import type { ListStoresResponse, PurchaseOfferRequest, PurchaseOfferResponse, Store } from './stores.js';
import type { DeleteUgcResponse, GetDownloadUrlResponse, GetUploadUrlResponse, ListUgcResponse, SubmitUgcRequest, UgcSubmission } from './ugc.js';
/** The minimal transport contract the generated API functions call through. */ /** The minimal transport contract the generated API functions call through. */
export interface Transport { export interface Transport {
@@ -61,24 +60,12 @@ export const api = {
): Promise<void> => ): Promise<void> =>
t.request<void>('DELETE', `/sdk/v1/storage${qs([['type', query?.type]])}`), t.request<void>('DELETE', `/sdk/v1/storage${qs([['type', query?.type]])}`),
deleteUgc: (
t: Transport,
path: { id: string },
): Promise<DeleteUgcResponse> =>
t.request<DeleteUgcResponse>('DELETE', `/sdk/v1/ugc/${enc(path.id)}`),
getBattlePassProgress: ( getBattlePassProgress: (
t: Transport, t: Transport,
body: GetBattlePassProgressRequest, body: GetBattlePassProgressRequest,
): Promise<GetBattlePassProgressResponse> => ): Promise<GetBattlePassProgressResponse> =>
t.request<GetBattlePassProgressResponse>('POST', '/sdk/v1/battlepass/progress', body), t.request<GetBattlePassProgressResponse>('POST', '/sdk/v1/battlepass/progress', body),
getDownloadUrl: (
t: Transport,
path: { id: string },
): Promise<GetDownloadUrlResponse> =>
t.request<GetDownloadUrlResponse>('GET', `/sdk/v1/ugc/${enc(path.id)}/download`),
getInventory: ( getInventory: (
t: Transport, t: Transport,
): Promise<GetInventoryResponse> => ): Promise<GetInventoryResponse> =>
@@ -131,18 +118,6 @@ export const api = {
): Promise<Store> => ): Promise<Store> =>
t.request<Store>('GET', `/sdk/v1/stores/${enc(path.slug)}`), t.request<Store>('GET', `/sdk/v1/stores/${enc(path.slug)}`),
getUgc: (
t: Transport,
path: { id: string },
): Promise<UgcSubmission> =>
t.request<UgcSubmission>('GET', `/sdk/v1/ugc/${enc(path.id)}`),
getUploadUrl: (
t: Transport,
query?: { filename?: string },
): Promise<GetUploadUrlResponse> =>
t.request<GetUploadUrlResponse>('GET', `/sdk/v1/ugc/upload-url${qs([['filename', query?.filename]])}`),
handleScenarioCallback: ( handleScenarioCallback: (
t: Transport, t: Transport,
body: HandleScenarioCallbackRequest, body: HandleScenarioCallbackRequest,
@@ -170,12 +145,6 @@ export const api = {
): Promise<ListStoresResponse> => ): Promise<ListStoresResponse> =>
t.request<ListStoresResponse>('GET', '/sdk/v1/stores'), t.request<ListStoresResponse>('GET', '/sdk/v1/stores'),
listUgc: (
t: Transport,
query?: { status?: string; limit?: number; cursor?: string },
): Promise<ListUgcResponse> =>
t.request<ListUgcResponse>('GET', `/sdk/v1/ugc${qs([['status', query?.status], ['limit', query?.limit], ['cursor', query?.cursor]])}`),
loginViaDevice: ( loginViaDevice: (
t: Transport, t: Transport,
body: LoginViaDeviceRequest, body: LoginViaDeviceRequest,
@@ -214,12 +183,6 @@ export const api = {
): Promise<void> => ): Promise<void> =>
t.request<void>('POST', `/sdk/v1/leaderboards/${enc(path.slug)}/submit-score`, body), t.request<void>('POST', `/sdk/v1/leaderboards/${enc(path.slug)}/submit-score`, body),
submitUgc: (
t: Transport,
body: SubmitUgcRequest,
): Promise<UgcSubmission> =>
t.request<UgcSubmission>('POST', '/sdk/v1/ugc', body),
triggerScenario: ( triggerScenario: (
t: Transport, t: Transport,
body: TriggerScenarioRequest, body: TriggerScenarioRequest,
-1
View File
@@ -13,6 +13,5 @@ export * from './remote-config.js';
export * from './scenarios.js'; export * from './scenarios.js';
export * from './storage.js'; export * from './storage.js';
export * from './stores.js'; export * from './stores.js';
export * from './ugc.js';
export * from './api.js'; export * from './api.js';
export * from './errors.js'; export * from './errors.js';
-47
View File
@@ -1,47 +0,0 @@
// Code generated by apigen. DO NOT EDIT.
export interface DeleteUgcResponse {
"success"?: boolean;
}
export interface GetDownloadUrlResponse {
"downloadUrl"?: string;
}
export interface GetUploadUrlResponse {
"fileKey"?: string;
"uploadUrl"?: string;
}
export interface ListUgcResponse {
"items"?: UgcSubmission[];
"nextCursor"?: string;
}
export interface SubmitUgcRequest {
"description"?: string;
"fileKey"?: string;
"fileSize"?: number;
"metadata"?: { [key: string]: unknown };
"name"?: string;
}
export interface SubmittedBy {
"userId"?: string;
"username"?: string;
}
export interface UgcSubmission {
"description"?: string;
"fileSize"?: number;
"fileUrl"?: string;
"id"?: string;
"metadata"?: { [key: string]: unknown };
"name"?: string;
"reviewedAt"?: string;
"reviewedBy"?: string;
"status"?: string;
"submittedAt"?: string;
"submittedBy"?: SubmittedBy;
}
+1 -1
View File
@@ -320,7 +320,7 @@ export class BattlePassLevelSession {
constructor(private readonly context: ScenarioNodeContext) {} constructor(private readonly context: ScenarioNodeContext) {}
get level(): number { get level(): number {
return this.context.get('level', 0); return this.context.get('levelNumber', 0);
} }
get data(): Record<string, unknown> { get data(): Record<string, unknown> {
+1 -1
View File
@@ -185,7 +185,7 @@ describe('ScenarioService', () => {
client.effects.onBattlePassLevel(onLevel); client.effects.onBattlePassLevel(onLevel);
const plan = makePlan({ const plan = makePlan({
nodes: [makeNode('start', 'battlepass_level', { level: 3 })], nodes: [makeNode('start', 'battlepass_level', { levelNumber: 3 })],
}); });
vi.stubGlobal('fetch', vi.fn().mockResolvedValue( vi.stubGlobal('fetch', vi.fn().mockResolvedValue(
new Response(JSON.stringify({ plans: [plan] }), { status: 200 }), new Response(JSON.stringify({ plans: [plan] }), { status: 200 }),
+2 -2
View File
@@ -11,7 +11,7 @@ interface AdminWalletDetails {
balance: number; balance: number;
} }
interface AdminInventoryItem { interface AdminInventoryItem {
itemId: string; slug: string;
amount: number; amount: number;
} }
interface AdminPlayerDetails { interface AdminPlayerDetails {
@@ -70,7 +70,7 @@ describe('e2e-prod: purchase (wallet/inventory/limits)', () => {
const details = await api.get<AdminPlayerDetails>( const details = await api.get<AdminPlayerDetails>(
`/game/v1/projects/${artifact.projectId}/players/${playerId}`, `/game/v1/projects/${artifact.projectId}/players/${playerId}`,
); );
const inv = details.inventory?.find((i) => i.itemId === artifact.item.id); const inv = details.inventory?.find((i) => i.slug === artifact.item.id);
expect(Number(inv?.amount)).toBe(artifact.store.paidGrantAmount); expect(Number(inv?.amount)).toBe(artifact.store.paidGrantAmount);
// 4. Idempotency: the same key twice charges once. // 4. Idempotency: the same key twice charges once.