longcelot-sheet-db 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.
Files changed (97) hide show
  1. package/API.md +608 -0
  2. package/CHANGELOG.md +0 -0
  3. package/LICENSE +21 -0
  4. package/README.md +369 -0
  5. package/dist/adapter/crud.d.ts +20 -0
  6. package/dist/adapter/crud.d.ts.map +1 -0
  7. package/dist/adapter/crud.js +219 -0
  8. package/dist/adapter/crud.js.map +1 -0
  9. package/dist/adapter/sheetAdapter.d.ts +31 -0
  10. package/dist/adapter/sheetAdapter.d.ts.map +1 -0
  11. package/dist/adapter/sheetAdapter.js +110 -0
  12. package/dist/adapter/sheetAdapter.js.map +1 -0
  13. package/dist/adapter/sheetClient.d.ts +20 -0
  14. package/dist/adapter/sheetClient.d.ts.map +1 -0
  15. package/dist/adapter/sheetClient.js +112 -0
  16. package/dist/adapter/sheetClient.js.map +1 -0
  17. package/dist/auth/oauth.d.ts +15 -0
  18. package/dist/auth/oauth.d.ts.map +1 -0
  19. package/dist/auth/oauth.js +37 -0
  20. package/dist/auth/oauth.js.map +1 -0
  21. package/dist/auth/password.d.ts +7 -0
  22. package/dist/auth/password.d.ts.map +1 -0
  23. package/dist/auth/password.js +36 -0
  24. package/dist/auth/password.js.map +1 -0
  25. package/dist/cli/commands/doctor.d.ts +2 -0
  26. package/dist/cli/commands/doctor.d.ts.map +1 -0
  27. package/dist/cli/commands/doctor.js +91 -0
  28. package/dist/cli/commands/doctor.js.map +1 -0
  29. package/dist/cli/commands/generate.d.ts +2 -0
  30. package/dist/cli/commands/generate.d.ts.map +1 -0
  31. package/dist/cli/commands/generate.js +121 -0
  32. package/dist/cli/commands/generate.js.map +1 -0
  33. package/dist/cli/commands/init.d.ts +2 -0
  34. package/dist/cli/commands/init.d.ts.map +1 -0
  35. package/dist/cli/commands/init.js +122 -0
  36. package/dist/cli/commands/init.js.map +1 -0
  37. package/dist/cli/commands/seed.d.ts +2 -0
  38. package/dist/cli/commands/seed.d.ts.map +1 -0
  39. package/dist/cli/commands/seed.js +119 -0
  40. package/dist/cli/commands/seed.js.map +1 -0
  41. package/dist/cli/commands/status.d.ts +2 -0
  42. package/dist/cli/commands/status.d.ts.map +1 -0
  43. package/dist/cli/commands/status.js +106 -0
  44. package/dist/cli/commands/status.js.map +1 -0
  45. package/dist/cli/commands/sync.d.ts +2 -0
  46. package/dist/cli/commands/sync.d.ts.map +1 -0
  47. package/dist/cli/commands/sync.js +152 -0
  48. package/dist/cli/commands/sync.js.map +1 -0
  49. package/dist/cli/commands/validate.d.ts +2 -0
  50. package/dist/cli/commands/validate.d.ts.map +1 -0
  51. package/dist/cli/commands/validate.js +91 -0
  52. package/dist/cli/commands/validate.js.map +1 -0
  53. package/dist/cli/index.d.ts +3 -0
  54. package/dist/cli/index.d.ts.map +1 -0
  55. package/dist/cli/index.js +46 -0
  56. package/dist/cli/index.js.map +1 -0
  57. package/dist/errors/PermissionError.d.ts +5 -0
  58. package/dist/errors/PermissionError.d.ts.map +1 -0
  59. package/dist/errors/PermissionError.js +13 -0
  60. package/dist/errors/PermissionError.js.map +1 -0
  61. package/dist/errors/SchemaError.d.ts +5 -0
  62. package/dist/errors/SchemaError.d.ts.map +1 -0
  63. package/dist/errors/SchemaError.js +13 -0
  64. package/dist/errors/SchemaError.js.map +1 -0
  65. package/dist/errors/ValidationError.d.ts +5 -0
  66. package/dist/errors/ValidationError.d.ts.map +1 -0
  67. package/dist/errors/ValidationError.js +13 -0
  68. package/dist/errors/ValidationError.js.map +1 -0
  69. package/dist/errors/index.d.ts +4 -0
  70. package/dist/errors/index.d.ts.map +1 -0
  71. package/dist/errors/index.js +10 -0
  72. package/dist/errors/index.js.map +1 -0
  73. package/dist/index.d.ts +12 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +29 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/schema/columnBuilder.d.ts +23 -0
  78. package/dist/schema/columnBuilder.d.ts.map +1 -0
  79. package/dist/schema/columnBuilder.js +78 -0
  80. package/dist/schema/columnBuilder.js.map +1 -0
  81. package/dist/schema/defineTable.d.ts +12 -0
  82. package/dist/schema/defineTable.d.ts.map +1 -0
  83. package/dist/schema/defineTable.js +31 -0
  84. package/dist/schema/defineTable.js.map +1 -0
  85. package/dist/schema/types.d.ts +50 -0
  86. package/dist/schema/types.d.ts.map +1 -0
  87. package/dist/schema/types.js +3 -0
  88. package/dist/schema/types.js.map +1 -0
  89. package/dist/utils/env.d.ts +6 -0
  90. package/dist/utils/env.d.ts.map +1 -0
  91. package/dist/utils/env.js +14 -0
  92. package/dist/utils/env.js.map +1 -0
  93. package/dist/utils/logger.d.ts +7 -0
  94. package/dist/utils/logger.d.ts.map +1 -0
  95. package/dist/utils/logger.js +15 -0
  96. package/dist/utils/logger.js.map +1 -0
  97. package/package.json +73 -0
package/API.md ADDED
@@ -0,0 +1,608 @@
1
+ # API Documentation
2
+
3
+ ## Table of Contents
4
+
5
+ - [Schema Definition](#schema-definition)
6
+ - [Column Builders](#column-builders)
7
+ - [Sheet Adapter](#sheet-adapter)
8
+ - [CRUD Operations](#crud-operations)
9
+ - [Authentication](#authentication)
10
+ - [CLI Commands](#cli-commands)
11
+
12
+ ## Schema Definition
13
+
14
+ ### `defineTable(config)`
15
+
16
+ Defines a table schema.
17
+
18
+ **Parameters:**
19
+
20
+ ```typescript
21
+ {
22
+ name: string; // Table name
23
+ actor: string; // Actor that owns this table
24
+ timestamps?: boolean; // Add _created_at, _updated_at (default: false)
25
+ softDelete?: boolean; // Add _deleted_at (default: false)
26
+ columns: {
27
+ [columnName: string]: ColumnBuilder | ColumnDefinition;
28
+ };
29
+ }
30
+ ```
31
+
32
+ **Returns:** `TableSchema`
33
+
34
+ **Example:**
35
+
36
+ ```typescript
37
+ import { defineTable, string, number } from 'longcelot-sheet-db';
38
+
39
+ const bookingsSchema = defineTable({
40
+ name: 'bookings',
41
+ actor: 'user',
42
+ timestamps: true,
43
+ columns: {
44
+ booking_id: string().required().unique(),
45
+ price: number().min(0),
46
+ },
47
+ });
48
+ ```
49
+
50
+ ## Column Builders
51
+
52
+ ### `string()`
53
+
54
+ Creates a string column.
55
+
56
+ **Modifiers:**
57
+
58
+ - `.required()` - Cannot be null
59
+ - `.unique()` - Must be unique
60
+ - `.default(value)` - Default value
61
+ - `.min(length)` - Minimum length
62
+ - `.max(length)` - Maximum length
63
+ - `.enum(values)` - Allowed values
64
+ - `.pattern(regex)` - Regex validation
65
+ - `.primary()` - Primary key
66
+ - `.readonly()` - Cannot be updated
67
+ - `.ref(table.column)` - Foreign key reference
68
+ - `.index()` - Create index
69
+
70
+ **Example:**
71
+
72
+ ```typescript
73
+ email: string().required().unique().min(5).max(100)
74
+ status: string().enum(['active', 'inactive']).default('active')
75
+ ```
76
+
77
+ ### `number()`
78
+
79
+ Creates a number column.
80
+
81
+ **Modifiers:**
82
+
83
+ - `.required()`
84
+ - `.unique()`
85
+ - `.default(value)`
86
+ - `.min(value)` - Minimum value
87
+ - `.max(value)` - Maximum value
88
+
89
+ **Example:**
90
+
91
+ ```typescript
92
+ age: number().min(0).max(120)
93
+ price: number().min(0).required()
94
+ ```
95
+
96
+ ### `boolean()`
97
+
98
+ Creates a boolean column.
99
+
100
+ **Modifiers:**
101
+
102
+ - `.required()`
103
+ - `.default(value)` - true or false
104
+
105
+ **Example:**
106
+
107
+ ```typescript
108
+ is_active: boolean().default(true)
109
+ verified: boolean().required()
110
+ ```
111
+
112
+ ### `date()`
113
+
114
+ Creates a date column (stored as ISO string).
115
+
116
+ **Modifiers:**
117
+
118
+ - `.required()`
119
+ - `.default(value)`
120
+
121
+ **Example:**
122
+
123
+ ```typescript
124
+ birth_date: date().required()
125
+ expires_at: date()
126
+ ```
127
+
128
+ ### `json()`
129
+
130
+ Creates a JSON column (stored as JSON string).
131
+
132
+ **Modifiers:**
133
+
134
+ - `.required()`
135
+ - `.default(value)`
136
+
137
+ **Example:**
138
+
139
+ ```typescript
140
+ metadata: json()
141
+ settings: json().default({})
142
+ ```
143
+
144
+ ## Sheet Adapter
145
+
146
+ ### `createSheetAdapter(config)`
147
+
148
+ Creates a new sheet adapter instance.
149
+
150
+ **Parameters:**
151
+
152
+ ```typescript
153
+ {
154
+ adminSheetId: string;
155
+ credentials: {
156
+ clientId: string;
157
+ clientSecret: string;
158
+ redirectUri: string;
159
+ };
160
+ tokens: any; // OAuth tokens
161
+ }
162
+ ```
163
+
164
+ **Returns:** `SheetAdapter`
165
+
166
+ **Example:**
167
+
168
+ ```typescript
169
+ const adapter = createSheetAdapter({
170
+ adminSheetId: process.env.ADMIN_SHEET_ID,
171
+ credentials: {
172
+ clientId: process.env.GOOGLE_CLIENT_ID,
173
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
174
+ redirectUri: process.env.GOOGLE_REDIRECT_URI,
175
+ },
176
+ tokens: userTokens,
177
+ });
178
+ ```
179
+
180
+ ### `adapter.registerSchema(schema)`
181
+
182
+ Registers a single schema.
183
+
184
+ **Parameters:**
185
+
186
+ - `schema: TableSchema`
187
+
188
+ **Example:**
189
+
190
+ ```typescript
191
+ adapter.registerSchema(bookingsSchema);
192
+ ```
193
+
194
+ ### `adapter.registerSchemas(schemas)`
195
+
196
+ Registers multiple schemas at once.
197
+
198
+ **Parameters:**
199
+
200
+ - `schemas: TableSchema[]`
201
+
202
+ **Example:**
203
+
204
+ ```typescript
205
+ adapter.registerSchemas([usersSchema, bookingsSchema, paymentsSchema]);
206
+ ```
207
+
208
+ ### `adapter.withContext(context)`
209
+
210
+ Creates a new adapter instance with user context.
211
+
212
+ **Parameters:**
213
+
214
+ ```typescript
215
+ {
216
+ userId: string;
217
+ role: string;
218
+ actorSheetId?: string;
219
+ }
220
+ ```
221
+
222
+ **Returns:** `SheetAdapter` with context
223
+
224
+ **Example:**
225
+
226
+ ```typescript
227
+ const userContext = adapter.withContext({
228
+ userId: 'user_123',
229
+ role: 'user',
230
+ actorSheetId: 'sheet-id-xyz',
231
+ });
232
+ ```
233
+
234
+ ### `adapter.table(tableName)`
235
+
236
+ Gets CRUD operations for a table.
237
+
238
+ **Parameters:**
239
+
240
+ - `tableName: string`
241
+
242
+ **Returns:** `CRUDOperations`
243
+
244
+ **Example:**
245
+
246
+ ```typescript
247
+ const bookings = adapter.table('bookings');
248
+ ```
249
+
250
+ ### `adapter.createUserSheet(userId, role, email)`
251
+
252
+ Creates a new sheet for a user.
253
+
254
+ **Parameters:**
255
+
256
+ - `userId: string` - Unique user ID
257
+ - `role: string` - User role/actor
258
+ - `email: string` - User email
259
+
260
+ **Returns:** `Promise<string>` - Sheet ID
261
+
262
+ **Example:**
263
+
264
+ ```typescript
265
+ const sheetId = await adapter.createUserSheet('user_123', 'student', 'student@school.com');
266
+ ```
267
+
268
+ ### `adapter.syncSchema(schema)`
269
+
270
+ Syncs a schema to Google Sheets.
271
+
272
+ **Parameters:**
273
+
274
+ - `schema: TableSchema`
275
+
276
+ **Returns:** `Promise<void>`
277
+
278
+ **Example:**
279
+
280
+ ```typescript
281
+ await adapter.syncSchema(bookingsSchema);
282
+ ```
283
+
284
+ ## CRUD Operations
285
+
286
+ ### `table.create(data)`
287
+
288
+ Creates a new row.
289
+
290
+ **Parameters:**
291
+
292
+ - `data: Record<string, any>` - Row data
293
+
294
+ **Returns:** `Promise<Record<string, any>>` - Created row with generated fields
295
+
296
+ **Example:**
297
+
298
+ ```typescript
299
+ const booking = await table.create({
300
+ booking_id: 'bk_001',
301
+ service: 'Consultation',
302
+ date: new Date().toISOString(),
303
+ price: 100,
304
+ });
305
+ ```
306
+
307
+ ### `table.findMany(options)`
308
+
309
+ Finds multiple rows.
310
+
311
+ **Parameters:**
312
+
313
+ ```typescript
314
+ {
315
+ where?: Record<string, any>;
316
+ limit?: number;
317
+ offset?: number;
318
+ orderBy?: string;
319
+ order?: 'asc' | 'desc';
320
+ }
321
+ ```
322
+
323
+ **Returns:** `Promise<Record<string, any>[]>`
324
+
325
+ **Example:**
326
+
327
+ ```typescript
328
+ const bookings = await table.findMany({
329
+ where: { status: 'pending' },
330
+ orderBy: 'date',
331
+ order: 'desc',
332
+ limit: 10,
333
+ });
334
+ ```
335
+
336
+ ### `table.findOne(options)`
337
+
338
+ Finds a single row.
339
+
340
+ **Parameters:**
341
+
342
+ ```typescript
343
+ {
344
+ where?: Record<string, any>;
345
+ }
346
+ ```
347
+
348
+ **Returns:** `Promise<Record<string, any> | null>`
349
+
350
+ **Example:**
351
+
352
+ ```typescript
353
+ const booking = await table.findOne({
354
+ where: { booking_id: 'bk_001' },
355
+ });
356
+ ```
357
+
358
+ ### `table.update(options)`
359
+
360
+ Updates rows matching criteria.
361
+
362
+ **Parameters:**
363
+
364
+ ```typescript
365
+ {
366
+ where: Record<string, any>;
367
+ data: Record<string, any>;
368
+ }
369
+ ```
370
+
371
+ **Returns:** `Promise<number>` - Number of rows updated
372
+
373
+ **Example:**
374
+
375
+ ```typescript
376
+ const updated = await table.update({
377
+ where: { booking_id: 'bk_001' },
378
+ data: { status: 'confirmed' },
379
+ });
380
+ ```
381
+
382
+ ### `table.delete(options)`
383
+
384
+ Deletes rows matching criteria.
385
+
386
+ **Parameters:**
387
+
388
+ ```typescript
389
+ {
390
+ where: Record<string, any>;
391
+ }
392
+ ```
393
+
394
+ **Returns:** `Promise<number>` - Number of rows deleted
395
+
396
+ **Example:**
397
+
398
+ ```typescript
399
+ const deleted = await table.delete({
400
+ where: { booking_id: 'bk_001' },
401
+ });
402
+ ```
403
+
404
+ ## Authentication
405
+
406
+ ### `createOAuthManager(config)`
407
+
408
+ Creates an OAuth manager.
409
+
410
+ **Parameters:**
411
+
412
+ ```typescript
413
+ {
414
+ clientId: string;
415
+ clientSecret: string;
416
+ redirectUri: string;
417
+ }
418
+ ```
419
+
420
+ **Returns:** `OAuthManager`
421
+
422
+ ### `oauth.getAuthUrl()`
423
+
424
+ Gets the OAuth authorization URL.
425
+
426
+ **Returns:** `string`
427
+
428
+ **Example:**
429
+
430
+ ```typescript
431
+ const authUrl = oauth.getAuthUrl();
432
+ // Redirect user to authUrl
433
+ ```
434
+
435
+ ### `oauth.getTokens(code)`
436
+
437
+ Exchanges authorization code for tokens.
438
+
439
+ **Parameters:**
440
+
441
+ - `code: string` - Authorization code from OAuth callback
442
+
443
+ **Returns:** `Promise<any>` - OAuth tokens
444
+
445
+ ### `oauth.refreshTokens(refreshToken)`
446
+
447
+ Refreshes expired tokens.
448
+
449
+ **Parameters:**
450
+
451
+ - `refreshToken: string`
452
+
453
+ **Returns:** `Promise<any>` - New tokens
454
+
455
+ ### `oauth.verifyToken(idToken)`
456
+
457
+ Verifies an ID token.
458
+
459
+ **Parameters:**
460
+
461
+ - `idToken: string`
462
+
463
+ **Returns:** `Promise<any>` - Token payload
464
+
465
+ ### `hashPassword(password)`
466
+
467
+ Hashes a password using bcrypt.
468
+
469
+ **Parameters:**
470
+
471
+ - `password: string`
472
+
473
+ **Returns:** `Promise<string>` - Hashed password
474
+
475
+ **Example:**
476
+
477
+ ```typescript
478
+ const hash = await hashPassword('SecurePass123!');
479
+ ```
480
+
481
+ ### `comparePassword(password, hash)`
482
+
483
+ Compares a password with a hash.
484
+
485
+ **Parameters:**
486
+
487
+ - `password: string` - Plain text password
488
+ - `hash: string` - Hashed password
489
+
490
+ **Returns:** `Promise<boolean>`
491
+
492
+ **Example:**
493
+
494
+ ```typescript
495
+ const isValid = await comparePassword('SecurePass123!', hash);
496
+ ```
497
+
498
+ ### `validatePasswordStrength(password)`
499
+
500
+ Validates password strength.
501
+
502
+ **Parameters:**
503
+
504
+ - `password: string`
505
+
506
+ **Returns:**
507
+
508
+ ```typescript
509
+ {
510
+ valid: boolean;
511
+ errors: string[];
512
+ }
513
+ ```
514
+
515
+ **Example:**
516
+
517
+ ```typescript
518
+ const { valid, errors } = validatePasswordStrength('weak');
519
+ if (!valid) {
520
+ console.log(errors); // ["Password must be at least 8 characters long", ...]
521
+ }
522
+ ```
523
+
524
+ ## CLI Commands
525
+
526
+ ### `sheet-db init`
527
+
528
+ Initializes a new longcelot-sheet-db project.
529
+
530
+ **Creates:**
531
+
532
+ - `sheet-db.config.ts`
533
+ - `.env`
534
+ - `schemas/` directory
535
+
536
+ ### `sheet-db generate <table-name>`
537
+
538
+ Generates a new table schema interactively.
539
+
540
+ **Example:**
541
+
542
+ ```bash
543
+ pnpm sheet-db generate bookings
544
+ ```
545
+
546
+ ### `sheet-db sync`
547
+
548
+ Syncs all schemas to Google Sheets.
549
+
550
+ **Actions:**
551
+
552
+ - Creates missing sheets
553
+ - Adds missing columns
554
+ - Never deletes existing data
555
+
556
+ ### `sheet-db validate`
557
+
558
+ Validates all schemas.
559
+
560
+ **Checks:**
561
+
562
+ - Duplicate table names
563
+ - Invalid modifiers
564
+ - Unknown actors
565
+ - Missing required fields
566
+
567
+ ## Type Definitions
568
+
569
+ ### `TableSchema`
570
+
571
+ ```typescript
572
+ interface TableSchema {
573
+ name: string;
574
+ actor: string;
575
+ timestamps?: boolean;
576
+ softDelete?: boolean;
577
+ columns: Record<string, ColumnDefinition>;
578
+ }
579
+ ```
580
+
581
+ ### `ColumnDefinition`
582
+
583
+ ```typescript
584
+ interface ColumnDefinition {
585
+ type: 'string' | 'number' | 'boolean' | 'date' | 'json';
586
+ required?: boolean;
587
+ unique?: boolean;
588
+ default?: any;
589
+ min?: number;
590
+ max?: number;
591
+ enum?: any[];
592
+ pattern?: RegExp;
593
+ readonly?: boolean;
594
+ primary?: boolean;
595
+ ref?: string;
596
+ index?: boolean;
597
+ }
598
+ ```
599
+
600
+ ### `UserContext`
601
+
602
+ ```typescript
603
+ interface UserContext {
604
+ userId: string;
605
+ role: string;
606
+ actorSheetId?: string;
607
+ }
608
+ ```
package/CHANGELOG.md ADDED
File without changes
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Longcelot
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.