0.4.0: battlepass levelNumber fix, UGC removed, regenerated API types, CI publish on tags
This commit is contained in:
@@ -3,6 +3,7 @@ name: CI
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
tags: ['v*']
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
@@ -29,3 +30,29 @@ jobs:
|
||||
|
||||
- name: 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 }}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# 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
|
||||
|
||||
Breaking changes — the package was aligned with the Rudder SDK glossary and
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@rudder/js-sdk",
|
||||
"version": "0.1.0",
|
||||
"version": "0.4.0",
|
||||
"publishConfig": {
|
||||
"registry": "https://hub.rudder.build/api/packages/rudder/npm/"
|
||||
},
|
||||
|
||||
@@ -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 { GetStorageResponse, UpdateStorageRequest } from './storage.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. */
|
||||
export interface Transport {
|
||||
@@ -61,24 +60,12 @@ export const api = {
|
||||
): Promise<void> =>
|
||||
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: (
|
||||
t: Transport,
|
||||
body: GetBattlePassProgressRequest,
|
||||
): Promise<GetBattlePassProgressResponse> =>
|
||||
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: (
|
||||
t: Transport,
|
||||
): Promise<GetInventoryResponse> =>
|
||||
@@ -131,18 +118,6 @@ export const api = {
|
||||
): Promise<Store> =>
|
||||
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: (
|
||||
t: Transport,
|
||||
body: HandleScenarioCallbackRequest,
|
||||
@@ -170,12 +145,6 @@ export const api = {
|
||||
): Promise<ListStoresResponse> =>
|
||||
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: (
|
||||
t: Transport,
|
||||
body: LoginViaDeviceRequest,
|
||||
@@ -214,12 +183,6 @@ export const api = {
|
||||
): Promise<void> =>
|
||||
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: (
|
||||
t: Transport,
|
||||
body: TriggerScenarioRequest,
|
||||
|
||||
@@ -13,6 +13,5 @@ export * from './remote-config.js';
|
||||
export * from './scenarios.js';
|
||||
export * from './storage.js';
|
||||
export * from './stores.js';
|
||||
export * from './ugc.js';
|
||||
export * from './api.js';
|
||||
export * from './errors.js';
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ export class BattlePassLevelSession {
|
||||
constructor(private readonly context: ScenarioNodeContext) {}
|
||||
|
||||
get level(): number {
|
||||
return this.context.get('level', 0);
|
||||
return this.context.get('levelNumber', 0);
|
||||
}
|
||||
|
||||
get data(): Record<string, unknown> {
|
||||
|
||||
@@ -185,7 +185,7 @@ describe('ScenarioService', () => {
|
||||
client.effects.onBattlePassLevel(onLevel);
|
||||
|
||||
const plan = makePlan({
|
||||
nodes: [makeNode('start', 'battlepass_level', { level: 3 })],
|
||||
nodes: [makeNode('start', 'battlepass_level', { levelNumber: 3 })],
|
||||
});
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(
|
||||
new Response(JSON.stringify({ plans: [plan] }), { status: 200 }),
|
||||
|
||||
@@ -11,7 +11,7 @@ interface AdminWalletDetails {
|
||||
balance: number;
|
||||
}
|
||||
interface AdminInventoryItem {
|
||||
itemId: string;
|
||||
slug: string;
|
||||
amount: number;
|
||||
}
|
||||
interface AdminPlayerDetails {
|
||||
@@ -70,7 +70,7 @@ describe('e2e-prod: purchase (wallet/inventory/limits)', () => {
|
||||
const details = await api.get<AdminPlayerDetails>(
|
||||
`/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);
|
||||
|
||||
// 4. Idempotency: the same key twice charges once.
|
||||
|
||||
Reference in New Issue
Block a user