@ponxa/potatobase-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 +21 -0
- package/README.md +171 -0
- package/dist/index.d.mts +460 -0
- package/dist/index.d.ts +460 -0
- package/dist/index.js +517 -0
- package/dist/index.mjs +478 -0
- package/package.json +61 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
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
|
+
PotatoBaseClient: () => PotatoBaseClient,
|
|
24
|
+
TableClient: () => TableClient,
|
|
25
|
+
between: () => between,
|
|
26
|
+
createClient: () => createClient,
|
|
27
|
+
daysAgo: () => daysAgo,
|
|
28
|
+
hoursAgo: () => hoursAgo,
|
|
29
|
+
lastDays: () => lastDays,
|
|
30
|
+
minutesAgo: () => minutesAgo,
|
|
31
|
+
since: () => since,
|
|
32
|
+
thisMonth: () => thisMonth,
|
|
33
|
+
thisYear: () => thisYear,
|
|
34
|
+
today: () => today,
|
|
35
|
+
until: () => until
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
|
|
39
|
+
// src/table-client.ts
|
|
40
|
+
var TableClient = class {
|
|
41
|
+
constructor(apiUrl, apiKey, projectId, tableName, debug = false) {
|
|
42
|
+
this.apiUrl = apiUrl;
|
|
43
|
+
this.apiKey = apiKey;
|
|
44
|
+
this.projectId = projectId;
|
|
45
|
+
this.tableName = tableName;
|
|
46
|
+
this.debug = debug;
|
|
47
|
+
}
|
|
48
|
+
async callAPI(procedure, input, method = "GET") {
|
|
49
|
+
const url = `${this.apiUrl}/${procedure}`;
|
|
50
|
+
if (method === "GET") {
|
|
51
|
+
const params = new URLSearchParams({
|
|
52
|
+
input: JSON.stringify(input)
|
|
53
|
+
});
|
|
54
|
+
const response = await fetch(`${url}?${params}`, {
|
|
55
|
+
method: "GET",
|
|
56
|
+
headers: {
|
|
57
|
+
"x-api-key": this.apiKey
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
const error = await response.text();
|
|
62
|
+
throw new Error(`API error: ${error}`);
|
|
63
|
+
}
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
return data.result?.data || data;
|
|
66
|
+
} else {
|
|
67
|
+
const response = await fetch(url, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
"x-api-key": this.apiKey
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify(input)
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
const error = await response.text();
|
|
77
|
+
throw new Error(`API error: ${error}`);
|
|
78
|
+
}
|
|
79
|
+
const data = await response.json();
|
|
80
|
+
return data.result?.data || data;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Query records from the table
|
|
85
|
+
*
|
|
86
|
+
* @param params - Query parameters (index, where, range, limit, cursor)
|
|
87
|
+
* @returns Query result with data and optional cursor
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* // Query by primary key
|
|
92
|
+
* const result = await products.query({ where: { id: 'prod-1' } });
|
|
93
|
+
*
|
|
94
|
+
* // Query by GSI
|
|
95
|
+
* const result = await products.query({
|
|
96
|
+
* index: 'byCategory',
|
|
97
|
+
* where: { category: 'clothing' },
|
|
98
|
+
* limit: 10
|
|
99
|
+
* });
|
|
100
|
+
*
|
|
101
|
+
* // Query with date range
|
|
102
|
+
* const result = await products.query({
|
|
103
|
+
* index: 'byCategory',
|
|
104
|
+
* where: { category: 'clothing' },
|
|
105
|
+
* range: {
|
|
106
|
+
* field: 'createdAt',
|
|
107
|
+
* gte: '2025-01-01',
|
|
108
|
+
* lte: '2025-01-31'
|
|
109
|
+
* }
|
|
110
|
+
* });
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
async query(params) {
|
|
114
|
+
if (this.debug) {
|
|
115
|
+
console.log(`[TableClient:${this.tableName}] query:`, params);
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const result = await this.callAPI("query.execute", {
|
|
119
|
+
projectId: this.projectId,
|
|
120
|
+
tableName: this.tableName,
|
|
121
|
+
index: params?.index,
|
|
122
|
+
where: params?.where,
|
|
123
|
+
range: params?.range,
|
|
124
|
+
limit: params?.limit,
|
|
125
|
+
cursor: params?.cursor
|
|
126
|
+
});
|
|
127
|
+
if (this.debug) {
|
|
128
|
+
console.log(`[TableClient:${this.tableName}] query result:`, {
|
|
129
|
+
count: result.data?.length || 0,
|
|
130
|
+
hasMore: !!result.cursor
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return result.data || result;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error(`[TableClient:${this.tableName}] query error:`, error.message);
|
|
136
|
+
throw new Error(`Failed to query ${this.tableName}: ${error.message}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get a single record by ID
|
|
141
|
+
*
|
|
142
|
+
* @param id - Record ID
|
|
143
|
+
* @returns Record or null if not found
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const product = await products.get('prod-1');
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
async get(id) {
|
|
151
|
+
if (this.debug) {
|
|
152
|
+
console.log(`[TableClient:${this.tableName}] get:`, id);
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const result = await this.callAPI("query.get", {
|
|
156
|
+
projectId: this.projectId,
|
|
157
|
+
tableName: this.tableName,
|
|
158
|
+
recordId: id
|
|
159
|
+
});
|
|
160
|
+
return result || null;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (error.message?.includes("not found")) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
console.error(`[TableClient:${this.tableName}] get error:`, error.message);
|
|
166
|
+
throw new Error(`Failed to get record from ${this.tableName}: ${error.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Insert a new record
|
|
171
|
+
*
|
|
172
|
+
* @param data - Record data (must include 'id' field)
|
|
173
|
+
* @returns Created record
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* const newProduct = await products.insert({
|
|
178
|
+
* id: 'prod-1',
|
|
179
|
+
* title: 'T-Shirt',
|
|
180
|
+
* price: 29.99,
|
|
181
|
+
* category: 'clothing'
|
|
182
|
+
* });
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
async insert(data) {
|
|
186
|
+
if (this.debug) {
|
|
187
|
+
console.log(`[TableClient:${this.tableName}] insert:`, data);
|
|
188
|
+
}
|
|
189
|
+
if (!data.id) {
|
|
190
|
+
throw new Error('Record must have an "id" field');
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const result = await this.callAPI("query.create", {
|
|
194
|
+
projectId: this.projectId,
|
|
195
|
+
tableName: this.tableName,
|
|
196
|
+
data
|
|
197
|
+
}, "POST");
|
|
198
|
+
if (this.debug) {
|
|
199
|
+
console.log(`[TableClient:${this.tableName}] insert success:`, result.id);
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error(`[TableClient:${this.tableName}] insert error:`, error.message);
|
|
204
|
+
throw new Error(`Failed to insert into ${this.tableName}: ${error.message}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Update an existing record
|
|
209
|
+
*
|
|
210
|
+
* @param id - Record ID
|
|
211
|
+
* @param data - Fields to update
|
|
212
|
+
* @returns Updated record
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* const updated = await products.update('prod-1', {
|
|
217
|
+
* price: 24.99,
|
|
218
|
+
* stock: 100
|
|
219
|
+
* });
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
async update(id, data) {
|
|
223
|
+
if (this.debug) {
|
|
224
|
+
console.log(`[TableClient:${this.tableName}] update:`, { id, data });
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const result = await this.callAPI("query.update", {
|
|
228
|
+
projectId: this.projectId,
|
|
229
|
+
tableName: this.tableName,
|
|
230
|
+
recordId: id,
|
|
231
|
+
data
|
|
232
|
+
}, "POST");
|
|
233
|
+
if (this.debug) {
|
|
234
|
+
console.log(`[TableClient:${this.tableName}] update success`);
|
|
235
|
+
}
|
|
236
|
+
return result;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error(`[TableClient:${this.tableName}] update error:`, error.message);
|
|
239
|
+
throw new Error(`Failed to update record in ${this.tableName}: ${error.message}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Delete a record
|
|
244
|
+
*
|
|
245
|
+
* @param id - Record ID
|
|
246
|
+
* @returns Success status
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```typescript
|
|
250
|
+
* await products.delete('prod-1');
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
async delete(id) {
|
|
254
|
+
if (this.debug) {
|
|
255
|
+
console.log(`[TableClient:${this.tableName}] delete:`, id);
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
const result = await this.callAPI("query.delete", {
|
|
259
|
+
projectId: this.projectId,
|
|
260
|
+
tableName: this.tableName,
|
|
261
|
+
recordId: id
|
|
262
|
+
}, "POST");
|
|
263
|
+
if (this.debug) {
|
|
264
|
+
console.log(`[TableClient:${this.tableName}] delete success`);
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.error(`[TableClient:${this.tableName}] delete error:`, error.message);
|
|
269
|
+
throw new Error(`Failed to delete from ${this.tableName}: ${error.message}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Create a new record (alias for insert)
|
|
274
|
+
*
|
|
275
|
+
* @param data - Record data (must include 'id' field)
|
|
276
|
+
* @returns Created record
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```typescript
|
|
280
|
+
* const newProduct = await products.create({
|
|
281
|
+
* id: 'prod-1',
|
|
282
|
+
* title: 'T-Shirt',
|
|
283
|
+
* price: 29.99,
|
|
284
|
+
* category: 'clothing'
|
|
285
|
+
* });
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
async create(data) {
|
|
289
|
+
return this.insert(data);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Alias for query() - chainable method
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* const items = await products.from().query({ limit: 10 });
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
from() {
|
|
300
|
+
return this;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// src/helpers.ts
|
|
305
|
+
function daysAgo(days) {
|
|
306
|
+
const date = new Date(Date.now() - days * 24 * 60 * 60 * 1e3);
|
|
307
|
+
return date.toISOString();
|
|
308
|
+
}
|
|
309
|
+
function hoursAgo(hours) {
|
|
310
|
+
const date = new Date(Date.now() - hours * 60 * 60 * 1e3);
|
|
311
|
+
return date.toISOString();
|
|
312
|
+
}
|
|
313
|
+
function minutesAgo(minutes) {
|
|
314
|
+
const date = new Date(Date.now() - minutes * 60 * 1e3);
|
|
315
|
+
return date.toISOString();
|
|
316
|
+
}
|
|
317
|
+
function lastDays(field, days) {
|
|
318
|
+
return {
|
|
319
|
+
field,
|
|
320
|
+
gte: daysAgo(days)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function between(field, startDate, endDate) {
|
|
324
|
+
return {
|
|
325
|
+
field,
|
|
326
|
+
between: [startDate, endDate]
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function since(field, date) {
|
|
330
|
+
return {
|
|
331
|
+
field,
|
|
332
|
+
gte: date
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function until(field, date) {
|
|
336
|
+
return {
|
|
337
|
+
field,
|
|
338
|
+
lte: date
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function thisMonth(field) {
|
|
342
|
+
const now = /* @__PURE__ */ new Date();
|
|
343
|
+
const start = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
344
|
+
const end = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999);
|
|
345
|
+
return {
|
|
346
|
+
field,
|
|
347
|
+
between: [start.toISOString(), end.toISOString()]
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function thisYear(field) {
|
|
351
|
+
const now = /* @__PURE__ */ new Date();
|
|
352
|
+
const start = new Date(now.getFullYear(), 0, 1);
|
|
353
|
+
const end = new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999);
|
|
354
|
+
return {
|
|
355
|
+
field,
|
|
356
|
+
between: [start.toISOString(), end.toISOString()]
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function today(field) {
|
|
360
|
+
const now = /* @__PURE__ */ new Date();
|
|
361
|
+
const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
362
|
+
const end = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
|
|
363
|
+
return {
|
|
364
|
+
field,
|
|
365
|
+
between: [start.toISOString(), end.toISOString()]
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/index.ts
|
|
370
|
+
var PotatoBaseClient = class {
|
|
371
|
+
constructor(config) {
|
|
372
|
+
if (!config.projectId) {
|
|
373
|
+
throw new Error("PotatoBase: projectId is required");
|
|
374
|
+
}
|
|
375
|
+
if (!config.apiKey) {
|
|
376
|
+
throw new Error("PotatoBase: apiKey is required");
|
|
377
|
+
}
|
|
378
|
+
this.config = {
|
|
379
|
+
...config,
|
|
380
|
+
apiUrl: config.apiUrl || "https://api.potatobase.com",
|
|
381
|
+
debug: config.debug || false
|
|
382
|
+
};
|
|
383
|
+
this.tableClients = /* @__PURE__ */ new Map();
|
|
384
|
+
if (this.config.debug) {
|
|
385
|
+
console.log("[PotatoBaseClient] Initializing with config:", {
|
|
386
|
+
projectId: this.config.projectId,
|
|
387
|
+
apiUrl: this.config.apiUrl,
|
|
388
|
+
apiKey: this.config.apiKey.substring(0, 20) + "..."
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Access a table by name
|
|
394
|
+
*
|
|
395
|
+
* Returns a TableClient instance for performing CRUD operations.
|
|
396
|
+
* TableClient instances are cached for performance.
|
|
397
|
+
*
|
|
398
|
+
* @param tableName - Name of the table
|
|
399
|
+
* @returns TableClient for the specified table
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* ```typescript
|
|
403
|
+
* const products = pb.table('products');
|
|
404
|
+
* const items = await products.query({ limit: 10 });
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
table(tableName) {
|
|
408
|
+
const key = tableName;
|
|
409
|
+
if (this.tableClients.has(key)) {
|
|
410
|
+
return this.tableClients.get(key);
|
|
411
|
+
}
|
|
412
|
+
if (this.config.debug) {
|
|
413
|
+
console.log(`[PotatoBaseClient] Creating TableClient for: ${key}`);
|
|
414
|
+
}
|
|
415
|
+
const tableClient = new TableClient(
|
|
416
|
+
this.config.apiUrl,
|
|
417
|
+
this.config.apiKey,
|
|
418
|
+
this.config.projectId,
|
|
419
|
+
key,
|
|
420
|
+
this.config.debug
|
|
421
|
+
);
|
|
422
|
+
this.tableClients.set(key, tableClient);
|
|
423
|
+
return tableClient;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Generate TypeScript types for your project
|
|
427
|
+
*
|
|
428
|
+
* Fetches the current schema and generates TypeScript interface definitions.
|
|
429
|
+
* Save the result to a .d.ts file in your project.
|
|
430
|
+
*
|
|
431
|
+
* @returns Generated TypeScript types as string
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```typescript
|
|
435
|
+
* const types = await pb.generateTypes();
|
|
436
|
+
* fs.writeFileSync('./types/database.d.ts', types);
|
|
437
|
+
* ```
|
|
438
|
+
*/
|
|
439
|
+
async generateTypes() {
|
|
440
|
+
if (this.config.debug) {
|
|
441
|
+
console.log("[PotatoBaseClient] Generating types for project:", this.config.projectId);
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
const params = new URLSearchParams({
|
|
445
|
+
input: JSON.stringify(this.config.projectId)
|
|
446
|
+
});
|
|
447
|
+
const response = await fetch(`${this.config.apiUrl}/projects.generateTypes?${params}`, {
|
|
448
|
+
method: "GET",
|
|
449
|
+
headers: {
|
|
450
|
+
"x-api-key": this.config.apiKey
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
if (!response.ok) {
|
|
454
|
+
throw new Error(`Failed to generate types: ${response.statusText}`);
|
|
455
|
+
}
|
|
456
|
+
const data = await response.json();
|
|
457
|
+
const result = data.result?.data || data;
|
|
458
|
+
if (this.config.debug) {
|
|
459
|
+
console.log("[PotatoBaseClient] Types generated:", {
|
|
460
|
+
length: result.types.length
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
return result.types;
|
|
464
|
+
} catch (error) {
|
|
465
|
+
console.error("[PotatoBaseClient] Failed to generate types:", error.message);
|
|
466
|
+
throw new Error(`Failed to generate types: ${error.message}`);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Get the project ID
|
|
471
|
+
*/
|
|
472
|
+
getProjectId() {
|
|
473
|
+
return this.config.projectId;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Get the API URL
|
|
477
|
+
*/
|
|
478
|
+
getApiUrl() {
|
|
479
|
+
return this.config.apiUrl;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Clear all cached table clients
|
|
483
|
+
*
|
|
484
|
+
* Useful for testing or when you want to force fresh clients.
|
|
485
|
+
*/
|
|
486
|
+
clearCache() {
|
|
487
|
+
if (this.config.debug) {
|
|
488
|
+
console.log("[PotatoBaseClient] Clearing table client cache");
|
|
489
|
+
}
|
|
490
|
+
this.tableClients.clear();
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Enable/disable debug logging
|
|
494
|
+
*/
|
|
495
|
+
setDebug(enabled) {
|
|
496
|
+
this.config.debug = enabled;
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
function createClient(config) {
|
|
500
|
+
return new PotatoBaseClient(config);
|
|
501
|
+
}
|
|
502
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
503
|
+
0 && (module.exports = {
|
|
504
|
+
PotatoBaseClient,
|
|
505
|
+
TableClient,
|
|
506
|
+
between,
|
|
507
|
+
createClient,
|
|
508
|
+
daysAgo,
|
|
509
|
+
hoursAgo,
|
|
510
|
+
lastDays,
|
|
511
|
+
minutesAgo,
|
|
512
|
+
since,
|
|
513
|
+
thisMonth,
|
|
514
|
+
thisYear,
|
|
515
|
+
today,
|
|
516
|
+
until
|
|
517
|
+
});
|