@softfault/blacketjs 0.1.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 +210 -0
- package/dist/client.d.ts +620 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/http.d.ts +86 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +734 -0
- package/dist/socket.d.ts +121 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/types.d.ts +420 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# @softfault/blacketjs
|
|
2
|
+
|
|
3
|
+
small typescript sdk for the blacket web api.
|
|
4
|
+
|
|
5
|
+
bun package. oop client. cookies in, typed responses out. no dependency pile, no factory labyrinth, no architecture pretending it pays rent.
|
|
6
|
+
|
|
7
|
+
## install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add @softfault/blacketjs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
local dev:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## auth
|
|
20
|
+
|
|
21
|
+
blacket uses a session cookie. this sdk does not log in for you.
|
|
22
|
+
|
|
23
|
+
grab a valid cookie from your app/browser context and pass it in:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { BlacketClient } from "@softfault/blacketjs";
|
|
27
|
+
|
|
28
|
+
const cookie = process.env.COOKIES;
|
|
29
|
+
|
|
30
|
+
if (!cookie) {
|
|
31
|
+
throw new Error("Missing COOKIES env var");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const client = new BlacketClient({ cookie });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
yes, the env var is named `COOKIES` in the examples. no, this is not spiritually elegant. it works.
|
|
38
|
+
|
|
39
|
+
## basic use
|
|
40
|
+
|
|
41
|
+
most api methods return blacket's normal response shape:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const res = await client.users.me();
|
|
45
|
+
|
|
46
|
+
if (res.error) {
|
|
47
|
+
throw new Error(res.reason ?? "failed to get current user");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(res.user.username);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
same thing for clans:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { BlacketClient, type BlacketClan } from "@softfault/blacketjs";
|
|
57
|
+
|
|
58
|
+
const client = new BlacketClient({ cookie });
|
|
59
|
+
const res = await client.clans.mine();
|
|
60
|
+
|
|
61
|
+
if (res.error) {
|
|
62
|
+
throw new Error(res.reason ?? "failed to get clan");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const clan: BlacketClan = res.clan;
|
|
66
|
+
|
|
67
|
+
console.log(clan.color);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
the error check matters. typescript is not being dramatic there. the response can actually be an error-shaped little brick.
|
|
71
|
+
|
|
72
|
+
## categories
|
|
73
|
+
|
|
74
|
+
the client is split by the same rough areas as the site:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
client.data.index();
|
|
78
|
+
client.account.currentUser();
|
|
79
|
+
client.users.get("softfault");
|
|
80
|
+
client.friends.request("user-id");
|
|
81
|
+
client.settings.color("#ff00ff");
|
|
82
|
+
client.cosmetics.avatar("Blook Name");
|
|
83
|
+
client.store.startPurchase("plus", 1, "https://blacket.org/");
|
|
84
|
+
client.market.openPack("Pack Name");
|
|
85
|
+
client.clans.mine();
|
|
86
|
+
client.trades.sendRequest("user-id");
|
|
87
|
+
client.messages.list(0);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
each category is just a small class. no registries. no adapters. no fake enterprise fog machine.
|
|
91
|
+
|
|
92
|
+
## raw requests
|
|
93
|
+
|
|
94
|
+
if the sdk does not have a named method yet, use the raw helpers:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const data = await client.get("/data/index.json");
|
|
98
|
+
|
|
99
|
+
const result = await client.post("/worker/friends/request", {
|
|
100
|
+
user: "user-id",
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
you can pass a generic if you know the shape:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
const res = await client.get<{ emojis: string[] }>("/content/emojis.json");
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## sockets
|
|
111
|
+
|
|
112
|
+
create and connect the socket:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const socket = client.connectSocket();
|
|
116
|
+
|
|
117
|
+
await socket.waitUntilOpen();
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
reply to heartbeats:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
client.account.replyToHeartbeat();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
listen for messages:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
client.messages.onCreate((event) => {
|
|
130
|
+
console.log(event.data.author.username, event.data.message.content);
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
send a message:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
await client.messages.send(0, "hello world");
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
trade events are typed too:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
client.trades.onRequestReceived(async (event) => {
|
|
144
|
+
if (event.data.user.username !== "Unblooked") {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const accepted = await client.trades.acceptRequest();
|
|
149
|
+
|
|
150
|
+
if (accepted.error) {
|
|
151
|
+
throw new Error(accepted.reason ?? "failed to accept trade");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
client.trades.sendTokens("200");
|
|
155
|
+
client.trades.acceptOngoing();
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## uploads
|
|
160
|
+
|
|
161
|
+
uploads follow blacket's signed upload flow:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
const file = Bun.file("./avatar.png");
|
|
165
|
+
const res = await client.account.upload(file);
|
|
166
|
+
|
|
167
|
+
if (res.error) {
|
|
168
|
+
throw new Error(res.reason ?? "upload failed");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log(res.url);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## scripts
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
bun run typecheck
|
|
178
|
+
bun run build
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`bun run build` writes `dist/`. git ignores it because generated files love lying about what changed.
|
|
182
|
+
|
|
183
|
+
## project shape
|
|
184
|
+
|
|
185
|
+
```txt
|
|
186
|
+
src/types.ts shared public types
|
|
187
|
+
src/http.ts fetch wrapper, cookies, uploads, socket url helpers
|
|
188
|
+
src/socket.ts websocket wrapper and event maps
|
|
189
|
+
src/client.ts the public sdk client and categories
|
|
190
|
+
src/index.ts package exports
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## what this does not do
|
|
194
|
+
|
|
195
|
+
- ZERO event stuff
|
|
196
|
+
- no runtime validation layer
|
|
197
|
+
- no retry strategy beyond the tiny 503 retry in `BlacketHttp`
|
|
198
|
+
|
|
199
|
+
the sdk is intentionally boring. boring survives production. flashy abstractions usually just leave fingerprints on the crash report.
|
|
200
|
+
|
|
201
|
+
## publishing
|
|
202
|
+
|
|
203
|
+
before publishing:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
bun run build
|
|
207
|
+
npm publish
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`prepublishOnly` runs the build too, because forgetting generated declarations is a classic way to ruin your own afternoon.
|