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:
|
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 }}
|
||||||
|
|||||||
@@ -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
@@ -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/"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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) {}
|
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> {
|
||||||
|
|||||||
@@ -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 }),
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user