keept-sdk 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.
@@ -0,0 +1,93 @@
1
+ interface KeeptConfig {
2
+ /** Base URL of the keept-server, e.g. "https://api.keept.io" */
3
+ baseUrl: string;
4
+ /**
5
+ * Optional: provide an existing apiKey to reuse across sessions.
6
+ * If omitted the SDK auto-generates and persists a UUID.
7
+ */
8
+ apiKey?: string;
9
+ /**
10
+ * Called once after the very first auto-registration.
11
+ * Use this to display or persist the credentials before they are
12
+ * stored locally. apiSecret will NOT be retrievable again from the SDK.
13
+ */
14
+ onRegister?: (apiKey: string, apiSecret: string) => void;
15
+ }
16
+ interface RegisterResponse {
17
+ api_secret: string;
18
+ plan: string;
19
+ expires_at: string | null;
20
+ monthly_call_limit: number;
21
+ storage_limit_bytes: number;
22
+ max_value_bytes: number;
23
+ }
24
+ interface LoginResponse {
25
+ access_token: string;
26
+ refresh_token: string;
27
+ expires_in: number;
28
+ }
29
+ interface KVItem {
30
+ key: string;
31
+ value: string;
32
+ }
33
+ interface StatsResponse {
34
+ plan: string;
35
+ monthly_calls: number;
36
+ monthly_call_limit: number;
37
+ storage_used: number;
38
+ storage_limit_bytes: number;
39
+ max_value_bytes: number;
40
+ expires_at: string | null;
41
+ }
42
+ /** Persisted local credentials. */
43
+ interface KeeptCredentials {
44
+ apiKey: string;
45
+ apiSecret: string;
46
+ accessToken: string;
47
+ refreshToken: string;
48
+ /** Unix ms */
49
+ accessTokenExpiresAt: number;
50
+ /** Unix ms */
51
+ refreshTokenExpiresAt: number;
52
+ }
53
+
54
+ declare class KeeptClient {
55
+ private baseUrl;
56
+ private store;
57
+ /** Promise guard to avoid concurrent token-refresh races */
58
+ private refreshPromise;
59
+ /** Called once after the very first registration. */
60
+ private onRegister?;
61
+ constructor(config: KeeptConfig);
62
+ /**
63
+ * Ensures the client is authenticated.
64
+ * - First call: auto-registers a new apiKey (UUID) and logs in.
65
+ * - Subsequent calls: reads credentials from local storage.
66
+ * - If accessToken is expired, refreshes automatically.
67
+ */
68
+ private ensureAuth;
69
+ private registerAndLogin;
70
+ private loginWithStored;
71
+ private doLogin;
72
+ private doRefresh;
73
+ /**
74
+ * Returns the current apiKey, or null if not yet registered.
75
+ * Useful for displaying the key in a dashboard or logs.
76
+ */
77
+ getApiKey(): string | null;
78
+ /** Write or overwrite a value. */
79
+ set(key: string, value: string): Promise<void>;
80
+ /** Read a value. Returns null if the key does not exist. */
81
+ get(key: string): Promise<string | null>;
82
+ /** Delete a single key. Returns true if it existed, false otherwise. */
83
+ delete(key: string): Promise<boolean>;
84
+ /** Get all stored key-value pairs. */
85
+ getAll(): Promise<KVItem[]>;
86
+ /** Delete all stored data. */
87
+ clear(): Promise<void>;
88
+ /** Get usage statistics. */
89
+ stats(): Promise<StatsResponse>;
90
+ private request;
91
+ }
92
+
93
+ export { type KVItem, KeeptClient, type KeeptConfig, type KeeptCredentials, type LoginResponse, type RegisterResponse, type StatsResponse };
@@ -0,0 +1,93 @@
1
+ interface KeeptConfig {
2
+ /** Base URL of the keept-server, e.g. "https://api.keept.io" */
3
+ baseUrl: string;
4
+ /**
5
+ * Optional: provide an existing apiKey to reuse across sessions.
6
+ * If omitted the SDK auto-generates and persists a UUID.
7
+ */
8
+ apiKey?: string;
9
+ /**
10
+ * Called once after the very first auto-registration.
11
+ * Use this to display or persist the credentials before they are
12
+ * stored locally. apiSecret will NOT be retrievable again from the SDK.
13
+ */
14
+ onRegister?: (apiKey: string, apiSecret: string) => void;
15
+ }
16
+ interface RegisterResponse {
17
+ api_secret: string;
18
+ plan: string;
19
+ expires_at: string | null;
20
+ monthly_call_limit: number;
21
+ storage_limit_bytes: number;
22
+ max_value_bytes: number;
23
+ }
24
+ interface LoginResponse {
25
+ access_token: string;
26
+ refresh_token: string;
27
+ expires_in: number;
28
+ }
29
+ interface KVItem {
30
+ key: string;
31
+ value: string;
32
+ }
33
+ interface StatsResponse {
34
+ plan: string;
35
+ monthly_calls: number;
36
+ monthly_call_limit: number;
37
+ storage_used: number;
38
+ storage_limit_bytes: number;
39
+ max_value_bytes: number;
40
+ expires_at: string | null;
41
+ }
42
+ /** Persisted local credentials. */
43
+ interface KeeptCredentials {
44
+ apiKey: string;
45
+ apiSecret: string;
46
+ accessToken: string;
47
+ refreshToken: string;
48
+ /** Unix ms */
49
+ accessTokenExpiresAt: number;
50
+ /** Unix ms */
51
+ refreshTokenExpiresAt: number;
52
+ }
53
+
54
+ declare class KeeptClient {
55
+ private baseUrl;
56
+ private store;
57
+ /** Promise guard to avoid concurrent token-refresh races */
58
+ private refreshPromise;
59
+ /** Called once after the very first registration. */
60
+ private onRegister?;
61
+ constructor(config: KeeptConfig);
62
+ /**
63
+ * Ensures the client is authenticated.
64
+ * - First call: auto-registers a new apiKey (UUID) and logs in.
65
+ * - Subsequent calls: reads credentials from local storage.
66
+ * - If accessToken is expired, refreshes automatically.
67
+ */
68
+ private ensureAuth;
69
+ private registerAndLogin;
70
+ private loginWithStored;
71
+ private doLogin;
72
+ private doRefresh;
73
+ /**
74
+ * Returns the current apiKey, or null if not yet registered.
75
+ * Useful for displaying the key in a dashboard or logs.
76
+ */
77
+ getApiKey(): string | null;
78
+ /** Write or overwrite a value. */
79
+ set(key: string, value: string): Promise<void>;
80
+ /** Read a value. Returns null if the key does not exist. */
81
+ get(key: string): Promise<string | null>;
82
+ /** Delete a single key. Returns true if it existed, false otherwise. */
83
+ delete(key: string): Promise<boolean>;
84
+ /** Get all stored key-value pairs. */
85
+ getAll(): Promise<KVItem[]>;
86
+ /** Delete all stored data. */
87
+ clear(): Promise<void>;
88
+ /** Get usage statistics. */
89
+ stats(): Promise<StatsResponse>;
90
+ private request;
91
+ }
92
+
93
+ export { type KVItem, KeeptClient, type KeeptConfig, type KeeptCredentials, type LoginResponse, type RegisterResponse, type StatsResponse };
package/dist/index.js ADDED
@@ -0,0 +1,293 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ KeeptClient: () => KeeptClient
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/storage.ts
28
+ var STORAGE_KEY = "__keept_creds__";
29
+ function createBrowserStore() {
30
+ return {
31
+ get() {
32
+ try {
33
+ const raw = localStorage.getItem(STORAGE_KEY);
34
+ return raw ? JSON.parse(raw) : null;
35
+ } catch (e) {
36
+ return null;
37
+ }
38
+ },
39
+ set(creds) {
40
+ try {
41
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(creds));
42
+ } catch (e) {
43
+ }
44
+ },
45
+ clear() {
46
+ try {
47
+ localStorage.removeItem(STORAGE_KEY);
48
+ } catch (e) {
49
+ }
50
+ }
51
+ };
52
+ }
53
+ function createFileStore(filePath) {
54
+ let fs = null;
55
+ function getFs() {
56
+ if (!fs) {
57
+ fs = require("fs");
58
+ }
59
+ return fs;
60
+ }
61
+ return {
62
+ get() {
63
+ try {
64
+ const raw = getFs().readFileSync(filePath, "utf-8");
65
+ return JSON.parse(raw);
66
+ } catch (e) {
67
+ return null;
68
+ }
69
+ },
70
+ set(creds) {
71
+ try {
72
+ getFs().writeFileSync(filePath, JSON.stringify(creds, null, 2), "utf-8");
73
+ } catch (e) {
74
+ }
75
+ },
76
+ clear() {
77
+ try {
78
+ getFs().unlinkSync(filePath);
79
+ } catch (e) {
80
+ }
81
+ }
82
+ };
83
+ }
84
+ function createMemoryStore() {
85
+ let data = null;
86
+ return {
87
+ get: () => data,
88
+ set: (creds) => {
89
+ data = creds;
90
+ },
91
+ clear: () => {
92
+ data = null;
93
+ }
94
+ };
95
+ }
96
+ function createStore(filePathOverride) {
97
+ var _a;
98
+ if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
99
+ return createBrowserStore();
100
+ }
101
+ if (typeof process !== "undefined" && ((_a = process.versions) == null ? void 0 : _a.node)) {
102
+ const path = filePathOverride != null ? filePathOverride : ".keept";
103
+ return createFileStore(path);
104
+ }
105
+ return createMemoryStore();
106
+ }
107
+
108
+ // src/client.ts
109
+ var KeeptError = class extends Error {
110
+ constructor(status, message) {
111
+ super(message);
112
+ this.status = status;
113
+ this.name = "KeeptError";
114
+ }
115
+ };
116
+ function generateUUID() {
117
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
118
+ return crypto.randomUUID();
119
+ }
120
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
121
+ const r = Math.random() * 16 | 0;
122
+ return (c === "x" ? r : r & 3 | 8).toString(16);
123
+ });
124
+ }
125
+ var KeeptClient = class {
126
+ constructor(config) {
127
+ /** Promise guard to avoid concurrent token-refresh races */
128
+ this.refreshPromise = null;
129
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
130
+ this.store = createStore();
131
+ this.onRegister = config.onRegister;
132
+ if (config.apiKey) {
133
+ const creds = this.store.get();
134
+ if (creds && creds.apiKey !== config.apiKey) {
135
+ this.store.clear();
136
+ }
137
+ }
138
+ }
139
+ // ------------------------------------------------------------------ auth
140
+ /**
141
+ * Ensures the client is authenticated.
142
+ * - First call: auto-registers a new apiKey (UUID) and logs in.
143
+ * - Subsequent calls: reads credentials from local storage.
144
+ * - If accessToken is expired, refreshes automatically.
145
+ */
146
+ async ensureAuth() {
147
+ let creds = this.store.get();
148
+ if (!creds) {
149
+ creds = await this.registerAndLogin();
150
+ }
151
+ if (Date.now() < creds.accessTokenExpiresAt - 6e4) {
152
+ return creds.accessToken;
153
+ }
154
+ if (Date.now() < creds.refreshTokenExpiresAt - 6e4) {
155
+ if (!this.refreshPromise) {
156
+ this.refreshPromise = this.doRefresh(creds).finally(() => {
157
+ this.refreshPromise = null;
158
+ });
159
+ }
160
+ await this.refreshPromise;
161
+ return this.store.get().accessToken;
162
+ }
163
+ creds = await this.loginWithStored(creds);
164
+ return creds.accessToken;
165
+ }
166
+ async registerAndLogin() {
167
+ var _a;
168
+ const apiKey = generateUUID();
169
+ const regRes = await this.request("POST", "/v1/register", { api_key: apiKey }, false);
170
+ const loginRes = await this.doLogin(apiKey, regRes.api_secret);
171
+ const creds = {
172
+ apiKey,
173
+ apiSecret: regRes.api_secret,
174
+ accessToken: loginRes.access_token,
175
+ refreshToken: loginRes.refresh_token,
176
+ accessTokenExpiresAt: Date.now() + loginRes.expires_in * 1e3,
177
+ refreshTokenExpiresAt: Date.now() + 30 * 24 * 60 * 60 * 1e3
178
+ };
179
+ this.store.set(creds);
180
+ (_a = this.onRegister) == null ? void 0 : _a.call(this, apiKey, regRes.api_secret);
181
+ return creds;
182
+ }
183
+ async loginWithStored(creds) {
184
+ const loginRes = await this.doLogin(creds.apiKey, creds.apiSecret);
185
+ const updated = {
186
+ ...creds,
187
+ accessToken: loginRes.access_token,
188
+ refreshToken: loginRes.refresh_token,
189
+ accessTokenExpiresAt: Date.now() + loginRes.expires_in * 1e3,
190
+ refreshTokenExpiresAt: Date.now() + 30 * 24 * 60 * 60 * 1e3
191
+ };
192
+ this.store.set(updated);
193
+ return updated;
194
+ }
195
+ async doLogin(apiKey, apiSecret) {
196
+ return this.request("POST", "/v1/login", { api_key: apiKey, api_secret: apiSecret }, false);
197
+ }
198
+ async doRefresh(creds) {
199
+ const res = await this.request(
200
+ "POST",
201
+ "/v1/refresh",
202
+ { refresh_token: creds.refreshToken },
203
+ false
204
+ );
205
+ const updated = {
206
+ ...creds,
207
+ accessToken: res.access_token,
208
+ accessTokenExpiresAt: Date.now() + res.expires_in * 1e3
209
+ };
210
+ this.store.set(updated);
211
+ }
212
+ // ------------------------------------------------------------------ public helpers
213
+ /**
214
+ * Returns the current apiKey, or null if not yet registered.
215
+ * Useful for displaying the key in a dashboard or logs.
216
+ */
217
+ getApiKey() {
218
+ var _a, _b;
219
+ return (_b = (_a = this.store.get()) == null ? void 0 : _a.apiKey) != null ? _b : null;
220
+ }
221
+ // ------------------------------------------------------------------ KV
222
+ /** Write or overwrite a value. */
223
+ async set(key, value) {
224
+ const token = await this.ensureAuth();
225
+ await this.request("POST", "/v1/set", { key, value }, true, token);
226
+ }
227
+ /** Read a value. Returns null if the key does not exist. */
228
+ async get(key) {
229
+ const token = await this.ensureAuth();
230
+ try {
231
+ const res = await this.request("GET", `/v1/get?key=${encodeURIComponent(key)}`, void 0, true, token);
232
+ return res.value;
233
+ } catch (err) {
234
+ if (err instanceof KeeptError && err.status === 404) return null;
235
+ throw err;
236
+ }
237
+ }
238
+ /** Delete a single key. Returns true if it existed, false otherwise. */
239
+ async delete(key) {
240
+ const token = await this.ensureAuth();
241
+ try {
242
+ await this.request("DELETE", `/v1/delete?key=${encodeURIComponent(key)}`, void 0, true, token);
243
+ return true;
244
+ } catch (err) {
245
+ if (err instanceof KeeptError && err.status === 404) return false;
246
+ throw err;
247
+ }
248
+ }
249
+ /** Get all stored key-value pairs. */
250
+ async getAll() {
251
+ const token = await this.ensureAuth();
252
+ const res = await this.request("GET", "/v1/all", void 0, true, token);
253
+ return res.data;
254
+ }
255
+ /** Delete all stored data. */
256
+ async clear() {
257
+ const token = await this.ensureAuth();
258
+ await this.request("DELETE", "/v1/clear", void 0, true, token);
259
+ }
260
+ /** Get usage statistics. */
261
+ async stats() {
262
+ const token = await this.ensureAuth();
263
+ return this.request("GET", "/v1/stats", void 0, true, token);
264
+ }
265
+ // ------------------------------------------------------------------ http
266
+ async request(method, path, body, auth = true, token) {
267
+ const headers = {
268
+ "Content-Type": "application/json"
269
+ };
270
+ if (auth && token) {
271
+ headers["Authorization"] = `Bearer ${token}`;
272
+ }
273
+ const res = await fetch(`${this.baseUrl}${path}`, {
274
+ method,
275
+ headers,
276
+ body: body !== void 0 ? JSON.stringify(body) : void 0
277
+ });
278
+ if (!res.ok) {
279
+ let message = res.statusText;
280
+ try {
281
+ const json = await res.json();
282
+ if (json.error) message = json.error;
283
+ } catch (e) {
284
+ }
285
+ throw new KeeptError(res.status, message);
286
+ }
287
+ return res.json();
288
+ }
289
+ };
290
+ // Annotate the CommonJS export names for ESM import in node:
291
+ 0 && (module.exports = {
292
+ KeeptClient
293
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,273 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/storage.ts
9
+ var STORAGE_KEY = "__keept_creds__";
10
+ function createBrowserStore() {
11
+ return {
12
+ get() {
13
+ try {
14
+ const raw = localStorage.getItem(STORAGE_KEY);
15
+ return raw ? JSON.parse(raw) : null;
16
+ } catch (e) {
17
+ return null;
18
+ }
19
+ },
20
+ set(creds) {
21
+ try {
22
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(creds));
23
+ } catch (e) {
24
+ }
25
+ },
26
+ clear() {
27
+ try {
28
+ localStorage.removeItem(STORAGE_KEY);
29
+ } catch (e) {
30
+ }
31
+ }
32
+ };
33
+ }
34
+ function createFileStore(filePath) {
35
+ let fs = null;
36
+ function getFs() {
37
+ if (!fs) {
38
+ fs = __require("fs");
39
+ }
40
+ return fs;
41
+ }
42
+ return {
43
+ get() {
44
+ try {
45
+ const raw = getFs().readFileSync(filePath, "utf-8");
46
+ return JSON.parse(raw);
47
+ } catch (e) {
48
+ return null;
49
+ }
50
+ },
51
+ set(creds) {
52
+ try {
53
+ getFs().writeFileSync(filePath, JSON.stringify(creds, null, 2), "utf-8");
54
+ } catch (e) {
55
+ }
56
+ },
57
+ clear() {
58
+ try {
59
+ getFs().unlinkSync(filePath);
60
+ } catch (e) {
61
+ }
62
+ }
63
+ };
64
+ }
65
+ function createMemoryStore() {
66
+ let data = null;
67
+ return {
68
+ get: () => data,
69
+ set: (creds) => {
70
+ data = creds;
71
+ },
72
+ clear: () => {
73
+ data = null;
74
+ }
75
+ };
76
+ }
77
+ function createStore(filePathOverride) {
78
+ var _a;
79
+ if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
80
+ return createBrowserStore();
81
+ }
82
+ if (typeof process !== "undefined" && ((_a = process.versions) == null ? void 0 : _a.node)) {
83
+ const path = filePathOverride != null ? filePathOverride : ".keept";
84
+ return createFileStore(path);
85
+ }
86
+ return createMemoryStore();
87
+ }
88
+
89
+ // src/client.ts
90
+ var KeeptError = class extends Error {
91
+ constructor(status, message) {
92
+ super(message);
93
+ this.status = status;
94
+ this.name = "KeeptError";
95
+ }
96
+ };
97
+ function generateUUID() {
98
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
99
+ return crypto.randomUUID();
100
+ }
101
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
102
+ const r = Math.random() * 16 | 0;
103
+ return (c === "x" ? r : r & 3 | 8).toString(16);
104
+ });
105
+ }
106
+ var KeeptClient = class {
107
+ constructor(config) {
108
+ /** Promise guard to avoid concurrent token-refresh races */
109
+ this.refreshPromise = null;
110
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
111
+ this.store = createStore();
112
+ this.onRegister = config.onRegister;
113
+ if (config.apiKey) {
114
+ const creds = this.store.get();
115
+ if (creds && creds.apiKey !== config.apiKey) {
116
+ this.store.clear();
117
+ }
118
+ }
119
+ }
120
+ // ------------------------------------------------------------------ auth
121
+ /**
122
+ * Ensures the client is authenticated.
123
+ * - First call: auto-registers a new apiKey (UUID) and logs in.
124
+ * - Subsequent calls: reads credentials from local storage.
125
+ * - If accessToken is expired, refreshes automatically.
126
+ */
127
+ async ensureAuth() {
128
+ let creds = this.store.get();
129
+ if (!creds) {
130
+ creds = await this.registerAndLogin();
131
+ }
132
+ if (Date.now() < creds.accessTokenExpiresAt - 6e4) {
133
+ return creds.accessToken;
134
+ }
135
+ if (Date.now() < creds.refreshTokenExpiresAt - 6e4) {
136
+ if (!this.refreshPromise) {
137
+ this.refreshPromise = this.doRefresh(creds).finally(() => {
138
+ this.refreshPromise = null;
139
+ });
140
+ }
141
+ await this.refreshPromise;
142
+ return this.store.get().accessToken;
143
+ }
144
+ creds = await this.loginWithStored(creds);
145
+ return creds.accessToken;
146
+ }
147
+ async registerAndLogin() {
148
+ var _a;
149
+ const apiKey = generateUUID();
150
+ const regRes = await this.request("POST", "/v1/register", { api_key: apiKey }, false);
151
+ const loginRes = await this.doLogin(apiKey, regRes.api_secret);
152
+ const creds = {
153
+ apiKey,
154
+ apiSecret: regRes.api_secret,
155
+ accessToken: loginRes.access_token,
156
+ refreshToken: loginRes.refresh_token,
157
+ accessTokenExpiresAt: Date.now() + loginRes.expires_in * 1e3,
158
+ refreshTokenExpiresAt: Date.now() + 30 * 24 * 60 * 60 * 1e3
159
+ };
160
+ this.store.set(creds);
161
+ (_a = this.onRegister) == null ? void 0 : _a.call(this, apiKey, regRes.api_secret);
162
+ return creds;
163
+ }
164
+ async loginWithStored(creds) {
165
+ const loginRes = await this.doLogin(creds.apiKey, creds.apiSecret);
166
+ const updated = {
167
+ ...creds,
168
+ accessToken: loginRes.access_token,
169
+ refreshToken: loginRes.refresh_token,
170
+ accessTokenExpiresAt: Date.now() + loginRes.expires_in * 1e3,
171
+ refreshTokenExpiresAt: Date.now() + 30 * 24 * 60 * 60 * 1e3
172
+ };
173
+ this.store.set(updated);
174
+ return updated;
175
+ }
176
+ async doLogin(apiKey, apiSecret) {
177
+ return this.request("POST", "/v1/login", { api_key: apiKey, api_secret: apiSecret }, false);
178
+ }
179
+ async doRefresh(creds) {
180
+ const res = await this.request(
181
+ "POST",
182
+ "/v1/refresh",
183
+ { refresh_token: creds.refreshToken },
184
+ false
185
+ );
186
+ const updated = {
187
+ ...creds,
188
+ accessToken: res.access_token,
189
+ accessTokenExpiresAt: Date.now() + res.expires_in * 1e3
190
+ };
191
+ this.store.set(updated);
192
+ }
193
+ // ------------------------------------------------------------------ public helpers
194
+ /**
195
+ * Returns the current apiKey, or null if not yet registered.
196
+ * Useful for displaying the key in a dashboard or logs.
197
+ */
198
+ getApiKey() {
199
+ var _a, _b;
200
+ return (_b = (_a = this.store.get()) == null ? void 0 : _a.apiKey) != null ? _b : null;
201
+ }
202
+ // ------------------------------------------------------------------ KV
203
+ /** Write or overwrite a value. */
204
+ async set(key, value) {
205
+ const token = await this.ensureAuth();
206
+ await this.request("POST", "/v1/set", { key, value }, true, token);
207
+ }
208
+ /** Read a value. Returns null if the key does not exist. */
209
+ async get(key) {
210
+ const token = await this.ensureAuth();
211
+ try {
212
+ const res = await this.request("GET", `/v1/get?key=${encodeURIComponent(key)}`, void 0, true, token);
213
+ return res.value;
214
+ } catch (err) {
215
+ if (err instanceof KeeptError && err.status === 404) return null;
216
+ throw err;
217
+ }
218
+ }
219
+ /** Delete a single key. Returns true if it existed, false otherwise. */
220
+ async delete(key) {
221
+ const token = await this.ensureAuth();
222
+ try {
223
+ await this.request("DELETE", `/v1/delete?key=${encodeURIComponent(key)}`, void 0, true, token);
224
+ return true;
225
+ } catch (err) {
226
+ if (err instanceof KeeptError && err.status === 404) return false;
227
+ throw err;
228
+ }
229
+ }
230
+ /** Get all stored key-value pairs. */
231
+ async getAll() {
232
+ const token = await this.ensureAuth();
233
+ const res = await this.request("GET", "/v1/all", void 0, true, token);
234
+ return res.data;
235
+ }
236
+ /** Delete all stored data. */
237
+ async clear() {
238
+ const token = await this.ensureAuth();
239
+ await this.request("DELETE", "/v1/clear", void 0, true, token);
240
+ }
241
+ /** Get usage statistics. */
242
+ async stats() {
243
+ const token = await this.ensureAuth();
244
+ return this.request("GET", "/v1/stats", void 0, true, token);
245
+ }
246
+ // ------------------------------------------------------------------ http
247
+ async request(method, path, body, auth = true, token) {
248
+ const headers = {
249
+ "Content-Type": "application/json"
250
+ };
251
+ if (auth && token) {
252
+ headers["Authorization"] = `Bearer ${token}`;
253
+ }
254
+ const res = await fetch(`${this.baseUrl}${path}`, {
255
+ method,
256
+ headers,
257
+ body: body !== void 0 ? JSON.stringify(body) : void 0
258
+ });
259
+ if (!res.ok) {
260
+ let message = res.statusText;
261
+ try {
262
+ const json = await res.json();
263
+ if (json.error) message = json.error;
264
+ } catch (e) {
265
+ }
266
+ throw new KeeptError(res.status, message);
267
+ }
268
+ return res.json();
269
+ }
270
+ };
271
+ export {
272
+ KeeptClient
273
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "keept-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight multi-platform user data sync SDK",
5
+ "author": "fengwenyi",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/fengwenyi/keept-sdk",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/fengwenyi/keept-sdk.git"
11
+ },
12
+ "keywords": ["sync", "kv", "storage", "multiplatform", "keept"],
13
+ "main": "dist/index.js",
14
+ "module": "dist/index.mjs",
15
+ "types": "dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
28
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
29
+ "typecheck": "tsc --noEmit",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "devDependencies": {
33
+ "tsup": "^8.0.0",
34
+ "typescript": "^5.3.0"
35
+ }
36
+ }