@oxyhq/core 5.3.0 → 5.4.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.
@@ -657,6 +657,32 @@ function OxyServicesUserMixin(Base) {
657
657
  throw this.handleError(error);
658
658
  }
659
659
  }
660
+ /**
661
+ * Get the authenticated VIEWER's bounded "follows-of-follows" user ids — the
662
+ * union of the accounts followed by the accounts the viewer follows (a
663
+ * two-hop walk of the follow graph), MINUS the viewer's own follows and the
664
+ * viewer themselves. The viewer is derived server-side from the SDK's auth
665
+ * token (never a param), so there is no target id to pass.
666
+ *
667
+ * Returns a bounded, lean list of ids meant to SEED a friends-of-friends
668
+ * feed (the consumer hydrates/ranks the posts itself), ordered by frequency
669
+ * (accounts followed by more of the viewer's follows first), then recency.
670
+ * An anonymous caller resolves to an empty array. Mirrors
671
+ * {@link getMutualUserIds}'s caching posture.
672
+ */
673
+ async getFollowsOfFollowsIds(params) {
674
+ try {
675
+ const query = (0, apiUtils_1.buildPaginationParams)(params || {});
676
+ const response = await this.makeRequest('GET', '/users/follows-of-follows-ids', query, {
677
+ cache: true,
678
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
679
+ });
680
+ return response.data || [];
681
+ }
682
+ catch (error) {
683
+ throw this.handleError(error);
684
+ }
685
+ }
660
686
  /**
661
687
  * Get notifications
662
688
  */
@@ -62,7 +62,17 @@ class SessionClient {
62
62
  applySync(raw) {
63
63
  const sync = (0, contracts_1.safeParseContract)(contracts_1.deviceSessionSyncSchema, raw);
64
64
  if (!sync) {
65
- loggerUtils_1.logger.warn('[SessionClient] discarded invalid session sync');
65
+ const parsed = contracts_1.deviceSessionSyncSchema.safeParse(raw);
66
+ // Log field-level type diagnostics ONLY — never values. The payload carries tokens and
67
+ // session ids; issue.path/code and the invalid_type expected/received TYPE names are safe,
68
+ // but zod messages can embed offending values for other codes, so they are omitted.
69
+ const issues = parsed.success
70
+ ? []
71
+ : parsed.error.issues.map((issue) => issue.code === 'invalid_type'
72
+ ? { path: issue.path.join('.'), code: issue.code, expected: issue.expected, received: issue.received }
73
+ : { path: issue.path.join('.'), code: issue.code });
74
+ const keys = raw && typeof raw === 'object' ? Object.keys(raw) : [];
75
+ loggerUtils_1.logger.warn('[SessionClient] discarded invalid session sync', { component: 'SessionClient', issues, keys });
66
76
  return;
67
77
  }
68
78
  this.applyState(sync.state);
@@ -72,19 +82,19 @@ class SessionClient {
72
82
  }
73
83
  async bootstrap() {
74
84
  const res = await this.host.makeRequest('GET', '/session/device/state', undefined, { cache: false });
75
- this.applySync(res?.data);
85
+ this.applySync(res);
76
86
  }
77
87
  async switchAccount(accountId) {
78
88
  const res = await this.host.makeRequest('POST', '/session/device/switch', { accountId }, { cache: false });
79
- this.applySync(res?.data);
89
+ this.applySync(res);
80
90
  }
81
91
  async signOut(target) {
82
92
  const res = await this.host.makeRequest('POST', '/session/device/signout', target, { cache: false });
83
- this.applySync(res?.data);
93
+ this.applySync(res);
84
94
  }
85
95
  async addCurrentAccount() {
86
96
  const res = await this.host.makeRequest('POST', '/session/device/add', undefined, { cache: false });
87
- this.applySync(res?.data);
97
+ this.applySync(res);
88
98
  }
89
99
  async start() {
90
100
  if (this.started)