Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ Headers: `authorization` (JWT), `x-mc-token` (required). Returns `{ count, entit

#### `GET /inventory/playfab/items?filter=<query>`

Headers: `authorization` (JWT), `x-playfab-session` (required), `x-playfab-id` (required). Returns the PlayFab Economy inventory payload with official PlayFab filter queries.
Headers: `authorization` (JWT), `x-playfab-session` (required), `x-playfab-id` (required). Returns the PlayFab Economy inventory payload with official PlayFab filter queries. Supported filter fields are `type`, `id`, and `stackId` with `eq`.

#### `POST /purchase/quote`

Expand Down Expand Up @@ -341,7 +341,11 @@ curl -sS "$BASE/inventory/entitlements?includeReceipt=true" \
-H "Authorization: Bearer $TOKEN" -H "x-mc-token: $MC"

# PlayFab inventory items with filter query
curl -sS "$BASE/inventory/playfab/items?filter=InventoryItem.ItemClass%20eq%20%27Subscription%27" \
curl -sS "$BASE/inventory/playfab/items?filter=type%20eq%20%27Subscription%27" \
-H "Authorization: Bearer $TOKEN" -H "x-playfab-session: $ST" -H "x-playfab-id: <playfabId>"

# PlayFab inventory items with shortcut parameters
curl -sS "$BASE/inventory/playfab/items?type=Subscription" \
-H "Authorization: Bearer $TOKEN" -H "x-playfab-session: $ST" -H "x-playfab-id: <playfabId>"

# Debug: decode multiple tokens
Expand Down
20 changes: 19 additions & 1 deletion src/routes/inventory.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,33 @@ router.get("/playfab/items", jwtMiddleware, asyncHandler(async (req, res) => {
const playfabId = req.headers["x-playfab-id"];
if (!sessionTicket || !playfabId) throw badRequest("x-playfab-session and x-playfab-id are required");
const filter = String(req.query.filter || "").trim();
const type = req.query.type ? String(req.query.type).trim() : "";
const id = req.query.id ? String(req.query.id).trim() : "";
const stackId = req.query.stackId ? String(req.query.stackId).trim() : "";
if (filter && (type || id || stackId)) throw badRequest("Use filter or type/id/stackId, not both");
if (!filter && !type && !id && !stackId) throw badRequest("Provide filter or type/id/stackId");
const countRaw = req.query.count;
const count = countRaw === undefined ? null : Number(countRaw);
if (count !== null && (!Number.isInteger(count) || count < 1 || count > 200)) {
throw badRequest("count must be an integer between 1 and 200");
}
const continuationToken = req.query.continuationToken ? String(req.query.continuationToken) : null;
const entityToken = await getEntityTokenForPlayer(sessionTicket, playfabId);
const data = await getInventoryItems(entityToken, {filter, count, continuationToken});
const resolvedFilter = filter || buildInventoryFilter({type, id, stackId});
const data = await getInventoryItems(entityToken, {filter: resolvedFilter, count, continuationToken});
res.json(data);
}));

function buildInventoryFilter({type, id, stackId}) {
const parts = [];
if (type) parts.push(`type eq '${escapeFilterValue(type)}'`);
if (id) parts.push(`id eq '${escapeFilterValue(id)}'`);
if (stackId) parts.push(`stackId eq '${escapeFilterValue(stackId)}'`);
return parts.join(" and ");
}

function escapeFilterValue(value) {
return value.replaceAll("'", "''");
}

export default router;
20 changes: 19 additions & 1 deletion src/utils/swagger.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,25 @@ const options = {
name: "filter",
required: false,
schema: {type: "string"},
description: "PlayFab Economy filter query string."
description: "PlayFab Economy filter query string. Supported fields: type, id, stackId with eq."
}, {
in: "query",
name: "type",
required: false,
schema: {type: "string"},
description: "Shortcut for type eq '<value>' when filter is omitted."
}, {
in: "query",
name: "id",
required: false,
schema: {type: "string"},
description: "Shortcut for id eq '<value>' when filter is omitted."
}, {
in: "query",
name: "stackId",
required: false,
schema: {type: "string"},
description: "Shortcut for stackId eq '<value>' when filter is omitted."
}, {
in: "query",
name: "count",
Expand Down