Local Setup
This document describes how to set up Delfino for local development, including integration with Zoo (the Docker environment for local development).
Prerequisites
- Git
- Docker running
- Zoo Docker environment with
delfino,volpe, andfarfallacontainers running
Note: Node.js and Yarn are not required on the host. The build and dependency installation run inside the
delfinocontainer viadocker exec.
Required Directory Structure
For local development to work correctly, projects must be organized as follows:
~/Dev/
├── delfino/
│ └── src/
│ └── index.ts
├── farfalla/
├── volpe/
└── zoo/
Installation
Clone the Repository
cd ~/Dev
git clone git@gitlab.com:publicala/delfino.git
Note: Dependency installation is handled automatically inside the
delfinocontainer when runningzdelfino syncfor the first time. There is no need to runyarn installmanually on the host.
Development Commands
The following commands run inside the delfino container via Zoo:
| Command | Description |
|---|---|
yarn build | Build the library (ESM + UMD) |
yarn dev | Watch mode for development |
yarn typecheck | Type checking only (no emit) |
yarn test | Run tests once |
yarn test:watch | Run tests in watch mode |
yarn test:coverage | Run tests with coverage report |
yarn lint | Run ESLint |
yarn lint:fix | Fix ESLint errors |
yarn format | Format code with Prettier |
yarn format:check | Check code formatting |
yarn clean | Remove build artifacts |
Zoo Integration
Delfino integrates with Farfalla and Volpe through direct synchronization to node_modules/@publicala/delfino inside the Docker containers. This approach does not modify any configuration files and is fully compatible with CI/CD without changes.
Architecture
HOST (macOS)
~/Dev/delfino/ (bind-mounted into delfino container)
│
▼
DELFINO CONTAINER (Docker)
yarn install + yarn build ──▶ ~/Dev/delfino/dist/ (visible on host)
│
┌────────────────────────┤
│ │ │
▼ ▼ ▼
docker cp Host IDE copy docker cp
(host → volpe) (type (host → farfalla)
resolution)
CONSUMER CONTAINERS (Docker)
┌──────────────────────────────────────────────────┐
│ volpe ▸ node_modules/@publicala/delfino/ │
│ farfalla ▸ node_modules/@publicala/delfino/ │
└──────────────────────────────────────────────────┘
The sync flow is:
- Verify that the
delfino,volpe, andfarfallacontainers are running - Install dependencies inside the
delfinocontainer withyarn install --frozen-lockfile(ifnode_modulesdoes not exist) - Build Delfino inside the
delfinocontainer withyarn build(the output indist/is visible on the host via bind mount) - Copy the build artifacts (
dist/andpackage.json) to the consumer containers viadocker cp - Install production dependencies inside each consumer container
- Write sync metadata (
.delfino_sync_metawith git hash,.delfino_sync_tokenfor bind mount detection) - Copy to the host's
node_modulesso the IDE can resolve types (only ifnode_modulesis not a Docker volume) - Restart the containers to clear the in-memory Vite module cache
Initial Setup
Run release-animals.sh and answer "y" when prompted with "Setup Delfino for local development?":
cd ~/Dev/zoo
./release-animals.sh
Or manually:
zdelfino sync
zdelfino Commands
| Command | Description |
|---|---|
zdelfino sync | Build and sync to Volpe and Farfalla |
zdelfino status | Show sync state across projects |
zdelfino restore | Restore Delfino from the npm registry |
zdelfino build | Build Delfino only, without syncing |
Daily Development
cd ~/Dev/delfino
# ... edit code ...
zdelfino sync
# Containers restart automatically
Check Sync Status
zdelfino status
Shows the version and git hash of Delfino in the source, Volpe, and Farfalla, and indicates whether they are in sync.
Restore from npm
To revert to the published version from the registry:
zdelfino restore
This cleans host IDE copies, temporarily disables the guard, and runs yarn install --force in both containers.
Delfino Guard
The guard automatically protects the locally synced copy of Delfino when package manager commands (yarn install, npm install, etc.) are executed via zex. Without this protection, yarn install would overwrite the locally synced version with the version from the registry.
How It Works
The guard activates automatically when all of the following conditions are met:
DELFINO_GUARD_SKIPis not set- The container is
farfallaorvolpe - The command is a package manager operation that resolves dependencies
@publicala/delfinoexists in the container'spackage.json- Volpe only: the installed version matches the version in
package.json(if the version changed intentionally, the guard deactivates to allow the update)
Note on Volpe: The guard includes version change detection (
delfino_guard_has_version_changed). If the version of@publicala/delfinoin Volpe'spackage.jsondiffers from the version installed innode_modules, the guard deactivates to allowyarn installto update to the new version. This behavior does not apply to Farfalla, where the guard always activates.
Commands That Activate the Guard
yarn install,yarn add,yarn upgrade,yarn remove,yarn(bare)npm install,npm ci,npm add,npm update,npm uninstall,npm i
Commands That Do NOT Activate the Guard
yarn dev,yarn build,yarn testnpm run devphp artisan migrate,composer install
Example
# The guard protects delfino automatically:
zex farfalla yarn add lodash
# 🛡️ Delfino Guard: protecting local sync in farfalla
# ... yarn add lodash runs without touching delfino ...
# 🛡️ Delfino Guard: node_modules/@publicala/delfino restored in farfalla
# 🛡️ Delfino Guard: package.json restored in farfalla
Manual Bypass
DELFINO_GUARD_SKIP=1 zex farfalla yarn install
Internal Guard Flow
When the guard activates, it executes the following phases:
- Backup: Backs up
package.json,yarn.lock, andnode_modules/@publicala/delfinoinside the container. Removes the@publicala/delfinoline frompackage.json. - Execution: Runs the original command. Since
@publicala/delfinois not inpackage.json, the package manager does not touch that directory. A trap is registered to ensure restoration even if the command fails. - Restoration: Restores
node_modules/@publicala/delfinofrom the tarball backup and restores the originalpackage.jsonandyarn.lock.
Sync Metadata
The system uses two metadata files inside node_modules/@publicala/delfino/ in each container:
| File | Content | Purpose |
|---|---|---|
.delfino_sync_meta | Git hash + dirty flag (e.g. abc1234:dirty) | Determine if projects are in sync via zdelfino status |
.delfino_sync_token | Timestamp + PID (e.g. 1709654321.12345) | Detect whether the directory is a bind mount or Docker volume to avoid re-copying and losing installed production dependencies |
Zoo File Structure
zoo/
├── bin/
│ ├── zdelfino # Main Delfino command
│ └── zex # Integrates delfino_guard
├── lib/
│ ├── delfino_sync.sh # Sync library
│ ├── delfino_guard.sh # Protection library against yarn/npm
│ └── project_info.sh
├── scripts/
│ └── setup_delfino.sh # Setup for release-animals
├── tests/
│ └── test_delfino_guard.bats # BATS tests for the guard
└── release-animals.sh # Includes Delfino setup option
Local Development Commands
Farfalla (inside Zoo/Docker)
# Start development with hot reload
zex farfalla yarn watch
# Development build
zex farfalla yarn dev
# TypeScript type checking
zex farfalla yarn type-check
Volpe (inside Zoo/Docker)
# Start Vite development server
zex volpe yarn dev
# Local build
zex volpe yarn build:local
# Preview build
zex volpe yarn preview
Package Registry Configuration
GitLab Package Registry
Delfino is published to the GitLab Package Registry under the @publicala scope.
.npmrc configuration:
@publicala:registry=https://gitlab.com/api/v4/packages/npm/
//gitlab.com/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}
//gitlab.com/api/v4/projects/:_authToken=${CI_JOB_TOKEN}
CI/CD Configuration Template
.npm_gitlab_auth: &npm_gitlab_auth
- |
echo "@publicala:registry=https://gitlab.com/api/v4/packages/npm/" > .npmrc
echo "//gitlab.com/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}" >> .npmrc
echo "//gitlab.com/api/v4/projects/:_authToken=${CI_JOB_TOKEN}" >> .npmrc
Testing
Running Tests
# Run all tests
yarn test
# Run tests in watch mode
yarn test:watch
# Run with coverage
yarn test:coverage
Test Environment
Tests use Vitest with jsdom environment. The setup file (vitest.setup.ts) configures the DOM simulation.
Test Files
| Test File | Coverage |
|---|---|
BridgeError.test.ts | Error handling and fluent helpers |
SecurityManager.test.ts | Rate limiting, logging |
HostBridge.test.ts | iframe validation, retry logic |
ClientBridge.test.ts | MessageChannel creation, handshake |
FullCycle.test.ts | End-to-end communication tests |
Build Outputs
After running yarn build (via Rollup), the following artifacts are created:
dist/
├── esm/
│ ├── index.js # ES Modules (tree-shakeable, comlink external)
│ └── types/
│ └── index.d.ts # TypeScript declarations
└── umd/
└── delfino.min.js # UMD (bundled + minified, comlink included)
Output Usage
| Output | Consumer | Import |
|---|---|---|
| ESM | Farfalla, Volpe (npm) | import { hostBridge } from '@publicala/delfino' |
| UMD | Fenice (CDN) | <script src="delfino.min.js"> then window.Delfino |
| Types | TypeScript projects | Automatic via types field in package.json |
Troubleshooting
"Cannot find module '@publicala/delfino'"
- Verify that the
delfinodirectory exists at~/Dev/delfino - Verify that the
delfino,volpe, andfarfallacontainers are running (docker ps) - Run
zdelfino syncto synchronize - Verify with
zdelfino statusthat projects are in sync
"Types not found"
- Run
yarn type-checkto verify TypeScript configuration - Restart the TypeScript server in your IDE
- Verify that
zdelfino synccopied files to the host'snode_modules
"Changes in Delfino are not reflected"
- Run
zdelfino sync(synchronization is manual, not automatic) - Containers restart automatically after sync
- If the issue persists, verify with
zdelfino statusthat the hashes match
"HostBridge must run inside an iframe"
This error indicates Volpe is running standalone. Ensure:
- Volpe is loaded in an iframe element
- The iframe
srcpoints to the correct Volpe URL - The Host is using
createClientBridge(iframe)before Volpe callshostBridge.ready()
"Timeout waiting for channel from host"
This indicates the handshake failed. Check:
- Host calls
clientBridge.ready()after creating the iframe - Iframe loads successfully
- No CORS issues blocking communication
- Both projects use compatible Delfino versions
Rate Limit Exceeded in Development
Switch to development security preset:
createClientBridge(iframe, { security: 'development' });
Guard Does Not Protect During yarn install
- Verify you are using
zexand not runningyarn installdirectly inside the container - Verify that
@publicala/delfinois in the project'spackage.json - Verify that
DELFINO_GUARD_SKIPis not set in the environment - Volpe only: verify that the version in
package.jsonhas not changed from the installed version (if it changed, the guard deactivates intentionally)
Empty node_modules After zex yarn install (False Positive)
When deleting node_modules from Volpe or Farfalla and running zex yarn install, a false positive may occur: the command finishes without errors but the node_modules folder is empty or incomplete. This happens occasionally within the Docker environment.
Solution:
-
Verify that
node_modulesactually contains the dependencies after runningzex yarn install -
If the folder is empty or incomplete, delete it manually:
# For Volpe
zex volpe rm -rf node_modules
# For Farfalla
zex farfalla rm -rf node_modules -
Run the install command again:
# For Volpe
zex volpe yarn install
# For Farfalla
zex farfalla yarn install -
Verify that the dependencies were downloaded correctly
zdelfino sync Fails with "container not running"
- Verify the
delfinocontainer is running:docker ps | grep delfino - Verify consumer containers are running:
docker ps | grep -E 'volpe|farfalla' - If any container is not running, start Zoo:
cd ~/Dev/zoo && docker compose up -d