@danceroutine/tango-resources 0.1.0 → 1.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +170 -0
  3. package/dist/context/RequestContext.d.ts +23 -4
  4. package/dist/filters/FilterSet.d.ts +59 -4
  5. package/dist/filters/index.d.ts +1 -1
  6. package/dist/index.d.ts +10 -4
  7. package/dist/index.js +515 -205
  8. package/dist/index.js.map +1 -1
  9. package/dist/pagination/CursorPaginationInput.d.ts +7 -0
  10. package/dist/pagination/OffsetPaginationInput.d.ts +7 -0
  11. package/dist/pagination/PaginatedResponse.d.ts +8 -2
  12. package/dist/pagination/Paginator.d.ts +5 -3
  13. package/dist/pagination/index.d.ts +5 -3
  14. package/dist/paginators/CursorPaginator.d.ts +32 -6
  15. package/dist/paginators/OffsetPaginator.d.ts +30 -7
  16. package/dist/resource/OpenAPIDescription.d.ts +21 -0
  17. package/dist/resource/ResourceModelLike.d.ts +16 -0
  18. package/dist/resource/index.d.ts +5 -0
  19. package/dist/serializer/ModelSerializer.d.ts +47 -0
  20. package/dist/serializer/Serializer.d.ts +52 -0
  21. package/dist/serializer/index.d.ts +5 -0
  22. package/dist/view/APIView.d.ts +26 -0
  23. package/dist/view/GenericAPIView.d.ts +57 -0
  24. package/dist/view/generics/CreateAPIView.d.ts +10 -0
  25. package/dist/view/generics/ListAPIView.d.ts +10 -0
  26. package/dist/view/generics/ListCreateAPIView.d.ts +11 -0
  27. package/dist/view/generics/RetrieveAPIView.d.ts +10 -0
  28. package/dist/view/generics/RetrieveDestroyAPIView.d.ts +11 -0
  29. package/dist/view/generics/RetrieveUpdateAPIView.d.ts +12 -0
  30. package/dist/view/generics/RetrieveUpdateDestroyAPIView.d.ts +13 -0
  31. package/dist/view/generics/index.d.ts +10 -0
  32. package/dist/view/index.d.ts +8 -0
  33. package/dist/view/index.js +3 -0
  34. package/dist/view/mixins/CreateModelMixin.d.ts +11 -0
  35. package/dist/view/mixins/DestroyModelMixin.d.ts +11 -0
  36. package/dist/view/mixins/ListModelMixin.d.ts +11 -0
  37. package/dist/view/mixins/RetrieveModelMixin.d.ts +11 -0
  38. package/dist/view/mixins/UpdateModelMixin.d.ts +12 -0
  39. package/dist/view/mixins/index.d.ts +8 -0
  40. package/dist/view-BNGEURL_.js +547 -0
  41. package/dist/view-BNGEURL_.js.map +1 -0
  42. package/dist/viewset/ModelViewSet.d.ts +91 -45
  43. package/dist/viewset/index.d.ts +2 -1
  44. package/package.json +75 -69
  45. package/dist/domain/index.d.ts +0 -8
  46. package/dist/pagination/PaginationInput.d.ts +0 -7
  47. package/dist/viewset/ModelViewSet.js +0 -143
@@ -0,0 +1,547 @@
1
+ import { HttpErrorFactory, NotFoundError, TangoResponse, TangoResponse as TangoResponse$1 } from "@danceroutine/tango-core";
2
+ import { z } from "zod";
3
+ import { Q } from "@danceroutine/tango-orm";
4
+
5
+ //#region rolldown:runtime
6
+ var __defProp = Object.defineProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ };
13
+
14
+ //#endregion
15
+ //#region src/pagination/OffsetPaginationInput.ts
16
+ const OffsetPaginationInput = z.object({
17
+ limit: z.coerce.number().int().min(1).default(25).transform((value) => Math.min(value, 100)),
18
+ offset: z.coerce.number().int().min(0).default(0),
19
+ page: z.coerce.number().int().min(1).optional()
20
+ });
21
+
22
+ //#endregion
23
+ //#region src/paginators/OffsetPaginator.ts
24
+ var OffsetPage = class OffsetPage {
25
+ static BRAND = "tango.resources.offset_page";
26
+ __tangoBrand = OffsetPage.BRAND;
27
+ constructor(results, pageNumber, perPage, totalCount) {
28
+ this.results = results;
29
+ this.pageNumber = pageNumber;
30
+ this.perPage = perPage;
31
+ this.totalCount = totalCount;
32
+ }
33
+ static isOffsetPage(value) {
34
+ return typeof value === "object" && value !== null && value.__tangoBrand === OffsetPage.BRAND;
35
+ }
36
+ /** Whether a next page exists based on known total count. */
37
+ hasNext() {
38
+ if (this.totalCount === undefined) return false;
39
+ return this.endIndex() < this.totalCount;
40
+ }
41
+ /** Whether a previous page exists. */
42
+ hasPrevious() {
43
+ return this.pageNumber > 1;
44
+ }
45
+ /** The next page number, if available. */
46
+ nextPageNumber() {
47
+ return this.hasNext() ? this.pageNumber + 1 : null;
48
+ }
49
+ /** The previous page number, if available. */
50
+ previousPageNumber() {
51
+ return this.hasPrevious() ? this.pageNumber - 1 : null;
52
+ }
53
+ /** Zero-based start index of this page in the full result set. */
54
+ startIndex() {
55
+ return (this.pageNumber - 1) * this.perPage;
56
+ }
57
+ /** Exclusive end index of this page in the full result set. */
58
+ endIndex() {
59
+ return this.startIndex() + this.results.length;
60
+ }
61
+ };
62
+ var OffsetPaginator = class OffsetPaginator {
63
+ static BRAND = "tango.resources.offset_paginator";
64
+ __tangoBrand = OffsetPaginator.BRAND;
65
+ limit = 25;
66
+ offset = 0;
67
+ constructor(queryset, perPage = 25) {
68
+ this.queryset = queryset;
69
+ this.perPage = perPage;
70
+ this.limit = perPage;
71
+ }
72
+ /**
73
+ * Narrow an unknown value to `OffsetPaginator`.
74
+ */
75
+ static isOffsetPaginator(value) {
76
+ return typeof value === "object" && value !== null && value.__tangoBrand === OffsetPaginator.BRAND;
77
+ }
78
+ /**
79
+ * Parse limit, offset, and page from Tango query params.
80
+ * If `page` is provided, it's converted to an offset.
81
+ * Stores parsed values for use by getPaginatedResponse.
82
+ */
83
+ parse(params) {
84
+ const input = {
85
+ limit: params.get("limit") ?? undefined,
86
+ offset: params.get("offset") ?? undefined,
87
+ page: params.get("page") ?? undefined
88
+ };
89
+ const parsed = OffsetPaginationInput.parse(input);
90
+ if (parsed.page) parsed.offset = (parsed.page - 1) * parsed.limit;
91
+ this.limit = parsed.limit;
92
+ this.offset = parsed.offset;
93
+ }
94
+ /**
95
+ * Parse params and return `{ limit, offset }` for compatibility callers.
96
+ */
97
+ parseParams(params) {
98
+ this.parse(params);
99
+ return {
100
+ limit: this.limit,
101
+ offset: this.offset
102
+ };
103
+ }
104
+ /**
105
+ * Build a DRF-style paginated response with count, next, and previous links.
106
+ * Uses the limit/offset stored from the most recent parseParams call.
107
+ */
108
+ needsTotalCount() {
109
+ return true;
110
+ }
111
+ toResponse(results, context) {
112
+ const totalCount = context?.totalCount;
113
+ const response = { results };
114
+ if (totalCount !== undefined) {
115
+ response.count = totalCount;
116
+ if (this.offset + this.limit < totalCount) response.next = `?limit=${this.limit}&offset=${this.offset + this.limit}`;
117
+ if (this.offset > 0) {
118
+ const prevOffset = Math.max(0, this.offset - this.limit);
119
+ response.previous = `?limit=${this.limit}&offset=${prevOffset}`;
120
+ }
121
+ }
122
+ return response;
123
+ }
124
+ /**
125
+ * Backward-compatible alias for `toResponse`.
126
+ */
127
+ getPaginatedResponse(results, totalCount) {
128
+ return this.toResponse(results, { totalCount });
129
+ }
130
+ /**
131
+ * Apply current limit/offset to a queryset.
132
+ */
133
+ apply(queryset) {
134
+ return queryset.limit(this.limit).offset(this.offset);
135
+ }
136
+ /**
137
+ * Fetch a 1-based page number from the bound queryset.
138
+ */
139
+ async paginate(page) {
140
+ return this.getPage(page);
141
+ }
142
+ /**
143
+ * Fetch a 1-based page and return page metadata.
144
+ */
145
+ async getPage(page) {
146
+ const offset = (page - 1) * this.perPage;
147
+ const results = await this.queryset.offset(offset).limit(this.perPage).fetch();
148
+ const totalCount = await this.count();
149
+ return new OffsetPage(results.results, page, this.perPage, totalCount);
150
+ }
151
+ /**
152
+ * Count total rows for the current queryset state.
153
+ */
154
+ async count() {
155
+ return this.queryset.count();
156
+ }
157
+ };
158
+
159
+ //#endregion
160
+ //#region src/view/APIView.ts
161
+ var APIView = class APIView {
162
+ static BRAND = "tango.resources.api_view";
163
+ __tangoBrand = APIView.BRAND;
164
+ /**
165
+ * Narrow an unknown value to `APIView`.
166
+ */
167
+ static isAPIView(value) {
168
+ return typeof value === "object" && value !== null && value.__tangoBrand === APIView.BRAND;
169
+ }
170
+ /**
171
+ * Dispatch the request to the handler for the current HTTP method.
172
+ */
173
+ async dispatch(ctx) {
174
+ const method = normalizeMethod(ctx.request.method);
175
+ if (!method) return this.httpMethodNotAllowed();
176
+ const handler = this.getMethodHandler(method);
177
+ return handler(ctx);
178
+ }
179
+ getAllowedMethods() {
180
+ const allowed = [];
181
+ if (this.get !== APIView.prototype.get) allowed.push("GET");
182
+ if (this.post !== APIView.prototype.post) allowed.push("POST");
183
+ if (this.put !== APIView.prototype.put) allowed.push("PUT");
184
+ if (this.patch !== APIView.prototype.patch) allowed.push("PATCH");
185
+ if (this.delete !== APIView.prototype.delete) allowed.push("DELETE");
186
+ return allowed;
187
+ }
188
+ get(_ctx) {
189
+ return Promise.resolve(this.httpMethodNotAllowed());
190
+ }
191
+ post(_ctx) {
192
+ return Promise.resolve(this.httpMethodNotAllowed());
193
+ }
194
+ put(_ctx) {
195
+ return Promise.resolve(this.httpMethodNotAllowed());
196
+ }
197
+ patch(_ctx) {
198
+ return Promise.resolve(this.httpMethodNotAllowed());
199
+ }
200
+ delete(_ctx) {
201
+ return Promise.resolve(this.httpMethodNotAllowed());
202
+ }
203
+ httpMethodNotAllowed() {
204
+ return TangoResponse$1.methodNotAllowed(this.getAllowedMethods());
205
+ }
206
+ getMethodHandler(method) {
207
+ if (method === "GET") return (ctx) => this.get(ctx);
208
+ if (method === "POST") return (ctx) => this.post(ctx);
209
+ if (method === "PUT") return (ctx) => this.put(ctx);
210
+ if (method === "PATCH") return (ctx) => this.patch(ctx);
211
+ return (ctx) => this.delete(ctx);
212
+ }
213
+ };
214
+ function normalizeMethod(method) {
215
+ const upper = method.toUpperCase();
216
+ if (upper === "GET") return "GET";
217
+ if (upper === "POST") return "POST";
218
+ if (upper === "PUT") return "PUT";
219
+ if (upper === "PATCH") return "PATCH";
220
+ if (upper === "DELETE") return "DELETE";
221
+ return null;
222
+ }
223
+
224
+ //#endregion
225
+ //#region src/view/GenericAPIView.ts
226
+ var GenericAPIView = class extends APIView {
227
+ serializerClass;
228
+ filters;
229
+ orderingFields;
230
+ searchFields;
231
+ lookupField;
232
+ lookupParam;
233
+ paginatorFactory;
234
+ serializer;
235
+ constructor(config) {
236
+ super();
237
+ this.serializerClass = config.serializer;
238
+ this.filters = config.filters;
239
+ this.orderingFields = config.orderingFields ?? [];
240
+ this.searchFields = config.searchFields ?? [];
241
+ this.lookupField = config.lookupField;
242
+ this.lookupParam = config.lookupParam ?? "id";
243
+ this.paginatorFactory = config.paginatorFactory;
244
+ }
245
+ /**
246
+ * Return the serializer class that owns this resource contract.
247
+ */
248
+ getSerializerClass() {
249
+ return this.serializerClass;
250
+ }
251
+ /**
252
+ * Return the serializer instance for the current resource.
253
+ */
254
+ getSerializer() {
255
+ if (!this.serializer) this.serializer = new this.serializerClass();
256
+ return this.serializer;
257
+ }
258
+ /**
259
+ * Describe the public HTTP contract that this resource contributes to OpenAPI generation.
260
+ */
261
+ describeOpenAPI() {
262
+ return {
263
+ model: this.requireModelMetadata(),
264
+ outputSchema: this.getOutputSchema(),
265
+ createSchema: this.getCreateSchema(),
266
+ updateSchema: this.getUpdateSchema(),
267
+ searchFields: this.searchFields,
268
+ orderingFields: this.orderingFields,
269
+ lookupField: this.getLookupField(),
270
+ lookupParam: this.lookupParam,
271
+ allowedMethods: this.getAllowedMethods(),
272
+ usesDefaultOffsetPagination: !this.paginatorFactory
273
+ };
274
+ }
275
+ getManager() {
276
+ return this.getSerializer().getManager();
277
+ }
278
+ getOutputSchema() {
279
+ return this.getSerializer().getOutputSchema();
280
+ }
281
+ getCreateSchema() {
282
+ return this.getSerializer().getCreateSchema();
283
+ }
284
+ getUpdateSchema() {
285
+ return this.getSerializer().getUpdateSchema();
286
+ }
287
+ getLookupField() {
288
+ return this.lookupField ?? this.getManager().meta.pk;
289
+ }
290
+ getLookupValue(ctx) {
291
+ const value = ctx.params[this.lookupParam]?.trim();
292
+ return value || null;
293
+ }
294
+ getPaginator(queryset) {
295
+ if (this.paginatorFactory) return this.paginatorFactory(queryset);
296
+ return new OffsetPaginator(queryset);
297
+ }
298
+ async performList(ctx) {
299
+ try {
300
+ const params = ctx.request.queryParams;
301
+ const baseQueryset = this.getManager().query();
302
+ const paginator = this.getPaginator(baseQueryset);
303
+ paginator.parse(params);
304
+ let qs = baseQueryset;
305
+ if (this.filters) {
306
+ const filterInputs = this.filters.apply(params);
307
+ if (filterInputs.length > 0) qs = qs.filter(Q.and(...filterInputs));
308
+ }
309
+ const search = params.getSearch();
310
+ if (search && this.searchFields.length > 0) {
311
+ const searchFilters = this.searchFields.map((field) => {
312
+ const lookup = `${String(field)}__icontains`;
313
+ return { [lookup]: search };
314
+ });
315
+ qs = qs.filter(Q.or(...searchFilters));
316
+ }
317
+ const ordering = params.getOrdering();
318
+ if (ordering.length > 0) {
319
+ const orderTokens = ordering.filter((field) => {
320
+ const cleanField = field.startsWith("-") ? field.slice(1) : field;
321
+ return this.orderingFields.includes(cleanField);
322
+ });
323
+ if (orderTokens.length > 0) qs = qs.orderBy(...orderTokens.map((token) => token));
324
+ }
325
+ qs = paginator.apply(qs);
326
+ const resultPromise = qs.fetch();
327
+ const totalCountPromise = paginator.needsTotalCount() ? qs.count() : Promise.resolve(undefined);
328
+ const [result, totalCount] = await Promise.all([resultPromise, totalCountPromise]);
329
+ const serializer = this.getSerializer();
330
+ const response = paginator.toResponse(result.results.map((row) => serializer.toRepresentation(row)), { totalCount });
331
+ return TangoResponse.json(response, { status: 200 });
332
+ } catch (error) {
333
+ return this.handleError(error);
334
+ }
335
+ }
336
+ async performCreate(ctx) {
337
+ try {
338
+ const body = await ctx.request.json();
339
+ const result = await this.getSerializer().create(body);
340
+ return TangoResponse.created(undefined, result);
341
+ } catch (error) {
342
+ return this.handleError(error);
343
+ }
344
+ }
345
+ async performRetrieve(ctx) {
346
+ try {
347
+ const value = this.getLookupValue(ctx);
348
+ if (!value) throw new NotFoundError("Lookup parameter was not provided.");
349
+ const lookupField = this.getLookupField();
350
+ const filterByLookup = { [lookupField]: value };
351
+ const result = await this.getManager().query().filter(filterByLookup).fetchOne();
352
+ if (!result) throw new NotFoundError(`No ${this.getManager().meta.table} record found for ${String(lookupField)}=${value}.`);
353
+ return TangoResponse.json(this.getSerializer().toRepresentation(result), { status: 200 });
354
+ } catch (error) {
355
+ return this.handleError(error);
356
+ }
357
+ }
358
+ async performUpdate(ctx) {
359
+ try {
360
+ const value = this.getLookupValue(ctx);
361
+ if (!value) throw new NotFoundError("Lookup parameter was not provided.");
362
+ const body = await ctx.request.json();
363
+ const result = await this.getSerializer().update(value, body);
364
+ return TangoResponse.json(result, { status: 200 });
365
+ } catch (error) {
366
+ return this.handleError(error);
367
+ }
368
+ }
369
+ async performDestroy(ctx) {
370
+ try {
371
+ const value = this.getLookupValue(ctx);
372
+ if (!value) throw new NotFoundError("Lookup parameter was not provided.");
373
+ await this.getManager().delete(value);
374
+ return TangoResponse.noContent();
375
+ } catch (error) {
376
+ return this.handleError(error);
377
+ }
378
+ }
379
+ handleError(error) {
380
+ const httpError = HttpErrorFactory.toHttpError(error);
381
+ return TangoResponse.json(httpError.body, { status: httpError.status });
382
+ }
383
+ requireModelMetadata() {
384
+ const model = this.getSerializer().getModel();
385
+ if (!model.metadata) throw new Error("OpenAPI generation requires Tango model metadata on GenericAPIView models.");
386
+ return model;
387
+ }
388
+ };
389
+
390
+ //#endregion
391
+ //#region src/view/mixins/ListModelMixin.ts
392
+ var ListModelMixin = class extends GenericAPIView {
393
+ list(ctx) {
394
+ return this.performList(ctx);
395
+ }
396
+ get(ctx) {
397
+ return this.list(ctx);
398
+ }
399
+ };
400
+
401
+ //#endregion
402
+ //#region src/view/mixins/CreateModelMixin.ts
403
+ var CreateModelMixin = class extends GenericAPIView {
404
+ create(ctx) {
405
+ return this.performCreate(ctx);
406
+ }
407
+ post(ctx) {
408
+ return this.create(ctx);
409
+ }
410
+ };
411
+
412
+ //#endregion
413
+ //#region src/view/mixins/RetrieveModelMixin.ts
414
+ var RetrieveModelMixin = class extends GenericAPIView {
415
+ retrieve(ctx) {
416
+ return this.performRetrieve(ctx);
417
+ }
418
+ get(ctx) {
419
+ return this.retrieve(ctx);
420
+ }
421
+ };
422
+
423
+ //#endregion
424
+ //#region src/view/mixins/UpdateModelMixin.ts
425
+ var UpdateModelMixin = class extends GenericAPIView {
426
+ update(ctx) {
427
+ return this.performUpdate(ctx);
428
+ }
429
+ put(ctx) {
430
+ return this.update(ctx);
431
+ }
432
+ patch(ctx) {
433
+ return this.update(ctx);
434
+ }
435
+ };
436
+
437
+ //#endregion
438
+ //#region src/view/mixins/DestroyModelMixin.ts
439
+ var DestroyModelMixin = class extends GenericAPIView {
440
+ destroy(ctx) {
441
+ return this.performDestroy(ctx);
442
+ }
443
+ delete(ctx) {
444
+ return this.destroy(ctx);
445
+ }
446
+ };
447
+
448
+ //#endregion
449
+ //#region src/view/generics/ListAPIView.ts
450
+ var ListAPIView = class extends ListModelMixin {
451
+ get(ctx) {
452
+ return super.get(ctx);
453
+ }
454
+ };
455
+
456
+ //#endregion
457
+ //#region src/view/generics/CreateAPIView.ts
458
+ var CreateAPIView = class extends CreateModelMixin {
459
+ post(ctx) {
460
+ return super.post(ctx);
461
+ }
462
+ };
463
+
464
+ //#endregion
465
+ //#region src/view/generics/RetrieveAPIView.ts
466
+ var RetrieveAPIView = class extends RetrieveModelMixin {
467
+ get(ctx) {
468
+ return super.get(ctx);
469
+ }
470
+ };
471
+
472
+ //#endregion
473
+ //#region src/view/generics/ListCreateAPIView.ts
474
+ var ListCreateAPIView = class extends GenericAPIView {
475
+ get(ctx) {
476
+ return this.performList(ctx);
477
+ }
478
+ post(ctx) {
479
+ return this.performCreate(ctx);
480
+ }
481
+ };
482
+
483
+ //#endregion
484
+ //#region src/view/generics/RetrieveUpdateAPIView.ts
485
+ var RetrieveUpdateAPIView = class extends GenericAPIView {
486
+ get(ctx) {
487
+ return this.performRetrieve(ctx);
488
+ }
489
+ put(ctx) {
490
+ return this.performUpdate(ctx);
491
+ }
492
+ patch(ctx) {
493
+ return this.performUpdate(ctx);
494
+ }
495
+ };
496
+
497
+ //#endregion
498
+ //#region src/view/generics/RetrieveDestroyAPIView.ts
499
+ var RetrieveDestroyAPIView = class extends GenericAPIView {
500
+ get(ctx) {
501
+ return this.performRetrieve(ctx);
502
+ }
503
+ delete(ctx) {
504
+ return this.performDestroy(ctx);
505
+ }
506
+ };
507
+
508
+ //#endregion
509
+ //#region src/view/generics/RetrieveUpdateDestroyAPIView.ts
510
+ var RetrieveUpdateDestroyAPIView = class extends GenericAPIView {
511
+ get(ctx) {
512
+ return this.performRetrieve(ctx);
513
+ }
514
+ put(ctx) {
515
+ return this.performUpdate(ctx);
516
+ }
517
+ patch(ctx) {
518
+ return this.performUpdate(ctx);
519
+ }
520
+ delete(ctx) {
521
+ return this.performDestroy(ctx);
522
+ }
523
+ };
524
+
525
+ //#endregion
526
+ //#region src/view/index.ts
527
+ var view_exports = {};
528
+ __export(view_exports, {
529
+ APIView: () => APIView,
530
+ CreateAPIView: () => CreateAPIView,
531
+ CreateModelMixin: () => CreateModelMixin,
532
+ DestroyModelMixin: () => DestroyModelMixin,
533
+ GenericAPIView: () => GenericAPIView,
534
+ ListAPIView: () => ListAPIView,
535
+ ListCreateAPIView: () => ListCreateAPIView,
536
+ ListModelMixin: () => ListModelMixin,
537
+ RetrieveAPIView: () => RetrieveAPIView,
538
+ RetrieveDestroyAPIView: () => RetrieveDestroyAPIView,
539
+ RetrieveModelMixin: () => RetrieveModelMixin,
540
+ RetrieveUpdateAPIView: () => RetrieveUpdateAPIView,
541
+ RetrieveUpdateDestroyAPIView: () => RetrieveUpdateDestroyAPIView,
542
+ UpdateModelMixin: () => UpdateModelMixin
543
+ });
544
+
545
+ //#endregion
546
+ export { APIView, CreateAPIView, CreateModelMixin, DestroyModelMixin, GenericAPIView, ListAPIView, ListCreateAPIView, ListModelMixin, OffsetPaginationInput, OffsetPaginator, RetrieveAPIView, RetrieveDestroyAPIView, RetrieveModelMixin, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, UpdateModelMixin, __export, view_exports };
547
+ //# sourceMappingURL=view-BNGEURL_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-BNGEURL_.js","names":["OffsetPaginationInput: z.ZodType<OffsetPaginationInputValue>","results: T[]","pageNumber: number","perPage: number","totalCount?: number","value: unknown","queryset: QuerySet<T>","params: TangoQueryParams","results: TResult[]","context?: { totalCount?: number }","response: OffsetPaginatedResponse<TResult>","page: number","value: unknown","ctx: RequestContext","allowed: APIViewMethod[]","_ctx: RequestContext","method: APIViewMethod","method: string","config: GenericAPIViewConfig<TModel, TSerializer>","ctx: RequestContext","queryset: QuerySet<TModel>","searchFilters: FilterInput<TModel>[]","error: unknown","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext","ctx: RequestContext"],"sources":["../src/pagination/OffsetPaginationInput.ts","../src/paginators/OffsetPaginator.ts","../src/view/APIView.ts","../src/view/GenericAPIView.ts","../src/view/mixins/ListModelMixin.ts","../src/view/mixins/CreateModelMixin.ts","../src/view/mixins/RetrieveModelMixin.ts","../src/view/mixins/UpdateModelMixin.ts","../src/view/mixins/DestroyModelMixin.ts","../src/view/generics/ListAPIView.ts","../src/view/generics/CreateAPIView.ts","../src/view/generics/RetrieveAPIView.ts","../src/view/generics/ListCreateAPIView.ts","../src/view/generics/RetrieveUpdateAPIView.ts","../src/view/generics/RetrieveDestroyAPIView.ts","../src/view/generics/RetrieveUpdateDestroyAPIView.ts","../src/view/index.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport type OffsetPaginationInputValue = {\n limit: number;\n offset: number;\n page?: number;\n};\n\nexport const OffsetPaginationInput: z.ZodType<OffsetPaginationInputValue> = z.object({\n limit: z.coerce\n .number()\n .int()\n .min(1)\n .default(25)\n .transform((value) => Math.min(value, 100)),\n offset: z.coerce.number().int().min(0).default(0),\n page: z.coerce.number().int().min(1).optional(),\n});\n","import { TangoQueryParams } from '@danceroutine/tango-core';\nimport type { QuerySet } from '@danceroutine/tango-orm';\nimport type { Paginator, Page } from '../pagination/Paginator';\nimport type { OffsetPaginatedResponse } from '../pagination/PaginatedResponse';\nimport { OffsetPaginationInput } from '../pagination/OffsetPaginationInput';\n\nclass OffsetPage<T> implements Page<T> {\n static readonly BRAND = 'tango.resources.offset_page' as const;\n readonly __tangoBrand: typeof OffsetPage.BRAND = OffsetPage.BRAND;\n\n constructor(\n public readonly results: T[],\n private readonly pageNumber: number,\n private readonly perPage: number,\n private readonly totalCount?: number\n ) {}\n\n static isOffsetPage<T>(value: unknown): value is OffsetPage<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === OffsetPage.BRAND\n );\n }\n\n /** Whether a next page exists based on known total count. */\n hasNext(): boolean {\n if (this.totalCount === undefined) {\n return false;\n }\n return this.endIndex() < this.totalCount;\n }\n\n /** Whether a previous page exists. */\n hasPrevious(): boolean {\n return this.pageNumber > 1;\n }\n\n /** The next page number, if available. */\n nextPageNumber(): number | null {\n return this.hasNext() ? this.pageNumber + 1 : null;\n }\n\n /** The previous page number, if available. */\n previousPageNumber(): number | null {\n return this.hasPrevious() ? this.pageNumber - 1 : null;\n }\n\n /** Zero-based start index of this page in the full result set. */\n startIndex(): number {\n return (this.pageNumber - 1) * this.perPage;\n }\n\n /** Exclusive end index of this page in the full result set. */\n endIndex(): number {\n return this.startIndex() + this.results.length;\n }\n}\n\n/**\n * Offset/limit paginator modelled after DRF's LimitOffsetPagination.\n * Handles parsing limit/offset/page from URL query params and building\n * the paginated response envelope with next/previous links.\n *\n * @example\n * ```typescript\n * const paginator = new OffsetPaginator(queryset);\n * const { limit, offset } = paginator.parseParams(searchParams);\n * const results = await queryset.limit(limit).offset(offset).fetchAll();\n * const response = paginator.getPaginatedResponse(results, totalCount);\n * ```\n */\nexport class OffsetPaginator<T extends Record<string, unknown>> implements Paginator<T, T, OffsetPaginatedResponse<T>> {\n static readonly BRAND = 'tango.resources.offset_paginator' as const;\n readonly __tangoBrand: typeof OffsetPaginator.BRAND = OffsetPaginator.BRAND;\n private limit = 25;\n private offset = 0;\n\n constructor(\n private queryset: QuerySet<T>,\n private perPage: number = 25\n ) {\n this.limit = perPage;\n }\n\n /**\n * Narrow an unknown value to `OffsetPaginator`.\n */\n static isOffsetPaginator<T extends Record<string, unknown>>(value: unknown): value is OffsetPaginator<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === OffsetPaginator.BRAND\n );\n }\n\n /**\n * Parse limit, offset, and page from Tango query params.\n * If `page` is provided, it's converted to an offset.\n * Stores parsed values for use by getPaginatedResponse.\n */\n parse(params: TangoQueryParams): void {\n const input = {\n limit: params.get('limit') ?? undefined,\n offset: params.get('offset') ?? undefined,\n page: params.get('page') ?? undefined,\n };\n\n const parsed = OffsetPaginationInput.parse(input);\n\n if (parsed.page) {\n parsed.offset = (parsed.page - 1) * parsed.limit;\n }\n\n this.limit = parsed.limit;\n this.offset = parsed.offset;\n }\n\n /**\n * Parse params and return `{ limit, offset }` for compatibility callers.\n */\n parseParams(params: TangoQueryParams): { limit: number; offset: number } {\n this.parse(params);\n return { limit: this.limit, offset: this.offset };\n }\n\n /**\n * Build a DRF-style paginated response with count, next, and previous links.\n * Uses the limit/offset stored from the most recent parseParams call.\n */\n needsTotalCount(): boolean {\n return true;\n }\n\n toResponse<TResult>(results: TResult[], context?: { totalCount?: number }): OffsetPaginatedResponse<TResult> {\n const totalCount = context?.totalCount;\n const response: OffsetPaginatedResponse<TResult> = { results };\n\n if (totalCount !== undefined) {\n response.count = totalCount;\n\n if (this.offset + this.limit < totalCount) {\n response.next = `?limit=${this.limit}&offset=${this.offset + this.limit}`;\n }\n\n if (this.offset > 0) {\n const prevOffset = Math.max(0, this.offset - this.limit);\n response.previous = `?limit=${this.limit}&offset=${prevOffset}`;\n }\n }\n\n return response;\n }\n\n /**\n * Backward-compatible alias for `toResponse`.\n */\n getPaginatedResponse<TResult>(results: TResult[], totalCount?: number): OffsetPaginatedResponse<TResult> {\n return this.toResponse(results, { totalCount });\n }\n\n /**\n * Apply current limit/offset to a queryset.\n */\n apply(queryset: QuerySet<T>): QuerySet<T> {\n return queryset.limit(this.limit).offset(this.offset);\n }\n\n /**\n * Fetch a 1-based page number from the bound queryset.\n */\n async paginate(page: number): Promise<Page<T>> {\n return this.getPage(page);\n }\n\n /**\n * Fetch a 1-based page and return page metadata.\n */\n async getPage(page: number): Promise<Page<T>> {\n const offset = (page - 1) * this.perPage;\n const results = await this.queryset.offset(offset).limit(this.perPage).fetch();\n\n const totalCount = await this.count();\n\n return new OffsetPage(results.results, page, this.perPage, totalCount);\n }\n\n /**\n * Count total rows for the current queryset state.\n */\n async count(): Promise<number> {\n return this.queryset.count();\n }\n}\n","import { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../context/index';\n\nexport type APIViewMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\ntype APIViewMethodHandler = (ctx: RequestContext) => Promise<TangoResponse>;\n\n/**\n * Lightweight class-based request dispatcher for non-model API endpoints.\n */\nexport abstract class APIView {\n static readonly BRAND = 'tango.resources.api_view' as const;\n readonly __tangoBrand: typeof APIView.BRAND = APIView.BRAND;\n\n /**\n * Narrow an unknown value to `APIView`.\n */\n static isAPIView(value: unknown): value is APIView {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === APIView.BRAND\n );\n }\n\n /**\n * Dispatch the request to the handler for the current HTTP method.\n */\n async dispatch(ctx: RequestContext): Promise<TangoResponse> {\n const method = normalizeMethod(ctx.request.method);\n if (!method) {\n return this.httpMethodNotAllowed();\n }\n\n const handler = this.getMethodHandler(method);\n return handler(ctx);\n }\n\n getAllowedMethods(): readonly APIViewMethod[] {\n const allowed: APIViewMethod[] = [];\n if (this.get !== APIView.prototype.get) {\n allowed.push('GET');\n }\n if (this.post !== APIView.prototype.post) {\n allowed.push('POST');\n }\n if (this.put !== APIView.prototype.put) {\n allowed.push('PUT');\n }\n if (this.patch !== APIView.prototype.patch) {\n allowed.push('PATCH');\n }\n if (this.delete !== APIView.prototype.delete) {\n allowed.push('DELETE');\n }\n return allowed;\n }\n\n protected get(_ctx: RequestContext): Promise<TangoResponse> {\n return Promise.resolve(this.httpMethodNotAllowed());\n }\n\n protected post(_ctx: RequestContext): Promise<TangoResponse> {\n return Promise.resolve(this.httpMethodNotAllowed());\n }\n\n protected put(_ctx: RequestContext): Promise<TangoResponse> {\n return Promise.resolve(this.httpMethodNotAllowed());\n }\n\n protected patch(_ctx: RequestContext): Promise<TangoResponse> {\n return Promise.resolve(this.httpMethodNotAllowed());\n }\n\n protected delete(_ctx: RequestContext): Promise<TangoResponse> {\n return Promise.resolve(this.httpMethodNotAllowed());\n }\n\n protected httpMethodNotAllowed(): TangoResponse {\n return TangoResponse.methodNotAllowed(this.getAllowedMethods());\n }\n\n private getMethodHandler(method: APIViewMethod): APIViewMethodHandler {\n if (method === 'GET') {\n return (ctx) => this.get(ctx);\n }\n if (method === 'POST') {\n return (ctx) => this.post(ctx);\n }\n if (method === 'PUT') {\n return (ctx) => this.put(ctx);\n }\n if (method === 'PATCH') {\n return (ctx) => this.patch(ctx);\n }\n return (ctx) => this.delete(ctx);\n }\n}\n\nfunction normalizeMethod(method: string): APIViewMethod | null {\n const upper = method.toUpperCase();\n if (upper === 'GET') {\n return 'GET';\n }\n if (upper === 'POST') {\n return 'POST';\n }\n if (upper === 'PUT') {\n return 'PUT';\n }\n if (upper === 'PATCH') {\n return 'PATCH';\n }\n if (upper === 'DELETE') {\n return 'DELETE';\n }\n return null;\n}\n","import { HttpErrorFactory, TangoResponse, type JsonValue, NotFoundError } from '@danceroutine/tango-core';\nimport { Q, type FilterInput, type ManagerLike, type QuerySet } from '@danceroutine/tango-orm';\nimport type { OffsetPaginatedResponse, Paginator } from '../pagination/index';\nimport { OffsetPaginator } from '../paginators/OffsetPaginator';\nimport { APIView } from './APIView';\nimport { RequestContext } from '../context/index';\nimport type { FilterSet } from '../filters/index';\nimport type { GenericAPIViewOpenAPIDescription } from '../resource/index';\nimport type { ModelSerializerClass, SerializerOutput, SerializerSchema } from '../serializer/index';\nimport type { ResourceModelLike } from '../resource/index';\n\nexport interface GenericAPIViewConfig<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> {\n serializer: TSerializer;\n filters?: FilterSet<TModel>;\n orderingFields?: (keyof TModel)[];\n searchFields?: (keyof TModel)[];\n lookupField?: keyof TModel;\n lookupParam?: string;\n paginatorFactory?: (queryset: QuerySet<TModel>) => Paginator<TModel, SerializerOutput<TSerializer>>;\n}\n\n/**\n * Generic API base class that centralizes query/build/validation helpers.\n */\nexport abstract class GenericAPIView<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends APIView {\n protected readonly serializerClass: TSerializer;\n protected readonly filters?: FilterSet<TModel>;\n protected readonly orderingFields: readonly (keyof TModel)[];\n protected readonly searchFields: readonly (keyof TModel)[];\n protected readonly lookupField?: keyof TModel;\n protected readonly lookupParam: string;\n protected readonly paginatorFactory?: (\n queryset: QuerySet<TModel>\n ) => Paginator<TModel, SerializerOutput<TSerializer>>;\n private serializer?: InstanceType<TSerializer>;\n\n constructor(config: GenericAPIViewConfig<TModel, TSerializer>) {\n super();\n this.serializerClass = config.serializer;\n this.filters = config.filters;\n this.orderingFields = config.orderingFields ?? [];\n this.searchFields = config.searchFields ?? [];\n this.lookupField = config.lookupField;\n this.lookupParam = config.lookupParam ?? 'id';\n this.paginatorFactory = config.paginatorFactory;\n }\n\n /**\n * Return the serializer class that owns this resource contract.\n */\n getSerializerClass(): TSerializer {\n return this.serializerClass;\n }\n\n /**\n * Return the serializer instance for the current resource.\n */\n getSerializer(): InstanceType<TSerializer> {\n if (!this.serializer) {\n this.serializer = new this.serializerClass() as InstanceType<TSerializer>;\n }\n\n return this.serializer;\n }\n\n /**\n * Describe the public HTTP contract that this resource contributes to OpenAPI generation.\n */\n describeOpenAPI(): GenericAPIViewOpenAPIDescription<TModel, TSerializer> {\n return {\n model: this.requireModelMetadata(),\n outputSchema: this.getOutputSchema(),\n createSchema: this.getCreateSchema(),\n updateSchema: this.getUpdateSchema(),\n searchFields: this.searchFields,\n orderingFields: this.orderingFields,\n lookupField: this.getLookupField(),\n lookupParam: this.lookupParam,\n allowedMethods: this.getAllowedMethods(),\n usesDefaultOffsetPagination: !this.paginatorFactory,\n };\n }\n\n protected getManager(): ManagerLike<TModel> {\n return this.getSerializer().getManager();\n }\n\n protected getOutputSchema(): TSerializer['outputSchema'] {\n return this.getSerializer().getOutputSchema() as TSerializer['outputSchema'];\n }\n\n protected getCreateSchema(): TSerializer['createSchema'] {\n return this.getSerializer().getCreateSchema() as TSerializer['createSchema'];\n }\n\n protected getUpdateSchema(): TSerializer['updateSchema'] {\n return this.getSerializer().getUpdateSchema() as TSerializer['updateSchema'];\n }\n\n protected getLookupField(): keyof TModel {\n return this.lookupField ?? (this.getManager().meta.pk as keyof TModel);\n }\n\n protected getLookupValue(ctx: RequestContext): string | null {\n const value = ctx.params[this.lookupParam]?.trim();\n return value || null;\n }\n\n protected getPaginator(queryset: QuerySet<TModel>): Paginator<TModel, SerializerOutput<TSerializer>> {\n if (this.paginatorFactory) {\n return this.paginatorFactory(queryset);\n }\n return new OffsetPaginator<TModel>(queryset) as Paginator<TModel, SerializerOutput<TSerializer>>;\n }\n\n protected async performList(ctx: RequestContext): Promise<TangoResponse> {\n try {\n const params = ctx.request.queryParams;\n const baseQueryset = this.getManager().query();\n const paginator = this.getPaginator(baseQueryset);\n paginator.parse(params);\n\n let qs = baseQueryset;\n\n if (this.filters) {\n const filterInputs = this.filters.apply(params);\n if (filterInputs.length > 0) {\n qs = qs.filter(Q.and(...filterInputs));\n }\n }\n\n const search = params.getSearch();\n if (search && this.searchFields.length > 0) {\n const searchFilters: FilterInput<TModel>[] = this.searchFields.map((field) => {\n const lookup = `${String(field)}__icontains`;\n return { [lookup]: search } as FilterInput<TModel>;\n });\n qs = qs.filter(Q.or(...searchFilters));\n }\n\n const ordering = params.getOrdering();\n if (ordering.length > 0) {\n const orderTokens = ordering.filter((field) => {\n const cleanField = field.startsWith('-') ? field.slice(1) : field;\n return this.orderingFields.includes(cleanField as keyof TModel);\n });\n if (orderTokens.length > 0) {\n qs = qs.orderBy(...orderTokens.map((token) => token as keyof TModel | `-${string & keyof TModel}`));\n }\n }\n\n qs = paginator.apply(qs);\n const resultPromise = qs.fetch();\n const totalCountPromise = paginator.needsTotalCount()\n ? qs.count()\n : Promise.resolve<number | undefined>(undefined);\n const [result, totalCount] = await Promise.all([resultPromise, totalCountPromise]);\n const serializer = this.getSerializer();\n const response = paginator.toResponse(\n result.results.map((row) => serializer.toRepresentation(row)) as SerializerOutput<TSerializer>[],\n { totalCount }\n ) as OffsetPaginatedResponse<SerializerOutput<TSerializer>>;\n\n return TangoResponse.json(response as unknown as JsonValue, { status: 200 });\n } catch (error) {\n return this.handleError(error);\n }\n }\n\n protected async performCreate(ctx: RequestContext): Promise<TangoResponse> {\n try {\n const body = await ctx.request.json();\n const result = await this.getSerializer().create(body);\n\n return TangoResponse.created(undefined, result as JsonValue);\n } catch (error) {\n return this.handleError(error);\n }\n }\n\n protected async performRetrieve(ctx: RequestContext): Promise<TangoResponse> {\n try {\n const value = this.getLookupValue(ctx);\n if (!value) {\n throw new NotFoundError('Lookup parameter was not provided.');\n }\n\n const lookupField = this.getLookupField();\n const filterByLookup = { [lookupField]: value } as FilterInput<TModel>;\n const result = await this.getManager().query().filter(filterByLookup).fetchOne();\n if (!result) {\n throw new NotFoundError(\n `No ${this.getManager().meta.table} record found for ${String(lookupField)}=${value}.`\n );\n }\n\n return TangoResponse.json(this.getSerializer().toRepresentation(result) as JsonValue, { status: 200 });\n } catch (error) {\n return this.handleError(error);\n }\n }\n\n protected async performUpdate(ctx: RequestContext): Promise<TangoResponse> {\n try {\n const value = this.getLookupValue(ctx);\n if (!value) {\n throw new NotFoundError('Lookup parameter was not provided.');\n }\n\n const body = await ctx.request.json();\n const result = await this.getSerializer().update(value as TModel[keyof TModel], body);\n\n return TangoResponse.json(result as JsonValue, { status: 200 });\n } catch (error) {\n return this.handleError(error);\n }\n }\n\n protected async performDestroy(ctx: RequestContext): Promise<TangoResponse> {\n try {\n const value = this.getLookupValue(ctx);\n if (!value) {\n throw new NotFoundError('Lookup parameter was not provided.');\n }\n\n await this.getManager().delete(value as TModel[keyof TModel]);\n return TangoResponse.noContent();\n } catch (error) {\n return this.handleError(error);\n }\n }\n\n protected handleError(error: unknown): TangoResponse {\n const httpError = HttpErrorFactory.toHttpError(error);\n return TangoResponse.json(httpError.body as JsonValue, { status: httpError.status });\n }\n\n private requireModelMetadata(): ResourceModelLike<TModel> & {\n metadata: NonNullable<ResourceModelLike<TModel>['metadata']>;\n } {\n const model = this.getSerializer().getModel();\n\n if (!model.metadata) {\n throw new Error('OpenAPI generation requires Tango model metadata on GenericAPIView models.');\n }\n\n return model as ResourceModelLike<TModel> & {\n metadata: NonNullable<ResourceModelLike<TModel>['metadata']>;\n };\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Mixin that wires `GET` requests to the generic list implementation.\n */\nexport abstract class ListModelMixin<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected list(ctx: RequestContext): Promise<TangoResponse> {\n return this.performList(ctx);\n }\n\n protected override get(ctx: RequestContext): Promise<TangoResponse> {\n return this.list(ctx);\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Mixin that wires `POST` requests to the generic create implementation.\n */\nexport abstract class CreateModelMixin<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected create(ctx: RequestContext): Promise<TangoResponse> {\n return this.performCreate(ctx);\n }\n\n protected override post(ctx: RequestContext): Promise<TangoResponse> {\n return this.create(ctx);\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Mixin that wires `GET` requests to the generic retrieve implementation.\n */\nexport abstract class RetrieveModelMixin<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected retrieve(ctx: RequestContext): Promise<TangoResponse> {\n return this.performRetrieve(ctx);\n }\n\n protected override get(ctx: RequestContext): Promise<TangoResponse> {\n return this.retrieve(ctx);\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Mixin that wires `PUT` and `PATCH` requests to the generic update implementation.\n */\nexport abstract class UpdateModelMixin<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected update(ctx: RequestContext): Promise<TangoResponse> {\n return this.performUpdate(ctx);\n }\n\n protected override put(ctx: RequestContext): Promise<TangoResponse> {\n return this.update(ctx);\n }\n\n protected override patch(ctx: RequestContext): Promise<TangoResponse> {\n return this.update(ctx);\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Mixin that wires `DELETE` requests to the generic destroy implementation.\n */\nexport abstract class DestroyModelMixin<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected destroy(ctx: RequestContext): Promise<TangoResponse> {\n return this.performDestroy(ctx);\n }\n\n protected override delete(ctx: RequestContext): Promise<TangoResponse> {\n return this.destroy(ctx);\n }\n}\n","import { ListModelMixin } from '../mixins/ListModelMixin';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Generic API view for endpoints that only expose a list operation.\n */\nexport abstract class ListAPIView<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends ListModelMixin<TModel, TSerializer> {\n protected override get(ctx: RequestContext): Promise<TangoResponse> {\n return super.get(ctx);\n }\n}\n","import { CreateModelMixin } from '../mixins/CreateModelMixin';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Generic API view for endpoints that only support resource creation.\n */\nexport abstract class CreateAPIView<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends CreateModelMixin<TModel, TSerializer> {\n protected override post(ctx: RequestContext): Promise<TangoResponse> {\n return super.post(ctx);\n }\n}\n","import { RetrieveModelMixin } from '../mixins/RetrieveModelMixin';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Generic API view for endpoints that retrieve a single resource by lookup.\n */\nexport abstract class RetrieveAPIView<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends RetrieveModelMixin<TModel, TSerializer> {\n protected override get(ctx: RequestContext): Promise<TangoResponse> {\n return super.get(ctx);\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Generic API view for collection endpoints that list and create resources.\n */\nexport abstract class ListCreateAPIView<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected override get(ctx: RequestContext): Promise<TangoResponse> {\n return this.performList(ctx);\n }\n\n protected override post(ctx: RequestContext): Promise<TangoResponse> {\n return this.performCreate(ctx);\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Generic API view for endpoints that retrieve and update a single resource.\n */\nexport abstract class RetrieveUpdateAPIView<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected override get(ctx: RequestContext): Promise<TangoResponse> {\n return this.performRetrieve(ctx);\n }\n\n protected override put(ctx: RequestContext): Promise<TangoResponse> {\n return this.performUpdate(ctx);\n }\n\n protected override patch(ctx: RequestContext): Promise<TangoResponse> {\n return this.performUpdate(ctx);\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Generic API view for endpoints that retrieve and delete a single resource.\n */\nexport abstract class RetrieveDestroyAPIView<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected override get(ctx: RequestContext): Promise<TangoResponse> {\n return this.performRetrieve(ctx);\n }\n\n protected override delete(ctx: RequestContext): Promise<TangoResponse> {\n return this.performDestroy(ctx);\n }\n}\n","import { GenericAPIView } from '../GenericAPIView';\nimport type { TangoResponse } from '@danceroutine/tango-core';\nimport { RequestContext } from '../../context/index';\nimport type { ModelSerializerClass, SerializerSchema } from '../../serializer/index';\n\n/**\n * Generic API view for full detail endpoints that retrieve, update, and delete.\n */\nexport abstract class RetrieveUpdateDestroyAPIView<\n TModel extends Record<string, unknown>,\n TSerializer extends ModelSerializerClass<TModel, SerializerSchema, SerializerSchema, SerializerSchema>,\n> extends GenericAPIView<TModel, TSerializer> {\n protected override get(ctx: RequestContext): Promise<TangoResponse> {\n return this.performRetrieve(ctx);\n }\n\n protected override put(ctx: RequestContext): Promise<TangoResponse> {\n return this.performUpdate(ctx);\n }\n\n protected override patch(ctx: RequestContext): Promise<TangoResponse> {\n return this.performUpdate(ctx);\n }\n\n protected override delete(ctx: RequestContext): Promise<TangoResponse> {\n return this.performDestroy(ctx);\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { APIView, type APIViewMethod } from './APIView';\nexport { GenericAPIView, type GenericAPIViewConfig } from './GenericAPIView';\nexport type { GenericAPIViewOpenAPIDescription } from '../resource/index';\nexport {\n ListModelMixin,\n CreateModelMixin,\n RetrieveModelMixin,\n UpdateModelMixin,\n DestroyModelMixin,\n} from './mixins/index';\nexport {\n ListAPIView,\n CreateAPIView,\n RetrieveAPIView,\n ListCreateAPIView,\n RetrieveUpdateAPIView,\n RetrieveDestroyAPIView,\n RetrieveUpdateDestroyAPIView,\n} from './generics/index';\n"],"mappings":";;;;;;;;;;;;;;;MAQaA,wBAA+D,EAAE,OAAO;CACjF,OAAO,EAAE,OACJ,QAAQ,CACR,KAAK,CACL,IAAI,EAAE,CACN,QAAQ,GAAG,CACX,UAAU,CAAC,UAAU,KAAK,IAAI,OAAO,IAAI,CAAC;CAC/C,QAAQ,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CACjD,MAAM,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU;AAClD,EAAC;;;;ICXI,aAAN,MAAM,WAAiC;CACnC,OAAgB,QAAQ;CACxB,eAAiD,WAAW;CAE5D,YACoBC,SACCC,YACAC,SACAC,YACnB;AAAA,OAJkB,UAAA;AAAA,OACC,aAAA;AAAA,OACA,UAAA;AAAA,OACA,aAAA;CACjB;CAEJ,OAAO,aAAgBC,OAAwC;AAC3D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,WAAW;CAEzE;;CAGD,UAAmB;AACf,MAAI,KAAK,eAAe,UACpB,QAAO;AAEX,SAAO,KAAK,UAAU,GAAG,KAAK;CACjC;;CAGD,cAAuB;AACnB,SAAO,KAAK,aAAa;CAC5B;;CAGD,iBAAgC;AAC5B,SAAO,KAAK,SAAS,GAAG,KAAK,aAAa,IAAI;CACjD;;CAGD,qBAAoC;AAChC,SAAO,KAAK,aAAa,GAAG,KAAK,aAAa,IAAI;CACrD;;CAGD,aAAqB;AACjB,UAAQ,KAAK,aAAa,KAAK,KAAK;CACvC;;CAGD,WAAmB;AACf,SAAO,KAAK,YAAY,GAAG,KAAK,QAAQ;CAC3C;AACJ;IAeY,kBAAN,MAAM,gBAA0G;CACnH,OAAgB,QAAQ;CACxB,eAAsD,gBAAgB;CACtE,QAAgB;CAChB,SAAiB;CAEjB,YACYC,UACAH,UAAkB,IAC5B;AAAA,OAFU,WAAA;AAAA,OACA,UAAA;AAER,OAAK,QAAQ;CAChB;;;;CAKD,OAAO,kBAAqDE,OAA6C;AACrG,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,gBAAgB;CAE9E;;;;;;CAOD,MAAME,QAAgC;EAClC,MAAM,QAAQ;GACV,OAAO,OAAO,IAAI,QAAQ,IAAI;GAC9B,QAAQ,OAAO,IAAI,SAAS,IAAI;GAChC,MAAM,OAAO,IAAI,OAAO,IAAI;EAC/B;EAED,MAAM,SAAS,sBAAsB,MAAM,MAAM;AAEjD,MAAI,OAAO,KACP,QAAO,UAAU,OAAO,OAAO,KAAK,OAAO;AAG/C,OAAK,QAAQ,OAAO;AACpB,OAAK,SAAS,OAAO;CACxB;;;;CAKD,YAAYA,QAA6D;AACrE,OAAK,MAAM,OAAO;AAClB,SAAO;GAAE,OAAO,KAAK;GAAO,QAAQ,KAAK;EAAQ;CACpD;;;;;CAMD,kBAA2B;AACvB,SAAO;CACV;CAED,WAAoBC,SAAoBC,SAAqE;EACzG,MAAM,aAAa,SAAS;EAC5B,MAAMC,WAA6C,EAAE,QAAS;AAE9D,MAAI,eAAe,WAAW;AAC1B,YAAS,QAAQ;AAEjB,OAAI,KAAK,SAAS,KAAK,QAAQ,WAC3B,UAAS,QAAQ,SAAS,KAAK,MAAM,UAAU,KAAK,SAAS,KAAK,MAAM;AAG5E,OAAI,KAAK,SAAS,GAAG;IACjB,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,SAAS,KAAK,MAAM;AACxD,aAAS,YAAY,SAAS,KAAK,MAAM,UAAU,WAAW;GACjE;EACJ;AAED,SAAO;CACV;;;;CAKD,qBAA8BF,SAAoBJ,YAAuD;AACrG,SAAO,KAAK,WAAW,SAAS,EAAE,WAAY,EAAC;CAClD;;;;CAKD,MAAME,UAAoC;AACtC,SAAO,SAAS,MAAM,KAAK,MAAM,CAAC,OAAO,KAAK,OAAO;CACxD;;;;CAKD,MAAM,SAASK,MAAgC;AAC3C,SAAO,KAAK,QAAQ,KAAK;CAC5B;;;;CAKD,MAAM,QAAQA,MAAgC;EAC1C,MAAM,UAAU,OAAO,KAAK,KAAK;EACjC,MAAM,UAAU,MAAM,KAAK,SAAS,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,OAAO;EAE9E,MAAM,aAAa,MAAM,KAAK,OAAO;AAErC,SAAO,IAAI,WAAW,QAAQ,SAAS,MAAM,KAAK,SAAS;CAC9D;;;;CAKD,MAAM,QAAyB;AAC3B,SAAO,KAAK,SAAS,OAAO;CAC/B;AACJ;;;;ICvLqB,UAAf,MAAe,QAAQ;CAC1B,OAAgB,QAAQ;CACxB,eAA8C,QAAQ;;;;CAKtD,OAAO,UAAUC,OAAkC;AAC/C,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,QAAQ;CAEtE;;;;CAKD,MAAM,SAASC,KAA6C;EACxD,MAAM,SAAS,gBAAgB,IAAI,QAAQ,OAAO;AAClD,OAAK,OACD,QAAO,KAAK,sBAAsB;EAGtC,MAAM,UAAU,KAAK,iBAAiB,OAAO;AAC7C,SAAO,QAAQ,IAAI;CACtB;CAED,oBAA8C;EAC1C,MAAMC,UAA2B,CAAE;AACnC,MAAI,KAAK,QAAQ,QAAQ,UAAU,IAC/B,SAAQ,KAAK,MAAM;AAEvB,MAAI,KAAK,SAAS,QAAQ,UAAU,KAChC,SAAQ,KAAK,OAAO;AAExB,MAAI,KAAK,QAAQ,QAAQ,UAAU,IAC/B,SAAQ,KAAK,MAAM;AAEvB,MAAI,KAAK,UAAU,QAAQ,UAAU,MACjC,SAAQ,KAAK,QAAQ;AAEzB,MAAI,KAAK,WAAW,QAAQ,UAAU,OAClC,SAAQ,KAAK,SAAS;AAE1B,SAAO;CACV;CAED,IAAcC,MAA8C;AACxD,SAAO,QAAQ,QAAQ,KAAK,sBAAsB,CAAC;CACtD;CAED,KAAeA,MAA8C;AACzD,SAAO,QAAQ,QAAQ,KAAK,sBAAsB,CAAC;CACtD;CAED,IAAcA,MAA8C;AACxD,SAAO,QAAQ,QAAQ,KAAK,sBAAsB,CAAC;CACtD;CAED,MAAgBA,MAA8C;AAC1D,SAAO,QAAQ,QAAQ,KAAK,sBAAsB,CAAC;CACtD;CAED,OAAiBA,MAA8C;AAC3D,SAAO,QAAQ,QAAQ,KAAK,sBAAsB,CAAC;CACtD;CAED,uBAAgD;AAC5C,SAAO,gBAAc,iBAAiB,KAAK,mBAAmB,CAAC;CAClE;CAED,iBAAyBC,QAA6C;AAClE,MAAI,WAAW,MACX,QAAO,CAAC,QAAQ,KAAK,IAAI,IAAI;AAEjC,MAAI,WAAW,OACX,QAAO,CAAC,QAAQ,KAAK,KAAK,IAAI;AAElC,MAAI,WAAW,MACX,QAAO,CAAC,QAAQ,KAAK,IAAI,IAAI;AAEjC,MAAI,WAAW,QACX,QAAO,CAAC,QAAQ,KAAK,MAAM,IAAI;AAEnC,SAAO,CAAC,QAAQ,KAAK,OAAO,IAAI;CACnC;AACJ;AAED,SAAS,gBAAgBC,QAAsC;CAC3D,MAAM,QAAQ,OAAO,aAAa;AAClC,KAAI,UAAU,MACV,QAAO;AAEX,KAAI,UAAU,OACV,QAAO;AAEX,KAAI,UAAU,MACV,QAAO;AAEX,KAAI,UAAU,QACV,QAAO;AAEX,KAAI,UAAU,SACV,QAAO;AAEX,QAAO;AACV;;;;IC1FqB,iBAAf,cAGG,QAAQ;CACd;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CAEA,YAAYC,QAAmD;AAC3D,SAAO;AACP,OAAK,kBAAkB,OAAO;AAC9B,OAAK,UAAU,OAAO;AACtB,OAAK,iBAAiB,OAAO,kBAAkB,CAAE;AACjD,OAAK,eAAe,OAAO,gBAAgB,CAAE;AAC7C,OAAK,cAAc,OAAO;AAC1B,OAAK,cAAc,OAAO,eAAe;AACzC,OAAK,mBAAmB,OAAO;CAClC;;;;CAKD,qBAAkC;AAC9B,SAAO,KAAK;CACf;;;;CAKD,gBAA2C;AACvC,OAAK,KAAK,WACN,MAAK,aAAa,IAAI,KAAK;AAG/B,SAAO,KAAK;CACf;;;;CAKD,kBAAyE;AACrE,SAAO;GACH,OAAO,KAAK,sBAAsB;GAClC,cAAc,KAAK,iBAAiB;GACpC,cAAc,KAAK,iBAAiB;GACpC,cAAc,KAAK,iBAAiB;GACpC,cAAc,KAAK;GACnB,gBAAgB,KAAK;GACrB,aAAa,KAAK,gBAAgB;GAClC,aAAa,KAAK;GAClB,gBAAgB,KAAK,mBAAmB;GACxC,8BAA8B,KAAK;EACtC;CACJ;CAED,aAA4C;AACxC,SAAO,KAAK,eAAe,CAAC,YAAY;CAC3C;CAED,kBAAyD;AACrD,SAAO,KAAK,eAAe,CAAC,iBAAiB;CAChD;CAED,kBAAyD;AACrD,SAAO,KAAK,eAAe,CAAC,iBAAiB;CAChD;CAED,kBAAyD;AACrD,SAAO,KAAK,eAAe,CAAC,iBAAiB;CAChD;CAED,iBAAyC;AACrC,SAAO,KAAK,eAAgB,KAAK,YAAY,CAAC,KAAK;CACtD;CAED,eAAyBC,KAAoC;EACzD,MAAM,QAAQ,IAAI,OAAO,KAAK,cAAc,MAAM;AAClD,SAAO,SAAS;CACnB;CAED,aAAuBC,UAA8E;AACjG,MAAI,KAAK,iBACL,QAAO,KAAK,iBAAiB,SAAS;AAE1C,SAAO,IAAI,gBAAwB;CACtC;CAED,MAAgB,YAAYD,KAA6C;AACrE,MAAI;GACA,MAAM,SAAS,IAAI,QAAQ;GAC3B,MAAM,eAAe,KAAK,YAAY,CAAC,OAAO;GAC9C,MAAM,YAAY,KAAK,aAAa,aAAa;AACjD,aAAU,MAAM,OAAO;GAEvB,IAAI,KAAK;AAET,OAAI,KAAK,SAAS;IACd,MAAM,eAAe,KAAK,QAAQ,MAAM,OAAO;AAC/C,QAAI,aAAa,SAAS,EACtB,MAAK,GAAG,OAAO,EAAE,IAAI,GAAG,aAAa,CAAC;GAE7C;GAED,MAAM,SAAS,OAAO,WAAW;AACjC,OAAI,UAAU,KAAK,aAAa,SAAS,GAAG;IACxC,MAAME,gBAAuC,KAAK,aAAa,IAAI,CAAC,UAAU;KAC1E,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AAChC,YAAO,GAAG,SAAS,OAAQ;IAC9B,EAAC;AACF,SAAK,GAAG,OAAO,EAAE,GAAG,GAAG,cAAc,CAAC;GACzC;GAED,MAAM,WAAW,OAAO,aAAa;AACrC,OAAI,SAAS,SAAS,GAAG;IACrB,MAAM,cAAc,SAAS,OAAO,CAAC,UAAU;KAC3C,MAAM,aAAa,MAAM,WAAW,IAAI,GAAG,MAAM,MAAM,EAAE,GAAG;AAC5D,YAAO,KAAK,eAAe,SAAS,WAA2B;IAClE,EAAC;AACF,QAAI,YAAY,SAAS,EACrB,MAAK,GAAG,QAAQ,GAAG,YAAY,IAAI,CAAC,UAAU,MAAoD,CAAC;GAE1G;AAED,QAAK,UAAU,MAAM,GAAG;GACxB,MAAM,gBAAgB,GAAG,OAAO;GAChC,MAAM,oBAAoB,UAAU,iBAAiB,GAC/C,GAAG,OAAO,GACV,QAAQ,QAA4B,UAAU;GACpD,MAAM,CAAC,QAAQ,WAAW,GAAG,MAAM,QAAQ,IAAI,CAAC,eAAe,iBAAkB,EAAC;GAClF,MAAM,aAAa,KAAK,eAAe;GACvC,MAAM,WAAW,UAAU,WACvB,OAAO,QAAQ,IAAI,CAAC,QAAQ,WAAW,iBAAiB,IAAI,CAAC,EAC7D,EAAE,WAAY,EACjB;AAED,UAAO,cAAc,KAAK,UAAkC,EAAE,QAAQ,IAAK,EAAC;EAC/E,SAAQ,OAAO;AACZ,UAAO,KAAK,YAAY,MAAM;EACjC;CACJ;CAED,MAAgB,cAAcF,KAA6C;AACvE,MAAI;GACA,MAAM,OAAO,MAAM,IAAI,QAAQ,MAAM;GACrC,MAAM,SAAS,MAAM,KAAK,eAAe,CAAC,OAAO,KAAK;AAEtD,UAAO,cAAc,QAAQ,WAAW,OAAoB;EAC/D,SAAQ,OAAO;AACZ,UAAO,KAAK,YAAY,MAAM;EACjC;CACJ;CAED,MAAgB,gBAAgBA,KAA6C;AACzE,MAAI;GACA,MAAM,QAAQ,KAAK,eAAe,IAAI;AACtC,QAAK,MACD,OAAM,IAAI,cAAc;GAG5B,MAAM,cAAc,KAAK,gBAAgB;GACzC,MAAM,iBAAiB,GAAG,cAAc,MAAO;GAC/C,MAAM,SAAS,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,OAAO,eAAe,CAAC,UAAU;AAChF,QAAK,OACD,OAAM,IAAI,eACL,KAAK,KAAK,YAAY,CAAC,KAAK,MAAM,oBAAoB,OAAO,YAAY,CAAC,GAAG,MAAM;AAI5F,UAAO,cAAc,KAAK,KAAK,eAAe,CAAC,iBAAiB,OAAO,EAAe,EAAE,QAAQ,IAAK,EAAC;EACzG,SAAQ,OAAO;AACZ,UAAO,KAAK,YAAY,MAAM;EACjC;CACJ;CAED,MAAgB,cAAcA,KAA6C;AACvE,MAAI;GACA,MAAM,QAAQ,KAAK,eAAe,IAAI;AACtC,QAAK,MACD,OAAM,IAAI,cAAc;GAG5B,MAAM,OAAO,MAAM,IAAI,QAAQ,MAAM;GACrC,MAAM,SAAS,MAAM,KAAK,eAAe,CAAC,OAAO,OAA+B,KAAK;AAErF,UAAO,cAAc,KAAK,QAAqB,EAAE,QAAQ,IAAK,EAAC;EAClE,SAAQ,OAAO;AACZ,UAAO,KAAK,YAAY,MAAM;EACjC;CACJ;CAED,MAAgB,eAAeA,KAA6C;AACxE,MAAI;GACA,MAAM,QAAQ,KAAK,eAAe,IAAI;AACtC,QAAK,MACD,OAAM,IAAI,cAAc;AAG5B,SAAM,KAAK,YAAY,CAAC,OAAO,MAA8B;AAC7D,UAAO,cAAc,WAAW;EACnC,SAAQ,OAAO;AACZ,UAAO,KAAK,YAAY,MAAM;EACjC;CACJ;CAED,YAAsBG,OAA+B;EACjD,MAAM,YAAY,iBAAiB,YAAY,MAAM;AACrD,SAAO,cAAc,KAAK,UAAU,MAAmB,EAAE,QAAQ,UAAU,OAAQ,EAAC;CACvF;CAED,uBAEE;EACE,MAAM,QAAQ,KAAK,eAAe,CAAC,UAAU;AAE7C,OAAK,MAAM,SACP,OAAM,IAAI,MAAM;AAGpB,SAAO;CAGV;AACJ;;;;ICxPqB,iBAAf,cAGG,eAAoC;CAC1C,KAAeC,KAA6C;AACxD,SAAO,KAAK,YAAY,IAAI;CAC/B;CAED,IAAuBA,KAA6C;AAChE,SAAO,KAAK,KAAK,IAAI;CACxB;AACJ;;;;ICXqB,mBAAf,cAGG,eAAoC;CAC1C,OAAiBC,KAA6C;AAC1D,SAAO,KAAK,cAAc,IAAI;CACjC;CAED,KAAwBA,KAA6C;AACjE,SAAO,KAAK,OAAO,IAAI;CAC1B;AACJ;;;;ICXqB,qBAAf,cAGG,eAAoC;CAC1C,SAAmBC,KAA6C;AAC5D,SAAO,KAAK,gBAAgB,IAAI;CACnC;CAED,IAAuBA,KAA6C;AAChE,SAAO,KAAK,SAAS,IAAI;CAC5B;AACJ;;;;ICXqB,mBAAf,cAGG,eAAoC;CAC1C,OAAiBC,KAA6C;AAC1D,SAAO,KAAK,cAAc,IAAI;CACjC;CAED,IAAuBA,KAA6C;AAChE,SAAO,KAAK,OAAO,IAAI;CAC1B;CAED,MAAyBA,KAA6C;AAClE,SAAO,KAAK,OAAO,IAAI;CAC1B;AACJ;;;;ICfqB,oBAAf,cAGG,eAAoC;CAC1C,QAAkBC,KAA6C;AAC3D,SAAO,KAAK,eAAe,IAAI;CAClC;CAED,OAA0BA,KAA6C;AACnE,SAAO,KAAK,QAAQ,IAAI;CAC3B;AACJ;;;;ICXqB,cAAf,cAGG,eAAoC;CAC1C,IAAuBC,KAA6C;AAChE,SAAO,MAAM,IAAI,IAAI;CACxB;AACJ;;;;ICPqB,gBAAf,cAGG,iBAAsC;CAC5C,KAAwBC,KAA6C;AACjE,SAAO,MAAM,KAAK,IAAI;CACzB;AACJ;;;;ICPqB,kBAAf,cAGG,mBAAwC;CAC9C,IAAuBC,KAA6C;AAChE,SAAO,MAAM,IAAI,IAAI;CACxB;AACJ;;;;ICPqB,oBAAf,cAGG,eAAoC;CAC1C,IAAuBC,KAA6C;AAChE,SAAO,KAAK,YAAY,IAAI;CAC/B;CAED,KAAwBA,KAA6C;AACjE,SAAO,KAAK,cAAc,IAAI;CACjC;AACJ;;;;ICXqB,wBAAf,cAGG,eAAoC;CAC1C,IAAuBC,KAA6C;AAChE,SAAO,KAAK,gBAAgB,IAAI;CACnC;CAED,IAAuBA,KAA6C;AAChE,SAAO,KAAK,cAAc,IAAI;CACjC;CAED,MAAyBA,KAA6C;AAClE,SAAO,KAAK,cAAc,IAAI;CACjC;AACJ;;;;ICfqB,yBAAf,cAGG,eAAoC;CAC1C,IAAuBC,KAA6C;AAChE,SAAO,KAAK,gBAAgB,IAAI;CACnC;CAED,OAA0BA,KAA6C;AACnE,SAAO,KAAK,eAAe,IAAI;CAClC;AACJ;;;;ICXqB,+BAAf,cAGG,eAAoC;CAC1C,IAAuBC,KAA6C;AAChE,SAAO,KAAK,gBAAgB,IAAI;CACnC;CAED,IAAuBA,KAA6C;AAChE,SAAO,KAAK,cAAc,IAAI;CACjC;CAED,MAAyBA,KAA6C;AAClE,SAAO,KAAK,cAAc,IAAI;CACjC;CAED,OAA0BA,KAA6C;AACnE,SAAO,KAAK,eAAe,IAAI;CAClC;AACJ"}