@casual-simulation/aux-records 3.2.2 → 3.2.4-alpha.5857788915

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.
@@ -106,6 +106,7 @@ export declare class RecordsHttpServer {
106
106
  private _stripeWebhook;
107
107
  private _handleOptions;
108
108
  private _listRecords;
109
+ private _createRecord;
109
110
  private _createRecordKey;
110
111
  private _policyGrantPermission;
111
112
  private _policyRevokePermission;
@@ -120,6 +121,11 @@ export declare class RecordsHttpServer {
120
121
  private _aiSkybox;
121
122
  private _aiGetSkybox;
122
123
  private _aiGenerateImage;
124
+ private _postStudio;
125
+ private _listStudios;
126
+ private _listStudioMembers;
127
+ private _addStudioMember;
128
+ private _removeStudioMember;
123
129
  private _listData;
124
130
  private _handleRecordFileOptions;
125
131
  private _recordFile;
@@ -148,7 +154,9 @@ export declare class RecordsHttpServer {
148
154
  private _postReplaceSession;
149
155
  private _getSessions;
150
156
  private _getSubscriptionInfo;
157
+ private _getSubscriptionInfoV2;
151
158
  private _manageSubscription;
159
+ private _manageSubscriptionV2;
152
160
  /**
153
161
  * Endpoint to retrieve info about a user.
154
162
  * @param request The request.
@@ -19,7 +19,7 @@ var __rest = (this && this.__rest) || function (s, e) {
19
19
  return t;
20
20
  };
21
21
  import { getStatusCode, parseInstancesList, tryDecodeUriComponent, tryParseJson, } from './Utils';
22
- import { INVALID_REQUEST_ERROR_MESSAGE, MAX_EMAIL_ADDRESS_LENGTH, MAX_OPEN_AI_API_KEY_LENGTH, MAX_SMS_ADDRESS_LENGTH, } from './AuthController';
22
+ import { INVALID_REQUEST_ERROR_MESSAGE, MAX_EMAIL_ADDRESS_LENGTH, MAX_SMS_ADDRESS_LENGTH, } from './AuthController';
23
23
  import { parseSessionKey } from './AuthUtils';
24
24
  import { z } from 'zod';
25
25
  import { AVAILABLE_PERMISSIONS_VALIDATION } from './PolicyPermissions';
@@ -207,6 +207,10 @@ export class RecordsHttpServer {
207
207
  request.path === '/api/v2/meet/token') {
208
208
  return formatResponse(request, yield this._postMeetToken(request), this._allowedApiOrigins);
209
209
  }
210
+ else if (request.method === 'POST' &&
211
+ request.path === '/api/v2/records') {
212
+ return formatResponse(request, yield this._createRecord(request), this._allowedAccountOrigins);
213
+ }
210
214
  else if (request.method === 'POST' &&
211
215
  request.path === '/api/v2/records/events/count') {
212
216
  return formatResponse(request, yield this._postRecordsEventsCount(request), this._allowedApiOrigins);
@@ -335,6 +339,34 @@ export class RecordsHttpServer {
335
339
  request.path === '/api/v2/ai/image') {
336
340
  return formatResponse(request, yield this._aiGenerateImage(request), this._allowedApiOrigins);
337
341
  }
342
+ else if (request.method === 'POST' &&
343
+ request.path === '/api/v2/studios') {
344
+ return formatResponse(request, yield this._postStudio(request), this._allowedAccountOrigins);
345
+ }
346
+ else if (request.method === 'GET' &&
347
+ request.path === '/api/v2/studios/list') {
348
+ return formatResponse(request, yield this._listStudios(request), this._allowedAccountOrigins);
349
+ }
350
+ else if (request.method === 'GET' &&
351
+ request.path === '/api/v2/studios/members/list') {
352
+ return formatResponse(request, yield this._listStudioMembers(request), this._allowedAccountOrigins);
353
+ }
354
+ else if (request.method === 'POST' &&
355
+ request.path === '/api/v2/studios/members') {
356
+ return formatResponse(request, yield this._addStudioMember(request), this._allowedAccountOrigins);
357
+ }
358
+ else if (request.method === 'DELETE' &&
359
+ request.path === '/api/v2/studios/members') {
360
+ return formatResponse(request, yield this._removeStudioMember(request), this._allowedAccountOrigins);
361
+ }
362
+ else if (request.method === 'GET' &&
363
+ request.path === '/api/v2/subscriptions') {
364
+ return formatResponse(request, yield this._getSubscriptionInfoV2(request), this._allowedAccountOrigins);
365
+ }
366
+ else if (request.method === 'POST' &&
367
+ request.path === '/api/v2/subscriptions/manage') {
368
+ return formatResponse(request, yield this._manageSubscriptionV2(request), this._allowedAccountOrigins);
369
+ }
338
370
  else if (request.method === 'OPTIONS') {
339
371
  return formatResponse(request, yield this._handleOptions(request), true);
340
372
  }
@@ -398,7 +430,83 @@ export class RecordsHttpServer {
398
430
  }
399
431
  return returnResult(validation);
400
432
  }
401
- const result = yield this._records.listRecords(validation.userId);
433
+ const schema = z.object({
434
+ studioId: z.string().nonempty().optional(),
435
+ });
436
+ const parseResult = schema.safeParse(request.query);
437
+ if (parseResult.success === false) {
438
+ return returnZodError(parseResult.error);
439
+ }
440
+ const { studioId } = parseResult.data;
441
+ if (studioId) {
442
+ const result = yield this._records.listStudioRecords(studioId, validation.userId);
443
+ return returnResult(result);
444
+ }
445
+ else {
446
+ const result = yield this._records.listRecords(validation.userId);
447
+ return returnResult(result);
448
+ }
449
+ });
450
+ }
451
+ _createRecord(request) {
452
+ return __awaiter(this, void 0, void 0, function* () {
453
+ if (!validateOrigin(request, this._allowedAccountOrigins)) {
454
+ return returnResult(INVALID_ORIGIN_RESULT);
455
+ }
456
+ if (typeof request.body !== 'string') {
457
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
458
+ }
459
+ const jsonResult = tryParseJson(request.body);
460
+ if (!jsonResult.success || typeof jsonResult.value !== 'object') {
461
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
462
+ }
463
+ const schema = z.object({
464
+ recordName: z
465
+ .string({
466
+ invalid_type_error: 'recordName must be a string.',
467
+ required_error: 'recordName is required.',
468
+ })
469
+ .nonempty('recordName must not be empty.'),
470
+ ownerId: z
471
+ .string({
472
+ invalid_type_error: 'ownerId must be a string.',
473
+ required_error: 'ownerId is required.',
474
+ })
475
+ .nonempty('ownerId must not be empty.')
476
+ .optional(),
477
+ studioId: z
478
+ .string({
479
+ invalid_type_error: 'studioId must be a string.',
480
+ required_error: 'studioId is required.',
481
+ })
482
+ .nonempty('studioId must not be empty.')
483
+ .optional(),
484
+ });
485
+ const parseResult = schema.safeParse(jsonResult.value);
486
+ if (parseResult.success === false) {
487
+ return returnZodError(parseResult.error);
488
+ }
489
+ const { recordName, ownerId, studioId } = parseResult.data;
490
+ if (!recordName || typeof recordName !== 'string') {
491
+ return returnResult({
492
+ success: false,
493
+ errorCode: 'unacceptable_request',
494
+ errorMessage: 'recordName is required and must be a string.',
495
+ });
496
+ }
497
+ const validation = yield this._validateSessionKey(request);
498
+ if (validation.success === false) {
499
+ if (validation.errorCode === 'no_session_key') {
500
+ return returnResult(NOT_LOGGED_IN_RESULT);
501
+ }
502
+ return returnResult(validation);
503
+ }
504
+ const result = yield this._records.createRecord({
505
+ recordName,
506
+ ownerId,
507
+ studioId,
508
+ userId: validation.userId,
509
+ });
402
510
  return returnResult(result);
403
511
  });
404
512
  }
@@ -1110,6 +1218,211 @@ export class RecordsHttpServer {
1110
1218
  return returnResult(result);
1111
1219
  });
1112
1220
  }
1221
+ _postStudio(request) {
1222
+ return __awaiter(this, void 0, void 0, function* () {
1223
+ if (!validateOrigin(request, this._allowedAccountOrigins)) {
1224
+ return returnResult(INVALID_ORIGIN_RESULT);
1225
+ }
1226
+ if (typeof request.body !== 'string') {
1227
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
1228
+ }
1229
+ const jsonResult = tryParseJson(request.body);
1230
+ if (!jsonResult.success || typeof jsonResult.value !== 'object') {
1231
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
1232
+ }
1233
+ const schema = z.object({
1234
+ displayName: z
1235
+ .string({
1236
+ invalid_type_error: 'displayName must be a string.',
1237
+ required_error: 'displayName is required.',
1238
+ })
1239
+ .nonempty('displayName must not be empty'),
1240
+ });
1241
+ const parseResult = schema.safeParse(jsonResult.value);
1242
+ if (parseResult.success === false) {
1243
+ return returnZodError(parseResult.error);
1244
+ }
1245
+ const { displayName } = parseResult.data;
1246
+ const sessionKeyValidation = yield this._validateSessionKey(request);
1247
+ if (sessionKeyValidation.success === false) {
1248
+ if (sessionKeyValidation.errorCode === 'no_session_key') {
1249
+ return returnResult(NOT_LOGGED_IN_RESULT);
1250
+ }
1251
+ return returnResult(sessionKeyValidation);
1252
+ }
1253
+ const result = yield this._records.createStudio(displayName, sessionKeyValidation.userId);
1254
+ return returnResult(result);
1255
+ });
1256
+ }
1257
+ _listStudios(request) {
1258
+ return __awaiter(this, void 0, void 0, function* () {
1259
+ if (!validateOrigin(request, this._allowedAccountOrigins)) {
1260
+ return returnResult(INVALID_ORIGIN_RESULT);
1261
+ }
1262
+ if (!this._aiController) {
1263
+ return returnResult(AI_NOT_SUPPORTED_RESULT);
1264
+ }
1265
+ const schema = z.object({});
1266
+ const parseResult = schema.safeParse(request.query);
1267
+ if (parseResult.success === false) {
1268
+ return returnZodError(parseResult.error);
1269
+ }
1270
+ const {} = parseResult.data;
1271
+ const sessionKeyValidation = yield this._validateSessionKey(request);
1272
+ if (sessionKeyValidation.success === false) {
1273
+ if (sessionKeyValidation.errorCode === 'no_session_key') {
1274
+ return returnResult(NOT_LOGGED_IN_RESULT);
1275
+ }
1276
+ return returnResult(sessionKeyValidation);
1277
+ }
1278
+ const result = yield this._records.listStudios(sessionKeyValidation.userId);
1279
+ return returnResult(result);
1280
+ });
1281
+ }
1282
+ _listStudioMembers(request) {
1283
+ return __awaiter(this, void 0, void 0, function* () {
1284
+ if (!validateOrigin(request, this._allowedAccountOrigins)) {
1285
+ return returnResult(INVALID_ORIGIN_RESULT);
1286
+ }
1287
+ if (!this._aiController) {
1288
+ return returnResult(AI_NOT_SUPPORTED_RESULT);
1289
+ }
1290
+ const schema = z.object({
1291
+ studioId: z
1292
+ .string({
1293
+ invalid_type_error: 'studioId must be a string.',
1294
+ required_error: 'studioId is required.',
1295
+ })
1296
+ .nonempty('studioId must not be empty'),
1297
+ });
1298
+ const parseResult = schema.safeParse(request.query);
1299
+ if (parseResult.success === false) {
1300
+ return returnZodError(parseResult.error);
1301
+ }
1302
+ const { studioId } = parseResult.data;
1303
+ const sessionKeyValidation = yield this._validateSessionKey(request);
1304
+ if (sessionKeyValidation.success === false) {
1305
+ if (sessionKeyValidation.errorCode === 'no_session_key') {
1306
+ return returnResult(NOT_LOGGED_IN_RESULT);
1307
+ }
1308
+ return returnResult(sessionKeyValidation);
1309
+ }
1310
+ const result = yield this._records.listStudioMembers(studioId, sessionKeyValidation.userId);
1311
+ return returnResult(result);
1312
+ });
1313
+ }
1314
+ _addStudioMember(request) {
1315
+ return __awaiter(this, void 0, void 0, function* () {
1316
+ if (!validateOrigin(request, this._allowedAccountOrigins)) {
1317
+ return returnResult(INVALID_ORIGIN_RESULT);
1318
+ }
1319
+ if (typeof request.body !== 'string') {
1320
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
1321
+ }
1322
+ const jsonResult = tryParseJson(request.body);
1323
+ if (!jsonResult.success || typeof jsonResult.value !== 'object') {
1324
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
1325
+ }
1326
+ const schema = z.object({
1327
+ studioId: z
1328
+ .string({
1329
+ invalid_type_error: 'studioId must be a string.',
1330
+ required_error: 'studioId is required.',
1331
+ })
1332
+ .nonempty('studioId must not be empty'),
1333
+ addedUserId: z
1334
+ .string({
1335
+ invalid_type_error: 'addedUserId must be a string.',
1336
+ required_error: 'addedUserId is required.',
1337
+ })
1338
+ .nonempty('addedUserId must not be empty')
1339
+ .optional(),
1340
+ addedEmail: z
1341
+ .string({
1342
+ invalid_type_error: 'addedEmail must be a string.',
1343
+ required_error: 'addedEmail is required.',
1344
+ })
1345
+ .nonempty('addedEmail must not be empty')
1346
+ .optional(),
1347
+ addedPhoneNumber: z
1348
+ .string({
1349
+ invalid_type_error: 'addedPhoneNumber must be a string.',
1350
+ required_error: 'addedPhoneNumber is required.',
1351
+ })
1352
+ .nonempty('addedPhoneNumber must not be empty')
1353
+ .optional(),
1354
+ role: z.union([z.literal('admin'), z.literal('member')]),
1355
+ });
1356
+ const parseResult = schema.safeParse(jsonResult.value);
1357
+ if (parseResult.success === false) {
1358
+ return returnZodError(parseResult.error);
1359
+ }
1360
+ const { studioId, addedUserId, addedEmail, addedPhoneNumber, role } = parseResult.data;
1361
+ const sessionKeyValidation = yield this._validateSessionKey(request);
1362
+ if (sessionKeyValidation.success === false) {
1363
+ if (sessionKeyValidation.errorCode === 'no_session_key') {
1364
+ return returnResult(NOT_LOGGED_IN_RESULT);
1365
+ }
1366
+ return returnResult(sessionKeyValidation);
1367
+ }
1368
+ const result = yield this._records.addStudioMember({
1369
+ studioId,
1370
+ userId: sessionKeyValidation.userId,
1371
+ role,
1372
+ addedUserId,
1373
+ addedEmail,
1374
+ addedPhoneNumber,
1375
+ });
1376
+ return returnResult(result);
1377
+ });
1378
+ }
1379
+ _removeStudioMember(request) {
1380
+ return __awaiter(this, void 0, void 0, function* () {
1381
+ if (!validateOrigin(request, this._allowedAccountOrigins)) {
1382
+ return returnResult(INVALID_ORIGIN_RESULT);
1383
+ }
1384
+ if (typeof request.body !== 'string') {
1385
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
1386
+ }
1387
+ const jsonResult = tryParseJson(request.body);
1388
+ if (!jsonResult.success || typeof jsonResult.value !== 'object') {
1389
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
1390
+ }
1391
+ const schema = z.object({
1392
+ studioId: z
1393
+ .string({
1394
+ invalid_type_error: 'studioId must be a string.',
1395
+ required_error: 'studioId is required.',
1396
+ })
1397
+ .nonempty('studioId must not be empty'),
1398
+ removedUserId: z
1399
+ .string({
1400
+ invalid_type_error: 'removedUserId must be a string.',
1401
+ required_error: 'removedUserId is required.',
1402
+ })
1403
+ .nonempty('removedUserId must not be empty')
1404
+ .optional(),
1405
+ });
1406
+ const parseResult = schema.safeParse(jsonResult.value);
1407
+ if (parseResult.success === false) {
1408
+ return returnZodError(parseResult.error);
1409
+ }
1410
+ const { studioId, removedUserId } = parseResult.data;
1411
+ const sessionKeyValidation = yield this._validateSessionKey(request);
1412
+ if (sessionKeyValidation.success === false) {
1413
+ if (sessionKeyValidation.errorCode === 'no_session_key') {
1414
+ return returnResult(NOT_LOGGED_IN_RESULT);
1415
+ }
1416
+ return returnResult(sessionKeyValidation);
1417
+ }
1418
+ const result = yield this._records.removeStudioMember({
1419
+ studioId,
1420
+ userId: sessionKeyValidation.userId,
1421
+ removedUserId,
1422
+ });
1423
+ return returnResult(result);
1424
+ });
1425
+ }
1113
1426
  _listData(request) {
1114
1427
  return __awaiter(this, void 0, void 0, function* () {
1115
1428
  const schema = z.object({
@@ -2165,6 +2478,77 @@ export class RecordsHttpServer {
2165
2478
  intervalLength: s.intervalLength,
2166
2479
  intervalCost: s.intervalCost,
2167
2480
  currency: s.currency,
2481
+ featureList: s.featureList,
2482
+ })),
2483
+ purchasableSubscriptions: result.purchasableSubscriptions.map((s) => ({
2484
+ id: s.id,
2485
+ name: s.name,
2486
+ description: s.description,
2487
+ featureList: s.featureList,
2488
+ prices: s.prices,
2489
+ })),
2490
+ });
2491
+ });
2492
+ }
2493
+ _getSubscriptionInfoV2(request) {
2494
+ return __awaiter(this, void 0, void 0, function* () {
2495
+ if (!this._subscriptions) {
2496
+ return returnResult(SUBSCRIPTIONS_NOT_SUPPORTED_RESULT);
2497
+ }
2498
+ if (!validateOrigin(request, this._allowedAccountOrigins)) {
2499
+ return returnResult(INVALID_ORIGIN_RESULT);
2500
+ }
2501
+ const sessionKey = getSessionKey(request);
2502
+ if (!sessionKey) {
2503
+ return returnResult(NOT_LOGGED_IN_RESULT);
2504
+ }
2505
+ const schema = z.object({
2506
+ studioId: z
2507
+ .string({
2508
+ invalid_type_error: 'studioId must be a string.',
2509
+ required_error: 'studioId is required.',
2510
+ })
2511
+ .nonempty('studioId must be non-empty.')
2512
+ .optional(),
2513
+ userId: z
2514
+ .string({
2515
+ invalid_type_error: 'userId must be a string.',
2516
+ required_error: 'userId is required.',
2517
+ })
2518
+ .nonempty('userId must be non-empty.')
2519
+ .optional(),
2520
+ });
2521
+ const parseResult = schema.safeParse(request.query || {});
2522
+ if (parseResult.success === false) {
2523
+ return returnZodError(parseResult.error);
2524
+ }
2525
+ const { studioId, userId } = parseResult.data;
2526
+ const result = yield this._subscriptions.getSubscriptionStatus({
2527
+ sessionKey,
2528
+ userId,
2529
+ studioId,
2530
+ });
2531
+ if (!result.success) {
2532
+ return returnResult(result);
2533
+ }
2534
+ return returnResult({
2535
+ success: true,
2536
+ publishableKey: result.publishableKey,
2537
+ subscriptions: result.subscriptions.map((s) => ({
2538
+ active: s.active,
2539
+ statusCode: s.statusCode,
2540
+ productName: s.productName,
2541
+ startDate: s.startDate,
2542
+ endedDate: s.endedDate,
2543
+ cancelDate: s.cancelDate,
2544
+ canceledDate: s.canceledDate,
2545
+ currentPeriodStart: s.currentPeriodStart,
2546
+ currentPeriodEnd: s.currentPeriodEnd,
2547
+ renewalInterval: s.renewalInterval,
2548
+ intervalLength: s.intervalLength,
2549
+ intervalCost: s.intervalCost,
2550
+ currency: s.currency,
2551
+ featureList: s.featureList,
2168
2552
  })),
2169
2553
  purchasableSubscriptions: result.purchasableSubscriptions.map((s) => ({
2170
2554
  id: s.id,
@@ -2236,6 +2620,71 @@ export class RecordsHttpServer {
2236
2620
  });
2237
2621
  });
2238
2622
  }
2623
+ _manageSubscriptionV2(request) {
2624
+ return __awaiter(this, void 0, void 0, function* () {
2625
+ if (!this._subscriptions) {
2626
+ return returnResult(SUBSCRIPTIONS_NOT_SUPPORTED_RESULT);
2627
+ }
2628
+ if (!validateOrigin(request, this._allowedAccountOrigins)) {
2629
+ return returnResult(INVALID_ORIGIN_RESULT);
2630
+ }
2631
+ const sessionKey = getSessionKey(request);
2632
+ if (!sessionKey) {
2633
+ return returnResult(NOT_LOGGED_IN_RESULT);
2634
+ }
2635
+ if (typeof request.body !== 'string') {
2636
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
2637
+ }
2638
+ const jsonResult = tryParseJson(request.body);
2639
+ if (!jsonResult.success || typeof jsonResult.value !== 'object') {
2640
+ return returnResult(UNACCEPTABLE_REQUEST_RESULT_MUST_BE_JSON);
2641
+ }
2642
+ const schema = z.object({
2643
+ userId: z
2644
+ .string({
2645
+ invalid_type_error: 'userId must be a string.',
2646
+ required_error: 'userId is required.',
2647
+ })
2648
+ .nonempty('userId must not be empty.')
2649
+ .optional(),
2650
+ studioId: z
2651
+ .string({
2652
+ invalid_type_error: 'studioId must be a string.',
2653
+ required_error: 'studioId is required.',
2654
+ })
2655
+ .nonempty('studioId must not be empty.')
2656
+ .optional(),
2657
+ subscriptionId: z.string().optional(),
2658
+ expectedPrice: z
2659
+ .object({
2660
+ currency: z.string(),
2661
+ cost: z.number(),
2662
+ interval: z.enum(['month', 'year', 'week', 'day']),
2663
+ intervalLength: z.number(),
2664
+ })
2665
+ .optional(),
2666
+ });
2667
+ const parseResult = schema.safeParse(jsonResult.value);
2668
+ if (parseResult.success === false) {
2669
+ return returnZodError(parseResult.error);
2670
+ }
2671
+ const { userId, studioId, subscriptionId, expectedPrice } = parseResult.data;
2672
+ const result = yield this._subscriptions.createManageSubscriptionLink({
2673
+ sessionKey,
2674
+ userId,
2675
+ studioId,
2676
+ subscriptionId,
2677
+ expectedPrice: expectedPrice,
2678
+ });
2679
+ if (!result.success) {
2680
+ return returnResult(result);
2681
+ }
2682
+ return returnResult({
2683
+ success: true,
2684
+ url: result.url,
2685
+ });
2686
+ });
2687
+ }
2239
2688
  /**
2240
2689
  * Endpoint to retrieve info about a user.
2241
2690
  * @param request The request.
@@ -2272,7 +2721,6 @@ export class RecordsHttpServer {
2272
2721
  phoneNumber: result.phoneNumber,
2273
2722
  hasActiveSubscription: result.hasActiveSubscription,
2274
2723
  subscriptionTier: result.subscriptionTier,
2275
- openAiKey: result.openAiKey,
2276
2724
  });
2277
2725
  });
2278
2726
  }
@@ -2314,11 +2762,6 @@ export class RecordsHttpServer {
2314
2762
  .nullable(),
2315
2763
  avatarUrl: z.string().url().optional().nullable(),
2316
2764
  avatarPortraitUrl: z.string().url().optional().nullable(),
2317
- openAiKey: z
2318
- .string()
2319
- .max(MAX_OPEN_AI_API_KEY_LENGTH)
2320
- .optional()
2321
- .nullable(),
2322
2765
  });
2323
2766
  const parseResult = schema.safeParse(jsonResult.value);
2324
2767
  if (parseResult.success === false) {