Skip to content

Commit ec30f70

Browse files
committed
Clarify UGC query limits
1 parent 184250e commit ec30f70

5 files changed

Lines changed: 37 additions & 9 deletions

File tree

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,14 +314,17 @@ UGC promises resolve from Steam call results. Continue pumping callbacks with
314314
reports completion through the `download-item-result` callback event:
315315

316316
`getItems()`, `getUserItems()`, and `getItemsByIds()` query options map to Steam's query setter
317-
methods. Tag filters, required key-value tags, return toggles, playtime stats,
318-
text search, trend windows, language, and cache age are applied before
319-
`SendQueryUGCRequest()`. `userId` is used only by `getUserItems()`.
317+
methods. `getItemsByIds()` accepts from one to 50 known published file IDs and
318+
throws if given more. Tag filters, required key-value tags, return toggles,
319+
playtime stats, text search, trend windows, language, and cache age are applied
320+
before `SendQueryUGCRequest()`. `userId` is used only by `getUserItems()`.
320321
`matchAnyTag`, `searchText`, and `rankedByTrendDays` are only valid for
321322
`getItems()`; `cloudFileNameFilter` is only valid for `getUserItems()`.
322323
`getItems()` also accepts a deep-pagination `cursor`, which cannot be combined
323324
with `page`. Pass the prior result's non-empty `nextCursor` to obtain the next
324-
page; cursor pagination is not available for user or ID-detail queries.
325+
page. Steam returns `nextCursor: ''` on the final page; do not pass that empty
326+
terminal value as `cursor`, because the binding throws. Cursor pagination is not
327+
available for user or ID-detail queries.
325328

326329
```ts
327330
import {

docs/api/ugc.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ flags, language, cache age, and the query-specific options documented below.
2222
deep-pagination `cursor`. Do not combine `cursor` with `page`.
2323
- `getUserItems()` supports `userId` for another public user and
2424
`cloudFileNameFilter`; without `userId`, it selects the current user.
25-
- `getItemsByIds()` accepts known published file IDs and return-field options;
26-
it does not support user or cursor options.
25+
- `getItemsByIds()` accepts one to 50 known published file IDs and return-field
26+
options; it does not support user or cursor options. Passing more than 50 IDs
27+
throws before Steam creates a query.
2728

2829
The result includes `items`, `totalMatchingResults`, `cachedData`, and
2930
`nextCursor`. Optional fields such as metadata, children, previews, key-value
@@ -51,7 +52,9 @@ const items = await waitForSteamCall(
5152
```
5253

5354
For deep pagination, pass a non-empty `nextCursor` from one all-item result to
54-
the next `getItems()` call.
55+
the next `getItems()` call. Steam returns `nextCursor: ''` on the final page;
56+
that empty terminal value must not be passed as `cursor` because the binding
57+
throws for an empty cursor. Use a truthiness check such as the one below.
5558

5659
```ts
5760
let result = await waitForSteamCall(

src/cpp/ugc.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,6 +1907,10 @@ JS_METHOD(getUserItems) {
19071907
JS_METHOD(getItemsByIds) {
19081908
NAPI_ENV;
19091909
REQ_ARRAY_ARG(1, publishedFileIds);
1910+
if (publishedFileIds.Length() > kNumUGCResultsPerPage) {
1911+
JS_THROW("publishedFileIds must contain no more than 50 item IDs.");
1912+
RET_UNDEFINED;
1913+
}
19101914

19111915
QueryOptions options = {};
19121916
if (!readQueryOptions(env, info[0], &options)) {

ts/index.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import assert from 'node:assert/strict';
33
import { existsSync } from 'node:fs';
44
import { join } from 'node:path';
55
import { getBin } from '@node-3d/addon-tools';
6-
import type { TSteamId, TSteamUgcDetails, TSteamUgcQueryOptions } from './index.ts';
6+
import type {
7+
TSteamId,
8+
TSteamPublishedFileId,
9+
TSteamUgcDetails,
10+
TSteamUgcQueryOptions,
11+
} from './index.ts';
712

813
const nativeBinaryPath = join(import.meta.dirname, '..', getBin(), 'steam-api.node');
914
const nativeSkip = existsSync(nativeBinaryPath) ? false : 'native binary is not built';
@@ -276,5 +281,13 @@ test(
276281
() => steamApi.friends.getFriendMessage(steamId, 0, 64 * 1024 + 1),
277282
/maximumMessageSize exceeds the maximum Steam friend message size/u,
278283
);
284+
assert.throws(
285+
() =>
286+
steamApi.ugc.getItemsByIds(
287+
{},
288+
Array.from({ length: 51 }, () => '1' as TSteamPublishedFileId),
289+
),
290+
/publishedFileIds must contain no more than 50 item IDs/u,
291+
);
279292
},
280293
);

ts/native.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ export type TSteamUgcQueryKeyValueTag = Readonly<{
111111
export type TSteamUgcQueryOptions = Readonly<{
112112
appId?: number;
113113
page?: number;
114-
/** Deep-pagination cursor for getItems(); cannot be combined with page. */
114+
/**
115+
* Deep-pagination cursor for getItems(); cannot be combined with page. Must
116+
* be a non-empty nextCursor from a previous result.
117+
*/
115118
cursor?: string;
116119
/** Steam user ID for getUserItems(); defaults to the current user. */
117120
userId?: TSteamId;
@@ -193,6 +196,7 @@ export type TSteamUgcQueryResult = Readonly<{
193196
result: number;
194197
totalMatchingResults: number;
195198
cachedData: boolean;
199+
/** Empty when there is no next page; do not pass an empty cursor to getItems(). */
196200
nextCursor: string;
197201
items: TSteamUgcDetails[];
198202
}>;
@@ -1022,6 +1026,7 @@ export type TSteamNativeUgcNamespace = Readonly<{
10221026
) => Promise<TSteamUgcQueryResult>;
10231027
getItemsByIds: (
10241028
options: TSteamUgcQueryOptions | null | undefined,
1029+
/** Accepts from one to 50 published file IDs. */
10251030
publishedFileIds: TSteamPublishedFileId[],
10261031
) => Promise<TSteamUgcQueryResult>;
10271032
createItem: (appId?: number, fileType?: number) => Promise<TSteamUgcCreateItemResult>;

0 commit comments

Comments
 (0)