Skip to content

Commit

Permalink
wip: domain handling -d
Browse files Browse the repository at this point in the history
  • Loading branch information
arpowers committed Mar 19, 2024
1 parent 669ff32 commit 255fb3e
Show file tree
Hide file tree
Showing 34 changed files with 777 additions and 459 deletions.
2 changes: 2 additions & 0 deletions @fiction/core/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ export type RunVars = {
RUNTIME_VERSION: string
SERVER_PORT: string
SUBDOMAIN: string
ORIGINAL_HOST: string
USER_AGENT: string
ORIGIN: string
URL: string
ALL_HEADERS: string
}

export type StandardServices = {
Expand Down
12 changes: 6 additions & 6 deletions @fiction/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@
"dayjs": "^1.11.10",
"deepmerge": "^4.3.1",
"domhandler": "^5.0.3",
"dompurify": "^3.0.9",
"dompurify": "^3.0.10",
"dotenv": "^16.4.5",
"enquirer": "^2.4.1",
"es-module-lexer": "^1.4.1",
"es-module-lexer": "^1.4.2",
"esbuild": "^0.20.2",
"events": "^3.3.0",
"execa": "^8.0.1",
Expand All @@ -72,7 +72,7 @@
"google-auth-library": "^9.7.0",
"google-one-tap": "^1.0.6",
"handlebars": "^4.7.8",
"happy-dom": "^13.10.1",
"happy-dom": "^14.0.0",
"helmet": "^7.1.0",
"highlight.js": "^11.9.0",
"html-minifier": "^4.0.0",
Expand Down Expand Up @@ -137,7 +137,7 @@
"zod-to-json-schema": "^3.22.4"
},
"devDependencies": {
"@babel/parser": "^7.24.0",
"@babel/parser": "^7.24.1",
"@playwright/test": "^1.42.1",
"@tailwindcss/forms": "^0.5.7",
"@types/bcrypt": "^5.0.2",
Expand All @@ -154,11 +154,11 @@
"@types/jsonwebtoken": "^9.0.6",
"@types/mime-types": "^2.1.4",
"@types/multer": "^1.4.11",
"@types/node": "^20.11.29",
"@types/node": "^20.11.30",
"@types/nodemailer": "^6.4.14",
"@types/nodemailer-html-to-text": "^3.1.3",
"@types/nodemon": "^1.19.6",
"@types/pg": "^8.11.2",
"@types/pg": "^8.11.3",
"@types/remove-markdown": "^0.3.4",
"@types/request-ip": "^0.0.41",
"@types/semver": "^7.5.8",
Expand Down
26 changes: 20 additions & 6 deletions @fiction/core/plugin-app/plugin-render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { FictionBuild } from '../plugin-build'
import { FictionPlugin } from '../plugin'
import { version } from '../package.json'
import { populateGlobal } from '../utils/globalUtils'
import type { RunVars } from '../inject'
import { getFaviconPath, renderPreloadLinks } from './utils'
import type * as types from './types'
import { FictionSitemap } from './sitemap'
Expand Down Expand Up @@ -596,30 +597,43 @@ export class FictionRender extends FictionPlugin<FictionRenderSettings> {

getRequestVars(args: { request: Request }): Record<string, string> {
const { request } = args

// Extracting protocol (HTTP vs HTTPS)
const protocol = request?.protocol || 'http' // Defaults to 'http' if protocol is not available

// Extracting subdomain
const subdomains = request?.subdomains || []
const subdomain = subdomains?.length > 0 ? subdomains.join('.') : ''
const subdomain = subdomains.length > 0 ? subdomains.join('.') : ''

// Extracting other relevant information
const host = request?.get('host') // Hostname with port if applicable
const hostname = request?.hostname
const ip = request?.ip // IP address of the request
const userAgent = request?.get('User-Agent') // User-Agent header

// For debugging: concatenate all headers into a single string
const allHeaders = request?.headers
? Object.entries(request.headers)
.map(([key, value]) => `${key}: ${String(value)}`)
.join(', ')
: ''

const originalHost = request?.get('X-Original-Host') || ''

const add = { APP_INSTANCE: this.fictionApp.appInstanceId }

const ORIGIN = `${protocol}://${host}`

const requestVars = {
const requestVars: Partial<RunVars> = {
...this.fictionEnv.getRenderedEnvVars(),
PROTOCOL: protocol,
SUBDOMAIN: subdomain,
HOST: host,
IP_ADDRESS: ip,
USER_AGENT: userAgent,
HOSTNAME: request?.hostname,
ORIGINAL_HOST: originalHost,
HOST: host || '',
HOSTNAME: hostname,
IP_ADDRESS: ip || '',
USER_AGENT: userAgent || '',
ALL_HEADERS: allHeaders,
PATHNAME: request?.originalUrl,
ORIGIN,
URL: `${ORIGIN}${request?.originalUrl}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,24 @@ describe('rendering tests', () => {
expect(html).toContain('type="application/json"')
})

it('generates correct request variables', () => {
it('generates correct request variables including ORIGINAL_SUBDOMAIN and ALL_HEADERS', () => {
if (!testUtils)
return

// Mock the Request object
const headers = {
'host': 'example.com:3000',
'User-Agent': 'Mozilla/5.0',
'X-Original-Host': 'whatever.com',
'Custom-Header': 'value123',
}
const mockRequest = {
protocol: 'https',
subdomains: ['api', 'test'],
get: vi.fn((header) => {
if (header === 'host')
return 'example.com:3000'
if (header === 'User-Agent')
return 'Mozilla/5.0'
}),
headers,
get(header: keyof typeof headers) {
return headers[header]
},
ip: '192.168.1.1',
hostname: 'api.test.example.com',
originalUrl: '/path',
Expand All @@ -45,7 +50,7 @@ describe('rendering tests', () => {
// Call `getRequestVars` function
const requestVars = testUtils?.fictionApp?.fictionRender?.getRequestVars({ request: mockRequest })

// Assertions
// Assertions for basic request variables
expect(requestVars).toBeDefined()
expect(requestVars?.PROTOCOL).toBe('https')
expect(requestVars?.SUBDOMAIN).toBe('api.test')
Expand All @@ -54,5 +59,11 @@ describe('rendering tests', () => {
expect(requestVars?.USER_AGENT).toBe('Mozilla/5.0')
expect(requestVars?.HOSTNAME).toBe('api.test.example.com')
expect(requestVars?.PATHNAME).toBe('/path')
expect(requestVars?.ORIGINAL_HOST).toBe('whatever.com')

expect(requestVars?.ALL_HEADERS).toContain('host: example.com:3000')
expect(requestVars?.ALL_HEADERS).toContain('User-Agent: Mozilla/5.0')
expect(requestVars?.ALL_HEADERS).toContain('X-Original-Host: whateverq.com')
expect(requestVars?.ALL_HEADERS).toContain('Custom-Header: value123')
})
})
6 changes: 3 additions & 3 deletions @fiction/core/plugin-db/objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { LogHelper } from '../plugin-log'
import { log } from '../plugin-log'

type CreateCol = (params: { schema: Knex.AlterTableBuilder, column: FictionDbCol, db: Knex }) => void
type PrepareForStorage = (args: { value: unknown, key: string, db: Knex }) => unknown
type PrepareForStorage<T extends DefaultValue = DefaultValue> = (args: { value: T, key: string, db: Knex }) => unknown
type DefaultValue = Knex.Value | undefined

export interface FictionDbColSettings<U extends string = string, T extends DefaultValue = DefaultValue> {
Expand All @@ -16,7 +16,7 @@ export interface FictionDbColSettings<U extends string = string, T extends Defau
description?: string
isComposite?: boolean // for composite keys
create: CreateCol
prepare?: PrepareForStorage
prepare?: PrepareForStorage<T>
isPrivate?: boolean
isSetting?: boolean
isAuthority?: boolean
Expand All @@ -41,7 +41,7 @@ export class FictionDbCol<U extends string = string, T extends DefaultValue = De
this.key = settings.key
this.pgKey = toSnakeCase(settings.key)
this.create = settings.create
this.prepare = settings.prepare
this.prepare = settings.prepare as PrepareForStorage // dont use generic as it overspecifies the class interface
this.isComposite = settings.isComposite
this.isPrivate = settings.isPrivate ?? false
this.isSetting = settings.isSetting ?? false
Expand Down
2 changes: 0 additions & 2 deletions @fiction/core/plugin-media/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,6 @@ abstract class MediaQuery extends Query<SaveMediaSettings> {

const ins = { userId, orgId, ...prepped }

this.log.info(`INSERTING`, { data: ins })

const [insertedMedia] = await db.insert(ins).into(this.fictionMedia.tableName).returning<TableMediaConfig[]>('*')

return insertedMedia
Expand Down
2 changes: 1 addition & 1 deletion @fiction/plugin-admin-index/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type PluginMain<T extends BaseAdminPluginSettings> = {

export type PluginLoader<T extends Record<string, any> = Record<string, any>> = {
load: () => Promise<{ setup: () => PluginMain<T & BaseAdminPluginSettings> }>
settings?: Omit<T, keyof BaseAdminPluginSettings>
settings?: () => Omit<T, keyof BaseAdminPluginSettings>
}

// Define a function that takes an array of plugins and returns it.
Expand Down
4 changes: 2 additions & 2 deletions @fiction/plugin-admin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ export class FictionAdmin extends FictionPlugin<FictionAdminSettings> {
if (!plugins)
return

await Promise.all(plugins.map(async ({ load, settings }) => {
await Promise.all(plugins.map(async ({ load, settings = () => undefined }) => {
const { setup } = await load()

const pluginConfig = setup()

const service = await pluginConfig.createPlugin({ ...this.settings, ...settings, fictionAdmin: this })
const service = await pluginConfig.createPlugin({ ...this.settings, ...settings(), fictionAdmin: this })

this.services[pluginConfig.serviceId] = service
}))
Expand Down
2 changes: 1 addition & 1 deletion @fiction/plugin-ai/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export abstract class QueryAi extends Query<QueryAiSettings> {
let message = ''
let more = ''
shortcodes.addShortcode('stock_img', async (args) => {
const { attributes, fullMatch } = args
const { attributes } = args
const search = attributes?.search || ''
const description = attributes?.description || ''
const orientation = attributes?.orientation as 'portrait' | 'landscape' || 'squarish'
Expand Down
2 changes: 1 addition & 1 deletion @fiction/plugin-ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"@fiction/core": "workspace:*",
"@fiction/plugin-unsplash": "workspace:*",
"@pinecone-database/pinecone": "^2.1.0",
"openai": "^4.29.1",
"openai": "^4.29.2",
"tailwindcss": "^3.4.1",
"vue": "^3.4.21"
},
Expand Down
2 changes: 1 addition & 1 deletion @fiction/plugin-sites/el/SiteEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type UserConfig = {
isNavItem: boolean
layoutFormat: 'full'
}
const props = defineProps({
defineProps({
card: {
type: Object as vue.PropType<Card<UserConfig>>,
required: true,
Expand Down
2 changes: 1 addition & 1 deletion @fiction/plugin-sites/el/ToolPagePublish.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const v = vue.computed({
async function save() {
loading.value = true
await saveSite({ site: props.site, delayUntilSaveConfig: props.site.editor.value.tempSite, successMessage: 'Settings saved' })
await saveSite({ site: props.site, delayUntilSaveConfig: props.site.editor.value.tempSite, successMessage: 'Published Successfully', isPublishingDomains: true })
props.site.editor.value.tempSite = {}
loading.value = false
}
Expand Down
8 changes: 6 additions & 2 deletions @fiction/plugin-sites/el/ViewIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const props = defineProps({
card: { type: Object as vue.PropType<Card<UserConfig>>, required: true },
})
const { fictionRouter, fictionSites, fictionAppSites } = useService<{ fictionSites: FictionSites, fictionAppSites: FictionApp }>()
const { fictionSites, fictionAppSites, fictionRouter } = useService<{ fictionSites: FictionSites, fictionAppSites: FictionApp }>()
const showCreateModal = vue.ref(false)
Expand All @@ -42,15 +42,19 @@ const formattedData = vue.computed<IndexItem[]>(() => {
const rows = sites.value.map((site) => {
const domain = site.primaryCustomDomain.value || fictionAppSites.liveUrl.value.replace('*', site.settings.subDomain || '')
const displayDomain = domain.replace('https://', '').replace('http://', '')
const editLink = props.card.link({ path: '/edit-site', query: { siteId: site.settings.siteId } })
const out: IndexItem = {
name: site.settings.title || 'Untitled',
key: site.settings.siteId,
links: [{ name: displayDomain, href: domain, target: '_blank', class: 'underline', icon: 'i-tabler-world' }, { name: `Created ${standardDate(site.settings.createdAt)}` }],
actions: [
{ name: 'Edit Website', btn: 'primary', href: props.card.link({ path: '/edit-site', query: { siteId: site.settings.siteId } }) },
{ name: 'Edit Website', btn: 'primary', href: editLink },
],
fig: vue.defineAsyncComponent(() => import('./fig/FigSite.vue')),
figProps: { site },
onClick: async () => {
await fictionRouter.push(editLink, { caller: 'indexLink' })
},
}
return out
Expand Down
26 changes: 24 additions & 2 deletions @fiction/plugin-sites/endpoint-certs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { EndpointMeta, EndpointResponse } from '@fiction/core'

import type { SitesQuerySettings } from './endpoint'
import { SitesQuery } from './endpoint'

type CertificateIssue = {
Expand Down Expand Up @@ -35,6 +36,21 @@ interface ManageCertParams {
export class ManageCert extends SitesQuery {
graphqlEndpoint = 'https://api.fly.io/graphql'
fictionSites = this.settings.fictionSites
flyIoApiToken = this.fictionSites.settings.flyIoApiToken
flyIoAppId = this.fictionSites.settings.flyIoAppId

constructor(settings: SitesQuerySettings) {
super(settings)

if (!this.settings.fictionEnv.isApp.value) {
if (!this.flyIoApiToken)
throw new Error('Fly.io API token is required for managing certificates.')

if (!this.flyIoAppId)
throw new Error('Fly.io App ID is required for managing certificates.')
}
}

async getClient() {
const { GraphQLClient } = await import('graphql-request')
return new GraphQLClient(this.graphqlEndpoint, {
Expand Down Expand Up @@ -96,10 +112,16 @@ export class ManageCert extends SitesQuery {
catch (error) {
const e = error as Error & { code: string }

// if it exists its unprocessable, if not found its not found
if (e.message.includes('NOT_FOUND') || e.message.includes('UNPROCESSABLE')) {
// The certificate doesn't exist, return successful query but undefined data
if (e.message.includes('NOT_FOUND')) {
return { status: 'success', data: undefined }
}
// The certificate already exists, return successful query with the existing certificate
else if (e.message.includes('UNPROCESSABLE')) {
const r = await this.run({ _action: 'check', hostname }, _meta)

return { status: 'success', data: r.data }
}
else {
this.log.error(`Error in GraphQL Request`, { error })
return { status: 'error', message: 'API error', error }
Expand Down
Loading

0 comments on commit 255fb3e

Please sign in to comment.