@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 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.