1 import { c } from 'ttag';
3 import { MAX_BATCH_PER_REQUEST } from '@proton/pass/constants';
4 import { api } from '@proton/pass/lib/api/api';
5 import { createPageIterator } from '@proton/pass/lib/api/utils';
6 import { PassCrypto } from '@proton/pass/lib/crypto';
7 import { serializeItemContent } from '@proton/pass/lib/items/item-proto.transformer';
8 import { itemBuilder } from '@proton/pass/lib/items/item.builder';
10 AliasCreateFromPendingDTO,
16 CreatePendingAliasRequest,
18 ItemRevisionContentsResponse,
20 } from '@proton/pass/types';
21 import chunk from '@proton/utils/chunk';
23 export const getAliasOptions = async (shareId: string): Promise<AliasOptions> => {
24 const aliasOptions = await api({
25 url: `pass/v1/share/${shareId}/alias/options`,
27 }).then(({ Options }) => {
28 if (!Options) throw new Error(c('Error').t`Alias options could not be resolved`);
32 const options: AliasOptions = {
33 suffixes: aliasOptions.Suffixes.map((data) => ({
34 signedSuffix: data.SignedSuffix!,
36 isCustom: data.IsCustom!,
39 mailboxes: aliasOptions.Mailboxes.map((mailbox) => ({
48 export const getAliasDetails = async (shareId: string, itemId: string): Promise<AliasDetails> => {
49 const result = await api({
50 url: `pass/v1/share/${shareId}/alias/${itemId}`,
55 aliasEmail: result.Alias!.Email,
56 mailboxes: result.Alias!.Mailboxes?.map(({ Email, ID }): AliasMailbox => ({ id: ID, email: Email })) ?? [],
60 export const getAliasCount = async (): Promise<number> =>
61 (await api({ url: `pass/v1/user/alias/count`, method: 'get' }))?.AliasCount?.Total ?? 0;
63 export const getAliasSyncStatus = async (): Promise<SlSyncStatusOutput> => {
64 const result = (await api({ url: `pass/v1/alias_sync/status`, method: 'get' }))?.SyncStatus;
65 return result ?? { PendingAliasCount: 0, Enabled: false };
68 export const enableAliasSync = async (data: EnableSLSyncRequest) =>
70 url: `pass/v1/alias_sync/sync`,
75 export const getPendingAliases = async (): Promise<AliasPending[]> =>
77 request: async (cursor) => {
78 const result = await api({ url: `pass/v1/alias_sync/pending`, method: 'get', params: { Since: cursor } });
79 const pending = (result.PendingAliases?.Aliases ?? []).map<AliasPending>((pending) => ({
80 aliasEmail: pending.AliasEmail!,
81 pendingAliasID: pending.PendingAliasID!,
82 aliasNote: pending.AliasNote!,
85 return { data: pending, cursor: result.PendingAliases?.LastToken };
89 export const createAliasesFromPending = async ({
92 }: AliasCreateFromPendingDTO): Promise<ItemRevisionContentsResponse[]> => {
93 const encryptedItems: CreatePendingAliasRequest[] = await Promise.all(
94 pendingAliases.map(async (alias) => {
95 const { pendingAliasID: PendingAliasID, aliasEmail: name } = alias;
97 const item = itemBuilder('alias');
98 item.set('metadata', (metadata) => metadata.merge({ name }));
99 const content = serializeItemContent(item.data);
100 const aliasItem = await PassCrypto.createItem({ shareId, content });
102 return { PendingAliasID, Item: aliasItem };
106 const aliases = await Promise.all(
107 chunk(encryptedItems, MAX_BATCH_PER_REQUEST).map(
111 url: `pass/v1/alias_sync/share/${shareId}/create`,
115 ).Revisions?.RevisionsData!
119 return aliases.flat();
122 export const toggleAliasStatus = async ({ shareId, itemId, enabled }: AliasToggleStatusDTO) =>
125 url: `pass/v1/share/${shareId}/alias/${itemId}/status`,
127 data: { Enable: enabled },