julion-shared 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-store.d.ts +35 -0
- package/dist/auth-store.d.ts.map +1 -0
- package/dist/auth-store.js +302 -0
- package/dist/auth-store.js.map +1 -0
- package/dist/env.d.ts +7 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +108 -0
- package/dist/env.js.map +1 -0
- package/dist/google-config.d.ts +8 -0
- package/dist/google-config.d.ts.map +1 -0
- package/dist/google-config.js +49 -0
- package/dist/google-config.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/package.json +29 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Connection } from 'mysql2/promise';
|
|
2
|
+
export interface DatabaseConfig {
|
|
3
|
+
host: string;
|
|
4
|
+
port: number;
|
|
5
|
+
user: string;
|
|
6
|
+
password: string;
|
|
7
|
+
database: string;
|
|
8
|
+
}
|
|
9
|
+
export interface JulionUser {
|
|
10
|
+
email: string;
|
|
11
|
+
name: string;
|
|
12
|
+
picture?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface AuthSessionResult {
|
|
15
|
+
sessionId: string;
|
|
16
|
+
token: Record<string, unknown>;
|
|
17
|
+
user_email: string;
|
|
18
|
+
user_name: string;
|
|
19
|
+
user_picture?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function loadDatabaseConfig(startDir?: string): Promise<DatabaseConfig | null>;
|
|
22
|
+
export declare function getDbConnection(startDir?: string): Promise<Connection>;
|
|
23
|
+
export declare function ensureAuthTables(connection: Connection): Promise<void>;
|
|
24
|
+
export declare function createSessionId(): string;
|
|
25
|
+
export declare function createAuthSession(sessionId: string, startDir?: string): Promise<void>;
|
|
26
|
+
export declare function upsertUser(user: JulionUser, startDir?: string): Promise<void>;
|
|
27
|
+
export declare function saveUserDriveToken(userEmail: string, token: unknown, startDir?: string): Promise<void>;
|
|
28
|
+
export declare function loadUserDriveToken(userEmail: string, startDir?: string): Promise<Record<string, unknown> | null>;
|
|
29
|
+
export declare function deleteUserDriveToken(userEmail: string, startDir?: string): Promise<void>;
|
|
30
|
+
export declare function completeAuthSession(sessionId: string, token: unknown, user: JulionUser, startDir?: string): Promise<void>;
|
|
31
|
+
export declare function claimAuthSession(sessionId: string, startDir?: string): Promise<AuthSessionResult | null>;
|
|
32
|
+
export declare function getAuthSessionStatus(sessionId: string, startDir?: string): Promise<'pending' | 'complete' | 'claimed' | 'missing' | 'expired'>;
|
|
33
|
+
export declare function getAuthSession(sessionId: string, startDir?: string): Promise<AuthSessionResult | null>;
|
|
34
|
+
export declare function waitForAuthSession(sessionId: string, timeoutMs?: number, startDir?: string): Promise<AuthSessionResult>;
|
|
35
|
+
//# sourceMappingURL=auth-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-store.d.ts","sourceRoot":"","sources":["../src/auth-store.ts"],"names":[],"mappings":"AACA,OAAc,EAAE,UAAU,EAAiB,MAAM,gBAAgB,CAAC;AAGlE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAcD,wBAAsB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAa1F;AAED,wBAAsB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAS5E;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,UAAU,iBAgC5D;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,iBAkB3E;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,iBAenE;AAED,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,iBAa5F;AAED,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAgBtH;AAED,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,iBAO9E;AAED,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,UAAU,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAqC9G;AAED,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC,CA2BrE;AAED,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CA0B5G;AAmCD,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,SAAS,SAAS,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,CAgC5B"}
|
|
@@ -0,0 +1,302 @@
|
|
|
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.loadDatabaseConfig = loadDatabaseConfig;
|
|
7
|
+
exports.getDbConnection = getDbConnection;
|
|
8
|
+
exports.ensureAuthTables = ensureAuthTables;
|
|
9
|
+
exports.createSessionId = createSessionId;
|
|
10
|
+
exports.createAuthSession = createAuthSession;
|
|
11
|
+
exports.upsertUser = upsertUser;
|
|
12
|
+
exports.saveUserDriveToken = saveUserDriveToken;
|
|
13
|
+
exports.loadUserDriveToken = loadUserDriveToken;
|
|
14
|
+
exports.deleteUserDriveToken = deleteUserDriveToken;
|
|
15
|
+
exports.completeAuthSession = completeAuthSession;
|
|
16
|
+
exports.claimAuthSession = claimAuthSession;
|
|
17
|
+
exports.getAuthSessionStatus = getAuthSessionStatus;
|
|
18
|
+
exports.getAuthSession = getAuthSession;
|
|
19
|
+
exports.waitForAuthSession = waitForAuthSession;
|
|
20
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
21
|
+
const promise_1 = __importDefault(require("mysql2/promise"));
|
|
22
|
+
const env_1 = require("./env");
|
|
23
|
+
const SESSION_TTL_MINUTES = 15;
|
|
24
|
+
async function loadDatabaseConfig(startDir) {
|
|
25
|
+
const env = await (0, env_1.loadMergedEnv)(startDir);
|
|
26
|
+
const host = env.DB_HOST || env.MYSQL_HOST || '127.0.0.1';
|
|
27
|
+
const user = env.DB_USER || env.MYSQL_USER || 'root';
|
|
28
|
+
const password = env.DB_PASSWORD ?? env.MYSQL_PASSWORD ?? '';
|
|
29
|
+
const database = env.DB_DATABASE || env.MYSQL_DATABASE || 'julion';
|
|
30
|
+
const port = env.DB_PORT ? Number(env.DB_PORT) : 3306;
|
|
31
|
+
if (!user) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return { host, port, user, password, database };
|
|
35
|
+
}
|
|
36
|
+
async function getDbConnection(startDir) {
|
|
37
|
+
const config = await loadDatabaseConfig(startDir);
|
|
38
|
+
if (!config) {
|
|
39
|
+
throw new Error('MySQL is not configured. Set DB_USER and DB_DATABASE in your .env file.');
|
|
40
|
+
}
|
|
41
|
+
const connection = await promise_1.default.createConnection(config);
|
|
42
|
+
await ensureAuthTables(connection);
|
|
43
|
+
return connection;
|
|
44
|
+
}
|
|
45
|
+
async function ensureAuthTables(connection) {
|
|
46
|
+
await connection.execute(`
|
|
47
|
+
CREATE TABLE IF NOT EXISTS julion_users (
|
|
48
|
+
email VARCHAR(255) PRIMARY KEY,
|
|
49
|
+
name VARCHAR(255) NOT NULL DEFAULT '',
|
|
50
|
+
picture VARCHAR(512) NULL,
|
|
51
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
52
|
+
last_login_at TIMESTAMP NULL
|
|
53
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
54
|
+
`);
|
|
55
|
+
await connection.execute(`
|
|
56
|
+
CREATE TABLE IF NOT EXISTS julion_auth_sessions (
|
|
57
|
+
session_id VARCHAR(64) PRIMARY KEY,
|
|
58
|
+
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
|
59
|
+
token_json LONGTEXT NULL,
|
|
60
|
+
user_email VARCHAR(255) NULL,
|
|
61
|
+
user_name VARCHAR(255) NULL,
|
|
62
|
+
user_picture VARCHAR(512) NULL,
|
|
63
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
64
|
+
expires_at TIMESTAMP NOT NULL,
|
|
65
|
+
INDEX idx_status_expires (status, expires_at)
|
|
66
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
67
|
+
`);
|
|
68
|
+
await connection.execute(`
|
|
69
|
+
CREATE TABLE IF NOT EXISTS julion_user_tokens (
|
|
70
|
+
user_email VARCHAR(255) PRIMARY KEY,
|
|
71
|
+
token_json LONGTEXT NOT NULL,
|
|
72
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
73
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
function createSessionId() {
|
|
77
|
+
return crypto_1.default.randomBytes(24).toString('hex');
|
|
78
|
+
}
|
|
79
|
+
async function createAuthSession(sessionId, startDir) {
|
|
80
|
+
const connection = await getDbConnection(startDir);
|
|
81
|
+
try {
|
|
82
|
+
await connection.execute(`INSERT INTO julion_auth_sessions (session_id, status, expires_at)
|
|
83
|
+
VALUES (?, 'pending', DATE_ADD(NOW(), INTERVAL ? MINUTE))
|
|
84
|
+
ON DUPLICATE KEY UPDATE
|
|
85
|
+
status = 'pending',
|
|
86
|
+
token_json = NULL,
|
|
87
|
+
user_email = NULL,
|
|
88
|
+
user_name = NULL,
|
|
89
|
+
user_picture = NULL,
|
|
90
|
+
expires_at = DATE_ADD(NOW(), INTERVAL ? MINUTE)`, [sessionId, SESSION_TTL_MINUTES, SESSION_TTL_MINUTES]);
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await connection.end();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function upsertUser(user, startDir) {
|
|
97
|
+
const connection = await getDbConnection(startDir);
|
|
98
|
+
try {
|
|
99
|
+
await connection.execute(`INSERT INTO julion_users (email, name, picture, last_login_at)
|
|
100
|
+
VALUES (?, ?, ?, NOW())
|
|
101
|
+
ON DUPLICATE KEY UPDATE
|
|
102
|
+
name = VALUES(name),
|
|
103
|
+
picture = VALUES(picture),
|
|
104
|
+
last_login_at = NOW()`, [user.email, user.name, user.picture ?? null]);
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
await connection.end();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function saveUserDriveToken(userEmail, token, startDir) {
|
|
111
|
+
const connection = await getDbConnection(startDir);
|
|
112
|
+
try {
|
|
113
|
+
const payload = JSON.stringify(token);
|
|
114
|
+
await connection.execute(`INSERT INTO julion_user_tokens (user_email, token_json)
|
|
115
|
+
VALUES (?, ?)
|
|
116
|
+
ON DUPLICATE KEY UPDATE token_json = VALUES(token_json), updated_at = CURRENT_TIMESTAMP`, [userEmail, payload]);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
await connection.end();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function loadUserDriveToken(userEmail, startDir) {
|
|
123
|
+
const connection = await getDbConnection(startDir);
|
|
124
|
+
try {
|
|
125
|
+
const [rows] = await connection.execute('SELECT token_json FROM julion_user_tokens WHERE user_email = ? LIMIT 1', [userEmail]);
|
|
126
|
+
if (!rows.length || !rows[0].token_json) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
return JSON.parse(String(rows[0].token_json));
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
await connection.end();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function deleteUserDriveToken(userEmail, startDir) {
|
|
139
|
+
const connection = await getDbConnection(startDir);
|
|
140
|
+
try {
|
|
141
|
+
await connection.execute('DELETE FROM julion_user_tokens WHERE user_email = ?', [userEmail]);
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
await connection.end();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async function completeAuthSession(sessionId, token, user, startDir) {
|
|
148
|
+
await upsertUser(user, startDir);
|
|
149
|
+
await saveUserDriveToken(user.email, token, startDir);
|
|
150
|
+
const connection = await getDbConnection(startDir);
|
|
151
|
+
try {
|
|
152
|
+
await connection.execute(`UPDATE julion_auth_sessions
|
|
153
|
+
SET status = 'complete',
|
|
154
|
+
token_json = ?,
|
|
155
|
+
user_email = ?,
|
|
156
|
+
user_name = ?,
|
|
157
|
+
user_picture = ?
|
|
158
|
+
WHERE session_id = ? AND status = 'pending' AND expires_at > NOW()`, [JSON.stringify(token), user.email, user.name, user.picture ?? null, sessionId]);
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
await connection.end();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function claimAuthSession(sessionId, startDir) {
|
|
165
|
+
const connection = await getDbConnection(startDir);
|
|
166
|
+
try {
|
|
167
|
+
await connection.beginTransaction();
|
|
168
|
+
const [rows] = await connection.execute(`SELECT session_id, status, token_json, user_email, user_name, user_picture
|
|
169
|
+
FROM julion_auth_sessions
|
|
170
|
+
WHERE session_id = ? AND status = 'complete' AND expires_at > NOW()
|
|
171
|
+
LIMIT 1
|
|
172
|
+
FOR UPDATE`, [sessionId]);
|
|
173
|
+
const row = rows[0];
|
|
174
|
+
if (!row || !row.token_json || !row.user_email) {
|
|
175
|
+
await connection.rollback();
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
await connection.execute(`UPDATE julion_auth_sessions SET status = 'claimed' WHERE session_id = ?`, [sessionId]);
|
|
179
|
+
await connection.commit();
|
|
180
|
+
return {
|
|
181
|
+
sessionId: row.session_id,
|
|
182
|
+
token: JSON.parse(row.token_json),
|
|
183
|
+
user_email: row.user_email,
|
|
184
|
+
user_name: row.user_name || row.user_email,
|
|
185
|
+
user_picture: row.user_picture || undefined
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
await connection.rollback();
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
await connection.end();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async function getAuthSessionStatus(sessionId, startDir) {
|
|
197
|
+
const connection = await getDbConnection(startDir);
|
|
198
|
+
try {
|
|
199
|
+
const [rows] = await connection.execute(`SELECT status, expires_at
|
|
200
|
+
FROM julion_auth_sessions
|
|
201
|
+
WHERE session_id = ?
|
|
202
|
+
LIMIT 1`, [sessionId]);
|
|
203
|
+
const row = rows[0];
|
|
204
|
+
if (!row) {
|
|
205
|
+
return 'missing';
|
|
206
|
+
}
|
|
207
|
+
if (row.status === 'claimed') {
|
|
208
|
+
return 'claimed';
|
|
209
|
+
}
|
|
210
|
+
if (new Date(row.expires_at) <= new Date()) {
|
|
211
|
+
return 'expired';
|
|
212
|
+
}
|
|
213
|
+
if (row.status === 'complete') {
|
|
214
|
+
return 'complete';
|
|
215
|
+
}
|
|
216
|
+
return 'pending';
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
await connection.end();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async function getAuthSession(sessionId, startDir) {
|
|
223
|
+
const connection = await getDbConnection(startDir);
|
|
224
|
+
try {
|
|
225
|
+
const [rows] = await connection.execute(`SELECT session_id, status, token_json, user_email, user_name, user_picture
|
|
226
|
+
FROM julion_auth_sessions
|
|
227
|
+
WHERE session_id = ? AND expires_at > NOW()
|
|
228
|
+
LIMIT 1`, [sessionId]);
|
|
229
|
+
const row = rows[0];
|
|
230
|
+
if (!row || row.status !== 'complete' || !row.token_json || !row.user_email) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
sessionId: row.session_id,
|
|
235
|
+
token: JSON.parse(row.token_json),
|
|
236
|
+
user_email: row.user_email,
|
|
237
|
+
user_name: row.user_name || row.user_email,
|
|
238
|
+
user_picture: row.user_picture || undefined
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
await connection.end();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function sleep(ms) {
|
|
249
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
250
|
+
}
|
|
251
|
+
async function waitForAuthSessionHttp(baseUrl, sessionId, timeoutMs) {
|
|
252
|
+
const deadline = Date.now() + timeoutMs;
|
|
253
|
+
const endpoint = `${baseUrl.replace(/\/$/, '')}/api/auth/session/${encodeURIComponent(sessionId)}`;
|
|
254
|
+
while (Date.now() < deadline) {
|
|
255
|
+
const response = await fetch(endpoint, { method: 'GET' });
|
|
256
|
+
if (response.status === 202) {
|
|
257
|
+
await sleep(2000);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (response.ok) {
|
|
261
|
+
const payload = (await response.json());
|
|
262
|
+
if (payload?.token && payload?.user_email) {
|
|
263
|
+
return payload;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (response.status === 410 || response.status === 404) {
|
|
267
|
+
throw new Error('Login session expired or not found. Run `julion auth google --website` again.');
|
|
268
|
+
}
|
|
269
|
+
await sleep(2000);
|
|
270
|
+
}
|
|
271
|
+
throw new Error('Timed out waiting for website login. Open the browser, sign in with Google, and try again.');
|
|
272
|
+
}
|
|
273
|
+
async function waitForAuthSession(sessionId, timeoutMs = 180000, startDir) {
|
|
274
|
+
const env = await (0, env_1.loadMergedEnv)(startDir);
|
|
275
|
+
const baseUrl = (0, env_1.resolvePublicBaseUrl)(env);
|
|
276
|
+
try {
|
|
277
|
+
return await waitForAuthSessionHttp(baseUrl, sessionId, timeoutMs);
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
281
|
+
const canUseDatabase = message.includes('fetch failed') ||
|
|
282
|
+
message.includes('ECONNREFUSED') ||
|
|
283
|
+
message.includes('ENOTFOUND');
|
|
284
|
+
if (!canUseDatabase) {
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const deadline = Date.now() + timeoutMs;
|
|
289
|
+
while (Date.now() < deadline) {
|
|
290
|
+
const result = await claimAuthSession(sessionId, startDir);
|
|
291
|
+
if (result) {
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
const status = await getAuthSessionStatus(sessionId, startDir);
|
|
295
|
+
if (status === 'claimed' || status === 'expired' || status === 'missing') {
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
await sleep(2000);
|
|
299
|
+
}
|
|
300
|
+
throw new Error('Timed out waiting for website login. Open the browser, sign in with Google, and try again.');
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=auth-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../src/auth-store.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function parseDotEnv(content: string): Record<string, string>;
|
|
2
|
+
export declare function findDotEnvPath(startDir?: string): string | null;
|
|
3
|
+
export declare function loadMergedEnv(startDir?: string): Promise<Record<string, string>>;
|
|
4
|
+
export declare function resolveWebsiteAuthUrl(env: Record<string, string>): string;
|
|
5
|
+
export declare function resolveGoogleRedirectUri(env: Record<string, string>): string;
|
|
6
|
+
export declare function resolvePublicBaseUrl(env: Record<string, string>): string;
|
|
7
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBnE;AAED,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAkB9E;AAED,wBAAsB,aAAa,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAYrG;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAezE;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAU5E;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAaxE"}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
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.parseDotEnv = parseDotEnv;
|
|
7
|
+
exports.findDotEnvPath = findDotEnvPath;
|
|
8
|
+
exports.loadMergedEnv = loadMergedEnv;
|
|
9
|
+
exports.resolveWebsiteAuthUrl = resolveWebsiteAuthUrl;
|
|
10
|
+
exports.resolveGoogleRedirectUri = resolveGoogleRedirectUri;
|
|
11
|
+
exports.resolvePublicBaseUrl = resolvePublicBaseUrl;
|
|
12
|
+
const fs_1 = require("fs");
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
function parseDotEnv(content) {
|
|
15
|
+
const result = {};
|
|
16
|
+
for (const line of content.split(/\r?\n/)) {
|
|
17
|
+
const trimmed = line.trim();
|
|
18
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const equalsIndex = trimmed.indexOf('=');
|
|
22
|
+
if (equalsIndex === -1) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const key = trimmed.slice(0, equalsIndex).trim();
|
|
26
|
+
let value = trimmed.slice(equalsIndex + 1).trim();
|
|
27
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
28
|
+
value = value.slice(1, -1);
|
|
29
|
+
}
|
|
30
|
+
result[key] = value;
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
function findDotEnvPath(startDir = process.cwd()) {
|
|
35
|
+
let currentDir = startDir;
|
|
36
|
+
while (true) {
|
|
37
|
+
const candidate = path_1.default.join(currentDir, '.env');
|
|
38
|
+
try {
|
|
39
|
+
if ((0, fs_1.statSync)(candidate).isFile()) {
|
|
40
|
+
return candidate;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// ignore
|
|
45
|
+
}
|
|
46
|
+
const parentDir = path_1.default.dirname(currentDir);
|
|
47
|
+
if (parentDir === currentDir) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
currentDir = parentDir;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
async function loadMergedEnv(startDir = process.cwd()) {
|
|
55
|
+
const envPath = findDotEnvPath(startDir);
|
|
56
|
+
let fileEnv = {};
|
|
57
|
+
if (envPath) {
|
|
58
|
+
try {
|
|
59
|
+
const raw = await fs_1.promises.readFile(envPath, 'utf8');
|
|
60
|
+
fileEnv = parseDotEnv(raw);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// ignore
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { ...fileEnv, ...process.env };
|
|
67
|
+
}
|
|
68
|
+
function resolveWebsiteAuthUrl(env) {
|
|
69
|
+
const explicit = env.JULION_WEBSITE_AUTH_URL || env.JULION_AUTH_URL || env.JULION_SITE_URL || env.JULION_WEB_URL;
|
|
70
|
+
if (explicit) {
|
|
71
|
+
const trimmed = explicit.replace(/\/$/, '');
|
|
72
|
+
if (trimmed.endsWith('/auth/google')) {
|
|
73
|
+
return trimmed;
|
|
74
|
+
}
|
|
75
|
+
if (trimmed.includes('/auth/google')) {
|
|
76
|
+
return trimmed;
|
|
77
|
+
}
|
|
78
|
+
return `${trimmed}/auth/google`;
|
|
79
|
+
}
|
|
80
|
+
const port = env.PORT || '3000';
|
|
81
|
+
return `http://localhost:${port}/auth/google`;
|
|
82
|
+
}
|
|
83
|
+
function resolveGoogleRedirectUri(env) {
|
|
84
|
+
const configured = env.GOOGLE_REDIRECT_URI || '';
|
|
85
|
+
if (configured.includes('/auth/google/callback')) {
|
|
86
|
+
return configured.replace(/\/$/, '');
|
|
87
|
+
}
|
|
88
|
+
if (configured) {
|
|
89
|
+
return `${configured.replace(/\/$/, '')}/auth/google/callback`;
|
|
90
|
+
}
|
|
91
|
+
const site = env.JULION_SITE_URL || env.JULION_WEB_URL || `http://localhost:${env.PORT || '3000'}`;
|
|
92
|
+
return `${site.replace(/\/$/, '')}/auth/google/callback`;
|
|
93
|
+
}
|
|
94
|
+
function resolvePublicBaseUrl(env) {
|
|
95
|
+
if (env.JULION_SITE_URL || env.JULION_WEB_URL) {
|
|
96
|
+
return (env.JULION_SITE_URL || env.JULION_WEB_URL || '').replace(/\/$/, '');
|
|
97
|
+
}
|
|
98
|
+
if (env.GOOGLE_REDIRECT_URI) {
|
|
99
|
+
const redirect = env.GOOGLE_REDIRECT_URI.replace(/\/$/, '');
|
|
100
|
+
if (redirect.endsWith('/auth/google/callback')) {
|
|
101
|
+
return redirect.slice(0, -'/auth/google/callback'.length);
|
|
102
|
+
}
|
|
103
|
+
return redirect;
|
|
104
|
+
}
|
|
105
|
+
const port = env.PORT || '3000';
|
|
106
|
+
return `http://localhost:${port}`;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const GOOGLE_DRIVE_SCOPES: string[];
|
|
2
|
+
export interface GoogleClientConfig {
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
redirectUri: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function loadGoogleClientConfig(startDir?: string): Promise<GoogleClientConfig>;
|
|
8
|
+
//# sourceMappingURL=google-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-config.d.ts","sourceRoot":"","sources":["../src/google-config.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,UAK/B,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAaD,wBAAsB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAyB3F"}
|
|
@@ -0,0 +1,49 @@
|
|
|
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.GOOGLE_DRIVE_SCOPES = void 0;
|
|
7
|
+
exports.loadGoogleClientConfig = loadGoogleClientConfig;
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const env_1 = require("./env");
|
|
12
|
+
exports.GOOGLE_DRIVE_SCOPES = [
|
|
13
|
+
'openid',
|
|
14
|
+
'email',
|
|
15
|
+
'profile',
|
|
16
|
+
'https://www.googleapis.com/auth/drive.file'
|
|
17
|
+
];
|
|
18
|
+
const CREDENTIALS_PATH = path_1.default.join(os_1.default.homedir(), '.julion', 'google-client.json');
|
|
19
|
+
async function readJson(filePath) {
|
|
20
|
+
try {
|
|
21
|
+
const raw = await fs_1.promises.readFile(filePath, 'utf8');
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function loadGoogleClientConfig(startDir) {
|
|
29
|
+
const env = await (0, env_1.loadMergedEnv)(startDir);
|
|
30
|
+
const clientId = env.GOOGLE_CLIENT_ID;
|
|
31
|
+
const clientSecret = env.GOOGLE_CLIENT_SECRET;
|
|
32
|
+
const redirectUri = (0, env_1.resolveGoogleRedirectUri)(env);
|
|
33
|
+
if (clientId && clientSecret) {
|
|
34
|
+
return { clientId, clientSecret, redirectUri };
|
|
35
|
+
}
|
|
36
|
+
const credentials = await readJson(CREDENTIALS_PATH);
|
|
37
|
+
if (credentials) {
|
|
38
|
+
const payload = credentials.installed ?? credentials.web;
|
|
39
|
+
if (payload?.client_id && payload?.client_secret) {
|
|
40
|
+
return {
|
|
41
|
+
clientId: payload.client_id,
|
|
42
|
+
clientSecret: payload.client_secret,
|
|
43
|
+
redirectUri: payload.redirect_uris?.[0] || redirectUri
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
throw new Error('Google OAuth is not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in your .env file.');
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=google-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-config.js","sourceRoot":"","sources":["../src/google-config.ts"],"names":[],"mappings":";;;;;;AA6BA,wDAyBC;AAtDD,2BAAoC;AACpC,4CAAoB;AACpB,gDAAwB;AACxB,+BAAgE;AAEnD,QAAA,mBAAmB,GAAG;IACjC,QAAQ;IACR,OAAO;IACP,SAAS;IACT,4CAA4C;CAC7C,CAAC;AAQF,MAAM,gBAAgB,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,oBAAoB,CAAC,CAAC;AAElF,KAAK,UAAU,QAAQ,CAAC,QAAgB;IACtC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,aAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,sBAAsB,CAAC,QAAiB;IAC5D,MAAM,GAAG,GAAG,MAAM,IAAA,mBAAa,EAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,GAAG,CAAC,gBAAgB,CAAC;IACtC,MAAM,YAAY,GAAG,GAAG,CAAC,oBAAoB,CAAC;IAC9C,MAAM,WAAW,GAAG,IAAA,8BAAwB,EAAC,GAAG,CAAC,CAAC;IAElD,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;QAC7B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACrD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,IAAI,WAAW,CAAC,GAAG,CAAC;QACzD,IAAI,OAAO,EAAE,SAAS,IAAI,OAAO,EAAE,aAAa,EAAE,CAAC;YACjD,OAAO;gBACL,QAAQ,EAAE,OAAO,CAAC,SAAS;gBAC3B,YAAY,EAAE,OAAO,CAAC,aAAa;gBACnC,WAAW,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,WAAW;aACvD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,kGAAkG,CACnG,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAEhC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,YAajD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.sanitizeIgnoreList = sanitizeIgnoreList;
|
|
18
|
+
__exportStar(require("./env"), exports);
|
|
19
|
+
__exportStar(require("./auth-store"), exports);
|
|
20
|
+
__exportStar(require("./google-config"), exports);
|
|
21
|
+
function sanitizeIgnoreList(files) {
|
|
22
|
+
const defaults = [
|
|
23
|
+
'vendor/',
|
|
24
|
+
'node_modules/',
|
|
25
|
+
'.git/',
|
|
26
|
+
'.env',
|
|
27
|
+
'storage/logs/',
|
|
28
|
+
'cache/',
|
|
29
|
+
'tmp/',
|
|
30
|
+
'dist/',
|
|
31
|
+
'build/'
|
|
32
|
+
];
|
|
33
|
+
return Array.from(new Set([...defaults, ...files]));
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAIA,gDAaC;AAjBD,wCAAsB;AACtB,+CAA6B;AAC7B,kDAAgC;AAEhC,SAAgB,kBAAkB,CAAC,KAAe;IAChD,MAAM,QAAQ,GAAG;QACf,SAAS;QACT,eAAe;QACf,OAAO;QACP,MAAM;QACN,eAAe;QACf,QAAQ;QACR,MAAM;QACN,OAAO;QACP,QAAQ;KACT,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "julion-shared",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared utility types and helpers for Julion engine packages.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc -p tsconfig.json"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"mongodb": "^6.3.0"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/JulioOxalis/Julion.git",
|
|
22
|
+
"directory": "packages/shared"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/JulioOxalis/Julion/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/JulioOxalis/Julion#readme",
|
|
28
|
+
"license": "MIT"
|
|
29
|
+
}
|