@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.
@@ -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
- * Get profile recommendations
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
- getProfileRecommendations(): Promise<Array<{
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/core",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
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
- * Get profile recommendations
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 getProfileRecommendations(): Promise<Array<{
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', undefined, { cache: true });
148
+ return await this.makeRequest('GET', '/profiles/recommendations', params, { cache: true });
126
149
  }, 'getProfileRecommendations');
127
150
  }
128
151
 
@@ -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
+ }