deploy: serve desktop installers from container
This commit is contained in:
parent
386ca99889
commit
569d3f140d
@ -1,7 +1,6 @@
|
|||||||
node_modules
|
node_modules
|
||||||
**/node_modules
|
**/node_modules
|
||||||
**/dist
|
**/dist
|
||||||
apps/print
|
|
||||||
.git
|
.git
|
||||||
.env
|
.env
|
||||||
.env.*
|
.env.*
|
||||||
|
|||||||
@ -12,3 +12,4 @@ FIELDLENS_TENANT_ID=fieldlens-production
|
|||||||
WEB_ORIGIN=https://fieldlens.example.invalid
|
WEB_ORIGIN=https://fieldlens.example.invalid
|
||||||
FIELDLENS_PRINT_RELEASE_TAG=fieldlens-print-v0.1.0
|
FIELDLENS_PRINT_RELEASE_TAG=fieldlens-print-v0.1.0
|
||||||
FIELDLENS_PRINT_RELEASE_BASE_URL=https://git.example.invalid/owner/fieldlens/releases/download
|
FIELDLENS_PRINT_RELEASE_BASE_URL=https://git.example.invalid/owner/fieldlens/releases/download
|
||||||
|
FIELDLENS_PRINT_DOWNLOAD_DIR=downloads
|
||||||
|
|||||||
52
Dockerfile
52
Dockerfile
@ -1,3 +1,53 @@
|
|||||||
|
FROM node:24-bookworm AS desktop-build
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
clang \
|
||||||
|
curl \
|
||||||
|
file \
|
||||||
|
libayatana-appindicator3-dev \
|
||||||
|
libssl-dev \
|
||||||
|
libwebkit2gtk-4.1-dev \
|
||||||
|
libxdo-dev \
|
||||||
|
lld \
|
||||||
|
llvm \
|
||||||
|
nsis \
|
||||||
|
patchelf \
|
||||||
|
pkg-config \
|
||||||
|
librsvg2-dev \
|
||||||
|
wget \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||||
|
| sh -s -- -y --profile minimal
|
||||||
|
ENV PATH="/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
|
RUN rustup target add x86_64-pc-windows-msvc \
|
||||||
|
&& cargo install --locked cargo-xwin
|
||||||
|
|
||||||
|
COPY package.json ./
|
||||||
|
COPY apps/api/package.json apps/api/package.json
|
||||||
|
COPY apps/web/package.json apps/web/package.json
|
||||||
|
COPY apps/print/package.json apps/print/package.json
|
||||||
|
COPY packages/contracts/package.json packages/contracts/package.json
|
||||||
|
COPY packages/fieldlens-core/package.json packages/fieldlens-core/package.json
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY apps/print apps/print
|
||||||
|
|
||||||
|
RUN npm run bundle:windows --workspace @fieldlens/print \
|
||||||
|
&& npm run bundle:deb --workspace @fieldlens/print \
|
||||||
|
&& mkdir -p /desktop-artifacts \
|
||||||
|
&& windows_file="$(find apps/print/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis -maxdepth 1 -type f -name '*-setup.exe' -print -quit)" \
|
||||||
|
&& linux_file="$(find apps/print/src-tauri/target/release/bundle/deb -maxdepth 1 -type f -name '*.deb' -print -quit)" \
|
||||||
|
&& test -n "$windows_file" \
|
||||||
|
&& test -n "$linux_file" \
|
||||||
|
&& cp "$windows_file" /desktop-artifacts/fieldlens-print-windows-x64-setup.exe \
|
||||||
|
&& cp "$linux_file" /desktop-artifacts/fieldlens-print-linux-x64.deb
|
||||||
|
|
||||||
FROM node:24-alpine AS build
|
FROM node:24-alpine AS build
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
@ -29,6 +79,7 @@ WORKDIR /app
|
|||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV PORT=3000
|
ENV PORT=3000
|
||||||
ENV STATIC_DIR=/app/web
|
ENV STATIC_DIR=/app/web
|
||||||
|
ENV FIELDLENS_PRINT_DOWNLOAD_DIR=/app/downloads
|
||||||
|
|
||||||
COPY --from=build /workspace/package.json /app/package.json
|
COPY --from=build /workspace/package.json /app/package.json
|
||||||
COPY --from=build /workspace/node_modules /app/node_modules
|
COPY --from=build /workspace/node_modules /app/node_modules
|
||||||
@ -38,6 +89,7 @@ COPY --from=build /workspace/migrations /app/migrations
|
|||||||
COPY --from=build /workspace/packages/contracts/package.json /app/packages/contracts/package.json
|
COPY --from=build /workspace/packages/contracts/package.json /app/packages/contracts/package.json
|
||||||
COPY --from=build /workspace/packages/contracts/dist /app/packages/contracts/dist
|
COPY --from=build /workspace/packages/contracts/dist /app/packages/contracts/dist
|
||||||
COPY --from=build /workspace/apps/web/dist /app/web
|
COPY --from=build /workspace/apps/web/dist /app/web
|
||||||
|
COPY --from=desktop-build /desktop-artifacts /app/downloads
|
||||||
|
|
||||||
USER node
|
USER node
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|||||||
@ -13,3 +13,4 @@ WEB_ORIGIN=http://localhost:5173
|
|||||||
STATIC_DIR=
|
STATIC_DIR=
|
||||||
FIELDLENS_PRINT_RELEASE_TAG=fieldlens-print-v0.1.0
|
FIELDLENS_PRINT_RELEASE_TAG=fieldlens-print-v0.1.0
|
||||||
FIELDLENS_PRINT_RELEASE_BASE_URL=https://git.example.invalid/owner/fieldlens/releases/download
|
FIELDLENS_PRINT_RELEASE_BASE_URL=https://git.example.invalid/owner/fieldlens/releases/download
|
||||||
|
FIELDLENS_PRINT_DOWNLOAD_DIR=downloads
|
||||||
|
|||||||
@ -18,6 +18,5 @@ export const config = {
|
|||||||
logLevel: process.env.LOG_LEVEL?.trim() || 'info',
|
logLevel: process.env.LOG_LEVEL?.trim() || 'info',
|
||||||
webOrigin: process.env.WEB_ORIGIN?.trim() || 'http://localhost:5173',
|
webOrigin: process.env.WEB_ORIGIN?.trim() || 'http://localhost:5173',
|
||||||
staticDir: process.env.STATIC_DIR?.trim() || '',
|
staticDir: process.env.STATIC_DIR?.trim() || '',
|
||||||
printReleaseTag: process.env.FIELDLENS_PRINT_RELEASE_TAG?.trim() || 'fieldlens-print-v0.1.0',
|
printDownloadDir: process.env.FIELDLENS_PRINT_DOWNLOAD_DIR?.trim() || 'downloads',
|
||||||
printReleaseBaseUrl: process.env.FIELDLENS_PRINT_RELEASE_BASE_URL?.trim() || 'https://git.arrowstack.dev/Admin/fieldlens/releases/download',
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import cors from 'cors'
|
import cors from 'cors'
|
||||||
import express from 'express'
|
import express, { type Response } from 'express'
|
||||||
import helmet from 'helmet'
|
import helmet from 'helmet'
|
||||||
import { FIELDLENS_SCHEMA_VERSION, isSyncRequest, type DeviceRegistration } from '@fieldlens/contracts'
|
import { FIELDLENS_SCHEMA_VERSION, isSyncRequest, type DeviceRegistration } from '@fieldlens/contracts'
|
||||||
import { getAccessRequest, listAccessRequests, requestAccess, reviewAccessRequest } from './access.js'
|
import { getAccessRequest, listAccessRequests, requestAccess, reviewAccessRequest } from './access.js'
|
||||||
@ -61,14 +61,33 @@ app.get('/api/health/live', (_req, res) => {
|
|||||||
res.json({ status: 'live', version: process.env.FIELDLENS_VERSION ?? 'dev' })
|
res.json({ status: 'live', version: process.env.FIELDLENS_VERSION ?? 'dev' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const desktopDownloadDir = path.resolve(config.printDownloadDir)
|
||||||
|
|
||||||
|
function sendDesktopDownload(res: Response, filename: string) {
|
||||||
|
const file = path.join(desktopDownloadDir, filename)
|
||||||
|
res.setHeader('Cache-Control', 'public, max-age=300')
|
||||||
|
res.download(file, filename, (error) => {
|
||||||
|
if (!error || res.headersSent) return
|
||||||
|
log('error', 'desktop_download_missing', { filename, file })
|
||||||
|
res.status(404).json({ error: 'desktop_download_unavailable' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/downloads/fieldlens-print-windows-x64-setup.exe', (_req, res) => {
|
||||||
|
sendDesktopDownload(res, 'fieldlens-print-windows-x64-setup.exe')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/downloads/fieldlens-print-linux-x64.deb', (_req, res) => {
|
||||||
|
sendDesktopDownload(res, 'fieldlens-print-linux-x64.deb')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Backward-compatible aliases used by the first downloads page.
|
||||||
app.get('/downloads/fieldlens-print/windows-x64', (_req, res) => {
|
app.get('/downloads/fieldlens-print/windows-x64', (_req, res) => {
|
||||||
res.setHeader('Cache-Control', 'no-store')
|
sendDesktopDownload(res, 'fieldlens-print-windows-x64-setup.exe')
|
||||||
res.redirect(302, `${config.printReleaseBaseUrl.replace(/\/$/, '')}/${encodeURIComponent(config.printReleaseTag)}/fieldlens-print-windows-x64-setup.exe`)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/downloads/fieldlens-print/linux-x64.deb', (_req, res) => {
|
app.get('/downloads/fieldlens-print/linux-x64.deb', (_req, res) => {
|
||||||
res.setHeader('Cache-Control', 'no-store')
|
sendDesktopDownload(res, 'fieldlens-print-linux-x64.deb')
|
||||||
res.redirect(302, `${config.printReleaseBaseUrl.replace(/\/$/, '')}/${encodeURIComponent(config.printReleaseTag)}/fieldlens-print-linux-x64.deb`)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/api/health/ready', async (_req, res) => {
|
app.get('/api/health/ready', async (_req, res) => {
|
||||||
|
|||||||
@ -2,13 +2,13 @@ import { ArrowLeft, Download, Monitor, Terminal } from 'lucide-react'
|
|||||||
|
|
||||||
const downloads = [
|
const downloads = [
|
||||||
{
|
{
|
||||||
href: '/downloads/fieldlens-print/windows-x64',
|
href: '/downloads/fieldlens-print-windows-x64-setup.exe',
|
||||||
label: 'Windows',
|
label: 'Windows',
|
||||||
detail: 'x64 · NSIS installer · current-user install',
|
detail: 'x64 · NSIS installer · current-user install',
|
||||||
icon: Monitor,
|
icon: Monitor,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/downloads/fieldlens-print/linux-x64.deb',
|
href: '/downloads/fieldlens-print-linux-x64.deb',
|
||||||
label: 'Linux',
|
label: 'Linux',
|
||||||
detail: 'x64 · Debian / Ubuntu .deb package',
|
detail: 'x64 · Debian / Ubuntu .deb package',
|
||||||
icon: Terminal,
|
icon: Terminal,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user