@seekprotocol/game 0.1.1 → 0.1.3
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 +2 -2
- package/bridge.d.ts +1 -0
- package/index.js +29 -3
- package/package.json +1 -1
- package/protocol.d.ts +5 -0
- package/seek-game.js +29 -3
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ import { createBridge } from '@seekprotocol/game';
|
|
|
12
12
|
|
|
13
13
|
`seek-game.js` is the same bridge as one file, for a game without a bundler.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
The guide is in Store Connect, under Documentation, after you sign in:
|
|
16
|
+
https://storeconnect.seekprotocol.ai
|
|
17
17
|
|
|
18
18
|
Copyright (c) 2026 Seek Protocol. MIT licensed, see `LICENSE.md`: ship the bridge with your game freely.
|
package/bridge.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -312,6 +312,26 @@ var TRACK_MAX_STRING = 64;
|
|
|
312
312
|
var MAX_TOKEN_LENGTH = 4096;
|
|
313
313
|
var PROXY_ORIGIN = "https://api.play.seekprotocol.ai";
|
|
314
314
|
var DEFAULT_HOST_ORIGINS = ["https://storeconnect.seekprotocol.ai"];
|
|
315
|
+
function readGameTexts(v) {
|
|
316
|
+
if (!isObj2(v))
|
|
317
|
+
return {};
|
|
318
|
+
const out = {};
|
|
319
|
+
let n = 0;
|
|
320
|
+
for (const [k, x] of Object.entries(v)) {
|
|
321
|
+
if (n >= 300)
|
|
322
|
+
break;
|
|
323
|
+
if (typeof x === "string" && x.length <= 2000 && /^[A-Za-z0-9_][A-Za-z0-9_.-]{0,59}$/.test(k)) {
|
|
324
|
+
out[k] = x;
|
|
325
|
+
n++;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return out;
|
|
329
|
+
}
|
|
330
|
+
function fillText(text, vars) {
|
|
331
|
+
if (!vars)
|
|
332
|
+
return text;
|
|
333
|
+
return text.replace(/\{([A-Za-z][A-Za-z0-9_]{0,30})\}/g, (m, name) => Object.prototype.hasOwnProperty.call(vars, name) ? String(vars[name]) : m);
|
|
334
|
+
}
|
|
315
335
|
var utf8Bytes = (s) => new TextEncoder().encode(s).byteLength;
|
|
316
336
|
function jsonBytes(value) {
|
|
317
337
|
try {
|
|
@@ -482,12 +502,13 @@ function decodeLaunchToken(token) {
|
|
|
482
502
|
}
|
|
483
503
|
if (!isObj2(c))
|
|
484
504
|
return null;
|
|
485
|
-
const { run, seed, lang, sub, game, version, exp } = c;
|
|
505
|
+
const { run, seed, lang, sub, game, version, exp, variant, step } = c;
|
|
486
506
|
if (typeof run !== "string" || typeof sub !== "string" || typeof game !== "string" || typeof version !== "string" || typeof lang !== "string")
|
|
487
507
|
return null;
|
|
488
508
|
if (typeof seed !== "number" || !Number.isSafeInteger(seed) || typeof exp !== "number")
|
|
489
509
|
return null;
|
|
490
|
-
|
|
510
|
+
const name = (v) => typeof v === "string" && /^[a-z0-9][a-z0-9-]{0,39}$/.test(v) ? v : null;
|
|
511
|
+
return { runId: run, seed, lang, sub, game, version, expiresAt: exp * 1000, variant: name(variant), step: name(step) };
|
|
491
512
|
}
|
|
492
513
|
var PRE_READY_ENTRIES = 20;
|
|
493
514
|
function createCollector(opts) {
|
|
@@ -729,6 +750,7 @@ function createBridge(opts = {}) {
|
|
|
729
750
|
let readyPromise = null;
|
|
730
751
|
let launchInfo = null;
|
|
731
752
|
let token = "";
|
|
753
|
+
let texts = {};
|
|
732
754
|
let transport = "proxy";
|
|
733
755
|
let finished = false;
|
|
734
756
|
let tracked = 0;
|
|
@@ -930,6 +952,9 @@ function createBridge(opts = {}) {
|
|
|
930
952
|
}
|
|
931
953
|
}
|
|
932
954
|
const bridge = {
|
|
955
|
+
t(key, vars) {
|
|
956
|
+
return fillText(texts[key] ?? key, vars);
|
|
957
|
+
},
|
|
933
958
|
ready() {
|
|
934
959
|
if (readyPromise)
|
|
935
960
|
return readyPromise;
|
|
@@ -940,6 +965,7 @@ function createBridge(opts = {}) {
|
|
|
940
965
|
throw new BridgeError("bad_launch", "The host sent no valid launch token.");
|
|
941
966
|
token = p.token;
|
|
942
967
|
transport = p.transport === "host" ? "host" : "proxy";
|
|
968
|
+
texts = readGameTexts(p.texts);
|
|
943
969
|
launchInfo = info;
|
|
944
970
|
if (vitals && !vitals.session) {
|
|
945
971
|
const readyMs = perf?.sinceLoad();
|
|
@@ -1044,4 +1070,4 @@ function createBridge(opts = {}) {
|
|
|
1044
1070
|
};
|
|
1045
1071
|
return bridge;
|
|
1046
1072
|
}
|
|
1047
|
-
export { BRIDGE_VERSION, BridgeError, DEFAULT_HOST_ORIGINS, DEVICE_CLASSES, DIAG_BODY_MAX_BYTES, DIAG_LIMITS, END_REASONS, ERROR_SOURCES, FINGERPRINT_FRAMES, HOST_EVENTS, HOST_EVENT_TEXT, HOST_HANG_MS, HOST_READY_TIMEOUT_MS, JANK_FRAME_MS, LOG_LEVELS, MAX_MESSAGE_BYTES, MAX_TOKEN_LENGTH, OS_NAMES, PERF_RANGES, PRE_READY_ENTRIES, PROTOCOL, PROTOCOL_VERSION, PROXY_ORIGIN, STORAGE_KEY, STORAGE_MAX_BYTES, TRACK_EVENT, TRACK_MAX_PROPS, TRACK_MAX_STRING, TRACK_PER_LAUNCH, TRACK_PROP_KEY, boundData, cleanDiagnosticEntry, createBridge, createCollector, createHostWatchdog, createPerfSampler, decodeLaunchToken, fingerprint, fingerprintInput, finishProblem, frameKey, isCrashEntry, isFatalSource, isHostEvent, isJsonValue, isLogLevel, jsonBytes, launchContextProblem, normaliseContext, normaliseMessage, parseDiagnosticsBatch, parseGameRequest, parseHostMessage, parseStack, scrubData, scrubText, sessionIdOf, sha256HexOf, shortenGameUrls, storageKeyProblem, trackProblem, utf8Bytes };
|
|
1073
|
+
export { BRIDGE_VERSION, BridgeError, DEFAULT_HOST_ORIGINS, DEVICE_CLASSES, DIAG_BODY_MAX_BYTES, DIAG_LIMITS, END_REASONS, ERROR_SOURCES, FINGERPRINT_FRAMES, HOST_EVENTS, HOST_EVENT_TEXT, HOST_HANG_MS, HOST_READY_TIMEOUT_MS, JANK_FRAME_MS, LOG_LEVELS, MAX_MESSAGE_BYTES, MAX_TOKEN_LENGTH, OS_NAMES, PERF_RANGES, PRE_READY_ENTRIES, PROTOCOL, PROTOCOL_VERSION, PROXY_ORIGIN, STORAGE_KEY, STORAGE_MAX_BYTES, TRACK_EVENT, TRACK_MAX_PROPS, TRACK_MAX_STRING, TRACK_PER_LAUNCH, TRACK_PROP_KEY, boundData, cleanDiagnosticEntry, createBridge, createCollector, createHostWatchdog, createPerfSampler, decodeLaunchToken, fillText, fingerprint, fingerprintInput, finishProblem, frameKey, isCrashEntry, isFatalSource, isHostEvent, isJsonValue, isLogLevel, jsonBytes, launchContextProblem, normaliseContext, normaliseMessage, parseDiagnosticsBatch, parseGameRequest, parseHostMessage, parseStack, readGameTexts, scrubData, scrubText, sessionIdOf, sha256HexOf, shortenGameUrls, storageKeyProblem, trackProblem, utf8Bytes };
|
package/package.json
CHANGED
package/protocol.d.ts
CHANGED
|
@@ -39,7 +39,10 @@ export interface HostEvent {
|
|
|
39
39
|
export interface ReadyPayload {
|
|
40
40
|
token: string;
|
|
41
41
|
transport?: "proxy" | "host";
|
|
42
|
+
texts?: Record<string, string>;
|
|
42
43
|
}
|
|
44
|
+
export declare function readGameTexts(v: unknown): Record<string, string>;
|
|
45
|
+
export declare function fillText(text: string, vars?: Record<string, string | number>): string;
|
|
43
46
|
export interface LaunchInfo {
|
|
44
47
|
runId: string;
|
|
45
48
|
seed: number;
|
|
@@ -48,6 +51,8 @@ export interface LaunchInfo {
|
|
|
48
51
|
game: string;
|
|
49
52
|
version: string;
|
|
50
53
|
expiresAt: number;
|
|
54
|
+
variant: string | null;
|
|
55
|
+
step: string | null;
|
|
51
56
|
}
|
|
52
57
|
export declare const utf8Bytes: (s: string) => number;
|
|
53
58
|
export declare function jsonBytes(value: unknown): number;
|
package/seek-game.js
CHANGED
|
@@ -312,6 +312,26 @@ var TRACK_MAX_STRING = 64;
|
|
|
312
312
|
var MAX_TOKEN_LENGTH = 4096;
|
|
313
313
|
var PROXY_ORIGIN = "https://api.play.seekprotocol.ai";
|
|
314
314
|
var DEFAULT_HOST_ORIGINS = ["https://storeconnect.seekprotocol.ai"];
|
|
315
|
+
function readGameTexts(v) {
|
|
316
|
+
if (!isObj2(v))
|
|
317
|
+
return {};
|
|
318
|
+
const out = {};
|
|
319
|
+
let n = 0;
|
|
320
|
+
for (const [k, x] of Object.entries(v)) {
|
|
321
|
+
if (n >= 300)
|
|
322
|
+
break;
|
|
323
|
+
if (typeof x === "string" && x.length <= 2000 && /^[A-Za-z0-9_][A-Za-z0-9_.-]{0,59}$/.test(k)) {
|
|
324
|
+
out[k] = x;
|
|
325
|
+
n++;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return out;
|
|
329
|
+
}
|
|
330
|
+
function fillText(text, vars) {
|
|
331
|
+
if (!vars)
|
|
332
|
+
return text;
|
|
333
|
+
return text.replace(/\{([A-Za-z][A-Za-z0-9_]{0,30})\}/g, (m, name) => Object.prototype.hasOwnProperty.call(vars, name) ? String(vars[name]) : m);
|
|
334
|
+
}
|
|
315
335
|
var utf8Bytes = (s) => new TextEncoder().encode(s).byteLength;
|
|
316
336
|
function jsonBytes(value) {
|
|
317
337
|
try {
|
|
@@ -482,12 +502,13 @@ function decodeLaunchToken(token) {
|
|
|
482
502
|
}
|
|
483
503
|
if (!isObj2(c))
|
|
484
504
|
return null;
|
|
485
|
-
const { run, seed, lang, sub, game, version, exp } = c;
|
|
505
|
+
const { run, seed, lang, sub, game, version, exp, variant, step } = c;
|
|
486
506
|
if (typeof run !== "string" || typeof sub !== "string" || typeof game !== "string" || typeof version !== "string" || typeof lang !== "string")
|
|
487
507
|
return null;
|
|
488
508
|
if (typeof seed !== "number" || !Number.isSafeInteger(seed) || typeof exp !== "number")
|
|
489
509
|
return null;
|
|
490
|
-
|
|
510
|
+
const name = (v) => typeof v === "string" && /^[a-z0-9][a-z0-9-]{0,39}$/.test(v) ? v : null;
|
|
511
|
+
return { runId: run, seed, lang, sub, game, version, expiresAt: exp * 1000, variant: name(variant), step: name(step) };
|
|
491
512
|
}
|
|
492
513
|
var PRE_READY_ENTRIES = 20;
|
|
493
514
|
function createCollector(opts) {
|
|
@@ -729,6 +750,7 @@ function createBridge(opts = {}) {
|
|
|
729
750
|
let readyPromise = null;
|
|
730
751
|
let launchInfo = null;
|
|
731
752
|
let token = "";
|
|
753
|
+
let texts = {};
|
|
732
754
|
let transport = "proxy";
|
|
733
755
|
let finished = false;
|
|
734
756
|
let tracked = 0;
|
|
@@ -930,6 +952,9 @@ function createBridge(opts = {}) {
|
|
|
930
952
|
}
|
|
931
953
|
}
|
|
932
954
|
const bridge = {
|
|
955
|
+
t(key, vars) {
|
|
956
|
+
return fillText(texts[key] ?? key, vars);
|
|
957
|
+
},
|
|
933
958
|
ready() {
|
|
934
959
|
if (readyPromise)
|
|
935
960
|
return readyPromise;
|
|
@@ -940,6 +965,7 @@ function createBridge(opts = {}) {
|
|
|
940
965
|
throw new BridgeError("bad_launch", "The host sent no valid launch token.");
|
|
941
966
|
token = p.token;
|
|
942
967
|
transport = p.transport === "host" ? "host" : "proxy";
|
|
968
|
+
texts = readGameTexts(p.texts);
|
|
943
969
|
launchInfo = info;
|
|
944
970
|
if (vitals && !vitals.session) {
|
|
945
971
|
const readyMs = perf?.sinceLoad();
|
|
@@ -1044,4 +1070,4 @@ function createBridge(opts = {}) {
|
|
|
1044
1070
|
};
|
|
1045
1071
|
return bridge;
|
|
1046
1072
|
}
|
|
1047
|
-
export { BRIDGE_VERSION, BridgeError, DEFAULT_HOST_ORIGINS, DEVICE_CLASSES, DIAG_BODY_MAX_BYTES, DIAG_LIMITS, END_REASONS, ERROR_SOURCES, FINGERPRINT_FRAMES, HOST_EVENTS, HOST_EVENT_TEXT, HOST_HANG_MS, HOST_READY_TIMEOUT_MS, JANK_FRAME_MS, LOG_LEVELS, MAX_MESSAGE_BYTES, MAX_TOKEN_LENGTH, OS_NAMES, PERF_RANGES, PRE_READY_ENTRIES, PROTOCOL, PROTOCOL_VERSION, PROXY_ORIGIN, STORAGE_KEY, STORAGE_MAX_BYTES, TRACK_EVENT, TRACK_MAX_PROPS, TRACK_MAX_STRING, TRACK_PER_LAUNCH, TRACK_PROP_KEY, boundData, cleanDiagnosticEntry, createBridge, createCollector, createHostWatchdog, createPerfSampler, decodeLaunchToken, fingerprint, fingerprintInput, finishProblem, frameKey, isCrashEntry, isFatalSource, isHostEvent, isJsonValue, isLogLevel, jsonBytes, launchContextProblem, normaliseContext, normaliseMessage, parseDiagnosticsBatch, parseGameRequest, parseHostMessage, parseStack, scrubData, scrubText, sessionIdOf, sha256HexOf, shortenGameUrls, storageKeyProblem, trackProblem, utf8Bytes };
|
|
1073
|
+
export { BRIDGE_VERSION, BridgeError, DEFAULT_HOST_ORIGINS, DEVICE_CLASSES, DIAG_BODY_MAX_BYTES, DIAG_LIMITS, END_REASONS, ERROR_SOURCES, FINGERPRINT_FRAMES, HOST_EVENTS, HOST_EVENT_TEXT, HOST_HANG_MS, HOST_READY_TIMEOUT_MS, JANK_FRAME_MS, LOG_LEVELS, MAX_MESSAGE_BYTES, MAX_TOKEN_LENGTH, OS_NAMES, PERF_RANGES, PRE_READY_ENTRIES, PROTOCOL, PROTOCOL_VERSION, PROXY_ORIGIN, STORAGE_KEY, STORAGE_MAX_BYTES, TRACK_EVENT, TRACK_MAX_PROPS, TRACK_MAX_STRING, TRACK_PER_LAUNCH, TRACK_PROP_KEY, boundData, cleanDiagnosticEntry, createBridge, createCollector, createHostWatchdog, createPerfSampler, decodeLaunchToken, fillText, fingerprint, fingerprintInput, finishProblem, frameKey, isCrashEntry, isFatalSource, isHostEvent, isJsonValue, isLogLevel, jsonBytes, launchContextProblem, normaliseContext, normaliseMessage, parseDiagnosticsBatch, parseGameRequest, parseHostMessage, parseStack, readGameTexts, scrubData, scrubText, sessionIdOf, sha256HexOf, shortenGameUrls, storageKeyProblem, trackProblem, utf8Bytes };
|