Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 316c03869a | |||
| 63d2acfab5 | |||
| bdeae0aca6 | |||
| 47c70a16f1 | |||
| b96d44bf6d | |||
| 73b60f14a9 |
7
.changeset/resilient-build-scripts.md
Normal file
7
.changeset/resilient-build-scripts.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@mintel/monorepo": patch
|
||||
"acquisition-manager": patch
|
||||
"feedback-commander": patch
|
||||
---
|
||||
|
||||
fix: make directus extension build scripts more resilient
|
||||
@@ -1,5 +1,5 @@
|
||||
# Project
|
||||
IMAGE_TAG=v1.7.3
|
||||
IMAGE_TAG=v1.7.10
|
||||
PROJECT_NAME=sample-website
|
||||
PROJECT_COLOR=#82ed20
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sample-website",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"pino-pretty": "^13.1.3",
|
||||
"require-in-the-middle": "^8.0.1"
|
||||
},
|
||||
"version": "1.7.9",
|
||||
"version": "1.7.10",
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"next": "16.1.6",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "acquisition-manager",
|
||||
"description": "Custom High-Fidelity Acquisition Management for Directus",
|
||||
"icon": "account_balance_wallet",
|
||||
"version": "1.0.0",
|
||||
"version": "1.7.10",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
{
|
||||
"name": "acquisition",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"directus:extension": {
|
||||
"type": "endpoint",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "^11.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build.js",
|
||||
"dev": "node build.js --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"esbuild": "^0.25.0",
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4"
|
||||
}
|
||||
}
|
||||
"name": "acquisition",
|
||||
"version": "1.7.10",
|
||||
"type": "module",
|
||||
"directus:extension": {
|
||||
"type": "endpoint",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "^11.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build.js",
|
||||
"dev": "node build.js --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"esbuild": "^0.25.0",
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/cli",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/cms-infra",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -9,4 +9,4 @@
|
||||
"logs": "docker compose logs -f",
|
||||
"build:extensions": "../../scripts/sync-extensions.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "customer-manager",
|
||||
"description": "Custom High-Fidelity Customer & Company Management for Directus",
|
||||
"icon": "supervisor_account",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
@@ -27,4 +27,4 @@
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/eslint-config",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "feedback-commander",
|
||||
"description": "Custom High-Fidelity Feedback Management Extension for Directus",
|
||||
"icon": "view_kanban",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/gatekeeper",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.12",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -33,4 +33,4 @@
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ export async function GET(req: NextRequest) {
|
||||
|
||||
// 1. URL Parameter Bypass (for automated tests/staging)
|
||||
const originalUrl = req.headers.get("x-forwarded-uri") || "/";
|
||||
|
||||
console.log(`[Verify] Check: ${originalUrl} | Cookie: ${session ? "Found" : "Missing"}`);
|
||||
const host =
|
||||
req.headers.get("x-forwarded-host") || req.headers.get("host") || "";
|
||||
const proto = req.headers.get("x-forwarded-proto") || "https";
|
||||
@@ -54,15 +56,17 @@ export async function GET(req: NextRequest) {
|
||||
if (session?.value) {
|
||||
if (session.value === password) {
|
||||
isAuthenticated = true;
|
||||
console.log(`[Verify] Legacy password match`);
|
||||
} else {
|
||||
try {
|
||||
const payload = JSON.parse(session.value);
|
||||
if (payload.identity) {
|
||||
isAuthenticated = true;
|
||||
identity = payload.identity;
|
||||
console.log(`[Verify] Identity verified: ${identity}`);
|
||||
}
|
||||
} catch (_e) {
|
||||
// Fallback or old format
|
||||
console.log(`[Verify] JSON Parse failed for cookie: ${session.value.substring(0, 10)}...`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ export default async function LoginPage({ searchParams }: LoginPageProps) {
|
||||
async function login(formData: FormData) {
|
||||
"use server";
|
||||
|
||||
const email = formData.get("email") as string;
|
||||
const password = formData.get("password") as string;
|
||||
const email = (formData.get("email") as string || "").trim();
|
||||
const password = (formData.get("password") as string || "").trim();
|
||||
|
||||
const expectedCode = process.env.GATEKEEPER_PASSWORD || "mintel";
|
||||
const adminEmail = process.env.DIRECTUS_ADMIN_EMAIL;
|
||||
@@ -31,19 +31,19 @@ export default async function LoginPage({ searchParams }: LoginPageProps) {
|
||||
let userIdentity = "";
|
||||
let userCompany: any = null;
|
||||
|
||||
// 1. Check Global Admin (from ENV)
|
||||
if (
|
||||
// 1. Check Generic Code (Guest) - High Priority to prevent autofill traps
|
||||
if (password === expectedCode) {
|
||||
userIdentity = "Guest";
|
||||
}
|
||||
// 2. Check Global Admin (from ENV)
|
||||
else if (
|
||||
adminEmail &&
|
||||
adminPassword &&
|
||||
email === adminEmail &&
|
||||
password === adminPassword
|
||||
email === adminEmail.trim() &&
|
||||
password === adminPassword.trim()
|
||||
) {
|
||||
userIdentity = "Admin";
|
||||
}
|
||||
// 2. Check Generic Code (Guest)
|
||||
else if (!email && password === expectedCode) {
|
||||
userIdentity = "Guest";
|
||||
}
|
||||
// 3. Check Lightweight Client Users (dedicated collection)
|
||||
if (email && password && process.env.INFRA_DIRECTUS_URL) {
|
||||
try {
|
||||
@@ -116,6 +116,7 @@ export default async function LoginPage({ searchParams }: LoginPageProps) {
|
||||
}
|
||||
|
||||
if (userIdentity) {
|
||||
console.log(`[Login] Success: ${userIdentity} | Redirect: ${targetRedirect}`);
|
||||
const cookieStore = await cookies();
|
||||
// Store identity in the cookie (simplified for now, ideally signed)
|
||||
const sessionValue = JSON.stringify({
|
||||
@@ -126,6 +127,8 @@ export default async function LoginPage({ searchParams }: LoginPageProps) {
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
|
||||
console.log(`[Login] Setting Cookie: ${authCookieName} | Domain: ${cookieDomain || "Default"}`);
|
||||
|
||||
cookieStore.set(authCookieName, sessionValue, {
|
||||
httpOnly: true,
|
||||
secure: !isDev,
|
||||
@@ -136,6 +139,7 @@ export default async function LoginPage({ searchParams }: LoginPageProps) {
|
||||
});
|
||||
redirect(targetRedirect);
|
||||
} else {
|
||||
console.log(`[Login] Failed for inputs. Redirecting back with error.`);
|
||||
redirect(`/login?error=1&redirect=${encodeURIComponent(targetRedirect)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/husky-config",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,38 +1,13 @@
|
||||
# Step 1: Builder image
|
||||
FROM node:20-alpine AS builder
|
||||
# Step 1: Base image for Next.js builds
|
||||
FROM node:20-alpine
|
||||
RUN apk add --no-cache libc6-compat curl
|
||||
|
||||
# Enable pnpm
|
||||
RUN corepack enable pnpm && \
|
||||
corepack prepare pnpm@10.2.0 --activate
|
||||
|
||||
WORKDIR /app
|
||||
RUN corepack enable pnpm
|
||||
|
||||
# Step 2: Install dependencies
|
||||
ENV NPM_TOKEN=placeholder
|
||||
# Copy manifest files specifically for better layer caching
|
||||
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc ./
|
||||
# Copy package manifest files individually to preserve directory structure
|
||||
COPY packages/cli/package.json ./packages/cli/
|
||||
COPY packages/cms-infra/package.json ./packages/cms-infra/
|
||||
COPY packages/customer-manager/package.json ./packages/customer-manager/
|
||||
COPY packages/eslint-config/package.json ./packages/eslint-config/
|
||||
COPY packages/feedback-commander/package.json ./packages/feedback-commander/
|
||||
COPY packages/gatekeeper/package.json ./packages/gatekeeper/
|
||||
COPY packages/husky-config/package.json ./packages/husky-config/
|
||||
COPY packages/infra/package.json ./packages/infra/
|
||||
COPY packages/mail/package.json ./packages/mail/
|
||||
COPY packages/next-config/package.json ./packages/next-config/
|
||||
COPY packages/next-feedback/package.json ./packages/next-feedback/
|
||||
COPY packages/next-observability/package.json ./packages/next-observability/
|
||||
COPY packages/next-utils/package.json ./packages/next-utils/
|
||||
COPY packages/observability/package.json ./packages/observability/
|
||||
COPY packages/tsconfig/package.json ./packages/tsconfig/
|
||||
# packages/ui does not have a package.json
|
||||
|
||||
# Use a secret for NPM_TOKEN and a standardized cache mount
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
|
||||
--mount=type=secret,id=NPM_TOKEN \
|
||||
export NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) && \
|
||||
pnpm config set store-dir /pnpm/store && \
|
||||
pnpm i --frozen-lockfile
|
||||
|
||||
# Step 3: Build shared packages
|
||||
COPY . .
|
||||
RUN pnpm --filter "./packages/*" -r build
|
||||
# Final environment
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/infra",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
90
packages/infra/scripts/wait-for-upstream.sh
Executable file
90
packages/infra/scripts/wait-for-upstream.sh
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# wait-for-upstream.sh
|
||||
# Usage: ./wait-for-upstream.sh <org/repo> <version_tag> [poll_interval_sec]
|
||||
|
||||
REPO=$1
|
||||
TAG=$2
|
||||
INTERVAL=${3:-30}
|
||||
MAX_RETRIES=40 # ~20 minutes default
|
||||
|
||||
if [[ -z "$REPO" || -z "$TAG" ]]; then
|
||||
echo "❌ Error: REPO and TAG are required."
|
||||
echo "Usage: $0 <org/repo> <version_tag>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$GITEA_TOKEN" ]]; then
|
||||
echo "❌ Error: GITEA_TOKEN is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GITEA_API="https://git.infra.mintel.me/api/v1"
|
||||
|
||||
echo "🔎 Searching for upstream release $TAG in $REPO..."
|
||||
|
||||
# 1. Find the run for the specific tag
|
||||
# We look for runs on the specific ref (refs/tags/vX.Y.Z)
|
||||
RUN_QUERY=$(curl -s -H "Authorization: token $GITEA_TOKEN" "$GITEA_API/repos/$REPO/actions/runs?ref=refs/tags/$TAG")
|
||||
|
||||
# Gitea returns a list of runs. We take the latest one by creation date.
|
||||
RUN_ID=$(echo "$RUN_QUERY" | jq -r '.workflow_runs | sort_by(.created_at) | last | .id // empty')
|
||||
|
||||
if [[ -z "$RUN_ID" || "$RUN_ID" == "null" ]]; then
|
||||
echo "ℹ️ No recent action run found for tag $TAG in $REPO."
|
||||
echo "🔎 Checking if tag $TAG exists in the repository..."
|
||||
|
||||
TAG_EXISTS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token $GITEA_TOKEN" "$GITEA_API/repos/$REPO/tags/$TAG")
|
||||
|
||||
if [[ "$TAG_EXISTS" == "200" ]]; then
|
||||
echo "✅ Tag $TAG exists. Assuming it was released successfully in the past."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "⚠️ Warning: Tag $TAG not found either. Upstream might be lagging or the version is invalid."
|
||||
echo " Waiting 15s to see if it appears..."
|
||||
sleep 15
|
||||
|
||||
RUN_QUERY=$(curl -s -H "Authorization: token $GITEA_TOKEN" "$GITEA_API/repos/$REPO/actions/runs?ref=refs/tags/$TAG")
|
||||
RUN_ID=$(echo "$RUN_QUERY" | jq -r '.workflow_runs[0].id // empty')
|
||||
|
||||
if [[ -z "$RUN_ID" || "$RUN_ID" == "null" ]]; then
|
||||
# Final check for tag
|
||||
TAG_EXISTS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token $GITEA_TOKEN" "$GITEA_API/repos/$REPO/tags/$TAG")
|
||||
if [[ "$TAG_EXISTS" == "200" ]]; then
|
||||
echo "✅ Tag $TAG finally detected. Proceeding."
|
||||
exit 0
|
||||
fi
|
||||
echo "❌ Error: Could not find any action run OR tag for $TAG in $REPO."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "⏳ Waiting for upstream run $RUN_ID status..."
|
||||
|
||||
RETRY_COUNT=0
|
||||
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
||||
STATUS_QUERY=$(curl -s -H "Authorization: token $GITEA_TOKEN" "$GITEA_API/repos/$REPO/actions/runs/$RUN_ID")
|
||||
STATUS=$(echo "$STATUS_QUERY" | jq -r '.status')
|
||||
CONCLUSION=$(echo "$STATUS_QUERY" | jq -r '.conclusion')
|
||||
|
||||
echo " - Current Status: $STATUS (Conclusion: $CONCLUSION)"
|
||||
|
||||
if [[ "$STATUS" == "success" || "$CONCLUSION" == "success" ]]; then
|
||||
echo "✅ Upstream release $TAG is READY."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$STATUS" == "failure" || "$CONCLUSION" == "failure" || "$CONCLUSION" == "cancelled" ]]; then
|
||||
echo "❌ Error: Upstream release $TAG FAILED or was CANCELLED."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " - Still working... waiting $INTERVAL seconds (Attempt $((RETRY_COUNT+1))/$MAX_RETRIES)"
|
||||
sleep $INTERVAL
|
||||
RETRY_COUNT=$((RETRY_COUNT+1))
|
||||
done
|
||||
|
||||
echo "❌ Error: Timeout waiting for upstream release $TAG."
|
||||
exit 1
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/mail",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/next-config",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/next-feedback",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/next-observability",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/next-utils",
|
||||
"version": "1.7.15",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/observability",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
{
|
||||
"name": "people-manager",
|
||||
"description": "Custom High-Fidelity People Management for Directus",
|
||||
"icon": "person",
|
||||
"version": "1.0.0",
|
||||
"name": "people-manager",
|
||||
"description": "Custom High-Fidelity People Management for Directus",
|
||||
"icon": "person",
|
||||
"version": "1.7.10",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "People Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "People Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/tsconfig",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
Reference in New Issue
Block a user