Download the PHP package joshcirre/duo without Composer

On this page you can find all versions of the php package joshcirre/duo. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package duo

Duo (VERY MUCH A WIP)

Local-first IndexedDB syncing for Laravel and Livewire applications.

Duo enables automatic client-side caching and synchronization of your Eloquent models using IndexedDB, providing a seamless offline-first experience for your Laravel/Livewire applications. Just add a trait to your Livewire component and Duo handles the restβ€”automatically transforming your server-side components to work with IndexedDB.

Features

Local Development Setup

Want to contribute or test Duo locally? Follow these steps to set up local development with symlinked packages.

1. Clone and Install Duo

2. Symlink Composer Package

Link the Duo package to your local Laravel application:

This creates a symlink in vendor/joshcirre/duo pointing to your local Duo directory. Changes to the PHP code are immediately reflected.

3. Symlink NPM Package

Link the Vite plugin to your Laravel application:

Now your Laravel app uses the local version of the Vite plugin.

4. Watch for Changes

In the Duo package directory, run the build watcher:

This watches for TypeScript changes and rebuilds automatically. Changes are immediately available in your linked Laravel app.

5. Test Your Changes

In your Laravel app:

This runs both npm run dev and php artisan serve concurrently. Any changes you make to Duo's PHP or TypeScript code will be reflected immediately!

Alternative (manual):

6. Unlinking (When Done)

To remove the symlinks:

Development Tips


Installation

Composer Package

NPM Package (Vite Plugin)

Note: Dexie is automatically installed as a dependency.

Publishing Assets (Optional)

Duo works out-of-the-box without publishing any files. However, you can publish various assets for customization:

What gets published:

See Publishing Components in the Configuration section for customization examples.

Quick Start

1. Add the Syncable Trait to Your Models

Add the Syncable trait to any Eloquent model you want to cache in IndexedDB:

Both $fillable and $guarded are supported:

Duo automatically extracts your model's fillable attributes and database schema (column types, nullable, defaults) to generate the IndexedDB manifestβ€”no manual configuration needed!

User-Scoped Models:

For models that belong to users, add a user() relationship but do NOT add user_id to $fillable:

Why? Including user_id in $fillable is a security riskβ€”users could assign items to other users. Duo automatically detects the user() relationship and assigns the authenticated user's ID securely during sync.

2. Add @duoMeta Directive to Your Layout

CRITICAL: Add the @duoMeta directive to the <head> section of your main layout. This provides the CSRF token and enables offline page caching:

The @duoMeta directive outputs:

3. Configure Vite

Add the Duo plugin to your vite.config.js:

That's all you need! The plugin will automatically:

Want to customize? All options have sensible defaults and are optional:

4. Add the WithDuo Trait to Your Livewire Components

This is where the magic happens! Add the WithDuo trait to any Livewire component and Duo will automatically transform it to use IndexedDB:

Volt Component Example:

Class-Based Component Example:

What Happens Automatically:

When you add the WithDuo trait, Duo will:

  1. βœ… Transform wire:click to Alpine.js @click handlers
  2. βœ… Convert @forelse loops to Alpine x-for templates
  3. βœ… Transform {{ $todo->property }} to x-text bindings
  4. βœ… Convert conditional classes to :class bindings
  5. βœ… Add x-cloak and loading state management
  6. βœ… Route all data operations through IndexedDB
  7. βœ… Queue changes for background sync to the server

5. Add Optional Components

Sync Status Indicator:

Display a visual indicator of the sync status:

This component shows:

Configuration Options:

Available Props:

Prop Type Default Description
position string 'top-right' Position of the indicator: 'top-right', 'top-left', 'bottom-right', 'bottom-left'
inline bool false Display inline instead of fixed positioning
show-delay int 1000 Milliseconds to wait before showing syncing indicator (prevents flash for fast syncs)
show-success bool false Whether to show "All changes synced" success message

Global Configuration:

You can set default values in your config/duo.php:

Component-level props override global config values.

Debug Panel (Local Development Only):

Add a debug panel to view IndexedDB info and manage the database during development:

This component (only visible in local environment) provides:

The debug panel automatically shows the current schema version (timestamp-based) and makes it easy to test schema migrations by clearing the database.

Available Props:

Prop Type Default Description
position string 'bottom-right' Position of the panel: 'top-right', 'top-left', 'bottom-right', 'bottom-left'

Note: Both components (sync-status and debug) can be customized by publishing the views. See Publishing Components for details.

6. Run Your Application

Development:

This runs both npm run dev and php artisan serve concurrently. The Vite plugin will automatically:

Production Build:

The production build will:

Important for Offline Support:

  1. Visit your application while online (at least once after deploying)
  2. The service worker will detect pages with @duoMeta and cache them
  3. After the initial visit, the page will work offline

The service worker route (/duo-sw.js) is automatically registered by the Duo service providerβ€”no additional configuration needed!

How It Works

Duo uses a sophisticated local-first architecture that transforms your Livewire components into offline-capable Alpine.js applications:

Initial Load

  1. Component Transformation: When a component with the WithDuo trait renders, Duo intercepts the HTML and transforms it:

    • Blade @forelse loops β†’ Alpine x-for templates
    • wire:click handlers β†’ Alpine @click with IndexedDB operations
    • {{ $model->property }} β†’ <span x-text="model.property"></span>
    • Conditional classes β†’ :class bindings
    • Adds loading states and x-cloak for smooth initialization
  2. Sync Server Data: On page load, the Alpine component syncs server data to IndexedDB
  3. Ready State: Component shows with duoReady flag set to true

Data Operations

Reads:

Writes:

Offline Support

Going Offline:

  1. Browser's navigator.onLine API detects offline state
  2. Sync queue automatically pauses
  3. All operations continue to work locally
  4. Sync status component shows orange "Offline" badge

Coming Back Online:

  1. Browser detects connection restored
  2. Sync queue automatically resumes
  3. All queued operations sync to server
  4. Network errors don't count against retry limit
  5. Sync status shows progress, then green "Synced" when complete

Background Sync

Configuration

Global Configuration

Publish the configuration file:

Edit config/duo.php:

Publishing Components

If you want to customize the Duo components (sync-status, debug panel), publish the views:

This will copy the component views to resources/views/vendor/duo/components/. Published views take precedence over the package views, so you can customize:

Sync Status Component:

Debug Panel Component:

After publishing, you can modify:

Example Customization:

Note: The components use inline styles by default, so they work out-of-the-box without requiring Tailwind or custom CSS. If you publish and customize them, you can keep the inline styles or switch to your own CSS approach.

Component-Level Configuration

You can customize Duo's behavior on a per-component basis using the type-safe DuoConfig class. This provides full IDE autocomplete and type checking!

Volt Component:

Class-Based Component:

Available Configuration Options:

All options can be set globally in config/duo.php and overridden per-component in duoConfig():

Option Type Default Global Config Component Override Description
syncInterval int 5000 duo.sync_interval syncInterval Milliseconds between sync attempts to server. Controls how often pending changes are sent.
timestampRefreshInterval int 10000 duo.timestamp_refresh_interval timestampRefreshInterval Milliseconds between timestamp updates. Controls how often relative times like "5 minutes ago" refresh.
maxRetryAttempts int 3 duo.max_retry_attempts maxRetryAttempts Maximum number of retry attempts for failed sync operations before giving up.
debug bool false duo.debug debug Enable verbose console logging. Useful for debugging transformation and sync issues.

Configuration Priority:

Example with all options:

Benefits of Type-Safe Config:

Why Component-Level Config?

Component-level configuration allows you to:

Global vs Component Config:

This architecture provides flexibility while maintaining sensible defaults across your entire application.

Vite Plugin Options

The Duo Vite plugin has sensible defaults and requires no configuration. Simply add duo() to your Vite plugins.

All options are optional:

Option Type Default Description
manifestPath string 'resources/js/duo/manifest.json' Path where the manifest file is generated
watch boolean true Watch files for changes during development
autoGenerate boolean true Automatically run duo:generate on build and file changes
patterns string[] ['app/Models/**/*.php'] Glob patterns to watch for changes. Add Volt/Livewire paths if you want manifest regeneration on component changes
entry string 'resources/js/app.js' Entry file where Duo initialization code is injected
autoInject boolean true Automatically inject Duo initialization code into entry file
command string 'php artisan duo:generate' Custom artisan command to run for manifest generation
basePath string process.cwd() Base path for resolving file paths

Example with custom options:

Disabling auto-injection (manual initialization):

If you want full control over Duo initialization:

Then manually initialize in your JavaScript:

Advanced Usage

Manual Database Operations

Manual Sync Operations

Listen for Sync Events

Duo dispatches a duo-synced event whenever a sync operation completes successfully. You can listen for this event to trigger custom behavior:

Livewire Components:

Alpine Components:

Vanilla JavaScript:

This is particularly useful for:

Access Sync Status in Custom Components

Clear Cache

Custom Sync Component

You can build your own sync indicator using the sync status API:

Artisan Commands

Discover Models

Lists all Eloquent models using the Syncable trait. Useful for verifying which models will be included in the manifest.

Generate Manifest

Generates the manifest.json file with IndexedDB schema from your models. The Vite plugin runs this automatically, but you can run it manually:

Note: The Vite plugin with watch: true automatically regenerates the manifest when model files change, so you rarely need to run this manually.

Troubleshooting

Component Not Transforming

If your Livewire component isn't being transformed to Alpine:

  1. Check the trait is present:

  2. Clear caches:

  3. Check Laravel logs:

"window.duo not available"

If you see this error in the console:

  1. Check Duo is initialized:

    • Duo initializes automatically via the Vite plugin
    • Check that the Duo plugin is added to your vite.config.js
  2. Regenerate the manifest:

  3. Check Vite is running:

Data Not Syncing

If changes aren't syncing to the server:

  1. Check the browser console for sync errors
  2. Check sync queue status:

  3. Verify routes are registered - Duo registers routes at /duo/sync
  4. Check network tab in DevTools for failed requests

Changes Not Persisting

If changes disappear after refresh:

  1. Check IndexedDB in Browser DevTools β†’ Application β†’ IndexedDB
  2. Verify the model has Syncable trait
  3. Check server logs for save errors
  4. Clear IndexedDB and resync:

Clearing IndexedDB

Need to clear IndexedDB during development? You have several options:

Option 1: Debug Panel (Easiest)

Click "Delete Database & Reload" to clear IndexedDB and reload the page.

Option 2: Browser Console

Option 3: Browser DevTools

When to clear IndexedDB:

FAQ

Do I need to change my Livewire components?

No! Just add the WithDuo trait. Your existing Blade templates and Livewire methods work as-is. Duo automatically transforms them to use IndexedDB and Alpine.js.

Will this work with Volt components?

Yes! Duo works seamlessly with both class-based Livewire components and Volt single-file components.

What happens if JavaScript is disabled?

Components without the WithDuo trait will continue to work as normal server-side Livewire components. Components with the trait require JavaScript for the IndexedDB functionality.

Can I use this with existing Alpine.js code?

Yes! Duo generates Alpine.js-compatible code, so you can mix Duo-transformed components with regular Alpine components.

Does this replace Livewire?

No. Duo enhances Livewire by adding local-first capabilities. The server is still the source of truth. Duo just caches data locally and provides offline support.

Can I use Flux components?

Partially. Flux components work great for forms, buttons, and static UI elements. However, Flux components inside @forelse loops won't transform correctly since they're server-side components. Use plain HTML with Alpine bindings for loop items.

How do I handle conflicts?

Duo uses a "server wins" strategy. When sync operations complete, the server response updates the local cache. This ensures the server remains the source of truth.

Can I customize the transformation?

Currently, the transformation is automatic. Custom transformation logic is planned for a future release.

Requirements

Browser Support

Duo works in all modern browsers that support IndexedDB:

License

MIT License. See LICENSE.md for details.

Credits

Created by Josh Cirre

Built with:

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Roadmap

See ROADMAP.md for planned features including:

Support


All versions of duo with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
illuminate/console Version ^11.0|^12.0
illuminate/database Version ^11.0|^12.0
illuminate/support Version ^11.0|^12.0
livewire/flux Version ^1.0|^2.0
livewire/livewire Version ^3.0
stillat/blade-parser Version ^2.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package joshcirre/duo contains the following files

Loading the files please wait ...