@abyss-project/link 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/.eslintrc.js +32 -0
  2. package/.prettierrc +5 -0
  3. package/README.md +21 -2
  4. package/dist/api/abyss.admin.api.d.ts +4 -0
  5. package/dist/api/abyss.admin.api.js +17 -0
  6. package/dist/api/abyss.admin.api.js.map +1 -0
  7. package/dist/api/index.d.ts +4 -0
  8. package/dist/api/index.js +21 -0
  9. package/dist/api/index.js.map +1 -0
  10. package/dist/api/link.admin.api.d.ts +14 -0
  11. package/dist/api/link.admin.api.js +64 -0
  12. package/dist/api/link.admin.api.js.map +1 -0
  13. package/dist/api/link.api.d.ts +15 -0
  14. package/dist/api/link.api.js +69 -0
  15. package/dist/api/link.api.js.map +1 -0
  16. package/dist/api/link.public.api.d.ts +2 -0
  17. package/dist/api/link.public.api.js +9 -0
  18. package/dist/api/link.public.api.js.map +1 -0
  19. package/dist/constants/index.d.ts +1 -0
  20. package/dist/constants/index.js +18 -0
  21. package/dist/constants/index.js.map +1 -0
  22. package/dist/constants/link.constants.d.ts +25 -0
  23. package/dist/constants/link.constants.js +48 -0
  24. package/dist/constants/link.constants.js.map +1 -0
  25. package/dist/index.d.ts +70 -0
  26. package/dist/index.js +157 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/types/enum/api-error.enum.d.ts +24 -0
  29. package/dist/types/enum/api-error.enum.js +30 -0
  30. package/dist/types/enum/api-error.enum.js.map +1 -0
  31. package/dist/types/enum/index.d.ts +4 -0
  32. package/dist/types/enum/index.js +21 -0
  33. package/dist/types/enum/index.js.map +1 -0
  34. package/dist/types/enum/link-share.enum.d.ts +11 -0
  35. package/dist/types/enum/link-share.enum.js +17 -0
  36. package/dist/types/enum/link-share.enum.js.map +1 -0
  37. package/dist/types/enum/link-stats.enum.d.ts +5 -0
  38. package/dist/types/enum/link-stats.enum.js +10 -0
  39. package/dist/types/enum/link-stats.enum.js.map +1 -0
  40. package/dist/types/enum/link.enum.d.ts +20 -0
  41. package/dist/types/enum/link.enum.js +27 -0
  42. package/dist/types/enum/link.enum.js.map +1 -0
  43. package/dist/types/index.d.ts +2 -0
  44. package/dist/types/index.js +19 -0
  45. package/dist/types/index.js.map +1 -0
  46. package/dist/types/interface/api/index.d.ts +5 -0
  47. package/dist/types/interface/api/index.js +22 -0
  48. package/dist/types/interface/api/index.js.map +1 -0
  49. package/dist/types/interface/api/requests/abyss.admin.request.d.ts +14 -0
  50. package/dist/types/interface/api/requests/abyss.admin.request.js +3 -0
  51. package/dist/types/interface/api/requests/abyss.admin.request.js.map +1 -0
  52. package/dist/types/interface/api/requests/index.d.ts +4 -0
  53. package/dist/types/interface/api/requests/index.js +21 -0
  54. package/dist/types/interface/api/requests/index.js.map +1 -0
  55. package/dist/types/interface/api/requests/link.admin.request.d.ts +69 -0
  56. package/dist/types/interface/api/requests/link.admin.request.js +3 -0
  57. package/dist/types/interface/api/requests/link.admin.request.js.map +1 -0
  58. package/dist/types/interface/api/requests/link.public.request.d.ts +13 -0
  59. package/dist/types/interface/api/requests/link.public.request.js +3 -0
  60. package/dist/types/interface/api/requests/link.public.request.js.map +1 -0
  61. package/dist/types/interface/api/requests/link.request.d.ts +74 -0
  62. package/dist/types/interface/api/requests/link.request.js +3 -0
  63. package/dist/types/interface/api/requests/link.request.js.map +1 -0
  64. package/dist/types/interface/api/responses/abyss.admin.response.d.ts +14 -0
  65. package/dist/types/interface/api/responses/abyss.admin.response.js +3 -0
  66. package/dist/types/interface/api/responses/abyss.admin.response.js.map +1 -0
  67. package/dist/types/interface/api/responses/index.d.ts +4 -0
  68. package/dist/types/interface/api/responses/index.js +21 -0
  69. package/dist/types/interface/api/responses/index.js.map +1 -0
  70. package/dist/types/interface/api/responses/link.admin.response.d.ts +43 -0
  71. package/dist/types/interface/api/responses/link.admin.response.js +3 -0
  72. package/dist/types/interface/api/responses/link.admin.response.js.map +1 -0
  73. package/dist/types/interface/api/responses/link.public.response.d.ts +5 -0
  74. package/dist/types/interface/api/responses/link.public.response.js +3 -0
  75. package/dist/types/interface/api/responses/link.public.response.js.map +1 -0
  76. package/dist/types/interface/api/responses/link.response.d.ts +43 -0
  77. package/dist/types/interface/api/responses/link.response.js +3 -0
  78. package/dist/types/interface/api/responses/link.response.js.map +1 -0
  79. package/dist/types/interface/api/type-message/api-error.d.ts +6 -0
  80. package/dist/types/interface/api/type-message/api-error.js +3 -0
  81. package/dist/types/interface/api/type-message/api-error.js.map +1 -0
  82. package/dist/types/interface/api/type-message/base-paginate.d.ts +10 -0
  83. package/dist/types/interface/api/type-message/base-paginate.js +3 -0
  84. package/dist/types/interface/api/type-message/base-paginate.js.map +1 -0
  85. package/dist/types/interface/api/type-message/response.d.ts +5 -0
  86. package/dist/types/interface/api/type-message/response.js +3 -0
  87. package/dist/types/interface/api/type-message/response.js.map +1 -0
  88. package/dist/types/interface/index.d.ts +2 -0
  89. package/dist/types/interface/index.js +19 -0
  90. package/dist/types/interface/index.js.map +1 -0
  91. package/dist/types/interface/models/index.d.ts +5 -0
  92. package/dist/types/interface/models/index.js +22 -0
  93. package/dist/types/interface/models/index.js.map +1 -0
  94. package/dist/types/interface/models/link-list.dto.d.ts +20 -0
  95. package/dist/types/interface/models/link-list.dto.js +3 -0
  96. package/dist/types/interface/models/link-list.dto.js.map +1 -0
  97. package/dist/types/interface/models/link.dto.d.ts +91 -0
  98. package/dist/types/interface/models/link.dto.js +3 -0
  99. package/dist/types/interface/models/link.dto.js.map +1 -0
  100. package/dist/types/interface/models/organization.dto.d.ts +11 -0
  101. package/dist/types/interface/models/organization.dto.js +3 -0
  102. package/dist/types/interface/models/organization.dto.js.map +1 -0
  103. package/dist/types/interface/models/project.dto.d.ts +12 -0
  104. package/dist/types/interface/models/project.dto.js +3 -0
  105. package/dist/types/interface/models/project.dto.js.map +1 -0
  106. package/dist/types/interface/models/user.dto.d.ts +11 -0
  107. package/dist/types/interface/models/user.dto.js +3 -0
  108. package/dist/types/interface/models/user.dto.js.map +1 -0
  109. package/dist/utils/enum.utils.d.ts +1 -0
  110. package/dist/utils/enum.utils.js +3 -0
  111. package/dist/utils/enum.utils.js.map +1 -0
  112. package/dist/utils/error.utils.d.ts +15 -0
  113. package/dist/utils/error.utils.js +25 -0
  114. package/dist/utils/error.utils.js.map +1 -0
  115. package/dist/utils/index.d.ts +3 -0
  116. package/dist/utils/index.js +20 -0
  117. package/dist/utils/index.js.map +1 -0
  118. package/dist/utils/link-slug.utils.d.ts +1 -0
  119. package/dist/utils/link-slug.utils.js +11 -0
  120. package/dist/utils/link-slug.utils.js.map +1 -0
  121. package/jest.config.cjs +9 -0
  122. package/package.json +62 -4
  123. package/src/api/abyss.admin.api.ts +39 -0
  124. package/src/api/index.ts +4 -0
  125. package/src/api/link.admin.api.ts +168 -0
  126. package/src/api/link.api.ts +158 -0
  127. package/src/api/link.public.api.ts +19 -0
  128. package/src/constants/index.ts +1 -0
  129. package/src/constants/link.constants.ts +66 -0
  130. package/src/constants/tests/link-forbidden-slugs.spec.ts +103 -0
  131. package/src/index.ts +180 -0
  132. package/src/tests/link-public-api.spec.ts +37 -0
  133. package/src/tests/link-sdk-surface.spec.ts +191 -0
  134. package/src/tests/sdk-surface.spec.ts +63 -0
  135. package/src/types/enum/api-error.enum.ts +31 -0
  136. package/src/types/enum/index.ts +4 -0
  137. package/src/types/enum/link-share.enum.ts +17 -0
  138. package/src/types/enum/link-stats.enum.ts +6 -0
  139. package/src/types/enum/link.enum.ts +34 -0
  140. package/src/types/index.ts +2 -0
  141. package/src/types/interface/api/index.ts +5 -0
  142. package/src/types/interface/api/requests/abyss.admin.request.ts +17 -0
  143. package/src/types/interface/api/requests/index.ts +4 -0
  144. package/src/types/interface/api/requests/link.admin.request.ts +104 -0
  145. package/src/types/interface/api/requests/link.public.request.ts +18 -0
  146. package/src/types/interface/api/requests/link.request.ts +100 -0
  147. package/src/types/interface/api/responses/abyss.admin.response.ts +17 -0
  148. package/src/types/interface/api/responses/index.ts +4 -0
  149. package/src/types/interface/api/responses/link.admin.response.ts +56 -0
  150. package/src/types/interface/api/responses/link.public.response.ts +7 -0
  151. package/src/types/interface/api/responses/link.response.ts +55 -0
  152. package/src/types/interface/api/type-message/api-error.ts +7 -0
  153. package/src/types/interface/api/type-message/base-paginate.ts +11 -0
  154. package/src/types/interface/api/type-message/response.ts +6 -0
  155. package/src/types/interface/index.ts +2 -0
  156. package/src/types/interface/models/index.ts +5 -0
  157. package/src/types/interface/models/link-list.dto.ts +28 -0
  158. package/src/types/interface/models/link.dto.ts +117 -0
  159. package/src/types/interface/models/organization.dto.ts +21 -0
  160. package/src/types/interface/models/project.dto.ts +16 -0
  161. package/src/types/interface/models/user.dto.ts +19 -0
  162. package/src/types/tests/link-enums.spec.ts +48 -0
  163. package/src/utils/enum.utils.ts +1 -0
  164. package/src/utils/error.utils.ts +30 -0
  165. package/src/utils/index.ts +3 -0
  166. package/src/utils/link-slug.utils.ts +10 -0
  167. package/tsconfig.check.json +15 -0
  168. package/tsconfig.json +36 -0
@@ -0,0 +1,104 @@
1
+ import { LinkKind } from '../../../enum/link.enum';
2
+ import { ILinkOrigin } from '../../models/link.dto';
3
+ import { QueryPaginate } from '../type-message/base-paginate';
4
+ import { IGetLinkStatsQuery, ILinkIdParams } from './link.request';
5
+
6
+ export interface IPaginateLinkAdminQuery extends QueryPaginate {
7
+ search?: string;
8
+ kind?: LinkKind;
9
+ userId?: string;
10
+ projectId?: string;
11
+ organizationId?: string;
12
+ isActive?: boolean;
13
+ isProtected?: boolean;
14
+ }
15
+
16
+ export type IGetLinkAdminParams = ILinkIdParams;
17
+ export type IGetVisitsLinkAdminParams = ILinkIdParams;
18
+ export type IGetVisitsLinkAdminQuery = QueryPaginate;
19
+ export type IGetCampaignStatsLinkAdminParams = ILinkIdParams;
20
+ export type ISetProtectionLinkAdminParams = ILinkIdParams;
21
+ export type IUpdateLinkAdminParams = ILinkIdParams;
22
+ export type IDeleteLinkAdminParams = ILinkIdParams;
23
+
24
+ /** Human visits of `[from, to)`, read from the raw visits: days older than the retention count nothing. */
25
+ export interface IGetCampaignStatsLinkAdminQuery {
26
+ from: Date | string;
27
+ to: Date | string;
28
+ }
29
+
30
+ export interface ISetProtectionLinkAdminBody {
31
+ isProtected: boolean;
32
+ /** The back-office administrator, recorded on the link and in abyss-main's audit. */
33
+ adminId: string;
34
+ }
35
+
36
+ /** What the back-office changes on a link: no password, which stays the owner's. */
37
+ export interface IUpdateLinkAdminBody {
38
+ targetUrl?: string;
39
+ slug?: string;
40
+ title?: string | null;
41
+ description?: string | null;
42
+ isActive?: boolean;
43
+ expiresAt?: Date | string | null;
44
+ maxClicks?: number | null;
45
+ }
46
+
47
+ /** The kinds a product creates through `sdk.link.admin.create`; SHORTENED belongs to the user. */
48
+ export type LinkProductKind = LinkKind.RESOURCE | LinkKind.CAMPAIGN_TOKEN;
49
+
50
+ /**
51
+ * The container of a product's link (spec §4): kept for the deletion fan-out and the access, never
52
+ * a billing scope (a product's link is free on Link's lines).
53
+ */
54
+ export interface ILinkContainerScope {
55
+ userId: string | null;
56
+ organizationId: string | null;
57
+ projectId: string | null;
58
+ /** The user acting in the product, when there is one. */
59
+ createdByUserId?: string | null;
60
+ }
61
+
62
+ /**
63
+ * A RESOURCE address (`<host>/<prefix>/<code>`) or a CAMPAIGN_TOKEN for a product resource. A
64
+ * RESOURCE is one per origin: a second call returns the existing link. A campaign token is a new
65
+ * token on each call, at most `LINK_CAMPAIGN_TOKENS_PER_PROJECT` per origin (422
66
+ * `link_campaign_token_limit` beyond).
67
+ */
68
+ export interface ICreateLinkAdminBody {
69
+ kind: LinkProductKind;
70
+ origin: ILinkOrigin;
71
+ targetUrl: string;
72
+ scope: ILinkContainerScope;
73
+ /** A label the product shows, for example the channel of a campaign token. */
74
+ title?: string | null;
75
+ }
76
+
77
+ /** The product resource, flattened in the query string. */
78
+ export type IGetByOriginLinkAdminQuery = ILinkOrigin;
79
+ export type IGetStatsByOriginLinkAdminQuery = ILinkOrigin & IGetLinkStatsQuery;
80
+ export type IListCampaignTokensLinkAdminQuery = ILinkOrigin;
81
+ export type IDeleteCampaignTokenLinkAdminParams = ILinkIdParams;
82
+
83
+ /** The campaign parameters of a page view, in the SDK's camelCase. */
84
+ export interface ILinkVisitCampaign {
85
+ utmSource?: string;
86
+ utmMedium?: string;
87
+ utmCampaign?: string;
88
+ utmTerm?: string;
89
+ utmContent?: string;
90
+ }
91
+
92
+ /**
93
+ * A page view a product reports for a campaign token, after answering its visitor. Link hashes the
94
+ * visitor with the day's salt, looks the country and the city up locally and discards the IP: it is
95
+ * never stored, logged nor sent on.
96
+ */
97
+ export interface IRecordCampaignViewLinkAdminBody {
98
+ token: string;
99
+ ip: string;
100
+ userAgent?: string;
101
+ /** The full referer: only its domain is kept. */
102
+ referer?: string;
103
+ utm?: ILinkVisitCampaign;
104
+ }
@@ -0,0 +1,18 @@
1
+ export interface IUnlockLinkPublicParams {
2
+ slug: string;
3
+ }
4
+
5
+ /**
6
+ * The password of a shortened link, plus what the visit records about where the visitor came from:
7
+ * the unlock page reads them from the address the Link host sent it to (`?ref`, `?lang`, `utm_*`).
8
+ */
9
+ export interface IUnlockLinkPublicBody {
10
+ password: string;
11
+ ref?: string;
12
+ lang?: string;
13
+ utmSource?: string;
14
+ utmMedium?: string;
15
+ utmCampaign?: string;
16
+ utmTerm?: string;
17
+ utmContent?: string;
18
+ }
@@ -0,0 +1,100 @@
1
+ import { LinkShareScope } from '../../../enum/link-share.enum';
2
+ import { LinkStatsGranularity } from '../../../enum/link-stats.enum';
3
+ import { ILinkOrigin } from '../../models/link.dto';
4
+ import { QueryPaginate } from '../type-message/base-paginate';
5
+
6
+ export interface ILinkIdParams {
7
+ linkId: string;
8
+ }
9
+
10
+ export type IGetLinkParams = ILinkIdParams;
11
+ export type IUpdateLinkParams = ILinkIdParams;
12
+ export type IDeleteLinkParams = ILinkIdParams;
13
+ export type ITransferLinkParams = ILinkIdParams;
14
+ export type IGetLinkStatsParams = ILinkIdParams;
15
+ export type IGetLinkVisitsParams = ILinkIdParams;
16
+
17
+ /** Filters of the SHORTENED lists: `search` matches the title, the slug and the target URL. */
18
+ export interface IPaginateLinkQuery extends QueryPaginate {
19
+ search?: string;
20
+ isActive?: boolean;
21
+ }
22
+
23
+ export interface IPaginateProjectLinkParams {
24
+ projectId: string;
25
+ }
26
+
27
+ export interface IPaginateOrganizationLinkParams {
28
+ organizationId: string;
29
+ }
30
+
31
+ export interface IPaginateOrganizationLinkQuery extends IPaginateLinkQuery {
32
+ scope?: LinkShareScope;
33
+ teamId?: string;
34
+ projectId?: string;
35
+ /** Honoured only for a member holding ORG_FULL_ACCESS. */
36
+ adminView?: boolean;
37
+ }
38
+
39
+ export interface ICountOrganizationLinkParams {
40
+ organizationId: string;
41
+ }
42
+
43
+ export interface ICountOrganizationLinkQuery {
44
+ adminView?: boolean;
45
+ }
46
+
47
+ /** A SHORTENED link. Without `slug`, a random one is drawn. */
48
+ export interface ICreateLinkBody {
49
+ targetUrl: string;
50
+ slug?: string;
51
+ password?: string;
52
+ title?: string;
53
+ description?: string;
54
+ expiresAt?: Date | string;
55
+ maxClicks?: number;
56
+ forwardCampaignParams?: boolean;
57
+ }
58
+
59
+ export interface ICreateForOrganizationLinkParams {
60
+ organizationId: string;
61
+ }
62
+
63
+ /** `projectId` puts the link in a project; `scope: 'USER'` makes it the caller's within the organization. */
64
+ export interface ICreateForOrganizationLinkBody extends ICreateLinkBody {
65
+ projectId?: string;
66
+ scope?: 'USER';
67
+ }
68
+
69
+ /** `password: null` removes the password; `expiresAt: null` and `maxClicks: null` lift the limit. */
70
+ export interface IUpdateLinkBody {
71
+ targetUrl?: string;
72
+ slug?: string;
73
+ password?: string | null;
74
+ title?: string | null;
75
+ description?: string | null;
76
+ isActive?: boolean;
77
+ expiresAt?: Date | string | null;
78
+ maxClicks?: number | null;
79
+ forwardCampaignParams?: boolean;
80
+ }
81
+
82
+ export interface ITransferLinkBody {
83
+ newOwnerId: string;
84
+ }
85
+
86
+ /** Period `[from, to)`, 30 days up to now by default. */
87
+ export interface IGetLinkStatsQuery {
88
+ from?: Date | string;
89
+ to?: Date | string;
90
+ granularity?: LinkStatsGranularity;
91
+ }
92
+
93
+ export type IGetLinkVisitsQuery = QueryPaginate;
94
+
95
+ /**
96
+ * The product resource of a RESOURCE address, flattened in the query string: the product page
97
+ * finds its address and its statistics, from EDIT on the resource (spec §5).
98
+ */
99
+ export type IGetByOriginLinkQuery = ILinkOrigin;
100
+ export type IGetStatsByOriginLinkQuery = ILinkOrigin & IGetLinkStatsQuery;
@@ -0,0 +1,17 @@
1
+ import { IUser, IOrganization, IProject } from '../..';
2
+ import { IResponse } from '../type-message/response';
3
+
4
+ export interface IActivateUserServiceAbyssAdminData {
5
+ user: IUser;
6
+ }
7
+ export type IActivateUserServiceAbyssAdminResponse = IResponse<IActivateUserServiceAbyssAdminData>;
8
+
9
+ export interface ISyncOrganizationAbyssAdminData {
10
+ organization: IOrganization;
11
+ }
12
+ export type ISyncOrganizationAbyssAdminResponse = IResponse<ISyncOrganizationAbyssAdminData>;
13
+
14
+ export interface ISyncProjectAbyssAdminData {
15
+ project: IProject;
16
+ }
17
+ export type ISyncProjectAbyssAdminResponse = IResponse<ISyncProjectAbyssAdminData>;
@@ -0,0 +1,4 @@
1
+ export * from './abyss.admin.response';
2
+ export * from './link.response';
3
+ export * from './link.admin.response';
4
+ export * from './link.public.response';
@@ -0,0 +1,56 @@
1
+ import { ILink, ILinkStats, ILinkVisit } from '../../models/link.dto';
2
+ import { ILinkCampaignStatsRow } from '../../models/link-list.dto';
3
+ import { BasePaginate } from '../type-message/base-paginate';
4
+ import { IResponse } from '../type-message/response';
5
+
6
+ export type IPaginateLinkAdminData = BasePaginate<ILink>;
7
+ export type IPaginateLinkAdminResponse = IResponse<IPaginateLinkAdminData>;
8
+
9
+ export interface IGetLinkAdminData {
10
+ link: ILink;
11
+ }
12
+ export type IGetLinkAdminResponse = IResponse<IGetLinkAdminData>;
13
+
14
+ export type IGetVisitsLinkAdminData = BasePaginate<ILinkVisit>;
15
+ export type IGetVisitsLinkAdminResponse = IResponse<IGetVisitsLinkAdminData>;
16
+
17
+ export interface IGetCampaignStatsLinkAdminData {
18
+ rows: ILinkCampaignStatsRow[];
19
+ }
20
+ export type IGetCampaignStatsLinkAdminResponse = IResponse<IGetCampaignStatsLinkAdminData>;
21
+
22
+ export interface ISetProtectionLinkAdminData {
23
+ link: ILink;
24
+ }
25
+ export type ISetProtectionLinkAdminResponse = IResponse<ISetProtectionLinkAdminData>;
26
+
27
+ export interface IUpdateLinkAdminData {
28
+ link: ILink;
29
+ }
30
+ export type IUpdateLinkAdminResponse = IResponse<IUpdateLinkAdminData>;
31
+
32
+ export type IDeleteLinkAdminResponse = IResponse<Record<string, never>>;
33
+
34
+ export interface ICreateLinkAdminData {
35
+ link: ILink;
36
+ }
37
+ export type ICreateLinkAdminResponse = IResponse<ICreateLinkAdminData>;
38
+
39
+ export interface IGetByOriginLinkAdminData {
40
+ link: ILink;
41
+ }
42
+ export type IGetByOriginLinkAdminResponse = IResponse<IGetByOriginLinkAdminData>;
43
+
44
+ export interface IGetStatsByOriginLinkAdminData {
45
+ stats: ILinkStats;
46
+ }
47
+ export type IGetStatsByOriginLinkAdminResponse = IResponse<IGetStatsByOriginLinkAdminData>;
48
+
49
+ export type IRecordCampaignViewLinkAdminResponse = IResponse<Record<string, never>>;
50
+
51
+ export interface IListCampaignTokensLinkAdminData {
52
+ links: ILink[];
53
+ }
54
+ export type IListCampaignTokensLinkAdminResponse = IResponse<IListCampaignTokensLinkAdminData>;
55
+
56
+ export type IDeleteCampaignTokenLinkAdminResponse = IResponse<Record<string, never>>;
@@ -0,0 +1,7 @@
1
+ import { IResponse } from '../type-message/response';
2
+
3
+ export interface IUnlockLinkPublicData {
4
+ /** The destination, with the campaign parameters forwarded when the link asks for it. */
5
+ url: string;
6
+ }
7
+ export type IUnlockLinkPublicResponse = IResponse<IUnlockLinkPublicData>;
@@ -0,0 +1,55 @@
1
+ import { ILink, ILinkStats, ILinkVisit } from '../../models/link.dto';
2
+ import { ILinkListItem } from '../../models/link-list.dto';
3
+ import { BasePaginate } from '../type-message/base-paginate';
4
+ import { IResponse } from '../type-message/response';
5
+
6
+ export interface IGetLinkData {
7
+ link: ILink;
8
+ }
9
+ export type IGetLinkResponse = IResponse<IGetLinkData>;
10
+
11
+ export type IPaginateLinkData = BasePaginate<ILinkListItem>;
12
+ export type IPaginateLinkResponse = IResponse<IPaginateLinkData>;
13
+
14
+ /** `orphan` and `unshared` are given to an organization administrator in `adminView` only. */
15
+ export interface ICountOrganizationLinkData {
16
+ total: number;
17
+ orphan?: number;
18
+ unshared?: number;
19
+ }
20
+ export type ICountOrganizationLinkResponse = IResponse<ICountOrganizationLinkData>;
21
+
22
+ export interface ICreateLinkData {
23
+ link: ILink;
24
+ }
25
+ export type ICreateLinkResponse = IResponse<ICreateLinkData>;
26
+
27
+ export interface IUpdateLinkData {
28
+ link: ILink;
29
+ }
30
+ export type IUpdateLinkResponse = IResponse<IUpdateLinkData>;
31
+
32
+ export type IDeleteLinkResponse = IResponse<Record<string, never>>;
33
+
34
+ export interface ITransferLinkData {
35
+ link: ILink;
36
+ }
37
+ export type ITransferLinkResponse = IResponse<ITransferLinkData>;
38
+
39
+ export interface IGetLinkStatsData {
40
+ stats: ILinkStats;
41
+ }
42
+ export type IGetLinkStatsResponse = IResponse<IGetLinkStatsData>;
43
+
44
+ export type IGetLinkVisitsData = BasePaginate<ILinkVisit>;
45
+ export type IGetLinkVisitsResponse = IResponse<IGetLinkVisitsData>;
46
+
47
+ export interface IGetByOriginLinkData {
48
+ link: ILink;
49
+ }
50
+ export type IGetByOriginLinkResponse = IResponse<IGetByOriginLinkData>;
51
+
52
+ export interface IGetStatsByOriginLinkData {
53
+ stats: ILinkStats;
54
+ }
55
+ export type IGetStatsByOriginLinkResponse = IResponse<IGetStatsByOriginLinkData>;
@@ -0,0 +1,7 @@
1
+ import { Code, ErrorType } from '../../../enum';
2
+
3
+ export interface IApiError {
4
+ code: Code;
5
+ type: ErrorType;
6
+ message?: string;
7
+ }
@@ -0,0 +1,11 @@
1
+ export interface BasePaginate<T> {
2
+ maxPages: number;
3
+ currentPage: number;
4
+ data: T[];
5
+ totalItems: number;
6
+ }
7
+
8
+ export interface QueryPaginate {
9
+ page?: number;
10
+ limit?: number;
11
+ }
@@ -0,0 +1,6 @@
1
+ import { IApiError } from './api-error';
2
+
3
+ export interface IResponse<T> {
4
+ data: T;
5
+ error?: IApiError | Error;
6
+ }
@@ -0,0 +1,2 @@
1
+ export * from './models';
2
+ export * from './api';
@@ -0,0 +1,5 @@
1
+ export * from './user.dto';
2
+ export * from './organization.dto';
3
+ export * from './project.dto';
4
+ export * from './link.dto';
5
+ export * from './link-list.dto';
@@ -0,0 +1,28 @@
1
+ import { LinkSharePermission } from '../../enum/link-share.enum';
2
+ import { ILink } from './link.dto';
3
+
4
+ /** A content share of a link, as abyss-main holds it (the fields the Links screen shows). */
5
+ export interface ILinkContentShare {
6
+ id: string;
7
+ /** `USER`, `TEAM`, `ORGANIZATION`, `PROJECT` or `PUBLIC` on abyss-main's side. */
8
+ targetType: string;
9
+ targetId: string | null;
10
+ permission: LinkSharePermission;
11
+ expiresAt: string | null;
12
+ createdByUserId: string | null;
13
+ }
14
+
15
+ /** A link of a list, with the caller's permission on it and its shares. */
16
+ export interface ILinkListItem extends ILink {
17
+ permission: LinkSharePermission;
18
+ shares: ILinkContentShare[];
19
+ }
20
+
21
+ /** One row of the campaign statistics of a link: human visits grouped by campaign and medium. */
22
+ export interface ILinkCampaignStatsRow {
23
+ utmCampaign: string | null;
24
+ utmMedium: string | null;
25
+ visits: number;
26
+ /** Sum over the days of the distinct visitors of each day (the visitor hash lives one day). */
27
+ uniqueVisitors: number;
28
+ }
@@ -0,0 +1,117 @@
1
+ import { LinkKind, LinkResourceProduct, LinkVisitSource } from '../../enum/link.enum';
2
+ import { IOrganization } from './organization.dto';
3
+ import { IProject } from './project.dto';
4
+ import { IUser } from './user.dto';
5
+
6
+ /** The product resource a RESOURCE or CAMPAIGN_TOKEN link belongs to (spec §4). */
7
+ export interface ILinkOrigin {
8
+ service: LinkResourceProduct;
9
+ /** Product-defined type, for example `beam_transfer`. */
10
+ resourceType: string;
11
+ resourceId: string;
12
+ }
13
+
14
+ /** A row of `links` (spec §7). Which address columns are set depends on `kind`. */
15
+ export interface ILink {
16
+ id: string;
17
+ kind: LinkKind;
18
+ /** SHORTENED only, case kept as typed. */
19
+ slug: string | null;
20
+ /** SHORTENED only: `lower(slug)`, unique, the resolution key. */
21
+ slugKey: string | null;
22
+ /** RESOURCE only: a value of `LINK_RESOURCE_PREFIXES`. */
23
+ prefix: string | null;
24
+ /** RESOURCE only: base62, `LINK_RESOURCE_CODE_LENGTH` characters. */
25
+ code: string | null;
26
+ /** CAMPAIGN_TOKEN only: base62, `LINK_CAMPAIGN_TOKEN_LENGTH` characters. */
27
+ token: string | null;
28
+ targetUrl: string;
29
+ title: string | null;
30
+ description: string | null;
31
+ userId: string | null;
32
+ projectId: string | null;
33
+ organizationId: string | null;
34
+ createdByUserId: string | null;
35
+ /** Null for SHORTENED, set for RESOURCE and CAMPAIGN_TOKEN. */
36
+ originService: LinkResourceProduct | null;
37
+ originResourceType: string | null;
38
+ originResourceId: string | null;
39
+ isActive: boolean;
40
+ expiresAt: Date | null;
41
+ maxClicks: number | null;
42
+ /** SHORTENED only (scrypt, ADR-0238). */
43
+ passwordHash: string | null;
44
+ forwardCampaignParams: boolean;
45
+ isProtected: boolean;
46
+ protectedAt: Date | null;
47
+ protectedByAdminId: string | null;
48
+ /** Display values refreshed by the daily rollup; never read to decide a resolution. */
49
+ clickCount: number;
50
+ uniqueClickCount: number;
51
+ lastVisitedAt: Date | null;
52
+ createdAt?: Date;
53
+ updatedAt?: Date;
54
+
55
+ user?: IUser | null;
56
+ project?: IProject | null;
57
+ organization?: IOrganization | null;
58
+ }
59
+
60
+ /** A row of `link_visits` (spec §7). No IP, no full referer, no raw user agent. */
61
+ export interface ILinkVisit {
62
+ id: string;
63
+ linkId: string;
64
+ visitedAt: Date;
65
+ source: LinkVisitSource;
66
+ /** `hashVisitor` of the visit's UTC day: comparable within one day only. */
67
+ visitorHash: string;
68
+ isBot: boolean;
69
+ isFirstOfDay: boolean;
70
+ country: string | null;
71
+ city: string | null;
72
+ device: string | null;
73
+ browser: string | null;
74
+ os: string | null;
75
+ language: string | null;
76
+ refererDomain: string | null;
77
+ utmSource: string | null;
78
+ utmMedium: string | null;
79
+ utmCampaign: string | null;
80
+ utmTerm: string | null;
81
+ utmContent: string | null;
82
+ }
83
+
84
+ /** Visit counts by value, human visits only (spec §3.4). */
85
+ export interface ILinkBreakdowns {
86
+ countries: Record<string, number>;
87
+ cities: Record<string, number>;
88
+ devices: Record<string, number>;
89
+ browsers: Record<string, number>;
90
+ oses: Record<string, number>;
91
+ languages: Record<string, number>;
92
+ refererDomains: Record<string, number>;
93
+ utmSources: Record<string, number>;
94
+ utmMediums: Record<string, number>;
95
+ utmCampaigns: Record<string, number>;
96
+ }
97
+
98
+ /** A row of `link_daily_stats`: one per link and UTC day (spec §3.4). */
99
+ export interface ILinkDailyStats extends ILinkBreakdowns {
100
+ linkId: string;
101
+ /** UTC day, `YYYY-MM-DD`. */
102
+ day: string;
103
+ /** Human visits. */
104
+ visits: number;
105
+ /** Distinct visitor hashes of the day. */
106
+ uniqueVisitors: number;
107
+ botVisits: number;
108
+ }
109
+
110
+ /** Statistics of a link over a period. `uniqueVisitors` is the sum of the daily distinct visitors. */
111
+ export interface ILinkStats extends ILinkBreakdowns {
112
+ visits: number;
113
+ uniqueVisitors: number;
114
+ botVisits: number;
115
+ lastVisitedAt: Date | null;
116
+ daily: ILinkDailyStats[];
117
+ }
@@ -0,0 +1,21 @@
1
+ import { IProject } from './project.dto';
2
+
3
+ export interface IOrganization {
4
+ id?: string;
5
+ name: string;
6
+ slug: string;
7
+ // Mirror of abyss-main Organization.kind. Drives the family default-share
8
+ // permission (family → EDIT, else VIEW). Synced by organization.middleware.ts.
9
+ // Typed as a literal union that mirrors @abyss-project/main's OrganizationKind
10
+ // enum values 1:1 — this published SDK package intentionally does NOT depend on
11
+ // @abyss-project/main, so the enum is referenced by value (the api-side model
12
+ // and middleware narrow this to OrganizationKind, where main IS resolvable).
13
+ kind?: 'standard' | 'family';
14
+ // Last refresh of `kind` from abyss-main; drives the TTL (≤5min) sync gate.
15
+ kindSyncedAt?: string | null;
16
+ updatedAt?: Date;
17
+ createdAt?: Date;
18
+
19
+ // Associations
20
+ projects?: IProject[];
21
+ }
@@ -0,0 +1,16 @@
1
+ import { IOrganization } from './organization.dto';
2
+ import { IUser } from './user.dto';
3
+
4
+ export interface IProject {
5
+ id?: string;
6
+ name: string;
7
+ // Historical creator of the project, null once their account is deleted. NOT used for access control.
8
+ createdByUserId: string | null;
9
+ organizationId: string;
10
+ updatedAt?: Date;
11
+ createdAt?: Date;
12
+
13
+ // Associations
14
+ organization?: IOrganization;
15
+ user?: IUser;
16
+ }
@@ -0,0 +1,19 @@
1
+ import { IProject } from './project.dto';
2
+
3
+ export interface IUser {
4
+ id?: string;
5
+ isAdmin: boolean;
6
+ // Personal API key mirror from abyss-main (ADR-0037). The lookup hash is the
7
+ // non-reversible sha256 fingerprint used for local validation; revokedAt marks
8
+ // a mirrored key that must no longer authenticate.
9
+ personalApiKeyLookupHash?: string | null;
10
+ personalApiKeyRevokedAt?: Date | null;
11
+ // Set when the account was deleted in abyss-main (USER_DELETED, #199): the row stays, marked,
12
+ // and a session token signed before the deletion no longer authenticates.
13
+ accountDeletedAt?: Date | null;
14
+ updatedAt?: Date;
15
+ createdAt?: Date;
16
+
17
+ // Associations
18
+ projects?: IProject[];
19
+ }
@@ -0,0 +1,48 @@
1
+ import {
2
+ CAMPAIGN_TOKEN_QUERY_PARAM,
3
+ LINK_CAMPAIGN_TOKEN_LENGTH,
4
+ LINK_CAMPAIGN_TOKENS_PER_PROJECT,
5
+ LINK_RESOURCE_CODE_LENGTH,
6
+ LINK_VISIT_RETENTION_DAYS,
7
+ LinkKind,
8
+ LinkResourceProduct,
9
+ LinkVisitSource,
10
+ MAX_LINK_PASSWORD_LENGTH,
11
+ MIN_LINK_PASSWORD_LENGTH,
12
+ } from '../..';
13
+
14
+ describe('link enums: stored values', () => {
15
+ it('LinkKind has exactly the three kinds of spec §2', () => {
16
+ expect(Object.values(LinkKind)).toEqual(['SHORTENED', 'RESOURCE', 'CAMPAIGN_TOKEN']);
17
+ });
18
+
19
+ it('LinkVisitSource has exactly REDIRECT and CAMPAIGN_VIEW', () => {
20
+ expect(Object.values(LinkVisitSource)).toEqual(['REDIRECT', 'CAMPAIGN_VIEW']);
21
+ });
22
+
23
+ it('LinkResourceProduct has exactly the products of spec §3.5 and Spotlight', () => {
24
+ expect(Object.values(LinkResourceProduct)).toEqual([
25
+ 'BEAM',
26
+ 'SPOTLIGHT',
27
+ 'ATLAS',
28
+ 'DRAW',
29
+ 'RETROSPECTIVE',
30
+ 'FORM',
31
+ 'EXTRACT',
32
+ 'CLOUD',
33
+ 'MEMORIES',
34
+ ]);
35
+ });
36
+ });
37
+
38
+ describe('link limits', () => {
39
+ it('carries the values of the spec', () => {
40
+ expect(MIN_LINK_PASSWORD_LENGTH).toBe(4);
41
+ expect(MAX_LINK_PASSWORD_LENGTH).toBe(128);
42
+ expect(LINK_RESOURCE_CODE_LENGTH).toBe(10);
43
+ expect(LINK_CAMPAIGN_TOKEN_LENGTH).toBe(12);
44
+ expect(LINK_CAMPAIGN_TOKENS_PER_PROJECT).toBe(50);
45
+ expect(CAMPAIGN_TOKEN_QUERY_PARAM).toBe('lnk');
46
+ expect(LINK_VISIT_RETENTION_DAYS).toBe(90);
47
+ });
48
+ });
@@ -0,0 +1 @@
1
+ export type ValueOf<T> = T[keyof T];