@crosspost/types 0.1.6 → 0.1.8

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/src/response.ts CHANGED
@@ -1,297 +1,57 @@
1
- /**
2
- * Enhanced Response Schemas and Types
3
- * Defines schemas and types for the enhanced API response format
4
- */
5
-
6
1
  import { z } from 'zod';
7
- import type { PlatformName } from './common.ts';
8
-
9
- /**
10
- * Standard API response schema
11
- */
12
- export const ApiResponseSchema = z.object({
13
- data: z.any().describe('Response data'),
14
- meta: z.object({
15
- rateLimit: z.object({
16
- remaining: z.number().describe('Number of requests remaining in the current window'),
17
- limit: z.number().describe('Total number of requests allowed in the window'),
18
- reset: z.number().describe('Timestamp when the rate limit resets (in seconds since epoch)'),
19
- }).optional().describe('Rate limit information'),
20
- pagination: z.object({
21
- page: z.number().describe('Current page number'),
22
- perPage: z.number().describe('Number of items per page'),
23
- total: z.number().describe('Total number of items'),
24
- totalPages: z.number().describe('Total number of pages'),
25
- nextCursor: z.string().optional().describe('Next page cursor (if applicable)'),
26
- prevCursor: z.string().optional().describe('Previous page cursor (if applicable)'),
27
- }).optional().describe('Pagination information'),
28
- }).optional().describe('Response metadata'),
29
- }).describe('Standard API response');
2
+ import { type ErrorDetail, ErrorDetailSchema } from './errors.ts';
30
3
 
31
- /**
32
- * Error response schema
33
- */
34
- export const ErrorResponseSchema = z.object({
35
- error: z.object({
36
- type: z.string().describe('Error type'),
37
- message: z.string().describe('Error message'),
38
- code: z.string().optional().describe('Error code (if applicable)'),
39
- details: z.any().optional().describe('Additional error details'),
40
- }).describe('Error information'),
41
- }).describe('Error response');
42
-
43
- /**
44
- * Schema for enhanced response metadata
45
- */
46
- export const EnhancedResponseMetaSchema = z.object({
47
- requestId: z.string().optional().describe('Unique request identifier'),
48
- timestamp: z.string().optional().describe('Request timestamp'),
4
+ export const ResponseMetaSchema = z.object({
5
+ requestId: z.string().uuid().describe('Unique identifier for the request'),
6
+ timestamp: z.string().datetime().describe('ISO timestamp of response generation'),
49
7
  rateLimit: z.object({
50
- remaining: z.number().describe('Number of requests remaining in the current window'),
51
- limit: z.number().describe('Total number of requests allowed in the window'),
52
- reset: z.number().describe('Timestamp when the rate limit resets (in seconds since epoch)'),
53
- }).optional().describe('Rate limit information'),
8
+ remaining: z.number().int().nonnegative(),
9
+ limit: z.number().int().positive(),
10
+ reset: z.number().int().positive().describe('Unix timestamp (seconds)'),
11
+ }).optional().describe('Rate limit information if applicable'),
54
12
  pagination: z.object({
55
- page: z.number().describe('Current page number'),
56
- perPage: z.number().describe('Number of items per page'),
57
- total: z.number().describe('Total number of items'),
58
- totalPages: z.number().describe('Total number of pages'),
59
- nextCursor: z.string().optional().describe('Next page cursor (if applicable)'),
60
- prevCursor: z.string().optional().describe('Previous page cursor (if applicable)'),
61
- }).optional().describe('Pagination information'),
62
- }).optional().describe('Response metadata');
63
-
64
- /**
65
- * Schema for error details
66
- */
67
- export const ErrorDetailSchema = z.object({
68
- platform: z.string().optional().describe('Platform associated with the error (if applicable)'),
69
- userId: z.string().optional().describe('User ID associated with the error (if applicable)'),
70
- status: z.literal('error').describe('Error status'),
71
- error: z.string().describe('Human-readable error message'),
72
- errorCode: z.string().describe('Machine-readable error code'),
73
- recoverable: z.boolean().describe('Whether the error is recoverable (can be retried)'),
74
- details: z.record(z.any()).optional().describe('Additional error details (platform-specific)'),
75
- }).describe('Error detail');
13
+ page: z.number().int().positive().optional(),
14
+ perPage: z.number().int().positive().optional(),
15
+ total: z.number().int().nonnegative().optional(),
16
+ limit: z.number().int().nonnegative().optional(),
17
+ offset: z.number().int().nonnegative().optional(),
18
+ totalPages: z.number().int().nonnegative().optional(),
19
+ nextCursor: z.string().optional(),
20
+ prevCursor: z.string().optional(),
21
+ }).optional().describe('Pagination information if applicable'),
22
+ });
76
23
 
77
- /**
78
- * Schema for enhanced error response
79
- */
80
- export const EnhancedErrorResponseSchema = z.object({
81
- success: z.literal(false).describe('Success indicator (always false for error responses)'),
82
- errors: z.array(ErrorDetailSchema).describe('Error information'),
83
- }).describe('Enhanced error response');
84
-
85
- /**
86
- * Schema for success details
87
- */
88
24
  export const SuccessDetailSchema = z.object({
89
- platform: z.string().describe('Platform associated with the success'),
90
- userId: z.string().describe('User ID associated with the success'),
91
- status: z.literal('success').describe('Success status'),
92
- postId: z.string().optional().describe('Post ID (if applicable)'),
93
- postUrl: z.string().optional().describe('Post URL (if applicable)'),
94
- }).catchall(z.any()).describe('Success detail');
95
-
96
- /**
97
- * Schema for multi-status response
98
- */
99
- export const MultiStatusResponseSchema = z.object({
100
- success: z.boolean().describe('Success indicator (true if at least one operation succeeded)'),
101
- data: z.object({
102
- summary: z.object({
103
- total: z.number().describe('Total number of operations'),
104
- succeeded: z.number().describe('Number of successful operations'),
105
- failed: z.number().describe('Number of failed operations'),
106
- }).describe('Summary of operations'),
107
- results: z.array(SuccessDetailSchema).describe('Successful results'),
108
- errors: z.array(ErrorDetailSchema).describe('Failed results'),
109
- }).describe('Response data'),
110
- }).describe('Multi-status response');
111
-
112
- /**
113
- * Function to create an enhanced response schema
114
- * @param schema The schema to wrap
115
- * @returns A schema for an enhanced response
116
- */
117
- export function EnhancedResponseSchema<T extends z.ZodTypeAny>(schema: T) {
118
- return z.object({
119
- success: z.boolean().describe('Whether the request was successful'),
120
- data: schema,
121
- meta: EnhancedResponseMetaSchema,
122
- });
123
- }
124
-
125
- // Derive TypeScript types from Zod schemas
126
- export type EnhancedResponseMeta = z.infer<typeof EnhancedResponseMetaSchema>;
127
- export type ErrorDetail = z.infer<typeof ErrorDetailSchema>;
128
- export type EnhancedErrorResponse = z.infer<typeof EnhancedErrorResponseSchema>;
129
- export type SuccessDetail = z.infer<typeof SuccessDetailSchema>;
130
- export type MultiStatusResponse = z.infer<typeof MultiStatusResponseSchema>;
131
- export type ApiResponse<T> = {
132
- data: T;
133
- meta?: {
134
- rateLimit?: { remaining: number; limit: number; reset: number };
135
- pagination?: {
136
- page: number;
137
- perPage: number;
138
- total: number;
139
- totalPages: number;
140
- nextCursor?: string;
141
- prevCursor?: string;
142
- };
143
- };
144
- };
145
- export type ErrorResponse = z.infer<typeof ErrorResponseSchema>;
146
-
147
- /**
148
- * Enhanced API response type
149
- */
150
- export interface EnhancedApiResponse<T> {
25
+ platform: z.string(),
26
+ userId: z.string(),
27
+ additionalData: z.any().optional(),
28
+ status: z.literal('success'),
29
+ }).catchall(z.any());
30
+
31
+ export const HealthStatusSchema = z.object({
32
+ status: z.string().describe('Health status of the API'),
33
+ version: z.string().optional().describe('API version'),
34
+ timestamp: z.string().datetime().describe('Current server time'),
35
+ }).describe('Health status response');
36
+
37
+ export const MultiStatusDataSchema = z.object({
38
+ summary: z.object({
39
+ total: z.number().int().nonnegative(),
40
+ succeeded: z.number().int().nonnegative(),
41
+ failed: z.number().int().nonnegative(),
42
+ }),
43
+ results: z.array(SuccessDetailSchema),
44
+ errors: z.array(ErrorDetailSchema),
45
+ });
46
+
47
+ export interface ApiResponse<T> {
151
48
  success: boolean;
152
- data: T;
153
- meta?: EnhancedResponseMeta;
154
- }
155
-
156
- /**
157
- * Helper function to create an enhanced API response
158
- * @param data The response data
159
- * @param meta Optional metadata
160
- * @returns An enhanced API response
161
- */
162
- export function createEnhancedApiResponse<T>(
163
- data: T,
164
- meta?: EnhancedResponseMeta,
165
- ): EnhancedApiResponse<T> {
166
- return {
167
- success: true,
168
- data,
169
- meta,
170
- };
49
+ data?: T | MultiStatusData | null; // Allow null for success without data
50
+ errors?: ErrorDetail[] | null; // Allow null for success
51
+ meta: ResponseMeta; // Mandatory, holds request id
171
52
  }
172
53
 
173
- /**
174
- * Create a standard API response
175
- * @param data The response data
176
- * @param meta The response metadata
177
- * @returns A standard API response
178
- */
179
- export function createApiResponse<T>(data: T, meta?: ApiResponse<T>['meta']): ApiResponse<T> {
180
- return {
181
- data,
182
- meta,
183
- };
184
- }
185
-
186
- /**
187
- * Create an error response
188
- * @param type The error type
189
- * @param message The error message
190
- * @param code The error code (if applicable)
191
- * @param details Additional error details
192
- * @returns An error response
193
- */
194
- export function createErrorResponse(
195
- type: string,
196
- message: string,
197
- code?: string,
198
- details?: any,
199
- ): ErrorResponse {
200
- return {
201
- error: {
202
- type,
203
- message,
204
- ...(code ? { code } : {}),
205
- ...(details ? { details } : {}),
206
- },
207
- };
208
- }
209
-
210
- /**
211
- * Helper function to create an enhanced error response
212
- * @param errors Array of error details
213
- * @returns An enhanced error response
214
- */
215
- export function createEnhancedErrorResponse(errors: ErrorDetail[]): EnhancedErrorResponse {
216
- return {
217
- success: false,
218
- errors,
219
- };
220
- }
221
-
222
- /**
223
- * Helper function to create an error detail
224
- * @param error Error message
225
- * @param errorCode Error code
226
- * @param recoverable Whether the error is recoverable
227
- * @param platform Optional platform
228
- * @param userId Optional user ID
229
- * @param details Optional additional details
230
- * @returns An error detail
231
- */
232
- export function createErrorDetail(
233
- error: string,
234
- errorCode: string,
235
- recoverable: boolean,
236
- platform?: PlatformName,
237
- userId?: string,
238
- details?: Record<string, any>,
239
- ): ErrorDetail {
240
- return {
241
- platform,
242
- userId,
243
- status: 'error',
244
- error,
245
- errorCode,
246
- recoverable,
247
- details,
248
- };
249
- }
250
-
251
- /**
252
- * Helper function to create a success detail
253
- * @param platform Platform
254
- * @param userId User ID
255
- * @param additionalData Additional data
256
- * @returns A success detail
257
- */
258
- export function createSuccessDetail(
259
- platform: PlatformName,
260
- userId: string,
261
- additionalData?: Record<string, any>,
262
- ): SuccessDetail {
263
- return {
264
- platform,
265
- userId,
266
- status: 'success',
267
- ...additionalData,
268
- };
269
- }
270
-
271
- /**
272
- * Helper function to create a multi-status response
273
- * @param results Successful results
274
- * @param errors Failed results
275
- * @returns A multi-status response
276
- */
277
- export function createMultiStatusResponse(
278
- results: SuccessDetail[],
279
- errors: ErrorDetail[],
280
- ): MultiStatusResponse {
281
- const total = results.length + errors.length;
282
- const succeeded = results.length;
283
- const failed = errors.length;
284
-
285
- return {
286
- success: succeeded > 0,
287
- data: {
288
- summary: {
289
- total,
290
- succeeded,
291
- failed,
292
- },
293
- results,
294
- errors,
295
- },
296
- };
297
- }
54
+ export type ResponseMeta = z.infer<typeof ResponseMetaSchema>;
55
+ export type SuccessDetail = z.infer<typeof SuccessDetailSchema>;
56
+ export type MultiStatusData = z.infer<typeof MultiStatusDataSchema>;
57
+ export type HealthStatus = z.infer<typeof HealthStatusSchema>;
@@ -1,16 +1,6 @@
1
- /**
2
- * User Profile Schemas and Types
3
- * Defines Zod schemas for user profile-related data
4
- * TypeScript types are derived from Zod schemas for type safety
5
- */
6
-
7
1
  import { z } from 'zod';
8
2
  import { PlatformSchema } from './common.ts';
9
- import { EnhancedResponseSchema } from './response.ts';
10
3
 
11
- /**
12
- * User profile schema
13
- */
14
4
  export const UserProfileSchema = z.object({
15
5
  userId: z.string().describe('User ID on the platform'),
16
6
  username: z.string().describe('Username on the platform'),
@@ -21,23 +11,9 @@ export const UserProfileSchema = z.object({
21
11
  lastUpdated: z.number().describe('Timestamp when the profile was last updated'),
22
12
  }).describe('User profile');
23
13
 
24
- /**
25
- * Profile refresh result schema
26
- */
27
- export const ProfileRefreshResultSchema = z.object({
28
- success: z.boolean().describe('Whether the profile refresh was successful'),
14
+ export const ProfileRefreshResponseSchema = z.object({
29
15
  profile: UserProfileSchema.optional().describe('The refreshed user profile (if successful)'),
30
- error: z.string().optional().describe('Error message (if unsuccessful)'),
31
- }).describe('Profile refresh result');
32
-
33
- /**
34
- * Profile refresh response schema
35
- */
36
- export const ProfileRefreshResponseSchema = EnhancedResponseSchema(
37
- ProfileRefreshResultSchema,
38
- ).describe('Profile refresh response');
16
+ }).describe('Profile refresh response');
39
17
 
40
- // Derive TypeScript types from Zod schemas
41
18
  export type UserProfile = z.infer<typeof UserProfileSchema>;
42
- export type ProfileRefreshResult = z.infer<typeof ProfileRefreshResultSchema>;
43
19
  export type ProfileRefreshResponse = z.infer<typeof ProfileRefreshResponseSchema>;
@@ -1,155 +0,0 @@
1
- import type { StatusCode } from 'hono/utils/http-status';
2
- import { BaseError } from './base-error.ts';
3
-
4
- /**
5
- * API Error codes for standardized error identification
6
- */
7
- export enum ApiErrorCode {
8
- // General errors
9
- UNKNOWN_ERROR = 'UNKNOWN_ERROR',
10
- INTERNAL_ERROR = 'INTERNAL_ERROR',
11
-
12
- // Authentication/Authorization errors
13
- UNAUTHORIZED = 'UNAUTHORIZED',
14
- FORBIDDEN = 'FORBIDDEN',
15
-
16
- // Validation errors
17
- VALIDATION_ERROR = 'VALIDATION_ERROR',
18
- INVALID_REQUEST = 'INVALID_REQUEST',
19
-
20
- // Rate limiting
21
- RATE_LIMITED = 'RATE_LIMITED',
22
-
23
- // Resource errors
24
- NOT_FOUND = 'NOT_FOUND',
25
-
26
- // Platform-specific errors
27
- PLATFORM_ERROR = 'PLATFORM_ERROR',
28
- PLATFORM_UNAVAILABLE = 'PLATFORM_UNAVAILABLE',
29
-
30
- // Content errors
31
- CONTENT_POLICY_VIOLATION = 'CONTENT_POLICY_VIOLATION',
32
- DUPLICATE_CONTENT = 'DUPLICATE_CONTENT',
33
-
34
- // Media errors
35
- MEDIA_UPLOAD_FAILED = 'MEDIA_UPLOAD_FAILED',
36
-
37
- // Post errors
38
- POST_CREATION_FAILED = 'POST_CREATION_FAILED',
39
- THREAD_CREATION_FAILED = 'THREAD_CREATION_FAILED',
40
- POST_DELETION_FAILED = 'POST_DELETION_FAILED',
41
- POST_INTERACTION_FAILED = 'POST_INTERACTION_FAILED',
42
-
43
- // Network errors
44
- NETWORK_ERROR = 'NETWORK_ERROR',
45
-
46
- MULTI_STATUS = 'MULTI_STATUS',
47
- }
48
-
49
- /**
50
- * API Error class for application-level errors
51
- */
52
- export class ApiError extends BaseError {
53
- public readonly code: ApiErrorCode;
54
- public readonly status: StatusCode;
55
- public readonly details?: Record<string, any>;
56
- public readonly recoverable: boolean;
57
-
58
- constructor(
59
- message: string,
60
- code: ApiErrorCode = ApiErrorCode.INTERNAL_ERROR,
61
- status: StatusCode = 500,
62
- details?: Record<string, any>,
63
- recoverable: boolean = false,
64
- ) {
65
- super(message);
66
- this.code = code;
67
- this.status = status;
68
- this.details = details;
69
- this.recoverable = recoverable;
70
- }
71
-
72
- /**
73
- * Create a validation error
74
- */
75
- static validation(message: string, details?: Record<string, any>): ApiError {
76
- return new ApiError(
77
- message,
78
- ApiErrorCode.VALIDATION_ERROR,
79
- 400,
80
- details,
81
- true,
82
- );
83
- }
84
-
85
- /**
86
- * Create an unauthorized error
87
- */
88
- static unauthorized(message: string = 'Unauthorized'): ApiError {
89
- return new ApiError(
90
- message,
91
- ApiErrorCode.UNAUTHORIZED,
92
- 401,
93
- undefined,
94
- true,
95
- );
96
- }
97
-
98
- /**
99
- * Create a forbidden error
100
- */
101
- static forbidden(message: string = 'Forbidden'): ApiError {
102
- return new ApiError(
103
- message,
104
- ApiErrorCode.FORBIDDEN,
105
- 403,
106
- undefined,
107
- false,
108
- );
109
- }
110
-
111
- /**
112
- * Create a not found error
113
- */
114
- static notFound(message: string = 'Resource not found'): ApiError {
115
- return new ApiError(
116
- message,
117
- ApiErrorCode.NOT_FOUND,
118
- 404,
119
- undefined,
120
- false,
121
- );
122
- }
123
-
124
- /**
125
- * Create a rate limit error
126
- */
127
- static rateLimited(
128
- message: string = 'Rate limit exceeded',
129
- details?: Record<string, any>,
130
- ): ApiError {
131
- return new ApiError(
132
- message,
133
- ApiErrorCode.RATE_LIMITED,
134
- 429,
135
- details,
136
- true,
137
- );
138
- }
139
-
140
- /**
141
- * Create an internal server error
142
- */
143
- static internal(
144
- message: string = 'Internal server error',
145
- details?: Record<string, any>,
146
- ): ApiError {
147
- return new ApiError(
148
- message,
149
- ApiErrorCode.INTERNAL_ERROR,
150
- 500,
151
- details,
152
- false,
153
- );
154
- }
155
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * Base Error class for all application errors
3
- */
4
- export class BaseError extends Error {
5
- constructor(message: string) {
6
- super(message);
7
- this.name = this.constructor.name;
8
- // Maintains proper stack trace for where our error was thrown
9
- if (Error.captureStackTrace) {
10
- Error.captureStackTrace(this, this.constructor);
11
- }
12
- }
13
- }
@@ -1,33 +0,0 @@
1
- import { ApiError, ApiErrorCode } from './api-error.ts';
2
- import type { ErrorDetail } from '../response.ts';
3
- import type { StatusCode } from 'hono/utils/http-status';
4
-
5
- /**
6
- * CompositeApiError represents a collection of multiple errors that occurred during an API operation.
7
- * This is particularly useful for handling multi-status responses (HTTP 207) where multiple operations
8
- * may have different outcomes.
9
- */
10
- export class CompositeApiError extends ApiError {
11
- /**
12
- * Array of individual error details
13
- */
14
- readonly errors: ErrorDetail[];
15
-
16
- constructor(
17
- message: string,
18
- errors: ErrorDetail[],
19
- status: StatusCode = 207,
20
- details?: Record<string, any>,
21
- recoverable: boolean = false,
22
- ) {
23
- super(
24
- message,
25
- ApiErrorCode.MULTI_STATUS,
26
- status,
27
- { ...details, errors },
28
- recoverable,
29
- );
30
-
31
- this.errors = errors;
32
- }
33
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * Error types for the Crosspost API
3
- */
4
-
5
- export * from './base-error.ts';
6
- export * from './api-error.ts';
7
- export * from './platform-error.ts';
8
- export * from './composite-api-error.ts';
@@ -1,34 +0,0 @@
1
- import { ApiErrorCode } from './api-error.ts';
2
- import type { PlatformName } from '../common.ts';
3
- import type { StatusCode } from 'hono/utils/http-status';
4
-
5
- /**
6
- * Platform Error
7
- * Custom error class for platform-specific errors
8
- */
9
- export class PlatformError extends Error {
10
- public readonly code: ApiErrorCode;
11
- public readonly recoverable: boolean;
12
- public readonly platform: PlatformName;
13
- public readonly userId?: string;
14
- public readonly details?: Record<string, any>;
15
-
16
- constructor(
17
- message: string,
18
- platform: PlatformName,
19
- code: ApiErrorCode = ApiErrorCode.PLATFORM_ERROR,
20
- recoverable: boolean = false,
21
- public originalError?: unknown,
22
- public status?: StatusCode,
23
- userId?: string,
24
- details?: Record<string, any>,
25
- ) {
26
- super(message);
27
- this.name = 'PlatformError';
28
- this.code = code;
29
- this.recoverable = recoverable;
30
- this.platform = platform;
31
- this.userId = userId;
32
- this.details = details;
33
- }
34
- }