Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
21ef82c
First running MVP
POBrien333 Mar 10, 2026
b248418
fix: resolve scaffold build error - convert author object to string
POBrien333 Mar 14, 2026
b45fdb4
refactor: rename plugin to Citation Styler Client Sync
POBrien333 Mar 14, 2026
8d21000
fix: fix JSON syntax error in package.json author URL
POBrien333 Mar 14, 2026
872cccd
chore(publish): release v1.0.0
POBrien333 Mar 15, 2026
e968a92
Update Zotero scaffold to 0.8.4
POBrien333 Mar 15, 2026
2167ba2
chore(publish): release v1.0.1
POBrien333 Mar 15, 2026
36951b8
chore(i18n): update display name to 'Citation Styler' brand
POBrien333 Mar 16, 2026
d4ae64c
Change prefs to be on brand
POBrien333 Mar 16, 2026
fbe09a1
add screenshot and link to releases
POBrien333 Mar 18, 2026
5024688
fix: improve 'no styles' error message to direct to support
POBrien333 Mar 19, 2026
f16a886
feat: dark mode support, prefs heading with version display, scaffold…
POBrien333 Mar 25, 2026
1497a60
Change
POBrien333 Mar 25, 2026
657953e
feat: add customer log export and bump to v1.0.2
POBrien333 Mar 25, 2026
ec57bc8
chore(publish): release v1.0.2
POBrien333 Mar 25, 2026
5a2fa65
fix: switch API to production, fix CI lint and artifact action
POBrien333 Mar 30, 2026
9863e54
docs: add v1.0.3 changelog and release process note
POBrien333 Mar 30, 2026
59e5759
chore(publish): release v1.0.3
POBrien333 Mar 30, 2026
6f5eba9
fix: display server reason on 429, add v1.0.4 changelog
POBrien333 Mar 30, 2026
998d82a
chore(publish): release v1.0.4
POBrien333 Mar 30, 2026
a1468f0
fix: prettier format license.ts, upgrade upload-artifact to v7
POBrien333 Mar 30, 2026
8b4e30c
feat: add support for Zotero 9
POBrien333 Apr 11, 2026
af7c881
chore(publish): release v1.0.5
POBrien333 Apr 11, 2026
8166392
chore(publish): release v1.0.5
POBrien333 Apr 11, 2026
6585930
chore(publish): release v1.0.6
POBrien333 Apr 28, 2026
303e29c
fix: install button stays on Install after style is installed
POBrien333 May 22, 2026
e6e340a
chore: support Zotero 10 (bump strict_max_version to 10.*)
POBrien333 May 22, 2026
4d60143
chore: fix Prettier formatting in customStyles.ts
POBrien333 May 22, 2026
09a1ca2
Merge pull request #1 from POBrien333/fix/install-button-state-not-up…
POBrien333 May 22, 2026
8140eaa
Merge pull request #6 from POBrien333/chore/zotero-10-max-version
POBrien333 May 22, 2026
d17a3dc
chore(publish): release v1.0.7
POBrien333 May 22, 2026
81269b8
fix(security): upgrade zotero-plugin-toolkit to 6.0.0
POBrien333 Nov 6, 2026
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
15 changes: 15 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"permissions": {
"allow": [
"Bash(npm run:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git push:*)",
"WebSearch",
"WebFetch(domain:raw.githubusercontent.com)",
"WebFetch(domain:github.com)",
"Bash(npx tsc:*)",
"Bash(curl -sL \"https://github.com/POBrien333/citationstyler-client-sync/releases/download/release/update-beta.json\")"
]
}
}
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- name: Run Build
run: npm run build
- name: Upload build result
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: build-result
path: .scaffold/build
Expand Down
277 changes: 277 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
# Citation Styler Client Sync β€” Zotero Plugin

## Project Overview

This is a Zotero plugin that enables users to install and manage custom citation styles directly within Zotero. The plugin authenticates users via license keys, validates their credentials, and provides an interface for installing and updating purchased custom styles.

**Repository:** https://github.com/POBrien333/citationstyler-client-sync
**Plugin ID:** `citationstyler-sync@citationstyler.com`
**License:** AGPL-3.0-or-later
**Version:** 1.0.0 (MVP)

## Release Process Notes

- When the user asks to "release" or "prepare a release", always:
1. Add a new version entry to the **Changelog** section in `README.md`
2. Bump the version in `package.json`
3. Run `npm run release`

## Key Features

- **License Validation**: Users enter email and license key; the plugin validates against a backend service
- **Custom Styles Installation**: Browse and install purchased citation styles directly in Zotero
- **Update Management**: Check for and install style updates
- **Zotero Integration**: Fully integrated preferences pane in Zotero settings
- **Multi-device Support**: Activation limits enforced per license
- **Graceful Degradation**: Cache-based validation allows offline usage

## Technology Stack

- **Language**: TypeScript
- **Framework**: [Zotero Plugin Toolkit](https://github.com/windingwind/zotero-plugin-toolkit) v5.1.0-beta.13
- **Build Tool**: [zotero-plugin-scaffold](https://www.npmjs.com/package/zotero-plugin-scaffold)
- **Testing**: Mocha + Chai
- **Code Quality**: ESLint + Prettier
- **Target**: Zotero 7+ (supports Firefox 115+)
- **Package Manager**: npm (Node.js 18+)

## Project Structure

```
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ addon.ts # Main addon class & data management
β”‚ β”œβ”€β”€ index.ts # Plugin initialization entry point
β”‚ β”œβ”€β”€ hooks.ts # Lifecycle hooks (startup, shutdown, prefs events)
β”‚ β”œβ”€β”€ modules/
β”‚ β”‚ β”œβ”€β”€ license.ts # License validation & credential management
β”‚ β”‚ └── customStyles.ts # Style installation & update logic
β”‚ └── utils/
β”‚ β”œβ”€β”€ ztoolkit.ts # Zotero toolkit wrapper
β”‚ β”œβ”€β”€ locale.ts # i18n localization strings
β”‚ β”œβ”€β”€ prefs.ts # Preferences utilities
β”‚ └── window.ts # Window management utilities
β”‚
β”œβ”€β”€ addon/
β”‚ β”œβ”€β”€ manifest.json # Plugin manifest (templated)
β”‚ β”œβ”€β”€ content/
β”‚ β”‚ β”œβ”€β”€ preferences.xhtml # Preferences pane UI
β”‚ β”‚ β”œβ”€β”€ icons/ # Plugin icons
β”‚ β”‚ └── styles/ # UI stylesheets
β”‚ └── locale/ # i18n translation files
β”‚
β”œβ”€β”€ test/
β”‚ └── startup.test.ts # Mocha test suite
β”‚
β”œβ”€β”€ zotero-plugin.config.ts # Build configuration
β”œβ”€β”€ package.json # Dependencies & config
β”œβ”€β”€ tsconfig.json # TypeScript configuration
└── eslint.config.mjs # ESLint configuration
```

## Core Modules

### License Module (`src/modules/license.ts`)

Handles license validation, credential storage, and Zotero account integration.

**Key Functions:**

- `validate(credentials, forceRefresh)` β€” Validate email + license key against backend
- `saveCredentials(email, licenseKey)` β€” Store encrypted credentials in Zotero prefs
- `loadCredentials()` β€” Retrieve stored credentials
- `clearCredentials()` β€” Remove stored credentials
- `getZoteroUserId()` β€” Get logged-in Zotero account ID
- `isCacheExpiringSoon()` β€” Check if validation cache is expiring

**Features:**

- Cache-based validation for offline support
- Grace period handling
- Device activation limit enforcement

### Custom Styles Module (`src/modules/customStyles.ts`)

Manages style installation, rendering, and updates.

**Key Functions:**

- `renderStylesInPrefs(doc, container, statusDiv, validationResult, licenseKey)` β€” Display available styles in preferences
- `checkAndInstallUpdates(doc, container, statusDiv, licenseKey)` β€” Fetch and install style updates
- `installStyle(styleName, styleContent)` β€” Install a style to Zotero

## Lifecycle Hooks (`src/hooks.ts`)

### `onStartup()`

- Waits for Zotero initialization
- Initializes localization
- Registers the preferences pane
- Opens preferences on first install

### `onMainWindowLoad(win)`

- Initializes ZToolkit for each window
- Registers FTL (Fluent) localization strings

### `onMainWindowUnload(win)` / `onShutdown()`

- Cleans up event listeners
- Closes dialog windows
- Unregisters all handlers

### `onPrefsEvent(type, data)`

Handles the preferences pane UI interactions:

- **Email/License Input**: Form fields for credentials
- **Verify Button**: Triggers license validation
- **Styles Container**: Displays installable styles with Install/Update buttons
- **Logout Button**: Clears stored credentials
- **Check for Updates Button**: Fetches updates for installed styles

**Status Colors:**

- Green (#28a745): Verified license
- Orange (#fd7e14): Grace period or expiring soon
- Red (#dc3545): Errors (invalid email, missing credentials, validation failed)
- Gray (#888): In-progress or neutral

## Build & Development

### Scripts

```bash
npm start # Start dev server with hot-reload
npm run build # Build plugin & run TypeScript check
npm run lint:check # Check formatting & linting
npm run lint:fix # Auto-fix formatting & linting
npm run release # Build release XPI
npm test # Run Mocha test suite
npm run update-deps # Update dependencies
```

### Build Output

- **Development**: `.scaffold/build/` directory
- **Release**: XPI file for distribution
- Manifest is templated with package.json values

## Configuration

### package.json Config Section

```json
"config": {
"addonName": "Citation Styler Client Sync",
"addonID": "citationstyler-sync@citationstyler.com",
"addonRef": "citationstyler-sync", // Namespace for chrome://
"addonInstance": "CitationStylerSync", // Global Zotero object instance
"prefsPrefix": "extensions.zotero.citationstyler-sync" // Prefs storage prefix
}
```

### Environment Variables

- `NODE_ENV`: "development" or "production" (passed to plugin via `__env__`)
- Plugin sets `__env__` in esbuild define

## Important Implementation Details

### First Install Experience

When the plugin is first installed:

1. Checks `extensions.citationstyler.installed` preference
2. If not set, opens the preferences pane automatically
3. User enters email and license key
4. Plugin validates against backend
5. Installed styles are displayed

### Preferences Pane Elements

All elements queried in `onPrefsEvent`:

- `#prefs-verify-btn` β€” License verification button
- `#prefs-email-input` β€” Email address input
- `#prefs-license-input` β€” License key input
- `#prefs-status` β€” Status messages
- `#prefs-styles-container` β€” Installed styles list
- `#prefs-logout-btn` β€” Clear credentials button
- `#prefs-check-updates-btn` β€” Check for updates button
- `#prefs-update-row` β€” Update controls container
- `#prefs-update-status` β€” Update status message

### Zotero Integration

- Uses `Zotero.Prefs` for persistent storage
- Uses `Zotero.getMainWindows()` to iterate windows
- Uses `Zotero.PreferencePanes.register()` to add settings pane
- Uses `Zotero.Utilities.Internal.openPreferences()` to open prefs
- Uses `MozXULElement.insertFTLIfNeeded()` for localization

### Email Validation

Simple regex validation in `onPrefsEvent`:

```typescript
!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
```

## Localization

Localization strings are stored in `addon/locale/` and referenced via `getString(key, options)` from `src/utils/locale.ts`.

**Common Keys:**

- `prefs-title` β€” Preferences pane title
- `email-placeholder`, `license-placeholder` β€” Input placeholders
- `status-verifying`, `status-verified`, `status-verification-failed` β€” Status messages
- `status-no-zotero` β€” Zotero account not logged in
- `status-grace-period` β€” License in grace period
- `status-all-uptodate` β€” No updates available

## Error Handling

**Common User-Facing Errors:**

- "Please log in to your Zotero account" β†’ User must sign in at zotero.org
- "Email does not match this license key" β†’ Email/key mismatch
- "Activation limit reached" β†’ Too many devices for this license

**Developer Error Handling:**

- Try-catch blocks around validation and update checks
- Errors logged via `ztoolkit.log()` for debugging
- User receives readable error messages in status display

## Release Process

1. Update version in `package.json`
2. Run `npm run build` to verify
3. Run `npm run release` to generate XPI
4. XPI is created from `.scaffold/build/`
5. Upload to GitHub releases
6. Plugin update URL points to release JSON

## Testing

Tests are written in Mocha + Chai in `test/startup.test.ts`.

**Key Test Requirement:**

- Tests wait for plugin initialization via: `Zotero.MyCustomStyles.data.initialized`

## Known Limitations & Notes

- Plugin requires active Zotero account (zotero.org login)
- License validation requires internet connection (unless cached)
- Email validation is basic regex-based
- Cache expiration is configurable in license module
- Style installation depends on Zotero's style management API

## Author & Support

**Author:** Citation Styler
**Email:** info@citationstyler.com
**Website:** https://citationstyler.com
**Issues:** https://github.com/POBrien333/citationstyler-client-sync/issues
Loading