{"_id":"@brandcast_app/cozi-api-client","name":"@brandcast_app/cozi-api-client","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@brandcast_app/cozi-api-client","version":"0.1.0","description":"Unofficial TypeScript/JavaScript client for Cozi Family Organizer API (reverse-engineered)","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"jest","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"keywords":["cozi","family-organizer","calendar","todo","shopping-list","api-client","typescript","javascript","reverse-engineered"],"author":{"name":"BrandCast Team"},"license":"MIT","engines":{"node":">=16.0.0"},"repository":{"type":"git","url":"git+https://github.com/BrandCast-Signage/cozi-api-client.git"},"bugs":{"url":"https://github.com/BrandCast-Signage/cozi-api-client/issues"},"homepage":"https://github.com/BrandCast-Signage/cozi-api-client#readme","dependencies":{"axios":"^1.7.0"},"devDependencies":{"@types/jest":"^29.5.0","@types/node":"^20.0.0","jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0"},"jest":{"preset":"ts-jest","testEnvironment":"node","testMatch":["**/__tests__/**/*.test.ts"],"collectCoverageFrom":["src/**/*.ts","!src/**/*.d.ts"]},"_id":"@brandcast_app/cozi-api-client@0.1.0","gitHead":"d2db34935c7cc89dd41624412e9ed23811b1785b","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-0G14aKFkMwM9lFLm3JtcJvLcaGU4UqUshqeREmXEyGkYTkQvNn16aezeiqsZsuMQsVAmmWLnC/hdW6AOAlvujw==","shasum":"344f3ab832fdfb784da7fb1a6126b170321f2841","tarball":"https://registry.npmjs.org/@brandcast_app/cozi-api-client/-/cozi-api-client-0.1.0.tgz","fileCount":9,"unpackedSize":33264,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDfCqpH1UhpE4rCXaA/f9tG9Mi3Lx0kg993cI/O3O7jXAiEA3qaqzqVWUWwT7XH937x6Guiil0BiUgUNJTnWEjaH5pg="}]},"_npmUser":{"name":"jamieeduncan","email":"jamie@brandcast.app"},"directories":{},"maintainers":[{"name":"jamieeduncan","email":"jamie@brandcast.app"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cozi-api-client_0.1.0_1759710164469_0.40058222685592915"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-06T00:22:44.392Z","0.1.0":"2025-10-06T00:22:44.692Z","modified":"2025-10-06T00:22:44.984Z"},"maintainers":[{"name":"jamieeduncan","email":"jamie@brandcast.app"}],"description":"Unofficial TypeScript/JavaScript client for Cozi Family Organizer API (reverse-engineered)","homepage":"https://github.com/BrandCast-Signage/cozi-api-client#readme","keywords":["cozi","family-organizer","calendar","todo","shopping-list","api-client","typescript","javascript","reverse-engineered"],"repository":{"type":"git","url":"git+https://github.com/BrandCast-Signage/cozi-api-client.git"},"author":{"name":"BrandCast Team"},"bugs":{"url":"https://github.com/BrandCast-Signage/cozi-api-client/issues"},"license":"MIT","readme":"# Cozi API Client\n\n[![npm version](https://badge.fury.io/js/%40brandcast_app%2Fcozi-api-client.svg)](https://badge.fury.io/js/%40brandcast_app%2Fcozi-api-client)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nUnofficial TypeScript/JavaScript client for the Cozi Family Organizer API.\n\n## ⚠️ Important Disclaimer\n\n**This is an UNOFFICIAL client library.** Cozi does not provide a public API, and this library is based on reverse engineering from the [py-cozi](https://github.com/Wetzel402/py-cozi) Python library.\n\n**Use at your own risk:**\n- The API may change without notice\n- Your account could be suspended for using unofficial clients\n- This library is provided AS-IS with no warranties\n- Not affiliated with or endorsed by Cozi\n\n## Features\n\n- 🔐 Username/password authentication\n- 📝 Full CRUD operations for lists (shopping & todo)\n- ✅ Item management (add, edit, mark, remove)\n- 📦 TypeScript support with full type definitions\n- 🛡️ Error handling and type safety\n- 🐛 Optional debug logging\n\n## Installation\n\n```bash\nnpm install @brandcast_app/cozi-api-client\n```\n\nor\n\n```bash\nyarn add @brandcast_app/cozi-api-client\n```\n\n## Quick Start\n\n```typescript\nimport { CoziApiClient } from '@brandcast_app/cozi-api-client';\n\n// Create a client instance\nconst client = new CoziApiClient({\n  debug: true, // Optional: enable debug logging\n  timeout: 30000, // Optional: request timeout in ms (default: 30000)\n  userAgent: 'my-app', // Optional: custom user agent\n});\n\n// Authenticate\nconst auth = await client.authenticate('your@email.com', 'your-password');\nconsole.log('Authenticated with account:', auth.accountId);\n\n// Get all lists\nconst lists = await client.getLists();\nconsole.log('Found lists:', lists.length);\n\n// Work with lists\nfor (const list of lists) {\n  console.log(`${list.title} (${list.listType}): ${list.items.length} items`);\n\n  for (const item of list.items) {\n    console.log(`  - [${item.status}] ${item.text}`);\n  }\n}\n```\n\n## API Reference\n\n### Authentication\n\n#### `authenticate(username: string, password: string): Promise<CoziAuthResponse>`\n\nAuthenticate with Cozi using your email and password.\n\n```typescript\nconst auth = await client.authenticate('your@email.com', 'your-password');\n// Returns: { accountId, accountPersonId, accessToken, expiresIn }\n```\n\n#### `setSessionToken(token: string, accountId?: string): void`\n\nRestore a previous session using a stored access token.\n\n```typescript\nclient.setSessionToken(storedToken, storedAccountId);\n```\n\n### Lists\n\n#### `getLists(): Promise<CoziList[]>`\n\nGet all lists for the authenticated user.\n\n```typescript\nconst lists = await client.getLists();\n```\n\n#### `getList(listId: string): Promise<CoziList>`\n\nGet a specific list by ID.\n\n```typescript\nconst list = await client.getList('list-id');\n```\n\n#### `addList(request: AddListRequest): Promise<string>`\n\nCreate a new list.\n\n```typescript\nconst listId = await client.addList({\n  title: 'Grocery Shopping',\n  type: 'shopping' // 'shopping' or 'todo'\n});\n```\n\n#### `removeList(listId: string): Promise<void>`\n\nDelete a list.\n\n```typescript\nawait client.removeList('list-id');\n```\n\n#### `reorderList(request: ReorderListRequest): Promise<void>`\n\nChange the order of a list.\n\n```typescript\nawait client.reorderList({\n  listId: 'list-id',\n  newOrder: 2\n});\n```\n\n### Items\n\n#### `addItem(request: AddItemRequest): Promise<void>`\n\nAdd an item to a list.\n\n```typescript\nawait client.addItem({\n  listId: 'shopping-list-id',\n  text: 'Milk'\n});\n```\n\n#### `editItem(request: EditItemRequest): Promise<void>`\n\nEdit an existing item.\n\n```typescript\nawait client.editItem({\n  listId: 'shopping-list-id',\n  itemId: 'item-id',\n  text: 'Whole Milk'\n});\n```\n\n#### `markItem(request: MarkItemRequest): Promise<void>`\n\nMark an item as complete or incomplete.\n\n```typescript\n// Mark as complete\nawait client.markItem({\n  listId: 'shopping-list-id',\n  itemId: 'item-id',\n  completed: true\n});\n\n// Mark as incomplete\nawait client.markItem({\n  listId: 'shopping-list-id',\n  itemId: 'item-id',\n  completed: false\n});\n```\n\n#### `removeItem(request: RemoveItemRequest): Promise<void>`\n\nRemove an item from a list.\n\n```typescript\nawait client.removeItem({\n  listId: 'shopping-list-id',\n  itemId: 'item-id'\n});\n```\n\n## Type Definitions\n\n### CoziList\n\n```typescript\ninterface CoziList {\n  listId: string;\n  title: string;\n  listType: 'shopping' | 'todo';\n  items: CoziItem[];\n  version: number;\n  notes?: string | null;\n  owner?: string | null;\n}\n```\n\n### CoziItem\n\n```typescript\ninterface CoziItem {\n  itemId: string;\n  text: string;\n  status: 'incomplete' | 'complete';\n  itemType?: string | null;\n  dueDate?: string | null;\n  notes?: string | null;\n  owner?: string | null;\n  version: number;\n}\n```\n\n### CoziAuthResponse\n\n```typescript\ninterface CoziAuthResponse {\n  accountId: string;\n  accountPersonId: string;\n  accessToken: string;\n  expiresIn: number; // seconds\n}\n```\n\n## Complete Example\n\n```typescript\nimport { CoziApiClient } from '@brandcast_app/cozi-api-client';\n\nasync function main() {\n  // Create client with debug logging\n  const client = new CoziApiClient({ debug: true });\n\n  try {\n    // Authenticate\n    const auth = await client.authenticate('your@email.com', 'your-password');\n    console.log('✓ Authenticated successfully');\n\n    // Get all lists\n    const lists = await client.getLists();\n    console.log(`✓ Found ${lists.length} lists`);\n\n    // Find shopping list\n    const shoppingList = lists.find(l => l.listType === 'shopping');\n    if (!shoppingList) {\n      throw new Error('No shopping list found');\n    }\n\n    // Add an item\n    await client.addItem({\n      listId: shoppingList.listId,\n      text: 'Organic Milk'\n    });\n    console.log('✓ Added item to shopping list');\n\n    // Get updated list\n    const updatedList = await client.getList(shoppingList.listId);\n    const newItem = updatedList.items.find(i => i.text === 'Organic Milk');\n\n    if (newItem) {\n      // Mark it as complete\n      await client.markItem({\n        listId: shoppingList.listId,\n        itemId: newItem.itemId,\n        completed: true\n      });\n      console.log('✓ Marked item as complete');\n\n      // Remove it\n      await client.removeItem({\n        listId: shoppingList.listId,\n        itemId: newItem.itemId\n      });\n      console.log('✓ Removed item from list');\n    }\n\n  } catch (error) {\n    console.error('Error:', error);\n  }\n}\n\nmain();\n```\n\n## Error Handling\n\nThe client throws errors that conform to the `CoziApiError` interface:\n\n```typescript\ninterface CoziApiError {\n  code: string;\n  message: string;\n  details?: unknown;\n}\n```\n\nExample error handling:\n\n```typescript\ntry {\n  await client.addItem({\n    listId: 'invalid-list-id',\n    text: 'Test item'\n  });\n} catch (error) {\n  const coziError = error as CoziApiError;\n  console.error('Error code:', coziError.code);\n  console.error('Error message:', coziError.message);\n  console.error('Error details:', coziError.details);\n}\n```\n\n## Session Management\n\nAccess tokens expire after a certain period (specified in `expiresIn` from the auth response). You can store the token and accountId to avoid re-authenticating:\n\n```typescript\n// Initial authentication\nconst auth = await client.authenticate('your@email.com', 'your-password');\n\n// Store token securely\nlocalStorage.setItem('cozi_token', auth.accessToken);\nlocalStorage.setItem('cozi_account_id', auth.accountId);\n\n// Later, restore session\nconst storedToken = localStorage.getItem('cozi_token');\nconst storedAccountId = localStorage.getItem('cozi_account_id');\n\nif (storedToken && storedAccountId) {\n  client.setSessionToken(storedToken, storedAccountId);\n  // Now you can make API calls without re-authenticating\n}\n```\n\n## Development\n\n### Building\n\n```bash\nnpm install\nnpm run build\n```\n\n### Testing\n\n```bash\nnpm test\n```\n\n## Credits\n\nThis library is based on the excellent reverse engineering work done in the [py-cozi](https://github.com/Wetzel402/py-cozi) Python library.\n\n## Legal\n\nThis is an unofficial library and is not affiliated with, endorsed by, or connected to Cozi. Use at your own risk. The developers of this library are not responsible for any issues that may arise from its use.\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## Support\n\n- 🐛 [Report Issues](https://github.com/BrandCast-Signage/cozi-api-client/issues)\n- 💬 [Discussions](https://github.com/BrandCast-Signage/cozi-api-client/discussions)\n\n## Changelog\n\n### 0.1.0 (Initial Release)\n\n- ✨ Initial implementation\n- 🔐 Username/password authentication\n- 📝 List management (create, read, update, delete, reorder)\n- ✅ Item management (add, edit, mark, remove)\n- 📦 Full TypeScript support\n- 🐛 Debug logging option\n","readmeFilename":"README.md","_rev":"1-d7120652ec3c7aba67dc83be1806f1f0"}