longcelot-sheet-db 0.1.4 → 0.1.7
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/CHANGELOG.md +93 -1
- package/LICENSE +1 -1
- package/README.md +167 -6
- package/dist/cli/commands/init.d.ts +3 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +30 -8
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/mock-users.d.ts +3 -0
- package/dist/cli/commands/mock-users.d.ts.map +1 -0
- package/dist/cli/commands/mock-users.js +101 -0
- package/dist/cli/commands/mock-users.js.map +1 -0
- package/dist/cli/commands/seed.d.ts +1 -1
- package/dist/cli/commands/seed.d.ts.map +1 -1
- package/dist/cli/commands/seed.js +42 -1
- package/dist/cli/commands/seed.js.map +1 -1
- package/dist/cli/commands/sync.d.ts +3 -1
- package/dist/cli/commands/sync.d.ts.map +1 -1
- package/dist/cli/commands/sync.js +43 -2
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/index.js +9 -1
- package/dist/cli/index.js.map +1 -1
- package/package.json +7 -3
- package/skills/auth/SKILL.md +142 -0
- package/skills/cli/SKILL.md +150 -0
- package/skills/core/SKILL.md +115 -0
- package/skills/crud/SKILL.md +185 -0
- package/skills/schema/SKILL.md +129 -0
package/CHANGELOG.md
CHANGED
|
@@ -1 +1,93 @@
|
|
|
1
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
> **How to read this file**
|
|
4
|
+
>
|
|
5
|
+
> Every time a new version is released, a new section is added here at the top.
|
|
6
|
+
> Changes are grouped by type:
|
|
7
|
+
> - **Added** – new features
|
|
8
|
+
> - **Changed** – changes to existing behaviour
|
|
9
|
+
> - **Fixed** – bug fixes
|
|
10
|
+
> - **Removed** – removed features
|
|
11
|
+
> - **Security** – security fixes
|
|
12
|
+
>
|
|
13
|
+
> The `[Unreleased]` section collects changes that are merged but not yet published to npm.
|
|
14
|
+
> When you run `npm publish`, rename `[Unreleased]` to the new version number and date.
|
|
15
|
+
|
|
16
|
+
All notable changes to this project will be documented in this file.
|
|
17
|
+
This project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and [Semantic Versioning](https://semver.org/).
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## [Unreleased]
|
|
22
|
+
|
|
23
|
+
### Planned (Phase 2 & 3 Roadmap)
|
|
24
|
+
- **Added**: `init --integrate` CLI command to integrate `longcelot-sheet-db` into an existing Node.js project without destroying existing configuration.
|
|
25
|
+
- **Added**: `sync --all-users` CLI command to bulk-update Google Sheets schemas across all initialized user endpoints.
|
|
26
|
+
- **Added**: Developer sandbox CLI tools (`sheet-db mock-users`).
|
|
27
|
+
- **Added**: Prisma/SQL DDL automated migration script (`sheet-db export`).
|
|
28
|
+
- **Changed**: Improved documentation for integrating with existing backends and planning forward migration to SQL.
|
|
29
|
+
- **Removed**: Redundant `Docs/apiReference.md` file layout to consolidate into root `API.md`.
|
|
30
|
+
|
|
31
|
+
### New Documentation (Q1-Q9)
|
|
32
|
+
- **Added**: Clarified OAuth requirement — cannot be skipped, required for backend-to-Sheets communication.
|
|
33
|
+
- **Added**: Integration workflow for existing projects — mapping user auth to sheet-db context.
|
|
34
|
+
- **Added**: Development workflow documentation — how to test with multiple actor sheets.
|
|
35
|
+
- **Added**: Migration path documentation — `user_id` vs `sheet_id` purpose.
|
|
36
|
+
- **Added**: Cross-actor operations documentation — join APIs and permission models (roadmap).
|
|
37
|
+
- **Added**: Export CLI (`sheet-db export`) for generating Prisma schemas and SQL DDL.
|
|
38
|
+
- **Added**: Sync `--all-users` for pushing schema changes to all registered users.
|
|
39
|
+
|
|
40
|
+
_Nothing yet — add your in-progress changes here before the next release._
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## [0.1.5] - 2026-03-09
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
- Download count badge in `README.md`
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
- Updated `LICENSE` copyright year to 2026
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## [0.1.0] - 2026-03-09
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
- Initial public release of `longcelot-sheet-db`
|
|
58
|
+
- `defineTable()` schema DSL with fluent column builders (`string()`, `number()`, `boolean()`, `date()`, `json()`)
|
|
59
|
+
- Column modifiers: `required`, `unique`, `default`, `min`, `max`, `enum`, `pattern`, `readonly`, `primary`, `ref`, `index`
|
|
60
|
+
- Auto-generated fields: `_id` (nanoid), `_created_at`, `_updated_at`, `_deleted_at`
|
|
61
|
+
- `SheetAdapter` — main adapter with actor-based sheet routing and permission enforcement
|
|
62
|
+
- `SheetClient` — low-level Google Sheets API wrapper
|
|
63
|
+
- `CRUDOperations` — `create`, `findMany`, `findOne`, `update`, `delete` with where/orderBy/limit/offset
|
|
64
|
+
- Uniqueness constraint enforcement via `checkUniqueness()` in `create()` and `update()`
|
|
65
|
+
- Soft delete support via `_deleted_at` column
|
|
66
|
+
- `OAuthManager` — full Google OAuth2 flow (auth URL, token exchange, refresh, verify)
|
|
67
|
+
- Password utilities: `hashPassword()`, `comparePassword()`, `validatePasswordStrength()` (bcrypt)
|
|
68
|
+
- CLI binary `sheet-db` with commands:
|
|
69
|
+
- `init` — interactive project scaffolding
|
|
70
|
+
- `generate` — interactive schema builder
|
|
71
|
+
- `validate` — schema validation
|
|
72
|
+
- `sync` — sync schemas to Google Sheets with OAuth token storage/refresh
|
|
73
|
+
- `seed` — load initial/test data into sheets
|
|
74
|
+
- `doctor` — diagnostics and environment health checks
|
|
75
|
+
- `status` — show tables, actors, and sheet IDs
|
|
76
|
+
- Custom error classes: `ValidationError`, `PermissionError`, `SchemaError`
|
|
77
|
+
- Structured logger (`src/utils/logger.ts`) using chalk
|
|
78
|
+
- Environment variable validator (`src/utils/env.ts`)
|
|
79
|
+
- Jest test suite — 28 tests passing (unit + integration with `MockSheetClient`)
|
|
80
|
+
- CI/CD pipeline via `.github/workflows/ci.yml` (Node 18 & 20, build + test + lint)
|
|
81
|
+
- `SECURITY.md` — vulnerability reporting policy
|
|
82
|
+
- `CONTRIBUTING.md` — contribution guide
|
|
83
|
+
- `LICENSE` — MIT
|
|
84
|
+
|
|
85
|
+
### Changed
|
|
86
|
+
- `dist/` removed from version control and added to `.gitignore`
|
|
87
|
+
- `package.json` updated with `files`, `repository`, `engines`, `publishConfig` for npm publish readiness
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
[Unreleased]: https://github.com/vannseavlong/longcelot-sheet-staging/compare/v0.1.5...HEAD
|
|
92
|
+
[0.1.5]: https://github.com/vannseavlong/longcelot-sheet-staging/compare/v0.1.0...v0.1.5
|
|
93
|
+
[0.1.0]: https://github.com/vannseavlong/longcelot-sheet-staging/releases/tag/v0.1.0
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/vannseavlong/longcelot-sheet-staging/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/longcelot-sheet-db)
|
|
5
|
+
[](https://www.npmjs.com/package/longcelot-sheet-db)
|
|
5
6
|
[](LICENSE)
|
|
6
7
|
|
|
7
8
|
**Google Sheets-backed Staging Database for Node.js**
|
|
@@ -32,15 +33,33 @@ Instead of running MySQL, PostgreSQL, or MongoDB for staging:
|
|
|
32
33
|
### Installation
|
|
33
34
|
|
|
34
35
|
```bash
|
|
36
|
+
# npm
|
|
35
37
|
npm install longcelot-sheet-db
|
|
36
|
-
|
|
38
|
+
|
|
39
|
+
# pnpm
|
|
37
40
|
pnpm add longcelot-sheet-db
|
|
41
|
+
|
|
42
|
+
# yarn
|
|
43
|
+
yarn add longcelot-sheet-db
|
|
44
|
+
|
|
45
|
+
# bun
|
|
46
|
+
bun add longcelot-sheet-db
|
|
38
47
|
```
|
|
39
48
|
|
|
40
49
|
### Initialize Project
|
|
41
50
|
|
|
42
51
|
```bash
|
|
43
|
-
|
|
52
|
+
# npm
|
|
53
|
+
npx sheet-db init
|
|
54
|
+
|
|
55
|
+
# pnpm
|
|
56
|
+
pnpm dlx sheet-db init
|
|
57
|
+
|
|
58
|
+
# yarn
|
|
59
|
+
yarn dlx sheet-db init
|
|
60
|
+
|
|
61
|
+
# bun
|
|
62
|
+
bunx sheet-db init
|
|
44
63
|
```
|
|
45
64
|
|
|
46
65
|
This creates:
|
|
@@ -48,6 +67,28 @@ This creates:
|
|
|
48
67
|
- `.env` - Environment variables
|
|
49
68
|
- `schemas/` - Schema directory
|
|
50
69
|
|
|
70
|
+
### Set Up Google OAuth
|
|
71
|
+
|
|
72
|
+
This package **requires Google OAuth2** to function — there is no way to skip it. OAuth is used for the backend to communicate with Google Sheets API.
|
|
73
|
+
|
|
74
|
+
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
|
75
|
+
2. Create a project and enable Google Sheets API and Google Drive API
|
|
76
|
+
3. Create OAuth 2.0 credentials (Client ID and Client Secret)
|
|
77
|
+
4. Set redirect URI (e.g., `http://localhost:3000/auth/callback`)
|
|
78
|
+
5. Add your credentials to `.env`:
|
|
79
|
+
|
|
80
|
+
```env
|
|
81
|
+
GOOGLE_CLIENT_ID=your_client_id
|
|
82
|
+
GOOGLE_CLIENT_SECRET=your_client_secret
|
|
83
|
+
GOOGLE_REDIRECT_URI=http://localhost:3000/auth/callback
|
|
84
|
+
ADMIN_SHEET_ID=your_admin_sheet_id
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**What if you have your own authentication?**
|
|
88
|
+
- OAuth is strictly for **backend-to-Google-Sheets** communication
|
|
89
|
+
- Your app's existing authentication (JWT, sessions, etc.) remains untouched
|
|
90
|
+
- You map your user identity to sheet-db context (see "Integrating into an Existing Project" below)
|
|
91
|
+
|
|
51
92
|
### Define a Schema
|
|
52
93
|
|
|
53
94
|
```typescript
|
|
@@ -187,12 +228,72 @@ Permissions are enforced automatically:
|
|
|
187
228
|
- Admin can access admin tables
|
|
188
229
|
- Cross-actor access is blocked
|
|
189
230
|
|
|
231
|
+
### Integrating into an Existing Project
|
|
232
|
+
If you already have a working backend (e.g., Express, NestJS), you can safely inject `longcelot-sheet-db` without ripping out your framework:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# 1. Add the package
|
|
236
|
+
pnpm add longcelot-sheet-db
|
|
237
|
+
|
|
238
|
+
# 2. Initialize project (creates config and schemas directory)
|
|
239
|
+
npx sheet-db init
|
|
240
|
+
|
|
241
|
+
# 3. Update your .env with Google OAuth credentials
|
|
242
|
+
|
|
243
|
+
# 4. Define your schemas in schemas/ directory
|
|
244
|
+
|
|
245
|
+
# 5. Sync schemas to Google Sheets
|
|
246
|
+
npx sheet-db sync
|
|
247
|
+
|
|
248
|
+
# 6. Use in your backend code
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**How it works with your existing auth**:
|
|
252
|
+
- Your app continues to use your existing authentication (JWT, sessions, cookies)
|
|
253
|
+
- When you need to access data, map your authenticated user to sheet-db context:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// Your Express/NestJS route handler
|
|
257
|
+
app.get('/bookings', async (req, res) => {
|
|
258
|
+
// Your existing auth provides user info
|
|
259
|
+
const developerUser = req.user; // From your JWT/session
|
|
260
|
+
|
|
261
|
+
// Map to sheet-db context
|
|
262
|
+
const userContext = adapter.withContext({
|
|
263
|
+
userId: developerUser.id, // Your app's user ID
|
|
264
|
+
role: developerUser.role, // 'student', 'teacher', etc.
|
|
265
|
+
actorSheetId: developerUser.sheetId, // From sheet-db user registry
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const bookings = await userContext.table('bookings').findMany();
|
|
269
|
+
res.json(bookings);
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Why do we need `user_id` if we have `sheet_id`?
|
|
274
|
+
|
|
275
|
+
The `sheet_id` dictates the **physical storage location** on Google Drive — it exists only in the sheet-db world. When you eventually graduate from Google Sheets to a production SQL database (MySQL, PostgreSQL), the `sheet_id` goes away entirely.
|
|
276
|
+
|
|
277
|
+
The `user_id` dictates the **logical domain identity** — it persists across all databases. This is your app's true primary key that ties your entire system together.
|
|
278
|
+
|
|
279
|
+
| Field | Purpose | Persists after migration |
|
|
280
|
+
|-------|---------|--------------------------|
|
|
281
|
+
| `sheet_id` | Physical location in Google Drive | No — Google Sheets only |
|
|
282
|
+
| `user_id` | Logical user identity | Yes — becomes PK in SQL |
|
|
283
|
+
|
|
284
|
+
**Migration example**: When you export to Prisma, `user_id` becomes your primary key, while `sheet_id` is simply not included in the export.
|
|
285
|
+
|
|
190
286
|
## 🛠️ CLI Commands
|
|
191
287
|
|
|
288
|
+
> All commands can be run with `npx`, `pnpm dlx`, `yarn dlx`, or `bunx` — or directly as `sheet-db <command>` if installed globally.
|
|
289
|
+
|
|
192
290
|
### Initialize Project
|
|
193
291
|
|
|
194
292
|
```bash
|
|
195
|
-
|
|
293
|
+
npx sheet-db init
|
|
294
|
+
# pnpm dlx sheet-db init
|
|
295
|
+
# yarn dlx sheet-db init
|
|
296
|
+
# bunx sheet-db init
|
|
196
297
|
```
|
|
197
298
|
|
|
198
299
|
Creates project structure and configuration files.
|
|
@@ -200,7 +301,10 @@ Creates project structure and configuration files.
|
|
|
200
301
|
### Generate Schema
|
|
201
302
|
|
|
202
303
|
```bash
|
|
203
|
-
|
|
304
|
+
npx sheet-db generate bookings
|
|
305
|
+
# pnpm dlx sheet-db generate bookings
|
|
306
|
+
# yarn dlx sheet-db generate bookings
|
|
307
|
+
# bunx sheet-db generate bookings
|
|
204
308
|
```
|
|
205
309
|
|
|
206
310
|
Interactive schema generator with prompts for columns and types.
|
|
@@ -208,7 +312,10 @@ Interactive schema generator with prompts for columns and types.
|
|
|
208
312
|
### Sync Schemas
|
|
209
313
|
|
|
210
314
|
```bash
|
|
211
|
-
|
|
315
|
+
npx sheet-db sync
|
|
316
|
+
# pnpm dlx sheet-db sync
|
|
317
|
+
# yarn dlx sheet-db sync
|
|
318
|
+
# bunx sheet-db sync
|
|
212
319
|
```
|
|
213
320
|
|
|
214
321
|
Creates missing sheets and adds missing columns (never deletes data).
|
|
@@ -216,7 +323,10 @@ Creates missing sheets and adds missing columns (never deletes data).
|
|
|
216
323
|
### Validate Schemas
|
|
217
324
|
|
|
218
325
|
```bash
|
|
219
|
-
|
|
326
|
+
npx sheet-db validate
|
|
327
|
+
# pnpm dlx sheet-db validate
|
|
328
|
+
# yarn dlx sheet-db validate
|
|
329
|
+
# bunx sheet-db validate
|
|
220
330
|
```
|
|
221
331
|
|
|
222
332
|
Checks for:
|
|
@@ -225,6 +335,39 @@ Checks for:
|
|
|
225
335
|
- Unknown actors
|
|
226
336
|
- Missing required fields
|
|
227
337
|
|
|
338
|
+
### Seed Data
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
npx sheet-db seed
|
|
342
|
+
# pnpm dlx sheet-db seed
|
|
343
|
+
# yarn dlx sheet-db seed
|
|
344
|
+
# bunx sheet-db seed
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Load initial or test data into your sheets.
|
|
348
|
+
|
|
349
|
+
### Doctor
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
npx sheet-db doctor
|
|
353
|
+
# pnpm dlx sheet-db doctor
|
|
354
|
+
# yarn dlx sheet-db doctor
|
|
355
|
+
# bunx sheet-db doctor
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Runs environment and configuration health checks.
|
|
359
|
+
|
|
360
|
+
### Status
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
npx sheet-db status
|
|
364
|
+
# pnpm dlx sheet-db status
|
|
365
|
+
# yarn dlx sheet-db status
|
|
366
|
+
# bunx sheet-db status
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Shows all registered tables, actors, and their sheet IDs.
|
|
370
|
+
|
|
228
371
|
## 🔐 Authentication
|
|
229
372
|
|
|
230
373
|
### Google OAuth
|
|
@@ -291,6 +434,18 @@ When you're ready for production:
|
|
|
291
434
|
3. Update CRUD calls (minimal changes)
|
|
292
435
|
4. No logic trapped in Sheets
|
|
293
436
|
|
|
437
|
+
We are building this adapter with a strict schema constraint so that graduating to production is effortless. By keeping logic in JS and using standard Data Types, your TS definitions can be directly ported over to a Prisma `schema.prisma` file later.
|
|
438
|
+
|
|
439
|
+
**Upcoming CLI for migration**:
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
# Export schemas to Prisma (coming soon)
|
|
443
|
+
npx sheet-db export --prisma --output ./prisma
|
|
444
|
+
|
|
445
|
+
# Export schemas to SQL DDL (coming soon)
|
|
446
|
+
npx sheet-db export --sql --output ./migrations
|
|
447
|
+
```
|
|
448
|
+
|
|
294
449
|
```typescript
|
|
295
450
|
// Development (Sheets)
|
|
296
451
|
const adapter = createSheetAdapter({ ... });
|
|
@@ -299,6 +454,12 @@ const adapter = createSheetAdapter({ ... });
|
|
|
299
454
|
const adapter = createSQLAdapter({ ... });
|
|
300
455
|
```
|
|
301
456
|
|
|
457
|
+
**Data migration workflow**:
|
|
458
|
+
1. Export your schemas using `sheet-db export` (coming soon)
|
|
459
|
+
2. Fetch all data from Sheets using the adapter: `await adapter.table('x').findMany()`
|
|
460
|
+
3. Insert data into your production database
|
|
461
|
+
4. Swap the adapter in your code
|
|
462
|
+
|
|
302
463
|
## ⚡ Performance
|
|
303
464
|
|
|
304
465
|
- Suitable for **hundreds to low thousands** of rows
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAwBA,wBAAsB,WAAW,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAwBA,wBAAsB,WAAW,CAAC,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,iBAsIjE"}
|
|
@@ -11,10 +11,10 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
11
11
|
function printBanner() {
|
|
12
12
|
const c = chalk_1.default.hex('#05b5fb').bold;
|
|
13
13
|
const lines = [
|
|
14
|
-
'█ ██ █ █ ██ ███ ████ █
|
|
14
|
+
'█ ██ █ █ ██ ███ ████ █ ██ ████ ███ █ █ ████ ████ ████ ███ ███ ',
|
|
15
15
|
'█ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █',
|
|
16
|
-
'█ █ █ █ ██ █ ██ █
|
|
17
|
-
'█ █ █ █ █ █ █ █
|
|
16
|
+
'█ █ █ █ ██ █ ██ █ ███ █ █ █ █ ██ ████ ███ ███ █ █ █ ███',
|
|
17
|
+
'█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █',
|
|
18
18
|
'████ ██ █ █ ███ ███ ████ ████ ██ █ ███ █ █ ████ ████ █ ███ ███',
|
|
19
19
|
];
|
|
20
20
|
console.log();
|
|
@@ -23,14 +23,19 @@ function printBanner() {
|
|
|
23
23
|
console.log(' ' + chalk_1.default.hex('#05b5fb')('Google Sheets-backed Staging Database Adapter'));
|
|
24
24
|
console.log();
|
|
25
25
|
}
|
|
26
|
-
async function initCommand() {
|
|
26
|
+
async function initCommand(options) {
|
|
27
27
|
printBanner();
|
|
28
|
+
if (options.integrate) {
|
|
29
|
+
console.log(chalk_1.default.blue('Integrating into an existing project...\n'));
|
|
30
|
+
}
|
|
31
|
+
const defaultProjectName = path_1.default.basename(process.cwd());
|
|
28
32
|
const answers = await inquirer_1.default.prompt([
|
|
29
33
|
{
|
|
30
34
|
type: 'input',
|
|
31
35
|
name: 'projectName',
|
|
32
36
|
message: 'Project name:',
|
|
33
|
-
default:
|
|
37
|
+
default: defaultProjectName,
|
|
38
|
+
when: !options.integrate,
|
|
34
39
|
},
|
|
35
40
|
{
|
|
36
41
|
type: 'input',
|
|
@@ -46,8 +51,9 @@ async function initCommand() {
|
|
|
46
51
|
filter: (input) => input.split(',').map((s) => s.trim()),
|
|
47
52
|
},
|
|
48
53
|
]);
|
|
54
|
+
const projectName = options.integrate ? defaultProjectName : answers.projectName;
|
|
49
55
|
const configContent = `export default {
|
|
50
|
-
projectName: "${
|
|
56
|
+
projectName: "${projectName}",
|
|
51
57
|
superAdminEmail: "${answers.superAdminEmail}",
|
|
52
58
|
actors: ${JSON.stringify(answers.actors, null, 2)}
|
|
53
59
|
};
|
|
@@ -65,8 +71,24 @@ ADMIN_SHEET_ID=
|
|
|
65
71
|
# Super admin email (new user sheets will be shared with this account)
|
|
66
72
|
SUPER_ADMIN_EMAIL=${answers.superAdminEmail}
|
|
67
73
|
`;
|
|
68
|
-
fs_1.default.
|
|
69
|
-
|
|
74
|
+
if (!fs_1.default.existsSync('sheet-db.config.ts') || !options.integrate) {
|
|
75
|
+
fs_1.default.writeFileSync('sheet-db.config.ts', configContent);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
console.log(chalk_1.default.yellow('ℹ sheet-db.config.ts already exists, skipping creation.'));
|
|
79
|
+
}
|
|
80
|
+
if (!fs_1.default.existsSync('.env') || !options.integrate) {
|
|
81
|
+
fs_1.default.writeFileSync('.env', envContent);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
console.log(chalk_1.default.yellow('ℹ .env already exists, please merge Google OAuth vars manually.'));
|
|
85
|
+
// Optionally append to .env
|
|
86
|
+
const currentEnv = fs_1.default.readFileSync('.env', 'utf-8');
|
|
87
|
+
if (!currentEnv.includes('GOOGLE_CLIENT_ID')) {
|
|
88
|
+
fs_1.default.appendFileSync('.env', '\n' + envContent);
|
|
89
|
+
console.log(chalk_1.default.green('✅ Appended Google Sheet DB variables to .env'));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
70
92
|
if (!fs_1.default.existsSync('schemas')) {
|
|
71
93
|
fs_1.default.mkdirSync('schemas');
|
|
72
94
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":";;;;;AAwBA,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":";;;;;AAwBA,kCAsIC;AA9JD,4CAAoB;AACpB,gDAAwB;AACxB,wDAAgC;AAChC,kDAA0B;AAE1B,SAAS,WAAW;IAClB,MAAM,CAAC,GAAG,eAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;IACpC,MAAM,KAAK,GAAG;QACZ,uFAAuF;QACvF,uFAAuF;QACvF,sFAAsF;QACtF,uFAAuF;QACvF,sFAAsF;KAGvF,CAAC;IAEF,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,eAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,+CAA+C,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC;AAEM,KAAK,UAAU,WAAW,CAAC,OAAgC;IAChE,WAAW,EAAE,CAAC;IAEd,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,kBAAkB,GAAG,cAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAExD,MAAM,OAAO,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC;QACpC;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,eAAe;YACxB,OAAO,EAAE,kBAAkB;YAC3B,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS;SACzB;QACD;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,oBAAoB;YAC7B,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,4BAA4B;SACzE;QACD;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,2BAA2B;YACpC,OAAO,EAAE,YAAY;YACrB,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACjE;KACF,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;IAEjF,MAAM,aAAa,GAAG;kBACN,WAAW;sBACP,OAAO,CAAC,eAAe;YACjC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;;CAElD,CAAC;IAEA,MAAM,UAAU,GAAG;;;;;;;;;;;oBAWD,OAAO,CAAC,eAAe;CAC1C,CAAC;IAEA,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QAC/D,YAAE,CAAC,aAAa,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAC;IACxD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,yDAAyD,CAAC,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACjD,YAAE,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,iEAAiE,CAAC,CAAC,CAAC;QAC7F,4BAA4B;QAC5B,MAAM,UAAU,GAAG,YAAE,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC7C,YAAE,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,GAAG,UAAU,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,YAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,YAAY,GAA2B;QAC3C,KAAK,EAAE;;;;;;;;;;;;;;CAcV;QACG,WAAW,EAAE;;;;;;;;;;;CAWhB;KACE,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC7C,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,YAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC3D,YAAE,CAAC,aAAa,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,eAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,eAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,eAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,eAAK,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,eAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,eAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,eAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,eAAK,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC;IACxF,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,eAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,eAAK,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-users.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/mock-users.ts"],"names":[],"mappings":"AASA,wBAAsB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,iBA4FhE;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.mockUsersCommand = mockUsersCommand;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const sheetAdapter_1 = require("../../adapter/sheetAdapter");
|
|
11
|
+
function makeEmail(userId, role) {
|
|
12
|
+
return `${role}.${userId}@example.local`;
|
|
13
|
+
}
|
|
14
|
+
async function mockUsersCommand(countArg) {
|
|
15
|
+
const count = Number(countArg) || 3;
|
|
16
|
+
console.log(chalk_1.default.blue.bold(`
|
|
17
|
+
🧪 Creating ${count} mock users (development)...
|
|
18
|
+
`));
|
|
19
|
+
require('dotenv').config();
|
|
20
|
+
const requiredEnvVars = [
|
|
21
|
+
'GOOGLE_CLIENT_ID',
|
|
22
|
+
'GOOGLE_CLIENT_SECRET',
|
|
23
|
+
'GOOGLE_REDIRECT_URI',
|
|
24
|
+
'ADMIN_SHEET_ID',
|
|
25
|
+
'SUPER_ADMIN_EMAIL',
|
|
26
|
+
];
|
|
27
|
+
for (const envVar of requiredEnvVars) {
|
|
28
|
+
if (!process.env[envVar]) {
|
|
29
|
+
console.error(chalk_1.default.red(`❌ Missing environment variable: ${envVar}`));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const tokensPath = path_1.default.join(process.cwd(), '.sheet-db-tokens.json');
|
|
34
|
+
if (!fs_1.default.existsSync(tokensPath)) {
|
|
35
|
+
console.error(chalk_1.default.red('❌ No OAuth tokens found. Run: sheet-db sync'));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
let tokens;
|
|
39
|
+
try {
|
|
40
|
+
tokens = JSON.parse(fs_1.default.readFileSync(tokensPath, 'utf-8'));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
console.error(chalk_1.default.red('❌ Failed to read tokens file.'));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
// Load config and schemas
|
|
47
|
+
let config;
|
|
48
|
+
try {
|
|
49
|
+
config = require(path_1.default.join(process.cwd(), 'sheet-db.config.ts')).default;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
console.error(chalk_1.default.red('❌ sheet-db.config.ts not found. Run: sheet-db init'));
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const adapter = (0, sheetAdapter_1.createSheetAdapter)({
|
|
56
|
+
adminSheetId: process.env.ADMIN_SHEET_ID,
|
|
57
|
+
credentials: {
|
|
58
|
+
clientId: process.env.GOOGLE_CLIENT_ID,
|
|
59
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
60
|
+
redirectUri: process.env.GOOGLE_REDIRECT_URI,
|
|
61
|
+
},
|
|
62
|
+
tokens,
|
|
63
|
+
});
|
|
64
|
+
// Load and register all schemas
|
|
65
|
+
const schemasDir = path_1.default.join(process.cwd(), 'schemas');
|
|
66
|
+
for (const actor of config.actors) {
|
|
67
|
+
const actorDir = path_1.default.join(schemasDir, actor);
|
|
68
|
+
if (!fs_1.default.existsSync(actorDir))
|
|
69
|
+
continue;
|
|
70
|
+
const files = fs_1.default.readdirSync(actorDir).filter((f) => f.endsWith('.ts'));
|
|
71
|
+
for (const file of files) {
|
|
72
|
+
try {
|
|
73
|
+
const schema = require(path_1.default.join(actorDir, file)).default;
|
|
74
|
+
adapter.registerSchema(schema);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// ignore failures to require optional schemas
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
let created = 0;
|
|
82
|
+
for (let i = 0; i < count; i++) {
|
|
83
|
+
const userId = `mock-${Date.now().toString(36)}-${i}`;
|
|
84
|
+
// Rotate roles among configured actors (skip admin)
|
|
85
|
+
const actors = config.actors.filter((a) => a !== 'admin');
|
|
86
|
+
const role = actors[i % actors.length] || 'student';
|
|
87
|
+
const email = makeEmail(userId, role);
|
|
88
|
+
try {
|
|
89
|
+
const sheetId = await adapter.createUserSheet(userId, role, email);
|
|
90
|
+
console.log(chalk_1.default.green(` ✓ Created ${role} user ${userId} → sheet ${sheetId}`));
|
|
91
|
+
created++;
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
console.error(chalk_1.default.red(` ✖ Failed to create user ${userId}: ${err}`));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(chalk_1.default.bold(`Done. ${created}/${count} mock users created.`));
|
|
99
|
+
}
|
|
100
|
+
exports.default = mockUsersCommand;
|
|
101
|
+
//# sourceMappingURL=mock-users.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-users.js","sourceRoot":"","sources":["../../../src/cli/commands/mock-users.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function seedCommand(seedFile: string): Promise<void>;
|
|
1
|
+
export declare function seedCommand(seedFile: string, opts?: any): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=seed.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/seed.ts"],"names":[],"mappings":"AAKA,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/seed.ts"],"names":[],"mappings":"AAKA,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,iBAkK7D"}
|
|
@@ -8,7 +8,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
10
|
const sheetAdapter_1 = require("../../adapter/sheetAdapter");
|
|
11
|
-
async function seedCommand(seedFile) {
|
|
11
|
+
async function seedCommand(seedFile, opts) {
|
|
12
12
|
console.log(chalk_1.default.blue.bold('🌱 Seeding data into Google Sheets...\n'));
|
|
13
13
|
require('dotenv').config();
|
|
14
14
|
const requiredEnvVars = [
|
|
@@ -88,6 +88,47 @@ async function seedCommand(seedFile) {
|
|
|
88
88
|
const adapterWithContext = adapter.withContext({ userId: 'seed-cli', role: 'admin', actorSheetId: process.env.ADMIN_SHEET_ID });
|
|
89
89
|
let totalInserted = 0;
|
|
90
90
|
let totalFailed = 0;
|
|
91
|
+
if (opts && opts.allActors) {
|
|
92
|
+
console.log(chalk_1.default.cyan('\nSeeding to all actor sheets (--all-actors)...'));
|
|
93
|
+
// Read users from admin users table
|
|
94
|
+
let users = [];
|
|
95
|
+
try {
|
|
96
|
+
users = await adapterWithContext.table('users').findMany();
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
console.error(chalk_1.default.red('❌ Could not read admin users table. Make sure `users` schema is registered and admin sheet has been synced.'));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
if (!users || users.length === 0) {
|
|
103
|
+
console.warn(chalk_1.default.yellow('No users found in admin users table. Nothing to seed.'));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
let totalInsertedActors = 0;
|
|
107
|
+
let totalFailedActors = 0;
|
|
108
|
+
for (const user of users) {
|
|
109
|
+
if (!user.actor_sheet_id)
|
|
110
|
+
continue;
|
|
111
|
+
const targetAdapter = adapter.withContext({ userId: 'seed-cli', role: 'admin', actorSheetId: user.actor_sheet_id });
|
|
112
|
+
for (const [tableName, records] of Object.entries(seedData)) {
|
|
113
|
+
if (!Array.isArray(records))
|
|
114
|
+
continue;
|
|
115
|
+
for (const record of records) {
|
|
116
|
+
try {
|
|
117
|
+
await targetAdapter.table(tableName).create(record);
|
|
118
|
+
totalInsertedActors++;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
totalFailedActors++;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
console.log();
|
|
127
|
+
console.log(chalk_1.default.bold(`Seed complete (all-actors): ${totalInsertedActors} inserted, ${totalFailedActors} failed.`));
|
|
128
|
+
if (totalFailedActors > 0)
|
|
129
|
+
process.exit(1);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
91
132
|
for (const [tableName, records] of Object.entries(seedData)) {
|
|
92
133
|
if (!Array.isArray(records)) {
|
|
93
134
|
console.warn(chalk_1.default.yellow(` ⚠️ Skipping "${tableName}": expected an array of records`));
|