@spacemolt/lib 15.2.0 → 15.2.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/COMMANDS.md +1 -1
- package/dist/auth/clerk.d.ts +3 -1
- package/dist/generated/actions.gen.d.ts +1 -1
- package/dist/generated/openapi/types.gen.d.ts +10 -11
- package/dist/index.js +25 -1
- package/dist/index.js.map +33 -0
- package/dist/node.js +26 -0
- package/dist/node.js.map +12 -0
- package/package.json +7 -9
package/dist/node.js
CHANGED
|
@@ -6,6 +6,11 @@ import { dirname } from "node:path";
|
|
|
6
6
|
function isRecord(value) {
|
|
7
7
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
8
|
}
|
|
9
|
+
function requireRecord(value, source) {
|
|
10
|
+
if (!isRecord(value))
|
|
11
|
+
throw new TypeError(`${source} must be a JSON object`);
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
9
14
|
|
|
10
15
|
// src/auth/credentials.ts
|
|
11
16
|
function hasString(value, key) {
|
|
@@ -29,6 +34,24 @@ function isStoredAccount(value) {
|
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
class MemoryCredentialStore {
|
|
38
|
+
accounts = new Map;
|
|
39
|
+
list() {
|
|
40
|
+
return Promise.resolve([...this.accounts.values()]);
|
|
41
|
+
}
|
|
42
|
+
get(id) {
|
|
43
|
+
return Promise.resolve(this.accounts.get(id));
|
|
44
|
+
}
|
|
45
|
+
put(account) {
|
|
46
|
+
this.accounts.set(account.id, account);
|
|
47
|
+
return Promise.resolve();
|
|
48
|
+
}
|
|
49
|
+
remove(id) {
|
|
50
|
+
this.accounts.delete(id);
|
|
51
|
+
return Promise.resolve();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
32
55
|
// src/auth/file-store.ts
|
|
33
56
|
class FileCredentialStore {
|
|
34
57
|
path;
|
|
@@ -91,3 +114,6 @@ function isMissingFileError(error) {
|
|
|
91
114
|
export {
|
|
92
115
|
FileCredentialStore
|
|
93
116
|
};
|
|
117
|
+
|
|
118
|
+
//# debugId=120575AA408B48D964756E2164756E21
|
|
119
|
+
//# sourceMappingURL=node.js.map
|
package/dist/node.js.map
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/auth/file-store.ts", "../src/validation.ts", "../src/auth/credentials.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * File-backed credential store (Node / Bun).\n *\n * Persists accounts as JSON. Credentials are stored in plaintext — the same\n * tradeoff the CLI makes — so point it at a path your environment protects.\n * Imports Node built-ins; do not import this from browser bundles (use a\n * custom `CredentialStore` there instead).\n */\n\nimport { readFile, writeFile, rename, mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { isStoredAccount, type CredentialStore, type StoredAccount } from './credentials.ts';\nimport { isRecord } from '../validation.ts';\n\ninterface FileShape {\n version: 1;\n accounts: Record<string, StoredAccount>;\n}\n\nexport class FileCredentialStore implements CredentialStore {\n private cache: Record<string, StoredAccount> | null = null;\n\n constructor(private readonly path: string) {}\n\n private async load(): Promise<Record<string, StoredAccount>> {\n if (this.cache) return this.cache;\n try {\n const raw = await readFile(this.path, 'utf-8');\n const parsed: unknown = JSON.parse(raw);\n if (!isRecord(parsed) || parsed.version !== 1 || !isRecord(parsed.accounts)) {\n throw new Error(`Invalid credential store format in ${this.path}`);\n }\n const accounts: Record<string, StoredAccount> = {};\n for (const [id, account] of Object.entries(parsed.accounts)) {\n if (!isStoredAccount(account) || account.id !== id) {\n throw new Error(`Invalid account ${JSON.stringify(id)} in credential store ${this.path}`);\n }\n accounts[id] = account;\n }\n this.cache = accounts;\n } catch (error) {\n if (isMissingFileError(error)) this.cache = {};\n else throw error;\n }\n return this.cache;\n }\n\n private async save(): Promise<void> {\n const data: FileShape = { version: 1, accounts: this.cache ?? {} };\n await mkdir(dirname(this.path), { recursive: true });\n // Atomic write: temp file + rename, so a crash can't truncate the store.\n const tmp = `${this.path}.tmp-${process.pid}`;\n await writeFile(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });\n await rename(tmp, this.path);\n }\n\n async list(): Promise<StoredAccount[]> {\n return Object.values(await this.load());\n }\n async get(id: string): Promise<StoredAccount | undefined> {\n return (await this.load())[id];\n }\n async put(account: StoredAccount): Promise<void> {\n const accounts = await this.load();\n accounts[account.id] = account;\n await this.save();\n }\n async remove(id: string): Promise<void> {\n const accounts = await this.load();\n delete accounts[id];\n await this.save();\n }\n}\n\nfunction isMissingFileError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error && error.code === 'ENOENT';\n}\n",
|
|
6
|
+
"/** True when a value is a non-null, non-array object with string keys. */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Require an object at an external-data boundary and include its source in failures. */\nexport function requireRecord(value: unknown, source: string): Record<string, unknown> {\n if (!isRecord(value)) throw new TypeError(`${source} must be a JSON object`);\n return value;\n}\n",
|
|
7
|
+
"/**\n * Pluggable credential storage for multi-account use.\n *\n * The `CredentialStore` interface is the only persistence seam in the library;\n * swap the implementation to control where credentials live (memory, a file,\n * the browser, a secrets manager, …). The core never imports Node built-ins —\n * the file-backed store does, and lives here in `src/auth/` for that reason.\n */\n\nimport { isRecord } from '../validation.ts';\n\n/**\n * How an account authenticates. Raw credentials (login / login_token / register)\n * plus `clerk`: a Clerk API key + the owned player's id, from which the account\n * mints a fresh single-use WS token on each (re)connect (see `src/auth/clerk.ts`).\n */\nexport type AuthCredentials =\n | { kind: 'login'; username: string; password: string }\n | { kind: 'login_token'; token: string }\n | { kind: 'clerk'; apiKey: string; playerId: string; httpBaseUrl: string }\n | { kind: 'register'; username: string; empire: string; registration_code?: string };\n\nexport interface StoredAccount {\n /** Stable handle for this account within the client (e.g. the username). */\n id: string;\n credentials: AuthCredentials;\n /** Filled in after a successful auth. */\n playerId?: string;\n}\n\nexport interface CredentialStore {\n list(): Promise<StoredAccount[]>;\n get(id: string): Promise<StoredAccount | undefined>;\n put(account: StoredAccount): Promise<void>;\n remove(id: string): Promise<void>;\n}\n\nfunction hasString(value: Record<string, unknown>, key: string): boolean {\n return typeof value[key] === 'string';\n}\n\nexport function isStoredAccount(value: unknown): value is StoredAccount {\n if (!isRecord(value) || !hasString(value, 'id') || !isRecord(value.credentials)) return false;\n const credentials = value.credentials;\n switch (credentials.kind) {\n case 'login':\n return hasString(credentials, 'username') && hasString(credentials, 'password');\n case 'login_token':\n return hasString(credentials, 'token');\n case 'clerk':\n return (\n hasString(credentials, 'apiKey') && hasString(credentials, 'playerId') && hasString(credentials, 'httpBaseUrl')\n );\n case 'register':\n return (\n hasString(credentials, 'username') &&\n hasString(credentials, 'empire') &&\n (credentials.registration_code === undefined || typeof credentials.registration_code === 'string')\n );\n default:\n return false;\n }\n}\n\n/** In-memory store. The default; nothing is persisted across process restarts. */\nexport class MemoryCredentialStore implements CredentialStore {\n private readonly accounts = new Map<string, StoredAccount>();\n\n list(): Promise<StoredAccount[]> {\n return Promise.resolve([...this.accounts.values()]);\n }\n get(id: string): Promise<StoredAccount | undefined> {\n return Promise.resolve(this.accounts.get(id));\n }\n put(account: StoredAccount): Promise<void> {\n this.accounts.set(account.id, account);\n return Promise.resolve();\n }\n remove(id: string): Promise<void> {\n this.accounts.delete(id);\n return Promise.resolve();\n }\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "120575AA408B48D964756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spacemolt/lib",
|
|
3
|
-
"version": "15.2.
|
|
3
|
+
"version": "15.2.1",
|
|
4
4
|
"description": "The definitive TypeScript library for SpaceMolt. WebSocket-v2-first, multi-account, with local state caches. Internals are regenerated from the server's OpenAPI spec.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"module": "./dist/index.js",
|
|
7
6
|
"types": "./dist/index.d.ts",
|
|
8
7
|
"exports": {
|
|
9
8
|
".": {
|
|
@@ -25,16 +24,17 @@
|
|
|
25
24
|
"fetch-spec": "bun run scripts/fetch-spec.ts",
|
|
26
25
|
"generate": "bun run openapi-ts && bun run scripts/generate.ts",
|
|
27
26
|
"generate:check": "bun run scripts/check-generated.ts",
|
|
28
|
-
"check": "bun run format:check && bun run lint && bun run generate:check && bun run typecheck && bun test && bun run build:browser-check && bun run build && bun run build:smoke",
|
|
27
|
+
"check": "bun run format:check && bun run lint && bun run generate:check && bun run typecheck && bun test && bun run build:browser-check && bun run build && bun run build:smoke && bun run check:consumer",
|
|
29
28
|
"format": "biome format --write .",
|
|
30
29
|
"format:check": "biome format .",
|
|
31
30
|
"lint": "biome lint .",
|
|
32
31
|
"typecheck": "bun x tsc --noEmit",
|
|
33
|
-
"
|
|
34
|
-
"build": "rm -rf dist && bun build src/index.ts --outfile dist/index.js --target node --format esm && bun build src/node.ts --outfile dist/node.js --target node --format esm && bun x tsc -p tsconfig.build.json && bun run scripts/fix-dts-extensions.ts",
|
|
32
|
+
"build": "rm -rf dist && bun build src/index.ts src/node.ts --outdir dist --target node --format esm --sourcemap=linked && bun x tsc -p tsconfig.build.json && bun run scripts/fix-dts-extensions.ts",
|
|
35
33
|
"build:smoke": "node scripts/check-build.mjs",
|
|
36
34
|
"build:browser-check": "bun run scripts/check-browser-build.ts",
|
|
37
|
-
"test": "bun test"
|
|
35
|
+
"test": "bun test",
|
|
36
|
+
"prepack": "bun run build",
|
|
37
|
+
"check:consumer": "bun run scripts/check-consumer.ts"
|
|
38
38
|
},
|
|
39
39
|
"repository": {
|
|
40
40
|
"type": "git",
|
|
@@ -52,9 +52,7 @@
|
|
|
52
52
|
"@biomejs/biome": "^2.5.3",
|
|
53
53
|
"@hey-api/openapi-ts": "^0.73.0",
|
|
54
54
|
"@types/bun": "^1.3.9",
|
|
55
|
+
"@types/node": "^22",
|
|
55
56
|
"typescript": "^5.9.3"
|
|
56
|
-
},
|
|
57
|
-
"peerDependencies": {
|
|
58
|
-
"typescript": "^5.5"
|
|
59
57
|
}
|
|
60
58
|
}
|