Skip to content

Commit

Permalink
Merge pull request #75 from acelaya-forks/feature/type-consolidation
Browse files Browse the repository at this point in the history
Feature/type consolidation
  • Loading branch information
acelaya authored Mar 5, 2024
2 parents 63f461c + 2f19dd3 commit ec16d59
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 192 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).

## [Unreleased]
### Added
* *Nothing*

### Changed
* Update dependencies.
* [#22](https://github.com/shlinkio/shlink-js-sdk/issues/22) Consolidate exposed types, making them more consistent.

* Types no longer couple with HTTP terminology, removing references to body, query, request, response, etc.
* All types that wrap a list of entities are now suffixed with `List` (`ShlinkShortUrlsList`, `ShlinkVisitsList`, etc.)
* Arguments passed to the API client frequently use the `Params` suffix when representing filters (like `ShlinkVisitsParams`) or `Data` suffix when wrapping props to be mutated (like `ShlinkEditShortUrlData`).
* Methods returning entities, just use the name of the entity itself, regardless of the method's nature (fetch or mutation).
* Methods returning the result of a mutation when it is not an entity, will return types using the `Result` suffix (like `ShlinkDeleteVisitsResult`).

### Deprecated
* *Nothing*

### Removed
* [#74](https://github.com/shlinkio/shlink-js-sdk/issues/74) Drop support for Shlink older than 3.3.0. This version introduced the API v3, so this allows to remove the logic to fall back to v2, and remove the error types used in v2.

### Fixed
* *Nothing*


## [0.2.2] - 2024-01-20
### Added
* *Nothing*
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
},
"./browser": {
"import": "./dist/browser.js",
"require": "./dist/browser.cjs",
"types": "./dist/browser.d.ts"
},
"./api-contract": {
"import": "./dist/api-contract.js",
"require": "./dist/api-contract.cjs",
"types": "./dist/api-contract.d.ts"
},
"./browser": {
"import": "./dist/browser.js",
"require": "./dist/browser.cjs",
"types": "./dist/browser.d.ts"
},
"./node": {
"import": "./dist/node.js",
"require": "./dist/node.cjs",
Expand Down
65 changes: 38 additions & 27 deletions src/api-contract/ShlinkApiClient.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,77 @@
import type {
ShlinkCreateShortUrlData,
ShlinkDeleteVisitsResponse,
ShlinkDeleteVisitsResult,
ShlinkDomainRedirects,
ShlinkDomainsResponse,
ShlinkDomainsList,
ShlinkEditDomainRedirects,
ShlinkEditShortUrlData,
ShlinkHealth,
ShlinkMercureInfo,
ShlinkShortUrl,
ShlinkShortUrlsList,
ShlinkShortUrlsListParams,
ShlinkShortUrlsResponse,
ShlinkShortUrlVisitsParams,
ShlinkTags,
ShlinkVisits,
ShlinkTagsList,
ShlinkTagsStatsList,
ShlinkVisitsList,
ShlinkVisitsOverview,
ShlinkVisitsParams,
} from './types';

export type ShlinkApiClient = {
listShortUrls(params?: ShlinkShortUrlsListParams): Promise<ShlinkShortUrlsResponse>;
// Short URLs

listShortUrls(params?: ShlinkShortUrlsListParams): Promise<ShlinkShortUrlsList>;

createShortUrl(options: ShlinkCreateShortUrlData): Promise<ShlinkShortUrl>;

getShortUrlVisits(shortCode: string, query?: ShlinkShortUrlVisitsParams): Promise<ShlinkVisits>;
getShortUrl(shortCode: string, domain?: string | null): Promise<ShlinkShortUrl>;

deleteShortUrlVisits(shortCode: string, domain?: string | null): Promise<ShlinkDeleteVisitsResponse>;
deleteShortUrl(shortCode: string, domain?: string | null): Promise<void>;

getTagVisits(tag: string, query?: ShlinkVisitsParams): Promise<ShlinkVisits>;
updateShortUrl(
shortCode: string,
domain: string | null | undefined,
data: ShlinkEditShortUrlData,
): Promise<ShlinkShortUrl>;

getDomainVisits(domain: string, query?: ShlinkVisitsParams): Promise<ShlinkVisits>;
// Visits

getOrphanVisits(query?: ShlinkVisitsParams): Promise<ShlinkVisits>;
getVisitsOverview(): Promise<ShlinkVisitsOverview>;

deleteOrphanVisits(): Promise<ShlinkDeleteVisitsResponse>;
getShortUrlVisits(shortCode: string, params?: ShlinkShortUrlVisitsParams): Promise<ShlinkVisitsList>;

getNonOrphanVisits(query?: ShlinkVisitsParams): Promise<ShlinkVisits>;
getTagVisits(tag: string, params?: ShlinkVisitsParams): Promise<ShlinkVisitsList>;

getVisitsOverview(): Promise<ShlinkVisitsOverview>;
getDomainVisits(domain: string, params?: ShlinkVisitsParams): Promise<ShlinkVisitsList>;

getShortUrl(shortCode: string, domain?: string | null): Promise<ShlinkShortUrl>;
getOrphanVisits(params?: ShlinkVisitsParams): Promise<ShlinkVisitsList>;

deleteShortUrl(shortCode: string, domain?: string | null): Promise<void>;
getNonOrphanVisits(params?: ShlinkVisitsParams): Promise<ShlinkVisitsList>;

updateShortUrl(
shortCode: string,
domain: string | null | undefined,
body: ShlinkEditShortUrlData,
): Promise<ShlinkShortUrl>;
deleteShortUrlVisits(shortCode: string, domain?: string | null): Promise<ShlinkDeleteVisitsResult>;

deleteOrphanVisits(): Promise<ShlinkDeleteVisitsResult>;

listTags(): Promise<ShlinkTags>;
// Tags

tagsStats(): Promise<ShlinkTags>;
listTags(): Promise<ShlinkTagsList>;

tagsStats(): Promise<ShlinkTagsStatsList>;

deleteTags(tags: string[]): Promise<{ tags: string[] }>;

editTag(oldName: string, newName: string): Promise<{ oldName: string; newName: string }>;

health(authority?: string): Promise<ShlinkHealth>;

mercureInfo(): Promise<ShlinkMercureInfo>;
// Domains

listDomains(): Promise<ShlinkDomainsResponse>;
listDomains(): Promise<ShlinkDomainsList>;

editDomainRedirects(domainRedirects: ShlinkEditDomainRedirects): Promise<ShlinkDomainRedirects>;

// Misc

health(authority?: string): Promise<ShlinkHealth>;

mercureInfo(): Promise<ShlinkMercureInfo>;
};
28 changes: 10 additions & 18 deletions src/api-contract/errors.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
export enum ErrorTypeV2 {
INVALID_ARGUMENT = 'INVALID_ARGUMENT',
INVALID_SHORT_URL_DELETION = 'INVALID_SHORT_URL_DELETION',
DOMAIN_NOT_FOUND = 'DOMAIN_NOT_FOUND',
FORBIDDEN_OPERATION = 'FORBIDDEN_OPERATION',
INVALID_URL = 'INVALID_URL',
INVALID_SLUG = 'INVALID_SLUG',
INVALID_SHORTCODE = 'INVALID_SHORTCODE',
TAG_CONFLICT = 'TAG_CONFLICT',
TAG_NOT_FOUND = 'TAG_NOT_FOUND',
MERCURE_NOT_CONFIGURED = 'MERCURE_NOT_CONFIGURED',
INVALID_AUTHORIZATION = 'INVALID_AUTHORIZATION',
INVALID_API_KEY = 'INVALID_API_KEY',
NOT_FOUND = 'NOT_FOUND',
}

export enum ErrorTypeV3 {
/**
* Possible error types returned by Shlink's API
*/
export enum ErrorType {
INVALID_ARGUMENT = 'https://shlink.io/api/error/invalid-data',
INVALID_SHORT_URL_DELETION = 'https://shlink.io/api/error/invalid-short-url-deletion',
DOMAIN_NOT_FOUND = 'https://shlink.io/api/error/domain-not-found',
FORBIDDEN_OPERATION = 'https://shlink.io/api/error/forbidden-tag-operation',
INVALID_URL = 'https://shlink.io/api/error/invalid-url',
INVALID_SLUG = 'https://shlink.io/api/error/non-unique-slug',
INVALID_SHORTCODE = 'https://shlink.io/api/error/short-url-not-found',
TAG_CONFLICT = 'https://shlink.io/api/error/tag-conflict',
Expand All @@ -28,8 +14,14 @@ export enum ErrorTypeV3 {
INVALID_AUTHORIZATION = 'https://shlink.io/api/error/missing-authentication',
INVALID_API_KEY = 'https://shlink.io/api/error/invalid-api-key',
NOT_FOUND = 'https://shlink.io/api/error/not-found',

/** @deprecated Shlink 4.0.0 no longer validates URLs, so this error will never happen with that version */
INVALID_URL = 'https://shlink.io/api/error/invalid-url',
}

/**
* Shape of the errors returned by Shlink
*/
export type ProblemDetailsError = {
type: string;
detail: string;
Expand Down
49 changes: 26 additions & 23 deletions src/api-contract/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ type Nullable<T> = {
[P in keyof T]: T[P] | null
};

/**
* @deprecated Shlink 4.0.0 no longer uses this.
*/
export type ShlinkDeviceLongUrls = {
android?: OptionalString;
ios?: OptionalString;
Expand All @@ -20,11 +23,7 @@ export type ShlinkShortUrl = {
shortCode: string;
shortUrl: string;
longUrl: string;
/** Optional only before Shlink 3.5.0 */
deviceLongUrls?: Required<ShlinkDeviceLongUrls>,
dateCreated: string;
/** @deprecated Use `visitsSummary.total` instead */
visitsCount: number;
/** Optional only before Shlink 3.4.0 */
visitsSummary?: ShlinkVisitsSummary;
meta: Required<Nullable<ShlinkShortUrlMeta>>;
Expand All @@ -33,37 +32,45 @@ export type ShlinkShortUrl = {
title?: string | null;
crawlable?: boolean;
forwardQuery?: boolean;

/** @deprecated Use `visitsSummary.total` instead */
visitsCount?: number;
/** @deprecated Removed in Shlink 4.0.0 */
deviceLongUrls?: Required<ShlinkDeviceLongUrls>,
};

export type ShlinkEditShortUrlData = {
longUrl?: string;
title?: string | null;
tags?: string[];
deviceLongUrls?: ShlinkDeviceLongUrls;
crawlable?: boolean;
forwardQuery?: boolean;
validSince?: string | null;
validUntil?: string | null;
maxVisits?: number | null;

/** @deprecated To be removed in Shlink 4.0.0 */
/** @deprecated Ignored by Shlink 4.0.0 */
validateUrl?: boolean;
/** @deprecated Ignored by Shlink 4.0.0. Use redirect rules instead */
deviceLongUrls?: ShlinkDeviceLongUrls;
};

export type ShlinkCreateShortUrlData = Omit<ShlinkEditShortUrlData, 'deviceLongUrls'> & {
export type ShlinkCreateShortUrlData = Omit<ShlinkEditShortUrlData, 'deviceLongUrls' | 'longUrl'> & {
longUrl: string;
customSlug?: string;
shortCodeLength?: number;
domain?: string;
findIfExists?: boolean;

/** @deprecated Ignored by Shlink 4.0.0. Use redirect rules instead */
deviceLongUrls?: {
android?: string;
ios?: string;
desktop?: string;
}
};

export type ShlinkShortUrlsResponse = {
export type ShlinkShortUrlsList = {
data: ShlinkShortUrl[];
pagination: ShlinkPaginator;
};
Expand All @@ -84,22 +91,18 @@ export type ShlinkTagsStats = {
/** Optional only before Shlink 3.5.0 */
visitsSummary?: ShlinkVisitsSummary;

/** @deprecated Use `visitsSummary.total` instead */
visitsCount: number;
/** @deprecated Not returned by Shlink 4.0.0. Use `visitsSummary.total` instead */
visitsCount?: number;
};

export type ShlinkTags = {
tags: string[];
stats: ShlinkTagsStats[];
};

export type ShlinkTagsResponse = {
export type ShlinkTagsList = {
data: string[];
/** @deprecated Present only when withStats=true is provided, which is deprecated */

/** @deprecated Never returned by Shlink 4.0.0 */
stats?: ShlinkTagsStats[];
};

export type ShlinkTagsStatsResponse = {
export type ShlinkTagsStatsList = {
data: ShlinkTagsStats[];
};

Expand Down Expand Up @@ -143,12 +146,12 @@ export type ShlinkOrphanVisit = ShlinkRegularVisit & {

export type ShlinkVisit = ShlinkRegularVisit | ShlinkOrphanVisit;

export type ShlinkVisits = {
export type ShlinkVisitsList = {
data: ShlinkVisit[];
pagination: ShlinkPaginator;
};

export type ShlinkDeleteVisitsResponse = {
export type ShlinkDeleteVisitsResult = {
deletedVisits: number;
};

Expand All @@ -159,9 +162,9 @@ export type ShlinkVisitsOverview = {
orphanVisits?: ShlinkVisitsSummary;

/** @deprecated Use `nonOrphanVisits.total` instead */
visitsCount: number;
visitsCount?: number;
/** @deprecated Use `orphanVisits.total` instead */
orphanVisitsCount: number;
orphanVisitsCount?: number;
};

export type ShlinkVisitsParams = {
Expand Down Expand Up @@ -192,7 +195,7 @@ export type ShlinkDomain = {
redirects: ShlinkDomainRedirects;
};

export type ShlinkDomainsResponse = {
export type ShlinkDomainsList = {
data: ShlinkDomain[];
defaultRedirects: ShlinkDomainRedirects;
};
Expand Down
Loading

0 comments on commit ec16d59

Please sign in to comment.