@ariadng/sheets 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 ariadng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,439 @@
1
+ # Sheets
2
+
3
+ A pragmatic TypeScript client for Google Sheets API v4 with stellar performance, that provides essential features without over-engineering. Start simple and add complexity only when needed.
4
+
5
+ ## Features
6
+
7
+ - **Progressive Enhancement** - Start with core features, add more as needed
8
+ - **Modular Packages** - Core (~3KB), Plus (~5KB), Advanced (~2KB)
9
+ - **Smart Retry Logic** - Exponential backoff with jitter
10
+ - **Optional Caching** - Reduce API calls with configurable TTL
11
+ - **Type Safety** - Full TypeScript support with type utilities
12
+ - **Rate Limiting** - Adaptive or token bucket strategies
13
+ - **Metrics Collection** - Track performance and errors
14
+ - **Batch Operations** - Efficient bulk reads/writes
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ # Core package only
20
+ npm install @ariadng/sheets
21
+
22
+ # With specific packages
23
+ npm install @ariadng/sheets
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### Basic Usage
29
+
30
+ ```typescript
31
+ import { GoogleSheetsCore, createServiceAccountAuth } from '@ariadng/sheets/core';
32
+
33
+ // Setup with service account
34
+ const auth = await createServiceAccountAuth('./service-account-key.json');
35
+ const sheets = new GoogleSheetsCore({ auth });
36
+
37
+ // Simple read
38
+ const data = await sheets.read('spreadsheetId', 'Sheet1!A1:B10');
39
+ console.log(data); // [[value1, value2], [value3, value4], ...]
40
+
41
+ // Simple write
42
+ await sheets.write('spreadsheetId', 'Sheet1!A1:B2', [
43
+ ['Name', 'Score'],
44
+ ['Alice', 100]
45
+ ]);
46
+ ```
47
+
48
+ ### With Caching
49
+
50
+ ```typescript
51
+ import { withCache } from '@ariadng/sheets/plus';
52
+
53
+ const cachedSheets = withCache(sheets, {
54
+ ttlSeconds: 300 // 5-minute cache
55
+ });
56
+
57
+ // First read hits API
58
+ const data1 = await cachedSheets.read(id, 'A1:B10');
59
+
60
+ // Second read uses cache (within 5 minutes)
61
+ const data2 = await cachedSheets.read(id, 'A1:B10'); // Much faster!
62
+ ```
63
+
64
+ ### With Rate Limiting
65
+
66
+ ```typescript
67
+ import { withAdaptiveRateLimit } from '@ariadng/sheets/advanced';
68
+
69
+ const rateLimitedSheets = withAdaptiveRateLimit(sheets);
70
+
71
+ // Automatically handles rate limits
72
+ for (let i = 0; i < 1000; i++) {
73
+ await rateLimitedSheets.read(id, `A${i}`);
74
+ // Automatically slows down if hitting limits
75
+ }
76
+ ```
77
+
78
+ ## Authentication
79
+
80
+ ### Service Account
81
+
82
+ ```typescript
83
+ import { createServiceAccountAuth } from '@ariadng/sheets/core';
84
+
85
+ // From file
86
+ const auth = await createServiceAccountAuth('./service-account.json');
87
+
88
+ // From object
89
+ const auth = await createServiceAccountAuth({
90
+ client_email: 'your-service-account@project.iam.gserviceaccount.com',
91
+ private_key: '-----BEGIN PRIVATE KEY-----...',
92
+ // ... other fields
93
+ });
94
+ ```
95
+
96
+ ### OAuth2
97
+
98
+ ```typescript
99
+ import { createOAuth2Client, generateAuthUrl, getTokenFromCode } from '@ariadng/sheets/core';
100
+
101
+ const client = await createOAuth2Client({
102
+ client_id: 'your-client-id',
103
+ client_secret: 'your-client-secret',
104
+ redirect_uris: ['http://localhost:3000/callback']
105
+ });
106
+
107
+ // Generate auth URL
108
+ const authUrl = generateAuthUrl(client);
109
+ console.log('Visit:', authUrl);
110
+
111
+ // After user authorizes, exchange code for token
112
+ const tokens = await getTokenFromCode(client, authorizationCode);
113
+ ```
114
+
115
+ ## Core Features
116
+
117
+ ### CRUD Operations
118
+
119
+ ```typescript
120
+ // Read
121
+ const values = await sheets.read(spreadsheetId, 'Sheet1!A1:C10');
122
+
123
+ // Write (replaces existing data)
124
+ await sheets.write(spreadsheetId, 'Sheet1!A1:C3', [
125
+ ['Header1', 'Header2', 'Header3'],
126
+ ['Value1', 'Value2', 'Value3']
127
+ ]);
128
+
129
+ // Append (adds to end)
130
+ await sheets.append(spreadsheetId, 'Sheet1!A:C', [
131
+ ['New1', 'New2', 'New3']
132
+ ]);
133
+
134
+ // Clear
135
+ await sheets.clear(spreadsheetId, 'Sheet1!A1:C10');
136
+ ```
137
+
138
+ ### Batch Operations
139
+
140
+ ```typescript
141
+ // Batch read multiple ranges
142
+ const results = await sheets.batchRead(spreadsheetId, [
143
+ 'Sheet1!A1:B10',
144
+ 'Sheet2!C1:D5'
145
+ ]);
146
+
147
+ // Batch write multiple ranges
148
+ await sheets.batchWrite(spreadsheetId, [
149
+ { range: 'Sheet1!A1:B2', values: [['A', 'B'], ['C', 'D']] },
150
+ { range: 'Sheet2!A1:B2', values: [['E', 'F'], ['G', 'H']] }
151
+ ]);
152
+ ```
153
+
154
+ ## Plus Package Features
155
+
156
+ ### Type Utilities
157
+
158
+ ```typescript
159
+ import { A1, TypedSheets, Parsers, Serializers } from '@ariadng/sheets/plus';
160
+
161
+ // A1 notation utilities
162
+ const col = A1.columnToIndex('C'); // 2
163
+ const letter = A1.indexToColumn(2); // 'C'
164
+ const range = A1.build('Sheet1', 'A', 1, 'C', 10); // 'Sheet1!A1:C10'
165
+
166
+ // Type-safe operations
167
+ interface User {
168
+ name: string;
169
+ email: string;
170
+ age: number;
171
+ }
172
+
173
+ const typed = new TypedSheets<User[]>(sheets);
174
+ const users = await typed.read(
175
+ spreadsheetId,
176
+ 'Users!A1:C100',
177
+ Parsers.rowsToObjects<User>
178
+ );
179
+
180
+ // Data transformation
181
+ const objects = [
182
+ { name: 'Alice', age: 30 },
183
+ { name: 'Bob', age: 25 }
184
+ ];
185
+ const rows = Serializers.objectsToRows(objects);
186
+ // [['name', 'age'], ['Alice', 30], ['Bob', 25]]
187
+ ```
188
+
189
+ ### Batch Operations Manager
190
+
191
+ ```typescript
192
+ import { BatchOperations } from '@ariadng/sheets/plus';
193
+
194
+ const batchOps = new BatchOperations(sheets);
195
+
196
+ // Automatically chunks large batches
197
+ const operations = Array.from({ length: 500 }, (_, i) => ({
198
+ range: `Sheet1!A${i}:B${i}`,
199
+ values: [[`Row${i}`, `Value${i}`]]
200
+ }));
201
+
202
+ await batchOps.batchWrite(spreadsheetId, operations); // Handles chunking
203
+ ```
204
+
205
+ ### Simple Cache
206
+
207
+ ```typescript
208
+ import { SimpleCache } from '@ariadng/sheets/plus';
209
+
210
+ const cache = new SimpleCache({
211
+ ttlSeconds: 60,
212
+ maxEntries: 100
213
+ });
214
+
215
+ cache.set('key', data);
216
+ const cached = cache.get('key');
217
+ cache.invalidate('pattern*'); // Wildcard invalidation
218
+ cache.clear(); // Clear all
219
+ ```
220
+
221
+ ## Advanced Package Features
222
+
223
+ ### Adaptive Rate Limiting
224
+
225
+ ```typescript
226
+ import { AdaptiveRateLimiter } from '@ariadng/sheets/advanced';
227
+
228
+ const limiter = new AdaptiveRateLimiter();
229
+
230
+ // Automatically adjusts delay based on success/failure
231
+ await limiter.execute(async () => {
232
+ return sheets.read(id, range);
233
+ });
234
+
235
+ // Get current stats
236
+ const stats = limiter.getStats();
237
+ console.log(stats); // { requestsInWindow: 45, successRate: 0.98, baseDelay: 0 }
238
+ ```
239
+
240
+ ### Metrics Collection
241
+
242
+ ```typescript
243
+ import { withMetrics } from '@ariadng/sheets/advanced';
244
+
245
+ const metricsSheets = withMetrics(sheets);
246
+
247
+ // Use normally
248
+ await metricsSheets.read(id, range);
249
+ await metricsSheets.write(id, range, values);
250
+
251
+ // Get metrics
252
+ const metrics = metricsSheets.metrics.getMetrics();
253
+ console.log(metrics);
254
+ // {
255
+ // totalRequests: 150,
256
+ // successfulRequests: 148,
257
+ // failedRequests: 2,
258
+ // averageLatency: 123.5,
259
+ // rateLimitHits: 1,
260
+ // errorsByCode: Map { 429 => 1, 500 => 1 }
261
+ // }
262
+
263
+ const summary = metricsSheets.metrics.getSummary();
264
+ console.log(summary);
265
+ // {
266
+ // successRate: 0.987,
267
+ // requestsPerSecond: 2.5,
268
+ // uptimeSeconds: 60
269
+ // }
270
+ ```
271
+
272
+ ## Error Handling
273
+
274
+ ```typescript
275
+ import { GoogleSheetsError } from '@ariadng/sheets/core';
276
+
277
+ try {
278
+ await sheets.read(spreadsheetId, range);
279
+ } catch (error) {
280
+ if (error instanceof GoogleSheetsError) {
281
+ console.error(`API Error ${error.code}: ${error.message}`);
282
+
283
+ if (error.isRetryable) {
284
+ console.log('This error is retryable');
285
+ }
286
+
287
+ if (error.isPermissionError()) {
288
+ console.log('Share the sheet with service account');
289
+ }
290
+
291
+ if (error.isRateLimitError()) {
292
+ console.log('Hit rate limit, slow down');
293
+ }
294
+
295
+ // User-friendly message
296
+ console.log(error.getUserMessage());
297
+ }
298
+ }
299
+ ```
300
+
301
+ ## Common Patterns
302
+
303
+ ### Progressive Enhancement
304
+
305
+ ```typescript
306
+ import { GoogleSheetsCore } from '@ariadng/sheets/core';
307
+ import { withCache } from '@ariadng/sheets/plus';
308
+ import { withAdaptiveRateLimit, withMetrics } from '@ariadng/sheets/advanced';
309
+
310
+ // Start simple
311
+ let sheets = new GoogleSheetsCore({ auth });
312
+
313
+ // Add features as needed
314
+ sheets = withCache(sheets, { ttlSeconds: 300 });
315
+ sheets = withAdaptiveRateLimit(sheets);
316
+ sheets = withMetrics(sheets);
317
+
318
+ // Now have all features!
319
+ ```
320
+
321
+ ### Data Processing Pipeline
322
+
323
+ ```typescript
324
+ import { Parsers, Serializers } from '@ariadng/sheets/plus';
325
+
326
+ // Read raw data
327
+ const raw = await sheets.read(id, 'Data!A1:Z1000');
328
+
329
+ // Parse to objects
330
+ const records = Parsers.rowsToObjects(raw);
331
+
332
+ // Process data
333
+ const processed = records
334
+ .filter(r => r.status === 'active')
335
+ .map(r => ({ ...r, processed: true }));
336
+
337
+ // Convert back to rows
338
+ const rows = Serializers.objectsToRows(processed);
339
+
340
+ // Write back
341
+ await sheets.write(id, 'Processed!A1', rows);
342
+ ```
343
+
344
+ ### Efficient Batch Processing
345
+
346
+ ```typescript
347
+ import { BatchOperations } from '@ariadng/sheets/plus';
348
+
349
+ const batch = new BatchOperations(sheets);
350
+
351
+ // Mixed operations
352
+ const results = await batch.executeBatch(spreadsheetId, {
353
+ reads: ['Summary!A1:Z1', 'Config!A1:B10'],
354
+ writes: [
355
+ { range: 'Output!A1:B100', values: outputData }
356
+ ],
357
+ clears: ['Temp!A:Z']
358
+ });
359
+
360
+ // All executed efficiently in parallel when possible
361
+ ```
362
+
363
+ ## API Reference
364
+
365
+ ### Core Package
366
+
367
+ #### GoogleSheetsCore
368
+
369
+ - `constructor(config: GoogleSheetsConfig)`
370
+ - `read(spreadsheetId: string, range: string): Promise<any[][]>`
371
+ - `write(spreadsheetId: string, range: string, values: any[][]): Promise<UpdateValuesResponse>`
372
+ - `append(spreadsheetId: string, range: string, values: any[][]): Promise<AppendValuesResponse>`
373
+ - `clear(spreadsheetId: string, range: string): Promise<ClearValuesResponse>`
374
+ - `batchRead(spreadsheetId: string, ranges: string[]): Promise<ValueRange[]>`
375
+ - `batchWrite(spreadsheetId: string, data: BatchWriteData[]): Promise<BatchUpdateValuesResponse>`
376
+ - `getSpreadsheet(spreadsheetId: string): Promise<Spreadsheet>`
377
+ - `getApi(): sheets_v4.Sheets`
378
+
379
+ ### Plus Package
380
+
381
+ #### A1 Utilities
382
+
383
+ - `A1.columnToIndex(column: string): number`
384
+ - `A1.indexToColumn(index: number): string`
385
+ - `A1.parse(notation: string): A1Components`
386
+ - `A1.build(sheet?, startCol, startRow, endCol?, endRow?): string`
387
+ - `A1.getDimensions(notation: string): { rows: number, columns: number }`
388
+ - `A1.offset(notation: string, rowOffset: number, colOffset: number): string`
389
+
390
+ #### Parsers
391
+
392
+ - `Parsers.rowsToObjects<T>(data: any[][]): T[]`
393
+ - `Parsers.asNumbers(data: any[][]): number[][]`
394
+ - `Parsers.asStrings(data: any[][]): string[][]`
395
+ - `Parsers.asMap<V>(data: any[][]): Map<string, V>`
396
+ - `Parsers.column<T>(data: any[][], columnIndex: number): T[]`
397
+
398
+ #### Serializers
399
+
400
+ - `Serializers.objectsToRows<T>(objects: T[], headers?: string[]): any[][]`
401
+ - `Serializers.mapToRows<K,V>(map: Map<K,V>): any[][]`
402
+ - `Serializers.arrayToColumn<T>(array: T[]): any[][]`
403
+ - `Serializers.transpose(data: any[][]): any[][]`
404
+
405
+ ## Performance
406
+
407
+ | Operation | Base Latency | With Cache | With Rate Limit |
408
+ |-----------|-------------|------------|-----------------|
409
+ | Single Read | 100-200ms | 0-1ms (hit) | +0-50ms |
410
+ | Batch Read (10) | 150-250ms | 0-1ms (hit) | +0-50ms |
411
+ | Single Write | 150-300ms | N/A | +0-50ms |
412
+ | Batch Write (100) | 300-500ms | N/A | +0-100ms |
413
+
414
+ ## Best Practices
415
+
416
+ 1. **Use batch operations** when reading/writing multiple ranges
417
+ 2. **Enable caching** for frequently read, rarely changed data
418
+ 3. **Add rate limiting** for bulk operations or scripts
419
+ 4. **Use type utilities** for better type safety and code clarity
420
+ 5. **Handle errors gracefully** with proper retry logic
421
+ 6. **Monitor with metrics** in production environments
422
+
423
+ ## Requirements
424
+
425
+ - Node.js 14+
426
+ - Google Sheets API enabled in Google Cloud Console
427
+ - Service account or OAuth2 credentials
428
+
429
+ ## License
430
+
431
+ MIT
432
+
433
+ ## Contributing
434
+
435
+ Contributions are welcome! Please read our contributing guidelines before submitting PRs.
436
+
437
+ ## Support
438
+
439
+ For issues and feature requests, please use the [GitHub issues page](https://github.com/ariadng/sheets/issues).
@@ -0,0 +1,5 @@
1
+ export { AdaptiveRateLimiter, TokenBucketRateLimiter, withAdaptiveRateLimit, withTokenBucketRateLimit, } from './rate-limit';
2
+ export { MetricsCollector, PerformanceMonitor, withMetrics, } from './metrics';
3
+ export type { Metrics } from './metrics';
4
+ export * from '../plus';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/advanced/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,GACxB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACN,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,GACX,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,cAAc,SAAS,CAAC"}