@pinta365/strava 0.0.1
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/LICENSE +21 -0
- package/README.md +390 -0
- package/esm/_dnt.shims.d.ts +2 -0
- package/esm/_dnt.shims.js +57 -0
- package/esm/deps/jsr.io/@cross/runtime/1.2.1/mod.d.ts +126 -0
- package/esm/deps/jsr.io/@cross/runtime/1.2.1/mod.js +480 -0
- package/esm/mod.d.ts +27 -0
- package/esm/mod.js +27 -0
- package/esm/package.json +3 -0
- package/esm/src/auth/oauth.d.ts +68 -0
- package/esm/src/auth/oauth.js +203 -0
- package/esm/src/auth/scopes.d.ts +52 -0
- package/esm/src/auth/scopes.js +71 -0
- package/esm/src/auth/token-store.d.ts +57 -0
- package/esm/src/auth/token-store.js +142 -0
- package/esm/src/client.d.ts +98 -0
- package/esm/src/client.js +235 -0
- package/esm/src/errors.d.ts +52 -0
- package/esm/src/errors.js +102 -0
- package/esm/src/http/deduplication.d.ts +33 -0
- package/esm/src/http/deduplication.js +96 -0
- package/esm/src/http/rate-limiter.d.ts +47 -0
- package/esm/src/http/rate-limiter.js +168 -0
- package/esm/src/http/request.d.ts +24 -0
- package/esm/src/http/request.js +158 -0
- package/esm/src/http/retry.d.ts +9 -0
- package/esm/src/http/retry.js +61 -0
- package/esm/src/resources/activities.d.ts +149 -0
- package/esm/src/resources/activities.js +189 -0
- package/esm/src/resources/athletes.d.ts +37 -0
- package/esm/src/resources/athletes.js +85 -0
- package/esm/src/resources/clubs.d.ts +45 -0
- package/esm/src/resources/clubs.js +71 -0
- package/esm/src/resources/gears.d.ts +17 -0
- package/esm/src/resources/gears.js +27 -0
- package/esm/src/resources/routes.d.ts +33 -0
- package/esm/src/resources/routes.js +71 -0
- package/esm/src/resources/segment-efforts.d.ts +38 -0
- package/esm/src/resources/segment-efforts.js +53 -0
- package/esm/src/resources/segments.d.ts +42 -0
- package/esm/src/resources/segments.js +67 -0
- package/esm/src/resources/streams.d.ts +44 -0
- package/esm/src/resources/streams.js +75 -0
- package/esm/src/resources/uploads.d.ts +41 -0
- package/esm/src/resources/uploads.js +79 -0
- package/esm/src/types/api.d.ts +9 -0
- package/esm/src/types/api.js +7 -0
- package/esm/src/types/common.d.ts +65 -0
- package/esm/src/types/common.js +4 -0
- package/esm/src/types/generated.d.ts +731 -0
- package/esm/src/types/generated.js +7 -0
- package/esm/src/utils/pagination.d.ts +45 -0
- package/esm/src/utils/pagination.js +112 -0
- package/esm/src/utils/transformers.d.ts +30 -0
- package/esm/src/utils/transformers.js +189 -0
- package/esm/src/utils/validators.d.ts +53 -0
- package/esm/src/utils/validators.js +84 -0
- package/package.json +40 -0
- package/script/_dnt.shims.d.ts +2 -0
- package/script/_dnt.shims.js +60 -0
- package/script/deps/jsr.io/@cross/runtime/1.2.1/mod.d.ts +126 -0
- package/script/deps/jsr.io/@cross/runtime/1.2.1/mod.js +526 -0
- package/script/mod.d.ts +27 -0
- package/script/mod.js +73 -0
- package/script/package.json +3 -0
- package/script/src/auth/oauth.d.ts +68 -0
- package/script/src/auth/oauth.js +211 -0
- package/script/src/auth/scopes.d.ts +52 -0
- package/script/src/auth/scopes.js +79 -0
- package/script/src/auth/token-store.d.ts +57 -0
- package/script/src/auth/token-store.js +182 -0
- package/script/src/client.d.ts +98 -0
- package/script/src/client.js +239 -0
- package/script/src/errors.d.ts +52 -0
- package/script/src/errors.js +111 -0
- package/script/src/http/deduplication.d.ts +33 -0
- package/script/src/http/deduplication.js +100 -0
- package/script/src/http/rate-limiter.d.ts +47 -0
- package/script/src/http/rate-limiter.js +172 -0
- package/script/src/http/request.d.ts +24 -0
- package/script/src/http/request.js +161 -0
- package/script/src/http/retry.d.ts +9 -0
- package/script/src/http/retry.js +64 -0
- package/script/src/resources/activities.d.ts +149 -0
- package/script/src/resources/activities.js +193 -0
- package/script/src/resources/athletes.d.ts +37 -0
- package/script/src/resources/athletes.js +89 -0
- package/script/src/resources/clubs.d.ts +45 -0
- package/script/src/resources/clubs.js +75 -0
- package/script/src/resources/gears.d.ts +17 -0
- package/script/src/resources/gears.js +31 -0
- package/script/src/resources/routes.d.ts +33 -0
- package/script/src/resources/routes.js +75 -0
- package/script/src/resources/segment-efforts.d.ts +38 -0
- package/script/src/resources/segment-efforts.js +57 -0
- package/script/src/resources/segments.d.ts +42 -0
- package/script/src/resources/segments.js +71 -0
- package/script/src/resources/streams.d.ts +44 -0
- package/script/src/resources/streams.js +79 -0
- package/script/src/resources/uploads.d.ts +41 -0
- package/script/src/resources/uploads.js +83 -0
- package/script/src/types/api.d.ts +9 -0
- package/script/src/types/api.js +23 -0
- package/script/src/types/common.d.ts +65 -0
- package/script/src/types/common.js +5 -0
- package/script/src/types/generated.d.ts +731 -0
- package/script/src/types/generated.js +8 -0
- package/script/src/utils/pagination.d.ts +45 -0
- package/script/src/utils/pagination.js +118 -0
- package/script/src/utils/transformers.d.ts +30 -0
- package/script/src/utils/transformers.js +196 -0
- package/script/src/utils/validators.d.ts +53 -0
- package/script/src/utils/validators.js +92 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auto-generated TypeScript types from Strava API Swagger specification
|
|
4
|
+
* Generated at: 2026-01-03T21:49:32.765Z
|
|
5
|
+
* Source: https://developers.strava.com/swagger/swagger.json
|
|
6
|
+
* DO NOT EDIT THIS FILE MANUALLY
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pagination helpers for Strava API
|
|
3
|
+
*/
|
|
4
|
+
import type { PaginationOptions } from "../types/common.js";
|
|
5
|
+
/**
|
|
6
|
+
* Paginated iterator for auto-pagination
|
|
7
|
+
*/
|
|
8
|
+
export declare class PaginatedIterator<T> {
|
|
9
|
+
private fetchPage;
|
|
10
|
+
private perPage;
|
|
11
|
+
private currentPage;
|
|
12
|
+
private currentItems;
|
|
13
|
+
private hasMore;
|
|
14
|
+
constructor(fetchPage: (page: number, perPage: number) => Promise<T[]>, perPage?: number);
|
|
15
|
+
/**
|
|
16
|
+
* Get next page
|
|
17
|
+
*/
|
|
18
|
+
next(): Promise<boolean>;
|
|
19
|
+
/**
|
|
20
|
+
* Get current page items
|
|
21
|
+
*/
|
|
22
|
+
get current(): T[];
|
|
23
|
+
/**
|
|
24
|
+
* Check if there are more pages
|
|
25
|
+
*/
|
|
26
|
+
get hasMorePages(): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Reset iterator
|
|
29
|
+
*/
|
|
30
|
+
reset(): void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create async iterator for auto-pagination
|
|
34
|
+
* @param fetchPage - Function to fetch a page of data
|
|
35
|
+
* @param perPage - Number of items per page (default: 30)
|
|
36
|
+
* @returns Async generator that yields all items across pages
|
|
37
|
+
*/
|
|
38
|
+
export declare function listAll<T>(fetchPage: (page: number, perPage: number) => Promise<T[]>, perPage?: number): AsyncGenerator<T, void, unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* Build pagination query parameters
|
|
41
|
+
* @param options - Pagination options
|
|
42
|
+
* @returns Query parameters object
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildPaginationQuery(options?: PaginationOptions): Record<string, number>;
|
|
45
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pagination helpers for Strava API
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PaginatedIterator = void 0;
|
|
7
|
+
exports.listAll = listAll;
|
|
8
|
+
exports.buildPaginationQuery = buildPaginationQuery;
|
|
9
|
+
/**
|
|
10
|
+
* Paginated iterator for auto-pagination
|
|
11
|
+
*/
|
|
12
|
+
class PaginatedIterator {
|
|
13
|
+
constructor(fetchPage, perPage = 30) {
|
|
14
|
+
Object.defineProperty(this, "fetchPage", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: fetchPage
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(this, "perPage", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
writable: true,
|
|
24
|
+
value: perPage
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(this, "currentPage", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: 1
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(this, "currentItems", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: []
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(this, "hasMore", {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
configurable: true,
|
|
41
|
+
writable: true,
|
|
42
|
+
value: true
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get next page
|
|
47
|
+
*/
|
|
48
|
+
async next() {
|
|
49
|
+
if (!this.hasMore) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const items = await this.fetchPage(this.currentPage, this.perPage);
|
|
53
|
+
this.currentItems = items;
|
|
54
|
+
this.currentPage++;
|
|
55
|
+
if (items.length < this.perPage) {
|
|
56
|
+
this.hasMore = false;
|
|
57
|
+
}
|
|
58
|
+
return items.length > 0;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get current page items
|
|
62
|
+
*/
|
|
63
|
+
get current() {
|
|
64
|
+
return this.currentItems;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if there are more pages
|
|
68
|
+
*/
|
|
69
|
+
get hasMorePages() {
|
|
70
|
+
return this.hasMore;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Reset iterator
|
|
74
|
+
*/
|
|
75
|
+
reset() {
|
|
76
|
+
this.currentPage = 1;
|
|
77
|
+
this.currentItems = [];
|
|
78
|
+
this.hasMore = true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.PaginatedIterator = PaginatedIterator;
|
|
82
|
+
/**
|
|
83
|
+
* Create async iterator for auto-pagination
|
|
84
|
+
* @param fetchPage - Function to fetch a page of data
|
|
85
|
+
* @param perPage - Number of items per page (default: 30)
|
|
86
|
+
* @returns Async generator that yields all items across pages
|
|
87
|
+
*/
|
|
88
|
+
async function* listAll(fetchPage, perPage = 30) {
|
|
89
|
+
let page = 1;
|
|
90
|
+
let hasMore = true;
|
|
91
|
+
while (hasMore) {
|
|
92
|
+
const items = await fetchPage(page, perPage);
|
|
93
|
+
for (const item of items) {
|
|
94
|
+
yield item;
|
|
95
|
+
}
|
|
96
|
+
if (items.length < perPage) {
|
|
97
|
+
hasMore = false;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
page++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Build pagination query parameters
|
|
106
|
+
* @param options - Pagination options
|
|
107
|
+
* @returns Query parameters object
|
|
108
|
+
*/
|
|
109
|
+
function buildPaginationQuery(options) {
|
|
110
|
+
const query = {};
|
|
111
|
+
if (options?.page !== undefined) {
|
|
112
|
+
query.page = options.page;
|
|
113
|
+
}
|
|
114
|
+
if (options?.perPage !== undefined) {
|
|
115
|
+
query.per_page = options.perPage;
|
|
116
|
+
}
|
|
117
|
+
return query;
|
|
118
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response transformers for opinionated data transformations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Convert snake_case keys to camelCase
|
|
6
|
+
* @param data - Data to normalize
|
|
7
|
+
* @returns Data with camelCase keys
|
|
8
|
+
*/
|
|
9
|
+
export declare function normalizeKeys<T>(data: T): T;
|
|
10
|
+
/**
|
|
11
|
+
* Transform ISO date strings to Date objects
|
|
12
|
+
* @param data - Data to transform
|
|
13
|
+
* @returns Data with Date objects instead of ISO strings
|
|
14
|
+
*/
|
|
15
|
+
export declare function transformDates<T>(data: T): T;
|
|
16
|
+
/**
|
|
17
|
+
* Flatten nested response structures
|
|
18
|
+
* @param data - Data to flatten
|
|
19
|
+
* @returns Flattened data structure
|
|
20
|
+
*/
|
|
21
|
+
export declare function flattenResponses<T>(data: T): T;
|
|
22
|
+
/**
|
|
23
|
+
* Add computed fields
|
|
24
|
+
*/
|
|
25
|
+
export declare function addComputedFields<T>(data: T): T;
|
|
26
|
+
/**
|
|
27
|
+
* Apply all transformations in order
|
|
28
|
+
*/
|
|
29
|
+
export declare function applyTransformations<T>(data: T, shouldNormalizeKeys: boolean, shouldTransformDates: boolean, shouldFlattenResponses: boolean, shouldAddComputedFields: boolean): T;
|
|
30
|
+
//# sourceMappingURL=transformers.d.ts.map
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Response transformers for opinionated data transformations
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.normalizeKeys = normalizeKeys;
|
|
7
|
+
exports.transformDates = transformDates;
|
|
8
|
+
exports.flattenResponses = flattenResponses;
|
|
9
|
+
exports.addComputedFields = addComputedFields;
|
|
10
|
+
exports.applyTransformations = applyTransformations;
|
|
11
|
+
/**
|
|
12
|
+
* Convert snake_case keys to camelCase
|
|
13
|
+
* @param data - Data to normalize
|
|
14
|
+
* @returns Data with camelCase keys
|
|
15
|
+
*/
|
|
16
|
+
function normalizeKeys(data) {
|
|
17
|
+
if (data === null || data === undefined) {
|
|
18
|
+
return data;
|
|
19
|
+
}
|
|
20
|
+
if (data instanceof Date) {
|
|
21
|
+
return data;
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(data)) {
|
|
24
|
+
return data.map(normalizeKeys);
|
|
25
|
+
}
|
|
26
|
+
if (typeof data === "object") {
|
|
27
|
+
const normalized = {};
|
|
28
|
+
for (const [key, value] of Object.entries(data)) {
|
|
29
|
+
const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
30
|
+
normalized[camelKey] = normalizeKeys(value);
|
|
31
|
+
}
|
|
32
|
+
return normalized;
|
|
33
|
+
}
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Transform ISO date strings to Date objects
|
|
38
|
+
* @param data - Data to transform
|
|
39
|
+
* @returns Data with Date objects instead of ISO strings
|
|
40
|
+
*/
|
|
41
|
+
function transformDates(data) {
|
|
42
|
+
if (data === null || data === undefined) {
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
if (data instanceof Date) {
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(data)) {
|
|
49
|
+
return data.map(transformDates);
|
|
50
|
+
}
|
|
51
|
+
if (typeof data === "object") {
|
|
52
|
+
const transformed = {};
|
|
53
|
+
for (const [key, value] of Object.entries(data)) {
|
|
54
|
+
const lowerKey = key.toLowerCase();
|
|
55
|
+
const isDateField = /_(at|date|time)$/i.test(key) ||
|
|
56
|
+
/[dD]ate/.test(key) ||
|
|
57
|
+
/[tT]ime/.test(key) ||
|
|
58
|
+
lowerKey.includes("date") ||
|
|
59
|
+
lowerKey.includes("time");
|
|
60
|
+
if (isDateField && typeof value === "string") {
|
|
61
|
+
const date = new Date(value);
|
|
62
|
+
if (!isNaN(date.getTime())) {
|
|
63
|
+
transformed[key] = date;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
transformed[key] = transformDates(value);
|
|
68
|
+
}
|
|
69
|
+
return transformed;
|
|
70
|
+
}
|
|
71
|
+
return data;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Flatten nested response structures
|
|
75
|
+
* @param data - Data to flatten
|
|
76
|
+
* @returns Flattened data structure
|
|
77
|
+
*/
|
|
78
|
+
function flattenResponses(data) {
|
|
79
|
+
if (data === null || data === undefined) {
|
|
80
|
+
return data;
|
|
81
|
+
}
|
|
82
|
+
if (data instanceof Date) {
|
|
83
|
+
return data;
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(data)) {
|
|
86
|
+
return data.map(flattenResponses);
|
|
87
|
+
}
|
|
88
|
+
if (typeof data === "object") {
|
|
89
|
+
const flattened = {};
|
|
90
|
+
for (const [key, value] of Object.entries(data)) {
|
|
91
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
92
|
+
if ("id" in value || "firstname" in value || "name" in value) {
|
|
93
|
+
for (const [nestedKey, nestedValue] of Object.entries(value)) {
|
|
94
|
+
const flattenedKey = `${key}${nestedKey.charAt(0).toUpperCase() + nestedKey.slice(1)}`;
|
|
95
|
+
flattened[flattenedKey] = nestedValue;
|
|
96
|
+
}
|
|
97
|
+
flattened[key] = value;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
flattened[key] = flattenResponses(value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
flattened[key] = flattenResponses(value);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return flattened;
|
|
108
|
+
}
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Add computed fields
|
|
113
|
+
*/
|
|
114
|
+
function addComputedFields(data) {
|
|
115
|
+
if (data === null || data === undefined) {
|
|
116
|
+
return data;
|
|
117
|
+
}
|
|
118
|
+
if (data instanceof Date) {
|
|
119
|
+
return data;
|
|
120
|
+
}
|
|
121
|
+
if (Array.isArray(data)) {
|
|
122
|
+
return data.map(addComputedFields);
|
|
123
|
+
}
|
|
124
|
+
if (typeof data === "object") {
|
|
125
|
+
const enhanced = { ...data };
|
|
126
|
+
const dataRecord = data;
|
|
127
|
+
if ("distance" in dataRecord && ("movingTime" in dataRecord || "elapsedTime" in dataRecord)) {
|
|
128
|
+
const distance = dataRecord.distance;
|
|
129
|
+
const movingTime = dataRecord.movingTime || dataRecord.elapsedTime;
|
|
130
|
+
if (movingTime > 0) {
|
|
131
|
+
enhanced.averageSpeed = distance / movingTime;
|
|
132
|
+
enhanced.averageSpeedKmh = (distance / 1000) / (movingTime / 3600);
|
|
133
|
+
const type = dataRecord.type;
|
|
134
|
+
const sportType = dataRecord.sportType;
|
|
135
|
+
if (type === "Run" || sportType === "Run") {
|
|
136
|
+
enhanced.pace = formatPace(movingTime / (distance / 1000));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if ("movingTime" in dataRecord || "elapsedTime" in dataRecord) {
|
|
141
|
+
const time = dataRecord.movingTime || dataRecord.elapsedTime;
|
|
142
|
+
enhanced.duration = {
|
|
143
|
+
seconds: time,
|
|
144
|
+
minutes: Math.floor(time / 60),
|
|
145
|
+
hours: Math.floor(time / 3600),
|
|
146
|
+
formatted: formatDuration(time),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
for (const [key, value] of Object.entries(enhanced)) {
|
|
150
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
151
|
+
enhanced[key] = addComputedFields(value);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return enhanced;
|
|
155
|
+
}
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Format pace (seconds per km to min:sec/km)
|
|
160
|
+
*/
|
|
161
|
+
function formatPace(secondsPerKm) {
|
|
162
|
+
const minutes = Math.floor(secondsPerKm / 60);
|
|
163
|
+
const seconds = Math.floor(secondsPerKm % 60);
|
|
164
|
+
return `${minutes}:${seconds.toString().padStart(2, "0")}/km`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Format duration (seconds to human-readable)
|
|
168
|
+
*/
|
|
169
|
+
function formatDuration(seconds) {
|
|
170
|
+
const hours = Math.floor(seconds / 3600);
|
|
171
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
172
|
+
const secs = Math.floor(seconds % 60);
|
|
173
|
+
if (hours > 0) {
|
|
174
|
+
return `${hours}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
|
|
175
|
+
}
|
|
176
|
+
return `${minutes}:${secs.toString().padStart(2, "0")}`;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Apply all transformations in order
|
|
180
|
+
*/
|
|
181
|
+
function applyTransformations(data, shouldNormalizeKeys, shouldTransformDates, shouldFlattenResponses, shouldAddComputedFields) {
|
|
182
|
+
let result = data;
|
|
183
|
+
if (shouldNormalizeKeys) {
|
|
184
|
+
result = normalizeKeys(result);
|
|
185
|
+
}
|
|
186
|
+
if (shouldTransformDates) {
|
|
187
|
+
result = transformDates(result);
|
|
188
|
+
}
|
|
189
|
+
if (shouldFlattenResponses) {
|
|
190
|
+
result = flattenResponses(result);
|
|
191
|
+
}
|
|
192
|
+
if (shouldAddComputedFields) {
|
|
193
|
+
result = addComputedFields(result);
|
|
194
|
+
}
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input validation helpers
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Validate that a value is a positive integer
|
|
6
|
+
* @param value - Value to validate
|
|
7
|
+
* @param name - Name of the parameter for error messages
|
|
8
|
+
* @returns Validated positive integer
|
|
9
|
+
* @throws Error if value is not a positive integer
|
|
10
|
+
*/
|
|
11
|
+
export declare function validatePositiveInteger(value: unknown, name: string): number;
|
|
12
|
+
/**
|
|
13
|
+
* Validate that a value is a non-negative integer
|
|
14
|
+
* @param value - Value to validate
|
|
15
|
+
* @param name - Name of the parameter for error messages
|
|
16
|
+
* @returns Validated non-negative integer
|
|
17
|
+
* @throws Error if value is not a non-negative integer
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateNonNegativeInteger(value: unknown, name: string): number;
|
|
20
|
+
/**
|
|
21
|
+
* Validate that a value is within a range
|
|
22
|
+
* @param value - Value to validate
|
|
23
|
+
* @param min - Minimum allowed value
|
|
24
|
+
* @param max - Maximum allowed value
|
|
25
|
+
* @param name - Name of the parameter for error messages
|
|
26
|
+
* @returns Validated value
|
|
27
|
+
* @throws Error if value is outside the range
|
|
28
|
+
*/
|
|
29
|
+
export declare function validateRange(value: number, min: number, max: number, name: string): number;
|
|
30
|
+
/**
|
|
31
|
+
* Validate that a value is a valid date
|
|
32
|
+
* @param value - Value to validate
|
|
33
|
+
* @param name - Name of the parameter for error messages
|
|
34
|
+
* @returns Validated Date object
|
|
35
|
+
* @throws Error if value is not a valid Date
|
|
36
|
+
*/
|
|
37
|
+
export declare function validateDate(value: unknown, name: string): Date;
|
|
38
|
+
/**
|
|
39
|
+
* Validate that a value is a non-empty string
|
|
40
|
+
* @param value - Value to validate
|
|
41
|
+
* @param name - Name of the parameter for error messages
|
|
42
|
+
* @returns Validated non-empty string
|
|
43
|
+
* @throws Error if value is not a non-empty string
|
|
44
|
+
*/
|
|
45
|
+
export declare function validateNonEmptyString(value: unknown, name: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Validate pagination options
|
|
48
|
+
* @param page - Page number (optional)
|
|
49
|
+
* @param perPage - Items per page (optional, must be 1-200)
|
|
50
|
+
* @throws Error if pagination options are invalid
|
|
51
|
+
*/
|
|
52
|
+
export declare function validatePagination(page?: number, perPage?: number): void;
|
|
53
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Input validation helpers
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.validatePositiveInteger = validatePositiveInteger;
|
|
7
|
+
exports.validateNonNegativeInteger = validateNonNegativeInteger;
|
|
8
|
+
exports.validateRange = validateRange;
|
|
9
|
+
exports.validateDate = validateDate;
|
|
10
|
+
exports.validateNonEmptyString = validateNonEmptyString;
|
|
11
|
+
exports.validatePagination = validatePagination;
|
|
12
|
+
/**
|
|
13
|
+
* Validate that a value is a positive integer
|
|
14
|
+
* @param value - Value to validate
|
|
15
|
+
* @param name - Name of the parameter for error messages
|
|
16
|
+
* @returns Validated positive integer
|
|
17
|
+
* @throws Error if value is not a positive integer
|
|
18
|
+
*/
|
|
19
|
+
function validatePositiveInteger(value, name) {
|
|
20
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
21
|
+
throw new Error(`${name} must be a positive integer, got: ${value}`);
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Validate that a value is a non-negative integer
|
|
27
|
+
* @param value - Value to validate
|
|
28
|
+
* @param name - Name of the parameter for error messages
|
|
29
|
+
* @returns Validated non-negative integer
|
|
30
|
+
* @throws Error if value is not a non-negative integer
|
|
31
|
+
*/
|
|
32
|
+
function validateNonNegativeInteger(value, name) {
|
|
33
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
34
|
+
throw new Error(`${name} must be a non-negative integer, got: ${value}`);
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Validate that a value is within a range
|
|
40
|
+
* @param value - Value to validate
|
|
41
|
+
* @param min - Minimum allowed value
|
|
42
|
+
* @param max - Maximum allowed value
|
|
43
|
+
* @param name - Name of the parameter for error messages
|
|
44
|
+
* @returns Validated value
|
|
45
|
+
* @throws Error if value is outside the range
|
|
46
|
+
*/
|
|
47
|
+
function validateRange(value, min, max, name) {
|
|
48
|
+
if (value < min || value > max) {
|
|
49
|
+
throw new Error(`${name} must be between ${min} and ${max}, got: ${value}`);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validate that a value is a valid date
|
|
55
|
+
* @param value - Value to validate
|
|
56
|
+
* @param name - Name of the parameter for error messages
|
|
57
|
+
* @returns Validated Date object
|
|
58
|
+
* @throws Error if value is not a valid Date
|
|
59
|
+
*/
|
|
60
|
+
function validateDate(value, name) {
|
|
61
|
+
if (!(value instanceof Date) || isNaN(value.getTime())) {
|
|
62
|
+
throw new Error(`${name} must be a valid Date object`);
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validate that a value is a non-empty string
|
|
68
|
+
* @param value - Value to validate
|
|
69
|
+
* @param name - Name of the parameter for error messages
|
|
70
|
+
* @returns Validated non-empty string
|
|
71
|
+
* @throws Error if value is not a non-empty string
|
|
72
|
+
*/
|
|
73
|
+
function validateNonEmptyString(value, name) {
|
|
74
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
75
|
+
throw new Error(`${name} must be a non-empty string`);
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Validate pagination options
|
|
81
|
+
* @param page - Page number (optional)
|
|
82
|
+
* @param perPage - Items per page (optional, must be 1-200)
|
|
83
|
+
* @throws Error if pagination options are invalid
|
|
84
|
+
*/
|
|
85
|
+
function validatePagination(page, perPage) {
|
|
86
|
+
if (page !== undefined) {
|
|
87
|
+
validatePositiveInteger(page, "page");
|
|
88
|
+
}
|
|
89
|
+
if (perPage !== undefined) {
|
|
90
|
+
validateRange(perPage, 1, 200, "perPage");
|
|
91
|
+
}
|
|
92
|
+
}
|