@livex/contracts 0.1.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.
@@ -0,0 +1,303 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "LIVEX API",
5
+ "version": "1.0.0",
6
+ "description": "Contratos v1 del MVP: catálogo, disponibilidad, bookings y webhooks de pago.",
7
+ "license": { "name": "MIT", "url": "https://opensource.org/licenses/MIT" }
8
+ },
9
+ "servers": [{ "url": "https://api.livex.app/v1" }],
10
+ "security": [
11
+ { "BearerAuth": [] }
12
+ ],
13
+ "paths": {
14
+ "/experiences": {
15
+ "get": {
16
+ "summary": "Listar experiencias",
17
+ "operationId": "listExperiences",
18
+ "security": [],
19
+ "parameters": [
20
+ { "name": "q", "in": "query", "schema": { "type": "string" } },
21
+ { "name": "categoryId", "in": "query", "schema": { "type": "string", "format": "uuid" } },
22
+ { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 } },
23
+ { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } }
24
+ ],
25
+ "responses": {
26
+ "200": {
27
+ "description": "OK",
28
+ "content": {
29
+ "application/json": {
30
+ "schema": {
31
+ "type": "object",
32
+ "properties": {
33
+ "items": { "type": "array", "items": { "$ref": "#/components/schemas/ExperienceSummary" } },
34
+ "total": { "type": "integer" }
35
+ },
36
+ "required": ["items", "total"]
37
+ }
38
+ }
39
+ }
40
+ },
41
+ "400": { "$ref": "#/components/responses/BadRequest" }
42
+ }
43
+ }
44
+ },
45
+ "/experiences/{experienceId}": {
46
+ "get": {
47
+ "summary": "Detalle de experiencia",
48
+ "operationId": "getExperience",
49
+ "security": [],
50
+ "parameters": [
51
+ { "name": "experienceId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
52
+ ],
53
+ "responses": {
54
+ "200": {
55
+ "description": "OK",
56
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Experience" } } }
57
+ },
58
+ "400": { "$ref": "#/components/responses/BadRequest" },
59
+ "404": { "$ref": "#/components/responses/NotFound" }
60
+ }
61
+ }
62
+ },
63
+ "/availability": {
64
+ "get": {
65
+ "summary": "Consultar disponibilidad por experiencia y fecha",
66
+ "operationId": "getAvailability",
67
+ "security": [],
68
+ "parameters": [
69
+ { "name": "experienceId", "in": "query", "required": true, "schema": { "type": "string", "format": "uuid" } },
70
+ { "name": "date", "in": "query", "required": true, "schema": { "type": "string", "format": "date" } }
71
+ ],
72
+ "responses": {
73
+ "200": {
74
+ "description": "OK",
75
+ "content": {
76
+ "application/json": {
77
+ "schema": { "type": "array", "items": { "$ref": "#/components/schemas/AvailabilitySlot" } }
78
+ }
79
+ }
80
+ },
81
+ "400": { "$ref": "#/components/responses/BadRequest" }
82
+ }
83
+ }
84
+ },
85
+ "/bookings": {
86
+ "post": {
87
+ "summary": "Crear booking (pending + lock de inventario)",
88
+ "operationId": "createBooking",
89
+ "parameters": [
90
+ {
91
+ "name": "Idempotency-Key",
92
+ "in": "header",
93
+ "required": true,
94
+ "description": "Requerido para evitar duplicados en creación.",
95
+ "schema": { "type": "string", "maxLength": 128 }
96
+ }
97
+ ],
98
+ "requestBody": {
99
+ "required": true,
100
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBookingInput" } } }
101
+ },
102
+ "responses": {
103
+ "201": {
104
+ "description": "Creado",
105
+ "headers": {
106
+ "Location": { "schema": { "type": "string" }, "description": "URL del booking creado." }
107
+ },
108
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Booking" } } }
109
+ },
110
+ "400": { "$ref": "#/components/responses/BadRequest" },
111
+ "409": { "$ref": "#/components/responses/Conflict" },
112
+ "422": { "$ref": "#/components/responses/UnprocessableEntity" }
113
+ }
114
+ }
115
+ },
116
+ "/bookings/{bookingId}": {
117
+ "get": {
118
+ "summary": "Obtener booking por ID",
119
+ "operationId": "getBooking",
120
+ "parameters": [
121
+ { "name": "bookingId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
122
+ ],
123
+ "responses": {
124
+ "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Booking" } } } },
125
+ "400": { "$ref": "#/components/responses/BadRequest" },
126
+ "404": { "$ref": "#/components/responses/NotFound" }
127
+ }
128
+ }
129
+ },
130
+ "/webhooks/payments/{provider}": {
131
+ "post": {
132
+ "summary": "Webhook de pagos (firma validada por API)",
133
+ "operationId": "paymentsWebhook",
134
+ "security": [],
135
+ "parameters": [
136
+ { "name": "provider", "in": "path", "required": true, "schema": { "type": "string", "enum": ["wompi", "epayco", "other"] } }
137
+ ],
138
+ "requestBody": {
139
+ "required": true,
140
+ "content": {
141
+ "application/json": { "schema": { "$ref": "#/components/schemas/PaymentWebhookPayload" } }
142
+ }
143
+ },
144
+ "responses": {
145
+ "202": { "description": "Aceptado para procesamiento asíncrono" },
146
+ "400": { "$ref": "#/components/responses/BadRequest" },
147
+ "401": { "$ref": "#/components/responses/Unauthorized" }
148
+ }
149
+ }
150
+ }
151
+ },
152
+ "components": {
153
+ "securitySchemes": {
154
+ "BearerAuth": {
155
+ "type": "http",
156
+ "scheme": "bearer",
157
+ "bearerFormat": "JWT"
158
+ }
159
+ },
160
+ "schemas": {
161
+ "UUID": { "type": "string", "format": "uuid" },
162
+ "Money": {
163
+ "type": "object",
164
+ "properties": {
165
+ "amount": { "type": "integer", "minimum": 0, "description": "Centavos" },
166
+ "currency": { "type": "string", "minLength": 3, "maxLength": 3, "example": "COP" }
167
+ },
168
+ "required": ["amount", "currency"],
169
+ "additionalProperties": false
170
+ },
171
+ "ExperienceSummary": {
172
+ "type": "object",
173
+ "properties": {
174
+ "id": { "$ref": "#/components/schemas/UUID" },
175
+ "title": { "type": "string" },
176
+ "coverImageUrl": { "type": "string", "format": "uri" },
177
+ "city": { "type": "string" },
178
+ "country": { "type": "string" },
179
+ "ratingAvg": { "type": "number", "minimum": 0, "maximum": 5 },
180
+ "ratingCount": { "type": "integer", "minimum": 0 },
181
+ "fromPrice": { "$ref": "#/components/schemas/Money" }
182
+ },
183
+ "required": ["id", "title", "fromPrice"]
184
+ },
185
+ "Experience": {
186
+ "allOf": [
187
+ { "$ref": "#/components/schemas/ExperienceSummary" },
188
+ {
189
+ "type": "object",
190
+ "properties": {
191
+ "description": { "type": "string" },
192
+ "includes": { "type": "array", "items": { "type": "string" } },
193
+ "notIncludes": { "type": "array", "items": { "type": "string" } },
194
+ "images": { "type": "array", "items": { "type": "string", "format": "uri" } },
195
+ "status": { "type": "string", "enum": ["draft", "under_review", "active", "rejected"] }
196
+ },
197
+ "required": ["status"]
198
+ }
199
+ ]
200
+ },
201
+ "AvailabilitySlot": {
202
+ "type": "object",
203
+ "properties": {
204
+ "slotId": { "$ref": "#/components/schemas/UUID" },
205
+ "start": { "type": "string", "format": "date-time" },
206
+ "end": { "type": "string", "format": "date-time" },
207
+ "capacity": { "type": "integer", "minimum": 1 },
208
+ "remaining": { "type": "integer", "minimum": 0 },
209
+ "price": { "$ref": "#/components/schemas/Money" }
210
+ },
211
+ "required": ["slotId", "start", "end", "capacity", "remaining", "price"]
212
+ },
213
+ "CreateBookingInput": {
214
+ "type": "object",
215
+ "properties": {
216
+ "experienceId": { "$ref": "#/components/schemas/UUID" },
217
+ "slotId": { "$ref": "#/components/schemas/UUID" },
218
+ "quantity": { "type": "integer", "minimum": 1 },
219
+ "buyer": {
220
+ "type": "object",
221
+ "properties": {
222
+ "fullName": { "type": "string" },
223
+ "email": { "type": "string", "format": "email" },
224
+ "phone": { "type": "string" }
225
+ },
226
+ "required": ["fullName", "email"]
227
+ },
228
+ "payment": {
229
+ "type": "object",
230
+ "properties": {
231
+ "method": { "type": "string", "enum": ["card", "pse", "cash", "other"] },
232
+ "provider": { "type": "string", "enum": ["wompi", "epayco", "other"] }
233
+ },
234
+ "required": ["method", "provider"]
235
+ }
236
+ },
237
+ "required": ["experienceId", "slotId", "quantity", "buyer", "payment"],
238
+ "additionalProperties": false
239
+ },
240
+ "Booking": {
241
+ "type": "object",
242
+ "properties": {
243
+ "id": { "$ref": "#/components/schemas/UUID" },
244
+ "status": { "type": "string", "enum": ["pending", "confirmed", "completed", "cancelled", "refunded", "expired"] },
245
+ "experienceId": { "$ref": "#/components/schemas/UUID" },
246
+ "slotId": { "$ref": "#/components/schemas/UUID" },
247
+ "quantity": { "type": "integer", "minimum": 1 },
248
+ "total": { "$ref": "#/components/schemas/Money" },
249
+ "createdAt": { "type": "string", "format": "date-time" }
250
+ },
251
+ "required": ["id", "status", "experienceId", "slotId", "quantity", "total", "createdAt"]
252
+ },
253
+ "PaymentWebhookPayload": {
254
+ "type": "object",
255
+ "properties": {
256
+ "event": { "type": "string", "example": "transaction.updated" },
257
+ "data": {
258
+ "type": "object",
259
+ "properties": {
260
+ "providerRef": { "type": "string" },
261
+ "status": { "type": "string", "enum": ["APPROVED", "DECLINED", "VOIDED", "ERROR", "PENDING"] },
262
+ "amountInCents": { "type": "integer", "minimum": 0 },
263
+ "currency": { "type": "string", "minLength": 3, "maxLength": 3 },
264
+ "bookingId": { "type": "string", "format": "uuid", "description": "Opcional si el flujo incluye referencia directa al booking." }
265
+ },
266
+ "required": ["providerRef", "status", "amountInCents", "currency"]
267
+ },
268
+ "sentAt": { "type": "string", "format": "date-time" }
269
+ },
270
+ "required": ["event", "data"]
271
+ },
272
+ "Error": {
273
+ "type": "object",
274
+ "properties": {
275
+ "error_code": { "type": "string" },
276
+ "message": { "type": "string" },
277
+ "details": { "type": ["object", "null"] }
278
+ },
279
+ "required": ["error_code", "message"]
280
+ }
281
+ },
282
+ "responses": {
283
+ "BadRequest": {
284
+ "description": "Solicitud inválida",
285
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
286
+ },
287
+ "Unauthorized": { "description": "No autorizado" },
288
+ "NotFound": {
289
+ "description": "No encontrado",
290
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
291
+ },
292
+ "Conflict": {
293
+ "description": "Conflicto (idempotencia, duplicado, etc.)",
294
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
295
+ },
296
+ "UnprocessableEntity": {
297
+ "description": "Validación fallida",
298
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
299
+ }
300
+ }
301
+ }
302
+ }
303
+
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@livex/contracts",
3
+ "version": "0.1.0",
4
+ "description": "Contratos compartidos LIVEX (OpenAPI v1 + esquemas de eventos)",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "dist/index.cjs",
8
+ "module": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "files": [
11
+ "dist",
12
+ "openapi",
13
+ "messages",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "./openapi": "./openapi/livex.v1.json",
25
+ "./messages/*": "./messages/*"
26
+ },
27
+ "scripts": {
28
+ "clean": "rimraf dist",
29
+ "build": "tsup src/index.ts src/validators.ts --dts --format esm,cjs --clean",
30
+ "typecheck": "tsc --noEmit",
31
+ "lint:openapi": "npx @redocly/cli lint openapi/livex.v1.json",
32
+ "validate:schemas": "node -e \"import('./dist/validators.js').then(()=>console.log('AJV ready'))\"",
33
+ "prepublishOnly": "npm run clean && npm run typecheck && npm run build && npm run lint:openapi"
34
+ },
35
+ "devDependencies": {
36
+ "@redocly/cli": "^1.28.0",
37
+ "rimraf": "^5.0.5",
38
+ "tsup": "^8.0.2",
39
+ "typescript": "^5.6.3"
40
+ },
41
+ "dependencies": {
42
+ "ajv": "^8.17.1",
43
+ "ajv-formats": "^3.0.1"
44
+ },
45
+ "keywords": ["openapi", "contracts", "schemas", "livex"],
46
+ "repository": { "type": "git", "url": "https://github.com/tu-org/livex-contracts.git" },
47
+ "publishConfig": { "access": "public" },
48
+ "overrides": {
49
+ "mobx-react-lite": "4.1.0"
50
+ }
51
+ }