scorezilla 0.1.0-next.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.
- package/API.md +305 -0
- package/CHANGELOG.md +24 -0
- package/COMPATIBILITY.md +170 -0
- package/LICENSE +21 -0
- package/README.md +212 -0
- package/VERSIONING.md +119 -0
- package/dist/index.cjs +686 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +557 -0
- package/dist/index.d.ts +557 -0
- package/dist/index.js +680 -0
- package/dist/index.js.map +1 -0
- package/dist/phaser.cjs +6 -0
- package/dist/phaser.cjs.map +1 -0
- package/dist/phaser.d.cts +2 -0
- package/dist/phaser.d.ts +2 -0
- package/dist/phaser.js +4 -0
- package/dist/phaser.js.map +1 -0
- package/dist/react.cjs +6 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +2 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +4 -0
- package/dist/react.js.map +1 -0
- package/dist/server-browser-stub.cjs +8 -0
- package/dist/server-browser-stub.cjs.map +1 -0
- package/dist/server-browser-stub.d.cts +2 -0
- package/dist/server-browser-stub.d.ts +2 -0
- package/dist/server-browser-stub.js +6 -0
- package/dist/server-browser-stub.js.map +1 -0
- package/dist/server.cjs +8 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +2 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +6 -0
- package/dist/server.js.map +1 -0
- package/package.json +142 -0
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# scorezilla
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/scorezilla)
|
|
4
|
+
[](https://bundlephobia.com/package/scorezilla)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](https://github.com/isco-tec/scorezilla-js/actions)
|
|
7
|
+
[](https://docs.npmjs.com/generating-provenance-statements)
|
|
8
|
+
|
|
9
|
+
Official JavaScript / TypeScript SDK for [Scorezilla](https://scorezilla.dev) —
|
|
10
|
+
focused leaderboard infrastructure for indie games, browser games, and
|
|
11
|
+
AI-vibe-coded games.
|
|
12
|
+
|
|
13
|
+
- **Tiny.** ~4 KB gzipped. No runtime dependencies.
|
|
14
|
+
- **Universal.** Browser, Node ≥ 20, Cloudflare Workers, Bun, Deno.
|
|
15
|
+
- **Typed.** First-class TypeScript with strict types and rich JSDoc.
|
|
16
|
+
- **Safe-by-default.** Automatic retries on transient failures with idempotency
|
|
17
|
+
keys; per-request timeouts; cancellation via `AbortSignal`.
|
|
18
|
+
- **Private.** No cookies, no `localStorage`, no fingerprinting beyond runtime
|
|
19
|
+
detection — see [COMPATIBILITY.md](./COMPATIBILITY.md).
|
|
20
|
+
|
|
21
|
+
> **Status:** v0.1.0 ships the **public-key client** (browser-safe). The HMAC
|
|
22
|
+
> server adapter (`scorezilla/server`) lands in v0.2.0; React
|
|
23
|
+
> (`scorezilla/react`) in v0.3.0; Phaser (`scorezilla/phaser`) in v0.4.0. See
|
|
24
|
+
> [CHANGELOG.md](./CHANGELOG.md) and [VERSIONING.md](./VERSIONING.md).
|
|
25
|
+
|
|
26
|
+
> **Commercial context.** Scorezilla is a hosted leaderboard service with free
|
|
27
|
+
> and paid tiers — see [scorezilla.dev/pricing](https://scorezilla.dev/pricing).
|
|
28
|
+
> This SDK is MIT-licensed and works identically across every plan; get your API
|
|
29
|
+
> key from the [operator dashboard](https://dashboard.scorezilla.dev).
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install scorezilla
|
|
35
|
+
# or
|
|
36
|
+
pnpm add scorezilla
|
|
37
|
+
# or
|
|
38
|
+
yarn add scorezilla
|
|
39
|
+
# or
|
|
40
|
+
bun add scorezilla
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quickstart
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { Scorezilla, ScorezillaError } from 'scorezilla';
|
|
47
|
+
|
|
48
|
+
const sz = new Scorezilla({ publicKey: 'pk_mygame_aBcDeF…' });
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const r = await sz.submitScore({
|
|
52
|
+
boardId: 'board-uuid',
|
|
53
|
+
playerId: 'player-uuid',
|
|
54
|
+
score: 9001,
|
|
55
|
+
metadata: { level: 'hard' },
|
|
56
|
+
});
|
|
57
|
+
if (r.isPersonalBest) {
|
|
58
|
+
console.log(`🏆 New personal best! Rank ${r.rank} of ${r.totalEntries}`);
|
|
59
|
+
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
if (e instanceof ScorezillaError && e.isRateLimited()) {
|
|
62
|
+
console.warn(`Rate-limited. Retry after ${e.retryAfter}s.`);
|
|
63
|
+
} else throw e;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The four public methods:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
await sz.submitScore({ boardId, playerId, score, metadata? });
|
|
71
|
+
await sz.getLeaderboard({ boardId, top?, offset? });
|
|
72
|
+
await sz.getPlayerRank({ boardId, playerId });
|
|
73
|
+
await sz.getWindowAround({ boardId, playerId, before?, after? });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
See [**API.md**](./API.md) for the full reference, including every response
|
|
77
|
+
field, every error code, and advanced patterns.
|
|
78
|
+
|
|
79
|
+
## Error handling
|
|
80
|
+
|
|
81
|
+
Every failure path — HTTP non-2xx, network error, timeout, abort, JSON parse
|
|
82
|
+
error — throws a single `ScorezillaError`. **Branch on `code`**
|
|
83
|
+
(machine-stable), never on `message` (English-only, may change without a major
|
|
84
|
+
bump):
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { ScorezillaError } from 'scorezilla';
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
await sz.submitScore({ boardId, playerId, score });
|
|
91
|
+
} catch (e) {
|
|
92
|
+
if (!(e instanceof ScorezillaError)) throw e;
|
|
93
|
+
|
|
94
|
+
if (e.isRateLimited()) await sleep((e.retryAfter ?? 30) * 1000);
|
|
95
|
+
else if (e.isAuth()) throw new Error('SDK misconfigured');
|
|
96
|
+
else if (e.code === 'out_of_bounds')
|
|
97
|
+
console.warn(`Score crosses ${e.reason} bound (limit ${e.bound})`);
|
|
98
|
+
else if (e.isTransient()) /* automatic retries already exhausted */ throw e;
|
|
99
|
+
else throw e;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The error class carries the request ID, status, and the underlying cause for
|
|
104
|
+
support tickets:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
console.error(`Scorezilla ${e.code} (${e.status}) — req ${e.requestId}`);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Runtime support
|
|
111
|
+
|
|
112
|
+
| Runtime | Status | Notes |
|
|
113
|
+
| ---------------------- | ----------------------------- | ------------------------------------------------------- |
|
|
114
|
+
| **Node** | ≥ 20 | Hard requirement. Native `fetch` + `crypto.randomUUID`. |
|
|
115
|
+
| **Browsers** | All evergreen | Chrome 92+, Firefox 95+, Safari 15.4+, Edge 92+. |
|
|
116
|
+
| **Cloudflare Workers** | ✅ | Detected via `navigator.userAgent`. |
|
|
117
|
+
| **Bun** | ≥ 1.0 (best-effort in v0.1.0) | Promoted to hard gate in v0.2.0 if stable. |
|
|
118
|
+
| **Deno** | ≥ 1.40 | Native fetch + Web Crypto. |
|
|
119
|
+
| **React Native** | unverified | Requires `react-native-get-random-values` polyfill. |
|
|
120
|
+
|
|
121
|
+
See [COMPATIBILITY.md](./COMPATIBILITY.md) for the detailed matrix, the
|
|
122
|
+
`exactOptionalPropertyTypes` workaround, and the privacy invariants.
|
|
123
|
+
|
|
124
|
+
## CDN usage
|
|
125
|
+
|
|
126
|
+
For zero-build prototyping, import from jsDelivr. Replace `<VERSION>` with the
|
|
127
|
+
exact release you want (see the [releases page](https://github.com/isco-tec/scorezilla-js/releases)):
|
|
128
|
+
|
|
129
|
+
```html
|
|
130
|
+
<script type="module">
|
|
131
|
+
import { Scorezilla } from 'https://cdn.jsdelivr.net/npm/scorezilla@<VERSION>/dist/index.js';
|
|
132
|
+
const sz = new Scorezilla({ publicKey: 'pk_…' });
|
|
133
|
+
// …
|
|
134
|
+
</script>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
For production, pair the version pin with
|
|
138
|
+
[Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)
|
|
139
|
+
— the SHA-384 hash for each release ships in the GitHub release notes:
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<script
|
|
143
|
+
type="module"
|
|
144
|
+
src="https://cdn.jsdelivr.net/npm/scorezilla@<VERSION>/dist/index.js"
|
|
145
|
+
integrity="sha384-<copy-from-release-notes>"
|
|
146
|
+
crossorigin="anonymous"
|
|
147
|
+
></script>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
A complete vanilla example lives at
|
|
151
|
+
[`examples/vanilla/`](https://github.com/isco-tec/scorezilla-js/tree/main/examples/vanilla)
|
|
152
|
+
and a Node CLI demo at
|
|
153
|
+
[`examples/node-cli/`](https://github.com/isco-tec/scorezilla-js/tree/main/examples/node-cli).
|
|
154
|
+
(The examples are in the source repo only — not in the npm tarball.)
|
|
155
|
+
|
|
156
|
+
## Custom fetch / polyfills
|
|
157
|
+
|
|
158
|
+
Pass your own `fetch` for environments where the global is missing or you want
|
|
159
|
+
to mock for tests:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import nodeFetch from 'node-fetch';
|
|
163
|
+
const sz = new Scorezilla({ publicKey, fetch: nodeFetch });
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The signature
|
|
167
|
+
`(input: RequestInfo | URL, init?: RequestInit) => Promise<Response>` is
|
|
168
|
+
intentionally broader than `typeof fetch` so `node-fetch`, `undici`, `vi.fn()`,
|
|
169
|
+
and `jest.fn()` all typecheck cleanly.
|
|
170
|
+
|
|
171
|
+
## Per-request timeout and retries
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
const sz = new Scorezilla({
|
|
175
|
+
publicKey,
|
|
176
|
+
timeoutMs: 5_000, // default 30_000
|
|
177
|
+
maxRetries: 1, // default 2 (retries 5xx / 429 / network)
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Retries automatically reuse the same `Idempotency-Key` across attempts, so
|
|
182
|
+
server-side dedup (when added) is safe by default.
|
|
183
|
+
|
|
184
|
+
## Versioning
|
|
185
|
+
|
|
186
|
+
Strict SemVer from v0.1.0 onward. The machine-stable surface is `code` strings
|
|
187
|
+
on `ScorezillaError`, response field names, method signatures, and config
|
|
188
|
+
fields. The human-readable `message` is **not** part of the contract.
|
|
189
|
+
|
|
190
|
+
See [VERSIONING.md](./VERSIONING.md) for the full breaking-change rules,
|
|
191
|
+
deprecation policy, and 0.x → 1.0 exit criteria.
|
|
192
|
+
|
|
193
|
+
## Contributing
|
|
194
|
+
|
|
195
|
+
Issues and PRs welcome. Local development:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pnpm install
|
|
199
|
+
pnpm typecheck
|
|
200
|
+
pnpm test # all projects
|
|
201
|
+
pnpm test:unit # unit only (fast)
|
|
202
|
+
pnpm test:coverage # unit + coverage gate
|
|
203
|
+
pnpm build # tsup → dist/
|
|
204
|
+
pnpm check:types-resolution # attw — exports map validation
|
|
205
|
+
pnpm size # size-limit (6 KB gzip ceiling)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Add a release note with `pnpm changeset` — see [`.changeset/README.md`](./.changeset/README.md) for the workflow.
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
[MIT](./LICENSE) © [isco-tec](https://github.com/isco-tec)
|
package/VERSIONING.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Versioning policy
|
|
2
|
+
|
|
3
|
+
Scorezilla follows [Semantic Versioning](https://semver.org/) starting at
|
|
4
|
+
**v0.1.0**. This document defines what counts as a breaking change, what the
|
|
5
|
+
SemVer contract covers (and explicitly does NOT cover), and the path to v1.0.
|
|
6
|
+
|
|
7
|
+
## The SemVer contract
|
|
8
|
+
|
|
9
|
+
### Covered by SemVer
|
|
10
|
+
|
|
11
|
+
**Machine-stable.** A change to any of these requires a major version bump.
|
|
12
|
+
|
|
13
|
+
| What | Where | Example |
|
|
14
|
+
| -------------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
15
|
+
| **Method names** | `Scorezilla.*` | Renaming `submitScore` → `postScore` is a major bump. |
|
|
16
|
+
| **Method signatures (required args, return type)** | `Scorezilla.*` | Adding a required parameter is a major bump. Tightening a return type (`number` → `1 \| 2 \| 3`) is a major bump. |
|
|
17
|
+
| **Error codes** | `ScorezillaError.code` | Renaming `out_of_bounds` → `score_out_of_range` is a major bump. Removing a code is a major bump. |
|
|
18
|
+
| **Error sub-fields** | `ScorezillaError.{reason, retryAfter, bound, layer, status, requestId}` | Renaming `retryAfter` → `retryAfterSec` is a major bump. |
|
|
19
|
+
| **Config field names** | `ScorezillaConfig.*` | Renaming `baseUrl` → `apiOrigin` is a major bump. |
|
|
20
|
+
| **Auth mode discriminator** | `publicKey` vs `secretKey` | Adding a third top-level auth field is non-breaking; renaming either is a major bump. |
|
|
21
|
+
| **Type exports** | `import type { … } from 'scorezilla'` | Removing or renaming a type export is a major bump. |
|
|
22
|
+
| **Default behavior of optional knobs** | `timeoutMs`, `maxRetries`, retry windows | Changing the default of `timeoutMs` from 30 000 to 5 000 is a major bump. |
|
|
23
|
+
|
|
24
|
+
### NOT covered by SemVer
|
|
25
|
+
|
|
26
|
+
**English-flavored and free to change.**
|
|
27
|
+
|
|
28
|
+
| What | Where | Why |
|
|
29
|
+
| ---------------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
30
|
+
| **`message` text on errors** | `ScorezillaError.message` | English-only operator hint. Branch on `code` and `reason` instead. |
|
|
31
|
+
| **Error stack format** | `ScorezillaError.stack` | V8 / SpiderMonkey / JavaScriptCore each format differently and update across runtime versions. |
|
|
32
|
+
| **Whitespace / casing in `User-Agent`** | Header value | Cosmetic. |
|
|
33
|
+
| **Internal module layout** | `src/*` | Not part of the public surface. Importing from anywhere other than `'scorezilla'` (or its documented subpaths `'scorezilla/server'` / `'scorezilla/react'` / `'scorezilla/phaser'`) is unsupported. |
|
|
34
|
+
| **Server-side response field additions** | New fields on `*Response` shapes | Response types are open `Record`-friendly — the API may add fields in a minor release without breaking consumers who don't read them. |
|
|
35
|
+
|
|
36
|
+
## What counts as a breaking change
|
|
37
|
+
|
|
38
|
+
### Breaking (major bump)
|
|
39
|
+
|
|
40
|
+
- Removing or renaming an exported symbol (class, function, type)
|
|
41
|
+
- Removing a method on `Scorezilla`
|
|
42
|
+
- Removing a field on a published response type
|
|
43
|
+
- Renaming or removing an error code
|
|
44
|
+
- Adding a **required** argument to a method
|
|
45
|
+
- Narrowing a return type (e.g., `number | undefined` → `number`)
|
|
46
|
+
- Changing the default value of an optional knob in a user-visible way
|
|
47
|
+
- Tightening runtime validation that used to accept some input
|
|
48
|
+
- Dropping support for a documented runtime (e.g., Node 20)
|
|
49
|
+
|
|
50
|
+
### Non-breaking (minor or patch bump)
|
|
51
|
+
|
|
52
|
+
- Adding a new method
|
|
53
|
+
- Adding a new optional argument with a backward-compatible default
|
|
54
|
+
- Adding a new error code that the server already returns
|
|
55
|
+
- Adding a new field on a response type
|
|
56
|
+
- Bug fixes that align behavior with the documented contract
|
|
57
|
+
- Performance / bundle-size improvements
|
|
58
|
+
- New exported type that doesn't replace an existing one
|
|
59
|
+
- New subpath export (e.g., adding `scorezilla/server` in v0.2.0)
|
|
60
|
+
|
|
61
|
+
### Patch-bump only
|
|
62
|
+
|
|
63
|
+
- Documentation updates
|
|
64
|
+
- Internal refactors that don't change observable behavior
|
|
65
|
+
- Dependency version bumps within `peerDependencies` semver ranges
|
|
66
|
+
|
|
67
|
+
## Deprecation policy
|
|
68
|
+
|
|
69
|
+
When we need to remove or replace a public symbol:
|
|
70
|
+
|
|
71
|
+
1. **Mark deprecated.** Add `@deprecated` JSDoc on the symbol with:
|
|
72
|
+
- The version it was deprecated (`@deprecated 0.5.0`)
|
|
73
|
+
- The version it will be removed (`will be removed in 1.0.0`)
|
|
74
|
+
- The replacement, if any
|
|
75
|
+
2. **Runtime warning.** First call site emits a single `console.warn`:
|
|
76
|
+
```
|
|
77
|
+
scorezilla: `oldMethod` is deprecated since 0.5.0 and will be removed in 1.0.0. Use `newMethod` instead.
|
|
78
|
+
```
|
|
79
|
+
Suppressible via `SCOREZILLA_SUPPRESS_DEPRECATION_WARNINGS=1` env or the
|
|
80
|
+
`suppressDeprecationWarnings: true` config field.
|
|
81
|
+
3. **Minimum window.** A symbol must spend at least **one full minor release**
|
|
82
|
+
in the deprecated state before removal in the next major. This gives
|
|
83
|
+
consumers a guaranteed upgrade path without forced churn.
|
|
84
|
+
4. **CHANGELOG entry.** Both the deprecation and the removal are explicitly
|
|
85
|
+
called out.
|
|
86
|
+
|
|
87
|
+
## 0.x → 1.0 exit criteria
|
|
88
|
+
|
|
89
|
+
The SDK stays in `0.x` until ALL of the following are true:
|
|
90
|
+
|
|
91
|
+
- [ ] 30 days have passed on `main` without a breaking change to the core
|
|
92
|
+
surface (the `Scorezilla` class + `ScorezillaError` + `ScorezillaConfig`).
|
|
93
|
+
- [ ] **`scorezilla/server`** (HMAC adapter, v0.2.0) has shipped and seen
|
|
94
|
+
production use.
|
|
95
|
+
- [ ] **`scorezilla/react`** (React adapter, v0.3.0) has shipped and seen
|
|
96
|
+
production use.
|
|
97
|
+
- [ ] Zero open issues tagged `api-shape-drift` from real-world consumers.
|
|
98
|
+
- [ ] The 4-method surface (`submitScore`, `getLeaderboard`, `getPlayerRank`,
|
|
99
|
+
`getWindowAround`) has not had a signature change for the same 30-day
|
|
100
|
+
window.
|
|
101
|
+
|
|
102
|
+
When all five are met, we cut **v1.0.0** with no breaking changes from the last
|
|
103
|
+
0.x — v1.0 is just "this is the surface we commit to." Subsequent breaking
|
|
104
|
+
changes follow normal SemVer (major bump).
|
|
105
|
+
|
|
106
|
+
## Pre-release tags
|
|
107
|
+
|
|
108
|
+
| Tag | Meaning |
|
|
109
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
110
|
+
| `latest` | Stable, recommended for production. |
|
|
111
|
+
| `next` | Release candidate. Installable via `npm install scorezilla@next`. |
|
|
112
|
+
| `experimental` | Alpha features behind a flag. May break without notice between releases. Not covered by the SemVer contract. |
|
|
113
|
+
|
|
114
|
+
## Reporting drift
|
|
115
|
+
|
|
116
|
+
If you encounter behavior that contradicts this document — e.g., a `code` value
|
|
117
|
+
changed across a minor release — please file an issue at
|
|
118
|
+
<https://github.com/isco-tec/scorezilla-js/issues> with the tag
|
|
119
|
+
`api-shape-drift`. These reports gate the 1.0 cut.
|