@oyna360/game-sdk 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +210 -203
- package/dist/index.d.ts +20 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +192 -107
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +57 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/docs/02-init.md +138 -138
- package/docs/03-user-session.md +33 -33
- package/docs/04-end-session.md +22 -22
- package/docs/05-scores.md +30 -30
- package/docs/06-leaderboard.md +19 -19
- package/docs/07-postmessage-protocol.md +8 -0
- package/docs/08-wallet.md +52 -19
- package/docs/12-commerce-release.md +12 -0
- package/package.json +57 -56
package/docs/06-leaderboard.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
# لیدربورد — `getLeaderboard`
|
|
2
|
-
|
|
3
|
-
```ts
|
|
4
|
-
const board = await PlatformSDK.getLeaderboard(20);
|
|
5
|
-
// { gameSlug, entries: [{ rank, score, achievedAt, user: { displayName, username, avatarUrl } }] }
|
|
6
|
-
```
|
|
7
|
-
|
|
8
|
-
- `limit` پیشفرض ۲۰
|
|
9
|
-
- نیاز به `init()` دارد
|
|
10
|
-
- **Production** و **Direct Dev** هر دو کار میکنند (iframe یا REST)
|
|
11
|
-
|
|
12
|
-
```ts
|
|
13
|
-
const { entries } = await PlatformSDK.getLeaderboard(10);
|
|
14
|
-
for (const row of entries) {
|
|
15
|
-
console.log(row.rank, row.user.displayName, row.score);
|
|
16
|
-
}
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
بعدی: [07-postmessage-protocol.md](./07-postmessage-protocol.md)
|
|
1
|
+
# لیدربورد — `getLeaderboard`
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
const board = await PlatformSDK.getLeaderboard(20);
|
|
5
|
+
// { gameSlug, entries: [{ rank, score, achievedAt, user: { displayName, username, avatarUrl } }] }
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
- `limit` پیشفرض ۲۰
|
|
9
|
+
- نیاز به `init()` دارد
|
|
10
|
+
- **Production** و **Direct Dev** هر دو کار میکنند (iframe یا REST)
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
const { entries } = await PlatformSDK.getLeaderboard(10);
|
|
14
|
+
for (const row of entries) {
|
|
15
|
+
console.log(row.rank, row.user.displayName, row.score);
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
بعدی: [07-postmessage-protocol.md](./07-postmessage-protocol.md)
|
|
@@ -43,3 +43,11 @@
|
|
|
43
43
|
بهجای parent، Authorize HTTP استفاده میشود؛ ولی **شکل نهایی Context همان `SdkInitPayload` است** تا lobby-sdk و کد بازی یکسان بمانند.
|
|
44
44
|
|
|
45
45
|
بعدی: [08-wallet.md](./08-wallet.md)
|
|
46
|
+
|
|
47
|
+
## Commerce 0.7
|
|
48
|
+
|
|
49
|
+
Game → parent: `{type: 'platform:commerce:request', requestId, operation, args}`.
|
|
50
|
+
Parent → game: `{type: 'platform:commerce:result', requestId, result?, error?}`.
|
|
51
|
+
The top-level requestId correlates the RPC; args.requestId is the persisted business operation ID.
|
|
52
|
+
Operations: products, purchase, purchaseStatus, receipts, inventory, consume, exchange, exchangeStatus.
|
|
53
|
+
Only accept replies from the real parent and pinned platform origin. The parent binds every REST call to the authenticated launched game session.
|
package/docs/08-wallet.md
CHANGED
|
@@ -1,32 +1,65 @@
|
|
|
1
|
-
#
|
|
1
|
+
# کیف پول، خرید محصول و موجودی آیتم — نسخهٔ ۰٫۷٫۰
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
این نسخه علاوه بر `getWallet`، خرید مستقیم محصول، رسیدهای قابل بازیابی و موجودی/مصرف آیتم را در هر دو حالت iframe و Direct Development دارد.
|
|
4
|
+
|
|
5
|
+
> ابتدا بکاند و پل والدِ سازگار با Commerce 0.7 را منتشر کنید. اضافهکردن SDK بهتنهایی سرور قدیمی را ارتقا نمیدهد. سرور قدیمی ممکن است 404 یا timeout بدهد؛ در این حالت هیچ آیتم یا سکهای به کاربر اعطا نکنید.
|
|
6
|
+
|
|
7
|
+
## محصولات و خرید
|
|
4
8
|
|
|
5
9
|
```ts
|
|
6
|
-
const
|
|
7
|
-
// {
|
|
10
|
+
const { products } = await PlatformSDK.getProducts();
|
|
11
|
+
// {itemId, title, priceGems, quantity, consumable}[] — قیمت فقط روی سرور تعیین میشود.
|
|
12
|
+
const requestId = crypto.randomUUID();
|
|
13
|
+
// قبل از ارسال، شناسه را کنار خرید در ذخیرهسازی پایدارِ بازی نگه دارید.
|
|
14
|
+
const receipt = await PlatformSDK.purchaseProduct(products[0].itemId, requestId);
|
|
15
|
+
// {id, requestId, itemId, gemsSpent, gemsRemaining, quantity, consumable, gameSlug, createdAt, ...}
|
|
16
|
+
```
|
|
8
17
|
|
|
9
|
-
|
|
10
|
-
|
|
18
|
+
تکرار **همان شناسه و محصول**، همان رسید را بدون کسر مجدد جم و بدون اعطای دوباره برمیگرداند. استفاده از همان شناسه برای محصول دیگر خطاست. برای خرید مستقل بعدی، شناسهٔ جدید بسازید. شناسه ۸ تا ۱۲۸ کاراکتر از حروف انگلیسی، عدد، `_` و `-` است.
|
|
19
|
+
|
|
20
|
+
برای محصولات دائمی، خرید مجدد با شناسهٔ متفاوت رد میشود. محصول مصرفی میتواند چند بار و با شناسههای مستقل خریده شود.
|
|
21
|
+
|
|
22
|
+
## بازیابی بعد از خطا، قطع اینترنت یا بستهشدن بازی
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const status = await PlatformSDK.getPurchaseStatus(savedRequestId);
|
|
26
|
+
if (status.status === 'COMPLETED') applyReceiptOnce(status.receipt.id, status.receipt);
|
|
27
|
+
// NOT_FOUND یعنی هنوز رسید نهایی ثبت نشده؛ اثبات شکست پرداخت نیست.
|
|
28
|
+
// اگر خرید هنوز لازم است، با همان requestId دوباره purchaseProduct را صدا بزنید.
|
|
29
|
+
const page = await PlatformSDK.getPurchaseReceipts();
|
|
30
|
+
const nextPage = page.next ? await PlatformSDK.getPurchaseReceipts(page.next) : null;
|
|
11
31
|
```
|
|
12
32
|
|
|
13
|
-
|
|
33
|
+
رسیدها به همان **کاربر و بازی** محدودند و صفحهبندی ۱۰۰تایی دارند. `getPurchaseStatus` فقط ثبت نهایی (COMPLETED) یا نبود رسید نهایی (NOT_FOUND) را اعلام میکند؛ پرداخت بانکی یا صف خرید معلق نیست.
|
|
14
34
|
|
|
15
|
-
|
|
16
|
-
**اعتبار سکه داخل اقتصاد خودتان** با شماست (در سرور/کلاینت بازی اعمال کنید).
|
|
35
|
+
## موجودی و مصرف آیتم
|
|
17
36
|
|
|
18
|
-
|
|
37
|
+
```ts
|
|
38
|
+
const inventory = await PlatformSDK.getInventory();
|
|
39
|
+
// {gameSlug, items: [{itemId, quantity, consumable}]}
|
|
40
|
+
const useId = crypto.randomUUID(); // پیش از مصرف ذخیره شود
|
|
41
|
+
const used = await PlatformSDK.consumeItem('potion', 1, useId);
|
|
42
|
+
// {id, requestId, itemId, quantity, remaining, gameSlug}
|
|
43
|
+
```
|
|
19
44
|
|
|
20
|
-
|
|
21
|
-
|
|
45
|
+
مصرف در سرور اتمیک است؛ موجودی منفی نمیشود، آیتم دائمی مصرف نمیشود و تکرار یک مصرف با همان شناسه، دوباره کم نمیکند. برای بازیابی نتیجهٔ مصرف، همان `consumeItem` و همان شناسه را تکرار کنید. استفادهٔ مجدد شناسه با مقدار یا آیتم متفاوت خطاست.
|
|
46
|
+
|
|
47
|
+
## تبدیل جم به سکهٔ اقتصاد خود بازی
|
|
22
48
|
|
|
23
49
|
```ts
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
50
|
+
const wallet = await PlatformSDK.getWallet();
|
|
51
|
+
const id = crypto.randomUUID(); // پیش از ارسال نگه دارید
|
|
52
|
+
const result = await PlatformSDK.convertGems(5, id);
|
|
53
|
+
// {id, requestId, gemsSpent, coinsReceived, coinsPerGem, gemsRemaining, gameSlug}
|
|
54
|
+
const recovered = await PlatformSDK.getExchangeStatus(id);
|
|
30
55
|
```
|
|
31
56
|
|
|
32
|
-
|
|
57
|
+
بکاند سازگار با این نسخه، تبدیل و نتیجه را در یک تراکنش با `(userId, gameId, requestId)` ذخیره میکند. تلاش مجدد کسر جدید ندارد و مبلغ ناسازگار خطا میدهد. **اعطای سکه در اقتصاد مستقل بازی همچنان مسئولیت سرور بازی است**؛ `result.id` را فقط یک بار اعمال کنید. رسید را از کاربر دیگر یا فقط از پیام دلخواه کلاینت قبول نکنید.
|
|
58
|
+
|
|
59
|
+
اگر `requestId` را در خرید/مصرف/تبدیل ندهید، SDK برای همان فراخوانی یکی میسازد؛ برای بازیابی پس از بستهشدن بازی کافی نیست. در عملیات مهم همیشه شناسهٔ ذخیرهشدهٔ خودتان را بدهید.
|
|
60
|
+
|
|
61
|
+
## پیکربندی محصولات
|
|
62
|
+
|
|
63
|
+
قیمت و مقدار در پلتفرم تعریف میشود؛ SDK قیمت دلخواه قبول نمیکند. پلتفرم مسیر ادمین محافظتشدهٔ `PUT /api/admin/games/:gameId/products/:itemId` دارد با بدنهٔ `{title, priceGems, quantity, consumable, active}`. این مسیر را از کلاینت بازی صدا نزنید و توکن ادمین را داخل بازی قرار ندهید.
|
|
64
|
+
|
|
65
|
+
محصول دائمی باید `quantity: 1` داشته باشد. برای تغییر مصرفی/دائمی بودن، شناسهٔ آیتم جدید تعریف کنید. کاتالوگ قدیمی گانچیکو حفظ میشود، ولی بازیهای دیگر باید محصولات خود را روی سرور تعریف کنند.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Commerce 0.7 release
|
|
2
|
+
|
|
3
|
+
- Package version, `SDK_VERSION` and `PlatformSDK.version` are all `0.7.0`.
|
|
4
|
+
- New: `getProducts`, `purchaseProduct`, `getPurchaseStatus`, `getPurchaseReceipts`, `getInventory`, `consumeItem`, `getExchangeStatus`.
|
|
5
|
+
- Commerce operations work via authenticated REST in Direct Development and trusted parent RPC in an iframe.
|
|
6
|
+
- Business operation IDs are separate from transport correlation IDs, so concurrent retries do not mix their replies.
|
|
7
|
+
- `convertGems` now uses the commerce route; it requires the matching platform backend and parent bridge. Deploy platform migration/API/web before upgrading games to this version.
|
|
8
|
+
- Stable operation IDs must be persisted by the game before sending. Replay protection is provided by the matching backend's database transactions, not local SDK storage.
|
|
9
|
+
- The platform owns item balances and consumption. External in-game coin credits/effects still require the game server to apply each receipt once.
|
|
10
|
+
- GitHub source/dist updates do not publish a release to npm. Until npm is published by the owner, install the exact Git commit or a locally packed tarball.
|
|
11
|
+
|
|
12
|
+
Run `npm run build`, then `npm test`. Tests cover both transports, operation IDs, input rejection, version alignment and forged-parent replies.
|
package/package.json
CHANGED
|
@@ -1,56 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@oyna360/game-sdk",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "oyna360 Game SDK — postMessage bridge, Developer Environment credentials, and Direct Development Mode.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "oyna360",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"oyna360",
|
|
9
|
-
"game-sdk",
|
|
10
|
-
"iframe",
|
|
11
|
-
"postmessage",
|
|
12
|
-
"leaderboard",
|
|
13
|
-
"achievements"
|
|
14
|
-
],
|
|
15
|
-
"main": "./dist/index.js",
|
|
16
|
-
"types": "./dist/index.d.ts",
|
|
17
|
-
"exports": {
|
|
18
|
-
".": {
|
|
19
|
-
"types": "./dist/index.d.ts",
|
|
20
|
-
"import": "./dist/index.js",
|
|
21
|
-
"require": "./dist/index.js",
|
|
22
|
-
"default": "./dist/index.js"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"files": [
|
|
26
|
-
"dist",
|
|
27
|
-
"docs",
|
|
28
|
-
"README.md",
|
|
29
|
-
"LICENSE"
|
|
30
|
-
],
|
|
31
|
-
"sideEffects": false,
|
|
32
|
-
"scripts": {
|
|
33
|
-
"build": "tsc",
|
|
34
|
-
"dev": "tsc --watch",
|
|
35
|
-
"prepublishOnly": "npm run build",
|
|
36
|
-
"typecheck": "tsc --noEmit",
|
|
37
|
-
"lint": "echo \"No lint configured for @oyna360/game-sdk\""
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@oyna360/game-sdk",
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "oyna360 Game SDK — postMessage bridge, Developer Environment credentials, and Direct Development Mode.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "oyna360",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"oyna360",
|
|
9
|
+
"game-sdk",
|
|
10
|
+
"iframe",
|
|
11
|
+
"postmessage",
|
|
12
|
+
"leaderboard",
|
|
13
|
+
"achievements"
|
|
14
|
+
],
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.js",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"docs",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc",
|
|
34
|
+
"dev": "tsc --watch",
|
|
35
|
+
"prepublishOnly": "npm run build",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"lint": "echo \"No lint configured for @oyna360/game-sdk\"",
|
|
38
|
+
"test": "node --test tests/*.cjs"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"typescript": "^5.7.2"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/mamadjavadrasti/oyna360-game-sdk.git"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/mamadjavadrasti/oyna360-game-sdk/issues"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://github.com/mamadjavadrasti/oyna360-game-sdk#readme",
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public"
|
|
56
|
+
}
|
|
57
|
+
}
|