@oxyhq/services 5.7.3 → 5.7.4
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/README.md +287 -80
- package/lib/commonjs/node/index.js +49 -2
- package/lib/commonjs/node/index.js.map +1 -1
- package/lib/commonjs/node/middleware.js +227 -0
- package/lib/commonjs/node/middleware.js.map +1 -0
- package/lib/commonjs/ui/index.js +16 -1
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/zero-config/index.js +25 -0
- package/lib/commonjs/ui/zero-config/index.js.map +1 -0
- package/lib/commonjs/ui/zero-config/provider.js +278 -0
- package/lib/commonjs/ui/zero-config/provider.js.map +1 -0
- package/lib/module/node/index.js +11 -1
- package/lib/module/node/index.js.map +1 -1
- package/lib/module/node/middleware.js +199 -0
- package/lib/module/node/middleware.js.map +1 -0
- package/lib/module/ui/index.js +16 -1
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/zero-config/index.js +8 -0
- package/lib/module/ui/zero-config/index.js.map +1 -0
- package/lib/module/ui/zero-config/provider.js +270 -0
- package/lib/module/ui/zero-config/provider.js.map +1 -0
- package/lib/typescript/node/index.d.ts +7 -1
- package/lib/typescript/node/index.d.ts.map +1 -1
- package/lib/typescript/node/middleware.d.ts +92 -0
- package/lib/typescript/node/middleware.d.ts.map +1 -0
- package/lib/typescript/ui/index.d.ts +2 -1
- package/lib/typescript/ui/index.d.ts.map +1 -1
- package/lib/typescript/ui/zero-config/index.d.ts +5 -0
- package/lib/typescript/ui/zero-config/index.d.ts.map +1 -0
- package/lib/typescript/ui/zero-config/provider.d.ts +84 -0
- package/lib/typescript/ui/zero-config/provider.d.ts.map +1 -0
- package/package.json +6 -1
- package/src/node/index.ts +17 -1
- package/src/node/middleware.ts +234 -0
- package/src/ui/index.ts +19 -1
- package/src/ui/zero-config/index.ts +11 -0
- package/src/ui/zero-config/provider.tsx +310 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-config Express middleware for OxyHQ Services authentication
|
|
3
|
+
*
|
|
4
|
+
* This provides a simple, one-line solution for adding authentication to Express apps.
|
|
5
|
+
* Simply import and use: app.use('/api', createOxyAuth())
|
|
6
|
+
*/
|
|
7
|
+
import { ApiError } from '../models/interfaces';
|
|
8
|
+
export interface OxyAuthConfig {
|
|
9
|
+
/** Base URL of your Oxy API server */
|
|
10
|
+
baseURL?: string;
|
|
11
|
+
/** Whether to load full user data (default: true) */
|
|
12
|
+
loadUser?: boolean;
|
|
13
|
+
/** Routes that don't require authentication */
|
|
14
|
+
publicPaths?: string[];
|
|
15
|
+
/** Custom error handler */
|
|
16
|
+
onError?: (error: ApiError, req: any, res: any) => void;
|
|
17
|
+
}
|
|
18
|
+
export interface AuthenticatedRequest {
|
|
19
|
+
user?: any;
|
|
20
|
+
userId?: string;
|
|
21
|
+
accessToken?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates zero-config authentication middleware for Express.js
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import express from 'express';
|
|
29
|
+
* import { createOxyAuth } from '@oxyhq/services/node';
|
|
30
|
+
*
|
|
31
|
+
* const app = express();
|
|
32
|
+
*
|
|
33
|
+
* // Zero-config auth for all /api routes
|
|
34
|
+
* app.use('/api', createOxyAuth());
|
|
35
|
+
*
|
|
36
|
+
* // Now all routes under /api automatically have req.user available
|
|
37
|
+
* app.get('/api/profile', (req, res) => {
|
|
38
|
+
* res.json({ user: req.user }); // req.user is automatically available
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function createOxyAuth(config?: OxyAuthConfig): (req: any, res: any, next: any) => Promise<any>;
|
|
43
|
+
/**
|
|
44
|
+
* Creates optional authentication middleware
|
|
45
|
+
* This middleware will attach user data if a valid token is present, but won't fail if missing
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* import { createOptionalOxyAuth } from '@oxyhq/services/node';
|
|
50
|
+
*
|
|
51
|
+
* app.use('/api', createOptionalOxyAuth());
|
|
52
|
+
*
|
|
53
|
+
* app.get('/api/content', (req, res) => {
|
|
54
|
+
* if (req.user) {
|
|
55
|
+
* // User is authenticated, show personalized content
|
|
56
|
+
* res.json({ content: 'personalized', user: req.user });
|
|
57
|
+
* } else {
|
|
58
|
+
* // Anonymous user, show public content
|
|
59
|
+
* res.json({ content: 'public' });
|
|
60
|
+
* }
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function createOptionalOxyAuth(config?: OxyAuthConfig): (req: any, res: any, next: any) => Promise<any>;
|
|
65
|
+
/**
|
|
66
|
+
* Utility function to quickly set up a complete Express app with authentication
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* import { createOxyExpressApp } from '@oxyhq/services/node';
|
|
71
|
+
*
|
|
72
|
+
* const app = createOxyExpressApp();
|
|
73
|
+
*
|
|
74
|
+
* // All routes automatically have authentication and req.user available
|
|
75
|
+
* app.get('/api/profile', (req, res) => {
|
|
76
|
+
* res.json({ user: req.user });
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* app.listen(3000);
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function createOxyExpressApp(config?: OxyAuthConfig & {
|
|
83
|
+
/** Express app configuration */
|
|
84
|
+
cors?: boolean;
|
|
85
|
+
/** JSON body parser limit */
|
|
86
|
+
jsonLimit?: string;
|
|
87
|
+
/** Additional middleware to apply */
|
|
88
|
+
middleware?: any[];
|
|
89
|
+
}): void;
|
|
90
|
+
export { OxyServices } from '../core';
|
|
91
|
+
export * from '../models/interfaces';
|
|
92
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/node/middleware.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;CACzD;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAE,aAAkB,IAUxC,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,kBA+E5C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,aAAkB,IAQhD,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,kBAgC5C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,GAAE,aAAa,GAAG;IAC1D,gCAAgC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC;CACf,QAKL;AAGD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,cAAc,sBAAsB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
declare let OxyProvider: any, OxySignInButton: any, OxyLogo: any, Avatar: any, FollowButton: any, OxyPayButton: any, FontLoader: any, setupFonts: any, OxyIcon: any, useOxy: any, OxyContextProvider: any, OxyContextState: any, OxyContextProviderProps: any, useFollow: any, ProfileScreen: any, OxyRouter: any, useAuthStore: any, fontFamilies: any, fontStyles: any, toast: any;
|
|
2
|
-
|
|
2
|
+
declare let OxyZeroConfigProvider: any, useOxyZeroConfig: any, useOxyApi: any;
|
|
3
|
+
export { OxyProvider, OxySignInButton, OxyLogo, Avatar, FollowButton, OxyPayButton, FontLoader, setupFonts, OxyIcon, useOxy, OxyContextProvider, OxyContextState, OxyContextProviderProps, useFollow, ProfileScreen, OxyRouter, useAuthStore, fontFamilies, fontStyles, toast, OxyZeroConfigProvider, useOxyZeroConfig, useOxyApi };
|
|
3
4
|
export { OxyServices } from '../core';
|
|
4
5
|
export type { User, LoginResponse, ApiError } from '../models/interfaces';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/index.ts"],"names":[],"mappings":"AASA,QAAA,IAAI,WAAW,KAAA,EAAE,eAAe,KAAA,EAAE,OAAO,KAAA,EAAE,MAAM,KAAA,EAAE,YAAY,KAAA,EAAE,YAAY,KAAA,EAAE,UAAU,KAAA,EAAE,UAAU,KAAA,EAAE,OAAO,KAAA,EAAE,MAAM,KAAA,EAA8H,kBAAkB,KAAA,EAAE,eAAe,KAAA,EAAE,uBAAuB,KAAA,EAAE,SAAS,KAAA,EAAE,aAAa,KAAA,EAAE,SAAS,KAAA,EAAE,YAAY,KAAA,EAAE,YAAY,KAAA,EAAE,UAAU,KAAA,EAAE,KAAK,KAAA,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/index.ts"],"names":[],"mappings":"AASA,QAAA,IAAI,WAAW,KAAA,EAAE,eAAe,KAAA,EAAE,OAAO,KAAA,EAAE,MAAM,KAAA,EAAE,YAAY,KAAA,EAAE,YAAY,KAAA,EAAE,UAAU,KAAA,EAAE,UAAU,KAAA,EAAE,OAAO,KAAA,EAAE,MAAM,KAAA,EAA8H,kBAAkB,KAAA,EAAE,eAAe,KAAA,EAAE,uBAAuB,KAAA,EAAE,SAAS,KAAA,EAAE,aAAa,KAAA,EAAE,SAAS,KAAA,EAAE,YAAY,KAAA,EAAE,YAAY,KAAA,EAAE,UAAU,KAAA,EAAE,KAAK,KAAA,CAAC;AAGrY,QAAA,IAAI,qBAAqB,KAAA,EAAE,gBAAgB,KAAA,EAAE,SAAS,KAAA,CAAC;AA2DvD,OAAO,EACL,WAAW,EACX,eAAe,EACf,OAAO,EACP,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,OAAO,EACP,MAAM,EACN,kBAAkB,EAClB,eAAe,EACf,uBAAuB,EACvB,SAAS,EACT,aAAa,EACb,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,KAAK,EAGL,qBAAqB,EACrB,gBAAgB,EAChB,SAAS,EACV,CAAC;AAGF,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/zero-config/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAChC,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-config OxyHQ Provider and Hook for React/React Native
|
|
3
|
+
*
|
|
4
|
+
* This provides a simplified, one-line setup for frontend authentication
|
|
5
|
+
* with automatic token management and API integration.
|
|
6
|
+
*/
|
|
7
|
+
import React, { ReactNode } from 'react';
|
|
8
|
+
import { OxyServices } from '../../core';
|
|
9
|
+
import { User } from '../../models/interfaces';
|
|
10
|
+
export interface OxyZeroConfigState {
|
|
11
|
+
user: User | null;
|
|
12
|
+
isAuthenticated: boolean;
|
|
13
|
+
isLoading: boolean;
|
|
14
|
+
error: string | null;
|
|
15
|
+
login: (username: string, password: string) => Promise<User>;
|
|
16
|
+
logout: () => Promise<void>;
|
|
17
|
+
register: (username: string, email: string, password: string) => Promise<User>;
|
|
18
|
+
api: OxyServices;
|
|
19
|
+
}
|
|
20
|
+
export interface OxyZeroConfigProviderProps {
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
/** Base URL of your Oxy API server (defaults to process.env.REACT_APP_OXY_API_URL or http://localhost:3001) */
|
|
23
|
+
apiUrl?: string;
|
|
24
|
+
/** Called when authentication state changes */
|
|
25
|
+
onAuthChange?: (user: User | null) => void;
|
|
26
|
+
/** Storage key prefix (default: 'oxy_zero') */
|
|
27
|
+
storagePrefix?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Zero-config provider for OxyHQ Services
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* import { OxyZeroConfigProvider } from '@oxyhq/services/ui';
|
|
35
|
+
*
|
|
36
|
+
* function App() {
|
|
37
|
+
* return (
|
|
38
|
+
* <OxyZeroConfigProvider>
|
|
39
|
+
* <MyApp />
|
|
40
|
+
* </OxyZeroConfigProvider>
|
|
41
|
+
* );
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare const OxyZeroConfigProvider: React.FC<OxyZeroConfigProviderProps>;
|
|
46
|
+
/**
|
|
47
|
+
* Zero-config hook for OxyHQ Services
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```tsx
|
|
51
|
+
* function MyComponent() {
|
|
52
|
+
* const { user, login, logout, isAuthenticated } = useOxyZeroConfig();
|
|
53
|
+
*
|
|
54
|
+
* const handleLogin = () => {
|
|
55
|
+
* login('username', 'password');
|
|
56
|
+
* };
|
|
57
|
+
*
|
|
58
|
+
* if (isAuthenticated) {
|
|
59
|
+
* return <div>Welcome, {user?.username}!</div>;
|
|
60
|
+
* }
|
|
61
|
+
*
|
|
62
|
+
* return <button onClick={handleLogin}>Login</button>;
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare const useOxyZeroConfig: () => OxyZeroConfigState;
|
|
67
|
+
/**
|
|
68
|
+
* Hook for automatic API client with authentication
|
|
69
|
+
* This automatically includes the auth token in requests
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* function ProfileComponent() {
|
|
74
|
+
* const api = useOxyApi();
|
|
75
|
+
*
|
|
76
|
+
* const updateProfile = async (data) => {
|
|
77
|
+
* const user = await api.updateProfile(data);
|
|
78
|
+
* // Token is automatically included
|
|
79
|
+
* };
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare const useOxyApi: () => OxyServices;
|
|
84
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../../src/ui/zero-config/provider.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,EAAkD,SAAS,EAAe,MAAM,OAAO,CAAC;AACtG,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,IAAI,EAAiB,MAAM,yBAAyB,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IAEjC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAGrB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAG/E,GAAG,EAAE,WAAW,CAAC;CAClB;AAID,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,SAAS,CAAC;IACpB,+GAA+G;IAC/G,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAC3C,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CA6MtE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,gBAAgB,QAAO,kBAMnC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,QAAO,WAG5B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/services",
|
|
3
|
-
"version": "5.7.
|
|
3
|
+
"version": "5.7.4",
|
|
4
4
|
"description": "Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"require": "./lib/commonjs/ui/index.js",
|
|
24
24
|
"types": "./lib/typescript/ui/index.d.ts"
|
|
25
25
|
},
|
|
26
|
+
"./node": {
|
|
27
|
+
"import": "./lib/module/node/index.js",
|
|
28
|
+
"require": "./lib/commonjs/node/index.js",
|
|
29
|
+
"types": "./lib/typescript/node/index.d.ts"
|
|
30
|
+
},
|
|
26
31
|
"./full": {
|
|
27
32
|
"import": "./lib/module/index.js",
|
|
28
33
|
"require": "./lib/commonjs/index.js",
|
package/src/node/index.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Node.js-specific exports for OxyHQ Services
|
|
3
|
+
*
|
|
4
|
+
* This module provides zero-config Express.js middleware and utilities
|
|
5
|
+
* for backend integration with OxyHQ Services.
|
|
3
6
|
*/
|
|
4
7
|
|
|
8
|
+
// Export the zero-config middleware
|
|
9
|
+
export {
|
|
10
|
+
createOxyAuth,
|
|
11
|
+
createOptionalOxyAuth,
|
|
12
|
+
createOxyExpressApp,
|
|
13
|
+
type OxyAuthConfig,
|
|
14
|
+
type AuthenticatedRequest
|
|
15
|
+
} from './middleware';
|
|
16
|
+
|
|
5
17
|
// ------------- Core Imports -------------
|
|
6
18
|
import { OxyServices, OXY_CLOUD_URL } from '../core'; // Adjusted path
|
|
7
19
|
import { createAuth } from './createAuth';
|
|
@@ -16,6 +28,10 @@ export { createAuth };
|
|
|
16
28
|
// ------------- Model Exports -------------
|
|
17
29
|
export { Models }; // Export all models as a namespace
|
|
18
30
|
export * from '../models/interfaces'; // Export all models directly
|
|
31
|
+
export * from '../models/secureSession';
|
|
32
|
+
|
|
33
|
+
// Re-export utilities
|
|
34
|
+
export { DeviceManager } from '../utils/deviceManager';
|
|
19
35
|
|
|
20
36
|
// Default export for consistency or specific use cases if needed
|
|
21
37
|
export default OxyServices;
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-config Express middleware for OxyHQ Services authentication
|
|
3
|
+
*
|
|
4
|
+
* This provides a simple, one-line solution for adding authentication to Express apps.
|
|
5
|
+
* Simply import and use: app.use('/api', createOxyAuth())
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { OxyServices } from '../core';
|
|
9
|
+
import { ApiError } from '../models/interfaces';
|
|
10
|
+
|
|
11
|
+
export interface OxyAuthConfig {
|
|
12
|
+
/** Base URL of your Oxy API server */
|
|
13
|
+
baseURL?: string;
|
|
14
|
+
/** Whether to load full user data (default: true) */
|
|
15
|
+
loadUser?: boolean;
|
|
16
|
+
/** Routes that don't require authentication */
|
|
17
|
+
publicPaths?: string[];
|
|
18
|
+
/** Custom error handler */
|
|
19
|
+
onError?: (error: ApiError, req: any, res: any) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AuthenticatedRequest {
|
|
23
|
+
user?: any;
|
|
24
|
+
userId?: string;
|
|
25
|
+
accessToken?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates zero-config authentication middleware for Express.js
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import express from 'express';
|
|
34
|
+
* import { createOxyAuth } from '@oxyhq/services/node';
|
|
35
|
+
*
|
|
36
|
+
* const app = express();
|
|
37
|
+
*
|
|
38
|
+
* // Zero-config auth for all /api routes
|
|
39
|
+
* app.use('/api', createOxyAuth());
|
|
40
|
+
*
|
|
41
|
+
* // Now all routes under /api automatically have req.user available
|
|
42
|
+
* app.get('/api/profile', (req, res) => {
|
|
43
|
+
* res.json({ user: req.user }); // req.user is automatically available
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function createOxyAuth(config: OxyAuthConfig = {}) {
|
|
48
|
+
const {
|
|
49
|
+
baseURL = process.env.OXY_API_URL || 'http://localhost:3001',
|
|
50
|
+
loadUser = true,
|
|
51
|
+
publicPaths = [],
|
|
52
|
+
onError
|
|
53
|
+
} = config;
|
|
54
|
+
|
|
55
|
+
const oxy = new OxyServices({ baseURL });
|
|
56
|
+
|
|
57
|
+
return async (req: any, res: any, next: any) => {
|
|
58
|
+
// Check if this is a public path
|
|
59
|
+
const isPublicPath = publicPaths.some(path =>
|
|
60
|
+
req.path === path || req.path.startsWith(path + '/')
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (isPublicPath) {
|
|
64
|
+
return next();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const authHeader = req.headers['authorization'];
|
|
69
|
+
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
70
|
+
|
|
71
|
+
if (!token) {
|
|
72
|
+
const error: ApiError = {
|
|
73
|
+
message: 'Access token required',
|
|
74
|
+
code: 'MISSING_TOKEN',
|
|
75
|
+
status: 401
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
if (onError) {
|
|
79
|
+
return onError(error, req, res);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return res.status(401).json({
|
|
83
|
+
error: 'Access token required',
|
|
84
|
+
code: 'MISSING_TOKEN'
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Validate token using the OxyServices client
|
|
89
|
+
const authResult = await oxy.authenticateToken(token);
|
|
90
|
+
|
|
91
|
+
if (!authResult.valid) {
|
|
92
|
+
const error: ApiError = {
|
|
93
|
+
message: authResult.error || 'Invalid token',
|
|
94
|
+
code: 'INVALID_TOKEN',
|
|
95
|
+
status: 403
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (onError) {
|
|
99
|
+
return onError(error, req, res);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return res.status(403).json({
|
|
103
|
+
error: authResult.error || 'Invalid token',
|
|
104
|
+
code: 'INVALID_TOKEN'
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Attach user data to request
|
|
109
|
+
req.userId = authResult.userId;
|
|
110
|
+
req.accessToken = token;
|
|
111
|
+
|
|
112
|
+
if (loadUser && authResult.user) {
|
|
113
|
+
req.user = authResult.user;
|
|
114
|
+
} else {
|
|
115
|
+
req.user = { id: authResult.userId };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
next();
|
|
119
|
+
} catch (error: any) {
|
|
120
|
+
const apiError: ApiError = {
|
|
121
|
+
message: error.message || 'Authentication failed',
|
|
122
|
+
code: error.code || 'AUTH_ERROR',
|
|
123
|
+
status: error.status || 500
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
if (onError) {
|
|
127
|
+
return onError(apiError, req, res);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
res.status(apiError.status).json({
|
|
131
|
+
error: apiError.message,
|
|
132
|
+
code: apiError.code
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Creates optional authentication middleware
|
|
140
|
+
* This middleware will attach user data if a valid token is present, but won't fail if missing
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* import { createOptionalOxyAuth } from '@oxyhq/services/node';
|
|
145
|
+
*
|
|
146
|
+
* app.use('/api', createOptionalOxyAuth());
|
|
147
|
+
*
|
|
148
|
+
* app.get('/api/content', (req, res) => {
|
|
149
|
+
* if (req.user) {
|
|
150
|
+
* // User is authenticated, show personalized content
|
|
151
|
+
* res.json({ content: 'personalized', user: req.user });
|
|
152
|
+
* } else {
|
|
153
|
+
* // Anonymous user, show public content
|
|
154
|
+
* res.json({ content: 'public' });
|
|
155
|
+
* }
|
|
156
|
+
* });
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function createOptionalOxyAuth(config: OxyAuthConfig = {}) {
|
|
160
|
+
const {
|
|
161
|
+
baseURL = process.env.OXY_API_URL || 'http://localhost:3001',
|
|
162
|
+
loadUser = true
|
|
163
|
+
} = config;
|
|
164
|
+
|
|
165
|
+
const oxy = new OxyServices({ baseURL });
|
|
166
|
+
|
|
167
|
+
return async (req: any, res: any, next: any) => {
|
|
168
|
+
try {
|
|
169
|
+
const authHeader = req.headers['authorization'];
|
|
170
|
+
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
171
|
+
|
|
172
|
+
if (!token) {
|
|
173
|
+
// No token provided, continue without authentication
|
|
174
|
+
return next();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Validate token using the OxyServices client
|
|
178
|
+
const authResult = await oxy.authenticateToken(token);
|
|
179
|
+
|
|
180
|
+
if (authResult.valid) {
|
|
181
|
+
// Attach user data to request if token is valid
|
|
182
|
+
req.userId = authResult.userId;
|
|
183
|
+
req.accessToken = token;
|
|
184
|
+
|
|
185
|
+
if (loadUser && authResult.user) {
|
|
186
|
+
req.user = authResult.user;
|
|
187
|
+
} else {
|
|
188
|
+
req.user = { id: authResult.userId };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
next();
|
|
193
|
+
} catch (error) {
|
|
194
|
+
// If there's an error, continue without authentication
|
|
195
|
+
// This makes the middleware truly optional
|
|
196
|
+
next();
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Utility function to quickly set up a complete Express app with authentication
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* import { createOxyExpressApp } from '@oxyhq/services/node';
|
|
207
|
+
*
|
|
208
|
+
* const app = createOxyExpressApp();
|
|
209
|
+
*
|
|
210
|
+
* // All routes automatically have authentication and req.user available
|
|
211
|
+
* app.get('/api/profile', (req, res) => {
|
|
212
|
+
* res.json({ user: req.user });
|
|
213
|
+
* });
|
|
214
|
+
*
|
|
215
|
+
* app.listen(3000);
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export function createOxyExpressApp(config: OxyAuthConfig & {
|
|
219
|
+
/** Express app configuration */
|
|
220
|
+
cors?: boolean;
|
|
221
|
+
/** JSON body parser limit */
|
|
222
|
+
jsonLimit?: string;
|
|
223
|
+
/** Additional middleware to apply */
|
|
224
|
+
middleware?: any[];
|
|
225
|
+
} = {}) {
|
|
226
|
+
// This is a lightweight helper - users should import express themselves
|
|
227
|
+
// We'll provide the middleware setup instructions instead
|
|
228
|
+
|
|
229
|
+
throw new Error('createOxyExpressApp is not implemented yet. Please use createOxyAuth() middleware with your existing Express app.');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Re-export for convenience
|
|
233
|
+
export { OxyServices } from '../core';
|
|
234
|
+
export * from '../models/interfaces';
|
package/src/ui/index.ts
CHANGED
|
@@ -9,6 +9,9 @@ import isFrontend from './isFrontend';
|
|
|
9
9
|
// Real UI exports
|
|
10
10
|
let OxyProvider, OxySignInButton, OxyLogo, Avatar, FollowButton, OxyPayButton, FontLoader, setupFonts, OxyIcon, useOxy, useOxyAuth, useOxyUser, useOxyKarma, useOxyPayments, useOxyDevices, useOxyNotifications, useOxySocket, useOxyQR, useOxyIAP, OxyContextProvider, OxyContextState, OxyContextProviderProps, useFollow, ProfileScreen, OxyRouter, useAuthStore, fontFamilies, fontStyles, toast;
|
|
11
11
|
|
|
12
|
+
// Zero-config exports
|
|
13
|
+
let OxyZeroConfigProvider, useOxyZeroConfig, useOxyApi;
|
|
14
|
+
|
|
12
15
|
if (isFrontend) {
|
|
13
16
|
OxyProvider = require('./components/OxyProvider').default;
|
|
14
17
|
OxySignInButton = require('./components/OxySignInButton').default;
|
|
@@ -30,6 +33,11 @@ if (isFrontend) {
|
|
|
30
33
|
fontFamilies = require('./styles/fonts').fontFamilies;
|
|
31
34
|
fontStyles = require('./styles/fonts').fontStyles;
|
|
32
35
|
toast = require('../lib/sonner').toast;
|
|
36
|
+
|
|
37
|
+
// Zero-config components
|
|
38
|
+
OxyZeroConfigProvider = require('./zero-config').OxyZeroConfigProvider;
|
|
39
|
+
useOxyZeroConfig = require('./zero-config').useOxyZeroConfig;
|
|
40
|
+
useOxyApi = require('./zero-config').useOxyApi;
|
|
33
41
|
} else {
|
|
34
42
|
// Backend: no-op fallbacks
|
|
35
43
|
const noopComponent = () => null;
|
|
@@ -54,6 +62,11 @@ if (isFrontend) {
|
|
|
54
62
|
fontFamilies = {};
|
|
55
63
|
fontStyles = {};
|
|
56
64
|
toast = () => {};
|
|
65
|
+
|
|
66
|
+
// Zero-config no-ops
|
|
67
|
+
OxyZeroConfigProvider = noopComponent;
|
|
68
|
+
useOxyZeroConfig = noopHook;
|
|
69
|
+
useOxyApi = () => ({});
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
export {
|
|
@@ -76,7 +89,12 @@ export {
|
|
|
76
89
|
useAuthStore,
|
|
77
90
|
fontFamilies,
|
|
78
91
|
fontStyles,
|
|
79
|
-
toast
|
|
92
|
+
toast,
|
|
93
|
+
|
|
94
|
+
// Zero-config exports
|
|
95
|
+
OxyZeroConfigProvider,
|
|
96
|
+
useOxyZeroConfig,
|
|
97
|
+
useOxyApi
|
|
80
98
|
};
|
|
81
99
|
|
|
82
100
|
// Re-export core services for convenience in UI context
|