@lokalise/api-contracts 5.3.0 → 6.0.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.
package/README.md CHANGED
@@ -18,6 +18,7 @@ const getContract = buildGetRoute({
18
18
  requestPathParamsSchema: REQUEST_PATH_PARAMS_SCHEMA,
19
19
  requestQuerySchema: REQUEST_QUERY_SCHEMA,
20
20
  requestHeaderSchema: REQUEST_HEADER_SCHEMA,
21
+ responseHeaderSchema: RESPONSE_HEADER_SCHEMA,
21
22
  pathResolver: (pathParams) => `/users/${pathParams.userId}`,
22
23
  summary: 'Route summary',
23
24
  metadata: { allowedRoles: ['admin'] },
@@ -63,3 +64,130 @@ Note that in order to make contract-based requests, you need to use a compatible
63
64
  (`@lokalise/frontend-http-client` or `@lokalise/backend-http-client`)
64
65
 
65
66
  In case you are using fastify on the backend, you can also use `@lokalise/fastify-api-contracts` in order to simplify definition of your fastify routes, utilizing contracts as the single source of truth.
67
+
68
+ ## Header Schemas
69
+
70
+ ### Request Headers (`requestHeaderSchema`)
71
+
72
+ Use `requestHeaderSchema` to define and validate headers that the client must send with the request. This is useful for authentication headers, API keys, content negotiation, and other request-specific headers.
73
+
74
+ ```ts
75
+ import { buildGetRoute } from '@lokalise/api-contracts'
76
+ import { z } from 'zod'
77
+
78
+ const contract = buildGetRoute({
79
+ successResponseBodySchema: DATA_SCHEMA,
80
+ requestHeaderSchema: z.object({
81
+ 'authorization': z.string(),
82
+ 'x-api-key': z.string(),
83
+ 'accept-language': z.string().optional(),
84
+ }),
85
+ pathResolver: () => '/api/data',
86
+ })
87
+ ```
88
+
89
+ ### Response Headers (`responseHeaderSchema`)
90
+
91
+ Use `responseHeaderSchema` to define and validate headers that the server will send in the response. This is particularly useful for documenting:
92
+ - Rate limiting headers
93
+ - Pagination headers
94
+ - Cache control headers
95
+ - Custom API metadata headers
96
+
97
+ ```ts
98
+ import { buildGetRoute } from '@lokalise/api-contracts'
99
+ import { z } from 'zod'
100
+
101
+ const contract = buildGetRoute({
102
+ successResponseBodySchema: DATA_SCHEMA,
103
+ responseHeaderSchema: z.object({
104
+ 'x-ratelimit-limit': z.string(),
105
+ 'x-ratelimit-remaining': z.string(),
106
+ 'x-ratelimit-reset': z.string(),
107
+ 'cache-control': z.string(),
108
+ }),
109
+ pathResolver: () => '/api/data',
110
+ })
111
+ ```
112
+
113
+ Both header schemas can be used together in a single contract:
114
+
115
+ ```ts
116
+ const contract = buildGetRoute({
117
+ successResponseBodySchema: DATA_SCHEMA,
118
+ requestHeaderSchema: z.object({
119
+ 'authorization': z.string(),
120
+ }),
121
+ responseHeaderSchema: z.object({
122
+ 'x-ratelimit-limit': z.string(),
123
+ 'x-ratelimit-remaining': z.string(),
124
+ }),
125
+ pathResolver: () => '/api/data',
126
+ })
127
+ ```
128
+
129
+ These header schemas are primarily used for:
130
+ - OpenAPI/Swagger documentation generation
131
+ - Client-side validation of response headers
132
+ - Type-safe header access in TypeScript
133
+ - Contract testing between frontend and backend
134
+
135
+ ## Utility Functions
136
+
137
+ ### `mapRouteToPath`
138
+
139
+ Converts a route definition to its corresponding path pattern with parameter placeholders.
140
+
141
+ ```ts
142
+ import { mapRouteToPath, buildGetRoute } from '@lokalise/api-contracts'
143
+
144
+ const userContract = buildGetRoute({
145
+ requestPathParamsSchema: z.object({ userId: z.string() }),
146
+ successResponseBodySchema: USER_SCHEMA,
147
+ pathResolver: (pathParams) => `/users/${pathParams.userId}`,
148
+ })
149
+
150
+ const pathPattern = mapRouteToPath(userContract)
151
+ // Returns: "/users/:userId"
152
+ ```
153
+
154
+ This function is useful when you need to:
155
+ - Generate OpenAPI/Swagger documentation
156
+ - Create route patterns for server-side routing frameworks
157
+ - Display route information in debugging or logging
158
+
159
+ The function replaces actual path parameters with placeholder syntax (`:paramName`), making it compatible with Express-style route patterns.
160
+
161
+ ### `describeContract`
162
+
163
+ Generates a human-readable description of a route contract, combining the HTTP method with the route path.
164
+
165
+ ```ts
166
+ import { describeContract, buildGetRoute, buildPayloadRoute } from '@lokalise/api-contracts'
167
+
168
+ const getContract = buildGetRoute({
169
+ requestPathParamsSchema: z.object({ userId: z.string() }),
170
+ successResponseBodySchema: USER_SCHEMA,
171
+ pathResolver: (pathParams) => `/users/${pathParams.userId}`,
172
+ })
173
+
174
+ const postContract = buildPayloadRoute({
175
+ method: 'post',
176
+ requestPathParamsSchema: z.object({
177
+ orgId: z.string(),
178
+ userId: z.string()
179
+ }),
180
+ requestBodySchema: CREATE_USER_SCHEMA,
181
+ successResponseBodySchema: USER_SCHEMA,
182
+ pathResolver: (pathParams) => `/orgs/${pathParams.orgId}/users/${pathParams.userId}`,
183
+ })
184
+
185
+ console.log(describeContract(getContract)) // "GET /users/:userId"
186
+ console.log(describeContract(postContract)) // "POST /orgs/:orgId/users/:userId"
187
+ ```
188
+
189
+ This function is particularly useful for:
190
+ - Logging and debugging API calls
191
+ - Generating documentation or route summaries
192
+ - Error messages that need to reference specific endpoints
193
+ - Test descriptions and assertions
@@ -1,18 +1,46 @@
1
1
  import type { ZodSchema, z } from 'zod/v4';
2
2
  import type { HttpStatusCode } from './HttpStatusCodes.ts';
3
- export type { HttpStatusCode };
4
3
  export type InferSchemaInput<T extends ZodSchema | undefined> = T extends ZodSchema ? z.input<T> : T extends undefined ? undefined : never;
5
4
  export type InferSchemaOutput<T extends ZodSchema | undefined> = T extends ZodSchema ? z.infer<T> : T extends undefined ? undefined : never;
6
5
  export type RoutePathResolver<PathParams> = (pathParams: PathParams) => string;
7
6
  export interface CommonRouteDefinitionMetadata extends Record<string, unknown> {
8
7
  }
9
- export type CommonRouteDefinition<ResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = {
8
+ export type CommonRouteDefinition<ResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, ResponseHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = {
10
9
  isNonJSONResponseExpected?: IsNonJSONResponseExpected;
11
10
  isEmptyResponseExpected?: IsEmptyResponseExpected;
12
11
  successResponseBodySchema: ResponseBodySchema;
13
12
  requestPathParamsSchema?: PathParamsSchema;
14
13
  requestQuerySchema?: RequestQuerySchema;
14
+ /**
15
+ * Schema for validating request headers.
16
+ * Used to define and validate headers that the client must send with the request.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * requestHeaderSchema: z.object({
21
+ * 'authorization': z.string(),
22
+ * 'x-api-key': z.string()
23
+ * })
24
+ * ```
25
+ */
15
26
  requestHeaderSchema?: RequestHeaderSchema;
27
+ /**
28
+ * Schema for validating response headers.
29
+ * Used to define and validate headers that the server will send in the response.
30
+ * This is useful for documenting expected response headers (e.g., rate limit headers,
31
+ * pagination headers, cache control headers) and can be used by clients to validate
32
+ * the response they receive.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * responseHeaderSchema: z.object({
37
+ * 'x-ratelimit-limit': z.string(),
38
+ * 'x-ratelimit-remaining': z.string(),
39
+ * 'x-ratelimit-reset': z.string()
40
+ * })
41
+ * ```
42
+ */
43
+ responseHeaderSchema?: ResponseHeaderSchema;
16
44
  pathResolver: RoutePathResolver<InferSchemaOutput<PathParamsSchema>>;
17
45
  responseSchemasByStatusCode?: ResponseSchemasByStatusCode;
18
46
  metadata?: CommonRouteDefinitionMetadata;
@@ -20,21 +48,21 @@ export type CommonRouteDefinition<ResponseBodySchema extends z.Schema | undefine
20
48
  summary?: string;
21
49
  tags?: readonly string[];
22
50
  };
23
- export type PayloadRouteDefinition<RequestBodySchema extends z.Schema | undefined = undefined, SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = CommonRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode> & {
51
+ export type PayloadRouteDefinition<RequestBodySchema extends z.Schema | undefined = undefined, SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, ResponseHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = CommonRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode> & {
24
52
  method: 'post' | 'put' | 'patch';
25
53
  requestBodySchema: RequestBodySchema;
26
54
  };
27
- export type GetRouteDefinition<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = CommonRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode> & {
55
+ export type GetRouteDefinition<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, ResponseHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = CommonRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode> & {
28
56
  method: 'get';
29
57
  };
30
- export type DeleteRouteDefinition<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = true, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = CommonRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode> & {
58
+ export type DeleteRouteDefinition<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, ResponseHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = true, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = CommonRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode> & {
31
59
  method: 'delete';
32
60
  };
33
- export declare function buildPayloadRoute<RequestBodySchema extends z.Schema | undefined = undefined, SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined>(params: PayloadRouteDefinition<RequestBodySchema, SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>): PayloadRouteDefinition<RequestBodySchema, SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>;
34
- export declare function buildGetRoute<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined>(params: Omit<GetRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>, 'method'>): GetRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>;
35
- export declare function buildDeleteRoute<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = true, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined>(params: Omit<DeleteRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>, 'method'>): DeleteRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>;
61
+ export declare function buildPayloadRoute<RequestBodySchema extends z.Schema | undefined = undefined, SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, ResponseHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined>(params: PayloadRouteDefinition<RequestBodySchema, SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>): PayloadRouteDefinition<RequestBodySchema, SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>;
62
+ export declare function buildGetRoute<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, ResponseHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined>(params: Omit<GetRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>, 'method'>): GetRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>;
63
+ export declare function buildDeleteRoute<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, ResponseHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = true, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined>(params: Omit<DeleteRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>, 'method'>): DeleteRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>;
36
64
  /**
37
65
  * This method maps given route definition to a string of the format '/static-path-part/:path-param-value'
38
66
  */
39
- export declare function mapRouteToPath(routeDefinition: CommonRouteDefinition<any, any, any, any, any, any, any>): string;
40
- export declare function describeContract(contract: PayloadRouteDefinition<any, any, any, any, any, any, any, any> | GetRouteDefinition<any, any, any, any, any, any, any> | DeleteRouteDefinition<any, any, any, any, any, any, any>): string;
67
+ export declare function mapRouteToPath(routeDefinition: CommonRouteDefinition<any, any, any, any, any, any, any, any>): string;
68
+ export declare function describeContract(contract: PayloadRouteDefinition<any, any, any, any, any, any, any, any, any> | GetRouteDefinition<any, any, any, any, any, any, any, any> | DeleteRouteDefinition<any, any, any, any, any, any, any, any>): string;
@@ -7,6 +7,7 @@ export function buildPayloadRoute(params) {
7
7
  pathResolver: params.pathResolver,
8
8
  requestBodySchema: params.requestBodySchema,
9
9
  requestHeaderSchema: params.requestHeaderSchema,
10
+ responseHeaderSchema: params.responseHeaderSchema,
10
11
  requestPathParamsSchema: params.requestPathParamsSchema,
11
12
  requestQuerySchema: params.requestQuerySchema,
12
13
  successResponseBodySchema: params.successResponseBodySchema,
@@ -24,6 +25,7 @@ export function buildGetRoute(params) {
24
25
  method: 'get',
25
26
  pathResolver: params.pathResolver,
26
27
  requestHeaderSchema: params.requestHeaderSchema,
28
+ responseHeaderSchema: params.responseHeaderSchema,
27
29
  requestPathParamsSchema: params.requestPathParamsSchema,
28
30
  requestQuerySchema: params.requestQuerySchema,
29
31
  successResponseBodySchema: params.successResponseBodySchema,
@@ -41,6 +43,7 @@ export function buildDeleteRoute(params) {
41
43
  method: 'delete',
42
44
  pathResolver: params.pathResolver,
43
45
  requestHeaderSchema: params.requestHeaderSchema,
46
+ responseHeaderSchema: params.responseHeaderSchema,
44
47
  requestPathParamsSchema: params.requestPathParamsSchema,
45
48
  requestQuerySchema: params.requestQuerySchema,
46
49
  successResponseBodySchema: params.successResponseBodySchema,
@@ -1 +1 @@
1
- {"version":3,"file":"apiContracts.js","sourceRoot":"","sources":["../src/apiContracts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apiContracts.js","sourceRoot":"","sources":["../src/apiContracts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './apiContracts.ts';
2
+ export * from './HttpStatusCodes.ts';
3
+ export * from './pathUtils.ts';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./apiContracts.js";
2
+ export * from "./HttpStatusCodes.js";
3
+ export * from "./pathUtils.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Builds a request path by combining a base path with an optional path prefix.
3
+ * Ensures proper slash handling to avoid double slashes or missing slashes.
4
+ *
5
+ * @param path - The base path for the request
6
+ * @param pathPrefix - Optional prefix to prepend to the path
7
+ * @returns The combined path with proper slash formatting
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * buildRequestPath('/api/users') // '/api/users'
12
+ * buildRequestPath('api/users') // '/api/users'
13
+ * buildRequestPath('/api/users', 'v1') // '/v1/api/users'
14
+ * buildRequestPath('/api/users', '/v1/') // '/v1/api/users'
15
+ * buildRequestPath('api/users', 'v1') // '/v1/api/users'
16
+ * ```
17
+ */
18
+ export declare function buildRequestPath(path: string, pathPrefix?: string): string;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Builds a request path by combining a base path with an optional path prefix.
3
+ * Ensures proper slash handling to avoid double slashes or missing slashes.
4
+ *
5
+ * @param path - The base path for the request
6
+ * @param pathPrefix - Optional prefix to prepend to the path
7
+ * @returns The combined path with proper slash formatting
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * buildRequestPath('/api/users') // '/api/users'
12
+ * buildRequestPath('api/users') // '/api/users'
13
+ * buildRequestPath('/api/users', 'v1') // '/v1/api/users'
14
+ * buildRequestPath('/api/users', '/v1/') // '/v1/api/users'
15
+ * buildRequestPath('api/users', 'v1') // '/v1/api/users'
16
+ * ```
17
+ */
18
+ export function buildRequestPath(path, pathPrefix) {
19
+ if (!pathPrefix) {
20
+ return ensureStartsWithSlash(path);
21
+ }
22
+ // Remove trailing slash from pathPrefix and leading slash from path
23
+ const cleanPrefix = pathPrefix.endsWith('/') ? pathPrefix.slice(0, -1) : pathPrefix;
24
+ const cleanPath = path.startsWith('/') ? path.slice(1) : path;
25
+ return ensureStartsWithSlash(`${cleanPrefix}/${cleanPath}`);
26
+ }
27
+ function ensureStartsWithSlash(str) {
28
+ return str.startsWith('/') ? str : `/${str}`;
29
+ }
30
+ //# sourceMappingURL=pathUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../src/pathUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,UAAmB;IAChE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAA;IACpC,CAAC;IAED,oEAAoE;IACpE,MAAM,WAAW,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAA;IACnF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAE7D,OAAO,qBAAqB,CAAC,GAAG,WAAW,IAAI,SAAS,EAAE,CAAC,CAAA;AAC7D,CAAC;AAED,SAAS,qBAAqB,CAAC,GAAW;IACxC,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAA;AAC9C,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@lokalise/api-contracts",
3
- "version": "5.3.0",
3
+ "version": "6.0.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
7
7
  "license": "Apache-2.0",
8
8
  "type": "module",
9
- "main": "./dist/apiContracts.js",
9
+ "main": "./dist/index.js",
10
10
  "enableTransparentWorkspaces": "false",
11
11
  "homepage": "https://github.com/lokalise/shared-ts-libs",
12
12
  "repository": {
@@ -14,7 +14,7 @@
14
14
  "url": "git://github.com/lokalise/shared-ts-libs.git"
15
15
  },
16
16
  "exports": {
17
- ".": "./dist/apiContracts.js",
17
+ ".": "./dist/index.js",
18
18
  "./package.json": "./package.json"
19
19
  },
20
20
  "private": false,
@@ -45,13 +45,13 @@
45
45
  "zod": ">=3.25.56"
46
46
  },
47
47
  "devDependencies": {
48
- "@biomejs/biome": "^2.1.4",
48
+ "@biomejs/biome": "^2.3.2",
49
49
  "@lokalise/biome-config": "^3.1.0",
50
50
  "@lokalise/tsconfig": "^1.3.0",
51
- "@vitest/coverage-v8": "^3.2.2",
51
+ "@vitest/coverage-v8": "^3.2.4",
52
52
  "rimraf": "^6.0.1",
53
- "typescript": "5.9.2",
54
- "vitest": "^3.2.2",
53
+ "typescript": "5.9.3",
54
+ "vitest": "^3.2.4",
55
55
  "zod": "^4.0.17"
56
56
  },
57
57
  "dependencies": {}