@aurora-interactive/sensei-productivity 1.8.0 → 1.9.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.
Files changed (69) hide show
  1. package/README.md +2 -0
  2. package/dist/commonjs/funcs/schools-leaderboard.d.ts +14 -0
  3. package/dist/commonjs/funcs/schools-leaderboard.d.ts.map +1 -0
  4. package/dist/commonjs/funcs/schools-leaderboard.js +126 -0
  5. package/dist/commonjs/funcs/schools-leaderboard.js.map +1 -0
  6. package/dist/commonjs/lib/config.d.ts +3 -3
  7. package/dist/commonjs/lib/config.js +3 -3
  8. package/dist/commonjs/lib/encodings.d.ts.map +1 -1
  9. package/dist/commonjs/lib/encodings.js +20 -5
  10. package/dist/commonjs/lib/encodings.js.map +1 -1
  11. package/dist/commonjs/lib/security.d.ts +1 -1
  12. package/dist/commonjs/lib/security.d.ts.map +1 -1
  13. package/dist/commonjs/lib/security.js +19 -8
  14. package/dist/commonjs/lib/security.js.map +1 -1
  15. package/dist/commonjs/models/operations/get-top-schools.d.ts +22 -0
  16. package/dist/commonjs/models/operations/get-top-schools.d.ts.map +1 -0
  17. package/dist/commonjs/models/operations/get-top-schools.js +61 -0
  18. package/dist/commonjs/models/operations/get-top-schools.js.map +1 -0
  19. package/dist/commonjs/models/operations/index.d.ts +1 -0
  20. package/dist/commonjs/models/operations/index.d.ts.map +1 -1
  21. package/dist/commonjs/models/operations/index.js +1 -0
  22. package/dist/commonjs/models/operations/index.js.map +1 -1
  23. package/dist/commonjs/sdk/schools.d.ts +4 -0
  24. package/dist/commonjs/sdk/schools.d.ts.map +1 -1
  25. package/dist/commonjs/sdk/schools.js +7 -0
  26. package/dist/commonjs/sdk/schools.js.map +1 -1
  27. package/dist/esm/funcs/schools-leaderboard.d.ts +14 -0
  28. package/dist/esm/funcs/schools-leaderboard.d.ts.map +1 -0
  29. package/dist/esm/funcs/schools-leaderboard.js +90 -0
  30. package/dist/esm/funcs/schools-leaderboard.js.map +1 -0
  31. package/dist/esm/lib/config.d.ts +3 -3
  32. package/dist/esm/lib/config.js +3 -3
  33. package/dist/esm/lib/encodings.d.ts.map +1 -1
  34. package/dist/esm/lib/encodings.js +20 -5
  35. package/dist/esm/lib/encodings.js.map +1 -1
  36. package/dist/esm/lib/security.d.ts +1 -1
  37. package/dist/esm/lib/security.d.ts.map +1 -1
  38. package/dist/esm/lib/security.js +19 -8
  39. package/dist/esm/lib/security.js.map +1 -1
  40. package/dist/esm/models/operations/get-top-schools.d.ts +22 -0
  41. package/dist/esm/models/operations/get-top-schools.d.ts.map +1 -0
  42. package/dist/esm/models/operations/get-top-schools.js +23 -0
  43. package/dist/esm/models/operations/get-top-schools.js.map +1 -0
  44. package/dist/esm/models/operations/index.d.ts +1 -0
  45. package/dist/esm/models/operations/index.d.ts.map +1 -1
  46. package/dist/esm/models/operations/index.js +1 -0
  47. package/dist/esm/models/operations/index.js.map +1 -1
  48. package/dist/esm/sdk/schools.d.ts +4 -0
  49. package/dist/esm/sdk/schools.d.ts.map +1 -1
  50. package/dist/esm/sdk/schools.js +7 -0
  51. package/dist/esm/sdk/schools.js.map +1 -1
  52. package/jsr.json +1 -1
  53. package/package.json +1 -1
  54. package/rest-api/cypress/e2e/school-endpoints.cy.js +58 -0
  55. package/rest-api/cypress/e2e/user-endpoints.cy.js +1 -1
  56. package/rest-api/cypress.config.ts +0 -1
  57. package/rest-api/index.js +34 -6
  58. package/rest-api/lib/users.js +37 -0
  59. package/rest-api/routes/ActivityPostFunctions.js +3 -2
  60. package/rest-api/routes/FriendFunctions.js +2 -35
  61. package/rest-api/routes/SchoolFunctions.js +50 -0
  62. package/rest-api/routes/UserActivityFunctions.js +26 -1
  63. package/src/funcs/schools-leaderboard.ts +184 -0
  64. package/src/lib/config.ts +3 -3
  65. package/src/lib/encodings.ts +23 -4
  66. package/src/lib/security.ts +14 -2
  67. package/src/models/operations/get-top-schools.ts +60 -0
  68. package/src/models/operations/index.ts +1 -0
  69. package/src/sdk/schools.ts +15 -0
package/rest-api/index.js CHANGED
@@ -1,8 +1,11 @@
1
- import Fastify from 'fastify';
2
- import oasFastify from '@aurora-interactive/oas-fastify';
3
- import { prisma } from './lib/prisma.js';
4
- import { load as yamlLoad } from 'js-yaml';
5
- import { readFileSync } from 'node:fs';
1
+ import Fastify from "fastify";
2
+ import oasFastify from "@aurora-interactive/oas-fastify";
3
+ import { prisma } from "./lib/prisma.js";
4
+ import { load as yamlLoad } from "js-yaml";
5
+ import { readFileSync } from "node:fs";
6
+ import { createServer } from "node:http";
7
+ import { Server } from "socket.io";
8
+ import express from "express";
6
9
 
7
10
  import * as UserFuctions from "./routes/UserFunctions.js";
8
11
  import * as SchoolFunctions from "./routes/SchoolFunctions.js";
@@ -14,7 +17,11 @@ import * as FriendFunctions from "./routes/FriendFunctions.js";
14
17
  const spec = yamlLoad(readFileSync("./api-spec.yaml"));
15
18
 
16
19
  // workaround for fastify spec -> route registrar
17
- spec.$id = '$';
20
+ spec.$id = "$";
21
+
22
+ const app = express();
23
+ const server = createServer(app);
24
+ const io = new Server(server);
18
25
 
19
26
  const fastify = Fastify({
20
27
  logger: false
@@ -29,6 +36,7 @@ const handler = {
29
36
  deleteUser: UserFuctions.deleteUserHandler,
30
37
  listSchools: SchoolFunctions.listSchoolsHandler,
31
38
  getSchoolById: SchoolFunctions.getSchoolByIdHandler,
39
+ getTopSchools: SchoolFunctions.getTopSchoolsHandler,
32
40
  listCategories: CategoryFunctions.listCategoriesHandler,
33
41
  createCategory: CategoryFunctions.createCategoryHandler,
34
42
  updateCategory: CategoryFunctions.updateCategoryHandler,
@@ -58,6 +66,26 @@ fastify.register(oasFastify, { spec, handler });
58
66
 
59
67
  fastify.prisma = prisma;
60
68
 
69
+ io.on('connection', (socket) => {
70
+ socket.send("Hey! You are now receiving real-time messaging events for Sensei Productivity. Glad to have you in :P");
71
+
72
+ socket.on("loginAs", username => {
73
+ if (typeof username !== "string") {
74
+ socket.send("The username which was provided is not a string");
75
+ return;
76
+ }
77
+
78
+ socket.join(username);
79
+ socket.send(`Successfully logged in as ${username}`);
80
+ })
81
+ });
82
+
83
+ server.listen(7654, "0.0.0.0", () => {
84
+ console.log('Websocket messaging running at http://0.0.0.0:7654');
85
+ });
86
+
87
+ fastify.socketio = io;
88
+
61
89
  try {
62
90
  await fastify.listen({ host: "0.0.0.0", port: 3000 })
63
91
  } catch (err) {
@@ -32,4 +32,41 @@ export async function areUsersFriends(prisma, userId, targetPotentialFriendId) {
32
32
  }
33
33
 
34
34
  return true;
35
+ }
36
+
37
+ export async function friendsOfUserById(prisma, userId) {
38
+ return await prisma.Friend_Requests.findMany({
39
+ where: {
40
+ OR: [
41
+ { initiator_user_id: userId, status: "accepted" },
42
+ { target_user_id: userId, status: "accepted" }
43
+ ]
44
+ },
45
+ select: {
46
+ users_Friend_Requests_initiator_user_idTousers: {
47
+ select: {
48
+ user_id: true,
49
+ first_name: true,
50
+ last_name: true,
51
+ username: true,
52
+ email: true,
53
+ school: {
54
+ select: { school_id: true, school_name: true }
55
+ }
56
+ }
57
+ },
58
+ users_Friend_Requests_target_user_idTousers: {
59
+ select: {
60
+ user_id: true,
61
+ first_name: true,
62
+ last_name: true,
63
+ username: true,
64
+ email: true,
65
+ school: {
66
+ select: { school_id: true, school_name: true }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ });
35
72
  }
@@ -39,6 +39,7 @@ export async function getUserPostsHandler(request, reply, fastify) {
39
39
  user_id: true
40
40
  }
41
41
  });
42
+
42
43
  if (targetExistsCheck === null) {
43
44
  reply.status(404);
44
45
  return;
@@ -160,7 +161,7 @@ export async function getFeedHandler(request, reply, fastify) {
160
161
  categoryName: post.Category.category_name,
161
162
  activityId: post.User_Activity.activity_id,
162
163
  likes: await getLikesForPost(post.post_id, fastify.prisma),
163
- likedByCurrentUser: userHasAlreadyLikedPost(post.post_id, userInfo.user_id, fastify.prisma)
164
+ likedByCurrentUser: await userHasAlreadyLikedPost(post.post_id, userInfo.user_id, fastify.prisma)
164
165
  })));
165
166
  }
166
167
 
@@ -209,7 +210,7 @@ export async function getPostByIdHandler(request, reply, fastify) {
209
210
  postStatus: post.post_status,
210
211
  caption: post.caption,
211
212
  likes: await getLikesForPost(post.post_id, fastify.prisma),
212
- likedByCurrentUser: userHasAlreadyLikedPost(post.post_id, userInfo.user_id, fastify.prisma)
213
+ likedByCurrentUser: await userHasAlreadyLikedPost(post.post_id, userInfo.user_id, fastify.prisma)
213
214
  };
214
215
  }
215
216
 
@@ -1,4 +1,4 @@
1
- import { getUserAuthInfo, areUsersFriends } from "../lib/users.js";
1
+ import { getUserAuthInfo, areUsersFriends, friendsOfUserById } from "../lib/users.js";
2
2
 
3
3
  export async function listFriendsHandler(request, reply, fastify) {
4
4
  const accessToken = (request.headers.authorization ?? "").substring(7);
@@ -22,40 +22,7 @@ export async function listFriendsHandler(request, reply, fastify) {
22
22
  return;
23
23
  }
24
24
 
25
- const friendsList = await fastify.prisma.Friend_Requests.findMany({
26
- where: {
27
- OR: [
28
- { initiator_user_id: request.params.id, status: "accepted" },
29
- { target_user_id: request.params.id, status: "accepted" }
30
- ]
31
- },
32
- select: {
33
- users_Friend_Requests_initiator_user_idTousers: {
34
- select: {
35
- user_id: true,
36
- first_name: true,
37
- last_name: true,
38
- username: true,
39
- email: true,
40
- school: {
41
- select: { school_id: true, school_name: true }
42
- }
43
- }
44
- },
45
- users_Friend_Requests_target_user_idTousers: {
46
- select: {
47
- user_id: true,
48
- first_name: true,
49
- last_name: true,
50
- username: true,
51
- email: true,
52
- school: {
53
- select: { school_id: true, school_name: true }
54
- }
55
- }
56
- }
57
- }
58
- });
25
+ const friendsList = await friendsOfUserById(fastify.prisma, request.params.id);
59
26
 
60
27
  return friendsList.map(friendEntry => {
61
28
  // determine which side of the relationship is the friend (not the current user)
@@ -48,4 +48,54 @@ export async function getSchoolByIdHandler(request, reply, fastify) {
48
48
  schoolNameShorthand: school.school_name_shorthand,
49
49
  userCount: school._count.users
50
50
  };
51
+ }
52
+
53
+ // authored with help from Claude
54
+ export async function getTopSchoolsHandler(request, reply, fastify) {
55
+ if (typeof request.headers.authorization !== "string") {
56
+ reply.status(401);
57
+ return;
58
+ }
59
+ const accessToken = request.headers.authorization.substring(7);
60
+ const user = await fastify.prisma.users.findFirst({
61
+ select: { user_id: true },
62
+ where: { access_token: accessToken }
63
+ });
64
+ if (user === null) {
65
+ reply.status(401);
66
+ return;
67
+ }
68
+
69
+ const limit = request.query.limit ?? 10;
70
+
71
+ const schools = await fastify.prisma.school.findMany({
72
+ select: {
73
+ school_name: true,
74
+ school_name_shorthand: true,
75
+ users: {
76
+ select: {
77
+ User_Activity_Posts: {
78
+ select: {
79
+ Category: {
80
+ select: { category_weight: true }
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ },
87
+ take: limit
88
+ });
89
+
90
+ const ranked = schools.map(school => {
91
+ const points = school.users.flatMap(u => u.User_Activity_Posts)
92
+ .reduce((sum, post) => sum + post.Category.category_weight, 0);
93
+ return {
94
+ schoolName: school.school_name,
95
+ schoolNameShorthand: school.school_name_shorthand,
96
+ points
97
+ };
98
+ }).sort((a, b) => b.points - a.points);
99
+
100
+ return ranked;
51
101
  }
@@ -1,4 +1,4 @@
1
- import { getUserAuthInfo, areUsersFriends } from "../lib/users.js";
1
+ import { getUserAuthInfo, areUsersFriends, friendsOfUserById } from "../lib/users.js";
2
2
 
3
3
  export async function getUserActivitiesHandler(request, reply, fastify) {
4
4
  const accessToken = (request.headers.authorization ?? "").substring(7);
@@ -205,6 +205,31 @@ export async function updateActivityHandler(request, reply, fastify) {
205
205
  return;
206
206
  }
207
207
 
208
+ if (currentActivity.activity_status === "active" && request.body.activityStatus === "completed") {
209
+ await fastify.prisma.User_Activity_Posts.create({
210
+ data: {
211
+ post_status: "public",
212
+ caption: currentActivity.details,
213
+ users: {
214
+ connect: { user_id: userInfo.user_id }
215
+ },
216
+ Category: {
217
+ connect: { category_name: currentActivity.category_name }
218
+ },
219
+ User_Activity: {
220
+ connect: { activity_id: request.params.id }
221
+ }
222
+ }
223
+ });
224
+
225
+ currentActivity.user_id = Number(currentActivity.user_id);
226
+ const friends = await friendsOfUserById(fastify.prisma, userInfo.user_id);
227
+ for (const friendObj of friends) {
228
+ const friend = (friendObj.users_Friend_Requests_initiator_user_idTousers.user_id === userInfo.user_id ? friendObj.users_Friend_Requests_target_user_idTousers : friendObj.users_Friend_Requests_initiator_user_idTousers).username;
229
+ fastify.socketio.to(friend).emit("userPost", currentActivity); // instantly propagate the post to all the user's friend for the post feed
230
+ }
231
+ }
232
+
208
233
  const targetActivityStatus = request.body.activityStatus ?? currentActivity.activity_status;
209
234
  const targetActivityDeadline = request.body.activityDeadline ?? currentActivity.activity_deadline;
210
235
  const targetDetails = request.body.details ?? currentActivity.details;
@@ -0,0 +1,184 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ */
4
+
5
+ import * as z from "zod/v4-mini";
6
+ import { SenseiProductivityCore } from "../core.js";
7
+ import { encodeFormQuery } from "../lib/encodings.js";
8
+ import * as M from "../lib/matchers.js";
9
+ import { compactMap } from "../lib/primitives.js";
10
+ import { safeParse } from "../lib/schemas.js";
11
+ import { RequestOptions } from "../lib/sdks.js";
12
+ import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
13
+ import { pathToFunc } from "../lib/url.js";
14
+ import {
15
+ ConnectionError,
16
+ InvalidRequestError,
17
+ RequestAbortedError,
18
+ RequestTimeoutError,
19
+ UnexpectedClientError,
20
+ } from "../models/errors/http-client-errors.js";
21
+ import { ResponseValidationError } from "../models/errors/response-validation-error.js";
22
+ import { SDKValidationError } from "../models/errors/sdk-validation-error.js";
23
+ import { SenseiProductivityError } from "../models/errors/sensei-productivity-error.js";
24
+ import * as operations from "../models/operations/index.js";
25
+ import { APICall, APIPromise } from "../types/async.js";
26
+ import { Result } from "../types/fp.js";
27
+ import * as types$ from "../types/primitives.js";
28
+
29
+ /**
30
+ * Get the top 10 schools (by points) in order
31
+ */
32
+ export function schoolsLeaderboard(
33
+ client: SenseiProductivityCore,
34
+ request?: operations.GetTopSchoolsRequest | undefined,
35
+ options?: RequestOptions,
36
+ ): APIPromise<
37
+ Result<
38
+ Array<operations.GetTopSchoolsResponse> | undefined,
39
+ | SenseiProductivityError
40
+ | ResponseValidationError
41
+ | ConnectionError
42
+ | RequestAbortedError
43
+ | RequestTimeoutError
44
+ | InvalidRequestError
45
+ | UnexpectedClientError
46
+ | SDKValidationError
47
+ >
48
+ > {
49
+ return new APIPromise($do(
50
+ client,
51
+ request,
52
+ options,
53
+ ));
54
+ }
55
+
56
+ async function $do(
57
+ client: SenseiProductivityCore,
58
+ request?: operations.GetTopSchoolsRequest | undefined,
59
+ options?: RequestOptions,
60
+ ): Promise<
61
+ [
62
+ Result<
63
+ Array<operations.GetTopSchoolsResponse> | undefined,
64
+ | SenseiProductivityError
65
+ | ResponseValidationError
66
+ | ConnectionError
67
+ | RequestAbortedError
68
+ | RequestTimeoutError
69
+ | InvalidRequestError
70
+ | UnexpectedClientError
71
+ | SDKValidationError
72
+ >,
73
+ APICall,
74
+ ]
75
+ > {
76
+ const parsed = safeParse(
77
+ request,
78
+ (value) =>
79
+ z.parse(
80
+ z.optional(operations.GetTopSchoolsRequest$outboundSchema),
81
+ value,
82
+ ),
83
+ "Input validation failed",
84
+ );
85
+ if (!parsed.ok) {
86
+ return [parsed, { status: "invalid" }];
87
+ }
88
+ const payload = parsed.value;
89
+ const body = null;
90
+
91
+ const path = pathToFunc("/api/v1/schools/leaderboard")();
92
+
93
+ const query = encodeFormQuery({
94
+ "limit": payload?.limit,
95
+ });
96
+
97
+ const headers = new Headers(compactMap({
98
+ Accept: "application/json",
99
+ }));
100
+
101
+ const secConfig = await extractSecurity(client._options.bearerAuth);
102
+ const securityInput = secConfig == null ? {} : { bearerAuth: secConfig };
103
+ const requestSecurity = resolveGlobalSecurity(securityInput);
104
+
105
+ const context = {
106
+ options: client._options,
107
+ baseURL: options?.serverURL ?? client._baseURL ?? "",
108
+ operationID: "getTopSchools",
109
+ oAuth2Scopes: null,
110
+
111
+ resolvedSecurity: requestSecurity,
112
+
113
+ securitySource: client._options.bearerAuth,
114
+ retryConfig: options?.retries
115
+ || client._options.retryConfig
116
+ || {
117
+ strategy: "backoff",
118
+ backoff: {
119
+ initialInterval: 1000,
120
+ maxInterval: 60000,
121
+ exponent: 1.3,
122
+ maxElapsedTime: 3600000,
123
+ },
124
+ retryConnectionErrors: true,
125
+ }
126
+ || { strategy: "none" },
127
+ retryCodes: options?.retryCodes || ["429", "5XX"],
128
+ };
129
+
130
+ const requestRes = client._createRequest(context, {
131
+ security: requestSecurity,
132
+ method: "GET",
133
+ baseURL: options?.serverURL,
134
+ path: path,
135
+ headers: headers,
136
+ query: query,
137
+ body: body,
138
+ userAgent: client._options.userAgent,
139
+ timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1,
140
+ }, options);
141
+ if (!requestRes.ok) {
142
+ return [requestRes, { status: "invalid" }];
143
+ }
144
+ const req = requestRes.value;
145
+
146
+ const doResult = await client._do(req, {
147
+ context,
148
+ errorCodes: ["429", "5XX"],
149
+ retryConfig: context.retryConfig,
150
+ retryCodes: context.retryCodes,
151
+ });
152
+ if (!doResult.ok) {
153
+ return [doResult, { status: "request-error", request: req }];
154
+ }
155
+ const response = doResult.value;
156
+
157
+ const [result] = await M.match<
158
+ Array<operations.GetTopSchoolsResponse> | undefined,
159
+ | SenseiProductivityError
160
+ | ResponseValidationError
161
+ | ConnectionError
162
+ | RequestAbortedError
163
+ | RequestTimeoutError
164
+ | InvalidRequestError
165
+ | UnexpectedClientError
166
+ | SDKValidationError
167
+ >(
168
+ M.json(
169
+ 200,
170
+ types$.optional(z.array(operations.GetTopSchoolsResponse$inboundSchema)),
171
+ ),
172
+ M.nil(
173
+ 401,
174
+ types$.optional(z.array(operations.GetTopSchoolsResponse$inboundSchema)),
175
+ ),
176
+ M.fail(429),
177
+ M.fail("5XX"),
178
+ )(response, req);
179
+ if (!result.ok) {
180
+ return [result, { status: "complete", request: req, response }];
181
+ }
182
+
183
+ return [result, { status: "complete", request: req, response }];
184
+ }
package/src/lib/config.ts CHANGED
@@ -61,8 +61,8 @@ export function serverURLFromOptions(options: SDKOptions): URL | null {
61
61
  export const SDK_METADATA = {
62
62
  language: "typescript",
63
63
  openapiDocVersion: "1.8.0",
64
- sdkVersion: "1.8.0",
65
- genVersion: "2.869.3",
64
+ sdkVersion: "1.9.0",
65
+ genVersion: "2.879.6",
66
66
  userAgent:
67
- "speakeasy-sdk/typescript 1.8.0 2.869.3 1.8.0 @aurora-interactive/sensei-productivity",
67
+ "speakeasy-sdk/typescript 1.9.0 2.879.6 1.8.0 @aurora-interactive/sensei-productivity",
68
68
  } as const;
@@ -479,6 +479,23 @@ export const encodeSpaceDelimitedQuery = queryEncoder(encodeSpaceDelimited);
479
479
  export const encodePipeDelimitedQuery = queryEncoder(encodePipeDelimited);
480
480
  export const encodeDeepObjectQuery = queryEncoder(encodeDeepObject);
481
481
 
482
+ function isBlobLike(val: unknown): val is Blob {
483
+ if (val instanceof Blob) {
484
+ return true;
485
+ }
486
+
487
+ if (typeof val !== "object" || val == null || !(Symbol.toStringTag in val)) {
488
+ return false;
489
+ }
490
+
491
+ const tag = val[Symbol.toStringTag];
492
+ if (tag !== "Blob" && tag !== "File") {
493
+ return false;
494
+ }
495
+
496
+ return "stream" in val && typeof val.stream === "function";
497
+ }
498
+
482
499
  export function appendForm(
483
500
  fd: FormData,
484
501
  key: string,
@@ -487,10 +504,12 @@ export function appendForm(
487
504
  ): void {
488
505
  if (value == null) {
489
506
  return;
490
- } else if (value instanceof Blob && fileName) {
491
- fd.append(key, value, fileName);
492
- } else if (value instanceof Blob) {
493
- fd.append(key, value);
507
+ } else if (isBlobLike(value)) {
508
+ if (fileName) {
509
+ fd.append(key, value as Blob, fileName);
510
+ } else {
511
+ fd.append(key, value as Blob);
512
+ }
494
513
  } else if (Array.isArray(value)) {
495
514
  value.forEach((v) => {
496
515
  appendForm(fd, key, v);
@@ -240,8 +240,9 @@ function applyBearer(
240
240
 
241
241
  export function resolveGlobalSecurity(
242
242
  security: Partial<models.Security> | null | undefined,
243
+ allowedFields?: number[],
243
244
  ): SecurityState | null {
244
- return resolveSecurity(
245
+ let inputs: SecurityInput[][] = [
245
246
  [
246
247
  {
247
248
  fieldName: "Authorization",
@@ -249,7 +250,18 @@ export function resolveGlobalSecurity(
249
250
  value: security?.bearerAuth ?? env().SENSEIPRODUCTIVITY_BEARER_AUTH,
250
251
  },
251
252
  ],
252
- );
253
+ ];
254
+
255
+ if (allowedFields) {
256
+ inputs = allowedFields.map((i) => {
257
+ if (i < 0 || i >= inputs.length) {
258
+ throw new RangeError(`invalid allowedFields index ${i}`);
259
+ }
260
+ return inputs[i]!;
261
+ });
262
+ }
263
+
264
+ return resolveSecurity(...inputs);
253
265
  }
254
266
 
255
267
  export async function extractSecurity<
@@ -0,0 +1,60 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ */
4
+
5
+ import * as z from "zod/v4-mini";
6
+ import { safeParse } from "../../lib/schemas.js";
7
+ import { Result as SafeParseResult } from "../../types/fp.js";
8
+ import * as types from "../../types/primitives.js";
9
+ import { SDKValidationError } from "../errors/sdk-validation-error.js";
10
+
11
+ export type GetTopSchoolsRequest = {
12
+ limit?: number | undefined;
13
+ };
14
+
15
+ export type GetTopSchoolsResponse = {
16
+ schoolName: string;
17
+ schoolNameShorthand: string;
18
+ points: number;
19
+ };
20
+
21
+ /** @internal */
22
+ export type GetTopSchoolsRequest$Outbound = {
23
+ limit: number;
24
+ };
25
+
26
+ /** @internal */
27
+ export const GetTopSchoolsRequest$outboundSchema: z.ZodMiniType<
28
+ GetTopSchoolsRequest$Outbound,
29
+ GetTopSchoolsRequest
30
+ > = z.object({
31
+ limit: z._default(z.int(), 5),
32
+ });
33
+
34
+ export function getTopSchoolsRequestToJSON(
35
+ getTopSchoolsRequest: GetTopSchoolsRequest,
36
+ ): string {
37
+ return JSON.stringify(
38
+ GetTopSchoolsRequest$outboundSchema.parse(getTopSchoolsRequest),
39
+ );
40
+ }
41
+
42
+ /** @internal */
43
+ export const GetTopSchoolsResponse$inboundSchema: z.ZodMiniType<
44
+ GetTopSchoolsResponse,
45
+ unknown
46
+ > = z.object({
47
+ schoolName: types.string(),
48
+ schoolNameShorthand: types.string(),
49
+ points: types.number(),
50
+ });
51
+
52
+ export function getTopSchoolsResponseFromJSON(
53
+ jsonString: string,
54
+ ): SafeParseResult<GetTopSchoolsResponse, SDKValidationError> {
55
+ return safeParse(
56
+ jsonString,
57
+ (x) => GetTopSchoolsResponse$inboundSchema.parse(JSON.parse(x)),
58
+ `Failed to parse 'GetTopSchoolsResponse' from JSON`,
59
+ );
60
+ }
@@ -14,6 +14,7 @@ export * from "./get-current-user.js";
14
14
  export * from "./get-feed.js";
15
15
  export * from "./get-post-by-id.js";
16
16
  export * from "./get-school-by-id.js";
17
+ export * from "./get-top-schools.js";
17
18
  export * from "./get-user-activities.js";
18
19
  export * from "./get-user-by-id.js";
19
20
  export * from "./get-user-posts.js";
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { schoolsGetAll } from "../funcs/schools-get-all.js";
6
6
  import { schoolsGet } from "../funcs/schools-get.js";
7
+ import { schoolsLeaderboard } from "../funcs/schools-leaderboard.js";
7
8
  import { ClientSDK, RequestOptions } from "../lib/sdks.js";
8
9
  import * as operations from "../models/operations/index.js";
9
10
  import { unwrapAsync } from "../types/fp.js";
@@ -21,6 +22,20 @@ export class Schools extends ClientSDK {
21
22
  ));
22
23
  }
23
24
 
25
+ /**
26
+ * Get the top 10 schools (by points) in order
27
+ */
28
+ async leaderboard(
29
+ request?: operations.GetTopSchoolsRequest | undefined,
30
+ options?: RequestOptions,
31
+ ): Promise<Array<operations.GetTopSchoolsResponse> | undefined> {
32
+ return unwrapAsync(schoolsLeaderboard(
33
+ this,
34
+ request,
35
+ options,
36
+ ));
37
+ }
38
+
24
39
  /**
25
40
  * Get a school's details by ID
26
41
  */