@prmichaelsen/agentbase-core 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/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/auth/guards.d.ts +15 -0
- package/dist/lib/auth/guards.d.ts.map +1 -0
- package/dist/lib/auth/guards.js +48 -0
- package/dist/lib/auth/guards.js.map +1 -0
- package/dist/lib/auth/helpers.d.ts +8 -0
- package/dist/lib/auth/helpers.d.ts.map +1 -0
- package/dist/lib/auth/helpers.js +9 -0
- package/dist/lib/auth/helpers.js.map +1 -0
- package/dist/lib/auth/index.d.ts +4 -0
- package/dist/lib/auth/index.d.ts.map +1 -0
- package/dist/lib/auth/index.js +4 -0
- package/dist/lib/auth/index.js.map +1 -0
- package/dist/lib/auth/session.d.ts +23 -0
- package/dist/lib/auth/session.d.ts.map +1 -0
- package/dist/lib/auth/session.js +104 -0
- package/dist/lib/auth/session.js.map +1 -0
- package/dist/lib/firebase-admin.d.ts +2 -0
- package/dist/lib/firebase-admin.d.ts.map +1 -0
- package/dist/lib/firebase-admin.js +8 -0
- package/dist/lib/firebase-admin.js.map +1 -0
- package/dist/lib/firebase-client.d.ts +29 -0
- package/dist/lib/firebase-client.d.ts.map +1 -0
- package/dist/lib/firebase-client.js +65 -0
- package/dist/lib/firebase-client.js.map +1 -0
- package/dist/lib/format-time.d.ts +6 -0
- package/dist/lib/format-time.d.ts.map +1 -0
- package/dist/lib/format-time.js +34 -0
- package/dist/lib/format-time.js.map +1 -0
- package/dist/lib/index.d.ts +11 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +13 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/linkify.d.ts +10 -0
- package/dist/lib/linkify.d.ts.map +1 -0
- package/dist/lib/linkify.js +51 -0
- package/dist/lib/linkify.js.map +1 -0
- package/dist/lib/logger.d.ts +42 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +112 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/rate-limiter.d.ts +31 -0
- package/dist/lib/rate-limiter.d.ts.map +1 -0
- package/dist/lib/rate-limiter.js +65 -0
- package/dist/lib/rate-limiter.js.map +1 -0
- package/dist/lib/uuid.d.ts +12 -0
- package/dist/lib/uuid.d.ts.map +1 -0
- package/dist/lib/uuid.js +23 -0
- package/dist/lib/uuid.js.map +1 -0
- package/dist/services/base.service.d.ts +46 -0
- package/dist/services/base.service.d.ts.map +1 -0
- package/dist/services/base.service.js +46 -0
- package/dist/services/base.service.js.map +1 -0
- package/dist/services/confirmation-token.service.d.ts +40 -0
- package/dist/services/confirmation-token.service.d.ts.map +1 -0
- package/dist/services/confirmation-token.service.js +60 -0
- package/dist/services/confirmation-token.service.js.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +3 -0
- package/dist/services/index.js.map +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +70 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { BaseService } from './services/base.service.js';
|
|
2
|
+
export type { Logger } from './services/base.service.js';
|
|
3
|
+
export { ConfirmationTokenService } from './services/confirmation-token.service.js';
|
|
4
|
+
export type { PendingAction } from './services/confirmation-token.service.js';
|
|
5
|
+
export type { AuthUser, ServerSession, AuthResult } from './types/index.js';
|
|
6
|
+
export { createLogger, sanitizeToken, sanitizeEmail, sanitizeUserId, sanitizeObject, authLogger, apiLogger, dbLogger, chatLogger, initFirebaseAdmin, initializeFirebase, getFirebaseApp, getFirebaseAuth, signIn, signUp, signInAnonymously, upgradeAnonymousAccount, upgradeAnonymousWithPopup, resetPassword, logout, onAuthChange, getCurrentUser, getIdToken, getServerSession, isAuthenticated, createSessionCookie, revokeSession, isRealUser, isRealUserServer, requireAuth, requireAdmin, isAdmin, formatExactTime, getRelativeTime, linkifyText, generateUUID, checkRateLimit, createRateLimitResponse, getRateLimitIdentifier, } from './lib/index.js';
|
|
7
|
+
export type { User, UserCredential, Auth } from './lib/index.js';
|
|
8
|
+
export type { RateLimitConfig, RateLimitResult } from './lib/index.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AACxD,YAAY,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAA;AACnF,YAAY,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAA;AAG7E,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG3E,OAAO,EAEL,YAAY,EACZ,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,QAAQ,EACR,UAAU,EAEV,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,MAAM,EACN,MAAM,EACN,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,aAAa,EACb,MAAM,EACN,YAAY,EACZ,cAAc,EACd,UAAU,EAEV,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,OAAO,EAEP,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,cAAc,EACd,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAChE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// @prmichaelsen/agentbase-core
|
|
2
|
+
// Shared service infrastructure for agentbase projects
|
|
3
|
+
// Services
|
|
4
|
+
export { BaseService } from './services/base.service.js';
|
|
5
|
+
export { ConfirmationTokenService } from './services/confirmation-token.service.js';
|
|
6
|
+
// Lib — re-export everything
|
|
7
|
+
export {
|
|
8
|
+
// Logger
|
|
9
|
+
createLogger, sanitizeToken, sanitizeEmail, sanitizeUserId, sanitizeObject, authLogger, apiLogger, dbLogger, chatLogger,
|
|
10
|
+
// Firebase
|
|
11
|
+
initFirebaseAdmin, initializeFirebase, getFirebaseApp, getFirebaseAuth, signIn, signUp, signInAnonymously, upgradeAnonymousAccount, upgradeAnonymousWithPopup, resetPassword, logout, onAuthChange, getCurrentUser, getIdToken,
|
|
12
|
+
// Auth
|
|
13
|
+
getServerSession, isAuthenticated, createSessionCookie, revokeSession, isRealUser, isRealUserServer, requireAuth, requireAdmin, isAdmin,
|
|
14
|
+
// Utilities
|
|
15
|
+
formatExactTime, getRelativeTime, linkifyText, generateUUID, checkRateLimit, createRateLimitResponse, getRateLimitIdentifier, } from './lib/index.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,uDAAuD;AAEvD,WAAW;AACX,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAExD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAA;AAMnF,6BAA6B;AAC7B,OAAO;AACL,SAAS;AACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,QAAQ,EACR,UAAU;AACV,WAAW;AACX,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,MAAM,EACN,MAAM,EACN,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,aAAa,EACb,MAAM,EACN,YAAY,EACZ,cAAc,EACd,UAAU;AACV,OAAO;AACP,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,OAAO;AACP,YAAY;AACZ,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,cAAc,EACd,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware to require authentication
|
|
3
|
+
* @returns Response object with error if not authenticated, null if authorized
|
|
4
|
+
*/
|
|
5
|
+
export declare function requireAuth(request: Request): Promise<Response | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Middleware to require admin access
|
|
8
|
+
* @param ownerEmails Comma-separated admin emails (or pass via env)
|
|
9
|
+
*/
|
|
10
|
+
export declare function requireAdmin(request: Request, ownerEmails?: string): Promise<Response | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Check if a user is an admin
|
|
13
|
+
*/
|
|
14
|
+
export declare function isAdmin(request: Request, ownerEmails?: string): Promise<boolean>;
|
|
15
|
+
//# sourceMappingURL=guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/guards.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAc5E;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA0BnG;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAStF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getServerSession } from './session.js';
|
|
2
|
+
/**
|
|
3
|
+
* Middleware to require authentication
|
|
4
|
+
* @returns Response object with error if not authenticated, null if authorized
|
|
5
|
+
*/
|
|
6
|
+
export async function requireAuth(request) {
|
|
7
|
+
const session = await getServerSession(request);
|
|
8
|
+
if (!session || !session.user) {
|
|
9
|
+
return new Response(JSON.stringify({ error: 'Unauthorized: Authentication required' }), {
|
|
10
|
+
status: 401,
|
|
11
|
+
headers: { 'Content-Type': 'application/json' },
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Middleware to require admin access
|
|
18
|
+
* @param ownerEmails Comma-separated admin emails (or pass via env)
|
|
19
|
+
*/
|
|
20
|
+
export async function requireAdmin(request, ownerEmails) {
|
|
21
|
+
const session = await getServerSession(request);
|
|
22
|
+
if (!session || !session.user) {
|
|
23
|
+
return new Response(JSON.stringify({ error: 'Unauthorized: Authentication required' }), {
|
|
24
|
+
status: 401,
|
|
25
|
+
headers: { 'Content-Type': 'application/json' },
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const emails = (ownerEmails ?? process.env.OWNER_EMAILS ?? '').split(',').map(e => e.trim());
|
|
29
|
+
if (!session.user.email || !emails.includes(session.user.email)) {
|
|
30
|
+
return new Response(JSON.stringify({ error: 'Forbidden: Admin access required' }), {
|
|
31
|
+
status: 403,
|
|
32
|
+
headers: { 'Content-Type': 'application/json' },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if a user is an admin
|
|
39
|
+
*/
|
|
40
|
+
export async function isAdmin(request, ownerEmails) {
|
|
41
|
+
const session = await getServerSession(request);
|
|
42
|
+
if (!session || !session.user || !session.user.email) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
const emails = (ownerEmails ?? process.env.OWNER_EMAILS ?? '').split(',').map(e => e.trim());
|
|
46
|
+
return emails.includes(session.user.email);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../../src/lib/auth/guards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAgB;IAChD,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC9B,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,uCAAuC,EAAE,CAAC,EAClE;YACE,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CACF,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAgB,EAAE,WAAoB;IACvE,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC9B,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,uCAAuC,EAAE,CAAC,EAClE;YACE,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CACF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAE7F,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC,EAC7D;YACE,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CACF,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAgB,EAAE,WAAoB;IAClE,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACrD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7F,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AuthUser } from '../../types/index.js';
|
|
2
|
+
/** Returns true if the user is authenticated with a real (non-anonymous) account */
|
|
3
|
+
export declare function isRealUser(user: {
|
|
4
|
+
isAnonymous?: boolean;
|
|
5
|
+
} | null | undefined): boolean;
|
|
6
|
+
/** Server-side version using AuthUser type */
|
|
7
|
+
export declare function isRealUserServer(user: AuthUser | null | undefined): boolean;
|
|
8
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAEpD,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEtF;AAED,8CAA8C;AAC9C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE3E"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Returns true if the user is authenticated with a real (non-anonymous) account */
|
|
2
|
+
export function isRealUser(user) {
|
|
3
|
+
return !!user && !user.isAnonymous;
|
|
4
|
+
}
|
|
5
|
+
/** Server-side version using AuthUser type */
|
|
6
|
+
export function isRealUserServer(user) {
|
|
7
|
+
return !!user && !user.isAnonymous;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/lib/auth/helpers.ts"],"names":[],"mappings":"AAEA,oFAAoF;AACpF,MAAM,UAAU,UAAU,CAAC,IAAkD;IAC3E,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAA;AACpC,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,gBAAgB,CAAC,IAAiC;IAChE,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAA;AACpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACpG,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACpG,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ServerSession } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get the user's session from the server
|
|
4
|
+
* @param request Request object to get cookies from
|
|
5
|
+
* @returns The user's session or null if not authenticated
|
|
6
|
+
*/
|
|
7
|
+
export declare function getServerSession(request: Request): Promise<ServerSession | null>;
|
|
8
|
+
/**
|
|
9
|
+
* Check if a user is authenticated
|
|
10
|
+
*/
|
|
11
|
+
export declare function isAuthenticated(request: Request): Promise<boolean>;
|
|
12
|
+
/**
|
|
13
|
+
* Create a session cookie for a user
|
|
14
|
+
* @param idToken Firebase ID token
|
|
15
|
+
* @param expiresInMs Expiry in milliseconds (default: 14 days)
|
|
16
|
+
* @returns Session cookie string
|
|
17
|
+
*/
|
|
18
|
+
export declare function createSessionCookie(idToken: string, expiresInMs?: number): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Revoke a user's session
|
|
21
|
+
*/
|
|
22
|
+
export declare function revokeSession(request: Request): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/session.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAY,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA8BpE;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAsCtF;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAGxE;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,SAA2B,GAAG,OAAO,CAAC,MAAM,CAAC,CAYlH;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAWnE"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { verifyIdToken, verifySessionCookie, createSessionCookie as createFirebaseSessionCookie } from '@prmichaelsen/firebase-admin-sdk-v8';
|
|
2
|
+
import { authLogger } from '../logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Get the session cookie from a request
|
|
5
|
+
*/
|
|
6
|
+
function getSessionCookie(request) {
|
|
7
|
+
try {
|
|
8
|
+
const cookieHeader = request.headers.get('cookie');
|
|
9
|
+
if (!cookieHeader) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const cookies = cookieHeader.split(';').reduce((acc, cookie) => {
|
|
13
|
+
const [name, value] = cookie.trim().split('=');
|
|
14
|
+
acc[name] = value;
|
|
15
|
+
return acc;
|
|
16
|
+
}, {});
|
|
17
|
+
return cookies.session;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.error('[getSessionCookie] Error:', error);
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get the user's session from the server
|
|
26
|
+
* @param request Request object to get cookies from
|
|
27
|
+
* @returns The user's session or null if not authenticated
|
|
28
|
+
*/
|
|
29
|
+
export async function getServerSession(request) {
|
|
30
|
+
try {
|
|
31
|
+
authLogger.debug('Getting server session');
|
|
32
|
+
const sessionCookie = getSessionCookie(request);
|
|
33
|
+
if (!sessionCookie) {
|
|
34
|
+
authLogger.debug('No session cookie found');
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
authLogger.debug('Session cookie found, verifying');
|
|
38
|
+
let decodedToken;
|
|
39
|
+
try {
|
|
40
|
+
decodedToken = await verifySessionCookie(sessionCookie);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
authLogger.debug('Session cookie verification failed, trying ID token verification');
|
|
44
|
+
decodedToken = await verifyIdToken(sessionCookie);
|
|
45
|
+
}
|
|
46
|
+
authLogger.info('Token verified', { userId: decodedToken.sub });
|
|
47
|
+
const isAnonymous = decodedToken.firebase?.sign_in_provider === 'anonymous' || !decodedToken.email;
|
|
48
|
+
const user = {
|
|
49
|
+
uid: decodedToken.sub,
|
|
50
|
+
email: decodedToken.email || null,
|
|
51
|
+
displayName: decodedToken.name || null,
|
|
52
|
+
photoURL: decodedToken.picture || null,
|
|
53
|
+
emailVerified: decodedToken.email_verified || false,
|
|
54
|
+
isAnonymous,
|
|
55
|
+
};
|
|
56
|
+
return { user };
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
authLogger.error('Failed to get server session', error);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if a user is authenticated
|
|
65
|
+
*/
|
|
66
|
+
export async function isAuthenticated(request) {
|
|
67
|
+
const session = await getServerSession(request);
|
|
68
|
+
return session !== null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Create a session cookie for a user
|
|
72
|
+
* @param idToken Firebase ID token
|
|
73
|
+
* @param expiresInMs Expiry in milliseconds (default: 14 days)
|
|
74
|
+
* @returns Session cookie string
|
|
75
|
+
*/
|
|
76
|
+
export async function createSessionCookie(idToken, expiresInMs = 60 * 60 * 24 * 14 * 1000) {
|
|
77
|
+
try {
|
|
78
|
+
const sessionCookie = await createFirebaseSessionCookie(idToken, {
|
|
79
|
+
expiresIn: expiresInMs
|
|
80
|
+
});
|
|
81
|
+
console.log('[createSessionCookie] Session cookie created');
|
|
82
|
+
return sessionCookie;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error('[createSessionCookie] Error:', error);
|
|
86
|
+
throw new Error('Failed to create session cookie');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Revoke a user's session
|
|
91
|
+
*/
|
|
92
|
+
export async function revokeSession(request) {
|
|
93
|
+
try {
|
|
94
|
+
const session = await getServerSession(request);
|
|
95
|
+
if (session?.user) {
|
|
96
|
+
console.log('[revokeSession] Session revoked for user:', session.user.uid);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error('[revokeSession] Error:', error);
|
|
101
|
+
throw new Error('Failed to revoke session');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/lib/auth/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebase-admin.d.ts","sourceRoot":"","sources":["../../src/lib/firebase-admin.ts"],"names":[],"mappings":"AAEA,wBAAgB,iBAAiB,SAKhC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { initializeApp as _initializeApp } from '@prmichaelsen/firebase-admin-sdk-v8';
|
|
2
|
+
export function initFirebaseAdmin() {
|
|
3
|
+
_initializeApp({
|
|
4
|
+
serviceAccount: process.env.FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY,
|
|
5
|
+
projectId: process.env.FIREBASE_PROJECT_ID,
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=firebase-admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebase-admin.js","sourceRoot":"","sources":["../../src/lib/firebase-admin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,IAAI,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAErF,MAAM,UAAU,iBAAiB;IAC/B,cAAc,CAAC;QACb,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,kCAAkC;QAC9D,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;KAC3C,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Client — singleton initialization and auth helpers.
|
|
3
|
+
*/
|
|
4
|
+
import { type FirebaseApp } from 'firebase/app';
|
|
5
|
+
import { type Auth, type User, type UserCredential, type AuthProvider } from 'firebase/auth';
|
|
6
|
+
interface FirebaseConfig {
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
authDomain?: string;
|
|
9
|
+
projectId?: string;
|
|
10
|
+
storageBucket?: string;
|
|
11
|
+
messagingSenderId?: string;
|
|
12
|
+
appId?: string;
|
|
13
|
+
measurementId?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function initializeFirebase(config: FirebaseConfig): FirebaseApp;
|
|
16
|
+
export declare function getFirebaseApp(): FirebaseApp;
|
|
17
|
+
export declare function getFirebaseAuth(): Auth;
|
|
18
|
+
export declare function signIn(email: string, password: string): Promise<UserCredential>;
|
|
19
|
+
export declare function signUp(email: string, password: string): Promise<UserCredential>;
|
|
20
|
+
export declare function signInAnonymously(): Promise<UserCredential>;
|
|
21
|
+
export declare function upgradeAnonymousAccount(email: string, password: string): Promise<UserCredential>;
|
|
22
|
+
export declare function upgradeAnonymousWithPopup(provider: AuthProvider): Promise<UserCredential>;
|
|
23
|
+
export declare function resetPassword(email: string): Promise<void>;
|
|
24
|
+
export declare function logout(): Promise<void>;
|
|
25
|
+
export declare function onAuthChange(callback: (user: User | null) => void): () => void;
|
|
26
|
+
export declare function getCurrentUser(): Promise<User | null>;
|
|
27
|
+
export declare function getIdToken(): Promise<string | null>;
|
|
28
|
+
export type { User, UserCredential, Auth };
|
|
29
|
+
//# sourceMappingURL=firebase-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebase-client.d.ts","sourceRoot":"","sources":["../../src/lib/firebase-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAkC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/E,OAAO,EAWL,KAAK,IAAI,EACT,KAAK,IAAI,EACT,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAA;AAKtB,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,CAMtE;AAED,wBAAgB,cAAc,IAAI,WAAW,CAG5C;AAED,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAErF;AAED,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAErF;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC,CAEjE;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,cAAc,CAAC,CAIzB;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhE;AAED,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5C;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,CAE9E;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAE3D;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIzD;AAED,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Client — singleton initialization and auth helpers.
|
|
3
|
+
*/
|
|
4
|
+
import { initializeApp, getApps, getApp } from 'firebase/app';
|
|
5
|
+
import { getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword, signInAnonymously as firebaseSignInAnonymously, linkWithCredential, linkWithPopup, EmailAuthProvider, sendPasswordResetEmail, signOut, onAuthStateChanged, } from 'firebase/auth';
|
|
6
|
+
let app = null;
|
|
7
|
+
let authInstance = null;
|
|
8
|
+
export function initializeFirebase(config) {
|
|
9
|
+
if (!app) {
|
|
10
|
+
app = getApps().length === 0 ? initializeApp(config) : getApp();
|
|
11
|
+
authInstance = getAuth(app);
|
|
12
|
+
}
|
|
13
|
+
return app;
|
|
14
|
+
}
|
|
15
|
+
export function getFirebaseApp() {
|
|
16
|
+
if (!app)
|
|
17
|
+
throw new Error('Firebase not initialized. Call initializeFirebase() first.');
|
|
18
|
+
return app;
|
|
19
|
+
}
|
|
20
|
+
export function getFirebaseAuth() {
|
|
21
|
+
if (!authInstance)
|
|
22
|
+
throw new Error('Firebase not initialized. Call initializeFirebase() first.');
|
|
23
|
+
return authInstance;
|
|
24
|
+
}
|
|
25
|
+
export async function signIn(email, password) {
|
|
26
|
+
return signInWithEmailAndPassword(getFirebaseAuth(), email, password);
|
|
27
|
+
}
|
|
28
|
+
export async function signUp(email, password) {
|
|
29
|
+
return createUserWithEmailAndPassword(getFirebaseAuth(), email, password);
|
|
30
|
+
}
|
|
31
|
+
export async function signInAnonymously() {
|
|
32
|
+
return firebaseSignInAnonymously(getFirebaseAuth());
|
|
33
|
+
}
|
|
34
|
+
export async function upgradeAnonymousAccount(email, password) {
|
|
35
|
+
const user = getFirebaseAuth().currentUser;
|
|
36
|
+
if (!user || !user.isAnonymous)
|
|
37
|
+
throw new Error('No anonymous user to upgrade');
|
|
38
|
+
const credential = EmailAuthProvider.credential(email, password);
|
|
39
|
+
return linkWithCredential(user, credential);
|
|
40
|
+
}
|
|
41
|
+
export async function upgradeAnonymousWithPopup(provider) {
|
|
42
|
+
const user = getFirebaseAuth().currentUser;
|
|
43
|
+
if (!user || !user.isAnonymous)
|
|
44
|
+
throw new Error('No anonymous user to upgrade');
|
|
45
|
+
return linkWithPopup(user, provider);
|
|
46
|
+
}
|
|
47
|
+
export async function resetPassword(email) {
|
|
48
|
+
return sendPasswordResetEmail(getFirebaseAuth(), email);
|
|
49
|
+
}
|
|
50
|
+
export async function logout() {
|
|
51
|
+
return signOut(getFirebaseAuth());
|
|
52
|
+
}
|
|
53
|
+
export function onAuthChange(callback) {
|
|
54
|
+
return onAuthStateChanged(getFirebaseAuth(), callback);
|
|
55
|
+
}
|
|
56
|
+
export async function getCurrentUser() {
|
|
57
|
+
return getFirebaseAuth().currentUser;
|
|
58
|
+
}
|
|
59
|
+
export async function getIdToken() {
|
|
60
|
+
const user = getFirebaseAuth().currentUser;
|
|
61
|
+
if (!user)
|
|
62
|
+
return null;
|
|
63
|
+
return user.getIdToken();
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=firebase-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebase-client.js","sourceRoot":"","sources":["../../src/lib/firebase-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-time.d.ts","sourceRoot":"","sources":["../../src/lib/format-time.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAQ1D;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAiB1D"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time formatting utilities.
|
|
3
|
+
*/
|
|
4
|
+
export function formatExactTime(dateString) {
|
|
5
|
+
const date = new Date(dateString);
|
|
6
|
+
const time = date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
|
|
7
|
+
const weekday = date.toLocaleDateString('en-US', { weekday: 'short' });
|
|
8
|
+
const month = date.getMonth() + 1;
|
|
9
|
+
const day = date.getDate();
|
|
10
|
+
const year = date.getFullYear().toString().slice(-2);
|
|
11
|
+
return `${time} ${weekday} ${month}/${day}/${year}`;
|
|
12
|
+
}
|
|
13
|
+
export function getRelativeTime(dateString) {
|
|
14
|
+
const date = new Date(dateString);
|
|
15
|
+
const now = new Date();
|
|
16
|
+
const diffMs = now.getTime() - date.getTime();
|
|
17
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
18
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
19
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
20
|
+
if (diffMins < 1)
|
|
21
|
+
return 'Just now';
|
|
22
|
+
if (diffMins < 60)
|
|
23
|
+
return `${diffMins}m ago`;
|
|
24
|
+
if (diffHours < 24)
|
|
25
|
+
return `${diffHours}h ago`;
|
|
26
|
+
if (diffDays < 7)
|
|
27
|
+
return `${diffDays}d ago`;
|
|
28
|
+
if (diffDays < 30) {
|
|
29
|
+
const weeks = Math.floor(diffDays / 7);
|
|
30
|
+
return `${weeks}w ago`;
|
|
31
|
+
}
|
|
32
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=format-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-time.js","sourceRoot":"","sources":["../../src/lib/format-time.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAA;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;IACnG,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IACtE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,GAAG,IAAI,IAAI,OAAO,IAAI,KAAK,IAAI,GAAG,IAAI,IAAI,EAAE,CAAA;AACrD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAA;IACjC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;IACtB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAA;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAA;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAA;IAE9C,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,UAAU,CAAA;IACnC,IAAI,QAAQ,GAAG,EAAE;QAAE,OAAO,GAAG,QAAQ,OAAO,CAAA;IAC5C,IAAI,SAAS,GAAG,EAAE;QAAE,OAAO,GAAG,SAAS,OAAO,CAAA;IAC9C,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,GAAG,QAAQ,OAAO,CAAA;IAC3C,IAAI,QAAQ,GAAG,EAAE,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAA;QACtC,OAAO,GAAG,KAAK,OAAO,CAAA;IACxB,CAAC;IACD,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;AAC9F,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { createLogger, sanitizeToken, sanitizeEmail, sanitizeUserId, sanitizeObject, authLogger, apiLogger, dbLogger, chatLogger, } from './logger.js';
|
|
2
|
+
export { initFirebaseAdmin } from './firebase-admin.js';
|
|
3
|
+
export { initializeFirebase, getFirebaseApp, getFirebaseAuth, signIn, signUp, signInAnonymously, upgradeAnonymousAccount, upgradeAnonymousWithPopup, resetPassword, logout, onAuthChange, getCurrentUser, getIdToken, } from './firebase-client.js';
|
|
4
|
+
export type { User, UserCredential, Auth } from './firebase-client.js';
|
|
5
|
+
export { getServerSession, isAuthenticated, createSessionCookie, revokeSession, isRealUser, isRealUserServer, requireAuth, requireAdmin, isAdmin, } from './auth/index.js';
|
|
6
|
+
export { formatExactTime, getRelativeTime } from './format-time.js';
|
|
7
|
+
export { linkifyText } from './linkify.js';
|
|
8
|
+
export { generateUUID } from './uuid.js';
|
|
9
|
+
export { checkRateLimit, createRateLimitResponse, getRateLimitIdentifier, } from './rate-limiter.js';
|
|
10
|
+
export type { RateLimitConfig, RateLimitResult } from './rate-limiter.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,QAAQ,EACR,UAAU,GACX,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,MAAM,EACN,MAAM,EACN,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,aAAa,EACb,MAAM,EACN,YAAY,EACZ,cAAc,EACd,UAAU,GACX,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAGtE,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,OAAO,GACR,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Logger & sanitization
|
|
2
|
+
export { createLogger, sanitizeToken, sanitizeEmail, sanitizeUserId, sanitizeObject, authLogger, apiLogger, dbLogger, chatLogger, } from './logger.js';
|
|
3
|
+
// Firebase wrappers
|
|
4
|
+
export { initFirebaseAdmin } from './firebase-admin.js';
|
|
5
|
+
export { initializeFirebase, getFirebaseApp, getFirebaseAuth, signIn, signUp, signInAnonymously, upgradeAnonymousAccount, upgradeAnonymousWithPopup, resetPassword, logout, onAuthChange, getCurrentUser, getIdToken, } from './firebase-client.js';
|
|
6
|
+
// Auth
|
|
7
|
+
export { getServerSession, isAuthenticated, createSessionCookie, revokeSession, isRealUser, isRealUserServer, requireAuth, requireAdmin, isAdmin, } from './auth/index.js';
|
|
8
|
+
// Utilities
|
|
9
|
+
export { formatExactTime, getRelativeTime } from './format-time.js';
|
|
10
|
+
export { linkifyText } from './linkify.js';
|
|
11
|
+
export { generateUUID } from './uuid.js';
|
|
12
|
+
export { checkRateLimit, createRateLimitResponse, getRateLimitIdentifier, } from './rate-limiter.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,QAAQ,EACR,UAAU,GACX,MAAM,aAAa,CAAA;AAEpB,oBAAoB;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,MAAM,EACN,MAAM,EACN,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,aAAa,EACb,MAAM,EACN,YAAY,EACZ,cAAc,EACd,UAAU,GACX,MAAM,sBAAsB,CAAA;AAG7B,OAAO;AACP,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,OAAO,GACR,MAAM,iBAAiB,CAAA;AAExB,YAAY;AACZ,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-linkify plain URLs in text to markdown link syntax.
|
|
3
|
+
*
|
|
4
|
+
* Uses a 3-pass placeholder approach:
|
|
5
|
+
* 1. Extract protected zones (code blocks, inline code, markdown links/images)
|
|
6
|
+
* 2. Convert plain URLs to [url](url) markdown
|
|
7
|
+
* 3. Restore protected content
|
|
8
|
+
*/
|
|
9
|
+
export declare function linkifyText(text: string): string;
|
|
10
|
+
//# sourceMappingURL=linkify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkify.d.ts","sourceRoot":"","sources":["../../src/lib/linkify.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwBH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkChD"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-linkify plain URLs in text to markdown link syntax.
|
|
3
|
+
*
|
|
4
|
+
* Uses a 3-pass placeholder approach:
|
|
5
|
+
* 1. Extract protected zones (code blocks, inline code, markdown links/images)
|
|
6
|
+
* 2. Convert plain URLs to [url](url) markdown
|
|
7
|
+
* 3. Restore protected content
|
|
8
|
+
*/
|
|
9
|
+
const KNOWN_TLDS = 'com|org|net|io|me|dev|app|xyz|co|ai|gg|cc|us|uk|ca|de|fr|jp|au|in|edu|gov|info|biz';
|
|
10
|
+
// Protected zone patterns (ordered by priority)
|
|
11
|
+
const PROTECTED_RE = new RegExp([
|
|
12
|
+
'```[\\s\\S]*?```', // fenced code blocks
|
|
13
|
+
'`[^`]+`', // inline code
|
|
14
|
+
'!\\[[^\\]]*\\]\\([^)]*\\)', // markdown images
|
|
15
|
+
'\\[[^\\]]*\\]\\([^)]*\\)', // markdown links
|
|
16
|
+
].join('|'), 'g');
|
|
17
|
+
// URL patterns
|
|
18
|
+
const PROTOCOL_URL_RE = /https?:\/\/[^\s<]+[^\s.,;:!?'")\]}<]/g;
|
|
19
|
+
const WWW_URL_RE = /(?<![/\w])www\.[^\s<]+[^\s.,;:!?'")\]}<]/g;
|
|
20
|
+
const BARE_DOMAIN_RE = new RegExp(`(?<![/@\\w])([a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.(?:${KNOWN_TLDS})(?:\\/[^\\s<]*[^\\s.,;:!?'"\\)\\]}<])?)`, 'g');
|
|
21
|
+
export function linkifyText(text) {
|
|
22
|
+
// Pass 1: extract protected zones
|
|
23
|
+
const placeholders = [];
|
|
24
|
+
let processed = text.replace(PROTECTED_RE, (match) => {
|
|
25
|
+
const idx = placeholders.length;
|
|
26
|
+
placeholders.push(match);
|
|
27
|
+
return `\x00PROTECTED${idx}\x00`;
|
|
28
|
+
});
|
|
29
|
+
// Pass 2: linkify URLs (protocol first, then www, then bare domains)
|
|
30
|
+
processed = processed.replace(PROTOCOL_URL_RE, (url) => {
|
|
31
|
+
const idx = placeholders.length;
|
|
32
|
+
placeholders.push(`[${url}](${url})`);
|
|
33
|
+
return `\x00PROTECTED${idx}\x00`;
|
|
34
|
+
});
|
|
35
|
+
processed = processed.replace(WWW_URL_RE, (url) => {
|
|
36
|
+
const idx = placeholders.length;
|
|
37
|
+
placeholders.push(`[${url}](https://${url})`);
|
|
38
|
+
return `\x00PROTECTED${idx}\x00`;
|
|
39
|
+
});
|
|
40
|
+
processed = processed.replace(BARE_DOMAIN_RE, (url) => {
|
|
41
|
+
const idx = placeholders.length;
|
|
42
|
+
placeholders.push(`[${url}](https://${url})`);
|
|
43
|
+
return `\x00PROTECTED${idx}\x00`;
|
|
44
|
+
});
|
|
45
|
+
// Pass 3: restore protected content
|
|
46
|
+
processed = processed.replace(/\x00PROTECTED(\d+)\x00/g, (_, idx) => {
|
|
47
|
+
return placeholders[Number(idx)];
|
|
48
|
+
});
|
|
49
|
+
return processed;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=linkify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkify.js","sourceRoot":"","sources":["../../src/lib/linkify.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,UAAU,GACd,oFAAoF,CAAA;AAEtF,gDAAgD;AAChD,MAAM,YAAY,GAAG,IAAI,MAAM,CAC7B;IACE,kBAAkB,EAAY,qBAAqB;IACnD,SAAS,EAAsB,cAAc;IAC7C,2BAA2B,EAAI,kBAAkB;IACjD,0BAA0B,EAAK,iBAAiB;CACjD,CAAC,IAAI,CAAC,GAAG,CAAC,EACX,GAAG,CACJ,CAAA;AAED,eAAe;AACf,MAAM,eAAe,GAAG,uCAAuC,CAAA;AAC/D,MAAM,UAAU,GAAG,2CAA2C,CAAA;AAC9D,MAAM,cAAc,GAAG,IAAI,MAAM,CAC/B,8DAA8D,UAAU,0CAA0C,EAClH,GAAG,CACJ,CAAA;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,kCAAkC;IAClC,MAAM,YAAY,GAAa,EAAE,CAAA;IACjC,IAAI,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE;QACnD,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAA;QAC/B,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxB,OAAO,gBAAgB,GAAG,MAAM,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,qEAAqE;IACrE,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE;QACrD,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAA;QAC/B,YAAY,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,GAAG,GAAG,CAAC,CAAA;QACrC,OAAO,gBAAgB,GAAG,MAAM,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE;QAChD,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAA;QAC/B,YAAY,CAAC,IAAI,CAAC,IAAI,GAAG,aAAa,GAAG,GAAG,CAAC,CAAA;QAC7C,OAAO,gBAAgB,GAAG,MAAM,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE;QACpD,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAA;QAC/B,YAAY,CAAC,IAAI,CAAC,IAAI,GAAG,aAAa,GAAG,GAAG,CAAC,CAAA;QAC7C,OAAO,gBAAgB,GAAG,MAAM,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,oCAAoC;IACpC,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAClE,OAAO,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,OAAO,SAAS,CAAA;AAClB,CAAC"}
|