Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ class AnyList extends EventEmitter {
await this._fetchTokens();
}

// Extract user ID from JWT token
if (this.accessToken) {
try {
const payload = JSON.parse(Buffer.from(this.accessToken.split('.')[1], 'base64').toString());
this.uid = payload.sub;
} catch {
// Token parsing failed; uid will remain undefined
}
}

if (connectWebSocket) {
this._setupWebSocket();
}
Expand Down Expand Up @@ -385,6 +395,88 @@ class AnyList extends EventEmitter {
return this.recentItems[listId];
}

/**
* Create a new shopping list.
* @param {string} name name for the new list
* @return {Promise<List>} the created list
*/
async createList(name) {
const listId = uuid();

const newList = new this.protobuf.ShoppingList();
newList.setIdentifier(listId);
newList.setName(name);
newList.setItems([]);

const op = new this.protobuf.PBListOperation();
op.setMetadata({
operationId: uuid(),
handlerId: 'new-shopping-list',
userId: this.uid,
});
op.setListId(listId);
op.setList(newList);

const ops = new this.protobuf.PBListOperationList();
ops.setOperations([op]);

const form = new FormData();
form.append('operations', ops.toBuffer());

await this.client.post('data/shopping-lists/update', {body: form});

await this.getLists();
return this.getListById(listId);
}

/**
* Delete a shopping list.
* @param {List} list the list to delete
* @return {Promise<void>}
*/
async deleteList(list) {
if (!this._userData) {
await this._getUserData();
}

const foldersResponse = this._userData.listFoldersResponse;
const rootFolderId = foldersResponse.rootFolderId;

// Find which folder contains this list
let parentFolderId = rootFolderId;
for (const folder of (foldersResponse.listFolders || [])) {
for (const item of (folder.items || [])) {
if (item.identifier === list.identifier) {
parentFolderId = folder.identifier;
break;
}
}
}

const folderItem = new this.protobuf.PBListFolderItem();
folderItem.setItemType(this.protobuf.PBListFolderItem.ItemType.ListType);
folderItem.setIdentifier(list.identifier);

const op = new this.protobuf.PBListFolderOperation();
op.setMetadata({
operationId: uuid(),
handlerId: 'delete-folder-items',
userId: this.uid,
});
op.setOriginalParentFolderId(parentFolderId);
op.setFolderItems([folderItem]);

const ops = new this.protobuf.PBListFolderOperationList();
ops.setOperations([op]);

const form = new FormData();
form.append('operations', ops.toBuffer());

await this.client.post('data/list-folders/update', {body: form});

this.lists = this.lists.filter(l => l.identifier !== list.identifier);
}

/**
* Factory function to create new Items.
* @param {object} item new item options
Expand Down
29 changes: 29 additions & 0 deletions lib/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,35 @@ class List {
return item;
}

/**
* Rename this list.
* @param {string} newName the new name for the list
* @return {Promise<void>}
*/
async rename(newName) {
const op = new this.protobuf.PBListOperation();

op.setMetadata({
operationId: uuid(),
handlerId: 'rename-list',
userId: this.uid,
});

op.setListId(this.identifier);
op.setUpdatedValue(newName);

const ops = new this.protobuf.PBListOperationList();
ops.setOperations([op]);

const form = new FormData();
form.append('operations', ops.toBuffer());
await this.client.post('data/shopping-lists/update', {
body: form,
});

this.name = newName;
}

/**
* Uncheck all items in a list
* @return {Promise}
Expand Down