Skip to content

decouple deployer#31

Closed
dskvr wants to merge 39 commits into
mainfrom
enhance/decouple-deployer
Closed

decouple deployer#31
dskvr wants to merge 39 commits into
mainfrom
enhance/decouple-deployer

Conversation

@dskvr
Copy link
Copy Markdown
Contributor

@dskvr dskvr commented Mar 25, 2026

I haven't checked anything, and integrating the package back into the SPA was deferred to the next milestone.

@dskvr dskvr requested a review from hzrd149 March 25, 2026 22:17
dskvr added a commit that referenced this pull request Mar 26, 2026
- Add nodeModulesDir: "none" to deno.json to fix esbuild resolution
  error caused by npm node_modules directory from deployer package
- Fix all require-await lint errors: remove async from functions that
  don't use await (validateAuth, handleServerInfo, putJson, getMeta,
  putMeta, verifySha256, etc.)
- Fix no-unused-vars: prefix unused params with underscore (_config,
  _request, _fetchProfile, etc.)
- Fix no-unversioned-import: pin npm:@libsql/client to ^0.17.0
- Fix prefer-const in local.test.ts
- Fix ban-unused-ignore in blossom-dev.ts
- Update router tests for direct blossom integration (no longer proxy
  stubs returning 503)
- Fix blob-get test to use correct SHA-256 hash for mock content
- Add .claude/, .worktrees/, node_modules/, packages/deployer/,
  packages/stealthis/ to fmt, lint, and test excludes
- Run deno fmt to fix all formatting issues

All CI steps pass: fmt --check, lint, check, test (242/242), build.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 26, 2026

Bundle Size Report

Bundle Base PR Delta Status
relay 126.5 KB 126.5 KB +0.0 KB ✅ OK
blossom 64.2 KB 64.2 KB +0.0 KB ✅ OK
gateway 235.1 KB 235.1 KB +0.0 KB ✅ OK

Generated by CI — hard limit 1MB, warning at 750KB.

@dskvr dskvr force-pushed the enhance/decouple-deployer branch from ebb279c to 4e1f694 Compare March 26, 2026 10:13
dskvr and others added 26 commits March 26, 2026 11:38
…geSite

- dispatch('delete-start') fires immediately when deleteState becomes 'deleting'
- dispatch('delete-end', { success: true }) fires when deletion completes successfully
- dispatch('delete-end', { success: false }) fires when deletion fails in catch block
- dispatch('delete-end', { cancelled: true }) fires when user cancels from confirm screen
… listener to App.svelte

- import onDestroy from 'svelte' alongside onMount
- add deleteInProgress state variable (toggled by ManageSite events)
- add DANGEROUS_DEPLOY_STEPS Set and isDangerousStep reactive derivation
- add handleBeforeUnload function with event.preventDefault() + returnValue
- add reactive $: block that attaches/detaches listener based on isDangerousStep
- add onDestroy cleanup to remove listener when component unmounts
- wire on:delete-start and on:delete-end handlers to ManageSite element
- Amber styled banner (bg-amber-900/40, border-amber-600/50) for in-progress operations
- Props: operationType, progress, step, completionState, onNavigateBack
- Pulsing amber dot during in-progress state
- Green checkmark on success, red X on error
- Auto-dismiss after 5s using dismissTimerSet guard pattern
- Not user-dismissible (no close button)
- View details button navigates back to operation tab via onNavigateBack callback
- Import OperationBanner component
- Add bannerCompletionState and bannerOperationType state variables
- Add reactive deploy completion tracking (prevStep pattern)
- Derive showBanner = isDangerousStep || bannerCompletionState !== null
- Update delete-start handler: reset bannerCompletionState, set operationType to delete
- Update delete-end handler: set bannerCompletionState based on success/error (skip cancelled)
- Reset bannerCompletionState at start of handleDeploy
- Render OperationBanner above tab buttons in idle/selecting block
…e MIME lookup

The SPA uses Vite for browser builds, but @std/media-types/content-type is a
Deno standard library module that fails to resolve in the Vite build pipeline.
Replace with an inline MIME type map covering common web file extensions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nction

Replace global deleteState variable with per-card deletingCards Map so the
card list always renders and each card independently tracks its delete lifecycle.
Fix the success/failure conflation bug where "done" always showed "Deletion
complete" regardless of outcome. Cards are dimmed and non-interactive while
deleting, failed cards show inline error and auto-recover after 4s timeout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ration

Add two-phase CSS exit animation for successful deletes: fade opacity (500ms)
then collapse height (300ms) for smooth card removal. Show green checkmark +
"Deleted" indicator before fade begins. Add optimistic site-removed event
to App.svelte for instant UI update. Implement activeDeleteCount for correct
delete-start/delete-end boundary events with concurrent deletes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…another on SuccessPanel

Replace the single "Update Site" button on the deploy success screen with
two navigation buttons: "Manage sites" (dispatches 'manage' event) and
"Deploy another" (dispatches 'deploy-another' event). Existing share
buttons (Copy URL, Share on nostr, View Manifest) remain unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a "Deploy new site" button at the bottom of the manage view that
dispatches a 'deploy-new' event. The button is always visible in both
empty and non-empty site list states, providing a discoverable path
to deploy from within the manage view.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tab buttons (Deploy/Manage) are now disabled and greyed out during
active operations (hashing/checking/uploading/publishing or active
delete). Uses isDangerousStep from Phase 13 for the disabled attribute
and click guard. Buttons show opacity-40 and cursor-not-allowed when
disabled, preserving existing active/inactive styling when enabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace on:update={resetForUpdate} with on:manage (navigates to manage
tab) and on:deploy-another (resets deploy state via resetForUpdate,
preserving signer). Remove the old "Deploy another site" text link that
incorrectly called resetDeploy() which would clear the signer session.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…y tab

Handle the 'deploy-new' event from ManageSite by switching to the deploy
tab and calling resetForUpdate() to clear deploy state while preserving
the signer session. This provides a discoverable path from manage view
to deploy without losing authentication.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add inline amber warnings when deploying to a site type that already
exists (root or named), with "Update existing site" buttons that route
into the update flow. Block deploy button with "Checking existing
sites..." while site data loads for logged-in users.

Implements GUARD-01 through GUARD-05:
- Root site guard with site URL, file count, and publish date
- Named site guard triggered by matching dTag
- handleGuardUpdate helper reuses manage view's update pattern
- canDeploy blocks during sitesLoading (pubkey-gated)
- Zero friction for users with no existing sites

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…link

Delay fetchSiteInfo() by 5s after deletion so relays have time to process
kind 5 events — prevents stale data from overwriting optimistic removal.
Hide OperationBanner "View details" link when already on the correct tab.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change default ports from 808x to 310x to match orchestrator
- Gateway shares dev-relay.db instead of separate dev-gateway.db
  (mirrors production where both share the same Bunny DB)
- Set GATEWAY_URL so resolver recognizes self-referencing manifest
  server tags and rewrites them to BLOSSOM_URL
- Set BLOSSOM_URL to gateway's own port so resolver fetches blobs
  from the inline blossom handler (same process that stored them)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nent

- localStorage-backed dismissal persists across reloads
- Fade transition (200ms) on hide
- Purple-themed styling consistent with dark slate/purple theme
- Link to https://github.com/nostr-protocol/nips/blob/master/5A.md
- Create root package.json with workspaces (apps/spa, packages/deployer)
- Create packages/deployer/package.json with exports map (svelte condition first)
- Create packages/deployer/svelte.config.js with vitePreprocess
- Create packages/deployer/src/index.js placeholder
- Create packages/deployer/src/widget/index.js placeholder with VERSION export
- Add @nsite/deployer as workspace dependency in apps/spa/package.json
- Add .npmrc with @jsr:registry=https://npm.jsr.io for JSR package resolution
- Delete apps/spa/package-lock.json (replaced by root-level lockfile)
- Run npm install from root: creates node_modules/@nsite/deployer symlink
- Root package-lock.json generated as single source of truth
- SPA builds successfully via workspace-hoisted Vite (520 modules)

[Rule 2] Added .npmrc with JSR registry scope — required for npm to
resolve @jsr/* packages used by @std/media-types alias in apps/spa
- Add vite.widget.config.js with Svelte plugin (css: injected) and IIFE+ESM lib mode
- Entry: src/widget/index.js, global name: NsiteDeployer, outputs: deployer.js / deployer.mjs
- cssCodeSplit: false and inlineDynamicImports: true for self-contained single-file bundles
- No external array — IIFE bundle is fully self-contained
- Build produces dist/deployer.js (IIFE) and dist/deployer.mjs (ESM)
git mv apps/spa/src/lib/{store,nostr,upload,publish,crypto,files,scanner,base36}.js
to packages/deployer/src/lib/ — file contents unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…actory

Replace module-level session/deployState/serverConfig exports with a
createDeployerStores(options) factory function. Accepts storagePrefix
for multi-instance isolation. Export DEFAULT_SESSION for consumer use.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…r package

Add 8 sub-path exports (./store, ./nostr, ./upload, ./publish, ./crypto,
./files, ./scanner, ./base36) with svelte+default conditions. Add runtime
deps (applesauce-signers, applesauce-relay, nostr-tools, fflate, nanotar)
and vitest devDep with test script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
packages/deployer/src/index.js now re-exports all public APIs from
the 8 lib modules for consumers using the root import path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 5 test files from apps/spa to packages/deployer/src/lib/__tests/.
Leave tools.test.js in apps/spa (tests SPA-specific tools-resources.yaml).
Add packages/deployer/vitest.config.js with node environment.
Fix pre-existing test mismatches: MIME charset expectations, auth batch test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace relative ./lib/ imports with @nsite/deployer/{store,nostr,crypto,
upload,publish,base36}. Wire createDeployerStores() factory at top-level.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dskvr and others added 12 commits March 26, 2026 11:38
Update all 8 SPA components from relative ../lib/ imports to
@nsite/deployer/{files,scanner,nostr,store,publish,upload,base36}.
Components needing stores now call createDeployerStores() locally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove applesauce-signers, applesauce-relay, applesauce-core, fflate,
nanotar, @std/media-types from apps/spa/package.json — now transitive
through @nsite/deployer. Keep nostr-tools (directly imported by SPA).
SPA build and all tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…/components/

- git mv all deployer-specific Svelte components from apps/spa/src/components/
- Navbar, NIP5ABanner, ToolsResources remain in apps/spa/src/components/
- No content changes, just file relocation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…store context

- Replace createDeployerStores() calls with getContext('deployer-stores')
- LoginModal and NIP46Dialog get session store from context
- AdvancedConfig gets serverConfig store from context
- No component in packages/deployer imports store.js as singleton

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…op and event dispatch

- Self-contained orchestrator hosting complete deploy+manage+update flow
- createDeployerStores() with setContext for child component store access
- Optional signer prop: null shows built-in auth, non-null skips auth
- Typed event dispatch: deploy-success, deploy-error, auth-change,
  operation-start, operation-end, site-deleted
- beforeunload guard and onDestroy cleanup
- OperationBanner with tab switching
- CSS custom properties (--deployer-accent, --deployer-bg, --deployer-text,
  --deployer-radius) with fallback defaults on .deployer-widget root
- Deploy button uses var(--_accent) for theming

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- App.svelte reduced from 1,177 to 168 lines
- All deploy logic now in DeployerWidget from @nsite/deployer
- App.svelte only renders Navbar, NIP5ABanner, ToolsResources, hero content,
  and DeployerWidget
- Navbar refactored to accept session data as props instead of store imports
- Navbar imports LogoutConfirmModal from @nsite/deployer package
- Navbar dispatches logout event for App.svelte coordination

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add DeployerWidget named export to index.js barrel file
- Add ./components/* sub-path export for direct component imports
- Add 'svelte' top-level field for legacy tool compatibility
- Add 'import' conditions to all sub-path exports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…uild

- qrcode required by NIP46Dialog component (moved to deployer package)
- SPA build succeeds with all @nsite/deployer imports resolving

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create shadow DOM styles for the nsite-deployer custom element:
trigger button with CSS custom property support, full-viewport modal
overlay with backdrop blur, modal container, and close button.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Vanilla HTMLElement class with shadow DOM that renders a trigger button,
opens a full-screen modal overlay, mounts DeployerWidget.svelte inside,
bridges HTML attributes and JS properties to Svelte props, and forwards
all 6 Svelte-dispatched events as composed CustomEvents.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Register nsite-deployer custom element via customElements.define with
double-registration guard. Export NsiteDeployerElement for ESM consumers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Test page validates all 5 success criteria: single script tag loading,
trigger button rendering, custom trigger-label attribute, event
observation via addEventListener, and programmatic property setting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dskvr dskvr force-pushed the enhance/decouple-deployer branch from 4e1f694 to fc676b9 Compare March 26, 2026 10:40
This PR introduces a root package.json (npm workspace for deployer).
nodeModulesDir: "none" prevents it from interfering with Deno's npm
resolution. CI needs deno install before build to cache npm packages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dskvr dskvr force-pushed the enhance/decouple-deployer branch from fc676b9 to 7a31df3 Compare March 26, 2026 10:47
@dskvr
Copy link
Copy Markdown
Contributor Author

dskvr commented Apr 10, 2026

superceded by #42

@dskvr dskvr closed this Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant