@oxyhq/core 1.11.0 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +5 -2
- package/dist/cjs/mixins/OxyServices.topics.js +123 -0
- package/dist/cjs/mixins/OxyServices.user.js +14 -3
- package/dist/cjs/mixins/index.js +2 -0
- package/dist/cjs/models/Topic.js +16 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/mixins/OxyServices.topics.js +120 -0
- package/dist/esm/mixins/OxyServices.user.js +14 -3
- package/dist/esm/mixins/index.js +2 -0
- package/dist/esm/models/Topic.js +13 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/mixins/OxyServices.topics.d.ts +106 -0
- package/dist/types/mixins/OxyServices.user.d.ts +19 -2
- package/dist/types/models/Topic.d.ts +32 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/mixins/OxyServices.topics.ts +135 -0
- package/src/mixins/OxyServices.user.ts +26 -3
- package/src/mixins/index.ts +2 -0
- package/src/models/Topic.ts +35 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Topics Methods Mixin
|
|
3
|
+
*
|
|
4
|
+
* Provides methods for topic discovery and management
|
|
5
|
+
*/
|
|
6
|
+
import type { OxyServicesBase } from '../OxyServices.base';
|
|
7
|
+
import type { TopicData, TopicTranslation } from '../models/Topic';
|
|
8
|
+
export declare function OxyServicesTopicsMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
9
|
+
new (...args: any[]): {
|
|
10
|
+
/**
|
|
11
|
+
* Get top-level topic categories
|
|
12
|
+
* @param locale - Optional locale for translated results
|
|
13
|
+
* @returns List of category topics
|
|
14
|
+
*/
|
|
15
|
+
getTopicCategories(locale?: string): Promise<TopicData[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Search topics by query string
|
|
18
|
+
* @param query - Search query
|
|
19
|
+
* @param limit - Optional result limit
|
|
20
|
+
* @returns Matching topics
|
|
21
|
+
*/
|
|
22
|
+
searchTopics(query: string, limit?: number): Promise<TopicData[]>;
|
|
23
|
+
/**
|
|
24
|
+
* List topics with optional filters
|
|
25
|
+
* @param options - Filter and pagination options
|
|
26
|
+
* @returns List of topics
|
|
27
|
+
*/
|
|
28
|
+
listTopics(options?: {
|
|
29
|
+
type?: string;
|
|
30
|
+
q?: string;
|
|
31
|
+
limit?: number;
|
|
32
|
+
offset?: number;
|
|
33
|
+
locale?: string;
|
|
34
|
+
}): Promise<TopicData[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Get a single topic by slug
|
|
37
|
+
* @param slug - Topic slug
|
|
38
|
+
* @returns Topic data
|
|
39
|
+
*/
|
|
40
|
+
getTopicBySlug(slug: string): Promise<TopicData>;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve an array of topic names to existing or newly created topics
|
|
43
|
+
* @param names - Array of { name, type } objects to resolve
|
|
44
|
+
* @returns Resolved topic data
|
|
45
|
+
*/
|
|
46
|
+
resolveTopicNames(names: Array<{
|
|
47
|
+
name: string;
|
|
48
|
+
type: string;
|
|
49
|
+
}>): Promise<TopicData[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Update metadata for a topic
|
|
52
|
+
* @param slug - Topic slug
|
|
53
|
+
* @param data - Metadata fields to update
|
|
54
|
+
* @returns Updated topic data
|
|
55
|
+
*/
|
|
56
|
+
updateTopicMetadata(slug: string, data: {
|
|
57
|
+
description?: string;
|
|
58
|
+
translations?: Record<string, TopicTranslation>;
|
|
59
|
+
}): Promise<TopicData>;
|
|
60
|
+
httpService: import("../HttpService").HttpService;
|
|
61
|
+
cloudURL: string;
|
|
62
|
+
config: import("../OxyServices.base").OxyConfig;
|
|
63
|
+
__resetTokensForTests(): void;
|
|
64
|
+
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
65
|
+
getBaseURL(): string;
|
|
66
|
+
getClient(): import("../HttpService").HttpService;
|
|
67
|
+
getMetrics(): {
|
|
68
|
+
totalRequests: number;
|
|
69
|
+
successfulRequests: number;
|
|
70
|
+
failedRequests: number;
|
|
71
|
+
cacheHits: number;
|
|
72
|
+
cacheMisses: number;
|
|
73
|
+
averageResponseTime: number;
|
|
74
|
+
};
|
|
75
|
+
clearCache(): void;
|
|
76
|
+
clearCacheEntry(key: string): void;
|
|
77
|
+
getCacheStats(): {
|
|
78
|
+
size: number;
|
|
79
|
+
hits: number;
|
|
80
|
+
misses: number;
|
|
81
|
+
hitRate: number;
|
|
82
|
+
};
|
|
83
|
+
getCloudURL(): string;
|
|
84
|
+
setTokens(accessToken: string, refreshToken?: string): void;
|
|
85
|
+
clearTokens(): void;
|
|
86
|
+
_cachedUserId: string | null | undefined;
|
|
87
|
+
_cachedAccessToken: string | null;
|
|
88
|
+
getCurrentUserId(): string | null;
|
|
89
|
+
hasValidToken(): boolean;
|
|
90
|
+
getAccessToken(): string | null;
|
|
91
|
+
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
92
|
+
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
93
|
+
maxRetries?: number;
|
|
94
|
+
retryDelay?: number;
|
|
95
|
+
authTimeoutMs?: number;
|
|
96
|
+
}): Promise<T_1>;
|
|
97
|
+
validate(): Promise<boolean>;
|
|
98
|
+
handleError(error: unknown): Error;
|
|
99
|
+
healthCheck(): Promise<{
|
|
100
|
+
status: string;
|
|
101
|
+
users?: number;
|
|
102
|
+
timestamp?: string;
|
|
103
|
+
[key: string]: any;
|
|
104
|
+
}>;
|
|
105
|
+
};
|
|
106
|
+
} & T;
|
|
@@ -21,9 +21,26 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
21
21
|
*/
|
|
22
22
|
resolveProfile(handle: string): Promise<User | null>;
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
24
|
+
* Resolve (find or create) a non-local user. All user creation for
|
|
25
|
+
* external accounts (federated, agent, automated) goes through this
|
|
26
|
+
* method — calling services never write user data directly.
|
|
25
27
|
*/
|
|
26
|
-
|
|
28
|
+
resolveExternalUser(data: {
|
|
29
|
+
type: "federated" | "agent" | "automated";
|
|
30
|
+
username: string;
|
|
31
|
+
actorUri?: string;
|
|
32
|
+
domain?: string;
|
|
33
|
+
displayName?: string;
|
|
34
|
+
avatar?: string;
|
|
35
|
+
bio?: string;
|
|
36
|
+
ownerId?: string;
|
|
37
|
+
}): Promise<User>;
|
|
38
|
+
/**
|
|
39
|
+
* Get profile recommendations, optionally filtering out specific user types.
|
|
40
|
+
*/
|
|
41
|
+
getProfileRecommendations(options?: {
|
|
42
|
+
excludeTypes?: Array<"federated" | "agent" | "automated">;
|
|
43
|
+
}): Promise<Array<{
|
|
27
44
|
id: string;
|
|
28
45
|
username: string;
|
|
29
46
|
name?: {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare enum TopicType {
|
|
2
|
+
CATEGORY = "category",
|
|
3
|
+
TOPIC = "topic",
|
|
4
|
+
ENTITY = "entity"
|
|
5
|
+
}
|
|
6
|
+
export declare enum TopicSource {
|
|
7
|
+
SEED = "seed",
|
|
8
|
+
AI = "ai",
|
|
9
|
+
MANUAL = "manual",
|
|
10
|
+
SYSTEM = "system"
|
|
11
|
+
}
|
|
12
|
+
export interface TopicTranslation {
|
|
13
|
+
displayName: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface TopicData {
|
|
17
|
+
_id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
slug: string;
|
|
20
|
+
displayName: string;
|
|
21
|
+
description: string;
|
|
22
|
+
type: TopicType;
|
|
23
|
+
source: TopicSource;
|
|
24
|
+
aliases: string[];
|
|
25
|
+
parentTopicId?: string;
|
|
26
|
+
icon?: string;
|
|
27
|
+
image?: string;
|
|
28
|
+
isActive: boolean;
|
|
29
|
+
translations?: Record<string, TopicTranslation>;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
updatedAt: string;
|
|
32
|
+
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -40,6 +40,8 @@ export type { KeyPair, SignedMessage, AuthChallenge, RecoveryPhraseResult } from
|
|
|
40
40
|
// --- Models & Types ---
|
|
41
41
|
export * from './models/interfaces';
|
|
42
42
|
export * from './models/session';
|
|
43
|
+
export type { TopicData, TopicTranslation } from './models/Topic';
|
|
44
|
+
export { TopicType, TopicSource } from './models/Topic';
|
|
43
45
|
|
|
44
46
|
// --- Device Management ---
|
|
45
47
|
export { DeviceManager } from './utils/deviceManager';
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Topics Methods Mixin
|
|
3
|
+
*
|
|
4
|
+
* Provides methods for topic discovery and management
|
|
5
|
+
*/
|
|
6
|
+
import type { OxyServicesBase } from '../OxyServices.base';
|
|
7
|
+
import type { TopicData, TopicTranslation } from '../models/Topic';
|
|
8
|
+
import { CACHE_TIMES } from './mixinHelpers';
|
|
9
|
+
|
|
10
|
+
export function OxyServicesTopicsMixin<T extends typeof OxyServicesBase>(Base: T) {
|
|
11
|
+
return class extends Base {
|
|
12
|
+
constructor(...args: any[]) {
|
|
13
|
+
super(...(args as [any]));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get top-level topic categories
|
|
18
|
+
* @param locale - Optional locale for translated results
|
|
19
|
+
* @returns List of category topics
|
|
20
|
+
*/
|
|
21
|
+
async getTopicCategories(locale?: string): Promise<TopicData[]> {
|
|
22
|
+
try {
|
|
23
|
+
const params: Record<string, string> = {};
|
|
24
|
+
if (locale) params.locale = locale;
|
|
25
|
+
return await this.makeRequest('GET', '/topics/categories', params, {
|
|
26
|
+
cache: true,
|
|
27
|
+
cacheTTL: CACHE_TIMES.EXTRA_LONG,
|
|
28
|
+
});
|
|
29
|
+
} catch (error) {
|
|
30
|
+
throw this.handleError(error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Search topics by query string
|
|
36
|
+
* @param query - Search query
|
|
37
|
+
* @param limit - Optional result limit
|
|
38
|
+
* @returns Matching topics
|
|
39
|
+
*/
|
|
40
|
+
async searchTopics(query: string, limit?: number): Promise<TopicData[]> {
|
|
41
|
+
try {
|
|
42
|
+
const params: Record<string, string | number> = { q: query };
|
|
43
|
+
if (limit) params.limit = limit;
|
|
44
|
+
return await this.makeRequest('GET', '/topics/search', params, {
|
|
45
|
+
cache: false,
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
throw this.handleError(error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* List topics with optional filters
|
|
54
|
+
* @param options - Filter and pagination options
|
|
55
|
+
* @returns List of topics
|
|
56
|
+
*/
|
|
57
|
+
async listTopics(options?: {
|
|
58
|
+
type?: string;
|
|
59
|
+
q?: string;
|
|
60
|
+
limit?: number;
|
|
61
|
+
offset?: number;
|
|
62
|
+
locale?: string;
|
|
63
|
+
}): Promise<TopicData[]> {
|
|
64
|
+
try {
|
|
65
|
+
const params: Record<string, string | number> = {};
|
|
66
|
+
if (options?.type) params.type = options.type;
|
|
67
|
+
if (options?.q) params.q = options.q;
|
|
68
|
+
if (options?.limit) params.limit = options.limit;
|
|
69
|
+
if (options?.offset) params.offset = options.offset;
|
|
70
|
+
if (options?.locale) params.locale = options.locale;
|
|
71
|
+
return await this.makeRequest('GET', '/topics', params, {
|
|
72
|
+
cache: true,
|
|
73
|
+
cacheTTL: CACHE_TIMES.SHORT,
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw this.handleError(error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get a single topic by slug
|
|
82
|
+
* @param slug - Topic slug
|
|
83
|
+
* @returns Topic data
|
|
84
|
+
*/
|
|
85
|
+
async getTopicBySlug(slug: string): Promise<TopicData> {
|
|
86
|
+
try {
|
|
87
|
+
return await this.makeRequest('GET', `/topics/${slug}`, undefined, {
|
|
88
|
+
cache: true,
|
|
89
|
+
cacheTTL: CACHE_TIMES.LONG,
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
throw this.handleError(error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolve an array of topic names to existing or newly created topics
|
|
98
|
+
* @param names - Array of { name, type } objects to resolve
|
|
99
|
+
* @returns Resolved topic data
|
|
100
|
+
*/
|
|
101
|
+
async resolveTopicNames(
|
|
102
|
+
names: Array<{ name: string; type: string }>
|
|
103
|
+
): Promise<TopicData[]> {
|
|
104
|
+
try {
|
|
105
|
+
return await this.makeRequest('POST', '/topics/resolve', { names }, {
|
|
106
|
+
cache: false,
|
|
107
|
+
});
|
|
108
|
+
} catch (error) {
|
|
109
|
+
throw this.handleError(error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Update metadata for a topic
|
|
115
|
+
* @param slug - Topic slug
|
|
116
|
+
* @param data - Metadata fields to update
|
|
117
|
+
* @returns Updated topic data
|
|
118
|
+
*/
|
|
119
|
+
async updateTopicMetadata(
|
|
120
|
+
slug: string,
|
|
121
|
+
data: {
|
|
122
|
+
description?: string;
|
|
123
|
+
translations?: Record<string, TopicTranslation>;
|
|
124
|
+
}
|
|
125
|
+
): Promise<TopicData> {
|
|
126
|
+
try {
|
|
127
|
+
return await this.makeRequest('PATCH', `/topics/${slug}`, data, {
|
|
128
|
+
cache: false,
|
|
129
|
+
});
|
|
130
|
+
} catch (error) {
|
|
131
|
+
throw this.handleError(error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -105,9 +105,29 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
|
-
*
|
|
108
|
+
* Resolve (find or create) a non-local user. All user creation for
|
|
109
|
+
* external accounts (federated, agent, automated) goes through this
|
|
110
|
+
* method — calling services never write user data directly.
|
|
109
111
|
*/
|
|
110
|
-
async
|
|
112
|
+
async resolveExternalUser(data: {
|
|
113
|
+
type: 'federated' | 'agent' | 'automated';
|
|
114
|
+
username: string;
|
|
115
|
+
actorUri?: string;
|
|
116
|
+
domain?: string;
|
|
117
|
+
displayName?: string;
|
|
118
|
+
avatar?: string;
|
|
119
|
+
bio?: string;
|
|
120
|
+
ownerId?: string;
|
|
121
|
+
}): Promise<User> {
|
|
122
|
+
return this.makeRequest<User>('PUT', '/users/resolve', data);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get profile recommendations, optionally filtering out specific user types.
|
|
127
|
+
*/
|
|
128
|
+
async getProfileRecommendations(options?: {
|
|
129
|
+
excludeTypes?: Array<'federated' | 'agent' | 'automated'>;
|
|
130
|
+
}): Promise<Array<{
|
|
111
131
|
id: string;
|
|
112
132
|
username: string;
|
|
113
133
|
name?: { first?: string; last?: string; full?: string };
|
|
@@ -121,8 +141,11 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
121
141
|
_count?: { followers: number; following: number };
|
|
122
142
|
[key: string]: unknown;
|
|
123
143
|
}>> {
|
|
144
|
+
const params = options?.excludeTypes?.length
|
|
145
|
+
? { excludeTypes: options.excludeTypes.join(',') }
|
|
146
|
+
: undefined;
|
|
124
147
|
return this.withAuthRetry(async () => {
|
|
125
|
-
return await this.makeRequest('GET', '/profiles/recommendations',
|
|
148
|
+
return await this.makeRequest('GET', '/profiles/recommendations', params, { cache: true });
|
|
126
149
|
}, 'getProfileRecommendations');
|
|
127
150
|
}
|
|
128
151
|
|
package/src/mixins/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { OxyServicesDevicesMixin } from './OxyServices.devices';
|
|
|
23
23
|
import { OxyServicesSecurityMixin } from './OxyServices.security';
|
|
24
24
|
import { OxyServicesUtilityMixin } from './OxyServices.utility';
|
|
25
25
|
import { OxyServicesFeaturesMixin } from './OxyServices.features';
|
|
26
|
+
import { OxyServicesTopicsMixin } from './OxyServices.topics';
|
|
26
27
|
|
|
27
28
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
29
|
type MixinFunction = (Base: any) => any;
|
|
@@ -66,6 +67,7 @@ const MIXIN_PIPELINE: MixinFunction[] = [
|
|
|
66
67
|
OxyServicesDevicesMixin,
|
|
67
68
|
OxyServicesSecurityMixin,
|
|
68
69
|
OxyServicesFeaturesMixin,
|
|
70
|
+
OxyServicesTopicsMixin,
|
|
69
71
|
|
|
70
72
|
// Utility (last, can use all above)
|
|
71
73
|
OxyServicesUtilityMixin,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export enum TopicType {
|
|
2
|
+
CATEGORY = 'category',
|
|
3
|
+
TOPIC = 'topic',
|
|
4
|
+
ENTITY = 'entity',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export enum TopicSource {
|
|
8
|
+
SEED = 'seed',
|
|
9
|
+
AI = 'ai',
|
|
10
|
+
MANUAL = 'manual',
|
|
11
|
+
SYSTEM = 'system',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TopicTranslation {
|
|
15
|
+
displayName: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TopicData {
|
|
20
|
+
_id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
displayName: string;
|
|
24
|
+
description: string;
|
|
25
|
+
type: TopicType;
|
|
26
|
+
source: TopicSource;
|
|
27
|
+
aliases: string[];
|
|
28
|
+
parentTopicId?: string;
|
|
29
|
+
icon?: string;
|
|
30
|
+
image?: string;
|
|
31
|
+
isActive: boolean;
|
|
32
|
+
translations?: Record<string, TopicTranslation>;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
updatedAt: string;
|
|
35
|
+
}
|