@meowpanel/api 0.1.0-alpha.11 → 1.0.0-beta.2

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.
Files changed (297) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +40 -0
  3. package/esm/mod.d.ts +87 -1
  4. package/esm/mod.d.ts.map +1 -1
  5. package/esm/mod.js +85 -1
  6. package/esm/src/client.d.ts +248 -0
  7. package/esm/src/client.d.ts.map +1 -0
  8. package/esm/src/client.js +235 -0
  9. package/esm/src/emitter.d.ts +53 -0
  10. package/esm/src/emitter.d.ts.map +1 -0
  11. package/esm/src/emitter.js +55 -0
  12. package/esm/src/errors.d.ts +42 -0
  13. package/esm/src/errors.d.ts.map +1 -0
  14. package/esm/src/errors.js +45 -0
  15. package/esm/src/http.d.ts +157 -0
  16. package/esm/src/http.d.ts.map +1 -0
  17. package/esm/src/http.js +317 -0
  18. package/esm/src/namespace.d.ts +59 -0
  19. package/esm/src/namespace.d.ts.map +1 -0
  20. package/esm/src/namespace.js +79 -0
  21. package/esm/src/reactive.d.ts +29 -0
  22. package/esm/src/reactive.d.ts.map +1 -0
  23. package/esm/src/reactive.js +35 -0
  24. package/esm/src/resources/account.d.ts +125 -0
  25. package/esm/src/resources/account.d.ts.map +1 -0
  26. package/esm/src/resources/account.js +151 -0
  27. package/esm/src/resources/api-keys.d.ts +116 -0
  28. package/esm/src/resources/api-keys.d.ts.map +1 -0
  29. package/esm/src/resources/api-keys.js +105 -0
  30. package/esm/src/resources/auth.d.ts +57 -0
  31. package/esm/src/resources/auth.d.ts.map +1 -0
  32. package/esm/src/resources/auth.js +39 -0
  33. package/esm/src/resources/eggs.d.ts +238 -0
  34. package/esm/src/resources/eggs.d.ts.map +1 -0
  35. package/esm/src/resources/eggs.js +187 -0
  36. package/esm/src/resources/hosts.d.ts +62 -0
  37. package/esm/src/resources/hosts.d.ts.map +1 -0
  38. package/esm/src/resources/hosts.js +62 -0
  39. package/esm/src/resources/members.d.ts +138 -0
  40. package/esm/src/resources/members.d.ts.map +1 -0
  41. package/esm/src/resources/members.js +122 -0
  42. package/esm/src/resources/nodes.d.ts +397 -0
  43. package/esm/src/resources/nodes.d.ts.map +1 -0
  44. package/esm/src/resources/nodes.js +352 -0
  45. package/esm/src/resources/server-groups.d.ts +150 -0
  46. package/esm/src/resources/server-groups.d.ts.map +1 -0
  47. package/esm/src/resources/server-groups.js +111 -0
  48. package/esm/src/resources/servers/activity.d.ts +120 -0
  49. package/esm/src/resources/servers/activity.d.ts.map +1 -0
  50. package/esm/src/resources/servers/activity.js +163 -0
  51. package/esm/src/resources/servers/allocations.d.ts +125 -0
  52. package/esm/src/resources/servers/allocations.d.ts.map +1 -0
  53. package/esm/src/resources/servers/allocations.js +137 -0
  54. package/esm/src/resources/servers/connection.d.ts +108 -0
  55. package/esm/src/resources/servers/connection.d.ts.map +1 -0
  56. package/esm/src/resources/servers/connection.js +169 -0
  57. package/esm/src/resources/servers/files.d.ts +164 -0
  58. package/esm/src/resources/servers/files.d.ts.map +1 -0
  59. package/esm/src/resources/servers/files.js +281 -0
  60. package/esm/src/resources/servers/index.d.ts +126 -0
  61. package/esm/src/resources/servers/index.d.ts.map +1 -0
  62. package/esm/src/resources/servers/index.js +135 -0
  63. package/esm/src/resources/servers/profiles.d.ts +138 -0
  64. package/esm/src/resources/servers/profiles.d.ts.map +1 -0
  65. package/esm/src/resources/servers/profiles.js +177 -0
  66. package/esm/src/resources/servers/server.d.ts +136 -0
  67. package/esm/src/resources/servers/server.d.ts.map +1 -0
  68. package/esm/src/resources/servers/server.js +202 -0
  69. package/esm/src/resources/servers/sftp.d.ts +147 -0
  70. package/esm/src/resources/servers/sftp.d.ts.map +1 -0
  71. package/esm/src/resources/servers/sftp.js +153 -0
  72. package/esm/src/resources/servers/types.d.ts +199 -0
  73. package/esm/src/resources/servers/types.d.ts.map +1 -0
  74. package/esm/src/resources/servers/types.js +1 -0
  75. package/esm/src/sse.d.ts +53 -0
  76. package/esm/src/sse.d.ts.map +1 -0
  77. package/esm/src/sse.js +133 -0
  78. package/esm/src/types.d.ts +126 -0
  79. package/esm/src/types.d.ts.map +1 -0
  80. package/esm/src/types.js +21 -0
  81. package/package.json +4 -92
  82. package/script/mod.d.ts +87 -1
  83. package/script/mod.d.ts.map +1 -1
  84. package/script/mod.js +132 -3
  85. package/script/src/client.d.ts +248 -0
  86. package/script/src/client.d.ts.map +1 -0
  87. package/script/src/client.js +239 -0
  88. package/script/src/emitter.d.ts +53 -0
  89. package/script/src/emitter.d.ts.map +1 -0
  90. package/script/src/emitter.js +59 -0
  91. package/script/src/errors.d.ts +42 -0
  92. package/script/src/errors.d.ts.map +1 -0
  93. package/script/src/errors.js +49 -0
  94. package/script/src/http.d.ts +157 -0
  95. package/script/src/http.d.ts.map +1 -0
  96. package/script/src/http.js +321 -0
  97. package/script/src/namespace.d.ts +59 -0
  98. package/script/src/namespace.d.ts.map +1 -0
  99. package/script/src/namespace.js +83 -0
  100. package/script/src/reactive.d.ts +29 -0
  101. package/script/src/reactive.d.ts.map +1 -0
  102. package/script/src/reactive.js +39 -0
  103. package/script/src/resources/account.d.ts +125 -0
  104. package/script/src/resources/account.d.ts.map +1 -0
  105. package/script/src/resources/account.js +158 -0
  106. package/script/src/resources/api-keys.d.ts +116 -0
  107. package/script/src/resources/api-keys.d.ts.map +1 -0
  108. package/script/src/resources/api-keys.js +110 -0
  109. package/script/src/resources/auth.d.ts +57 -0
  110. package/script/src/resources/auth.d.ts.map +1 -0
  111. package/script/src/resources/auth.js +43 -0
  112. package/script/src/resources/eggs.d.ts +238 -0
  113. package/script/src/resources/eggs.d.ts.map +1 -0
  114. package/script/src/resources/eggs.js +193 -0
  115. package/script/src/resources/hosts.d.ts +62 -0
  116. package/script/src/resources/hosts.d.ts.map +1 -0
  117. package/script/src/resources/hosts.js +67 -0
  118. package/script/src/resources/members.d.ts +138 -0
  119. package/script/src/resources/members.d.ts.map +1 -0
  120. package/script/src/resources/members.js +127 -0
  121. package/script/src/resources/nodes.d.ts +397 -0
  122. package/script/src/resources/nodes.d.ts.map +1 -0
  123. package/script/src/resources/nodes.js +362 -0
  124. package/script/src/resources/server-groups.d.ts +150 -0
  125. package/script/src/resources/server-groups.d.ts.map +1 -0
  126. package/script/src/resources/server-groups.js +116 -0
  127. package/script/src/resources/servers/activity.d.ts +120 -0
  128. package/script/src/resources/servers/activity.d.ts.map +1 -0
  129. package/script/src/resources/servers/activity.js +170 -0
  130. package/script/src/resources/servers/allocations.d.ts +125 -0
  131. package/script/src/resources/servers/allocations.d.ts.map +1 -0
  132. package/script/src/resources/servers/allocations.js +142 -0
  133. package/script/src/resources/servers/connection.d.ts +108 -0
  134. package/script/src/resources/servers/connection.d.ts.map +1 -0
  135. package/script/src/resources/servers/connection.js +173 -0
  136. package/script/src/resources/servers/files.d.ts +164 -0
  137. package/script/src/resources/servers/files.d.ts.map +1 -0
  138. package/script/src/resources/servers/files.js +286 -0
  139. package/script/src/resources/servers/index.d.ts +126 -0
  140. package/script/src/resources/servers/index.d.ts.map +1 -0
  141. package/script/src/resources/servers/index.js +139 -0
  142. package/script/src/resources/servers/profiles.d.ts +138 -0
  143. package/script/src/resources/servers/profiles.d.ts.map +1 -0
  144. package/script/src/resources/servers/profiles.js +182 -0
  145. package/script/src/resources/servers/server.d.ts +136 -0
  146. package/script/src/resources/servers/server.d.ts.map +1 -0
  147. package/script/src/resources/servers/server.js +206 -0
  148. package/script/src/resources/servers/sftp.d.ts +147 -0
  149. package/script/src/resources/servers/sftp.d.ts.map +1 -0
  150. package/script/src/resources/servers/sftp.js +158 -0
  151. package/script/src/resources/servers/types.d.ts +199 -0
  152. package/script/src/resources/servers/types.d.ts.map +1 -0
  153. package/script/src/resources/servers/types.js +2 -0
  154. package/script/src/sse.d.ts +53 -0
  155. package/script/src/sse.d.ts.map +1 -0
  156. package/script/src/sse.js +137 -0
  157. package/script/src/types.d.ts +126 -0
  158. package/script/src/types.d.ts.map +1 -0
  159. package/script/src/types.js +25 -0
  160. package/esm/api.d.ts +0 -76
  161. package/esm/api.d.ts.map +0 -1
  162. package/esm/api.js +0 -187
  163. package/esm/components/auth.d.ts +0 -15
  164. package/esm/components/auth.d.ts.map +0 -1
  165. package/esm/components/auth.js +0 -13
  166. package/esm/components/connection/abstract.d.ts +0 -23
  167. package/esm/components/connection/abstract.d.ts.map +0 -1
  168. package/esm/components/connection/abstract.js +0 -43
  169. package/esm/components/connection/sse.d.ts +0 -20
  170. package/esm/components/connection/sse.d.ts.map +0 -1
  171. package/esm/components/connection/sse.js +0 -65
  172. package/esm/components/egg/egg.d.ts +0 -32
  173. package/esm/components/egg/egg.d.ts.map +0 -1
  174. package/esm/components/egg/egg.js +0 -70
  175. package/esm/components/group.d.ts +0 -14
  176. package/esm/components/group.d.ts.map +0 -1
  177. package/esm/components/group.js +0 -33
  178. package/esm/components/member_2.d.ts +0 -69
  179. package/esm/components/member_2.d.ts.map +0 -1
  180. package/esm/components/member_2.js +0 -140
  181. package/esm/components/node.d.ts +0 -78
  182. package/esm/components/node.d.ts.map +0 -1
  183. package/esm/components/node.js +0 -342
  184. package/esm/components/server/activity.d.ts +0 -45
  185. package/esm/components/server/activity.d.ts.map +0 -1
  186. package/esm/components/server/activity.js +0 -158
  187. package/esm/components/server/allocations.d.ts +0 -45
  188. package/esm/components/server/allocations.d.ts.map +0 -1
  189. package/esm/components/server/allocations.js +0 -146
  190. package/esm/components/server/files.d.ts +0 -50
  191. package/esm/components/server/files.d.ts.map +0 -1
  192. package/esm/components/server/files.js +0 -90
  193. package/esm/components/server/power.d.ts +0 -21
  194. package/esm/components/server/power.d.ts.map +0 -1
  195. package/esm/components/server/power.js +0 -43
  196. package/esm/components/server/profiles.d.ts +0 -63
  197. package/esm/components/server/profiles.d.ts.map +0 -1
  198. package/esm/components/server/profiles.js +0 -163
  199. package/esm/components/server/server.d.ts +0 -141
  200. package/esm/components/server/server.d.ts.map +0 -1
  201. package/esm/components/server/server.js +0 -358
  202. package/esm/components/server/sftp.d.ts +0 -31
  203. package/esm/components/server/sftp.d.ts.map +0 -1
  204. package/esm/components/server/sftp.js +0 -84
  205. package/esm/components/server/startup.d.ts +0 -17
  206. package/esm/components/server/startup.d.ts.map +0 -1
  207. package/esm/components/server/startup.js +0 -21
  208. package/esm/components/server/stats.d.ts +0 -19
  209. package/esm/components/server/stats.d.ts.map +0 -1
  210. package/esm/components/server/stats.js +0 -46
  211. package/esm/utils/cache.d.ts +0 -20
  212. package/esm/utils/cache.d.ts.map +0 -1
  213. package/esm/utils/cache.js +0 -66
  214. package/esm/utils/event.d.ts +0 -38
  215. package/esm/utils/event.d.ts.map +0 -1
  216. package/esm/utils/event.js +0 -71
  217. package/esm/utils/object.d.ts +0 -58
  218. package/esm/utils/object.d.ts.map +0 -1
  219. package/esm/utils/object.js +0 -86
  220. package/esm/utils/subscribe.d.ts +0 -37
  221. package/esm/utils/subscribe.d.ts.map +0 -1
  222. package/esm/utils/subscribe.js +0 -29
  223. package/esm/utils/timer.d.ts +0 -13
  224. package/esm/utils/timer.d.ts.map +0 -1
  225. package/esm/utils/timer.js +0 -32
  226. package/esm/utils/units.d.ts +0 -18
  227. package/esm/utils/units.d.ts.map +0 -1
  228. package/esm/utils/units.js +0 -82
  229. package/script/api.d.ts +0 -76
  230. package/script/api.d.ts.map +0 -1
  231. package/script/api.js +0 -192
  232. package/script/components/auth.d.ts +0 -15
  233. package/script/components/auth.d.ts.map +0 -1
  234. package/script/components/auth.js +0 -17
  235. package/script/components/connection/abstract.d.ts +0 -23
  236. package/script/components/connection/abstract.d.ts.map +0 -1
  237. package/script/components/connection/abstract.js +0 -47
  238. package/script/components/connection/sse.d.ts +0 -20
  239. package/script/components/connection/sse.d.ts.map +0 -1
  240. package/script/components/connection/sse.js +0 -69
  241. package/script/components/egg/egg.d.ts +0 -32
  242. package/script/components/egg/egg.d.ts.map +0 -1
  243. package/script/components/egg/egg.js +0 -74
  244. package/script/components/group.d.ts +0 -14
  245. package/script/components/group.d.ts.map +0 -1
  246. package/script/components/group.js +0 -37
  247. package/script/components/member_2.d.ts +0 -69
  248. package/script/components/member_2.d.ts.map +0 -1
  249. package/script/components/member_2.js +0 -146
  250. package/script/components/node.d.ts +0 -78
  251. package/script/components/node.d.ts.map +0 -1
  252. package/script/components/node.js +0 -349
  253. package/script/components/server/activity.d.ts +0 -45
  254. package/script/components/server/activity.d.ts.map +0 -1
  255. package/script/components/server/activity.js +0 -164
  256. package/script/components/server/allocations.d.ts +0 -45
  257. package/script/components/server/allocations.d.ts.map +0 -1
  258. package/script/components/server/allocations.js +0 -152
  259. package/script/components/server/files.d.ts +0 -50
  260. package/script/components/server/files.d.ts.map +0 -1
  261. package/script/components/server/files.js +0 -94
  262. package/script/components/server/power.d.ts +0 -21
  263. package/script/components/server/power.d.ts.map +0 -1
  264. package/script/components/server/power.js +0 -47
  265. package/script/components/server/profiles.d.ts +0 -63
  266. package/script/components/server/profiles.d.ts.map +0 -1
  267. package/script/components/server/profiles.js +0 -168
  268. package/script/components/server/server.d.ts +0 -141
  269. package/script/components/server/server.d.ts.map +0 -1
  270. package/script/components/server/server.js +0 -362
  271. package/script/components/server/sftp.d.ts +0 -31
  272. package/script/components/server/sftp.d.ts.map +0 -1
  273. package/script/components/server/sftp.js +0 -88
  274. package/script/components/server/startup.d.ts +0 -17
  275. package/script/components/server/startup.d.ts.map +0 -1
  276. package/script/components/server/startup.js +0 -25
  277. package/script/components/server/stats.d.ts +0 -19
  278. package/script/components/server/stats.d.ts.map +0 -1
  279. package/script/components/server/stats.js +0 -50
  280. package/script/utils/cache.d.ts +0 -20
  281. package/script/utils/cache.d.ts.map +0 -1
  282. package/script/utils/cache.js +0 -70
  283. package/script/utils/event.d.ts +0 -38
  284. package/script/utils/event.d.ts.map +0 -1
  285. package/script/utils/event.js +0 -75
  286. package/script/utils/object.d.ts +0 -58
  287. package/script/utils/object.d.ts.map +0 -1
  288. package/script/utils/object.js +0 -90
  289. package/script/utils/subscribe.d.ts +0 -37
  290. package/script/utils/subscribe.d.ts.map +0 -1
  291. package/script/utils/subscribe.js +0 -32
  292. package/script/utils/timer.d.ts +0 -13
  293. package/script/utils/timer.d.ts.map +0 -1
  294. package/script/utils/timer.js +0 -36
  295. package/script/utils/units.d.ts +0 -18
  296. package/script/utils/units.d.ts.map +0 -1
  297. package/script/utils/units.js +0 -86
@@ -0,0 +1,317 @@
1
+ import { ApiError } from './errors.js';
2
+ /**
3
+ * A thin `fetch` wrapper providing bearer auth, JSON serialization, error parsing,
4
+ * and paginated list support.
5
+ *
6
+ * All methods throw {@link ApiError} for non-2xx HTTP responses.
7
+ */
8
+ export class HttpClient {
9
+ baseUrl;
10
+ token;
11
+ fetchImpl;
12
+ logger;
13
+ credentials;
14
+ onTokenRefresh;
15
+ refreshPromise = null;
16
+ [Symbol.for('nodejs.util.inspect.custom')]() {
17
+ return `HttpClient { ${this.baseUrl} }`;
18
+ }
19
+ constructor(options) {
20
+ this.baseUrl = options.url.replace(/\/$/, '') + '/v1';
21
+ this.token = options.token ?? '';
22
+ this.fetchImpl = options.fetch ?? globalThis.fetch;
23
+ this.logger = options.logger;
24
+ this.credentials = options.credentials;
25
+ this.onTokenRefresh = options.onTokenRefresh;
26
+ }
27
+ /** Replace the bearer token for all subsequent requests. */
28
+ setToken(token) {
29
+ this.token = token;
30
+ }
31
+ /** Return the current bearer token. */
32
+ getToken() {
33
+ return this.token;
34
+ }
35
+ /** Build a fully qualified URL with optional query parameters. */
36
+ buildUrl(path, params) {
37
+ const url = new URL(this.baseUrl + path);
38
+ if (params) {
39
+ for (const [key, value] of Object.entries(params)) {
40
+ if (value !== undefined)
41
+ url.searchParams.set(key, String(value));
42
+ }
43
+ }
44
+ return url.toString();
45
+ }
46
+ /** Shared headers sent with every JSON request. */
47
+ get defaultHeaders() {
48
+ const headers = {
49
+ 'Content-Type': 'application/json',
50
+ 'Accept': 'application/json',
51
+ };
52
+ if (this.token)
53
+ headers['Authorization'] = `Bearer ${this.token}`;
54
+ return headers;
55
+ }
56
+ /** Parse a non-2xx response body into an {@link ApiError}. */
57
+ async parseError(response) {
58
+ let message = `HTTP ${response.status}`;
59
+ let helpUrl = null;
60
+ try {
61
+ const body = await response.json();
62
+ if (typeof body.message === 'string')
63
+ message = body.message;
64
+ else if (typeof body.error === 'string')
65
+ message = body.error;
66
+ if (typeof body.help_url === 'string')
67
+ helpUrl = body.help_url;
68
+ }
69
+ catch { /* ignore JSON parse failures */ }
70
+ return new ApiError({ message, status: response.status, helpUrl });
71
+ }
72
+ log(event) {
73
+ try {
74
+ this.logger?.(event);
75
+ }
76
+ catch {
77
+ // Logger failures must never affect API requests.
78
+ }
79
+ }
80
+ async executeFetch(path, init, params) {
81
+ const method = init.method ?? 'GET';
82
+ const url = this.buildUrl(path, params);
83
+ const startedAt = Date.now();
84
+ this.log({
85
+ code: 'request.start',
86
+ method,
87
+ path,
88
+ url,
89
+ params,
90
+ });
91
+ try {
92
+ const response = await this.fetchImpl(url, { ...init, credentials: this.credentials });
93
+ const durationMs = Date.now() - startedAt;
94
+ if (!response.ok) {
95
+ const error = await this.parseError(response);
96
+ this.log({
97
+ code: 'request.error',
98
+ method,
99
+ path,
100
+ url,
101
+ params,
102
+ status: response.status,
103
+ durationMs,
104
+ error,
105
+ });
106
+ throw error;
107
+ }
108
+ this.log({
109
+ code: 'request.success',
110
+ method,
111
+ path,
112
+ url,
113
+ params,
114
+ status: response.status,
115
+ durationMs,
116
+ });
117
+ return response;
118
+ }
119
+ catch (error) {
120
+ if (error instanceof ApiError) {
121
+ throw error;
122
+ }
123
+ if (error instanceof Error) {
124
+ this.log({
125
+ code: 'request.error',
126
+ method,
127
+ path,
128
+ url,
129
+ params,
130
+ durationMs: Date.now() - startedAt,
131
+ error,
132
+ });
133
+ }
134
+ throw error;
135
+ }
136
+ }
137
+ /** Extract the `exp` claim from a JWT without verification. Returns 0 for non-JWT tokens. */
138
+ getTokenExp() {
139
+ const parts = this.token.split('.');
140
+ if (parts.length !== 3)
141
+ return 0; // Not a JWT token
142
+ try {
143
+ const payload = JSON.parse(atob(parts[1]));
144
+ return typeof payload.exp === 'number' ? payload.exp : 0;
145
+ }
146
+ catch {
147
+ return 0;
148
+ }
149
+ }
150
+ /** Refresh the access token if it's a JWT and about to expire. */
151
+ async refreshTokenIfNeeded() {
152
+ const exp = this.getTokenExp();
153
+ if (exp === 0)
154
+ return;
155
+ const nowSec = Math.floor(Date.now() / 1000);
156
+ if (exp - nowSec > 60)
157
+ return;
158
+ await this.forceRefresh();
159
+ }
160
+ /** Force a token refresh regardless of expiry. Only works if credentials are set (cookie auth). */
161
+ async forceRefresh() {
162
+ if (this.refreshPromise) {
163
+ await this.refreshPromise;
164
+ return !!this.token;
165
+ }
166
+ this.refreshPromise = (async () => {
167
+ try {
168
+ const res = await this.fetchImpl(this.baseUrl + '/auth/refresh', {
169
+ method: 'POST',
170
+ headers: {
171
+ 'Content-Type': 'application/json',
172
+ 'Accept': 'application/json',
173
+ },
174
+ credentials: this.credentials,
175
+ });
176
+ if (res.ok) {
177
+ const data = await res.json();
178
+ this.token = data.access_token;
179
+ this.onTokenRefresh?.(data.access_token);
180
+ }
181
+ }
182
+ finally {
183
+ this.refreshPromise = null;
184
+ }
185
+ })();
186
+ await this.refreshPromise;
187
+ return !!this.token;
188
+ }
189
+ /**
190
+ * Perform a raw `fetch` and throw {@link ApiError} on non-2xx responses.
191
+ *
192
+ * Proactively refreshes JWT tokens that are about to expire and retries
193
+ * once on `401 Unauthorized` after forcing a token refresh.
194
+ *
195
+ * @param path Path relative to the API base URL, e.g. `/servers`.
196
+ * @param init Standard `RequestInit` options.
197
+ * @param params Query parameters to append.
198
+ */
199
+ async fetch(path, init = {}, params) {
200
+ await this.refreshTokenIfNeeded();
201
+ const buildInit = () => ({
202
+ ...init,
203
+ headers: { ...this.defaultHeaders, ...init.headers },
204
+ });
205
+ try {
206
+ return await this.executeFetch(path, buildInit(), params);
207
+ }
208
+ catch (error) {
209
+ if (error instanceof ApiError && error.status === 401 && path !== '/auth/refresh') {
210
+ const refreshed = await this.forceRefresh();
211
+ if (refreshed) {
212
+ return await this.executeFetch(path, buildInit(), params);
213
+ }
214
+ }
215
+ throw error;
216
+ }
217
+ }
218
+ /**
219
+ * GET and deserialize a JSON response body.
220
+ *
221
+ * @param path Path relative to the API base URL.
222
+ * @param opts Additional request options.
223
+ */
224
+ async get(path, opts = {}) {
225
+ const res = await this.fetch(path, { method: 'GET', signal: opts.signal }, opts.params);
226
+ return res.json();
227
+ }
228
+ /**
229
+ * POST with an optional JSON body. Returns `undefined` for `204 No Content`.
230
+ *
231
+ * @param path Path relative to the API base URL.
232
+ * @param body Request body, serialized as JSON.
233
+ * @param opts Additional request options.
234
+ */
235
+ async post(path, body, opts = {}) {
236
+ const res = await this.fetch(path, { method: 'POST', body: body !== undefined ? JSON.stringify(body) : undefined, signal: opts.signal }, opts.params);
237
+ if (res.status === 204)
238
+ return undefined;
239
+ return res.json();
240
+ }
241
+ /**
242
+ * PATCH with an optional JSON body. Returns `undefined` for `204 No Content`.
243
+ *
244
+ * @param path Path relative to the API base URL.
245
+ * @param body Partial update body, serialized as JSON.
246
+ * @param opts Additional request options.
247
+ */
248
+ async patch(path, body, opts = {}) {
249
+ const res = await this.fetch(path, { method: 'PATCH', body: body !== undefined ? JSON.stringify(body) : undefined, signal: opts.signal }, opts.params);
250
+ if (res.status === 204)
251
+ return undefined;
252
+ return res.json();
253
+ }
254
+ /**
255
+ * DELETE a resource.
256
+ *
257
+ * @param path Path relative to the API base URL.
258
+ * @param opts Additional request options.
259
+ */
260
+ async delete(path, opts = {}) {
261
+ await this.fetch(path, { method: 'DELETE', signal: opts.signal }, opts.params);
262
+ }
263
+ /**
264
+ * PUT raw body content (e.g. for binary or multipart uploads).
265
+ *
266
+ * @param path Path relative to the API base URL.
267
+ * @param body Raw body content.
268
+ * @param contentType The `Content-Type` header value.
269
+ * @param opts Additional request options.
270
+ */
271
+ async put(path, body, contentType, opts = {}) {
272
+ const headers = { 'Accept': 'application/json', 'Content-Type': contentType };
273
+ if (this.token)
274
+ headers['Authorization'] = `Bearer ${this.token}`;
275
+ const res = await this.executeFetch(path, {
276
+ method: 'PUT',
277
+ body,
278
+ headers,
279
+ signal: opts.signal,
280
+ }, opts.params);
281
+ if (res.status === 204)
282
+ return undefined;
283
+ return res.json();
284
+ }
285
+ /**
286
+ * GET a paginated list, parsing the `Content-Range` header for metadata when available.
287
+ *
288
+ * The `Content-Range` header format expected is: `items {from}-{to}/{total}`.
289
+ *
290
+ * @param path Path relative to the API base URL.
291
+ * @param opts Pagination and search options.
292
+ */
293
+ async list(path, opts = {}, extraParams) {
294
+ const params = { ...extraParams };
295
+ if (opts.page !== undefined)
296
+ params['page'] = opts.page;
297
+ if (opts.perPage !== undefined)
298
+ params['per_page'] = opts.perPage;
299
+ if (opts.search)
300
+ params['search'] = opts.search;
301
+ const res = await this.fetch(path, { method: 'GET' }, params);
302
+ const data = (await res.json());
303
+ const array = Array.isArray(data) ? data : [];
304
+ const perPage = opts.perPage ?? array.length;
305
+ let total = array.length;
306
+ let page = opts.page ?? 1;
307
+ const range = res.headers.get('Content-Range');
308
+ if (range) {
309
+ const m = /items\s+(\d+)-(\d+)\/(\d+)/.exec(range);
310
+ if (m) {
311
+ total = parseInt(m[3], 10);
312
+ page = perPage > 0 ? Math.floor(parseInt(m[1], 10) / perPage) + 1 : 1;
313
+ }
314
+ }
315
+ return { data: array, total, page, perPage };
316
+ }
317
+ }
@@ -0,0 +1,59 @@
1
+ import { TypedEmitter } from './emitter.js';
2
+ import type { HttpClient } from './http.js';
3
+ import type { NanoID } from './types.js';
4
+ /**
5
+ * Base class for all resource namespaces (e.g. `api.servers`, `api.members`).
6
+ *
7
+ * Provides:
8
+ * - A **readable store** so reactive consumers can auto-subscribe with `$api.servers`, etc.
9
+ * - A **typed event emitter** for mutation events via `.on('created', ...)`, etc.
10
+ * - A **local list cache** updated after every successful `list()`, `create()`,
11
+ * `update()`, or `delete()` call.
12
+ *
13
+ * @template TResource The resource type stored in this namespace. Must expose an `id: NanoID`.
14
+ * @template TEvents The typed event map. Keys are event names; values are payload types.
15
+ *
16
+ * @example
17
+ * ```ts ignore
18
+ * // Reactive store usage
19
+ * // {#each $api.servers as server} ... {/each}
20
+ *
21
+ * // Event listener usage
22
+ * api.servers.on('created', (server) => console.log('New server:', server.name));
23
+ * api.servers.on('deleted', (id) => console.log('Deleted:', id));
24
+ * ```
25
+ */
26
+ export declare abstract class ResourceNamespace<TResource extends {
27
+ id: NanoID;
28
+ }, TEvents extends object = Record<never, never>> extends TypedEmitter<TEvents> {
29
+ protected readonly http: HttpClient;
30
+ /** The current cached list of resources. Updated after every successful list/mutation. */
31
+ protected cache: TResource[];
32
+ private readonly subs;
33
+ /** @internal */
34
+ protected constructor(http: HttpClient);
35
+ /**
36
+ * Subscribe to the list of cached resources.
37
+ *
38
+ * The subscriber is called immediately with the current cached list, and again after any
39
+ * call to {@link list}, {@link create}, or other mutating methods refreshes the cache.
40
+ *
41
+ * @param run Callback invoked with the full array of cached resources.
42
+ * @returns A function that, when called, removes this subscriber.
43
+ */
44
+ subscribe(run: (value: TResource[]) => void): () => void;
45
+ /** Replace the entire list cache and notify all subscribers. */
46
+ protected setCache(data: TResource[]): void;
47
+ /** Append a new item to the cache and notify all subscribers. */
48
+ protected addToCache(item: TResource): void;
49
+ /**
50
+ * Update an existing item in the cache (matched by `id`) in-place, or append it if not found.
51
+ * Since resources are mutable, the existing instance has already been updated in-place before
52
+ * this is called. Notifies all subscribers.
53
+ */
54
+ protected upsertCache(item: TResource): void;
55
+ /** Remove an item from the cache by `id` and notify all subscribers. */
56
+ protected removeFromCache(id: NanoID): void;
57
+ protected notifySubs(): void;
58
+ }
59
+ //# sourceMappingURL=namespace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../src/src/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,8BAAsB,iBAAiB,CACtC,SAAS,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAChC,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAC5C,SAAQ,YAAY,CAAC,OAAO,CAAC;IAMR,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU;IALzD,0FAA0F;IAC1F,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,CAAM;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2C;IAEhE,gBAAgB;IAChB,SAAS,aAAgC,IAAI,EAAE,UAAU;IAIzD;;;;;;;;OAQG;IACI,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI;IAM/D,gEAAgE;IAChE,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI;IAK3C,iEAAiE;IACjE,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAK3C;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAQ5C,wEAAwE;IACxE,SAAS,CAAC,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK3C,SAAS,CAAC,UAAU,IAAI,IAAI;CAG5B"}
@@ -0,0 +1,79 @@
1
+ import { TypedEmitter } from './emitter.js';
2
+ /**
3
+ * Base class for all resource namespaces (e.g. `api.servers`, `api.members`).
4
+ *
5
+ * Provides:
6
+ * - A **readable store** so reactive consumers can auto-subscribe with `$api.servers`, etc.
7
+ * - A **typed event emitter** for mutation events via `.on('created', ...)`, etc.
8
+ * - A **local list cache** updated after every successful `list()`, `create()`,
9
+ * `update()`, or `delete()` call.
10
+ *
11
+ * @template TResource The resource type stored in this namespace. Must expose an `id: NanoID`.
12
+ * @template TEvents The typed event map. Keys are event names; values are payload types.
13
+ *
14
+ * @example
15
+ * ```ts ignore
16
+ * // Reactive store usage
17
+ * // {#each $api.servers as server} ... {/each}
18
+ *
19
+ * // Event listener usage
20
+ * api.servers.on('created', (server) => console.log('New server:', server.name));
21
+ * api.servers.on('deleted', (id) => console.log('Deleted:', id));
22
+ * ```
23
+ */
24
+ export class ResourceNamespace extends TypedEmitter {
25
+ http;
26
+ /** The current cached list of resources. Updated after every successful list/mutation. */
27
+ cache = [];
28
+ subs = new Set();
29
+ /** @internal */
30
+ constructor(http) {
31
+ super();
32
+ this.http = http;
33
+ }
34
+ /**
35
+ * Subscribe to the list of cached resources.
36
+ *
37
+ * The subscriber is called immediately with the current cached list, and again after any
38
+ * call to {@link list}, {@link create}, or other mutating methods refreshes the cache.
39
+ *
40
+ * @param run Callback invoked with the full array of cached resources.
41
+ * @returns A function that, when called, removes this subscriber.
42
+ */
43
+ subscribe(run) {
44
+ run(this.cache);
45
+ this.subs.add(run);
46
+ return () => this.subs.delete(run);
47
+ }
48
+ /** Replace the entire list cache and notify all subscribers. */
49
+ setCache(data) {
50
+ this.cache = data;
51
+ this.notifySubs();
52
+ }
53
+ /** Append a new item to the cache and notify all subscribers. */
54
+ addToCache(item) {
55
+ this.cache = [...this.cache, item];
56
+ this.notifySubs();
57
+ }
58
+ /**
59
+ * Update an existing item in the cache (matched by `id`) in-place, or append it if not found.
60
+ * Since resources are mutable, the existing instance has already been updated in-place before
61
+ * this is called. Notifies all subscribers.
62
+ */
63
+ upsertCache(item) {
64
+ const idx = this.cache.findIndex((c) => c.id === item.id);
65
+ if (idx < 0) {
66
+ this.cache = [...this.cache, item];
67
+ }
68
+ this.notifySubs();
69
+ }
70
+ /** Remove an item from the cache by `id` and notify all subscribers. */
71
+ removeFromCache(id) {
72
+ this.cache = this.cache.filter((c) => c.id !== id);
73
+ this.notifySubs();
74
+ }
75
+ notifySubs() {
76
+ for (const run of this.subs)
77
+ run(this.cache);
78
+ }
79
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Base class for all API resource instances.
3
+ *
4
+ * Implements the reactive store contract so any resource can be used as a
5
+ * store directly - e.g. `$server.name`, `$profile.isActive`.
6
+ *
7
+ * When the resource's data changes (via an instance method or an incoming SSE event),
8
+ * call {@link notify} to push the updated instance to all subscribers.
9
+ */
10
+ export declare abstract class ReactiveResource {
11
+ private readonly subscribers;
12
+ /**
13
+ * Subscribe to changes on this resource instance.
14
+ *
15
+ * The subscriber is called immediately with the current instance, and again
16
+ * whenever {@link notify} is called (e.g. after an update or SSE event).
17
+ *
18
+ * @param run Callback invoked with the resource instance.
19
+ * @returns A function that, when called, removes this subscriber.
20
+ */
21
+ subscribe(run: (value: this) => void): () => void;
22
+ /**
23
+ * Notify all subscribers that this resource has changed.
24
+ *
25
+ * Call this after mutating any public property on the instance.
26
+ */
27
+ protected notify(): void;
28
+ }
29
+ //# sourceMappingURL=reactive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactive.d.ts","sourceRoot":"","sources":["../../src/src/reactive.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,8BAAsB,gBAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoC;IAEhE;;;;;;;;OAQG;IACI,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI;IAMxD;;;;OAIG;IACH,SAAS,CAAC,MAAM,IAAI,IAAI;CAGxB"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Base class for all API resource instances.
3
+ *
4
+ * Implements the reactive store contract so any resource can be used as a
5
+ * store directly - e.g. `$server.name`, `$profile.isActive`.
6
+ *
7
+ * When the resource's data changes (via an instance method or an incoming SSE event),
8
+ * call {@link notify} to push the updated instance to all subscribers.
9
+ */
10
+ export class ReactiveResource {
11
+ subscribers = new Set();
12
+ /**
13
+ * Subscribe to changes on this resource instance.
14
+ *
15
+ * The subscriber is called immediately with the current instance, and again
16
+ * whenever {@link notify} is called (e.g. after an update or SSE event).
17
+ *
18
+ * @param run Callback invoked with the resource instance.
19
+ * @returns A function that, when called, removes this subscriber.
20
+ */
21
+ subscribe(run) {
22
+ run(this);
23
+ this.subscribers.add(run);
24
+ return () => this.subscribers.delete(run);
25
+ }
26
+ /**
27
+ * Notify all subscribers that this resource has changed.
28
+ *
29
+ * Call this after mutating any public property on the instance.
30
+ */
31
+ notify() {
32
+ for (const run of this.subscribers)
33
+ run(this);
34
+ }
35
+ }
@@ -0,0 +1,125 @@
1
+ import type { HttpClient } from '../http.js';
2
+ import { ReactiveResource } from '../reactive.js';
3
+ import type { IncludeOptions, ISODate, NanoID } from '../types.js';
4
+ /** Shared fields present on all account responses. @internal */
5
+ interface AccountDataBase {
6
+ id: string;
7
+ issuer_type: string;
8
+ permissions?: string[];
9
+ created_at: ISODate;
10
+ updated_at: ISODate;
11
+ }
12
+ /** Raw API shape for a user account. @internal */
13
+ interface UserAccountData extends AccountDataBase {
14
+ issuer_type: 'user';
15
+ email: string;
16
+ nickname: string | null;
17
+ avatar_uri: string | null;
18
+ display?: {
19
+ language: string | null;
20
+ theme: string | null;
21
+ } | null;
22
+ }
23
+ /** Raw API shape for an API key account. @internal */
24
+ interface ApiKeyAccountData extends AccountDataBase {
25
+ issuer_type: 'api_key';
26
+ name: string;
27
+ description: string | null;
28
+ owner_id: string;
29
+ owner?: UserAccountData;
30
+ }
31
+ type AccountData = UserAccountData | ApiKeyAccountData;
32
+ /**
33
+ * Base class for the authenticated account.
34
+ *
35
+ * Use {@link isUser} / {@link isApiKey} to narrow to the specific subclass.
36
+ */
37
+ export declare abstract class Account extends ReactiveResource {
38
+ protected readonly http: HttpClient;
39
+ readonly id: NanoID;
40
+ abstract readonly issuerType: 'user' | 'api_key';
41
+ permissions: string[] | undefined;
42
+ createdAt: Date;
43
+ updatedAt: Date;
44
+ /** @internal */
45
+ protected constructor(data: AccountDataBase, http: HttpClient);
46
+ isUser(): this is UserAccount;
47
+ isApiKey(): this is ApiKeyAccount;
48
+ /** @internal */
49
+ static create(data: AccountData, http: HttpClient): UserAccount | ApiKeyAccount;
50
+ }
51
+ /** A human user account. */
52
+ export declare class UserAccount extends Account {
53
+ readonly issuerType: "user";
54
+ email: string;
55
+ nickname: string | null;
56
+ avatarUri: string | null;
57
+ /**
58
+ * Display preferences. Populated with `include=display`.
59
+ * Requires `member.display.read` permission or being the account owner.
60
+ */
61
+ display: {
62
+ language: string | null;
63
+ theme: string | null;
64
+ } | undefined;
65
+ /** @internal */
66
+ constructor(data: UserAccountData, http: HttpClient);
67
+ /** Update this user account in place. */
68
+ update(payload: UpdateAccountPayload): Promise<void>;
69
+ /** Fetch the avatar image as a Blob. */
70
+ fetchAvatar(): Promise<Blob>;
71
+ }
72
+ /** An API key credential. */
73
+ export declare class ApiKeyAccount extends Account {
74
+ readonly issuerType: "api_key";
75
+ name: string;
76
+ description: string | null;
77
+ readonly ownerId: NanoID;
78
+ /** The owner user. */
79
+ owner: UserAccount | undefined;
80
+ /** @internal */
81
+ constructor(data: ApiKeyAccountData, http: HttpClient);
82
+ }
83
+ /** Valid include keys for the account endpoint. */
84
+ export type AccountInclude = 'display' | 'permissions';
85
+ /** Fields that can be updated on a user account. */
86
+ export interface UpdateAccountPayload {
87
+ nickname?: string;
88
+ display?: {
89
+ language?: string | null;
90
+ theme?: string | null;
91
+ };
92
+ }
93
+ /**
94
+ * Resource for the currently authenticated account.
95
+ *
96
+ * Access via `api.account`.
97
+ *
98
+ * @example
99
+ * ```ts ignore
100
+ * const me = await api.account.get();
101
+ * if (me.isUser()) {
102
+ * console.log(me.nickname, me.email);
103
+ * await me.update({ display: { theme: 'dark' } });
104
+ * } else {
105
+ * console.log('API key:', me.name, 'owner:', me.ownerId);
106
+ * }
107
+ * ```
108
+ */
109
+ export declare class AccountResource {
110
+ private readonly http;
111
+ /** @internal */
112
+ constructor(http: HttpClient);
113
+ /** Fetch the currently authenticated account. */
114
+ get(opts?: IncludeOptions<AccountInclude>): Promise<UserAccount | ApiKeyAccount>;
115
+ /** Update the current user account. Only works for user accounts. */
116
+ update(payload: UpdateAccountPayload): Promise<UserAccount>;
117
+ /** Upload a new avatar image. Only works for user accounts. */
118
+ uploadAvatar(image: Blob | ArrayBuffer, contentType: string): Promise<void>;
119
+ /** Fetch the current account avatar image. */
120
+ fetchAvatar(): Promise<Blob>;
121
+ /** Fetch the permission scopes available to the current account. */
122
+ scopes(): Promise<string[]>;
123
+ }
124
+ export {};
125
+ //# sourceMappingURL=account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../../src/src/resources/account.ts"],"names":[],"mappings":"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"}