diff --git a/.changeset/hip-donkeys-jog.md b/.changeset/hip-donkeys-jog.md new file mode 100644 index 0000000..dbd08f6 --- /dev/null +++ b/.changeset/hip-donkeys-jog.md @@ -0,0 +1,7 @@ +--- +'@spur.us/monocle-backend': minor +'@spur.us/monocle-nextjs': minor +'@spur.us/monocle-react': minor +--- + +Allow overriding of Monocle domain diff --git a/package.json b/package.json index 4d3230e..177dd63 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "release:canary": "changeset publish --tag canary", "test": "turbo run test", "version-packages": "changeset version && pnpm install --lockfile-only --engine-strict=false", - "version-packages:canary": "./scripts/canary.mjs", + "version-packages:canary": "changeset version --snapshot canary", "yalc:all": "for d in packages/*/; do echo $d; cd $d; pnpm yalc push --replace --sig; cd '../../'; done" }, "devDependencies": { @@ -41,8 +41,7 @@ "typescript-eslint": "^8.31.0", "vitest": "^3.1.2", "yalc": "1.0.0-pre.53", - "yaml": "^2.7.1", - "zx": "catalog:repo" + "yaml": "^2.7.1" }, "packageManager": "pnpm@10.8.0", "engines": { diff --git a/packages/monocle-backend/src/__tests__/monocle-client.test.ts b/packages/monocle-backend/src/__tests__/monocle-client.test.ts index ee53033..cbddebc 100644 --- a/packages/monocle-backend/src/__tests__/monocle-client.test.ts +++ b/packages/monocle-backend/src/__tests__/monocle-client.test.ts @@ -15,7 +15,7 @@ vi.mock('jose', () => ({ describe('MonocleClient', () => { const mockSecretKey = 'test-secret-key'; - const mockBaseUrl = 'https://api.test.com'; + const mockBaseDomain = 'test.com'; const mockEncryptedAssessment = 'encrypted-data'; const mockDecryptedAssessment: MonocleAssessment = { vpn: false, @@ -38,7 +38,7 @@ describe('MonocleClient', () => { beforeEach(() => { client = createMonocleClient({ secretKey: mockSecretKey, - baseUrl: mockBaseUrl, + baseDomain: mockBaseDomain, }); vi.clearAllMocks(); }); @@ -47,7 +47,7 @@ describe('MonocleClient', () => { it('should throw error when secret key is missing', () => { expect(() => createMonocleClient({ - baseUrl: mockBaseUrl, + baseUrl: mockBaseDomain, // @ts-expect-error Testing missing secretKey secretKey: undefined, }) @@ -66,7 +66,7 @@ describe('MonocleClient', () => { const result = await client.decryptAssessment(mockEncryptedAssessment); expect(global.fetch).toHaveBeenCalledWith( - `${mockBaseUrl}/api/v1/assessment`, + `https://decrypt.${mockBaseDomain}/api/v1/assessment`, { method: 'POST', headers: { diff --git a/packages/monocle-backend/src/constants.ts b/packages/monocle-backend/src/constants.ts index 9c87bce..4c75d8d 100644 --- a/packages/monocle-backend/src/constants.ts +++ b/packages/monocle-backend/src/constants.ts @@ -1,2 +1,2 @@ -export const API_URL = 'https://decrypt.mcl.spur.us'; +export const BASE_DOMAIN = 'mcl.spur.us'; export const USER_AGENT = `${PACKAGE_NAME}@${PACKAGE_VERSION}`; diff --git a/packages/monocle-backend/src/monocleClient.ts b/packages/monocle-backend/src/monocleClient.ts index 8aa3a0e..25b0405 100644 --- a/packages/monocle-backend/src/monocleClient.ts +++ b/packages/monocle-backend/src/monocleClient.ts @@ -1,6 +1,6 @@ import { MonocleAssessment } from '@spur.us/types'; import * as jose from 'jose'; -import { API_URL, USER_AGENT } from './constants.js'; +import { BASE_DOMAIN, USER_AGENT } from './constants.js'; import { MonocleOptions } from './types.js'; import { MonocleAPIError, @@ -24,7 +24,7 @@ export class MonocleClient { /** The secret key used for API authentication */ private secretKey: string; /** The base URL for API requests */ - private baseUrl: string; + private decryptApiUrl: string; /** * Creates a new MonocleClient instance @@ -37,7 +37,7 @@ export class MonocleClient { }); } this.secretKey = options.secretKey; - this.baseUrl = options.baseUrl || API_URL; + this.decryptApiUrl = `https://decrypt.${options.baseDomain || BASE_DOMAIN}`; } /** @@ -67,7 +67,7 @@ export class MonocleClient { encryptedAssessment: string ): Promise { try { - const response = await fetch(`${this.baseUrl}/api/v1/assessment`, { + const response = await fetch(`${this.decryptApiUrl}/api/v1/assessment`, { method: 'POST', headers: { 'Content-Type': 'text/plain; charset=utf-8', diff --git a/packages/monocle-backend/src/types.ts b/packages/monocle-backend/src/types.ts index 0216d4c..f6ba8e1 100644 --- a/packages/monocle-backend/src/types.ts +++ b/packages/monocle-backend/src/types.ts @@ -4,6 +4,6 @@ export interface MonocleOptions { /** The secret key used for authentication with the Monocle API */ secretKey: string; - /** Optional base URL for the Monocle API. Defaults to the standard API URL if not provided */ - baseUrl?: string; + /** Optional base domain for the Monocle API. Defaults to `mcl.spur.us` if not provided */ + baseDomain?: string; } diff --git a/packages/monocle-nextjs/src/client-boundary/MonocleProvider.tsx b/packages/monocle-nextjs/src/client-boundary/MonocleProvider.tsx index e28fd48..c6ec7d8 100644 --- a/packages/monocle-nextjs/src/client-boundary/MonocleProvider.tsx +++ b/packages/monocle-nextjs/src/client-boundary/MonocleProvider.tsx @@ -7,13 +7,20 @@ import { NextMonocleProviderProps } from '../types'; export const MonocleProvider = ({ children, publishableKey, + domain, ...rest }: NextMonocleProviderProps) => { const safePublishableKey = publishableKey || process.env.NEXT_PUBLIC_MONOCLE_PUBLISHABLE_KEY || ''; + const safeDomain = + domain || process.env.NEXT_PUBLIC_MONOCLE_DOMAIN || undefined; return ( - + {children} ); diff --git a/packages/monocle-nextjs/src/server/constants.ts b/packages/monocle-nextjs/src/server/constants.ts index 4734888..b023af6 100644 --- a/packages/monocle-nextjs/src/server/constants.ts +++ b/packages/monocle-nextjs/src/server/constants.ts @@ -1 +1,2 @@ +export const DOMAIN = process.env.NEXT_PUBLIC_MONOCLE_DOMAIN || undefined; export const SECRET_KEY = process.env.MONOCLE_SECRET_KEY || ''; diff --git a/packages/monocle-nextjs/src/server/monocleClient.ts b/packages/monocle-nextjs/src/server/monocleClient.ts index f35f951..68d993d 100644 --- a/packages/monocle-nextjs/src/server/monocleClient.ts +++ b/packages/monocle-nextjs/src/server/monocleClient.ts @@ -1,9 +1,10 @@ import { createMonocleClient } from '@spur.us/monocle-backend'; -import { SECRET_KEY } from './constants'; +import { DOMAIN, SECRET_KEY } from './constants'; const monocleClient = async () => { return createMonocleClient({ secretKey: SECRET_KEY, + baseDomain: DOMAIN, }); }; diff --git a/packages/monocle-react/src/constants.ts b/packages/monocle-react/src/constants.ts new file mode 100644 index 0000000..d8104ef --- /dev/null +++ b/packages/monocle-react/src/constants.ts @@ -0,0 +1 @@ +export const DOMAIN = 'mcl.spur.us'; diff --git a/packages/monocle-react/src/contexts/MonocleProvider.tsx b/packages/monocle-react/src/contexts/MonocleProvider.tsx index 97ae169..08990ab 100644 --- a/packages/monocle-react/src/contexts/MonocleProvider.tsx +++ b/packages/monocle-react/src/contexts/MonocleProvider.tsx @@ -1,7 +1,7 @@ import React, { createContext, useContext, useEffect, useState } from 'react'; import { withMaxAllowedInstancesGuard } from '../utils'; import { MonocleProviderProps } from '../types'; - +import { DOMAIN } from '../constants'; interface MonocleContextType { assessment: string | undefined; refresh: () => void; @@ -14,6 +14,7 @@ const MonocleContext = createContext(null); const MonocleProviderComponent: React.FC = ({ children, publishableKey, + domain = DOMAIN, }) => { const [assessment, setAssessment] = useState(undefined); const [isLoading, setIsLoading] = useState(true); @@ -37,7 +38,7 @@ const MonocleProviderComponent: React.FC = ({ const script = document.createElement('script'); script.id = '_mcl'; script.async = true; - script.src = `https://mcl.spur.us/d/mcl.js?tk=${publishableKey}`; + script.src = `https://${domain}/d/mcl.js?tk=${publishableKey}`; script.onload = () => { resolve(); }; diff --git a/packages/monocle-react/src/types.ts b/packages/monocle-react/src/types.ts index 8c7dfdf..042bfae 100644 --- a/packages/monocle-react/src/types.ts +++ b/packages/monocle-react/src/types.ts @@ -7,4 +7,6 @@ export interface MonocleProviderProps { children: React.ReactNode; /** The publishable key used for authentication with Monocle. */ publishableKey: string; + /** Optional base domain for the Monocle API. Defaults to `mcl.spur.us` if not provided */ + domain?: string; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72fb245..7ca33db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,13 +5,6 @@ settings: excludeLinksFromLockfile: false catalogs: - peer-react: - react: - specifier: ^18.0.0 || ^19.0.0 || ^19.0.0-0 - version: 19.1.0 - react-dom: - specifier: ^18.0.0 || ^19.0.0 || ^19.0.0-0 - version: 19.1.0 react: '@types/react': specifier: 18.3.20 @@ -20,18 +13,12 @@ catalogs: specifier: 18.3.6 version: 18.3.6 repo: - tslib: - specifier: 2.8.1 - version: 2.8.1 tsup: specifier: 8.4.0 version: 8.4.0 typescript: specifier: 5.8.3 version: 5.8.3 - zx: - specifier: 8.4.1 - version: 8.4.1 patchedDependencies: yalc@1.0.0-pre.53: @@ -111,9 +98,6 @@ importers: yaml: specifier: ^2.7.1 version: 2.7.1 - zx: - specifier: catalog:repo - version: 8.4.1 packages/monocle-backend: dependencies: @@ -2747,11 +2731,6 @@ packages: resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} engines: {node: '>=12.20'} - zx@8.4.1: - resolution: {integrity: sha512-1Cb+Tfwt/daKV6wckBeDbB6h3IMauqj9KWp+EcbYzi9doeJeIHCktxp/yWspXOXRdoUzBCQSKoUgm3g8r9fz5A==} - engines: {node: '>= 12.17.0'} - hasBin: true - snapshots: '@adobe/css-tools@4.4.2': {} @@ -5267,5 +5246,3 @@ snapshots: yocto-queue@0.1.0: {} yocto-queue@1.2.1: {} - - zx@8.4.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1da9317..6c6cd6c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -16,4 +16,3 @@ catalogs: tslib: 2.8.1 tsup: 8.4.0 typescript: 5.8.3 - zx: 8.4.1 diff --git a/scripts/canary.mjs b/scripts/canary.mjs deleted file mode 100755 index 4608398..0000000 --- a/scripts/canary.mjs +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env zx - -import { $, echo } from 'zx'; - -const CHANGESET_CONFIG = '.changeset/config.json'; -const snapshot = `--- -'@spur.us/monocle-backend': patch -'@spur.us/monocle-nextjs': patch -'@spur.us/monocle-react': patch ---- - -Canary release -`; - -await $`pnpm dlx json -I -f ${CHANGESET_CONFIG} -e "this.changelog = false"`; - -try { - // exit pre-release mode if we're in it - await $`pnpm changeset pre exit`; - // bump the version of all affected packages - // this will remove the prerelease versions - // but will also clear the changeset .md files - await $`pnpm changeset version`; - // generate a temp .md file that indicates that all packages have changes - // in order to force a snapshot release - await $`touch .changeset/snap.md && echo ${snapshot} > .changeset/snap.md`; -} catch { - // otherwise, do nothing -} - -const res = await $`pnpm changeset version --snapshot canary`; -const success = !res.stderr.includes('No unreleased changesets found'); - -await $`git checkout HEAD -- ${CHANGESET_CONFIG}`; - -if (success) { - echo('success=1'); -} else { - echo('success=0'); -}