@lokalise/api-contracts 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -63,3 +63,63 @@ Note that in order to make contract-based requests, you need to use a compatible
63
63
  (`@lokalise/frontend-http-client` or `@lokalise/backend-http-client`)
64
64
 
65
65
  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.
66
+
67
+ ## Utility Functions
68
+
69
+ ### `mapRouteToPath`
70
+
71
+ Converts a route definition to its corresponding path pattern with parameter placeholders.
72
+
73
+ ```ts
74
+ import { mapRouteToPath, buildGetRoute } from '@lokalise/api-contracts'
75
+
76
+ const userContract = buildGetRoute({
77
+ requestPathParamsSchema: z.object({ userId: z.string() }),
78
+ successResponseBodySchema: USER_SCHEMA,
79
+ pathResolver: (pathParams) => `/users/${pathParams.userId}`,
80
+ })
81
+
82
+ const pathPattern = mapRouteToPath(userContract)
83
+ // Returns: "/users/:userId"
84
+ ```
85
+
86
+ This function is useful when you need to:
87
+ - Generate OpenAPI/Swagger documentation
88
+ - Create route patterns for server-side routing frameworks
89
+ - Display route information in debugging or logging
90
+
91
+ The function replaces actual path parameters with placeholder syntax (`:paramName`), making it compatible with Express-style route patterns.
92
+
93
+ ### `describeContract`
94
+
95
+ Generates a human-readable description of a route contract, combining the HTTP method with the route path.
96
+
97
+ ```ts
98
+ import { describeContract, buildGetRoute, buildPayloadRoute } from '@lokalise/api-contracts'
99
+
100
+ const getContract = buildGetRoute({
101
+ requestPathParamsSchema: z.object({ userId: z.string() }),
102
+ successResponseBodySchema: USER_SCHEMA,
103
+ pathResolver: (pathParams) => `/users/${pathParams.userId}`,
104
+ })
105
+
106
+ const postContract = buildPayloadRoute({
107
+ method: 'post',
108
+ requestPathParamsSchema: z.object({
109
+ orgId: z.string(),
110
+ userId: z.string()
111
+ }),
112
+ requestBodySchema: CREATE_USER_SCHEMA,
113
+ successResponseBodySchema: USER_SCHEMA,
114
+ pathResolver: (pathParams) => `/orgs/${pathParams.orgId}/users/${pathParams.userId}`,
115
+ })
116
+
117
+ console.log(describeContract(getContract)) // "GET /users/:userId"
118
+ console.log(describeContract(postContract)) // "POST /orgs/:orgId/users/:userId"
119
+ ```
120
+
121
+ This function is particularly useful for:
122
+ - Logging and debugging API calls
123
+ - Generating documentation or route summaries
124
+ - Error messages that need to reference specific endpoints
125
+ - Test descriptions and assertions
@@ -1,6 +1,5 @@
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;
@@ -37,3 +36,4 @@ export declare function buildDeleteRoute<SuccessResponseBodySchema extends z.Sch
37
36
  * This method maps given route definition to a string of the format '/static-path-part/:path-param-value'
38
37
  */
39
38
  export declare function mapRouteToPath(routeDefinition: CommonRouteDefinition<any, any, any, any, any, any, any>): string;
39
+ 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,4 +67,7 @@ routeDefinition) {
67
67
  }
68
68
  return routeDefinition.pathResolver(resolverParams);
69
69
  }
70
+ export function describeContract(contract) {
71
+ return `${contract.method.toUpperCase()} ${mapRouteToPath(contract)}`;
72
+ }
70
73
  //# sourceMappingURL=apiContracts.js.map
@@ -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.2.0",
3
+ "version": "5.4.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,