@codixus/client 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/LICENSE +31 -0
- package/dist/index.cjs +451 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +112 -0
- package/dist/index.d.ts +112 -0
- package/dist/index.js +413 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +75 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +31 -0
- package/dist/react/index.d.ts +31 -0
- package/dist/react/index.js +51 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Codixus SDK - Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Codixus. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
proprietary property of Codixus.
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted to install and use the Software in applications
|
|
9
|
+
developed by the licensee, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
1. The Software may not be copied, modified, merged, published, distributed,
|
|
12
|
+
sublicensed, or sold, in whole or in part, without the prior written
|
|
13
|
+
permission of Codixus.
|
|
14
|
+
|
|
15
|
+
2. The Software may not be reverse engineered, decompiled, or disassembled,
|
|
16
|
+
except to the extent that such activity is expressly permitted by
|
|
17
|
+
applicable law.
|
|
18
|
+
|
|
19
|
+
3. The source code of the Software may not be used to create derivative
|
|
20
|
+
works or competing products.
|
|
21
|
+
|
|
22
|
+
4. This license does not grant any rights to use the Codixus name, logo,
|
|
23
|
+
or trademarks.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ApiClient: () => ApiClient,
|
|
34
|
+
CodixusClient: () => CodixusClient,
|
|
35
|
+
CodixusError: () => import_shared.CodixusError,
|
|
36
|
+
Collection: () => Collection,
|
|
37
|
+
ErrorCodes: () => import_shared.ErrorCodes
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(index_exports);
|
|
40
|
+
|
|
41
|
+
// src/auth/auth-manager.ts
|
|
42
|
+
var AuthManager = class {
|
|
43
|
+
constructor(storage, storageKey) {
|
|
44
|
+
this.storage = storage;
|
|
45
|
+
this.storageKey = storageKey;
|
|
46
|
+
}
|
|
47
|
+
accessToken = null;
|
|
48
|
+
refreshTokenValue = null;
|
|
49
|
+
user = null;
|
|
50
|
+
listeners = /* @__PURE__ */ new Set();
|
|
51
|
+
_isLoading = true;
|
|
52
|
+
storageKey;
|
|
53
|
+
api;
|
|
54
|
+
deviceId = null;
|
|
55
|
+
/** @internal */
|
|
56
|
+
_setApi(api) {
|
|
57
|
+
this.api = api;
|
|
58
|
+
}
|
|
59
|
+
async init() {
|
|
60
|
+
if (!this.storage) {
|
|
61
|
+
this._isLoading = false;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const storedRefresh = await this.storage.getItem(
|
|
66
|
+
`${this.storageKey}_refresh_token`
|
|
67
|
+
);
|
|
68
|
+
const storedUser = await this.storage.getItem(
|
|
69
|
+
`${this.storageKey}_user`
|
|
70
|
+
);
|
|
71
|
+
const storedDeviceId = await this.storage.getItem(
|
|
72
|
+
`${this.storageKey}_device_id`
|
|
73
|
+
);
|
|
74
|
+
if (storedRefresh) {
|
|
75
|
+
this.refreshTokenValue = storedRefresh;
|
|
76
|
+
}
|
|
77
|
+
if (storedUser) {
|
|
78
|
+
try {
|
|
79
|
+
this.user = JSON.parse(storedUser);
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (storedDeviceId) {
|
|
84
|
+
this.deviceId = storedDeviceId;
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.warn("[CodixusClient] Failed to restore auth state from storage:", error);
|
|
88
|
+
}
|
|
89
|
+
this._isLoading = false;
|
|
90
|
+
this.notify();
|
|
91
|
+
}
|
|
92
|
+
async signIn(params) {
|
|
93
|
+
const deviceId = params.deviceId ?? this.deviceId ?? this.generateDeviceId();
|
|
94
|
+
const response = await this.api.post("/auth/token", {
|
|
95
|
+
deviceId,
|
|
96
|
+
deviceInfo: params.deviceInfo,
|
|
97
|
+
metadata: params.metadata
|
|
98
|
+
});
|
|
99
|
+
const data = response.data;
|
|
100
|
+
this.accessToken = data.accessToken;
|
|
101
|
+
this.refreshTokenValue = data.refreshToken;
|
|
102
|
+
this.user = data.user;
|
|
103
|
+
this.deviceId = deviceId;
|
|
104
|
+
if (this.storage) {
|
|
105
|
+
await this.storage.setItem(
|
|
106
|
+
`${this.storageKey}_refresh_token`,
|
|
107
|
+
data.refreshToken
|
|
108
|
+
);
|
|
109
|
+
await this.storage.setItem(
|
|
110
|
+
`${this.storageKey}_user`,
|
|
111
|
+
JSON.stringify(data.user)
|
|
112
|
+
);
|
|
113
|
+
await this.storage.setItem(`${this.storageKey}_device_id`, deviceId);
|
|
114
|
+
}
|
|
115
|
+
this.notify();
|
|
116
|
+
return { user: data.user, isNewUser: data.isNewUser };
|
|
117
|
+
}
|
|
118
|
+
async getToken() {
|
|
119
|
+
if (this.accessToken) return this.accessToken;
|
|
120
|
+
if (this.refreshTokenValue) {
|
|
121
|
+
try {
|
|
122
|
+
await this.forceRefresh();
|
|
123
|
+
return this.accessToken;
|
|
124
|
+
} catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
async forceRefresh() {
|
|
131
|
+
if (!this.refreshTokenValue) return null;
|
|
132
|
+
try {
|
|
133
|
+
const response = await this.api.post("/auth/refresh", {
|
|
134
|
+
refreshToken: this.refreshTokenValue
|
|
135
|
+
});
|
|
136
|
+
this.accessToken = response.data.accessToken;
|
|
137
|
+
this.refreshTokenValue = response.data.refreshToken;
|
|
138
|
+
if (this.storage) {
|
|
139
|
+
await this.storage.setItem(
|
|
140
|
+
`${this.storageKey}_refresh_token`,
|
|
141
|
+
response.data.refreshToken
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return this.accessToken;
|
|
145
|
+
} catch {
|
|
146
|
+
await this.signOut();
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async signOut() {
|
|
151
|
+
if (this.refreshTokenValue) {
|
|
152
|
+
try {
|
|
153
|
+
await this.api.post("/auth/logout", {
|
|
154
|
+
refreshToken: this.refreshTokenValue
|
|
155
|
+
});
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
this.accessToken = null;
|
|
160
|
+
this.refreshTokenValue = null;
|
|
161
|
+
this.user = null;
|
|
162
|
+
if (this.storage) {
|
|
163
|
+
await this.storage.removeItem(`${this.storageKey}_refresh_token`);
|
|
164
|
+
await this.storage.removeItem(`${this.storageKey}_user`);
|
|
165
|
+
await this.storage.removeItem(`${this.storageKey}_device_id`);
|
|
166
|
+
}
|
|
167
|
+
this.notify();
|
|
168
|
+
}
|
|
169
|
+
getState() {
|
|
170
|
+
return {
|
|
171
|
+
isAuthenticated: this.accessToken !== null || this.refreshTokenValue !== null,
|
|
172
|
+
isLoading: this._isLoading,
|
|
173
|
+
user: this.user
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
getDeviceId() {
|
|
177
|
+
return this.deviceId;
|
|
178
|
+
}
|
|
179
|
+
onAuthStateChange(listener) {
|
|
180
|
+
this.listeners.add(listener);
|
|
181
|
+
listener(this.getState());
|
|
182
|
+
return () => {
|
|
183
|
+
this.listeners.delete(listener);
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/** @internal - used by API interceptor */
|
|
187
|
+
_getAccessToken() {
|
|
188
|
+
return this.accessToken;
|
|
189
|
+
}
|
|
190
|
+
/** @internal - called by API interceptor after refresh */
|
|
191
|
+
_setAccessToken(token) {
|
|
192
|
+
this.accessToken = token;
|
|
193
|
+
}
|
|
194
|
+
notify() {
|
|
195
|
+
const state = this.getState();
|
|
196
|
+
for (const listener of this.listeners) {
|
|
197
|
+
listener(state);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
generateDeviceId() {
|
|
201
|
+
const bytes = new Uint8Array(16);
|
|
202
|
+
crypto.getRandomValues(bytes);
|
|
203
|
+
return "dev-" + Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// src/api/api-client.ts
|
|
208
|
+
var import_axios = __toESM(require("axios"), 1);
|
|
209
|
+
async function sha256(data) {
|
|
210
|
+
if (typeof globalThis.crypto?.subtle !== "undefined") {
|
|
211
|
+
const encoded = new TextEncoder().encode(data);
|
|
212
|
+
const hash = await globalThis.crypto.subtle.digest("SHA-256", encoded);
|
|
213
|
+
return Array.from(
|
|
214
|
+
new Uint8Array(hash),
|
|
215
|
+
(b) => b.toString(16).padStart(2, "0")
|
|
216
|
+
).join("");
|
|
217
|
+
}
|
|
218
|
+
return simpleHash(data);
|
|
219
|
+
}
|
|
220
|
+
async function hmacSha256(secret, data) {
|
|
221
|
+
if (typeof globalThis.crypto?.subtle !== "undefined") {
|
|
222
|
+
const key = await globalThis.crypto.subtle.importKey(
|
|
223
|
+
"raw",
|
|
224
|
+
new TextEncoder().encode(secret),
|
|
225
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
226
|
+
false,
|
|
227
|
+
["sign"]
|
|
228
|
+
);
|
|
229
|
+
const sig = await globalThis.crypto.subtle.sign(
|
|
230
|
+
"HMAC",
|
|
231
|
+
key,
|
|
232
|
+
new TextEncoder().encode(data)
|
|
233
|
+
);
|
|
234
|
+
return Array.from(
|
|
235
|
+
new Uint8Array(sig),
|
|
236
|
+
(b) => b.toString(16).padStart(2, "0")
|
|
237
|
+
).join("");
|
|
238
|
+
}
|
|
239
|
+
return simpleHmac(secret, data);
|
|
240
|
+
}
|
|
241
|
+
function simpleHash(str) {
|
|
242
|
+
let hash = 0;
|
|
243
|
+
for (let i = 0; i < str.length; i++) {
|
|
244
|
+
const char = str.charCodeAt(i);
|
|
245
|
+
hash = (hash << 5) - hash + char;
|
|
246
|
+
hash |= 0;
|
|
247
|
+
}
|
|
248
|
+
return Math.abs(hash).toString(16).padStart(16, "0");
|
|
249
|
+
}
|
|
250
|
+
function simpleHmac(key, data) {
|
|
251
|
+
return simpleHash(key + ":" + data);
|
|
252
|
+
}
|
|
253
|
+
function generateNonce() {
|
|
254
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
255
|
+
return globalThis.crypto.randomUUID();
|
|
256
|
+
}
|
|
257
|
+
const bytes = new Uint8Array(16);
|
|
258
|
+
if (typeof globalThis.crypto?.getRandomValues === "function") {
|
|
259
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
260
|
+
} else {
|
|
261
|
+
for (let i = 0; i < 16; i++) {
|
|
262
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
266
|
+
}
|
|
267
|
+
var ApiClient = class {
|
|
268
|
+
constructor(baseURL, authManager, appSecret) {
|
|
269
|
+
this.authManager = authManager;
|
|
270
|
+
this.appSecret = appSecret;
|
|
271
|
+
this.instance = import_axios.default.create({
|
|
272
|
+
baseURL,
|
|
273
|
+
headers: { "Content-Type": "application/json" }
|
|
274
|
+
});
|
|
275
|
+
this.instance.interceptors.request.use(async (config) => {
|
|
276
|
+
if (!config.url?.includes("/auth/")) {
|
|
277
|
+
const token = this.authManager._getAccessToken();
|
|
278
|
+
if (token) {
|
|
279
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (this.appSecret) {
|
|
283
|
+
const timestamp = Date.now().toString();
|
|
284
|
+
const nonce = generateNonce();
|
|
285
|
+
const body = config.data && typeof config.data === "object" ? JSON.stringify(config.data) : config.data ?? "";
|
|
286
|
+
const bodyHash = body ? await sha256(body) : "";
|
|
287
|
+
const method = (config.method ?? "GET").toUpperCase();
|
|
288
|
+
const url = config.url ?? "/";
|
|
289
|
+
const payload = [method, url, timestamp, nonce, bodyHash].join("\n");
|
|
290
|
+
const signature = await hmacSha256(this.appSecret, payload);
|
|
291
|
+
config.headers["X-Codixus-Timestamp"] = timestamp;
|
|
292
|
+
config.headers["X-Codixus-Nonce"] = nonce;
|
|
293
|
+
config.headers["X-Codixus-Signature"] = signature;
|
|
294
|
+
}
|
|
295
|
+
return config;
|
|
296
|
+
});
|
|
297
|
+
this.instance.interceptors.response.use(
|
|
298
|
+
(response) => response,
|
|
299
|
+
async (error) => {
|
|
300
|
+
if (error.response?.status === 401) {
|
|
301
|
+
const originalRequest = error.config;
|
|
302
|
+
if (originalRequest && !originalRequest._retry) {
|
|
303
|
+
originalRequest._retry = true;
|
|
304
|
+
try {
|
|
305
|
+
if (!this.refreshPromise) {
|
|
306
|
+
this.refreshPromise = this.authManager.forceRefresh().finally(() => {
|
|
307
|
+
this.refreshPromise = null;
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
const newToken = await this.refreshPromise;
|
|
311
|
+
if (newToken) {
|
|
312
|
+
originalRequest.headers.Authorization = `Bearer ${newToken}`;
|
|
313
|
+
return this.instance(originalRequest);
|
|
314
|
+
}
|
|
315
|
+
} catch (refreshError) {
|
|
316
|
+
console.warn("[CodixusClient] Token refresh failed:", refreshError);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return Promise.reject(error);
|
|
321
|
+
}
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
instance;
|
|
325
|
+
refreshPromise = null;
|
|
326
|
+
appSecret;
|
|
327
|
+
async get(url, config) {
|
|
328
|
+
return this.instance.get(url, config);
|
|
329
|
+
}
|
|
330
|
+
async post(url, data, config) {
|
|
331
|
+
return this.instance.post(url, data, config);
|
|
332
|
+
}
|
|
333
|
+
async patch(url, data, config) {
|
|
334
|
+
return this.instance.patch(url, data, config);
|
|
335
|
+
}
|
|
336
|
+
async delete(url, config) {
|
|
337
|
+
return this.instance.delete(url, config);
|
|
338
|
+
}
|
|
339
|
+
async put(url, data, config) {
|
|
340
|
+
return this.instance.put(url, data, config);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
// src/db/collection.ts
|
|
345
|
+
var Collection = class {
|
|
346
|
+
constructor(api, basePath) {
|
|
347
|
+
this.api = api;
|
|
348
|
+
this.basePath = basePath;
|
|
349
|
+
}
|
|
350
|
+
async find(filter, options) {
|
|
351
|
+
const params = new URLSearchParams();
|
|
352
|
+
if (filter && Object.keys(filter).length > 0) {
|
|
353
|
+
params.set("filter", JSON.stringify(filter));
|
|
354
|
+
}
|
|
355
|
+
if (options?.sort) params.set("sort", JSON.stringify(options.sort));
|
|
356
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
357
|
+
if (options?.skip) params.set("skip", String(options.skip));
|
|
358
|
+
if (options?.cursor) params.set("cursor", String(options.cursor));
|
|
359
|
+
const qs = params.toString();
|
|
360
|
+
const url = qs ? `${this.basePath}?${qs}` : this.basePath;
|
|
361
|
+
const { data } = await this.api.get(url);
|
|
362
|
+
return data.data;
|
|
363
|
+
}
|
|
364
|
+
async findWithCursor(filter, options) {
|
|
365
|
+
const params = new URLSearchParams();
|
|
366
|
+
if (filter && Object.keys(filter).length > 0) {
|
|
367
|
+
params.set("filter", JSON.stringify(filter));
|
|
368
|
+
}
|
|
369
|
+
if (options?.sort) params.set("sort", JSON.stringify(options.sort));
|
|
370
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
371
|
+
if (options?.cursor) params.set("cursor", String(options.cursor));
|
|
372
|
+
const qs = params.toString();
|
|
373
|
+
const url = qs ? `${this.basePath}?${qs}` : this.basePath;
|
|
374
|
+
const { data } = await this.api.get(url);
|
|
375
|
+
return { data: data.data, nextCursor: data.nextCursor };
|
|
376
|
+
}
|
|
377
|
+
async findById(id) {
|
|
378
|
+
try {
|
|
379
|
+
const { data } = await this.api.get(
|
|
380
|
+
`${this.basePath}/${id}`
|
|
381
|
+
);
|
|
382
|
+
return data.data;
|
|
383
|
+
} catch (error) {
|
|
384
|
+
if (error.response?.status === 404) return null;
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async create(doc) {
|
|
389
|
+
const { data } = await this.api.post(
|
|
390
|
+
this.basePath,
|
|
391
|
+
doc
|
|
392
|
+
);
|
|
393
|
+
return data.data;
|
|
394
|
+
}
|
|
395
|
+
async updateById(id, update) {
|
|
396
|
+
const { data } = await this.api.patch(
|
|
397
|
+
`${this.basePath}/${id}`,
|
|
398
|
+
{ update }
|
|
399
|
+
);
|
|
400
|
+
return data.data;
|
|
401
|
+
}
|
|
402
|
+
async deleteById(id) {
|
|
403
|
+
await this.api.delete(`${this.basePath}/${id}`);
|
|
404
|
+
}
|
|
405
|
+
async count(filter) {
|
|
406
|
+
const { data } = await this.api.post(
|
|
407
|
+
`${this.basePath}/count`,
|
|
408
|
+
{ filter: filter ?? {} }
|
|
409
|
+
);
|
|
410
|
+
return data.count;
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// src/index.ts
|
|
415
|
+
var import_shared = require("@codixus/shared");
|
|
416
|
+
var CodixusClient = class {
|
|
417
|
+
auth;
|
|
418
|
+
api;
|
|
419
|
+
constructor(config) {
|
|
420
|
+
const storageKey = config.storageKey ?? "codixus";
|
|
421
|
+
const storage = config.storage ?? null;
|
|
422
|
+
this.auth = new AuthManager(storage, storageKey);
|
|
423
|
+
this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);
|
|
424
|
+
this.auth._setApi(this.api);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Create a typed collection accessor.
|
|
428
|
+
* Maps to auto REST routes on server: codixus.rest(Model)
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* interface Product { _id: string; name: string; price: number; }
|
|
432
|
+
* const products = codixus.collection<Product>("products");
|
|
433
|
+
* const all = await products.find(); // Product[]
|
|
434
|
+
* const one = await products.findById("abc"); // Product | null
|
|
435
|
+
*/
|
|
436
|
+
collection(name) {
|
|
437
|
+
return new Collection(this.api, `/api/${name}`);
|
|
438
|
+
}
|
|
439
|
+
async init() {
|
|
440
|
+
await this.auth.init();
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
444
|
+
0 && (module.exports = {
|
|
445
|
+
ApiClient,
|
|
446
|
+
CodixusClient,
|
|
447
|
+
CodixusError,
|
|
448
|
+
Collection,
|
|
449
|
+
ErrorCodes
|
|
450
|
+
});
|
|
451
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/auth/auth-manager.ts","../src/api/api-client.ts","../src/db/collection.ts"],"sourcesContent":["import {\n AuthManager,\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n} from \"./auth/auth-manager.js\";\nimport { ApiClient } from \"./api/api-client.js\";\nimport { Collection, type FindOptions } from \"./db/collection.js\";\n\nexport interface CodixusClientConfig {\n apiUrl: string;\n storageKey?: string;\n storage?: StorageAdapter | null;\n appSecret?: string;\n}\n\nexport class CodixusClient {\n readonly auth: AuthManager;\n readonly api: ApiClient;\n\n constructor(config: CodixusClientConfig) {\n const storageKey = config.storageKey ?? \"codixus\";\n const storage = config.storage ?? null;\n\n this.auth = new AuthManager(storage, storageKey);\n this.api = new ApiClient(config.apiUrl, this.auth, config.appSecret);\n this.auth._setApi(this.api);\n }\n\n /**\n * Create a typed collection accessor.\n * Maps to auto REST routes on server: codixus.rest(Model)\n *\n * @example\n * interface Product { _id: string; name: string; price: number; }\n * const products = codixus.collection<Product>(\"products\");\n * const all = await products.find(); // Product[]\n * const one = await products.findById(\"abc\"); // Product | null\n */\n collection<T>(name: string): Collection<T> {\n return new Collection<T>(this.api, `/api/${name}`);\n }\n\n async init(): Promise<void> {\n await this.auth.init();\n }\n}\n\nexport {\n type StorageAdapter,\n type SignInParams,\n type AuthState,\n} from \"./auth/auth-manager.js\";\nexport { ApiClient } from \"./api/api-client.js\";\nexport { Collection, type FindOptions } from \"./db/collection.js\";\n\n// Re-export shared types\nexport {\n type AuthUser,\n type TokenPair,\n type DeviceInfo,\n type DeviceMetadata,\n type AuthTokenRequest,\n type AuthTokenResponse,\n type ApiResponse,\n CodixusError,\n ErrorCodes,\n} from \"@codixus/shared\";\n","import type {\n AuthTokenResponse,\n DeviceInfo,\n DeviceMetadata,\n} from \"@codixus/shared\";\nimport type { ApiClient } from \"../api/api-client.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): Promise<string | null> | string | null;\n setItem(key: string, value: string): Promise<void> | void;\n removeItem(key: string): Promise<void> | void;\n}\n\nexport interface SignInParams {\n deviceId?: string;\n deviceInfo: DeviceInfo;\n metadata?: DeviceMetadata;\n}\n\nexport interface AuthState {\n isAuthenticated: boolean;\n isLoading: boolean;\n user: Record<string, unknown> | null;\n}\n\ntype AuthStateListener = (state: AuthState) => void;\n\nexport class AuthManager {\n private accessToken: string | null = null;\n private refreshTokenValue: string | null = null;\n private user: Record<string, unknown> | null = null;\n private listeners: Set<AuthStateListener> = new Set();\n private _isLoading = true;\n private storageKey: string;\n private api!: ApiClient;\n private deviceId: string | null = null;\n\n constructor(\n private storage: StorageAdapter | null,\n storageKey: string,\n ) {\n this.storageKey = storageKey;\n }\n\n /** @internal */\n _setApi(api: ApiClient): void {\n this.api = api;\n }\n\n async init(): Promise<void> {\n if (!this.storage) {\n this._isLoading = false;\n return;\n }\n\n try {\n const storedRefresh = await this.storage.getItem(\n `${this.storageKey}_refresh_token`,\n );\n const storedUser = await this.storage.getItem(\n `${this.storageKey}_user`,\n );\n const storedDeviceId = await this.storage.getItem(\n `${this.storageKey}_device_id`,\n );\n\n if (storedRefresh) {\n this.refreshTokenValue = storedRefresh;\n }\n if (storedUser) {\n try {\n this.user = JSON.parse(storedUser);\n } catch {\n // Corrupted user data in storage, ignore\n }\n }\n if (storedDeviceId) {\n this.deviceId = storedDeviceId;\n }\n } catch (error) {\n console.warn(\"[CodixusClient] Failed to restore auth state from storage:\", error);\n }\n\n this._isLoading = false;\n this.notify();\n }\n\n async signIn(\n params: SignInParams,\n ): Promise<{ user: Record<string, unknown>; isNewUser: boolean }> {\n const deviceId = params.deviceId ?? this.deviceId ?? this.generateDeviceId();\n\n const response = await this.api.post<AuthTokenResponse>(\"/auth/token\", {\n deviceId,\n deviceInfo: params.deviceInfo,\n metadata: params.metadata,\n });\n\n const data = response.data;\n this.accessToken = data.accessToken;\n this.refreshTokenValue = data.refreshToken;\n this.user = data.user;\n this.deviceId = deviceId;\n\n // Persist\n if (this.storage) {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n data.refreshToken,\n );\n await this.storage.setItem(\n `${this.storageKey}_user`,\n JSON.stringify(data.user),\n );\n await this.storage.setItem(`${this.storageKey}_device_id`, deviceId);\n }\n\n this.notify();\n return { user: data.user, isNewUser: data.isNewUser };\n }\n\n async getToken(): Promise<string | null> {\n if (this.accessToken) return this.accessToken;\n\n // Try refresh\n if (this.refreshTokenValue) {\n try {\n await this.forceRefresh();\n return this.accessToken;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n async forceRefresh(): Promise<string | null> {\n if (!this.refreshTokenValue) return null;\n\n try {\n const response = await this.api.post<{\n success: boolean;\n accessToken: string;\n refreshToken: string;\n }>(\"/auth/refresh\", {\n refreshToken: this.refreshTokenValue,\n });\n\n this.accessToken = response.data.accessToken;\n this.refreshTokenValue = response.data.refreshToken;\n\n if (this.storage) {\n await this.storage.setItem(\n `${this.storageKey}_refresh_token`,\n response.data.refreshToken,\n );\n }\n\n return this.accessToken;\n } catch {\n // Refresh failed, clear auth state\n await this.signOut();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n // Notify server\n if (this.refreshTokenValue) {\n try {\n await this.api.post(\"/auth/logout\", {\n refreshToken: this.refreshTokenValue,\n });\n } catch {}\n }\n\n this.accessToken = null;\n this.refreshTokenValue = null;\n this.user = null;\n\n if (this.storage) {\n await this.storage.removeItem(`${this.storageKey}_refresh_token`);\n await this.storage.removeItem(`${this.storageKey}_user`);\n await this.storage.removeItem(`${this.storageKey}_device_id`);\n }\n\n this.notify();\n }\n\n getState(): AuthState {\n return {\n isAuthenticated: this.accessToken !== null || this.refreshTokenValue !== null,\n isLoading: this._isLoading,\n user: this.user,\n };\n }\n\n getDeviceId(): string | null {\n return this.deviceId;\n }\n\n onAuthStateChange(listener: AuthStateListener): () => void {\n this.listeners.add(listener);\n // Call immediately with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** @internal - used by API interceptor */\n _getAccessToken(): string | null {\n return this.accessToken;\n }\n\n /** @internal - called by API interceptor after refresh */\n _setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n private notify(): void {\n const state = this.getState();\n for (const listener of this.listeners) {\n listener(state);\n }\n }\n\n private generateDeviceId(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return \"dev-\" + Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n }\n}\n","import axios, {\n type AxiosInstance,\n type AxiosRequestConfig,\n type AxiosResponse,\n} from \"axios\";\nimport type { AuthManager } from \"../auth/auth-manager.js\";\n\n// Lightweight crypto helpers that work in both browser and React Native\nasync function sha256(data: string): Promise<string> {\n if (typeof globalThis.crypto?.subtle !== \"undefined\") {\n const encoded = new TextEncoder().encode(data);\n const hash = await globalThis.crypto.subtle.digest(\"SHA-256\", encoded);\n return Array.from(new Uint8Array(hash), (b) =>\n b.toString(16).padStart(2, \"0\"),\n ).join(\"\");\n }\n // Fallback: simple hash (React Native without crypto.subtle)\n return simpleHash(data);\n}\n\nasync function hmacSha256(secret: string, data: string): Promise<string> {\n if (typeof globalThis.crypto?.subtle !== \"undefined\") {\n const key = await globalThis.crypto.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const sig = await globalThis.crypto.subtle.sign(\n \"HMAC\",\n key,\n new TextEncoder().encode(data),\n );\n return Array.from(new Uint8Array(sig), (b) =>\n b.toString(16).padStart(2, \"0\"),\n ).join(\"\");\n }\n // Fallback for environments without SubtleCrypto\n return simpleHmac(secret, data);\n}\n\n// Simple fallback hash for environments without SubtleCrypto\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash |= 0;\n }\n return Math.abs(hash).toString(16).padStart(16, \"0\");\n}\n\nfunction simpleHmac(key: string, data: string): string {\n return simpleHash(key + \":\" + data);\n}\n\nfunction generateNonce(): string {\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n // Fallback\n const bytes = new Uint8Array(16);\n if (typeof globalThis.crypto?.getRandomValues === \"function\") {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport class ApiClient {\n readonly instance: AxiosInstance;\n private refreshPromise: Promise<string | null> | null = null;\n private appSecret: string | undefined;\n\n constructor(\n baseURL: string,\n private authManager: AuthManager,\n appSecret?: string,\n ) {\n this.appSecret = appSecret;\n\n this.instance = axios.create({\n baseURL,\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n // Request interceptor: add Bearer token + signing\n this.instance.interceptors.request.use(async (config) => {\n // Skip auth for auth endpoints\n if (!config.url?.includes(\"/auth/\")) {\n const token = this.authManager._getAccessToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n }\n\n // Request signing\n if (this.appSecret) {\n const timestamp = Date.now().toString();\n const nonce = generateNonce();\n const body =\n config.data && typeof config.data === \"object\"\n ? JSON.stringify(config.data)\n : (config.data ?? \"\");\n const bodyHash = body ? await sha256(body) : \"\";\n const method = (config.method ?? \"GET\").toUpperCase();\n const url = config.url ?? \"/\";\n const payload = [method, url, timestamp, nonce, bodyHash].join(\"\\n\");\n const signature = await hmacSha256(this.appSecret, payload);\n\n config.headers[\"X-Codixus-Timestamp\"] = timestamp;\n config.headers[\"X-Codixus-Nonce\"] = nonce;\n config.headers[\"X-Codixus-Signature\"] = signature;\n }\n\n return config;\n });\n\n // Response interceptor: handle 401 with token refresh\n this.instance.interceptors.response.use(\n (response) => response,\n async (error) => {\n if (error.response?.status === 401) {\n const originalRequest = error.config;\n if (originalRequest && !originalRequest._retry) {\n originalRequest._retry = true;\n\n try {\n // Promise lock to prevent concurrent refreshes\n if (!this.refreshPromise) {\n this.refreshPromise = this.authManager\n .forceRefresh()\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n\n const newToken = await this.refreshPromise;\n if (newToken) {\n originalRequest.headers.Authorization = `Bearer ${newToken}`;\n return this.instance(originalRequest);\n }\n } catch (refreshError) {\n console.warn(\"[CodixusClient] Token refresh failed:\", refreshError);\n }\n }\n }\n return Promise.reject(error);\n },\n );\n }\n\n async get<T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n ): Promise<AxiosResponse<T>> {\n return this.instance.get<T>(url, config);\n }\n\n async post<T = unknown>(\n url: string,\n data?: unknown,\n config?: AxiosRequestConfig,\n ): Promise<AxiosResponse<T>> {\n return this.instance.post<T>(url, data, config);\n }\n\n async patch<T = unknown>(\n url: string,\n data?: unknown,\n config?: AxiosRequestConfig,\n ): Promise<AxiosResponse<T>> {\n return this.instance.patch<T>(url, data, config);\n }\n\n async delete<T = unknown>(\n url: string,\n config?: AxiosRequestConfig,\n ): Promise<AxiosResponse<T>> {\n return this.instance.delete<T>(url, config);\n }\n\n async put<T = unknown>(\n url: string,\n data?: unknown,\n config?: AxiosRequestConfig,\n ): Promise<AxiosResponse<T>> {\n return this.instance.put<T>(url, data, config);\n }\n}\n","import type { ApiClient } from \"../api/api-client.js\";\n\nexport interface FindOptions {\n sort?: Record<string, 1 | -1>;\n limit?: number;\n skip?: number;\n cursor?: string | number;\n}\n\nexport class Collection<T = Record<string, unknown>> {\n constructor(\n private api: ApiClient,\n private basePath: string,\n ) {}\n\n async find(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<T[]> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.skip) params.set(\"skip\", String(options.skip));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor?: string | null }>(url);\n return data.data;\n }\n\n async findWithCursor(\n filter?: Record<string, unknown>,\n options?: FindOptions,\n ): Promise<{ data: T[]; nextCursor: string | number | null }> {\n const params = new URLSearchParams();\n if (filter && Object.keys(filter).length > 0) {\n params.set(\"filter\", JSON.stringify(filter));\n }\n if (options?.sort) params.set(\"sort\", JSON.stringify(options.sort));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.cursor) params.set(\"cursor\", String(options.cursor));\n\n const qs = params.toString();\n const url = qs ? `${this.basePath}?${qs}` : this.basePath;\n const { data } = await this.api.get<{ success: boolean; data: T[]; nextCursor: string | number | null }>(url);\n return { data: data.data, nextCursor: data.nextCursor };\n }\n\n async findById(id: string): Promise<T | null> {\n try {\n const { data } = await this.api.get<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n );\n return data.data;\n } catch (error: any) {\n if (error.response?.status === 404) return null;\n throw error;\n }\n }\n\n async create(doc: Partial<T> & Record<string, unknown>): Promise<T> {\n const { data } = await this.api.post<{ success: boolean; data: T }>(\n this.basePath,\n doc,\n );\n return data.data;\n }\n\n async updateById(\n id: string,\n update: Record<string, unknown>,\n ): Promise<T> {\n const { data } = await this.api.patch<{ success: boolean; data: T }>(\n `${this.basePath}/${id}`,\n { update },\n );\n return data.data;\n }\n\n async deleteById(id: string): Promise<void> {\n await this.api.delete(`${this.basePath}/${id}`);\n }\n\n async count(filter?: Record<string, unknown>): Promise<number> {\n const { data } = await this.api.post<{ success: boolean; count: number }>(\n `${this.basePath}/count`,\n { filter: filter ?? {} },\n );\n return data.count;\n }\n}\n"],"mappings":"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","names":["axios"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { DeviceInfo, DeviceMetadata } from '@codixus/shared';
|
|
2
|
+
export { ApiResponse, AuthTokenRequest, AuthTokenResponse, AuthUser, CodixusError, DeviceInfo, DeviceMetadata, ErrorCodes, TokenPair } from '@codixus/shared';
|
|
3
|
+
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
4
|
+
|
|
5
|
+
declare class ApiClient {
|
|
6
|
+
private authManager;
|
|
7
|
+
readonly instance: AxiosInstance;
|
|
8
|
+
private refreshPromise;
|
|
9
|
+
private appSecret;
|
|
10
|
+
constructor(baseURL: string, authManager: AuthManager, appSecret?: string);
|
|
11
|
+
get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
12
|
+
post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
13
|
+
patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
14
|
+
delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
15
|
+
put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface StorageAdapter {
|
|
19
|
+
getItem(key: string): Promise<string | null> | string | null;
|
|
20
|
+
setItem(key: string, value: string): Promise<void> | void;
|
|
21
|
+
removeItem(key: string): Promise<void> | void;
|
|
22
|
+
}
|
|
23
|
+
interface SignInParams {
|
|
24
|
+
deviceId?: string;
|
|
25
|
+
deviceInfo: DeviceInfo;
|
|
26
|
+
metadata?: DeviceMetadata;
|
|
27
|
+
}
|
|
28
|
+
interface AuthState {
|
|
29
|
+
isAuthenticated: boolean;
|
|
30
|
+
isLoading: boolean;
|
|
31
|
+
user: Record<string, unknown> | null;
|
|
32
|
+
}
|
|
33
|
+
type AuthStateListener = (state: AuthState) => void;
|
|
34
|
+
declare class AuthManager {
|
|
35
|
+
private storage;
|
|
36
|
+
private accessToken;
|
|
37
|
+
private refreshTokenValue;
|
|
38
|
+
private user;
|
|
39
|
+
private listeners;
|
|
40
|
+
private _isLoading;
|
|
41
|
+
private storageKey;
|
|
42
|
+
private api;
|
|
43
|
+
private deviceId;
|
|
44
|
+
constructor(storage: StorageAdapter | null, storageKey: string);
|
|
45
|
+
/** @internal */
|
|
46
|
+
_setApi(api: ApiClient): void;
|
|
47
|
+
init(): Promise<void>;
|
|
48
|
+
signIn(params: SignInParams): Promise<{
|
|
49
|
+
user: Record<string, unknown>;
|
|
50
|
+
isNewUser: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
getToken(): Promise<string | null>;
|
|
53
|
+
forceRefresh(): Promise<string | null>;
|
|
54
|
+
signOut(): Promise<void>;
|
|
55
|
+
getState(): AuthState;
|
|
56
|
+
getDeviceId(): string | null;
|
|
57
|
+
onAuthStateChange(listener: AuthStateListener): () => void;
|
|
58
|
+
/** @internal - used by API interceptor */
|
|
59
|
+
_getAccessToken(): string | null;
|
|
60
|
+
/** @internal - called by API interceptor after refresh */
|
|
61
|
+
_setAccessToken(token: string): void;
|
|
62
|
+
private notify;
|
|
63
|
+
private generateDeviceId;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface FindOptions {
|
|
67
|
+
sort?: Record<string, 1 | -1>;
|
|
68
|
+
limit?: number;
|
|
69
|
+
skip?: number;
|
|
70
|
+
cursor?: string | number;
|
|
71
|
+
}
|
|
72
|
+
declare class Collection<T = Record<string, unknown>> {
|
|
73
|
+
private api;
|
|
74
|
+
private basePath;
|
|
75
|
+
constructor(api: ApiClient, basePath: string);
|
|
76
|
+
find(filter?: Record<string, unknown>, options?: FindOptions): Promise<T[]>;
|
|
77
|
+
findWithCursor(filter?: Record<string, unknown>, options?: FindOptions): Promise<{
|
|
78
|
+
data: T[];
|
|
79
|
+
nextCursor: string | number | null;
|
|
80
|
+
}>;
|
|
81
|
+
findById(id: string): Promise<T | null>;
|
|
82
|
+
create(doc: Partial<T> & Record<string, unknown>): Promise<T>;
|
|
83
|
+
updateById(id: string, update: Record<string, unknown>): Promise<T>;
|
|
84
|
+
deleteById(id: string): Promise<void>;
|
|
85
|
+
count(filter?: Record<string, unknown>): Promise<number>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface CodixusClientConfig {
|
|
89
|
+
apiUrl: string;
|
|
90
|
+
storageKey?: string;
|
|
91
|
+
storage?: StorageAdapter | null;
|
|
92
|
+
appSecret?: string;
|
|
93
|
+
}
|
|
94
|
+
declare class CodixusClient {
|
|
95
|
+
readonly auth: AuthManager;
|
|
96
|
+
readonly api: ApiClient;
|
|
97
|
+
constructor(config: CodixusClientConfig);
|
|
98
|
+
/**
|
|
99
|
+
* Create a typed collection accessor.
|
|
100
|
+
* Maps to auto REST routes on server: codixus.rest(Model)
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* interface Product { _id: string; name: string; price: number; }
|
|
104
|
+
* const products = codixus.collection<Product>("products");
|
|
105
|
+
* const all = await products.find(); // Product[]
|
|
106
|
+
* const one = await products.findById("abc"); // Product | null
|
|
107
|
+
*/
|
|
108
|
+
collection<T>(name: string): Collection<T>;
|
|
109
|
+
init(): Promise<void>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { ApiClient, type AuthState, CodixusClient, type CodixusClientConfig, Collection, type FindOptions, type SignInParams, type StorageAdapter };
|