Skip to content

Commit 521716a

Browse files
Added edge-api graphdl proxy
1 parent 5b6627d commit 521716a

File tree

7 files changed

+1626
-3
lines changed

7 files changed

+1626
-3
lines changed

admin/worker/analytics.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const logRequests = (req, env, ctx) => {
2+
3+
}

admin/worker/package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "worker",
3+
"version": "0.1.0",
4+
"type": "module",
5+
"scripts": {
6+
"build": "wrangler build",
7+
"dev": "wrangler dev",
8+
"deploy": "wrangler deploy"
9+
},
10+
"devDependencies": {
11+
"wrangler": "^3.13.1"
12+
},
13+
"dependencies": {
14+
"ai-functions": "^0.0.4",
15+
"camelcase": "^8.0.0",
16+
"edge-api": "^0.1.69"
17+
}
18+
}

admin/worker/worker.js

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import { API, json, withCookies } from 'edge-api'
2+
import { withContext } from 'edge-api/middleware'
3+
import { sha1, staleWhileRevalidate, swrFetch } from 'edge-api/utils'
4+
import { withUser } from 'edge-api/jwt'
5+
import camelCase from 'camelcase'
6+
// import { withDB } from 'edge-api/mongo'
7+
8+
export const api = API({
9+
domain: 'graphdl.org',
10+
description: '🚀 AI-Powered SaaS for SaaS',
11+
url: 'https://api.graphdl.org',
12+
docs: 'https://graphdl.org',
13+
site: 'https://graphdl.org',
14+
// base: '/api',
15+
})
16+
17+
18+
// withAIGateway({ account: 'a826340b3b93189c9ebb7c0eaeba3c46', gateway: 'svc' }),
19+
20+
const links = {
21+
'Access': 'https://api.graphdl.org/access',
22+
'Health Check': 'https://api.graphdl.org/health',
23+
}
24+
25+
const getRelationships = (fields) => {
26+
// console.log({ fields })
27+
const relationships = []
28+
fields?.map(field => {
29+
if (field.type === 'row') {
30+
relationships.push(getRelationships(field.fields))
31+
} else if (field.type === 'tabs') {
32+
field.tabs?.map(tab => relationships.push(getRelationships(tab.fields)))
33+
} else if (field.type === 'relationship') {
34+
relationships.push(field)
35+
}
36+
})
37+
return relationships.flat()
38+
}
39+
40+
const linkRelationships = (collection, doc) => {
41+
const relationships = getRelationships(config[collection]?.fields)
42+
relationships?.map(field => {
43+
if (doc[field.name]?.id) {
44+
doc[field.name].id = origin + '/' + field.relationTo + '/' + doc[field.name].id
45+
doc = linkRelationships(field.relationTo, doc[field.name])
46+
}
47+
})
48+
return doc
49+
}
50+
51+
let config
52+
53+
api
54+
.all('*', withCookies, staleWhileRevalidate, async (req, env, ctx) => {
55+
const jwt = req.cookies['auth-token']
56+
const { email } = jwt ? JSON.parse(atob(jwt.split('.')[1])) : {}
57+
req.user = { email, account: email ? 'https://graphdl.org/admin' : undefined, ...req.user }
58+
req.jwt = jwt
59+
if (!config) {
60+
config = await req.swrFetch('https://graphdl.org/api/_cfg', { cf: { cacheEverything: true, cacheTtl: 1 } }).then(res => res.json())
61+
} else {
62+
ctx.waitUntil(req.swrFetch('https://graphdl.org/api/_cfg', { cf: { cacheEverything: true, cacheTtl: 1 } }).then(res => res.json()).then(cfg => config = cfg))
63+
}
64+
65+
})
66+
.get('/', async ({ origin, swrFetch }) => {
67+
// const data = await swrFetch('https://graphdl.org/api/access', { cf: { cacheEverything: true, cacheTtl: 1 } }).then(res => res.json())
68+
const nav = {
69+
api: {
70+
'graphdl.org': origin,
71+
},
72+
app: {
73+
'graphdl.org': 'https://graphdl.org/admin',
74+
},
75+
}
76+
const collections = {}
77+
Object.keys(config.collections).map((name) => collections[config.collections[name].config.labels.plural ?? name] = 'https://api.graphdl.org/' + name)
78+
return { nav, collections }
79+
})
80+
.get('/config', () => ({ config }))
81+
.get('/api', (req) => {
82+
withCookies
83+
const { cookies } = req
84+
const headers = Object.fromEntries(req.headers)
85+
return { links: {
86+
'Health Check': 'https://graphdl.org/api/health',
87+
'Debug': 'https://graphdl.org/api?_debug',
88+
}, cookies }
89+
})
90+
.all('/swr/*', ({ url, method, content, headers, swrFetch }) => swrFetch(url.replace('/swr/','/'), { method, body: content ? JSON.stringify(content) : undefined, cf: { cacheEverything: true, cacheTtl: 1 } }).then(res => res.json()))
91+
92+
.all('/:collection', async ({ collection, origin, url, method, content, headers, pathname, search, query, swrFetch }) => {
93+
// const data = await swrFetch('https://graphdl.org/api' + pathname + search , { method, body: content ? JSON.stringify(content) : undefined, headers, cf: { cacheEverything: true, cacheTtl: 1 } }).then(res => res.json())
94+
const meta = config.collections[collection]?.config
95+
const relationships = getRelationships(meta?.fields)
96+
const data = await fetch('https://graphdl.org/api' + pathname + search , { method, body: content ? JSON.stringify(content) : undefined, headers }).then(res => res.json())
97+
const mergeQuery = obj => origin + pathname + '?' + new URLSearchParams({ ...query, ...obj }).toString()
98+
const nav = {
99+
api: {
100+
'graphdl.org': origin,
101+
[meta?.labels?.plural]: origin + '/' + collection,
102+
},
103+
app: {
104+
'graphdl.org': 'https://graphdl.org/admin',
105+
[meta?.labels?.plural]: 'https://graphdl.org/admin/collections/' + collection,
106+
},
107+
}
108+
const links = {
109+
first: data.totalPages ? mergeQuery({ page: 1 }) : undefined,
110+
next: data.nextPage ? mergeQuery({ page: data.nextPage }) : undefined,
111+
prev: data.prevPage ? mergeQuery({ page: data.prevPage }) : undefined,
112+
last: data.totalPages ? mergeQuery({ page: data.totalPages ?? 1 }) : undefined,
113+
more: data.limit < 10000 && data.hasNextPage ? mergeQuery({ limit: data.limit * 10 }) : undefined,
114+
less: data.limit > 1 ? mergeQuery({ limit: data.limit / 10 }) : undefined,
115+
}
116+
data?.docs?.map(doc => {
117+
doc.id = origin + '/' + collection + '/' + doc.id
118+
relationships?.map(field => {
119+
if (doc[field.name]?.id) {
120+
doc[field.name].id = origin + '/' + field.relationTo + '/' + doc[field.name].id
121+
doc[field.name] = linkRelationships(field.relationTo, doc[field.name])
122+
}
123+
})
124+
})
125+
return { collection, query, nav, links, [camelCase(meta?.labels?.plural)]: data.docs } // , relationships, meta }
126+
})
127+
.all('/:collection/:id', async ({ collection, id, origin, url, method, content, headers, pathname, search, query, swrFetch }) => {
128+
const meta = config.collections[collection]?.config
129+
// const data = await swrFetch('https://graphdl.org/api' + pathname + search , { method, body: content ? JSON.stringify(content) : undefined, headers, cf: { cacheEverything: true, cacheTtl: 1 } }).then(res => res.json())
130+
const data = await fetch('https://graphdl.org/api' + pathname + search , { method, body: content ? JSON.stringify(content) : undefined, headers }).then(res => res.json())
131+
const mergeQuery = obj => origin + pathname + '?' + new URLSearchParams({ ...query, ...obj }).toString()
132+
const nav = {
133+
api: {
134+
'graphdl.org': origin,
135+
[meta?.labels?.plural]: origin + '/' + collection,
136+
[data[meta.admin?.useAsTitle] ?? id]: origin + '/' + collection + '/' + id,
137+
},
138+
app: {
139+
'graphdl.org': 'https://graphdl.org/admin',
140+
[meta?.labels?.plural]: 'https://graphdl.org/admin/collections/' + collection,
141+
[data[meta.admin?.useAsTitle] ?? id]: 'https://graphdl.org/admin/collections/' + collection + '/' + id,
142+
},
143+
}
144+
data.id = origin + '/' + collection + '/' + data.id
145+
// TODO: link relationships - need to refactor collection to collection relationships to be pre-calculated, and map by field name
146+
return { nav, collection, id, [camelCase(meta?.labels?.singular)]: data }
147+
})
148+
.all('*', async ({ origin, url, method, content, headers }) => {
149+
const data = await fetch(url, { method, body: content ? JSON.stringify(content) : undefined, headers }).then(res => res.json())
150+
const links = {
151+
home: origin,
152+
153+
}
154+
return { links, ...data }
155+
})
156+
157+
158+
// .get('/:input', async ({ input, query, user }, { db, terms, openai }) => {
159+
// let result
160+
// // let [ vector ] = await terms.getByIds([ input ])
161+
// let [ vector ] = await db.getByIds([ input ])
162+
// if (!vector) {
163+
// const embedding = await openai.embeddings.create({ input, model: 'text-embedding-ada-002' })
164+
// vector = { id: input, values: embedding.data[0].embedding, metadata: { createdAt: new Date(), createdBy: user.email, createdIn: user.requestId } }
165+
// // result = await terms.upsert([ vector ])
166+
// result = await db.upsert([ vector ])
167+
// }
168+
// let { count, matches } = await db.query(vector.values, { topK: 10, returnVectors: false })
169+
// matches.map(match => {
170+
// if (match.vector?.values) {
171+
// match.vector.values = undefined
172+
// }
173+
// })
174+
// return { input, count, matches, result }
175+
// })
176+
177+
178+
179+
export default {
180+
fetch: (req, env, ctx) => {
181+
withContext(req, env, ctx)
182+
const { url, user = null } = req
183+
// console.log({ url, user })
184+
return api.fetch(req, env, ctx)
185+
}
186+
}
187+

admin/worker/wrangler.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name = "graphdl-api"
2+
main = "worker.js"
3+
compatibility_date = "2023-10-01"
4+
workers_dev = false
5+
account_id = "a826340b3b93189c9ebb7c0eaeba3c46"
6+
routes = [
7+
{ pattern = "api.graphdl.org/*", zone_name = "graphdl.org" },
8+
]
9+
logpush = true
10+
usage_model = "unbound"
11+
12+
tail_consumers = [{service = "tail", environment = "production"}]
13+
14+
15+
[[analytics_engine_datasets]]
16+
binding = "ANALYTICS"

0 commit comments

Comments
 (0)