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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../../../src/cli/commands/seed.ts"],"names":[],"mappings":";;;;;AAKA,
|
|
1
|
+
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../../../src/cli/commands/seed.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"AAqEA,wBAAsB,WAAW,
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"AAqEA,wBAAsB,WAAW,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,iBA8IhE"}
|
|
@@ -60,7 +60,7 @@ async function resolveTokens(oauth) {
|
|
|
60
60
|
console.log(chalk_1.default.green(`✅ Tokens saved to ${TOKENS_FILE}\n`));
|
|
61
61
|
return tokens;
|
|
62
62
|
}
|
|
63
|
-
async function syncCommand() {
|
|
63
|
+
async function syncCommand(options) {
|
|
64
64
|
console.log(chalk_1.default.blue.bold('🔄 Syncing schemas to Google Sheets...\n'));
|
|
65
65
|
require('dotenv').config();
|
|
66
66
|
const requiredEnvVars = [
|
|
@@ -133,7 +133,11 @@ async function syncCommand() {
|
|
|
133
133
|
adapter.registerSchemas(schemas);
|
|
134
134
|
let synced = 0;
|
|
135
135
|
let failed = 0;
|
|
136
|
-
|
|
136
|
+
// Sync admin schemas first
|
|
137
|
+
const adminSchemas = schemas.filter(s => s.actor === 'admin');
|
|
138
|
+
const userSchemas = schemas.filter(s => s.actor !== 'admin');
|
|
139
|
+
console.log(chalk_1.default.bold('\nSyncing Admin Schemas...'));
|
|
140
|
+
for (const schema of adminSchemas) {
|
|
137
141
|
try {
|
|
138
142
|
await adapter.syncSchema(schema);
|
|
139
143
|
console.log(chalk_1.default.green(` ✓ ${schema.name} (${schema.actor})`));
|
|
@@ -144,6 +148,43 @@ async function syncCommand() {
|
|
|
144
148
|
failed++;
|
|
145
149
|
}
|
|
146
150
|
}
|
|
151
|
+
if (options.allUsers && userSchemas.length > 0) {
|
|
152
|
+
console.log(chalk_1.default.bold('\nSyncing User Schemas...'));
|
|
153
|
+
try {
|
|
154
|
+
// Fetch all users from admin sheet to get their actor_sheet_id
|
|
155
|
+
const usersTable = adapter.table('users');
|
|
156
|
+
const allUsers = await usersTable.findMany({});
|
|
157
|
+
for (const user of allUsers) {
|
|
158
|
+
if (!user.actor_sheet_id)
|
|
159
|
+
continue;
|
|
160
|
+
console.log(chalk_1.default.cyan(`\nUser: ${user.email} (${user.role})`));
|
|
161
|
+
const roleSchemas = userSchemas.filter(s => s.actor === user.role);
|
|
162
|
+
// inject context for this user to resolve correct sheet ID
|
|
163
|
+
const userAdapter = adapter.withContext({
|
|
164
|
+
userId: user.user_id,
|
|
165
|
+
role: user.role,
|
|
166
|
+
actorSheetId: user.actor_sheet_id
|
|
167
|
+
});
|
|
168
|
+
for (const schema of roleSchemas) {
|
|
169
|
+
try {
|
|
170
|
+
await userAdapter.syncSchema(schema);
|
|
171
|
+
console.log(chalk_1.default.green(` ✓ ${schema.name} (${schema.actor})`));
|
|
172
|
+
synced++;
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
console.error(chalk_1.default.red(` ✖ ${schema.name} — ${err}`));
|
|
176
|
+
failed++;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
console.log(chalk_1.default.yellow(`⚠️ Could not fetch users table for all-users sync. Is it initialized? ${err}`));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (userSchemas.length > 0) {
|
|
186
|
+
console.log(chalk_1.default.yellow('\nℹ Skipping user schemas sync. Use --all-users to sync to all user sheets.'));
|
|
187
|
+
}
|
|
147
188
|
console.log();
|
|
148
189
|
console.log(chalk_1.default.bold(`Sync complete: ${synced} synced, ${failed} failed.`));
|
|
149
190
|
if (failed > 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":";;;;;AAqEA,
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const generate_1 = require("./commands/generate");
|
|
|
7
7
|
const sync_1 = require("./commands/sync");
|
|
8
8
|
const validate_1 = require("./commands/validate");
|
|
9
9
|
const seed_1 = require("./commands/seed");
|
|
10
|
+
const mock_users_1 = require("./commands/mock-users");
|
|
10
11
|
const doctor_1 = require("./commands/doctor");
|
|
11
12
|
const status_1 = require("./commands/status");
|
|
12
13
|
const program = new commander_1.Command();
|
|
@@ -17,6 +18,7 @@ program
|
|
|
17
18
|
program
|
|
18
19
|
.command('init')
|
|
19
20
|
.description('Initialize a new longcelot-sheet-db project')
|
|
21
|
+
.option('--integrate', 'Integrate into an existing project without overwriting configs')
|
|
20
22
|
.action(init_1.initCommand);
|
|
21
23
|
program
|
|
22
24
|
.command('generate <table-name>')
|
|
@@ -25,6 +27,7 @@ program
|
|
|
25
27
|
program
|
|
26
28
|
.command('sync')
|
|
27
29
|
.description('Sync schemas to Google Sheets')
|
|
30
|
+
.option('--all-users', 'Sync schema changes to all registered user sheets')
|
|
28
31
|
.action(sync_1.syncCommand);
|
|
29
32
|
program
|
|
30
33
|
.command('validate')
|
|
@@ -33,7 +36,12 @@ program
|
|
|
33
36
|
program
|
|
34
37
|
.command('seed <seed-file>')
|
|
35
38
|
.description('Seed initial data into Google Sheets from a JS/TS file')
|
|
36
|
-
.
|
|
39
|
+
.option('--all-actors', 'Distribute seed data to all actor sheets (per users table)')
|
|
40
|
+
.action((seedFile, options) => (0, seed_1.seedCommand)(seedFile, options));
|
|
41
|
+
program
|
|
42
|
+
.command('mock-users [count]')
|
|
43
|
+
.description('Create mock user sheets for development/testing')
|
|
44
|
+
.action((count) => (0, mock_users_1.mockUsersCommand)(count));
|
|
37
45
|
program
|
|
38
46
|
.command('doctor')
|
|
39
47
|
.description('Run diagnostics: check env vars, config, OAuth tokens, and schemas')
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,0CAA8C;AAC9C,kDAAsD;AACtD,0CAA8C;AAC9C,kDAAsD;AACtD,0CAA8C;AAC9C,8CAAkD;AAClD,8CAAkD;AAElD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,kBAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,uBAAuB,CAAC;KAChC,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,0BAAe,CAAC,CAAC;AAE3B,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,kBAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,0BAAe,CAAC,CAAC;AAE3B,OAAO;KACJ,OAAO,CAAC,kBAAkB,CAAC;KAC3B,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CAAC,kBAAW,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,0CAA8C;AAC9C,kDAAsD;AACtD,0CAA8C;AAC9C,kDAAsD;AACtD,0CAA8C;AAC9C,sDAAyD;AACzD,8CAAkD;AAClD,8CAAkD;AAElD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,aAAa,EAAE,gEAAgE,CAAC;KACvF,MAAM,CAAC,kBAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,uBAAuB,CAAC;KAChC,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,0BAAe,CAAC,CAAC;AAE3B,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,aAAa,EAAE,mDAAmD,CAAC;KAC1E,MAAM,CAAC,kBAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,0BAAe,CAAC,CAAC;AAE3B,OAAO;KACJ,OAAO,CAAC,kBAAkB,CAAC;KAC3B,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CAAC,cAAc,EAAE,4DAA4D,CAAC;KACpF,MAAM,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,IAAA,kBAAW,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AAEjE,OAAO;KACJ,OAAO,CAAC,oBAAoB,CAAC;KAC7B,WAAW,CAAC,iDAAiD,CAAC;KAC9D,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAA,6BAAgB,EAAC,KAAK,CAAC,CAAC,CAAC;AAE9C,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,oEAAoE,CAAC;KACjF,MAAM,CAAC,sBAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,sBAAa,CAAC,CAAC;AAEzB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "longcelot-sheet-db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Google Sheets-backed staging database adapter for Node.js with schema-first design",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,14 +12,17 @@
|
|
|
12
12
|
"README.md",
|
|
13
13
|
"API.md",
|
|
14
14
|
"CHANGELOG.md",
|
|
15
|
-
"LICENSE"
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"skills",
|
|
17
|
+
"!skills/_artifacts"
|
|
16
18
|
],
|
|
17
19
|
"keywords": [
|
|
18
20
|
"google-sheets",
|
|
19
21
|
"database",
|
|
20
22
|
"staging",
|
|
21
23
|
"adapter",
|
|
22
|
-
"schema"
|
|
24
|
+
"schema",
|
|
25
|
+
"tanstack-intent"
|
|
23
26
|
],
|
|
24
27
|
"author": "Longcelot",
|
|
25
28
|
"license": "MIT",
|
|
@@ -44,6 +47,7 @@
|
|
|
44
47
|
"zod": "^4.3.6"
|
|
45
48
|
},
|
|
46
49
|
"devDependencies": {
|
|
50
|
+
"@tanstack/intent": "latest",
|
|
47
51
|
"@testing-library/dom": "^10.4.1",
|
|
48
52
|
"@types/bcryptjs": "^2.4.6",
|
|
49
53
|
"@types/inquirer": "^8.2.10",
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: auth
|
|
3
|
+
description: Handle authentication with longcelot-sheet-db. Use when implementing Google OAuth2 login flow, exchanging authorization codes for tokens, refreshing expired tokens, verifying Google ID tokens, hashing or comparing passwords with bcrypt, or validating password strength.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
package: longcelot-sheet-db
|
|
7
|
+
version: "0.1.5"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# longcelot-sheet-db — Authentication
|
|
11
|
+
|
|
12
|
+
The package provides two authentication utilities: **OAuthManager** for Google OAuth2 (required for Sheets API access) and **password utilities** for bcrypt-based password hashing.
|
|
13
|
+
|
|
14
|
+
## Google OAuth2 — OAuthManager
|
|
15
|
+
|
|
16
|
+
### Why OAuth is required
|
|
17
|
+
|
|
18
|
+
Google Sheets API requires OAuth2 for all read/write operations. This is a hard requirement — there is no way to bypass it. OAuth is used strictly for **backend-to-Google-Sheets** communication. Your app's own authentication (JWT, sessions, etc.) is separate and unaffected.
|
|
19
|
+
|
|
20
|
+
### Creating the OAuthManager
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { createOAuthManager } from 'longcelot-sheet-db';
|
|
24
|
+
|
|
25
|
+
const oauth = createOAuthManager({
|
|
26
|
+
clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
27
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
28
|
+
redirectUri: process.env.GOOGLE_REDIRECT_URI!,
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### OAuthConfig type
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
interface OAuthConfig {
|
|
36
|
+
clientId: string;
|
|
37
|
+
clientSecret: string;
|
|
38
|
+
redirectUri: string;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Complete OAuth2 Flow
|
|
43
|
+
|
|
44
|
+
**Step 1 — Generate authorization URL and redirect user:**
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const authUrl = oauth.getAuthUrl();
|
|
48
|
+
// Redirect user to authUrl in their browser
|
|
49
|
+
res.redirect(authUrl);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Step 2 — Handle the callback and exchange code for tokens:**
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// In your redirect URI handler (e.g., GET /auth/callback)
|
|
56
|
+
app.get('/auth/callback', async (req, res) => {
|
|
57
|
+
const { code } = req.query;
|
|
58
|
+
const tokens = await oauth.getTokens(code as string);
|
|
59
|
+
// tokens contains: access_token, refresh_token, id_token, expiry_date
|
|
60
|
+
|
|
61
|
+
// Verify the user's identity
|
|
62
|
+
const payload = await oauth.verifyToken(tokens.id_token!);
|
|
63
|
+
// payload.email, payload.name, payload.sub (Google user ID)
|
|
64
|
+
|
|
65
|
+
// Store tokens securely (e.g., encrypted in DB or session)
|
|
66
|
+
// Use tokens when creating the SheetAdapter
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Step 3 — Refresh expired tokens:**
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const refreshedTokens = await oauth.refreshTokens(storedRefreshToken);
|
|
74
|
+
// Use refreshedTokens.access_token for the next request
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### OAuthManager methods
|
|
78
|
+
|
|
79
|
+
| Method | Signature | Description |
|
|
80
|
+
|--|--|--|
|
|
81
|
+
| `getAuthUrl()` | `() => string` | Returns Google authorization URL |
|
|
82
|
+
| `getTokens(code)` | `(code: string) => Promise<Credentials>` | Exchanges auth code for tokens |
|
|
83
|
+
| `refreshTokens(refreshToken)` | `(token: string) => Promise<Credentials>` | Refreshes an expired access token |
|
|
84
|
+
| `verifyToken(idToken)` | `(token: string) => Promise<TokenPayload>` | Verifies and decodes a Google ID token |
|
|
85
|
+
|
|
86
|
+
### Passing Tokens to the Adapter
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { createSheetAdapter } from 'longcelot-sheet-db';
|
|
90
|
+
|
|
91
|
+
const adapter = createSheetAdapter({
|
|
92
|
+
adminSheetId: process.env.ADMIN_SHEET_ID!,
|
|
93
|
+
credentials: { clientId, clientSecret, redirectUri },
|
|
94
|
+
tokens: userTokens, // Credentials object from getTokens() or refreshTokens()
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Password Utilities
|
|
99
|
+
|
|
100
|
+
For apps that need username/password authentication alongside or instead of Google OAuth:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import {
|
|
104
|
+
hashPassword,
|
|
105
|
+
comparePassword,
|
|
106
|
+
validatePasswordStrength,
|
|
107
|
+
} from 'longcelot-sheet-db';
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### hashPassword()
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const hash = await hashPassword('SecurePass123!');
|
|
114
|
+
// Uses bcrypt with 10 salt rounds
|
|
115
|
+
// Store hash in your credentials table, never the plain text password
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### comparePassword()
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
const isValid = await comparePassword('SecurePass123!', storedHash);
|
|
122
|
+
// Returns true if the password matches
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### validatePasswordStrength()
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const { valid, errors } = validatePasswordStrength('weakpass');
|
|
129
|
+
// valid: false
|
|
130
|
+
// errors: ['Password must be at least 8 characters', 'Must contain uppercase letter', ...]
|
|
131
|
+
|
|
132
|
+
const { valid } = validatePasswordStrength('SecurePass123!');
|
|
133
|
+
// valid: true
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Common Mistakes
|
|
137
|
+
|
|
138
|
+
- **Not storing the `refresh_token`** — Google only returns `refresh_token` on the first authorization. Store it persistently; losing it requires the user to re-authorize.
|
|
139
|
+
- **Creating the adapter with expired `access_token`** — Access tokens expire after 1 hour. Always call `oauth.refreshTokens()` before constructing the adapter if the stored token is expired (`tokens.expiry_date < Date.now()`).
|
|
140
|
+
- **Using `verifyToken()` for access control** — `verifyToken()` confirms the token's cryptographic validity and returns the user's Google profile, but your app must still check whether the user exists in your `users` table.
|
|
141
|
+
- **Storing plaintext passwords** — Always use `hashPassword()` before persisting credentials. Never store the raw password.
|
|
142
|
+
- **Calling `hashPassword()` synchronously** — It is async (bcrypt); always `await` it.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cli
|
|
3
|
+
description: Use the longcelot-sheet-db CLI (sheet-db). Use when running sheet-db init, generate, sync, validate, seed, doctor, or status commands — or when scaffolding a new project, generating schema files interactively, syncing schemas to Google Sheets, diagnosing configuration issues, or checking project status.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
package: longcelot-sheet-db
|
|
7
|
+
version: "0.1.5"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# longcelot-sheet-db — CLI Reference (`sheet-db`)
|
|
11
|
+
|
|
12
|
+
All commands are available as `sheet-db <command>` (global install) or via:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx sheet-db <command>
|
|
16
|
+
pnpm dlx sheet-db <command>
|
|
17
|
+
yarn dlx sheet-db <command>
|
|
18
|
+
bunx sheet-db <command>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## init — Scaffold a new project
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx sheet-db init
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**What it creates:**
|
|
30
|
+
- `sheet-db.config.ts` — Project configuration (project name, actors list)
|
|
31
|
+
- `.env` — Environment variable template
|
|
32
|
+
- `schemas/` — Schemas directory with default admin schemas (`users`, `credentials`)
|
|
33
|
+
|
|
34
|
+
Run this **once** when first adding `longcelot-sheet-db` to a project.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## generate — Interactive schema generator
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx sheet-db generate bookings
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Launches an interactive prompt that asks:
|
|
45
|
+
- Column name
|
|
46
|
+
- Column type (`string` | `number` | `boolean` | `date` | `json`)
|
|
47
|
+
- Modifiers (`required`, `unique`, `default`, etc.)
|
|
48
|
+
|
|
49
|
+
Writes a new schema file to the `schemas/` directory. Use instead of hand-authoring schema files when you're not sure of the syntax.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## sync — Sync schemas to Google Sheets
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx sheet-db sync
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**What it does:**
|
|
60
|
+
1. Loads all schemas from `schemas/`
|
|
61
|
+
2. Validates environment variables (`GOOGLE_CLIENT_ID`, etc.)
|
|
62
|
+
3. Handles OAuth: reads stored tokens from `.sheet-db-tokens.json`, prompts for browser authorization if no token is found, and stores tokens for future use
|
|
63
|
+
4. Calls `adapter.syncSchema()` for every schema
|
|
64
|
+
5. Creates missing sheet tabs and adds missing column headers — **never deletes data**
|
|
65
|
+
|
|
66
|
+
Run after:
|
|
67
|
+
- Adding new schemas
|
|
68
|
+
- Adding new columns to existing schemas
|
|
69
|
+
- Setting up a new environment
|
|
70
|
+
|
|
71
|
+
> `.sheet-db-tokens.json` is written to the project root and should be in `.gitignore`.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## validate — Validate all schemas
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx sheet-db validate
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Checks all schema files in `schemas/` for:
|
|
82
|
+
- Duplicate table names (within same actor)
|
|
83
|
+
- Invalid column modifiers
|
|
84
|
+
- Unknown actor references (actor not listed in `sheet-db.config.ts`)
|
|
85
|
+
- Missing required schema fields (`name`, `actor`, `columns`)
|
|
86
|
+
|
|
87
|
+
Use this in CI to catch schema problems before they reach Google Sheets.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## seed — Load initial/test data
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx sheet-db seed
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Loads initial or test data into your sheets. Reads seed definitions from your project. Useful for populating development and staging environments with realistic data.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## doctor — Diagnostics and health checks
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx sheet-db doctor
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Runs a series of environment and configuration checks:
|
|
108
|
+
- Verifies all required environment variables are set
|
|
109
|
+
- Checks Google OAuth credentials are valid
|
|
110
|
+
- Validates `sheet-db.config.ts` structure
|
|
111
|
+
- Reports any issues with color-coded output
|
|
112
|
+
|
|
113
|
+
Run `doctor` first when debugging mysterious adapter errors.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## status — Show project status
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx sheet-db status
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Displays:
|
|
124
|
+
- All registered tables and their actors
|
|
125
|
+
- Associated Google Sheet IDs
|
|
126
|
+
- Schema counts per actor
|
|
127
|
+
- Current configuration summary
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## sheet-db.config.ts structure
|
|
132
|
+
|
|
133
|
+
The init command generates this file. Customize actors and project name here:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
export default {
|
|
137
|
+
projectName: 'my-app',
|
|
138
|
+
actors: ['admin', 'user', 'seller'], // all roles that own data
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Common Mistakes
|
|
145
|
+
|
|
146
|
+
- **Running `sync` without `.env` configured** — `sync` will fail at the OAuth step if environment variables are missing. Run `doctor` first to verify environment setup.
|
|
147
|
+
- **Committing `.sheet-db-tokens.json`** — This file contains OAuth tokens. It is added to `.gitignore` by `init` but verify it is excluded before pushing to a public repo.
|
|
148
|
+
- **Running `generate` with a name that conflicts** — If a schema with the same `name` and `actor` already exists, you'll get a duplicate error on next `validate`. Use unique table names per actor.
|
|
149
|
+
- **Not running `sync` after schema changes** — Schema files are the source of truth. After adding columns or tables, you must run `sync` to create the corresponding headers in Google Sheets; otherwise `create()` will fail silently or store data in wrong columns.
|
|
150
|
+
- **`init` on an existing project** — Running `init` again will not overwrite existing files, but always review generated defaults and merge manually if needed.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: core
|
|
3
|
+
description: Set up and configure longcelot-sheet-db. Use when installing the package, creating a SheetAdapter, providing OAuth credentials, wiring environment variables, or connecting the adapter to an existing backend (Express, NestJS, etc.).
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
package: longcelot-sheet-db
|
|
7
|
+
version: "0.1.5"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# longcelot-sheet-db — Core Setup
|
|
11
|
+
|
|
12
|
+
`longcelot-sheet-db` is a schema-first, actor-aware database adapter that uses **Google Sheets as the storage engine**. It is designed for MVPs, prototypes, staging environments, and internal tools where zero infrastructure cost is a priority.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install longcelot-sheet-db
|
|
18
|
+
# or
|
|
19
|
+
pnpm add longcelot-sheet-db
|
|
20
|
+
# or
|
|
21
|
+
yarn add longcelot-sheet-db
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Required Environment Variables
|
|
25
|
+
|
|
26
|
+
All five variables must be set before the adapter can function:
|
|
27
|
+
|
|
28
|
+
```env
|
|
29
|
+
GOOGLE_CLIENT_ID=your_client_id
|
|
30
|
+
GOOGLE_CLIENT_SECRET=your_client_secret
|
|
31
|
+
GOOGLE_REDIRECT_URI=http://localhost:3000/auth/callback
|
|
32
|
+
ADMIN_SHEET_ID=your_central_admin_google_sheet_id
|
|
33
|
+
SUPER_ADMIN_EMAIL=admin@example.com
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> **GOOGLE_REDIRECT_URI** must exactly match a URI registered in the Google Cloud Console OAuth 2.0 credentials.
|
|
37
|
+
|
|
38
|
+
## Creating the Adapter
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { createSheetAdapter } from 'longcelot-sheet-db';
|
|
42
|
+
|
|
43
|
+
const adapter = createSheetAdapter({
|
|
44
|
+
adminSheetId: process.env.ADMIN_SHEET_ID!,
|
|
45
|
+
credentials: {
|
|
46
|
+
clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
47
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
48
|
+
redirectUri: process.env.GOOGLE_REDIRECT_URI!,
|
|
49
|
+
},
|
|
50
|
+
tokens: userOAuthTokens, // obtained from OAuthManager.getTokens()
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### SheetAdapterConfig type
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
interface SheetAdapterConfig {
|
|
58
|
+
adminSheetId: string;
|
|
59
|
+
credentials: {
|
|
60
|
+
clientId: string;
|
|
61
|
+
clientSecret: string;
|
|
62
|
+
redirectUri: string;
|
|
63
|
+
};
|
|
64
|
+
tokens: any; // Google OAuth2 token object
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Registering Schemas
|
|
69
|
+
|
|
70
|
+
Schemas **must** be registered before calling `adapter.table()`:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import bookingsSchema from './schemas/bookings';
|
|
74
|
+
import usersSchema from './schemas/users';
|
|
75
|
+
|
|
76
|
+
adapter.registerSchema(bookingsSchema);
|
|
77
|
+
// or register many at once:
|
|
78
|
+
adapter.registerSchemas([bookingsSchema, usersSchema]);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Integrating with an Existing Backend
|
|
82
|
+
|
|
83
|
+
OAuth in this package is strictly for **backend-to-Google-Sheets** communication. Your app's own authentication (JWT, sessions, etc.) is untouched.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Express example
|
|
87
|
+
app.get('/bookings', async (req, res) => {
|
|
88
|
+
const user = req.user; // from your JWT middleware
|
|
89
|
+
|
|
90
|
+
const ctx = adapter.withContext({
|
|
91
|
+
userId: user.id,
|
|
92
|
+
role: user.role, // must match an actor defined in your config
|
|
93
|
+
actorSheetId: user.sheetId, // Google Sheet ID for this user
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const bookings = await ctx.table('bookings').findMany();
|
|
97
|
+
res.json(bookings);
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Creating a User Sheet on Registration
|
|
102
|
+
|
|
103
|
+
When a new user registers, create their personal sheet:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const sheetId = await adapter.createUserSheet(userId, role);
|
|
107
|
+
// Store sheetId in your users table for future withContext() calls
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Common Mistakes
|
|
111
|
+
|
|
112
|
+
- **Missing `registerSchema()` call** — Calling `adapter.table('x')` before `registerSchema()` throws `SchemaError: Schema 'x' not registered`.
|
|
113
|
+
- **Wrong `actorSheetId`** — The `actorSheetId` in `withContext()` must match the Google Sheet that belongs to that user's role; using the admin sheet ID for a non-admin actor causes a permission error.
|
|
114
|
+
- **Stale/expired OAuth tokens** — Pass refreshed tokens each request or use `OAuthManager.refreshTokens()` to renew before constructing the adapter.
|
|
115
|
+
- **ESM/CJS mismatch** — The package ships CommonJS. Do **not** upgrade `chalk`, `inquirer`, or `nanoid` to ESM-only versions (chalk v5+, inquirer v9+, nanoid v4+) without migrating the project to ESM.
|