@nuberea/sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/dist/auth.d.ts +61 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +245 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli/index.d.ts +22 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +417 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/client.d.ts +159 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +306 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +125 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +255 -0
- package/dist/mcp.js.map +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NuBerea
|
|
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,146 @@
|
|
|
1
|
+
# @nuberea/sdk
|
|
2
|
+
|
|
3
|
+
Client library and CLI for the [NuBerea](https://nuberea.com) biblical data platform.
|
|
4
|
+
|
|
5
|
+
Query morphological corpora, lexicons, Bible texts, manuscripts, and scrolls — via MCP tools or SQL analytics.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @nuberea/sdk
|
|
11
|
+
|
|
12
|
+
# Or globally for the CLI
|
|
13
|
+
npm install -g @nuberea/sdk
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### As a library
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { NuBerea } from '@nuberea/sdk';
|
|
22
|
+
|
|
23
|
+
const client = new NuBerea();
|
|
24
|
+
await client.login(); // Opens browser for sign-in
|
|
25
|
+
|
|
26
|
+
// Get a verse
|
|
27
|
+
const verse = await client.verse('John', 1, 1);
|
|
28
|
+
console.log(verse);
|
|
29
|
+
|
|
30
|
+
// Call any MCP tool
|
|
31
|
+
const result = await client.tool('macula_greek_query_verse', {
|
|
32
|
+
book: 'John', chapter: 1, verse: 1,
|
|
33
|
+
});
|
|
34
|
+
console.log(result.content[0].text);
|
|
35
|
+
|
|
36
|
+
// Run SQL analytics (cross-database joins)
|
|
37
|
+
const rows = await client.query(`
|
|
38
|
+
SELECT h.text, h.lemma, h.strong, b.short_def
|
|
39
|
+
FROM hebrew.morphemes h
|
|
40
|
+
LEFT JOIN bdb.entries b ON h.strong = b.strong
|
|
41
|
+
WHERE h.book_id = 'Gen' AND h.chapter = 1 AND h.verse = 1
|
|
42
|
+
ORDER BY h.word_position
|
|
43
|
+
`);
|
|
44
|
+
console.log(rows.rows);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### As a CLI
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Authenticate
|
|
51
|
+
nuberea login
|
|
52
|
+
|
|
53
|
+
# Get a verse
|
|
54
|
+
nuberea verse John 1:1
|
|
55
|
+
|
|
56
|
+
# Search KJV text
|
|
57
|
+
nuberea search "In the beginning"
|
|
58
|
+
|
|
59
|
+
# Look up Greek word
|
|
60
|
+
nuberea greek λόγος
|
|
61
|
+
|
|
62
|
+
# Look up Hebrew Strong's number
|
|
63
|
+
nuberea hebrew H430
|
|
64
|
+
|
|
65
|
+
# List available tools
|
|
66
|
+
nuberea tools
|
|
67
|
+
|
|
68
|
+
# Call any tool
|
|
69
|
+
nuberea tool bible_kjv_get_verse '{"book":"John","chapter":1,"verse":1}'
|
|
70
|
+
|
|
71
|
+
# Run SQL query
|
|
72
|
+
nuberea query "SELECT * FROM hebrew.morphemes WHERE book_id = 'Gen' AND chapter = 1 LIMIT 5"
|
|
73
|
+
|
|
74
|
+
# Explore databases
|
|
75
|
+
nuberea databases
|
|
76
|
+
nuberea describe hebrew morphemes
|
|
77
|
+
nuberea introspect lsj
|
|
78
|
+
|
|
79
|
+
# Raw JSON output
|
|
80
|
+
nuberea tool bible_kjv_search_text '{"query":"love","limit":3}' --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Available Databases
|
|
84
|
+
|
|
85
|
+
| Schema | Table | Description | Rows |
|
|
86
|
+
|---|---|---|---|
|
|
87
|
+
| `hebrew` | `morphemes` | Hebrew Bible morphological analysis | 467,770 |
|
|
88
|
+
| `greek` | `morphemes` | Greek NT morphological analysis | 137,741 |
|
|
89
|
+
| `lxx` | `morphemes` | Septuagint morphological analysis | 623,693 |
|
|
90
|
+
| `lsj` | `entries` | Liddell-Scott-Jones Greek Lexicon | 119,553 |
|
|
91
|
+
| `bdb` | `entries` | Brown-Driver-Briggs Hebrew Lexicon | 10,221 |
|
|
92
|
+
| `abbott_smith` | `entries` | Abbott-Smith NT Greek Lexicon | 555 |
|
|
93
|
+
| `kjv` | `verses` | King James Version Bible text | 36,821 |
|
|
94
|
+
| `cntr` | `transcriptions` | Greek NT manuscript transcriptions | 41,956 |
|
|
95
|
+
| `dss` | `scrolls` | Dead Sea Scrolls annotations | 500,991 |
|
|
96
|
+
| `aland` | `pericopes` | Synoptic parallel pericopes | 330 |
|
|
97
|
+
|
|
98
|
+
## Available MCP Tools
|
|
99
|
+
|
|
100
|
+
55+ tools organized by collection:
|
|
101
|
+
|
|
102
|
+
- **`bible_kjv_*`** — KJV Bible text (get_verse, get_chapter, search_text, ...)
|
|
103
|
+
- **`macula_hebrew_*`** — Hebrew morphology (query_verse, search_lemma, search_strong, ...)
|
|
104
|
+
- **`macula_greek_*`** — Greek NT morphology
|
|
105
|
+
- **`macula_lxx_*`** — Septuagint morphology
|
|
106
|
+
- **`lexicon_lsj_*`** — LSJ Greek lexicon (lookup, search, search_latin, ...)
|
|
107
|
+
- **`lexicon_bdb_*`** — BDB Hebrew lexicon
|
|
108
|
+
- **`lexicon_abbott_smith_*`** — Abbott-Smith lexicon
|
|
109
|
+
- **`scroll_dss_*`** — Dead Sea Scrolls
|
|
110
|
+
- **`transcription_cntr_*`** — CNTR manuscripts
|
|
111
|
+
- **`synoptic_*`** — Synoptic parallels
|
|
112
|
+
- **`analytics_*`** — SQL queries, schema introspection
|
|
113
|
+
|
|
114
|
+
Run `nuberea tools` to see the full list.
|
|
115
|
+
|
|
116
|
+
## Configuration
|
|
117
|
+
|
|
118
|
+
### Environment Variables
|
|
119
|
+
|
|
120
|
+
| Variable | Description |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `NUBEREA_BASE_URL` | API base URL (default: `https://auth.aws-dev.streamsappsgslbex.com`) |
|
|
123
|
+
| `NUBEREA_ACCESS_TOKEN` | Pre-set access token (skip login) |
|
|
124
|
+
| `NUBEREA_FIREBASE_TOKEN` | Pre-set Firebase token (skip browser sign-in) |
|
|
125
|
+
|
|
126
|
+
### Programmatic
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const client = new NuBerea({
|
|
130
|
+
baseUrl: 'https://auth.aws-dev.streamsappsgslbex.com',
|
|
131
|
+
accessToken: 'your-token', // Skip login
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Authentication
|
|
136
|
+
|
|
137
|
+
NuBerea uses OAuth 2.1 with PKCE.
|
|
138
|
+
|
|
139
|
+
1. `nuberea login` opens your browser to `nuberea.com/login`
|
|
140
|
+
2. Sign in to your nuberea account
|
|
141
|
+
3. Tokens are stored at `~/.nuberea/tokens.json` (mode 0600)
|
|
142
|
+
4. Tokens auto-refresh — you rarely need to re-login
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NuBerea Auth — OAuth 2.1 + PKCE authentication flow.
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* 1. Firebase sign-in (browser-based or token-based)
|
|
6
|
+
* 2. OAuth 2.1 authorization code + PKCE exchange
|
|
7
|
+
* 3. Token persistence and refresh
|
|
8
|
+
*/
|
|
9
|
+
export interface AuthConfig {
|
|
10
|
+
/** OAuth server base URL */
|
|
11
|
+
oauthBaseUrl: string;
|
|
12
|
+
/** MCP endpoint URL (used as `resource` in OAuth) */
|
|
13
|
+
mcpUrl: string;
|
|
14
|
+
/** OAuth client_id */
|
|
15
|
+
clientId: string;
|
|
16
|
+
/** Local port for OAuth redirect callback */
|
|
17
|
+
callbackPort: number;
|
|
18
|
+
/** Local port for Firebase sign-in callback */
|
|
19
|
+
firebaseAuthPort: number;
|
|
20
|
+
/** Path to store tokens on disk */
|
|
21
|
+
tokenFile: string;
|
|
22
|
+
/** Login page URL for browser-based sign-in */
|
|
23
|
+
loginUrl: string;
|
|
24
|
+
}
|
|
25
|
+
export interface StoredTokens {
|
|
26
|
+
accessToken: string;
|
|
27
|
+
refreshToken: string;
|
|
28
|
+
expiresAt: number;
|
|
29
|
+
firebaseToken?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare class NuBereaAuth {
|
|
32
|
+
private config;
|
|
33
|
+
private tokens;
|
|
34
|
+
constructor(config?: Partial<AuthConfig>);
|
|
35
|
+
/**
|
|
36
|
+
* Get a valid access token, refreshing or re-authenticating as needed.
|
|
37
|
+
*/
|
|
38
|
+
getAccessToken(): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Run the full interactive login flow (opens browser).
|
|
41
|
+
*/
|
|
42
|
+
login(firebaseToken?: string): Promise<StoredTokens>;
|
|
43
|
+
/**
|
|
44
|
+
* Refresh the access token using the stored refresh token.
|
|
45
|
+
*/
|
|
46
|
+
refresh(): Promise<StoredTokens>;
|
|
47
|
+
/**
|
|
48
|
+
* Clear stored tokens (logout).
|
|
49
|
+
*/
|
|
50
|
+
logout(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Check if we have a valid (non-expired) token.
|
|
53
|
+
*/
|
|
54
|
+
isAuthenticated(): boolean;
|
|
55
|
+
private fetchFirebaseToken;
|
|
56
|
+
private fetchAuthCode;
|
|
57
|
+
private exchangeCode;
|
|
58
|
+
private loadTokens;
|
|
59
|
+
private saveTokens;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,gBAAgB,EAAE,MAAM,CAAC;IACzB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAYD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC;IAQxC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IA0BvC;;OAEG;IACG,KAAK,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAiB1D;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;IAiCtC;;OAEG;IACH,MAAM,IAAI,IAAI;IASd;;OAEG;IACH,eAAe,IAAI,OAAO;IAS1B,OAAO,CAAC,kBAAkB;IA+B1B,OAAO,CAAC,aAAa;YAuCP,YAAY;IA4B1B,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,UAAU;CAKnB"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NuBerea Auth — OAuth 2.1 + PKCE authentication flow.
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* 1. Firebase sign-in (browser-based or token-based)
|
|
6
|
+
* 2. OAuth 2.1 authorization code + PKCE exchange
|
|
7
|
+
* 3. Token persistence and refresh
|
|
8
|
+
*/
|
|
9
|
+
import { exec } from 'node:child_process';
|
|
10
|
+
import crypto from 'node:crypto';
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import http from 'node:http';
|
|
13
|
+
import os from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
const DEFAULT_CONFIG = {
|
|
16
|
+
oauthBaseUrl: 'https://auth.aws-dev.streamsappsgslbex.com',
|
|
17
|
+
mcpUrl: 'https://auth.aws-dev.streamsappsgslbex.com/mcp',
|
|
18
|
+
clientId: 'mcp-client-test',
|
|
19
|
+
callbackPort: 9876,
|
|
20
|
+
firebaseAuthPort: 9875,
|
|
21
|
+
tokenFile: path.join(os.homedir(), '.nuberea', 'tokens.json'),
|
|
22
|
+
loginUrl: 'https://nuberea.com/login',
|
|
23
|
+
};
|
|
24
|
+
export class NuBereaAuth {
|
|
25
|
+
config;
|
|
26
|
+
tokens = null;
|
|
27
|
+
constructor(config) {
|
|
28
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
29
|
+
}
|
|
30
|
+
// ==========================================================================
|
|
31
|
+
// Public API
|
|
32
|
+
// ==========================================================================
|
|
33
|
+
/**
|
|
34
|
+
* Get a valid access token, refreshing or re-authenticating as needed.
|
|
35
|
+
*/
|
|
36
|
+
async getAccessToken() {
|
|
37
|
+
// Try loading from disk
|
|
38
|
+
if (!this.tokens) {
|
|
39
|
+
this.tokens = this.loadTokens();
|
|
40
|
+
}
|
|
41
|
+
// Still valid?
|
|
42
|
+
if (this.tokens && this.tokens.expiresAt > Date.now() + 60_000) {
|
|
43
|
+
return this.tokens.accessToken;
|
|
44
|
+
}
|
|
45
|
+
// Try refresh
|
|
46
|
+
if (this.tokens?.refreshToken) {
|
|
47
|
+
try {
|
|
48
|
+
await this.refresh();
|
|
49
|
+
return this.tokens.accessToken;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Refresh failed — fall through to full login
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Full login flow
|
|
56
|
+
await this.login();
|
|
57
|
+
return this.tokens.accessToken;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run the full interactive login flow (opens browser).
|
|
61
|
+
*/
|
|
62
|
+
async login(firebaseToken) {
|
|
63
|
+
const fbToken = firebaseToken ?? await this.fetchFirebaseToken();
|
|
64
|
+
const { verifier, challenge } = generatePkce();
|
|
65
|
+
const code = await this.fetchAuthCode(fbToken, challenge);
|
|
66
|
+
const tokenResponse = await this.exchangeCode(code, verifier);
|
|
67
|
+
this.tokens = {
|
|
68
|
+
accessToken: tokenResponse.access_token,
|
|
69
|
+
refreshToken: tokenResponse.refresh_token,
|
|
70
|
+
expiresAt: Date.now() + tokenResponse.expires_in * 1000,
|
|
71
|
+
firebaseToken: fbToken,
|
|
72
|
+
};
|
|
73
|
+
this.saveTokens(this.tokens);
|
|
74
|
+
return this.tokens;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Refresh the access token using the stored refresh token.
|
|
78
|
+
*/
|
|
79
|
+
async refresh() {
|
|
80
|
+
if (!this.tokens?.refreshToken) {
|
|
81
|
+
throw new Error('No refresh token available. Run login() first.');
|
|
82
|
+
}
|
|
83
|
+
const res = await fetch(`${this.config.oauthBaseUrl}/token`, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
86
|
+
body: new URLSearchParams({
|
|
87
|
+
grant_type: 'refresh_token',
|
|
88
|
+
refresh_token: this.tokens.refreshToken,
|
|
89
|
+
client_id: this.config.clientId,
|
|
90
|
+
resource: this.config.mcpUrl,
|
|
91
|
+
}).toString(),
|
|
92
|
+
});
|
|
93
|
+
if (!res.ok) {
|
|
94
|
+
const body = await res.text();
|
|
95
|
+
throw new Error(`Token refresh failed: HTTP ${res.status} — ${body}`);
|
|
96
|
+
}
|
|
97
|
+
const data = await res.json();
|
|
98
|
+
this.tokens = {
|
|
99
|
+
accessToken: data.access_token,
|
|
100
|
+
refreshToken: data.refresh_token ?? this.tokens.refreshToken,
|
|
101
|
+
expiresAt: Date.now() + data.expires_in * 1000,
|
|
102
|
+
firebaseToken: this.tokens.firebaseToken,
|
|
103
|
+
};
|
|
104
|
+
this.saveTokens(this.tokens);
|
|
105
|
+
return this.tokens;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Clear stored tokens (logout).
|
|
109
|
+
*/
|
|
110
|
+
logout() {
|
|
111
|
+
this.tokens = null;
|
|
112
|
+
try {
|
|
113
|
+
fs.unlinkSync(this.config.tokenFile);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// File may not exist
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if we have a valid (non-expired) token.
|
|
121
|
+
*/
|
|
122
|
+
isAuthenticated() {
|
|
123
|
+
if (!this.tokens)
|
|
124
|
+
this.tokens = this.loadTokens();
|
|
125
|
+
return !!this.tokens && this.tokens.expiresAt > Date.now() + 60_000;
|
|
126
|
+
}
|
|
127
|
+
// ==========================================================================
|
|
128
|
+
// Firebase sign-in
|
|
129
|
+
// ==========================================================================
|
|
130
|
+
fetchFirebaseToken() {
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
const callbackUrl = `http://localhost:${this.config.firebaseAuthPort}/callback`;
|
|
133
|
+
const loginUrl = `${this.config.loginUrl}?return_to=${encodeURIComponent(callbackUrl)}`;
|
|
134
|
+
const server = http.createServer((req, res) => {
|
|
135
|
+
const url = new URL(req.url, `http://localhost:${this.config.firebaseAuthPort}`);
|
|
136
|
+
const token = url.searchParams.get('firebase_token');
|
|
137
|
+
const error = url.searchParams.get('error');
|
|
138
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
139
|
+
res.end('<html><body><h2>✅ Signed in — you can close this tab.</h2></body></html>');
|
|
140
|
+
server.close();
|
|
141
|
+
if (error)
|
|
142
|
+
return reject(new Error(`Firebase auth error: ${error}`));
|
|
143
|
+
if (!token)
|
|
144
|
+
return reject(new Error('firebase_token missing from callback'));
|
|
145
|
+
resolve(token);
|
|
146
|
+
});
|
|
147
|
+
server.listen(this.config.firebaseAuthPort, () => {
|
|
148
|
+
openBrowser(loginUrl);
|
|
149
|
+
});
|
|
150
|
+
server.on('error', reject);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// ==========================================================================
|
|
154
|
+
// OAuth 2.1 + PKCE
|
|
155
|
+
// ==========================================================================
|
|
156
|
+
fetchAuthCode(firebaseJwt, challenge) {
|
|
157
|
+
return new Promise((resolve, reject) => {
|
|
158
|
+
const redirectUri = `http://localhost:${this.config.callbackPort}/callback`;
|
|
159
|
+
const params = new URLSearchParams({
|
|
160
|
+
response_type: 'code',
|
|
161
|
+
client_id: this.config.clientId,
|
|
162
|
+
redirect_uri: redirectUri,
|
|
163
|
+
code_challenge: challenge,
|
|
164
|
+
code_challenge_method: 'S256',
|
|
165
|
+
state: crypto.randomBytes(8).toString('hex'),
|
|
166
|
+
scope: 'mcp',
|
|
167
|
+
resource: this.config.mcpUrl,
|
|
168
|
+
});
|
|
169
|
+
const authorizeUrl = `${this.config.oauthBaseUrl}/authorize?${params}`;
|
|
170
|
+
// Call authorize directly with Firebase token
|
|
171
|
+
fetch(authorizeUrl, {
|
|
172
|
+
method: 'GET',
|
|
173
|
+
redirect: 'manual',
|
|
174
|
+
headers: { Authorization: `Bearer ${firebaseJwt}` },
|
|
175
|
+
})
|
|
176
|
+
.then((res) => {
|
|
177
|
+
const location = res.headers.get('location');
|
|
178
|
+
if (!location)
|
|
179
|
+
throw new Error(`Expected redirect from /authorize, got HTTP ${res.status}`);
|
|
180
|
+
const url = new URL(location.startsWith('http') ? location : `${redirectUri}${location}`);
|
|
181
|
+
const code = url.searchParams.get('code');
|
|
182
|
+
const error = url.searchParams.get('error');
|
|
183
|
+
if (error)
|
|
184
|
+
throw new Error(`OAuth error: ${error}`);
|
|
185
|
+
if (!code)
|
|
186
|
+
throw new Error(`No code in redirect: ${location}`);
|
|
187
|
+
resolve(code);
|
|
188
|
+
})
|
|
189
|
+
.catch(reject);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
async exchangeCode(code, verifier) {
|
|
193
|
+
const redirectUri = `http://localhost:${this.config.callbackPort}/callback`;
|
|
194
|
+
const res = await fetch(`${this.config.oauthBaseUrl}/token`, {
|
|
195
|
+
method: 'POST',
|
|
196
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
197
|
+
body: new URLSearchParams({
|
|
198
|
+
grant_type: 'authorization_code',
|
|
199
|
+
code,
|
|
200
|
+
redirect_uri: redirectUri,
|
|
201
|
+
client_id: this.config.clientId,
|
|
202
|
+
code_verifier: verifier,
|
|
203
|
+
resource: this.config.mcpUrl,
|
|
204
|
+
}).toString(),
|
|
205
|
+
});
|
|
206
|
+
if (!res.ok) {
|
|
207
|
+
const body = await res.text();
|
|
208
|
+
throw new Error(`Token exchange failed: HTTP ${res.status} — ${body}`);
|
|
209
|
+
}
|
|
210
|
+
return res.json();
|
|
211
|
+
}
|
|
212
|
+
// ==========================================================================
|
|
213
|
+
// Token persistence
|
|
214
|
+
// ==========================================================================
|
|
215
|
+
loadTokens() {
|
|
216
|
+
try {
|
|
217
|
+
const raw = fs.readFileSync(this.config.tokenFile, 'utf-8');
|
|
218
|
+
return JSON.parse(raw);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
saveTokens(tokens) {
|
|
225
|
+
const dir = path.dirname(this.config.tokenFile);
|
|
226
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
227
|
+
fs.writeFileSync(this.config.tokenFile, JSON.stringify(tokens, null, 2), { mode: 0o600 });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function generatePkce() {
|
|
231
|
+
const verifier = crypto.randomBytes(32).toString('base64url');
|
|
232
|
+
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
|
|
233
|
+
return { verifier, challenge };
|
|
234
|
+
}
|
|
235
|
+
function openBrowser(url) {
|
|
236
|
+
const cmd = process.platform === 'darwin'
|
|
237
|
+
? `open "${url}"`
|
|
238
|
+
: process.platform === 'win32'
|
|
239
|
+
? `start "" "${url}"`
|
|
240
|
+
: `xdg-open "${url}"`;
|
|
241
|
+
exec(cmd, () => {
|
|
242
|
+
// Ignore errors — user can open manually
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* NuBerea CLI
|
|
4
|
+
*
|
|
5
|
+
* Command-line interface for the NuBerea biblical data platform.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* nuberea login — Authenticate (opens browser)
|
|
9
|
+
* nuberea logout — Clear stored credentials
|
|
10
|
+
* nuberea tools — List available MCP tools
|
|
11
|
+
* nuberea tool <name> [json] — Call an MCP tool
|
|
12
|
+
* nuberea query <sql> — Run a SQL analytics query
|
|
13
|
+
* nuberea databases — List available databases
|
|
14
|
+
* nuberea describe <db> <tbl>— Describe a table
|
|
15
|
+
* nuberea introspect <schema>— Deep schema introspection
|
|
16
|
+
* nuberea verse <ref> — Get a KJV verse (e.g., "John 1:1")
|
|
17
|
+
* nuberea search <text> — Search KJV text
|
|
18
|
+
* nuberea greek <word> — Look up a Greek word in LSJ
|
|
19
|
+
* nuberea hebrew <strong> — Look up a Hebrew Strong's number in BDB
|
|
20
|
+
*/
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;GAkBG"}
|