FROM node:22-bookworm-slim AS builder

ENV PNPM_HOME=/pnpm
ENV PATH="${PNPM_HOME}:${PATH}"

WORKDIR /workspace

RUN corepack enable

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json tsconfig.base.json ./
COPY apps/api/package.json apps/api/package.json
COPY packages/adapters/package.json packages/adapters/package.json
COPY packages/api/package.json packages/api/package.json
COPY packages/compute/package.json packages/compute/package.json
COPY packages/core/package.json packages/core/package.json
COPY packages/database/package.json packages/database/package.json
COPY packages/dify-datasource-runtime-client/package.json packages/dify-datasource-runtime-client/package.json
COPY packages/dify-model-runtime-client/package.json packages/dify-model-runtime-client/package.json
COPY packages/embeddings/package.json packages/embeddings/package.json
COPY packages/generation/package.json packages/generation/package.json
COPY packages/parsers/package.json packages/parsers/package.json

RUN pnpm install --frozen-lockfile --filter @knowledge/api-app...

COPY apps/api apps/api
COPY packages/adapters packages/adapters
COPY packages/api packages/api
COPY packages/compute packages/compute
COPY packages/core packages/core
COPY packages/database packages/database
COPY packages/dify-datasource-runtime-client packages/dify-datasource-runtime-client
COPY packages/dify-model-runtime-client packages/dify-model-runtime-client
COPY packages/embeddings packages/embeddings
COPY packages/generation packages/generation
COPY packages/parsers packages/parsers

RUN pnpm --filter @knowledge/api-app build:prod

# sharp loads a platform-specific native module at runtime. The API bundle keeps
# sharp external, so copy its resolved production dependency closure instead of
# assuming esbuild can embed the native .node and libvips artifacts.
RUN sharp_runtime_source="$(dirname "$(realpath apps/api/node_modules/sharp)")" \
    && mkdir -p /runtime/node_modules \
    && cp -LR "${sharp_runtime_source}/." /runtime/node_modules/

FROM node:22-bookworm-slim

ENV NODE_ENV=production \
    KNOWLEDGE_PDF_RASTERIZER=poppler \
    KNOWLEDGE_PDF_RASTERIZER_DPI=144 \
    KNOWLEDGE_PDF_RASTERIZER_THUMBNAIL_DPI=48 \
    KNOWLEDGE_PDF_RASTERIZER_TIMEOUT_MS=30000 \
    KNOWLEDGE_PDF_RASTERIZER_MAX_ASSETS=500 \
    KNOWLEDGE_PDF_RASTERIZER_MAX_CONCURRENCY=2

WORKDIR /workspace

# PDF image elements are rasterized outside Unstructured. Keep Poppler in the
# final image and fail the build if the executable is not usable on the target
# platform. Deployments can set KNOWLEDGE_PDF_RASTERIZER=off as a kill switch.
RUN apt-get update \
    && apt-get install --yes --no-install-recommends poppler-utils \
    && rm -rf /var/lib/apt/lists/* \
    && command -v pdftoppm >/dev/null \
    && pdftoppm -v >/dev/null 2>&1

COPY --from=builder /workspace/apps/api/dist/server.mjs ./server.mjs
COPY --from=builder /workspace/apps/api/dist/migrate.mjs ./migrate.mjs
COPY --from=builder /runtime/node_modules ./node_modules

# Fail the image build if the target platform's sharp binary or libvips payload
# is absent. Importing the JavaScript wrapper alone is not sufficient.
RUN node --input-type=module --eval "const sharp = (await import('sharp')).default; const { data, info } = await sharp({ create: { width: 1, height: 1, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } } }).png().toBuffer({ resolveWithObject: true }); if (data.byteLength < 1 || info.format !== 'png' || info.width !== 1 || info.height !== 1) throw new Error('sharp native runtime smoke failed')"

EXPOSE 8787

USER node

CMD ["node", "server.mjs"]
