@gamotech/game-sdk-client 1.0.0

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.
Files changed (3) hide show
  1. package/errors.js +9 -0
  2. package/index.js +196 -0
  3. package/package.json +15 -0
package/errors.js ADDED
@@ -0,0 +1,9 @@
1
+ export class ProviderSDKError extends Error {
2
+ constructor(message, { status, code, data } = {}) {
3
+ super(message);
4
+ this.name = "ProviderSDKError";
5
+ this.status = status ?? null;
6
+ this.code = code ?? null;
7
+ this.data = data ?? null;
8
+ }
9
+ }
package/index.js ADDED
@@ -0,0 +1,196 @@
1
+ import { ProviderSDKError } from "./errors.js";
2
+
3
+ const DEFAULT_API_BASE = "https://api.dpbossking.com/api/v1";
4
+
5
+ /**
6
+ * Browser/client SDK — session validate + lifecycle events only.
7
+ * Wallet operations must use @gamotech/game-sdk-nodejs on your game backend.
8
+ */
9
+ export class ProviderGameSDK {
10
+ #apiBase;
11
+ #sessionToken = null;
12
+ #session = null;
13
+
14
+ constructor(options = {}) {
15
+ this.#apiBase = (options.apiBaseUrl ?? DEFAULT_API_BASE).replace(/\/+$/, "");
16
+ }
17
+
18
+ get sessionToken() {
19
+ return this.#sessionToken;
20
+ }
21
+
22
+ get session() {
23
+ return this.#session;
24
+ }
25
+
26
+ get operatorId() {
27
+ return this.#session?.operatorId ?? null;
28
+ }
29
+
30
+ get playerId() {
31
+ return this.#session?.playerId ?? null;
32
+ }
33
+
34
+ get playerUsername() {
35
+ return this.#session?.playerUsername ?? null;
36
+ }
37
+
38
+ get gameCode() {
39
+ return this.#session?.gameCode ?? null;
40
+ }
41
+
42
+ get currency() {
43
+ return this.#session?.currency ?? null;
44
+ }
45
+
46
+ async initFromUrl(search = typeof window !== "undefined" ? window.location.search : "") {
47
+ const sessionToken = new URLSearchParams(search).get("sessionToken");
48
+ if (!sessionToken) {
49
+ throw new ProviderSDKError("Missing sessionToken in URL");
50
+ }
51
+ return this.init(sessionToken);
52
+ }
53
+
54
+ async init(sessionToken) {
55
+ this.#sessionToken = sessionToken;
56
+ this.#session = await this.#validateSession(sessionToken);
57
+ return this.#session;
58
+ }
59
+
60
+ async createTable({ tableId, ...payload } = {}) {
61
+ const id = tableId ?? `table_${Date.now()}`;
62
+ await this.#sendEvent("TABLE_CREATED", { tableId: id, payload });
63
+ return id;
64
+ }
65
+
66
+ async createRound({ roundId, ...payload } = {}) {
67
+ const id = roundId ?? `round_${Date.now()}`;
68
+ await this.#sendEvent("ROUND_CREATED", { roundId: id, payload });
69
+ return id;
70
+ }
71
+
72
+ async startRound({ roundId, ...payload }) {
73
+ this.#requireFields({ roundId }, ["roundId"]);
74
+ await this.#sendEvent("ROUND_STARTED", { roundId, payload });
75
+ return roundId;
76
+ }
77
+
78
+ async endRound({ roundId, ...payload }) {
79
+ this.#requireFields({ roundId }, ["roundId"]);
80
+ await this.#sendEvent("ROUND_ENDED", { roundId, payload });
81
+ return roundId;
82
+ }
83
+
84
+ async endSession(payload = { reason: "PLAYER_LEFT" }) {
85
+ this.#requireSession();
86
+ await this.#sendEvent("SESSION_ENDED", { payload });
87
+ this.#session = { ...this.#session, status: "ENDED" };
88
+ }
89
+
90
+ async sendEvent(event, { tableId, roundId, payload } = {}) {
91
+ return this.#sendEvent(event, { tableId, roundId, payload });
92
+ }
93
+
94
+ attachUnloadHandler() {
95
+ if (typeof window === "undefined") return;
96
+
97
+ window.addEventListener("beforeunload", () => {
98
+ if (!this.#sessionToken || this.#session?.status === "ENDED") return;
99
+
100
+ const body = JSON.stringify({
101
+ sessionToken: this.#sessionToken,
102
+ event: "SESSION_ENDED",
103
+ payload: { reason: "PLAYER_LEFT" },
104
+ });
105
+
106
+ navigator.sendBeacon(`${this.#apiBase}/sessions/events`, body);
107
+ });
108
+ }
109
+
110
+ async #validateSession(sessionToken) {
111
+ const data = await this.#request("/sessions/validate", {
112
+ method: "POST",
113
+ body: { sessionToken },
114
+ });
115
+ return data.session;
116
+ }
117
+
118
+ async #sendEvent(event, { tableId, roundId, payload } = {}) {
119
+ this.#requireSession();
120
+
121
+ const data = await this.#request("/sessions/events", {
122
+ method: "POST",
123
+ body: {
124
+ sessionToken: this.#sessionToken,
125
+ event,
126
+ tableId,
127
+ roundId,
128
+ payload,
129
+ },
130
+ });
131
+
132
+ if (data.session) {
133
+ this.#session = data.session;
134
+ }
135
+
136
+ return data;
137
+ }
138
+
139
+ async #request(path, { method = "GET", body } = {}) {
140
+ const url = `${this.#apiBase}${path.startsWith("/") ? path : `/${path}`}`;
141
+
142
+ const options = {
143
+ method,
144
+ headers: { "Content-Type": "application/json" },
145
+ };
146
+
147
+ if (body && method !== "GET") {
148
+ options.body = JSON.stringify(body);
149
+ }
150
+
151
+ let response;
152
+ try {
153
+ response = await fetch(url, options);
154
+ } catch {
155
+ throw new ProviderSDKError("Network error — unable to reach Provider API");
156
+ }
157
+
158
+ let data;
159
+ try {
160
+ data = await response.json();
161
+ } catch {
162
+ throw new ProviderSDKError("Invalid JSON response from Provider API", {
163
+ status: response.status,
164
+ });
165
+ }
166
+
167
+ if (!response.ok || data.success === false) {
168
+ throw new ProviderSDKError(data.message || "Provider API request failed", {
169
+ status: response.status,
170
+ data,
171
+ });
172
+ }
173
+
174
+ return data;
175
+ }
176
+
177
+ #requireSession() {
178
+ if (!this.#sessionToken || !this.#session) {
179
+ throw new ProviderSDKError("SDK not initialized — call init() or initFromUrl() first");
180
+ }
181
+ if (this.#session.status === "ENDED") {
182
+ throw new ProviderSDKError("Session has ended");
183
+ }
184
+ }
185
+
186
+ #requireFields(obj, fields) {
187
+ for (const field of fields) {
188
+ if (obj[field] === undefined || obj[field] === null || obj[field] === "") {
189
+ throw new ProviderSDKError(`${field} is required`);
190
+ }
191
+ }
192
+ }
193
+ }
194
+
195
+ export { ProviderSDKError };
196
+ export default ProviderGameSDK;
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@gamotech/game-sdk-client",
3
+ "version": "1.0.0",
4
+ "description": "Provider platform browser SDK — session validate and lifecycle events",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js"
9
+ },
10
+ "files": ["index.js", "errors.js"],
11
+ "license": "ISC",
12
+ "publishConfig": {
13
+ "access": "public"
14
+ }
15
+ }