@abyss-project/beam 0.0.0-stage → 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.
- package/.eslintrc.js +32 -0
- package/.prettierrc +5 -0
- package/README.md +21 -2
- package/dist/api/beam.api.d.ts +49 -0
- package/dist/api/beam.api.js +110 -0
- package/dist/api/beam.api.js.map +1 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +18 -0
- package/dist/api/index.js.map +1 -0
- package/dist/constants/beam.constants.d.ts +1 -0
- package/dist/constants/beam.constants.js +5 -0
- package/dist/constants/beam.constants.js.map +1 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +18 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +149 -0
- package/dist/index.js.map +1 -0
- package/dist/types/enum/api-error.enum.d.ts +31 -0
- package/dist/types/enum/api-error.enum.js +37 -0
- package/dist/types/enum/api-error.enum.js.map +1 -0
- package/dist/types/enum/beam.enum.d.ts +22 -0
- package/dist/types/enum/beam.enum.js +30 -0
- package/dist/types/enum/beam.enum.js.map +1 -0
- package/dist/types/enum/content-share.enum.d.ts +34 -0
- package/dist/types/enum/content-share.enum.js +42 -0
- package/dist/types/enum/content-share.enum.js.map +1 -0
- package/dist/types/enum/index.d.ts +3 -0
- package/dist/types/enum/index.js +20 -0
- package/dist/types/enum/index.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +19 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/interface/api/index.d.ts +5 -0
- package/dist/types/interface/api/index.js +22 -0
- package/dist/types/interface/api/index.js.map +1 -0
- package/dist/types/interface/api/requests/beam.request.d.ts +139 -0
- package/dist/types/interface/api/requests/beam.request.js +3 -0
- package/dist/types/interface/api/requests/beam.request.js.map +1 -0
- package/dist/types/interface/api/requests/index.d.ts +1 -0
- package/dist/types/interface/api/requests/index.js +18 -0
- package/dist/types/interface/api/requests/index.js.map +1 -0
- package/dist/types/interface/api/responses/beam.response.d.ts +115 -0
- package/dist/types/interface/api/responses/beam.response.js +3 -0
- package/dist/types/interface/api/responses/beam.response.js.map +1 -0
- package/dist/types/interface/api/responses/index.d.ts +1 -0
- package/dist/types/interface/api/responses/index.js +18 -0
- package/dist/types/interface/api/responses/index.js.map +1 -0
- package/dist/types/interface/api/type-message/api-error.d.ts +6 -0
- package/dist/types/interface/api/type-message/api-error.js +3 -0
- package/dist/types/interface/api/type-message/api-error.js.map +1 -0
- package/dist/types/interface/api/type-message/base-paginate.d.ts +10 -0
- package/dist/types/interface/api/type-message/base-paginate.js +3 -0
- package/dist/types/interface/api/type-message/base-paginate.js.map +1 -0
- package/dist/types/interface/api/type-message/response.d.ts +5 -0
- package/dist/types/interface/api/type-message/response.js +3 -0
- package/dist/types/interface/api/type-message/response.js.map +1 -0
- package/dist/types/interface/index.d.ts +2 -0
- package/dist/types/interface/index.js +19 -0
- package/dist/types/interface/index.js.map +1 -0
- package/dist/types/interface/models/beam.dto.d.ts +70 -0
- package/dist/types/interface/models/beam.dto.js +3 -0
- package/dist/types/interface/models/beam.dto.js.map +1 -0
- package/dist/types/interface/models/content-share.dto.d.ts +15 -0
- package/dist/types/interface/models/content-share.dto.js +3 -0
- package/dist/types/interface/models/content-share.dto.js.map +1 -0
- package/dist/types/interface/models/index.d.ts +5 -0
- package/dist/types/interface/models/index.js +22 -0
- package/dist/types/interface/models/index.js.map +1 -0
- package/dist/types/interface/models/organization.dto.d.ts +11 -0
- package/dist/types/interface/models/organization.dto.js +3 -0
- package/dist/types/interface/models/organization.dto.js.map +1 -0
- package/dist/types/interface/models/project.dto.d.ts +12 -0
- package/dist/types/interface/models/project.dto.js +3 -0
- package/dist/types/interface/models/project.dto.js.map +1 -0
- package/dist/types/interface/models/user.dto.d.ts +11 -0
- package/dist/types/interface/models/user.dto.js +3 -0
- package/dist/types/interface/models/user.dto.js.map +1 -0
- package/dist/utils/enum.utils.d.ts +1 -0
- package/dist/utils/enum.utils.js +3 -0
- package/dist/utils/enum.utils.js.map +1 -0
- package/dist/utils/error.utils.d.ts +15 -0
- package/dist/utils/error.utils.js +25 -0
- package/dist/utils/error.utils.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +58 -4
- package/src/api/beam.api.ts +325 -0
- package/src/api/index.ts +1 -0
- package/src/api/tests/beam.api.spec.ts +106 -0
- package/src/constants/beam.constants.ts +4 -0
- package/src/constants/index.ts +1 -0
- package/src/index.ts +167 -0
- package/src/types/enum/api-error.enum.ts +33 -0
- package/src/types/enum/beam.enum.ts +48 -0
- package/src/types/enum/content-share.enum.ts +37 -0
- package/src/types/enum/index.ts +3 -0
- package/src/types/index.ts +2 -0
- package/src/types/interface/api/index.ts +5 -0
- package/src/types/interface/api/requests/beam.request.ts +180 -0
- package/src/types/interface/api/requests/index.ts +1 -0
- package/src/types/interface/api/responses/beam.response.ts +162 -0
- package/src/types/interface/api/responses/index.ts +1 -0
- package/src/types/interface/api/type-message/api-error.ts +7 -0
- package/src/types/interface/api/type-message/base-paginate.ts +11 -0
- package/src/types/interface/api/type-message/response.ts +6 -0
- package/src/types/interface/index.ts +2 -0
- package/src/types/interface/models/beam.dto.ts +86 -0
- package/src/types/interface/models/content-share.dto.ts +20 -0
- package/src/types/interface/models/index.ts +5 -0
- package/src/types/interface/models/organization.dto.ts +21 -0
- package/src/types/interface/models/project.dto.ts +16 -0
- package/src/types/interface/models/user.dto.ts +19 -0
- package/src/types/tests/beam-management-types.spec.ts +38 -0
- package/src/types/tests/beam-share-enums.spec.ts +11 -0
- package/src/types/tests/beam.dto.spec.ts +61 -0
- package/src/types/tests/beam.request-response.spec.ts +43 -0
- package/src/utils/enum.utils.ts +1 -0
- package/src/utils/error.utils.ts +30 -0
- package/src/utils/index.ts +2 -0
- package/tsconfig.check.json +15 -0
- package/tsconfig.json +36 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { AbyssBeamCore } from '..';
|
|
2
|
+
import type {
|
|
3
|
+
IGetBeamParams,
|
|
4
|
+
IGetBeamResponse,
|
|
5
|
+
IGetBeamBySlugParams,
|
|
6
|
+
IGetBeamPublicResponse,
|
|
7
|
+
IUnlockBeamPublicParams,
|
|
8
|
+
IUnlockBeamPublicBody,
|
|
9
|
+
IUnlockBeamPublicResponse,
|
|
10
|
+
IPaginateBeamQuery,
|
|
11
|
+
IPaginateBeamResponse,
|
|
12
|
+
IPaginateProjectBeamParams,
|
|
13
|
+
IPaginateOrganizationBeamParams,
|
|
14
|
+
ICreateBeamBody,
|
|
15
|
+
ICreateBeamResponse,
|
|
16
|
+
ICreateForOrganizationBeamParams,
|
|
17
|
+
IUpdateBeamParams,
|
|
18
|
+
IUpdateBeamBody,
|
|
19
|
+
IUpdateBeamResponse,
|
|
20
|
+
IDeleteBeamParams,
|
|
21
|
+
IDeleteBeamResponse,
|
|
22
|
+
ICreateBeamPublicBody,
|
|
23
|
+
IAddBeamFilesParams,
|
|
24
|
+
IAddBeamFilesBody,
|
|
25
|
+
IAddBeamFilesResponse,
|
|
26
|
+
IImportCloudBeamFilesParams,
|
|
27
|
+
IImportCloudBeamFilesBody,
|
|
28
|
+
IFinalizeBeamParams,
|
|
29
|
+
IFinalizeBeamBody,
|
|
30
|
+
IFinalizeBeamResponse,
|
|
31
|
+
IRenewBeamParams,
|
|
32
|
+
IRenewBeamResponse,
|
|
33
|
+
IReactivateBeamParams,
|
|
34
|
+
IReactivateBeamResponse,
|
|
35
|
+
ICreateBeamShareParams,
|
|
36
|
+
ICreateBeamShareBody,
|
|
37
|
+
ICreateBeamShareResponse,
|
|
38
|
+
IListBeamSharesParams,
|
|
39
|
+
IListBeamSharesResponse,
|
|
40
|
+
IRevokeBeamShareParams,
|
|
41
|
+
IRevokeBeamShareResponse,
|
|
42
|
+
IAddRecipientsBeamBody,
|
|
43
|
+
IAddRecipientsBeamResponse,
|
|
44
|
+
IListRecipientsBeamResponse,
|
|
45
|
+
IGetBeamStatsParams,
|
|
46
|
+
IGetBeamStatsQuery,
|
|
47
|
+
IGetBeamStatsResponse,
|
|
48
|
+
} from '../types';
|
|
49
|
+
import { BEAM_MANAGE_TOKEN_HEADER } from '../constants/beam.constants';
|
|
50
|
+
|
|
51
|
+
// Anonymous management requests carry the plaintext manage token as a header the
|
|
52
|
+
// API (BeamMiddleware) compares to beam_transfers.manageTokenHash. Owner requests
|
|
53
|
+
// omit it and authorize via the session JWT instead.
|
|
54
|
+
const manageTokenHeader = (manageToken?: string): { headers?: Record<string, string> } =>
|
|
55
|
+
manageToken ? { headers: { [BEAM_MANAGE_TOKEN_HEADER]: manageToken } } : {};
|
|
56
|
+
|
|
57
|
+
// renew/reactivate POST body: only carry `days` when the caller requested a
|
|
58
|
+
// specific extension window (the API clamps it to the tier cap; default 7).
|
|
59
|
+
const renewalBody = (days?: number): { days?: number } => (days !== undefined ? { days } : {});
|
|
60
|
+
|
|
61
|
+
export const beamApi = {
|
|
62
|
+
get: async (params: IGetBeamParams): Promise<IGetBeamResponse> => {
|
|
63
|
+
const response = await AbyssBeamCore.axios.get<IGetBeamResponse>(`/beam/${params.beamId}`);
|
|
64
|
+
return response.data;
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
getBySlug: async (params: IGetBeamBySlugParams): Promise<IGetBeamPublicResponse> => {
|
|
68
|
+
const response = await AbyssBeamCore.axios.get<IGetBeamPublicResponse>(`/b/${params.slug}`);
|
|
69
|
+
return response.data;
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
unlock: async (
|
|
73
|
+
params: IUnlockBeamPublicParams,
|
|
74
|
+
body: IUnlockBeamPublicBody,
|
|
75
|
+
): Promise<IUnlockBeamPublicResponse> => {
|
|
76
|
+
const response = await AbyssBeamCore.axios.post<IUnlockBeamPublicResponse>(
|
|
77
|
+
`/b/${params.slug}/unlock`,
|
|
78
|
+
body,
|
|
79
|
+
);
|
|
80
|
+
return response.data;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
paginate: async (query: IPaginateBeamQuery): Promise<IPaginateBeamResponse> => {
|
|
84
|
+
const response = await AbyssBeamCore.axios.get<IPaginateBeamResponse>('/beam/paginate', {
|
|
85
|
+
params: query,
|
|
86
|
+
});
|
|
87
|
+
return response.data;
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
paginateProject: async (
|
|
91
|
+
params: IPaginateProjectBeamParams,
|
|
92
|
+
query: IPaginateBeamQuery,
|
|
93
|
+
): Promise<IPaginateBeamResponse> => {
|
|
94
|
+
const response = await AbyssBeamCore.axios.get<IPaginateBeamResponse>(
|
|
95
|
+
`/beam/project/${params.projectId}/paginate`,
|
|
96
|
+
{ params: query },
|
|
97
|
+
);
|
|
98
|
+
return response.data;
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
paginateOrganization: async (
|
|
102
|
+
params: IPaginateOrganizationBeamParams,
|
|
103
|
+
query: IPaginateBeamQuery,
|
|
104
|
+
): Promise<IPaginateBeamResponse> => {
|
|
105
|
+
const response = await AbyssBeamCore.axios.get<IPaginateBeamResponse>(
|
|
106
|
+
`/beam/organization/${params.organizationId}/paginate`,
|
|
107
|
+
{ params: query },
|
|
108
|
+
);
|
|
109
|
+
return response.data;
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
create: async (body: ICreateBeamBody): Promise<ICreateBeamResponse> => {
|
|
113
|
+
const response = await AbyssBeamCore.axios.post<ICreateBeamResponse>('/beam', body);
|
|
114
|
+
return response.data;
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
createForOrganization: async (
|
|
118
|
+
params: ICreateForOrganizationBeamParams,
|
|
119
|
+
body: ICreateBeamBody,
|
|
120
|
+
): Promise<ICreateBeamResponse> => {
|
|
121
|
+
const response = await AbyssBeamCore.axios.post<ICreateBeamResponse>(
|
|
122
|
+
`/beam/organization/${params.organizationId}`,
|
|
123
|
+
body,
|
|
124
|
+
);
|
|
125
|
+
return response.data;
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
update: async (
|
|
129
|
+
params: IUpdateBeamParams,
|
|
130
|
+
body: IUpdateBeamBody,
|
|
131
|
+
): Promise<IUpdateBeamResponse> => {
|
|
132
|
+
const response = await AbyssBeamCore.axios.put<IUpdateBeamResponse>(
|
|
133
|
+
`/beam/${params.beamId}`,
|
|
134
|
+
body,
|
|
135
|
+
);
|
|
136
|
+
return response.data;
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
delete: async (params: IDeleteBeamParams): Promise<IDeleteBeamResponse> => {
|
|
140
|
+
const response = await AbyssBeamCore.axios.delete<IDeleteBeamResponse>(
|
|
141
|
+
`/beam/${params.beamId}`,
|
|
142
|
+
);
|
|
143
|
+
return response.data;
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
renew: async (params: IRenewBeamParams): Promise<IRenewBeamResponse> => {
|
|
147
|
+
return (
|
|
148
|
+
await AbyssBeamCore.axios.post<IRenewBeamResponse>(
|
|
149
|
+
`/beam/${params.beamId}/renew`,
|
|
150
|
+
renewalBody(params.days),
|
|
151
|
+
)
|
|
152
|
+
).data;
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
reactivate: async (params: IReactivateBeamParams): Promise<IReactivateBeamResponse> => {
|
|
156
|
+
return (
|
|
157
|
+
await AbyssBeamCore.axios.post<IReactivateBeamResponse>(
|
|
158
|
+
`/beam/${params.beamId}/reactivate`,
|
|
159
|
+
renewalBody(params.days),
|
|
160
|
+
)
|
|
161
|
+
).data;
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
// Owner download stats (MANAGE-gated): per-day series + recent events + totals.
|
|
165
|
+
stats: async (
|
|
166
|
+
params: IGetBeamStatsParams,
|
|
167
|
+
query?: IGetBeamStatsQuery,
|
|
168
|
+
): Promise<IGetBeamStatsResponse> => {
|
|
169
|
+
return (
|
|
170
|
+
await AbyssBeamCore.axios.get<IGetBeamStatsResponse>(`/beam/${params.beamId}/stats`, {
|
|
171
|
+
params: query,
|
|
172
|
+
})
|
|
173
|
+
).data;
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
share: {
|
|
177
|
+
create: async (
|
|
178
|
+
params: ICreateBeamShareParams,
|
|
179
|
+
body: ICreateBeamShareBody,
|
|
180
|
+
): Promise<ICreateBeamShareResponse> => {
|
|
181
|
+
return (
|
|
182
|
+
await AbyssBeamCore.axios.post<ICreateBeamShareResponse>(
|
|
183
|
+
`/beam/${params.beamId}/share`,
|
|
184
|
+
body,
|
|
185
|
+
)
|
|
186
|
+
).data;
|
|
187
|
+
},
|
|
188
|
+
list: async (params: IListBeamSharesParams): Promise<IListBeamSharesResponse> => {
|
|
189
|
+
return (
|
|
190
|
+
await AbyssBeamCore.axios.get<IListBeamSharesResponse>(`/beam/${params.beamId}/share`)
|
|
191
|
+
).data;
|
|
192
|
+
},
|
|
193
|
+
revoke: async (params: IRevokeBeamShareParams): Promise<IRevokeBeamShareResponse> => {
|
|
194
|
+
return (
|
|
195
|
+
await AbyssBeamCore.axios.delete<IRevokeBeamShareResponse>(
|
|
196
|
+
`/beam/${params.beamId}/share/${params.shareId}`,
|
|
197
|
+
)
|
|
198
|
+
).data;
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
recipients: {
|
|
203
|
+
add: async (
|
|
204
|
+
params: { beamId: string },
|
|
205
|
+
body: IAddRecipientsBeamBody,
|
|
206
|
+
): Promise<IAddRecipientsBeamResponse> =>
|
|
207
|
+
(
|
|
208
|
+
await AbyssBeamCore.axios.post<IAddRecipientsBeamResponse>(
|
|
209
|
+
`beam/${params.beamId}/recipients`,
|
|
210
|
+
body,
|
|
211
|
+
)
|
|
212
|
+
).data,
|
|
213
|
+
list: async (params: { beamId: string }): Promise<IListRecipientsBeamResponse> =>
|
|
214
|
+
(
|
|
215
|
+
await AbyssBeamCore.axios.get<IListRecipientsBeamResponse>(
|
|
216
|
+
`beam/${params.beamId}/recipients`,
|
|
217
|
+
)
|
|
218
|
+
).data,
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
addFiles: async (
|
|
222
|
+
params: IAddBeamFilesParams,
|
|
223
|
+
body: IAddBeamFilesBody,
|
|
224
|
+
): Promise<IAddBeamFilesResponse> => {
|
|
225
|
+
return (
|
|
226
|
+
await AbyssBeamCore.axios.post<IAddBeamFilesResponse>(`/beam/${params.beamId}/files`, body)
|
|
227
|
+
).data;
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
importCloudFiles: async (
|
|
231
|
+
params: IImportCloudBeamFilesParams,
|
|
232
|
+
body: IImportCloudBeamFilesBody,
|
|
233
|
+
): Promise<IAddBeamFilesResponse> => {
|
|
234
|
+
return (
|
|
235
|
+
await AbyssBeamCore.axios.post<IAddBeamFilesResponse>(
|
|
236
|
+
`/beam/${params.beamId}/files/import-cloud`,
|
|
237
|
+
body,
|
|
238
|
+
)
|
|
239
|
+
).data;
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
finalize: async (
|
|
243
|
+
params: IFinalizeBeamParams,
|
|
244
|
+
body?: IFinalizeBeamBody,
|
|
245
|
+
): Promise<IFinalizeBeamResponse> => {
|
|
246
|
+
return (
|
|
247
|
+
await AbyssBeamCore.axios.post<IFinalizeBeamResponse>(
|
|
248
|
+
`/beam/${params.beamId}/finalize`,
|
|
249
|
+
body ?? {},
|
|
250
|
+
)
|
|
251
|
+
).data;
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
public: {
|
|
255
|
+
create: async (body: ICreateBeamPublicBody): Promise<ICreateBeamResponse> => {
|
|
256
|
+
return (await AbyssBeamCore.axios.post<ICreateBeamResponse>(`/beam/public`, body)).data;
|
|
257
|
+
},
|
|
258
|
+
addFiles: async (
|
|
259
|
+
params: IAddBeamFilesParams,
|
|
260
|
+
body: IAddBeamFilesBody,
|
|
261
|
+
): Promise<IAddBeamFilesResponse> => {
|
|
262
|
+
return (
|
|
263
|
+
await AbyssBeamCore.axios.post<IAddBeamFilesResponse>(
|
|
264
|
+
`/beam/public/${params.beamId}/files`,
|
|
265
|
+
body,
|
|
266
|
+
)
|
|
267
|
+
).data;
|
|
268
|
+
},
|
|
269
|
+
finalize: async (
|
|
270
|
+
params: IFinalizeBeamParams,
|
|
271
|
+
body?: IFinalizeBeamBody,
|
|
272
|
+
): Promise<IFinalizeBeamResponse> => {
|
|
273
|
+
return (
|
|
274
|
+
await AbyssBeamCore.axios.post<IFinalizeBeamResponse>(
|
|
275
|
+
`/beam/public/${params.beamId}/finalize`,
|
|
276
|
+
body ?? {},
|
|
277
|
+
)
|
|
278
|
+
).data;
|
|
279
|
+
},
|
|
280
|
+
renew: async (
|
|
281
|
+
params: IRenewBeamParams & { manageToken?: string },
|
|
282
|
+
): Promise<IRenewBeamResponse> => {
|
|
283
|
+
return (
|
|
284
|
+
await AbyssBeamCore.axios.post<IRenewBeamResponse>(
|
|
285
|
+
`/beam/${params.beamId}/renew`,
|
|
286
|
+
renewalBody(params.days),
|
|
287
|
+
manageTokenHeader(params.manageToken),
|
|
288
|
+
)
|
|
289
|
+
).data;
|
|
290
|
+
},
|
|
291
|
+
reactivate: async (
|
|
292
|
+
params: IReactivateBeamParams & { manageToken?: string },
|
|
293
|
+
): Promise<IReactivateBeamResponse> => {
|
|
294
|
+
return (
|
|
295
|
+
await AbyssBeamCore.axios.post<IReactivateBeamResponse>(
|
|
296
|
+
`/beam/${params.beamId}/reactivate`,
|
|
297
|
+
renewalBody(params.days),
|
|
298
|
+
manageTokenHeader(params.manageToken),
|
|
299
|
+
)
|
|
300
|
+
).data;
|
|
301
|
+
},
|
|
302
|
+
update: async (
|
|
303
|
+
params: IUpdateBeamParams & { manageToken?: string },
|
|
304
|
+
body: IUpdateBeamBody,
|
|
305
|
+
): Promise<IUpdateBeamResponse> => {
|
|
306
|
+
return (
|
|
307
|
+
await AbyssBeamCore.axios.put<IUpdateBeamResponse>(
|
|
308
|
+
`/beam/${params.beamId}`,
|
|
309
|
+
body,
|
|
310
|
+
manageTokenHeader(params.manageToken),
|
|
311
|
+
)
|
|
312
|
+
).data;
|
|
313
|
+
},
|
|
314
|
+
delete: async (
|
|
315
|
+
params: IDeleteBeamParams & { manageToken?: string },
|
|
316
|
+
): Promise<IDeleteBeamResponse> => {
|
|
317
|
+
return (
|
|
318
|
+
await AbyssBeamCore.axios.delete<IDeleteBeamResponse>(
|
|
319
|
+
`/beam/${params.beamId}`,
|
|
320
|
+
manageTokenHeader(params.manageToken),
|
|
321
|
+
)
|
|
322
|
+
).data;
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
};
|
package/src/api/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './beam.api';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { AbyssBeamCore } from '../../index';
|
|
2
|
+
import { BeamVisibility } from '../../types';
|
|
3
|
+
|
|
4
|
+
describe('beamApi', () => {
|
|
5
|
+
it('exposes the beam CRUD namespace on the SDK facade', () => {
|
|
6
|
+
const beam = AbyssBeamCore.sdk.beam;
|
|
7
|
+
expect(typeof beam.get).toBe('function');
|
|
8
|
+
expect(typeof beam.getBySlug).toBe('function');
|
|
9
|
+
expect(typeof beam.paginate).toBe('function');
|
|
10
|
+
expect(typeof beam.paginateProject).toBe('function');
|
|
11
|
+
expect(typeof beam.paginateOrganization).toBe('function');
|
|
12
|
+
expect(typeof beam.create).toBe('function');
|
|
13
|
+
expect(typeof beam.update).toBe('function');
|
|
14
|
+
expect(typeof beam.delete).toBe('function');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('create posts to /beam and returns the wrapped transfer', async () => {
|
|
18
|
+
const post = jest
|
|
19
|
+
.spyOn(AbyssBeamCore.axios, 'post')
|
|
20
|
+
.mockResolvedValue({ data: { data: { beamTransfer: { id: 't1' } } } });
|
|
21
|
+
|
|
22
|
+
const res = await AbyssBeamCore.sdk.beam.create({
|
|
23
|
+
title: 'T',
|
|
24
|
+
visibility: BeamVisibility.PUBLIC,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect(post).toHaveBeenCalledWith('/beam', { title: 'T', visibility: BeamVisibility.PUBLIC });
|
|
28
|
+
expect(res.data.beamTransfer.id).toBe('t1');
|
|
29
|
+
post.mockRestore();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('getBySlug reads the public /b/:slug path', async () => {
|
|
33
|
+
const get = jest
|
|
34
|
+
.spyOn(AbyssBeamCore.axios, 'get')
|
|
35
|
+
.mockResolvedValue({ data: { data: { beamTransfer: { id: 't1', slug: 'abcdefghij' } } } });
|
|
36
|
+
|
|
37
|
+
await AbyssBeamCore.sdk.beam.getBySlug({ slug: 'abcdefghij' });
|
|
38
|
+
|
|
39
|
+
expect(get).toHaveBeenCalledWith('/b/abcdefghij');
|
|
40
|
+
get.mockRestore();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('renew posts an empty body by default and { days } when a window is requested', async () => {
|
|
44
|
+
const post = jest
|
|
45
|
+
.spyOn(AbyssBeamCore.axios, 'post')
|
|
46
|
+
.mockResolvedValue({ data: { data: { beamTransfer: { id: 't1' } } } });
|
|
47
|
+
|
|
48
|
+
await AbyssBeamCore.sdk.beam.renew({ beamId: 't1' });
|
|
49
|
+
expect(post).toHaveBeenCalledWith('/beam/t1/renew', {});
|
|
50
|
+
|
|
51
|
+
await AbyssBeamCore.sdk.beam.renew({ beamId: 't1', days: 30 });
|
|
52
|
+
expect(post).toHaveBeenCalledWith('/beam/t1/renew', { days: 30 });
|
|
53
|
+
post.mockRestore();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('reactivate posts an empty body by default and { days } when a window is requested', async () => {
|
|
57
|
+
const post = jest
|
|
58
|
+
.spyOn(AbyssBeamCore.axios, 'post')
|
|
59
|
+
.mockResolvedValue({ data: { data: { beamTransfer: { id: 't1' } } } });
|
|
60
|
+
|
|
61
|
+
await AbyssBeamCore.sdk.beam.reactivate({ beamId: 't1' });
|
|
62
|
+
expect(post).toHaveBeenCalledWith('/beam/t1/reactivate', {});
|
|
63
|
+
|
|
64
|
+
await AbyssBeamCore.sdk.beam.reactivate({ beamId: 't1', days: 14 });
|
|
65
|
+
expect(post).toHaveBeenCalledWith('/beam/t1/reactivate', { days: 14 });
|
|
66
|
+
post.mockRestore();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('public.renew carries the manage token header AND the optional days body', async () => {
|
|
70
|
+
const post = jest
|
|
71
|
+
.spyOn(AbyssBeamCore.axios, 'post')
|
|
72
|
+
.mockResolvedValue({ data: { data: { beamTransfer: { id: 't1' } } } });
|
|
73
|
+
|
|
74
|
+
await AbyssBeamCore.sdk.beam.public.renew({ beamId: 't1', manageToken: 'tok', days: 7 });
|
|
75
|
+
|
|
76
|
+
expect(post).toHaveBeenCalledWith(
|
|
77
|
+
'/beam/t1/renew',
|
|
78
|
+
{ days: 7 },
|
|
79
|
+
{ headers: { 'x-beam-manage-token': 'tok' } },
|
|
80
|
+
);
|
|
81
|
+
post.mockRestore();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('stats reads /beam/:beamId/stats with the window/pagination query', async () => {
|
|
85
|
+
const get = jest.spyOn(AbyssBeamCore.axios, 'get').mockResolvedValue({
|
|
86
|
+
data: {
|
|
87
|
+
data: {
|
|
88
|
+
byDay: [{ day: '2026-07-09', count: 2, zipCount: 1 }],
|
|
89
|
+
recent: [],
|
|
90
|
+
totals: { downloadCount: 2, lastDownloadedAt: null },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const res = await AbyssBeamCore.sdk.beam.stats(
|
|
96
|
+
{ beamId: 't1' },
|
|
97
|
+
{ days: 7, limit: 10, offset: 0 },
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(get).toHaveBeenCalledWith('/beam/t1/stats', {
|
|
101
|
+
params: { days: 7, limit: 10, offset: 0 },
|
|
102
|
+
});
|
|
103
|
+
expect(res.data.byDay[0].zipCount).toBe(1);
|
|
104
|
+
get.mockRestore();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Header carrying the anonymous transfer management secret (spec §7). The front
|
|
2
|
+
// keeps the plaintext manageToken in the URL fragment and sends it here; the API
|
|
3
|
+
// (BeamMiddleware) compares sha256(header) to beam_transfers.manageTokenHash.
|
|
4
|
+
export const BEAM_MANAGE_TOKEN_HEADER = 'x-beam-manage-token';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './beam.constants';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import axiosRetry, { IAxiosRetryConfig, isNetworkOrIdempotentRequestError } from 'axios-retry';
|
|
3
|
+
|
|
4
|
+
export * from './api';
|
|
5
|
+
export * from './types';
|
|
6
|
+
export * from './utils';
|
|
7
|
+
export * from './constants';
|
|
8
|
+
|
|
9
|
+
import * as beamApiModule from './api/beam.api';
|
|
10
|
+
|
|
11
|
+
const DEFAULT_BASE_URL = 'https://beam-api.abyss-project.fr/api/';
|
|
12
|
+
|
|
13
|
+
export const API_KEY_HEADER = 'abyss-api-key';
|
|
14
|
+
export const ADMIN_TOKEN_HEADER = 'abyss-admin-token';
|
|
15
|
+
|
|
16
|
+
const NUMBER_RETRY_API = 10;
|
|
17
|
+
const BASE_DELAY_BETWEEN_RETRY = 5000;
|
|
18
|
+
const RETRY_CODES = [
|
|
19
|
+
502, // Bad Gateway
|
|
20
|
+
503, // Service Unavailable
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
type CoreConfig = {
|
|
24
|
+
token?: string;
|
|
25
|
+
apiKey?: string;
|
|
26
|
+
adminToken?: string;
|
|
27
|
+
baseURL?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type AbyssBeamCoreSDK = {
|
|
31
|
+
beam: {
|
|
32
|
+
get: typeof beamApiModule.beamApi.get;
|
|
33
|
+
getBySlug: typeof beamApiModule.beamApi.getBySlug;
|
|
34
|
+
unlock: typeof beamApiModule.beamApi.unlock;
|
|
35
|
+
paginate: typeof beamApiModule.beamApi.paginate;
|
|
36
|
+
paginateProject: typeof beamApiModule.beamApi.paginateProject;
|
|
37
|
+
paginateOrganization: typeof beamApiModule.beamApi.paginateOrganization;
|
|
38
|
+
create: typeof beamApiModule.beamApi.create;
|
|
39
|
+
createForOrganization: typeof beamApiModule.beamApi.createForOrganization;
|
|
40
|
+
update: typeof beamApiModule.beamApi.update;
|
|
41
|
+
delete: typeof beamApiModule.beamApi.delete;
|
|
42
|
+
renew: typeof beamApiModule.beamApi.renew;
|
|
43
|
+
reactivate: typeof beamApiModule.beamApi.reactivate;
|
|
44
|
+
stats: typeof beamApiModule.beamApi.stats;
|
|
45
|
+
share: {
|
|
46
|
+
create: typeof beamApiModule.beamApi.share.create;
|
|
47
|
+
list: typeof beamApiModule.beamApi.share.list;
|
|
48
|
+
revoke: typeof beamApiModule.beamApi.share.revoke;
|
|
49
|
+
};
|
|
50
|
+
recipients: {
|
|
51
|
+
add: typeof beamApiModule.beamApi.recipients.add;
|
|
52
|
+
list: typeof beamApiModule.beamApi.recipients.list;
|
|
53
|
+
};
|
|
54
|
+
addFiles: typeof beamApiModule.beamApi.addFiles;
|
|
55
|
+
importCloudFiles: typeof beamApiModule.beamApi.importCloudFiles;
|
|
56
|
+
finalize: typeof beamApiModule.beamApi.finalize;
|
|
57
|
+
public: {
|
|
58
|
+
create: typeof beamApiModule.beamApi.public.create;
|
|
59
|
+
addFiles: typeof beamApiModule.beamApi.public.addFiles;
|
|
60
|
+
finalize: typeof beamApiModule.beamApi.public.finalize;
|
|
61
|
+
renew: typeof beamApiModule.beamApi.public.renew;
|
|
62
|
+
reactivate: typeof beamApiModule.beamApi.public.reactivate;
|
|
63
|
+
update: typeof beamApiModule.beamApi.public.update;
|
|
64
|
+
delete: typeof beamApiModule.beamApi.public.delete;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export class AbyssBeamCore {
|
|
70
|
+
private static config = {
|
|
71
|
+
token: '',
|
|
72
|
+
apiKey: '',
|
|
73
|
+
adminToken: '',
|
|
74
|
+
baseURL: DEFAULT_BASE_URL,
|
|
75
|
+
};
|
|
76
|
+
static axios = axios.create({
|
|
77
|
+
baseURL: this.config.baseURL,
|
|
78
|
+
withCredentials: true,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
private static _sdk: AbyssBeamCoreSDK | null = null;
|
|
82
|
+
|
|
83
|
+
public static get sdk(): AbyssBeamCoreSDK {
|
|
84
|
+
if (!AbyssBeamCore._sdk) {
|
|
85
|
+
AbyssBeamCore._sdk = AbyssBeamCore.buildSDK();
|
|
86
|
+
}
|
|
87
|
+
return AbyssBeamCore._sdk;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private static buildSDK(): AbyssBeamCoreSDK {
|
|
91
|
+
return {
|
|
92
|
+
beam: {
|
|
93
|
+
get: beamApiModule.beamApi.get,
|
|
94
|
+
getBySlug: beamApiModule.beamApi.getBySlug,
|
|
95
|
+
unlock: beamApiModule.beamApi.unlock,
|
|
96
|
+
paginate: beamApiModule.beamApi.paginate,
|
|
97
|
+
paginateProject: beamApiModule.beamApi.paginateProject,
|
|
98
|
+
paginateOrganization: beamApiModule.beamApi.paginateOrganization,
|
|
99
|
+
create: beamApiModule.beamApi.create,
|
|
100
|
+
createForOrganization: beamApiModule.beamApi.createForOrganization,
|
|
101
|
+
update: beamApiModule.beamApi.update,
|
|
102
|
+
delete: beamApiModule.beamApi.delete,
|
|
103
|
+
renew: beamApiModule.beamApi.renew,
|
|
104
|
+
reactivate: beamApiModule.beamApi.reactivate,
|
|
105
|
+
stats: beamApiModule.beamApi.stats,
|
|
106
|
+
share: {
|
|
107
|
+
create: beamApiModule.beamApi.share.create,
|
|
108
|
+
list: beamApiModule.beamApi.share.list,
|
|
109
|
+
revoke: beamApiModule.beamApi.share.revoke,
|
|
110
|
+
},
|
|
111
|
+
recipients: {
|
|
112
|
+
add: beamApiModule.beamApi.recipients.add,
|
|
113
|
+
list: beamApiModule.beamApi.recipients.list,
|
|
114
|
+
},
|
|
115
|
+
addFiles: beamApiModule.beamApi.addFiles,
|
|
116
|
+
importCloudFiles: beamApiModule.beamApi.importCloudFiles,
|
|
117
|
+
finalize: beamApiModule.beamApi.finalize,
|
|
118
|
+
public: {
|
|
119
|
+
create: beamApiModule.beamApi.public.create,
|
|
120
|
+
addFiles: beamApiModule.beamApi.public.addFiles,
|
|
121
|
+
finalize: beamApiModule.beamApi.public.finalize,
|
|
122
|
+
renew: beamApiModule.beamApi.public.renew,
|
|
123
|
+
reactivate: beamApiModule.beamApi.public.reactivate,
|
|
124
|
+
update: beamApiModule.beamApi.public.update,
|
|
125
|
+
delete: beamApiModule.beamApi.public.delete,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public static enableAxiosRetry(axiosRetryConfig?: IAxiosRetryConfig): void {
|
|
132
|
+
axiosRetry(AbyssBeamCore.axios, {
|
|
133
|
+
retries: NUMBER_RETRY_API,
|
|
134
|
+
retryDelay: (retryCount) => retryCount * BASE_DELAY_BETWEEN_RETRY,
|
|
135
|
+
retryCondition: (error) =>
|
|
136
|
+
isNetworkOrIdempotentRequestError(error) ||
|
|
137
|
+
RETRY_CODES.includes(error.response?.status || 502),
|
|
138
|
+
...axiosRetryConfig,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public static setConfig(config: CoreConfig): void {
|
|
143
|
+
AbyssBeamCore._sdk = null;
|
|
144
|
+
|
|
145
|
+
AbyssBeamCore.config = { ...AbyssBeamCore.config, ...config };
|
|
146
|
+
|
|
147
|
+
if (config.baseURL) {
|
|
148
|
+
AbyssBeamCore.axios.defaults.baseURL = config.baseURL;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (config.token) {
|
|
152
|
+
AbyssBeamCore.axios.defaults.headers.common.Authorization = `Bearer ${config.token}`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (config.apiKey) {
|
|
156
|
+
AbyssBeamCore.axios.defaults.headers.common[API_KEY_HEADER] = `${config.apiKey}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (config.adminToken) {
|
|
160
|
+
AbyssBeamCore.axios.defaults.headers.common[ADMIN_TOKEN_HEADER] = `${config.adminToken}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public static getConfig(): CoreConfig {
|
|
165
|
+
return AbyssBeamCore.config;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export enum ErrorType {
|
|
2
|
+
apiError = 'api_error',
|
|
3
|
+
authError = 'authentication_error',
|
|
4
|
+
resourceError = 'resource_error',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export enum Code {
|
|
8
|
+
// HTTP Error
|
|
9
|
+
tokenFailure = 'token_authentication_failure',
|
|
10
|
+
authenticationFailure = 'authentication_credentials_failure',
|
|
11
|
+
accessNotAllowed = 'access_not_allowed',
|
|
12
|
+
notFound = 'not_found',
|
|
13
|
+
validationError = 'resource_validation_error',
|
|
14
|
+
constraintError = 'resource_constraint_error',
|
|
15
|
+
internalServerError = 'internal_server_error',
|
|
16
|
+
serviceUnavailable = 'service_unavailable',
|
|
17
|
+
invalidData = 'invalid_data',
|
|
18
|
+
notImplemented = 'not_implemented',
|
|
19
|
+
retrospectiveCannotBeModifiedWhenCompleted = 'retrospective_cannot_be_modified_when_completed',
|
|
20
|
+
retrospectiveActionNotAllowedInPhase = 'retrospective_action_not_allowed_in_phase',
|
|
21
|
+
retrospectiveVoteBudgetExhausted = 'retrospective_vote_budget_exhausted',
|
|
22
|
+
retrospectiveActionLimitReached = 'retrospective_action_limit_reached',
|
|
23
|
+
atlasDocumentLimitReached = 'atlas_document_limit_reached',
|
|
24
|
+
boardCardDocumentLimitReached = 'board_card_document_limit_reached',
|
|
25
|
+
boardCardMoveInvalidDestination = 'board_card_move_invalid_destination',
|
|
26
|
+
boardCardLinkLimitReached = 'board_card_link_limit_reached',
|
|
27
|
+
boardCardLinkAlreadyExists = 'board_card_link_already_exists',
|
|
28
|
+
boardCardLinkToSelf = 'board_card_link_to_self',
|
|
29
|
+
shortLinkProtected = 'short_link_protected',
|
|
30
|
+
drawImageLimitReached = 'draw_image_limit_reached',
|
|
31
|
+
drawImageOwnerRequired = 'draw_image_owner_required',
|
|
32
|
+
drawImageNotInDraw = 'draw_image_not_in_draw',
|
|
33
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// AbyssBeam transfer visibility (design D7). PUBLIC = a contentShare LINK so the
|
|
2
|
+
// /b/:slug link works for anyone until expiry; RESTRICTED = USER/ORG/TEAM/PROJECT
|
|
3
|
+
// grants resolved via contentShare.resolveAccess (>= VIEW). Password is an
|
|
4
|
+
// independent second factor, NOT a visibility level.
|
|
5
|
+
export enum BeamVisibility {
|
|
6
|
+
PUBLIC = 'PUBLIC',
|
|
7
|
+
RESTRICTED = 'RESTRICTED',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Machine-readable denial reason returned on the public serving discovery path
|
|
11
|
+
// (GET /b/:slug) so the front renders the correct state from the reason code
|
|
12
|
+
// rather than inferring it from the bare HTTP status (spec §17.1). Mirrors the
|
|
13
|
+
// backend `BeamServeDenyReason`; only the non-password discovery denials are
|
|
14
|
+
// surfaced here (PASSWORD_REQUIRED is not a VIEW denial — the metadata is still
|
|
15
|
+
// returned with isLocked=true). Byte endpoints (/file, /raw, /thumb, /zip) stay
|
|
16
|
+
// bare-status by design (CDN-visible), so this reason is a VIEW-only signal.
|
|
17
|
+
export enum BeamServeDenyReasonCode {
|
|
18
|
+
NOT_FOUND = 'not_found',
|
|
19
|
+
EXPIRED = 'expired',
|
|
20
|
+
FORBIDDEN_VISIBILITY = 'forbidden_visibility',
|
|
21
|
+
MAX_DOWNLOADS = 'max_downloads',
|
|
22
|
+
SCAN_PENDING = 'scan_pending',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Per-file AV verdict surfaced on the public listing (GET /b/:slug) so the
|
|
26
|
+
// front can render a per-file badge — clean / "en analyse" (pending) /
|
|
27
|
+
// "infecté" — independently of the whole-transfer denial reason above.
|
|
28
|
+
// Storage-neutral: AbyssBeam serves an INFECTED file's bytes (spec decision —
|
|
29
|
+
// infected files stay downloadable, not blocked; the front is expected to
|
|
30
|
+
// warn before/at download). Mirrors the storage extension's `FileScanStatus`
|
|
31
|
+
// (`@abyss-project/storage`) byte-for-byte; duplicated locally because this
|
|
32
|
+
// package does not depend on `@abyss-project/storage` (same rationale as
|
|
33
|
+
// BeamServeDenyReasonCode above).
|
|
34
|
+
export enum BeamFileScanStatus {
|
|
35
|
+
PENDING_SCAN = 'pending_scan',
|
|
36
|
+
CLEAN = 'clean',
|
|
37
|
+
INFECTED = 'infected',
|
|
38
|
+
SKIPPED = 'skipped',
|
|
39
|
+
ERROR = 'error',
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// What a beam_download_events row counted: a single-file download (/b/:slug/
|
|
43
|
+
// file/:fileId) or the whole-transfer zip (/b/:slug/zip). Inline embeds (/raw)
|
|
44
|
+
// and thumbnails (/thumb) are deliberately NOT download events (spec §17.6).
|
|
45
|
+
export enum BeamDownloadKind {
|
|
46
|
+
FILE = 'file',
|
|
47
|
+
ZIP = 'zip',
|
|
48
|
+
}
|