@oasisomniverse/web5-api 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.
- package/README.md +250 -0
- package/docs/README.md +44 -0
- package/docs/modules/Avatar.md +606 -0
- package/docs/modules/CelestialBodies.md +1051 -0
- package/docs/modules/CelestialBodiesMetaData.md +949 -0
- package/docs/modules/CelestialSpaces.md +1051 -0
- package/docs/modules/Chapters.md +955 -0
- package/docs/modules/Competition.md +594 -0
- package/docs/modules/Cosmic.md +3653 -0
- package/docs/modules/Games.md +2619 -0
- package/docs/modules/GeoHotSpots.md +1027 -0
- package/docs/modules/GeoNFTs.md +1049 -0
- package/docs/modules/Health.md +90 -0
- package/docs/modules/Holons.md +1139 -0
- package/docs/modules/HolonsMetaData.md +949 -0
- package/docs/modules/InventoryItems.md +1071 -0
- package/docs/modules/Libraries.md +1052 -0
- package/docs/modules/Missions.md +1286 -0
- package/docs/modules/NFTs.md +1008 -0
- package/docs/modules/OAPPs.md +1190 -0
- package/docs/modules/Parks.md +1079 -0
- package/docs/modules/Plugins.md +1138 -0
- package/docs/modules/Quests.md +1941 -0
- package/docs/modules/Runtimes.md +1112 -0
- package/docs/modules/STAR.md +178 -0
- package/docs/modules/Templates.md +990 -0
- package/docs/modules/Zomes.md +1049 -0
- package/docs/modules/ZomesMetaData.md +949 -0
- package/index.d.ts +97 -0
- package/index.js +3 -0
- package/index.mjs +4 -0
- package/package.json +117 -0
- package/src/core/httpClient.js +110 -0
- package/src/core/routeHelper.js +85 -0
- package/src/core/tokenStore.js +52 -0
- package/src/core/types.d.ts +18 -0
- package/src/index.js +60 -0
- package/src/modules/Auth.d.ts +15 -0
- package/src/modules/Auth.js +62 -0
- package/src/modules/Avatar.d.ts +45 -0
- package/src/modules/Avatar.js +47 -0
- package/src/modules/CelestialBodies.d.ts +72 -0
- package/src/modules/CelestialBodies.js +65 -0
- package/src/modules/CelestialBodiesMetaData.d.ts +69 -0
- package/src/modules/CelestialBodiesMetaData.js +61 -0
- package/src/modules/CelestialSpaces.d.ts +72 -0
- package/src/modules/CelestialSpaces.js +65 -0
- package/src/modules/Chapters.d.ts +66 -0
- package/src/modules/Chapters.js +61 -0
- package/src/modules/Competition.d.ts +33 -0
- package/src/modules/Competition.js +39 -0
- package/src/modules/Cosmic.d.ts +222 -0
- package/src/modules/Cosmic.js +165 -0
- package/src/modules/Games.d.ts +171 -0
- package/src/modules/Games.js +131 -0
- package/src/modules/GeoHotSpots.d.ts +66 -0
- package/src/modules/GeoHotSpots.js +61 -0
- package/src/modules/GeoNFTs.d.ts +72 -0
- package/src/modules/GeoNFTs.js +65 -0
- package/src/modules/Health.d.ts +12 -0
- package/src/modules/Health.js +25 -0
- package/src/modules/Holons.d.ts +78 -0
- package/src/modules/Holons.js +69 -0
- package/src/modules/HolonsMetaData.d.ts +69 -0
- package/src/modules/HolonsMetaData.js +61 -0
- package/src/modules/InventoryItems.d.ts +69 -0
- package/src/modules/InventoryItems.js +63 -0
- package/src/modules/Libraries.d.ts +72 -0
- package/src/modules/Libraries.js +65 -0
- package/src/modules/Missions.d.ts +87 -0
- package/src/modules/Missions.js +75 -0
- package/src/modules/NFTs.d.ts +69 -0
- package/src/modules/NFTs.js +63 -0
- package/src/modules/OAPPs.d.ts +69 -0
- package/src/modules/OAPPs.js +61 -0
- package/src/modules/Parks.d.ts +72 -0
- package/src/modules/Parks.js +65 -0
- package/src/modules/Plugins.d.ts +78 -0
- package/src/modules/Plugins.js +69 -0
- package/src/modules/Quests.d.ts +129 -0
- package/src/modules/Quests.js +101 -0
- package/src/modules/Runtimes.d.ts +81 -0
- package/src/modules/Runtimes.js +69 -0
- package/src/modules/STAR.d.ts +18 -0
- package/src/modules/STAR.js +29 -0
- package/src/modules/Templates.d.ts +72 -0
- package/src/modules/Templates.js +63 -0
- package/src/modules/Zomes.d.ts +72 -0
- package/src/modules/Zomes.js +65 -0
- package/src/modules/ZomesMetaData.d.ts +69 -0
- package/src/modules/ZomesMetaData.js +61 -0
- package/src/modules/index.js +67 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-types.js - do not hand-edit.
|
|
2
|
+
import type { OASISResponse, OASISSession } from './src/core/types';
|
|
3
|
+
import type { AuthModule } from './src/modules/Auth';
|
|
4
|
+
import type { AvatarModule } from './src/modules/Avatar';
|
|
5
|
+
import type { CelestialBodiesModule } from './src/modules/CelestialBodies';
|
|
6
|
+
import type { CelestialBodiesMetaDataModule } from './src/modules/CelestialBodiesMetaData';
|
|
7
|
+
import type { CelestialSpacesModule } from './src/modules/CelestialSpaces';
|
|
8
|
+
import type { ChaptersModule } from './src/modules/Chapters';
|
|
9
|
+
import type { CompetitionModule } from './src/modules/Competition';
|
|
10
|
+
import type { CosmicModule } from './src/modules/Cosmic';
|
|
11
|
+
import type { GamesModule } from './src/modules/Games';
|
|
12
|
+
import type { GeoHotSpotsModule } from './src/modules/GeoHotSpots';
|
|
13
|
+
import type { GeoNFTsModule } from './src/modules/GeoNFTs';
|
|
14
|
+
import type { HealthModule } from './src/modules/Health';
|
|
15
|
+
import type { HolonsModule } from './src/modules/Holons';
|
|
16
|
+
import type { HolonsMetaDataModule } from './src/modules/HolonsMetaData';
|
|
17
|
+
import type { InventoryItemsModule } from './src/modules/InventoryItems';
|
|
18
|
+
import type { LibrariesModule } from './src/modules/Libraries';
|
|
19
|
+
import type { MissionsModule } from './src/modules/Missions';
|
|
20
|
+
import type { NFTsModule } from './src/modules/NFTs';
|
|
21
|
+
import type { OAPPsModule } from './src/modules/OAPPs';
|
|
22
|
+
import type { ParksModule } from './src/modules/Parks';
|
|
23
|
+
import type { PluginsModule } from './src/modules/Plugins';
|
|
24
|
+
import type { QuestsModule } from './src/modules/Quests';
|
|
25
|
+
import type { RuntimesModule } from './src/modules/Runtimes';
|
|
26
|
+
import type { STARModule } from './src/modules/STAR';
|
|
27
|
+
import type { TemplatesModule } from './src/modules/Templates';
|
|
28
|
+
import type { ZomesModule } from './src/modules/Zomes';
|
|
29
|
+
import type { ZomesMetaDataModule } from './src/modules/ZomesMetaData';
|
|
30
|
+
|
|
31
|
+
export type { OASISResponse, OASISSession };
|
|
32
|
+
|
|
33
|
+
export interface STARClientOptions {
|
|
34
|
+
baseUrl?: string;
|
|
35
|
+
persistSession?: boolean;
|
|
36
|
+
fetchImpl?: typeof fetch;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export declare class HttpClient {
|
|
40
|
+
constructor(options?: { baseUrl?: string; tokenStore?: unknown; fetchImpl?: typeof fetch });
|
|
41
|
+
setBaseUrl(baseUrl: string): void;
|
|
42
|
+
request(verb: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, options?: Record<string, any>): Promise<OASISResponse>;
|
|
43
|
+
get(path: string, options?: Record<string, any>): Promise<OASISResponse>;
|
|
44
|
+
post(path: string, options?: Record<string, any>): Promise<OASISResponse>;
|
|
45
|
+
put(path: string, options?: Record<string, any>): Promise<OASISResponse>;
|
|
46
|
+
delete(path: string, options?: Record<string, any>): Promise<OASISResponse>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export declare class TokenStore {
|
|
50
|
+
constructor(options?: { persist?: boolean });
|
|
51
|
+
getSession(): OASISSession | null;
|
|
52
|
+
getToken(): string | null;
|
|
53
|
+
setSession(session: OASISSession | null): void;
|
|
54
|
+
clear(): void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export declare const DEFAULT_BASE_URL: string;
|
|
58
|
+
|
|
59
|
+
export declare class STARClient {
|
|
60
|
+
constructor(options?: STARClientOptions);
|
|
61
|
+
readonly http: HttpClient;
|
|
62
|
+
readonly tokenStore: TokenStore;
|
|
63
|
+
readonly auth: AuthModule;
|
|
64
|
+
readonly avatar: AvatarModule;
|
|
65
|
+
readonly celestialBodies: CelestialBodiesModule;
|
|
66
|
+
readonly celestialBodiesMetaData: CelestialBodiesMetaDataModule;
|
|
67
|
+
readonly celestialSpaces: CelestialSpacesModule;
|
|
68
|
+
readonly chapters: ChaptersModule;
|
|
69
|
+
readonly competition: CompetitionModule;
|
|
70
|
+
readonly cosmic: CosmicModule;
|
|
71
|
+
readonly games: GamesModule;
|
|
72
|
+
readonly geoHotSpots: GeoHotSpotsModule;
|
|
73
|
+
readonly geoNFTs: GeoNFTsModule;
|
|
74
|
+
readonly health: HealthModule;
|
|
75
|
+
readonly holons: HolonsModule;
|
|
76
|
+
readonly holonsMetaData: HolonsMetaDataModule;
|
|
77
|
+
readonly inventoryItems: InventoryItemsModule;
|
|
78
|
+
readonly libraries: LibrariesModule;
|
|
79
|
+
readonly missions: MissionsModule;
|
|
80
|
+
readonly nFTs: NFTsModule;
|
|
81
|
+
readonly oAPPs: OAPPsModule;
|
|
82
|
+
readonly parks: ParksModule;
|
|
83
|
+
readonly plugins: PluginsModule;
|
|
84
|
+
readonly quests: QuestsModule;
|
|
85
|
+
readonly runtimes: RuntimesModule;
|
|
86
|
+
readonly sTAR: STARModule;
|
|
87
|
+
readonly templates: TemplatesModule;
|
|
88
|
+
readonly zomes: ZomesModule;
|
|
89
|
+
readonly zomesMetaData: ZomesMetaDataModule;
|
|
90
|
+
setBaseUrl(baseUrl: string): void;
|
|
91
|
+
setToken(jwtToken: string, sessionExtras?: Partial<OASISSession>): void;
|
|
92
|
+
starIgnite(args?: Record<string, any>): Promise<OASISResponse>;
|
|
93
|
+
starExtinguish(args?: Record<string, any>): Promise<OASISResponse>;
|
|
94
|
+
starStatus(args?: Record<string, any>): Promise<OASISResponse>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export default STARClient;
|
package/index.js
ADDED
package/index.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oasisomniverse/web5-api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"publishConfig": { "access": "public" },
|
|
5
|
+
"description": "Isomorphic (Node + browser) JavaScript/TypeScript-friendly client for the WEB5 STAR API - full coverage of the OASIS2 STAR WebAPI (OAPPs, Quests, Missions, Games, Celestial Bodies/Spaces, Cosmic hierarchy, NFTs, GeoNFTs, Plugins, Templates, Libraries, Runtimes, Competition/Leaderboards, and more).",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"module": "index.mjs",
|
|
8
|
+
"types": "index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./index.d.ts",
|
|
12
|
+
"import": "./index.mjs",
|
|
13
|
+
"require": "./index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=18"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"index.js",
|
|
21
|
+
"index.mjs",
|
|
22
|
+
"index.d.ts",
|
|
23
|
+
"src",
|
|
24
|
+
"docs"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"generate": "node scripts/generate-modules.js",
|
|
28
|
+
"docs": "node scripts/generate-docs.js",
|
|
29
|
+
"types": "node scripts/generate-types.js",
|
|
30
|
+
"test": "node --test test"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/NextGenSoftwareUK/OASIS-API-Javascript-Package-WEB5.git"
|
|
35
|
+
},
|
|
36
|
+
"author": "NextGen Software Ltd",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"keywords": [
|
|
39
|
+
"WEB5 STAR API",
|
|
40
|
+
"STAR ODK",
|
|
41
|
+
"STAR WebAPI",
|
|
42
|
+
"OAPPs",
|
|
43
|
+
"Quests",
|
|
44
|
+
"Missions",
|
|
45
|
+
"Games",
|
|
46
|
+
"Celestial Bodies",
|
|
47
|
+
"Celestial Spaces",
|
|
48
|
+
"Cosmic",
|
|
49
|
+
"Omniverse",
|
|
50
|
+
"Multiverse",
|
|
51
|
+
"Universe",
|
|
52
|
+
"Galaxy",
|
|
53
|
+
"GeoNFTs",
|
|
54
|
+
"GeoHotSpots",
|
|
55
|
+
"Plugins",
|
|
56
|
+
"Templates",
|
|
57
|
+
"Libraries",
|
|
58
|
+
"Runtimes",
|
|
59
|
+
"Competition",
|
|
60
|
+
"Leaderboards",
|
|
61
|
+
"Tournaments",
|
|
62
|
+
"Holons",
|
|
63
|
+
"Zomes",
|
|
64
|
+
"Parks",
|
|
65
|
+
"Chapters",
|
|
66
|
+
"Inventory Items",
|
|
67
|
+
"OASIS API",
|
|
68
|
+
"Avatar API",
|
|
69
|
+
"WEB 3",
|
|
70
|
+
"WEB 4",
|
|
71
|
+
"WEB 5",
|
|
72
|
+
"Blockchain",
|
|
73
|
+
"NFT",
|
|
74
|
+
"Tokens",
|
|
75
|
+
"Crypto",
|
|
76
|
+
"Interoperable",
|
|
77
|
+
"Future-Prove",
|
|
78
|
+
"Metaverse",
|
|
79
|
+
"Aggregation",
|
|
80
|
+
"HOT-Swappable-Architecture",
|
|
81
|
+
"P2P",
|
|
82
|
+
"Decentralised",
|
|
83
|
+
"Distributed",
|
|
84
|
+
"Interoprability",
|
|
85
|
+
"Abstraction-Layer",
|
|
86
|
+
"Multi-Network",
|
|
87
|
+
"Multi-Chain",
|
|
88
|
+
"Bridging",
|
|
89
|
+
"Network-Of-Networks",
|
|
90
|
+
"SSO",
|
|
91
|
+
"Auto-FailOver",
|
|
92
|
+
"Auto-LoadBalancing",
|
|
93
|
+
"Auto-Replication",
|
|
94
|
+
"Auto-Sync",
|
|
95
|
+
"Offline-Support",
|
|
96
|
+
"Write-Once-Deploy-Everywhere",
|
|
97
|
+
"Triple-Level-Quantum-Resistant-Encryption",
|
|
98
|
+
"Quantum",
|
|
99
|
+
"Encryption",
|
|
100
|
+
"Smart-Contracts",
|
|
101
|
+
"Intelligent-Key-Management",
|
|
102
|
+
"Zero-Lag",
|
|
103
|
+
"Zero-Downtime",
|
|
104
|
+
"Agent-Centric",
|
|
105
|
+
"Smart-City-Ready",
|
|
106
|
+
"WEB/2D/3D/AR/VR/IR/Map/Meta-Visusalization",
|
|
107
|
+
"IR-(Infinite-Reality)-Ready",
|
|
108
|
+
"Infinite-Players-Online-At-Same-Time",
|
|
109
|
+
"AI/Machine-Learning-Over-All-Of-World's-Aggregated-Data",
|
|
110
|
+
"HTTP-REST/gRPC/GraphQL/CLI/Native-Endpoints",
|
|
111
|
+
"Best-Of-All-Worlds",
|
|
112
|
+
"GOD-Protocol/API",
|
|
113
|
+
"Our-World-Geo-Location/AR/IR/Map-UI-(Game-of-Games-Engine)",
|
|
114
|
+
"One-World-Open-World-MMO-(VR)-UI-(Game-of-Games-Engine)",
|
|
115
|
+
"More Coming..."
|
|
116
|
+
]
|
|
117
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_BASE_URL = 'https://api.star.oasisweb5.one';
|
|
4
|
+
|
|
5
|
+
function buildQueryString(query) {
|
|
6
|
+
const entries = Object.entries(query || {}).filter(([, v]) => v !== undefined && v !== null);
|
|
7
|
+
if (!entries.length) return '';
|
|
8
|
+
const params = new URLSearchParams();
|
|
9
|
+
for (const [key, value] of entries) {
|
|
10
|
+
params.set(key, typeof value === 'object' ? JSON.stringify(value) : String(value));
|
|
11
|
+
}
|
|
12
|
+
return `?${params.toString()}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Thin isomorphic HTTP client around the global fetch API (Node 18+, all modern browsers).
|
|
17
|
+
* Every WEB5 STAR API call ultimately goes through `request()` below - there are no mocked
|
|
18
|
+
* or stubbed responses anywhere in this SDK.
|
|
19
|
+
*/
|
|
20
|
+
class HttpClient {
|
|
21
|
+
constructor({ baseUrl = DEFAULT_BASE_URL, tokenStore, fetchImpl = globalThis.fetch } = {}) {
|
|
22
|
+
if (!fetchImpl) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
'No global fetch implementation found. Use Node 18+, a modern browser, or pass { fetchImpl } explicitly.'
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
28
|
+
this.tokenStore = tokenStore;
|
|
29
|
+
this.fetchImpl = fetchImpl;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setBaseUrl(baseUrl) {
|
|
33
|
+
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {string} verb GET | POST | PUT | DELETE
|
|
38
|
+
* @param {string} path e.g. "api/avatar/authenticate"
|
|
39
|
+
* @param {object} [options]
|
|
40
|
+
* @param {object} [options.query] query string params (GET/DELETE)
|
|
41
|
+
* @param {object} [options.body] JSON body (POST/PUT/DELETE)
|
|
42
|
+
* @param {boolean} [options.auth] attach Authorization: Bearer <token> (default true)
|
|
43
|
+
* @param {string} [options.token] override token for this single request
|
|
44
|
+
*/
|
|
45
|
+
async request(verb, path, { query, body, auth = true, token } = {}) {
|
|
46
|
+
const url = `${this.baseUrl}/${path.replace(/^\/+/, '')}${buildQueryString(query)}`;
|
|
47
|
+
const headers = {
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
Accept: 'application/json'
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const bearer = token || (auth ? this.tokenStore?.getToken() : null);
|
|
53
|
+
if (bearer) headers.Authorization = `Bearer ${bearer}`;
|
|
54
|
+
|
|
55
|
+
const init = { method: verb, headers };
|
|
56
|
+
if (body !== undefined && verb !== 'GET') init.body = JSON.stringify(body);
|
|
57
|
+
|
|
58
|
+
let res;
|
|
59
|
+
try {
|
|
60
|
+
res = await this.fetchImpl(url, init);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
return { isError: true, message: `Network error calling ${url}: ${err.message}`, exception: err };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const text = await res.text();
|
|
66
|
+
let json;
|
|
67
|
+
try {
|
|
68
|
+
json = text ? JSON.parse(text) : null;
|
|
69
|
+
} catch {
|
|
70
|
+
json = null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
const message =
|
|
75
|
+
json?.result?.message || json?.message || json?.title || `Request failed with status ${res.status}`;
|
|
76
|
+
return { isError: true, message, statusCode: res.status, raw: json };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// OASIS responses are typically { isError, message, result: { isError, message, result: <payload> } }.
|
|
80
|
+
// We surface the innermost payload as `.result` while keeping the full envelope available as `.raw`.
|
|
81
|
+
const inner = json?.result !== undefined ? json.result : json;
|
|
82
|
+
const payload = inner?.result !== undefined ? inner.result : inner;
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
isError: Boolean(inner?.isError || json?.isError),
|
|
86
|
+
message: inner?.message || json?.message || null,
|
|
87
|
+
result: payload,
|
|
88
|
+
raw: json,
|
|
89
|
+
statusCode: res.status
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
get(path, options) {
|
|
94
|
+
return this.request('GET', path, options);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
post(path, options) {
|
|
98
|
+
return this.request('POST', path, options);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
put(path, options) {
|
|
102
|
+
return this.request('PUT', path, options);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
delete(path, options) {
|
|
106
|
+
return this.request('DELETE', path, options);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = { HttpClient, DEFAULT_BASE_URL };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const TOKEN_PATTERN = /\{(\w+)(?::\w+)?\}/g;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Resolves a route template like "get-by-id/{id}" against an args object,
|
|
7
|
+
* substituting path tokens and returning the resolved path plus whatever
|
|
8
|
+
* args were *not* consumed as path tokens (these become the query/body).
|
|
9
|
+
*/
|
|
10
|
+
function resolveRoute(routeTemplate, args = {}) {
|
|
11
|
+
const consumed = new Set();
|
|
12
|
+
const path = routeTemplate.replace(TOKEN_PATTERN, (match, name) => {
|
|
13
|
+
const key = Object.keys(args).find((k) => k.toLowerCase() === name.toLowerCase());
|
|
14
|
+
consumed.add(key);
|
|
15
|
+
const value = key !== undefined ? args[key] : undefined;
|
|
16
|
+
if (value === undefined) {
|
|
17
|
+
throw new Error(`Missing required route parameter "${name}" for route "${routeTemplate}"`);
|
|
18
|
+
}
|
|
19
|
+
return encodeURIComponent(value);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const rest = {};
|
|
23
|
+
for (const [key, value] of Object.entries(args)) {
|
|
24
|
+
if (!consumed.has(key)) rest[key] = value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return { path, rest };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function takeKey(obj, name) {
|
|
31
|
+
const matchKey = Object.keys(obj).find((k) => k.toLowerCase() === name.toLowerCase());
|
|
32
|
+
if (matchKey === undefined) return { found: false, value: undefined };
|
|
33
|
+
const value = obj[matchKey];
|
|
34
|
+
delete obj[matchKey];
|
|
35
|
+
return { found: true, value };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Builds a bound method for a single WEB5 STAR API endpoint operation.
|
|
40
|
+
* @param {import('./httpClient').HttpClient} http
|
|
41
|
+
* @param {string} routePrefix e.g. "api/avatar"
|
|
42
|
+
* @param {string} verb GET | POST | PUT | DELETE
|
|
43
|
+
* @param {string} route route template relative to routePrefix, e.g. "get-by-id/{id}"
|
|
44
|
+
* @param {object} [opts]
|
|
45
|
+
* @param {string[]} [opts.query] arg names that ASP.NET binds from the query
|
|
46
|
+
* string on this action regardless of HTTP verb (e.g. `[FromQuery]` flags
|
|
47
|
+
* mixed into an otherwise-body-bound POST/PUT action). Always sent as query.
|
|
48
|
+
* @param {string} [opts.bodyParam] when the action's entire request body is a
|
|
49
|
+
* single `[FromBody]` parameter (primitive or object), the JSON body is
|
|
50
|
+
* that arg's value directly rather than the leftover-args object wrapped
|
|
51
|
+
* around it.
|
|
52
|
+
*/
|
|
53
|
+
function makeOperation(http, routePrefix, verb, route, opts = {}) {
|
|
54
|
+
const declaredQueryKeys = opts.query || [];
|
|
55
|
+
const bodyParam = opts.bodyParam;
|
|
56
|
+
|
|
57
|
+
return async function operation(args = {}) {
|
|
58
|
+
const { path, rest } = resolveRoute(route, args);
|
|
59
|
+
const fullPath = path ? `${routePrefix}/${path}` : routePrefix;
|
|
60
|
+
|
|
61
|
+
const query = {};
|
|
62
|
+
for (const key of declaredQueryKeys) {
|
|
63
|
+
const { found, value } = takeKey(rest, key);
|
|
64
|
+
if (found) query[key] = value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let body;
|
|
68
|
+
if (bodyParam) {
|
|
69
|
+
const { found, value } = takeKey(rest, bodyParam);
|
|
70
|
+
if (found) body = value;
|
|
71
|
+
// Any args left over that we don't recognize still get sent (as query)
|
|
72
|
+
// rather than silently dropped.
|
|
73
|
+
Object.assign(query, rest);
|
|
74
|
+
} else if (verb === 'GET' || verb === 'DELETE') {
|
|
75
|
+
Object.assign(query, rest);
|
|
76
|
+
} else {
|
|
77
|
+
body = Object.keys(rest).length ? rest : undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const hasQuery = Object.keys(query).length > 0;
|
|
81
|
+
return http.request(verb, fullPath, { query: hasQuery ? query : undefined, body });
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = { resolveRoute, makeOperation };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const hasLocalStorage = typeof globalThis.localStorage !== 'undefined';
|
|
4
|
+
const STORAGE_KEY = 'oasis_session';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Holds the current JWT/avatar session for the SDK.
|
|
8
|
+
* In the browser it persists to localStorage by default; in Node (or when
|
|
9
|
+
* persistence is disabled) it simply lives in memory for the lifetime of
|
|
10
|
+
* the client instance. Callers can always set/get/clear explicitly.
|
|
11
|
+
*/
|
|
12
|
+
class TokenStore {
|
|
13
|
+
constructor({ persist = hasLocalStorage } = {}) {
|
|
14
|
+
this.persist = persist;
|
|
15
|
+
this._session = null;
|
|
16
|
+
|
|
17
|
+
if (this.persist) {
|
|
18
|
+
try {
|
|
19
|
+
const raw = globalThis.localStorage.getItem(STORAGE_KEY);
|
|
20
|
+
if (raw) this._session = JSON.parse(raw);
|
|
21
|
+
} catch {
|
|
22
|
+
this._session = null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getSession() {
|
|
28
|
+
return this._session;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getToken() {
|
|
32
|
+
return this._session?.jwtToken || this._session?.token || null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setSession(session) {
|
|
36
|
+
this._session = session || null;
|
|
37
|
+
if (this.persist) {
|
|
38
|
+
try {
|
|
39
|
+
if (session) globalThis.localStorage.setItem(STORAGE_KEY, JSON.stringify(session));
|
|
40
|
+
else globalThis.localStorage.removeItem(STORAGE_KEY);
|
|
41
|
+
} catch {
|
|
42
|
+
// Storage unavailable (e.g. private browsing) - in-memory session still works.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
clear() {
|
|
48
|
+
this.setSession(null);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = { TokenStore };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-types.js - do not hand-edit.
|
|
2
|
+
export interface OASISResponse<T = any> {
|
|
3
|
+
isError: boolean;
|
|
4
|
+
message: string | null;
|
|
5
|
+
result: T;
|
|
6
|
+
raw: any;
|
|
7
|
+
statusCode: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface OASISSession {
|
|
11
|
+
avatarId: string;
|
|
12
|
+
username: string;
|
|
13
|
+
email: string;
|
|
14
|
+
firstName?: string;
|
|
15
|
+
lastName?: string;
|
|
16
|
+
jwtToken: string;
|
|
17
|
+
refreshToken?: string;
|
|
18
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { HttpClient, DEFAULT_BASE_URL } = require('./core/httpClient');
|
|
4
|
+
const { TokenStore } = require('./core/tokenStore');
|
|
5
|
+
const { attachGeneratedModules } = require('./modules/index');
|
|
6
|
+
const { AuthModule } = require('./modules/Auth');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Main SDK entry point. Works in Node 18+ and any modern browser.
|
|
10
|
+
*
|
|
11
|
+
* const { STARClient } = require('@oasisomniverse/web5-api');
|
|
12
|
+
* const star = new STARClient({ baseUrl: 'https://api.star.oasisweb5.one' });
|
|
13
|
+
* await star.auth.login({ username: 'me@example.com', password: '...' });
|
|
14
|
+
* const quests = await star.quests.getAllQuestsForAvatar();
|
|
15
|
+
*
|
|
16
|
+
* Every controller on the OASIS2 STAR WebAPI is reachable as a lowerCamel
|
|
17
|
+
* property (star.avatar, star.quests, star.missions, star.games, star.cosmic,
|
|
18
|
+
* star.holons, star.nFTs, star.geoNFTs, star.plugins, star.templates,
|
|
19
|
+
* star.libraries, star.runtimes, star.competition, ...). Generated methods
|
|
20
|
+
* take a single args object; route template tokens (e.g. {id}) are consumed
|
|
21
|
+
* from it automatically, remaining keys become the query string (GET/DELETE)
|
|
22
|
+
* or JSON body (POST/PUT). star.auth is a hand-written convenience wrapper
|
|
23
|
+
* that also manages the session/token for you.
|
|
24
|
+
*/
|
|
25
|
+
class STARClient {
|
|
26
|
+
constructor({ baseUrl = DEFAULT_BASE_URL, persistSession, fetchImpl } = {}) {
|
|
27
|
+
this.tokenStore = new TokenStore({ persist: persistSession });
|
|
28
|
+
this.http = new HttpClient({ baseUrl, tokenStore: this.tokenStore, fetchImpl });
|
|
29
|
+
|
|
30
|
+
attachGeneratedModules(this, this.http);
|
|
31
|
+
|
|
32
|
+
// Hand-written ergonomic wrapper, built on top of the generated avatar module.
|
|
33
|
+
this.auth = new AuthModule(this.http, this.tokenStore, this.avatar);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
setBaseUrl(baseUrl) {
|
|
37
|
+
this.http.setBaseUrl(baseUrl);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Use an externally-issued JWT (e.g. one your server already obtained) for subsequent calls. */
|
|
41
|
+
setToken(jwtToken, sessionExtras = {}) {
|
|
42
|
+
this.tokenStore.setSession({ ...sessionExtras, jwtToken });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Convenience pass-throughs to the generated STAR module (star.sTAR). */
|
|
46
|
+
starIgnite(args) {
|
|
47
|
+
return this.sTAR.igniteSTAR(args);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
starExtinguish(args) {
|
|
51
|
+
return this.sTAR.extinguishSTAR(args);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
starStatus(args) {
|
|
55
|
+
return this.sTAR.getStatus(args);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { STARClient, HttpClient, TokenStore, DEFAULT_BASE_URL };
|
|
60
|
+
module.exports.default = STARClient;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Hand-written type declaration for src/modules/Auth.js
|
|
2
|
+
import type { OASISResponse, OASISSession } from '../core/types';
|
|
3
|
+
|
|
4
|
+
export interface LoginCredentials {
|
|
5
|
+
username: string;
|
|
6
|
+
password: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export declare class AuthModule {
|
|
10
|
+
constructor(http: unknown, tokenStore: unknown, avatarModule: unknown);
|
|
11
|
+
getSession(): OASISSession | null;
|
|
12
|
+
isAuthenticated(): boolean;
|
|
13
|
+
login(credentials: LoginCredentials): Promise<OASISResponse & { session?: OASISSession }>;
|
|
14
|
+
logout(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hand-written ergonomic auth wrapper. Built on top of the generated
|
|
5
|
+
* AvatarModule (api/avatar/authenticate) and manages the SDK's TokenStore
|
|
6
|
+
* automatically on login/logout - this is the one place callers don't have
|
|
7
|
+
* to think about JWTs themselves.
|
|
8
|
+
*
|
|
9
|
+
* STAR's AvatarController has no logout/revoke-token endpoint of its own (it
|
|
10
|
+
* only forwards a subset of WEB4 avatar operations), so logout() just clears
|
|
11
|
+
* the local session client-side.
|
|
12
|
+
*/
|
|
13
|
+
class AuthModule {
|
|
14
|
+
constructor(http, tokenStore, avatarModule) {
|
|
15
|
+
this._http = http;
|
|
16
|
+
this._tokenStore = tokenStore;
|
|
17
|
+
this._avatar = avatarModule;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Returns the currently stored session ({ avatarId, username, email, jwtToken, ... }) or null. */
|
|
21
|
+
getSession() {
|
|
22
|
+
return this._tokenStore.getSession();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
isAuthenticated() {
|
|
26
|
+
return Boolean(this._tokenStore.getToken());
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {{username: string, password: string}} credentials `username` may also be an email,
|
|
31
|
+
* OASIS' authenticate endpoint accepts either.
|
|
32
|
+
*/
|
|
33
|
+
async login({ username, password }) {
|
|
34
|
+
const res = await this._avatar.authenticate({ Username: username, Password: password });
|
|
35
|
+
if (res.isError || !res.result) return res;
|
|
36
|
+
|
|
37
|
+
const avatar = res.result;
|
|
38
|
+
const session = {
|
|
39
|
+
avatarId: avatar.id || avatar.Id,
|
|
40
|
+
username: avatar.username || avatar.Username || username,
|
|
41
|
+
email: avatar.email || avatar.Email,
|
|
42
|
+
firstName: avatar.firstName || avatar.FirstName,
|
|
43
|
+
lastName: avatar.lastName || avatar.LastName,
|
|
44
|
+
jwtToken: avatar.jwtToken || avatar.JwtToken,
|
|
45
|
+
refreshToken: avatar.refreshToken || avatar.RefreshToken
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
if (!session.jwtToken) {
|
|
49
|
+
return { isError: true, message: 'Authentication succeeded but no JWT token was returned.', raw: res.raw };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this._tokenStore.setSession(session);
|
|
53
|
+
return { ...res, session };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Clears the local session. STAR's AvatarController has no server-side revoke endpoint to call. */
|
|
57
|
+
async logout() {
|
|
58
|
+
this._tokenStore.clear();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { AuthModule };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-types.js - do not hand-edit.
|
|
2
|
+
import type { OASISResponse } from '../core/types';
|
|
3
|
+
|
|
4
|
+
export declare class AvatarModule {
|
|
5
|
+
constructor(http: unknown);
|
|
6
|
+
|
|
7
|
+
/** POST api/avatar/inventory */
|
|
8
|
+
addItemToInventory(args?: Record<string, any>): Promise<OASISResponse>;
|
|
9
|
+
|
|
10
|
+
/** POST api/avatar/add-xp */
|
|
11
|
+
addXp(args?: Record<string, any>): Promise<OASISResponse>;
|
|
12
|
+
|
|
13
|
+
/** POST api/avatar/authenticate */
|
|
14
|
+
authenticate(args?: Record<string, any>): Promise<OASISResponse>;
|
|
15
|
+
|
|
16
|
+
/** GET api/avatar/current */
|
|
17
|
+
getCurrentAvatar(args?: Record<string, any>): Promise<OASISResponse>;
|
|
18
|
+
|
|
19
|
+
/** GET api/avatar/inventory */
|
|
20
|
+
getInventory(args?: Record<string, any>): Promise<OASISResponse>;
|
|
21
|
+
|
|
22
|
+
/** GET api/avatar/inventory/{itemId} */
|
|
23
|
+
getInventoryItem(args?: Record<string, any>): Promise<OASISResponse>;
|
|
24
|
+
|
|
25
|
+
/** GET api/avatar/inventory/{itemId}/has */
|
|
26
|
+
hasItem(args?: Record<string, any>): Promise<OASISResponse>;
|
|
27
|
+
|
|
28
|
+
/** GET api/avatar/inventory/has-by-name (query: itemName) */
|
|
29
|
+
hasItemByName(args?: Record<string, any>): Promise<OASISResponse>;
|
|
30
|
+
|
|
31
|
+
/** DELETE api/avatar/inventory/{itemId} */
|
|
32
|
+
removeItemFromInventory(args?: Record<string, any>): Promise<OASISResponse>;
|
|
33
|
+
|
|
34
|
+
/** GET api/avatar/inventory/search (query: searchTerm) */
|
|
35
|
+
searchInventory(args?: Record<string, any>): Promise<OASISResponse>;
|
|
36
|
+
|
|
37
|
+
/** POST api/avatar/inventory/send-to-avatar */
|
|
38
|
+
sendItemToAvatar(args?: Record<string, any>): Promise<OASISResponse>;
|
|
39
|
+
|
|
40
|
+
/** POST api/avatar/inventory/send-to-clan */
|
|
41
|
+
sendItemToClan(args?: Record<string, any>): Promise<OASISResponse>;
|
|
42
|
+
|
|
43
|
+
/** POST api/avatar/set-active-quest */
|
|
44
|
+
setActiveQuest(args?: Record<string, any>): Promise<OASISResponse>;
|
|
45
|
+
}
|